diff --git a/dep/Changes.log b/dep/Changes.log new file mode 100644 index 000000000..470c68987 --- /dev/null +++ b/dep/Changes.log @@ -0,0 +1,58 @@ +June 16, 2019 + - revert some ACE changes which badly affected threads in FreeBSD + +May 27, 2019 + - fixed TomLib::Crypt build on VS + - fixed Detour/Recast CMake configuration + - assuring STATIC generation of libraries for ZLIB::ZLIB, BZIP2::BZIP2 and mpqlib + +May 17,2019 + - removed useless files from ACE + +May 15, 2019 + - added PCH support for ACE + +May 10th, 2019 + - cleaned up libmpq + - bzip2 version raised to 1.0.6 + - zlib version raised to 1.2.11 + - root CMakeLists.txt logic improved + - revert some FreBSD patches + +May 3rd, 2019 + - added missing sources to ACE CMakeLists.txt + - fixed ACE_SIZE_T_FORMAT_SPECIFIER for FreeBSD + - applied FreeBSD 12+ patches from ports collection to ACE + +May 2nd, 2019 + - fixed a typo which prevented ACE to be built as static lib + - added _WANT_SEMUN compiler definition for ACE when build on FreeBSD 12+ + - removed __fastcall attribute from G3D sources + - removed redundant zlib and bzip2 sources from stormlib + - added TomCrypt and TomMath as static libs for future removal of OpenSSL + - changed CmakeLists.txt files to proper show header files on IDEs + - removed mersenne source code + +January 16th, 2019 + - ACE is built as static library by default. + - Fixed ACE_HAS_CPP11/14 defines for compatibility with other compilers. + - added support for FreeBSD on stormlib + +March 7th, 2018 + - To build ACE as static library, one has to add the following line to the global CMakeLists.txt + 'add_definitions(-DACE_AS_STATIC_LIBS)' + +2017 and older + - The default files for ACE_LITE were amended in commit: https://github.com/mangos/mangosDeps/commit/52e4c984dbca474f7a4353b444339067a95ea277 + - The same changes need to be reapplied if a new version is added. + - The following two lines were amended to fix a connection bottleneck (especially on Linux): + ACE_DEFAULT_BACKLOG - Change 5 to 128 https://github.com/mangos/mangosDeps/blob/Rel21/acelite/ace/Default_Constants.h#L81 + ACE_DEFAULT_ASYNCH_BACKLOG - Change 5 to 128 https://github.com/mangos/mangosDeps/blob/Rel21/acelite/ace/Default_Constants.h#L85 + - For MacOS X, the ACE_UINT64_TYPE should be defined as follows in `ace/config-macosx-leopard.h` + #define ACE_UINT64_TYPE unsigned long long + - To get Travis CI working with `macos10.12` and `xcode8.3`, the following changes should be made to `ace/config-macosx-yosemite.h` + #include "ace/config-macosx-mavericks.h" + #undef ACE_LACKS_CLOCKID_T + #undef ACE_LACKS_CLOCK_MONOTONIC + #undef ACE_LACKS_CLOCK_REALTIME + diff --git a/dep/README.md b/dep/README.md new file mode 100644 index 000000000..677aed632 --- /dev/null +++ b/dep/README.md @@ -0,0 +1,65 @@ + + +
+ + + + +
+ +Mangos Dependencies +------------ +*Mangos* stands on the shoulders of well-known Open Source +libraries, and a few awesome, but less known libraries to prevent us from +inventing the wheel again. + +*Please note that Linux and Mac OS X users should install packages using +their systems package management instead of source packages.* + +* **MySQL** / **PostgreSQL**: to store content, and user data, we rely on + [MySQL][1]/[MariaDB][2] and [PostgreSQL][3] to handle data. +* **ACE**: the [ADAPTIVE Communication Environment][4] aka. *ACE* provides us + with a solid cross-platform framework for abstracting operating system + specific details. +* **Recast**: in order to create navigation data from the client's map files, + we use [Recast][5] to do the dirty work. It provides functions for + rendering, pathing, etc. +* **G3D**: the [G3D][6] engine provides the basic framework for handling 3D + data, and is used to handle basic map data. +* **libmpq**: [libmpq][7] provides an abstraction layer for reading from the + client's data files. +* **Zlib**: [Zlib][12] ([Zlib for Windows][10]) provides compression algorithms + used in both MPQ archive handling and the client/server protocol. +* **Bzip2**: [Bzip2][13] ([Bzip2 for Windows][11]) provides compression + algorithms used in MPQ archives. +* **OpenSSL**: [OpenSSL][8] ([OpenSSL for Windows][14]) provides encryption + algorithms used when authenticating clients. +* **Lua**: [Lua 5.2][15] ([Lua 5.2 for Windows][16]) provides a convenient, fast + scripting environment, which allows us to make live changes to scripted + content. + +*Recast*, *G3D* and *libmpq* are included in the *Mangos* distribution as +we rely on specific versions. *libmpq* is to be replaced with *stormlib* shortly. + +Optional dependencies +--------------------- + +* **Doxygen**: if you want to export HTML or PDF formatted documentation for the + *Mangos* API, you should install [Doxygen][9]. + +[1]: http://www.mysql.com/ "MySQL · The world's most popular open source database" +[2]: http://www.mariadb.org/ "MariaDB · An enhanced, drop-in replacement for MySQL" +[3]: http://www.postgresql.org/ "PostgreSQL · The world's most advanced open source database" +[4]: http://www.cs.wustl.edu/~schmidt/ACE.html "ACE · The ADAPTIVE Communication Environment" +[5]: http://github.com/memononen/recastnavigation "Recast · Navigation-mesh Toolset for Games" +[6]: http://sourceforge.net/projects/g3d/ "G3D · G3D Innovation Engine" +[7]: http://github.com/ge0rg/libmpq "libmpq · A library for reading data from MPQ archives" +[8]: http://www.openssl.org/ "OpenSSL · The Open Source toolkit for SSL/TLS" +[9]: http://www.stack.nl/~dimitri/doxygen/ "Doxygen · API documentation generator" +[10]: http://gnuwin32.sourceforge.net/packages/zlib.htm "Zlib for Windows" +[11]: http://gnuwin32.sourceforge.net/packages/bzip2.htm "Bzip2 for Windows" +[12]: http://www.zlib.net/ "Zlib" +[13]: http://www.bzip.org/ "Bzip2" +[14]: http://slproweb.com/products/Win32OpenSSL.html "OpenSSL for Windows" +[15]: http://www.lua.org/ "Lua" +[16]: https://code.google.com/p/luaforwindows/ "Lua for Windows" diff --git a/dep/StormLib/CMakeLists.txt b/dep/StormLib/CMakeLists.txt new file mode 100644 index 000000000..3c3b3c818 --- /dev/null +++ b/dep/StormLib/CMakeLists.txt @@ -0,0 +1,54 @@ +project(StormLib VERSION 9.22.0) + +add_library(stormlib STATIC + src/adpcm/adpcm.cpp + src/huffman/huff.cpp + src/jenkins/lookup3.c + src/lzma/C/LzFind.c + src/lzma/C/LzmaDec.c + src/lzma/C/LzmaEnc.c + src/pklib/explode.c + src/pklib/implode.c + src/sparse/sparse.cpp + src/rsa/rsa_verify_simple.c + src/FileStream.cpp + src/SBaseCommon.cpp + src/SBaseDumpData.cpp + src/SBaseFileTable.cpp + src/SBaseSubTypes.cpp + src/SCompression.cpp + src/SFileAddFile.cpp + src/SFileAttributes.cpp + src/SFileCompactArchive.cpp + src/SFileCreateArchive.cpp + src/SFileExtractFile.cpp + src/SFileFindFile.cpp + src/SFileGetFileInfo.cpp + src/SFileListFile.cpp + src/SFileOpenArchive.cpp + src/SFileOpenFileEx.cpp + src/SFilePatchArchives.cpp + src/SFileReadFile.cpp + src/SFileVerify.cpp +) + +target_include_directories(stormlib + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src) + +target_compile_definitions(stormlib + PUBLIC + _7ZIP_ST + __SYS_BZLIB + __SYS_ZLIB + LTM_DESC + INTERFACE + STORMLIB_NO_AUTO_LINK +) + +target_link_libraries(stormlib + PRIVATE + ZLIB::ZLIB + BZip2::BZip2 + TomLib::Crypt + TomLib::Math +) \ No newline at end of file diff --git a/dep/StormLib/LICENSE b/dep/StormLib/LICENSE new file mode 100644 index 000000000..136cae4f4 --- /dev/null +++ b/dep/StormLib/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 1999-2013 Ladislav Zezula + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/dep/StormLib/README b/dep/StormLib/README new file mode 100644 index 000000000..d5d803ec7 --- /dev/null +++ b/dep/StormLib/README @@ -0,0 +1 @@ +This is official repository for the StomLib library, an open-source project that can work with Blizzard MPQ archives. \ No newline at end of file diff --git a/dep/StormLib/src/FileStream.cpp b/dep/StormLib/src/FileStream.cpp new file mode 100644 index 000000000..55324ecb3 --- /dev/null +++ b/dep/StormLib/src/FileStream.cpp @@ -0,0 +1,2841 @@ +/*****************************************************************************/ +/* FileStream.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* File stream support for StormLib */ +/* */ +/* Windows support: Written by Ladislav Zezula */ +/* Mac support: Written by Sam Wilkins */ +/* Linux support: Written by Sam Wilkins and Ivan Komissarov */ +/* Big-endian: Written & debugged by Sam Wilkins */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.06.10 1.00 Lad Derived from StormPortMac.cpp and StormPortLinux.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" +#include "FileStream.h" + +#ifdef _MSC_VER +#pragma comment(lib, "wininet.lib") // Internet functions for HTTP stream +#pragma warning(disable: 4800) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#endif + +//----------------------------------------------------------------------------- +// Local defines + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE ((HANDLE)-1) +#endif + +//----------------------------------------------------------------------------- +// Local functions - platform-specific functions + +#ifndef PLATFORM_WINDOWS +static DWORD nLastError = ERROR_SUCCESS; + +DWORD GetLastError() +{ + return nLastError; +} + +void SetLastError(DWORD dwErrCode) +{ + nLastError = dwErrCode; +} +#endif + +static DWORD StringToInt(const char * szString) +{ + DWORD dwValue = 0; + + while('0' <= szString[0] && szString[0] <= '9') + { + dwValue = (dwValue * 10) + (szString[0] - '9'); + szString++; + } + + return dwValue; +} + +//----------------------------------------------------------------------------- +// Dummy init function + +static void BaseNone_Init(TFileStream *) +{ + // Nothing here +} + +//----------------------------------------------------------------------------- +// Local functions - base file support + +static bool BaseFile_Create(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + { + DWORD dwWriteShare = (pStream->dwFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0; + + pStream->Base.File.hFile = CreateFile(pStream->szFileName, + GENERIC_READ | GENERIC_WRITE, + dwWriteShare | FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + 0, + NULL); + if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE) + return false; + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + intptr_t handle; + + handle = open(pStream->szFileName, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if(handle == -1) + { + nLastError = errno; + return false; + } + + pStream->Base.File.hFile = (HANDLE)handle; + } +#endif + + // Reset the file size and position + pStream->Base.File.FileSize = 0; + pStream->Base.File.FilePos = 0; + return true; +} + +static bool BaseFile_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + { + ULARGE_INTEGER FileSize; + DWORD dwWriteAccess = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? 0 : FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_WRITE_ATTRIBUTES; + DWORD dwWriteShare = (dwStreamFlags & STREAM_FLAG_WRITE_SHARE) ? FILE_SHARE_WRITE : 0; + + // Open the file + pStream->Base.File.hFile = CreateFile(szFileName, + FILE_READ_DATA | FILE_READ_ATTRIBUTES | dwWriteAccess, + FILE_SHARE_READ | dwWriteShare, + NULL, + OPEN_EXISTING, + 0, + NULL); + if(pStream->Base.File.hFile == INVALID_HANDLE_VALUE) + return false; + + // Query the file size + FileSize.LowPart = GetFileSize(pStream->Base.File.hFile, &FileSize.HighPart); + pStream->Base.File.FileSize = FileSize.QuadPart; + + // Query last write time + GetFileTime(pStream->Base.File.hFile, NULL, NULL, (LPFILETIME)&pStream->Base.File.FileTime); + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + struct stat64 fileinfo; + int oflag = (dwStreamFlags & STREAM_FLAG_READ_ONLY) ? O_RDONLY : O_RDWR; + intptr_t handle; + + // Open the file + handle = open(szFileName, oflag | O_LARGEFILE); + if(handle == -1) + { + nLastError = errno; + return false; + } + + // Get the file size + if(fstat64(handle, &fileinfo) == -1) + { + nLastError = errno; + close(handle); + return false; + } + + // time_t is number of seconds since 1.1.1970, UTC. + // 1 second = 10000000 (decimal) in FILETIME + // Set the start to 1.1.1970 00:00:00 + pStream->Base.File.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime); + pStream->Base.File.FileSize = (ULONGLONG)fileinfo.st_size; + pStream->Base.File.hFile = (HANDLE)handle; + } +#endif + + // Reset the file position + pStream->Base.File.FilePos = 0; + return true; +} + +static bool BaseFile_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos; + DWORD dwBytesRead = 0; // Must be set by platform-specific code + +#ifdef PLATFORM_WINDOWS + { + // Note: StormLib no longer supports Windows 9x. + // Thus, we can use the OVERLAPPED structure to specify + // file offset to read from file. This allows us to skip + // one system call to SetFilePointer + + // Update the byte offset + pStream->Base.File.FilePos = ByteOffset; + + // Read the data + if(dwBytesToRead != 0) + { + OVERLAPPED Overlapped; + + Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32); + Overlapped.Offset = (DWORD)ByteOffset; + Overlapped.hEvent = NULL; + if(!ReadFile(pStream->Base.File.hFile, pvBuffer, dwBytesToRead, &dwBytesRead, &Overlapped)) + return false; + } + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + ssize_t bytes_read; + + // If the byte offset is different from the current file position, + // we have to update the file position xxx + if(ByteOffset != pStream->Base.File.FilePos) + { + lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET); + pStream->Base.File.FilePos = ByteOffset; + } + + // Perform the read operation + if(dwBytesToRead != 0) + { + bytes_read = read((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToRead); + if(bytes_read == -1) + { + nLastError = errno; + return false; + } + + dwBytesRead = (DWORD)(size_t)bytes_read; + } + } +#endif + + // Increment the current file position by number of bytes read + // If the number of bytes read doesn't match to required amount, return false + pStream->Base.File.FilePos = ByteOffset + dwBytesRead; + if(dwBytesRead != dwBytesToRead) + SetLastError(ERROR_HANDLE_EOF); + return (dwBytesRead == dwBytesToRead); +} + +/** + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, writes to current position + * \a pvBuffer Pointer to data to be written + * \a dwBytesToWrite Number of bytes to write to the file + */ + +static bool BaseFile_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite) +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.File.FilePos; + DWORD dwBytesWritten = 0; // Must be set by platform-specific code + +#ifdef PLATFORM_WINDOWS + { + // Note: StormLib no longer supports Windows 9x. + // Thus, we can use the OVERLAPPED structure to specify + // file offset to read from file. This allows us to skip + // one system call to SetFilePointer + + // Update the byte offset + pStream->Base.File.FilePos = ByteOffset; + + // Read the data + if(dwBytesToWrite != 0) + { + OVERLAPPED Overlapped; + + Overlapped.OffsetHigh = (DWORD)(ByteOffset >> 32); + Overlapped.Offset = (DWORD)ByteOffset; + Overlapped.hEvent = NULL; + if(!WriteFile(pStream->Base.File.hFile, pvBuffer, dwBytesToWrite, &dwBytesWritten, &Overlapped)) + return false; + } + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + ssize_t bytes_written; + + // If the byte offset is different from the current file position, + // we have to update the file position + if(ByteOffset != pStream->Base.File.FilePos) + { + lseek64((intptr_t)pStream->Base.File.hFile, (off64_t)(ByteOffset), SEEK_SET); + pStream->Base.File.FilePos = ByteOffset; + } + + // Perform the read operation + bytes_written = write((intptr_t)pStream->Base.File.hFile, pvBuffer, (size_t)dwBytesToWrite); + if(bytes_written == -1) + { + nLastError = errno; + return false; + } + + dwBytesWritten = (DWORD)(size_t)bytes_written; + } +#endif + + // Increment the current file position by number of bytes read + pStream->Base.File.FilePos = ByteOffset + dwBytesWritten; + + // Also modify the file size, if needed + if(pStream->Base.File.FilePos > pStream->Base.File.FileSize) + pStream->Base.File.FileSize = pStream->Base.File.FilePos; + + if(dwBytesWritten != dwBytesToWrite) + SetLastError(ERROR_DISK_FULL); + return (dwBytesWritten == dwBytesToWrite); +} + +/** + * \a pStream Pointer to an open stream + * \a NewFileSize New size of the file + */ +static bool BaseFile_Resize(TFileStream * pStream, ULONGLONG NewFileSize) +{ +#ifdef PLATFORM_WINDOWS + { + LONG FileSizeHi = (LONG)(NewFileSize >> 32); + LONG FileSizeLo; + DWORD dwNewPos; + bool bResult; + + // Set the position at the new file size + dwNewPos = SetFilePointer(pStream->Base.File.hFile, (LONG)NewFileSize, &FileSizeHi, FILE_BEGIN); + if(dwNewPos == INVALID_SET_FILE_POINTER && GetLastError() != ERROR_SUCCESS) + return false; + + // Set the current file pointer as the end of the file + bResult = (bool)SetEndOfFile(pStream->Base.File.hFile); + if(bResult) + pStream->Base.File.FileSize = NewFileSize; + + // Restore the file position + FileSizeHi = (LONG)(pStream->Base.File.FilePos >> 32); + FileSizeLo = (LONG)(pStream->Base.File.FilePos); + SetFilePointer(pStream->Base.File.hFile, FileSizeLo, &FileSizeHi, FILE_BEGIN); + return bResult; + } +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + { + if(ftruncate64((intptr_t)pStream->Base.File.hFile, (off64_t)NewFileSize) == -1) + { + nLastError = errno; + return false; + } + + pStream->Base.File.FileSize = NewFileSize; + return true; + } +#endif +} + +// Gives the current file size +static bool BaseFile_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + // Note: Used by all thre base providers. + // Requires the TBaseData union to have the same layout for all three base providers + *pFileSize = pStream->Base.File.FileSize; + return true; +} + +// Gives the current file position +static bool BaseFile_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + // Note: Used by all thre base providers. + // Requires the TBaseData union to have the same layout for all three base providers + *pByteOffset = pStream->Base.File.FilePos; + return true; +} + +// Renames the file pointed by pStream so that it contains data from pNewStream +static bool BaseFile_Replace(TFileStream * pStream, TFileStream * pNewStream) +{ +#ifdef PLATFORM_WINDOWS + // Delete the original stream file. Don't check the result value, + // because if the file doesn't exist, it would fail + DeleteFile(pStream->szFileName); + + // Rename the new file to the old stream's file + return (bool)MoveFile(pNewStream->szFileName, pStream->szFileName); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + // "rename" on Linux also works if the target file exists + if(rename(pNewStream->szFileName, pStream->szFileName) == -1) + { + nLastError = errno; + return false; + } + + return true; +#endif +} + +static void BaseFile_Close(TFileStream * pStream) +{ + if(pStream->Base.File.hFile != INVALID_HANDLE_VALUE) + { +#ifdef PLATFORM_WINDOWS + CloseHandle(pStream->Base.File.hFile); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + close((intptr_t)pStream->Base.File.hFile); +#endif + } + + // Also invalidate the handle + pStream->Base.File.hFile = INVALID_HANDLE_VALUE; +} + +// Initializes base functions for the disk file +static void BaseFile_Init(TFileStream * pStream) +{ + pStream->BaseCreate = BaseFile_Create; + pStream->BaseOpen = BaseFile_Open; + pStream->BaseRead = BaseFile_Read; + pStream->BaseWrite = BaseFile_Write; + pStream->BaseResize = BaseFile_Resize; + pStream->BaseGetSize = BaseFile_GetSize; + pStream->BaseGetPos = BaseFile_GetPos; + pStream->BaseClose = BaseFile_Close; +} + +//----------------------------------------------------------------------------- +// Local functions - base memory-mapped file support + +static bool BaseMap_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + + ULARGE_INTEGER FileSize; + HANDLE hFile; + HANDLE hMap; + bool bResult = false; + + // Keep compiler happy + dwStreamFlags = dwStreamFlags; + + // Open the file for read access + hFile = CreateFile(szFileName, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + // Retrieve file size. Don't allow mapping file of a zero size. + FileSize.LowPart = GetFileSize(hFile, &FileSize.HighPart); + if(FileSize.QuadPart != 0) + { + // Now create mapping object + hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if(hMap != NULL) + { + // Map the entire view into memory + // Note that this operation will fail if the file can't fit + // into usermode address space + pStream->Base.Map.pbFile = (LPBYTE)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0); + if(pStream->Base.Map.pbFile != NULL) + { + // Retrieve file time + GetFileTime(hFile, NULL, NULL, (LPFILETIME)&pStream->Base.Map.FileTime); + + // Retrieve file size and position + pStream->Base.Map.FileSize = FileSize.QuadPart; + pStream->Base.Map.FilePos = 0; + bResult = true; + } + + // Close the map handle + CloseHandle(hMap); + } + } + + // Close the file handle + CloseHandle(hFile); + } + + // If the file is not there and is not available for random access, + // report error + if(bResult == false) + return false; +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + struct stat64 fileinfo; + intptr_t handle; + bool bResult = false; + + // Open the file + handle = open(szFileName, O_RDONLY); + if(handle != -1) + { + // Get the file size + if(fstat64(handle, &fileinfo) != -1) + { + pStream->Base.Map.pbFile = (LPBYTE)mmap(NULL, (size_t)fileinfo.st_size, PROT_READ, MAP_PRIVATE, handle, 0); + if(pStream->Base.Map.pbFile != NULL) + { + // time_t is number of seconds since 1.1.1970, UTC. + // 1 second = 10000000 (decimal) in FILETIME + // Set the start to 1.1.1970 00:00:00 + pStream->Base.Map.FileTime = 0x019DB1DED53E8000ULL + (10000000 * fileinfo.st_mtime); + pStream->Base.Map.FileSize = (ULONGLONG)fileinfo.st_size; + pStream->Base.Map.FilePos = 0; + bResult = true; + } + } + close(handle); + } + + // Did the mapping fail? + if(bResult == false) + { + nLastError = errno; + return false; + } +#endif + + return true; +} + +static bool BaseMap_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Map.FilePos; + + // Do we have to read anything at all? + if(dwBytesToRead != 0) + { + // Don't allow reading past file size + if((ByteOffset + dwBytesToRead) > pStream->Base.Map.FileSize) + return false; + + // Copy the required data + memcpy(pvBuffer, pStream->Base.Map.pbFile + (size_t)ByteOffset, dwBytesToRead); + } + + // Move the current file position + pStream->Base.Map.FilePos += dwBytesToRead; + return true; +} + +static void BaseMap_Close(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + if(pStream->Base.Map.pbFile != NULL) + UnmapViewOfFile(pStream->Base.Map.pbFile); +#endif + +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) + if(pStream->Base.Map.pbFile != NULL) + munmap(pStream->Base.Map.pbFile, (size_t )pStream->Base.Map.FileSize); +#endif + + pStream->Base.Map.pbFile = NULL; +} + +// Initializes base functions for the mapped file +static void BaseMap_Init(TFileStream * pStream) +{ + // Supply the file stream functions + pStream->BaseOpen = BaseMap_Open; + pStream->BaseRead = BaseMap_Read; + pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function + pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function + pStream->BaseClose = BaseMap_Close; + + // Mapped files are read-only + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; +} + +//----------------------------------------------------------------------------- +// Local functions - base HTTP file support + +static const TCHAR * BaseHttp_ExtractServerName(const TCHAR * szFileName, TCHAR * szServerName) +{ + // Check for HTTP + if(!_tcsnicmp(szFileName, _T("http://"), 7)) + szFileName += 7; + + // Cut off the server name + if(szServerName != NULL) + { + while(szFileName[0] != 0 && szFileName[0] != _T('/')) + *szServerName++ = *szFileName++; + *szServerName = 0; + } + else + { + while(szFileName[0] != 0 && szFileName[0] != _T('/')) + szFileName++; + } + + // Return the remainder + return szFileName; +} + +static bool BaseHttp_Open(TFileStream * pStream, const TCHAR * szFileName, DWORD dwStreamFlags) +{ +#ifdef PLATFORM_WINDOWS + + HINTERNET hRequest; + DWORD dwTemp = 0; + + // Keep compiler happy + dwStreamFlags = dwStreamFlags; + + // Don't connect to the internet + if(!InternetGetConnectedState(&dwTemp, 0)) + return false; + + // Initiate the connection to the internet + pStream->Base.Http.hInternet = InternetOpen(_T("StormLib HTTP MPQ reader"), + INTERNET_OPEN_TYPE_PRECONFIG, + NULL, + NULL, + 0); + if(pStream->Base.Http.hInternet != NULL) + { + TCHAR szServerName[MAX_PATH]; + DWORD dwFlags = INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_NO_UI | INTERNET_FLAG_NO_CACHE_WRITE; + + // Initiate connection with the server + szFileName = BaseHttp_ExtractServerName(szFileName, szServerName); + pStream->Base.Http.hConnect = InternetConnect(pStream->Base.Http.hInternet, + szServerName, + INTERNET_DEFAULT_HTTP_PORT, + NULL, + NULL, + INTERNET_SERVICE_HTTP, + dwFlags, + 0); + if(pStream->Base.Http.hConnect != NULL) + { + // Open HTTP request to the file + hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + if(hRequest != NULL) + { + if(HttpSendRequest(hRequest, NULL, 0, NULL, 0)) + { + ULONGLONG FileTime = 0; + DWORD dwFileSize = 0; + DWORD dwDataSize; + DWORD dwIndex = 0; + TCHAR StatusCode[0x08]; + + // Check if the file succeeded to open + dwDataSize = sizeof(StatusCode); + if(HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE, StatusCode, &dwDataSize, &dwIndex)) + { + if(_tcscmp(StatusCode, _T("200"))) + { + InternetCloseHandle(hRequest); + SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } + } + + // Check if the MPQ has Last Modified field + dwDataSize = sizeof(ULONGLONG); + if(HttpQueryInfo(hRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, &FileTime, &dwDataSize, &dwIndex)) + pStream->Base.Http.FileTime = FileTime; + + // Verify if the server supports random access + dwDataSize = sizeof(DWORD); + if(HttpQueryInfo(hRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &dwFileSize, &dwDataSize, &dwIndex)) + { + if(dwFileSize != 0) + { + InternetCloseHandle(hRequest); + pStream->Base.Http.FileSize = dwFileSize; + pStream->Base.Http.FilePos = 0; + return true; + } + } + } + + // Close the request + InternetCloseHandle(hRequest); + } + + // Close the connection handle + InternetCloseHandle(pStream->Base.Http.hConnect); + pStream->Base.Http.hConnect = NULL; + } + + // Close the internet handle + InternetCloseHandle(pStream->Base.Http.hInternet); + pStream->Base.Http.hInternet = NULL; + } + + // If the file is not there or is not available for random access, report error + pStream->BaseClose(pStream); + return false; + +#else + + // Not supported + SetLastError(ERROR_NOT_SUPPORTED); + pStream = pStream; + return false; + +#endif +} + +static bool BaseHttp_Read( + TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ +#ifdef PLATFORM_WINDOWS + ULONGLONG ByteOffset = (pByteOffset != NULL) ? *pByteOffset : pStream->Base.Http.FilePos; + DWORD dwTotalBytesRead = 0; + + // Do we have to read anything at all? + if(dwBytesToRead != 0) + { + HINTERNET hRequest; + LPCTSTR szFileName; + LPBYTE pbBuffer = (LPBYTE)pvBuffer; + TCHAR szRangeRequest[0x80]; + DWORD dwStartOffset = (DWORD)ByteOffset; + DWORD dwEndOffset = dwStartOffset + dwBytesToRead; + + // Open HTTP request to the file + szFileName = BaseHttp_ExtractServerName(pStream->szFileName, NULL); + hRequest = HttpOpenRequest(pStream->Base.Http.hConnect, _T("GET"), szFileName, NULL, NULL, NULL, INTERNET_FLAG_NO_CACHE_WRITE, 0); + if(hRequest != NULL) + { + // Add range request to the HTTP headers + // http://www.clevercomponents.com/articles/article015/resuming.asp + _stprintf(szRangeRequest, _T("Range: bytes=%u-%u"), (unsigned int)dwStartOffset, (unsigned int)dwEndOffset); + HttpAddRequestHeaders(hRequest, szRangeRequest, 0xFFFFFFFF, HTTP_ADDREQ_FLAG_ADD_IF_NEW); + + // Send the request to the server + if(HttpSendRequest(hRequest, NULL, 0, NULL, 0)) + { + while(dwTotalBytesRead < dwBytesToRead) + { + DWORD dwBlockBytesToRead = dwBytesToRead - dwTotalBytesRead; + DWORD dwBlockBytesRead = 0; + + // Read the block from the file + if(dwBlockBytesToRead > 0x200) + dwBlockBytesToRead = 0x200; + InternetReadFile(hRequest, pbBuffer, dwBlockBytesToRead, &dwBlockBytesRead); + + // Check for end + if(dwBlockBytesRead == 0) + break; + + // Move buffers + dwTotalBytesRead += dwBlockBytesRead; + pbBuffer += dwBlockBytesRead; + } + } + InternetCloseHandle(hRequest); + } + } + + // Increment the current file position by number of bytes read + pStream->Base.Http.FilePos = ByteOffset + dwTotalBytesRead; + + // If the number of bytes read doesn't match the required amount, return false + if(dwTotalBytesRead != dwBytesToRead) + SetLastError(ERROR_HANDLE_EOF); + return (dwTotalBytesRead == dwBytesToRead); + +#else + + // Not supported + pStream = pStream; + pByteOffset = pByteOffset; + pvBuffer = pvBuffer; + dwBytesToRead = dwBytesToRead; + SetLastError(ERROR_NOT_SUPPORTED); + return false; + +#endif +} + +static void BaseHttp_Close(TFileStream * pStream) +{ +#ifdef PLATFORM_WINDOWS + if(pStream->Base.Http.hConnect != NULL) + InternetCloseHandle(pStream->Base.Http.hConnect); + pStream->Base.Http.hConnect = NULL; + + if(pStream->Base.Http.hInternet != NULL) + InternetCloseHandle(pStream->Base.Http.hInternet); + pStream->Base.Http.hInternet = NULL; +#else + pStream = pStream; +#endif +} + +// Initializes base functions for the mapped file +static void BaseHttp_Init(TFileStream * pStream) +{ + // Supply the stream functions + pStream->BaseOpen = BaseHttp_Open; + pStream->BaseRead = BaseHttp_Read; + pStream->BaseGetSize = BaseFile_GetSize; // Reuse BaseFile function + pStream->BaseGetPos = BaseFile_GetPos; // Reuse BaseFile function + pStream->BaseClose = BaseHttp_Close; + + // HTTP files are read-only + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; +} + +//----------------------------------------------------------------------------- +// Local functions - base block-based support + +// Generic function that loads blocks from the file +// The function groups the block with the same availability, +// so the called BlockRead can finish the request in a single system call +static bool BlockStream_Read( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead) // Number of bytes to read from the file +{ + ULONGLONG BlockOffset0; + ULONGLONG BlockOffset; + ULONGLONG ByteOffset; + ULONGLONG EndOffset; + LPBYTE TransferBuffer; + LPBYTE BlockBuffer; + DWORD BlockBufferOffset; // Offset of the desired data in the block buffer + DWORD BytesNeeded; // Number of bytes that really need to be read + DWORD BlockSize = pStream->BlockSize; + DWORD BlockCount; + bool bPrevBlockAvailable; + bool bCallbackCalled = false; + bool bBlockAvailable; + bool bResult = true; + + // The base block read function must be present + assert(pStream->BlockRead != NULL); + + // NOP reading of zero bytes + if(dwBytesToRead == 0) + return true; + + // Get the current position in the stream + ByteOffset = (pByteOffset != NULL) ? pByteOffset[0] : pStream->StreamPos; + EndOffset = ByteOffset + dwBytesToRead; + if(EndOffset > pStream->StreamSize) + { + SetLastError(ERROR_HANDLE_EOF); + return false; + } + + // Calculate the block parameters + BlockOffset0 = BlockOffset = ByteOffset & ~((ULONGLONG)BlockSize - 1); + BlockCount = (DWORD)(((EndOffset - BlockOffset) + (BlockSize - 1)) / BlockSize); + BytesNeeded = (DWORD)(EndOffset - BlockOffset); + + // Remember where we have our data + assert((BlockSize & (BlockSize - 1)) == 0); + BlockBufferOffset = (DWORD)(ByteOffset & (BlockSize - 1)); + + // Allocate buffer for reading blocks + TransferBuffer = BlockBuffer = STORM_ALLOC(BYTE, (BlockCount * BlockSize)); + if(TransferBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return false; + } + + // If all blocks are available, just read all blocks at once + if(pStream->IsComplete == 0) + { + // Now parse the blocks and send the block read request + // to all blocks with the same availability + assert(pStream->BlockCheck != NULL); + bPrevBlockAvailable = pStream->BlockCheck(pStream, BlockOffset); + + // Loop as long as we have something to read + while(BlockOffset < EndOffset) + { + // Determine availability of the next block + bBlockAvailable = pStream->BlockCheck(pStream, BlockOffset); + + // If the availability has changed, read all blocks up to this one + if(bBlockAvailable != bPrevBlockAvailable) + { + // Call the file stream callback, if the block is not available + if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false) + { + pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0)); + bCallbackCalled = true; + } + + // Load the continuous blocks with the same availability + assert(BlockOffset > BlockOffset0); + bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable); + if(!bResult) + break; + + // Move the block offset + BlockBuffer += (DWORD)(BlockOffset - BlockOffset0); + BytesNeeded -= (DWORD)(BlockOffset - BlockOffset0); + bPrevBlockAvailable = bBlockAvailable; + BlockOffset0 = BlockOffset; + } + + // Move to the block offset in the stream + BlockOffset += BlockSize; + } + + // If there is a block(s) remaining to be read, do it + if(BlockOffset > BlockOffset0) + { + // Call the file stream callback, if the block is not available + if(pStream->pMaster && pStream->pfnCallback && bPrevBlockAvailable == false) + { + pStream->pfnCallback(pStream->UserData, BlockOffset0, (DWORD)(BlockOffset - BlockOffset0)); + bCallbackCalled = true; + } + + // Read the complete blocks from the file + if(BlockOffset > pStream->StreamSize) + BlockOffset = pStream->StreamSize; + bResult = pStream->BlockRead(pStream, BlockOffset0, BlockOffset, BlockBuffer, BytesNeeded, bPrevBlockAvailable); + } + } + else + { + // Read the complete blocks from the file + if(EndOffset > pStream->StreamSize) + EndOffset = pStream->StreamSize; + bResult = pStream->BlockRead(pStream, BlockOffset, EndOffset, BlockBuffer, BytesNeeded, true); + } + + // Now copy the data to the user buffer + if(bResult) + { + memcpy(pvBuffer, TransferBuffer + BlockBufferOffset, dwBytesToRead); + pStream->StreamPos = ByteOffset + dwBytesToRead; + } + else + { + // If the block read failed, set the last error + SetLastError(ERROR_FILE_INCOMPLETE); + } + + // Call the callback to indicate we are done + if(bCallbackCalled) + pStream->pfnCallback(pStream->UserData, 0, 0); + + // Free the block buffer and return + STORM_FREE(TransferBuffer); + return bResult; +} + +static bool BlockStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + *pFileSize = pStream->StreamSize; + return true; +} + +static bool BlockStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + *pByteOffset = pStream->StreamPos; + return true; +} + +static void BlockStream_Close(TBlockStream * pStream) +{ + // Free the data map, if any + if(pStream->FileBitmap != NULL) + STORM_FREE(pStream->FileBitmap); + pStream->FileBitmap = NULL; + + // Call the base class for closing the stream + pStream->BaseClose(pStream); +} + +//----------------------------------------------------------------------------- +// File stream allocation function + +static STREAM_INIT StreamBaseInit[4] = +{ + BaseFile_Init, + BaseMap_Init, + BaseHttp_Init, + BaseNone_Init +}; + +// This function allocates an empty structure for the file stream +// The stream structure is created as flat block, variable length +// The file name is placed after the end of the stream structure data +static TFileStream * AllocateFileStream( + const TCHAR * szFileName, + size_t StreamSize, + DWORD dwStreamFlags) +{ + TFileStream * pMaster = NULL; + TFileStream * pStream; + const TCHAR * szNextFile = szFileName; + size_t FileNameSize; + + // Sanity check + assert(StreamSize != 0); + + // The caller can specify chain of files in the following form: + // C:\archive.MPQ*http://www.server.com/MPQs/archive-server.MPQ + // In that case, we use the part after "*" as master file name + while(szNextFile[0] != 0 && szNextFile[0] != _T('*')) + szNextFile++; + FileNameSize = (size_t)((szNextFile - szFileName) * sizeof(TCHAR)); + + // If we have a next file, we need to open it as master stream + // Note that we don't care if the master stream exists or not, + // If it doesn't, later attempts to read missing file block will fail + if(szNextFile[0] == _T('*')) + { + // Don't allow another master file in the string + if(_tcschr(szNextFile + 1, _T('*')) != NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } + + // Open the master file + pMaster = FileStream_OpenFile(szNextFile + 1, STREAM_FLAG_READ_ONLY); + } + + // Allocate the stream structure for the given stream type + pStream = (TFileStream *)STORM_ALLOC(BYTE, StreamSize + FileNameSize + sizeof(TCHAR)); + if(pStream != NULL) + { + // Zero the entire structure + memset(pStream, 0, StreamSize); + pStream->pMaster = pMaster; + pStream->dwFlags = dwStreamFlags; + + // Initialize the file name + pStream->szFileName = (TCHAR *)((BYTE *)pStream + StreamSize); + memcpy(pStream->szFileName, szFileName, FileNameSize); + pStream->szFileName[FileNameSize / sizeof(TCHAR)] = 0; + + // Initialize the stream functions + StreamBaseInit[dwStreamFlags & 0x03](pStream); + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - flat stream support + +static DWORD FlatStream_CheckFile(TBlockStream * pStream) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD WholeByteCount = (pStream->BlockCount / 8); + DWORD ExtraBitsCount = (pStream->BlockCount & 7); + BYTE ExpectedValue; + + // Verify the whole bytes - their value must be 0xFF + for(DWORD i = 0; i < WholeByteCount; i++) + { + if(FileBitmap[i] != 0xFF) + return 0; + } + + // If there are extra bits, calculate the mask + if(ExtraBitsCount != 0) + { + ExpectedValue = (BYTE)((1 << ExtraBitsCount) - 1); + if(FileBitmap[WholeByteCount] != ExpectedValue) + return 0; + } + + // Yes, the file is complete + return 1; +} + +static bool FlatStream_LoadBitmap(TBlockStream * pStream) +{ + FILE_BITMAP_FOOTER Footer; + ULONGLONG ByteOffset; + LPBYTE FileBitmap; + DWORD BlockCount; + DWORD BitmapSize; + + // Do not load the bitmap if we should not have to + if(!(pStream->dwFlags & STREAM_FLAG_USE_BITMAP)) + return false; + + // Only if the size is greater than size of bitmap footer + if(pStream->Base.File.FileSize > sizeof(FILE_BITMAP_FOOTER)) + { + // Load the bitmap footer + ByteOffset = pStream->Base.File.FileSize - sizeof(FILE_BITMAP_FOOTER); + if(pStream->BaseRead(pStream, &ByteOffset, &Footer, sizeof(FILE_BITMAP_FOOTER))) + { + // Make sure that the array is properly BSWAP-ed + BSWAP_ARRAY32_UNSIGNED((LPDWORD)(&Footer), sizeof(FILE_BITMAP_FOOTER)); + + // Verify if there is actually a footer + if(Footer.Signature == ID_FILE_BITMAP_FOOTER && Footer.Version == 0x03) + { + // Get the offset of the bitmap, number of blocks and size of the bitmap + ByteOffset = MAKE_OFFSET64(Footer.MapOffsetHi, Footer.MapOffsetLo); + BlockCount = (DWORD)(((ByteOffset - 1) / Footer.BlockSize) + 1); + BitmapSize = ((BlockCount + 7) / 8); + + // Check if the sizes match + if(ByteOffset + BitmapSize + sizeof(FILE_BITMAP_FOOTER) == pStream->Base.File.FileSize) + { + // Allocate space for the bitmap + FileBitmap = STORM_ALLOC(BYTE, BitmapSize); + if(FileBitmap != NULL) + { + // Load the bitmap bits + if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize)) + { + STORM_FREE(FileBitmap); + return false; + } + + // Update the stream size + pStream->BuildNumber = Footer.BuildNumber; + pStream->StreamSize = ByteOffset; + + // Fill the bitmap information + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = BitmapSize; + pStream->BlockSize = Footer.BlockSize; + pStream->BlockCount = BlockCount; + pStream->IsComplete = FlatStream_CheckFile(pStream); + return true; + } + } + } + } + } + + return false; +} + +static void FlatStream_UpdateBitmap( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD BlockIndex; + DWORD BlockSize = pStream->BlockSize; + DWORD ByteIndex; + BYTE BitMask; + + // Sanity checks + assert((StartOffset & (BlockSize - 1)) == 0); + assert(FileBitmap != NULL); + + // Calculate the index of the block + BlockIndex = (DWORD)(StartOffset / BlockSize); + ByteIndex = (BlockIndex / 0x08); + BitMask = (BYTE)(1 << (BlockIndex & 0x07)); + + // Set all bits for the specified range + while(StartOffset < EndOffset) + { + // Set the bit + FileBitmap[ByteIndex] |= BitMask; + + // Move all + StartOffset += BlockSize; + ByteIndex += (BitMask >> 0x07); + BitMask = (BitMask >> 0x07) | (BitMask << 0x01); + } + + // Increment the bitmap update count + pStream->IsModified = 1; +} + +static bool FlatStream_BlockCheck( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG BlockOffset) +{ + LPBYTE FileBitmap = (LPBYTE)pStream->FileBitmap; + DWORD BlockIndex; + BYTE BitMask; + + // Sanity checks + assert((BlockOffset & (pStream->BlockSize - 1)) == 0); + assert(FileBitmap != NULL); + + // Calculate the index of the block + BlockIndex = (DWORD)(BlockOffset / pStream->BlockSize); + BitMask = (BYTE)(1 << (BlockIndex & 0x07)); + + // Check if the bit is present + return (FileBitmap[BlockIndex / 0x08] & BitMask) ? true : false; +} + +static bool FlatStream_BlockRead( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + DWORD BytesToRead = (DWORD)(EndOffset - StartOffset); + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + + // If the blocks are not available, we need to load them from the master + // and then save to the mirror + if(bAvailable == false) + { + // If we have no master, we cannot satisfy read request + if(pStream->pMaster == NULL) + return false; + + // Load the blocks from the master stream + // Note that we always have to read complete blocks + // so they get properly stored to the mirror stream + if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead)) + return false; + + // Store the loaded blocks to the mirror file. + // Note that this operation is not required to succeed + if(pStream->BaseWrite(pStream, &StartOffset, BlockBuffer, BytesToRead)) + FlatStream_UpdateBitmap(pStream, StartOffset, EndOffset); + + return true; + } + else + { + if(BytesToRead > BytesNeeded) + BytesToRead = BytesNeeded; + return pStream->BaseRead(pStream, &StartOffset, BlockBuffer, BytesToRead); + } +} + +static void FlatStream_Close(TBlockStream * pStream) +{ + FILE_BITMAP_FOOTER Footer; + + if(pStream->FileBitmap && pStream->IsModified) + { + // Write the file bitmap + pStream->BaseWrite(pStream, &pStream->StreamSize, pStream->FileBitmap, pStream->BitmapSize); + + // Prepare and write the file footer + Footer.Signature = ID_FILE_BITMAP_FOOTER; + Footer.Version = 3; + Footer.BuildNumber = pStream->BuildNumber; + Footer.MapOffsetLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF); + Footer.MapOffsetHi = (DWORD)(pStream->StreamSize >> 0x20); + Footer.BlockSize = pStream->BlockSize; + BSWAP_ARRAY32_UNSIGNED(&Footer, sizeof(FILE_BITMAP_FOOTER)); + pStream->BaseWrite(pStream, NULL, &Footer, sizeof(FILE_BITMAP_FOOTER)); + } + + // Close the base class + BlockStream_Close(pStream); +} + +static bool FlatStream_CreateMirror(TBlockStream * pStream) +{ + ULONGLONG MasterSize = 0; + ULONGLONG MirrorSize = 0; + LPBYTE FileBitmap = NULL; + DWORD dwBitmapSize; + DWORD dwBlockCount; + bool bNeedCreateMirrorStream = true; + bool bNeedResizeMirrorStream = true; + + // Do we have master function and base creation function? + if(pStream->pMaster == NULL || pStream->BaseCreate == NULL) + return false; + + // Retrieve the master file size, block count and bitmap size + FileStream_GetSize(pStream->pMaster, &MasterSize); + dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + dwBitmapSize = (DWORD)((dwBlockCount + 7) / 8); + + // Setup stream size and position + pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really??? + pStream->StreamSize = MasterSize; + pStream->StreamPos = 0; + + // Open the base stream for write access + if(pStream->BaseOpen(pStream, pStream->szFileName, 0)) + { + // If the file open succeeded, check if the file size matches required size + pStream->BaseGetSize(pStream, &MirrorSize); + if(MirrorSize == MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER)) + { + // Attempt to load an existing file bitmap + if(FlatStream_LoadBitmap(pStream)) + return true; + + // We need to create new file bitmap + bNeedResizeMirrorStream = false; + } + + // We need to create mirror stream + bNeedCreateMirrorStream = false; + } + + // Create a new stream, if needed + if(bNeedCreateMirrorStream) + { + if(!pStream->BaseCreate(pStream)) + return false; + } + + // If we need to, then resize the mirror stream + if(bNeedResizeMirrorStream) + { + if(!pStream->BaseResize(pStream, MasterSize + dwBitmapSize + sizeof(FILE_BITMAP_FOOTER))) + return false; + } + + // Allocate the bitmap array + FileBitmap = STORM_ALLOC(BYTE, dwBitmapSize); + if(FileBitmap == NULL) + return false; + + // Initialize the bitmap + memset(FileBitmap, 0, dwBitmapSize); + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = dwBitmapSize; + pStream->BlockSize = DEFAULT_BLOCK_SIZE; + pStream->BlockCount = dwBlockCount; + pStream->IsComplete = 0; + pStream->IsModified = 1; + + // Note: Don't write the stream bitmap right away. + // Doing so would cause sparse file resize on NTFS, + // which would take long time on larger files. + return true; +} + +static TFileStream * FlatStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBlockStream * pStream; + ULONGLONG ByteOffset = 0; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Do we have a master stream? + if(pStream->pMaster != NULL) + { + if(!FlatStream_CreateMirror(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + } + else + { + // Attempt to open the base stream + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + { + FileStream_Close(pStream); + return NULL; + } + + // Load the bitmap, if required to + if(dwStreamFlags & STREAM_FLAG_USE_BITMAP) + FlatStream_LoadBitmap(pStream); + } + + // If we have a stream bitmap, set the reading functions + // which check presence of each file block + if(pStream->FileBitmap != NULL) + { + // Set the stream position to zero. Stream size is already set + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Supply the stream functions + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamClose = (STREAM_CLOSE)FlatStream_Close; + + // Supply the block functions + pStream->BlockCheck = (BLOCK_CHECK)FlatStream_BlockCheck; + pStream->BlockRead = (BLOCK_READ)FlatStream_BlockRead; + } + else + { + // Reset the base position to zero + pStream->BaseRead(pStream, &ByteOffset, NULL, 0); + + // Setup stream size and position + pStream->StreamSize = pStream->Base.File.FileSize; + pStream->StreamPos = 0; + + // Set the base functions + pStream->StreamRead = pStream->BaseRead; + pStream->StreamWrite = pStream->BaseWrite; + pStream->StreamResize = pStream->BaseResize; + pStream->StreamGetSize = pStream->BaseGetSize; + pStream->StreamGetPos = pStream->BaseGetPos; + pStream->StreamClose = pStream->BaseClose; + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - partial stream support + +static bool IsPartHeader(PPART_FILE_HEADER pPartHdr) +{ + // Version number must be 2 + if(pPartHdr->PartialVersion == 2) + { + // GameBuildNumber must be an ASCII number + if(isdigit(pPartHdr->GameBuildNumber[0]) && isdigit(pPartHdr->GameBuildNumber[1]) && isdigit(pPartHdr->GameBuildNumber[2])) + { + // Block size must be power of 2 + if((pPartHdr->BlockSize & (pPartHdr->BlockSize - 1)) == 0) + return true; + } + } + + return false; +} + +static DWORD PartStream_CheckFile(TBlockStream * pStream) +{ + PPART_FILE_MAP_ENTRY FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap; + DWORD dwBlockCount; + + // Get the number of blocks + dwBlockCount = (DWORD)((pStream->StreamSize + pStream->BlockSize - 1) / pStream->BlockSize); + + // Check all blocks + for(DWORD i = 0; i < dwBlockCount; i++, FileBitmap++) + { + // Few sanity checks + assert(FileBitmap->LargeValueHi == 0); + assert(FileBitmap->LargeValueLo == 0); + assert(FileBitmap->Flags == 0 || FileBitmap->Flags == 3); + + // Check if this block is present + if(FileBitmap->Flags != 3) + return 0; + } + + // Yes, the file is complete + return 1; +} + +static bool PartStream_LoadBitmap(TBlockStream * pStream) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + PART_FILE_HEADER PartHdr; + ULONGLONG ByteOffset = 0; + ULONGLONG StreamSize = 0; + DWORD BlockCount; + DWORD BitmapSize; + + // Only if the size is greater than size of the bitmap header + if(pStream->Base.File.FileSize > sizeof(PART_FILE_HEADER)) + { + // Attempt to read PART file header + if(pStream->BaseRead(pStream, &ByteOffset, &PartHdr, sizeof(PART_FILE_HEADER))) + { + // We need to swap PART file header on big-endian platforms + BSWAP_ARRAY32_UNSIGNED(&PartHdr, sizeof(PART_FILE_HEADER)); + + // Verify the PART file header + if(IsPartHeader(&PartHdr)) + { + // Get the number of blocks and size of one block + StreamSize = MAKE_OFFSET64(PartHdr.FileSizeHi, PartHdr.FileSizeLo); + ByteOffset = sizeof(PART_FILE_HEADER); + BlockCount = (DWORD)((StreamSize + PartHdr.BlockSize - 1) / PartHdr.BlockSize); + BitmapSize = BlockCount * sizeof(PART_FILE_MAP_ENTRY); + + // Check if sizes match + if((ByteOffset + BitmapSize) < pStream->Base.File.FileSize) + { + // Allocate space for the array of PART_FILE_MAP_ENTRY + FileBitmap = STORM_ALLOC(PART_FILE_MAP_ENTRY, BlockCount); + if(FileBitmap != NULL) + { + // Load the block map + if(!pStream->BaseRead(pStream, &ByteOffset, FileBitmap, BitmapSize)) + { + STORM_FREE(FileBitmap); + return false; + } + + // Make sure that the byte order is correct + BSWAP_ARRAY32_UNSIGNED(FileBitmap, BitmapSize); + + // Update the stream size + pStream->BuildNumber = StringToInt(PartHdr.GameBuildNumber); + pStream->StreamSize = StreamSize; + + // Fill the bitmap information + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = BitmapSize; + pStream->BlockSize = PartHdr.BlockSize; + pStream->BlockCount = BlockCount; + pStream->IsComplete = PartStream_CheckFile(pStream); + return true; + } + } + } + } + } + + return false; +} + +static void PartStream_UpdateBitmap( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + ULONGLONG RealOffset) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + DWORD BlockSize = pStream->BlockSize; + + // Sanity checks + assert((StartOffset & (BlockSize - 1)) == 0); + assert(pStream->FileBitmap != NULL); + + // Calculate the first entry in the block map + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (StartOffset / BlockSize); + + // Set all bits for the specified range + while(StartOffset < EndOffset) + { + // Set the bit + FileBitmap->BlockOffsHi = (DWORD)(RealOffset >> 0x20); + FileBitmap->BlockOffsLo = (DWORD)(RealOffset & 0xFFFFFFFF); + FileBitmap->Flags = 3; + + // Move all + StartOffset += BlockSize; + RealOffset += BlockSize; + FileBitmap++; + } + + // Increment the bitmap update count + pStream->IsModified = 1; +} + +static bool PartStream_BlockCheck( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG BlockOffset) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + + // Sanity checks + assert((BlockOffset & (pStream->BlockSize - 1)) == 0); + assert(pStream->FileBitmap != NULL); + + // Calculate the block map entry + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + (BlockOffset / pStream->BlockSize); + + // Check if the flags are present + return (FileBitmap->Flags & 0x03) ? true : false; +} + +static bool PartStream_BlockRead( + TBlockStream * pStream, + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + PPART_FILE_MAP_ENTRY FileBitmap; + ULONGLONG ByteOffset; + DWORD BytesToRead; + DWORD BlockIndex = (DWORD)(StartOffset / pStream->BlockSize); + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + + // If the blocks are not available, we need to load them from the master + // and then save to the mirror + if(bAvailable == false) + { + // If we have no master, we cannot satisfy read request + if(pStream->pMaster == NULL) + return false; + + // Load the blocks from the master stream + // Note that we always have to read complete blocks + // so they get properly stored to the mirror stream + BytesToRead = (DWORD)(EndOffset - StartOffset); + if(!FileStream_Read(pStream->pMaster, &StartOffset, BlockBuffer, BytesToRead)) + return false; + + // The loaded blocks are going to be stored to the end of the file + // Note that this operation is not required to succeed + if(pStream->BaseGetSize(pStream, &ByteOffset)) + { + // Store the loaded blocks to the mirror file. + if(pStream->BaseWrite(pStream, &ByteOffset, BlockBuffer, BytesToRead)) + { + PartStream_UpdateBitmap(pStream, StartOffset, EndOffset, ByteOffset); + } + } + } + else + { + // Get the file map entry + FileBitmap = (PPART_FILE_MAP_ENTRY)pStream->FileBitmap + BlockIndex; + + // Read all blocks + while(StartOffset < EndOffset) + { + // Get the number of bytes to be read + BytesToRead = (DWORD)(EndOffset - StartOffset); + if(BytesToRead > pStream->BlockSize) + BytesToRead = pStream->BlockSize; + if(BytesToRead > BytesNeeded) + BytesToRead = BytesNeeded; + + // Read the block + ByteOffset = MAKE_OFFSET64(FileBitmap->BlockOffsHi, FileBitmap->BlockOffsLo); + if(!pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead)) + return false; + + // Move the pointers + StartOffset += pStream->BlockSize; + BlockBuffer += pStream->BlockSize; + BytesNeeded -= pStream->BlockSize; + FileBitmap++; + } + } + + return true; +} + +static void PartStream_Close(TBlockStream * pStream) +{ + PART_FILE_HEADER PartHeader; + ULONGLONG ByteOffset = 0; + + if(pStream->FileBitmap && pStream->IsModified) + { + // Prepare the part file header + memset(&PartHeader, 0, sizeof(PART_FILE_HEADER)); + PartHeader.PartialVersion = 2; + PartHeader.FileSizeHi = (DWORD)(pStream->StreamSize >> 0x20); + PartHeader.FileSizeLo = (DWORD)(pStream->StreamSize & 0xFFFFFFFF); + PartHeader.BlockSize = pStream->BlockSize; + + // Make sure that the header is properly BSWAPed + BSWAP_ARRAY32_UNSIGNED(&PartHeader, sizeof(PART_FILE_HEADER)); + sprintf(PartHeader.GameBuildNumber, "%u", (unsigned int)pStream->BuildNumber); + + // Write the part header + pStream->BaseWrite(pStream, &ByteOffset, &PartHeader, sizeof(PART_FILE_HEADER)); + + // Write the block bitmap + BSWAP_ARRAY32_UNSIGNED(pStream->FileBitmap, pStream->BitmapSize); + pStream->BaseWrite(pStream, NULL, pStream->FileBitmap, pStream->BitmapSize); + } + + // Close the base class + BlockStream_Close(pStream); +} + +static bool PartStream_CreateMirror(TBlockStream * pStream) +{ + ULONGLONG RemainingSize; + ULONGLONG MasterSize = 0; + ULONGLONG MirrorSize = 0; + LPBYTE FileBitmap = NULL; + DWORD dwBitmapSize; + DWORD dwBlockCount; + bool bNeedCreateMirrorStream = true; + bool bNeedResizeMirrorStream = true; + + // Do we have master function and base creation function? + if(pStream->pMaster == NULL || pStream->BaseCreate == NULL) + return false; + + // Retrieve the master file size, block count and bitmap size + FileStream_GetSize(pStream->pMaster, &MasterSize); + dwBlockCount = (DWORD)((MasterSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + dwBitmapSize = (DWORD)(dwBlockCount * sizeof(PART_FILE_MAP_ENTRY)); + + // Setup stream size and position + pStream->BuildNumber = DEFAULT_BUILD_NUMBER; // BUGBUG: Really??? + pStream->StreamSize = MasterSize; + pStream->StreamPos = 0; + + // Open the base stream for write access + if(pStream->BaseOpen(pStream, pStream->szFileName, 0)) + { + // If the file open succeeded, check if the file size matches required size + pStream->BaseGetSize(pStream, &MirrorSize); + if(MirrorSize >= sizeof(PART_FILE_HEADER) + dwBitmapSize) + { + // Check if the remaining size is aligned to block + RemainingSize = MirrorSize - sizeof(PART_FILE_HEADER) - dwBitmapSize; + if((RemainingSize & (DEFAULT_BLOCK_SIZE - 1)) == 0 || RemainingSize == MasterSize) + { + // Attempt to load an existing file bitmap + if(PartStream_LoadBitmap(pStream)) + return true; + } + } + + // We need to create mirror stream + bNeedCreateMirrorStream = false; + } + + // Create a new stream, if needed + if(bNeedCreateMirrorStream) + { + if(!pStream->BaseCreate(pStream)) + return false; + } + + // If we need to, then resize the mirror stream + if(bNeedResizeMirrorStream) + { + if(!pStream->BaseResize(pStream, sizeof(PART_FILE_HEADER) + dwBitmapSize)) + return false; + } + + // Allocate the bitmap array + FileBitmap = STORM_ALLOC(BYTE, dwBitmapSize); + if(FileBitmap == NULL) + return false; + + // Initialize the bitmap + memset(FileBitmap, 0, dwBitmapSize); + pStream->FileBitmap = FileBitmap; + pStream->BitmapSize = dwBitmapSize; + pStream->BlockSize = DEFAULT_BLOCK_SIZE; + pStream->BlockCount = dwBlockCount; + pStream->IsComplete = 0; + pStream->IsModified = 1; + + // Note: Don't write the stream bitmap right away. + // Doing so would cause sparse file resize on NTFS, + // which would take long time on larger files. + return true; +} + + +static TFileStream * PartStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBlockStream * pStream; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Do we have a master stream? + if(pStream->pMaster != NULL) + { + if(!PartStream_CreateMirror(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + return NULL; + } + } + else + { + // Attempt to open the base stream + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + { + FileStream_Close(pStream); + return NULL; + } + + // Load the part stream block map + if(!PartStream_LoadBitmap(pStream)) + { + FileStream_Close(pStream); + SetLastError(ERROR_BAD_FORMAT); + return NULL; + } + } + + // Set the stream position to zero. Stream size is already set + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Set new function pointers + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamClose = (STREAM_CLOSE)PartStream_Close; + + // Supply the block functions + pStream->BlockCheck = (BLOCK_CHECK)PartStream_BlockCheck; + pStream->BlockRead = (BLOCK_READ)PartStream_BlockRead; + return pStream; +} + +//----------------------------------------------------------------------------- +// Local functions - MPQE stream support + +static const char * szKeyTemplate = "expand 32-byte k000000000000000000000000000000000000000000000000"; + +static const char * AuthCodeArray[] = +{ + // Starcraft II (Heart of the Swarm) + // Authentication code URL: http://dist.blizzard.com/mediakey/hots-authenticationcode-bgdl.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "S48B6CDTN5XEQAKQDJNDLJBJ73FDFM3U", // SC2 Heart of the Swarm-all : "expand 32-byte kQAKQ0000FM3UN5XE000073FD6CDT0000LJBJS48B0000DJND" + + // Diablo III: Agent.exe (1.0.0.954) + // Address of decryption routine: 00502b00 + // Pointer to decryptor object: ECX + // Pointer to key: ECX+0x5C + // Authentication code URL: http://dist.blizzard.com/mediakey/d3-authenticationcode-enGB.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "UCMXF6EJY352EFH4XFRXCFH2XC9MQRZK", // Diablo III Installer (deDE): "expand 32-byte kEFH40000QRZKY3520000XC9MF6EJ0000CFH2UCMX0000XFRX" + "MMKVHY48RP7WXP4GHYBQ7SL9J9UNPHBP", // Diablo III Installer (enGB): "expand 32-byte kXP4G0000PHBPRP7W0000J9UNHY4800007SL9MMKV0000HYBQ" + "8MXLWHQ7VGGLTZ9MQZQSFDCLJYET3CPP", // Diablo III Installer (enSG): "expand 32-byte kTZ9M00003CPPVGGL0000JYETWHQ70000FDCL8MXL0000QZQS" + "EJ2R5TM6XFE2GUNG5QDGHKQ9UAKPWZSZ", // Diablo III Installer (enUS): "expand 32-byte kGUNG0000WZSZXFE20000UAKP5TM60000HKQ9EJ2R00005QDG" + "PBGFBE42Z6LNK65UGJQ3WZVMCLP4HQQT", // Diablo III Installer (esES): "expand 32-byte kK65U0000HQQTZ6LN0000CLP4BE420000WZVMPBGF0000GJQ3" + "X7SEJJS9TSGCW5P28EBSC47AJPEY8VU2", // Diablo III Installer (esMX): "expand 32-byte kW5P200008VU2TSGC0000JPEYJJS90000C47AX7SE00008EBS" + "5KVBQA8VYE6XRY3DLGC5ZDE4XS4P7YA2", // Diablo III Installer (frFR): "expand 32-byte kRY3D00007YA2YE6X0000XS4PQA8V0000ZDE45KVB0000LGC5" + "478JD2K56EVNVVY4XX8TDWYT5B8KB254", // Diablo III Installer (itIT): "expand 32-byte kVVY40000B2546EVN00005B8KD2K50000DWYT478J0000XX8T" + "8TS4VNFQRZTN6YWHE9CHVDH9NVWD474A", // Diablo III Installer (koKR): "expand 32-byte k6YWH0000474ARZTN0000NVWDVNFQ0000VDH98TS40000E9CH" + "LJ52Z32DF4LZ4ZJJXVKK3AZQA6GABLJB", // Diablo III Installer (plPL): "expand 32-byte k4ZJJ0000BLJBF4LZ0000A6GAZ32D00003AZQLJ520000XVKK" + "K6BDHY2ECUE2545YKNLBJPVYWHE7XYAG", // Diablo III Installer (ptBR): "expand 32-byte k545Y0000XYAGCUE20000WHE7HY2E0000JPVYK6BD0000KNLB" + "NDVW8GWLAYCRPGRNY8RT7ZZUQU63VLPR", // Diablo III Installer (ruRU): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "6VWCQTN8V3ZZMRUCZXV8A8CGUX2TAA8H", // Diablo III Installer (zhTW): "expand 32-byte kMRUC0000AA8HV3ZZ0000UX2TQTN80000A8CG6VWC0000ZXV8" +// "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // Diablo III Installer (zhCN): "expand 32-byte kXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + + // Starcraft II (Wings of Liberty): Installer.exe (4.1.1.4219) + // Address of decryption routine: 0053A3D0 + // Pointer to decryptor object: ECX + // Pointer to key: ECX+0x5C + // Authentication code URL: http://dist.blizzard.com/mediakey/sc2-authenticationcode-enUS.txt + // -0C- -1C--08- -18--04- -14--00- -10- + "Y45MD3CAK4KXSSXHYD9VY64Z8EKJ4XFX", // SC2 Wings of Liberty (deDE): "expand 32-byte kSSXH00004XFXK4KX00008EKJD3CA0000Y64ZY45M0000YD9V" + "G8MN8UDG6NA2ANGY6A3DNY82HRGF29ZH", // SC2 Wings of Liberty (enGB): "expand 32-byte kANGY000029ZH6NA20000HRGF8UDG0000NY82G8MN00006A3D" + "W9RRHLB2FDU9WW5B3ECEBLRSFWZSF7HW", // SC2 Wings of Liberty (enSG): "expand 32-byte kWW5B0000F7HWFDU90000FWZSHLB20000BLRSW9RR00003ECE" + "3DH5RE5NVM5GTFD85LXGWT6FK859ETR5", // SC2 Wings of Liberty (enUS): "expand 32-byte kTFD80000ETR5VM5G0000K859RE5N0000WT6F3DH500005LXG" + "8WLKUAXE94PFQU4Y249PAZ24N4R4XKTQ", // SC2 Wings of Liberty (esES): "expand 32-byte kQU4Y0000XKTQ94PF0000N4R4UAXE0000AZ248WLK0000249P" + "A34DXX3VHGGXSQBRFE5UFFDXMF9G4G54", // SC2 Wings of Liberty (esMX): "expand 32-byte kSQBR00004G54HGGX0000MF9GXX3V0000FFDXA34D0000FE5U" + "ZG7J9K938HJEFWPQUA768MA2PFER6EAJ", // SC2 Wings of Liberty (frFR): "expand 32-byte kFWPQ00006EAJ8HJE0000PFER9K9300008MA2ZG7J0000UA76" + "NE7CUNNNTVAPXV7E3G2BSVBWGVMW8BL2", // SC2 Wings of Liberty (itIT): "expand 32-byte kXV7E00008BL2TVAP0000GVMWUNNN0000SVBWNE7C00003G2B" + "3V9E2FTMBM9QQWK7U6MAMWAZWQDB838F", // SC2 Wings of Liberty (koKR): "expand 32-byte kQWK70000838FBM9Q0000WQDB2FTM0000MWAZ3V9E0000U6MA" + "2NSFB8MELULJ83U6YHA3UP6K4MQD48L6", // SC2 Wings of Liberty (plPL): "expand 32-byte k83U6000048L6LULJ00004MQDB8ME0000UP6K2NSF0000YHA3" + "QA2TZ9EWZ4CUU8BMB5WXCTY65F9CSW4E", // SC2 Wings of Liberty (ptBR): "expand 32-byte kU8BM0000SW4EZ4CU00005F9CZ9EW0000CTY6QA2T0000B5WX" + "VHB378W64BAT9SH7D68VV9NLQDK9YEGT", // SC2 Wings of Liberty (ruRU): "expand 32-byte k9SH70000YEGT4BAT0000QDK978W60000V9NLVHB30000D68V" + "U3NFQJV4M6GC7KBN9XQJ3BRDN3PLD9NE", // SC2 Wings of Liberty (zhTW): "expand 32-byte k7KBN0000D9NEM6GC0000N3PLQJV400003BRDU3NF00009XQJ" + + NULL +}; + +static DWORD Rol32(DWORD dwValue, DWORD dwRolCount) +{ + DWORD dwShiftRight = 32 - dwRolCount; + + return (dwValue << dwRolCount) | (dwValue >> dwShiftRight); +} + +static void CreateKeyFromAuthCode( + LPBYTE pbKeyBuffer, + const char * szAuthCode) +{ + LPDWORD KeyPosition = (LPDWORD)(pbKeyBuffer + 0x10); + LPDWORD AuthCode32 = (LPDWORD)szAuthCode; + + memcpy(pbKeyBuffer, szKeyTemplate, MPQE_CHUNK_SIZE); + KeyPosition[0x00] = AuthCode32[0x03]; + KeyPosition[0x02] = AuthCode32[0x07]; + KeyPosition[0x03] = AuthCode32[0x02]; + KeyPosition[0x05] = AuthCode32[0x06]; + KeyPosition[0x06] = AuthCode32[0x01]; + KeyPosition[0x08] = AuthCode32[0x05]; + KeyPosition[0x09] = AuthCode32[0x00]; + KeyPosition[0x0B] = AuthCode32[0x04]; + BSWAP_ARRAY32_UNSIGNED(pbKeyBuffer, MPQE_CHUNK_SIZE); +} + +static void DecryptFileChunk( + DWORD * MpqData, + LPBYTE pbKey, + ULONGLONG ByteOffset, + DWORD dwLength) +{ + ULONGLONG ChunkOffset; + DWORD KeyShuffled[0x10]; + DWORD KeyMirror[0x10]; + DWORD RoundCount = 0x14; + + // Prepare the key + ChunkOffset = ByteOffset / MPQE_CHUNK_SIZE; + memcpy(KeyMirror, pbKey, MPQE_CHUNK_SIZE); + BSWAP_ARRAY32_UNSIGNED(KeyMirror, MPQE_CHUNK_SIZE); + KeyMirror[0x05] = (DWORD)(ChunkOffset >> 32); + KeyMirror[0x08] = (DWORD)(ChunkOffset); + + while(dwLength >= MPQE_CHUNK_SIZE) + { + // Shuffle the key - part 1 + KeyShuffled[0x0E] = KeyMirror[0x00]; + KeyShuffled[0x0C] = KeyMirror[0x01]; + KeyShuffled[0x05] = KeyMirror[0x02]; + KeyShuffled[0x0F] = KeyMirror[0x03]; + KeyShuffled[0x0A] = KeyMirror[0x04]; + KeyShuffled[0x07] = KeyMirror[0x05]; + KeyShuffled[0x0B] = KeyMirror[0x06]; + KeyShuffled[0x09] = KeyMirror[0x07]; + KeyShuffled[0x03] = KeyMirror[0x08]; + KeyShuffled[0x06] = KeyMirror[0x09]; + KeyShuffled[0x08] = KeyMirror[0x0A]; + KeyShuffled[0x0D] = KeyMirror[0x0B]; + KeyShuffled[0x02] = KeyMirror[0x0C]; + KeyShuffled[0x04] = KeyMirror[0x0D]; + KeyShuffled[0x01] = KeyMirror[0x0E]; + KeyShuffled[0x00] = KeyMirror[0x0F]; + + // Shuffle the key - part 2 + for(DWORD i = 0; i < RoundCount; i += 2) + { + KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x02]), 0x07); + KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0E]), 0x09); + KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x0A]), 0x0D); + KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x03]), 0x12); + + KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x04]), 0x07); + KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x0C]), 0x09); + KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x07]), 0x0D); + KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x06]), 0x12); + + KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x01]), 0x07); + KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x05]), 0x09); + KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x0B]), 0x0D); + KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x08]), 0x12); + + KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x00]), 0x07); + KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x0F]), 0x09); + KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x09]), 0x0D); + KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x0D]), 0x12); + + KeyShuffled[0x04] = KeyShuffled[0x04] ^ Rol32((KeyShuffled[0x0E] + KeyShuffled[0x09]), 0x07); + KeyShuffled[0x08] = KeyShuffled[0x08] ^ Rol32((KeyShuffled[0x04] + KeyShuffled[0x0E]), 0x09); + KeyShuffled[0x09] = KeyShuffled[0x09] ^ Rol32((KeyShuffled[0x08] + KeyShuffled[0x04]), 0x0D); + KeyShuffled[0x0E] = KeyShuffled[0x0E] ^ Rol32((KeyShuffled[0x09] + KeyShuffled[0x08]), 0x12); + + KeyShuffled[0x01] = KeyShuffled[0x01] ^ Rol32((KeyShuffled[0x0C] + KeyShuffled[0x0A]), 0x07); + KeyShuffled[0x0D] = KeyShuffled[0x0D] ^ Rol32((KeyShuffled[0x01] + KeyShuffled[0x0C]), 0x09); + KeyShuffled[0x0A] = KeyShuffled[0x0A] ^ Rol32((KeyShuffled[0x0D] + KeyShuffled[0x01]), 0x0D); + KeyShuffled[0x0C] = KeyShuffled[0x0C] ^ Rol32((KeyShuffled[0x0A] + KeyShuffled[0x0D]), 0x12); + + KeyShuffled[0x00] = KeyShuffled[0x00] ^ Rol32((KeyShuffled[0x05] + KeyShuffled[0x07]), 0x07); + KeyShuffled[0x03] = KeyShuffled[0x03] ^ Rol32((KeyShuffled[0x00] + KeyShuffled[0x05]), 0x09); + KeyShuffled[0x07] = KeyShuffled[0x07] ^ Rol32((KeyShuffled[0x03] + KeyShuffled[0x00]), 0x0D); + KeyShuffled[0x05] = KeyShuffled[0x05] ^ Rol32((KeyShuffled[0x07] + KeyShuffled[0x03]), 0x12); + + KeyShuffled[0x02] = KeyShuffled[0x02] ^ Rol32((KeyShuffled[0x0F] + KeyShuffled[0x0B]), 0x07); + KeyShuffled[0x06] = KeyShuffled[0x06] ^ Rol32((KeyShuffled[0x02] + KeyShuffled[0x0F]), 0x09); + KeyShuffled[0x0B] = KeyShuffled[0x0B] ^ Rol32((KeyShuffled[0x06] + KeyShuffled[0x02]), 0x0D); + KeyShuffled[0x0F] = KeyShuffled[0x0F] ^ Rol32((KeyShuffled[0x0B] + KeyShuffled[0x06]), 0x12); + } + + // Decrypt one data chunk + BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE); + MpqData[0x00] = MpqData[0x00] ^ (KeyShuffled[0x0E] + KeyMirror[0x00]); + MpqData[0x01] = MpqData[0x01] ^ (KeyShuffled[0x04] + KeyMirror[0x0D]); + MpqData[0x02] = MpqData[0x02] ^ (KeyShuffled[0x08] + KeyMirror[0x0A]); + MpqData[0x03] = MpqData[0x03] ^ (KeyShuffled[0x09] + KeyMirror[0x07]); + MpqData[0x04] = MpqData[0x04] ^ (KeyShuffled[0x0A] + KeyMirror[0x04]); + MpqData[0x05] = MpqData[0x05] ^ (KeyShuffled[0x0C] + KeyMirror[0x01]); + MpqData[0x06] = MpqData[0x06] ^ (KeyShuffled[0x01] + KeyMirror[0x0E]); + MpqData[0x07] = MpqData[0x07] ^ (KeyShuffled[0x0D] + KeyMirror[0x0B]); + MpqData[0x08] = MpqData[0x08] ^ (KeyShuffled[0x03] + KeyMirror[0x08]); + MpqData[0x09] = MpqData[0x09] ^ (KeyShuffled[0x07] + KeyMirror[0x05]); + MpqData[0x0A] = MpqData[0x0A] ^ (KeyShuffled[0x05] + KeyMirror[0x02]); + MpqData[0x0B] = MpqData[0x0B] ^ (KeyShuffled[0x00] + KeyMirror[0x0F]); + MpqData[0x0C] = MpqData[0x0C] ^ (KeyShuffled[0x02] + KeyMirror[0x0C]); + MpqData[0x0D] = MpqData[0x0D] ^ (KeyShuffled[0x06] + KeyMirror[0x09]); + MpqData[0x0E] = MpqData[0x0E] ^ (KeyShuffled[0x0B] + KeyMirror[0x06]); + MpqData[0x0F] = MpqData[0x0F] ^ (KeyShuffled[0x0F] + KeyMirror[0x03]); + BSWAP_ARRAY32_UNSIGNED(MpqData, MPQE_CHUNK_SIZE); + + // Update byte offset in the key + KeyMirror[0x08]++; + if(KeyMirror[0x08] == 0) + KeyMirror[0x05]++; + + // Move pointers and decrease number of bytes to decrypt + MpqData += (MPQE_CHUNK_SIZE / sizeof(DWORD)); + dwLength -= MPQE_CHUNK_SIZE; + } +} + +static bool MpqeStream_DetectFileKey(TEncryptedStream * pStream) +{ + ULONGLONG ByteOffset = 0; + BYTE EncryptedHeader[MPQE_CHUNK_SIZE]; + BYTE FileHeader[MPQE_CHUNK_SIZE]; + + // Read the first file chunk + if(pStream->BaseRead(pStream, &ByteOffset, EncryptedHeader, sizeof(EncryptedHeader))) + { + // We just try all known keys one by one + for(int i = 0; AuthCodeArray[i] != NULL; i++) + { + // Prepare they decryption key from game serial number + CreateKeyFromAuthCode(pStream->Key, AuthCodeArray[i]); + + // Try to decrypt with the given key + memcpy(FileHeader, EncryptedHeader, MPQE_CHUNK_SIZE); + DecryptFileChunk((LPDWORD)FileHeader, pStream->Key, ByteOffset, MPQE_CHUNK_SIZE); + + // We check the decrypted data + // All known encrypted MPQs have header at the begin of the file, + // so we check for MPQ signature there. + if(FileHeader[0] == 'M' && FileHeader[1] == 'P' && FileHeader[2] == 'Q') + { + // Update the stream size + pStream->StreamSize = pStream->Base.File.FileSize; + + // Fill the block information + pStream->BlockSize = MPQE_CHUNK_SIZE; + pStream->BlockCount = (DWORD)(pStream->Base.File.FileSize + MPQE_CHUNK_SIZE - 1) / MPQE_CHUNK_SIZE; + pStream->IsComplete = 1; + return true; + } + } + } + + // Key not found, sorry + return false; +} + +static bool MpqeStream_BlockRead( + TEncryptedStream * pStream, + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + DWORD dwBytesToRead; + + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + assert(bAvailable != false); + BytesNeeded = BytesNeeded; + bAvailable = bAvailable; + + // Read the file from the stream as-is + // Limit the reading to number of blocks really needed + dwBytesToRead = (DWORD)(EndOffset - StartOffset); + if(!pStream->BaseRead(pStream, &StartOffset, BlockBuffer, dwBytesToRead)) + return false; + + // Decrypt the data + dwBytesToRead = (dwBytesToRead + MPQE_CHUNK_SIZE - 1) & ~(MPQE_CHUNK_SIZE - 1); + DecryptFileChunk((LPDWORD)BlockBuffer, pStream->Key, StartOffset, dwBytesToRead); + return true; +} + +static TFileStream * MpqeStream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TEncryptedStream * pStream; + + // Create new empty stream + pStream = (TEncryptedStream *)AllocateFileStream(szFileName, sizeof(TEncryptedStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Attempt to open the base stream + assert(pStream->BaseOpen != NULL); + if(!pStream->BaseOpen(pStream, pStream->szFileName, dwStreamFlags)) + return NULL; + + // Determine the encryption key for the MPQ + if(MpqeStream_DetectFileKey(pStream)) + { + // Set the stream position and size + assert(pStream->StreamSize != 0); + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + // Set new function pointers + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamClose = pStream->BaseClose; + + // Supply the block functions + pStream->BlockRead = (BLOCK_READ)MpqeStream_BlockRead; + return pStream; + } + + // Cleanup the stream and return + FileStream_Close(pStream); + SetLastError(ERROR_UNKNOWN_FILE_KEY); + return NULL; +} + +//----------------------------------------------------------------------------- +// Local functions - Block4 stream support + +#define BLOCK4_BLOCK_SIZE 0x4000 // Size of one block +#define BLOCK4_HASH_SIZE 0x20 // Size of MD5 hash that is after each block +#define BLOCK4_MAX_BLOCKS 0x00002000 // Maximum amount of blocks per file +#define BLOCK4_MAX_FSIZE 0x08040000 // Max size of one file + +static bool Block4Stream_BlockRead( + TBlockStream * pStream, // Pointer to an open stream + ULONGLONG StartOffset, + ULONGLONG EndOffset, + LPBYTE BlockBuffer, + DWORD BytesNeeded, + bool bAvailable) +{ + TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap; + ULONGLONG ByteOffset; + DWORD BytesToRead; + DWORD StreamIndex; + DWORD BlockIndex; + bool bResult; + + // The starting offset must be aligned to size of the block + assert(pStream->FileBitmap != NULL); + assert((StartOffset & (pStream->BlockSize - 1)) == 0); + assert(StartOffset < EndOffset); + assert(bAvailable == true); + + // Keep compiler happy + bAvailable = bAvailable; + EndOffset = EndOffset; + + while(BytesNeeded != 0) + { + // Calculate the block index and the file index + StreamIndex = (DWORD)((StartOffset / pStream->BlockSize) / BLOCK4_MAX_BLOCKS); + BlockIndex = (DWORD)((StartOffset / pStream->BlockSize) % BLOCK4_MAX_BLOCKS); + if(StreamIndex > pStream->BitmapSize) + return false; + + // Calculate the block offset + ByteOffset = ((ULONGLONG)BlockIndex * (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE)); + BytesToRead = STORMLIB_MIN(BytesNeeded, BLOCK4_BLOCK_SIZE); + + // Read from the base stream + pStream->Base = BaseArray[StreamIndex]; + bResult = pStream->BaseRead(pStream, &ByteOffset, BlockBuffer, BytesToRead); + BaseArray[StreamIndex] = pStream->Base; + + // Did the result succeed? + if(bResult == false) + return false; + + // Move pointers + StartOffset += BytesToRead; + BlockBuffer += BytesToRead; + BytesNeeded -= BytesToRead; + } + + return true; +} + + +static void Block4Stream_Close(TBlockStream * pStream) +{ + TBaseProviderData * BaseArray = (TBaseProviderData *)pStream->FileBitmap; + + // If we have a non-zero count of base streams, + // we have to close them all + if(BaseArray != NULL) + { + // Close all base streams + for(DWORD i = 0; i < pStream->BitmapSize; i++) + { + memcpy(&pStream->Base, BaseArray + i, sizeof(TBaseProviderData)); + pStream->BaseClose(pStream); + } + } + + // Free the data map, if any + if(pStream->FileBitmap != NULL) + STORM_FREE(pStream->FileBitmap); + pStream->FileBitmap = NULL; + + // Do not call the BaseClose function, + // we closed all handles already + return; +} + +static TFileStream * Block4Stream_Open(const TCHAR * szFileName, DWORD dwStreamFlags) +{ + TBaseProviderData * NewBaseArray = NULL; + ULONGLONG RemainderBlock; + ULONGLONG BlockCount; + ULONGLONG FileSize; + TBlockStream * pStream; + TCHAR * szNameBuff; + size_t nNameLength; + DWORD dwBaseFiles = 0; + DWORD dwBaseFlags; + + // Create new empty stream + pStream = (TBlockStream *)AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream == NULL) + return NULL; + + // Sanity check + assert(pStream->BaseOpen != NULL); + + // Get the length of the file name without numeric suffix + nNameLength = _tcslen(pStream->szFileName); + if(pStream->szFileName[nNameLength - 2] == '.' && pStream->szFileName[nNameLength - 1] == '0') + nNameLength -= 2; + pStream->szFileName[nNameLength] = 0; + + // Supply the stream functions + pStream->StreamRead = (STREAM_READ)BlockStream_Read; + pStream->StreamGetSize = BlockStream_GetSize; + pStream->StreamGetPos = BlockStream_GetPos; + pStream->StreamClose = (STREAM_CLOSE)Block4Stream_Close; + pStream->BlockRead = (BLOCK_READ)Block4Stream_BlockRead; + + // Allocate work space for numeric names + szNameBuff = STORM_ALLOC(TCHAR, nNameLength + 4); + if(szNameBuff != NULL) + { + // Set the base flags + dwBaseFlags = (dwStreamFlags & STREAM_PROVIDERS_MASK) | STREAM_FLAG_READ_ONLY; + + // Go all suffixes from 0 to 30 + for(int nSuffix = 0; nSuffix < 30; nSuffix++) + { + // Open the n-th file + _stprintf(szNameBuff, _T("%s.%u"), pStream->szFileName, nSuffix); + if(!pStream->BaseOpen(pStream, szNameBuff, dwBaseFlags)) + break; + + // If the open succeeded, we re-allocate the base provider array + NewBaseArray = STORM_ALLOC(TBaseProviderData, dwBaseFiles + 1); + if(NewBaseArray == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + // Copy the old base data array to the new base data array + if(pStream->FileBitmap != NULL) + { + memcpy(NewBaseArray, pStream->FileBitmap, sizeof(TBaseProviderData) * dwBaseFiles); + STORM_FREE(pStream->FileBitmap); + } + + // Also copy the opened base array + memcpy(NewBaseArray + dwBaseFiles, &pStream->Base, sizeof(TBaseProviderData)); + pStream->FileBitmap = NewBaseArray; + dwBaseFiles++; + + // Get the size of the base stream + pStream->BaseGetSize(pStream, &FileSize); + assert(FileSize <= BLOCK4_MAX_FSIZE); + RemainderBlock = FileSize % (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE); + BlockCount = FileSize / (BLOCK4_BLOCK_SIZE + BLOCK4_HASH_SIZE); + + // Increment the stream size and number of blocks + pStream->StreamSize += (BlockCount * BLOCK4_BLOCK_SIZE); + pStream->BlockCount += (DWORD)BlockCount; + + // Is this the last file? + if(FileSize < BLOCK4_MAX_FSIZE) + { + if(RemainderBlock) + { + pStream->StreamSize += (RemainderBlock - BLOCK4_HASH_SIZE); + pStream->BlockCount++; + } + break; + } + } + + // Fill the remainining block stream variables + pStream->BitmapSize = dwBaseFiles; + pStream->BlockSize = BLOCK4_BLOCK_SIZE; + pStream->IsComplete = 1; + pStream->IsModified = 0; + + // Fill the remaining stream variables + pStream->StreamPos = 0; + pStream->dwFlags |= STREAM_FLAG_READ_ONLY; + + STORM_FREE(szNameBuff); + } + + // If we opened something, return success + if(dwBaseFiles == 0) + { + FileStream_Close(pStream); + SetLastError(ERROR_FILE_NOT_FOUND); + pStream = NULL; + } + + return pStream; +} + +//----------------------------------------------------------------------------- +// Public functions + +/** + * This function creates a new file for read-write access + * + * - If the current platform supports file sharing, + * the file must be created for read sharing (i.e. another application + * can open the file for read, but not for write) + * - If the file does not exist, the function must create new one + * - If the file exists, the function must rewrite it and set to zero size + * - The parameters of the function must be validate by the caller + * - The function must initialize all stream function pointers in TFileStream + * - If the function fails from any reason, it must close all handles + * and free all memory that has been allocated in the process of stream creation, + * including the TFileStream structure itself + * + * \a szFileName Name of the file to create + */ + +TFileStream * FileStream_CreateFile( + const TCHAR * szFileName, + DWORD dwStreamFlags) +{ + TFileStream * pStream; + + // We only support creation of flat, local file + if((dwStreamFlags & (STREAM_PROVIDERS_MASK)) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE)) + { + SetLastError(ERROR_NOT_SUPPORTED); + return NULL; + } + + // Allocate file stream structure for flat stream + pStream = AllocateFileStream(szFileName, sizeof(TBlockStream), dwStreamFlags); + if(pStream != NULL) + { + // Attempt to create the disk file + if(BaseFile_Create(pStream)) + { + // Fill the stream provider functions + pStream->StreamRead = pStream->BaseRead; + pStream->StreamWrite = pStream->BaseWrite; + pStream->StreamResize = pStream->BaseResize; + pStream->StreamGetSize = pStream->BaseGetSize; + pStream->StreamGetPos = pStream->BaseGetPos; + pStream->StreamClose = pStream->BaseClose; + return pStream; + } + + // File create failed, delete the stream + STORM_FREE(pStream); + pStream = NULL; + } + + // Return the stream + return pStream; +} + +/** + * This function opens an existing file for read or read-write access + * - If the current platform supports file sharing, + * the file must be open for read sharing (i.e. another application + * can open the file for read, but not for write) + * - If the file does not exist, the function must return NULL + * - If the file exists but cannot be open, then function must return NULL + * - The parameters of the function must be validate by the caller + * - The function must initialize all stream function pointers in TFileStream + * - If the function fails from any reason, it must close all handles + * and free all memory that has been allocated in the process of stream creation, + * including the TFileStream structure itself + * + * \a szFileName Name of the file to open + * \a dwStreamFlags specifies the provider and base storage type + */ + +TFileStream * FileStream_OpenFile( + const TCHAR * szFileName, + DWORD dwStreamFlags) +{ + DWORD dwProvider = dwStreamFlags & STREAM_PROVIDERS_MASK; + size_t nPrefixLength = FileStream_Prefix(szFileName, &dwProvider); + + // Re-assemble the stream flags + dwStreamFlags = (dwStreamFlags & STREAM_OPTIONS_MASK) | dwProvider; + szFileName += nPrefixLength; + + // Perform provider-specific open + switch(dwStreamFlags & STREAM_PROVIDER_MASK) + { + case STREAM_PROVIDER_FLAT: + return FlatStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_PARTIAL: + return PartStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_MPQE: + return MpqeStream_Open(szFileName, dwStreamFlags); + + case STREAM_PROVIDER_BLOCK4: + return Block4Stream_Open(szFileName, dwStreamFlags); + + default: + SetLastError(ERROR_INVALID_PARAMETER); + return NULL; + } +} + +/** + * Returns the file name of the stream + * + * \a pStream Pointer to an open stream + */ +const TCHAR * FileStream_GetFileName(TFileStream * pStream) +{ + assert(pStream != NULL); + return pStream->szFileName; +} + +/** + * Returns the length of the provider prefix. Returns zero if no prefix + * + * \a szFileName Pointer to a stream name (file, mapped file, URL) + * \a pdwStreamProvider Pointer to a DWORD variable that receives stream provider (STREAM_PROVIDER_XXX) + */ + +size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider) +{ + size_t nPrefixLength1 = 0; + size_t nPrefixLength2 = 0; + DWORD dwProvider = 0; + + if(szFileName != NULL) + { + // + // Determine the stream provider + // + + if(!_tcsnicmp(szFileName, _T("flat-"), 5)) + { + dwProvider |= STREAM_PROVIDER_FLAT; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("part-"), 5)) + { + dwProvider |= STREAM_PROVIDER_PARTIAL; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("mpqe-"), 5)) + { + dwProvider |= STREAM_PROVIDER_MPQE; + nPrefixLength1 = 5; + } + + else if(!_tcsnicmp(szFileName, _T("blk4-"), 5)) + { + dwProvider |= STREAM_PROVIDER_BLOCK4; + nPrefixLength1 = 5; + } + + // + // Determine the base provider + // + + if(!_tcsnicmp(szFileName+nPrefixLength1, _T("file:"), 5)) + { + dwProvider |= BASE_PROVIDER_FILE; + nPrefixLength2 = 5; + } + + else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("map:"), 4)) + { + dwProvider |= BASE_PROVIDER_MAP; + nPrefixLength2 = 4; + } + + else if(!_tcsnicmp(szFileName+nPrefixLength1, _T("http:"), 5)) + { + dwProvider |= BASE_PROVIDER_HTTP; + nPrefixLength2 = 5; + } + + // Only accept stream provider if we recognized the base provider + if(nPrefixLength2 != 0) + { + // It is also allowed to put "//" after the base provider, e.g. "file://", "http://" + if(szFileName[nPrefixLength1+nPrefixLength2] == '/' && szFileName[nPrefixLength1+nPrefixLength2+1] == '/') + nPrefixLength2 += 2; + + if(pdwProvider != NULL) + *pdwProvider = dwProvider; + return nPrefixLength1 + nPrefixLength2; + } + } + + return 0; +} + +/** + * Sets a download callback. Whenever the stream needs to download one or more blocks + * from the server, the callback is called + * + * \a pStream Pointer to an open stream + * \a pfnCallback Pointer to callback function + * \a pvUserData Arbitrary user pointer passed to the download callback + */ + +bool FileStream_SetCallback(TFileStream * pStream, SFILE_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData) +{ + TBlockStream * pBlockStream = (TBlockStream *)pStream; + + if(pStream->BlockRead == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return false; + } + + pBlockStream->pfnCallback = pfnCallback; + pBlockStream->UserData = pvUserData; + return true; +} + +/** + * This function gives the block map. The 'pvBitmap' pointer must point to a buffer + * of at least sizeof(STREAM_BLOCK_MAP) size. It can also have size of the complete + * block map (i.e. sizeof(STREAM_BLOCK_MAP) + BitmapSize). In that case, the function + * also copies the bit-based block map. + * + * \a pStream Pointer to an open stream + * \a pvBitmap Pointer to buffer where the block map will be stored + * \a cbBitmap Length of the buffer, of the block map + * \a cbLengthNeeded Length of the bitmap, in bytes + */ + +bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, DWORD * pcbLengthNeeded) +{ + TStreamBitmap * pBitmap = (TStreamBitmap *)pvBitmap; + TBlockStream * pBlockStream = (TBlockStream *)pStream; + ULONGLONG BlockOffset; + LPBYTE Bitmap = (LPBYTE)(pBitmap + 1); + DWORD BitmapSize; + DWORD BlockCount; + DWORD BlockSize; + bool bResult = false; + + // Retrieve the size of one block + if(pStream->BlockCheck != NULL) + { + BlockCount = pBlockStream->BlockCount; + BlockSize = pBlockStream->BlockSize; + } + else + { + BlockCount = (DWORD)((pStream->StreamSize + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE); + BlockSize = DEFAULT_BLOCK_SIZE; + } + + // Fill-in the variables + BitmapSize = (BlockCount + 7) / 8; + + // Give the number of blocks + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = sizeof(TStreamBitmap) + BitmapSize; + + // If the length of the buffer is not enough + if(pvBitmap != NULL && cbBitmap != 0) + { + // Give the STREAM_BLOCK_MAP structure + if(cbBitmap >= sizeof(TStreamBitmap)) + { + pBitmap->StreamSize = pStream->StreamSize; + pBitmap->BitmapSize = BitmapSize; + pBitmap->BlockCount = BlockCount; + pBitmap->BlockSize = BlockSize; + pBitmap->IsComplete = (pStream->BlockCheck != NULL) ? pBlockStream->IsComplete : 1; + bResult = true; + } + + // Give the block bitmap, if enough space + if(cbBitmap >= sizeof(TStreamBitmap) + BitmapSize) + { + // Version with bitmap present + if(pStream->BlockCheck != NULL) + { + DWORD ByteIndex = 0; + BYTE BitMask = 0x01; + + // Initialize the map with zeros + memset(Bitmap, 0, BitmapSize); + + // Fill the map + for(BlockOffset = 0; BlockOffset < pStream->StreamSize; BlockOffset += BlockSize) + { + // Set the bit if the block is present + if(pBlockStream->BlockCheck(pStream, BlockOffset)) + Bitmap[ByteIndex] |= BitMask; + + // Move bit position + ByteIndex += (BitMask >> 0x07); + BitMask = (BitMask >> 0x07) | (BitMask << 0x01); + } + } + else + { + memset(Bitmap, 0xFF, BitmapSize); + } + } + } + + // Set last error value and return + if(bResult == false) + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return bResult; +} + +/** + * Reads data from the stream + * + * - Returns true if the read operation succeeded and all bytes have been read + * - Returns false if either read failed or not all bytes have been read + * - If the pByteOffset is NULL, the function must read the data from the current file position + * - The function can be called with dwBytesToRead = 0. In that case, pvBuffer is ignored + * and the function just adjusts file pointer. + * + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position + * \a pvBuffer Pointer to data to be read + * \a dwBytesToRead Number of bytes to read from the file + * + * \returns + * - If the function reads the required amount of bytes, it returns true. + * - If the function reads less than required bytes, it returns false and GetLastError() returns ERROR_HANDLE_EOF + * - If the function fails, it reads false and GetLastError() returns an error code different from ERROR_HANDLE_EOF + */ +bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead) +{ + assert(pStream->StreamRead != NULL); + return pStream->StreamRead(pStream, pByteOffset, pvBuffer, dwBytesToRead); +} + +/** + * This function writes data to the stream + * + * - Returns true if the write operation succeeded and all bytes have been written + * - Returns false if either write failed or not all bytes have been written + * - If the pByteOffset is NULL, the function must write the data to the current file position + * + * \a pStream Pointer to an open stream + * \a pByteOffset Pointer to file byte offset. If NULL, it reads from the current position + * \a pvBuffer Pointer to data to be written + * \a dwBytesToWrite Number of bytes to write to the file + */ +bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite) +{ + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + assert(pStream->StreamWrite != NULL); + return pStream->StreamWrite(pStream, pByteOffset, pvBuffer, dwBytesToWrite); +} + +/** + * Returns the size of a file + * + * \a pStream Pointer to an open stream + * \a FileSize Pointer where to store the file size + */ +bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize) +{ + assert(pStream->StreamGetSize != NULL); + return pStream->StreamGetSize(pStream, pFileSize); +} + +/** + * Sets the size of a file + * + * \a pStream Pointer to an open stream + * \a NewFileSize File size to set + */ +bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize) +{ + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + assert(pStream->StreamResize != NULL); + return pStream->StreamResize(pStream, NewFileSize); +} + +/** + * This function returns the current file position + * \a pStream + * \a pByteOffset + */ +bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset) +{ + assert(pStream->StreamGetPos != NULL); + return pStream->StreamGetPos(pStream, pByteOffset); +} + +/** + * Returns the last write time of a file + * + * \a pStream Pointer to an open stream + * \a pFileType Pointer where to store the file last write time + */ +bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFileTime) +{ + // Just use the saved filetime value + *pFileTime = pStream->Base.File.FileTime; + return true; +} + +/** + * Returns the stream flags + * + * \a pStream Pointer to an open stream + * \a pdwStreamFlags Pointer where to store the stream flags + */ +bool FileStream_GetFlags(TFileStream * pStream, LPDWORD pdwStreamFlags) +{ + *pdwStreamFlags = pStream->dwFlags; + return true; +} + +/** + * Switches a stream with another. Used for final phase of archive compacting. + * Performs these steps: + * + * 1) Closes the handle to the existing MPQ + * 2) Renames the temporary MPQ to the original MPQ, overwrites existing one + * 3) Opens the MPQ stores the handle and stream position to the new stream structure + * + * \a pStream Pointer to an open stream + * \a pNewStream Temporary ("working") stream (created during archive compacting) + */ +bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream) +{ + // Only supported on flat files + if((pStream->dwFlags & STREAM_PROVIDERS_MASK) != (STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE)) + { + SetLastError(ERROR_NOT_SUPPORTED); + return false; + } + + // Not supported on read-only streams + if(pStream->dwFlags & STREAM_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // Close both stream's base providers + pNewStream->BaseClose(pNewStream); + pStream->BaseClose(pStream); + + // Now we have to delete the (now closed) old file and rename the new file + if(!BaseFile_Replace(pStream, pNewStream)) + return false; + + // Now open the base file again + if(!BaseFile_Open(pStream, pStream->szFileName, pStream->dwFlags)) + return false; + + // Cleanup the new stream + FileStream_Close(pNewStream); + return true; +} + +/** + * This function closes an archive file and frees any data buffers + * that have been allocated for stream management. The function must also + * support partially allocated structure, i.e. one or more buffers + * can be NULL, if there was an allocation failure during the process + * + * \a pStream Pointer to an open stream + */ +void FileStream_Close(TFileStream * pStream) +{ + // Check if the stream structure is allocated at all + if(pStream != NULL) + { + // Free the master stream, if any + if(pStream->pMaster != NULL) + FileStream_Close(pStream->pMaster); + pStream->pMaster = NULL; + + // Close the stream provider ... + if(pStream->StreamClose != NULL) + pStream->StreamClose(pStream); + + // ... or close base stream, if any + else if(pStream->BaseClose != NULL) + pStream->BaseClose(pStream); + + // Free the stream itself + STORM_FREE(pStream); + } +} diff --git a/dep/StormLib/src/FileStream.h b/dep/StormLib/src/FileStream.h new file mode 100644 index 000000000..44beeed91 --- /dev/null +++ b/dep/StormLib/src/FileStream.h @@ -0,0 +1,217 @@ +/*****************************************************************************/ +/* FileStream.h Copyright (c) Ladislav Zezula 2012 */ +/*---------------------------------------------------------------------------*/ +/* Description: Definitions for FileStream object */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 14.04.12 1.00 Lad The first version of FileStream.h */ +/*****************************************************************************/ + +#ifndef __FILESTREAM_H__ +#define __FILESTREAM_H__ + +//----------------------------------------------------------------------------- +// Function prototypes + +typedef void (*STREAM_INIT)( + struct TFileStream * pStream // Pointer to an unopened stream +); + +typedef bool (*STREAM_CREATE)( + struct TFileStream * pStream // Pointer to an unopened stream + ); + +typedef bool (*STREAM_OPEN)( + struct TFileStream * pStream, // Pointer to an unopened stream + const TCHAR * szFileName, // Pointer to file name to be open + DWORD dwStreamFlags // Stream flags + ); + +typedef bool (*STREAM_READ)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it reads from the current position + void * pvBuffer, // Pointer to data to be read + DWORD dwBytesToRead // Number of bytes to read from the file + ); + +typedef bool (*STREAM_WRITE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset, // Pointer to file byte offset. If NULL, it writes to the current position + const void * pvBuffer, // Pointer to data to be written + DWORD dwBytesToWrite // Number of bytes to read from the file + ); + +typedef bool (*STREAM_RESIZE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG FileSize // New size for the file, in bytes + ); + +typedef bool (*STREAM_GETSIZE)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pFileSize // Receives the file size, in bytes + ); + +typedef bool (*STREAM_GETPOS)( + struct TFileStream * pStream, // Pointer to an open stream + ULONGLONG * pByteOffset // Pointer to store current file position + ); + +typedef void (*STREAM_CLOSE)( + struct TFileStream * pStream // Pointer to an open stream + ); + +typedef bool (*BLOCK_READ)( + struct TFileStream * pStream, // Pointer to a block-oriented stream + ULONGLONG StartOffset, // Byte offset of start of the block array + ULONGLONG EndOffset, // End offset (either end of the block or end of the file) + LPBYTE BlockBuffer, // Pointer to block-aligned buffer + DWORD BytesNeeded, // Number of bytes that are really needed + bool bAvailable // true if the block is available + ); + +typedef bool (*BLOCK_CHECK)( + struct TFileStream * pStream, // Pointer to a block-oriented stream + ULONGLONG BlockOffset // Offset of the file to check + ); + +typedef void (*BLOCK_SAVEMAP)( + struct TFileStream * pStream // Pointer to a block-oriented stream + ); + +//----------------------------------------------------------------------------- +// Local structures - partial file structure and bitmap footer + +#define ID_FILE_BITMAP_FOOTER 0x33767470 // Signature of the file bitmap footer ('ptv3') +#define DEFAULT_BLOCK_SIZE 0x00004000 // Default size of the stream block +#define DEFAULT_BUILD_NUMBER 10958 // Build number for newly created partial MPQs + +typedef struct _PART_FILE_HEADER +{ + DWORD PartialVersion; // Always set to 2 + char GameBuildNumber[0x20]; // Minimum build number of the game that can use this MPQ + DWORD Flags; // Flags (details unknown) + DWORD FileSizeLo; // Low 32 bits of the contained file size + DWORD FileSizeHi; // High 32 bits of the contained file size + DWORD BlockSize; // Size of one file block, in bytes + +} PART_FILE_HEADER, *PPART_FILE_HEADER; + +// Structure describing the block-to-file map entry +typedef struct _PART_FILE_MAP_ENTRY +{ + DWORD Flags; // 3 = the block is present in the file + DWORD BlockOffsLo; // Low 32 bits of the block position in the file + DWORD BlockOffsHi; // High 32 bits of the block position in the file + DWORD LargeValueLo; // 64-bit value, meaning is unknown + DWORD LargeValueHi; + +} PART_FILE_MAP_ENTRY, *PPART_FILE_MAP_ENTRY; + +typedef struct _FILE_BITMAP_FOOTER +{ + DWORD Signature; // 'ptv3' (ID_FILE_BITMAP_FOOTER) + DWORD Version; // Unknown, seems to always have value of 3 (version?) + DWORD BuildNumber; // Game build number for that MPQ + DWORD MapOffsetLo; // Low 32-bits of the offset of the bit map + DWORD MapOffsetHi; // High 32-bits of the offset of the bit map + DWORD BlockSize; // Size of one block (usually 0x4000 bytes) + +} FILE_BITMAP_FOOTER, *PFILE_BITMAP_FOOTER; + +//----------------------------------------------------------------------------- +// Structure for file stream + +union TBaseProviderData +{ + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + HANDLE hFile; // File handle + } File; + + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + LPBYTE pbFile; // Pointer to mapped view + } Map; + + struct + { + ULONGLONG FileSize; // Size of the file + ULONGLONG FilePos; // Current file position + ULONGLONG FileTime; // Last write time + HANDLE hInternet; // Internet handle + HANDLE hConnect; // Connection to the internet server + } Http; +}; + +struct TFileStream +{ + // Stream provider functions + STREAM_READ StreamRead; // Pointer to stream read function for this archive. Do not use directly. + STREAM_WRITE StreamWrite; // Pointer to stream write function for this archive. Do not use directly. + STREAM_RESIZE StreamResize; // Pointer to function changing file size + STREAM_GETSIZE StreamGetSize; // Pointer to function returning file size + STREAM_GETPOS StreamGetPos; // Pointer to function that returns current file position + STREAM_CLOSE StreamClose; // Pointer to function closing the stream + + // Block-oriented functions + BLOCK_READ BlockRead; // Pointer to function reading one or more blocks + BLOCK_CHECK BlockCheck; // Pointer to function checking whether the block is present + + // Base provider functions + STREAM_CREATE BaseCreate; // Pointer to base create function + STREAM_OPEN BaseOpen; // Pointer to base open function + STREAM_READ BaseRead; // Read from the stream + STREAM_WRITE BaseWrite; // Write to the stream + STREAM_RESIZE BaseResize; // Pointer to function changing file size + STREAM_GETSIZE BaseGetSize; // Pointer to function returning file size + STREAM_GETPOS BaseGetPos; // Pointer to function that returns current file position + STREAM_CLOSE BaseClose; // Pointer to function closing the stream + + // Base provider data (file size, file position) + TBaseProviderData Base; + + // Stream provider data + TFileStream * pMaster; // Master stream (e.g. MPQ on a web server) + TCHAR * szFileName; // File name (self-relative pointer) + + ULONGLONG StreamSize; // Stream size (can be less than file size) + ULONGLONG StreamPos; // Stream position + DWORD BuildNumber; // Game build number + DWORD dwFlags; // Stream flags + + // Followed by stream provider data, with variable length +}; + +//----------------------------------------------------------------------------- +// Structures for block-oriented stream + +struct TBlockStream : public TFileStream +{ + SFILE_DOWNLOAD_CALLBACK pfnCallback; // Callback for downloading + void * FileBitmap; // Array of bits for file blocks + void * UserData; // User data to be passed to the download callback + DWORD BitmapSize; // Size of the file bitmap (in bytes) + DWORD BlockSize; // Size of one block, in bytes + DWORD BlockCount; // Number of data blocks in the file + DWORD IsComplete; // If nonzero, no blocks are missing + DWORD IsModified; // nonzero if the bitmap has been modified +}; + +//----------------------------------------------------------------------------- +// Structure for encrypted stream + +#define MPQE_CHUNK_SIZE 0x40 // Size of one chunk to be decrypted + +struct TEncryptedStream : public TBlockStream +{ + BYTE Key[MPQE_CHUNK_SIZE]; // File key +}; + +#endif // __FILESTREAM_H__ diff --git a/dep/StormLib/src/SBaseCommon.cpp b/dep/StormLib/src/SBaseCommon.cpp new file mode 100644 index 000000000..782e154a3 --- /dev/null +++ b/dep/StormLib/src/SBaseCommon.cpp @@ -0,0 +1,1842 @@ +/*****************************************************************************/ +/* SBaseCommon.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Common functions for StormLib, used by all SFile*** modules */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 24.03.03 1.00 Lad The first version of SFileCommon.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/* 12.06.04 1.01 Lad Renamed to SCommon.cpp */ +/* 06.09.10 1.01 Lad Renamed to SBaseCommon.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +char StormLibCopyright[] = "StormLib v " STORMLIB_VERSION_STRING " Copyright Ladislav Zezula 1998-2014"; + +//----------------------------------------------------------------------------- +// Local variables + +LCID lcFileLocale = LANG_NEUTRAL; // File locale +USHORT wPlatform = 0; // File platform + +//----------------------------------------------------------------------------- +// Conversion to uppercase/lowercase + +// Converts ASCII characters to lowercase +// Converts slash (0x2F) to backslash (0x5C) +unsigned char AsciiToLowerTable[256] = +{ + 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +// Converts ASCII characters to uppercase +// Converts slash (0x2F) to backslash (0x5C) +unsigned char AsciiToUpperTable[256] = +{ + 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, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x5C, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +// Converts ASCII characters to uppercase +// Does NOT convert slash (0x2F) to backslash (0x5C) +unsigned char AsciiToUpperTable_Slash[256] = +{ + 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, 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, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, + 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +//----------------------------------------------------------------------------- +// Safe string functions (for ANSI builds) + +void StringCopy(char * szTarget, size_t cchTarget, const char * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = strlen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + memcpy(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource) +{ + // Get the current length of the target + size_t cchTarget = strlen(szTarget); + + // Copy the string to the target + if(cchTarget < cchTargetMax) + { + StringCopy(szTarget + cchTarget, (cchTargetMax - cchTarget), szSource); + } +} + +//----------------------------------------------------------------------------- +// Utility functions (UNICODE) only exist in the ANSI version of the library +// In ANSI builds, TCHAR = char, so we don't need these functions implemented + +#ifdef _UNICODE +void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = strlen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + mbstowcs(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCopy(char * szTarget, size_t cchTarget, const TCHAR * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = _tcslen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + wcstombs(szTarget, szSource, cchSource); + szTarget[cchSource] = 0; + } +} + +void StringCopy(TCHAR * szTarget, size_t cchTarget, const TCHAR * szSource) +{ + if(cchTarget > 0) + { + size_t cchSource = _tcslen(szSource); + + if(cchSource >= cchTarget) + cchSource = cchTarget - 1; + + memcpy(szTarget, szSource, cchSource * sizeof(TCHAR)); + szTarget[cchSource] = 0; + } +} + +void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource) +{ + // Get the current length of the target + size_t cchTarget = _tcslen(szTarget); + + // Copy the string to the target + if(cchTarget < cchTargetMax) + { + StringCopy(szTarget + cchTarget, (cchTargetMax - cchTarget), szSource); + } +} +#endif + +//----------------------------------------------------------------------------- +// Storm hashing functions + +#define STORM_BUFFER_SIZE 0x500 +#define HASH_INDEX_MASK(ha) (ha->pHeader->dwHashTableSize ? (ha->pHeader->dwHashTableSize - 1) : 0) + +static DWORD StormBuffer[STORM_BUFFER_SIZE]; // Buffer for the decryption engine +static bool bMpqCryptographyInitialized = false; + +void InitializeMpqCryptography() +{ + DWORD dwSeed = 0x00100001; + DWORD index1 = 0; + DWORD index2 = 0; + int i; + + // Initialize the decryption buffer. + // Do nothing if already done. + if(bMpqCryptographyInitialized == false) + { + for(index1 = 0; index1 < 0x100; index1++) + { + for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100) + { + DWORD temp1, temp2; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp1 = (dwSeed & 0xFFFF) << 0x10; + + dwSeed = (dwSeed * 125 + 3) % 0x2AAAAB; + temp2 = (dwSeed & 0xFFFF); + + StormBuffer[index2] = (temp1 | temp2); + } + } + + // Also register both MD5 and SHA1 hash algorithms + register_hash(&md5_desc); + register_hash(&sha1_desc); + + // Use LibTomMath as support math library for LibTomCrypt + ltc_mp = ltm_desc; + + // Don't do that again + bMpqCryptographyInitialized = true; + } +} + +// +// Note: Implementation of this function in WorldEdit.exe and storm.dll +// incorrectly treats the character as signed, which leads to the +// a buffer underflow if the character in the file name >= 0x80: +// The following steps happen when *pbKey == 0xBF and dwHashType == 0x0000 +// (calculating hash index) +// +// 1) Result of AsciiToUpperTable_Slash[*pbKey++] is sign-extended to 0xffffffbf +// 2) The "ch" is added to dwHashType (0xffffffbf + 0x0000 => 0xffffffbf) +// 3) The result is used as index to the StormBuffer table, +// thus dereferences a random value BEFORE the begin of StormBuffer. +// +// As result, MPQs containing files with non-ANSI characters will not work between +// various game versions and localizations. Even WorldEdit, after importing a file +// with Korean characters in the name, cannot open the file back. +// +DWORD HashString(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to uppercase + // Convert slash (0x2F) to backslash (0x5C) + ch = AsciiToUpperTable[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +DWORD HashStringSlash(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to uppercase + // DON'T convert slash (0x2F) to backslash (0x5C) + ch = AsciiToUpperTable_Slash[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +DWORD HashStringLower(const char * szFileName, DWORD dwHashType) +{ + LPBYTE pbKey = (BYTE *)szFileName; + DWORD dwSeed1 = 0x7FED7FED; + DWORD dwSeed2 = 0xEEEEEEEE; + DWORD ch; + + while(*pbKey != 0) + { + // Convert the input character to lower + // DON'T convert slash (0x2F) to backslash (0x5C) + ch = AsciiToLowerTable[*pbKey++]; + + dwSeed1 = StormBuffer[dwHashType + ch] ^ (dwSeed1 + dwSeed2); + dwSeed2 = ch + dwSeed1 + dwSeed2 + (dwSeed2 << 5) + 3; + } + + return dwSeed1; +} + +//----------------------------------------------------------------------------- +// Calculates the hash table size for a given amount of files + +// Returns the nearest higher power of two. +// If the value is already a power of two, returns the same value +DWORD GetNearestPowerOfTwo(DWORD dwFileCount) +{ + dwFileCount --; + + dwFileCount |= dwFileCount >> 1; + dwFileCount |= dwFileCount >> 2; + dwFileCount |= dwFileCount >> 4; + dwFileCount |= dwFileCount >> 8; + dwFileCount |= dwFileCount >> 16; + + return dwFileCount + 1; +} +/* +DWORD GetNearestPowerOfTwo(DWORD dwFileCount) +{ + DWORD dwPowerOfTwo = HASH_TABLE_SIZE_MIN; + + // For zero files, there is no hash table needed + if(dwFileCount == 0) + return 0; + + // Round the hash table size up to the nearest power of two + // Don't allow the hash table size go over allowed maximum + while(dwPowerOfTwo < HASH_TABLE_SIZE_MAX && dwPowerOfTwo < dwFileCount) + dwPowerOfTwo <<= 1; + return dwPowerOfTwo; +} +*/ +//----------------------------------------------------------------------------- +// Calculates a Jenkin's Encrypting and decrypting MPQ file data + +ULONGLONG HashStringJenkins(const char * szFileName) +{ + LPBYTE pbFileName = (LPBYTE)szFileName; + char szNameBuff[0x108]; + size_t nLength = 0; + unsigned int primary_hash = 1; + unsigned int secondary_hash = 2; + + // Normalize the file name - convert to uppercase, and convert "/" to "\\". + if(pbFileName != NULL) + { + char * szNamePtr = szNameBuff; + char * szNameEnd = szNamePtr + sizeof(szNameBuff); + + // Normalize the file name. Doesn't have to be zero terminated for hashing + while(szNamePtr < szNameEnd && pbFileName[0] != 0) + *szNamePtr++ = (char)AsciiToLowerTable[*pbFileName++]; + nLength = szNamePtr - szNameBuff; + } + + // Thanks Quantam for finding out what the algorithm is. + // I am really getting old for reversing large chunks of assembly + // that does hashing :-) + hashlittle2(szNameBuff, nLength, &secondary_hash, &primary_hash); + + // Combine those 2 together + return ((ULONGLONG)primary_hash << 0x20) | (ULONGLONG)secondary_hash; +} + +//----------------------------------------------------------------------------- +// Default flags for (attributes) and (listfile) + +DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion) +{ + // Fixed for format 1.0 + if(wFormatVersion == MPQ_FORMAT_VERSION_1) + return MPQ_FILE_COMPRESS | MPQ_FILE_ENCRYPTED | MPQ_FILE_FIX_KEY; + + // Size-dependent for formats 2.0-4.0 + return (dwFileSize > 0x4000) ? (MPQ_FILE_COMPRESS | MPQ_FILE_SECTOR_CRC) : (MPQ_FILE_COMPRESS | MPQ_FILE_SINGLE_UNIT); +} + + +//----------------------------------------------------------------------------- +// Encrypting/Decrypting MPQ data block + +void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) +{ + LPDWORD DataBlock = (LPDWORD)pvDataBlock; + DWORD dwValue32; + DWORD dwKey2 = 0xEEEEEEEE; + + // Round to DWORDs + dwLength >>= 2; + + // Encrypt the data block at array of DWORDs + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + dwValue32 = DataBlock[i]; + DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } +} + +void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey1) +{ + LPDWORD DataBlock = (LPDWORD)pvDataBlock; + DWORD dwValue32; + DWORD dwKey2 = 0xEEEEEEEE; + + // Round to DWORDs + dwLength >>= 2; + + // Decrypt the data block at array of DWORDs + for(DWORD i = 0; i < dwLength; i++) + { + // Modify the second key + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + + DataBlock[i] = DataBlock[i] ^ (dwKey1 + dwKey2); + dwValue32 = DataBlock[i]; + + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = dwValue32 + dwKey2 + (dwKey2 << 5) + 3; + } +} + +/** + * Functions tries to get file decryption key. This comes from these facts + * + * - We know the decrypted value of the first DWORD in the encrypted data + * - We know the decrypted value of the second DWORD (at least aproximately) + * - There is only 256 variants of how the second key is modified + * + * The first iteration of dwKey1 and dwKey2 is this: + * + * dwKey2 = 0xEEEEEEEE + StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)] + * dwDecrypted0 = DataBlock[0] ^ (dwKey1 + dwKey2); + * + * This means: + * + * (dwKey1 + dwKey2) = DataBlock[0] ^ dwDecrypted0; + * + */ + +DWORD DetectFileKeyBySectorSize(LPDWORD EncryptedData, DWORD dwSectorSize, DWORD dwDecrypted0) +{ + DWORD dwDecrypted1Max = dwSectorSize + dwDecrypted0; + DWORD dwKey1PlusKey2; + DWORD DataBlock[2]; + + // We must have at least 2 DWORDs there to be able to decrypt something + if(dwSectorSize < 0x08) + return 0; + + // Get the value of the combined encryption key + dwKey1PlusKey2 = (EncryptedData[0] ^ dwDecrypted0) - 0xEEEEEEEE; + + // Try all 256 combinations of dwKey1 + for(DWORD i = 0; i < 0x100; i++) + { + DWORD dwSaveKey1; + DWORD dwKey1 = dwKey1PlusKey2 - StormBuffer[MPQ_HASH_KEY2_MIX + i]; + DWORD dwKey2 = 0xEEEEEEEE; + + // Modify the second key and decrypt the first DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[0] = EncryptedData[0] ^ (dwKey1 + dwKey2); + + // Did we obtain the same value like dwDecrypted0? + if(DataBlock[0] == dwDecrypted0) + { + // Save this key value. Increment by one because + // we are decrypting sector offset table + dwSaveKey1 = dwKey1 + 1; + + // Rotate both keys + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = DataBlock[0] + dwKey2 + (dwKey2 << 5) + 3; + + // Modify the second key again and decrypt the second DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[1] = EncryptedData[1] ^ (dwKey1 + dwKey2); + + // Now compare the results + if(DataBlock[1] <= dwDecrypted1Max) + return dwSaveKey1; + } + } + + // Key not found + return 0; +} + +// Function tries to detect file encryption key based on expected file content +// It is the same function like before, except that we know the value of the second DWORD +DWORD DetectFileKeyByKnownContent(void * pvEncryptedData, DWORD dwDecrypted0, DWORD dwDecrypted1) +{ + LPDWORD EncryptedData = (LPDWORD)pvEncryptedData; + DWORD dwKey1PlusKey2; + DWORD DataBlock[2]; + + // Get the value of the combined encryption key + dwKey1PlusKey2 = (EncryptedData[0] ^ dwDecrypted0) - 0xEEEEEEEE; + + // Try all 256 combinations of dwKey1 + for(DWORD i = 0; i < 0x100; i++) + { + DWORD dwSaveKey1; + DWORD dwKey1 = dwKey1PlusKey2 - StormBuffer[MPQ_HASH_KEY2_MIX + i]; + DWORD dwKey2 = 0xEEEEEEEE; + + // Modify the second key and decrypt the first DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[0] = EncryptedData[0] ^ (dwKey1 + dwKey2); + + // Did we obtain the same value like dwDecrypted0? + if(DataBlock[0] == dwDecrypted0) + { + // Save this key value + dwSaveKey1 = dwKey1; + + // Rotate both keys + dwKey1 = ((~dwKey1 << 0x15) + 0x11111111) | (dwKey1 >> 0x0B); + dwKey2 = DataBlock[0] + dwKey2 + (dwKey2 << 5) + 3; + + // Modify the second key again and decrypt the second DWORD + dwKey2 += StormBuffer[MPQ_HASH_KEY2_MIX + (dwKey1 & 0xFF)]; + DataBlock[1] = EncryptedData[1] ^ (dwKey1 + dwKey2); + + // Now compare the results + if(DataBlock[1] == dwDecrypted1) + return dwSaveKey1; + } + } + + // Key not found + return 0; +} + +DWORD DetectFileKeyByContent(void * pvEncryptedData, DWORD dwSectorSize, DWORD dwFileSize) +{ + DWORD dwFileKey; + + // Try to break the file encryption key as if it was a WAVE file + if(dwSectorSize >= 0x0C) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x46464952, dwFileSize - 8); + if(dwFileKey != 0) + return dwFileKey; + } + + // Try to break the encryption key as if it was an EXE file + if(dwSectorSize > 0x40) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x00905A4D, 0x00000003); + if(dwFileKey != 0) + return dwFileKey; + } + + // Try to break the encryption key as if it was a XML file + if(dwSectorSize > 0x04) + { + dwFileKey = DetectFileKeyByKnownContent(pvEncryptedData, 0x6D783F3C, 0x6576206C); + if(dwFileKey != 0) + return dwFileKey; + } + + // Not detected, sorry + return 0; +} + +DWORD DecryptFileKey( + const char * szFileName, + ULONGLONG MpqPos, + DWORD dwFileSize, + DWORD dwFlags) +{ + DWORD dwFileKey; + DWORD dwMpqPos = (DWORD)MpqPos; + + // File key is calculated from plain name + szFileName = GetPlainFileName(szFileName); + dwFileKey = HashString(szFileName, MPQ_HASH_FILE_KEY); + + // Fix the key, if needed + if(dwFlags & MPQ_FILE_FIX_KEY) + dwFileKey = (dwFileKey + dwMpqPos) ^ dwFileSize; + + // Return the key + return dwFileKey; +} + +//----------------------------------------------------------------------------- +// Handle validation functions + +TMPQArchive * IsValidMpqHandle(HANDLE hMpq) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + return (ha != NULL && ha->pHeader != NULL && ha->pHeader->dwID == ID_MPQ) ? ha : NULL; +} + +TMPQFile * IsValidFileHandle(HANDLE hFile) +{ + TMPQFile * hf = (TMPQFile *)hFile; + + // Must not be NULL + if(hf != NULL && hf->dwMagic == ID_MPQ_FILE) + { + // Local file handle? + if(hf->pStream != NULL) + return hf; + + // Also verify the MPQ handle within the file handle + if(IsValidMpqHandle(hf->ha)) + return hf; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Hash table and block table manipulation + +// Attempts to search a free hash entry, or an entry whose names and locale matches +TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale) +{ + TMPQHash * pDeletedEntry = NULL; // If a deleted entry was found in the continuous hash range + TMPQHash * pFreeEntry = NULL; // If a free entry was found in the continuous hash range + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & dwHashIndexMask); + + // Search the hash table and return the found entries in the following priority: + // 1) + // 2) + // 3) + // 4) NULL + for(;;) + { + TMPQHash * pHash = ha->pHashTable + dwIndex; + + // If we found a matching entry, return that one + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && pHash->lcLocale == lcLocale) + return pHash; + + // If we found a deleted entry, remember it but keep searching + if(pHash->dwBlockIndex == HASH_ENTRY_DELETED && pDeletedEntry == NULL) + pDeletedEntry = pHash; + + // If we found a free entry, we need to stop searching + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + { + pFreeEntry = pHash; + break; + } + + // Move to the next hash entry. + // If we reached the starting entry, it's failure. + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + break; + } + + // If we found a deleted entry, return that one preferentially + return (pDeletedEntry != NULL) ? pDeletedEntry : pFreeEntry; +} + +// Retrieves the first hash entry for the given file. +// Every locale version of a file has its own hash entry +TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName) +{ + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwStartIndex = ha->pfnHashString(szFileName, MPQ_HASH_TABLE_INDEX); + DWORD dwName1 = ha->pfnHashString(szFileName, MPQ_HASH_NAME_A); + DWORD dwName2 = ha->pfnHashString(szFileName, MPQ_HASH_NAME_B); + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & dwHashIndexMask); + + // Search the hash table + for(;;) + { + TMPQHash * pHash = ha->pHashTable + dwIndex; + + // If the entry matches, we found it. + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + return pHash; + + // If that hash entry is a free entry, it means we haven't found the file + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return NULL; + + // Move to the next hash entry. Stop searching + // if we got reached the original hash entry + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + return NULL; + } +} + +TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pHash) +{ + DWORD dwHashIndexMask = HASH_INDEX_MASK(ha); + DWORD dwStartIndex = (DWORD)(pFirstHash - ha->pHashTable); + DWORD dwName1 = pHash->dwName1; + DWORD dwName2 = pHash->dwName2; + DWORD dwIndex = (DWORD)(pHash - ha->pHashTable); + + // Now go for any next entry that follows the pHash, + // until either free hash entry was found, or the start entry was reached + for(;;) + { + // Move to the next hash entry. Stop searching + // if we got reached the original hash entry + dwIndex = (dwIndex + 1) & dwHashIndexMask; + if(dwIndex == dwStartIndex) + return NULL; + pHash = ha->pHashTable + dwIndex; + + // If the entry matches, we found it. + if(pHash->dwName1 == dwName1 && pHash->dwName2 == dwName2 && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + return pHash; + + // If that hash entry is a free entry, it means we haven't found the file + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return NULL; + } +} + +// Allocates an entry in the hash table +TMPQHash * AllocateHashEntry( + TMPQArchive * ha, + TFileEntry * pFileEntry, + LCID lcLocale) +{ + TMPQHash * pHash; + DWORD dwStartIndex = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_TABLE_INDEX); + DWORD dwName1 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_A); + DWORD dwName2 = ha->pfnHashString(pFileEntry->szFileName, MPQ_HASH_NAME_B); + + // Attempt to find a free hash entry + pHash = FindFreeHashEntry(ha, dwStartIndex, dwName1, dwName2, lcLocale); + if(pHash != NULL) + { + // Fill the free hash entry + pHash->dwName1 = dwName1; + pHash->dwName2 = dwName2; + pHash->lcLocale = (USHORT)lcLocale; + pHash->Platform = 0; + pHash->dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); + } + + return pHash; +} + +// Finds a free space in the MPQ where to store next data +// The free space begins beyond the file that is stored at the fuhrtest +// position in the MPQ. (listfile), (attributes) and (signature) are ignored, +// unless the MPQ is being flushed. +ULONGLONG FindFreeMpqSpace(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + ULONGLONG FreeSpacePos = ha->pHeader->dwHeaderSize; + DWORD dwChunkCount; + + // Parse the entire block table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Only take existing files with nonzero size + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && (pFileEntry->dwCmpSize != 0)) + { + // If we are not saving MPQ tables, ignore internal MPQ files + if((ha->dwFlags & MPQ_FLAG_SAVING_TABLES) == 0 && IsInternalMpqFileName(pFileEntry->szFileName)) + continue; + + // If the end of the file is bigger than current MPQ table pos, update it + if((pFileEntry->ByteOffset + pFileEntry->dwCmpSize) > FreeSpacePos) + { + // Get the end of the file data + FreeSpacePos = pFileEntry->ByteOffset + pFileEntry->dwCmpSize; + + // Add the MD5 chunks, if present + if(pHeader->dwRawChunkSize != 0 && pFileEntry->dwCmpSize != 0) + { + dwChunkCount = ((pFileEntry->dwCmpSize - 1) / pHeader->dwRawChunkSize) + 1; + FreeSpacePos += dwChunkCount * MD5_DIGEST_SIZE; + } + } + } + } + + // Give the free space position to the caller + return FreeSpacePos; +} + +//----------------------------------------------------------------------------- +// Common functions - MPQ File + +TMPQFile * CreateFileHandle(TMPQArchive * ha, TFileEntry * pFileEntry) +{ + TMPQFile * hf; + + // Allocate space for TMPQFile + hf = STORM_ALLOC(TMPQFile, 1); + if(hf != NULL) + { + // Fill the file structure + memset(hf, 0, sizeof(TMPQFile)); + hf->dwMagic = ID_MPQ_FILE; + hf->pStream = NULL; + hf->ha = ha; + + // If the called entered a file entry, we also copy informations from the file entry + if(ha != NULL && pFileEntry != NULL) + { + // Set the raw position and MPQ position + hf->RawFilePos = FileOffsetFromMpqOffset(ha, pFileEntry->ByteOffset); + hf->MpqFilePos = pFileEntry->ByteOffset; + + // Set the data size + hf->dwDataSize = pFileEntry->dwFileSize; + hf->pFileEntry = pFileEntry; + } + } + + return hf; +} + +TMPQFile * CreateWritableHandle(TMPQArchive * ha, DWORD dwFileSize) +{ + ULONGLONG FreeMpqSpace; + ULONGLONG TempPos; + TMPQFile * hf; + + // We need to find the position in the MPQ where we save the file data + FreeMpqSpace = FindFreeMpqSpace(ha); + + // When format V1, the size of the archive cannot exceed 4 GB + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + TempPos = FreeMpqSpace + + dwFileSize + + (ha->pHeader->dwHashTableSize * sizeof(TMPQHash)) + + (ha->dwFileTableSize * sizeof(TMPQBlock)); + if((TempPos >> 32) != 0) + { + SetLastError(ERROR_DISK_FULL); + return NULL; + } + } + + // Allocate the file handle + hf = CreateFileHandle(ha, NULL); + if(hf == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + // We need to find the position in the MPQ where we save the file data + hf->MpqFilePos = FreeMpqSpace; + hf->bIsWriteHandle = true; + return hf; +} + +// Loads a table from MPQ. +// Can be used for hash table, block table, sector offset table or sector checksum table +void * LoadMpqTable( + TMPQArchive * ha, + ULONGLONG ByteOffset, + DWORD dwCompressedSize, + DWORD dwTableSize, + DWORD dwKey, + bool * pbTableIsCut) +{ + ULONGLONG FileSize = 0; + LPBYTE pbCompressed = NULL; + LPBYTE pbMpqTable; + LPBYTE pbToRead; + DWORD dwBytesToRead = dwCompressedSize; + int nError = ERROR_SUCCESS; + + // Allocate the MPQ table + pbMpqTable = pbToRead = STORM_ALLOC(BYTE, dwTableSize); + if(pbMpqTable != NULL) + { + // Check if the MPQ table is encrypted + if(dwCompressedSize < dwTableSize) + { + // Allocate temporary buffer for holding compressed data + pbCompressed = pbToRead = STORM_ALLOC(BYTE, dwCompressedSize); + if(pbCompressed == NULL) + { + STORM_FREE(pbMpqTable); + return NULL; + } + } + + // Get the file offset from which we will read the table + // Note: According to Storm.dll from Warcraft III (version 2002), + // if the hash table position is 0xFFFFFFFF, no SetFilePointer call is done + // and the table is loaded from the current file offset + if(ByteOffset == SFILE_INVALID_POS) + FileStream_GetPos(ha->pStream, &ByteOffset); + + // On archives v 1.0, hash table and block table can go beyond EOF. + // Storm.dll reads as much as possible, then fills the missing part with zeros. + // Abused by Spazzler map protector which sets hash table size to 0x00100000 + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + // Cut the table size + FileStream_GetSize(ha->pStream, &FileSize); + if((ByteOffset + dwBytesToRead) > FileSize) + { + // Fill the extra data with zeros + dwBytesToRead = (DWORD)(FileSize - ByteOffset); + memset(pbMpqTable + dwBytesToRead, 0, (dwTableSize - dwBytesToRead)); + + // Give the caller information that the table was cut + if(pbTableIsCut != NULL) + pbTableIsCut[0] = true; + } + } + + // If everything succeeded, read the raw table form the MPQ + if(FileStream_Read(ha->pStream, &ByteOffset, pbToRead, dwBytesToRead)) + { + // First of all, decrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize); + DecryptMpqBlock(pbToRead, dwCompressedSize, dwKey); + BSWAP_ARRAY32_UNSIGNED(pbToRead, dwCompressedSize); + } + + // If the table is compressed, decompress it + if(dwCompressedSize < dwTableSize) + { + int cbOutBuffer = (int)dwTableSize; + int cbInBuffer = (int)dwCompressedSize; + + if(!SCompDecompress2(pbMpqTable, &cbOutBuffer, pbCompressed, cbInBuffer)) + nError = GetLastError(); + } + + // Make sure that the table is properly byte-swapped + BSWAP_ARRAY32_UNSIGNED(pbMpqTable, dwTableSize); + } + else + { + nError = GetLastError(); + } + + // If read failed, free the table and return + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pbMpqTable); + pbMpqTable = NULL; + } + + // Free the compression buffer, if any + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + } + + // Return the MPQ table + return pbMpqTable; +} + +unsigned char * AllocateMd5Buffer( + DWORD dwRawDataSize, + DWORD dwChunkSize, + LPDWORD pcbMd5Size) +{ + unsigned char * md5_array; + DWORD cbMd5Size; + + // Sanity check + assert(dwRawDataSize != 0); + assert(dwChunkSize != 0); + + // Calculate how many MD5's we will calculate + cbMd5Size = (((dwRawDataSize - 1) / dwChunkSize) + 1) * MD5_DIGEST_SIZE; + + // Allocate space for array or MD5s + md5_array = STORM_ALLOC(BYTE, cbMd5Size); + + // Give the size of the MD5 array + if(pcbMd5Size != NULL) + *pcbMd5Size = cbMd5Size; + return md5_array; +} + +// Allocates sector buffer and sector offset table +int AllocateSectorBuffer(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + + // Caller of AllocateSectorBuffer must ensure these + assert(hf->pbFileSector == NULL); + assert(hf->pFileEntry != NULL); + assert(hf->ha != NULL); + + // Don't allocate anything if the file has zero size + if(hf->pFileEntry->dwFileSize == 0 || hf->dwDataSize == 0) + return ERROR_SUCCESS; + + // Determine the file sector size and allocate buffer for it + hf->dwSectorSize = (hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) ? hf->dwDataSize : ha->dwSectorSize; + hf->pbFileSector = STORM_ALLOC(BYTE, hf->dwSectorSize); + hf->dwSectorOffs = SFILE_INVALID_POS; + + // Return result + return (hf->pbFileSector != NULL) ? (int)ERROR_SUCCESS : (int)ERROR_NOT_ENOUGH_MEMORY; +} + +// Allocates sector offset table +int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + DWORD dwLength = sizeof(TPatchInfo); + + // The following conditions must be true + assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE); + assert(hf->pPatchInfo == NULL); + +__AllocateAndLoadPatchInfo: + + // Allocate space for patch header. Start with default size, + // and if its size if bigger, then we reload them + hf->pPatchInfo = STORM_ALLOC(TPatchInfo, 1); + if(hf->pPatchInfo == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Do we have to load the patch header from the file ? + if(bLoadFromFile) + { + // Load the patch header + if(!FileStream_Read(ha->pStream, &hf->RawFilePos, hf->pPatchInfo, dwLength)) + { + // Free the patch info + STORM_FREE(hf->pPatchInfo); + hf->pPatchInfo = NULL; + return GetLastError(); + } + + // Perform necessary swapping + hf->pPatchInfo->dwLength = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwLength); + hf->pPatchInfo->dwFlags = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwFlags); + hf->pPatchInfo->dwDataSize = BSWAP_INT32_UNSIGNED(hf->pPatchInfo->dwDataSize); + + // Verify the size of the patch header + // If it's not default size, we have to reload them + if(hf->pPatchInfo->dwLength > dwLength) + { + // Free the patch info + dwLength = hf->pPatchInfo->dwLength; + STORM_FREE(hf->pPatchInfo); + hf->pPatchInfo = NULL; + + // If the length is out of all possible ranges, fail the operation + if(dwLength > 0x400) + return ERROR_FILE_CORRUPT; + goto __AllocateAndLoadPatchInfo; + } + + // Patch file data size according to the patch header + hf->dwDataSize = hf->pPatchInfo->dwDataSize; + } + else + { + memset(hf->pPatchInfo, 0, dwLength); + } + + // Save the final length to the patch header + hf->pPatchInfo->dwLength = dwLength; + hf->pPatchInfo->dwFlags = 0x80000000; + return ERROR_SUCCESS; +} + +// Allocates sector offset table +int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + DWORD dwSectorOffsLen; + bool bSectorOffsetTableCorrupt = false; + + // Caller of AllocateSectorOffsets must ensure these + assert(hf->SectorOffsets == NULL); + assert(hf->pFileEntry != NULL); + assert(hf->dwDataSize != 0); + assert(hf->ha != NULL); + + // If the file is stored as single unit, just set number of sectors to 1 + if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + { + hf->dwSectorCount = 1; + return ERROR_SUCCESS; + } + + // Calculate the number of data sectors + // Note that this doesn't work if the file size is zero + hf->dwSectorCount = ((hf->dwDataSize - 1) / hf->dwSectorSize) + 1; + + // Calculate the number of file sectors + dwSectorOffsLen = (hf->dwSectorCount + 1) * sizeof(DWORD); + + // If MPQ_FILE_SECTOR_CRC flag is set, there will either be extra DWORD + // or an array of MD5's. Either way, we read at least 4 bytes more + // in order to save additional read from the file. + if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) + dwSectorOffsLen += sizeof(DWORD); + + // Only allocate and load the table if the file is compressed + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + __LoadSectorOffsets: + + // Allocate the sector offset table + hf->SectorOffsets = STORM_ALLOC(DWORD, (dwSectorOffsLen / sizeof(DWORD))); + if(hf->SectorOffsets == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Only read from the file if we are supposed to do so + if(bLoadFromFile) + { + ULONGLONG RawFilePos = hf->RawFilePos; + + // Append the length of the patch info, if any + if(hf->pPatchInfo != NULL) + { + if((RawFilePos + hf->pPatchInfo->dwLength) < RawFilePos) + return ERROR_FILE_CORRUPT; + RawFilePos += hf->pPatchInfo->dwLength; + } + + // Load the sector offsets from the file + if(!FileStream_Read(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen)) + { + // Free the sector offsets + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return GetLastError(); + } + + // Swap the sector positions + BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + + // Decrypt loaded sector positions if necessary + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + // If we don't know the file key, try to find it. + if(hf->dwFileKey == 0) + { + hf->dwFileKey = DetectFileKeyBySectorSize(hf->SectorOffsets, ha->dwSectorSize, dwSectorOffsLen); + if(hf->dwFileKey == 0) + { + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return ERROR_UNKNOWN_FILE_KEY; + } + } + + // Decrypt sector positions + DecryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1); + } + + // + // Validate the sector offset table + // + // Note: Some MPQ protectors put the actual file data before the sector offset table. + // In this case, the sector offsets are negative (> 0x80000000). + // + + for(DWORD i = 0; i < hf->dwSectorCount; i++) + { + DWORD dwSectorOffset1 = hf->SectorOffsets[i+1]; + DWORD dwSectorOffset0 = hf->SectorOffsets[i]; + + // Every following sector offset must be bigger than the previous one + if(dwSectorOffset1 <= dwSectorOffset0) + { + bSectorOffsetTableCorrupt = true; + break; + } + + // The sector size must not be bigger than compressed file size + // Edit: Yes, but apparently, in original Storm.dll, the compressed + // size is not checked anywhere. However, we need to do this check + // in order to sector offset table malformed by MPQ protectors + if((dwSectorOffset1 - dwSectorOffset0) > ha->dwSectorSize) + { + bSectorOffsetTableCorrupt = true; + break; + } + } + + // If data corruption detected, free the sector offset table + if(bSectorOffsetTableCorrupt) + { + STORM_FREE(hf->SectorOffsets); + hf->SectorOffsets = NULL; + return ERROR_FILE_CORRUPT; + } + + // + // There may be various extra DWORDs loaded after the sector offset table. + // They are mostly empty on WoW release MPQs, but on MPQs from PTR, + // they contain random non-zero data. Their meaning is unknown. + // + // These extra values are, however, include in the dwCmpSize in the file + // table. We cannot ignore them, because compacting archive would fail + // + + if(hf->SectorOffsets[0] > dwSectorOffsLen) + { + // MPQ protectors put some ridiculous values there. We must limit the extra bytes + if(hf->SectorOffsets[0] > (dwSectorOffsLen + 0x400)) + return ERROR_FILE_CORRUPT; + + // Free the old sector offset table + dwSectorOffsLen = hf->SectorOffsets[0]; + STORM_FREE(hf->SectorOffsets); + goto __LoadSectorOffsets; + } + } + else + { + memset(hf->SectorOffsets, 0, dwSectorOffsLen); + hf->SectorOffsets[0] = dwSectorOffsLen; + } + } + + return ERROR_SUCCESS; +} + +int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG RawFilePos; + DWORD dwCompressedSize = 0; + DWORD dwExpectedSize; + DWORD dwCrcOffset; // Offset of the CRC table, relative to file offset in the MPQ + DWORD dwCrcSize; + + // Caller of AllocateSectorChecksums must ensure these + assert(hf->SectorChksums == NULL); + assert(hf->SectorOffsets != NULL); + assert(hf->pFileEntry != NULL); + assert(hf->ha != NULL); + + // Single unit files don't have sector checksums + if(pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + return ERROR_SUCCESS; + + // Caller must ensure that we are only called when we have sector checksums + assert(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC); + + // + // Older MPQs store an array of CRC32's after + // the raw file data in the MPQ. + // + // In newer MPQs, the (since Cataclysm BETA) the (attributes) file + // contains additional 32-bit values beyond the sector table. + // Their number depends on size of the (attributes), but their + // meaning is unknown. They are usually zeroed in retail game files, + // but contain some sort of checksum in BETA MPQs + // + + // Does the size of the file table match with the CRC32-based checksums? + dwExpectedSize = (hf->dwSectorCount + 2) * sizeof(DWORD); + if(hf->SectorOffsets[0] != 0 && hf->SectorOffsets[0] == dwExpectedSize) + { + // If we are not loading from the MPQ file, we just allocate the sector table + // In that case, do not check any sizes + if(bLoadFromFile == false) + { + hf->SectorChksums = STORM_ALLOC(DWORD, hf->dwSectorCount); + if(hf->SectorChksums == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the checksum table with zeros + memset(hf->SectorChksums, 0, hf->dwSectorCount * sizeof(DWORD)); + return ERROR_SUCCESS; + } + else + { + // Is there valid size of the sector checksums? + if(hf->SectorOffsets[hf->dwSectorCount + 1] >= hf->SectorOffsets[hf->dwSectorCount]) + dwCompressedSize = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount]; + + // Ignore cases when the length is too small or too big. + if(dwCompressedSize < sizeof(DWORD) || dwCompressedSize > hf->dwSectorSize) + return ERROR_SUCCESS; + + // Calculate offset of the CRC table + dwCrcSize = hf->dwSectorCount * sizeof(DWORD); + dwCrcOffset = hf->SectorOffsets[hf->dwSectorCount]; + RawFilePos = CalculateRawSectorOffset(hf, dwCrcOffset); + + // Now read the table from the MPQ + hf->SectorChksums = (DWORD *)LoadMpqTable(ha, RawFilePos, dwCompressedSize, dwCrcSize, 0, NULL); + if(hf->SectorChksums == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } + } + + // If the size doesn't match, we ignore sector checksums +// assert(false); + return ERROR_SUCCESS; +} + +int WritePatchInfo(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + TPatchInfo * pPatchInfo = hf->pPatchInfo; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE); + assert(pPatchInfo != NULL); + + BSWAP_ARRAY32_UNSIGNED(pPatchInfo, 3 * sizeof(DWORD)); + if(!FileStream_Write(ha->pStream, &hf->RawFilePos, pPatchInfo, sizeof(TPatchInfo))) + return GetLastError(); + + return ERROR_SUCCESS; +} + +int WriteSectorOffsets(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG RawFilePos = hf->RawFilePos; + DWORD dwSectorOffsLen; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK); + assert(hf->SectorOffsets != NULL); + dwSectorOffsLen = hf->SectorOffsets[0]; + + // If file is encrypted, sector positions are also encrypted + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + EncryptMpqBlock(hf->SectorOffsets, dwSectorOffsLen, hf->dwFileKey - 1); + BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + + // Adjust sector offset table position, if we also have patch info + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + + // Write sector offsets to the archive + if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, dwSectorOffsLen)) + return GetLastError(); + + // Not necessary, as the sector checksums + // are going to be freed when this is done. +// BSWAP_ARRAY32_UNSIGNED(hf->SectorOffsets, dwSectorOffsLen); + return ERROR_SUCCESS; +} + + +int WriteSectorChecksums(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + ULONGLONG RawFilePos; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed; + DWORD dwCompressedSize = 0; + DWORD dwCrcSize; + int nOutSize; + int nError = ERROR_SUCCESS; + + // The caller must make sure that this function is only called + // when the following is true. + assert(hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC); + assert(hf->SectorOffsets != NULL); + assert(hf->SectorChksums != NULL); + + // If the MPQ has MD5 of each raw data chunk, + // we leave sector offsets empty + if(ha->pHeader->dwRawChunkSize != 0) + { + hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount]; + return ERROR_SUCCESS; + } + + // Calculate size of the checksum array + dwCrcSize = hf->dwSectorCount * sizeof(DWORD); + + // Allocate buffer for compressed sector CRCs. + pbCompressed = STORM_ALLOC(BYTE, dwCrcSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Perform the compression + BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize); + + nOutSize = (int)dwCrcSize; + SCompCompress(pbCompressed, &nOutSize, hf->SectorChksums, (int)dwCrcSize, MPQ_COMPRESSION_ZLIB, 0, 0); + dwCompressedSize = (DWORD)nOutSize; + + // Write the sector CRCs to the archive + RawFilePos = hf->RawFilePos + hf->SectorOffsets[hf->dwSectorCount]; + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + if(!FileStream_Write(ha->pStream, &RawFilePos, pbCompressed, dwCompressedSize)) + nError = GetLastError(); + + // Not necessary, as the sector checksums + // are going to be freed when this is done. +// BSWAP_ARRAY32_UNSIGNED(hf->SectorChksums, dwCrcSize); + + // Store the sector CRCs + hf->SectorOffsets[hf->dwSectorCount + 1] = hf->SectorOffsets[hf->dwSectorCount] + dwCompressedSize; + pFileEntry->dwCmpSize += dwCompressedSize; + STORM_FREE(pbCompressed); + return nError; +} + +int WriteMemDataMD5( + TFileStream * pStream, + ULONGLONG RawDataOffs, + void * pvRawData, + DWORD dwRawDataSize, + DWORD dwChunkSize, + LPDWORD pcbTotalSize) +{ + unsigned char * md5_array; + unsigned char * md5; + LPBYTE pbRawData = (LPBYTE)pvRawData; + DWORD dwBytesRemaining = dwRawDataSize; + DWORD dwMd5ArraySize = 0; + int nError = ERROR_SUCCESS; + + // Allocate buffer for array of MD5 + md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize); + if(md5_array == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // For every file chunk, calculate MD5 + while(dwBytesRemaining != 0) + { + // Get the remaining number of bytes to read + dwChunkSize = STORMLIB_MIN(dwBytesRemaining, dwChunkSize); + + // Calculate MD5 + CalculateDataBlockHash(pbRawData, dwChunkSize, md5); + md5 += MD5_DIGEST_SIZE; + + // Move offset and size + dwBytesRemaining -= dwChunkSize; + pbRawData += dwChunkSize; + } + + // Write the array od MD5's to the file + RawDataOffs += dwRawDataSize; + if(!FileStream_Write(pStream, &RawDataOffs, md5_array, dwMd5ArraySize)) + nError = GetLastError(); + + // Give the caller the size of the MD5 array + if(pcbTotalSize != NULL) + *pcbTotalSize = dwRawDataSize + dwMd5ArraySize; + + // Free buffers and exit + STORM_FREE(md5_array); + return nError; +} + + +// Writes the MD5 for each chunk of the raw file data +int WriteMpqDataMD5( + TFileStream * pStream, + ULONGLONG RawDataOffs, + DWORD dwRawDataSize, + DWORD dwChunkSize) +{ + unsigned char * md5_array; + unsigned char * md5; + LPBYTE pbFileChunk; + DWORD dwMd5ArraySize = 0; + DWORD dwToRead = dwRawDataSize; + int nError = ERROR_SUCCESS; + + // Allocate buffer for array of MD5 + md5_array = md5 = AllocateMd5Buffer(dwRawDataSize, dwChunkSize, &dwMd5ArraySize); + if(md5_array == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Allocate space for file chunk + pbFileChunk = STORM_ALLOC(BYTE, dwChunkSize); + if(pbFileChunk == NULL) + { + STORM_FREE(md5_array); + return ERROR_NOT_ENOUGH_MEMORY; + } + + // For every file chunk, calculate MD5 + while(dwRawDataSize != 0) + { + // Get the remaining number of bytes to read + dwToRead = STORMLIB_MIN(dwRawDataSize, dwChunkSize); + + // Read the chunk + if(!FileStream_Read(pStream, &RawDataOffs, pbFileChunk, dwToRead)) + { + nError = GetLastError(); + break; + } + + // Calculate MD5 + CalculateDataBlockHash(pbFileChunk, dwToRead, md5); + md5 += MD5_DIGEST_SIZE; + + // Move offset and size + RawDataOffs += dwToRead; + dwRawDataSize -= dwToRead; + } + + // Write the array od MD5's to the file + if(nError == ERROR_SUCCESS) + { + if(!FileStream_Write(pStream, NULL, md5_array, dwMd5ArraySize)) + nError = GetLastError(); + } + + // Free buffers and exit + STORM_FREE(pbFileChunk); + STORM_FREE(md5_array); + return nError; +} + +// Frees the structure for MPQ file +void FreeFileHandle(TMPQFile *& hf) +{ + if(hf != NULL) + { + // If we have patch file attached to this one, free it first + if(hf->hfPatch != NULL) + FreeFileHandle(hf->hfPatch); + + // Then free all buffers allocated in the file structure + if(hf->pbFileData != NULL) + STORM_FREE(hf->pbFileData); + if(hf->pPatchInfo != NULL) + STORM_FREE(hf->pPatchInfo); + if(hf->SectorOffsets != NULL) + STORM_FREE(hf->SectorOffsets); + if(hf->SectorChksums != NULL) + STORM_FREE(hf->SectorChksums); + if(hf->pbFileSector != NULL) + STORM_FREE(hf->pbFileSector); + if(hf->pStream != NULL) + FileStream_Close(hf->pStream); + STORM_FREE(hf); + hf = NULL; + } +} + +// Frees the MPQ archive +void FreeArchiveHandle(TMPQArchive *& ha) +{ + if(ha != NULL) + { + // First of all, free the patch archive, if any + if(ha->haPatch != NULL) + FreeArchiveHandle(ha->haPatch); + + // Free the patch prefix, if any + if(ha->pPatchPrefix != NULL) + STORM_FREE(ha->pPatchPrefix); + + // Close the file stream + FileStream_Close(ha->pStream); + ha->pStream = NULL; + + // Free the file names from the file table + if(ha->pFileTable != NULL) + { + for(DWORD i = 0; i < ha->dwFileTableSize; i++) + { + if(ha->pFileTable[i].szFileName != NULL) + STORM_FREE(ha->pFileTable[i].szFileName); + ha->pFileTable[i].szFileName = NULL; + } + + // Then free all buffers allocated in the archive structure + STORM_FREE(ha->pFileTable); + } + + if(ha->pHashTable != NULL) + STORM_FREE(ha->pHashTable); + if(ha->pHetTable != NULL) + FreeHetTable(ha->pHetTable); + STORM_FREE(ha); + ha = NULL; + } +} + +bool IsInternalMpqFileName(const char * szFileName) +{ + if(szFileName != NULL && szFileName[0] == '(') + { + if(!_stricmp(szFileName, LISTFILE_NAME) || + !_stricmp(szFileName, ATTRIBUTES_NAME) || + !_stricmp(szFileName, SIGNATURE_NAME)) + { + return true; + } + } + + return false; +} + +// Verifies if the file name is a pseudo-name +bool IsPseudoFileName(const char * szFileName, DWORD * pdwFileIndex) +{ + DWORD dwFileIndex = 0; + + if(szFileName != NULL) + { + // Must be "File########.ext" + if(!_strnicmp(szFileName, "File", 4)) + { + // Check 8 digits + for(int i = 4; i < 4+8; i++) + { + if(szFileName[i] < '0' || szFileName[i] > '9') + return false; + dwFileIndex = (dwFileIndex * 10) + (szFileName[i] - '0'); + } + + // An extension must follow + if(szFileName[12] == '.') + { + if(pdwFileIndex != NULL) + *pdwFileIndex = dwFileIndex; + return true; + } + } + } + + // Not a pseudo-name + return false; +} + +//----------------------------------------------------------------------------- +// Functions calculating and verifying the MD5 signature + +bool IsValidMD5(LPBYTE pbMd5) +{ + LPDWORD Md5 = (LPDWORD)pbMd5; + + return (Md5[0] | Md5[1] | Md5[2] | Md5[3]) ? true : false; +} + +bool IsValidSignature(LPBYTE pbSignature) +{ + LPDWORD Signature = (LPDWORD)pbSignature; + DWORD SigValid = 0; + + for(int i = 0; i < MPQ_WEAK_SIGNATURE_SIZE / sizeof(DWORD); i++) + SigValid |= Signature[i]; + + return (SigValid != 0) ? true : false; +} + + +bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5) +{ + hash_state md5_state; + BYTE md5_digest[MD5_DIGEST_SIZE]; + + // Don't verify the block if the MD5 is not valid. + if(!IsValidMD5(expected_md5)) + return true; + + // Calculate the MD5 of the data block + md5_init(&md5_state); + md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); + md5_done(&md5_state, md5_digest); + + // Does the MD5's match? + return (memcmp(md5_digest, expected_md5, MD5_DIGEST_SIZE) == 0); +} + +void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash) +{ + hash_state md5_state; + + md5_init(&md5_state); + md5_process(&md5_state, (unsigned char *)pvDataBlock, cbDataBlock); + md5_done(&md5_state, md5_hash); +} + + +//----------------------------------------------------------------------------- +// Swapping functions + +#ifndef PLATFORM_LITTLE_ENDIAN + +// +// Note that those functions are implemented for Mac operating system, +// as this is the only supported platform that uses big endian. +// + +// Swaps a signed 16-bit integer +int16_t SwapInt16(uint16_t data) +{ + return (int16_t)CFSwapInt16(data); +} + +// Swaps an unsigned 16-bit integer +uint16_t SwapUInt16(uint16_t data) +{ + return CFSwapInt16(data); +} + +// Swaps signed 32-bit integer +int32_t SwapInt32(uint32_t data) +{ + return (int32_t)CFSwapInt32(data); +} + +// Swaps an unsigned 32-bit integer +uint32_t SwapUInt32(uint32_t data) +{ + return CFSwapInt32(data); +} + +// Swaps signed 64-bit integer +int64_t SwapInt64(int64_t data) +{ + return (int64_t)CFSwapInt64(data); +} + +// Swaps an unsigned 64-bit integer +uint64_t SwapUInt64(uint64_t data) +{ + return CFSwapInt64(data); +} + +// Swaps array of unsigned 16-bit integers +void ConvertUInt16Buffer(void * ptr, size_t length) +{ + uint16_t * buffer = (uint16_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint16_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt16(*buffer); + buffer++; + } +} + +// Swaps array of unsigned 32-bit integers +void ConvertUInt32Buffer(void * ptr, size_t length) +{ + uint32_t * buffer = (uint32_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint32_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt32(*buffer); + buffer++; + } +} + +// Swaps array of unsigned 64-bit integers +void ConvertUInt64Buffer(void * ptr, size_t length) +{ + uint64_t * buffer = (uint64_t *)ptr; + uint32_t nElements = (uint32_t)(length / sizeof(uint64_t)); + + while(nElements-- > 0) + { + *buffer = SwapUInt64(*buffer); + buffer++; + } +} + +// Swaps the TMPQHeader structure +void ConvertTMPQHeader(void *header, uint16_t version) +{ + TMPQHeader * theHeader = (TMPQHeader *)header; + + // Swap header part version 1 + if(version == MPQ_FORMAT_VERSION_1) + { + theHeader->dwID = SwapUInt32(theHeader->dwID); + theHeader->dwHeaderSize = SwapUInt32(theHeader->dwHeaderSize); + theHeader->dwArchiveSize = SwapUInt32(theHeader->dwArchiveSize); + theHeader->wFormatVersion = SwapUInt16(theHeader->wFormatVersion); + theHeader->wSectorSize = SwapUInt16(theHeader->wSectorSize); + theHeader->dwHashTablePos = SwapUInt32(theHeader->dwHashTablePos); + theHeader->dwBlockTablePos = SwapUInt32(theHeader->dwBlockTablePos); + theHeader->dwHashTableSize = SwapUInt32(theHeader->dwHashTableSize); + theHeader->dwBlockTableSize = SwapUInt32(theHeader->dwBlockTableSize); + } + + if(version == MPQ_FORMAT_VERSION_2) + { + theHeader->HiBlockTablePos64 = SwapUInt64(theHeader->HiBlockTablePos64); + theHeader->wHashTablePosHi = SwapUInt16(theHeader->wHashTablePosHi); + theHeader->wBlockTablePosHi = SwapUInt16(theHeader->wBlockTablePosHi); + } + + if(version == MPQ_FORMAT_VERSION_3) + { + theHeader->ArchiveSize64 = SwapUInt64(theHeader->ArchiveSize64); + theHeader->BetTablePos64 = SwapUInt64(theHeader->BetTablePos64); + theHeader->HetTablePos64 = SwapUInt64(theHeader->HetTablePos64); + } + + if(version == MPQ_FORMAT_VERSION_4) + { + theHeader->HashTableSize64 = SwapUInt64(theHeader->HashTableSize64); + theHeader->BlockTableSize64 = SwapUInt64(theHeader->BlockTableSize64); + theHeader->HiBlockTableSize64 = SwapUInt64(theHeader->HiBlockTableSize64); + theHeader->HetTableSize64 = SwapUInt64(theHeader->HetTableSize64); + theHeader->BetTableSize64 = SwapUInt64(theHeader->BetTableSize64); + } +} + +#endif // PLATFORM_LITTLE_ENDIAN diff --git a/dep/StormLib/src/SBaseDumpData.cpp b/dep/StormLib/src/SBaseDumpData.cpp new file mode 100644 index 000000000..334561b85 --- /dev/null +++ b/dep/StormLib/src/SBaseDumpData.cpp @@ -0,0 +1,189 @@ +/*****************************************************************************/ +/* SBaseDumpData.cpp Copyright (c) Ladislav Zezula 2011 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 26.01.11 1.00 Lad The first version of SBaseDumpData.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +#ifdef __STORMLIB_DUMP_DATA__ + +void DumpMpqHeader(TMPQHeader * pHeader) +{ + printf("== MPQ Header =================================\n"); + printf("DWORD dwID = %08X\n", pHeader->dwID); + printf("DWORD dwHeaderSize = %08X\n", pHeader->dwHeaderSize); + printf("DWORD dwArchiveSize = %08X\n", pHeader->dwArchiveSize); + printf("USHORT wFormatVersion = %04X\n", pHeader->wFormatVersion); + printf("USHORT wSectorSize = %04X\n", pHeader->wSectorSize); + printf("DWORD dwHashTablePos = %08X\n", pHeader->dwHashTablePos); + printf("DWORD dwBlockTablePos = %08X\n", pHeader->dwBlockTablePos); + printf("DWORD dwHashTableSize = %08X\n", pHeader->dwHashTableSize); + printf("DWORD dwBlockTableSize = %08X\n", pHeader->dwBlockTableSize); + printf("ULONGLONG HiBlockTablePos64 = %016llX\n", pHeader->HiBlockTablePos64); + printf("USHORT wHashTablePosHi = %04X\n", pHeader->wHashTablePosHi); + printf("USHORT wBlockTablePosHi = %04X\n", pHeader->wBlockTablePosHi); + printf("ULONGLONG ArchiveSize64 = %016llX\n", pHeader->ArchiveSize64); + printf("ULONGLONG BetTablePos64 = %016llX\n", pHeader->BetTablePos64); + printf("ULONGLONG HetTablePos64 = %016llX\n", pHeader->HetTablePos64); + printf("ULONGLONG HashTableSize64 = %016llX\n", pHeader->HashTableSize64); + printf("ULONGLONG BlockTableSize64 = %016llX\n", pHeader->BlockTableSize64); + printf("ULONGLONG HiBlockTableSize64 = %016llX\n", pHeader->HiBlockTableSize64); + printf("ULONGLONG HetTableSize64 = %016llX\n", pHeader->HetTableSize64); + printf("ULONGLONG BetTableSize64 = %016llX\n", pHeader->BetTableSize64); + printf("DWORD dwRawChunkSize = %08X\n", pHeader->dwRawChunkSize); + printf("-----------------------------------------------\n\n"); +} + +void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize) +{ + DWORD i; + + if(pHashTable == NULL || dwHashTableSize == 0) + return; + + printf("== Hash Table =================================\n"); + for(i = 0; i < dwHashTableSize; i++) + { + printf("[%08x] %08X %08X %04X %02X %08X\n", i, + pHashTable[i].dwName1, + pHashTable[i].dwName2, + pHashTable[i].lcLocale, + pHashTable[i].Platform, + pHashTable[i].dwBlockIndex); + } + printf("-----------------------------------------------\n\n"); +} + +void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable) +{ + DWORD i; + + if(pHetTable == NULL || pBetTable == NULL) + return; + + printf("== HET Header =================================\n"); + printf("ULONGLONG AndMask64 = %016llX\n", pHetTable->AndMask64); + printf("ULONGLONG OrMask64 = %016llX\n", pHetTable->OrMask64); + printf("DWORD dwEntryCount = %08X\n", pHetTable->dwEntryCount); + printf("DWORD dwTotalCount = %08X\n", pHetTable->dwTotalCount); + printf("DWORD dwNameHashBitSize = %08X\n", pHetTable->dwNameHashBitSize); + printf("DWORD dwIndexSizeTotal = %08X\n", pHetTable->dwIndexSizeTotal); + printf("DWORD dwIndexSizeExtra = %08X\n", pHetTable->dwIndexSizeExtra); + printf("DWORD dwIndexSize = %08X\n", pHetTable->dwIndexSize); + printf("-----------------------------------------------\n\n"); + + printf("== BET Header =================================\n"); + printf("DWORD dwTableEntrySize = %08X\n", pBetTable->dwTableEntrySize); + printf("DWORD dwBitIndex_FilePos = %08X\n", pBetTable->dwBitIndex_FilePos); + printf("DWORD dwBitIndex_FileSize = %08X\n", pBetTable->dwBitIndex_FileSize); + printf("DWORD dwBitIndex_CmpSize = %08X\n", pBetTable->dwBitIndex_CmpSize); + printf("DWORD dwBitIndex_FlagIndex = %08X\n", pBetTable->dwBitIndex_FlagIndex); + printf("DWORD dwBitIndex_Unknown = %08X\n", pBetTable->dwBitIndex_Unknown); + printf("DWORD dwBitCount_FilePos = %08X\n", pBetTable->dwBitCount_FilePos); + printf("DWORD dwBitCount_FileSize = %08X\n", pBetTable->dwBitCount_FileSize); + printf("DWORD dwBitCount_CmpSize = %08X\n", pBetTable->dwBitCount_CmpSize); + printf("DWORD dwBitCount_FlagIndex = %08X\n", pBetTable->dwBitCount_FlagIndex); + printf("DWORD dwBitCount_Unknown = %08X\n", pBetTable->dwBitCount_Unknown); + printf("DWORD dwBitTotal_NameHash2 = %08X\n", pBetTable->dwBitTotal_NameHash2); + printf("DWORD dwBitExtra_NameHash2 = %08X\n", pBetTable->dwBitExtra_NameHash2); + printf("DWORD dwBitCount_NameHash2 = %08X\n", pBetTable->dwBitCount_NameHash2); + printf("DWORD dwEntryCount = %08X\n", pBetTable->dwEntryCount); + printf("DWORD dwFlagCount = %08X\n", pBetTable->dwFlagCount); + printf("-----------------------------------------------\n\n"); + + printf("== HET & Bet Table ======================================================================\n\n"); + printf("HetIdx HetHash BetIdx BetHash ByteOffset FileSize CmpSize FlgIdx Flags \n"); + printf("------ ------- ------ ---------------- ---------------- -------- -------- ------ --------\n"); + for(i = 0; i < pHetTable->dwTotalCount; i++) + { + ULONGLONG ByteOffset = 0; + ULONGLONG BetHash = 0; + DWORD dwFileSize = 0; + DWORD dwCmpSize = 0; + DWORD dwFlagIndex = 0; + DWORD dwFlags = 0; + DWORD dwBetIndex = 0; + + GetBits(pHetTable->pBetIndexes, i * pHetTable->dwIndexSizeTotal, + pHetTable->dwIndexSize, + &dwBetIndex, + 4); + + if(dwBetIndex < pHetTable->dwTotalCount) + { + DWORD dwEntryIndex = pBetTable->dwTableEntrySize * dwBetIndex; + + GetBits(pBetTable->pNameHashes, dwBetIndex * pBetTable->dwBitTotal_NameHash2, + pBetTable->dwBitCount_NameHash2, + &BetHash, + 8); + + GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FilePos, + pBetTable->dwBitCount_FilePos, + &ByteOffset, + 8); + + GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FileSize, + pBetTable->dwBitCount_FileSize, + &dwFileSize, + 4); + + GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_CmpSize, + pBetTable->dwBitCount_CmpSize, + &dwCmpSize, + 4); + + GetBits(pBetTable->pFileTable, dwEntryIndex + pBetTable->dwBitIndex_FlagIndex, + pBetTable->dwBitCount_FlagIndex, + &dwFlagIndex, + 4); + + dwFlags = pBetTable->pFileFlags[dwFlagIndex]; + } + + printf(" %04X %02lX %04X %016llX %016llX %08X %08X %04X %08X\n", i, + pHetTable->pNameHashes[i], + dwBetIndex, + BetHash, + ByteOffset, + dwFileSize, + dwCmpSize, + dwFlagIndex, + dwFlags); + } + printf("-----------------------------------------------------------------------------------------\n"); +} + +void DumpFileTable(TFileEntry * pFileTable, DWORD dwFileTableSize) +{ + DWORD i; + + if(pFileTable == NULL || dwFileTableSize == 0) + return; + + printf("== File Table =================================\n"); + for(i = 0; i < dwFileTableSize; i++, pFileTable++) + { + printf("[%04u] %08X-%08X %08X-%08X %08X-%08X 0x%08X 0x%08X 0x%08X %s\n", i, + (DWORD)(pFileTable->FileNameHash >> 0x20), + (DWORD)(pFileTable->FileNameHash & 0xFFFFFFFF), + (DWORD)(pFileTable->ByteOffset >> 0x20), + (DWORD)(pFileTable->ByteOffset & 0xFFFFFFFF), + (DWORD)(pFileTable->FileTime >> 0x20), + (DWORD)(pFileTable->FileTime & 0xFFFFFFFF), + pFileTable->dwFileSize, + pFileTable->dwCmpSize, + pFileTable->dwFlags, + pFileTable->szFileName != NULL ? pFileTable->szFileName : ""); + } + printf("-----------------------------------------------\n\n"); +} + +#endif // __STORMLIB_DUMP_DATA__ diff --git a/dep/StormLib/src/SBaseFileTable.cpp b/dep/StormLib/src/SBaseFileTable.cpp new file mode 100644 index 000000000..e66536d7c --- /dev/null +++ b/dep/StormLib/src/SBaseFileTable.cpp @@ -0,0 +1,2958 @@ +/*****************************************************************************/ +/* SBaseFileTable.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* Description: Common handler for classic and new hash&block tables */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 06.09.10 1.00 Lad The first version of SBaseFileTable.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +#define INVALID_FLAG_VALUE 0xCCCCCCCC +#define MAX_FLAG_INDEX 512 + +//----------------------------------------------------------------------------- +// Support for calculating bit sizes + +static void InitFileFlagArray(LPDWORD FlagArray) +{ + memset(FlagArray, 0xCC, MAX_FLAG_INDEX * sizeof(DWORD)); +} + +static DWORD GetFileFlagIndex(LPDWORD FlagArray, DWORD dwFlags) +{ + // Find free or equal entry in the flag array + for(DWORD dwFlagIndex = 0; dwFlagIndex < MAX_FLAG_INDEX; dwFlagIndex++) + { + if(FlagArray[dwFlagIndex] == INVALID_FLAG_VALUE || FlagArray[dwFlagIndex] == dwFlags) + { + FlagArray[dwFlagIndex] = dwFlags; + return dwFlagIndex; + } + } + + // This should never happen + assert(false); + return 0xFFFFFFFF; +} + +static DWORD GetNecessaryBitCount(ULONGLONG MaxValue) +{ + DWORD dwBitCount = 0; + + while(MaxValue > 0) + { + MaxValue >>= 1; + dwBitCount++; + } + + return dwBitCount; +} + +//----------------------------------------------------------------------------- +// Support functions for BIT_ARRAY + +static USHORT SetBitsMask[] = {0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF}; + +static TBitArray * CreateBitArray( + DWORD NumberOfBits, + BYTE FillValue) +{ + TBitArray * pBitArray; + size_t nSize = sizeof(TBitArray) + (NumberOfBits + 7) / 8; + + // Allocate the bit array + pBitArray = (TBitArray *)STORM_ALLOC(BYTE, nSize); + if(pBitArray != NULL) + { + memset(pBitArray, FillValue, nSize); + pBitArray->NumberOfBytes = (NumberOfBits + 7) / 8; + pBitArray->NumberOfBits = NumberOfBits; + } + + return pBitArray; +} + +void GetBits( + TBitArray * pArray, + unsigned int nBitPosition, + unsigned int nBitLength, + void * pvBuffer, + int nResultByteSize) +{ + unsigned char * pbBuffer = (unsigned char *)pvBuffer; + unsigned int nBytePosition0 = (nBitPosition / 8); + unsigned int nBytePosition1 = nBytePosition0 + 1; + unsigned int nByteLength = (nBitLength / 8); + unsigned int nBitOffset = (nBitPosition & 0x07); + unsigned char BitBuffer; + + // Keep compiler happy for platforms where nResultByteSize is not used + nResultByteSize = nResultByteSize; + +#ifdef _DEBUG + // Check if the target is properly zeroed + for(int i = 0; i < nResultByteSize; i++) + assert(pbBuffer[i] == 0); +#endif + +#ifndef PLATFORM_LITTLE_ENDIAN + // Adjust the buffer pointer for big endian platforms + pbBuffer += (nResultByteSize - 1); +#endif + + // Copy whole bytes, if any + while(nByteLength > 0) + { + // Is the current position in the Elements byte-aligned? + if(nBitOffset != 0) + { + BitBuffer = (unsigned char)((pArray->Elements[nBytePosition0] >> nBitOffset) | (pArray->Elements[nBytePosition1] << (0x08 - nBitOffset))); + } + else + { + BitBuffer = pArray->Elements[nBytePosition0]; + } + +#ifdef PLATFORM_LITTLE_ENDIAN + *pbBuffer++ = BitBuffer; +#else + *pbBuffer-- = BitBuffer; +#endif + + // Move byte positions and lengths + nBytePosition1++; + nBytePosition0++; + nByteLength--; + } + + // Get the rest of the bits + nBitLength = (nBitLength & 0x07); + if(nBitLength != 0) + { + *pbBuffer = (unsigned char)(pArray->Elements[nBytePosition0] >> nBitOffset); + + if(nBitLength > (8 - nBitOffset)) + *pbBuffer = (unsigned char)((pArray->Elements[nBytePosition1] << (8 - nBitOffset)) | (pArray->Elements[nBytePosition0] >> nBitOffset)); + + *pbBuffer &= (0x01 << nBitLength) - 1; + } +} + +void SetBits( + TBitArray * pArray, + unsigned int nBitPosition, + unsigned int nBitLength, + void * pvBuffer, + int nResultByteSize) +{ + unsigned char * pbBuffer = (unsigned char *)pvBuffer; + unsigned int nBytePosition = (nBitPosition / 8); + unsigned int nBitOffset = (nBitPosition & 0x07); + unsigned short BitBuffer = 0; + unsigned short AndMask = 0; + unsigned short OneByte = 0; + + // Keep compiler happy for platforms where nResultByteSize is not used + nResultByteSize = nResultByteSize; + +#ifndef PLATFORM_LITTLE_ENDIAN + // Adjust the buffer pointer for big endian platforms + pbBuffer += (nResultByteSize - 1); +#endif + + // Copy whole bytes, if any + while(nBitLength > 8) + { + // Reload the bit buffer +#ifdef PLATFORM_LITTLE_ENDIAN + OneByte = *pbBuffer++; +#else + OneByte = *pbBuffer--; +#endif + // Update the BitBuffer and AndMask for the bit array + BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset); + AndMask = (AndMask >> 0x08) | (0x00FF << nBitOffset); + + // Update the byte in the array + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + + // Move byte positions and lengths + nBytePosition++; + nBitLength -= 0x08; + } + + if(nBitLength != 0) + { + // Reload the bit buffer + OneByte = *pbBuffer; + + // Update the AND mask for the last bit + BitBuffer = (BitBuffer >> 0x08) | (OneByte << nBitOffset); + AndMask = (AndMask >> 0x08) | (SetBitsMask[nBitLength] << nBitOffset); + + // Update the byte in the array + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + + // Update the next byte, if needed + if(AndMask & 0xFF00) + { + nBytePosition++; + BitBuffer >>= 0x08; + AndMask >>= 0x08; + + pArray->Elements[nBytePosition] = (BYTE)((pArray->Elements[nBytePosition] & ~AndMask) | BitBuffer); + } + } +} + +//----------------------------------------------------------------------------- +// Support for MPQ header + +static ULONGLONG DetermineArchiveSize_V1( + TMPQArchive * ha, + TMPQHeader * pHeader, + ULONGLONG MpqOffset, + ULONGLONG FileSize) +{ + ULONGLONG ByteOffset; + ULONGLONG EndOfMpq = FileSize; + DWORD SignatureHeader = 0; + DWORD dwArchiveSize32; + + // This could only be called for MPQs version 1.0 + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + + // Check if we can rely on the archive size in the header + if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) + { + // The block table cannot be compressed, so the sizes must match + if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) == (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) + return pHeader->dwArchiveSize; + + // If the archive size in the header is less than real file size + dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); + if(pHeader->dwArchiveSize == dwArchiveSize32) + return pHeader->dwArchiveSize; + } + + // Check if there is a signature header + if((EndOfMpq - MpqOffset) > (MPQ_STRONG_SIGNATURE_SIZE + 4)) + { + ByteOffset = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4; + if(FileStream_Read(ha->pStream, &ByteOffset, &SignatureHeader, sizeof(DWORD))) + { + if(BSWAP_INT32_UNSIGNED(SignatureHeader) == MPQ_STRONG_SIGNATURE_ID) + EndOfMpq = EndOfMpq - MPQ_STRONG_SIGNATURE_SIZE - 4; + } + } + + // Return the returned archive size + return (EndOfMpq - MpqOffset); +} + +static ULONGLONG DetermineArchiveSize_V2( + TMPQHeader * pHeader, + ULONGLONG MpqOffset, + ULONGLONG FileSize) +{ + ULONGLONG EndOfMpq = FileSize; + DWORD dwArchiveSize32; + + // This could only be called for MPQs version 2.0 + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_2); + + // Check if we can rely on the archive size in the header + if((FileSize >> 0x20) == 0) + { + if(pHeader->dwBlockTablePos < pHeader->dwArchiveSize) + { + if((pHeader->dwArchiveSize - pHeader->dwBlockTablePos) <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))) + return pHeader->dwArchiveSize; + + // If the archive size in the header is less than real file size + dwArchiveSize32 = (DWORD)(FileSize - MpqOffset); + if(pHeader->dwArchiveSize <= dwArchiveSize32) + return pHeader->dwArchiveSize; + } + } + + // Return the calculated archive size + return (EndOfMpq - MpqOffset); +} + +ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset) +{ + if(ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + { + // For MPQ archive v1, any file offset is only 32-bit + return (ULONGLONG)((DWORD)ha->MpqPos + (DWORD)MpqOffset); + } + else + { + // For MPQ archive v2+, file offsets are full 64-bit + return ha->MpqPos + MpqOffset; + } +} + +ULONGLONG CalculateRawSectorOffset( + TMPQFile * hf, + DWORD dwSectorOffset) +{ + ULONGLONG RawFilePos; + + // Must be used for files within a MPQ + assert(hf->ha != NULL); + assert(hf->ha->pHeader != NULL); + + // + // Some MPQ protectors place the sector offset table after the actual file data. + // Sector offsets in the sector offset table are negative. When added + // to MPQ file offset from the block table entry, the result is a correct + // position of the file data in the MPQ. + // + // For MPQs version 1.0, the offset is purely 32-bit + // + + RawFilePos = hf->RawFilePos + dwSectorOffset; + if(hf->ha->pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1) + RawFilePos = (DWORD)hf->ha->MpqPos + (DWORD)hf->pFileEntry->ByteOffset + dwSectorOffset; + + // We also have to add patch header size, if patch header is present + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + + // Return the result offset + return RawFilePos; +} + +// This function converts the MPQ header so it always looks like version 4 +int ConvertMpqHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG MpqOffset, + ULONGLONG FileSize, + DWORD dwFlags, + bool bIsWarcraft3Map) +{ + TMPQHeader * pHeader = (TMPQHeader *)ha->HeaderData; + ULONGLONG BlockTablePos64 = 0; + ULONGLONG HashTablePos64 = 0; + ULONGLONG BlockTableMask = (ULONGLONG)-1; + ULONGLONG ByteOffset; + USHORT wFormatVersion = BSWAP_INT16_UNSIGNED(pHeader->wFormatVersion); + int nError = ERROR_SUCCESS; + + // If version 1.0 is forced, then the format version is forced to be 1.0 + // Reason: Storm.dll in Warcraft III ignores format version value + if((dwFlags & MPQ_OPEN_FORCE_MPQ_V1) || bIsWarcraft3Map) + wFormatVersion = MPQ_FORMAT_VERSION_1; + + // Format-specific fixes + switch(wFormatVersion) + { + case MPQ_FORMAT_VERSION_1: + + // Check for malformed MPQ header version 1.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_1); + if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_1 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V1) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // + // Note: The value of "dwArchiveSize" member in the MPQ header + // is ignored by Storm.dll and can contain garbage value + // ("w3xmaster" protector). + // + + Label_ArchiveVersion1: + if(pHeader->dwBlockTableSize > 1) // Prevent empty MPQs being marked as malformed + { + if(pHeader->dwHashTablePos <= pHeader->dwHeaderSize || (pHeader->dwHashTablePos & 0x80000000)) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + if(pHeader->dwBlockTablePos <= pHeader->dwHeaderSize || (pHeader->dwBlockTablePos & 0x80000000)) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // Only low byte of sector size is really used + if(pHeader->wSectorSize & 0xFF00) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + pHeader->wSectorSize = pHeader->wSectorSize & 0xFF; + + // Fill the rest of the header + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V1, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V1); + pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash); + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + + // Block table position must be calculated as 32-bit value + // Note: BOBA protector puts block table before the MPQ header, so it is negative + BlockTablePos64 = (ULONGLONG)((DWORD)MpqOffset + pHeader->dwBlockTablePos); + BlockTableMask = 0xFFFFFFF0; + + // Determine the archive size on malformed MPQs + if(ha->dwFlags & MPQ_FLAG_MALFORMED) + { + // Calculate the archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V1(ha, pHeader, MpqOffset, FileSize); + pHeader->dwArchiveSize = (DWORD)pHeader->ArchiveSize64; + } + + // EWIX_v8_7.w3x: TMPQHeader::dwBlockTableSize = 0x00319601 + // Size of TFileTable goes to ~200MB, so we artificially cut it + if(BlockTablePos64 + (pHeader->dwBlockTableSize * sizeof(TMPQBlock)) > FileSize) + { + pHeader->dwBlockTableSize = (DWORD)((FileSize - BlockTablePos64) / sizeof(TMPQBlock)); + pHeader->BlockTableSize64 = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + } + break; + + case MPQ_FORMAT_VERSION_2: + + // Check for malformed MPQ header version 1.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_2); + if(pHeader->wFormatVersion != MPQ_FORMAT_VERSION_2 || pHeader->dwHeaderSize != MPQ_HEADER_SIZE_V2) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + goto Label_ArchiveVersion1; + } + + // Fill the rest of the header with zeros + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V2, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V2); + + // Calculate the expected hash table size + pHeader->HashTableSize64 = (pHeader->dwHashTableSize * sizeof(TMPQHash)); + HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + + // Calculate the expected block table size + pHeader->BlockTableSize64 = (pHeader->dwBlockTableSize * sizeof(TMPQBlock)); + BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + + // We require the block table to follow hash table + if(BlockTablePos64 >= HashTablePos64) + { + // HashTableSize64 may be less than TblSize * sizeof(TMPQHash). + // That means that the hash table is compressed. + pHeader->HashTableSize64 = BlockTablePos64 - HashTablePos64; + + // Calculate the compressed block table size + if(pHeader->HiBlockTablePos64 != 0) + { + // BlockTableSize64 may be less than TblSize * sizeof(TMPQBlock). + // That means that the block table is compressed. + pHeader->BlockTableSize64 = pHeader->HiBlockTablePos64 - BlockTablePos64; + assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); + + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, MpqOffset, FileSize); + + // Calculate the size of the hi-block table + pHeader->HiBlockTableSize64 = pHeader->ArchiveSize64 - pHeader->HiBlockTablePos64; + assert(pHeader->HiBlockTableSize64 == (pHeader->dwBlockTableSize * sizeof(USHORT))); + } + else + { + // Determine real archive size + pHeader->ArchiveSize64 = DetermineArchiveSize_V2(pHeader, MpqOffset, FileSize); + + // Calculate size of the block table + pHeader->BlockTableSize64 = pHeader->ArchiveSize64 - BlockTablePos64; + assert(pHeader->BlockTableSize64 <= (pHeader->dwBlockTableSize * sizeof(TMPQBlock))); + } + } + else + { + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + } + + // Add the MPQ Offset + BlockTablePos64 += MpqOffset; + break; + + case MPQ_FORMAT_VERSION_3: + + // In MPQ format 3.0, the entire header is optional + // and the size of the header can actually be identical + // to size of header 2.0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_3); + if(pHeader->dwHeaderSize < MPQ_HEADER_SIZE_V3) + { + pHeader->ArchiveSize64 = pHeader->dwArchiveSize; + pHeader->HetTablePos64 = 0; + pHeader->BetTablePos64 = 0; + } + + // + // We need to calculate the compressed size of each table. We assume the following order: + // 1) HET table + // 2) BET table + // 3) Classic hash table + // 4) Classic block table + // 5) Hi-block table + // + + // Fill the rest of the header with zeros + memset((LPBYTE)pHeader + MPQ_HEADER_SIZE_V3, 0, sizeof(TMPQHeader) - MPQ_HEADER_SIZE_V3); + BlockTablePos64 = MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + HashTablePos64 = MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos); + ByteOffset = pHeader->ArchiveSize64; + + // Size of the hi-block table + if(pHeader->HiBlockTablePos64) + { + pHeader->HiBlockTableSize64 = ByteOffset - pHeader->HiBlockTablePos64; + ByteOffset = pHeader->HiBlockTablePos64; + } + + // Size of the block table + if(BlockTablePos64) + { + pHeader->BlockTableSize64 = ByteOffset - BlockTablePos64; + ByteOffset = BlockTablePos64; + } + + // Size of the hash table + if(HashTablePos64) + { + pHeader->HashTableSize64 = ByteOffset - HashTablePos64; + ByteOffset = HashTablePos64; + } + + // Size of the BET table + if(pHeader->BetTablePos64) + { + pHeader->BetTableSize64 = ByteOffset - pHeader->BetTablePos64; + ByteOffset = pHeader->BetTablePos64; + } + + // Size of the HET table + if(pHeader->HetTablePos64) + { + pHeader->HetTableSize64 = ByteOffset - pHeader->HetTablePos64; +// ByteOffset = pHeader->HetTablePos64; + } + + // Add the MPQ Offset + BlockTablePos64 += MpqOffset; + break; + + case MPQ_FORMAT_VERSION_4: + + // Verify header MD5. Header MD5 is calculated from the MPQ header since the 'MPQ\x1A' + // signature until the position of header MD5 at offset 0xC0 + BSWAP_TMPQHEADER(pHeader, MPQ_FORMAT_VERSION_4); + if(!VerifyDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader)) + nError = ERROR_FILE_CORRUPT; + + // Calculate the block table position + BlockTablePos64 = MpqOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + break; + + default: + + // Check if it's a War of the Immortal data file (SQP) + // If not, we treat it as malformed MPQ version 1.0 + if(ConvertSqpHeaderToFormat4(ha, FileSize, dwFlags) != ERROR_SUCCESS) + { + pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_MALFORMED; + goto Label_ArchiveVersion1; + } + + // Calculate the block table position + BlockTablePos64 = MpqOffset + MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos); + break; + } + + // Handle case when block table is placed before the MPQ header + // Used by BOBA protector + if(BlockTablePos64 < MpqOffset) + ha->dwFlags |= MPQ_FLAG_MALFORMED; + return nError; +} + +//----------------------------------------------------------------------------- +// Support for hash table + +// Hash entry verification when the file table does not exist yet +bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash) +{ + TFileEntry * pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + + return ((MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) && (pFileEntry->dwFlags & MPQ_FILE_EXISTS)) ? true : false; +} + +// Hash entry verification when the file table does not exist yet +static bool IsValidHashEntry1(TMPQArchive * ha, TMPQHash * pHash, TMPQBlock * pBlockTable) +{ + ULONGLONG ByteOffset; + TMPQBlock * pBlock; + + // The block index is considered valid if it's less than block table size + if(MPQ_BLOCK_INDEX(pHash) < ha->pHeader->dwBlockTableSize) + { + // Calculate the block table position + pBlock = pBlockTable + MPQ_BLOCK_INDEX(pHash); + + // Check whether this is an existing file + // Also we do not allow to be file size greater than 2GB + if((pBlock->dwFlags & MPQ_FILE_EXISTS) && (pBlock->dwFSize & 0x80000000) == 0) + { + // The begin of the file must be within the archive + ByteOffset = FileOffsetFromMpqOffset(ha, pBlock->dwFilePos); + return (ByteOffset < ha->FileSize); + } + } + + return false; +} + +// Returns a hash table entry in the following order: +// 1) A hash table entry with the preferred locale and platform +// 2) A hash table entry with the neutral|matching locale and neutral|matching platform +// 3) NULL +// Storm_2016.dll: 15020940 +static TMPQHash * GetHashEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale, BYTE Platform) +{ + TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName); + TMPQHash * pBestEntry = NULL; + TMPQHash * pHash = pFirstHash; + + // Parse the found hashes + while(pHash != NULL) + { + // Storm_2016.dll: 150209CB + // If the hash entry matches both locale and platform, return it immediately + // Note: We only succeed this check if the locale is non-neutral, because + // some Warcraft III maps have several items with neutral locale&platform, which leads + // to wrong item being returned + if((lcLocale || Platform) && pHash->lcLocale == lcLocale && pHash->Platform == Platform) + return pHash; + + // Storm_2016.dll: 150209D9 + // If (locale matches or is neutral) OR (platform matches or is neutral) + // remember this as the best entry + if(pHash->lcLocale == 0 || pHash->lcLocale == lcLocale) + { + if(pHash->Platform == 0 || pHash->Platform == Platform) + pBestEntry = pHash; + } + + // Get the next hash entry for that file + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // At the end, return neutral hash (if found), otherwise NULL + return pBestEntry; +} + +// Returns a hash table entry in the following order: +// 1) A hash table entry with the preferred locale +// 2) NULL +static TMPQHash * GetHashEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale) +{ + TMPQHash * pFirstHash = GetFirstHashEntry(ha, szFileName); + TMPQHash * pHash = pFirstHash; + + // Parse the found hashes + while(pHash != NULL) + { + // If the locales match, return it + if(pHash->lcLocale == lcLocale) + return pHash; + + // Get the next hash entry for that file + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // Not found + return NULL; +} + +// Defragment the file table so it does not contain any gaps +// Note: As long as all values of all TMPQHash::dwBlockIndex +// are not HASH_ENTRY_FREE, the startup search index does not matter. +// Hash table is circular, so as long as there is no terminator, +// all entries will be found. +static TMPQHash * DefragmentHashTable( + TMPQArchive * ha, + TMPQHash * pHashTable, + TMPQBlock * pBlockTable) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQHash * pHashTableEnd = pHashTable + pHeader->dwHashTableSize; + TMPQHash * pSource = pHashTable; + TMPQHash * pTarget = pHashTable; + DWORD dwFirstFreeEntry; + DWORD dwNewTableSize; + + // Sanity checks + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + assert(pHeader->HiBlockTablePos64 == 0); + + // Parse the hash table and move the entries to the begin of it + for(pSource = pHashTable; pSource < pHashTableEnd; pSource++) + { + // Check whether this is a valid hash table entry + if(IsValidHashEntry1(ha, pSource, pBlockTable)) + { + // Copy the hash table entry back + if(pSource > pTarget) + pTarget[0] = pSource[0]; + + // Move the target + pTarget++; + } + } + + // Calculate how many entries in the hash table we really need + dwFirstFreeEntry = (DWORD)(pTarget - pHashTable); + dwNewTableSize = GetNearestPowerOfTwo(dwFirstFreeEntry); + + // Fill the rest with entries that look like deleted + pHashTableEnd = pHashTable + dwNewTableSize; + pSource = pHashTable + dwFirstFreeEntry; + memset(pSource, 0xFF, (dwNewTableSize - dwFirstFreeEntry) * sizeof(TMPQHash)); + + // Mark the block indexes as deleted + for(; pSource < pHashTableEnd; pSource++) + pSource->dwBlockIndex = HASH_ENTRY_DELETED; + + // Free some of the space occupied by the hash table + if(dwNewTableSize < pHeader->dwHashTableSize) + { + pHashTable = STORM_REALLOC(TMPQHash, pHashTable, dwNewTableSize); + ha->pHeader->BlockTableSize64 = dwNewTableSize * sizeof(TMPQHash); + ha->pHeader->dwHashTableSize = dwNewTableSize; + } + + return pHashTable; +} + +static int BuildFileTableFromBlockTable( + TMPQArchive * ha, + TMPQBlock * pBlockTable) +{ + TFileEntry * pFileEntry; + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlock; + TMPQHash * pHashTableEnd; + TMPQHash * pHash; + LPDWORD DefragmentTable = NULL; + DWORD dwItemCount = 0; + DWORD dwFlagMask; + + // Sanity checks + assert(ha->pFileTable != NULL); + assert(ha->dwFileTableSize >= ha->dwMaxFileCount); + + // MPQs for Warcraft III doesn't know some flags, namely MPQ_FILE_SINGLE_UNIT and MPQ_FILE_PATCH_FILE + dwFlagMask = (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS; + + // Defragment the hash table, if needed + if(ha->dwFlags & MPQ_FLAG_HASH_TABLE_CUT) + { + ha->pHashTable = DefragmentHashTable(ha, ha->pHashTable, pBlockTable); + ha->dwMaxFileCount = pHeader->dwHashTableSize; + } + + // If the hash table or block table is cut, + // we will defragment the block table + if(ha->dwFlags & (MPQ_FLAG_HASH_TABLE_CUT | MPQ_FLAG_BLOCK_TABLE_CUT)) + { + // Sanity checks + assert(pHeader->wFormatVersion == MPQ_FORMAT_VERSION_1); + assert(pHeader->HiBlockTablePos64 == 0); + + // Allocate the translation table + DefragmentTable = STORM_ALLOC(DWORD, pHeader->dwBlockTableSize); + if(DefragmentTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the translation table + memset(DefragmentTable, 0xFF, pHeader->dwBlockTableSize * sizeof(DWORD)); + } + + // Parse the entire hash table + pHashTableEnd = ha->pHashTable + pHeader->dwHashTableSize; + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + // + // We need to properly handle these cases: + // - Multiple hash entries (same file name) point to the same block entry + // - Multiple hash entries (different file name) point to the same block entry + // + // Ignore all hash table entries where: + // - Block Index >= BlockTableSize + // - Flags of the appropriate block table entry + // + + if(IsValidHashEntry1(ha, pHash, pBlockTable)) + { + DWORD dwOldIndex = MPQ_BLOCK_INDEX(pHash); + DWORD dwNewIndex = MPQ_BLOCK_INDEX(pHash); + + // Determine the new block index + if(DefragmentTable != NULL) + { + // Need to handle case when multiple hash + // entries point to the same block entry + if(DefragmentTable[dwOldIndex] == HASH_ENTRY_FREE) + { + DefragmentTable[dwOldIndex] = dwItemCount; + dwNewIndex = dwItemCount++; + } + else + { + dwNewIndex = DefragmentTable[dwOldIndex]; + } + + // Fix the pointer in the hash entry + pHash->dwBlockIndex = dwNewIndex; + + // Dump the relocation entry +// printf("Relocating hash entry %08X-%08X: %08X -> %08X\n", pHash->dwName1, pHash->dwName2, dwBlockIndex, dwNewIndex); + } + + // Get the pointer to the file entry and the block entry + pFileEntry = ha->pFileTable + dwNewIndex; + pBlock = pBlockTable + dwOldIndex; + + // ByteOffset is only valid if file size is not zero + pFileEntry->ByteOffset = pBlock->dwFilePos; + if(pFileEntry->ByteOffset == 0 && pBlock->dwFSize == 0) + pFileEntry->ByteOffset = ha->pHeader->dwHeaderSize; + + // Fill the rest of the file entry + pFileEntry->dwFileSize = pBlock->dwFSize; + pFileEntry->dwCmpSize = pBlock->dwCSize; + pFileEntry->dwFlags = pBlock->dwFlags & dwFlagMask; + } + } + + // Free the translation table + if(DefragmentTable != NULL) + { + // If we defragmented the block table in the process, + // free some memory by shrinking the file table + if(ha->dwFileTableSize > ha->dwMaxFileCount) + { + ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, ha->dwMaxFileCount); + ha->pHeader->BlockTableSize64 = ha->dwMaxFileCount * sizeof(TMPQBlock); + ha->pHeader->dwBlockTableSize = ha->dwMaxFileCount; + ha->dwFileTableSize = ha->dwMaxFileCount; + } + +// DumpFileTable(ha->pFileTable, ha->dwFileTableSize); + + // Free the translation table + STORM_FREE(DefragmentTable); + } + + return ERROR_SUCCESS; +} + +static TMPQHash * TranslateHashTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize) +{ + TMPQHash * pHashTable; + size_t HashTableSize; + + // Allocate copy of the hash table + pHashTable = STORM_ALLOC(TMPQHash, ha->pHeader->dwHashTableSize); + if(pHashTable != NULL) + { + // Copy the hash table + HashTableSize = sizeof(TMPQHash) * ha->pHeader->dwHashTableSize; + memcpy(pHashTable, ha->pHashTable, HashTableSize); + + // Give the size to the caller + if(pcbTableSize != NULL) + { + *pcbTableSize = (ULONGLONG)HashTableSize; + } + } + + return pHashTable; +} + +// Also used in SFileGetFileInfo +TMPQBlock * TranslateBlockTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize, + bool * pbNeedHiBlockTable) +{ + TFileEntry * pFileEntry = ha->pFileTable; + TMPQBlock * pBlockTable; + TMPQBlock * pBlock; + DWORD NeedHiBlockTable = 0; + DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize; + + // Allocate copy of the hash table + pBlockTable = pBlock = STORM_ALLOC(TMPQBlock, dwBlockTableSize); + if(pBlockTable != NULL) + { + // Convert the block table + for(DWORD i = 0; i < dwBlockTableSize; i++) + { + NeedHiBlockTable |= (DWORD)(pFileEntry->ByteOffset >> 32); + pBlock->dwFilePos = (DWORD)pFileEntry->ByteOffset; + pBlock->dwFSize = pFileEntry->dwFileSize; + pBlock->dwCSize = pFileEntry->dwCmpSize; + pBlock->dwFlags = pFileEntry->dwFlags; + + pFileEntry++; + pBlock++; + } + + // Give the size to the caller + if(pcbTableSize != NULL) + *pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(TMPQBlock); + + if(pbNeedHiBlockTable != NULL) + *pbNeedHiBlockTable = NeedHiBlockTable ? true : false; + } + + return pBlockTable; +} + +static USHORT * TranslateHiBlockTable( + TMPQArchive * ha, + ULONGLONG * pcbTableSize) +{ + TFileEntry * pFileEntry = ha->pFileTable; + USHORT * pHiBlockTable; + USHORT * pHiBlock; + DWORD dwBlockTableSize = ha->pHeader->dwBlockTableSize; + + // Allocate copy of the hash table + pHiBlockTable = pHiBlock = STORM_ALLOC(USHORT, dwBlockTableSize); + if(pHiBlockTable != NULL) + { + // Copy the block table + for(DWORD i = 0; i < dwBlockTableSize; i++) + pHiBlock[i] = (USHORT)(pFileEntry[i].ByteOffset >> 0x20); + + // Give the size to the caller + if(pcbTableSize != NULL) + *pcbTableSize = (ULONGLONG)dwBlockTableSize * sizeof(USHORT); + } + + return pHiBlockTable; +} + +//----------------------------------------------------------------------------- +// General EXT table functions + +TMPQExtHeader * LoadExtTable( + TMPQArchive * ha, + ULONGLONG ByteOffset, + size_t Size, + DWORD dwSignature, + DWORD dwKey) +{ + TMPQExtHeader * pCompressed = NULL; // Compressed table + TMPQExtHeader * pExtTable = NULL; // Uncompressed table + + // Do nothing if the size is zero + if(ByteOffset != 0 && Size != 0) + { + // Allocate size for the compressed table + pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, Size); + if(pExtTable != NULL) + { + // Load the table from the MPQ + ByteOffset += ha->MpqPos; + if(!FileStream_Read(ha->pStream, &ByteOffset, pExtTable, (DWORD)Size)) + { + STORM_FREE(pExtTable); + return NULL; + } + + // Swap the ext table header + BSWAP_ARRAY32_UNSIGNED(pExtTable, sizeof(TMPQExtHeader)); + if(pExtTable->dwSignature != dwSignature) + { + STORM_FREE(pExtTable); + return NULL; + } + + // Decrypt the block + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + DecryptMpqBlock(pExtTable + 1, (DWORD)(Size - sizeof(TMPQExtHeader)), dwKey); + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + + // If the table is compressed, decompress it + if((pExtTable->dwDataSize + sizeof(TMPQExtHeader)) > Size) + { + pCompressed = pExtTable; + pExtTable = (TMPQExtHeader *)STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + pCompressed->dwDataSize); + if(pExtTable != NULL) + { + int cbOutBuffer = (int)pCompressed->dwDataSize; + int cbInBuffer = (int)Size; + + // Decompress the extended table + pExtTable->dwSignature = pCompressed->dwSignature; + pExtTable->dwVersion = pCompressed->dwVersion; + pExtTable->dwDataSize = pCompressed->dwDataSize; + if(!SCompDecompress2(pExtTable + 1, &cbOutBuffer, pCompressed + 1, cbInBuffer)) + { + STORM_FREE(pExtTable); + pExtTable = NULL; + } + } + + // Free the compressed block + STORM_FREE(pCompressed); + } + } + } + + // Return the decompressed table to the caller + return pExtTable; +} + +static int SaveMpqTable( + TMPQArchive * ha, + void * pMpqTable, + ULONGLONG ByteOffset, + size_t Size, + unsigned char * md5, + DWORD dwKey, + bool bCompress) +{ + ULONGLONG FileOffset; + void * pCompressed = NULL; + int nError = ERROR_SUCCESS; + + // Do we have to compress the table? + if(bCompress) + { + int cbOutBuffer = (int)Size; + int cbInBuffer = (int)Size; + + // Allocate extra space for compressed table + pCompressed = STORM_ALLOC(BYTE, Size); + if(pCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Compress the table + SCompCompress(pCompressed, &cbOutBuffer, pMpqTable, cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0); + + // If the compression failed, revert it. Otherwise, swap the tables + if(cbOutBuffer >= cbInBuffer) + { + STORM_FREE(pCompressed); + pCompressed = NULL; + } + else + { + pMpqTable = pCompressed; + } + } + + // Encrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + EncryptMpqBlock(pMpqTable, (DWORD)Size, dwKey); + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + } + + // Calculate the MD5 + if(md5 != NULL) + { + CalculateDataBlockHash(pMpqTable, (DWORD)Size, md5); + } + + // Save the table to the MPQ + BSWAP_ARRAY32_UNSIGNED(pMpqTable, Size); + FileOffset = ha->MpqPos + ByteOffset; + if(!FileStream_Write(ha->pStream, &FileOffset, pMpqTable, (DWORD)Size)) + nError = GetLastError(); + + // Free the compressed table, if any + if(pCompressed != NULL) + STORM_FREE(pCompressed); + return nError; +} + +static int SaveExtTable( + TMPQArchive * ha, + TMPQExtHeader * pExtTable, + ULONGLONG ByteOffset, + DWORD dwTableSize, + unsigned char * md5, + DWORD dwKey, + bool bCompress, + LPDWORD pcbTotalSize) +{ + ULONGLONG FileOffset; + TMPQExtHeader * pCompressed = NULL; + DWORD cbTotalSize = 0; + int nError = ERROR_SUCCESS; + + // Do we have to compress the table? + if(bCompress) + { + int cbOutBuffer = (int)dwTableSize; + int cbInBuffer = (int)dwTableSize; + + // Allocate extra space for compressed table + pCompressed = (TMPQExtHeader *)STORM_ALLOC(BYTE, dwTableSize); + if(pCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Compress the table + pCompressed->dwSignature = pExtTable->dwSignature; + pCompressed->dwVersion = pExtTable->dwVersion; + pCompressed->dwDataSize = pExtTable->dwDataSize; + SCompCompress((pCompressed + 1), &cbOutBuffer, (pExtTable + 1), cbInBuffer, MPQ_COMPRESSION_ZLIB, 0, 0); + + // If the compression failed, revert it. Otherwise, swap the tables + if(cbOutBuffer >= cbInBuffer) + { + STORM_FREE(pCompressed); + pCompressed = NULL; + } + else + { + pExtTable = pCompressed; + } + } + + // Encrypt the table + if(dwKey != 0) + { + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + EncryptMpqBlock(pExtTable + 1, (DWORD)(dwTableSize - sizeof(TMPQExtHeader)), dwKey); + BSWAP_ARRAY32_UNSIGNED(pExtTable + 1, pExtTable->dwDataSize); + } + + // Calculate the MD5 of the table after + if(md5 != NULL) + { + CalculateDataBlockHash(pExtTable, dwTableSize, md5); + } + + // Save the table to the MPQ + FileOffset = ha->MpqPos + ByteOffset; + if(FileStream_Write(ha->pStream, &FileOffset, pExtTable, dwTableSize)) + cbTotalSize += dwTableSize; + else + nError = GetLastError(); + + // We have to write raw data MD5 + if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0) + { + nError = WriteMemDataMD5(ha->pStream, + FileOffset, + pExtTable, + dwTableSize, + ha->pHeader->dwRawChunkSize, + &cbTotalSize); + } + + // Give the total written size, if needed + if(pcbTotalSize != NULL) + *pcbTotalSize = cbTotalSize; + + // Free the compressed table, if any + if(pCompressed != NULL) + STORM_FREE(pCompressed); + return nError; +} + +//----------------------------------------------------------------------------- +// Support for HET table + +static void CreateHetHeader( + TMPQHetTable * pHetTable, + TMPQHetHeader * pHetHeader) +{ + // Fill the common header + pHetHeader->ExtHdr.dwSignature = HET_TABLE_SIGNATURE; + pHetHeader->ExtHdr.dwVersion = 1; + pHetHeader->ExtHdr.dwDataSize = 0; + + // Fill the HET header + pHetHeader->dwEntryCount = pHetTable->dwEntryCount; + pHetHeader->dwTotalCount = pHetTable->dwTotalCount; + pHetHeader->dwNameHashBitSize = pHetTable->dwNameHashBitSize; + pHetHeader->dwIndexSizeTotal = pHetTable->dwIndexSizeTotal; + pHetHeader->dwIndexSizeExtra = pHetTable->dwIndexSizeExtra; + pHetHeader->dwIndexSize = pHetTable->dwIndexSize; + pHetHeader->dwIndexTableSize = ((pHetHeader->dwIndexSizeTotal * pHetTable->dwTotalCount) + 7) / 8; + + // Calculate the total size needed for holding HET table + pHetHeader->ExtHdr.dwDataSize = + pHetHeader->dwTableSize = sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + + pHetHeader->dwTotalCount + + pHetHeader->dwIndexTableSize; +} + +TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwNameHashBitSize, LPBYTE pbSrcData) +{ + TMPQHetTable * pHetTable; + + pHetTable = STORM_ALLOC(TMPQHetTable, 1); + if(pHetTable != NULL) + { + // Zero the HET table + memset(pHetTable, 0, sizeof(TMPQHetTable)); + + // Hash sizes less than 0x40 bits are not tested + assert(dwNameHashBitSize == 0x40); + + // Calculate masks + pHetTable->AndMask64 = ((dwNameHashBitSize != 0x40) ? ((ULONGLONG)1 << dwNameHashBitSize) : 0) - 1; + pHetTable->OrMask64 = (ULONGLONG)1 << (dwNameHashBitSize - 1); + + // If the total count is not entered, use default + if(dwTotalCount == 0) + dwTotalCount = (dwEntryCount * 4) / 3; + + // Store the HET table parameters + pHetTable->dwEntryCount = dwEntryCount; + pHetTable->dwTotalCount = dwTotalCount; + pHetTable->dwNameHashBitSize = dwNameHashBitSize; + pHetTable->dwIndexSizeTotal = GetNecessaryBitCount(dwEntryCount); + pHetTable->dwIndexSizeExtra = 0; + pHetTable->dwIndexSize = pHetTable->dwIndexSizeTotal; + + // Allocate array of hashes + pHetTable->pNameHashes = STORM_ALLOC(BYTE, dwTotalCount); + if(pHetTable->pNameHashes != NULL) + { + // Make sure the data are initialized + memset(pHetTable->pNameHashes, 0, dwTotalCount); + + // Allocate the bit array for file indexes + pHetTable->pBetIndexes = CreateBitArray(dwTotalCount * pHetTable->dwIndexSizeTotal, 0xFF); + if(pHetTable->pBetIndexes != NULL) + { + // Initialize the HET table from the source data (if given) + if(pbSrcData != NULL) + { + // Copy the name hashes + memcpy(pHetTable->pNameHashes, pbSrcData, dwTotalCount); + + // Copy the file indexes + memcpy(pHetTable->pBetIndexes->Elements, pbSrcData + dwTotalCount, pHetTable->pBetIndexes->NumberOfBytes); + } + + // Return the result HET table + return pHetTable; + } + + // Free the name hashes + STORM_FREE(pHetTable->pNameHashes); + } + + STORM_FREE(pHetTable); + } + + // Failed + return NULL; +} + +static int InsertHetEntry(TMPQHetTable * pHetTable, ULONGLONG FileNameHash, DWORD dwFileIndex) +{ + DWORD StartIndex; + DWORD Index; + BYTE NameHash1; + + // Get the start index and the high 8 bits of the name hash + StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount); + NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8)); + + // Find a place where to put it + for(;;) + { + // Did we find a free HET entry? + if(pHetTable->pNameHashes[Index] == HET_ENTRY_FREE) + { + // Set the entry in the name hash table + pHetTable->pNameHashes[Index] = NameHash1; + + // Set the entry in the file index table + SetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * Index, + pHetTable->dwIndexSize, + &dwFileIndex, + 4); + return ERROR_SUCCESS; + } + + // Move to the next entry in the HET table + // If we came to the start index again, we are done + Index = (Index + 1) % pHetTable->dwTotalCount; + if(Index == StartIndex) + break; + } + + // No space in the HET table. Should never happen, + // because the HET table is created according to the number of files + assert(false); + return ERROR_DISK_FULL; +} + +static TMPQHetTable * TranslateHetTable(TMPQHetHeader * pHetHeader) +{ + TMPQHetTable * pHetTable = NULL; + LPBYTE pbSrcData = (LPBYTE)(pHetHeader + 1); + + // Sanity check + assert(pHetHeader->ExtHdr.dwSignature == HET_TABLE_SIGNATURE); + assert(pHetHeader->ExtHdr.dwVersion == 1); + + // Verify size of the HET table + if(pHetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader))) + { + // Verify the size of the table in the header + if(pHetHeader->dwTableSize == pHetHeader->ExtHdr.dwDataSize) + { + // The size of the HET table must be sum of header, hash and index table size + assert((sizeof(TMPQHetHeader) - sizeof(TMPQExtHeader) + pHetHeader->dwTotalCount + pHetHeader->dwIndexTableSize) == pHetHeader->dwTableSize); + + // So far, all MPQs with HET Table have had total number of entries equal to 4/3 of file count + // Exception: "2010 - Starcraft II\!maps\Tya's Zerg Defense (unprotected).SC2Map" +// assert(((pHetHeader->dwEntryCount * 4) / 3) == pHetHeader->dwTotalCount); + + // The size of one index is predictable as well + assert(GetNecessaryBitCount(pHetHeader->dwEntryCount) == pHetHeader->dwIndexSizeTotal); + + // The size of index table (in entries) is expected + // to be the same like the hash table size (in bytes) + assert(((pHetHeader->dwTotalCount * pHetHeader->dwIndexSizeTotal) + 7) / 8 == pHetHeader->dwIndexTableSize); + + // Create translated table + pHetTable = CreateHetTable(pHetHeader->dwEntryCount, pHetHeader->dwTotalCount, pHetHeader->dwNameHashBitSize, pbSrcData); + if(pHetTable != NULL) + { + // Now the sizes in the hash table should be already set + assert(pHetTable->dwEntryCount == pHetHeader->dwEntryCount); + assert(pHetTable->dwTotalCount == pHetHeader->dwTotalCount); + assert(pHetTable->dwIndexSizeTotal == pHetHeader->dwIndexSizeTotal); + + // Copy the missing variables + pHetTable->dwIndexSizeExtra = pHetHeader->dwIndexSizeExtra; + pHetTable->dwIndexSize = pHetHeader->dwIndexSize; + } + } + } + + return pHetTable; +} + +static TMPQExtHeader * TranslateHetTable(TMPQHetTable * pHetTable, ULONGLONG * pcbHetTable) +{ + TMPQHetHeader * pHetHeader = NULL; + TMPQHetHeader HetHeader; + LPBYTE pbLinearTable = NULL; + LPBYTE pbTrgData; + + // Prepare header of the HET table + CreateHetHeader(pHetTable, &HetHeader); + + // Allocate space for the linear table + pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + HetHeader.dwTableSize); + if(pbLinearTable != NULL) + { + // Copy the table header + pHetHeader = (TMPQHetHeader *)pbLinearTable; + memcpy(pHetHeader, &HetHeader, sizeof(TMPQHetHeader)); + pbTrgData = (LPBYTE)(pHetHeader + 1); + + // Copy the array of name hashes + memcpy(pbTrgData, pHetTable->pNameHashes, pHetTable->dwTotalCount); + pbTrgData += pHetTable->dwTotalCount; + + // Copy the bit array of BET indexes + memcpy(pbTrgData, pHetTable->pBetIndexes->Elements, HetHeader.dwIndexTableSize); + + // Calculate the total size of the table, including the TMPQExtHeader + if(pcbHetTable != NULL) + { + *pcbHetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + HetHeader.dwTableSize); + } + } + + // Keep Coverity happy + assert((TMPQExtHeader *)&pHetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable); + return (TMPQExtHeader *)pbLinearTable; +} + +static DWORD GetFileIndex_Het(TMPQArchive * ha, const char * szFileName) +{ + TMPQHetTable * pHetTable = ha->pHetTable; + ULONGLONG FileNameHash; + DWORD StartIndex; + DWORD Index; + BYTE NameHash1; // Upper 8 bits of the masked file name hash + + // If there are no entries in the HET table, do nothing + if(pHetTable->dwEntryCount == 0) + return HASH_ENTRY_FREE; + + // Do nothing if the MPQ has no HET table + assert(ha->pHetTable != NULL); + + // Calculate 64-bit hash of the file name + FileNameHash = (HashStringJenkins(szFileName) & pHetTable->AndMask64) | pHetTable->OrMask64; + + // Split the file name hash into two parts: + // NameHash1: The highest 8 bits of the name hash + // NameHash2: File name hash limited to hash size + // Note: Our file table contains full name hash, no need to cut the high 8 bits before comparison + NameHash1 = (BYTE)(FileNameHash >> (pHetTable->dwNameHashBitSize - 8)); + + // Calculate the starting index to the hash table + StartIndex = Index = (DWORD)(FileNameHash % pHetTable->dwTotalCount); + + // Go through HET table until we find a terminator + while(pHetTable->pNameHashes[Index] != HET_ENTRY_FREE) + { + // Did we find a match ? + if(pHetTable->pNameHashes[Index] == NameHash1) + { + DWORD dwFileIndex = 0; + + // Get the file index + GetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * Index, + pHetTable->dwIndexSize, + &dwFileIndex, + sizeof(DWORD)); + + // Verify the FileNameHash against the entry in the table of name hashes + if(dwFileIndex <= ha->dwFileTableSize && ha->pFileTable[dwFileIndex].FileNameHash == FileNameHash) + { + return dwFileIndex; + } + } + + // Move to the next entry in the HET table + // If we came to the start index again, we are done + Index = (Index + 1) % pHetTable->dwTotalCount; + if(Index == StartIndex) + break; + } + + // File not found + return HASH_ENTRY_FREE; +} + +void FreeHetTable(TMPQHetTable * pHetTable) +{ + if(pHetTable != NULL) + { + if(pHetTable->pNameHashes != NULL) + STORM_FREE(pHetTable->pNameHashes); + if(pHetTable->pBetIndexes != NULL) + STORM_FREE(pHetTable->pBetIndexes); + + STORM_FREE(pHetTable); + } +} + +//----------------------------------------------------------------------------- +// Support for BET table + +static void CreateBetHeader( + TMPQArchive * ha, + TMPQBetHeader * pBetHeader) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + ULONGLONG MaxByteOffset = 0; + DWORD FlagArray[MAX_FLAG_INDEX]; + DWORD dwMaxFlagIndex = 0; + DWORD dwMaxFileSize = 0; + DWORD dwMaxCmpSize = 0; + DWORD dwFlagIndex; + + // Initialize array of flag combinations + InitFileFlagArray(FlagArray); + + // Fill the common header + pBetHeader->ExtHdr.dwSignature = BET_TABLE_SIGNATURE; + pBetHeader->ExtHdr.dwVersion = 1; + pBetHeader->ExtHdr.dwDataSize = 0; + + // Get the maximum values for the BET table + pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // + // Note: Deleted files must be counted as well + // + + // Highest file position in the MPQ + if(pFileEntry->ByteOffset > MaxByteOffset) + MaxByteOffset = pFileEntry->ByteOffset; + + // Biggest file size + if(pFileEntry->dwFileSize > dwMaxFileSize) + dwMaxFileSize = pFileEntry->dwFileSize; + + // Biggest compressed size + if(pFileEntry->dwCmpSize > dwMaxCmpSize) + dwMaxCmpSize = pFileEntry->dwCmpSize; + + // Check if this flag was there before + dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags); + if(dwFlagIndex > dwMaxFlagIndex) + dwMaxFlagIndex = dwFlagIndex; + } + + // Now save bit count for every piece of file information + pBetHeader->dwBitIndex_FilePos = 0; + pBetHeader->dwBitCount_FilePos = GetNecessaryBitCount(MaxByteOffset); + + pBetHeader->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FilePos + pBetHeader->dwBitCount_FilePos; + pBetHeader->dwBitCount_FileSize = GetNecessaryBitCount(dwMaxFileSize); + + pBetHeader->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_FileSize + pBetHeader->dwBitCount_FileSize; + pBetHeader->dwBitCount_CmpSize = GetNecessaryBitCount(dwMaxCmpSize); + + pBetHeader->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_CmpSize + pBetHeader->dwBitCount_CmpSize; + pBetHeader->dwBitCount_FlagIndex = GetNecessaryBitCount(dwMaxFlagIndex + 1); + + pBetHeader->dwBitIndex_Unknown = pBetHeader->dwBitIndex_FlagIndex + pBetHeader->dwBitCount_FlagIndex; + pBetHeader->dwBitCount_Unknown = 0; + + // Calculate the total size of one entry + pBetHeader->dwTableEntrySize = pBetHeader->dwBitCount_FilePos + + pBetHeader->dwBitCount_FileSize + + pBetHeader->dwBitCount_CmpSize + + pBetHeader->dwBitCount_FlagIndex + + pBetHeader->dwBitCount_Unknown; + + // Save the file count and flag count + pBetHeader->dwEntryCount = ha->pHeader->dwBlockTableSize; + pBetHeader->dwFlagCount = dwMaxFlagIndex + 1; + pBetHeader->dwUnknown08 = 0x10; + + // Save the total size of the BET hash + pBetHeader->dwBitTotal_NameHash2 = ha->pHetTable->dwNameHashBitSize - 0x08; + pBetHeader->dwBitExtra_NameHash2 = 0; + pBetHeader->dwBitCount_NameHash2 = pBetHeader->dwBitTotal_NameHash2; + pBetHeader->dwNameHashArraySize = ((pBetHeader->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount) + 7) / 8; + + // Save the total table size + pBetHeader->ExtHdr.dwDataSize = + pBetHeader->dwTableSize = sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader) + + pBetHeader->dwFlagCount * sizeof(DWORD) + + ((pBetHeader->dwTableEntrySize * pBetHeader->dwEntryCount) + 7) / 8 + + pBetHeader->dwNameHashArraySize; +} + +TMPQBetTable * CreateBetTable(DWORD dwEntryCount) +{ + TMPQBetTable * pBetTable; + + // Allocate BET table + pBetTable = STORM_ALLOC(TMPQBetTable, 1); + if(pBetTable != NULL) + { + memset(pBetTable, 0, sizeof(TMPQBetTable)); + pBetTable->dwEntryCount = dwEntryCount; + } + + return pBetTable; +} + +static TMPQBetTable * TranslateBetTable( + TMPQArchive * ha, + TMPQBetHeader * pBetHeader) +{ + TMPQBetTable * pBetTable = NULL; + LPBYTE pbSrcData = (LPBYTE)(pBetHeader + 1); + DWORD LengthInBytes = 0; + + // Sanity check + assert(pBetHeader->ExtHdr.dwSignature == BET_TABLE_SIGNATURE); + assert(pBetHeader->ExtHdr.dwVersion == 1); + assert(ha->pHetTable != NULL); + ha = ha; + + // Verify size of the HET table + if(pBetHeader->ExtHdr.dwDataSize >= (sizeof(TMPQBetHeader) - sizeof(TMPQExtHeader))) + { + // Verify the size of the table in the header + if(pBetHeader->dwTableSize == pBetHeader->ExtHdr.dwDataSize) + { + // The number of entries in the BET table must be the same like number of entries in the block table + assert(pBetHeader->dwEntryCount == ha->pHeader->dwBlockTableSize); + assert(pBetHeader->dwEntryCount <= ha->dwMaxFileCount); + + // The number of entries in the BET table must be the same like number of entries in the HET table + // Note that if it's not, it is not a problem + //assert(pBetHeader->dwEntryCount == ha->pHetTable->dwEntryCount); + + // Create translated table + pBetTable = CreateBetTable(pBetHeader->dwEntryCount); + if(pBetTable != NULL) + { + // Copy the variables from the header to the BetTable + pBetTable->dwTableEntrySize = pBetHeader->dwTableEntrySize; + pBetTable->dwBitIndex_FilePos = pBetHeader->dwBitIndex_FilePos; + pBetTable->dwBitIndex_FileSize = pBetHeader->dwBitIndex_FileSize; + pBetTable->dwBitIndex_CmpSize = pBetHeader->dwBitIndex_CmpSize; + pBetTable->dwBitIndex_FlagIndex = pBetHeader->dwBitIndex_FlagIndex; + pBetTable->dwBitIndex_Unknown = pBetHeader->dwBitIndex_Unknown; + pBetTable->dwBitCount_FilePos = pBetHeader->dwBitCount_FilePos; + pBetTable->dwBitCount_FileSize = pBetHeader->dwBitCount_FileSize; + pBetTable->dwBitCount_CmpSize = pBetHeader->dwBitCount_CmpSize; + pBetTable->dwBitCount_FlagIndex = pBetHeader->dwBitCount_FlagIndex; + pBetTable->dwBitCount_Unknown = pBetHeader->dwBitCount_Unknown; + + // Since we don't know what the "unknown" is, we'll assert when it's zero + assert(pBetTable->dwBitCount_Unknown == 0); + + // Allocate array for flags + if(pBetHeader->dwFlagCount != 0) + { + // Allocate array for file flags and load it + pBetTable->pFileFlags = STORM_ALLOC(DWORD, pBetHeader->dwFlagCount); + if(pBetTable->pFileFlags != NULL) + { + LengthInBytes = pBetHeader->dwFlagCount * sizeof(DWORD); + memcpy(pBetTable->pFileFlags, pbSrcData, LengthInBytes); + BSWAP_ARRAY32_UNSIGNED(pBetTable->pFileFlags, LengthInBytes); + pbSrcData += LengthInBytes; + } + + // Save the number of flags + pBetTable->dwFlagCount = pBetHeader->dwFlagCount; + } + + // Load the bit-based file table + pBetTable->pFileTable = CreateBitArray(pBetTable->dwTableEntrySize * pBetHeader->dwEntryCount, 0); + if(pBetTable->pFileTable != NULL) + { + LengthInBytes = (pBetTable->pFileTable->NumberOfBits + 7) / 8; + memcpy(pBetTable->pFileTable->Elements, pbSrcData, LengthInBytes); + pbSrcData += LengthInBytes; + } + + // Fill the sizes of BET hash + pBetTable->dwBitTotal_NameHash2 = pBetHeader->dwBitTotal_NameHash2; + pBetTable->dwBitExtra_NameHash2 = pBetHeader->dwBitExtra_NameHash2; + pBetTable->dwBitCount_NameHash2 = pBetHeader->dwBitCount_NameHash2; + + // Create and load the array of BET hashes + pBetTable->pNameHashes = CreateBitArray(pBetTable->dwBitTotal_NameHash2 * pBetHeader->dwEntryCount, 0); + if(pBetTable->pNameHashes != NULL) + { + LengthInBytes = (pBetTable->pNameHashes->NumberOfBits + 7) / 8; + memcpy(pBetTable->pNameHashes->Elements, pbSrcData, LengthInBytes); +// pbSrcData += LengthInBytes; + } + + // Dump both tables +// DumpHetAndBetTable(ha->pHetTable, pBetTable); + } + } + } + + return pBetTable; +} + +TMPQExtHeader * TranslateBetTable( + TMPQArchive * ha, + ULONGLONG * pcbBetTable) +{ + TMPQBetHeader * pBetHeader = NULL; + TMPQBetHeader BetHeader; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + TBitArray * pBitArray = NULL; + LPBYTE pbLinearTable = NULL; + LPBYTE pbTrgData; + DWORD LengthInBytes; + DWORD FlagArray[MAX_FLAG_INDEX]; + + // Calculate the bit sizes of various entries + InitFileFlagArray(FlagArray); + CreateBetHeader(ha, &BetHeader); + + // Allocate space + pbLinearTable = STORM_ALLOC(BYTE, sizeof(TMPQExtHeader) + BetHeader.dwTableSize); + if(pbLinearTable != NULL) + { + // Copy the BET header to the linear buffer + pBetHeader = (TMPQBetHeader *)pbLinearTable; + memcpy(pBetHeader, &BetHeader, sizeof(TMPQBetHeader)); + pbTrgData = (LPBYTE)(pBetHeader + 1); + + // Save the bit-based block table + pBitArray = CreateBitArray(BetHeader.dwEntryCount * BetHeader.dwTableEntrySize, 0); + if(pBitArray != NULL) + { + DWORD dwFlagIndex = 0; + DWORD nBitOffset = 0; + + // Construct the bit-based file table + pFileTableEnd = ha->pFileTable + BetHeader.dwEntryCount; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // + // Note: Missing files must be included as well + // + + // Save the byte offset + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FilePos, + BetHeader.dwBitCount_FilePos, + &pFileEntry->ByteOffset, + 8); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FileSize, + BetHeader.dwBitCount_FileSize, + &pFileEntry->dwFileSize, + 4); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_CmpSize, + BetHeader.dwBitCount_CmpSize, + &pFileEntry->dwCmpSize, + 4); + + // Save the flag index + dwFlagIndex = GetFileFlagIndex(FlagArray, pFileEntry->dwFlags); + SetBits(pBitArray, nBitOffset + BetHeader.dwBitIndex_FlagIndex, + BetHeader.dwBitCount_FlagIndex, + &dwFlagIndex, + 4); + + // Move the bit offset + nBitOffset += BetHeader.dwTableEntrySize; + } + + // Write the array of flags + LengthInBytes = BetHeader.dwFlagCount * sizeof(DWORD); + memcpy(pbTrgData, FlagArray, LengthInBytes); + BSWAP_ARRAY32_UNSIGNED(pbTrgData, LengthInBytes); + pbTrgData += LengthInBytes; + + // Write the bit-based block table + LengthInBytes = (pBitArray->NumberOfBits + 7) / 8; + memcpy(pbTrgData, pBitArray->Elements, LengthInBytes); + pbTrgData += LengthInBytes; + + // Free the bit array + STORM_FREE(pBitArray); + } + + // Create bit array for name hashes + pBitArray = CreateBitArray(BetHeader.dwBitTotal_NameHash2 * BetHeader.dwEntryCount, 0); + if(pBitArray != NULL) + { + DWORD dwFileIndex = 0; + + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Insert the name hash to the bit array + SetBits(pBitArray, BetHeader.dwBitTotal_NameHash2 * dwFileIndex, + BetHeader.dwBitCount_NameHash2, + &pFileEntry->FileNameHash, + 8); + + assert(dwFileIndex < BetHeader.dwEntryCount); + dwFileIndex++; + } + + // Write the array of BET hashes + LengthInBytes = (pBitArray->NumberOfBits + 7) / 8; + memcpy(pbTrgData, pBitArray->Elements, LengthInBytes); +// pbTrgData += LengthInBytes; + + // Free the bit array + STORM_FREE(pBitArray); + } + + // Write the size of the BET table in the MPQ + if(pcbBetTable != NULL) + { + *pcbBetTable = (ULONGLONG)(sizeof(TMPQExtHeader) + BetHeader.dwTableSize); + } + } + + // Keep Coverity happy + assert((TMPQExtHeader *)&pBetHeader->ExtHdr == (TMPQExtHeader *)pbLinearTable); + return (TMPQExtHeader *)pbLinearTable; +} + +void FreeBetTable(TMPQBetTable * pBetTable) +{ + if(pBetTable != NULL) + { + if(pBetTable->pFileTable != NULL) + STORM_FREE(pBetTable->pFileTable); + if(pBetTable->pFileFlags != NULL) + STORM_FREE(pBetTable->pFileFlags); + if(pBetTable->pNameHashes != NULL) + STORM_FREE(pBetTable->pNameHashes); + + STORM_FREE(pBetTable); + } +} + +//----------------------------------------------------------------------------- +// Support for file table + +TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TMPQHash * pHash; + DWORD dwFileIndex; + + // First, we have to search the classic hash table + // This is because on renaming, deleting, or changing locale, + // we will need the pointer to hash table entry + if(ha->pHashTable != NULL) + { + pHash = GetHashEntryLocale(ha, szFileName, lcLocale, 0); + if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + return ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + } + } + + // If we have HET table in the MPQ, try to find the file in HET table + if(ha->pHetTable != NULL) + { + dwFileIndex = GetFileIndex_Het(ha, szFileName); + if(dwFileIndex != HASH_ENTRY_FREE) + return ha->pFileTable + dwFileIndex; + } + + // Not found + return NULL; +} + +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale) +{ + return GetFileEntryLocale2(ha, szFileName, lcLocale, NULL); +} + +TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TMPQHash * pHash; + DWORD dwFileIndex; + + // If the hash table is present, find the entry from hash table + if(ha->pHashTable != NULL) + { + pHash = GetHashEntryExact(ha, szFileName, lcLocale); + if(pHash != NULL && MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + return ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + } + } + + // If we have HET table in the MPQ, try to find the file in HET table + if(ha->pHetTable != NULL) + { + dwFileIndex = GetFileIndex_Het(ha, szFileName); + if(dwFileIndex != HASH_ENTRY_FREE) + { + if(PtrHashIndex != NULL) + PtrHashIndex[0] = HASH_ENTRY_FREE; + return ha->pFileTable + dwFileIndex; + } + } + + // Not found + return NULL; +} + +void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName) +{ + // Sanity check + assert(pFileEntry != NULL); + + // If the file name is pseudo file name, free it at this point + if(IsPseudoFileName(pFileEntry->szFileName, NULL)) + { + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + } + + // Only allocate new file name if it's not there yet + if(pFileEntry->szFileName == NULL) + { + pFileEntry->szFileName = STORM_ALLOC(char, strlen(szFileName) + 1); + if(pFileEntry->szFileName != NULL) + strcpy(pFileEntry->szFileName, szFileName); + } + + // We also need to create the file name hash + if(ha->pHetTable != NULL) + { + ULONGLONG AndMask64 = ha->pHetTable->AndMask64; + ULONGLONG OrMask64 = ha->pHetTable->OrMask64; + + pFileEntry->FileNameHash = (HashStringJenkins(szFileName) & AndMask64) | OrMask64; + } +} + +TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFreeEntry = NULL; + TFileEntry * pFileEntry; + TMPQHash * pHash = NULL; + DWORD dwReservedFiles = ha->dwReservedFiles; + DWORD dwFreeCount = 0; + + // Sanity check: File table size must be greater or equal to max file count + assert(ha->dwFileTableSize >= ha->dwMaxFileCount); + + // If we are saving MPQ tables, we don't tale number of reserved files into account + dwReservedFiles = (ha->dwFlags & MPQ_FLAG_SAVING_TABLES) ? 0 : ha->dwReservedFiles; + + // Now find a free entry in the file table. + // Note that in the case when free entries are in the middle, + // we need to use these + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + // Remember the first free entry + if(pFreeEntry == NULL) + pFreeEntry = pFileEntry; + dwFreeCount++; + + // If the number of free items is greater than number + // of reserved items, We can add the file + if(dwFreeCount > dwReservedFiles) + break; + } + } + + // If the total number of free entries is less than number of reserved files, + // we cannot add the file to the archive + if(pFreeEntry == NULL || dwFreeCount <= dwReservedFiles) + return NULL; + + // Initialize the file entry and set its file name + memset(pFreeEntry, 0, sizeof(TFileEntry)); + AllocateFileName(ha, pFreeEntry, szFileName); + + // If the archive has a hash table, we need to first free entry there + if(ha->pHashTable != NULL) + { + // Make sure that the entry is not there yet + assert(GetHashEntryExact(ha, szFileName, lcLocale) == NULL); + + // Find a free hash table entry for the name + pHash = AllocateHashEntry(ha, pFreeEntry, lcLocale); + if(pHash == NULL) + return NULL; + + // Set the file index to the hash table + pHash->dwBlockIndex = (DWORD)(pFreeEntry - ha->pFileTable); + PtrHashIndex[0] = (DWORD)(pHash - ha->pHashTable); + } + + // If the archive has a HET table, just do some checks + // Note: Don't bother modifying the HET table. It will be rebuilt from scratch after, anyway + if(ha->pHetTable != NULL) + { + assert(GetFileIndex_Het(ha, szFileName) == HASH_ENTRY_FREE); + } + + // Return the free table entry + return pFreeEntry; +} + +int RenameFileEntry( + TMPQArchive * ha, + TMPQFile * hf, + const char * szNewFileName) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + TMPQHash * pHashEntry = hf->pHashEntry; + LCID lcLocale = 0; + + // If the archive hash hash table, we need to free the hash table entry + if(ha->pHashTable != NULL) + { + // The file must have hash table entry assigned + // Will exit if there are multiple HASH entries pointing to the same file entry + if(pHashEntry == NULL) + return ERROR_NOT_SUPPORTED; + + // Save the locale + lcLocale = pHashEntry->lcLocale; + + // Mark the hash table entry as deleted + pHashEntry->dwName1 = 0xFFFFFFFF; + pHashEntry->dwName2 = 0xFFFFFFFF; + pHashEntry->lcLocale = 0xFFFF; + pHashEntry->Platform = 0xFF; + pHashEntry->Reserved = 0xFF; + pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED; + } + + // Free the old file name + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + + // Allocate new file name + AllocateFileName(ha, pFileEntry, szNewFileName); + + // Allocate new hash entry + if(ha->pHashTable != NULL) + { + // Since we freed one hash entry before, this must succeed + hf->pHashEntry = AllocateHashEntry(ha, pFileEntry, lcLocale); + assert(hf->pHashEntry != NULL); + } + + return ERROR_SUCCESS; +} + +int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + TMPQHash * pHashEntry = hf->pHashEntry; + + // If the archive hash hash table, we need to free the hash table entry + if(ha->pHashTable != NULL) + { + // The file must have hash table entry assigned + // Will exit if there are multiple HASH entries pointing to the same file entry + if(pHashEntry == NULL) + return ERROR_NOT_SUPPORTED; + + // Mark the hash table entry as deleted + pHashEntry->dwName1 = 0xFFFFFFFF; + pHashEntry->dwName2 = 0xFFFFFFFF; + pHashEntry->lcLocale = 0xFFFF; + pHashEntry->Platform = 0xFF; + pHashEntry->Reserved = 0xFF; + pHashEntry->dwBlockIndex = HASH_ENTRY_DELETED; + } + + // Free the file name, and set the file entry as deleted + if(pFileEntry->szFileName != NULL) + STORM_FREE(pFileEntry->szFileName); + pFileEntry->szFileName = NULL; + + // + // Don't modify the HET table, because it gets recreated by the caller + // Don't decrement the number of entries in the file table + // Keep Byte Offset, file size, compressed size, CRC32 and MD5 + // Clear the file name hash and the MPQ_FILE_EXISTS bit + // + + pFileEntry->dwFlags &= ~MPQ_FILE_EXISTS; + pFileEntry->FileNameHash = 0; + return ERROR_SUCCESS; +} + +DWORD InvalidateInternalFile(TMPQArchive * ha, const char * szFileName, DWORD dwFlagNone, DWORD dwFlagNew, DWORD dwForceAddTheFile = 0) +{ + TMPQFile * hf = NULL; + DWORD dwFileFlags = MPQ_FILE_DEFAULT_INTERNAL; + int nError = ERROR_FILE_NOT_FOUND; + + // Open the file from the MPQ + if(SFileOpenFileEx((HANDLE)ha, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf)) + { + // Remember the file flags + dwFileFlags = hf->pFileEntry->dwFlags; + + // Delete the file entry + nError = DeleteFileEntry(ha, hf); + if(nError == ERROR_SUCCESS) + dwForceAddTheFile = 1; + + // Close the file + FreeFileHandle(hf); + } + + // Are we going to add the file? + if(dwForceAddTheFile) + { + ha->dwFlags |= dwFlagNew; + ha->dwReservedFiles++; + } + else + { + ha->dwFlags |= dwFlagNone; + dwFileFlags = 0; + } + + // Return the intended file flags + return dwFileFlags; +} + +void InvalidateInternalFiles(TMPQArchive * ha) +{ + // Do nothing if we are in the middle of saving internal files + if(!(ha->dwFlags & MPQ_FLAG_SAVING_TABLES)) + { + // + // We clear the file entries for (listfile), (attributes) and (signature) + // For each internal file cleared, we increment the number + // of reserved entries in the file table. + // + + // Invalidate the (listfile), if not done yet + if((ha->dwFlags & (MPQ_FLAG_LISTFILE_NONE | MPQ_FLAG_LISTFILE_NEW)) == 0) + { + ha->dwFileFlags1 = InvalidateInternalFile(ha, LISTFILE_NAME, MPQ_FLAG_LISTFILE_NONE, MPQ_FLAG_LISTFILE_NEW, (ha->dwFlags & MPQ_FLAG_LISTFILE_FORCE)); + } + + // Invalidate the (attributes), if not done yet + if((ha->dwFlags & (MPQ_FLAG_ATTRIBUTES_NONE | MPQ_FLAG_ATTRIBUTES_NEW)) == 0) + { + ha->dwFileFlags2 = InvalidateInternalFile(ha, ATTRIBUTES_NAME, MPQ_FLAG_ATTRIBUTES_NONE, MPQ_FLAG_ATTRIBUTES_NEW); + } + + // Invalidate the (signature), if not done yet + if((ha->dwFlags & (MPQ_FLAG_SIGNATURE_NONE | MPQ_FLAG_SIGNATURE_NEW)) == 0) + { + ha->dwFileFlags3 = InvalidateInternalFile(ha, SIGNATURE_NAME, MPQ_FLAG_SIGNATURE_NONE, MPQ_FLAG_SIGNATURE_NEW); + } + + // Remember that the MPQ has been changed + ha->dwFlags |= MPQ_FLAG_CHANGED; + } +} + +//----------------------------------------------------------------------------- +// Support for file tables - hash table, block table, hi-block table + +int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize) +{ + TMPQHash * pHashTable; + + // Sanity checks + assert((dwHashTableSize & (dwHashTableSize - 1)) == 0); + assert(ha->pHashTable == NULL); + + // If the required hash table size is zero, don't create anything + if(dwHashTableSize == 0) + dwHashTableSize = HASH_TABLE_SIZE_DEFAULT; + + // Create the hash table + pHashTable = STORM_ALLOC(TMPQHash, dwHashTableSize); + if(pHashTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill it + memset(pHashTable, 0xFF, dwHashTableSize * sizeof(TMPQHash)); + ha->pHeader->dwHashTableSize = dwHashTableSize; + ha->dwMaxFileCount = dwHashTableSize; + ha->pHashTable = pHashTable; + return ERROR_SUCCESS; +} + +static TMPQHash * LoadHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + ULONGLONG ByteOffset; + TMPQHash * pHashTable = NULL; + DWORD dwTableSize; + DWORD dwCmpSize; + bool bHashTableIsCut = false; + + // Note: It is allowed to load hash table if it is at offset 0. + // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x +// if(pHeader->dwHashTablePos == 0 && pHeader->wHashTablePosHi == 0) +// return NULL; + + // If the hash table size is zero, do nothing + if(pHeader->dwHashTableSize == 0) + return NULL; + + // Load the hash table for MPQ variations + switch(ha->dwSubType) + { + case MPQ_SUBTYPE_MPQ: + + // Calculate the position and size of the hash table + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos)); + dwTableSize = pHeader->dwHashTableSize * sizeof(TMPQHash); + dwCmpSize = (DWORD)pHeader->HashTableSize64; + + // Read, decrypt and uncompress the hash table + pHashTable = (TMPQHash *)LoadMpqTable(ha, ByteOffset, dwCmpSize, dwTableSize, MPQ_KEY_HASH_TABLE, &bHashTableIsCut); +// DumpHashTable(pHashTable, pHeader->dwHashTableSize); + + // If the hash table was cut, we can/have to defragment it + if(pHashTable != NULL && bHashTableIsCut) + ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_HASH_TABLE_CUT); + break; + + case MPQ_SUBTYPE_SQP: + pHashTable = LoadSqpHashTable(ha); + break; + + case MPQ_SUBTYPE_MPK: + pHashTable = LoadMpkHashTable(ha); + break; + } + + // Remember the size of the hash table + return pHashTable; +} + +int CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize) +{ + ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + memset(ha->pFileTable, 0x00, sizeof(TFileEntry) * dwFileTableSize); + ha->dwFileTableSize = dwFileTableSize; + return ERROR_SUCCESS; +} + +TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool /* bDontFixEntries */) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable = NULL; + ULONGLONG ByteOffset; + DWORD dwTableSize; + DWORD dwCmpSize; + bool bBlockTableIsCut = false; + + // Note: It is possible that the block table starts at offset 0 + // Example: MPQ_2016_v1_ProtectedMap_HashOffsIsZero.w3x +// if(pHeader->dwBlockTablePos == 0 && pHeader->wBlockTablePosHi == 0) +// return NULL; + + // Do nothing if the block table size is zero + if(pHeader->dwBlockTableSize == 0) + return NULL; + + // Load the block table for MPQ variations + switch(ha->dwSubType) + { + case MPQ_SUBTYPE_MPQ: + + // Calculate byte position of the block table + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos)); + dwTableSize = pHeader->dwBlockTableSize * sizeof(TMPQBlock); + dwCmpSize = (DWORD)pHeader->BlockTableSize64; + + // Read, decrypt and uncompress the block table + pBlockTable = (TMPQBlock * )LoadMpqTable(ha, ByteOffset, dwCmpSize, dwTableSize, MPQ_KEY_BLOCK_TABLE, &bBlockTableIsCut); + + // If the block table was cut, we need to remember it + if(pBlockTable != NULL && bBlockTableIsCut) + ha->dwFlags |= (MPQ_FLAG_MALFORMED | MPQ_FLAG_BLOCK_TABLE_CUT); + break; + + case MPQ_SUBTYPE_SQP: + + pBlockTable = LoadSqpBlockTable(ha); + break; + + case MPQ_SUBTYPE_MPK: + + pBlockTable = LoadMpkBlockTable(ha); + break; + } + + return pBlockTable; +} + +TMPQHetTable * LoadHetTable(TMPQArchive * ha) +{ + TMPQExtHeader * pExtTable; + TMPQHetTable * pHetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + + // If the HET table position is not 0, we expect the table to be present + if(pHeader->HetTablePos64 != 0 && pHeader->HetTableSize64 != 0) + { + // Attempt to load the HET table (Hash Extended Table) + pExtTable = LoadExtTable(ha, pHeader->HetTablePos64, (size_t)pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pExtTable != NULL) + { + // If loading HET table fails, we ignore the result. + pHetTable = TranslateHetTable((TMPQHetHeader *)pExtTable); + STORM_FREE(pExtTable); + } + } + + return pHetTable; +} + +TMPQBetTable * LoadBetTable(TMPQArchive * ha) +{ + TMPQExtHeader * pExtTable; + TMPQBetTable * pBetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + + // If the BET table position is not 0, we expect the table to be present + if(pHeader->BetTablePos64 != 0 && pHeader->BetTableSize64 != 0) + { + // Attempt to load the HET table (Hash Extended Table) + pExtTable = LoadExtTable(ha, pHeader->BetTablePos64, (size_t)pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pExtTable != NULL) + { + // If succeeded, we translate the BET table + // to more readable form + pBetTable = TranslateBetTable(ha, (TMPQBetHeader *)pExtTable); + STORM_FREE(pExtTable); + } + } + + return pBetTable; +} + +int LoadAnyHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + + // If the MPQ archive is empty, don't bother trying to load anything + if(pHeader->dwHashTableSize == 0 && pHeader->HetTableSize64 == 0) + return CreateHashTable(ha, HASH_TABLE_SIZE_DEFAULT); + + // Try to load HET table + if(pHeader->HetTablePos64 != 0) + ha->pHetTable = LoadHetTable(ha); + + // Try to load classic hash table + if(pHeader->dwHashTableSize) + ha->pHashTable = LoadHashTable(ha); + + // At least one of the tables must be present + if(ha->pHetTable == NULL && ha->pHashTable == NULL) + return ERROR_FILE_CORRUPT; + + // Set the maximum file count to the size of the hash table. + // Note: We don't care about HET table limits, because HET table is rebuilt + // after each file add/rename/delete. + ha->dwMaxFileCount = (ha->pHashTable != NULL) ? pHeader->dwHashTableSize : HASH_TABLE_SIZE_MAX; + return ERROR_SUCCESS; +} + +static int BuildFileTable_Classic(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable; + int nError = ERROR_SUCCESS; + + // Sanity checks + assert(ha->pHashTable != NULL); + assert(ha->pFileTable != NULL); + + // If the MPQ has no block table, do nothing + if(pHeader->dwBlockTableSize == 0) + return ERROR_SUCCESS; + assert(ha->dwFileTableSize >= pHeader->dwBlockTableSize); + + // Load the block table + // WARNING! ha->pFileTable can change in the process!! + pBlockTable = (TMPQBlock *)LoadBlockTable(ha); + if(pBlockTable != NULL) + { + nError = BuildFileTableFromBlockTable(ha, pBlockTable); + STORM_FREE(pBlockTable); + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Load the hi-block table + if(nError == ERROR_SUCCESS && pHeader->HiBlockTablePos64 != 0) + { + ULONGLONG ByteOffset; + USHORT * pHiBlockTable = NULL; + DWORD dwTableSize = pHeader->dwBlockTableSize * sizeof(USHORT); + + // Allocate space for the hi-block table + // Note: pHeader->dwBlockTableSize can be zero !!! + pHiBlockTable = STORM_ALLOC(USHORT, pHeader->dwBlockTableSize + 1); + if(pHiBlockTable != NULL) + { + // Load the hi-block table. It is not encrypted, nor compressed + ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64; + if(!FileStream_Read(ha->pStream, &ByteOffset, pHiBlockTable, dwTableSize)) + nError = GetLastError(); + + // Now merge the hi-block table to the file table + if(nError == ERROR_SUCCESS) + { + TFileEntry * pFileEntry = ha->pFileTable; + + // Swap the hi-block table + BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, dwTableSize); + + // Add the high file offset to the base file offset. + for(DWORD i = 0; i < pHeader->dwBlockTableSize; i++, pFileEntry++) + pFileEntry->ByteOffset = MAKE_OFFSET64(pHiBlockTable[i], pFileEntry->ByteOffset); + } + + // Free the hi-block table + STORM_FREE(pHiBlockTable); + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + return nError; +} + +static int BuildFileTable_HetBet(TMPQArchive * ha) +{ + TMPQHetTable * pHetTable = ha->pHetTable; + TMPQBetTable * pBetTable; + TFileEntry * pFileEntry = ha->pFileTable; + TBitArray * pBitArray; + DWORD dwBitPosition = 0; + DWORD i; + int nError = ERROR_FILE_CORRUPT; + + // Load the BET table from the MPQ + pBetTable = LoadBetTable(ha); + if(pBetTable != NULL) + { + // Verify the size of NameHash2 in the BET table. + // It has to be 8 bits less than the information in HET table + if((pBetTable->dwBitCount_NameHash2 + 8) != pHetTable->dwNameHashBitSize) + { + FreeBetTable(pBetTable); + return ERROR_FILE_CORRUPT; + } + + // Step one: Fill the name indexes + for(i = 0; i < pHetTable->dwTotalCount; i++) + { + DWORD dwFileIndex = 0; + + // Is the entry in the HET table occupied? + if(pHetTable->pNameHashes[i] != HET_ENTRY_FREE) + { + // Load the index to the BET table + GetBits(pHetTable->pBetIndexes, pHetTable->dwIndexSizeTotal * i, + pHetTable->dwIndexSize, + &dwFileIndex, + 4); + // Overflow test + if(dwFileIndex < pBetTable->dwEntryCount) + { + ULONGLONG NameHash1 = pHetTable->pNameHashes[i]; + ULONGLONG NameHash2 = 0; + + // Load the BET hash + GetBits(pBetTable->pNameHashes, pBetTable->dwBitTotal_NameHash2 * dwFileIndex, + pBetTable->dwBitCount_NameHash2, + &NameHash2, + 8); + + // Combine both part of the name hash and put it to the file table + pFileEntry = ha->pFileTable + dwFileIndex; + pFileEntry->FileNameHash = (NameHash1 << pBetTable->dwBitCount_NameHash2) | NameHash2; + } + } + } + + // Go through the entire BET table and convert it to the file table. + pFileEntry = ha->pFileTable; + pBitArray = pBetTable->pFileTable; + for(i = 0; i < pBetTable->dwEntryCount; i++) + { + DWORD dwFlagIndex = 0; + + // Read the file position + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FilePos, + pBetTable->dwBitCount_FilePos, + &pFileEntry->ByteOffset, + 8); + + // Read the file size + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FileSize, + pBetTable->dwBitCount_FileSize, + &pFileEntry->dwFileSize, + 4); + + // Read the compressed size + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_CmpSize, + pBetTable->dwBitCount_CmpSize, + &pFileEntry->dwCmpSize, + 4); + + + // Read the flag index + if(pBetTable->dwFlagCount != 0) + { + GetBits(pBitArray, dwBitPosition + pBetTable->dwBitIndex_FlagIndex, + pBetTable->dwBitCount_FlagIndex, + &dwFlagIndex, + 4); + pFileEntry->dwFlags = pBetTable->pFileFlags[dwFlagIndex]; + } + + // + // TODO: Locale (?) + // + + // Move the current bit position + dwBitPosition += pBetTable->dwTableEntrySize; + pFileEntry++; + } + + // Set the current size of the file table + FreeBetTable(pBetTable); + nError = ERROR_SUCCESS; + } + else + { + nError = ERROR_FILE_CORRUPT; + } + + return nError; +} + +int BuildFileTable(TMPQArchive * ha) +{ + DWORD dwFileTableSize; + bool bFileTableCreated = false; + + // Sanity checks + assert(ha->pFileTable == NULL); + assert(ha->dwFileTableSize == 0); + assert(ha->dwMaxFileCount != 0); + + // Determine the allocation size for the file table + dwFileTableSize = STORMLIB_MAX(ha->pHeader->dwBlockTableSize, ha->dwMaxFileCount); + + // Allocate the file table with size determined before + ha->pFileTable = STORM_ALLOC(TFileEntry, dwFileTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Fill the table with zeros + memset(ha->pFileTable, 0, dwFileTableSize * sizeof(TFileEntry)); + ha->dwFileTableSize = dwFileTableSize; + + // If we have HET table, we load file table from the BET table + // Note: If BET table is corrupt or missing, we set the archive as read only + if(ha->pHetTable != NULL) + { + if(BuildFileTable_HetBet(ha) != ERROR_SUCCESS) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + else + bFileTableCreated = true; + } + + // If we have hash table, we load the file table from the block table + // Note: If block table is corrupt or missing, we set the archive as read only + if(ha->pHashTable != NULL) + { + if(BuildFileTable_Classic(ha) != ERROR_SUCCESS) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + else + bFileTableCreated = true; + } + + // Return result + return bFileTableCreated ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; +} + +/* +void UpdateBlockTableSize(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + DWORD dwBlockTableSize = 0; + + // Calculate the number of files + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // If the source table entry is valid, + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + dwBlockTableSize = (DWORD)(pFileEntry - ha->pFileTable) + 1; + } + + // Save the block table size to the MPQ header + ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize; +} +*/ + +// Defragment the file table so it does not contain any gaps +int DefragmentFileTable(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pSource = ha->pFileTable; + TFileEntry * pTarget = ha->pFileTable; + LPDWORD DefragmentTable; + DWORD dwBlockTableSize = 0; + DWORD dwSrcIndex; + DWORD dwTrgIndex; + + // Allocate brand new file table + DefragmentTable = STORM_ALLOC(DWORD, ha->dwFileTableSize); + if(DefragmentTable != NULL) + { + // Clear the file table + memset(DefragmentTable, 0xFF, sizeof(DWORD) * ha->dwFileTableSize); + + // Parse the entire file table and defragment it + for(; pSource < pFileTableEnd; pSource++) + { + // If the source table entry is valid, + if(pSource->dwFlags & MPQ_FILE_EXISTS) + { + // Remember the index conversion + dwSrcIndex = (DWORD)(pSource - ha->pFileTable); + dwTrgIndex = (DWORD)(pTarget - ha->pFileTable); + DefragmentTable[dwSrcIndex] = dwTrgIndex; + + // Move the entry, if needed + if(pTarget != pSource) + pTarget[0] = pSource[0]; + pTarget++; + + // Update the block table size + dwBlockTableSize = (DWORD)(pTarget - ha->pFileTable); + } + else + { + // If there is file name left, free it + if(pSource->szFileName != NULL) + STORM_FREE(pSource->szFileName); + pSource->szFileName = NULL; + } + } + + // Did we defragment something? + if(pTarget < pFileTableEnd) + { + // Clear the remaining file entries + memset(pTarget, 0, (pFileTableEnd - pTarget) * sizeof(TFileEntry)); + + // Go through the hash table and relocate the block indexes + if(ha->pHashTable != NULL) + { + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pHash; + DWORD dwNewBlockIndex; + + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + if(MPQ_BLOCK_INDEX(pHash) < ha->dwFileTableSize) + { + // If that block entry is there, set it to the hash entry + // If not, set it as DELETED + dwNewBlockIndex = DefragmentTable[MPQ_BLOCK_INDEX(pHash)]; + pHash->dwBlockIndex = (dwNewBlockIndex != HASH_ENTRY_FREE) ? dwNewBlockIndex : HASH_ENTRY_DELETED; + } + } + } + } + + // Save the block table size + ha->pHeader->dwBlockTableSize = ha->dwReservedFiles + dwBlockTableSize; + + // Free the defragment table + STORM_FREE(DefragmentTable); + } + + return ERROR_SUCCESS; +} + +// Rebuilds the HET table from scratch based on the file table +// Used after a modifying operation (add, rename, delete) +int RebuildHetTable(TMPQArchive * ha) +{ + TMPQHetTable * pOldHetTable = ha->pHetTable; + TFileEntry * pFileTableEnd; + TFileEntry * pFileEntry; + DWORD dwBlockTableSize = ha->dwFileTableSize; + int nError = ERROR_SUCCESS; + + // If we are in the state of saving MPQ tables, the real size of block table + // must already have been calculated. Use that value instead + if(ha->dwFlags & MPQ_FLAG_SAVING_TABLES) + { + assert(ha->pHeader->dwBlockTableSize != 0); + dwBlockTableSize = ha->pHeader->dwBlockTableSize; + } + + // Create new HET table based on the total number of entries in the file table + // Note that if we fail to create it, we just stop using HET table + ha->pHetTable = CreateHetTable(dwBlockTableSize, 0, 0x40, NULL); + if(ha->pHetTable != NULL) + { + // Go through the file table again and insert all existing files + pFileTableEnd = ha->pFileTable + dwBlockTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + { + // Get the high + nError = InsertHetEntry(ha->pHetTable, pFileEntry->FileNameHash, (DWORD)(pFileEntry - ha->pFileTable)); + if(nError != ERROR_SUCCESS) + break; + } + } + } + + // Free the old HET table + FreeHetTable(pOldHetTable); + return nError; +} + +// Rebuilds the file table, removing all deleted file entries. +// Used when compacting the archive +int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize) +{ + TFileEntry * pFileEntry; + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pOldHashTable = ha->pHashTable; + TMPQHash * pHashTable = NULL; + TMPQHash * pHash; + int nError = ERROR_SUCCESS; + + // The new hash table size must be greater or equal to the current hash table size + assert(dwNewHashTableSize >= ha->pHeader->dwHashTableSize); + assert(dwNewHashTableSize >= ha->dwMaxFileCount); + assert((dwNewHashTableSize & (dwNewHashTableSize - 1)) == 0); + assert(ha->pHashTable != NULL); + + // Reallocate the new file table, if needed + if(dwNewHashTableSize > ha->dwFileTableSize) + { + ha->pFileTable = STORM_REALLOC(TFileEntry, ha->pFileTable, dwNewHashTableSize); + if(ha->pFileTable == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + memset(ha->pFileTable + ha->dwFileTableSize, 0, (dwNewHashTableSize - ha->dwFileTableSize) * sizeof(TFileEntry)); + } + + // Allocate new hash table + if(nError == ERROR_SUCCESS) + { + pHashTable = STORM_ALLOC(TMPQHash, dwNewHashTableSize); + if(pHashTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // If both succeeded, we need to rebuild the file table + if(nError == ERROR_SUCCESS) + { + // Make sure that the hash table is properly filled + memset(pHashTable, 0xFF, sizeof(TMPQHash) * dwNewHashTableSize); + ha->pHashTable = pHashTable; + + // Set the new limits to the MPQ archive + ha->pHeader->dwHashTableSize = dwNewHashTableSize; + + // Parse the old hash table and copy all entries to the new table + for(pHash = pOldHashTable; pHash < pHashTableEnd; pHash++) + { + if(IsValidHashEntry(ha, pHash)) + { + pFileEntry = ha->pFileTable + MPQ_BLOCK_INDEX(pHash); + AllocateHashEntry(ha, pFileEntry, pHash->lcLocale); + } + } + + // Increment the max file count for the file + ha->dwFileTableSize = dwNewHashTableSize; + ha->dwMaxFileCount = dwNewHashTableSize; + ha->dwFlags |= MPQ_FLAG_CHANGED; + } + + // Now free the remaining entries + if(pOldHashTable != NULL) + STORM_FREE(pOldHashTable); + return nError; +} + +// Saves MPQ header, hash table, block table and hi-block table. +int SaveMPQTables(TMPQArchive * ha) +{ + TMPQExtHeader * pHetTable = NULL; + TMPQExtHeader * pBetTable = NULL; + TMPQHeader * pHeader = ha->pHeader; + TMPQBlock * pBlockTable = NULL; + TMPQHash * pHashTable = NULL; + ULONGLONG HetTableSize64 = 0; + ULONGLONG BetTableSize64 = 0; + ULONGLONG HashTableSize64 = 0; + ULONGLONG BlockTableSize64 = 0; + ULONGLONG HiBlockTableSize64 = 0; + ULONGLONG TablePos = 0; // A table position, relative to the begin of the MPQ + USHORT * pHiBlockTable = NULL; + DWORD cbTotalSize; + bool bNeedHiBlockTable = false; + int nError = ERROR_SUCCESS; + + // We expect this function to be called only when tables have been changed + assert(ha->dwFlags & MPQ_FLAG_CHANGED); + + // Find the space where the MPQ tables will be saved + TablePos = FindFreeMpqSpace(ha); + + // If the MPQ has HET table, we prepare a ready-to-save version + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + { + pHetTable = TranslateHetTable(ha->pHetTable, &HetTableSize64); + if(pHetTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // If the MPQ has HET table, we also must create BET table to be saved + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + { + pBetTable = TranslateBetTable(ha, &BetTableSize64); + if(pBetTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Now create hash table + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL) + { + pHashTable = TranslateHashTable(ha, &HashTableSize64); + if(pHashTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Create block table + if(nError == ERROR_SUCCESS && ha->pFileTable != NULL) + { + pBlockTable = TranslateBlockTable(ha, &BlockTableSize64, &bNeedHiBlockTable); + if(pBlockTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Create hi-block table, if needed + if(nError == ERROR_SUCCESS && bNeedHiBlockTable) + { + pHiBlockTable = TranslateHiBlockTable(ha, &HiBlockTableSize64); + if(pHiBlockTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Write the HET table, if any + if(nError == ERROR_SUCCESS && pHetTable != NULL) + { + pHeader->HetTableSize64 = HetTableSize64; + pHeader->HetTablePos64 = TablePos; + nError = SaveExtTable(ha, pHetTable, TablePos, (DWORD)HetTableSize64, pHeader->MD5_HetTable, MPQ_KEY_HASH_TABLE, false, &cbTotalSize); + TablePos += cbTotalSize; + } + + // Write the BET table, if any + if(nError == ERROR_SUCCESS && pBetTable != NULL) + { + pHeader->BetTableSize64 = BetTableSize64; + pHeader->BetTablePos64 = TablePos; + nError = SaveExtTable(ha, pBetTable, TablePos, (DWORD)BetTableSize64, pHeader->MD5_BetTable, MPQ_KEY_BLOCK_TABLE, false, &cbTotalSize); + TablePos += cbTotalSize; + } + + // Write the hash table, if we have any + if(nError == ERROR_SUCCESS && pHashTable != NULL) + { + pHeader->HashTableSize64 = HashTableSize64; + pHeader->wHashTablePosHi = (USHORT)(TablePos >> 32); + pHeader->dwHashTableSize = (DWORD)(HashTableSize64 / sizeof(TMPQHash)); + pHeader->dwHashTablePos = (DWORD)TablePos; + nError = SaveMpqTable(ha, pHashTable, TablePos, (size_t)HashTableSize64, pHeader->MD5_HashTable, MPQ_KEY_HASH_TABLE, false); + TablePos += HashTableSize64; + } + + // Write the block table, if we have any + if(nError == ERROR_SUCCESS && pBlockTable != NULL) + { + pHeader->BlockTableSize64 = BlockTableSize64; + pHeader->wBlockTablePosHi = (USHORT)(TablePos >> 32); + pHeader->dwBlockTableSize = (DWORD)(BlockTableSize64 / sizeof(TMPQBlock)); + pHeader->dwBlockTablePos = (DWORD)TablePos; + nError = SaveMpqTable(ha, pBlockTable, TablePos, (size_t)BlockTableSize64, pHeader->MD5_BlockTable, MPQ_KEY_BLOCK_TABLE, false); + TablePos += BlockTableSize64; + } + + // Write the hi-block table, if we have any + if(nError == ERROR_SUCCESS && pHiBlockTable != NULL) + { + ULONGLONG ByteOffset = ha->MpqPos + TablePos; + + pHeader->HiBlockTableSize64 = HiBlockTableSize64; + pHeader->HiBlockTablePos64 = TablePos; + BSWAP_ARRAY16_UNSIGNED(pHiBlockTable, HiBlockTableSize64); + + if(!FileStream_Write(ha->pStream, &ByteOffset, pHiBlockTable, (DWORD)HiBlockTableSize64)) + nError = GetLastError(); + TablePos += HiBlockTableSize64; + } + + // Cut the MPQ + if(nError == ERROR_SUCCESS) + { + ULONGLONG FileSize = ha->MpqPos + TablePos; + + if(!FileStream_SetSize(ha->pStream, FileSize)) + nError = GetLastError(); + } + + // Write the MPQ header + if(nError == ERROR_SUCCESS) + { + TMPQHeader SaveMpqHeader; + + // Update the size of the archive + pHeader->ArchiveSize64 = TablePos; + pHeader->dwArchiveSize = (DWORD)TablePos; + + // Update the MD5 of the archive header + CalculateDataBlockHash(pHeader, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE, pHeader->MD5_MpqHeader); + + // Write the MPQ header to the file + memcpy(&SaveMpqHeader, pHeader, pHeader->dwHeaderSize); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_1); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_2); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_3); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_4); + if(!FileStream_Write(ha->pStream, &ha->MpqPos, &SaveMpqHeader, pHeader->dwHeaderSize)) + nError = GetLastError(); + } + + // Clear the changed flag + if(nError == ERROR_SUCCESS) + ha->dwFlags &= ~MPQ_FLAG_CHANGED; + + // Cleanup and exit + if(pHetTable != NULL) + STORM_FREE(pHetTable); + if(pBetTable != NULL) + STORM_FREE(pBetTable); + if(pHashTable != NULL) + STORM_FREE(pHashTable); + if(pBlockTable != NULL) + STORM_FREE(pBlockTable); + if(pHiBlockTable != NULL) + STORM_FREE(pHiBlockTable); + return nError; +} diff --git a/dep/StormLib/src/SBaseSubTypes.cpp b/dep/StormLib/src/SBaseSubTypes.cpp new file mode 100644 index 000000000..47c205e47 --- /dev/null +++ b/dep/StormLib/src/SBaseSubTypes.cpp @@ -0,0 +1,618 @@ +/*****************************************************************************/ +/* SBaseSubTypes.cpp Copyright (c) Ladislav Zezula 2013 */ +/*---------------------------------------------------------------------------*/ +/* Conversion routines for archive formats that are similar to MPQ format */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 02.11.11 1.00 Lad The first version of SBaseSubTypes.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +/*****************************************************************************/ +/* */ +/* Support for SQP file format (War of the Immortals) */ +/* */ +/*****************************************************************************/ + +typedef struct _TSQPHeader +{ + // The ID_MPQ ('MPQ\x1A') signature + DWORD dwID; + + // Size of the archive header + DWORD dwHeaderSize; + + // 32-bit size of MPQ archive + DWORD dwArchiveSize; + + // Offset to the beginning of the hash table, relative to the beginning of the archive. + DWORD dwHashTablePos; + + // Offset to the beginning of the block table, relative to the beginning of the archive. + DWORD dwBlockTablePos; + + // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for + // the original MoPaQ format, or less than 2^20 for the Burning Crusade format. + DWORD dwHashTableSize; + + // Number of entries in the block table + DWORD dwBlockTableSize; + + // Must be zero for SQP files + USHORT wFormatVersion; + + // Power of two exponent specifying the number of 512-byte disk sectors in each file sector + // in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize. + USHORT wSectorSize; + +} TSQPHeader; + +typedef struct _TSQPHash +{ + // Most likely the lcLocale+wPlatform. + DWORD dwAlwaysZero; + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; + + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + +} TSQPHash; + +typedef struct _TSQPBlock +{ + // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFilePos; + + // Flags for the file. See MPQ_FILE_XXXX constants + DWORD dwFlags; + + // Compressed file size + DWORD dwCSize; + + // Uncompressed file size + DWORD dwFSize; + +} TSQPBlock; + +//----------------------------------------------------------------------------- +// Functions - SQP file format + +// This function converts SQP file header into MPQ file header +int ConvertSqpHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG FileSize, + DWORD dwFlags) +{ + TSQPHeader * pSqpHeader = (TSQPHeader *)ha->HeaderData; + TMPQHeader Header; + + // SQP files from War of the Immortal use MPQ file format with slightly + // modified structure. These fields have different position: + // + // Offset TMPQHeader TSQPHeader + // ------ ---------- ----------- + // 000C wFormatVersion dwHashTablePos (lo) + // 000E wSectorSize dwHashTablePos (hi) + // 001C dwBlockTableSize (lo) wBlockSize + // 001E dwHashTableSize (hi) wFormatVersion + + // Can't open the archive with certain flags + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + return ERROR_FILE_CORRUPT; + + // The file must not be greater than 4 GB + if((FileSize >> 0x20) != 0) + return ERROR_FILE_CORRUPT; + + // Translate the SQP header into a MPQ header + memset(&Header, 0, sizeof(TMPQHeader)); + Header.dwID = BSWAP_INT32_UNSIGNED(pSqpHeader->dwID); + Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHeaderSize); + Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwArchiveSize); + Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTablePos); + Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTablePos); + Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwHashTableSize); + Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pSqpHeader->dwBlockTableSize); + Header.wFormatVersion = BSWAP_INT16_UNSIGNED(pSqpHeader->wFormatVersion); + Header.wSectorSize = BSWAP_INT16_UNSIGNED(pSqpHeader->wSectorSize); + + // Verify the SQP header + if(Header.dwID == ID_MPQ && Header.dwHeaderSize == sizeof(TSQPHeader) && Header.dwArchiveSize == FileSize) + { + // Check for fixed values of version and sector size + if(Header.wFormatVersion == MPQ_FORMAT_VERSION_1 && Header.wSectorSize == 3) + { + // Initialize the fields of 3.0 header + Header.ArchiveSize64 = Header.dwArchiveSize; + Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash); + Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock); + + // Copy the converted MPQ header back + memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader)); + + // Mark this file as SQP file + ha->pfnHashString = HashStringSlash; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->dwSubType = MPQ_SUBTYPE_SQP; + return ERROR_SUCCESS; + } + } + + return ERROR_FILE_CORRUPT; +} + +void * LoadSqpTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize, DWORD dwKey) +{ + ULONGLONG ByteOffset; + LPBYTE pbSqpTable; + + // Allocate buffer for the table + pbSqpTable = STORM_ALLOC(BYTE, cbTableSize); + if(pbSqpTable != NULL) + { + // Load the table + ByteOffset = ha->MpqPos + dwByteOffset; + if(FileStream_Read(ha->pStream, &ByteOffset, pbSqpTable, cbTableSize)) + { + // Decrypt the SQP table + DecryptMpqBlock(pbSqpTable, cbTableSize, dwKey); + return pbSqpTable; + } + + // Free the table + STORM_FREE(pbSqpTable); + } + + return NULL; +} + +TMPQHash * LoadSqpHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TSQPHash * pSqpHashTable; + TSQPHash * pSqpHashEnd; + TSQPHash * pSqpHash; + TMPQHash * pMpqHash; + int nError = ERROR_SUCCESS; + + // Load the hash table + pSqpHashTable = (TSQPHash *)LoadSqpTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TSQPHash), MPQ_KEY_HASH_TABLE); + if(pSqpHashTable != NULL) + { + // Parse the entire hash table and convert it to MPQ hash table + pSqpHashEnd = pSqpHashTable + pHeader->dwHashTableSize; + pMpqHash = (TMPQHash *)pSqpHashTable; + for(pSqpHash = pSqpHashTable; pSqpHash < pSqpHashEnd; pSqpHash++, pMpqHash++) + { + // Ignore free entries + if(pSqpHash->dwBlockIndex != HASH_ENTRY_FREE) + { + // Check block index against the size of the block table + if(pHeader->dwBlockTableSize <= MPQ_BLOCK_INDEX(pSqpHash) && pSqpHash->dwBlockIndex < HASH_ENTRY_DELETED) + nError = ERROR_FILE_CORRUPT; + + // We do not support nonzero locale and platform ID + if(pSqpHash->dwAlwaysZero != 0 && pSqpHash->dwAlwaysZero != HASH_ENTRY_FREE) + nError = ERROR_FILE_CORRUPT; + + // Store the file name hash + pMpqHash->dwName1 = pSqpHash->dwName1; + pMpqHash->dwName2 = pSqpHash->dwName2; + + // Store the rest. Note that this must be done last, + // because block index corresponds to pMpqHash->dwName2 + pMpqHash->dwBlockIndex = MPQ_BLOCK_INDEX(pSqpHash); + pMpqHash->Platform = 0; + pMpqHash->lcLocale = 0; + } + } + + // If an error occured, we need to free the hash table + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pSqpHashTable); + pSqpHashTable = NULL; + } + } + + // Return the converted hash table (or NULL on failure) + return (TMPQHash *)pSqpHashTable; +} + +// Loads the SQP Block table and converts it to a MPQ block table +TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TSQPBlock * pSqpBlockTable; + TSQPBlock * pSqpBlockEnd; + TSQPBlock * pSqpBlock; + TMPQBlock * pMpqBlock; + DWORD dwFlags; + int nError = ERROR_SUCCESS; + + // Load the hash table + pSqpBlockTable = (TSQPBlock *)LoadSqpTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TSQPBlock), MPQ_KEY_BLOCK_TABLE); + if(pSqpBlockTable != NULL) + { + // Parse the entire hash table and convert it to MPQ hash table + pSqpBlockEnd = pSqpBlockTable + pHeader->dwBlockTableSize; + pMpqBlock = (TMPQBlock *)pSqpBlockTable; + for(pSqpBlock = pSqpBlockTable; pSqpBlock < pSqpBlockEnd; pSqpBlock++, pMpqBlock++) + { + // Check for valid flags + if(pSqpBlock->dwFlags & ~MPQ_FILE_VALID_FLAGS) + nError = ERROR_FILE_CORRUPT; + + // Convert SQP block table entry to MPQ block table entry + dwFlags = pSqpBlock->dwFlags; + pMpqBlock->dwCSize = pSqpBlock->dwCSize; + pMpqBlock->dwFSize = pSqpBlock->dwFSize; + pMpqBlock->dwFlags = dwFlags; + } + + // If an error occured, we need to free the hash table + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pSqpBlockTable); + pSqpBlockTable = NULL; + } + } + + // Return the converted hash table (or NULL on failure) + return (TMPQBlock *)pSqpBlockTable; +} + +/*****************************************************************************/ +/* */ +/* Support for MPK file format (Longwu Online) */ +/* */ +/*****************************************************************************/ + +#define MPK_FILE_UNKNOWN_0001 0x00000001 // Seems to be always present +#define MPK_FILE_UNKNOWN_0010 0x00000010 // Seems to be always present +#define MPK_FILE_COMPRESSED 0x00000100 // Indicates a compressed file +#define MPK_FILE_UNKNOWN_2000 0x00002000 // Seems to be always present +#define MPK_FILE_EXISTS 0x01000000 // Seems to be always present + +typedef struct _TMPKHeader +{ + // The ID_MPK ('MPK\x1A') signature + DWORD dwID; + + // Contains '2000' + DWORD dwVersion; + + // 32-bit size of the archive + DWORD dwArchiveSize; + + // Size of the archive header + DWORD dwHeaderSize; + + DWORD dwHashTablePos; + DWORD dwHashTableSize; + DWORD dwBlockTablePos; + DWORD dwBlockTableSize; + DWORD dwUnknownPos; + DWORD dwUnknownSize; +} TMPKHeader; + + +typedef struct _TMPKHash +{ + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + + // The hash of the file path, using method C. + DWORD dwName3; + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; + +} TMPKHash; + +typedef struct _TMPKBlock +{ + DWORD dwFlags; // 0x1121 - Compressed , 0x1120 - Not compressed + DWORD dwFilePos; // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFSize; // Uncompressed file size + DWORD dwCSize; // Compressed file size + DWORD dwUnknown; // 0x86364E6D +} TMPKBlock; + +//----------------------------------------------------------------------------- +// Local variables - MPK file format + +static const unsigned char MpkDecryptionKey[512] = +{ + 0x60, 0x20, 0x29, 0xE1, 0x01, 0xCE, 0xAA, 0xFE, 0xA3, 0xAB, 0x8E, 0x30, 0xAF, 0x02, 0xD1, 0x7D, + 0x41, 0x24, 0x06, 0xBD, 0xAE, 0xBE, 0x43, 0xC3, 0xBA, 0xB7, 0x08, 0x13, 0x51, 0xCF, 0xF8, 0xF7, + 0x25, 0x42, 0xA5, 0x4A, 0xDA, 0x0F, 0x52, 0x1C, 0x90, 0x3B, 0x63, 0x49, 0x36, 0xF6, 0xDD, 0x1B, + 0xEA, 0x58, 0xD4, 0x40, 0x70, 0x61, 0x55, 0x09, 0xCD, 0x0B, 0xA2, 0x4B, 0x68, 0x2C, 0x8A, 0xF1, + 0x3C, 0x3A, 0x65, 0xBB, 0xA1, 0xA8, 0x23, 0x97, 0xFD, 0x15, 0x00, 0x94, 0x88, 0x33, 0x59, 0xE9, + 0xFB, 0x69, 0x21, 0xEF, 0x85, 0x5B, 0x57, 0x6C, 0xFA, 0xB5, 0xEE, 0xB8, 0x71, 0xDC, 0xB1, 0x38, + 0x0C, 0x0A, 0x5C, 0x56, 0xC9, 0xB4, 0x84, 0x17, 0x1E, 0xE5, 0xD3, 0x5A, 0xCC, 0xFC, 0x11, 0x86, + 0x7F, 0x45, 0x4F, 0x54, 0xC8, 0x8D, 0x73, 0x89, 0x79, 0x5D, 0xB3, 0xBF, 0xB9, 0xE3, 0x93, 0xE4, + 0x6F, 0x35, 0x2D, 0x46, 0xF2, 0x76, 0xC5, 0x7E, 0xE2, 0xA4, 0xE6, 0xD9, 0x6E, 0x48, 0x34, 0x2B, + 0xC6, 0x5F, 0xBC, 0xA0, 0x6D, 0x0D, 0x47, 0x6B, 0x95, 0x96, 0x92, 0x91, 0xB2, 0x27, 0xEB, 0x9E, + 0xEC, 0x8F, 0xDF, 0x9C, 0x74, 0x99, 0x64, 0xF5, 0xFF, 0x28, 0xB6, 0x37, 0xF3, 0x7C, 0x81, 0x03, + 0x44, 0x62, 0x1F, 0xDB, 0x04, 0x7B, 0xB0, 0x9B, 0x31, 0xA7, 0xDE, 0x78, 0x9F, 0xAD, 0x0E, 0x3F, + 0x3E, 0x4D, 0xC7, 0xD7, 0x39, 0x19, 0x5E, 0xC2, 0xD0, 0xAC, 0xE8, 0x1A, 0x87, 0x8B, 0x07, 0x05, + 0x22, 0xED, 0x72, 0x2E, 0x1D, 0xC1, 0xA9, 0xD6, 0xE0, 0x83, 0xD5, 0xD8, 0xCB, 0x80, 0xF0, 0x66, + 0x7A, 0x9D, 0x50, 0xF9, 0x10, 0x4E, 0x16, 0x14, 0x77, 0x75, 0x6A, 0x67, 0xD2, 0xC0, 0xA6, 0xC4, + 0x53, 0x8C, 0x32, 0xCA, 0x82, 0x2A, 0x18, 0x9A, 0xF4, 0x4C, 0x3D, 0x26, 0x12, 0xE7, 0x98, 0x2F, + 0x4A, 0x04, 0x0D, 0xAF, 0xB4, 0xCF, 0x12, 0xCE, 0x1A, 0x37, 0x61, 0x39, 0x60, 0x95, 0xBE, 0x25, + 0xE4, 0x6E, 0xFC, 0x1B, 0xE7, 0x49, 0xE6, 0x67, 0xF6, 0xC5, 0xCB, 0x2F, 0x27, 0xD4, 0x68, 0xB2, + 0x01, 0x52, 0xD0, 0x46, 0x11, 0x20, 0xFB, 0x9D, 0xA9, 0x02, 0xF5, 0x8F, 0x3D, 0x82, 0xD3, 0xFF, + 0x0B, 0xB8, 0xF2, 0x4D, 0x8E, 0x81, 0x2C, 0xAB, 0x5F, 0xC4, 0x41, 0x29, 0x40, 0xFA, 0xC0, 0xBF, + 0x33, 0x10, 0x21, 0x16, 0xB0, 0x71, 0x83, 0x96, 0x8D, 0x2B, 0x23, 0x3B, 0xF9, 0xC1, 0xE5, 0x72, + 0xE2, 0x1C, 0x26, 0xF0, 0x73, 0x36, 0x63, 0x56, 0x31, 0x4E, 0x6B, 0x55, 0x62, 0x79, 0xC6, 0x91, + 0x00, 0x35, 0xB1, 0x2A, 0xA6, 0x42, 0xDF, 0xEB, 0x3C, 0x51, 0xEA, 0x97, 0x57, 0x94, 0x8C, 0x80, + 0x34, 0x5C, 0xD2, 0x76, 0xA4, 0xE9, 0x85, 0xE8, 0xBB, 0x78, 0xE0, 0xB5, 0xAD, 0x0F, 0x87, 0x70, + 0xDD, 0xAE, 0xF4, 0xD9, 0x66, 0x54, 0x6F, 0xCC, 0x4C, 0x77, 0x3E, 0xCD, 0xF1, 0x75, 0x0A, 0xA1, + 0x28, 0x9B, 0x9A, 0x7E, 0x4B, 0x98, 0x99, 0x47, 0xFE, 0xA5, 0xF7, 0xB7, 0xA3, 0xE1, 0x9F, 0xBC, + 0x93, 0x44, 0x3A, 0x08, 0x89, 0x22, 0xEE, 0xB9, 0x45, 0xD6, 0x06, 0x09, 0xC9, 0xBD, 0x14, 0x0C, + 0xB6, 0x5E, 0x9C, 0x7A, 0x65, 0x59, 0xAA, 0x19, 0x5B, 0x7C, 0x18, 0x43, 0x92, 0x13, 0x15, 0x7B, + 0xED, 0xD5, 0xC7, 0x17, 0xEF, 0x86, 0x90, 0xC2, 0x74, 0x64, 0xF3, 0xDC, 0x6C, 0x38, 0x05, 0x1D, + 0xC8, 0x0E, 0xEC, 0x6A, 0x32, 0xDA, 0xD7, 0xC3, 0xDB, 0x8B, 0x24, 0xB3, 0x5D, 0x2E, 0xBA, 0xA2, + 0xD8, 0x03, 0x88, 0x7D, 0x7F, 0x69, 0x8A, 0xFD, 0xCA, 0x4F, 0x30, 0x9E, 0xA0, 0xD1, 0x5A, 0x53, + 0xDE, 0x3F, 0x84, 0xAC, 0xF8, 0xA7, 0x2D, 0x1F, 0x1E, 0xE3, 0x58, 0x50, 0x6D, 0x48, 0x07, 0xA8 +}; + +//----------------------------------------------------------------------------- +// Functions - MPK file format + +// This function converts MPK file header into MPQ file header +int ConvertMpkHeaderToFormat4( + TMPQArchive * ha, + ULONGLONG FileSize, + DWORD dwFlags) +{ + TMPKHeader * pMpkHeader = (TMPKHeader *)ha->HeaderData; + TMPQHeader Header; + + // Can't open the archive with certain flags + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + return ERROR_FILE_CORRUPT; + + // Translate the MPK header into a MPQ header + // Note: Hash table size and block table size are in bytes, not in entries + memset(&Header, 0, sizeof(TMPQHeader)); + Header.dwID = BSWAP_INT32_UNSIGNED(pMpkHeader->dwID); + Header.dwArchiveSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwArchiveSize); + Header.dwHeaderSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHeaderSize); + Header.dwHashTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTablePos); + Header.dwHashTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwHashTableSize) / sizeof(TMPKHash); + Header.dwBlockTablePos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTablePos); + Header.dwBlockTableSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwBlockTableSize) / sizeof(TMPKBlock); +// Header.dwUnknownPos = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownPos); +// Header.dwUnknownSize = BSWAP_INT32_UNSIGNED(pMpkHeader->dwUnknownSize); + assert(Header.dwHeaderSize == sizeof(TMPKHeader)); + + // Verify the MPK header + if(Header.dwID == ID_MPK && Header.dwHeaderSize == sizeof(TMPKHeader) && Header.dwArchiveSize == (DWORD)FileSize) + { + // The header ID must be ID_MPQ + Header.dwID = ID_MPQ; + Header.wFormatVersion = MPQ_FORMAT_VERSION_1; + Header.wSectorSize = 3; + + // Initialize the fields of 3.0 header + Header.ArchiveSize64 = Header.dwArchiveSize; + Header.HashTableSize64 = Header.dwHashTableSize * sizeof(TMPQHash); + Header.BlockTableSize64 = Header.dwBlockTableSize * sizeof(TMPQBlock); + + // Copy the converted MPQ header back + memcpy(ha->HeaderData, &Header, sizeof(TMPQHeader)); + + // Mark this file as MPK file + ha->pfnHashString = HashStringLower; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->dwSubType = MPQ_SUBTYPE_MPK; + return ERROR_SUCCESS; + } + return ERROR_FILE_CORRUPT; +} + +// Attempts to search a free hash entry in the hash table being converted. +// The created hash table must always be of nonzero size, +// should have no duplicated items and no deleted entries +TMPQHash * FindFreeHashEntry(TMPQHash * pHashTable, DWORD dwHashTableSize, DWORD dwStartIndex) +{ + TMPQHash * pHash; + DWORD dwIndex; + + // Set the initial index + dwStartIndex = dwIndex = (dwStartIndex & (dwHashTableSize - 1)); + assert(dwHashTableSize != 0); + + // Search the hash table and return the found entries in the following priority: + for(;;) + { + // We are not expecting to find matching entry in the hash table being built + // We are not expecting to find deleted entry either + pHash = pHashTable + dwIndex; + + // If we found a free entry, we need to stop searching + if(pHash->dwBlockIndex == HASH_ENTRY_FREE) + return pHash; + + // Move to the next hash entry. + // If we reached the starting entry, it's failure. + dwIndex = (dwIndex + 1) & (dwHashTableSize - 1); + if(dwIndex == dwStartIndex) + break; + } + + // We haven't found anything + assert(false); + return NULL; +} + +void DecryptMpkTable(void * pvMpkTable, size_t cbSize) +{ + LPBYTE pbMpkTable = (LPBYTE)pvMpkTable; + + for(size_t i = 0; i < cbSize; i++) + pbMpkTable[i] = MpkDecryptionKey[pbMpkTable[i]]; +} + +void * LoadMpkTable(TMPQArchive * ha, DWORD dwByteOffset, DWORD cbTableSize) +{ + ULONGLONG ByteOffset; + LPBYTE pbMpkTable = NULL; + + // Allocate space for the table + pbMpkTable = STORM_ALLOC(BYTE, cbTableSize); + if(pbMpkTable != NULL) + { + // Load and the MPK hash table + ByteOffset = ha->MpqPos + dwByteOffset; + if(FileStream_Read(ha->pStream, &ByteOffset, pbMpkTable, cbTableSize)) + { + // Decrypt the table + DecryptMpkTable(pbMpkTable, cbTableSize); + return pbMpkTable; + } + + // Free the MPK table + STORM_FREE(pbMpkTable); + pbMpkTable = NULL; + } + + // Return the table + return pbMpkTable; +} + +TMPQHash * LoadMpkHashTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQHash * pHashTable = NULL; + TMPKHash * pMpkHash; + TMPQHash * pHash = NULL; + DWORD dwHashTableSize = pHeader->dwHashTableSize; + + // MPKs use different hash table searching. + // Instead of using MPQ_HASH_TABLE_INDEX hash as index, + // they store the value directly in the hash table. + // Also for faster searching, the hash table is sorted ascending by the value + + // Load and decrypt the MPK hash table. + pMpkHash = (TMPKHash *)LoadMpkTable(ha, pHeader->dwHashTablePos, pHeader->dwHashTableSize * sizeof(TMPKHash)); + if(pMpkHash != NULL) + { + // Calculate the hash table size as if it was real MPQ hash table + pHeader->dwHashTableSize = GetNearestPowerOfTwo(pHeader->dwHashTableSize); + pHeader->HashTableSize64 = pHeader->dwHashTableSize * sizeof(TMPQHash); + + // Now allocate table that will serve like a true MPQ hash table, + // so we translate the MPK hash table to MPQ hash table + pHashTable = STORM_ALLOC(TMPQHash, pHeader->dwHashTableSize); + if(pHashTable != NULL) + { + // Set the entire hash table to free + memset(pHashTable, 0xFF, (size_t)pHeader->HashTableSize64); + + // Copy the MPK hash table into MPQ hash table + for(DWORD i = 0; i < dwHashTableSize; i++) + { + // Finds the free hash entry in the hash table + // We don't expect any errors here, because we are putting files to empty hash table + pHash = FindFreeHashEntry(pHashTable, pHeader->dwHashTableSize, pMpkHash[i].dwName1); + assert(pHash->dwBlockIndex == HASH_ENTRY_FREE); + + // Copy the MPK hash entry to the hash table + pHash->dwBlockIndex = pMpkHash[i].dwBlockIndex; + pHash->Platform = 0; + pHash->lcLocale = 0; + pHash->dwName1 = pMpkHash[i].dwName2; + pHash->dwName2 = pMpkHash[i].dwName3; + } + } + + // Free the temporary hash table + STORM_FREE(pMpkHash); + } + + return pHashTable; +} + +static DWORD ConvertMpkFlagsToMpqFlags(DWORD dwMpkFlags) +{ + DWORD dwMpqFlags = MPQ_FILE_EXISTS; + + // Check for flags that are always present + assert((dwMpkFlags & MPK_FILE_UNKNOWN_0001) != 0); + assert((dwMpkFlags & MPK_FILE_UNKNOWN_0010) != 0); + assert((dwMpkFlags & MPK_FILE_UNKNOWN_2000) != 0); + assert((dwMpkFlags & MPK_FILE_EXISTS) != 0); + + // Append the compressed flag + dwMpqFlags |= (dwMpkFlags & MPK_FILE_COMPRESSED) ? MPQ_FILE_COMPRESS : 0; + + // All files in the MPQ seem to be single unit files + dwMpqFlags |= MPQ_FILE_ENCRYPTED | MPQ_FILE_SINGLE_UNIT; + + return dwMpqFlags; +} + +TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPKBlock * pMpkBlockTable; + TMPKBlock * pMpkBlockEnd; + TMPQBlock * pBlockTable = NULL; + TMPKBlock * pMpkBlock; + TMPQBlock * pMpqBlock; + + // Load and decrypt the MPK block table + pMpkBlockTable = pMpkBlock = (TMPKBlock *)LoadMpkTable(ha, pHeader->dwBlockTablePos, pHeader->dwBlockTableSize * sizeof(TMPKBlock)); + if(pMpkBlockTable != NULL) + { + // Allocate buffer for MPQ-like block table + pBlockTable = pMpqBlock = STORM_ALLOC(TMPQBlock, pHeader->dwBlockTableSize); + if(pBlockTable != NULL) + { + // Convert the MPK block table to MPQ block table + pMpkBlockEnd = pMpkBlockTable + pHeader->dwBlockTableSize; + while(pMpkBlock < pMpkBlockEnd) + { + // Translate the MPK block table entry to MPQ block table entry + pMpqBlock->dwFilePos = pMpkBlock->dwFilePos; + pMpqBlock->dwCSize = pMpkBlock->dwCSize; + pMpqBlock->dwFSize = pMpkBlock->dwFSize; + pMpqBlock->dwFlags = ConvertMpkFlagsToMpqFlags(pMpkBlock->dwFlags); + + // Move both + pMpkBlock++; + pMpqBlock++; + } + } + + // Free the MPK block table + STORM_FREE(pMpkBlockTable); + } + + return pBlockTable; +} diff --git a/dep/StormLib/src/SCompression.cpp b/dep/StormLib/src/SCompression.cpp new file mode 100644 index 000000000..d706a6f37 --- /dev/null +++ b/dep/StormLib/src/SCompression.cpp @@ -0,0 +1,1145 @@ +/*****************************************************************************/ +/* SCompression.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* This module serves as a bridge between StormLib code and (de)compression */ +/* functions. All (de)compression calls go (and should only go) through this */ +/* module. No system headers should be included in this module to prevent */ +/* compile-time problems. */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 01.04.03 1.00 Lad The first version of SCompression.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +// Information about the input and output buffers for pklib +typedef struct +{ + unsigned char * pbInBuff; // Pointer to input data buffer + unsigned char * pbInBuffEnd; // End of the input buffer + unsigned char * pbOutBuff; // Pointer to output data buffer + unsigned char * pbOutBuffEnd; // Pointer to output data buffer +} TDataInfo; + +// Prototype of the compression function +// Function doesn't return an error. A success means that the size of compressed buffer +// is lower than size of uncompressed buffer. +typedef void (*COMPRESS)( + void * pvOutBuffer, // [out] Pointer to the buffer where the compressed data will be stored + int * pcbOutBuffer, // [in] Pointer to length of the buffer pointed by pvOutBuffer + void * pvInBuffer, // [in] Pointer to the buffer with data to compress + int cbInBuffer, // [in] Length of the buffer pointer by pvInBuffer + int * pCmpType, // [in] Compression-method specific value. ADPCM Setups this for the following Huffman compression + int nCmpLevel); // [in] Compression specific value. ADPCM uses this. Should be set to zero. + +// Prototype of the decompression function +// Returns 1 if success, 0 if failure +typedef int (*DECOMPRESS)( + void * pvOutBuffer, // [out] Pointer to the buffer where to store decompressed data + int * pcbOutBuffer, // [in] Pointer to total size of the buffer pointed by pvOutBuffer + // [out] Contains length of the decompressed data + void * pvInBuffer, // [in] Pointer to data to be decompressed + int cbInBuffer); // [in] Length of the data to be decompressed + +// Table of compression functions +typedef struct +{ + unsigned long uMask; // Compression mask + COMPRESS Compress; // Compression function +} TCompressTable; + +// Table of decompression functions +typedef struct +{ + unsigned long uMask; // Decompression bit + DECOMPRESS Decompress; // Decompression function +} TDecompressTable; + + +/*****************************************************************************/ +/* */ +/* Support for Huffman compression (0x01) */ +/* */ +/*****************************************************************************/ + +void Compress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + THuffmannTree ht(true); + TOutputStream os(pvOutBuffer, *pcbOutBuffer); + + STORMLIB_UNUSED(nCmpLevel); + *pcbOutBuffer = ht.Compress(&os, pvInBuffer, cbInBuffer, *pCmpType); +} + +int Decompress_huff(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + THuffmannTree ht(false); + TInputStream is(pvInBuffer, cbInBuffer); + + *pcbOutBuffer = ht.Decompress(pvOutBuffer, *pcbOutBuffer, &is); + return (*pcbOutBuffer == 0) ? 0 : 1; +} + +/******************************************************************************/ +/* */ +/* Support for ZLIB compression (0x02) */ +/* */ +/******************************************************************************/ + +void Compress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + z_stream z; // Stream information for zlib + int windowBits; + int nResult; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Fill the stream structure for zlib + z.next_in = (Bytef *)pvInBuffer; + z.avail_in = (uInt)cbInBuffer; + z.total_in = cbInBuffer; + z.next_out = (Bytef *)pvOutBuffer; + z.avail_out = *pcbOutBuffer; + z.total_out = 0; + z.zalloc = NULL; + z.zfree = NULL; + + // Determine the proper window bits (WoW.exe build 12694) + if(cbInBuffer <= 0x100) + windowBits = 8; + else if(cbInBuffer <= 0x200) + windowBits = 9; + else if(cbInBuffer <= 0x400) + windowBits = 10; + else if(cbInBuffer <= 0x800) + windowBits = 11; + else if(cbInBuffer <= 0x1000) + windowBits = 12; + else if(cbInBuffer <= 0x2000) + windowBits = 13; + else if(cbInBuffer <= 0x4000) + windowBits = 14; + else + windowBits = 15; + + // Initialize the compression. + // Storm.dll uses zlib version 1.1.3 + // Wow.exe uses zlib version 1.2.3 + nResult = deflateInit2(&z, + 6, // Compression level used by WoW MPQs + Z_DEFLATED, + windowBits, + 8, + Z_DEFAULT_STRATEGY); + if(nResult == Z_OK) + { + // Call zlib to compress the data + nResult = deflate(&z, Z_FINISH); + + if(nResult == Z_OK || nResult == Z_STREAM_END) + *pcbOutBuffer = z.total_out; + + deflateEnd(&z); + } +} + +int Decompress_ZLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + z_stream z; // Stream information for zlib + int nResult; + + // Fill the stream structure for zlib + z.next_in = (Bytef *)pvInBuffer; + z.avail_in = (uInt)cbInBuffer; + z.total_in = cbInBuffer; + z.next_out = (Bytef *)pvOutBuffer; + z.avail_out = *pcbOutBuffer; + z.total_out = 0; + z.zalloc = NULL; + z.zfree = NULL; + + // Initialize the decompression structure. Storm.dll uses zlib version 1.1.3 + if((nResult = inflateInit(&z)) == 0) + { + // Call zlib to decompress the data + nResult = inflate(&z, Z_FINISH); + *pcbOutBuffer = z.total_out; + inflateEnd(&z); + } + return nResult; +} + +/******************************************************************************/ +/* */ +/* Support functions for PKWARE Data Compression Library compression (0x08) */ +/* */ +/******************************************************************************/ + +// Function loads data from the input buffer. Used by Pklib's "implode" +// and "explode" function as user-defined callback +// Returns number of bytes loaded +// +// char * buf - Pointer to a buffer where to store loaded data +// unsigned int * size - Max. number of bytes to read +// void * param - Custom pointer, parameter of implode/explode + +static unsigned int ReadInputData(char * buf, unsigned int * size, void * param) +{ + TDataInfo * pInfo = (TDataInfo *)param; + unsigned int nMaxAvail = (unsigned int)(pInfo->pbInBuffEnd - pInfo->pbInBuff); + unsigned int nToRead = *size; + + // Check the case when not enough data available + if(nToRead > nMaxAvail) + nToRead = nMaxAvail; + + // Load data and increment offsets + memcpy(buf, pInfo->pbInBuff, nToRead); + pInfo->pbInBuff += nToRead; + assert(pInfo->pbInBuff <= pInfo->pbInBuffEnd); + return nToRead; +} + +// Function for store output data. Used by Pklib's "implode" and "explode" +// as user-defined callback +// +// char * buf - Pointer to data to be written +// unsigned int * size - Number of bytes to write +// void * param - Custom pointer, parameter of implode/explode + +static void WriteOutputData(char * buf, unsigned int * size, void * param) +{ + TDataInfo * pInfo = (TDataInfo *)param; + unsigned int nMaxWrite = (unsigned int)(pInfo->pbOutBuffEnd - pInfo->pbOutBuff); + unsigned int nToWrite = *size; + + // Check the case when not enough space in the output buffer + if(nToWrite > nMaxWrite) + nToWrite = nMaxWrite; + + // Write output data and increments offsets + memcpy(pInfo->pbOutBuff, buf, nToWrite); + pInfo->pbOutBuff += nToWrite; + assert(pInfo->pbOutBuff <= pInfo->pbOutBuffEnd); +} + +static void Compress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + TDataInfo Info; // Data information + char * work_buf = STORM_ALLOC(char, CMP_BUFFER_SIZE);// Pklib's work buffer + unsigned int dict_size; // Dictionary size + unsigned int ctype = CMP_BINARY; // Compression type + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Handle no-memory condition + if(work_buf != NULL) + { + // Fill data information structure + memset(work_buf, 0, CMP_BUFFER_SIZE); + Info.pbInBuff = (unsigned char *)pvInBuffer; + Info.pbInBuffEnd = (unsigned char *)pvInBuffer + cbInBuffer; + Info.pbOutBuff = (unsigned char *)pvOutBuffer; + Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer; + + // + // Set the dictionary size + // + // Diablo I uses fixed dictionary size of CMP_IMPLODE_DICT_SIZE3 + // Starcraft I uses the variable dictionary size based on algorithm below + // + + if (cbInBuffer < 0x600) + dict_size = CMP_IMPLODE_DICT_SIZE1; + else if(0x600 <= cbInBuffer && cbInBuffer < 0xC00) + dict_size = CMP_IMPLODE_DICT_SIZE2; + else + dict_size = CMP_IMPLODE_DICT_SIZE3; + + // Do the compression + if(implode(ReadInputData, WriteOutputData, work_buf, &Info, &ctype, &dict_size) == CMP_NO_ERROR) + *pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer); + + STORM_FREE(work_buf); + } +} + +static int Decompress_PKLIB(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + TDataInfo Info; // Data information + char * work_buf = STORM_ALLOC(char, EXP_BUFFER_SIZE);// Pklib's work buffer + + // Handle no-memory condition + if(work_buf == NULL) + return 0; + + // Fill data information structure + memset(work_buf, 0, EXP_BUFFER_SIZE); + Info.pbInBuff = (unsigned char *)pvInBuffer; + Info.pbInBuffEnd = (unsigned char *)pvInBuffer + cbInBuffer; + Info.pbOutBuff = (unsigned char *)pvOutBuffer; + Info.pbOutBuffEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer; + + // Do the decompression + explode(ReadInputData, WriteOutputData, work_buf, &Info); + + // If PKLIB is unable to decompress the data, return 0; + if(Info.pbOutBuff == pvOutBuffer) + { + STORM_FREE(work_buf); + return 0; + } + + // Give away the number of decompressed bytes + *pcbOutBuffer = (int)(Info.pbOutBuff - (unsigned char *)pvOutBuffer); + STORM_FREE(work_buf); + return 1; +} + +/******************************************************************************/ +/* */ +/* Support for Bzip2 compression (0x10) */ +/* */ +/******************************************************************************/ + +static void Compress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + bz_stream strm; + int blockSize100k = 9; + int workFactor = 30; + int bzError; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Initialize the BZIP2 compression + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + + // Blizzard uses 9 as blockSize100k, (0x30 as workFactor) + // Last checked on Starcraft II + if(BZ2_bzCompressInit(&strm, blockSize100k, 0, workFactor) == BZ_OK) + { + strm.next_in = (char *)pvInBuffer; + strm.avail_in = cbInBuffer; + strm.next_out = (char *)pvOutBuffer; + strm.avail_out = *pcbOutBuffer; + + // Perform the compression + for(;;) + { + bzError = BZ2_bzCompress(&strm, (strm.avail_in != 0) ? BZ_RUN : BZ_FINISH); + if(bzError == BZ_STREAM_END || bzError < 0) + break; + } + + // Put the stream into idle state + BZ2_bzCompressEnd(&strm); + + if(bzError > 0) + *pcbOutBuffer = strm.total_out_lo32; + } +} + +static int Decompress_BZIP2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + bz_stream strm; + int nResult = BZ_OK; + + // Initialize the BZIP2 decompression + strm.bzalloc = NULL; + strm.bzfree = NULL; + strm.opaque = NULL; + + // Initialize decompression + if(BZ2_bzDecompressInit(&strm, 0, 0) == BZ_OK) + { + strm.next_in = (char *)pvInBuffer; + strm.avail_in = cbInBuffer; + strm.next_out = (char *)pvOutBuffer; + strm.avail_out = *pcbOutBuffer; + + // Perform the decompression + while(nResult != BZ_STREAM_END) + { + nResult = BZ2_bzDecompress(&strm); + + // If any error there, break the loop + if(nResult < BZ_OK) + break; + } + + // Put the stream into idle state + BZ2_bzDecompressEnd(&strm); + + // If all succeeded, set the number of output bytes + if(nResult >= BZ_OK) + { + *pcbOutBuffer = strm.total_out_lo32; + return 1; + } + } + + // Something failed, so set number of output bytes to zero + *pcbOutBuffer = 0; + return 1; +} + +/******************************************************************************/ +/* */ +/* Support functions for LZMA compression (0x12) */ +/* */ +/******************************************************************************/ + +#define LZMA_HEADER_SIZE (1 + LZMA_PROPS_SIZE + 8) + +static SRes LZMA_Callback_Progress(void * /* p */, UInt64 /* inSize */, UInt64 /* outSize */) +{ + return SZ_OK; +} + +static void * LZMA_Callback_Alloc(void *p, size_t size) +{ + p = p; + return STORM_ALLOC(BYTE, size); +} + +/* address can be 0 */ +static void LZMA_Callback_Free(void *p, void *address) +{ + p = p; + if(address != NULL) + STORM_FREE(address); +} + +// +// Note: So far, I haven't seen any files compressed by LZMA. +// This code haven't been verified against code ripped from Starcraft II Beta, +// but we know that Starcraft LZMA decompression code is able to decompress +// the data compressed by StormLib. +// + +static void Compress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + ICompressProgress Progress; + CLzmaEncProps props; + ISzAlloc SzAlloc; + Byte * pbOutBuffer = (Byte *)pvOutBuffer; + Byte * destBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + Byte encodedProps[LZMA_PROPS_SIZE]; + size_t encodedPropsSize = LZMA_PROPS_SIZE; + SRes nResult; + + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + // Fill the callbacks in structures + Progress.Progress = LZMA_Callback_Progress; + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Initialize properties + LzmaEncProps_Init(&props); + + // Perform compression + destBuffer = (Byte *)pvOutBuffer + LZMA_HEADER_SIZE; + destLen = *pcbOutBuffer - LZMA_HEADER_SIZE; + nResult = LzmaEncode(destBuffer, + &destLen, + (Byte *)pvInBuffer, + srcLen, + &props, + encodedProps, + &encodedPropsSize, + 0, + &Progress, + &SzAlloc, + &SzAlloc); + if(nResult != SZ_OK) + return; + + // If we failed to compress the data + if(destLen >= (SizeT)(*pcbOutBuffer - LZMA_HEADER_SIZE)) + return; + + // Write "useFilter" variable. Blizzard MPQ must not use filter. + *pbOutBuffer++ = 0; + + // Copy the encoded properties to the output buffer + memcpy(pvOutBuffer, encodedProps, encodedPropsSize); + pbOutBuffer += encodedPropsSize; + + // Copy the size of the data + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x00); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x08); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x10); + *pbOutBuffer++ = (unsigned char)(srcLen >> 0x18); + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + *pbOutBuffer++ = 0; + + // Give the size of the data to the caller + *pcbOutBuffer = (unsigned int)(destLen + LZMA_HEADER_SIZE); +} + +static int Decompress_LZMA(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + ELzmaStatus LzmaStatus; + ISzAlloc SzAlloc; + Byte * destBuffer = (Byte *)pvOutBuffer; + Byte * srcBuffer = (Byte *)pvInBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + SRes nResult; + + // There must be at least 0x0E bytes in the buffer + if(srcLen <= LZMA_HEADER_SIZE) + return 0; + + // We only accept blocks that have no filter used + if(*srcBuffer != 0) + return 0; + + // Fill the callbacks in structures + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Perform compression + srcLen = cbInBuffer - LZMA_HEADER_SIZE; + nResult = LzmaDecode(destBuffer, + &destLen, + srcBuffer + LZMA_HEADER_SIZE, + &srcLen, + srcBuffer + 1, + LZMA_PROPS_SIZE, + LZMA_FINISH_END, + &LzmaStatus, + &SzAlloc); + if(nResult != SZ_OK) + return 0; + + *pcbOutBuffer = (unsigned int)destLen; + return 1; +} + +static int Decompress_LZMA_MPK(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + ELzmaStatus LzmaStatus; + ISzAlloc SzAlloc; + Byte * destBuffer = (Byte *)pvOutBuffer; + Byte * srcBuffer = (Byte *)pvInBuffer; + SizeT destLen = *pcbOutBuffer; + SizeT srcLen = cbInBuffer; + SRes nResult; + BYTE LZMA_Props[] = {0x5D, 0x00, 0x00, 0x00, 0x01}; + + // There must be at least 0x0E bytes in the buffer + if(srcLen <= sizeof(LZMA_Props)) + return 0; + + // Verify the props header + if(memcmp(pvInBuffer, LZMA_Props, sizeof(LZMA_Props))) + return 0; + + // Fill the callbacks in structures + SzAlloc.Alloc = LZMA_Callback_Alloc; + SzAlloc.Free = LZMA_Callback_Free; + + // Perform compression + srcLen = cbInBuffer - sizeof(LZMA_Props); + nResult = LzmaDecode(destBuffer, + &destLen, + srcBuffer + sizeof(LZMA_Props), + &srcLen, + srcBuffer, + sizeof(LZMA_Props), + LZMA_FINISH_END, + &LzmaStatus, + &SzAlloc); + if(nResult != SZ_OK) + return 0; + + *pcbOutBuffer = (unsigned int)destLen; + return 1; +} + +/******************************************************************************/ +/* */ +/* Support functions for SPARSE compression (0x20) */ +/* */ +/******************************************************************************/ + +void Compress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Keep compilers happy + STORMLIB_UNUSED(pCmpType); + STORMLIB_UNUSED(nCmpLevel); + + CompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} + +int Decompress_SPARSE(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + return DecompressSparse(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} + +/******************************************************************************/ +/* */ +/* Support for ADPCM mono compression (0x40) */ +/* */ +/******************************************************************************/ + +static void Compress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Prepare the compression level for Huffmann compression, + // which will be called as next step + if(0 < nCmpLevel && nCmpLevel <= 2) + { + nCmpLevel = 4; + *pCmpType = 6; + } + else if(nCmpLevel == 3) + { + nCmpLevel = 6; + *pCmpType = 8; + } + else + { + nCmpLevel = 5; + *pCmpType = 7; + } + *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1, nCmpLevel); +} + +static int Decompress_ADPCM_mono(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 1); + return 1; +} + +/******************************************************************************/ +/* */ +/* Support for ADPCM stereo compression (0x80) */ +/* */ +/******************************************************************************/ + +static void Compress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, int * pCmpType, int nCmpLevel) +{ + // Prepare the compression level for Huffmann compression, + // which will be called as next step + if(0 < nCmpLevel && nCmpLevel <= 2) + { + nCmpLevel = 4; + *pCmpType = 6; + } + else if(nCmpLevel == 3) + { + nCmpLevel = 6; + *pCmpType = 8; + } + else + { + nCmpLevel = 5; + *pCmpType = 7; + } + *pcbOutBuffer = CompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2, nCmpLevel); +} + +static int Decompress_ADPCM_stereo(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + *pcbOutBuffer = DecompressADPCM(pvOutBuffer, *pcbOutBuffer, pvInBuffer, cbInBuffer, 2); + return 1; +} + +/*****************************************************************************/ +/* */ +/* SCompImplode */ +/* */ +/*****************************************************************************/ + +int WINAPI SCompImplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + int cbOutBuffer; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // Perform the compression + cbOutBuffer = *pcbOutBuffer; + Compress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer, NULL, 0); + + // If the compression was unsuccessful, copy the data as-is + if(cbOutBuffer >= *pcbOutBuffer) + { + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + cbOutBuffer = *pcbOutBuffer; + } + + *pcbOutBuffer = cbOutBuffer; + return 1; +} + +/*****************************************************************************/ +/* */ +/* SCompExplode */ +/* */ +/*****************************************************************************/ + +int WINAPI SCompExplode(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + int cbOutBuffer; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // If the input length is the same as output length, do nothing. + cbOutBuffer = *pcbOutBuffer; + if(cbInBuffer == cbOutBuffer) + { + // If the buffers are equal, don't copy anything. + if(pvInBuffer == pvOutBuffer) + return 1; + + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Perform decompression + if(!Decompress_PKLIB(pvOutBuffer, &cbOutBuffer, pvInBuffer, cbInBuffer)) + { + SetLastError(ERROR_FILE_CORRUPT); + return 0; + } + + *pcbOutBuffer = cbOutBuffer; + return 1; +} + +/*****************************************************************************/ +/* */ +/* SCompCompress */ +/* */ +/*****************************************************************************/ + +// This table contains compress functions which can be applied to +// uncompressed data. Each bit means the corresponding +// compression method/function must be applied. +// +// WAVes compression Data compression +// ------------------ ------------------- +// 1st sector - 0x08 0x08 (D, HF, W2, SC, D2) +// Next sectors - 0x81 0x02 (W3) + +static TCompressTable cmp_table[] = +{ + {MPQ_COMPRESSION_SPARSE, Compress_SPARSE}, // Sparse compression + {MPQ_COMPRESSION_ADPCM_MONO, Compress_ADPCM_mono}, // IMA ADPCM mono compression + {MPQ_COMPRESSION_ADPCM_STEREO, Compress_ADPCM_stereo}, // IMA ADPCM stereo compression + {MPQ_COMPRESSION_HUFFMANN, Compress_huff}, // Huffmann compression + {MPQ_COMPRESSION_ZLIB, Compress_ZLIB}, // Compression with the "zlib" library + {MPQ_COMPRESSION_PKWARE, Compress_PKLIB}, // Compression with Pkware DCL + {MPQ_COMPRESSION_BZIP2, Compress_BZIP2} // Compression Bzip2 library +}; + +int WINAPI SCompCompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel) +{ + COMPRESS CompressFuncArray[0x10]; // Array of compression functions, applied sequentially + unsigned char CompressByte[0x10]; // CompressByte for each method in the CompressFuncArray array + unsigned char * pbWorkBuffer = NULL; // Temporary storage for decompressed data + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbOutput = (unsigned char *)pvOutBuffer;// Current output buffer + unsigned char * pbInput = (unsigned char *)pvInBuffer; // Current input buffer + int nCompressCount = 0; + int nCompressIndex = 0; + int nAtLeastOneCompressionDone = 0; + int cbOutBuffer = 0; + int cbInLength = cbInBuffer; + int nResult = 1; + + // Check for valid parameters + if(!pcbOutBuffer || *pcbOutBuffer < cbInBuffer || !pvOutBuffer || !pvInBuffer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } + + // Zero input length brings zero output length + if(cbInBuffer == 0) + { + *pcbOutBuffer = 0; + return true; + } + + // Setup the compression function array + if(uCompressionMask == MPQ_COMPRESSION_LZMA) + { + CompressFuncArray[0] = Compress_LZMA; + CompressByte[0] = (char)uCompressionMask; + nCompressCount = 1; + } + else + { + // Fill the compressions array + for(size_t i = 0; i < (sizeof(cmp_table) / sizeof(TCompressTable)); i++) + { + // If the mask agrees, insert the compression function to the array + if(uCompressionMask & cmp_table[i].uMask) + { + CompressFuncArray[nCompressCount] = cmp_table[i].Compress; + CompressByte[nCompressCount] = (unsigned char)cmp_table[i].uMask; + uCompressionMask &= ~cmp_table[i].uMask; + nCompressCount++; + } + } + + // If at least one of the compressions remaing unknown, return an error + if(uCompressionMask != 0) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + } + + // If there is at least one compression, do it + if(nCompressCount > 0) + { + // If we need to do more than 1 compression, allocate intermediate buffer + if(nCompressCount > 1) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Get the current compression index + nCompressIndex = nCompressCount - 1; + + // Perform all compressions in the array + for(int i = 0; i < nCompressCount; i++) + { + // Choose the proper output buffer + pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer; + nCompressIndex--; + + // Perform the (next) compression + // Note that if the compression method is unable to compress the input data block + // by at least 2 bytes, we consider it as failure and will use source data instead + cbOutBuffer = *pcbOutBuffer - 1; + CompressFuncArray[i](pbOutput + 1, &cbOutBuffer, pbInput, cbInLength, &nCmpType, nCmpLevel); + + // If the compression failed, we copy the input buffer as-is. + // Note that there is one extra byte at the end of the intermediate buffer, so it should be OK + if(cbOutBuffer > (cbInLength - 2)) + { + memcpy(pbOutput + nAtLeastOneCompressionDone, pbInput, cbInLength); + cbOutBuffer = cbInLength; + } + else + { + // Remember that we have done at least one compression + nAtLeastOneCompressionDone = 1; + uCompressionMask |= CompressByte[i]; + } + + // Now point input buffer to the output buffer + pbInput = pbOutput + nAtLeastOneCompressionDone; + cbInLength = cbOutBuffer; + } + + // If at least one compression succeeded, put the compression + // mask to the begin of the output buffer + if(nAtLeastOneCompressionDone) + *pbOutBuffer = (unsigned char)uCompressionMask; + *pcbOutBuffer = cbOutBuffer + nAtLeastOneCompressionDone; + } + else + { + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + *pcbOutBuffer = cbInBuffer; + } + + // Cleanup and return + if(pbWorkBuffer != NULL) + STORM_FREE(pbWorkBuffer); + return nResult; +} + +/*****************************************************************************/ +/* */ +/* SCompDecompress */ +/* */ +/*****************************************************************************/ + +// This table contains decompress functions which can be applied to +// uncompressed data. The compression mask is stored in the first byte +// of compressed data +static TDecompressTable dcmp_table[] = +{ + {MPQ_COMPRESSION_BZIP2, Decompress_BZIP2}, // Decompression with Bzip2 library + {MPQ_COMPRESSION_PKWARE, Decompress_PKLIB}, // Decompression with Pkware Data Compression Library + {MPQ_COMPRESSION_ZLIB, Decompress_ZLIB}, // Decompression with the "zlib" library + {MPQ_COMPRESSION_HUFFMANN, Decompress_huff}, // Huffmann decompression + {MPQ_COMPRESSION_ADPCM_STEREO, Decompress_ADPCM_stereo}, // IMA ADPCM stereo decompression + {MPQ_COMPRESSION_ADPCM_MONO, Decompress_ADPCM_mono}, // IMA ADPCM mono decompression + {MPQ_COMPRESSION_SPARSE, Decompress_SPARSE} // Sparse decompression +}; + +int WINAPI SCompDecompress(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + unsigned char * pbWorkBuffer = NULL; + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + unsigned char * pbOutput = (unsigned char *)pvOutBuffer; + unsigned char * pbInput; + unsigned uCompressionMask; // Decompressions applied to the data + unsigned uCompressionCopy; // Decompressions applied to the data + int cbOutBuffer = *pcbOutBuffer; // Current size of the output buffer + int cbInLength; // Current size of the input buffer + int nCompressCount = 0; // Number of compressions to be applied + int nCompressIndex = 0; + int nResult = 1; + + // Verify buffer sizes + if(cbOutBuffer < cbInBuffer || cbInBuffer < 1) + return 0; + + // If the input length is the same as output length, do nothing. + if(cbOutBuffer == cbInBuffer) + { + // If the buffers are equal, don't copy anything. + if(pvInBuffer != pvOutBuffer) + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Get applied compression types and decrement data length + uCompressionMask = uCompressionCopy = (unsigned char)*pbInBuffer++; + cbInBuffer--; + + // Get current compressed data and length of it + pbInput = pbInBuffer; + cbInLength = cbInBuffer; + + // This compression function doesn't support LZMA + assert(uCompressionMask != MPQ_COMPRESSION_LZMA); + + // Parse the compression mask + for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++) + { + // If the mask agrees, insert the compression function to the array + if(uCompressionMask & dcmp_table[i].uMask) + { + uCompressionCopy &= ~dcmp_table[i].uMask; + nCompressCount++; + } + } + + // If at least one of the compressions remaing unknown, return an error + if(nCompressCount == 0 || uCompressionCopy != 0) + { + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + } + + // If there is more than one compression, we have to allocate extra buffer + if(nCompressCount > 1) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, cbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Get the current compression index + nCompressIndex = nCompressCount - 1; + + // Apply all decompressions + for(size_t i = 0; i < (sizeof(dcmp_table) / sizeof(TDecompressTable)); i++) + { + // Perform the (next) decompression + if(uCompressionMask & dcmp_table[i].uMask) + { + // Get the correct output buffer + pbOutput = (nCompressIndex & 1) ? pbWorkBuffer : pbOutBuffer; + nCompressIndex--; + + // Perform the decompression + cbOutBuffer = *pcbOutBuffer; + nResult = dcmp_table[i].Decompress(pbOutput, &cbOutBuffer, pbInput, cbInLength); + if(nResult == 0 || cbOutBuffer == 0) + { + SetLastError(ERROR_FILE_CORRUPT); + nResult = 0; + break; + } + + // Switch buffers + cbInLength = cbOutBuffer; + pbInput = pbOutput; + } + } + + // Put the length of the decompressed data to the output buffer + *pcbOutBuffer = cbOutBuffer; + + // Cleanup and return + if(pbWorkBuffer != NULL) + STORM_FREE(pbWorkBuffer); + return nResult; +} + +int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + DECOMPRESS pfnDecompress1 = NULL; + DECOMPRESS pfnDecompress2 = NULL; + unsigned char * pbWorkBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + int cbWorkBuffer = *pcbOutBuffer; + int nResult; + char CompressionMethod; + + // Verify buffer sizes + if(*pcbOutBuffer < cbInBuffer || cbInBuffer < 1) + return 0; + + // If the outputbuffer is as big as input buffer, just copy the block + if(*pcbOutBuffer == cbInBuffer) + { + if(pvOutBuffer != pvInBuffer) + memcpy(pvOutBuffer, pvInBuffer, cbInBuffer); + return 1; + } + + // Get the compression methods + CompressionMethod = *pbInBuffer++; + cbInBuffer--; + + // We only recognize a fixed set of compression methods + switch((unsigned char)CompressionMethod) + { + case MPQ_COMPRESSION_ZLIB: + pfnDecompress1 = Decompress_ZLIB; + break; + + case MPQ_COMPRESSION_PKWARE: + pfnDecompress1 = Decompress_PKLIB; + break; + + case MPQ_COMPRESSION_BZIP2: + pfnDecompress1 = Decompress_BZIP2; + break; + + case MPQ_COMPRESSION_LZMA: + pfnDecompress1 = Decompress_LZMA; + break; + + case MPQ_COMPRESSION_SPARSE: + pfnDecompress1 = Decompress_SPARSE; + break; + + case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_ZLIB): + pfnDecompress1 = Decompress_ZLIB; + pfnDecompress2 = Decompress_SPARSE; + break; + + case (MPQ_COMPRESSION_SPARSE | MPQ_COMPRESSION_BZIP2): + pfnDecompress1 = Decompress_BZIP2; + pfnDecompress2 = Decompress_SPARSE; + break; + + // + // Note: Any combination including MPQ_COMPRESSION_ADPCM_MONO, + // MPQ_COMPRESSION_ADPCM_STEREO or MPQ_COMPRESSION_HUFFMANN + // is not supported by newer MPQs. + // + + case (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_HUFFMANN): + pfnDecompress1 = Decompress_huff; + pfnDecompress2 = Decompress_ADPCM_mono; + break; + + case (MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN): + pfnDecompress1 = Decompress_huff; + pfnDecompress2 = Decompress_ADPCM_stereo; + break; + + default: + SetLastError(ERROR_FILE_CORRUPT); + return 0; + } + + // If we have to use two decompressions, allocate temporary buffer + if(pfnDecompress2 != NULL) + { + pbWorkBuffer = STORM_ALLOC(unsigned char, *pcbOutBuffer); + if(pbWorkBuffer == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return 0; + } + } + + // Apply the first decompression method + nResult = pfnDecompress1(pbWorkBuffer, &cbWorkBuffer, pbInBuffer, cbInBuffer); + + // Apply the second decompression method, if any + if(pfnDecompress2 != NULL && nResult != 0) + { + cbInBuffer = cbWorkBuffer; + cbWorkBuffer = *pcbOutBuffer; + nResult = pfnDecompress2(pvOutBuffer, &cbWorkBuffer, pbWorkBuffer, cbInBuffer); + } + + // Supply the output buffer size + *pcbOutBuffer = cbWorkBuffer; + + // Free temporary buffer + if(pbWorkBuffer != pvOutBuffer) + STORM_FREE(pbWorkBuffer); + + if(nResult == 0) + SetLastError(ERROR_FILE_CORRUPT); + return nResult; +} + +/*****************************************************************************/ +/* */ +/* File decompression for MPK archives */ +/* */ +/*****************************************************************************/ + +int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + return Decompress_LZMA_MPK(pvOutBuffer, pcbOutBuffer, pvInBuffer, cbInBuffer); +} + diff --git a/dep/StormLib/src/SFileAddFile.cpp b/dep/StormLib/src/SFileAddFile.cpp new file mode 100644 index 000000000..4572d89b8 --- /dev/null +++ b/dep/StormLib/src/SFileAddFile.cpp @@ -0,0 +1,1312 @@ +/*****************************************************************************/ +/* SFileAddFile.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* MPQ Editing functions */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 27.03.10 1.00 Lad Splitted from SFileCreateArchiveEx.cpp */ +/* 21.04.13 1.01 Dea AddFile callback now part of TMPQArchive */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local variables + +// Mask for lossy compressions +#define MPQ_LOSSY_COMPRESSION_MASK (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN) + +// Data compression for SFileAddFile +// Kept here for compatibility with code that was created with StormLib version < 6.50 +static DWORD DefaultDataCompression = MPQ_COMPRESSION_PKWARE; + +//----------------------------------------------------------------------------- +// WAVE verification + +#define FILE_SIGNATURE_RIFF 0x46464952 +#define FILE_SIGNATURE_WAVE 0x45564157 +#define FILE_SIGNATURE_FMT 0x20746D66 +#define AUDIO_FORMAT_PCM 1 + +typedef struct _WAVE_FILE_HEADER +{ + DWORD dwChunkId; // 0x52494646 ("RIFF") + DWORD dwChunkSize; // Size of that chunk, in bytes + DWORD dwFormat; // Must be 0x57415645 ("WAVE") + + // Format sub-chunk + DWORD dwSubChunk1Id; // 0x666d7420 ("fmt ") + DWORD dwSubChunk1Size; // 0x16 for PCM + USHORT wAudioFormat; // 1 = PCM. Other value means some sort of compression + USHORT wChannels; // Number of channels + DWORD dwSampleRate; // 8000, 44100, etc. + DWORD dwBytesRate; // SampleRate * NumChannels * BitsPerSample/8 + USHORT wBlockAlign; // NumChannels * BitsPerSample/8 + USHORT wBitsPerSample; // 8 bits = 8, 16 bits = 16, etc. + + // Followed by "data" sub-chunk (we don't care) +} WAVE_FILE_HEADER, *PWAVE_FILE_HEADER; + +static bool IsWaveFile_16BitsPerAdpcmSample( + LPBYTE pbFileData, + DWORD cbFileData, + LPDWORD pdwChannels) +{ + PWAVE_FILE_HEADER pWaveHdr = (PWAVE_FILE_HEADER)pbFileData; + + // The amount of file data must be at least size of WAVE header + if(cbFileData > sizeof(WAVE_FILE_HEADER)) + { + // Check for the RIFF header + if(pWaveHdr->dwChunkId == FILE_SIGNATURE_RIFF && pWaveHdr->dwFormat == FILE_SIGNATURE_WAVE) + { + // Check for ADPCM format + if(pWaveHdr->dwSubChunk1Id == FILE_SIGNATURE_FMT && pWaveHdr->wAudioFormat == AUDIO_FORMAT_PCM) + { + // Now the number of bits per sample must be at least 16. + // If not, the WAVE file gets corrupted by the ADPCM compression + if(pWaveHdr->wBitsPerSample >= 0x10) + { + *pdwChannels = pWaveHdr->wChannels; + return true; + } + } + } + } + + return false; +} + +static int FillWritableHandle( + TMPQArchive * ha, + TMPQFile * hf, + ULONGLONG FileTime, + DWORD dwFileSize, + DWORD dwFlags) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + + // Initialize the hash entry for the file + hf->RawFilePos = ha->MpqPos + hf->MpqFilePos; + hf->dwDataSize = dwFileSize; + + // Initialize the block table entry for the file + pFileEntry->ByteOffset = hf->MpqFilePos; + pFileEntry->dwFileSize = dwFileSize; + pFileEntry->dwCmpSize = 0; + pFileEntry->dwFlags = dwFlags | MPQ_FILE_EXISTS; + + // Initialize the file time, CRC32 and MD5 + assert(sizeof(hf->hctx) >= sizeof(hash_state)); + memset(pFileEntry->md5, 0, MD5_DIGEST_SIZE); + md5_init((hash_state *)hf->hctx); + pFileEntry->dwCrc32 = crc32(0, Z_NULL, 0); + + // If the caller gave us a file time, use it. + pFileEntry->FileTime = FileTime; + + // Mark the archive as modified + ha->dwFlags |= MPQ_FLAG_CHANGED; + + // Call the callback, if needed + if(ha->pfnAddFileCB != NULL) + ha->pfnAddFileCB(ha->pvAddFileUserData, 0, hf->dwDataSize, false); + hf->nAddFileError = ERROR_SUCCESS; + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// MPQ write data functions + +static int WriteDataToMpqFile( + TMPQArchive * ha, + TMPQFile * hf, + LPBYTE pbFileData, + DWORD dwDataSize, + DWORD dwCompression) +{ + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG ByteOffset; + LPBYTE pbCompressed = NULL; // Compressed (target) data + LPBYTE pbToWrite = hf->pbFileSector; // Data to write to the file + int nCompressionLevel; // ADPCM compression level (only used for wave files) + int nError = ERROR_SUCCESS; + + // Make sure that the caller won't overrun the previously initiated file size + assert(hf->dwFilePos + dwDataSize <= pFileEntry->dwFileSize); + assert(hf->dwSectorCount != 0); + assert(hf->pbFileSector != NULL); + if((hf->dwFilePos + dwDataSize) > pFileEntry->dwFileSize) + return ERROR_DISK_FULL; + + // Now write all data to the file sector buffer + if(nError == ERROR_SUCCESS) + { + DWORD dwBytesInSector = hf->dwFilePos % hf->dwSectorSize; + DWORD dwSectorIndex = hf->dwFilePos / hf->dwSectorSize; + DWORD dwBytesToCopy; + + // Process all data. + while(dwDataSize != 0) + { + dwBytesToCopy = dwDataSize; + + // Check for sector overflow + if(dwBytesToCopy > (hf->dwSectorSize - dwBytesInSector)) + dwBytesToCopy = (hf->dwSectorSize - dwBytesInSector); + + // Copy the data to the file sector + memcpy(hf->pbFileSector + dwBytesInSector, pbFileData, dwBytesToCopy); + dwBytesInSector += dwBytesToCopy; + pbFileData += dwBytesToCopy; + dwDataSize -= dwBytesToCopy; + + // Update the file position + hf->dwFilePos += dwBytesToCopy; + + // If the current sector is full, or if the file is already full, + // then write the data to the MPQ + if(dwBytesInSector >= hf->dwSectorSize || hf->dwFilePos >= pFileEntry->dwFileSize) + { + // Set the position in the file + ByteOffset = hf->RawFilePos + pFileEntry->dwCmpSize; + + // Update CRC32 and MD5 of the file + md5_process((hash_state *)hf->hctx, hf->pbFileSector, dwBytesInSector); + hf->dwCrc32 = crc32(hf->dwCrc32, hf->pbFileSector, dwBytesInSector); + + // Compress the file sector, if needed + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + int nOutBuffer = (int)dwBytesInSector; + int nInBuffer = (int)dwBytesInSector; + + // If the file is compressed, allocate buffer for the compressed data. + // Note that we allocate buffer that is a bit longer than sector size, + // for case if the compression method performs a buffer overrun + if(pbCompressed == NULL) + { + pbToWrite = pbCompressed = STORM_ALLOC(BYTE, hf->dwSectorSize + 0x100); + if(pbCompressed == NULL) + { + nError = ERROR_NOT_ENOUGH_MEMORY; + break; + } + } + + // + // Note that both SCompImplode and SCompCompress copy data as-is, + // if they are unable to compress the data. + // + + if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + { + SCompImplode(pbCompressed, &nOutBuffer, hf->pbFileSector, nInBuffer); + } + + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) + { + // If this is the first sector, we need to override the given compression + // by the first sector compression. This is because the entire sector must + // be compressed by the same compression. + // + // Test case: + // + // WRITE_FILE(hFile, pvBuffer, 0x10, MPQ_COMPRESSION_PKWARE) // Write 0x10 bytes (sector 0) + // WRITE_FILE(hFile, pvBuffer, 0x10, MPQ_COMPRESSION_ADPCM_MONO) // Write 0x10 bytes (still sector 0) + // WRITE_FILE(hFile, pvBuffer, 0x10, MPQ_COMPRESSION_ADPCM_MONO) // Write 0x10 bytes (still sector 0) + // WRITE_FILE(hFile, pvBuffer, 0x10, MPQ_COMPRESSION_ADPCM_MONO) // Write 0x10 bytes (still sector 0) + dwCompression = (dwSectorIndex == 0) ? hf->dwCompression0 : dwCompression; + + // If the caller wants ADPCM compression, we will set wave compression level to 4, + // which corresponds to medium quality + nCompressionLevel = (dwCompression & MPQ_LOSSY_COMPRESSION_MASK) ? 4 : -1; + SCompCompress(pbCompressed, &nOutBuffer, hf->pbFileSector, nInBuffer, (unsigned)dwCompression, 0, nCompressionLevel); + } + + // Update sector positions + dwBytesInSector = nOutBuffer; + if(hf->SectorOffsets != NULL) + hf->SectorOffsets[dwSectorIndex+1] = hf->SectorOffsets[dwSectorIndex] + dwBytesInSector; + + // We have to calculate sector CRC, if enabled + if(hf->SectorChksums != NULL) + hf->SectorChksums[dwSectorIndex] = adler32(0, pbCompressed, nOutBuffer); + } + + // Encrypt the sector, if necessary + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector); + EncryptMpqBlock(pbToWrite, dwBytesInSector, hf->dwFileKey + dwSectorIndex); + BSWAP_ARRAY32_UNSIGNED(pbToWrite, dwBytesInSector); + } + + // Write the file sector + if(!FileStream_Write(ha->pStream, &ByteOffset, pbToWrite, dwBytesInSector)) + { + nError = GetLastError(); + break; + } + + // Call the compact callback, if any + if(ha->pfnAddFileCB != NULL) + ha->pfnAddFileCB(ha->pvAddFileUserData, hf->dwFilePos, hf->dwDataSize, false); + + // Update the compressed file size + pFileEntry->dwCmpSize += dwBytesInSector; + dwBytesInSector = 0; + dwSectorIndex++; + } + } + } + + // Cleanup + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + return nError; +} + +//----------------------------------------------------------------------------- +// Recrypts file data for file renaming + +static int RecryptFileData( + TMPQArchive * ha, + TMPQFile * hf, + const char * szFileName, + const char * szNewFileName) +{ + ULONGLONG RawFilePos; + TFileEntry * pFileEntry = hf->pFileEntry; + DWORD dwBytesToRecrypt = pFileEntry->dwCmpSize; + DWORD dwOldKey; + DWORD dwNewKey; + int nError = ERROR_SUCCESS; + + // The file must be encrypted + assert(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED); + + // File decryption key is calculated from the plain name + szNewFileName = GetPlainFileName(szNewFileName); + szFileName = GetPlainFileName(szFileName); + + // Calculate both file keys + dwOldKey = DecryptFileKey(szFileName, pFileEntry->ByteOffset, pFileEntry->dwFileSize, pFileEntry->dwFlags); + dwNewKey = DecryptFileKey(szNewFileName, pFileEntry->ByteOffset, pFileEntry->dwFileSize, pFileEntry->dwFlags); + + // Incase the keys are equal, don't recrypt the file + if(dwNewKey == dwOldKey) + return ERROR_SUCCESS; + hf->dwFileKey = dwOldKey; + + // Calculate the raw position of the file in the archive + hf->MpqFilePos = pFileEntry->ByteOffset; + hf->RawFilePos = ha->MpqPos + hf->MpqFilePos; + + // Allocate buffer for file transfer + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS) + return nError; + + // Also allocate buffer for sector offsets + // Note: Don't load sector checksums, we don't need to recrypt them + nError = AllocateSectorOffsets(hf, true); + if(nError != ERROR_SUCCESS) + return nError; + + // If we have sector offsets, recrypt these as well + if(hf->SectorOffsets != NULL) + { + // Allocate secondary buffer for sectors copy + DWORD * SectorOffsetsCopy = STORM_ALLOC(DWORD, hf->SectorOffsets[0] / sizeof(DWORD)); + DWORD dwSectorOffsLen = hf->SectorOffsets[0]; + + if(SectorOffsetsCopy == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Recrypt the array of sector offsets + memcpy(SectorOffsetsCopy, hf->SectorOffsets, dwSectorOffsLen); + EncryptMpqBlock(SectorOffsetsCopy, dwSectorOffsLen, dwNewKey - 1); + BSWAP_ARRAY32_UNSIGNED(SectorOffsetsCopy, dwSectorOffsLen); + + // Write the recrypted array back + if(!FileStream_Write(ha->pStream, &hf->RawFilePos, SectorOffsetsCopy, dwSectorOffsLen)) + nError = GetLastError(); + STORM_FREE(SectorOffsetsCopy); + } + + // Now we have to recrypt all file sectors. We do it without + // recompression, because recompression is not necessary in this case + if(nError == ERROR_SUCCESS) + { + for(DWORD dwSector = 0; dwSector < hf->dwSectorCount; dwSector++) + { + DWORD dwRawDataInSector = hf->dwSectorSize; + DWORD dwRawByteOffset = dwSector * hf->dwSectorSize; + + // Last sector: If there is not enough bytes remaining in the file, cut the raw size + if(dwRawDataInSector > dwBytesToRecrypt) + dwRawDataInSector = dwBytesToRecrypt; + + // Fix the raw data length if the file is compressed + if(hf->SectorOffsets != NULL) + { + dwRawDataInSector = hf->SectorOffsets[dwSector+1] - hf->SectorOffsets[dwSector]; + dwRawByteOffset = hf->SectorOffsets[dwSector]; + } + + // Calculate the raw file offset of the file sector + RawFilePos = CalculateRawSectorOffset(hf, dwRawByteOffset); + + // Read the file sector + if(!FileStream_Read(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector)) + { + nError = GetLastError(); + break; + } + + // If necessary, re-encrypt the sector + // Note: Recompression is not necessary here. Unlike encryption, + // the compression does not depend on the position of the file in MPQ. + BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector); + DecryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwOldKey + dwSector); + EncryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwNewKey + dwSector); + BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector); + + // Write the sector back + if(!FileStream_Write(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector)) + { + nError = GetLastError(); + break; + } + + // Decrement number of bytes remaining + dwBytesToRecrypt -= hf->dwSectorSize; + } + } + + return nError; +} + +//----------------------------------------------------------------------------- +// Internal support for MPQ modifications + +int SFileAddFile_Init( + TMPQArchive * ha, + const char * szFileName, + ULONGLONG FileTime, + DWORD dwFileSize, + LCID lcLocale, + DWORD dwFlags, + TMPQFile ** phf) +{ + TFileEntry * pFileEntry = NULL; + TMPQFile * hf = NULL; // File structure for newly added file + DWORD dwHashIndex = HASH_ENTRY_FREE; + int nError = ERROR_SUCCESS; + + // + // Note: This is an internal function so no validity checks are done. + // It is the caller's responsibility to make sure that no invalid + // flags get to this point + // + + // Sestor CRC is not allowed with single unit files + if(dwFlags & MPQ_FILE_SINGLE_UNIT) + dwFlags &= ~MPQ_FILE_SECTOR_CRC; + + // Sector CRC is not allowed if the file is not compressed + if(!(dwFlags & MPQ_FILE_COMPRESS_MASK)) + dwFlags &= ~MPQ_FILE_SECTOR_CRC; + + // Fix Key is not allowed if the file is not enrypted + if(!(dwFlags & MPQ_FILE_ENCRYPTED)) + dwFlags &= ~MPQ_FILE_FIX_KEY; + + // If the MPQ is of version 3.0 or higher, we ignore file locale. + // This is because HET and BET tables have no known support for it + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_3) + lcLocale = 0; + + // Allocate the TMPQFile entry for newly added file + hf = CreateWritableHandle(ha, dwFileSize); + if(hf == NULL) + return false; + + // Allocate file entry in the MPQ + if(nError == ERROR_SUCCESS) + { + // Check if the file already exists in the archive + pFileEntry = GetFileEntryExact(ha, szFileName, lcLocale, &dwHashIndex); + if(pFileEntry != NULL) + { + if(dwFlags & MPQ_FILE_REPLACEEXISTING) + InvalidateInternalFiles(ha); + else + nError = ERROR_ALREADY_EXISTS; + } + else + { + // Attempt to allocate new file entry + pFileEntry = AllocateFileEntry(ha, szFileName, lcLocale, &dwHashIndex); + if(pFileEntry != NULL) + InvalidateInternalFiles(ha); + else + nError = ERROR_DISK_FULL; + } + + // Set the file entry to the file structure + hf->pFileEntry = pFileEntry; + } + + // Prepare the pointer to hash table entry + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && dwHashIndex < ha->pHeader->dwHashTableSize) + { + hf->pHashEntry = ha->pHashTable + dwHashIndex; + hf->pHashEntry->lcLocale = (USHORT)lcLocale; + } + + // Prepare the file key + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) + { + hf->dwFileKey = DecryptFileKey(szFileName, hf->MpqFilePos, dwFileSize, dwFlags); + if(hf->dwFileKey == 0) + nError = ERROR_UNKNOWN_FILE_KEY; + } + + // Fill the file entry and TMPQFile structure + if(nError == ERROR_SUCCESS) + { + // At this point, the file name in the file entry must be set + assert(pFileEntry->szFileName != NULL); + assert(_stricmp(pFileEntry->szFileName, szFileName) == 0); + + nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags); + } + + // Free the file handle if failed + if(nError != ERROR_SUCCESS && hf != NULL) + FreeFileHandle(hf); + + // Give the handle to the caller + *phf = hf; + return nError; +} + +int SFileAddFile_Init( + TMPQArchive * ha, + TMPQFile * hfSrc, + TMPQFile ** phf) +{ + TFileEntry * pFileEntry = NULL; + TMPQFile * hf = NULL; // File structure for newly added file + ULONGLONG FileTime = hfSrc->pFileEntry->FileTime; + DWORD dwFileSize = hfSrc->pFileEntry->dwFileSize; + DWORD dwFlags = hfSrc->pFileEntry->dwFlags; + int nError = ERROR_SUCCESS; + + // Allocate the TMPQFile entry for newly added file + hf = CreateWritableHandle(ha, dwFileSize); + if(hf == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + + // We need to keep the file entry index the same like in the source archive + // This is because multiple hash table entries can point to the same file entry + if(nError == ERROR_SUCCESS) + { + // Retrieve the file entry for the target file + pFileEntry = ha->pFileTable + (hfSrc->pFileEntry - hfSrc->ha->pFileTable); + + // Copy all variables except file name + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + pFileEntry[0] = hfSrc->pFileEntry[0]; + pFileEntry->szFileName = NULL; + } + else + nError = ERROR_ALREADY_EXISTS; + + // Set the file entry to the file structure + hf->pFileEntry = pFileEntry; + } + + // Prepare the pointer to hash table entry + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL && hfSrc->pHashEntry != NULL) + { + hf->dwHashIndex = (DWORD)(hfSrc->pHashEntry - hfSrc->ha->pHashTable); + hf->pHashEntry = ha->pHashTable + hf->dwHashIndex; + } + + // Prepare the file key (copy from source file) + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_FILE_ENCRYPTED)) + { + hf->dwFileKey = hfSrc->dwFileKey; + if(hf->dwFileKey == 0) + nError = ERROR_UNKNOWN_FILE_KEY; + } + + // Fill the file entry and TMPQFile structure + if(nError == ERROR_SUCCESS) + { + nError = FillWritableHandle(ha, hf, FileTime, dwFileSize, dwFlags); + } + + // Free the file handle if failed + if(nError != ERROR_SUCCESS && hf != NULL) + FreeFileHandle(hf); + + // Give the handle to the caller + *phf = hf; + return nError; +} + +int SFileAddFile_Write(TMPQFile * hf, const void * pvData, DWORD dwSize, DWORD dwCompression) +{ + TMPQArchive * ha; + TFileEntry * pFileEntry; + int nError = ERROR_SUCCESS; + + // Don't bother if the caller gave us zero size + if(pvData == NULL || dwSize == 0) + return ERROR_SUCCESS; + + // Get pointer to the MPQ archive + pFileEntry = hf->pFileEntry; + ha = hf->ha; + + // Allocate file buffers + if(hf->pbFileSector == NULL) + { + ULONGLONG RawFilePos = hf->RawFilePos; + + // Allocate buffer for file sector + hf->nAddFileError = nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS) + return nError; + + // Allocate patch info, if the data is patch + if(hf->pPatchInfo == NULL && IsIncrementalPatchFile(pvData, dwSize, &hf->dwPatchedFileSize)) + { + // Set the MPQ_FILE_PATCH_FILE flag + hf->pFileEntry->dwFlags |= MPQ_FILE_PATCH_FILE; + + // Allocate the patch info + hf->nAddFileError = nError = AllocatePatchInfo(hf, false); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Allocate sector offsets + if(hf->SectorOffsets == NULL) + { + hf->nAddFileError = nError = AllocateSectorOffsets(hf, false); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Create array of sector checksums + if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC)) + { + hf->nAddFileError = nError = AllocateSectorChecksums(hf, false); + if(nError != ERROR_SUCCESS) + return nError; + } + + // Pre-save the patch info, if any + if(hf->pPatchInfo != NULL) + { + if(!FileStream_Write(ha->pStream, &RawFilePos, hf->pPatchInfo, hf->pPatchInfo->dwLength)) + nError = GetLastError(); + + pFileEntry->dwCmpSize += hf->pPatchInfo->dwLength; + RawFilePos += hf->pPatchInfo->dwLength; + } + + // Pre-save the sector offset table, just to reserve space in the file. + // Note that we dont need to swap the sector positions, nor encrypt the table + // at the moment, as it will be written again after writing all file sectors. + if(hf->SectorOffsets != NULL) + { + if(!FileStream_Write(ha->pStream, &RawFilePos, hf->SectorOffsets, hf->SectorOffsets[0])) + nError = GetLastError(); + + pFileEntry->dwCmpSize += hf->SectorOffsets[0]; + RawFilePos += hf->SectorOffsets[0]; + } + } + + // Write the MPQ data to the file + if(nError == ERROR_SUCCESS) + { + // Save the first sector compression to the file structure + // Note that the entire first file sector will be compressed + // by compression that was passed to the first call of SFileAddFile_Write + if(hf->dwFilePos == 0) + hf->dwCompression0 = dwCompression; + + // Write the data to the MPQ + nError = WriteDataToMpqFile(ha, hf, (LPBYTE)pvData, dwSize, dwCompression); + } + + // If it succeeded and we wrote all the file data, + // we need to re-save sector offset table + if(nError == ERROR_SUCCESS) + { + if(hf->dwFilePos >= pFileEntry->dwFileSize) + { + // Finish calculating CRC32 + hf->pFileEntry->dwCrc32 = hf->dwCrc32; + + // Finish calculating MD5 + md5_done((hash_state *)hf->hctx, hf->pFileEntry->md5); + + // If we also have sector checksums, write them to the file + if(hf->SectorChksums != NULL) + { + nError = WriteSectorChecksums(hf); + } + + // Now write patch info + if(hf->pPatchInfo != NULL) + { + memcpy(hf->pPatchInfo->md5, hf->pFileEntry->md5, MD5_DIGEST_SIZE); + hf->pPatchInfo->dwDataSize = hf->pFileEntry->dwFileSize; + hf->pFileEntry->dwFileSize = hf->dwPatchedFileSize; + nError = WritePatchInfo(hf); + } + + // Now write sector offsets to the file + if(hf->SectorOffsets != NULL) + { + nError = WriteSectorOffsets(hf); + } + + // Write the MD5 hashes of each file chunk, if required + if(ha->pHeader->dwRawChunkSize != 0) + { + nError = WriteMpqDataMD5(ha->pStream, + ha->MpqPos + hf->pFileEntry->ByteOffset, + hf->pFileEntry->dwCmpSize, + ha->pHeader->dwRawChunkSize); + } + } + } + + // Store the error code from the Write File operation + hf->nAddFileError = nError; + return nError; +} + +int SFileAddFile_Finish(TMPQFile * hf) +{ + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + int nError = hf->nAddFileError; + + // If all previous operations succeeded, we can update the MPQ + if(nError == ERROR_SUCCESS) + { + // Verify if the caller wrote the file properly + if(hf->pPatchInfo == NULL) + { + assert(pFileEntry != NULL); + if(hf->dwFilePos != pFileEntry->dwFileSize) + nError = ERROR_CAN_NOT_COMPLETE; + } + else + { + if(hf->dwFilePos != hf->pPatchInfo->dwDataSize) + nError = ERROR_CAN_NOT_COMPLETE; + } + } + + // Now we need to recreate the HET table, if exists + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + { + nError = RebuildHetTable(ha); + } + + // Update the block table size + if(nError == ERROR_SUCCESS) + { + // Call the user callback, if any + if(ha->pfnAddFileCB != NULL) + ha->pfnAddFileCB(ha->pvAddFileUserData, hf->dwDataSize, hf->dwDataSize, true); + } + else + { + // Free the file entry in MPQ tables + if(pFileEntry != NULL) + DeleteFileEntry(ha, hf); + } + + // Clear the add file callback + FreeFileHandle(hf); + return nError; +} + +//----------------------------------------------------------------------------- +// Adds data as file to the archive + +bool WINAPI SFileCreateFile( + HANDLE hMpq, + const char * szArchivedName, + ULONGLONG FileTime, + DWORD dwFileSize, + LCID lcLocale, + DWORD dwFlags, + HANDLE * phFile) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + int nError = ERROR_SUCCESS; + + // Check valid parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(szArchivedName == NULL || *szArchivedName == 0) + nError = ERROR_INVALID_PARAMETER; + if(phFile == NULL) + nError = ERROR_INVALID_PARAMETER; + + // Don't allow to add file if the MPQ is open for read only + if(nError == ERROR_SUCCESS) + { + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + nError = ERROR_ACCESS_DENIED; + + // Don't allow to add a file under pseudo-file name + if(IsPseudoFileName(szArchivedName, NULL)) + nError = ERROR_INVALID_PARAMETER; + + // Don't allow to add any of the internal files + if(IsInternalMpqFileName(szArchivedName)) + nError = ERROR_INTERNAL_FILE; + } + + // Perform validity check of the MPQ flags + if(nError == ERROR_SUCCESS) + { + // Mask all unsupported flags out + dwFlags &= (ha->dwFlags & MPQ_FLAG_WAR3_MAP) ? MPQ_FILE_VALID_FLAGS_W3X : MPQ_FILE_VALID_FLAGS; + + // Check for valid flag combinations + if((dwFlags & (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) == (MPQ_FILE_IMPLODE | MPQ_FILE_COMPRESS)) + nError = ERROR_INVALID_PARAMETER; + } + + // Initiate the add file operation + if(nError == ERROR_SUCCESS) + nError = SFileAddFile_Init(ha, szArchivedName, FileTime, dwFileSize, lcLocale, dwFlags, (TMPQFile **)phFile); + + // Deal with the errors + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +bool WINAPI SFileWriteFile( + HANDLE hFile, + const void * pvData, + DWORD dwSize, + DWORD dwCompression) +{ + TMPQFile * hf = (TMPQFile *)hFile; + int nError = ERROR_SUCCESS; + + // Check the proper parameters + if(!IsValidFileHandle(hFile)) + nError = ERROR_INVALID_HANDLE; + if(hf->bIsWriteHandle == false) + nError = ERROR_INVALID_HANDLE; + + // Special checks for single unit files + if(nError == ERROR_SUCCESS && (hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT)) + { + // + // Note: Blizzard doesn't support single unit files + // that are stored as encrypted or imploded. We will allow them here, + // the calling application must ensure that such flag combination doesn't get here + // + +// if(dwFlags & MPQ_FILE_IMPLODE) +// nError = ERROR_INVALID_PARAMETER; +// +// if(dwFlags & MPQ_FILE_ENCRYPTED) +// nError = ERROR_INVALID_PARAMETER; + + // Lossy compression is not allowed on single unit files + if(dwCompression & MPQ_LOSSY_COMPRESSION_MASK) + nError = ERROR_INVALID_PARAMETER; + } + + + // Write the data to the file + if(nError == ERROR_SUCCESS) + nError = SFileAddFile_Write(hf, pvData, dwSize, dwCompression); + + // Deal with errors + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +bool WINAPI SFileFinishFile(HANDLE hFile) +{ + TMPQFile * hf = (TMPQFile *)hFile; + int nError = ERROR_SUCCESS; + + // Check the proper parameters + if(!IsValidFileHandle(hFile)) + nError = ERROR_INVALID_HANDLE; + if(hf->bIsWriteHandle == false) + nError = ERROR_INVALID_HANDLE; + + // Finish the file + if(nError == ERROR_SUCCESS) + nError = SFileAddFile_Finish(hf); + + // Deal with errors + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// Adds a file to the archive + +bool WINAPI SFileAddFileEx( + HANDLE hMpq, + const TCHAR * szFileName, + const char * szArchivedName, + DWORD dwFlags, + DWORD dwCompression, // Compression of the first sector + DWORD dwCompressionNext) // Compression of next sectors +{ + ULONGLONG FileSize = 0; + ULONGLONG FileTime = 0; + TFileStream * pStream = NULL; + HANDLE hMpqFile = NULL; + LPBYTE pbFileData = NULL; + DWORD dwBytesRemaining = 0; + DWORD dwBytesToRead; + DWORD dwSectorSize = 0x1000; + DWORD dwChannels = 0; + bool bIsAdpcmCompression = false; + bool bIsFirstSector = true; + int nError = ERROR_SUCCESS; + + // Check parameters + if(hMpq == NULL || szFileName == NULL || *szFileName == 0) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Open added file + pStream = FileStream_OpenFile(szFileName, STREAM_FLAG_READ_ONLY | STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE); + if(pStream == NULL) + return false; + + // Files bigger than 4GB cannot be added to MPQ + FileStream_GetTime(pStream, &FileTime); + FileStream_GetSize(pStream, &FileSize); + if(FileSize >> 32) + nError = ERROR_DISK_FULL; + + // Allocate data buffer for reading from the source file + if(nError == ERROR_SUCCESS) + { + dwBytesRemaining = (DWORD)FileSize; + pbFileData = STORM_ALLOC(BYTE, dwSectorSize); + if(pbFileData == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Deal with various combination of compressions + if(nError == ERROR_SUCCESS) + { + // When the compression for next blocks is set to default, + // we will copy the compression for the first sector + if(dwCompressionNext == MPQ_COMPRESSION_NEXT_SAME) + dwCompressionNext = dwCompression; + + // If the caller wants ADPCM compression, we make sure + // that the first sector is not compressed with lossy compression + if(dwCompressionNext & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO)) + { + // The compression of the first file sector must not be ADPCM + // in order not to corrupt the headers + if(dwCompression & (MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO)) + dwCompression = MPQ_COMPRESSION_PKWARE; + + // Remove both flag mono and stereo flags. + // They will be re-added according to WAVE type + dwCompressionNext &= ~(MPQ_COMPRESSION_ADPCM_MONO | MPQ_COMPRESSION_ADPCM_STEREO); + bIsAdpcmCompression = true; + } + + // Initiate adding file to the MPQ + if(!SFileCreateFile(hMpq, szArchivedName, FileTime, (DWORD)FileSize, lcFileLocale, dwFlags, &hMpqFile)) + nError = GetLastError(); + } + + // Write the file data to the MPQ + while(nError == ERROR_SUCCESS && dwBytesRemaining != 0) + { + // Get the number of bytes remaining in the source file + dwBytesToRead = dwBytesRemaining; + if(dwBytesToRead > dwSectorSize) + dwBytesToRead = dwSectorSize; + + // Read data from the local file + if(!FileStream_Read(pStream, NULL, pbFileData, dwBytesToRead)) + { + nError = GetLastError(); + break; + } + + // If the file being added is a WAVE file, we check number of channels + if(bIsFirstSector && bIsAdpcmCompression) + { + // The file must really be a WAVE file with at least 16 bits per sample, + // otherwise the ADPCM compression will corrupt it + if(IsWaveFile_16BitsPerAdpcmSample(pbFileData, dwBytesToRead, &dwChannels)) + { + // Setup the compression of next sectors according to number of channels + dwCompressionNext |= (dwChannels == 1) ? MPQ_COMPRESSION_ADPCM_MONO : MPQ_COMPRESSION_ADPCM_STEREO; + } + else + { + // Setup the compression of next sectors to a lossless compression + dwCompressionNext = (dwCompression & MPQ_LOSSY_COMPRESSION_MASK) ? MPQ_COMPRESSION_PKWARE : dwCompression; + } + + bIsFirstSector = false; + } + + // Add the file sectors to the MPQ + if(!SFileWriteFile(hMpqFile, pbFileData, dwBytesToRead, dwCompression)) + { + nError = GetLastError(); + break; + } + + // Set the next data compression + dwBytesRemaining -= dwBytesToRead; + dwCompression = dwCompressionNext; + } + + // Finish the file writing + if(hMpqFile != NULL) + { + if(!SFileFinishFile(hMpqFile)) + nError = GetLastError(); + } + + // Cleanup and exit + if(pbFileData != NULL) + STORM_FREE(pbFileData); + if(pStream != NULL) + FileStream_Close(pStream); + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +// Adds a data file into the archive +bool WINAPI SFileAddFile(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags) +{ + return SFileAddFileEx(hMpq, + szFileName, + szArchivedName, + dwFlags, + DefaultDataCompression, + DefaultDataCompression); +} + +// Adds a WAVE file into the archive +bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality) +{ + DWORD dwCompression = 0; + + // + // Note to wave compression level: + // The following conversion table applied: + // High quality: WaveCompressionLevel = -1 + // Medium quality: WaveCompressionLevel = 4 + // Low quality: WaveCompressionLevel = 2 + // + // Starcraft files are packed as Mono (0x41) on medium quality. + // Because this compression is not used anymore, our compression functions + // will default to WaveCompressionLevel = 4 when using ADPCM compression + // + + // Convert quality to data compression + switch(dwQuality) + { + case MPQ_WAVE_QUALITY_HIGH: +// WaveCompressionLevel = -1; + dwCompression = MPQ_COMPRESSION_PKWARE; + break; + + case MPQ_WAVE_QUALITY_MEDIUM: +// WaveCompressionLevel = 4; + dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN; + break; + + case MPQ_WAVE_QUALITY_LOW: +// WaveCompressionLevel = 2; + dwCompression = MPQ_COMPRESSION_ADPCM_STEREO | MPQ_COMPRESSION_HUFFMANN; + break; + } + + return SFileAddFileEx(hMpq, + szFileName, + szArchivedName, + dwFlags, + MPQ_COMPRESSION_PKWARE, // First sector should be compressed as data + dwCompression); // Next sectors should be compressed as WAVE +} + +//----------------------------------------------------------------------------- +// bool SFileRemoveFile(HANDLE hMpq, char * szFileName) +// +// This function removes a file from the archive. +// + +bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + TMPQFile * hf = NULL; + int nError = ERROR_SUCCESS; + + // Keep compiler happy + dwSearchScope = dwSearchScope; + + // Check the parameters + if(ha == NULL) + nError = ERROR_INVALID_HANDLE; + if(szFileName == NULL || *szFileName == 0) + nError = ERROR_INVALID_PARAMETER; + if(IsInternalMpqFileName(szFileName)) + nError = ERROR_INTERNAL_FILE; + + // Do not allow to remove files from read-only or patched MPQs + if(nError == ERROR_SUCCESS) + { + if((ha->dwFlags & MPQ_FLAG_READ_ONLY) || (ha->haPatch != NULL)) + nError = ERROR_ACCESS_DENIED; + } + + // If all checks have passed, we can delete the file from the MPQ + if(nError == ERROR_SUCCESS) + { + // Open the file from the MPQ + if(SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf)) + { + // Delete the file entry + nError = DeleteFileEntry(ha, hf); + FreeFileHandle(hf); + } + else + nError = GetLastError(); + } + + // If the file has been deleted, we need to invalidate + // the internal files and recreate HET table + if(nError == ERROR_SUCCESS) + { + // Invalidate the entries for internal files + // After we are done with MPQ changes, we need to re-create them anyway + InvalidateInternalFiles(ha); + + // + // Don't rebuild HET table now; the file's flags indicate + // that it's been deleted, which is enough + // + } + + // Resolve error and exit + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +// Renames the file within the archive. +bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szFileName, const char * szNewFileName) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + TMPQFile * hf; + int nError = ERROR_SUCCESS; + + // Test the valid parameters + if(ha == NULL) + nError = ERROR_INVALID_HANDLE; + if(szFileName == NULL || *szFileName == 0 || szNewFileName == NULL || *szNewFileName == 0) + nError = ERROR_INVALID_PARAMETER; + if(IsInternalMpqFileName(szFileName) || IsInternalMpqFileName(szNewFileName)) + nError = ERROR_INTERNAL_FILE; + + // Do not allow to rename files in MPQ open for read only + if(nError == ERROR_SUCCESS) + { + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + nError = ERROR_ACCESS_DENIED; + } + + // Open the new file. If exists, we don't allow rename operation + if(nError == ERROR_SUCCESS) + { + if(GetFileEntryLocale(ha, szNewFileName, lcFileLocale) != NULL) + nError = ERROR_ALREADY_EXISTS; + } + + // Open the file from the MPQ + if(nError == ERROR_SUCCESS) + { + // Attempt to open the file + if(SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, (HANDLE *)&hf)) + { + ULONGLONG RawDataOffs; + TFileEntry * pFileEntry = hf->pFileEntry; + + // Invalidate the entries for internal files + InvalidateInternalFiles(ha); + + // Rename the file entry in the table + nError = RenameFileEntry(ha, hf, szNewFileName); + + // If the file is encrypted, we have to re-crypt the file content + // with the new decryption key + if((nError == ERROR_SUCCESS) && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)) + { + // Recrypt the file data in the MPQ + nError = RecryptFileData(ha, hf, szFileName, szNewFileName); + + // Update the MD5 of the raw block + if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0) + { + RawDataOffs = ha->MpqPos + pFileEntry->ByteOffset; + WriteMpqDataMD5(ha->pStream, + RawDataOffs, + pFileEntry->dwCmpSize, + ha->pHeader->dwRawChunkSize); + } + } + + // Free the file handle + FreeFileHandle(hf); + } + else + { + nError = GetLastError(); + } + } + + // We also need to rebuild the HET table, if present + if(nError == ERROR_SUCCESS && ha->pHetTable != NULL) + nError = RebuildHetTable(ha); + + // Resolve error and exit + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// Sets default data compression for SFileAddFile + +bool WINAPI SFileSetDataCompression(DWORD DataCompression) +{ + unsigned int uValidMask = (MPQ_COMPRESSION_ZLIB | MPQ_COMPRESSION_PKWARE | MPQ_COMPRESSION_BZIP2 | MPQ_COMPRESSION_SPARSE); + + if((DataCompression & uValidMask) != DataCompression) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + DefaultDataCompression = DataCompression; + return true; +} + +//----------------------------------------------------------------------------- +// Changes locale ID of a file + +bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale) +{ + TMPQArchive * ha; + TFileEntry * pFileEntry; + TMPQFile * hf = IsValidFileHandle(hFile); + + // Invalid handle => do nothing + if(hf == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Do not allow to rename files in MPQ open for read only + ha = hf->ha; + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // Do not allow unnamed access + if(hf->pFileEntry->szFileName == NULL) + { + SetLastError(ERROR_CAN_NOT_COMPLETE); + return false; + } + + // Do not allow to change locale of any internal file + if(IsInternalMpqFileName(hf->pFileEntry->szFileName)) + { + SetLastError(ERROR_INTERNAL_FILE); + return false; + } + + // Do not allow changing file locales if there is no hash table + if(hf->pHashEntry == NULL) + { + SetLastError(ERROR_NOT_SUPPORTED); + return false; + } + + // We have to check if the file+locale is not already there + pFileEntry = GetFileEntryExact(ha, hf->pFileEntry->szFileName, lcNewLocale, NULL); + if(pFileEntry != NULL) + { + SetLastError(ERROR_ALREADY_EXISTS); + return false; + } + + // Update the locale in the hash table entry + hf->pHashEntry->lcLocale = (USHORT)lcNewLocale; + ha->dwFlags |= MPQ_FLAG_CHANGED; + return true; +} + +//----------------------------------------------------------------------------- +// Sets add file callback + +bool WINAPI SFileSetAddFileCallback(HANDLE hMpq, SFILE_ADDFILE_CALLBACK AddFileCB, void * pvUserData) +{ + TMPQArchive * ha = (TMPQArchive *) hMpq; + + if(!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + ha->pvAddFileUserData = pvUserData; + ha->pfnAddFileCB = AddFileCB; + return true; +} diff --git a/dep/StormLib/src/SFileAttributes.cpp b/dep/StormLib/src/SFileAttributes.cpp new file mode 100644 index 000000000..d565be738 --- /dev/null +++ b/dep/StormLib/src/SFileAttributes.cpp @@ -0,0 +1,570 @@ +/*****************************************************************************/ +/* SAttrFile.cpp Copyright (c) Ladislav Zezula 2007 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 12.06.04 1.00 Lad The first version of SAttrFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +typedef struct _MPQ_ATTRIBUTES_HEADER +{ + DWORD dwVersion; // Version of the (attributes) file. Must be 100 (0x64) + DWORD dwFlags; // See MPQ_ATTRIBUTE_XXXX + + // Followed by an array of CRC32 + // Followed by an array of file times + // Followed by an array of MD5 + // Followed by an array of patch bits + + // Note: The MD5 in (attributes), if present, is a hash of the entire file. + // In case the file is an incremental patch, it contains MD5 of the file + // after being patched. + +} MPQ_ATTRIBUTES_HEADER, *PMPQ_ATTRIBUTES_HEADER; + +//----------------------------------------------------------------------------- +// Local functions + +static DWORD GetSizeOfAttributesFile(DWORD dwAttrFlags, DWORD dwBlockTableSize) +{ + DWORD cbAttrFile = sizeof(MPQ_ATTRIBUTES_HEADER); + + // Calculate size of the (attributes) file + if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32) + cbAttrFile += dwBlockTableSize * sizeof(DWORD); + if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) + cbAttrFile += dwBlockTableSize * sizeof(ULONGLONG); + if(dwAttrFlags & MPQ_ATTRIBUTE_MD5) + cbAttrFile += dwBlockTableSize * MD5_DIGEST_SIZE; + + // The bit array has been created without the last bit belonging to (attributes) + // When the number of files is a multiplier of 8 plus one, then the size of (attributes) + // if 1 byte less than expected. + // Example: wow-update-13164.MPQ: BlockTableSize = 0x62E1, but there's only 0xC5C bytes + if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) + cbAttrFile += (dwBlockTableSize + 6) / 8; + + return cbAttrFile; +} + +static DWORD CheckSizeOfAttributesFile(DWORD cbAttrFile, DWORD dwAttrFlags, DWORD dwBlockTableSize) +{ + DWORD cbHeaderSize = sizeof(MPQ_ATTRIBUTES_HEADER); + DWORD cbChecksumSize1 = 0; + DWORD cbChecksumSize2 = 0; + DWORD cbFileTimeSize1 = 0; + DWORD cbFileTimeSize2 = 0; + DWORD cbFileHashSize1 = 0; + DWORD cbFileHashSize2 = 0; + DWORD cbPatchBitSize1 = 0; + DWORD cbPatchBitSize2 = 0; + DWORD cbPatchBitSize3 = 0; + + // + // Various variants with the patch bit + // + // interface.MPQ.part from WoW build 10958 has + // the MPQ_ATTRIBUTE_PATCH_BIT set, but there's an array of DWORDs instead. + // The array is filled with zeros, so we don't know what it should contain + // + // Zenith.SC2MAP has the MPQ_ATTRIBUTE_PATCH_BIT set, but the bit array is missing + // + // Elimination Tournament 2.w3x's (attributes) have one entry less + // + // There may be two variants: Either the (attributes) file has full + // number of entries, or has one entry less + // + + // Get the expected size of CRC32 array + if(dwAttrFlags & MPQ_ATTRIBUTE_CRC32) + { + cbChecksumSize1 += dwBlockTableSize * sizeof(DWORD); + cbChecksumSize2 += cbChecksumSize1 - sizeof(DWORD); + } + + // Get the expected size of FILETIME array + if(dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) + { + cbFileTimeSize1 += dwBlockTableSize * sizeof(ULONGLONG); + cbFileTimeSize2 += cbFileTimeSize1 - sizeof(ULONGLONG); + } + + // Get the expected size of MD5 array + if(dwAttrFlags & MPQ_ATTRIBUTE_MD5) + { + cbFileHashSize1 += dwBlockTableSize * MD5_DIGEST_SIZE; + cbFileHashSize2 += cbFileHashSize1 - MD5_DIGEST_SIZE; + } + + // Get the expected size of patch bit array + if(dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) + { + cbPatchBitSize1 = + cbPatchBitSize2 = ((dwBlockTableSize + 6) / 8); + cbPatchBitSize3 = dwBlockTableSize * sizeof(DWORD); + } + + // Check if the (attributes) file entry count is equal to our file table size + if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize1)) + return dwBlockTableSize; + + // Check if the (attributes) file entry count is equal to our file table size minus one + if(cbAttrFile == (cbHeaderSize + cbChecksumSize2 + cbFileTimeSize2 + cbFileHashSize2 + cbPatchBitSize2)) + return dwBlockTableSize - 1; + + // Zenith.SC2MAP has the MPQ_ATTRIBUTE_PATCH_BIT set, but the bit array is missing + if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1)) + return dwBlockTableSize; + + // interface.MPQ.part (WoW build 10958) has the MPQ_ATTRIBUTE_PATCH_BIT set + // but there's an array of DWORDs (filled with zeros) instead of array of bits + if(cbAttrFile == (cbHeaderSize + cbChecksumSize1 + cbFileTimeSize1 + cbFileHashSize1 + cbPatchBitSize3)) + return dwBlockTableSize; + +#ifdef __STORMLIB_TEST__ + // Invalid size of the (attributes) file + // Note that many MPQs, especially Warcraft III maps have the size of (attributes) invalid. + // We only perform this check if this is the STORMLIB testprogram itself +// assert(false); +#endif + + return 0; +} + +static int LoadAttributesFile(TMPQArchive * ha, LPBYTE pbAttrFile, DWORD cbAttrFile) +{ + LPBYTE pbAttrFileEnd = pbAttrFile + cbAttrFile; + LPBYTE pbAttrPtr = pbAttrFile; + DWORD dwAttributesEntries = 0; + DWORD i; + + // Load and verify the header + if((pbAttrPtr + sizeof(MPQ_ATTRIBUTES_HEADER)) <= pbAttrFileEnd) + { + PMPQ_ATTRIBUTES_HEADER pAttrHeader = (PMPQ_ATTRIBUTES_HEADER)pbAttrPtr; + + // Verify the header version + BSWAP_ARRAY32_UNSIGNED(pAttrHeader, sizeof(MPQ_ATTRIBUTES_HEADER)); + if(pAttrHeader->dwVersion != MPQ_ATTRIBUTES_V1) + return ERROR_BAD_FORMAT; + + // Verify the flags + if(pAttrHeader->dwFlags & ~MPQ_ATTRIBUTE_ALL) + return ERROR_BAD_FORMAT; + + // Verify whether file size of (attributes) is expected + dwAttributesEntries = CheckSizeOfAttributesFile(cbAttrFile, pAttrHeader->dwFlags, ha->pHeader->dwBlockTableSize); + if(dwAttributesEntries == 0) + return ERROR_BAD_FORMAT; + + ha->dwAttrFlags = pAttrHeader->dwFlags; + pbAttrPtr = (LPBYTE)(pAttrHeader + 1); + } + + // Load the CRC32 (if present) + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32) + { + LPDWORD ArrayCRC32 = (LPDWORD)pbAttrPtr; + DWORD cbArraySize = dwAttributesEntries * sizeof(DWORD); + + // Verify if there's enough data + if((pbAttrPtr + cbArraySize) > pbAttrFileEnd) + return ERROR_FILE_CORRUPT; + + BSWAP_ARRAY32_UNSIGNED(ArrayCRC32, cbCRC32Size); + for(i = 0; i < dwAttributesEntries; i++) + ha->pFileTable[i].dwCrc32 = ArrayCRC32[i]; + pbAttrPtr += cbArraySize; + } + + // Load the FILETIME (if present) + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) + { + ULONGLONG * ArrayFileTime = (ULONGLONG *)pbAttrPtr; + DWORD cbArraySize = dwAttributesEntries * sizeof(ULONGLONG); + + // Verify if there's enough data + if((pbAttrPtr + cbArraySize) > pbAttrFileEnd) + return ERROR_FILE_CORRUPT; + + BSWAP_ARRAY64_UNSIGNED(ArrayFileTime, cbFileTimeSize); + for(i = 0; i < dwAttributesEntries; i++) + ha->pFileTable[i].FileTime = ArrayFileTime[i]; + pbAttrPtr += cbArraySize; + } + + // Load the MD5 (if present) + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5) + { + LPBYTE ArrayMd5 = pbAttrPtr; + DWORD cbArraySize = dwAttributesEntries * MD5_DIGEST_SIZE; + + // Verify if there's enough data + if((pbAttrPtr + cbArraySize) > pbAttrFileEnd) + return ERROR_FILE_CORRUPT; + + for(i = 0; i < dwAttributesEntries; i++) + { + memcpy(ha->pFileTable[i].md5, ArrayMd5, MD5_DIGEST_SIZE); + ArrayMd5 += MD5_DIGEST_SIZE; + } + pbAttrPtr += cbArraySize; + } + + // Read the patch bit for each file (if present) + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) + { + LPBYTE pbBitArray = pbAttrPtr; + DWORD cbArraySize = (dwAttributesEntries + 7) / 8; + DWORD dwByteIndex = 0; + DWORD dwBitMask = 0x80; + + // Verify if there's enough data + if((pbAttrPtr + cbArraySize) == pbAttrFileEnd) + { + for(i = 0; i < dwAttributesEntries; i++) + { + ha->pFileTable[i].dwFlags |= (pbBitArray[dwByteIndex] & dwBitMask) ? MPQ_FILE_PATCH_FILE : 0; + dwByteIndex += (dwBitMask & 0x01); + dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01); + } + } + } + + return ERROR_SUCCESS; +} + +static LPBYTE CreateAttributesFile(TMPQArchive * ha, DWORD * pcbAttrFile) +{ + PMPQ_ATTRIBUTES_HEADER pAttrHeader; + TFileEntry * pFileTableEnd = ha->pFileTable + ha->pHeader->dwBlockTableSize; + TFileEntry * pFileEntry; + LPBYTE pbAttrFile; + LPBYTE pbAttrPtr; + size_t cbAttrFile; + + // Check if we need patch bits in the (attributes) file + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + { + ha->dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT; + break; + } + } + + // Allocate the buffer for holding the entire (attributes) + // Allocate 1 byte more (See GetSizeOfAttributesFile for more info) + cbAttrFile = GetSizeOfAttributesFile(ha->dwAttrFlags, ha->pHeader->dwBlockTableSize); + pbAttrFile = pbAttrPtr = STORM_ALLOC(BYTE, cbAttrFile + 1); + if(pbAttrFile != NULL) + { + // Make sure it's all zeroed + memset(pbAttrFile, 0, cbAttrFile + 1); + + // Write the header of the (attributes) file + pAttrHeader = (PMPQ_ATTRIBUTES_HEADER)pbAttrPtr; + pAttrHeader->dwVersion = BSWAP_INT32_UNSIGNED(100); + pAttrHeader->dwFlags = BSWAP_INT32_UNSIGNED((ha->dwAttrFlags & MPQ_ATTRIBUTE_ALL)); + pbAttrPtr = (LPBYTE)(pAttrHeader + 1); + + // Write the array of CRC32, if present + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_CRC32) + { + LPDWORD pArrayCRC32 = (LPDWORD)pbAttrPtr; + + // Copy from file table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + *pArrayCRC32++ = BSWAP_INT32_UNSIGNED(pFileEntry->dwCrc32); + + // Update pointer + pbAttrPtr = (LPBYTE)pArrayCRC32; + } + + // Write the array of file time + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_FILETIME) + { + ULONGLONG * pArrayFileTime = (ULONGLONG *)pbAttrPtr; + + // Copy from file table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + *pArrayFileTime++ = BSWAP_INT64_UNSIGNED(pFileEntry->FileTime); + + // Update pointer + pbAttrPtr = (LPBYTE)pArrayFileTime; + } + + // Write the array of MD5s + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_MD5) + { + LPBYTE pbArrayMD5 = pbAttrPtr; + + // Copy from file table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + memcpy(pbArrayMD5, pFileEntry->md5, MD5_DIGEST_SIZE); + pbArrayMD5 += MD5_DIGEST_SIZE; + } + + // Update pointer + pbAttrPtr = pbArrayMD5; + } + + // Write the array of patch bits + if(ha->dwAttrFlags & MPQ_ATTRIBUTE_PATCH_BIT) + { + LPBYTE pbBitArray = pbAttrPtr; + DWORD dwByteIndex = 0; + BYTE dwBitMask = 0x80; + + // Copy from file table + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Set the bit, if needed + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + pbBitArray[dwByteIndex] |= dwBitMask; + + // Update bit index and bit mask + dwByteIndex += (dwBitMask & 0x01); + dwBitMask = (dwBitMask << 0x07) | (dwBitMask >> 0x01); + } + + // Move past the bit array + pbAttrPtr += (ha->pHeader->dwBlockTableSize + 6) / 8; + } + + // Now we expect that current position matches the estimated size + // Note that if there is 1 extra bit above the byte size, + // the table is actually 1 byte shorter in Blizzard MPQs. See GetSizeOfAttributesFile + assert((size_t)(pbAttrPtr - pbAttrFile) == cbAttrFile); + } + + // Give away the attributes file + if(pcbAttrFile != NULL) + *pcbAttrFile = (DWORD)cbAttrFile; + return pbAttrFile; +} + +//----------------------------------------------------------------------------- +// Public functions (internal use by StormLib) + +int SAttrLoadAttributes(TMPQArchive * ha) +{ + HANDLE hFile = NULL; + LPBYTE pbAttrFile; + DWORD dwBytesRead; + DWORD cbAttrFile = 0; + int nError = ERROR_FILE_CORRUPT; + + // File table must be initialized + assert(ha->pFileTable != NULL); + assert((ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0); + + // Don't load the attributes file from malformed Warcraft III maps + if(ha->dwFlags & MPQ_FLAG_MALFORMED) + return ERROR_FILE_CORRUPT; + + // Attempt to open the "(attributes)" file. + if(SFileOpenFileEx((HANDLE)ha, ATTRIBUTES_NAME, SFILE_OPEN_ANY_LOCALE, &hFile)) + { + // Retrieve and check size of the (attributes) file + cbAttrFile = SFileGetFileSize(hFile, NULL); + + // Integer overflow check + if((cbAttrFile + 1) > cbAttrFile) + { + // Size of the (attributes) might be 1 byte less than expected + // See GetSizeOfAttributesFile for more info + pbAttrFile = STORM_ALLOC(BYTE, cbAttrFile + 1); + if(pbAttrFile != NULL) + { + // Set the last byte to 0 in case the size should be 1 byte greater + pbAttrFile[cbAttrFile] = 0; + + // Load the entire file to memory + SFileReadFile(hFile, pbAttrFile, cbAttrFile, &dwBytesRead, NULL); + if(dwBytesRead == cbAttrFile) + nError = LoadAttributesFile(ha, pbAttrFile, cbAttrFile); + + // Free the buffer + STORM_FREE(pbAttrFile); + } + } + + // Close the attributes file + SFileCloseFile(hFile); + } + + return nError; +} + +// Saves the (attributes) to the MPQ +int SAttrFileSaveToMpq(TMPQArchive * ha) +{ + TMPQFile * hf = NULL; + LPBYTE pbAttrFile; + DWORD cbAttrFile = 0; + int nError = ERROR_SUCCESS; + + // Only save the attributes if we should do so + if(ha->dwFileFlags2 != 0) + { + // At this point, we expect to have at least one reserved entry in the file table + assert(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW); + assert(ha->dwReservedFiles > 0); + + // Create the raw data that is to be written to (attributes) + // Note: Blizzard MPQs have entries for (listfile) and (attributes), + // but they are filled empty + pbAttrFile = CreateAttributesFile(ha, &cbAttrFile); + if(pbAttrFile != NULL) + { + // Determine the real flags for (attributes) + if(ha->dwFileFlags2 == MPQ_FILE_DEFAULT_INTERNAL) + ha->dwFileFlags2 = GetDefaultSpecialFileFlags(cbAttrFile, ha->pHeader->wFormatVersion); + + // Create the attributes file in the MPQ + nError = SFileAddFile_Init(ha, ATTRIBUTES_NAME, + 0, + cbAttrFile, + LANG_NEUTRAL, + ha->dwFileFlags2 | MPQ_FILE_REPLACEEXISTING, + &hf); + + // Write the attributes file raw data to it + if(nError == ERROR_SUCCESS) + { + // Write the content of the attributes file to the MPQ + nError = SFileAddFile_Write(hf, pbAttrFile, cbAttrFile, MPQ_COMPRESSION_ZLIB); + SFileAddFile_Finish(hf); + } + + // Clear the number of reserved files + ha->dwFlags &= ~(MPQ_FLAG_ATTRIBUTES_NEW | MPQ_FLAG_ATTRIBUTES_NONE); + ha->dwReservedFiles--; + + // Free the attributes buffer + STORM_FREE(pbAttrFile); + } + else + { + // If the (attributes) file would be empty, its OK + nError = (cbAttrFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; + } + } + + return nError; +} + +//----------------------------------------------------------------------------- +// Public functions + +DWORD WINAPI SFileGetAttributes(HANDLE hMpq) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Verify the parameters + if(!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return SFILE_INVALID_ATTRIBUTES; + } + + return ha->dwAttrFlags; +} + +bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Verify the parameters + if(!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Not allowed when the archive is read-only + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // Set the attributes + InvalidateInternalFiles(ha); + ha->dwAttrFlags = (dwFlags & MPQ_ATTRIBUTE_ALL); + return true; +} + +bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName) +{ + hash_state md5_state; + TMPQArchive * ha = (TMPQArchive *)hMpq; + TMPQFile * hf; + BYTE Buffer[0x1000]; + HANDLE hFile = NULL; + DWORD dwTotalBytes = 0; + DWORD dwBytesRead; + DWORD dwCrc32; + + // Verify the parameters + if(!IsValidMpqHandle(ha)) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Not allowed when the archive is read-only + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // Attempt to open the file + if(!SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_BASE_FILE, &hFile)) + return false; + + // Get the file size + hf = (TMPQFile *)hFile; + dwTotalBytes = hf->pFileEntry->dwFileSize; + + // Initialize the CRC32 and MD5 contexts + md5_init(&md5_state); + dwCrc32 = crc32(0, Z_NULL, 0); + + // Go through entire file and calculate both CRC32 and MD5 + while(dwTotalBytes != 0) + { + // Read data from file + SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); + if(dwBytesRead == 0) + break; + + // Update CRC32 and MD5 + dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead); + md5_process(&md5_state, Buffer, dwBytesRead); + + // Decrement the total size + dwTotalBytes -= dwBytesRead; + } + + // Update both CRC32 and MD5 + hf->pFileEntry->dwCrc32 = dwCrc32; + md5_done(&md5_state, hf->pFileEntry->md5); + + // Remember that we need to save the MPQ tables + InvalidateInternalFiles(ha); + SFileCloseFile(hFile); + return true; +} diff --git a/dep/StormLib/src/SFileCompactArchive.cpp b/dep/StormLib/src/SFileCompactArchive.cpp new file mode 100644 index 000000000..7b3fcd6f4 --- /dev/null +++ b/dep/StormLib/src/SFileCompactArchive.cpp @@ -0,0 +1,654 @@ +/*****************************************************************************/ +/* SFileCompactArchive.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Archive compacting function */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 14.04.03 1.00 Lad Splitted from SFileCreateArchiveEx.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/* 21.04.13 1.02 Dea Compact callback now part of TMPQArchive */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +/*****************************************************************************/ +/* Local functions */ +/*****************************************************************************/ + +static int CheckIfAllFilesKnown(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + DWORD dwBlockIndex = 0; + int nError = ERROR_SUCCESS; + + // Verify the file table + if(nError == ERROR_SUCCESS) + { + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++, dwBlockIndex++) + { + // If there is an existing entry in the file table, check its name + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + { + // The name must be valid and must not be a pseudo-name + if(pFileEntry->szFileName == NULL || IsPseudoFileName(pFileEntry->szFileName, NULL)) + { + nError = ERROR_UNKNOWN_FILE_NAMES; + break; + } + } + } + } + + return nError; +} + +static int CheckIfAllKeysKnown(TMPQArchive * ha, const TCHAR * szListFile, LPDWORD pFileKeys) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + DWORD dwBlockIndex = 0; + int nError = ERROR_SUCCESS; + + // Add the listfile to the MPQ + if(szListFile != NULL) + { + // Notify the user + if(ha->pfnCompactCB != NULL) + ha->pfnCompactCB(ha->pvCompactUserData, CCB_CHECKING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes); + + nError = SFileAddListFile((HANDLE)ha, szListFile); + } + + // Verify the file table + if(nError == ERROR_SUCCESS) + { + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++, dwBlockIndex++) + { + // If the file exists and it's encrypted + if(pFileEntry->dwFlags & MPQ_FILE_EXISTS) + { + // If we know the name, we decrypt the file key from the file name + if(pFileEntry->szFileName != NULL && !IsPseudoFileName(pFileEntry->szFileName, NULL)) + { + // Give the key to the caller + pFileKeys[dwBlockIndex] = DecryptFileKey(pFileEntry->szFileName, + pFileEntry->ByteOffset, + pFileEntry->dwFileSize, + pFileEntry->dwFlags); + continue; + } + + // We don't know the encryption key of this file, + // thus we cannot compact the file + nError = ERROR_UNKNOWN_FILE_NAMES; + break; + } + } + } + + return nError; +} + +static int CopyNonMpqData( + TMPQArchive * ha, + TFileStream * pSrcStream, + TFileStream * pTrgStream, + ULONGLONG & ByteOffset, + ULONGLONG & ByteCount) +{ + ULONGLONG DataSize = ByteCount; + DWORD dwToRead; + char DataBuffer[0x1000]; + int nError = ERROR_SUCCESS; + + // Copy the data + while(DataSize > 0) + { + // Get the proper size of data + dwToRead = sizeof(DataBuffer); + if(DataSize < dwToRead) + dwToRead = (DWORD)DataSize; + + // Read from the source stream + if(!FileStream_Read(pSrcStream, &ByteOffset, DataBuffer, dwToRead)) + { + nError = GetLastError(); + break; + } + + // Write to the target stream + if(!FileStream_Write(pTrgStream, NULL, DataBuffer, dwToRead)) + { + nError = GetLastError(); + break; + } + + // Update the progress + if(ha->pfnCompactCB != NULL) + { + ha->CompactBytesProcessed += dwToRead; + ha->pfnCompactCB(ha->pvCompactUserData, CCB_COPYING_NON_MPQ_DATA, ha->CompactBytesProcessed, ha->CompactTotalBytes); + } + + // Decrement the number of data to be copied + ByteOffset += dwToRead; + DataSize -= dwToRead; + } + + return nError; +} + +// Copies all file sectors into another archive. +static int CopyMpqFileSectors( + TMPQArchive * ha, + TMPQFile * hf, + TFileStream * pNewStream, + ULONGLONG MpqFilePos) // MPQ file position in the new archive +{ + TFileEntry * pFileEntry = hf->pFileEntry; + ULONGLONG RawFilePos; // Used for calculating sector offset in the old MPQ archive + DWORD dwBytesToCopy = pFileEntry->dwCmpSize; + DWORD dwPatchSize = 0; // Size of patch header + DWORD dwFileKey1 = 0; // File key used for decryption + DWORD dwFileKey2 = 0; // File key used for encryption + DWORD dwCmpSize = 0; // Compressed file size, including patch header + int nError = ERROR_SUCCESS; + + // Resolve decryption keys. Note that the file key given + // in the TMPQFile structure also includes the key adjustment + if(nError == ERROR_SUCCESS && (pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED)) + { + dwFileKey2 = dwFileKey1 = hf->dwFileKey; + if(pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) + { + dwFileKey2 = (dwFileKey1 ^ pFileEntry->dwFileSize) - (DWORD)pFileEntry->ByteOffset; + dwFileKey2 = (dwFileKey2 + (DWORD)MpqFilePos) ^ pFileEntry->dwFileSize; + } + } + + // If we have to save patch header, do it + if(nError == ERROR_SUCCESS && hf->pPatchInfo != NULL) + { + BSWAP_ARRAY32_UNSIGNED(hf->pPatchInfo, sizeof(DWORD) * 3); + if(!FileStream_Write(pNewStream, NULL, hf->pPatchInfo, hf->pPatchInfo->dwLength)) + nError = GetLastError(); + + // Save the size of the patch info + dwPatchSize = hf->pPatchInfo->dwLength; + } + + // If we have to save sector offset table, do it. + if(nError == ERROR_SUCCESS && hf->SectorOffsets != NULL) + { + DWORD * SectorOffsetsCopy = STORM_ALLOC(DWORD, hf->SectorOffsets[0] / sizeof(DWORD)); + DWORD dwSectorOffsLen = hf->SectorOffsets[0]; + + assert((pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) == 0); + assert(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK); + + if(SectorOffsetsCopy == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + + // Encrypt the secondary sector offset table and write it to the target file + if(nError == ERROR_SUCCESS) + { + memcpy(SectorOffsetsCopy, hf->SectorOffsets, dwSectorOffsLen); + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + EncryptMpqBlock(SectorOffsetsCopy, dwSectorOffsLen, dwFileKey2 - 1); + + BSWAP_ARRAY32_UNSIGNED(SectorOffsetsCopy, dwSectorOffsLen); + if(!FileStream_Write(pNewStream, NULL, SectorOffsetsCopy, dwSectorOffsLen)) + nError = GetLastError(); + + dwBytesToCopy -= dwSectorOffsLen; + dwCmpSize += dwSectorOffsLen; + } + + // Update compact progress + if(ha->pfnCompactCB != NULL) + { + ha->CompactBytesProcessed += dwSectorOffsLen; + ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes); + } + + STORM_FREE(SectorOffsetsCopy); + } + + // Now we have to copy all file sectors. We do it without + // recompression, because recompression is not necessary in this case + if(nError == ERROR_SUCCESS) + { + for(DWORD dwSector = 0; dwSector < hf->dwSectorCount; dwSector++) + { + DWORD dwRawDataInSector = hf->dwSectorSize; + DWORD dwRawByteOffset = dwSector * hf->dwSectorSize; + + // Fix the raw data length if the file is compressed + if(hf->SectorOffsets != NULL) + { + dwRawDataInSector = hf->SectorOffsets[dwSector+1] - hf->SectorOffsets[dwSector]; + dwRawByteOffset = hf->SectorOffsets[dwSector]; + } + + // Last sector: If there is not enough bytes remaining in the file, cut the raw size + if(dwRawDataInSector > dwBytesToCopy) + dwRawDataInSector = dwBytesToCopy; + + // Calculate the raw file offset of the file sector + RawFilePos = CalculateRawSectorOffset(hf, dwRawByteOffset); + + // Read the file sector + if(!FileStream_Read(ha->pStream, &RawFilePos, hf->pbFileSector, dwRawDataInSector)) + { + nError = GetLastError(); + break; + } + + // If necessary, re-encrypt the sector + // Note: Recompression is not necessary here. Unlike encryption, + // the compression does not depend on the position of the file in MPQ. + if((pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) && dwFileKey1 != dwFileKey2) + { + BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector); + DecryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey1 + dwSector); + EncryptMpqBlock(hf->pbFileSector, dwRawDataInSector, dwFileKey2 + dwSector); + BSWAP_ARRAY32_UNSIGNED(hf->pbFileSector, dwRawDataInSector); + } + + // Now write the sector back to the file + if(!FileStream_Write(pNewStream, NULL, hf->pbFileSector, dwRawDataInSector)) + { + nError = GetLastError(); + break; + } + + // Update compact progress + if(ha->pfnCompactCB != NULL) + { + ha->CompactBytesProcessed += dwRawDataInSector; + ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes); + } + + // Adjust byte counts + dwBytesToCopy -= dwRawDataInSector; + dwCmpSize += dwRawDataInSector; + } + } + + // Copy the sector CRCs, if any + // Sector CRCs are always compressed (not imploded) and unencrypted + if(nError == ERROR_SUCCESS && hf->SectorOffsets != NULL && hf->SectorChksums != NULL) + { + DWORD dwCrcLength; + + dwCrcLength = hf->SectorOffsets[hf->dwSectorCount + 1] - hf->SectorOffsets[hf->dwSectorCount]; + if(dwCrcLength != 0) + { + if(!FileStream_Read(ha->pStream, NULL, hf->SectorChksums, dwCrcLength)) + nError = GetLastError(); + + if(!FileStream_Write(pNewStream, NULL, hf->SectorChksums, dwCrcLength)) + nError = GetLastError(); + + // Update compact progress + if(ha->pfnCompactCB != NULL) + { + ha->CompactBytesProcessed += dwCrcLength; + ha->pfnCompactCB(ha->pvCompactUserData, CCB_COMPACTING_FILES, ha->CompactBytesProcessed, ha->CompactTotalBytes); + } + + // Size of the CRC block is also included in the compressed file size + dwBytesToCopy -= dwCrcLength; + dwCmpSize += dwCrcLength; + } + } + + // There might be extra data beyond sector checksum table + // Sometimes, these data are even part of sector offset table + // Examples: + // 2012 - WoW\15354\locale-enGB.MPQ:DBFilesClient\SpellLevels.dbc + // 2012 - WoW\15354\locale-enGB.MPQ:Interface\AddOns\Blizzard_AuctionUI\Blizzard_AuctionUI.xml + if(nError == ERROR_SUCCESS && dwBytesToCopy != 0) + { + LPBYTE pbExtraData; + + // Allocate space for the extra data + pbExtraData = STORM_ALLOC(BYTE, dwBytesToCopy); + if(pbExtraData != NULL) + { + if(!FileStream_Read(ha->pStream, NULL, pbExtraData, dwBytesToCopy)) + nError = GetLastError(); + + if(!FileStream_Write(pNewStream, NULL, pbExtraData, dwBytesToCopy)) + nError = GetLastError(); + + // Include these extra data in the compressed size + dwCmpSize += dwBytesToCopy; + STORM_FREE(pbExtraData); + } + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Write the MD5's of the raw file data, if needed + if(nError == ERROR_SUCCESS && ha->pHeader->dwRawChunkSize != 0) + { + nError = WriteMpqDataMD5(pNewStream, + ha->MpqPos + MpqFilePos, + pFileEntry->dwCmpSize, + ha->pHeader->dwRawChunkSize); + } + + // Verify the number of bytes written + if(nError == ERROR_SUCCESS) + { + // At this point, number of bytes written should be exactly + // the same like the compressed file size. If it isn't, + // there's something wrong (an unknown archive version, MPQ malformation, ...) + // + // Note: Diablo savegames have very weird layout, and the file "hero" + // seems to have improper compressed size. Instead of real compressed size, + // the "dwCmpSize" member of the block table entry contains + // uncompressed size of file data + size of the sector table. + // If we compact the archive, Diablo will refuse to load the game + // + // Note: Some patch files in WOW patches don't count the patch header + // into compressed size + // + + if(!(dwCmpSize <= pFileEntry->dwCmpSize && pFileEntry->dwCmpSize <= dwCmpSize + dwPatchSize)) + { + nError = ERROR_FILE_CORRUPT; + assert(false); + } + } + + return nError; +} + +static int CopyMpqFiles(TMPQArchive * ha, LPDWORD pFileKeys, TFileStream * pNewStream) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + TMPQFile * hf = NULL; + ULONGLONG MpqFilePos; + int nError = ERROR_SUCCESS; + + // Walk through all files and write them to the destination MPQ archive + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Copy all the file sectors + // Only do that when the file has nonzero size + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS)) + { + // Query the position where the destination file will be + FileStream_GetPos(pNewStream, &MpqFilePos); + MpqFilePos = MpqFilePos - ha->MpqPos; + + // Perform file copy ONLY if the file has nonzero size + if(pFileEntry->dwFileSize != 0) + { + // Allocate structure for the MPQ file + hf = CreateFileHandle(ha, pFileEntry); + if(hf == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Set the file decryption key + hf->dwFileKey = pFileKeys[pFileEntry - ha->pFileTable]; + + // If the file is a patch file, load the patch header + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + { + nError = AllocatePatchInfo(hf, true); + if(nError != ERROR_SUCCESS) + break; + } + + // Allocate buffers for file sector and sector offset table + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS) + break; + + // Also allocate sector offset table and sector checksum table + nError = AllocateSectorOffsets(hf, true); + if(nError != ERROR_SUCCESS) + break; + + // Also load sector checksums, if any + if(pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) + { + nError = AllocateSectorChecksums(hf, false); + if(nError != ERROR_SUCCESS) + break; + } + + // Copy all file sectors + nError = CopyMpqFileSectors(ha, hf, pNewStream, MpqFilePos); + if(nError != ERROR_SUCCESS) + break; + + // Free buffers. This also sets "hf" to NULL. + FreeFileHandle(hf); + } + + // Note: DO NOT update the compressed size in the file entry, no matter how bad it is. + pFileEntry->ByteOffset = MpqFilePos; + } + } + + // Cleanup and exit + if(hf != NULL) + FreeFileHandle(hf); + return nError; +} + +/*****************************************************************************/ +/* Public functions */ +/*****************************************************************************/ + +//----------------------------------------------------------------------------- +// Changing hash table size + +DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + return ha->dwMaxFileCount; +} + +bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + DWORD dwNewHashTableSize = 0; + int nError = ERROR_SUCCESS; + + // Test the valid parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + nError = ERROR_ACCESS_DENIED; + if(dwMaxFileCount < ha->dwFileTableSize) + nError = ERROR_DISK_FULL; + + // ALL file names must be known in order to be able to rebuild hash table + if(nError == ERROR_SUCCESS && ha->pHashTable != NULL) + { + nError = CheckIfAllFilesKnown(ha); + if(nError == ERROR_SUCCESS) + { + // Calculate the hash table size for the new file limit + dwNewHashTableSize = GetNearestPowerOfTwo(dwMaxFileCount); + + // Rebuild both file tables + nError = RebuildFileTable(ha, dwNewHashTableSize); + } + } + + // We always have to rebuild the (attributes) file due to file table change + if(nError == ERROR_SUCCESS) + { + // Invalidate (listfile) and (attributes) + InvalidateInternalFiles(ha); + + // Rebuild the HET table, if we have any + if(ha->pHetTable != NULL) + nError = RebuildHetTable(ha); + } + + // Return the error + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// Archive compacting + +bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK pfnCompactCB, void * pvUserData) +{ + TMPQArchive * ha = (TMPQArchive *) hMpq; + + if (!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + ha->pfnCompactCB = pfnCompactCB; + ha->pvCompactUserData = pvUserData; + return true; +} + +bool WINAPI SFileCompactArchive(HANDLE hMpq, const TCHAR * szListFile, bool /* bReserved */) +{ + TFileStream * pTempStream = NULL; + TMPQArchive * ha = (TMPQArchive *)hMpq; + ULONGLONG ByteOffset; + ULONGLONG ByteCount; + LPDWORD pFileKeys = NULL; + TCHAR szTempFile[MAX_PATH+1] = _T(""); + int nError = ERROR_SUCCESS; + + // Test the valid parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(ha->dwFlags & MPQ_FLAG_READ_ONLY) + nError = ERROR_ACCESS_DENIED; + + // If the MPQ is changed at this moment, we have to flush the archive + if(nError == ERROR_SUCCESS && (ha->dwFlags & MPQ_FLAG_CHANGED)) + { + SFileFlushArchive(hMpq); + } + + // Create the table with file keys + if(nError == ERROR_SUCCESS) + { + if((pFileKeys = STORM_ALLOC(DWORD, ha->dwFileTableSize)) != NULL) + memset(pFileKeys, 0, sizeof(DWORD) * ha->dwFileTableSize); + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // First of all, we have to check of we are able to decrypt all files. + // If not, sorry, but the archive cannot be compacted. + if(nError == ERROR_SUCCESS) + { + // Initialize the progress variables for compact callback + FileStream_GetSize(ha->pStream, &(ha->CompactTotalBytes)); + ha->CompactBytesProcessed = 0; + nError = CheckIfAllKeysKnown(ha, szListFile, pFileKeys); + } + + // Get the temporary file name and create it + if(nError == ERROR_SUCCESS) + { + // Create temporary file name. Prevent buffer overflow + StringCopy(szTempFile, _countof(szTempFile), FileStream_GetFileName(ha->pStream)); + StringCat(szTempFile, _countof(szTempFile), _T(".tmp")); + + // Create temporary file + pTempStream = FileStream_CreateFile(szTempFile, STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE); + if(pTempStream == NULL) + nError = GetLastError(); + } + + // Write the data before MPQ user data (if any) + if(nError == ERROR_SUCCESS && ha->UserDataPos != 0) + { + // Inform the application about the progress + if(ha->pfnCompactCB != NULL) + ha->pfnCompactCB(ha->pvCompactUserData, CCB_COPYING_NON_MPQ_DATA, ha->CompactBytesProcessed, ha->CompactTotalBytes); + + ByteOffset = 0; + ByteCount = ha->UserDataPos; + nError = CopyNonMpqData(ha, ha->pStream, pTempStream, ByteOffset, ByteCount); + } + + // Write the MPQ user data (if any) + if(nError == ERROR_SUCCESS && ha->MpqPos > ha->UserDataPos) + { + // At this point, we assume that the user data size is equal + // to pUserData->dwHeaderOffs. + // If this assumption doesn't work, then we have an unknown version of MPQ + ByteOffset = ha->UserDataPos; + ByteCount = ha->MpqPos - ha->UserDataPos; + + assert(ha->pUserData != NULL); + assert(ha->pUserData->dwHeaderOffs == ByteCount); + nError = CopyNonMpqData(ha, ha->pStream, pTempStream, ByteOffset, ByteCount); + } + + // Write the MPQ header + if(nError == ERROR_SUCCESS) + { + TMPQHeader SaveMpqHeader; + + // Write the MPQ header to the file + memcpy(&SaveMpqHeader, ha->pHeader, ha->pHeader->dwHeaderSize); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_1); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_2); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_3); + BSWAP_TMPQHEADER(&SaveMpqHeader, MPQ_FORMAT_VERSION_4); + if(!FileStream_Write(pTempStream, NULL, &SaveMpqHeader, ha->pHeader->dwHeaderSize)) + nError = GetLastError(); + + // Update the progress + ha->CompactBytesProcessed += ha->pHeader->dwHeaderSize; + } + + // Now copy all files + if(nError == ERROR_SUCCESS) + nError = CopyMpqFiles(ha, pFileKeys, pTempStream); + + // If succeeded, switch the streams + if(nError == ERROR_SUCCESS) + { + ha->dwFlags |= MPQ_FLAG_CHANGED; + if(FileStream_Replace(ha->pStream, pTempStream)) + pTempStream = NULL; + else + nError = ERROR_CAN_NOT_COMPLETE; + } + + // Final user notification + if(nError == ERROR_SUCCESS && ha->pfnCompactCB != NULL) + { + ha->CompactBytesProcessed += (ha->pHeader->dwHashTableSize * sizeof(TMPQHash)); + ha->CompactBytesProcessed += (ha->dwFileTableSize * sizeof(TMPQBlock)); + ha->pfnCompactCB(ha->pvCompactUserData, CCB_CLOSING_ARCHIVE, ha->CompactBytesProcessed, ha->CompactTotalBytes); + } + + // Cleanup and return + if(pTempStream != NULL) + FileStream_Close(pTempStream); + if(pFileKeys != NULL) + STORM_FREE(pFileKeys); + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} diff --git a/dep/StormLib/src/SFileCreateArchive.cpp b/dep/StormLib/src/SFileCreateArchive.cpp new file mode 100644 index 000000000..de4ab36f9 --- /dev/null +++ b/dep/StormLib/src/SFileCreateArchive.cpp @@ -0,0 +1,274 @@ +/*****************************************************************************/ +/* SFileCreateArchive.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* MPQ Editing functions */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 24.03.03 1.00 Lad Splitted from SFileOpenArchive.cpp */ +/* 08.06.10 1.00 Lad Renamed to SFileCreateArchive.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local variables + +static const DWORD MpqHeaderSizes[] = +{ + MPQ_HEADER_SIZE_V1, + MPQ_HEADER_SIZE_V2, + MPQ_HEADER_SIZE_V3, + MPQ_HEADER_SIZE_V4 +}; + +//----------------------------------------------------------------------------- +// Local functions + +static USHORT GetSectorSizeShift(DWORD dwSectorSize) +{ + USHORT wSectorSizeShift = 0; + + while(dwSectorSize > 0x200) + { + dwSectorSize >>= 1; + wSectorSizeShift++; + } + + return wSectorSizeShift; +} + +static int WriteNakedMPQHeader(TMPQArchive * ha) +{ + TMPQHeader * pHeader = ha->pHeader; + TMPQHeader Header; + DWORD dwBytesToWrite = pHeader->dwHeaderSize; + int nError = ERROR_SUCCESS; + + // Prepare the naked MPQ header + memset(&Header, 0, sizeof(TMPQHeader)); + Header.dwID = pHeader->dwID; + Header.dwHeaderSize = pHeader->dwHeaderSize; + Header.dwArchiveSize = pHeader->dwHeaderSize; + Header.wFormatVersion = pHeader->wFormatVersion; + Header.wSectorSize = pHeader->wSectorSize; + + // Write it to the file + BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_1); + BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_2); + BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_3); + BSWAP_TMPQHEADER(&Header, MPQ_FORMAT_VERSION_4); + if(!FileStream_Write(ha->pStream, &ha->MpqPos, &Header, dwBytesToWrite)) + nError = GetLastError(); + + return nError; +} + +//----------------------------------------------------------------------------- +// Creates a new MPQ archive. + +bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq) +{ + SFILE_CREATE_MPQ CreateInfo; + + // Fill the create structure + memset(&CreateInfo, 0, sizeof(SFILE_CREATE_MPQ)); + CreateInfo.cbSize = sizeof(SFILE_CREATE_MPQ); + CreateInfo.dwMpqVersion = (dwCreateFlags & MPQ_CREATE_ARCHIVE_VMASK) >> FLAGS_TO_FORMAT_SHIFT; + CreateInfo.dwStreamFlags = STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE; + CreateInfo.dwFileFlags1 = (dwCreateFlags & MPQ_CREATE_LISTFILE) ? MPQ_FILE_DEFAULT_INTERNAL : 0; + CreateInfo.dwFileFlags2 = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? MPQ_FILE_DEFAULT_INTERNAL : 0; + CreateInfo.dwFileFlags3 = (dwCreateFlags & MPQ_CREATE_SIGNATURE) ? MPQ_FILE_DEFAULT_INTERNAL : 0; + CreateInfo.dwAttrFlags = (dwCreateFlags & MPQ_CREATE_ATTRIBUTES) ? (MPQ_ATTRIBUTE_CRC32 | MPQ_ATTRIBUTE_FILETIME | MPQ_ATTRIBUTE_MD5) : 0; + CreateInfo.dwSectorSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) ? 0x4000 : 0x1000; + CreateInfo.dwRawChunkSize = (CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_4) ? 0x4000 : 0; + CreateInfo.dwMaxFileCount = dwMaxFileCount; + + // Set the proper attribute parts + if((CreateInfo.dwMpqVersion >= MPQ_FORMAT_VERSION_3) && (dwCreateFlags & MPQ_CREATE_ATTRIBUTES)) + CreateInfo.dwAttrFlags |= MPQ_ATTRIBUTE_PATCH_BIT; + + // Backward compatibility: SFileCreateArchive always used to add (listfile) + // We would break loads of applications if we change that + CreateInfo.dwFileFlags1 = MPQ_FILE_DEFAULT_INTERNAL; + + // Let the main function create the archive + return SFileCreateArchive2(szMpqName, &CreateInfo, phMpq); +} + +bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq) +{ + TFileStream * pStream = NULL; // File stream + TMPQArchive * ha = NULL; // MPQ archive handle + TMPQHeader * pHeader; + ULONGLONG MpqPos = 0; // Position of MPQ header in the file + HANDLE hMpq = NULL; + DWORD dwBlockTableSize = 0; // Initial block table size + DWORD dwHashTableSize = 0; + DWORD dwReservedFiles = 0; // Number of reserved file entries + DWORD dwMpqFlags = 0; + int nError = ERROR_SUCCESS; + + // Check the parameters, if they are valid + if(szMpqName == NULL || *szMpqName == 0 || pCreateInfo == NULL || phMpq == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Verify if all variables in SFILE_CREATE_MPQ are correct + if((pCreateInfo->cbSize == 0 || pCreateInfo->cbSize > sizeof(SFILE_CREATE_MPQ)) || + (pCreateInfo->dwMpqVersion > MPQ_FORMAT_VERSION_4) || + (pCreateInfo->pvUserData != NULL || pCreateInfo->cbUserData != 0) || + (pCreateInfo->dwAttrFlags & ~MPQ_ATTRIBUTE_ALL) || + (pCreateInfo->dwSectorSize & (pCreateInfo->dwSectorSize - 1)) || + (pCreateInfo->dwRawChunkSize & (pCreateInfo->dwRawChunkSize - 1))) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // One time initialization of MPQ cryptography + InitializeMpqCryptography(); + + // We verify if the file already exists and if it's a MPQ archive. + // If yes, we won't allow to overwrite it. + if(SFileOpenArchive(szMpqName, 0, STREAM_PROVIDER_FLAT | BASE_PROVIDER_FILE | MPQ_OPEN_NO_ATTRIBUTES | MPQ_OPEN_NO_LISTFILE, &hMpq)) + { + SFileCloseArchive(hMpq); + SetLastError(ERROR_ALREADY_EXISTS); + return false; + } + + // + // At this point, we have to create the archive. + // - If the file exists, convert it to MPQ archive. + // - If the file doesn't exist, create new empty file + // + + pStream = FileStream_OpenFile(szMpqName, pCreateInfo->dwStreamFlags); + if(pStream == NULL) + { + pStream = FileStream_CreateFile(szMpqName, pCreateInfo->dwStreamFlags); + if(pStream == NULL) + return false; + } + + // Increment the maximum amount of files to have space for (listfile) + if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags1) + { + dwMpqFlags |= MPQ_FLAG_LISTFILE_NEW; + dwReservedFiles++; + } + + // Increment the maximum amount of files to have space for (attributes) + if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags2 && pCreateInfo->dwAttrFlags) + { + dwMpqFlags |= MPQ_FLAG_ATTRIBUTES_NEW; + dwReservedFiles++; + } + + // Increment the maximum amount of files to have space for (signature) + if(pCreateInfo->dwMaxFileCount && pCreateInfo->dwFileFlags3) + { + dwMpqFlags |= MPQ_FLAG_SIGNATURE_NEW; + dwReservedFiles++; + } + + // If file count is not zero, initialize the hash table size + dwHashTableSize = GetNearestPowerOfTwo(pCreateInfo->dwMaxFileCount + dwReservedFiles); + + // Retrieve the file size and round it up to 0x200 bytes + FileStream_GetSize(pStream, &MpqPos); + MpqPos = (MpqPos + 0x1FF) & (ULONGLONG)0xFFFFFFFFFFFFFE00ULL; + if(!FileStream_SetSize(pStream, MpqPos)) + nError = GetLastError(); + +#ifdef _DEBUG + // Debug code, used for testing StormLib +// dwBlockTableSize = dwHashTableSize * 2; +#endif + + // Create the archive handle + if(nError == ERROR_SUCCESS) + { + if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Fill the MPQ archive handle structure + if(nError == ERROR_SUCCESS) + { + memset(ha, 0, sizeof(TMPQArchive)); + ha->pfnHashString = HashStringSlash; + ha->pStream = pStream; + ha->dwSectorSize = pCreateInfo->dwSectorSize; + ha->UserDataPos = MpqPos; + ha->MpqPos = MpqPos; + ha->pHeader = pHeader = (TMPQHeader *)ha->HeaderData; + ha->dwMaxFileCount = dwHashTableSize; + ha->dwFileTableSize = 0; + ha->dwReservedFiles = dwReservedFiles; + ha->dwFileFlags1 = pCreateInfo->dwFileFlags1; + ha->dwFileFlags2 = pCreateInfo->dwFileFlags2; + ha->dwFileFlags3 = pCreateInfo->dwFileFlags3 ? MPQ_FILE_EXISTS : 0; + ha->dwAttrFlags = pCreateInfo->dwAttrFlags; + ha->dwFlags = dwMpqFlags | MPQ_FLAG_CHANGED; + pStream = NULL; + + // Fill the MPQ header + memset(pHeader, 0, sizeof(ha->HeaderData)); + pHeader->dwID = ID_MPQ; + pHeader->dwHeaderSize = MpqHeaderSizes[pCreateInfo->dwMpqVersion]; + pHeader->dwArchiveSize = pHeader->dwHeaderSize + dwHashTableSize * sizeof(TMPQHash); + pHeader->wFormatVersion = (USHORT)pCreateInfo->dwMpqVersion; + pHeader->wSectorSize = GetSectorSizeShift(ha->dwSectorSize); + pHeader->dwHashTablePos = pHeader->dwHeaderSize; + pHeader->dwHashTableSize = dwHashTableSize; + pHeader->dwBlockTablePos = pHeader->dwHashTablePos + dwHashTableSize * sizeof(TMPQHash); + pHeader->dwBlockTableSize = dwBlockTableSize; + + // For MPQs version 4 and higher, we set the size of raw data block + // for calculating MD5 + if(pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_4) + pHeader->dwRawChunkSize = pCreateInfo->dwRawChunkSize; + + // Write the naked MPQ header + nError = WriteNakedMPQHeader(ha); + } + + // Create initial HET table, if the caller required an MPQ format 3.0 or newer + if(nError == ERROR_SUCCESS && pCreateInfo->dwMpqVersion >= MPQ_FORMAT_VERSION_3 && pCreateInfo->dwMaxFileCount != 0) + { + ha->pHetTable = CreateHetTable(ha->dwFileTableSize, 0, 0x40, NULL); + if(ha->pHetTable == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Create initial hash table + if(nError == ERROR_SUCCESS && dwHashTableSize != 0) + { + nError = CreateHashTable(ha, dwHashTableSize); + } + + // Create initial file table + if(nError == ERROR_SUCCESS && ha->dwMaxFileCount != 0) + { + nError = CreateFileTable(ha, ha->dwMaxFileCount); + } + + // Cleanup : If an error, delete all buffers and return + if(nError != ERROR_SUCCESS) + { + FileStream_Close(pStream); + FreeArchiveHandle(ha); + SetLastError(nError); + ha = NULL; + } + + // Return the values + *phMpq = (HANDLE)ha; + return (nError == ERROR_SUCCESS); +} diff --git a/dep/StormLib/src/SFileExtractFile.cpp b/dep/StormLib/src/SFileExtractFile.cpp new file mode 100644 index 000000000..cabde4927 --- /dev/null +++ b/dep/StormLib/src/SFileExtractFile.cpp @@ -0,0 +1,64 @@ +/*****************************************************************************/ +/* SFileExtractFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Simple extracting utility */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 20.06.03 1.00 Lad The first version of SFileExtractFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope) +{ + TFileStream * pLocalFile = NULL; + HANDLE hMpqFile = NULL; + int nError = ERROR_SUCCESS; + + // Open the MPQ file + if(nError == ERROR_SUCCESS) + { + if(!SFileOpenFileEx(hMpq, szToExtract, dwSearchScope, &hMpqFile)) + nError = GetLastError(); + } + + // Create the local file + if(nError == ERROR_SUCCESS) + { + pLocalFile = FileStream_CreateFile(szExtracted, 0); + if(pLocalFile == NULL) + nError = GetLastError(); + } + + // Copy the file's content + while(nError == ERROR_SUCCESS) + { + char szBuffer[0x1000]; + DWORD dwTransferred = 0; + + // dwTransferred is only set to nonzero if something has been read. + // nError can be ERROR_SUCCESS or ERROR_HANDLE_EOF + if(!SFileReadFile(hMpqFile, szBuffer, sizeof(szBuffer), &dwTransferred, NULL)) + nError = GetLastError(); + if(nError == ERROR_HANDLE_EOF) + nError = ERROR_SUCCESS; + if(dwTransferred == 0) + break; + + // If something has been actually read, write it + if(!FileStream_Write(pLocalFile, NULL, szBuffer, dwTransferred)) + nError = GetLastError(); + } + + // Close the files + if(hMpqFile != NULL) + SFileCloseFile(hMpqFile); + if(pLocalFile != NULL) + FileStream_Close(pLocalFile); + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} diff --git a/dep/StormLib/src/SFileFindFile.cpp b/dep/StormLib/src/SFileFindFile.cpp new file mode 100644 index 000000000..a27cf02f7 --- /dev/null +++ b/dep/StormLib/src/SFileFindFile.cpp @@ -0,0 +1,479 @@ +/*****************************************************************************/ +/* SFileFindFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* A module for file searching within MPQs */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 25.03.03 1.00 Lad The first version of SFileFindFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Private structure used for file search (search handle) + +// Used by searching in MPQ archives +struct TMPQSearch +{ + TMPQArchive * ha; // Handle to MPQ, where the search runs + TFileEntry ** pSearchTable; // Table for files that have been already found + DWORD dwSearchTableItems; // Number of items in the search table + DWORD dwNextIndex; // Next file index to be checked + DWORD dwFlagMask; // For checking flag mask + char szSearchMask[1]; // Search mask (variable length) +}; + +//----------------------------------------------------------------------------- +// Local functions + +static TMPQSearch * IsValidSearchHandle(HANDLE hFind) +{ + TMPQSearch * hs = (TMPQSearch *)hFind; + + if(hs != NULL && IsValidMpqHandle(hs->ha)) + return hs; + + return NULL; +} + +bool CheckWildCard(const char * szString, const char * szWildCard) +{ + const char * szWildCardPtr; + + for(;;) + { + // If there is '?' in the wildcard, we skip one char + while(szWildCard[0] == '?') + { + if(szString[0] == 0) + return false; + + szWildCard++; + szString++; + } + + // Handle '*' + szWildCardPtr = szWildCard; + if(szWildCardPtr[0] != 0) + { + if(szWildCardPtr[0] == '*') + { + szWildCardPtr++; + + if(szWildCardPtr[0] == '*') + continue; + + if(szWildCardPtr[0] == 0) + return true; + + if(AsciiToUpperTable[szWildCardPtr[0]] == AsciiToUpperTable[szString[0]]) + { + if(CheckWildCard(szString, szWildCardPtr)) + return true; + } + } + else + { + if(AsciiToUpperTable[szWildCardPtr[0]] != AsciiToUpperTable[szString[0]]) + return false; + + szWildCard = szWildCardPtr + 1; + } + + if(szString[0] == 0) + return false; + szString++; + } + else + { + return (szString[0] == 0) ? true : false; + } + } +} + +static DWORD GetSearchTableItems(TMPQArchive * ha) +{ + DWORD dwMergeItems = 0; + + // Loop over all patches + while(ha != NULL) + { + // Append the number of files + dwMergeItems += (ha->pHetTable != NULL) ? ha->pHetTable->dwEntryCount + : ha->pHeader->dwBlockTableSize; + // Move to the patched archive + ha = ha->haPatch; + } + + // Return the double size of number of items + return (dwMergeItems | 1); +} + +static bool FileWasFoundBefore( + TMPQArchive * ha, + TMPQSearch * hs, + TFileEntry * pFileEntry) +{ + TFileEntry * pEntry; + char * szRealFileName = pFileEntry->szFileName; + DWORD dwStartIndex; + DWORD dwNameHash; + DWORD dwIndex; + + if(hs->pSearchTable != NULL && szRealFileName != NULL) + { + // If we are in patch MPQ, we check if patch prefix matches + // and then trim the patch prefix + if(ha->pPatchPrefix != NULL) + { + // If the patch prefix doesn't fit, we pretend that the file + // was there before and it will be skipped + if(_strnicmp(szRealFileName, ha->pPatchPrefix->szPatchPrefix, ha->pPatchPrefix->nLength)) + return true; + + szRealFileName += ha->pPatchPrefix->nLength; + } + + // Calculate the hash to the table + dwNameHash = ha->pfnHashString(szRealFileName, MPQ_HASH_NAME_A); + dwStartIndex = dwIndex = (dwNameHash % hs->dwSearchTableItems); + + // The file might have been found before + // only if this is not the first MPQ being searched + if(ha->haBase != NULL) + { + // Enumerate all entries in the search table + for(;;) + { + // Get the file entry at that position + pEntry = hs->pSearchTable[dwIndex]; + if(pEntry == NULL) + break; + + if(pEntry->szFileName != NULL) + { + // Does the name match? + if(!_stricmp(pEntry->szFileName, szRealFileName)) + return true; + } + + // Move to the next entry + dwIndex = (dwIndex + 1) % hs->dwSearchTableItems; + if(dwIndex == dwStartIndex) + break; + } + } + + // Put the entry to the table for later use + hs->pSearchTable[dwIndex] = pFileEntry; + } + return false; +} + +static TFileEntry * FindPatchEntry(TMPQArchive * ha, TFileEntry * pFileEntry) +{ + TFileEntry * pPatchEntry = pFileEntry; + TFileEntry * pTempEntry; + char szFileName[MAX_PATH+1]; + + // Can't find patch entry for a file that doesn't have name + if(pFileEntry->szFileName != NULL && pFileEntry->szFileName[0] != 0) + { + // Go while there are patches + while(ha->haPatch != NULL) + { + // Move to the patch archive + ha = ha->haPatch; + szFileName[0] = 0; + + // Prepare the prefix for the file name + if(ha->pPatchPrefix && ha->pPatchPrefix->nLength) + StringCopy(szFileName, _countof(szFileName), ha->pPatchPrefix->szPatchPrefix); + StringCat(szFileName, _countof(szFileName), pFileEntry->szFileName); + + // Try to find the file there + pTempEntry = GetFileEntryExact(ha, szFileName, 0, NULL); + if(pTempEntry != NULL) + pPatchEntry = pTempEntry; + } + } + + // Return the found patch entry + return pPatchEntry; +} + +static bool DoMPQSearch_FileEntry( + TMPQSearch * hs, + SFILE_FIND_DATA * lpFindFileData, + TMPQArchive * ha, + TMPQHash * pHashEntry, + TFileEntry * pFileEntry) +{ + TFileEntry * pPatchEntry; + HANDLE hFile = NULL; + const char * szFileName; + size_t nPrefixLength = (ha->pPatchPrefix != NULL) ? ha->pPatchPrefix->nLength : 0; + DWORD dwBlockIndex; + char szNameBuff[MAX_PATH]; + + // Is it a file but not a patch file? + if((pFileEntry->dwFlags & hs->dwFlagMask) == MPQ_FILE_EXISTS) + { + // Now we have to check if this file was not enumerated before + if(!FileWasFoundBefore(ha, hs, pFileEntry)) + { +// if(pFileEntry != NULL && !_stricmp(pFileEntry->szFileName, "TriggerLibs\\NativeLib.galaxy")) +// DebugBreak(); + + // Find a patch to this file + // Note: This either succeeds or returns pFileEntry + pPatchEntry = FindPatchEntry(ha, pFileEntry); + + // Prepare the block index + dwBlockIndex = (DWORD)(pFileEntry - ha->pFileTable); + + // Get the file name. If it's not known, we will create pseudo-name + szFileName = pFileEntry->szFileName; + if(szFileName == NULL) + { + // Open the file by its pseudo-name. + sprintf(szNameBuff, "File%08u.xxx", (unsigned int)dwBlockIndex); + if(SFileOpenFileEx((HANDLE)hs->ha, szNameBuff, SFILE_OPEN_BASE_FILE, &hFile)) + { + SFileGetFileName(hFile, szNameBuff); + szFileName = szNameBuff; + SFileCloseFile(hFile); + } + } + + // If the file name is still NULL, we cannot include the file to search results + if(szFileName != NULL) + { + // Check the file name against the wildcard + if(CheckWildCard(szFileName + nPrefixLength, hs->szSearchMask)) + { + // Fill the found entry. hash entry and block index are taken from the base MPQ + lpFindFileData->dwHashIndex = HASH_ENTRY_FREE; + lpFindFileData->dwBlockIndex = dwBlockIndex; + lpFindFileData->dwFileSize = pPatchEntry->dwFileSize; + lpFindFileData->dwFileFlags = pPatchEntry->dwFlags; + lpFindFileData->dwCompSize = pPatchEntry->dwCmpSize; + lpFindFileData->lcLocale = 0; // pPatchEntry->lcLocale; + + // Fill the filetime + lpFindFileData->dwFileTimeHi = (DWORD)(pPatchEntry->FileTime >> 32); + lpFindFileData->dwFileTimeLo = (DWORD)(pPatchEntry->FileTime); + + // Fill-in the entries from hash table entry, if given + if(pHashEntry != NULL) + { + lpFindFileData->dwHashIndex = (DWORD)(pHashEntry - ha->pHashTable); + lpFindFileData->lcLocale = pHashEntry->lcLocale; + } + + // Fill the file name and plain file name + StringCopy(lpFindFileData->cFileName, _countof(lpFindFileData->cFileName), szFileName + nPrefixLength); + lpFindFileData->szPlainName = (char *)GetPlainFileName(lpFindFileData->cFileName); + return true; + } + } + } + } + + // Either not a valid item or was found before + return false; +} + +static int DoMPQSearch_HashTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha) +{ + TMPQHash * pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + TMPQHash * pHash; + + // Parse the file table + for(pHash = ha->pHashTable + hs->dwNextIndex; pHash < pHashTableEnd; pHash++) + { + // Increment the next index for subsequent search + hs->dwNextIndex++; + + // Does this hash table entry point to a proper block table entry? + if(IsValidHashEntry(ha, pHash)) + { + // Check if this file entry should be included in the search result + if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, pHash, ha->pFileTable + MPQ_BLOCK_INDEX(pHash))) + return ERROR_SUCCESS; + } + } + + // No more files + return ERROR_NO_MORE_FILES; +} + +static int DoMPQSearch_FileTable(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData, TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + + // Parse the file table + for(pFileEntry = ha->pFileTable + hs->dwNextIndex; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Increment the next index for subsequent search + hs->dwNextIndex++; + + // Check if this file entry should be included in the search result + if(DoMPQSearch_FileEntry(hs, lpFindFileData, ha, NULL, pFileEntry)) + return ERROR_SUCCESS; + } + + // No more files + return ERROR_NO_MORE_FILES; +} + +// Performs one MPQ search +static int DoMPQSearch(TMPQSearch * hs, SFILE_FIND_DATA * lpFindFileData) +{ + TMPQArchive * ha = hs->ha; + int nError; + + // Start searching with base MPQ + while(ha != NULL) + { + // If the archive has hash table, we need to use hash table + // in order to catch hash table index and file locale. + // Note: If multiple hash table entries, point to the same block entry, + // we need, to report them all + nError = (ha->pHashTable != NULL) ? DoMPQSearch_HashTable(hs, lpFindFileData, ha) + : DoMPQSearch_FileTable(hs, lpFindFileData, ha); + if(nError == ERROR_SUCCESS) + return nError; + + // If there is no more patches in the chain, stop it. + // This also keeps hs->ha non-NULL, which is required + // for freeing the handle later + if(ha->haPatch == NULL) + break; + + // Move to the next patch in the patch chain + hs->ha = ha = ha->haPatch; + hs->dwNextIndex = 0; + } + + // No more files found, return error + return ERROR_NO_MORE_FILES; +} + +static void FreeMPQSearch(TMPQSearch *& hs) +{ + if(hs != NULL) + { + if(hs->pSearchTable != NULL) + STORM_FREE(hs->pSearchTable); + STORM_FREE(hs); + hs = NULL; + } +} + +//----------------------------------------------------------------------------- +// Public functions + +HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const TCHAR * szListFile) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + TMPQSearch * hs = NULL; + size_t nSize = 0; + int nError = ERROR_SUCCESS; + + // Check for the valid parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(szMask == NULL || lpFindFileData == NULL) + nError = ERROR_INVALID_PARAMETER; + + // Include the listfile into the MPQ's internal listfile + // Note that if the listfile name is NULL, do nothing because the + // internal listfile is always included. + if(nError == ERROR_SUCCESS && szListFile != NULL && *szListFile != 0) + nError = SFileAddListFile((HANDLE)ha, szListFile); + + // Allocate the structure for MPQ search + if(nError == ERROR_SUCCESS) + { + nSize = sizeof(TMPQSearch) + strlen(szMask) + 1; + if((hs = (TMPQSearch *)STORM_ALLOC(char, nSize)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Perform the first search + if(nError == ERROR_SUCCESS) + { + memset(hs, 0, sizeof(TMPQSearch)); + strcpy(hs->szSearchMask, szMask); + hs->dwFlagMask = MPQ_FILE_EXISTS; + hs->ha = ha; + + // If the archive is patched archive, we have to create a merge table + // to prevent files being repeated + if(ha->haPatch != NULL) + { + hs->dwSearchTableItems = GetSearchTableItems(ha); + hs->pSearchTable = STORM_ALLOC(TFileEntry *, hs->dwSearchTableItems); + hs->dwFlagMask = MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE; + if(hs->pSearchTable != NULL) + memset(hs->pSearchTable, 0, hs->dwSearchTableItems * sizeof(TFileEntry *)); + else + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Perform first item searching + if(nError == ERROR_SUCCESS) + { + nError = DoMPQSearch(hs, lpFindFileData); + } + + // Cleanup + if(nError != ERROR_SUCCESS) + { + FreeMPQSearch(hs); + SetLastError(nError); + } + + // Return the result value + return (HANDLE)hs; +} + +bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) +{ + TMPQSearch * hs = IsValidSearchHandle(hFind); + int nError = ERROR_SUCCESS; + + // Check the parameters + if(hs == NULL) + nError = ERROR_INVALID_HANDLE; + if(lpFindFileData == NULL) + nError = ERROR_INVALID_PARAMETER; + + if(nError == ERROR_SUCCESS) + nError = DoMPQSearch(hs, lpFindFileData); + + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +bool WINAPI SFileFindClose(HANDLE hFind) +{ + TMPQSearch * hs = IsValidSearchHandle(hFind); + + // Check the parameters + if(hs == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + FreeMPQSearch(hs); + return true; +} diff --git a/dep/StormLib/src/SFileGetFileInfo.cpp b/dep/StormLib/src/SFileGetFileInfo.cpp new file mode 100644 index 000000000..226e8b8d6 --- /dev/null +++ b/dep/StormLib/src/SFileGetFileInfo.cpp @@ -0,0 +1,1003 @@ +/*****************************************************************************/ +/* SFileGetFileInfo.cpp Copyright (c) Ladislav Zezula 2013 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 30.11.13 1.00 Lad The first version of SFileGetFileInfo.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +// Information types for SFileGetFileInfo +#define SFILE_INFO_TYPE_INVALID_HANDLE 0 +#define SFILE_INFO_TYPE_NOT_FOUND 1 +#define SFILE_INFO_TYPE_DIRECT_POINTER 2 +#define SFILE_INFO_TYPE_ALLOCATED 3 +#define SFILE_INFO_TYPE_READ_FROM_FILE 4 +#define SFILE_INFO_TYPE_TABLE_POINTER 5 +#define SFILE_INFO_TYPE_FILE_ENTRY 6 + +//----------------------------------------------------------------------------- +// Local functions + +static void ConvertFileEntryToSelfRelative(TFileEntry * pFileEntry, TFileEntry * pSrcFileEntry) +{ + // Copy the file entry itself + memcpy(pFileEntry, pSrcFileEntry, sizeof(TFileEntry)); + + // If source is NULL, leave it NULL + if(pSrcFileEntry->szFileName != NULL) + { + // Set the file name pointer after the file entry + pFileEntry->szFileName = (char *)(pFileEntry + 1); + strcpy(pFileEntry->szFileName, pSrcFileEntry->szFileName); + } +} + + +static DWORD GetMpqFileCount(TMPQArchive * ha) +{ + TFileEntry * pFileTableEnd; + TFileEntry * pFileEntry; + DWORD dwFileCount = 0; + + // Go through all open MPQs, including patches + while(ha != NULL) + { + // Only count files that are not patch files + pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // If the file is patch file and this is not primary archive, skip it + // BUGBUG: This errorneously counts non-patch files that are in both + // base MPQ and in patches, and increases the number of files by cca 50% + if((pFileEntry->dwFlags & (MPQ_FILE_EXISTS | MPQ_FILE_PATCH_FILE)) == MPQ_FILE_EXISTS) + dwFileCount++; + } + + // Move to the next patch archive + ha = ha->haPatch; + } + + return dwFileCount; +} + +static bool GetFilePatchChain(TMPQFile * hf, void * pvFileInfo, DWORD cbFileInfo, DWORD * pcbLengthNeeded) +{ + TMPQFile * hfTemp; + TCHAR * szFileInfo = (TCHAR *)pvFileInfo; + size_t cchCharsNeeded = 1; + size_t cchFileInfo = (cbFileInfo / sizeof(TCHAR)); + size_t nLength; + + // Patch chain is only supported on MPQ files. + if(hf->pStream != NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // Calculate the necessary length of the multi-string + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + cchCharsNeeded += _tcslen(FileStream_GetFileName(hfTemp->ha->pStream)) + 1; + + // Give the caller the needed length + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = (DWORD)(cchCharsNeeded * sizeof(TCHAR)); + + // If the caller gave both buffer pointer and data length, + // try to copy the patch chain + if(szFileInfo != NULL && cchFileInfo != 0) + { + // If there is enough space in the buffer, copy the patch chain + if(cchCharsNeeded > cchFileInfo) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return false; + } + + // Copy each patch + for(hfTemp = hf; hfTemp != NULL; hfTemp = hfTemp->hfPatch) + { + // Get the file name and its length + const TCHAR * szFileName = FileStream_GetFileName(hfTemp->ha->pStream); + nLength = _tcslen(szFileName) + 1; + + // Copy the file name + memcpy(szFileInfo, szFileName, nLength * sizeof(TCHAR)); + szFileInfo += nLength; + } + + // Make it multi-string + szFileInfo[0] = 0; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Retrieves an information about an archive or about a file within the archive +// +// hMpqOrFile - Handle to an MPQ archive or to a file +// InfoClass - Information to obtain +// pvFileInfo - Pointer to buffer to store the information +// cbFileInfo - Size of the buffer pointed by pvFileInfo +// pcbLengthNeeded - Receives number of bytes necessary to store the information + +bool WINAPI SFileGetFileInfo( + HANDLE hMpqOrFile, + SFileInfoClass InfoClass, + void * pvFileInfo, + DWORD cbFileInfo, + LPDWORD pcbLengthNeeded) +{ + MPQ_SIGNATURE_INFO SignatureInfo; + TMPQArchive * ha = NULL; + TFileEntry * pFileEntry = NULL; + ULONGLONG Int64Value = 0; + ULONGLONG ByteOffset = 0; + TMPQFile * hf = NULL; + void * pvSrcFileInfo = NULL; + DWORD cbSrcFileInfo = 0; + DWORD dwInt32Value = 0; + int nInfoType = SFILE_INFO_TYPE_INVALID_HANDLE; + int nError = ERROR_SUCCESS; + + switch(InfoClass) + { + case SFileMpqFileName: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = (void *)FileStream_GetFileName(ha->pStream); + cbSrcFileInfo = (DWORD)(_tcslen((TCHAR *)pvSrcFileInfo) + 1) * sizeof(TCHAR); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqStreamBitmap: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + return FileStream_GetBitmap(ha->pStream, pvFileInfo, cbFileInfo, pcbLengthNeeded); + break; + + case SFileMpqUserDataOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + pvSrcFileInfo = &ha->UserDataPos; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqUserDataHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + ByteOffset = ha->UserDataPos; + cbSrcFileInfo = sizeof(TMPQUserData); + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + } + break; + + case SFileMpqUserData: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pUserData != NULL) + { + ByteOffset = ha->UserDataPos + sizeof(TMPQUserData); + cbSrcFileInfo = ha->pUserData->dwHeaderOffs - sizeof(TMPQUserData); + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + } + break; + + case SFileMpqHeaderOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->MpqPos; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHeaderSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwHeaderSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + ByteOffset = ha->MpqPos; + cbSrcFileInfo = ha->pHeader->dwHeaderSize; + nInfoType = SFILE_INFO_TYPE_READ_FROM_FILE; + } + break; + + case SFileMpqHetTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HetTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHetTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HetTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHetHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->HetTablePos64, (size_t)ha->pHeader->HetTableSize64, HET_TABLE_SIGNATURE, MPQ_KEY_HASH_TABLE); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(TMPQHetHeader); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqHetTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadHetTable(ha); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(void *); + nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; + } + } + break; + + case SFileMpqBetTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BetTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBetTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BetTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBetHeader: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadExtTable(ha, ha->pHeader->BetTablePos64, (size_t)ha->pHeader->BetTableSize64, BET_TABLE_SIGNATURE, MPQ_KEY_BLOCK_TABLE); + if(pvSrcFileInfo != NULL) + { + // It is allowed for the caller to only require BET header. + cbSrcFileInfo = sizeof(TMPQBetHeader) + ((TMPQBetHeader *)pvSrcFileInfo)->dwFlagCount * sizeof(DWORD); + if(cbFileInfo == sizeof(TMPQBetHeader)) + cbSrcFileInfo = sizeof(TMPQBetHeader); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqBetTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + pvSrcFileInfo = LoadBetTable(ha); + if(pvSrcFileInfo != NULL) + { + cbSrcFileInfo = sizeof(void *); + nInfoType = SFILE_INFO_TYPE_TABLE_POINTER; + } + } + break; + + case SFileMpqHashTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + Int64Value = MAKE_OFFSET64(ha->pHeader->wHashTablePosHi, ha->pHeader->dwHashTablePos); + pvSrcFileInfo = &Int64Value; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HashTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwHashTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHashTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL && ha->pHashTable != NULL) + { + pvSrcFileInfo = ha->pHashTable; + cbSrcFileInfo = ha->pHeader->dwHashTableSize * sizeof(TMPQHash); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + Int64Value = MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos); + pvSrcFileInfo = &Int64Value; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->BlockTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwBlockTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqBlockTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(MAKE_OFFSET64(ha->pHeader->wBlockTablePosHi, ha->pHeader->dwBlockTablePos) < ha->FileSize) + { + cbSrcFileInfo = ha->pHeader->dwBlockTableSize * sizeof(TMPQBlock); + if(cbFileInfo >= cbSrcFileInfo) + pvSrcFileInfo = LoadBlockTable(ha, true); + nInfoType = SFILE_INFO_TYPE_ALLOCATED; + } + } + break; + + case SFileMpqHiBlockTableOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HiBlockTablePos64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHiBlockTableSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->HiBlockTableSize64; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqHiBlockTable: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pHeader->HiBlockTablePos64 && ha->pHeader->HiBlockTableSize64) + { + assert(false); + } + } + break; + + case SFileMpqSignatures: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL && QueryMpqSignatureInfo(ha, &SignatureInfo)) + { + pvSrcFileInfo = &SignatureInfo.SignatureTypes; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqStrongSignatureOffset: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + pvSrcFileInfo = &SignatureInfo.EndMpqData; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStrongSignatureSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + dwInt32Value = MPQ_STRONG_SIGNATURE_SIZE + 4; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStrongSignature: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(QueryMpqSignatureInfo(ha, &SignatureInfo) && (SignatureInfo.SignatureTypes & SIGNATURE_TYPE_STRONG)) + { + pvSrcFileInfo = SignatureInfo.Signature; + cbSrcFileInfo = MPQ_STRONG_SIGNATURE_SIZE + 4; + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqArchiveSize64: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->ArchiveSize64; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqArchiveSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->pHeader->dwArchiveSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqMaxFileCount: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwMaxFileCount; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqFileTableSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwFileTableSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqSectorSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &ha->dwSectorSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqNumberOfFiles: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + dwInt32Value = GetMpqFileCount(ha); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqRawChunkSize: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + nInfoType = SFILE_INFO_TYPE_NOT_FOUND; + if(ha->pHeader->dwRawChunkSize != 0) + { + pvSrcFileInfo = &ha->pHeader->dwRawChunkSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + } + break; + + case SFileMpqStreamFlags: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + FileStream_GetFlags(ha->pStream, &dwInt32Value); + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileMpqFlags: + ha = IsValidMpqHandle(hMpqOrFile); + if(ha != NULL) + { + dwInt32Value = ha->dwFlags; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoPatchChain: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL) + return GetFilePatchChain(hf, pvFileInfo, cbFileInfo, pcbLengthNeeded); + break; + + case SFileInfoFileEntry: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = pFileEntry = hf->pFileEntry; + cbSrcFileInfo = sizeof(TFileEntry); + if(pFileEntry->szFileName != NULL) + cbSrcFileInfo += (DWORD)strlen(pFileEntry->szFileName) + 1; + nInfoType = SFILE_INFO_TYPE_FILE_ENTRY; + } + break; + + case SFileInfoHashEntry: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + pvSrcFileInfo = hf->pHashEntry; + cbSrcFileInfo = sizeof(TMPQHash); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoHashIndex: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + pvSrcFileInfo = &hf->dwHashIndex; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash1: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->dwName1; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash2: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->dwName2; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoNameHash3: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->FileNameHash; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoLocale: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pHashEntry != NULL) + { + dwInt32Value = hf->pHashEntry->lcLocale; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileIndex: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->ha != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = (DWORD)(hf->pFileEntry - hf->ha->pFileTable); + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoByteOffset: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->ByteOffset; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileTime: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->FileTime; + cbSrcFileInfo = sizeof(ULONGLONG); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFileSize: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwFileSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoCompressedSize: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwCmpSize; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoFlags: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + pvSrcFileInfo = &hf->pFileEntry->dwFlags; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoEncryptionKey: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL) + { + pvSrcFileInfo = &hf->dwFileKey; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoEncryptionKeyRaw: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = hf->dwFileKey; + if(hf->pFileEntry->dwFlags & MPQ_FILE_FIX_KEY) + dwInt32Value = (dwInt32Value ^ hf->pFileEntry->dwFileSize) - (DWORD)hf->MpqFilePos; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + case SFileInfoCRC32: + hf = IsValidFileHandle(hMpqOrFile); + if(hf != NULL && hf->pFileEntry != NULL) + { + dwInt32Value = hf->pFileEntry->dwCrc32; + pvSrcFileInfo = &dwInt32Value; + cbSrcFileInfo = sizeof(DWORD); + nInfoType = SFILE_INFO_TYPE_DIRECT_POINTER; + } + break; + + default: // Invalid info class + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // If we validated the handle and info class, give as much info as possible + if(nInfoType >= SFILE_INFO_TYPE_DIRECT_POINTER) + { + // Give the length needed, if wanted + if(pcbLengthNeeded != NULL) + pcbLengthNeeded[0] = cbSrcFileInfo; + + // If the caller entered an output buffer, the output size must also be entered + if(pvFileInfo != NULL && cbFileInfo != 0) + { + // Check if there is enough space in the output buffer + if(cbSrcFileInfo <= cbFileInfo) + { + switch(nInfoType) + { + case SFILE_INFO_TYPE_DIRECT_POINTER: + case SFILE_INFO_TYPE_ALLOCATED: + assert(pvSrcFileInfo != NULL); + memcpy(pvFileInfo, pvSrcFileInfo, cbSrcFileInfo); + break; + + case SFILE_INFO_TYPE_READ_FROM_FILE: + if(!FileStream_Read(ha->pStream, &ByteOffset, pvFileInfo, cbSrcFileInfo)) + nError = GetLastError(); + break; + + case SFILE_INFO_TYPE_TABLE_POINTER: + assert(pvSrcFileInfo != NULL); + *(void **)pvFileInfo = pvSrcFileInfo; + pvSrcFileInfo = NULL; + break; + + case SFILE_INFO_TYPE_FILE_ENTRY: + assert(pFileEntry != NULL); + ConvertFileEntryToSelfRelative((TFileEntry *)pvFileInfo, pFileEntry); + break; + } + } + else + { + nError = ERROR_INSUFFICIENT_BUFFER; + } + } + + // Free the file info if needed + if(nInfoType == SFILE_INFO_TYPE_ALLOCATED && pvSrcFileInfo != NULL) + STORM_FREE(pvSrcFileInfo); + if(nInfoType == SFILE_INFO_TYPE_TABLE_POINTER && pvSrcFileInfo != NULL) + SFileFreeFileInfo(pvSrcFileInfo, InfoClass); + } + else + { + // Handle error cases + if(nInfoType == SFILE_INFO_TYPE_INVALID_HANDLE) + nError = ERROR_INVALID_HANDLE; + if(nInfoType == SFILE_INFO_TYPE_NOT_FOUND) + nError = ERROR_FILE_NOT_FOUND; + } + + // Set the last error value, if needed + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass) +{ + switch(InfoClass) + { + case SFileMpqHetTable: + FreeHetTable((TMPQHetTable *)pvFileInfo); + return true; + + case SFileMpqBetTable: + FreeBetTable((TMPQBetTable *)pvFileInfo); + return true; + + default: + break; + } + + SetLastError(ERROR_INVALID_PARAMETER); + return false; +} + +//----------------------------------------------------------------------------- +// Tries to retrieve the file name + +struct TFileHeader2Ext +{ + DWORD dwOffset00Data; // Required data at offset 00 (32-bits) + DWORD dwOffset00Mask; // Mask for data at offset 00 (32 bits). 0 = data are ignored + DWORD dwOffset04Data; // Required data at offset 04 (32-bits) + DWORD dwOffset04Mask; // Mask for data at offset 04 (32 bits). 0 = data are ignored + const char * szExt; // Supplied extension, if the condition is true +}; + +static TFileHeader2Ext data2ext[] = +{ + {0x00005A4D, 0x0000FFFF, 0x00000000, 0x00000000, "exe"}, // EXE files + {0x00000006, 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, "dc6"}, // EXE files + {0x1A51504D, 0xFFFFFFFF, 0x00000000, 0x00000000, "mpq"}, // MPQ archive header ID ('MPQ\x1A') + {0x46464952, 0xFFFFFFFF, 0x00000000, 0x00000000, "wav"}, // WAVE header 'RIFF' + {0x324B4D53, 0xFFFFFFFF, 0x00000000, 0x00000000, "smk"}, // Old "Smacker Video" files 'SMK2' + {0x694B4942, 0xFFFFFFFF, 0x00000000, 0x00000000, "bik"}, // Bink video files (new) + {0x0801050A, 0xFFFFFFFF, 0x00000000, 0x00000000, "pcx"}, // PCX images used in Diablo I + {0x544E4F46, 0xFFFFFFFF, 0x00000000, 0x00000000, "fnt"}, // Font files used in Diablo II + {0x6D74683C, 0xFFFFFFFF, 0x00000000, 0x00000000, "html"}, // HTML 'ha->pFileTable), data2ext[i].szExt); + + // Save the pseudo-name in the file entry as well + AllocateFileName(hf->ha, pFileEntry, szPseudoName); + + // If the caller wants to copy the file name, do it + if(szFileName != NULL) + strcpy(szFileName, szPseudoName); + return ERROR_SUCCESS; + } + } + } + + return ERROR_CAN_NOT_COMPLETE; +} + +bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName) +{ + TMPQFile * hf = (TMPQFile *)hFile; // MPQ File handle + int nError = ERROR_INVALID_HANDLE; + + // Check valid parameters + if(IsValidFileHandle(hFile)) + { + TFileEntry * pFileEntry = hf->pFileEntry; + + // For MPQ files, retrieve the file name from the file entry + if(hf->pStream == NULL) + { + if(pFileEntry != NULL) + { + // If the file name is not there yet, create a pseudo name + if(pFileEntry->szFileName == NULL) + nError = CreatePseudoFileName(hFile, pFileEntry, szFileName); + + // Copy the file name to the output buffer, if any + if(pFileEntry->szFileName && szFileName) + { + strcpy(szFileName, pFileEntry->szFileName); + nError = ERROR_SUCCESS; + } + } + } + + // For local files, copy the file name from the stream + else + { + if(szFileName != NULL) + { + const TCHAR * szStreamName = FileStream_GetFileName(hf->pStream); + StringCopy(szFileName, MAX_PATH, szStreamName); + } + nError = ERROR_SUCCESS; + } + } + + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + diff --git a/dep/StormLib/src/SFileListFile.cpp b/dep/StormLib/src/SFileListFile.cpp new file mode 100644 index 000000000..777bba3cf --- /dev/null +++ b/dep/StormLib/src/SFileListFile.cpp @@ -0,0 +1,668 @@ +/*****************************************************************************/ +/* SListFile.cpp Copyright (c) Ladislav Zezula 2004 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 12.06.04 1.00 Lad The first version of SListFile.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" +#include + +//----------------------------------------------------------------------------- +// Listfile entry structure + +#define CACHE_BUFFER_SIZE 0x1000 // Size of the cache buffer +#define MAX_LISTFILE_SIZE 0x04000000 // Maximum accepted listfile size is about 68 MB + +union TListFileHandle +{ + TFileStream * pStream; // Opened local file + HANDLE hFile; // Opened MPQ file +}; + +struct TListFileCache +{ + char * szWildCard; // Self-relative pointer to file mask + LPBYTE pBegin; // The begin of the listfile cache + LPBYTE pPos; // Current position in the cache + LPBYTE pEnd; // The last character in the file cache + DWORD dwFlags; // Flags from TMPQArchive + +// char szWildCard[wildcard_length]; // Followed by the name mask (if any) +// char szListFile[listfile_length]; // Followed by the listfile (if any) +}; + +typedef bool (*LOAD_LISTFILE)(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead); + +//----------------------------------------------------------------------------- +// Local functions (cache) + +static char * CopyListLine(char * szListLine, const char * szFileName) +{ + // Copy the string + while(szFileName[0] != 0) + *szListLine++ = *szFileName++; + + // Append the end-of-line + *szListLine++ = 0x0D; + *szListLine++ = 0x0A; + return szListLine; +} + +static bool LoadListFile_Stream(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead) +{ + ULONGLONG ByteOffset = 0; + bool bResult; + + bResult = FileStream_Read(pHandle->pStream, &ByteOffset, pvBuffer, cbBuffer); + if(bResult) + *pdwBytesRead = cbBuffer; + return bResult; +} + +static bool LoadListFile_MPQ(TListFileHandle * pHandle, void * pvBuffer, DWORD cbBuffer, LPDWORD pdwBytesRead) +{ + return SFileReadFile(pHandle->hFile, pvBuffer, cbBuffer, pdwBytesRead, NULL); +} + +static bool FreeListFileCache(TListFileCache * pCache) +{ + // Valid parameter check + if(pCache != NULL) + STORM_FREE(pCache); + return true; +} + +static TListFileCache * CreateListFileCache( + LOAD_LISTFILE PfnLoadFile, + TListFileHandle * pHandle, + const char * szWildCard, + DWORD dwFileSize, + DWORD dwMaxSize, + DWORD dwFlags) +{ + TListFileCache * pCache = NULL; + size_t cchWildCard = 0; + DWORD dwBytesRead = 0; + + // Get the amount of bytes that need to be allocated + if(dwFileSize == 0 || dwFileSize > dwMaxSize) + return NULL; + + // Append buffer for name mask, if any + if(szWildCard != NULL) + cchWildCard = strlen(szWildCard) + 1; + + // Allocate cache for one file block + pCache = (TListFileCache *)STORM_ALLOC(BYTE, sizeof(TListFileCache) + cchWildCard + dwFileSize + 1); + if(pCache != NULL) + { + // Clear the entire structure + memset(pCache, 0, sizeof(TListFileCache) + cchWildCard); + pCache->dwFlags = dwFlags; + + // Shall we copy the mask? + if(cchWildCard != 0) + { + pCache->szWildCard = (char *)(pCache + 1); + memcpy(pCache->szWildCard, szWildCard, cchWildCard); + } + + // Fill-in the rest of the cache pointers + pCache->pBegin = (LPBYTE)(pCache + 1) + cchWildCard; + + // Load the entire listfile to the cache + PfnLoadFile(pHandle, pCache->pBegin, dwFileSize, &dwBytesRead); + if(dwBytesRead != 0) + { + // Allocate pointers + pCache->pPos = pCache->pBegin; + pCache->pEnd = pCache->pBegin + dwBytesRead; + } + else + { + FreeListFileCache(pCache); + pCache = NULL; + } + } + + // Return the cache + return pCache; +} + +static TListFileCache * CreateListFileCache( + HANDLE hMpq, + const TCHAR * szListFile, + const char * szWildCard, + DWORD dwMaxSize, + DWORD dwFlags) +{ + TListFileCache * pCache = NULL; + TListFileHandle ListHandle = {NULL}; + + // Internal listfile: hMPQ must be non NULL and szListFile must be NULL. + // We load the MPQ::(listfile) file + if(hMpq != NULL && szListFile == NULL) + { + DWORD dwFileSize = 0; + + // Open the file from the MPQ + if(SFileOpenFileEx(hMpq, LISTFILE_NAME, 0, &ListHandle.hFile)) + { + // Get the file size and create the listfile cache + dwFileSize = SFileGetFileSize(ListHandle.hFile, NULL); + pCache = CreateListFileCache(LoadListFile_MPQ, &ListHandle, szWildCard, dwFileSize, dwMaxSize, dwFlags); + + // Close the MPQ file + SFileCloseFile(ListHandle.hFile); + } + + // Return the loaded cache + return pCache; + } + + // External listfile: hMpq must be NULL and szListFile must be non-NULL. + // We load the file using TFileStream + if(hMpq == NULL && szListFile != NULL) + { + ULONGLONG FileSize = 0; + + // Open the local file + ListHandle.pStream = FileStream_OpenFile(szListFile, STREAM_FLAG_READ_ONLY); + if(ListHandle.pStream != NULL) + { + // Verify the file size + FileStream_GetSize(ListHandle.pStream, &FileSize); + if(0 < FileSize && FileSize < MAX_LISTFILE_SIZE) + { + pCache = CreateListFileCache(LoadListFile_Stream, &ListHandle, szWildCard, (DWORD)FileSize, dwMaxSize, dwFlags); + } + + // Close the stream + FileStream_Close(ListHandle.pStream); + } + + // Return the loaded cache + return pCache; + } + + // This combination should never happen + SetLastError(ERROR_INVALID_PARAMETER); + assert(false); + return NULL; +} + +#ifdef _DEBUG +/* +TMPQNameCache * CreateNameCache(HANDLE hListFile, const char * szSearchMask) +{ + TMPQNameCache * pNameCache; + char * szCachePointer; + size_t cbToAllocate; + size_t nMaskLength = 1; + DWORD dwBytesRead = 0; + DWORD dwFileSize; + + // Get the size of the listfile. Ignore zero or too long ones + dwFileSize = SFileGetFileSize(hListFile, NULL); + if(dwFileSize == 0 || dwFileSize > MAX_LISTFILE_SIZE) + return NULL; + + // Get the length of the search mask + if(szSearchMask == NULL) + szSearchMask = "*"; + nMaskLength = strlen(szSearchMask) + 1; + + // Allocate the name cache + cbToAllocate = sizeof(TMPQNameCache) + nMaskLength + dwFileSize + 1; + pNameCache = (TMPQNameCache *)STORM_ALLOC(BYTE, cbToAllocate); + if(pNameCache != NULL) + { + // Initialize the name cache + memset(pNameCache, 0, sizeof(TMPQNameCache)); + pNameCache->TotalCacheSize = (DWORD)(nMaskLength + dwFileSize + 1); + szCachePointer = (char *)(pNameCache + 1); + + // Copy the search mask, if any + memcpy(szCachePointer, szSearchMask, nMaskLength); + pNameCache->FirstNameOffset = (DWORD)nMaskLength; + pNameCache->FreeSpaceOffset = (DWORD)nMaskLength; + + // Read the listfile itself + SFileSetFilePointer(hListFile, 0, NULL, FILE_BEGIN); + SFileReadFile(hListFile, szCachePointer + nMaskLength, dwFileSize, &dwBytesRead, NULL); + + // If nothing has been read from the listfile, clear the cache + if(dwBytesRead == 0) + { + STORM_FREE(pNameCache); + return NULL; + } + + // Move the free space offset + pNameCache->FreeSpaceOffset = pNameCache->FirstNameOffset + dwBytesRead + 1; + szCachePointer[nMaskLength + dwBytesRead] = 0; + } + + return pNameCache; +} + +static void FreeNameCache(TMPQNameCache * pNameCache) +{ + if(pNameCache != NULL) + STORM_FREE(pNameCache); + pNameCache = NULL; +} +*/ +#endif // _DEBUG + +static char * ReadListFileLine(TListFileCache * pCache, size_t * PtrLength) +{ + LPBYTE pbLineBegin; + LPBYTE pbLineEnd; + + // Skip newlines. Keep spaces and tabs, as they can be a legal part of the file name + while(pCache->pPos < pCache->pEnd && (pCache->pPos[0] == 0x0A || pCache->pPos[0] == 0x0D)) + pCache->pPos++; + + // Set the line begin and end + if(pCache->pPos >= pCache->pEnd) + return NULL; + pbLineBegin = pbLineEnd = pCache->pPos; + + // Find the end of the line + while(pCache->pPos < pCache->pEnd && pCache->pPos[0] != 0x0A && pCache->pPos[0] != 0x0D) + pCache->pPos++; + + // Remember the end of the line + pbLineEnd = pCache->pPos++; + pbLineEnd[0] = 0; + + // Give the line to the caller + if(PtrLength != NULL) + PtrLength[0] = (size_t)(pbLineEnd - pbLineBegin); + return (char *)pbLineBegin; +} + +static int CompareFileNodes(const void * p1, const void * p2) +{ + char * szFileName1 = *(char **)p1; + char * szFileName2 = *(char **)p2; + + return _stricmp(szFileName1, szFileName2); +} + +static LPBYTE CreateListFile(TMPQArchive * ha, DWORD * pcbListFile) +{ + TFileEntry * pFileTableEnd = ha->pFileTable + ha->dwFileTableSize; + TFileEntry * pFileEntry; + char ** SortTable = NULL; + char * szListFile = NULL; + char * szListLine; + size_t nFileNodes = 0; + size_t cbListFile = 0; + size_t nIndex0; + size_t nIndex1; + + // Allocate the table for sorting listfile + SortTable = STORM_ALLOC(char*, ha->dwFileTableSize); + if(SortTable == NULL) + return NULL; + + // Construct the sort table + // Note: in MPQs with multiple locale versions of the same file, + // this code causes adding multiple listfile entries. + // They will get removed after the listfile sorting + for(pFileEntry = ha->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Only take existing items + if((pFileEntry->dwFlags & MPQ_FILE_EXISTS) && pFileEntry->szFileName != NULL) + { + // Ignore pseudo-names and internal names + if(!IsPseudoFileName(pFileEntry->szFileName, NULL) && !IsInternalMpqFileName(pFileEntry->szFileName)) + { + SortTable[nFileNodes++] = pFileEntry->szFileName; + } + } + } + + // Remove duplicities + if(nFileNodes > 0) + { + // Sort the table + qsort(SortTable, nFileNodes, sizeof(char *), CompareFileNodes); + + // Count the 0-th item + cbListFile += strlen(SortTable[0]) + 2; + + // Walk through the items and only use the ones that are not duplicated + for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++) + { + // If the next file node is different, we will include it to the result listfile + if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0) + { + cbListFile += strlen(SortTable[nIndex1]) + 2; + nIndex0 = nIndex1; + } + } + + // Now allocate buffer for the entire listfile + szListFile = szListLine = STORM_ALLOC(char, cbListFile + 1); + if(szListFile != NULL) + { + // Copy the 0-th item + szListLine = CopyListLine(szListLine, SortTable[0]); + + // Walk through the items and only use the ones that are not duplicated + for(nIndex0 = 0, nIndex1 = 1; nIndex1 < nFileNodes; nIndex1++) + { + // If the next file node is different, we will include it to the result listfile + if(_stricmp(SortTable[nIndex1], SortTable[nIndex0]) != 0) + { + // Copy the listfile line + szListLine = CopyListLine(szListLine, SortTable[nIndex1]); + nIndex0 = nIndex1; + } + } + + // Sanity check - does the size match? + assert((size_t)(szListLine - szListFile) == cbListFile); + } + } + else + { + szListFile = STORM_ALLOC(char, 1); + cbListFile = 0; + } + + // Free the sort table + STORM_FREE(SortTable); + + // Give away the listfile + if(pcbListFile != NULL) + *pcbListFile = (DWORD)cbListFile; + return (LPBYTE)szListFile; +} + +//----------------------------------------------------------------------------- +// Local functions (listfile nodes) + +// Adds a name into the list of all names. For each locale in the MPQ, +// one entry will be created +// If the file name is already there, does nothing. +static int SListFileCreateNodeForAllLocales(TMPQArchive * ha, const char * szFileName) +{ + TFileEntry * pFileEntry; + TMPQHash * pFirstHash; + TMPQHash * pHash; + + // If we have HET table, use that one + if(ha->pHetTable != NULL) + { + pFileEntry = GetFileEntryLocale(ha, szFileName, 0); + if(pFileEntry != NULL) + { + // Allocate file name for the file entry + AllocateFileName(ha, pFileEntry, szFileName); + } + + return ERROR_SUCCESS; + } + + // If we have hash table, we use it + if(ha->pHashTable != NULL) + { + // Go while we found something + pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); + while(pHash != NULL) + { + // Allocate file name for the file entry + AllocateFileName(ha, ha->pFileTable + MPQ_BLOCK_INDEX(pHash), szFileName); + + // Now find the next language version of the file + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + return ERROR_SUCCESS; + } + + return ERROR_CAN_NOT_COMPLETE; +} + +// Saves the whole listfile to the MPQ +int SListFileSaveToMpq(TMPQArchive * ha) +{ + TMPQFile * hf = NULL; + LPBYTE pbListFile; + DWORD cbListFile = 0; + int nError = ERROR_SUCCESS; + + // Only save the listfile if we should do so + if(ha->dwFileFlags1 != 0) + { + // At this point, we expect to have at least one reserved entry in the file table + assert(ha->dwFlags & MPQ_FLAG_LISTFILE_NEW); + assert(ha->dwReservedFiles > 0); + + // Create the raw data that is to be written to (listfile) + // Note: Creating the raw data before the (listfile) has been created in the MPQ + // causes that the name of the listfile will not be included in the listfile itself. + // That is OK, because (listfile) in Blizzard MPQs does not contain it either. + pbListFile = CreateListFile(ha, &cbListFile); + if(pbListFile != NULL) + { + // Determine the real flags for (listfile) + if(ha->dwFileFlags1 == MPQ_FILE_DEFAULT_INTERNAL) + ha->dwFileFlags1 = GetDefaultSpecialFileFlags(cbListFile, ha->pHeader->wFormatVersion); + + // Create the listfile in the MPQ + nError = SFileAddFile_Init(ha, LISTFILE_NAME, + 0, + cbListFile, + LANG_NEUTRAL, + ha->dwFileFlags1 | MPQ_FILE_REPLACEEXISTING, + &hf); + + // Write the listfile raw data to it + if(nError == ERROR_SUCCESS) + { + // Write the content of the listfile to the MPQ + nError = SFileAddFile_Write(hf, pbListFile, cbListFile, MPQ_COMPRESSION_ZLIB); + SFileAddFile_Finish(hf); + } + + // Clear the listfile flags + ha->dwFlags &= ~(MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_NONE); + ha->dwReservedFiles--; + + // Free the listfile buffer + STORM_FREE(pbListFile); + } + else + { + // If the (listfile) file would be empty, its OK + nError = (cbListFile == 0) ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY; + } + } + + return nError; +} + +static int SFileAddArbitraryListFile( + TMPQArchive * ha, + HANDLE hMpq, + const TCHAR * szListFile, + DWORD dwMaxSize) +{ + TListFileCache * pCache = NULL; + + // Create the listfile cache for that file + pCache = CreateListFileCache(hMpq, szListFile, NULL, dwMaxSize, ha->dwFlags); + if(pCache != NULL) + { + char * szFileName; + size_t nLength = 0; + + // Get the next line + while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL) + { + // Add the line to the MPQ + if(nLength != 0) + SListFileCreateNodeForAllLocales(ha, szFileName); + } + + // Delete the cache + FreeListFileCache(pCache); + } + + return (pCache != NULL) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; +} + +static int SFileAddInternalListFile( + TMPQArchive * ha, + HANDLE hMpq) +{ + TMPQHash * pFirstHash; + TMPQHash * pHash; + LCID lcSaveLocale = lcFileLocale; + DWORD dwMaxSize = MAX_LISTFILE_SIZE; + int nError = ERROR_SUCCESS; + + // If there is hash table, we need to support multiple listfiles + // with different locales (BrooDat.mpq) + if(ha->pHashTable != NULL) + { + // If the archive is a malformed map, ignore too large listfiles + if(ha->dwFlags & MPQ_FLAG_MALFORMED) + dwMaxSize = 0x40000; + + pFirstHash = pHash = GetFirstHashEntry(ha, LISTFILE_NAME); + while(nError == ERROR_SUCCESS && pHash != NULL) + { + // Set the prefered locale to that from list file + SFileSetLocale(pHash->lcLocale); + + // Add that listfile + nError = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize); + + // Move to the next hash + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // Restore the original locale + SFileSetLocale(lcSaveLocale); + } + else + { + // Add the single listfile + nError = SFileAddArbitraryListFile(ha, hMpq, NULL, dwMaxSize); + } + + // Return the result of the operation + return nError; +} + +static bool DoListFileSearch(TListFileCache * pCache, SFILE_FIND_DATA * lpFindFileData) +{ + // Check for the valid search handle + if(pCache != NULL) + { + char * szFileName; + size_t nLength = 0; + + // Get the next line + while((szFileName = ReadListFileLine(pCache, &nLength)) != NULL) + { + // Check search mask + if(nLength != 0 && CheckWildCard(szFileName, pCache->szWildCard)) + { + if(nLength >= sizeof(lpFindFileData->cFileName)) + nLength = sizeof(lpFindFileData->cFileName) - 1; + + memcpy(lpFindFileData->cFileName, szFileName, nLength); + lpFindFileData->cFileName[nLength] = 0; + return true; + } + } + } + + // No more files + memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); + SetLastError(ERROR_NO_MORE_FILES); + return false; +} + +//----------------------------------------------------------------------------- +// File functions + +// Adds a listfile into the MPQ archive. +int WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + int nError = ERROR_SUCCESS; + + // Add the listfile for each MPQ in the patch chain + while(ha != NULL) + { + if(szListFile != NULL) + nError = SFileAddArbitraryListFile(ha, NULL, szListFile, MAX_LISTFILE_SIZE); + else + nError = SFileAddInternalListFile(ha, hMpq); + + // Also, add three special files to the listfile: + // (listfile) itself, (attributes) and (signature) + SListFileCreateNodeForAllLocales(ha, LISTFILE_NAME); + SListFileCreateNodeForAllLocales(ha, SIGNATURE_NAME); + SListFileCreateNodeForAllLocales(ha, ATTRIBUTES_NAME); + + // Move to the next archive in the chain + ha = ha->haPatch; + } + + return nError; +} + +//----------------------------------------------------------------------------- +// Enumerating files in listfile + +HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const TCHAR * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData) +{ + TListFileCache * pCache = NULL; + + // Initialize the structure with zeros + memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); + + // Open the local/internal listfile + pCache = CreateListFileCache(hMpq, szListFile, szMask, 0, 0); + if(pCache != NULL) + { + if(!DoListFileSearch(pCache, lpFindFileData)) + { + memset(lpFindFileData, 0, sizeof(SFILE_FIND_DATA)); + SetLastError(ERROR_NO_MORE_FILES); + FreeListFileCache(pCache); + pCache = NULL; + } + } + + // Return the listfile cache as handle + return (HANDLE)pCache; +} + +bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData) +{ + return DoListFileSearch((TListFileCache *)hFind, lpFindFileData); +} + +bool WINAPI SListFileFindClose(HANDLE hFind) +{ + TListFileCache * pCache = (TListFileCache *)hFind; + + return FreeListFileCache(pCache); +} + diff --git a/dep/StormLib/src/SFileOpenArchive.cpp b/dep/StormLib/src/SFileOpenArchive.cpp new file mode 100644 index 000000000..bba0aad95 --- /dev/null +++ b/dep/StormLib/src/SFileOpenArchive.cpp @@ -0,0 +1,600 @@ +/*****************************************************************************/ +/* SFileOpenArchive.cpp Copyright Ladislav Zezula 1999 */ +/* */ +/* Author : Ladislav Zezula */ +/* E-mail : ladik@zezula.net */ +/* WWW : www.zezula.net */ +/*---------------------------------------------------------------------------*/ +/* Archive functions of Storm.dll */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of SFileOpenArchive.cpp */ +/* 19.11.03 1.01 Dan Big endian handling */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +#define HEADER_SEARCH_BUFFER_SIZE 0x1000 + +/*****************************************************************************/ +/* Local functions */ +/*****************************************************************************/ + +static bool IsAviFile(DWORD * HeaderData) +{ + DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderData[0]); + DWORD DwordValue2 = BSWAP_INT32_UNSIGNED(HeaderData[2]); + DWORD DwordValue3 = BSWAP_INT32_UNSIGNED(HeaderData[3]); + + // Test for 'RIFF', 'AVI ' or 'LIST' + return (DwordValue0 == 0x46464952 && DwordValue2 == 0x20495641 && DwordValue3 == 0x5453494C); +} + +static bool IsWarcraft3Map(DWORD * HeaderData) +{ + DWORD DwordValue0 = BSWAP_INT32_UNSIGNED(HeaderData[0]); + DWORD DwordValue1 = BSWAP_INT32_UNSIGNED(HeaderData[1]); + + return (DwordValue0 == 0x57334D48 && DwordValue1 == 0x00000000); +} + +static TMPQUserData * IsValidMpqUserData(ULONGLONG ByteOffset, ULONGLONG FileSize, void * pvUserData) +{ + TMPQUserData * pUserData; + + // BSWAP the source data and copy them to our buffer + BSWAP_ARRAY32_UNSIGNED(&pvUserData, sizeof(TMPQUserData)); + pUserData = (TMPQUserData *)pvUserData; + + // Check the sizes + if(pUserData->cbUserDataHeader <= pUserData->cbUserDataSize && pUserData->cbUserDataSize <= pUserData->dwHeaderOffs) + { + // Move to the position given by the userdata + ByteOffset += pUserData->dwHeaderOffs; + + // The MPQ header should be within range of the file size + if((ByteOffset + MPQ_HEADER_SIZE_V1) < FileSize) + { + // Note: We should verify if there is the MPQ header. + // However, the header could be at any position below that + // that is multiplier of 0x200 + return (TMPQUserData *)pvUserData; + } + } + + return NULL; +} + +// This function gets the right positions of the hash table and the block table. +static int VerifyMpqTablePositions(TMPQArchive * ha, ULONGLONG FileSize) +{ + TMPQHeader * pHeader = ha->pHeader; + ULONGLONG ByteOffset; + + // Check the begin of HET table + if(pHeader->HetTablePos64) + { + ByteOffset = ha->MpqPos + pHeader->HetTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of BET table + if(pHeader->BetTablePos64) + { + ByteOffset = ha->MpqPos + pHeader->BetTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of hash table + if(pHeader->wHashTablePosHi || pHeader->dwHashTablePos) + { + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wHashTablePosHi, pHeader->dwHashTablePos)); + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of block table + if(pHeader->wBlockTablePosHi || pHeader->dwBlockTablePos) + { + ByteOffset = FileOffsetFromMpqOffset(ha, MAKE_OFFSET64(pHeader->wBlockTablePosHi, pHeader->dwBlockTablePos)); + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // Check the begin of hi-block table + if(pHeader->HiBlockTablePos64 != 0) + { + ByteOffset = ha->MpqPos + pHeader->HiBlockTablePos64; + if(ByteOffset > FileSize) + return ERROR_BAD_FORMAT; + } + + // All OK. + return ERROR_SUCCESS; +} + +/*****************************************************************************/ +/* Public functions */ +/*****************************************************************************/ + +//----------------------------------------------------------------------------- +// SFileGetLocale and SFileSetLocale +// Set the locale for all newly opened files + +LCID WINAPI SFileGetLocale() +{ + return lcFileLocale; +} + +LCID WINAPI SFileSetLocale(LCID lcNewLocale) +{ + lcFileLocale = lcNewLocale; + return lcFileLocale; +} + +//----------------------------------------------------------------------------- +// SFileOpenArchive +// +// szFileName - MPQ archive file name to open +// dwPriority - When SFileOpenFileEx called, this contains the search priority for searched archives +// dwFlags - See MPQ_OPEN_XXX in StormLib.h +// phMpq - Pointer to store open archive handle + +bool WINAPI SFileOpenArchive( + const TCHAR * szMpqName, + DWORD dwPriority, + DWORD dwFlags, + HANDLE * phMpq) +{ + TMPQUserData * pUserData; + TFileStream * pStream = NULL; // Open file stream + TMPQArchive * ha = NULL; // Archive handle + TFileEntry * pFileEntry; + ULONGLONG FileSize = 0; // Size of the file + LPBYTE pbHeaderBuffer = NULL; // Buffer for searching MPQ header + DWORD dwStreamFlags = (dwFlags & STREAM_FLAGS_MASK); + bool bIsWarcraft3Map = false; + int nError = ERROR_SUCCESS; + + // Verify the parameters + if(szMpqName == NULL || *szMpqName == 0 || phMpq == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // One time initialization of MPQ cryptography + InitializeMpqCryptography(); + + // If not forcing MPQ v 1.0, also use file bitmap + dwStreamFlags |= (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) ? 0 : STREAM_FLAG_USE_BITMAP; + + // Open the MPQ archive file + pStream = FileStream_OpenFile(szMpqName, dwStreamFlags); + if(pStream == NULL) + return false; + + // Check the file size. There must be at least 0x20 bytes + if(nError == ERROR_SUCCESS) + { + FileStream_GetSize(pStream, &FileSize); + if(FileSize < MPQ_HEADER_SIZE_V1) + nError = ERROR_BAD_FORMAT; + } + + // Allocate the MPQhandle + if(nError == ERROR_SUCCESS) + { + if((ha = STORM_ALLOC(TMPQArchive, 1)) == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Allocate buffer for searching MPQ header + if(nError == ERROR_SUCCESS) + { + pbHeaderBuffer = STORM_ALLOC(BYTE, HEADER_SEARCH_BUFFER_SIZE); + if(pbHeaderBuffer == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + } + + // Find the position of MPQ header + if(nError == ERROR_SUCCESS) + { + ULONGLONG SearchOffset = 0; + ULONGLONG EndOfSearch = FileSize; + DWORD dwStrmFlags = 0; + DWORD dwHeaderSize; + DWORD dwHeaderID; + bool bSearchComplete = false; + + memset(ha, 0, sizeof(TMPQArchive)); + ha->pfnHashString = HashStringSlash; + ha->pStream = pStream; + pStream = NULL; + + // Set the archive read only if the stream is read-only + FileStream_GetFlags(ha->pStream, &dwStrmFlags); + ha->dwFlags |= (dwStrmFlags & STREAM_FLAG_READ_ONLY) ? MPQ_FLAG_READ_ONLY : 0; + + // Also remember if we shall check sector CRCs when reading file + ha->dwFlags |= (dwFlags & MPQ_OPEN_CHECK_SECTOR_CRC) ? MPQ_FLAG_CHECK_SECTOR_CRC : 0; + + // Also remember if this MPQ is a patch + ha->dwFlags |= (dwFlags & MPQ_OPEN_PATCH) ? MPQ_FLAG_PATCH : 0; + + // Limit the header searching to about 130 MB of data + if(EndOfSearch > 0x08000000) + EndOfSearch = 0x08000000; + + // Find the offset of MPQ header within the file + while(bSearchComplete == false && SearchOffset < EndOfSearch) + { + // Always read at least 0x1000 bytes for performance. + // This is what Storm.dll (2002) does. + DWORD dwBytesAvailable = HEADER_SEARCH_BUFFER_SIZE; + DWORD dwInBufferOffset = 0; + + // Cut the bytes available, if needed + if((FileSize - SearchOffset) < HEADER_SEARCH_BUFFER_SIZE) + dwBytesAvailable = (DWORD)(FileSize - SearchOffset); + + // Read the eventual MPQ header + if(!FileStream_Read(ha->pStream, &SearchOffset, pbHeaderBuffer, dwBytesAvailable)) + { + nError = GetLastError(); + break; + } + + // There are AVI files from Warcraft III with 'MPQ' extension. + if(SearchOffset == 0) + { + if(IsAviFile((DWORD *)pbHeaderBuffer)) + { + nError = ERROR_AVI_FILE; + break; + } + + bIsWarcraft3Map = IsWarcraft3Map((DWORD *)pbHeaderBuffer); + } + + // Search the header buffer + while(dwInBufferOffset < dwBytesAvailable) + { + // Copy the data from the potential header buffer to the MPQ header + memcpy(ha->HeaderData, pbHeaderBuffer + dwInBufferOffset, sizeof(ha->HeaderData)); + + // If there is the MPQ user data, process it + // Note that Warcraft III does not check for user data, which is abused by many map protectors + dwHeaderID = BSWAP_INT32_UNSIGNED(ha->HeaderData[0]); + if(bIsWarcraft3Map == false && (dwFlags & MPQ_OPEN_FORCE_MPQ_V1) == 0) + { + if(ha->pUserData == NULL && dwHeaderID == ID_MPQ_USERDATA) + { + // Verify if this looks like a valid user data + pUserData = IsValidMpqUserData(SearchOffset, FileSize, ha->HeaderData); + if(pUserData != NULL) + { + // Fill the user data header + ha->UserDataPos = SearchOffset; + ha->pUserData = &ha->UserData; + memcpy(ha->pUserData, pUserData, sizeof(TMPQUserData)); + + // Continue searching from that position + SearchOffset += ha->pUserData->dwHeaderOffs; + break; + } + } + } + + // There must be MPQ header signature. Note that STORM.dll from Warcraft III actually + // tests the MPQ header size. It must be at least 0x20 bytes in order to load it + // Abused by Spazzler Map protector. Note that the size check is not present + // in Storm.dll v 1.00, so Diablo I code would load the MPQ anyway. + dwHeaderSize = BSWAP_INT32_UNSIGNED(ha->HeaderData[1]); + if(dwHeaderID == ID_MPQ && dwHeaderSize >= MPQ_HEADER_SIZE_V1) + { + // Now convert the header to version 4 + nError = ConvertMpqHeaderToFormat4(ha, SearchOffset, FileSize, dwFlags, bIsWarcraft3Map); + bSearchComplete = true; + break; + } + + // Check for MPK archives (Longwu Online - MPQ fork) + if(bIsWarcraft3Map == false && dwHeaderID == ID_MPK) + { + // Now convert the MPK header to MPQ Header version 4 + nError = ConvertMpkHeaderToFormat4(ha, FileSize, dwFlags); + bSearchComplete = true; + break; + } + + // If searching for the MPQ header is disabled, return an error + if(dwFlags & MPQ_OPEN_NO_HEADER_SEARCH) + { + nError = ERROR_NOT_SUPPORTED; + bSearchComplete = true; + break; + } + + // Move the pointers + SearchOffset += 0x200; + dwInBufferOffset += 0x200; + } + } + + // Did we identify one of the supported headers? + if(nError == ERROR_SUCCESS) + { + // Set the user data position to the MPQ header, if none + if(ha->pUserData == NULL) + ha->UserDataPos = SearchOffset; + + // Set the position of the MPQ header + ha->pHeader = (TMPQHeader *)ha->HeaderData; + ha->MpqPos = SearchOffset; + ha->FileSize = FileSize; + + // Sector size must be nonzero. + if(SearchOffset >= FileSize || ha->pHeader->wSectorSize == 0) + nError = ERROR_BAD_FORMAT; + } + } + + // Fix table positions according to format + if(nError == ERROR_SUCCESS) + { + // Dump the header +// DumpMpqHeader(ha->pHeader); + + // W3x Map Protectors use the fact that War3's Storm.dll ignores the MPQ user data, + // and ignores the MPQ format version as well. The trick is to + // fake MPQ format 2, with an improper hi-word position of hash table and block table + // We can overcome such protectors by forcing opening the archive as MPQ v 1.0 + if(dwFlags & MPQ_OPEN_FORCE_MPQ_V1) + { + ha->pHeader->wFormatVersion = MPQ_FORMAT_VERSION_1; + ha->pHeader->dwHeaderSize = MPQ_HEADER_SIZE_V1; + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + ha->pUserData = NULL; + } + + // Anti-overflow. If the hash table size in the header is + // higher than 0x10000000, it would overflow in 32-bit version + // Observed in the malformed Warcraft III maps + // Example map: MPQ_2016_v1_ProtectedMap_TableSizeOverflow.w3x + ha->pHeader->dwBlockTableSize = (ha->pHeader->dwBlockTableSize & BLOCK_INDEX_MASK); + ha->pHeader->dwHashTableSize = (ha->pHeader->dwHashTableSize & BLOCK_INDEX_MASK); + + // Both MPQ_OPEN_NO_LISTFILE or MPQ_OPEN_NO_ATTRIBUTES trigger read only mode + if(dwFlags & (MPQ_OPEN_NO_LISTFILE | MPQ_OPEN_NO_ATTRIBUTES)) + ha->dwFlags |= MPQ_FLAG_READ_ONLY; + + // Check if the caller wants to force adding listfile + if(dwFlags & MPQ_OPEN_FORCE_LISTFILE) + ha->dwFlags |= MPQ_FLAG_LISTFILE_FORCE; + + // Remember whether whis is a map for Warcraft III + if(bIsWarcraft3Map) + ha->dwFlags |= MPQ_FLAG_WAR3_MAP; + + // Set the size of file sector + ha->dwSectorSize = (0x200 << ha->pHeader->wSectorSize); + + // Verify if any of the tables doesn't start beyond the end of the file + nError = VerifyMpqTablePositions(ha, FileSize); + } + + // Read the hash table. Ignore the result, as hash table is no longer required + // Read HET table. Ignore the result, as HET table is no longer required + if(nError == ERROR_SUCCESS) + { + nError = LoadAnyHashTable(ha); + } + + // Now, build the file table. It will be built by combining + // the block table, BET table, hi-block table, (attributes) and (listfile). + if(nError == ERROR_SUCCESS) + { + nError = BuildFileTable(ha); + } + + // Load the internal listfile and include it to the file table + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_LISTFILE) == 0) + { + // Quick check for (listfile) + pFileEntry = GetFileEntryLocale(ha, LISTFILE_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Ignore result of the operation. (listfile) is optional. + SFileAddListFile((HANDLE)ha, NULL); + ha->dwFileFlags1 = pFileEntry->dwFlags; + } + } + + // Load the "(attributes)" file and merge it to the file table + if(nError == ERROR_SUCCESS && (dwFlags & MPQ_OPEN_NO_ATTRIBUTES) == 0 && (ha->dwFlags & MPQ_FLAG_BLOCK_TABLE_CUT) == 0) + { + // Quick check for (attributes) + pFileEntry = GetFileEntryLocale(ha, ATTRIBUTES_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Ignore result of the operation. (attributes) is optional. + SAttrLoadAttributes(ha); + ha->dwFileFlags2 = pFileEntry->dwFlags; + } + } + + // Remember whether the archive has weak signature. Only for MPQs format 1.0. + if(nError == ERROR_SUCCESS) + { + // Quick check for (signature) + pFileEntry = GetFileEntryLocale(ha, SIGNATURE_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Just remember that the archive is weak-signed + assert((pFileEntry->dwFlags & MPQ_FILE_EXISTS) != 0); + ha->dwFileFlags3 = pFileEntry->dwFlags; + } + + // Finally, set the MPQ_FLAG_READ_ONLY if the MPQ was found malformed + ha->dwFlags |= (ha->dwFlags & MPQ_FLAG_MALFORMED) ? MPQ_FLAG_READ_ONLY : 0; + } + + // Cleanup and exit + if(nError != ERROR_SUCCESS) + { + FileStream_Close(pStream); + FreeArchiveHandle(ha); + SetLastError(nError); + ha = NULL; + } + + // Free the header buffer + if(pbHeaderBuffer != NULL) + STORM_FREE(pbHeaderBuffer); + if(phMpq != NULL) + *phMpq = ha; + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// bool WINAPI SFileSetDownloadCallback(HANDLE, SFILE_DOWNLOAD_CALLBACK, void *); +// +// Sets a callback that is called when content is downloaded from the master MPQ +// + +bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Do nothing if 'hMpq' is bad parameter + if(!IsValidMpqHandle(hMpq)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + return FileStream_SetCallback(ha->pStream, DownloadCB, pvUserData); +} + +//----------------------------------------------------------------------------- +// bool SFileFlushArchive(HANDLE hMpq) +// +// Saves all dirty data into MPQ archive. +// Has similar effect like SFileCloseArchive, but the archive is not closed. +// Use on clients who keep MPQ archive open even for write operations, +// and terminating without calling SFileCloseArchive might corrupt the archive. +// + +bool WINAPI SFileFlushArchive(HANDLE hMpq) +{ + TMPQArchive * ha; + int nResultError = ERROR_SUCCESS; + int nError; + + // Do nothing if 'hMpq' is bad parameter + if((ha = IsValidMpqHandle(hMpq)) == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Only if the MPQ was changed + if(ha->dwFlags & MPQ_FLAG_CHANGED) + { + // Indicate that we are saving MPQ internal structures + ha->dwFlags |= MPQ_FLAG_SAVING_TABLES; + + // Defragment the file table. This will allow us to put the internal files to the end + DefragmentFileTable(ha); + + // + // Create each internal file + // Note that the (signature) file is usually before (listfile) in the file table + // + + if(ha->dwFlags & MPQ_FLAG_SIGNATURE_NEW) + { + nError = SSignFileCreate(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + + if(ha->dwFlags & (MPQ_FLAG_LISTFILE_NEW | MPQ_FLAG_LISTFILE_FORCE)) + { + nError = SListFileSaveToMpq(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + + if(ha->dwFlags & MPQ_FLAG_ATTRIBUTES_NEW) + { + nError = SAttrFileSaveToMpq(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + + // Save HET table, BET table, hash table, block table, hi-block table + if(ha->dwFlags & MPQ_FLAG_CHANGED) + { + // Rebuild the HET table + if(ha->pHetTable != NULL) + RebuildHetTable(ha); + + // Save all MPQ tables first + nError = SaveMPQTables(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + + // If the archive has weak signature, we need to finish it + if(ha->dwFileFlags3 != 0) + { + nError = SSignFileFinish(ha); + if(nError != ERROR_SUCCESS) + nResultError = nError; + } + } + + // We are no longer saving internal MPQ structures + ha->dwFlags &= ~MPQ_FLAG_SAVING_TABLES; + } + + // Return the error + if(nResultError != ERROR_SUCCESS) + SetLastError(nResultError); + return (nResultError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// bool SFileCloseArchive(HANDLE hMpq); +// + +bool WINAPI SFileCloseArchive(HANDLE hMpq) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + bool bResult = false; + + // Only if the handle is valid + if(ha == NULL) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Invalidate the add file callback so it won't be called + // when saving (listfile) and (attributes) + ha->pfnAddFileCB = NULL; + ha->pvAddFileUserData = NULL; + + // Flush all unsaved data to the storage + bResult = SFileFlushArchive(hMpq); + + // Free all memory used by MPQ archive + FreeArchiveHandle(ha); + return bResult; +} diff --git a/dep/StormLib/src/SFileOpenFileEx.cpp b/dep/StormLib/src/SFileOpenFileEx.cpp new file mode 100644 index 000000000..72eb15d9f --- /dev/null +++ b/dep/StormLib/src/SFileOpenFileEx.cpp @@ -0,0 +1,398 @@ +/*****************************************************************************/ +/* SFileOpenFileEx.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad The first version of SFileOpenFileEx.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +/*****************************************************************************/ +/* Local functions */ +/*****************************************************************************/ + +static DWORD FindHashIndex(TMPQArchive * ha, DWORD dwFileIndex) +{ + TMPQHash * pHashTableEnd; + TMPQHash * pHash; + DWORD dwFirstIndex = HASH_ENTRY_FREE; + + // Should only be called if the archive has hash table + assert(ha->pHashTable != NULL); + + // Multiple hash table entries can point to the file table entry. + // We need to search all of them + pHashTableEnd = ha->pHashTable + ha->pHeader->dwHashTableSize; + for(pHash = ha->pHashTable; pHash < pHashTableEnd; pHash++) + { + if(MPQ_BLOCK_INDEX(pHash) == dwFileIndex) + { + // Duplicate hash entry found + if(dwFirstIndex != HASH_ENTRY_FREE) + return HASH_ENTRY_FREE; + dwFirstIndex = (DWORD)(pHash - ha->pHashTable); + } + } + + // Return the hash table entry index + return dwFirstIndex; +} + +static const char * GetPatchFileName(TMPQArchive * ha, const char * szFileName, char * szBuffer) +{ + TMPQNamePrefix * pPrefix; + + // Are there patches in the current MPQ? + if(ha->dwFlags & MPQ_FLAG_PATCH) + { + // The patch prefix must be already known here + assert(ha->pPatchPrefix != NULL); + pPrefix = ha->pPatchPrefix; + + // The patch name for "OldWorld\\XXX\\YYY" is "Base\\XXX\YYY" + // We need to remove the "OldWorld\\" prefix + if(!_strnicmp(szFileName, "OldWorld\\", 9)) + szFileName += 9; + + // Create the file name from the known patch entry + memcpy(szBuffer, pPrefix->szPatchPrefix, pPrefix->nLength); + strcpy(szBuffer + pPrefix->nLength, szFileName); + szFileName = szBuffer; + } + + return szFileName; +} + +static bool OpenLocalFile(const char * szFileName, HANDLE * PtrFile) +{ + TFileStream * pStream; + TMPQFile * hf = NULL; + TCHAR szFileNameT[MAX_PATH]; + + // Convert the file name to UNICODE (if needed) + StringCopy(szFileNameT, _countof(szFileNameT), szFileName); + + // Open the file and create the TMPQFile structure + pStream = FileStream_OpenFile(szFileNameT, STREAM_FLAG_READ_ONLY); + if(pStream != NULL) + { + // Allocate and initialize file handle + hf = CreateFileHandle(NULL, NULL); + if(hf != NULL) + { + hf->pStream = pStream; + *PtrFile = hf; + return true; + } + else + { + FileStream_Close(pStream); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + } + } + *PtrFile = NULL; + return false; +} + +bool OpenPatchedFile(HANDLE hMpq, const char * szFileName, HANDLE * PtrFile) +{ + TMPQArchive * haBase = NULL; + TMPQArchive * ha = (TMPQArchive *)hMpq; + TFileEntry * pFileEntry; + TMPQFile * hfPatch; // Pointer to patch file + TMPQFile * hfBase = NULL; // Pointer to base open file + TMPQFile * hf = NULL; + HANDLE hPatchFile; + char szNameBuffer[MAX_PATH]; + + // First of all, find the latest archive where the file is in base version + // (i.e. where the original, unpatched version of the file exists) + while(ha != NULL) + { + // If the file is there, then we remember the archive + pFileEntry = GetFileEntryExact(ha, GetPatchFileName(ha, szFileName, szNameBuffer), 0, NULL); + if(pFileEntry != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + haBase = ha; + + // Move to the patch archive + ha = ha->haPatch; + } + + // If we couldn't find the base file in any of the patches, it doesn't exist + if((ha = haBase) == NULL) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return false; + } + + // Now open the base file + if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, (HANDLE *)&hfBase)) + { + // The file must be a base file, i.e. without MPQ_FILE_PATCH_FILE + assert((hfBase->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0); + hf = hfBase; + + // Now open all patches and attach them on top of the base file + for(ha = ha->haPatch; ha != NULL; ha = ha->haPatch) + { + // Prepare the file name with a correct prefix + if(SFileOpenFileEx((HANDLE)ha, GetPatchFileName(ha, szFileName, szNameBuffer), SFILE_OPEN_BASE_FILE, &hPatchFile)) + { + // Remember the new version + hfPatch = (TMPQFile *)hPatchFile; + + // We should not find patch file + assert((hfPatch->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) != 0); + + // Attach the patch to the base file + hf->hfPatch = hfPatch; + hf = hfPatch; + } + } + } + + // Give the updated base MPQ + if(PtrFile != NULL) + *PtrFile = (HANDLE)hfBase; + return (hfBase != NULL); +} + +/*****************************************************************************/ +/* Public functions */ +/*****************************************************************************/ + +//----------------------------------------------------------------------------- +// SFileEnumLocales enums all locale versions within MPQ. +// Functions fills all available language identifiers on a file into the buffer +// pointed by plcLocales. There must be enough entries to copy the localed, +// otherwise the function returns ERROR_INSUFFICIENT_BUFFER. + +int WINAPI SFileEnumLocales( + HANDLE hMpq, + const char * szFileName, + LCID * PtrLocales, + LPDWORD PtrMaxLocales, + DWORD dwSearchScope) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + TMPQHash * pFirstHash; + TMPQHash * pHash; + DWORD dwFileIndex = 0; + DWORD dwMaxLocales; + DWORD dwLocales = 0; + + // Test the parameters + if(!IsValidMpqHandle(hMpq)) + return ERROR_INVALID_HANDLE; + if(szFileName == NULL || *szFileName == 0) + return ERROR_INVALID_PARAMETER; + if(ha->pHashTable == NULL) + return ERROR_NOT_SUPPORTED; + if(PtrMaxLocales == NULL) + return ERROR_INVALID_PARAMETER; + if(IsPseudoFileName(szFileName, &dwFileIndex)) + return ERROR_INVALID_PARAMETER; + + // Keep compiler happy + dwMaxLocales = PtrMaxLocales[0]; + + // Parse all files with that name + pFirstHash = pHash = GetFirstHashEntry(ha, szFileName); + while(pHash != NULL) + { + // Put the locales to the buffer + if(PtrLocales != NULL && dwLocales < dwMaxLocales) + *PtrLocales++ = pHash->lcLocale; + dwLocales++; + + // Get the next locale + pHash = GetNextHashEntry(ha, pFirstHash, pHash); + } + + // Give the caller the number of locales and return + PtrMaxLocales[0] = dwLocales; + return (dwLocales <= dwMaxLocales) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER; +} + +//----------------------------------------------------------------------------- +// SFileOpenFileEx +// +// hMpq - Handle of opened MPQ archive +// szFileName - Name of file to open +// dwSearchScope - Where to search +// PtrFile - Pointer to store opened file handle + +bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * PtrFile) +{ + TMPQArchive * ha = IsValidMpqHandle(hMpq); + TFileEntry * pFileEntry = NULL; + TMPQFile * hf = NULL; + DWORD dwHashIndex = HASH_ENTRY_FREE; + DWORD dwFileIndex = 0; + bool bOpenByIndex = false; + int nError = ERROR_SUCCESS; + + // Don't accept NULL pointer to file handle + if(szFileName == NULL || *szFileName == 0) + nError = ERROR_INVALID_PARAMETER; + + // When opening a file from MPQ, the handle must be valid + if(dwSearchScope != SFILE_OPEN_LOCAL_FILE && ha == NULL) + nError = ERROR_INVALID_HANDLE; + + // When not checking for existence, the pointer to file handle must be valid + if(dwSearchScope != SFILE_OPEN_CHECK_EXISTS && PtrFile == NULL) + nError = ERROR_INVALID_PARAMETER; + + // Prepare the file opening + if(nError == ERROR_SUCCESS) + { + switch(dwSearchScope) + { + case SFILE_OPEN_FROM_MPQ: + case SFILE_OPEN_BASE_FILE: + case SFILE_OPEN_CHECK_EXISTS: + + // If this MPQ has no patches, open the file from this MPQ directly + if(ha->haPatch == NULL || dwSearchScope == SFILE_OPEN_BASE_FILE) + { + pFileEntry = GetFileEntryLocale2(ha, szFileName, lcFileLocale, &dwHashIndex); + } + + // If this MPQ is a patched archive, open the file as patched + else + { + return OpenPatchedFile(hMpq, szFileName, PtrFile); + } + break; + + case SFILE_OPEN_ANY_LOCALE: + + // This open option is reserved for opening MPQ internal listfile. + // No argument validation. Tries to open file with neutral locale first, + // then any other available. + pFileEntry = GetFileEntryLocale2(ha, szFileName, 0, &dwHashIndex); + break; + + case SFILE_OPEN_LOCAL_FILE: + + // Open a local file + return OpenLocalFile(szFileName, PtrFile); + + default: + + // Don't accept any other value + nError = ERROR_INVALID_PARAMETER; + break; + } + } + + // Check whether the file really exists in the MPQ + if(nError == ERROR_SUCCESS) + { + if(pFileEntry == NULL || (pFileEntry->dwFlags & MPQ_FILE_EXISTS) == 0) + { + // Check the pseudo-file name + if((bOpenByIndex = IsPseudoFileName(szFileName, &dwFileIndex)) == true) + { + // Get the file entry for the file + if(dwFileIndex < ha->dwFileTableSize) + { + pFileEntry = ha->pFileTable + dwFileIndex; + } + } + + if(pFileEntry == NULL) + { + nError = ERROR_FILE_NOT_FOUND; + } + } + + // Ignore unknown loading flags (example: MPQ_2016_v1_WME4_4.w3x) +// if(pFileEntry != NULL && pFileEntry->dwFlags & ~MPQ_FILE_VALID_FLAGS) +// nError = ERROR_NOT_SUPPORTED; + } + + // Did the caller just wanted to know if the file exists? + if(nError == ERROR_SUCCESS && dwSearchScope != SFILE_OPEN_CHECK_EXISTS) + { + // Allocate file handle + hf = CreateFileHandle(ha, pFileEntry); + if(hf != NULL) + { + // Get the hash index for the file + if(ha->pHashTable != NULL && dwHashIndex == HASH_ENTRY_FREE) + dwHashIndex = FindHashIndex(ha, dwFileIndex); + if(dwHashIndex != HASH_ENTRY_FREE) + hf->pHashEntry = ha->pHashTable + dwHashIndex; + hf->dwHashIndex = dwHashIndex; + + // If the MPQ has sector CRC enabled, enable if for the file + if(ha->dwFlags & MPQ_FLAG_CHECK_SECTOR_CRC) + hf->bCheckSectorCRCs = true; + + // If we know the real file name, copy it to the file entry + if(bOpenByIndex == false) + { + // If there is no file name yet, allocate it + AllocateFileName(ha, pFileEntry, szFileName); + + // If the file is encrypted, we should detect the file key + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + hf->dwFileKey = DecryptFileKey(szFileName, + pFileEntry->ByteOffset, + pFileEntry->dwFileSize, + pFileEntry->dwFlags); + } + } + } + else + { + nError = ERROR_NOT_ENOUGH_MEMORY; + } + } + + // Give the file entry + if(PtrFile != NULL) + PtrFile[0] = hf; + + // Return error code + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// SFileHasFile +// +// hMpq - Handle of opened MPQ archive +// szFileName - Name of file to look for + +bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName) +{ + return SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_CHECK_EXISTS, NULL); +} + +//----------------------------------------------------------------------------- +// bool WINAPI SFileCloseFile(HANDLE hFile); + +bool WINAPI SFileCloseFile(HANDLE hFile) +{ + TMPQFile * hf = (TMPQFile *)hFile; + + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + // Free the structure + FreeFileHandle(hf); + return true; +} diff --git a/dep/StormLib/src/SFilePatchArchives.cpp b/dep/StormLib/src/SFilePatchArchives.cpp new file mode 100644 index 000000000..dc16631bc --- /dev/null +++ b/dep/StormLib/src/SFilePatchArchives.cpp @@ -0,0 +1,1175 @@ +/*****************************************************************************/ +/* SFilePatchArchives.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* Description: */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 18.08.10 1.00 Lad The first version of SFilePatchArchives.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local structures + +#define MAX_SC2_PATCH_PREFIX 0x80 + +#define PATCH_SIGNATURE_HEADER 0x48435450 +#define PATCH_SIGNATURE_MD5 0x5f35444d +#define PATCH_SIGNATURE_XFRM 0x4d524658 + +#define SIZE_OF_XFRM_HEADER 0x0C + +// Header for incremental patch files +typedef struct _MPQ_PATCH_HEADER +{ + //-- PATCH header ----------------------------------- + DWORD dwSignature; // 'PTCH' + DWORD dwSizeOfPatchData; // Size of the entire patch (decompressed) + DWORD dwSizeBeforePatch; // Size of the file before patch + DWORD dwSizeAfterPatch; // Size of file after patch + + //-- MD5 block -------------------------------------- + DWORD dwMD5; // 'MD5_' + DWORD dwMd5BlockSize; // Size of the MD5 block, including the signature and size itself + BYTE md5_before_patch[0x10]; // MD5 of the original (unpached) file + BYTE md5_after_patch[0x10]; // MD5 of the patched file + + //-- XFRM block ------------------------------------- + DWORD dwXFRM; // 'XFRM' + DWORD dwXfrmBlockSize; // Size of the XFRM block, includes XFRM header and patch data + DWORD dwPatchType; // Type of patch ('BSD0' or 'COPY') + + // Followed by the patch data +} MPQ_PATCH_HEADER, *PMPQ_PATCH_HEADER; + +typedef struct _BLIZZARD_BSDIFF40_FILE +{ + ULONGLONG Signature; + ULONGLONG CtrlBlockSize; + ULONGLONG DataBlockSize; + ULONGLONG NewFileSize; +} BLIZZARD_BSDIFF40_FILE, *PBLIZZARD_BSDIFF40_FILE; + +typedef struct _BSDIFF_CTRL_BLOCK +{ + DWORD dwAddDataLength; + DWORD dwMovDataLength; + DWORD dwOldMoveLength; + +} BSDIFF_CTRL_BLOCK, *PBSDIFF_CTRL_BLOCK; + +typedef struct _LOCALIZED_MPQ_INFO +{ + const char * szNameTemplate; // Name template + size_t nLangOffset; // Offset of the language + size_t nLength; // Length of the name template +} LOCALIZED_MPQ_INFO, *PLOCALIZED_MPQ_INFO; + +//----------------------------------------------------------------------------- +// Local variables + +// 4-byte groups for all languages +static const char * LanguageList = "baseteenenUSenGBenCNenTWdeDEesESesMXfrFRitITkoKRptBRptPTruRUzhCNzhTW"; + +// List of localized MPQs for World of Warcraft +static LOCALIZED_MPQ_INFO LocaleMpqs_WoW[] = +{ + {"expansion1-locale-####", 18, 22}, + {"expansion1-speech-####", 18, 22}, + {"expansion2-locale-####", 18, 22}, + {"expansion2-speech-####", 18, 22}, + {"expansion3-locale-####", 18, 22}, + {"expansion3-speech-####", 18, 22}, + {"locale-####", 7, 11}, + {"speech-####", 7, 11}, + {NULL, 0, 0} +}; + +//----------------------------------------------------------------------------- +// Local functions + +static inline bool IsPatchMetadataFile(TFileEntry * pFileEntry) +{ + // The file must ave a name + if(pFileEntry->szFileName != NULL && (pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + { + // The file must be small + if(0 < pFileEntry->dwFileSize && pFileEntry->dwFileSize < 0x40) + { + // Compare the plain name + return (_stricmp(GetPlainFileName(pFileEntry->szFileName), PATCH_METADATA_NAME) == 0); + } + } + + // Not a patch_metadata + return false; +} + +static void Decompress_RLE(LPBYTE pbDecompressed, DWORD cbDecompressed, LPBYTE pbCompressed, DWORD cbCompressed) +{ + LPBYTE pbDecompressedEnd = pbDecompressed + cbDecompressed; + LPBYTE pbCompressedEnd = pbCompressed + cbCompressed; + BYTE RepeatCount; + BYTE OneByte; + + // Cut the initial DWORD from the compressed chunk + pbCompressed += sizeof(DWORD); + + // Pre-fill decompressed buffer with zeros + memset(pbDecompressed, 0, cbDecompressed); + + // Unpack + while(pbCompressed < pbCompressedEnd && pbDecompressed < pbDecompressedEnd) + { + OneByte = *pbCompressed++; + + // Is it a repetition byte ? + if(OneByte & 0x80) + { + RepeatCount = (OneByte & 0x7F) + 1; + for(BYTE i = 0; i < RepeatCount; i++) + { + if(pbDecompressed == pbDecompressedEnd || pbCompressed == pbCompressedEnd) + break; + + *pbDecompressed++ = *pbCompressed++; + } + } + else + { + pbDecompressed += (OneByte + 1); + } + } +} + +static int LoadFilePatch_COPY(TMPQFile * hf, PMPQ_PATCH_HEADER pFullPatch) +{ + DWORD cbBytesToRead = pFullPatch->dwSizeOfPatchData - sizeof(MPQ_PATCH_HEADER); + DWORD cbBytesRead = 0; + + // Simply load the rest of the patch + SFileReadFile((HANDLE)hf, (pFullPatch + 1), cbBytesToRead, &cbBytesRead, NULL); + return (cbBytesRead == cbBytesToRead) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; +} + +static int LoadFilePatch_BSD0(TMPQFile * hf, PMPQ_PATCH_HEADER pFullPatch) +{ + LPBYTE pbDecompressed = (LPBYTE)(pFullPatch + 1); + LPBYTE pbCompressed = NULL; + DWORD cbDecompressed = 0; + DWORD cbCompressed = 0; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Calculate the size of compressed data + cbDecompressed = pFullPatch->dwSizeOfPatchData - sizeof(MPQ_PATCH_HEADER); + cbCompressed = pFullPatch->dwXfrmBlockSize - SIZE_OF_XFRM_HEADER; + + // Is that file compressed? + if(cbCompressed < cbDecompressed) + { + pbCompressed = STORM_ALLOC(BYTE, cbCompressed); + if(pbCompressed == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + + // Read the compressed patch data + if(nError == ERROR_SUCCESS) + { + SFileReadFile((HANDLE)hf, pbCompressed, cbCompressed, &dwBytesRead, NULL); + if(dwBytesRead != cbCompressed) + nError = ERROR_FILE_CORRUPT; + } + + // Decompress the data + if(nError == ERROR_SUCCESS) + Decompress_RLE(pbDecompressed, cbDecompressed, pbCompressed, cbCompressed); + + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + } + else + { + SFileReadFile((HANDLE)hf, pbDecompressed, cbDecompressed, &dwBytesRead, NULL); + if(dwBytesRead != cbDecompressed) + nError = ERROR_FILE_CORRUPT; + } + + return nError; +} + +static int ApplyFilePatch_COPY( + TMPQPatcher * pPatcher, + PMPQ_PATCH_HEADER pFullPatch, + LPBYTE pbTarget, + LPBYTE pbSource) +{ + // Sanity checks + assert(pPatcher->cbMaxFileData >= pPatcher->cbFileData); + pFullPatch = pFullPatch; + + // Copy the patch data as-is + memcpy(pbTarget, pbSource, pPatcher->cbFileData); + return ERROR_SUCCESS; +} + +static int ApplyFilePatch_BSD0( + TMPQPatcher * pPatcher, + PMPQ_PATCH_HEADER pFullPatch, + LPBYTE pbTarget, + LPBYTE pbSource) +{ + PBLIZZARD_BSDIFF40_FILE pBsdiff; + PBSDIFF_CTRL_BLOCK pCtrlBlock; + LPBYTE pbPatchData = (LPBYTE)(pFullPatch + 1); + LPBYTE pDataBlock; + LPBYTE pExtraBlock; + LPBYTE pbOldData = pbSource; + LPBYTE pbNewData = pbTarget; + DWORD dwCombineSize; + DWORD dwNewOffset = 0; // Current position to patch + DWORD dwOldOffset = 0; // Current source position + DWORD dwNewSize; // Patched file size + DWORD dwOldSize = pPatcher->cbFileData; // File size before patch + + // Get pointer to the patch header + // Format of BSDIFF header corresponds to original BSDIFF, which is: + // 0000 8 bytes signature "BSDIFF40" + // 0008 8 bytes size of the control block + // 0010 8 bytes size of the data block + // 0018 8 bytes new size of the patched file + pBsdiff = (PBLIZZARD_BSDIFF40_FILE)pbPatchData; + pbPatchData += sizeof(BLIZZARD_BSDIFF40_FILE); + + // Get pointer to the 32-bit BSDIFF control block + // The control block follows immediately after the BSDIFF header + // and consists of three 32-bit integers + // 0000 4 bytes Length to copy from the BSDIFF data block the new file + // 0004 4 bytes Length to copy from the BSDIFF extra block + // 0008 4 bytes Size to increment source file offset + pCtrlBlock = (PBSDIFF_CTRL_BLOCK)pbPatchData; + pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->CtrlBlockSize); + + // Get the pointer to the data block + pDataBlock = (LPBYTE)pbPatchData; + pbPatchData += (size_t)BSWAP_INT64_UNSIGNED(pBsdiff->DataBlockSize); + + // Get the pointer to the extra block + pExtraBlock = (LPBYTE)pbPatchData; + dwNewSize = (DWORD)BSWAP_INT64_UNSIGNED(pBsdiff->NewFileSize); + + // Now patch the file + while(dwNewOffset < dwNewSize) + { + DWORD dwAddDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwAddDataLength); + DWORD dwMovDataLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwMovDataLength); + DWORD dwOldMoveLength = BSWAP_INT32_UNSIGNED(pCtrlBlock->dwOldMoveLength); + DWORD i; + + // Sanity check + if((dwNewOffset + dwAddDataLength) > dwNewSize) + return ERROR_FILE_CORRUPT; + + // Read the diff string to the target buffer + memcpy(pbNewData + dwNewOffset, pDataBlock, dwAddDataLength); + pDataBlock += dwAddDataLength; + + // Get the longest block that we can combine + dwCombineSize = ((dwOldOffset + dwAddDataLength) >= dwOldSize) ? (dwOldSize - dwOldOffset) : dwAddDataLength; + if((dwNewOffset + dwCombineSize) > dwNewSize || (dwNewOffset + dwCombineSize) < dwNewOffset) + return ERROR_FILE_CORRUPT; + + // Now combine the patch data with the original file + for(i = 0; i < dwCombineSize; i++) + pbNewData[dwNewOffset + i] = pbNewData[dwNewOffset + i] + pbOldData[dwOldOffset + i]; + + // Move the offsets + dwNewOffset += dwAddDataLength; + dwOldOffset += dwAddDataLength; + + // Sanity check + if((dwNewOffset + dwMovDataLength) > dwNewSize) + return ERROR_FILE_CORRUPT; + + // Copy the data from the extra block in BSDIFF patch + memcpy(pbNewData + dwNewOffset, pExtraBlock, dwMovDataLength); + pExtraBlock += dwMovDataLength; + dwNewOffset += dwMovDataLength; + + // Move the old offset + if(dwOldMoveLength & 0x80000000) + dwOldMoveLength = 0x80000000 - dwOldMoveLength; + dwOldOffset += dwOldMoveLength; + pCtrlBlock++; + } + + // The size after patch must match + if(dwNewOffset != pFullPatch->dwSizeAfterPatch) + return ERROR_FILE_CORRUPT; + + // Update the new data size + pPatcher->cbFileData = dwNewOffset; + return ERROR_SUCCESS; +} + +static PMPQ_PATCH_HEADER LoadFullFilePatch(TMPQFile * hf, MPQ_PATCH_HEADER & PatchHeader) +{ + PMPQ_PATCH_HEADER pFullPatch; + int nError = ERROR_SUCCESS; + + // BSWAP the entire header, if needed + BSWAP_ARRAY32_UNSIGNED(&PatchHeader, sizeof(DWORD) * 6); + BSWAP_ARRAY32_UNSIGNED(&PatchHeader.dwXFRM, sizeof(DWORD) * 3); + + // Verify the signatures in the patch header + if(PatchHeader.dwSignature != PATCH_SIGNATURE_HEADER || PatchHeader.dwMD5 != PATCH_SIGNATURE_MD5 || PatchHeader.dwXFRM != PATCH_SIGNATURE_XFRM) + return NULL; + + // Allocate space for patch header and compressed data + pFullPatch = (PMPQ_PATCH_HEADER)STORM_ALLOC(BYTE, PatchHeader.dwSizeOfPatchData); + if(pFullPatch != NULL) + { + // Copy the patch header + memcpy(pFullPatch, &PatchHeader, sizeof(MPQ_PATCH_HEADER)); + + // Read the patch, depending on patch type + if(nError == ERROR_SUCCESS) + { + switch(PatchHeader.dwPatchType) + { + case 0x59504f43: // 'COPY' + nError = LoadFilePatch_COPY(hf, pFullPatch); + break; + + case 0x30445342: // 'BSD0' + nError = LoadFilePatch_BSD0(hf, pFullPatch); + break; + + default: + nError = ERROR_FILE_CORRUPT; + break; + } + } + + // If something failed, free the patch buffer + if(nError != ERROR_SUCCESS) + { + STORM_FREE(pFullPatch); + pFullPatch = NULL; + } + } + + // Give the result to the caller + return pFullPatch; +} + +static int ApplyFilePatch( + TMPQPatcher * pPatcher, + PMPQ_PATCH_HEADER pFullPatch) +{ + LPBYTE pbSource = (pPatcher->nCounter & 0x1) ? pPatcher->pbFileData2 : pPatcher->pbFileData1; + LPBYTE pbTarget = (pPatcher->nCounter & 0x1) ? pPatcher->pbFileData1 : pPatcher->pbFileData2; + int nError; + + // Sanity checks + assert(pFullPatch->dwSizeAfterPatch <= pPatcher->cbMaxFileData); + + // Apply the patch according to the type + switch(pFullPatch->dwPatchType) + { + case 0x59504f43: // 'COPY' + nError = ApplyFilePatch_COPY(pPatcher, pFullPatch, pbTarget, pbSource); + break; + + case 0x30445342: // 'BSD0' + nError = ApplyFilePatch_BSD0(pPatcher, pFullPatch, pbTarget, pbSource); + break; + + default: + nError = ERROR_FILE_CORRUPT; + break; + } + + // Verify MD5 after patch + if(nError == ERROR_SUCCESS && pFullPatch->dwSizeAfterPatch != 0) + { + // Verify the patched file + if(!VerifyDataBlockHash(pbTarget, pFullPatch->dwSizeAfterPatch, pFullPatch->md5_after_patch)) + nError = ERROR_FILE_CORRUPT; + + // Copy the MD5 of the new block + memcpy(pPatcher->this_md5, pFullPatch->md5_after_patch, MD5_DIGEST_SIZE); + } + + return nError; +} + +//----------------------------------------------------------------------------- +// Local functions (patch prefix matching) + +static bool CreatePatchPrefix(TMPQArchive * ha, const char * szFileName, size_t nLength) +{ + TMPQNamePrefix * pNewPrefix; + + // If the length of the patch prefix was not entered, find it + // Not that the patch prefix must always begin with backslash + if(szFileName != NULL && nLength == 0) + nLength = strlen(szFileName); + + // Create the patch prefix + pNewPrefix = (TMPQNamePrefix *)STORM_ALLOC(BYTE, sizeof(TMPQNamePrefix) + nLength + 1); + if(pNewPrefix != NULL) + { + // Fill the name prefix. Also add the backslash + if(szFileName && nLength) + { + memcpy(pNewPrefix->szPatchPrefix, szFileName, nLength); + if(pNewPrefix->szPatchPrefix[nLength - 1] != '\\') + pNewPrefix->szPatchPrefix[nLength++] = '\\'; + } + + // Terminate the string and fill the length + pNewPrefix->szPatchPrefix[nLength] = 0; + pNewPrefix->nLength = nLength; + } + + ha->pPatchPrefix = pNewPrefix; + return (pNewPrefix != NULL); +} + +static bool CheckAndCreatePatchPrefix(TMPQArchive * ha, const char * szPatchPrefix, size_t nLength) +{ + char szTempName[MAX_SC2_PATCH_PREFIX + 0x41]; + bool bResult = false; + + // Prepare the patch file name + if(nLength > MAX_SC2_PATCH_PREFIX) + return false; + + // Prepare the patched file name + memcpy(szTempName, szPatchPrefix, nLength); + memcpy(&szTempName[nLength], "\\(patch_metadata)", 18); + + // Verifywhether that file exists + if(GetFileEntryLocale(ha, szTempName, 0) != NULL) + bResult = CreatePatchPrefix(ha, szPatchPrefix, nLength); + + return bResult; +} + +static bool IsMatchingPatchFile( + TMPQArchive * ha, + const char * szFileName, + LPBYTE pbBaseFileMd5) +{ + MPQ_PATCH_HEADER PatchHeader = {0}; + HANDLE hFile = NULL; + DWORD dwTransferred = 0; + DWORD dwFlags = 0; + bool bResult = false; + + // Open the file and load the patch header + if(SFileOpenFileEx((HANDLE)ha, szFileName, SFILE_OPEN_BASE_FILE, &hFile)) + { + // Retrieve the flags. We need to know whether the file is a patch or not + SFileGetFileInfo(hFile, SFileInfoFlags, &dwFlags, sizeof(DWORD), &dwTransferred); + if(dwFlags & MPQ_FILE_PATCH_FILE) + { + // Load the patch header + SFileReadFile(hFile, &PatchHeader, sizeof(MPQ_PATCH_HEADER), &dwTransferred, NULL); + BSWAP_ARRAY32_UNSIGNED(pPatchHeader, sizeof(DWORD) * 6); + + // If the file contains an incremental patch, + // compare the "MD5 before patching" with the base file MD5 + if(dwTransferred == sizeof(MPQ_PATCH_HEADER) && PatchHeader.dwSignature == PATCH_SIGNATURE_HEADER) + bResult = (!memcmp(PatchHeader.md5_before_patch, pbBaseFileMd5, MD5_DIGEST_SIZE)); + } + else + { + // TODO: How to match it if it's not an incremental patch? + // Example: StarCraft II\Updates\enGB\s2-update-enGB-23258.MPQ: + // Mods\Core.SC2Mod\enGB.SC2Assets\StreamingBuckets.txt" + bResult = false; + } + + // Close the file + SFileCloseFile(hFile); + } + + return bResult; +} + +static const char * FindArchiveLanguage(TMPQArchive * ha, PLOCALIZED_MPQ_INFO pMpqInfo) +{ + TFileEntry * pFileEntry; + const char * szLanguage = LanguageList; + char szFileName[0x40]; + + // Iterate through all localized languages + while(pMpqInfo->szNameTemplate != NULL) + { + // Iterate through all languages + for(szLanguage = LanguageList; szLanguage[0] != 0; szLanguage += 4) + { + // Construct the file name + memcpy(szFileName, pMpqInfo->szNameTemplate, pMpqInfo->nLength); + szFileName[pMpqInfo->nLangOffset + 0] = szLanguage[0]; + szFileName[pMpqInfo->nLangOffset + 1] = szLanguage[1]; + szFileName[pMpqInfo->nLangOffset + 2] = szLanguage[2]; + szFileName[pMpqInfo->nLangOffset + 3] = szLanguage[3]; + + // Append the suffix + memcpy(szFileName + pMpqInfo->nLength, "-md5.lst", 9); + + // Check whether the name exists + pFileEntry = GetFileEntryLocale(ha, szFileName, 0); + if(pFileEntry != NULL) + return szLanguage; + } + + // Move to the next language name + pMpqInfo++; + } + + // Not found + return NULL; +} + +//----------------------------------------------------------------------------- +// Finding ratch prefix for an temporary build of WoW (Pre-Cataclysm) + +static bool FindPatchPrefix_WoW_13164_13623(TMPQArchive * haBase, TMPQArchive * haPatch) +{ + const char * szPatchPrefix; + char szNamePrefix[0x08]; + + // Try to find the language of the MPQ archive + szPatchPrefix = FindArchiveLanguage(haBase, LocaleMpqs_WoW); + if(szPatchPrefix == NULL) + szPatchPrefix = "Base"; + + // Format the patch prefix + szNamePrefix[0] = szPatchPrefix[0]; + szNamePrefix[1] = szPatchPrefix[1]; + szNamePrefix[2] = szPatchPrefix[2]; + szNamePrefix[3] = szPatchPrefix[3]; + szNamePrefix[4] = '\\'; + szNamePrefix[5] = 0; + return CreatePatchPrefix(haPatch, szNamePrefix, 5); +} + +//----------------------------------------------------------------------------- +// Finding patch prefix for Starcraft II (Pre-Legacy of the Void) + +// +// This method tries to match the patch by placement of the archive (in the game subdirectory) +// +// Archive Path: %GAME_DIR%\Mods\SwarmMulti.SC2Mod\Base.SC2Data +// Patch Prefix: Mods\SwarmMulti.SC2Mod\Base.SC2Data +// +// Archive Path: %ANY_DIR%\MPQ_2013_v4_Mods#Liberty.SC2Mod#enGB.SC2Data +// Patch Prefix: Mods\Liberty.SC2Mod\enGB.SC2Data +// + +static bool CheckPatchPrefix_SC2_ArchiveName( + TMPQArchive * haPatch, + const TCHAR * szPathPtr, + const TCHAR * szSeparator, + const TCHAR * szPathEnd, + const TCHAR * szExpectedString, + size_t cchExpectedString) +{ + char szPatchPrefix[MAX_SC2_PATCH_PREFIX+0x41]; + size_t nLength = 0; + bool bResult = false; + + // Check whether the length is equal to the length of the expected string + if((size_t)(szSeparator - szPathPtr) == cchExpectedString) + { + // Now check the string itself + if(!_tcsnicmp(szPathPtr, szExpectedString, szSeparator - szPathPtr)) + { + // Copy the name string + for(; szPathPtr < szPathEnd; szPathPtr++) + { + if(szPathPtr[0] != _T('/') && szPathPtr[0] != _T('#')) + szPatchPrefix[nLength++] = (char)szPathPtr[0]; + else + szPatchPrefix[nLength++] = '\\'; + } + + // Check and create the patch prefix + bResult = CheckAndCreatePatchPrefix(haPatch, szPatchPrefix, nLength); + } + } + + return bResult; +} + +static bool FindPatchPrefix_SC2_ArchiveName(TMPQArchive * haBase, TMPQArchive * haPatch) +{ + const TCHAR * szPathBegin = FileStream_GetFileName(haBase->pStream); + const TCHAR * szSeparator = NULL; + const TCHAR * szPathEnd = szPathBegin + _tcslen(szPathBegin); + const TCHAR * szPathPtr; + int nSlashCount = 0; + int nDotCount = 0; + + // Skip the part where the patch prefix would be too long + if((szPathEnd - szPathBegin) > MAX_SC2_PATCH_PREFIX) + szPathBegin = szPathEnd - MAX_SC2_PATCH_PREFIX; + + // Search for the file extension + for(szPathPtr = szPathEnd; szPathPtr > szPathBegin; szPathPtr--) + { + if(szPathPtr[0] == _T('.')) + { + nDotCount++; + break; + } + } + + // Search for the possible begin of the prefix name + for(/* NOTHING */; szPathPtr > szPathBegin; szPathPtr--) + { + // Check the slashes, backslashes and hashes + if(szPathPtr[0] == _T('\\') || szPathPtr[0] == _T('/') || szPathPtr[0] == _T('#')) + { + if(nDotCount == 0) + return false; + szSeparator = szPathPtr; + nSlashCount++; + } + + // Check the path parts + if(szSeparator != NULL && nSlashCount >= nDotCount) + { + if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Battle.net"), 10)) + return true; + if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Campaigns"), 9)) + return true; + if(CheckPatchPrefix_SC2_ArchiveName(haPatch, szPathPtr, szSeparator, szPathEnd, _T("Mods"), 4)) + return true; + } + } + + // Not matched, sorry + return false; +} + +// +// This method tries to read the patch prefix from a helper file +// +// Example +// ========================================================= +// MPQ File Name: MPQ_2013_v4_Base1.SC2Data +// Helper File : MPQ_2013_v4_Base1.SC2Data-PATCH +// File Contains: PatchPrefix=Mods\Core.SC2Mod\Base.SC2Data +// Patch Prefix : Mods\Core.SC2Mod\Base.SC2Data +// + +static bool ExtractPatchPrefixFromFile(const TCHAR * szHelperFile, char * szPatchPrefix, size_t nMaxChars, size_t * PtrLength) +{ + TFileStream * pStream; + ULONGLONG FileSize = 0; + size_t nLength; + char szFileData[MAX_PATH+1]; + bool bResult = false; + + pStream = FileStream_OpenFile(szHelperFile, STREAM_FLAG_READ_ONLY); + if(pStream != NULL) + { + // Retrieve and check the file size + FileStream_GetSize(pStream, &FileSize); + if(12 <= FileSize && FileSize < MAX_PATH) + { + // Read the entire file to memory + if(FileStream_Read(pStream, NULL, szFileData, (DWORD)FileSize)) + { + // Terminate the buffer with zero + szFileData[(DWORD)FileSize] = 0; + + // The file data must begin with the "PatchPrefix" variable + if(!_strnicmp(szFileData, "PatchPrefix", 11)) + { + char * szLinePtr = szFileData + 11; + char * szLineEnd; + + // Skip spaces or '=' + while(szLinePtr[0] == ' ' || szLinePtr[0] == '=') + szLinePtr++; + szLineEnd = szLinePtr; + + // Find the end + while(szLineEnd[0] != 0 && szLineEnd[0] != 0x0A && szLineEnd[0] != 0x0D) + szLineEnd++; + nLength = (size_t)(szLineEnd - szLinePtr); + + // Copy the variable + if(szLineEnd > szLinePtr && nLength <= nMaxChars) + { + memcpy(szPatchPrefix, szLinePtr, nLength); + szPatchPrefix[nLength] = 0; + PtrLength[0] = nLength; + bResult = true; + } + } + } + } + + // Close the stream + FileStream_Close(pStream); + } + + return bResult; +} + + +static bool FindPatchPrefix_SC2_HelperFile(TMPQArchive * haBase, TMPQArchive * haPatch) +{ + TCHAR szHelperFile[MAX_PATH+1]; + char szPatchPrefix[MAX_SC2_PATCH_PREFIX+0x41]; + size_t nLength = 0; + bool bResult = false; + + // Create the name of the patch helper file + _tcscpy(szHelperFile, FileStream_GetFileName(haBase->pStream)); + if(_tcslen(szHelperFile) + 6 > MAX_PATH) + return false; + _tcscat(szHelperFile, _T("-PATCH")); + + // Open the patch helper file and read the line + if(ExtractPatchPrefixFromFile(szHelperFile, szPatchPrefix, MAX_SC2_PATCH_PREFIX, &nLength)) + bResult = CheckAndCreatePatchPrefix(haPatch, szPatchPrefix, nLength); + + return bResult; +} + +// +// Find match in Starcraft II patch MPQs +// Match a LST file in the root directory if the MPQ with any of the file in subdirectories +// +// The problem: +// File in the base MPQ: enGB-md5.lst +// File in the patch MPQ: Campaigns\Liberty.SC2Campaign\enGB.SC2Assets\enGB-md5.lst +// Campaigns\Liberty.SC2Campaign\enGB.SC2Data\enGB-md5.lst +// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst +// Campaigns\LibertyStory.SC2Campaign\enGB.SC2Data\enGB-md5.lst Mods\Core.SC2Mod\enGB.SC2Assets\enGB-md5.lst +// Mods\Core.SC2Mod\enGB.SC2Data\enGB-md5.lst +// Mods\Liberty.SC2Mod\enGB.SC2Assets\enGB-md5.lst +// Mods\Liberty.SC2Mod\enGB.SC2Data\enGB-md5.lst +// Mods\LibertyMulti.SC2Mod\enGB.SC2Data\enGB-md5.lst +// +// Solution: +// We need to match the file by its MD5 +// + +static bool FindPatchPrefix_SC2_MatchFiles(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry) +{ + TMPQNamePrefix * pPatchPrefix; + char * szPatchFileName; + char * szPlainName; + size_t cchWorkBuffer = 0x400; + bool bResult = false; + + // First-level patches: Find the same file within the patch archive + // and verify by MD5-before-patch + if(haBase->haPatch == NULL) + { + TFileEntry * pFileTableEnd = haPatch->pFileTable + haPatch->dwFileTableSize; + TFileEntry * pFileEntry; + + // Allocate working buffer for merging LST file + szPatchFileName = STORM_ALLOC(char, cchWorkBuffer); + if(szPatchFileName != NULL) + { + // Parse the entire file table + for(pFileEntry = haPatch->pFileTable; pFileEntry < pFileTableEnd; pFileEntry++) + { + // Look for "patch_metadata" file + if(IsPatchMetadataFile(pFileEntry)) + { + // Construct the name of the MD5 file + strcpy(szPatchFileName, pFileEntry->szFileName); + szPlainName = (char *)GetPlainFileName(szPatchFileName); + strcpy(szPlainName, pBaseEntry->szFileName); + + // Check for matching MD5 file + if(IsMatchingPatchFile(haPatch, szPatchFileName, pBaseEntry->md5)) + { + bResult = CreatePatchPrefix(haPatch, szPatchFileName, (size_t)(szPlainName - szPatchFileName)); + break; + } + } + } + + // Delete the merge buffer + STORM_FREE(szPatchFileName); + } + } + + // For second-level patches, just take the patch prefix from the lower level patch + else + { + // There must be at least two patches in the chain + assert(haBase->haPatch->pPatchPrefix != NULL); + pPatchPrefix = haBase->haPatch->pPatchPrefix; + + // Copy the patch prefix + bResult = CreatePatchPrefix(haPatch, + pPatchPrefix->szPatchPrefix, + pPatchPrefix->nLength); + } + + return bResult; +} + +// Note: pBaseEntry is the file entry of the base version of "StreamingBuckets.txt" +static bool FindPatchPrefix_SC2(TMPQArchive * haBase, TMPQArchive * haPatch, TFileEntry * pBaseEntry) +{ + // Method 1: Try it by the placement of the archive. + // Works when someone is opening an archive in the game (sub)directory + if(FindPatchPrefix_SC2_ArchiveName(haBase, haPatch)) + return true; + + // Method 2: Try to locate the Name.Ext-PATCH file and read the patch prefix from it + if(FindPatchPrefix_SC2_HelperFile(haBase, haPatch)) + return true; + + // Method 3: Try to pair any version of "StreamingBuckets.txt" from the patch MPQ + // with the "StreamingBuckets.txt" in the base MPQ. Does not always work + if(FindPatchPrefix_SC2_MatchFiles(haBase, haPatch, pBaseEntry)) + return true; + + return false; +} + +// +// Patch prefix is the path subdirectory where the patched files are within MPQ. +// +// Example 1: +// Main MPQ: locale-enGB.MPQ +// Patch MPQ: wow-update-12694.MPQ +// File in main MPQ: DBFilesClient\Achievement.dbc +// File in patch MPQ: enGB\DBFilesClient\Achievement.dbc +// Path prefix: enGB +// +// Example 2: +// Main MPQ: expansion1.MPQ +// Patch MPQ: wow-update-12694.MPQ +// File in main MPQ: DBFilesClient\Achievement.dbc +// File in patch MPQ: Base\DBFilesClient\Achievement.dbc +// Path prefix: Base +// +// Example 3: +// Main MPQ: %GAME%\Battle.net\Battle.net.MPQ +// Patch MPQ: s2-update-base-26147.MPQ +// File in main MPQ: Battle.net\i18n\deDE\String\CLIENT_ACHIEVEMENTS.xml +// File in patch MPQ: Battle.net\Battle.net.MPQ\Battle.net\i18n\deDE\String\CLIENT_ACHIEVEMENTS.xml +// Path prefix: Battle.net\Battle.net.MPQ +// +// Example 4: +// Main MPQ: %GAME%\Campaigns\Liberty.SC2Campaign\enGB.SC2Data +// *OR* %ANY_DIR%\%ANY_NAME%Campaigns#Liberty.SC2Campaign#enGB.SC2Data +// Patch MPQ: s2-update-enGB-23258.MPQ +// File in main MPQ: LocalizedData\GameHotkeys.txt +// File in patch MPQ: Campaigns\Liberty.SC2Campaign\enGB.SC2Data\LocalizedData\GameHotkeys.txt +// Patch Prefix: Campaigns\Liberty.SC2Campaign\enGB.SC2Data +// + +static bool FindPatchPrefix(TMPQArchive * haBase, TMPQArchive * haPatch, const char * szPatchPathPrefix) +{ + TFileEntry * pFileEntry; + + // If the patch prefix was explicitly entered, we use that one + if(szPatchPathPrefix != NULL) + return CreatePatchPrefix(haPatch, szPatchPathPrefix, 0); + + // Patches for World of Warcraft - they mostly do not use prefix. + // All patches that use patch prefix have the "base\\(patch_metadata) file present + if(GetFileEntryLocale(haPatch, "base\\" PATCH_METADATA_NAME, 0)) + return FindPatchPrefix_WoW_13164_13623(haBase, haPatch); + + // Updates for Starcraft II + // Match: LocalizedData\GameHotkeys.txt <==> Campaigns\Liberty.SC2Campaign\enGB.SC2Data\LocalizedData\GameHotkeys.txt + // All Starcraft II base archives seem to have the file "StreamingBuckets.txt" present + pFileEntry = GetFileEntryLocale(haBase, "StreamingBuckets.txt", 0); + if(pFileEntry != NULL) + return FindPatchPrefix_SC2(haBase, haPatch, pFileEntry); + + // Diablo III patch MPQs don't use patch prefix + // Hearthstone MPQs don't use patch prefix + CreatePatchPrefix(haPatch, NULL, 0); + return true; +} + +//----------------------------------------------------------------------------- +// Public functions (StormLib internals) + +bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize) +{ + PMPQ_PATCH_HEADER pPatchHeader = (PMPQ_PATCH_HEADER)pvData; + BLIZZARD_BSDIFF40_FILE DiffFile; + DWORD dwPatchType; + + if(cbData >= sizeof(MPQ_PATCH_HEADER) + sizeof(BLIZZARD_BSDIFF40_FILE)) + { + dwPatchType = BSWAP_INT32_UNSIGNED(pPatchHeader->dwPatchType); + if(dwPatchType == 0x30445342) + { + // Give the caller the patch file size + if(pdwPatchedFileSize != NULL) + { + Decompress_RLE((LPBYTE)&DiffFile, sizeof(BLIZZARD_BSDIFF40_FILE), (LPBYTE)(pPatchHeader + 1), sizeof(BLIZZARD_BSDIFF40_FILE)); + DiffFile.NewFileSize = BSWAP_INT64_UNSIGNED(DiffFile.NewFileSize); + *pdwPatchedFileSize = (DWORD)DiffFile.NewFileSize; + return true; + } + } + } + + return false; +} + +int Patch_InitPatcher(TMPQPatcher * pPatcher, TMPQFile * hf) +{ + DWORD cbMaxFileData = 0; + + // Overflow check + if((cbMaxFileData + (DWORD)sizeof(MPQ_PATCH_HEADER)) < cbMaxFileData) + return ERROR_NOT_ENOUGH_MEMORY; + if(hf->hfPatch == NULL) + return ERROR_INVALID_PARAMETER; + + // Initialize the entire structure with zeros + memset(pPatcher, 0, sizeof(TMPQPatcher)); + + // Copy the MD5 of the current file + memcpy(pPatcher->this_md5, hf->pFileEntry->md5, MD5_DIGEST_SIZE); + + // Find out the biggest data size needed during the patching process + while(hf != NULL) + { + if(hf->pFileEntry->dwFileSize > cbMaxFileData) + cbMaxFileData = hf->pFileEntry->dwFileSize; + hf = hf->hfPatch; + } + + // Allocate primary and secondary buffer + pPatcher->pbFileData1 = STORM_ALLOC(BYTE, cbMaxFileData); + pPatcher->pbFileData2 = STORM_ALLOC(BYTE, cbMaxFileData); + if(!pPatcher->pbFileData1 || !pPatcher->pbFileData2) + return ERROR_NOT_ENOUGH_MEMORY; + + pPatcher->cbMaxFileData = cbMaxFileData; + return ERROR_SUCCESS; +} + +// +// Note: The patch may either be applied to the base file or to the previous version +// In Starcraft II, Mods\Core.SC2Mod\Base.SC2Data, file StreamingBuckets.txt: +// +// Base file MD5: 31376b0344b6df59ad009d4296125539 +// +// s2-update-base-23258: from 31376b0344b6df59ad009d4296125539 to 941a82683452e54bf024a8d491501824 +// s2-update-base-24540: from 31376b0344b6df59ad009d4296125539 to 941a82683452e54bf024a8d491501824 +// s2-update-base-26147: from 31376b0344b6df59ad009d4296125539 to d5d5253c762fac6b9761240288a0771a +// s2-update-base-28522: from 31376b0344b6df59ad009d4296125539 to 5a76c4b356920aab7afd22e0e1913d7a +// s2-update-base-30508: from 31376b0344b6df59ad009d4296125539 to 8cb0d4799893fe801cc78ae4488a3671 +// s2-update-base-32283: from 31376b0344b6df59ad009d4296125539 to 8cb0d4799893fe801cc78ae4488a3671 +// +// We don't keep all intermediate versions in memory, as it would cause massive +// memory usage during patching process. A prime example is the file +// DBFilesClient\\Item-Sparse.db2 from locale-enGB.MPQ (WoW 16965), which has +// 9 patches in a row, each requiring 70 MB memory (35 MB patch data + 35 MB work buffer) +// + +int Patch_Process(TMPQPatcher * pPatcher, TMPQFile * hf) +{ + PMPQ_PATCH_HEADER pFullPatch; + MPQ_PATCH_HEADER PatchHeader1; + MPQ_PATCH_HEADER PatchHeader2 = {0}; + TMPQFile * hfBase = hf; + DWORD cbBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Move to the first patch + assert(hfBase->pbFileData == NULL); + assert(hfBase->cbFileData == 0); + hf = hf->hfPatch; + + // Read the header of the current patch + SFileReadFile((HANDLE)hf, &PatchHeader1, sizeof(MPQ_PATCH_HEADER), &cbBytesRead, NULL); + if(cbBytesRead != sizeof(MPQ_PATCH_HEADER)) + return ERROR_FILE_CORRUPT; + + // Perform the patching process + while(nError == ERROR_SUCCESS && hf != NULL) + { + // Try to read the next patch header. If the md5_before_patch + // still matches we go directly to the next one and repeat + while(hf->hfPatch != NULL) + { + // Attempt to read the patch header + SFileReadFile((HANDLE)hf->hfPatch, &PatchHeader2, sizeof(MPQ_PATCH_HEADER), &cbBytesRead, NULL); + if(cbBytesRead != sizeof(MPQ_PATCH_HEADER)) + return ERROR_FILE_CORRUPT; + + // Compare the md5_before_patch + if(memcmp(PatchHeader2.md5_before_patch, pPatcher->this_md5, MD5_DIGEST_SIZE)) + break; + + // Move one patch fuhrter + PatchHeader1 = PatchHeader2; + hf = hf->hfPatch; + } + + // Allocate memory for the patch data + pFullPatch = LoadFullFilePatch(hf, PatchHeader1); + if(pFullPatch != NULL) + { + // Apply the patch + nError = ApplyFilePatch(pPatcher, pFullPatch); + STORM_FREE(pFullPatch); + } + else + { + nError = ERROR_FILE_CORRUPT; + } + + // Move to the next patch + PatchHeader1 = PatchHeader2; + pPatcher->nCounter++; + hf = hf->hfPatch; + } + + // Put the result data to the file structure + if(nError == ERROR_SUCCESS) + { + // Swap the pointer to the file data structure + if(pPatcher->nCounter & 0x01) + { + hfBase->pbFileData = pPatcher->pbFileData2; + pPatcher->pbFileData2 = NULL; + } + else + { + hfBase->pbFileData = pPatcher->pbFileData1; + pPatcher->pbFileData1 = NULL; + } + + // Also supply the data size + hfBase->cbFileData = pPatcher->cbFileData; + } + + return ERROR_SUCCESS; +} + +void Patch_Finalize(TMPQPatcher * pPatcher) +{ + if(pPatcher != NULL) + { + if(pPatcher->pbFileData1 != NULL) + STORM_FREE(pPatcher->pbFileData1); + if(pPatcher->pbFileData2 != NULL) + STORM_FREE(pPatcher->pbFileData2); + + memset(pPatcher, 0, sizeof(TMPQPatcher)); + } +} + + +//----------------------------------------------------------------------------- +// Public functions + +bool WINAPI SFileOpenPatchArchive( + HANDLE hMpq, + const TCHAR * szPatchMpqName, + const char * szPatchPathPrefix, + DWORD dwFlags) +{ + TMPQArchive * haPatch; + TMPQArchive * ha = (TMPQArchive *)hMpq; + HANDLE hPatchMpq = NULL; + int nError = ERROR_SUCCESS; + + // Keep compiler happy + dwFlags = dwFlags; + + // Verify input parameters + if(!IsValidMpqHandle(hMpq)) + nError = ERROR_INVALID_HANDLE; + if(szPatchMpqName == NULL || *szPatchMpqName == 0) + nError = ERROR_INVALID_PARAMETER; + + // + // We don't allow adding patches to archives that have been open for write + // + // Error scenario: + // + // 1) Open archive for writing + // 2) Modify or replace a file + // 3) Add patch archive to the opened MPQ + // 4) Read patched file + // 5) Now what ? + // + + if(nError == ERROR_SUCCESS) + { + if(!(ha->dwFlags & MPQ_FLAG_READ_ONLY)) + nError = ERROR_ACCESS_DENIED; + } + + // Open the archive like it is normal archive + if(nError == ERROR_SUCCESS) + { + if(SFileOpenArchive(szPatchMpqName, 0, MPQ_OPEN_READ_ONLY | MPQ_OPEN_PATCH, &hPatchMpq)) + { + // Cast the archive handle to structure pointer + haPatch = (TMPQArchive *)hPatchMpq; + + // We need to remember the proper patch prefix to match names of patched files + if(FindPatchPrefix(ha, (TMPQArchive *)hPatchMpq, szPatchPathPrefix)) + { + // Now add the patch archive to the list of patches to the original MPQ + while(ha != NULL) + { + if(ha->haPatch == NULL) + { + haPatch->haBase = ha; + ha->haPatch = haPatch; + return true; + } + + // Move to the next archive + ha = ha->haPatch; + } + } + + // Close the archive + SFileCloseArchive(hPatchMpq); + nError = ERROR_CANT_FIND_PATCH_PREFIX; + } + else + { + nError = GetLastError(); + } + } + + SetLastError(nError); + return false; +} + +bool WINAPI SFileIsPatchedArchive(HANDLE hMpq) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Verify input parameters + if(!IsValidMpqHandle(hMpq)) + return false; + + return (ha->haPatch != NULL); +} diff --git a/dep/StormLib/src/SFileReadFile.cpp b/dep/StormLib/src/SFileReadFile.cpp new file mode 100644 index 000000000..719064b0a --- /dev/null +++ b/dep/StormLib/src/SFileReadFile.cpp @@ -0,0 +1,898 @@ +/*****************************************************************************/ +/* SFileReadFile.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad The first version of SFileReadFile.cpp */ +/* 24.03.99 1.00 Lad Added the SFileGetFileInfo function */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local functions + +// hf - MPQ File handle. +// pbBuffer - Pointer to target buffer to store sectors. +// dwByteOffset - Position of sector in the file (relative to file begin) +// dwBytesToRead - Number of bytes to read. Must be multiplier of sector size. +// pdwBytesRead - Stored number of bytes loaded +static int ReadMpqSectors(TMPQFile * hf, LPBYTE pbBuffer, DWORD dwByteOffset, DWORD dwBytesToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos; + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbRawSector = NULL; + LPBYTE pbOutSector = pbBuffer; + LPBYTE pbInSector = pbBuffer; + DWORD dwRawBytesToRead; + DWORD dwRawSectorOffset = dwByteOffset; + DWORD dwSectorsToRead = dwBytesToRead / ha->dwSectorSize; + DWORD dwSectorIndex = dwByteOffset / ha->dwSectorSize; + DWORD dwSectorsDone = 0; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Note that dwByteOffset must be aligned to size of one sector + // Note that dwBytesToRead must be a multiplier of one sector size + // This is local function, so we won't check if that's true. + // Note that files stored in single units are processed by a separate function + + // If there is not enough bytes remaining, cut dwBytesToRead + if((dwByteOffset + dwBytesToRead) > hf->dwDataSize) + dwBytesToRead = hf->dwDataSize - dwByteOffset; + dwRawBytesToRead = dwBytesToRead; + + // Perform all necessary work to do with compressed files + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // If the sector positions are not loaded yet, do it + if(hf->SectorOffsets == NULL) + { + nError = AllocateSectorOffsets(hf, true); + if(nError != ERROR_SUCCESS || hf->SectorOffsets == NULL) + return nError; + } + + // If the sector checksums are not loaded yet, load them now. + if(hf->SectorChksums == NULL && (pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->bLoadedSectorCRCs == false) + { + // + // Sector CRCs is plain crap feature. It is almost never present, + // often it's empty, or the end offset of sector CRCs is zero. + // We only try to load sector CRCs once, and regardless if it fails + // or not, we won't try that again for the given file. + // + + AllocateSectorChecksums(hf, true); + hf->bLoadedSectorCRCs = true; + } + + // TODO: If the raw data MD5s are not loaded yet, load them now + // Only do it if the MPQ is of format 4.0 +// if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_4 && ha->pHeader->dwRawChunkSize != 0) +// { +// nError = AllocateRawMD5s(hf, true); +// if(nError != ERROR_SUCCESS) +// return nError; +// } + + // Assign the temporary buffer as target for read operation + dwRawSectorOffset = hf->SectorOffsets[dwSectorIndex]; + dwRawBytesToRead = hf->SectorOffsets[dwSectorIndex + dwSectorsToRead] - dwRawSectorOffset; + + // If the file is compressed, also allocate secondary buffer + pbInSector = pbRawSector = STORM_ALLOC(BYTE, dwRawBytesToRead); + if(pbRawSector == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + } + + // Calculate raw file offset where the sector(s) are stored. + RawFilePos = CalculateRawSectorOffset(hf, dwRawSectorOffset); + + // Set file pointer and read all required sectors + if(FileStream_Read(ha->pStream, &RawFilePos, pbInSector, dwRawBytesToRead)) + { + // Now we have to decrypt and decompress all file sectors that have been loaded + for(DWORD i = 0; i < dwSectorsToRead; i++) + { + DWORD dwRawBytesInThisSector = ha->dwSectorSize; + DWORD dwBytesInThisSector = ha->dwSectorSize; + DWORD dwIndex = dwSectorIndex + i; + + // If there is not enough bytes in the last sector, + // cut the number of bytes in this sector + if(dwRawBytesInThisSector > dwBytesToRead) + dwRawBytesInThisSector = dwBytesToRead; + if(dwBytesInThisSector > dwBytesToRead) + dwBytesInThisSector = dwBytesToRead; + + // If the file is compressed, we have to adjust the raw sector size + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + dwRawBytesInThisSector = hf->SectorOffsets[dwIndex + 1] - hf->SectorOffsets[dwIndex]; + + // If the file is encrypted, we have to decrypt the sector + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); + + // If we don't know the key, try to detect it by file content + if(hf->dwFileKey == 0) + { + hf->dwFileKey = DetectFileKeyByContent(pbInSector, dwBytesInThisSector, hf->dwDataSize); + if(hf->dwFileKey == 0) + { + nError = ERROR_UNKNOWN_FILE_KEY; + break; + } + } + + DecryptMpqBlock(pbInSector, dwRawBytesInThisSector, hf->dwFileKey + dwIndex); + BSWAP_ARRAY32_UNSIGNED(pbInSector, dwRawBytesInThisSector); + } + + // If the file has sector CRC check turned on, perform it + if(hf->bCheckSectorCRCs && hf->SectorChksums != NULL) + { + DWORD dwAdlerExpected = hf->SectorChksums[dwIndex]; + DWORD dwAdlerValue = 0; + + // We can only check sector CRC when it's not zero + // Neither can we check it if it's 0xFFFFFFFF. + if(dwAdlerExpected != 0 && dwAdlerExpected != 0xFFFFFFFF) + { + dwAdlerValue = adler32(0, pbInSector, dwRawBytesInThisSector); + if(dwAdlerValue != dwAdlerExpected) + { + nError = ERROR_CHECKSUM_ERROR; + break; + } + } + } + + // If the sector is really compressed, decompress it. + // WARNING : Some sectors may not be compressed, it can be determined only + // by comparing uncompressed and compressed size !!! + if(dwRawBytesInThisSector < dwBytesInThisSector) + { + int cbOutSector = dwBytesInThisSector; + int cbInSector = dwRawBytesInThisSector; + int nResult = 0; + + // Is the file compressed by Blizzard's multiple compression ? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) + { + // Remember the last used compression + hf->dwCompression0 = pbInSector[0]; + + // Decompress the data + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + nResult = SCompDecompress2(pbOutSector, &cbOutSector, pbInSector, cbInSector); + else + nResult = SCompDecompress(pbOutSector, &cbOutSector, pbInSector, cbInSector); + } + + // Is the file compressed by PKWARE Data Compression Library ? + else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + { + nResult = SCompExplode(pbOutSector, &cbOutSector, pbInSector, cbInSector); + } + + // Did the decompression fail ? + if(nResult == 0) + { + nError = ERROR_FILE_CORRUPT; + break; + } + } + else + { + if(pbOutSector != pbInSector) + memcpy(pbOutSector, pbInSector, dwBytesInThisSector); + } + + // Move pointers + dwBytesToRead -= dwBytesInThisSector; + dwByteOffset += dwBytesInThisSector; + dwBytesRead += dwBytesInThisSector; + pbOutSector += dwBytesInThisSector; + pbInSector += dwRawBytesInThisSector; + dwSectorsDone++; + } + } + else + { + nError = GetLastError(); + } + + // Free all used buffers + if(pbRawSector != NULL) + STORM_FREE(pbRawSector); + + // Give the caller thenumber of bytes read + *pdwBytesRead = dwBytesRead; + return nError; +} + +static int ReadMpqFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos = hf->RawFilePos; + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed = NULL; + LPBYTE pbRawData; + int nError = ERROR_SUCCESS; + + // If the file buffer is not allocated yet, do it. + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + } + + // If the file is a patch file, adjust raw data offset + if(hf->pPatchInfo != NULL) + RawFilePos += hf->pPatchInfo->dwLength; + pbRawData = hf->pbFileSector; + + // If the file sector is not loaded yet, do it + if(hf->dwSectorOffs != 0) + { + // Is the file compressed? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // Allocate space for compressed data + pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + pbRawData = pbCompressed; + } + + // Load the raw (compressed, encrypted) data + if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize)) + { + STORM_FREE(pbCompressed); + return GetLastError(); + } + + // If the file is encrypted, we have to decrypt the data first + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize); + DecryptMpqBlock(pbRawData, pFileEntry->dwCmpSize, hf->dwFileKey); + BSWAP_ARRAY32_UNSIGNED(pbRawData, pFileEntry->dwCmpSize); + } + + // If the file is compressed, we have to decompress it now + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + int cbOutBuffer = (int)hf->dwDataSize; + int cbInBuffer = (int)pFileEntry->dwCmpSize; + int nResult = 0; + + // + // If the file is an incremental patch, the size of compressed data + // is determined as pFileEntry->dwCmpSize - sizeof(TPatchInfo) + // + // In "wow-update-12694.MPQ" from Wow-Cataclysm BETA: + // + // File CmprSize DcmpSize DataSize Compressed? + // -------------------------------------- ---------- -------- -------- --------------- + // esES\DBFilesClient\LightSkyBox.dbc 0xBE->0xA2 0xBC 0xBC Yes + // deDE\DBFilesClient\MountCapability.dbc 0x93->0x77 0x77 0x77 No + // + + if(pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) + cbInBuffer = cbInBuffer - sizeof(TPatchInfo); + + // Is the file compressed by Blizzard's multiple compression ? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS) + { + // Remember the last used compression + hf->dwCompression0 = pbRawData[0]; + + // Decompress the file + if(ha->pHeader->wFormatVersion >= MPQ_FORMAT_VERSION_2) + nResult = SCompDecompress2(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + else + nResult = SCompDecompress(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + } + + // Is the file compressed by PKWARE Data Compression Library ? + // Note: Single unit files compressed with IMPLODE are not supported by Blizzard + else if(pFileEntry->dwFlags & MPQ_FILE_IMPLODE) + nResult = SCompExplode(hf->pbFileSector, &cbOutBuffer, pbRawData, cbInBuffer); + + nError = (nResult != 0) ? ERROR_SUCCESS : ERROR_FILE_CORRUPT; + } + else + { + if(hf->pbFileSector != NULL && pbRawData != hf->pbFileSector) + memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize); + } + + // Free the decompression buffer. + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + + // The file sector is now properly loaded + hf->dwSectorOffs = 0; + } + + // At this moment, we have the file loaded into the file buffer. + // Copy as much as the caller wants + if(nError == ERROR_SUCCESS && hf->dwSectorOffs == 0) + { + // File position is greater or equal to file size ? + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes remaining in the file, cut them + if((hf->dwDataSize - dwFilePos) < dwToRead) + dwToRead = (hf->dwDataSize - dwFilePos); + + // Copy the bytes + memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead); + + // Give the number of bytes read + *pdwBytesRead = dwToRead; + return ERROR_SUCCESS; + } + + // An error, sorry + return ERROR_CAN_NOT_COMPLETE; +} + +static int ReadMpkFileSingleUnit(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG RawFilePos = hf->RawFilePos + 0x0C; // For some reason, MPK files start at position (hf->RawFilePos + 0x0C) + TMPQArchive * ha = hf->ha; + TFileEntry * pFileEntry = hf->pFileEntry; + LPBYTE pbCompressed = NULL; + LPBYTE pbRawData = hf->pbFileSector; + int nError = ERROR_SUCCESS; + + // We do not support patch files in MPK archives + assert(hf->pPatchInfo == NULL); + + // If the file buffer is not allocated yet, do it. + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + pbRawData = hf->pbFileSector; + } + + // If the file sector is not loaded yet, do it + if(hf->dwSectorOffs != 0) + { + // Is the file compressed? + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + // Allocate space for compressed data + pbCompressed = STORM_ALLOC(BYTE, pFileEntry->dwCmpSize); + if(pbCompressed == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + pbRawData = pbCompressed; + } + + // Load the raw (compressed, encrypted) data + if(!FileStream_Read(ha->pStream, &RawFilePos, pbRawData, pFileEntry->dwCmpSize)) + { + STORM_FREE(pbCompressed); + return GetLastError(); + } + + // If the file is encrypted, we have to decrypt the data first + if(pFileEntry->dwFlags & MPQ_FILE_ENCRYPTED) + { + DecryptMpkTable(pbRawData, pFileEntry->dwCmpSize); + } + + // If the file is compressed, we have to decompress it now + if(pFileEntry->dwFlags & MPQ_FILE_COMPRESS_MASK) + { + int cbOutBuffer = (int)hf->dwDataSize; + + hf->dwCompression0 = pbRawData[0]; + if(!SCompDecompressMpk(hf->pbFileSector, &cbOutBuffer, pbRawData, (int)pFileEntry->dwCmpSize)) + nError = ERROR_FILE_CORRUPT; + } + else + { + if(pbRawData != hf->pbFileSector) + memcpy(hf->pbFileSector, pbRawData, hf->dwDataSize); + } + + // Free the decompression buffer. + if(pbCompressed != NULL) + STORM_FREE(pbCompressed); + + // The file sector is now properly loaded + hf->dwSectorOffs = 0; + } + + // At this moment, we have the file loaded into the file buffer. + // Copy as much as the caller wants + if(nError == ERROR_SUCCESS && hf->dwSectorOffs == 0) + { + // File position is greater or equal to file size ? + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes remaining in the file, cut them + if((hf->dwDataSize - dwFilePos) < dwToRead) + dwToRead = (hf->dwDataSize - dwFilePos); + + // Copy the bytes + memcpy(pvBuffer, hf->pbFileSector + dwFilePos, dwToRead); + + // Give the number of bytes read + *pdwBytesRead = dwToRead; + return ERROR_SUCCESS; + } + + // An error, sorry + return ERROR_CAN_NOT_COMPLETE; +} + + +static int ReadMpqFileSectorFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwBytesToRead, LPDWORD pdwBytesRead) +{ + TMPQArchive * ha = hf->ha; + LPBYTE pbBuffer = (BYTE *)pvBuffer; + DWORD dwTotalBytesRead = 0; // Total bytes read in all three parts + DWORD dwSectorSizeMask = ha->dwSectorSize - 1; // Mask for block size, usually 0x0FFF + DWORD dwFileSectorPos; // File offset of the loaded sector + DWORD dwBytesRead; // Number of bytes read (temporary variable) + int nError; + + // If the file position is at or beyond end of file, do nothing + if(dwFilePos >= hf->dwDataSize) + { + *pdwBytesRead = 0; + return ERROR_SUCCESS; + } + + // If not enough bytes in the file remaining, cut them + if(dwBytesToRead > (hf->dwDataSize - dwFilePos)) + dwBytesToRead = (hf->dwDataSize - dwFilePos); + + // Compute sector position in the file + dwFileSectorPos = dwFilePos & ~dwSectorSizeMask; // Position in the block + + // If the file sector buffer is not allocated yet, do it now + if(hf->pbFileSector == NULL) + { + nError = AllocateSectorBuffer(hf); + if(nError != ERROR_SUCCESS || hf->pbFileSector == NULL) + return nError; + } + + // Load the first (incomplete) file sector + if(dwFilePos & dwSectorSizeMask) + { + DWORD dwBytesInSector = ha->dwSectorSize; + DWORD dwBufferOffs = dwFilePos & dwSectorSizeMask; + DWORD dwToCopy; + + // Is the file sector already loaded ? + if(hf->dwSectorOffs != dwFileSectorPos) + { + // Load one MPQ sector into archive buffer + nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesInSector); + if(nError != ERROR_SUCCESS) + return nError; + + // Remember that the data loaded to the sector have new file offset + hf->dwSectorOffs = dwFileSectorPos; + } + else + { + if((dwFileSectorPos + dwBytesInSector) > hf->dwDataSize) + dwBytesInSector = hf->dwDataSize - dwFileSectorPos; + } + + // Copy the data from the offset in the loaded sector to the end of the sector + dwToCopy = dwBytesInSector - dwBufferOffs; + if(dwToCopy > dwBytesToRead) + dwToCopy = dwBytesToRead; + + // Copy data from sector buffer into target buffer + memcpy(pbBuffer, hf->pbFileSector + dwBufferOffs, dwToCopy); + + // Update pointers and byte counts + dwTotalBytesRead += dwToCopy; + dwFileSectorPos += dwBytesInSector; + pbBuffer += dwToCopy; + dwBytesToRead -= dwToCopy; + } + + // Load the whole ("middle") sectors only if there is at least one full sector to be read + if(dwBytesToRead >= ha->dwSectorSize) + { + DWORD dwBlockBytes = dwBytesToRead & ~dwSectorSizeMask; + + // Load all sectors to the output buffer + nError = ReadMpqSectors(hf, pbBuffer, dwFileSectorPos, dwBlockBytes, &dwBytesRead); + if(nError != ERROR_SUCCESS) + return nError; + + // Update pointers + dwTotalBytesRead += dwBytesRead; + dwFileSectorPos += dwBytesRead; + pbBuffer += dwBytesRead; + dwBytesToRead -= dwBytesRead; + } + + // Read the terminating sector + if(dwBytesToRead > 0) + { + DWORD dwToCopy = ha->dwSectorSize; + + // Is the file sector already loaded ? + if(hf->dwSectorOffs != dwFileSectorPos) + { + // Load one MPQ sector into archive buffer + nError = ReadMpqSectors(hf, hf->pbFileSector, dwFileSectorPos, ha->dwSectorSize, &dwBytesRead); + if(nError != ERROR_SUCCESS) + return nError; + + // Remember that the data loaded to the sector have new file offset + hf->dwSectorOffs = dwFileSectorPos; + } + + // Check number of bytes read + if(dwToCopy > dwBytesToRead) + dwToCopy = dwBytesToRead; + + // Copy the data from the cached last sector to the caller's buffer + memcpy(pbBuffer, hf->pbFileSector, dwToCopy); + + // Update pointers + dwTotalBytesRead += dwToCopy; + } + + // Store total number of bytes read to the caller + *pdwBytesRead = dwTotalBytesRead; + return ERROR_SUCCESS; +} + +static int ReadMpqFilePatchFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + TMPQPatcher Patcher; + DWORD dwBytesToRead = dwToRead; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + // Make sure that the patch file is loaded completely + if(nError == ERROR_SUCCESS && hf->pbFileData == NULL) + { + // Initialize patching process and allocate data + nError = Patch_InitPatcher(&Patcher, hf); + if(nError != ERROR_SUCCESS) + return nError; + + // Set the current data size + Patcher.cbFileData = hf->pFileEntry->dwFileSize; + + // Initialize the patcher object with initial file data + if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + nError = ReadMpqFileSingleUnit(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead); + else + nError = ReadMpqFileSectorFile(hf, Patcher.pbFileData1, 0, Patcher.cbFileData, &dwBytesRead); + + // Perform the patching process + if(nError == ERROR_SUCCESS) + nError = Patch_Process(&Patcher, hf); + + // Finalize the patcher structure + Patch_Finalize(&Patcher); + dwBytesRead = 0; + } + + // If there is something to read, do it + if(nError == ERROR_SUCCESS) + { + if(dwFilePos < hf->cbFileData) + { + // Make sure we don't copy more than file size + if((dwFilePos + dwToRead) > hf->cbFileData) + dwToRead = hf->cbFileData - dwFilePos; + + // Copy the appropriate amount of the file data to the caller's buffer + memcpy(pvBuffer, hf->pbFileData + dwFilePos, dwToRead); + dwBytesRead = dwToRead; + } + + // Set the proper error code + nError = (dwBytesRead == dwBytesToRead) ? ERROR_SUCCESS : ERROR_HANDLE_EOF; + } + + // Give the result to the caller + if(pdwBytesRead != NULL) + *pdwBytesRead = dwBytesRead; + return nError; +} + +static int ReadMpqFileLocalFile(TMPQFile * hf, void * pvBuffer, DWORD dwFilePos, DWORD dwToRead, LPDWORD pdwBytesRead) +{ + ULONGLONG FilePosition1 = dwFilePos; + ULONGLONG FilePosition2; + DWORD dwBytesRead = 0; + int nError = ERROR_SUCCESS; + + assert(hf->pStream != NULL); + + // Because stream I/O functions are designed to read + // "all or nothing", we compare file position before and after, + // and if they differ, we assume that number of bytes read + // is the difference between them + + if(!FileStream_Read(hf->pStream, &FilePosition1, pvBuffer, dwToRead)) + { + // If not all bytes have been read, then return the number of bytes read + if((nError = GetLastError()) == ERROR_HANDLE_EOF) + { + FileStream_GetPos(hf->pStream, &FilePosition2); + dwBytesRead = (DWORD)(FilePosition2 - FilePosition1); + } + } + else + { + dwBytesRead = dwToRead; + } + + *pdwBytesRead = dwBytesRead; + return nError; +} + +//----------------------------------------------------------------------------- +// SFileReadFile + +bool WINAPI SFileReadFile(HANDLE hFile, void * pvBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped) +{ + TMPQFile * hf = (TMPQFile *)hFile; + DWORD dwBytesRead = 0; // Number of bytes read + int nError = ERROR_SUCCESS; + + // Always zero the result + if(pdwRead != NULL) + *pdwRead = 0; + + // Check valid parameters + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return false; + } + + if(pvBuffer == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // If we didn't load the patch info yet, do it now + if(hf->pFileEntry != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) && hf->pPatchInfo == NULL) + { + nError = AllocatePatchInfo(hf, true); + if(nError != ERROR_SUCCESS || hf->pPatchInfo == NULL) + { + SetLastError(nError); + return false; + } + } + + // Clear the last used compression + hf->dwCompression0 = 0; + + // If the file is local file, read the data directly from the stream + if(hf->pStream != NULL) + { + nError = ReadMpqFileLocalFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // If the file is a patch file, we have to read it special way + else if(hf->hfPatch != NULL && (hf->pFileEntry->dwFlags & MPQ_FILE_PATCH_FILE) == 0) + { + nError = ReadMpqFilePatchFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // If the archive is a MPK archive, we need special way to read the file + else if(hf->ha->dwSubType == MPQ_SUBTYPE_MPK) + { + nError = ReadMpkFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // If the file is single unit file, redirect it to read file + else if(hf->pFileEntry->dwFlags & MPQ_FILE_SINGLE_UNIT) + { + nError = ReadMpqFileSingleUnit(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // Otherwise read it as sector based MPQ file + else + { + nError = ReadMpqFileSectorFile(hf, pvBuffer, hf->dwFilePos, dwToRead, &dwBytesRead); + } + + // Increment the file position + hf->dwFilePos += dwBytesRead; + + // Give the caller the number of bytes read + if(pdwRead != NULL) + *pdwRead = dwBytesRead; + + // If the read operation succeeded, but not full number of bytes was read, + // set the last error to ERROR_HANDLE_EOF + if(nError == ERROR_SUCCESS && (dwBytesRead < dwToRead)) + nError = ERROR_HANDLE_EOF; + + // If something failed, set the last error value + if(nError != ERROR_SUCCESS) + SetLastError(nError); + return (nError == ERROR_SUCCESS); +} + +//----------------------------------------------------------------------------- +// SFileGetFileSize + +DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh) +{ + ULONGLONG FileSize; + TMPQFile * hf = (TMPQFile *)hFile; + + // Validate the file handle before we go on + if(IsValidFileHandle(hFile)) + { + // Make sure that the variable is initialized + FileSize = 0; + + // If the file is patched file, we have to get the size of the last version + if(hf->hfPatch != NULL) + { + // Walk through the entire patch chain, take the last version + while(hf != NULL) + { + // Get the size of the currently pointed version + FileSize = hf->pFileEntry->dwFileSize; + + // Move to the next patch file in the hierarchy + hf = hf->hfPatch; + } + } + else + { + // Is it a local file ? + if(hf->pStream != NULL) + { + FileStream_GetSize(hf->pStream, &FileSize); + } + else + { + FileSize = hf->dwDataSize; + } + } + + // If opened from archive, return file size + if(pdwFileSizeHigh != NULL) + *pdwFileSizeHigh = (DWORD)(FileSize >> 32); + return (DWORD)FileSize; + } + + SetLastError(ERROR_INVALID_HANDLE); + return SFILE_INVALID_SIZE; +} + +DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod) +{ + TMPQFile * hf = (TMPQFile *)hFile; + ULONGLONG OldPosition; + ULONGLONG NewPosition; + ULONGLONG FileSize; + ULONGLONG DeltaPos; + + // If the hFile is not a valid file handle, return an error. + if(!IsValidFileHandle(hFile)) + { + SetLastError(ERROR_INVALID_HANDLE); + return SFILE_INVALID_POS; + } + + // Retrieve the file size for handling the limits + if(hf->pStream != NULL) + { + FileStream_GetSize(hf->pStream, &FileSize); + } + else + { + FileSize = SFileGetFileSize(hFile, NULL); + } + + // Handle the NULL and non-NULL values of plFilePosHigh + // Non-NULL: The DeltaPos is combined from lFilePos and *lpFilePosHigh + // NULL: The DeltaPos is sign-extended value of lFilePos + DeltaPos = (plFilePosHigh != NULL) ? MAKE_OFFSET64(plFilePosHigh[0], lFilePos) : (ULONGLONG)(LONGLONG)lFilePos; + + // Get the relative point where to move from + switch(dwMoveMethod) + { + case FILE_BEGIN: + + // Move relative to the file begin. + OldPosition = 0; + break; + + case FILE_CURRENT: + + // Retrieve the current file position + if(hf->pStream != NULL) + { + FileStream_GetPos(hf->pStream, &OldPosition); + } + else + { + OldPosition = hf->dwFilePos; + } + break; + + case FILE_END: + + // Move relative to the end of the file + OldPosition = FileSize; + break; + + default: + SetLastError(ERROR_INVALID_PARAMETER); + return SFILE_INVALID_POS; + } + + // Calculate the new position + NewPosition = OldPosition + DeltaPos; + + // If moving backward, don't allow the new position go negative + if((LONGLONG)DeltaPos < 0) + { + if(NewPosition > FileSize) // Position is negative + { + SetLastError(ERROR_NEGATIVE_SEEK); + return SFILE_INVALID_POS; + } + } + + // If moving forward, don't allow the new position go past the end of the file + else + { + if(NewPosition > FileSize) + NewPosition = FileSize; + } + + // Now apply the file pointer to the file + if(hf->pStream != NULL) + { + if(!FileStream_Read(hf->pStream, &NewPosition, NULL, 0)) + return SFILE_INVALID_POS; + } + else + { + hf->dwFilePos = (DWORD)NewPosition; + } + + // Return the new file position + if(plFilePosHigh != NULL) + *plFilePosHigh = (LONG)(NewPosition >> 32); + return (DWORD)NewPosition; +} diff --git a/dep/StormLib/src/SFileVerify.cpp b/dep/StormLib/src/SFileVerify.cpp new file mode 100644 index 000000000..0248b9136 --- /dev/null +++ b/dep/StormLib/src/SFileVerify.cpp @@ -0,0 +1,1054 @@ +/*****************************************************************************/ +/* SFileVerify.cpp Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* MPQ files and MPQ archives verification. */ +/* */ +/* The MPQ signature verification has been written by Jean-Francois Roy */ +/* and Justin Olbrantz (Quantam). */ +/* The MPQ public keys have been created by MPQKit, using OpenSSL library. */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 04.05.10 1.00 Lad The first version of SFileVerify.cpp */ +/*****************************************************************************/ + +#define __STORMLIB_SELF__ +#include "StormLib.h" +#include "StormCommon.h" + +//----------------------------------------------------------------------------- +// Local defines + +#define MPQ_DIGEST_UNIT_SIZE 0x10000 + +//----------------------------------------------------------------------------- +// Known Blizzard public keys +// Created by Jean-Francois Roy using OpenSSL + +static const char * szBlizzardWeakPrivateKey = + "-----BEGIN PRIVATE KEY-----" + "MIIBOQIBAAJBAJJidwS/uILMBSO5DLGsBFknIXWWjQJe2kfdfEk3G/j66w4KkhZ1" + "V61Rt4zLaMVCYpDun7FLwRjkMDSepO1q2DcCAwEAAQJANtiztVDMJh2hE1hjPDKy" + "UmEJ9U/aN3gomuKOjbQbQ/bWWcM/WfhSVHmPqtqh/bQI2UXFr0rnXngeteZHLr/b" + "8QIhAMuWriSKGMACw18/rVVfUrThs915odKBH1Alr3vMVVzZAiEAuBHPSQkgwcb6" + "L4MWaiKuOzq08mSyNqPeN8oSy18q848CIHeMn+3s+eOmu7su1UYQl6yH7OrdBd1q" + "3UxfFNEJiAbhAiAqxdCyOxHGlbM7aS3DOg3cq5ayoN2cvtV7h1R4t8OmVwIgF+5z" + "/6vkzBUsZhd8Nwyis+MeQYH0rpFpMKdTlqmPF2Q=" + "-----END PRIVATE KEY-----"; + +static const char * szBlizzardWeakPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJJidwS/uILMBSO5DLGsBFknIXWWjQJe" + "2kfdfEk3G/j66w4KkhZ1V61Rt4zLaMVCYpDun7FLwRjkMDSepO1q2DcCAwEAAQ==" + "-----END PUBLIC KEY-----"; + +static const char * szBlizzardStrongPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsQZ+ziT2h8h+J/iMQpgd" + "tH1HaJzOBE3agjU4yMPcrixaPOZoA4t8bwfey7qczfWywocYo3pleytFF+IuD4HD" + "Fl9OXN1SFyupSgMx1EGZlgbFAomnbq9MQJyMqQtMhRAjFgg4TndS7YNb+JMSAEKp" + "kXNqY28n/EVBHD5TsMuVCL579gIenbr61dI92DDEdy790IzIG0VKWLh/KOTcTJfm" + "Ds/7HQTkGouVW+WUsfekuqNQo7ND9DBnhLjLjptxeFE2AZqYcA1ao3S9LN3GL1tW" + "lVXFIX9c7fWqaVTQlZ2oNsI/ARVApOK3grNgqvwH6YoVYVXjNJEo5sQJsPsdV/hk" + "dwIDAQAB" + "-----END PUBLIC KEY-----"; + +static const char * szWarcraft3MapPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1BwklUUQ3UvjizOBRoF5" + "yyOVc7KD+oGOQH5i6eUk1yfs0luCC70kNucNrfqhmviywVtahRse1JtXCPrx2bd3" + "iN8Dx91fbkxjYIOGTsjYoHKTp0BbaFkJih776fcHgnFSb+7mJcDuJVvJOXxEH6w0" + "1vo6VtujCqj1arqbyoal+xtAaczF3us5cOEp45sR1zAWTn1+7omN7VWV4QqJPaDS" + "gBSESc0l1grO0i1VUSumayk7yBKIkb+LBvcG6WnYZHCi7VdLmaxER5m8oZfER66b" + "heHoiSQIZf9PAY6Guw2DT5BTc54j/AaLQAKf2qcRSgQLVo5kQaddF3rCpsXoB/74" + "6QIDAQAB" + "-----END PUBLIC KEY-----"; + +static const char * szWowPatchPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwOsMV0LagAWPEtEQM6b9" + "6FHFkUyGbbyda2/Dfc9dyl21E9QvX+Yw7qKRMAKPzA2TlQQLZKvXpnKXF/YIK5xa" + "5uwg9CEHCEAYolLG4xn0FUOE0E/0PuuytI0p0ICe6rk00PifZzTr8na2wI/l/GnQ" + "bvnIVF1ck6cslATpQJ5JJVMXzoFlUABS19WESw4MXuJAS3AbMhxNWdEhVv7eO51c" + "yGjRLy9QjogZODZTY0fSEksgBqQxNCoYVJYI/sF5K2flDsGqrIp0OdJ6teJlzg1Y" + "UjYnb6bKjlidXoHEXI2TgA/mD6O3XFIt08I9s3crOCTgICq7cgX35qrZiIVWZdRv" + "TwIDAQAB" + "-----END PUBLIC KEY-----"; + +static const char * szWowSurveyPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnIt1DR6nRyyKsy2qahHe" + "MKLtacatn/KxieHcwH87wLBxKy+jZ0gycTmJ7SaTdBAEMDs/V5IPIXEtoqYnid2c" + "63TmfGDU92oc3Ph1PWUZ2PWxBhT06HYxRdbrgHw9/I29pNPi/607x+lzPORITOgU" + "BR6MR8au8HsQP4bn4vkJNgnSgojh48/XQOB/cAln7As1neP61NmVimoLR4Bwi3zt" + "zfgrZaUpyeNCUrOYJmH09YIjbBySTtXOUidoPHjFrMsCWpr6xs8xbETbs7MJFL6a" + "vcUfTT67qfIZ9RsuKfnXJTIrV0kwDSjjuNXiPTmWAehSsiHIsrUXX5RNcwsSjClr" + "nQIDAQAB" + "-----END PUBLIC KEY-----"; + +static const char * szStarcraft2MapPublicKey = + "-----BEGIN PUBLIC KEY-----" + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmk4GT8zb+ICC25a17KZB" + "q/ygKGJ2VSO6IT5PGHJlm1KfnHBA4B6SH3xMlJ4c6eG2k7QevZv+FOhjsAHubyWq" + "2VKqWbrIFKv2ILc2RfMn8J9EDVRxvcxh6slRrVL69D0w1tfVGjMiKq2Fym5yGoRT" + "E7CRgDqbAbXP9LBsCNWHiJLwfxMGzHbk8pIl9oia5pvM7ofZamSHchxlpy6xa4GJ" + "7xKN01YCNvklTL1D7uol3wkwcHc7vrF8QwuJizuA5bSg4poEGtH62BZOYi+UL/z0" + "31YK+k9CbQyM0X0pJoJoYz1TK+Y5J7vBnXCZtfcTYQ/ZzN6UcxTa57dJaiOlCh9z" + "nQIDAQAB" + "-----END PUBLIC KEY-----"; + +//----------------------------------------------------------------------------- +// Local functions + +static void memrev(unsigned char *buf, size_t count) +{ + unsigned char *r; + + for (r = buf + count - 1; buf < r; buf++, r--) + { + *buf ^= *r; + *r ^= *buf; + *buf ^= *r; + } +} + +static bool decode_base64_key(const char * szKeyBase64, rsa_key * key) +{ + unsigned char decoded_key[0x200]; + const char * szBase64Begin; + const char * szBase64End; + unsigned long decoded_length = sizeof(decoded_key); + unsigned long length; + + // Find out the begin of the BASE64 data + szBase64Begin = szKeyBase64 + strlen("-----BEGIN PUBLIC KEY-----"); + szBase64End = szBase64Begin + strlen(szBase64Begin) - strlen("-----END PUBLIC KEY-----"); + if(szBase64End[0] != '-') + return false; + + // decode the base64 string + length = (unsigned long)(szBase64End - szBase64Begin); + if(base64_decode(szBase64Begin, length, decoded_key, &decoded_length) != CRYPT_OK) + return false; + + // Create RSA key + if(rsa_import(decoded_key, decoded_length, key) != CRYPT_OK) + return false; + + return true; +} + +static void GetPlainAnsiFileName( + const TCHAR * szFileName, + char * szPlainName) +{ + const TCHAR * szPlainNameT = GetPlainFileName(szFileName); + + // Convert the plain name to ANSI + while(*szPlainNameT != 0) + *szPlainName++ = (char)*szPlainNameT++; + *szPlainName = 0; +} + +// Calculate begin and end of the MPQ archive +static void CalculateArchiveRange( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI) +{ + ULONGLONG TempPos = 0; + char szMapHeader[0x200]; + + // Get the MPQ begin + pSI->BeginMpqData = ha->MpqPos; + + // Warcraft III maps are signed from the map header to the end + if(FileStream_Read(ha->pStream, &TempPos, szMapHeader, sizeof(szMapHeader))) + { + // Is it a map header ? + if(szMapHeader[0] == 'H' && szMapHeader[1] == 'M' && szMapHeader[2] == '3' && szMapHeader[3] == 'W') + { + // We will have to hash since the map header + pSI->BeginMpqData = 0; + } + } + + // Get the MPQ data end. This is stored in the MPQ header + pSI->EndMpqData = ha->MpqPos + ha->pHeader->ArchiveSize64; + + // Get the size of the entire file + FileStream_GetSize(ha->pStream, &pSI->EndOfFile); +} + +static bool CalculateMpqHashMd5( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI, + LPBYTE pMd5Digest) +{ + hash_state md5_state; + ULONGLONG BeginBuffer; + ULONGLONG EndBuffer; + LPBYTE pbDigestBuffer = NULL; + + // Allocate buffer for creating the MPQ digest. + pbDigestBuffer = STORM_ALLOC(BYTE, MPQ_DIGEST_UNIT_SIZE); + if(pbDigestBuffer == NULL) + return false; + + // Initialize the MD5 hash state + md5_init(&md5_state); + + // Set the byte offset of begin of the data + BeginBuffer = pSI->BeginMpqData; + + // Create the digest + for(;;) + { + ULONGLONG BytesRemaining; + LPBYTE pbSigBegin = NULL; + LPBYTE pbSigEnd = NULL; + DWORD dwToRead = MPQ_DIGEST_UNIT_SIZE; + + // Check the number of bytes remaining + BytesRemaining = pSI->EndMpqData - BeginBuffer; + if(BytesRemaining < MPQ_DIGEST_UNIT_SIZE) + dwToRead = (DWORD)BytesRemaining; + if(dwToRead == 0) + break; + + // Read the next chunk + if(!FileStream_Read(ha->pStream, &BeginBuffer, pbDigestBuffer, dwToRead)) + { + STORM_FREE(pbDigestBuffer); + return false; + } + + // Move the current byte offset + EndBuffer = BeginBuffer + dwToRead; + + // Check if the signature is within the loaded digest + if(BeginBuffer <= pSI->BeginExclude && pSI->BeginExclude < EndBuffer) + pbSigBegin = pbDigestBuffer + (size_t)(pSI->BeginExclude - BeginBuffer); + if(BeginBuffer <= pSI->EndExclude && pSI->EndExclude < EndBuffer) + pbSigEnd = pbDigestBuffer + (size_t)(pSI->EndExclude - BeginBuffer); + + // Zero the part that belongs to the signature + if(pbSigBegin != NULL || pbSigEnd != NULL) + { + if(pbSigBegin == NULL) + pbSigBegin = pbDigestBuffer; + if(pbSigEnd == NULL) + pbSigEnd = pbDigestBuffer + dwToRead; + + memset(pbSigBegin, 0, (pbSigEnd - pbSigBegin)); + } + + // Pass the buffer to the hashing function + md5_process(&md5_state, pbDigestBuffer, dwToRead); + + // Move pointers + BeginBuffer += dwToRead; + } + + // Finalize the MD5 hash + md5_done(&md5_state, pMd5Digest); + STORM_FREE(pbDigestBuffer); + return true; +} + +static void AddTailToSha1( + hash_state * psha1_state, + const char * szTail) +{ + unsigned char * pbTail = (unsigned char *)szTail; + unsigned char szUpperCase[0x200]; + unsigned long nLength = 0; + + // Convert the tail to uppercase + // Note that we don't need to terminate the string with zero + while(*pbTail != 0) + { + szUpperCase[nLength++] = AsciiToUpperTable[*pbTail++]; + } + + // Append the tail to the SHA1 + sha1_process(psha1_state, szUpperCase, nLength); +} + +static bool CalculateMpqHashSha1( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI, + unsigned char * sha1_tail0, + unsigned char * sha1_tail1, + unsigned char * sha1_tail2) +{ + ULONGLONG BeginBuffer; + hash_state sha1_state_temp; + hash_state sha1_state; + LPBYTE pbDigestBuffer = NULL; + char szPlainName[MAX_PATH]; + + // Allocate buffer for creating the MPQ digest. + pbDigestBuffer = STORM_ALLOC(BYTE, MPQ_DIGEST_UNIT_SIZE); + if(pbDigestBuffer == NULL) + return false; + + // Initialize SHA1 state structure + sha1_init(&sha1_state); + + // Calculate begin of data to be hashed + BeginBuffer = pSI->BeginMpqData; + + // Create the digest + for(;;) + { + ULONGLONG BytesRemaining; + DWORD dwToRead = MPQ_DIGEST_UNIT_SIZE; + + // Check the number of bytes remaining + BytesRemaining = pSI->EndMpqData - BeginBuffer; + if(BytesRemaining < MPQ_DIGEST_UNIT_SIZE) + dwToRead = (DWORD)BytesRemaining; + if(dwToRead == 0) + break; + + // Read the next chunk + if(!FileStream_Read(ha->pStream, &BeginBuffer, pbDigestBuffer, dwToRead)) + { + STORM_FREE(pbDigestBuffer); + return false; + } + + // Pass the buffer to the hashing function + sha1_process(&sha1_state, pbDigestBuffer, dwToRead); + + // Move pointers + BeginBuffer += dwToRead; + } + + // Add all three known tails and generate three hashes + memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state)); + sha1_done(&sha1_state_temp, sha1_tail0); + + memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state)); + GetPlainAnsiFileName(FileStream_GetFileName(ha->pStream), szPlainName); + AddTailToSha1(&sha1_state_temp, szPlainName); + sha1_done(&sha1_state_temp, sha1_tail1); + + memcpy(&sha1_state_temp, &sha1_state, sizeof(hash_state)); + AddTailToSha1(&sha1_state_temp, "ARCHIVE"); + sha1_done(&sha1_state_temp, sha1_tail2); + + // Finalize the MD5 hash + STORM_FREE(pbDigestBuffer); + return true; +} + +static int VerifyRawMpqData( + TMPQArchive * ha, + ULONGLONG ByteOffset, + DWORD dwDataSize) +{ + ULONGLONG DataOffset = ha->MpqPos + ByteOffset; + LPBYTE pbDataChunk; + LPBYTE pbMD5Array1; // Calculated MD5 array + LPBYTE pbMD5Array2; // MD5 array loaded from the MPQ + DWORD dwBytesInChunk; + DWORD dwChunkCount; + DWORD dwChunkSize = ha->pHeader->dwRawChunkSize; + DWORD dwMD5Size; + int nError = ERROR_SUCCESS; + + // Don't verify zero-sized blocks + if(dwDataSize == 0) + return ERROR_SUCCESS; + + // Get the number of data chunks to calculate MD5 + assert(dwChunkSize != 0); + dwChunkCount = ((dwDataSize - 1) / dwChunkSize) + 1; + dwMD5Size = dwChunkCount * MD5_DIGEST_SIZE; + + // Allocate space for data chunk and for the MD5 array + pbDataChunk = STORM_ALLOC(BYTE, dwChunkSize); + if(pbDataChunk == NULL) + return ERROR_NOT_ENOUGH_MEMORY; + + // Allocate space for MD5 array + pbMD5Array1 = STORM_ALLOC(BYTE, dwMD5Size); + pbMD5Array2 = STORM_ALLOC(BYTE, dwMD5Size); + if(pbMD5Array1 == NULL || pbMD5Array2 == NULL) + nError = ERROR_NOT_ENOUGH_MEMORY; + + // Calculate MD5 of each data chunk + if(nError == ERROR_SUCCESS) + { + LPBYTE pbMD5 = pbMD5Array1; + + for(DWORD i = 0; i < dwChunkCount; i++) + { + // Get the number of bytes in the chunk + dwBytesInChunk = STORMLIB_MIN(dwChunkSize, dwDataSize); + + // Read the data chunk + if(!FileStream_Read(ha->pStream, &DataOffset, pbDataChunk, dwBytesInChunk)) + { + nError = ERROR_FILE_CORRUPT; + break; + } + + // Calculate MD5 + CalculateDataBlockHash(pbDataChunk, dwBytesInChunk, pbMD5); + + // Move pointers and offsets + DataOffset += dwBytesInChunk; + dwDataSize -= dwBytesInChunk; + pbMD5 += MD5_DIGEST_SIZE; + } + } + + // Read the MD5 array + if(nError == ERROR_SUCCESS) + { + // Read the array of MD5 + if(!FileStream_Read(ha->pStream, &DataOffset, pbMD5Array2, dwMD5Size)) + nError = GetLastError(); + } + + // Compare the array of MD5 + if(nError == ERROR_SUCCESS) + { + // Compare the MD5 + if(memcmp(pbMD5Array1, pbMD5Array2, dwMD5Size)) + nError = ERROR_FILE_CORRUPT; + } + + // Free memory and return result + if(pbMD5Array2 != NULL) + STORM_FREE(pbMD5Array2); + if(pbMD5Array1 != NULL) + STORM_FREE(pbMD5Array1); + if(pbDataChunk != NULL) + STORM_FREE(pbDataChunk); + return nError; +} + +static DWORD VerifyWeakSignature( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI) +{ + BYTE RevSignature[MPQ_WEAK_SIGNATURE_SIZE]; + BYTE Md5Digest[MD5_DIGEST_SIZE]; + rsa_key key; + int hash_idx = find_hash("md5"); + int result = 0; + + // The signature might be zeroed out. In that case, we ignore it + if(!IsValidSignature(pSI->Signature)) + return ERROR_WEAK_SIGNATURE_OK; + + // Calculate hash of the entire archive, skipping the (signature) file + if(!CalculateMpqHashMd5(ha, pSI, Md5Digest)) + return ERROR_VERIFY_FAILED; + + // Import the Blizzard key in OpenSSL format + if(!decode_base64_key(szBlizzardWeakPublicKey, &key)) + return ERROR_VERIFY_FAILED; + + // Verify the signature + memcpy(RevSignature, &pSI->Signature[8], MPQ_WEAK_SIGNATURE_SIZE); + memrev(RevSignature, MPQ_WEAK_SIGNATURE_SIZE); + rsa_verify_hash_ex(RevSignature, MPQ_WEAK_SIGNATURE_SIZE, Md5Digest, sizeof(Md5Digest), LTC_PKCS_1_V1_5, hash_idx, 0, &result, &key); + rsa_free(&key); + + // Return the result + return result ? ERROR_WEAK_SIGNATURE_OK : ERROR_WEAK_SIGNATURE_ERROR; +} + +static DWORD VerifyStrongSignatureWithKey( + unsigned char * reversed_signature, + unsigned char * padded_digest, + const char * szPublicKey) +{ + rsa_key key; + int result = 0; + + // Import the Blizzard key in OpenSSL format + if(!decode_base64_key(szPublicKey, &key)) + { + assert(false); + return ERROR_VERIFY_FAILED; + } + + // Verify the signature + if(rsa_verify_simple(reversed_signature, MPQ_STRONG_SIGNATURE_SIZE, padded_digest, MPQ_STRONG_SIGNATURE_SIZE, &result, &key) != CRYPT_OK) + return ERROR_VERIFY_FAILED; + + // Free the key and return result + rsa_free(&key); + return result ? ERROR_STRONG_SIGNATURE_OK : ERROR_STRONG_SIGNATURE_ERROR; +} + +static DWORD VerifyStrongSignature( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI) +{ + unsigned char reversed_signature[MPQ_STRONG_SIGNATURE_SIZE]; + unsigned char Sha1Digest_tail0[SHA1_DIGEST_SIZE]; + unsigned char Sha1Digest_tail1[SHA1_DIGEST_SIZE]; + unsigned char Sha1Digest_tail2[SHA1_DIGEST_SIZE]; + unsigned char padded_digest[MPQ_STRONG_SIGNATURE_SIZE]; + DWORD dwResult; + size_t digest_offset; + + // Calculate SHA1 hash of the archive + if(!CalculateMpqHashSha1(ha, pSI, Sha1Digest_tail0, Sha1Digest_tail1, Sha1Digest_tail2)) + return ERROR_VERIFY_FAILED; + + // Prepare the signature for decryption + memcpy(reversed_signature, &pSI->Signature[4], MPQ_STRONG_SIGNATURE_SIZE); + memrev(reversed_signature, MPQ_STRONG_SIGNATURE_SIZE); + + // Prepare the padded digest for comparison + digest_offset = sizeof(padded_digest) - SHA1_DIGEST_SIZE; + memset(padded_digest, 0xbb, digest_offset); + padded_digest[0] = 0x0b; + + // Try Blizzard Strong public key with no SHA1 tail + memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE); + memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE); + dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szBlizzardStrongPublicKey); + if(dwResult == ERROR_STRONG_SIGNATURE_OK) + return dwResult; + + // Try War 3 map public key with plain file name as SHA1 tail + memcpy(padded_digest + digest_offset, Sha1Digest_tail1, SHA1_DIGEST_SIZE); + memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE); + dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWarcraft3MapPublicKey); + if(dwResult == ERROR_STRONG_SIGNATURE_OK) + return dwResult; + + // Try WoW-TBC public key with "ARCHIVE" as SHA1 tail + memcpy(padded_digest + digest_offset, Sha1Digest_tail2, SHA1_DIGEST_SIZE); + memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE); + dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWowPatchPublicKey); + if(dwResult == ERROR_STRONG_SIGNATURE_OK) + return dwResult; + + // Try Survey public key with no SHA1 tail + memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE); + memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE); + dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szWowSurveyPublicKey); + if(dwResult == ERROR_STRONG_SIGNATURE_OK) + return dwResult; + + // Try Starcraft II public key with no SHA1 tail + memcpy(padded_digest + digest_offset, Sha1Digest_tail0, SHA1_DIGEST_SIZE); + memrev(padded_digest + digest_offset, SHA1_DIGEST_SIZE); + dwResult = VerifyStrongSignatureWithKey(reversed_signature, padded_digest, szStarcraft2MapPublicKey); + if(dwResult == ERROR_STRONG_SIGNATURE_OK) + return dwResult; + + return ERROR_STRONG_SIGNATURE_ERROR; +} + +static DWORD VerifyFile( + HANDLE hMpq, + const char * szFileName, + LPDWORD pdwCrc32, + char * pMD5, + DWORD dwFlags) +{ + hash_state md5_state; + unsigned char * pFileMd5; + unsigned char md5[MD5_DIGEST_SIZE]; + TFileEntry * pFileEntry; + TMPQFile * hf; + BYTE Buffer[0x1000]; + HANDLE hFile = NULL; + DWORD dwVerifyResult = 0; + DWORD dwTotalBytes = 0; + DWORD dwCrc32 = 0; + + // + // Note: When the MPQ is patched, it will + // automatically check the patched version of the file + // + + // Make sure the md5 is initialized + memset(md5, 0, sizeof(md5)); + + // If we have to verify raw data MD5, do it before file open + if(dwFlags & SFILE_VERIFY_RAW_MD5) + { + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Parse the base MPQ and all patches + while(ha != NULL) + { + // Does the archive have support for raw MD5? + if(ha->pHeader->dwRawChunkSize != 0) + { + // The file has raw MD5 if the archive supports it + dwVerifyResult |= VERIFY_FILE_HAS_RAW_MD5; + + // Find file entry for the file + pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale); + if(pFileEntry != NULL) + { + // If the file's raw MD5 doesn't match, don't bother with more checks + if(VerifyRawMpqData(ha, pFileEntry->ByteOffset, pFileEntry->dwCmpSize) != ERROR_SUCCESS) + return dwVerifyResult | VERIFY_FILE_RAW_MD5_ERROR; + } + } + + // Move to the next patch + ha = ha->haPatch; + } + } + + // Attempt to open the file + if(SFileOpenFileEx(hMpq, szFileName, SFILE_OPEN_FROM_MPQ, &hFile)) + { + // Get the file size + hf = (TMPQFile *)hFile; + pFileEntry = hf->pFileEntry; + dwTotalBytes = SFileGetFileSize(hFile, NULL); + + // Initialize the CRC32 and MD5 contexts + md5_init(&md5_state); + dwCrc32 = crc32(0, Z_NULL, 0); + + // Also turn on sector checksum verification + if(dwFlags & SFILE_VERIFY_SECTOR_CRC) + hf->bCheckSectorCRCs = true; + + // Go through entire file and update both CRC32 and MD5 + for(;;) + { + DWORD dwBytesRead = 0; + + // Read data from file + SFileReadFile(hFile, Buffer, sizeof(Buffer), &dwBytesRead, NULL); + if(dwBytesRead == 0) + { + if(GetLastError() == ERROR_CHECKSUM_ERROR) + dwVerifyResult |= VERIFY_FILE_SECTOR_CRC_ERROR; + break; + } + + // Update CRC32 value + if(dwFlags & SFILE_VERIFY_FILE_CRC) + dwCrc32 = crc32(dwCrc32, Buffer, dwBytesRead); + + // Update MD5 value + if(dwFlags & SFILE_VERIFY_FILE_MD5) + md5_process(&md5_state, Buffer, dwBytesRead); + + // Decrement the total size + dwTotalBytes -= dwBytesRead; + } + + // If the file has sector checksums, indicate it in the flags + if(dwFlags & SFILE_VERIFY_SECTOR_CRC) + { + if((hf->pFileEntry->dwFlags & MPQ_FILE_SECTOR_CRC) && hf->SectorChksums != NULL && hf->SectorChksums[0] != 0) + dwVerifyResult |= VERIFY_FILE_HAS_SECTOR_CRC; + } + + // Check if the entire file has been read + // No point in checking CRC32 and MD5 if not + // Skip checksum checks if the file has patches + if(dwTotalBytes == 0) + { + // Check CRC32 and MD5 only if there is no patches + if(hf->hfPatch == NULL) + { + // Check if the CRC32 matches. + if(dwFlags & SFILE_VERIFY_FILE_CRC) + { + // Only check the CRC32 if it is valid + if(pFileEntry->dwCrc32 != 0) + { + dwVerifyResult |= VERIFY_FILE_HAS_CHECKSUM; + if(dwCrc32 != pFileEntry->dwCrc32) + dwVerifyResult |= VERIFY_FILE_CHECKSUM_ERROR; + } + } + + // Check if MD5 matches + if(dwFlags & SFILE_VERIFY_FILE_MD5) + { + // Patch files have their MD5 saved in the patch info + pFileMd5 = (hf->pPatchInfo != NULL) ? hf->pPatchInfo->md5 : pFileEntry->md5; + md5_done(&md5_state, md5); + + // Only check the MD5 if it is valid + if(IsValidMD5(pFileMd5)) + { + dwVerifyResult |= VERIFY_FILE_HAS_MD5; + if(memcmp(md5, pFileMd5, MD5_DIGEST_SIZE)) + dwVerifyResult |= VERIFY_FILE_MD5_ERROR; + } + } + } + else + { + // Patched files are MD5-checked automatically + dwVerifyResult |= VERIFY_FILE_HAS_MD5; + } + } + else + { + dwVerifyResult |= VERIFY_READ_ERROR; + } + + SFileCloseFile(hFile); + } + else + { + // Remember that the file couldn't be open + dwVerifyResult |= VERIFY_OPEN_ERROR; + } + + // If the caller required CRC32 and/or MD5, give it to him + if(pdwCrc32 != NULL) + *pdwCrc32 = dwCrc32; + if(pMD5 != NULL) + memcpy(pMD5, md5, MD5_DIGEST_SIZE); + + return dwVerifyResult; +} + +// Used in SFileGetFileInfo +bool QueryMpqSignatureInfo( + TMPQArchive * ha, + PMPQ_SIGNATURE_INFO pSI) +{ + TFileEntry * pFileEntry; + ULONGLONG ExtraBytes; + DWORD dwFileSize; + + // Make sure it's all zeroed + memset(pSI, 0, sizeof(MPQ_SIGNATURE_INFO)); + + // Calculate the range of the MPQ + CalculateArchiveRange(ha, pSI); + + // If there is "(signature)" file in the MPQ, it has a weak signature + pFileEntry = GetFileEntryLocale(ha, SIGNATURE_NAME, LANG_NEUTRAL); + if(pFileEntry != NULL) + { + // Calculate the begin and end of the signature file itself + pSI->BeginExclude = ha->MpqPos + pFileEntry->ByteOffset; + pSI->EndExclude = pSI->BeginExclude + pFileEntry->dwCmpSize; + dwFileSize = (DWORD)(pSI->EndExclude - pSI->BeginExclude); + + // Does the signature have proper size? + if(dwFileSize == MPQ_SIGNATURE_FILE_SIZE) + { + // Read the weak signature + if(!FileStream_Read(ha->pStream, &pSI->BeginExclude, pSI->Signature, dwFileSize)) + return false; + + pSI->SignatureTypes |= SIGNATURE_TYPE_WEAK; + pSI->cbSignatureSize = dwFileSize; + return true; + } + } + + // If there is extra bytes beyond the end of the archive, + // it's the strong signature + ExtraBytes = pSI->EndOfFile - pSI->EndMpqData; + if(ExtraBytes >= (MPQ_STRONG_SIGNATURE_SIZE + 4)) + { + // Read the strong signature + if(!FileStream_Read(ha->pStream, &pSI->EndMpqData, pSI->Signature, (MPQ_STRONG_SIGNATURE_SIZE + 4))) + return false; + + // Check the signature header "NGIS" + if(pSI->Signature[0] != 'N' || pSI->Signature[1] != 'G' || pSI->Signature[2] != 'I' || pSI->Signature[3] != 'S') + return false; + + pSI->SignatureTypes |= SIGNATURE_TYPE_STRONG; + return true; + } + + // Succeeded, but no known signature found + return true; +} + +//----------------------------------------------------------------------------- +// Support for weak signature + +int SSignFileCreate(TMPQArchive * ha) +{ + TMPQFile * hf = NULL; + BYTE EmptySignature[MPQ_SIGNATURE_FILE_SIZE]; + int nError = ERROR_SUCCESS; + + // Only save the signature if we should do so + if(ha->dwFileFlags3 != 0) + { + // The (signature) file must be non-encrypted and non-compressed + assert(ha->dwFlags & MPQ_FLAG_SIGNATURE_NEW); + assert(ha->dwFileFlags3 == MPQ_FILE_EXISTS); + assert(ha->dwReservedFiles > 0); + + // Create the (signature) file file in the MPQ + // Note that the file must not be compressed or encrypted + nError = SFileAddFile_Init(ha, SIGNATURE_NAME, + 0, + sizeof(EmptySignature), + LANG_NEUTRAL, + ha->dwFileFlags3 | MPQ_FILE_REPLACEEXISTING, + &hf); + + // Write the empty signature file to the archive + if(nError == ERROR_SUCCESS) + { + // Write the empty zeroed file to the MPQ + memset(EmptySignature, 0, sizeof(EmptySignature)); + nError = SFileAddFile_Write(hf, EmptySignature, (DWORD)sizeof(EmptySignature), 0); + SFileAddFile_Finish(hf); + + // Clear the invalid mark + ha->dwFlags &= ~(MPQ_FLAG_SIGNATURE_NEW | MPQ_FLAG_SIGNATURE_NONE); + ha->dwReservedFiles--; + } + } + + return nError; +} + +int SSignFileFinish(TMPQArchive * ha) +{ + MPQ_SIGNATURE_INFO si; + unsigned long signature_len = MPQ_WEAK_SIGNATURE_SIZE; + BYTE WeakSignature[MPQ_SIGNATURE_FILE_SIZE]; + BYTE Md5Digest[MD5_DIGEST_SIZE]; + rsa_key key; + int hash_idx = find_hash("md5"); + + // Sanity checks + assert((ha->dwFlags & MPQ_FLAG_CHANGED) == 0); + assert(ha->dwFileFlags3 == MPQ_FILE_EXISTS); + + // Query the weak signature info + memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO)); + if(!QueryMpqSignatureInfo(ha, &si)) + return ERROR_FILE_CORRUPT; + + // There must be exactly one signature + if(si.SignatureTypes != SIGNATURE_TYPE_WEAK) + return ERROR_FILE_CORRUPT; + + // Calculate MD5 of the entire archive + if(!CalculateMpqHashMd5(ha, &si, Md5Digest)) + return ERROR_VERIFY_FAILED; + + // Decode the private key + if(!decode_base64_key(szBlizzardWeakPrivateKey, &key)) + return ERROR_VERIFY_FAILED; + + // Sign the hash + memset(WeakSignature, 0, sizeof(WeakSignature)); + rsa_sign_hash_ex(Md5Digest, sizeof(Md5Digest), WeakSignature + 8, &signature_len, LTC_PKCS_1_V1_5, 0, 0, hash_idx, 0, &key); + memrev(WeakSignature + 8, MPQ_WEAK_SIGNATURE_SIZE); + rsa_free(&key); + + // Write the signature to the MPQ. Don't use SFile* functions, but write the hash directly + if(!FileStream_Write(ha->pStream, &si.BeginExclude, WeakSignature, MPQ_SIGNATURE_FILE_SIZE)) + return GetLastError(); + + return ERROR_SUCCESS; +} + +//----------------------------------------------------------------------------- +// Public (exported) functions + +bool WINAPI SFileGetFileChecksums(HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5) +{ + DWORD dwVerifyResult; + DWORD dwVerifyFlags = 0; + + if(pdwCrc32 != NULL) + dwVerifyFlags |= SFILE_VERIFY_FILE_CRC; + if(pMD5 != NULL) + dwVerifyFlags |= SFILE_VERIFY_FILE_MD5; + + dwVerifyResult = VerifyFile(hMpq, + szFileName, + pdwCrc32, + pMD5, + dwVerifyFlags); + + // If verification failed, return zero + if(dwVerifyResult & VERIFY_FILE_ERROR_MASK) + { + SetLastError(ERROR_FILE_CORRUPT); + return false; + } + + return true; +} + + +DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags) +{ + return VerifyFile(hMpq, + szFileName, + NULL, + NULL, + dwFlags); +} + +// Verifies raw data of the archive Only works for MPQs version 4 or newer +int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * szFileName) +{ + TMPQArchive * ha = (TMPQArchive *)hMpq; + TFileEntry * pFileEntry; + TMPQHeader * pHeader; + + // Verify input parameters + if(!IsValidMpqHandle(hMpq)) + return ERROR_INVALID_PARAMETER; + pHeader = ha->pHeader; + + // If the archive doesn't have raw data MD5, report it as OK + if(pHeader->dwRawChunkSize == 0) + return ERROR_SUCCESS; + + // If we have to verify MPQ header, do it + switch(dwWhatToVerify) + { + case SFILE_VERIFY_MPQ_HEADER: + + // Only if the header is of version 4 or newer + if(pHeader->dwHeaderSize >= (MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE)) + return VerifyRawMpqData(ha, 0, MPQ_HEADER_SIZE_V4 - MD5_DIGEST_SIZE); + return ERROR_SUCCESS; + + case SFILE_VERIFY_HET_TABLE: + + // Only if we have HET table + if(pHeader->HetTablePos64 && pHeader->HetTableSize64) + return VerifyRawMpqData(ha, pHeader->HetTablePos64, (DWORD)pHeader->HetTableSize64); + return ERROR_SUCCESS; + + case SFILE_VERIFY_BET_TABLE: + + // Only if we have BET table + if(pHeader->BetTablePos64 && pHeader->BetTableSize64) + return VerifyRawMpqData(ha, pHeader->BetTablePos64, (DWORD)pHeader->BetTableSize64); + return ERROR_SUCCESS; + + case SFILE_VERIFY_HASH_TABLE: + + // Hash table is not protected by MD5 + return ERROR_SUCCESS; + + case SFILE_VERIFY_BLOCK_TABLE: + + // Block table is not protected by MD5 + return ERROR_SUCCESS; + + case SFILE_VERIFY_HIBLOCK_TABLE: + + // It is unknown if the hi-block table is protected my MD5 or not. + return ERROR_SUCCESS; + + case SFILE_VERIFY_FILE: + + // Verify parameters + if(szFileName == NULL || *szFileName == 0) + return ERROR_INVALID_PARAMETER; + + // Get the offset of a file + pFileEntry = GetFileEntryLocale(ha, szFileName, lcFileLocale); + if(pFileEntry == NULL) + return ERROR_FILE_NOT_FOUND; + + return VerifyRawMpqData(ha, pFileEntry->ByteOffset, pFileEntry->dwCmpSize); + } + + return ERROR_INVALID_PARAMETER; +} + + +// Verifies the archive against the signature +DWORD WINAPI SFileVerifyArchive(HANDLE hMpq) +{ + MPQ_SIGNATURE_INFO si; + TMPQArchive * ha = (TMPQArchive *)hMpq; + + // Verify input parameters + if(!IsValidMpqHandle(hMpq)) + return ERROR_VERIFY_FAILED; + + // If the archive was modified, we need to flush it + if(ha->dwFlags & MPQ_FLAG_CHANGED) + SFileFlushArchive(hMpq); + + // Get the MPQ signature and signature type + memset(&si, 0, sizeof(MPQ_SIGNATURE_INFO)); + if(!QueryMpqSignatureInfo(ha, &si)) + return ERROR_VERIFY_FAILED; + + // If there is no signature + if(si.SignatureTypes == 0) + return ERROR_NO_SIGNATURE; + + // We haven't seen a MPQ with both signatures + assert(si.SignatureTypes == SIGNATURE_TYPE_WEAK || si.SignatureTypes == SIGNATURE_TYPE_STRONG); + + // Verify the strong signature, if present + if(si.SignatureTypes & SIGNATURE_TYPE_STRONG) + return VerifyStrongSignature(ha, &si); + + // Verify the weak signature, if present + if(si.SignatureTypes & SIGNATURE_TYPE_WEAK) + return VerifyWeakSignature(ha, &si); + + return ERROR_NO_SIGNATURE; +} + +// Verifies the archive against the signature +bool WINAPI SFileSignArchive(HANDLE hMpq, DWORD dwSignatureType) +{ + TMPQArchive * ha; + + // Verify the archive handle + ha = IsValidMpqHandle(hMpq); + if(ha == NULL) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // We only support weak signature, and only for MPQs version 1.0 + if(dwSignatureType != SIGNATURE_TYPE_WEAK) + { + SetLastError(ERROR_INVALID_PARAMETER); + return false; + } + + // The archive must not be malformed and must not be read-only + if(ha->dwFlags & (MPQ_FLAG_READ_ONLY | MPQ_FLAG_MALFORMED)) + { + SetLastError(ERROR_ACCESS_DENIED); + return false; + } + + // If the signature is not there yet + if(ha->dwFileFlags3 == 0) + { + // Turn the signature on. The signature will + // be applied when the archive is closed + ha->dwFlags |= MPQ_FLAG_SIGNATURE_NEW | MPQ_FLAG_CHANGED; + ha->dwFileFlags3 = MPQ_FILE_EXISTS; + ha->dwReservedFiles++; + } + + return true; +} + diff --git a/dep/StormLib/src/StormCommon.h b/dep/StormLib/src/StormCommon.h new file mode 100644 index 000000000..4a016c6da --- /dev/null +++ b/dep/StormLib/src/StormCommon.h @@ -0,0 +1,387 @@ +/*****************************************************************************/ +/* SCommon.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Common functions for encryption/decryption from Storm.dll. Included by */ +/* SFile*** functions, do not include and do not use this file directly */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 24.03.03 1.00 Lad The first version of SFileCommon.h */ +/* 12.06.04 1.00 Lad Renamed to SCommon.h */ +/* 06.09.10 1.00 Lad Renamed to StormCommon.h */ +/*****************************************************************************/ + +#ifndef __STORMCOMMON_H__ +#define __STORMCOMMON_H__ + +//----------------------------------------------------------------------------- +// Compression support + +// Include functions from Pkware Data Compression Library +#include "pklib/pklib.h" + +// Include functions from Huffmann compression +#include "huffman/huff.h" + +// Include functions from IMA ADPCM compression +#include "adpcm/adpcm.h" + +// Include functions from SPARSE compression +#include "sparse/sparse.h" + +// Include functions from LZMA compression +#include "lzma/C/LzmaEnc.h" +#include "lzma/C/LzmaDec.h" + +// Include functions from zlib +#ifndef __SYS_ZLIB + #include "zlib/zlib.h" +#else + #include +#endif + +// Include functions from bzlib +#ifndef __SYS_BZLIB + #include "bzip2/bzlib.h" +#else + #include +#endif + +//----------------------------------------------------------------------------- +// Cryptography support + +// Headers from LibTomCrypt +#include "tomcrypt.h" + +#include "rsa/rsa_verify_simple.h" + +// For HashStringJenkins +#include "jenkins/lookup.h" + +//----------------------------------------------------------------------------- +// StormLib private defines + +#define ID_MPQ_FILE 0x46494c45 // Used internally for checking TMPQFile ('FILE') + +// Prevent problems with CRT "min" and "max" functions, +// as they are not defined on all platforms +#define STORMLIB_MIN(a, b) ((a < b) ? a : b) +#define STORMLIB_MAX(a, b) ((a > b) ? a : b) +#define STORMLIB_UNUSED(p) ((void)(p)) + +// Macro for building 64-bit file offset from two 32-bit +#define MAKE_OFFSET64(hi, lo) (((ULONGLONG)hi << 32) | (ULONGLONG)lo) + +//----------------------------------------------------------------------------- +// MPQ signature information + +// Size of each signature type +#define MPQ_WEAK_SIGNATURE_SIZE 64 +#define MPQ_STRONG_SIGNATURE_SIZE 256 +#define MPQ_STRONG_SIGNATURE_ID 0x5349474E // ID of the strong signature ("NGIS") +#define MPQ_SIGNATURE_FILE_SIZE (MPQ_WEAK_SIGNATURE_SIZE + 8) + +// MPQ signature info +typedef struct _MPQ_SIGNATURE_INFO +{ + ULONGLONG BeginMpqData; // File offset where the hashing starts + ULONGLONG BeginExclude; // Begin of the excluded area (used for (signature) file) + ULONGLONG EndExclude; // End of the excluded area (used for (signature) file) + ULONGLONG EndMpqData; // File offset where the hashing ends + ULONGLONG EndOfFile; // Size of the entire file + BYTE Signature[MPQ_STRONG_SIGNATURE_SIZE + 0x10]; + DWORD cbSignatureSize; // Length of the signature + DWORD SignatureTypes; // See SIGNATURE_TYPE_XXX + +} MPQ_SIGNATURE_INFO, *PMPQ_SIGNATURE_INFO; + +//----------------------------------------------------------------------------- +// Memory management +// +// We use our own macros for allocating/freeing memory. If you want +// to redefine them, please keep the following rules: +// +// - The memory allocation must return NULL if not enough memory +// (i.e not to throw exception) +// - The allocating function does not need to fill the allocated buffer with zeros +// - Memory freeing function doesn't have to test the pointer to NULL +// + +//#if defined(_MSC_VER) && defined(_DEBUG) +// +//#define STORM_ALLOC(type, nitems) (type *)HeapAlloc(GetProcessHeap(), 0, ((nitems) * sizeof(type))) +//#define STORM_REALLOC(type, ptr, nitems) (type *)HeapReAlloc(GetProcessHeap(), 0, ptr, ((nitems) * sizeof(type))) +//#define STORM_FREE(ptr) HeapFree(GetProcessHeap(), 0, ptr) +// +//#else + +#define STORM_ALLOC(type, nitems) (type *)malloc((nitems) * sizeof(type)) +#define STORM_REALLOC(type, ptr, nitems) (type *)realloc(ptr, ((nitems) * sizeof(type))) +#define STORM_FREE(ptr) free(ptr) + +//#endif + +//----------------------------------------------------------------------------- +// StormLib internal global variables + +extern LCID lcFileLocale; // Preferred file locale + +//----------------------------------------------------------------------------- +// Conversion to uppercase/lowercase (and "/" to "\") + +extern unsigned char AsciiToLowerTable[256]; +extern unsigned char AsciiToUpperTable[256]; + +//----------------------------------------------------------------------------- +// Safe string functions + +void StringCopy(char * szTarget, size_t cchTarget, const char * szSource); +void StringCat(char * szTarget, size_t cchTargetMax, const char * szSource); + +#ifdef _UNICODE +void StringCopy(TCHAR * szTarget, size_t cchTarget, const char * szSource); +void StringCopy(char * szTarget, size_t cchTarget, const TCHAR * szSource); +void StringCopy(TCHAR * szTarget, size_t cchTarget, const TCHAR * szSource); +void StringCat(TCHAR * szTarget, size_t cchTargetMax, const TCHAR * szSource); +#endif + +//----------------------------------------------------------------------------- +// Encryption and decryption functions + +#define MPQ_HASH_TABLE_INDEX 0x000 +#define MPQ_HASH_NAME_A 0x100 +#define MPQ_HASH_NAME_B 0x200 +#define MPQ_HASH_FILE_KEY 0x300 +#define MPQ_HASH_KEY2_MIX 0x400 + +DWORD HashString(const char * szFileName, DWORD dwHashType); +DWORD HashStringSlash(const char * szFileName, DWORD dwHashType); +DWORD HashStringLower(const char * szFileName, DWORD dwHashType); + +void InitializeMpqCryptography(); + +DWORD GetNearestPowerOfTwo(DWORD dwFileCount); + +bool IsPseudoFileName(const char * szFileName, LPDWORD pdwFileIndex); +ULONGLONG HashStringJenkins(const char * szFileName); + +DWORD GetDefaultSpecialFileFlags(DWORD dwFileSize, USHORT wFormatVersion); + +void EncryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey); +void DecryptMpqBlock(void * pvDataBlock, DWORD dwLength, DWORD dwKey); + +DWORD DetectFileKeyBySectorSize(LPDWORD EncryptedData, DWORD dwSectorSize, DWORD dwSectorOffsLen); +DWORD DetectFileKeyByContent(void * pvEncryptedData, DWORD dwSectorSize, DWORD dwFileSize); +DWORD DecryptFileKey(const char * szFileName, ULONGLONG MpqPos, DWORD dwFileSize, DWORD dwFlags); + +bool IsValidMD5(LPBYTE pbMd5); +bool IsValidSignature(LPBYTE pbSignature); +bool VerifyDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE expected_md5); +void CalculateDataBlockHash(void * pvDataBlock, DWORD cbDataBlock, LPBYTE md5_hash); + +//----------------------------------------------------------------------------- +// Handle validation functions + +TMPQArchive * IsValidMpqHandle(HANDLE hMpq); +TMPQFile * IsValidFileHandle(HANDLE hFile); + +//----------------------------------------------------------------------------- +// Support for MPQ file tables + +ULONGLONG FileOffsetFromMpqOffset(TMPQArchive * ha, ULONGLONG MpqOffset); +ULONGLONG CalculateRawSectorOffset(TMPQFile * hf, DWORD dwSectorOffset); + +int ConvertMpqHeaderToFormat4(TMPQArchive * ha, ULONGLONG MpqOffset, ULONGLONG FileSize, DWORD dwFlags, bool bIsWarcraft3Map); + +bool IsValidHashEntry(TMPQArchive * ha, TMPQHash * pHash); + +TMPQHash * FindFreeHashEntry(TMPQArchive * ha, DWORD dwStartIndex, DWORD dwName1, DWORD dwName2, LCID lcLocale); +TMPQHash * GetFirstHashEntry(TMPQArchive * ha, const char * szFileName); +TMPQHash * GetNextHashEntry(TMPQArchive * ha, TMPQHash * pFirstHash, TMPQHash * pPrevHash); +TMPQHash * AllocateHashEntry(TMPQArchive * ha, TFileEntry * pFileEntry, LCID lcLocale); + +TMPQExtHeader * LoadExtTable(TMPQArchive * ha, ULONGLONG ByteOffset, size_t Size, DWORD dwSignature, DWORD dwKey); +TMPQHetTable * LoadHetTable(TMPQArchive * ha); +TMPQBetTable * LoadBetTable(TMPQArchive * ha); + +TMPQBlock * LoadBlockTable(TMPQArchive * ha, bool bDontFixEntries = false); +TMPQBlock * TranslateBlockTable(TMPQArchive * ha, ULONGLONG * pcbTableSize, bool * pbNeedHiBlockTable); + +ULONGLONG FindFreeMpqSpace(TMPQArchive * ha); + +// Functions that load the HET and BET tables +int CreateHashTable(TMPQArchive * ha, DWORD dwHashTableSize); +int LoadAnyHashTable(TMPQArchive * ha); +int BuildFileTable(TMPQArchive * ha); +int DefragmentFileTable(TMPQArchive * ha); + +int CreateFileTable(TMPQArchive * ha, DWORD dwFileTableSize); +int RebuildHetTable(TMPQArchive * ha); +int RebuildFileTable(TMPQArchive * ha, DWORD dwNewHashTableSize); +int SaveMPQTables(TMPQArchive * ha); + +TMPQHetTable * CreateHetTable(DWORD dwEntryCount, DWORD dwTotalCount, DWORD dwHashBitSize, LPBYTE pbSrcData); +void FreeHetTable(TMPQHetTable * pHetTable); + +TMPQBetTable * CreateBetTable(DWORD dwMaxFileCount); +void FreeBetTable(TMPQBetTable * pBetTable); + +// Functions for finding files in the file table +TFileEntry * GetFileEntryLocale2(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); +TFileEntry * GetFileEntryLocale(TMPQArchive * ha, const char * szFileName, LCID lcLocale); +TFileEntry * GetFileEntryExact(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); + +// Allocates file name in the file entry +void AllocateFileName(TMPQArchive * ha, TFileEntry * pFileEntry, const char * szFileName); + +// Allocates new file entry in the MPQ tables. Reuses existing, if possible +TFileEntry * AllocateFileEntry(TMPQArchive * ha, const char * szFileName, LCID lcLocale, LPDWORD PtrHashIndex); +int RenameFileEntry(TMPQArchive * ha, TMPQFile * hf, const char * szNewFileName); +int DeleteFileEntry(TMPQArchive * ha, TMPQFile * hf); + +// Invalidates entries for (listfile) and (attributes) +void InvalidateInternalFiles(TMPQArchive * ha); + +// Retrieves information about the strong signature +bool QueryMpqSignatureInfo(TMPQArchive * ha, PMPQ_SIGNATURE_INFO pSignatureInfo); + +//----------------------------------------------------------------------------- +// Support for alternate file formats (SBaseSubTypes.cpp) + +int ConvertSqpHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags); +TMPQHash * LoadSqpHashTable(TMPQArchive * ha); +TMPQBlock * LoadSqpBlockTable(TMPQArchive * ha); + +int ConvertMpkHeaderToFormat4(TMPQArchive * ha, ULONGLONG FileSize, DWORD dwFlags); +void DecryptMpkTable(void * pvMpkTable, size_t cbSize); +TMPQHash * LoadMpkHashTable(TMPQArchive * ha); +TMPQBlock * LoadMpkBlockTable(TMPQArchive * ha); +int SCompDecompressMpk(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); + +//----------------------------------------------------------------------------- +// Common functions - MPQ File + +TMPQFile * CreateFileHandle(TMPQArchive * ha, TFileEntry * pFileEntry); +TMPQFile * CreateWritableHandle(TMPQArchive * ha, DWORD dwFileSize); +void * LoadMpqTable(TMPQArchive * ha, ULONGLONG ByteOffset, DWORD dwCompressedSize, DWORD dwRealSize, DWORD dwKey, bool * pbTableIsCut); +int AllocateSectorBuffer(TMPQFile * hf); +int AllocatePatchInfo(TMPQFile * hf, bool bLoadFromFile); +int AllocateSectorOffsets(TMPQFile * hf, bool bLoadFromFile); +int AllocateSectorChecksums(TMPQFile * hf, bool bLoadFromFile); +int WritePatchInfo(TMPQFile * hf); +int WriteSectorOffsets(TMPQFile * hf); +int WriteSectorChecksums(TMPQFile * hf); +int WriteMemDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, void * pvRawData, DWORD dwRawDataSize, DWORD dwChunkSize, LPDWORD pcbTotalSize); +int WriteMpqDataMD5(TFileStream * pStream, ULONGLONG RawDataOffs, DWORD dwRawDataSize, DWORD dwChunkSize); +void FreeFileHandle(TMPQFile *& hf); +void FreeArchiveHandle(TMPQArchive *& ha); + +//----------------------------------------------------------------------------- +// Patch functions + +// Structure used for the patching process +typedef struct _TMPQPatcher +{ + BYTE this_md5[MD5_DIGEST_SIZE]; // MD5 of the current file state + LPBYTE pbFileData1; // Primary working buffer + LPBYTE pbFileData2; // Secondary working buffer + DWORD cbMaxFileData; // Maximum allowed size of the patch data + DWORD cbFileData; // Current size of the result data + DWORD nCounter; // Counter of the patch process + +} TMPQPatcher; + +bool IsIncrementalPatchFile(const void * pvData, DWORD cbData, LPDWORD pdwPatchedFileSize); +int Patch_InitPatcher(TMPQPatcher * pPatcher, TMPQFile * hf); +int Patch_Process(TMPQPatcher * pPatcher, TMPQFile * hf); +void Patch_Finalize(TMPQPatcher * pPatcher); + +//----------------------------------------------------------------------------- +// Utility functions + +bool CheckWildCard(const char * szString, const char * szWildCard); +bool IsInternalMpqFileName(const char * szFileName); + +template +const XCHAR * GetPlainFileName(const XCHAR * szFileName) +{ + const XCHAR * szPlainName = szFileName; + + while(*szFileName != 0) + { + if(*szFileName == '\\' || *szFileName == '/') + szPlainName = szFileName + 1; + szFileName++; + } + + return szPlainName; +} + +//----------------------------------------------------------------------------- +// Internal support for MPQ modifications + +int SFileAddFile_Init( + TMPQArchive * ha, + const char * szArchivedName, + ULONGLONG ft, + DWORD dwFileSize, + LCID lcLocale, + DWORD dwFlags, + TMPQFile ** phf + ); + +int SFileAddFile_Init( + TMPQArchive * ha, + TMPQFile * hfSrc, + TMPQFile ** phf + ); + +int SFileAddFile_Write( + TMPQFile * hf, + const void * pvData, + DWORD dwSize, + DWORD dwCompression + ); + +int SFileAddFile_Finish( + TMPQFile * hf + ); + +//----------------------------------------------------------------------------- +// Attributes support + +int SAttrLoadAttributes(TMPQArchive * ha); +int SAttrFileSaveToMpq(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Listfile functions + +int SListFileSaveToMpq(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Weak signature support + +int SSignFileCreate(TMPQArchive * ha); +int SSignFileFinish(TMPQArchive * ha); + +//----------------------------------------------------------------------------- +// Dump data support + +#ifdef __STORMLIB_DUMP_DATA__ + +void DumpMpqHeader(TMPQHeader * pHeader); +void DumpHashTable(TMPQHash * pHashTable, DWORD dwHashTableSize); +void DumpHetAndBetTable(TMPQHetTable * pHetTable, TMPQBetTable * pBetTable); +void DumpFileTable(TFileEntry * pFileTable, DWORD dwFileTableSize); + +#else + +#define DumpMpqHeader(h) /* */ +#define DumpHashTable(t, s) /* */ +#define DumpHetAndBetTable(t, s) /* */ +#define DumpFileTable(t, s) /* */ + +#endif + +#endif // __STORMCOMMON_H__ + diff --git a/dep/StormLib/src/StormLib.h b/dep/StormLib/src/StormLib.h new file mode 100644 index 000000000..31f6edae9 --- /dev/null +++ b/dep/StormLib/src/StormLib.h @@ -0,0 +1,1124 @@ +/*****************************************************************************/ +/* StormLib.h Copyright (c) Ladislav Zezula 1999-2017 */ +/*---------------------------------------------------------------------------*/ +/* StormLib library v 9.22 */ +/* */ +/* Author : Ladislav Zezula */ +/* E-mail : ladik@zezula.net */ +/* WWW : http://www.zezula.net */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.99 1.00 Lad Created */ +/* 24.03.03 2.50 Lad Version 2.50 */ +/* 02.04.03 3.00 Lad Version 3.00 with compression */ +/* 11.04.03 3.01 Lad Renamed to StormLib.h for compatibility with */ +/* original headers for Storm.dll */ +/* 10.05.03 3.02 Lad Added Pkware DCL compression */ +/* 26.05.03 4.00 Lad Completed all compressions */ +/* 18.06.03 4.01 Lad Added SFileSetFileLocale */ +/* Added SFileExtractFile */ +/* 26.07.03 4.02 Lad Implemented nameless rename and delete */ +/* 26.07.03 4.03 Lad Added support for protected MPQs */ +/* 28.08.03 4.10 Lad Fixed bugs that caused StormLib incorrectly work */ +/* with Diablo I savegames and with files having full */ +/* hash table */ +/* 08.12.03 4.11 DCH Fixed bug in reading file sector larger than 0x1000 */ +/* on certain files. */ +/* Fixed bug in AddFile with MPQ_FILE_REPLACE_EXISTING */ +/* (Thanx Daniel Chiamarello, dchiamarello@madvawes.com)*/ +/* 21.12.03 4.50 Lad Completed port for Mac */ +/* Fixed bug in compacting (if fsize is mul of 0x1000) */ +/* Fixed bug in SCompCompress */ +/* 27.05.04 4.51 Lad Changed memory management from new/delete to our */ +/* own macros */ +/* 22.06.04 4.60 Lad Optimized search. Support for multiple listfiles. */ +/* 30.09.04 4.61 Lad Fixed some bugs (Aaargh !!!) */ +/* Correctly works if HashTableSize > BlockTableSize */ +/* 29.12.04 4.70 Lad Fixed compatibility problem with MPQs from WoW */ +/* 14.07.05 5.00 Lad Added the BZLIB compression support */ +/* Added suport of files stored as single unit */ +/* 17.04.06 5.01 Lad Converted to MS Visual Studio 8.0 */ +/* Fixed issue with protected Warcraft 3 protected maps */ +/* 15.05.06 5.02 Lad Fixed issue with WoW 1.10+ */ +/* 07.09.06 5.10 Lad Fixed processing files longer than 2GB */ +/* 22.11.06 6.00 Lad Support for MPQ archives V2 */ +/* 12.06.07 6.10 Lad Support for (attributes) file */ +/* 10.09.07 6.12 Lad Support for MPQs protected by corrupting hash table */ +/* 03.12.07 6.13 Lad Support for MPQs with hash tbl size > block tbl size */ +/* 07.04.08 6.20 Lad Added SFileFlushArchive */ +/* 09.04.08 Lad Removed FilePointer variable from MPQ handle */ +/* structure, as it caused more problems than benefits */ +/* 12.05.08 6.22 Lad Support for w3xMaster map protector */ +/* 05.10.08 6.23 Lad Support for protectors who set negative values in */ +/* the table of file blocks */ +/* 26.05.09 6.24 Lad Fixed search for multiple lang files with deleted */ +/* entries */ +/* 03.09.09 6.25 Lad Fixed decompression bug in huffmann decompression */ +/* 22.03.10 6.50 Lad New compressions in Starcraft II (LZMA, sparse) */ +/* Fixed compacting MPQs that contain single unit files */ +/* 26.04.10 7.00 Lad Major rewrite */ +/* 08.06.10 7.10 Lad Support for partial MPQs */ +/* 08.07.10 7.11 Lad Support for MPQs v 3.0 */ +/* 20.08.10 7.20 Lad Support for opening multiple MPQs in patch mode */ +/* 20.09.10 8.00 Lad MPQs v 4, HET and BET tables */ +/* 07.01.11 8.01 Lad Write support for MPQs v 3 and 4 */ +/* 15.09.11 8.04 Lad Bug fixes, testing for Diablo III MPQs */ +/* 26.04.12 8.10 Lad Support for data map, added SFileGetArchiveBitmap */ +/* 29.05.12 8.20 Lad C-only interface */ +/* 14.01.13 8.21 Lad ADPCM and Huffmann (de)compression refactored */ +/* 04.12.13 9.00 Lad Unit tests, bug fixes */ +/* 27.08.14 9.10 Lad Signing archives with weak digital signature */ +/* 25.11.14 9.11 Lad Fixed bug reading & creating HET table */ +/* 18.09.15 9.20 Lad Release 9.20 */ +/* 12.12.16 9.21 Lad Release 9.21 */ +/* 10.11.17 9.22 Lad Release 9.22 */ +/*****************************************************************************/ + +#ifndef __STORMLIB_H__ +#define __STORMLIB_H__ + +#ifdef _MSC_VER +#pragma warning(disable:4668) // 'XXX' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif' +#pragma warning(disable:4820) // 'XXX' : '2' bytes padding added after data member 'XXX::yyy' +#endif + +#include "StormPort.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//----------------------------------------------------------------------------- +// Use the apropriate library +// +// The library type is encoded in the library name as the following +// StormLibXYZ.lib +// +// X - D for Debug version, R for Release version +// Y - A for ANSI version, U for Unicode version +// Z - S for static-linked CRT library, D for multithreaded DLL CRT library +// + +#if defined(__STORMLIB_SELF__) && !defined(STORMLIB_NO_AUTO_LINK) +#define STORMLIB_NO_AUTO_LINK // Define this if you don't want to link using pragmas when using msvc +#endif + +#if defined(_MSC_VER) && !defined(STORMLIB_NO_AUTO_LINK) + #ifdef _DEBUG // DEBUG VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "StormLibDAD.lib") // Debug Ansi CRT-DLL version + #else + #pragma comment(lib, "StormLibDAS.lib") // Debug Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "StormLibDUD.lib") // Debug Unicode CRT-DLL version + #else + #pragma comment(lib, "StormLibDUS.lib") // Debug Unicode CRT-LIB version + #endif + #endif + #else // RELEASE VERSIONS + #ifndef _UNICODE + #ifdef _DLL + #pragma comment(lib, "StormLibRAD.lib") // Release Ansi CRT-DLL version + #else + #pragma comment(lib, "StormLibRAS.lib") // Release Ansi CRT-LIB version + #endif + #else + #ifdef _DLL + #pragma comment(lib, "StormLibRUD.lib") // Release Unicode CRT-DLL version + #else + #pragma comment(lib, "StormLibRUS.lib") // Release Unicode CRT-LIB version + #endif + #endif + #endif + +#endif + +//----------------------------------------------------------------------------- +// Defines + +#define STORMLIB_VERSION 0x0916 // Current version of StormLib (9.21) +#define STORMLIB_VERSION_STRING "9.22" // String version of StormLib version + +#define ID_MPQ 0x1A51504D // MPQ archive header ID ('MPQ\x1A') +#define ID_MPQ_USERDATA 0x1B51504D // MPQ userdata entry ('MPQ\x1B') +#define ID_MPK 0x1A4B504D // MPK archive header ID ('MPK\x1A') + +#define ERROR_AVI_FILE 10000 // Not a MPQ file, but an AVI file. +#define ERROR_UNKNOWN_FILE_KEY 10001 // Returned by SFileReadFile when can't find file key +#define ERROR_CHECKSUM_ERROR 10002 // Returned by SFileReadFile when sector CRC doesn't match +#define ERROR_INTERNAL_FILE 10003 // The given operation is not allowed on internal file +#define ERROR_BASE_FILE_MISSING 10004 // The file is present as incremental patch file, but base file is missing +#define ERROR_MARKED_FOR_DELETE 10005 // The file was marked as "deleted" in the MPQ +#define ERROR_FILE_INCOMPLETE 10006 // The required file part is missing +#define ERROR_UNKNOWN_FILE_NAMES 10007 // A name of at least one file is unknown +#define ERROR_CANT_FIND_PATCH_PREFIX 10008 // StormLib was unable to find patch prefix for the patches + +// Values for SFileCreateArchive +#define HASH_TABLE_SIZE_MIN 0x00000004 // Verified: If there is 1 file, hash table size is 4 +#define HASH_TABLE_SIZE_DEFAULT 0x00001000 // Default hash table size for empty MPQs +#define HASH_TABLE_SIZE_MAX 0x00080000 // Maximum acceptable hash table size + +#define HASH_ENTRY_DELETED 0xFFFFFFFE // Block index for deleted entry in the hash table +#define HASH_ENTRY_FREE 0xFFFFFFFF // Block index for free entry in the hash table + +#define HET_ENTRY_DELETED 0x80 // NameHash1 value for a deleted entry +#define HET_ENTRY_FREE 0x00 // NameHash1 value for free entry + +#define HASH_STATE_SIZE 0x60 // Size of LibTomCrypt's hash_state structure + +// Values for SFileOpenArchive +#define SFILE_OPEN_HARD_DISK_FILE 2 // Open the archive on HDD +#define SFILE_OPEN_CDROM_FILE 3 // Open the archive only if it is on CDROM + +// Values for SFileOpenFile +#define SFILE_OPEN_FROM_MPQ 0x00000000 // Open the file from the MPQ archive +#define SFILE_OPEN_CHECK_EXISTS 0xFFFFFFFC // Only check whether the file exists +#define SFILE_OPEN_BASE_FILE 0xFFFFFFFD // Reserved for StormLib internal use +#define SFILE_OPEN_ANY_LOCALE 0xFFFFFFFE // Reserved for StormLib internal use +#define SFILE_OPEN_LOCAL_FILE 0xFFFFFFFF // Open a local file + +// Flags for TMPQArchive::dwFlags. Used internally +#define MPQ_FLAG_READ_ONLY 0x00000001 // If set, the MPQ has been open for read-only access +#define MPQ_FLAG_CHANGED 0x00000002 // If set, the MPQ tables have been changed +#define MPQ_FLAG_MALFORMED 0x00000004 // Malformed data structure detected (W3M map protectors) +#define MPQ_FLAG_HASH_TABLE_CUT 0x00000008 // The hash table goes beyond EOF +#define MPQ_FLAG_BLOCK_TABLE_CUT 0x00000010 // The hash table goes beyond EOF +#define MPQ_FLAG_CHECK_SECTOR_CRC 0x00000020 // Checking sector CRC when reading files +#define MPQ_FLAG_SAVING_TABLES 0x00000040 // If set, we are saving MPQ internal files and MPQ tables +#define MPQ_FLAG_PATCH 0x00000080 // If set, this MPQ is a patch archive +#define MPQ_FLAG_WAR3_MAP 0x00000100 // If set, this MPQ is a map for Warcraft III +#define MPQ_FLAG_LISTFILE_NONE 0x00000200 // Set when no (listfile) was found in InvalidateInternalFiles +#define MPQ_FLAG_LISTFILE_NEW 0x00000400 // Set when (listfile) invalidated by InvalidateInternalFiles +#define MPQ_FLAG_LISTFILE_FORCE 0x00000800 // Save updated listfile on exit +#define MPQ_FLAG_ATTRIBUTES_NONE 0x00001000 // Set when no (attributes) was found in InvalidateInternalFiles +#define MPQ_FLAG_ATTRIBUTES_NEW 0x00002000 // Set when (attributes) invalidated by InvalidateInternalFiles +#define MPQ_FLAG_SIGNATURE_NONE 0x00004000 // Set when no (signature) was found in InvalidateInternalFiles +#define MPQ_FLAG_SIGNATURE_NEW 0x00008000 // Set when (signature) invalidated by InvalidateInternalFiles + +// Values for TMPQArchive::dwSubType +#define MPQ_SUBTYPE_MPQ 0x00000000 // The file is a MPQ file (Blizzard games) +#define MPQ_SUBTYPE_SQP 0x00000001 // The file is a SQP file (War of the Immortals) +#define MPQ_SUBTYPE_MPK 0x00000002 // The file is a MPK file (Longwu Online) + +// Return value for SFileGetFileSize and SFileSetFilePointer +#define SFILE_INVALID_SIZE 0xFFFFFFFF +#define SFILE_INVALID_POS 0xFFFFFFFF +#define SFILE_INVALID_ATTRIBUTES 0xFFFFFFFF + +// Flags for SFileAddFile +#define MPQ_FILE_IMPLODE 0x00000100 // Implode method (By PKWARE Data Compression Library) +#define MPQ_FILE_COMPRESS 0x00000200 // Compress methods (By multiple methods) +#define MPQ_FILE_ENCRYPTED 0x00010000 // Indicates whether file is encrypted +#define MPQ_FILE_FIX_KEY 0x00020000 // File decryption key has to be fixed +#define MPQ_FILE_PATCH_FILE 0x00100000 // The file is a patch file. Raw file data begin with TPatchInfo structure +#define MPQ_FILE_SINGLE_UNIT 0x01000000 // File is stored as a single unit, rather than split into sectors (Thx, Quantam) +#define MPQ_FILE_DELETE_MARKER 0x02000000 // File is a deletion marker. Used in MPQ patches, indicating that the file no longer exists. +#define MPQ_FILE_SECTOR_CRC 0x04000000 // File has checksums for each sector. + // Ignored if file is not compressed or imploded. +#define MPQ_FILE_SIGNATURE 0x10000000 // Present on STANDARD.SNP\(signature). The only occurence ever observed +#define MPQ_FILE_EXISTS 0x80000000 // Set if file exists, reset when the file was deleted +#define MPQ_FILE_REPLACEEXISTING 0x80000000 // Replace when the file exist (SFileAddFile) + +#define MPQ_FILE_COMPRESS_MASK 0x0000FF00 // Mask for a file being compressed + +#define MPQ_FILE_DEFAULT_INTERNAL 0xFFFFFFFF // Use default flags for internal files + +#define MPQ_FILE_VALID_FLAGS (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIX_KEY | \ + MPQ_FILE_PATCH_FILE | \ + MPQ_FILE_SINGLE_UNIT | \ + MPQ_FILE_DELETE_MARKER | \ + MPQ_FILE_SECTOR_CRC | \ + MPQ_FILE_SIGNATURE | \ + MPQ_FILE_EXISTS) + +#define MPQ_FILE_VALID_FLAGS_W3X (MPQ_FILE_IMPLODE | \ + MPQ_FILE_COMPRESS | \ + MPQ_FILE_ENCRYPTED | \ + MPQ_FILE_FIX_KEY | \ + MPQ_FILE_DELETE_MARKER | \ + MPQ_FILE_SECTOR_CRC | \ + MPQ_FILE_SIGNATURE | \ + MPQ_FILE_EXISTS) + +// We need to mask out the upper 4 bits of the block table index. +// This is because it gets shifted out when calculating block table offset +// BlockTableOffset = pHash->dwBlockIndex << 0x04 +// Malformed MPQ maps may contain block indexes like 0x40000001 or 0xF0000023 +#define BLOCK_INDEX_MASK 0x0FFFFFFF +#define MPQ_BLOCK_INDEX(pHash) (pHash->dwBlockIndex & BLOCK_INDEX_MASK) + +// Compression types for multiple compressions +#define MPQ_COMPRESSION_HUFFMANN 0x01 // Huffmann compression (used on WAVE files only) +#define MPQ_COMPRESSION_ZLIB 0x02 // ZLIB compression +#define MPQ_COMPRESSION_PKWARE 0x08 // PKWARE DCL compression +#define MPQ_COMPRESSION_BZIP2 0x10 // BZIP2 compression (added in Warcraft III) +#define MPQ_COMPRESSION_SPARSE 0x20 // Sparse compression (added in Starcraft 2) +#define MPQ_COMPRESSION_ADPCM_MONO 0x40 // IMA ADPCM compression (mono) +#define MPQ_COMPRESSION_ADPCM_STEREO 0x80 // IMA ADPCM compression (stereo) +#define MPQ_COMPRESSION_LZMA 0x12 // LZMA compression. Added in Starcraft 2. This value is NOT a combination of flags. +#define MPQ_COMPRESSION_NEXT_SAME 0xFFFFFFFF // Same compression + +// Constants for SFileAddWave +#define MPQ_WAVE_QUALITY_HIGH 0 // Best quality, the worst compression +#define MPQ_WAVE_QUALITY_MEDIUM 1 // Medium quality, medium compression +#define MPQ_WAVE_QUALITY_LOW 2 // Low quality, the best compression + +// Signatures for HET and BET table +#define HET_TABLE_SIGNATURE 0x1A544548 // 'HET\x1a' +#define BET_TABLE_SIGNATURE 0x1A544542 // 'BET\x1a' + +// Decryption keys for MPQ tables +#define MPQ_KEY_HASH_TABLE 0xC3AF3770 // Obtained by HashString("(hash table)", MPQ_HASH_FILE_KEY) +#define MPQ_KEY_BLOCK_TABLE 0xEC83B3A3 // Obtained by HashString("(block table)", MPQ_HASH_FILE_KEY) + +#define LISTFILE_NAME "(listfile)" // Name of internal listfile +#define SIGNATURE_NAME "(signature)" // Name of internal signature +#define ATTRIBUTES_NAME "(attributes)" // Name of internal attributes file +#define PATCH_METADATA_NAME "(patch_metadata)" + +#define MPQ_FORMAT_VERSION_1 0 // Up to The Burning Crusade +#define MPQ_FORMAT_VERSION_2 1 // The Burning Crusade and newer +#define MPQ_FORMAT_VERSION_3 2 // WoW Cataclysm Beta +#define MPQ_FORMAT_VERSION_4 3 // WoW Cataclysm and newer + +// Flags for MPQ attributes +#define MPQ_ATTRIBUTE_CRC32 0x00000001 // The "(attributes)" contains CRC32 for each file +#define MPQ_ATTRIBUTE_FILETIME 0x00000002 // The "(attributes)" contains file time for each file +#define MPQ_ATTRIBUTE_MD5 0x00000004 // The "(attributes)" contains MD5 for each file +#define MPQ_ATTRIBUTE_PATCH_BIT 0x00000008 // The "(attributes)" contains a patch bit for each file +#define MPQ_ATTRIBUTE_ALL 0x0000000F // Summary mask + +#define MPQ_ATTRIBUTES_V1 100 // (attributes) format version 1.00 + +// Flags for SFileOpenArchive +#define BASE_PROVIDER_FILE 0x00000000 // Base data source is a file +#define BASE_PROVIDER_MAP 0x00000001 // Base data source is memory-mapped file +#define BASE_PROVIDER_HTTP 0x00000002 // Base data source is a file on web server +#define BASE_PROVIDER_MASK 0x0000000F // Mask for base provider value + +#define STREAM_PROVIDER_FLAT 0x00000000 // Stream is linear with no offset mapping +#define STREAM_PROVIDER_PARTIAL 0x00000010 // Stream is partial file (.part) +#define STREAM_PROVIDER_MPQE 0x00000020 // Stream is an encrypted MPQ +#define STREAM_PROVIDER_BLOCK4 0x00000030 // 0x4000 per block, text MD5 after each block, max 0x2000 blocks per file +#define STREAM_PROVIDER_MASK 0x000000F0 // Mask for stream provider value + +#define STREAM_FLAG_READ_ONLY 0x00000100 // Stream is read only +#define STREAM_FLAG_WRITE_SHARE 0x00000200 // Allow write sharing when open for write +#define STREAM_FLAG_USE_BITMAP 0x00000400 // If the file has a file bitmap, load it and use it +#define STREAM_OPTIONS_MASK 0x0000FF00 // Mask for stream options + +#define STREAM_PROVIDERS_MASK 0x000000FF // Mask to get stream providers +#define STREAM_FLAGS_MASK 0x0000FFFF // Mask for all stream flags (providers+options) + +#define MPQ_OPEN_NO_LISTFILE 0x00010000 // Don't load the internal listfile +#define MPQ_OPEN_NO_ATTRIBUTES 0x00020000 // Don't open the attributes +#define MPQ_OPEN_NO_HEADER_SEARCH 0x00040000 // Don't search for the MPQ header past the begin of the file +#define MPQ_OPEN_FORCE_MPQ_V1 0x00080000 // Always open the archive as MPQ v 1.00, ignore the "wFormatVersion" variable in the header +#define MPQ_OPEN_CHECK_SECTOR_CRC 0x00100000 // On files with MPQ_FILE_SECTOR_CRC, the CRC will be checked when reading file +#define MPQ_OPEN_PATCH 0x00200000 // This archive is a patch MPQ. Used internally. +#define MPQ_OPEN_FORCE_LISTFILE 0x00400000 // Force add listfile even if there is none at the moment of opening +#define MPQ_OPEN_READ_ONLY STREAM_FLAG_READ_ONLY + +// Flags for SFileCreateArchive +#define MPQ_CREATE_LISTFILE 0x00100000 // Also add the (listfile) file +#define MPQ_CREATE_ATTRIBUTES 0x00200000 // Also add the (attributes) file +#define MPQ_CREATE_SIGNATURE 0x00400000 // Also add the (signature) file +#define MPQ_CREATE_ARCHIVE_V1 0x00000000 // Creates archive of version 1 (size up to 4GB) +#define MPQ_CREATE_ARCHIVE_V2 0x01000000 // Creates archive of version 2 (larger than 4 GB) +#define MPQ_CREATE_ARCHIVE_V3 0x02000000 // Creates archive of version 3 +#define MPQ_CREATE_ARCHIVE_V4 0x03000000 // Creates archive of version 4 +#define MPQ_CREATE_ARCHIVE_VMASK 0x0F000000 // Mask for archive version + +#define FLAGS_TO_FORMAT_SHIFT 24 // (MPQ_CREATE_ARCHIVE_V4 >> FLAGS_TO_FORMAT_SHIFT) => MPQ_FORMAT_VERSION_4 + +// Flags for SFileVerifyFile +#define SFILE_VERIFY_SECTOR_CRC 0x00000001 // Verify sector checksum for the file, if available +#define SFILE_VERIFY_FILE_CRC 0x00000002 // Verify file CRC, if available +#define SFILE_VERIFY_FILE_MD5 0x00000004 // Verify file MD5, if available +#define SFILE_VERIFY_RAW_MD5 0x00000008 // Verify raw file MD5, if available +#define SFILE_VERIFY_ALL 0x0000000F // Verify every checksum possible + +// Return values for SFileVerifyFile +#define VERIFY_OPEN_ERROR 0x0001 // Failed to open the file +#define VERIFY_READ_ERROR 0x0002 // Failed to read all data from the file +#define VERIFY_FILE_HAS_SECTOR_CRC 0x0004 // File has sector CRC +#define VERIFY_FILE_SECTOR_CRC_ERROR 0x0008 // Sector CRC check failed +#define VERIFY_FILE_HAS_CHECKSUM 0x0010 // File has CRC32 +#define VERIFY_FILE_CHECKSUM_ERROR 0x0020 // CRC32 check failed +#define VERIFY_FILE_HAS_MD5 0x0040 // File has data MD5 +#define VERIFY_FILE_MD5_ERROR 0x0080 // MD5 check failed +#define VERIFY_FILE_HAS_RAW_MD5 0x0100 // File has raw data MD5 +#define VERIFY_FILE_RAW_MD5_ERROR 0x0200 // Raw MD5 check failed +#define VERIFY_FILE_ERROR_MASK (VERIFY_OPEN_ERROR | VERIFY_READ_ERROR | VERIFY_FILE_SECTOR_CRC_ERROR | VERIFY_FILE_CHECKSUM_ERROR | VERIFY_FILE_MD5_ERROR | VERIFY_FILE_RAW_MD5_ERROR) + +// Flags for SFileVerifyRawData (for MPQs version 4.0 or higher) +#define SFILE_VERIFY_MPQ_HEADER 0x0001 // Verify raw MPQ header +#define SFILE_VERIFY_HET_TABLE 0x0002 // Verify raw data of the HET table +#define SFILE_VERIFY_BET_TABLE 0x0003 // Verify raw data of the BET table +#define SFILE_VERIFY_HASH_TABLE 0x0004 // Verify raw data of the hash table +#define SFILE_VERIFY_BLOCK_TABLE 0x0005 // Verify raw data of the block table +#define SFILE_VERIFY_HIBLOCK_TABLE 0x0006 // Verify raw data of the hi-block table +#define SFILE_VERIFY_FILE 0x0007 // Verify raw data of a file + +// Signature types +#define SIGNATURE_TYPE_NONE 0x0000 // The archive has no signature in it +#define SIGNATURE_TYPE_WEAK 0x0001 // The archive has weak signature +#define SIGNATURE_TYPE_STRONG 0x0002 // The archive has strong signature + +// Return values for SFileVerifyArchive +#define ERROR_NO_SIGNATURE 0 // There is no signature in the MPQ +#define ERROR_VERIFY_FAILED 1 // There was an error during verifying signature (like no memory) +#define ERROR_WEAK_SIGNATURE_OK 2 // There is a weak signature and sign check passed +#define ERROR_WEAK_SIGNATURE_ERROR 3 // There is a weak signature but sign check failed +#define ERROR_STRONG_SIGNATURE_OK 4 // There is a strong signature and sign check passed +#define ERROR_STRONG_SIGNATURE_ERROR 5 // There is a strong signature but sign check failed + +#ifndef MD5_DIGEST_SIZE +#define MD5_DIGEST_SIZE 0x10 +#endif + +#ifndef SHA1_DIGEST_SIZE +#define SHA1_DIGEST_SIZE 0x14 // 160 bits +#endif + +#ifndef LANG_NEUTRAL +#define LANG_NEUTRAL 0x00 // Neutral locale +#endif + +// Pointer to hashing function +typedef DWORD (*HASH_STRING)(const char * szFileName, DWORD dwHashType); + +//----------------------------------------------------------------------------- +// File information classes for SFileGetFileInfo and SFileFreeFileInfo + +typedef enum _SFileInfoClass +{ + // Info classes for archives + SFileMpqFileName, // Name of the archive file (TCHAR []) + SFileMpqStreamBitmap, // Array of bits, each bit means availability of one block (BYTE []) + SFileMpqUserDataOffset, // Offset of the user data header (ULONGLONG) + SFileMpqUserDataHeader, // Raw (unfixed) user data header (TMPQUserData) + SFileMpqUserData, // MPQ USer data, without the header (BYTE []) + SFileMpqHeaderOffset, // Offset of the MPQ header (ULONGLONG) + SFileMpqHeaderSize, // Fixed size of the MPQ header + SFileMpqHeader, // Raw (unfixed) archive header (TMPQHeader) + SFileMpqHetTableOffset, // Offset of the HET table, relative to MPQ header (ULONGLONG) + SFileMpqHetTableSize, // Compressed size of the HET table (ULONGLONG) + SFileMpqHetHeader, // HET table header (TMPQHetHeader) + SFileMpqHetTable, // HET table as pointer. Must be freed using SFileFreeFileInfo + SFileMpqBetTableOffset, // Offset of the BET table, relative to MPQ header (ULONGLONG) + SFileMpqBetTableSize, // Compressed size of the BET table (ULONGLONG) + SFileMpqBetHeader, // BET table header, followed by the flags (TMPQBetHeader + DWORD[]) + SFileMpqBetTable, // BET table as pointer. Must be freed using SFileFreeFileInfo + SFileMpqHashTableOffset, // Hash table offset, relative to MPQ header (ULONGLONG) + SFileMpqHashTableSize64, // Compressed size of the hash table (ULONGLONG) + SFileMpqHashTableSize, // Size of the hash table, in entries (DWORD) + SFileMpqHashTable, // Raw (unfixed) hash table (TMPQBlock []) + SFileMpqBlockTableOffset, // Block table offset, relative to MPQ header (ULONGLONG) + SFileMpqBlockTableSize64, // Compressed size of the block table (ULONGLONG) + SFileMpqBlockTableSize, // Size of the block table, in entries (DWORD) + SFileMpqBlockTable, // Raw (unfixed) block table (TMPQBlock []) + SFileMpqHiBlockTableOffset, // Hi-block table offset, relative to MPQ header (ULONGLONG) + SFileMpqHiBlockTableSize64, // Compressed size of the hi-block table (ULONGLONG) + SFileMpqHiBlockTable, // The hi-block table (USHORT []) + SFileMpqSignatures, // Signatures present in the MPQ (DWORD) + SFileMpqStrongSignatureOffset, // Byte offset of the strong signature, relative to begin of the file (ULONGLONG) + SFileMpqStrongSignatureSize, // Size of the strong signature (DWORD) + SFileMpqStrongSignature, // The strong signature (BYTE []) + SFileMpqArchiveSize64, // Archive size from the header (ULONGLONG) + SFileMpqArchiveSize, // Archive size from the header (DWORD) + SFileMpqMaxFileCount, // Max number of files in the archive (DWORD) + SFileMpqFileTableSize, // Number of entries in the file table (DWORD) + SFileMpqSectorSize, // Sector size (DWORD) + SFileMpqNumberOfFiles, // Number of files (DWORD) + SFileMpqRawChunkSize, // Size of the raw data chunk for MD5 + SFileMpqStreamFlags, // Stream flags (DWORD) + SFileMpqFlags, // Nonzero if the MPQ is read only (DWORD) + + // Info classes for files + SFileInfoPatchChain, // Chain of patches where the file is (TCHAR []) + SFileInfoFileEntry, // The file entry for the file (TFileEntry) + SFileInfoHashEntry, // Hash table entry for the file (TMPQHash) + SFileInfoHashIndex, // Index of the hash table entry (DWORD) + SFileInfoNameHash1, // The first name hash in the hash table (DWORD) + SFileInfoNameHash2, // The second name hash in the hash table (DWORD) + SFileInfoNameHash3, // 64-bit file name hash for the HET/BET tables (ULONGLONG) + SFileInfoLocale, // File locale (DWORD) + SFileInfoFileIndex, // Block index (DWORD) + SFileInfoByteOffset, // File position in the archive (ULONGLONG) + SFileInfoFileTime, // File time (ULONGLONG) + SFileInfoFileSize, // Size of the file (DWORD) + SFileInfoCompressedSize, // Compressed file size (DWORD) + SFileInfoFlags, // File flags from (DWORD) + SFileInfoEncryptionKey, // File encryption key + SFileInfoEncryptionKeyRaw, // Unfixed value of the file key + SFileInfoCRC32, // CRC32 of the file +} SFileInfoClass; + +//----------------------------------------------------------------------------- +// Callback functions + +// Values for compact callback +#define CCB_CHECKING_FILES 1 // Checking archive (dwParam1 = current, dwParam2 = total) +#define CCB_CHECKING_HASH_TABLE 2 // Checking hash table (dwParam1 = current, dwParam2 = total) +#define CCB_COPYING_NON_MPQ_DATA 3 // Copying non-MPQ data: No params used +#define CCB_COMPACTING_FILES 4 // Compacting archive (dwParam1 = current, dwParam2 = total) +#define CCB_CLOSING_ARCHIVE 5 // Closing archive: No params used + +typedef void (WINAPI * SFILE_DOWNLOAD_CALLBACK)(void * pvUserData, ULONGLONG ByteOffset, DWORD dwTotalBytes); +typedef void (WINAPI * SFILE_ADDFILE_CALLBACK)(void * pvUserData, DWORD dwBytesWritten, DWORD dwTotalBytes, bool bFinalCall); +typedef void (WINAPI * SFILE_COMPACT_CALLBACK)(void * pvUserData, DWORD dwWorkType, ULONGLONG BytesProcessed, ULONGLONG TotalBytes); + +typedef struct TFileStream TFileStream; + +//----------------------------------------------------------------------------- +// Structure for bit arrays used for HET and BET tables + +typedef struct _TBitArray +{ + DWORD NumberOfBytes; // Total number of bytes in "Elements" + DWORD NumberOfBits; // Total number of bits that are available + BYTE Elements[1]; // Array of elements (variable length) +} TBitArray; + +void GetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); +void SetBits(TBitArray * array, unsigned int nBitPosition, unsigned int nBitLength, void * pvBuffer, int nResultSize); + +//----------------------------------------------------------------------------- +// Structures related to MPQ format +// +// Note: All structures in this header file are supposed to remain private +// to StormLib. The structures may (and will) change over time, as the MPQ +// file format evolves. Programmers directly using these structures need to +// be aware of this. And the last, but not least, NEVER do any modifications +// to those structures directly, always use SFile* functions. +// + +#define MPQ_HEADER_SIZE_V1 0x20 +#define MPQ_HEADER_SIZE_V2 0x2C +#define MPQ_HEADER_SIZE_V3 0x44 +#define MPQ_HEADER_SIZE_V4 0xD0 +#define MPQ_HEADER_DWORDS (MPQ_HEADER_SIZE_V4 / 0x04) + +typedef struct _TMPQUserData +{ + // The ID_MPQ_USERDATA ('MPQ\x1B') signature + DWORD dwID; + + // Maximum size of the user data + DWORD cbUserDataSize; + + // Offset of the MPQ header, relative to the begin of this header + DWORD dwHeaderOffs; + + // Appears to be size of user data header (Starcraft II maps) + DWORD cbUserDataHeader; +} TMPQUserData; + +// MPQ file header +// +// We have to make sure that the header is packed OK. +// Reason: A 64-bit integer at the beginning of 3.0 part, +// which is offset 0x2C +#pragma pack(push, 1) +typedef struct _TMPQHeader +{ + // The ID_MPQ ('MPQ\x1A') signature + DWORD dwID; + + // Size of the archive header + DWORD dwHeaderSize; + + // 32-bit size of MPQ archive + // This field is deprecated in the Burning Crusade MoPaQ format, and the size of the archive + // is calculated as the size from the beginning of the archive to the end of the hash table, + // block table, or hi-block table (whichever is largest). + DWORD dwArchiveSize; + + // 0 = Format 1 (up to The Burning Crusade) + // 1 = Format 2 (The Burning Crusade and newer) + // 2 = Format 3 (WoW - Cataclysm beta or newer) + // 3 = Format 4 (WoW - Cataclysm beta or newer) + USHORT wFormatVersion; + + // Power of two exponent specifying the number of 512-byte disk sectors in each file sector + // in the archive. The size of each file sector in the archive is 512 * 2 ^ wSectorSize. + USHORT wSectorSize; + + // Offset to the beginning of the hash table, relative to the beginning of the archive. + DWORD dwHashTablePos; + + // Offset to the beginning of the block table, relative to the beginning of the archive. + DWORD dwBlockTablePos; + + // Number of entries in the hash table. Must be a power of two, and must be less than 2^16 for + // the original MoPaQ format, or less than 2^20 for the Burning Crusade format. + DWORD dwHashTableSize; + + // Number of entries in the block table + DWORD dwBlockTableSize; + + //-- MPQ HEADER v 2 ------------------------------------------- + + // Offset to the beginning of array of 16-bit high parts of file offsets. + ULONGLONG HiBlockTablePos64; + + // High 16 bits of the hash table offset for large archives. + USHORT wHashTablePosHi; + + // High 16 bits of the block table offset for large archives. + USHORT wBlockTablePosHi; + + //-- MPQ HEADER v 3 ------------------------------------------- + + // 64-bit version of the archive size + ULONGLONG ArchiveSize64; + + // 64-bit position of the BET table + ULONGLONG BetTablePos64; + + // 64-bit position of the HET table + ULONGLONG HetTablePos64; + + //-- MPQ HEADER v 4 ------------------------------------------- + + // Compressed size of the hash table + ULONGLONG HashTableSize64; + + // Compressed size of the block table + ULONGLONG BlockTableSize64; + + // Compressed size of the hi-block table + ULONGLONG HiBlockTableSize64; + + // Compressed size of the HET block + ULONGLONG HetTableSize64; + + // Compressed size of the BET block + ULONGLONG BetTableSize64; + + // Size of raw data chunk to calculate MD5. + // MD5 of each data chunk follows the raw file data. + DWORD dwRawChunkSize; + + // MD5 of MPQ tables + unsigned char MD5_BlockTable[MD5_DIGEST_SIZE]; // MD5 of the block table before decryption + unsigned char MD5_HashTable[MD5_DIGEST_SIZE]; // MD5 of the hash table before decryption + unsigned char MD5_HiBlockTable[MD5_DIGEST_SIZE]; // MD5 of the hi-block table + unsigned char MD5_BetTable[MD5_DIGEST_SIZE]; // MD5 of the BET table before decryption + unsigned char MD5_HetTable[MD5_DIGEST_SIZE]; // MD5 of the HET table before decryption + unsigned char MD5_MpqHeader[MD5_DIGEST_SIZE]; // MD5 of the MPQ header from signature to (including) MD5_HetTable +} TMPQHeader; +#pragma pack(pop) + +// Hash table entry. All files in the archive are searched by their hashes. +typedef struct _TMPQHash +{ + // The hash of the file path, using method A. + DWORD dwName1; + + // The hash of the file path, using method B. + DWORD dwName2; + +#ifdef PLATFORM_LITTLE_ENDIAN + + // The language of the file. This is a Windows LANGID data type, and uses the same values. + // 0 indicates the default language (American English), or that the file is language-neutral. + USHORT lcLocale; + + // The platform the file is used for. 0 indicates the default platform. + // No other values have been observed. + BYTE Platform; + BYTE Reserved; + +#else + + BYTE Platform; + BYTE Reserved; + USHORT lcLocale; + +#endif + + // If the hash table entry is valid, this is the index into the block table of the file. + // Otherwise, one of the following two values: + // - FFFFFFFFh: Hash table entry is empty, and has always been empty. + // Terminates searches for a given file. + // - FFFFFFFEh: Hash table entry is empty, but was valid at some point (a deleted file). + // Does not terminate searches for a given file. + DWORD dwBlockIndex; +} TMPQHash; + +// File description block contains informations about the file +typedef struct _TMPQBlock +{ + // Offset of the beginning of the file, relative to the beginning of the archive. + DWORD dwFilePos; + + // Compressed file size + DWORD dwCSize; + + // Only valid if the block is a file; otherwise meaningless, and should be 0. + // If the file is compressed, this is the size of the uncompressed file data. + DWORD dwFSize; + + // Flags for the file. See MPQ_FILE_XXXX constants + DWORD dwFlags; +} TMPQBlock; + +// Patch file information, preceding the sector offset table +typedef struct _TPatchInfo +{ + DWORD dwLength; // Length of patch info header, in bytes + DWORD dwFlags; // Flags. 0x80000000 = MD5 (?) + DWORD dwDataSize; // Uncompressed size of the patch file + BYTE md5[0x10]; // MD5 of the entire patch file after decompression + + // Followed by the sector table (variable length) +} TPatchInfo; + +// This is the combined file entry for maintaining file list in the MPQ. +// This structure is combined from block table, hi-block table, +// (attributes) file and from (listfile). +typedef struct _TFileEntry +{ + ULONGLONG FileNameHash; // Jenkins hash of the file name. Only used when the MPQ has BET table. + ULONGLONG ByteOffset; // Position of the file content in the MPQ, relative to the MPQ header + ULONGLONG FileTime; // FileTime from the (attributes) file. 0 if not present. + DWORD dwFileSize; // Decompressed size of the file + DWORD dwCmpSize; // Compressed size of the file (i.e., size of the file data in the MPQ) + DWORD dwFlags; // File flags (from block table) + DWORD dwCrc32; // CRC32 from (attributes) file. 0 if not present. + BYTE md5[MD5_DIGEST_SIZE]; // File MD5 from the (attributes) file. 0 if not present. + char * szFileName; // File name. NULL if not known. +} TFileEntry; + +// Common header for HET and BET tables +typedef struct _TMPQExtHeader +{ + DWORD dwSignature; // 'HET\x1A' or 'BET\x1A' + DWORD dwVersion; // Version. Seems to be always 1 + DWORD dwDataSize; // Size of the contained table + + // Followed by the table header + // Followed by the table data + +} TMPQExtHeader; + +// Structure for HET table header +typedef struct _TMPQHetHeader +{ + TMPQExtHeader ExtHdr; + + DWORD dwTableSize; // Size of the entire HET table, including HET_TABLE_HEADER (in bytes) + DWORD dwEntryCount; // Number of occupied entries in the HET table + DWORD dwTotalCount; // Total number of entries in the HET table + DWORD dwNameHashBitSize; // Size of the name hash entry (in bits) + DWORD dwIndexSizeTotal; // Total size of file index (in bits) + DWORD dwIndexSizeExtra; // Extra bits in the file index + DWORD dwIndexSize; // Effective size of the file index (in bits) + DWORD dwIndexTableSize; // Size of the block index subtable (in bytes) + +} TMPQHetHeader; + +// Structure for BET table header +typedef struct _TMPQBetHeader +{ + TMPQExtHeader ExtHdr; + + DWORD dwTableSize; // Size of the entire BET table, including the header (in bytes) + DWORD dwEntryCount; // Number of entries in the BET table. Must match HET_TABLE_HEADER::dwEntryCount + DWORD dwUnknown08; + DWORD dwTableEntrySize; // Size of one table entry (in bits) + DWORD dwBitIndex_FilePos; // Bit index of the file position (within the entry record) + DWORD dwBitIndex_FileSize; // Bit index of the file size (within the entry record) + DWORD dwBitIndex_CmpSize; // Bit index of the compressed size (within the entry record) + DWORD dwBitIndex_FlagIndex; // Bit index of the flag index (within the entry record) + DWORD dwBitIndex_Unknown; // Bit index of the ??? (within the entry record) + DWORD dwBitCount_FilePos; // Bit size of file position (in the entry record) + DWORD dwBitCount_FileSize; // Bit size of file size (in the entry record) + DWORD dwBitCount_CmpSize; // Bit size of compressed file size (in the entry record) + DWORD dwBitCount_FlagIndex; // Bit size of flags index (in the entry record) + DWORD dwBitCount_Unknown; // Bit size of ??? (in the entry record) + DWORD dwBitTotal_NameHash2; // Total bit size of the NameHash2 + DWORD dwBitExtra_NameHash2; // Extra bits in the NameHash2 + DWORD dwBitCount_NameHash2; // Effective size of NameHash2 (in bits) + DWORD dwNameHashArraySize; // Size of NameHash2 table, in bytes + DWORD dwFlagCount; // Number of flags in the following array + +} TMPQBetHeader; + +// Structure for parsed HET table +typedef struct _TMPQHetTable +{ + TBitArray * pBetIndexes; // Bit array of FileIndex values + LPBYTE pNameHashes; // Array of NameHash1 values (NameHash1 = upper 8 bits of FileName hashe) + ULONGLONG AndMask64; // AND mask used for calculating file name hash + ULONGLONG OrMask64; // OR mask used for setting the highest bit of the file name hash + + DWORD dwEntryCount; // Number of occupied entries in the HET table + DWORD dwTotalCount; // Number of entries in both NameHash and FileIndex table + DWORD dwNameHashBitSize; // Size of the name hash entry (in bits) + DWORD dwIndexSizeTotal; // Total size of one entry in pBetIndexes (in bits) + DWORD dwIndexSizeExtra; // Extra bits in the entry in pBetIndexes + DWORD dwIndexSize; // Effective size of one entry in pBetIndexes (in bits) +} TMPQHetTable; + +// Structure for parsed BET table +typedef struct _TMPQBetTable +{ + TBitArray * pNameHashes; // Array of NameHash2 entries (lower 24 bits of FileName hash) + TBitArray * pFileTable; // Bit-based file table + LPDWORD pFileFlags; // Array of file flags + + DWORD dwTableEntrySize; // Size of one table entry, in bits + DWORD dwBitIndex_FilePos; // Bit index of the file position in the table entry + DWORD dwBitIndex_FileSize; // Bit index of the file size in the table entry + DWORD dwBitIndex_CmpSize; // Bit index of the compressed size in the table entry + DWORD dwBitIndex_FlagIndex; // Bit index of the flag index in the table entry + DWORD dwBitIndex_Unknown; // Bit index of ??? in the table entry + DWORD dwBitCount_FilePos; // Size of file offset (in bits) within table entry + DWORD dwBitCount_FileSize; // Size of file size (in bits) within table entry + DWORD dwBitCount_CmpSize; // Size of compressed file size (in bits) within table entry + DWORD dwBitCount_FlagIndex; // Size of flag index (in bits) within table entry + DWORD dwBitCount_Unknown; // Size of ??? (in bits) within table entry + DWORD dwBitTotal_NameHash2; // Total size of the NameHash2 + DWORD dwBitExtra_NameHash2; // Extra bits in the NameHash2 + DWORD dwBitCount_NameHash2; // Effective size of the NameHash2 + DWORD dwEntryCount; // Number of entries + DWORD dwFlagCount; // Number of file flags in pFileFlags +} TMPQBetTable; + +// Structure for patch prefix +typedef struct _TMPQNamePrefix +{ + size_t nLength; // Length of this patch prefix. Can be 0 + char szPatchPrefix[1]; // Patch name prefix (variable length). If not empty, it always starts with backslash. +} TMPQNamePrefix; + +// Structure for name cache +typedef struct _TMPQNameCache +{ + DWORD FirstNameOffset; // Offset of the first name in the name list (in bytes) + DWORD FreeSpaceOffset; // Offset of the first free byte in the name cache (in bytes) + DWORD TotalCacheSize; // Size, in bytes, of the cache. Includes wildcard + DWORD SearchOffset; // Used by SListFileFindFirstFile + + // Followed by search mask (ASCIIZ, '\0' if none) + // Followed by name cache (ANSI multistring) + +} TMPQNameCache; + +// Archive handle structure +typedef struct _TMPQArchive +{ + TFileStream * pStream; // Open stream for the MPQ + + ULONGLONG UserDataPos; // Position of user data (relative to the begin of the file) + ULONGLONG MpqPos; // MPQ header offset (relative to the begin of the file) + ULONGLONG FileSize; // Size of the file at the moment of file open + + struct _TMPQArchive * haPatch; // Pointer to patch archive, if any + struct _TMPQArchive * haBase; // Pointer to base ("previous version") archive, if any + TMPQNamePrefix * pPatchPrefix; // Patch prefix to precede names of patch files + + TMPQUserData * pUserData; // MPQ user data (NULL if not present in the file) + TMPQHeader * pHeader; // MPQ file header + TMPQHash * pHashTable; // Hash table + TMPQHetTable * pHetTable; // HET table + TFileEntry * pFileTable; // File table + HASH_STRING pfnHashString; // Hashing function that will convert the file name into hash + + TMPQUserData UserData; // MPQ user data. Valid only when ID_MPQ_USERDATA has been found + DWORD HeaderData[MPQ_HEADER_DWORDS]; // Storage for MPQ header + + DWORD dwHETBlockSize; + DWORD dwBETBlockSize; + DWORD dwMaxFileCount; // Maximum number of files in the MPQ. Also total size of the file table. + DWORD dwFileTableSize; // Current size of the file table, e.g. index of the entry past the last occupied one + DWORD dwReservedFiles; // Number of entries reserved for internal MPQ files (listfile, attributes) + DWORD dwSectorSize; // Default size of one file sector + DWORD dwFileFlags1; // Flags for (listfile) + DWORD dwFileFlags2; // Flags for (attributes) + DWORD dwFileFlags3; // Flags for (signature) + DWORD dwAttrFlags; // Flags for the (attributes) file, see MPQ_ATTRIBUTE_XXX + DWORD dwFlags; // See MPQ_FLAG_XXXXX + DWORD dwSubType; // See MPQ_SUBTYPE_XXX + + SFILE_ADDFILE_CALLBACK pfnAddFileCB; // Callback function for adding files + void * pvAddFileUserData; // User data thats passed to the callback + + SFILE_COMPACT_CALLBACK pfnCompactCB; // Callback function for compacting the archive + ULONGLONG CompactBytesProcessed; // Amount of bytes that have been processed during a particular compact call + ULONGLONG CompactTotalBytes; // Total amount of bytes to be compacted + void * pvCompactUserData; // User data thats passed to the callback +} TMPQArchive; + +// File handle structure +typedef struct _TMPQFile +{ + TFileStream * pStream; // File stream. Only used on local files + TMPQArchive * ha; // Archive handle + TMPQHash * pHashEntry; // Pointer to hash table entry, if the file was open using hash table + TFileEntry * pFileEntry; // File entry for the file + ULONGLONG RawFilePos; // Offset in MPQ archive (relative to file begin) + ULONGLONG MpqFilePos; // Offset in MPQ archive (relative to MPQ header) + DWORD dwHashIndex; // Hash table index (0xFFFFFFFF if not used) + DWORD dwFileKey; // Decryption key + DWORD dwFilePos; // Current file position + DWORD dwMagic; // 'FILE' + + struct _TMPQFile * hfPatch; // Pointer to opened patch file + + TPatchInfo * pPatchInfo; // Patch info block, preceding the sector table + LPDWORD SectorOffsets; // Position of each file sector, relative to the begin of the file. Only for compressed files. + LPDWORD SectorChksums; // Array of sector checksums (either ADLER32 or MD5) values for each file sector + LPBYTE pbFileData; // Data of the file (single unit files, patched files) + DWORD cbFileData; // Size of file data + DWORD dwCompression0; // Compression that will be used on the first file sector + DWORD dwSectorCount; // Number of sectors in the file + DWORD dwPatchedFileSize; // Size of patched file. Used when saving patch file to the MPQ + DWORD dwDataSize; // Size of data in the file (on patch files, this differs from file size in block table entry) + + LPBYTE pbFileSector; // Last loaded file sector. For single unit files, entire file content + DWORD dwSectorOffs; // File position of currently loaded file sector + DWORD dwSectorSize; // Size of the file sector. For single unit files, this is equal to the file size + + unsigned char hctx[HASH_STATE_SIZE]; // Hash state for MD5. Used when saving file to MPQ + DWORD dwCrc32; // CRC32 value, used when saving file to MPQ + + int nAddFileError; // Result of the "Add File" operations + + bool bLoadedSectorCRCs; // If true, we already tried to load sector CRCs + bool bCheckSectorCRCs; // If true, then SFileReadFile will check sector CRCs when reading the file + bool bIsWriteHandle; // If true, this handle has been created by SFileCreateFile +} TMPQFile; + +// Structure for SFileFindFirstFile and SFileFindNextFile +typedef struct _SFILE_FIND_DATA +{ + char cFileName[MAX_PATH]; // Full name of the found file + char * szPlainName; // Plain name of the found file + DWORD dwHashIndex; // Hash table index for the file (HAH_ENTRY_FREE if no hash table) + DWORD dwBlockIndex; // Block table index for the file + DWORD dwFileSize; // File size in bytes + DWORD dwFileFlags; // MPQ file flags + DWORD dwCompSize; // Compressed file size + DWORD dwFileTimeLo; // Low 32-bits of the file time (0 if not present) + DWORD dwFileTimeHi; // High 32-bits of the file time (0 if not present) + LCID lcLocale; // Locale version + +} SFILE_FIND_DATA, *PSFILE_FIND_DATA; + +typedef struct _SFILE_CREATE_MPQ +{ + DWORD cbSize; // Size of this structure, in bytes + DWORD dwMpqVersion; // Version of the MPQ to be created + void *pvUserData; // Reserved, must be NULL + DWORD cbUserData; // Reserved, must be 0 + DWORD dwStreamFlags; // Stream flags for creating the MPQ + DWORD dwFileFlags1; // File flags for (listfile). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwFileFlags2; // File flags for (attributes). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwFileFlags3; // File flags for (signature). Use MPQ_FILE_DEFAULT_INTERNAL to set default flags + DWORD dwAttrFlags; // Flags for the (attributes) file. If 0, no attributes will be created + DWORD dwSectorSize; // Sector size for compressed files + DWORD dwRawChunkSize; // Size of raw data chunk + DWORD dwMaxFileCount; // File limit for the MPQ + +} SFILE_CREATE_MPQ, *PSFILE_CREATE_MPQ; + +//----------------------------------------------------------------------------- +// Stream support - functions + +// Structure used by FileStream_GetBitmap +typedef struct _TStreamBitmap +{ + ULONGLONG StreamSize; // Size of the stream, in bytes + DWORD BitmapSize; // Size of the block map, in bytes + DWORD BlockCount; // Number of blocks in the stream + DWORD BlockSize; // Size of one block + DWORD IsComplete; // Nonzero if the file is complete + + // Followed by the BYTE array, each bit means availability of one block + +} TStreamBitmap; + +// UNICODE versions of the file access functions +TFileStream * FileStream_CreateFile(const TCHAR * szFileName, DWORD dwStreamFlags); +TFileStream * FileStream_OpenFile(const TCHAR * szFileName, DWORD dwStreamFlags); +const TCHAR * FileStream_GetFileName(TFileStream * pStream); +size_t FileStream_Prefix(const TCHAR * szFileName, DWORD * pdwProvider); + +bool FileStream_SetCallback(TFileStream * pStream, SFILE_DOWNLOAD_CALLBACK pfnCallback, void * pvUserData); + +bool FileStream_GetBitmap(TFileStream * pStream, void * pvBitmap, DWORD cbBitmap, LPDWORD pcbLengthNeeded); +bool FileStream_Read(TFileStream * pStream, ULONGLONG * pByteOffset, void * pvBuffer, DWORD dwBytesToRead); +bool FileStream_Write(TFileStream * pStream, ULONGLONG * pByteOffset, const void * pvBuffer, DWORD dwBytesToWrite); +bool FileStream_SetSize(TFileStream * pStream, ULONGLONG NewFileSize); +bool FileStream_GetSize(TFileStream * pStream, ULONGLONG * pFileSize); +bool FileStream_GetPos(TFileStream * pStream, ULONGLONG * pByteOffset); +bool FileStream_GetTime(TFileStream * pStream, ULONGLONG * pFT); +bool FileStream_GetFlags(TFileStream * pStream, LPDWORD pdwStreamFlags); +bool FileStream_Replace(TFileStream * pStream, TFileStream * pNewStream); +void FileStream_Close(TFileStream * pStream); + +//----------------------------------------------------------------------------- +// Functions prototypes for Storm.dll + +// Typedefs for functions exported by Storm.dll +typedef LCID (WINAPI * SFILESETLOCALE)(LCID); +typedef bool (WINAPI * SFILEOPENARCHIVE)(const char *, DWORD, DWORD, HANDLE *); +typedef bool (WINAPI * SFILECLOSEARCHIVE)(HANDLE); +typedef bool (WINAPI * SFILEOPENFILEEX)(HANDLE, const char *, DWORD, HANDLE *); +typedef bool (WINAPI * SFILECLOSEFILE)(HANDLE); +typedef DWORD (WINAPI * SFILEGETFILESIZE)(HANDLE, LPDWORD); +typedef DWORD (WINAPI * SFILESETFILEPOINTER)(HANDLE, LONG, LONG *, DWORD); +typedef bool (WINAPI * SFILEREADFILE)(HANDLE, void *, DWORD, LPDWORD, LPOVERLAPPED); + +//----------------------------------------------------------------------------- +// Functions for manipulation with StormLib global flags + +LCID WINAPI SFileGetLocale(); +LCID WINAPI SFileSetLocale(LCID lcNewLocale); + +//----------------------------------------------------------------------------- +// Functions for archive manipulation + +bool WINAPI SFileOpenArchive(const TCHAR * szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE * phMpq); +bool WINAPI SFileCreateArchive(const TCHAR * szMpqName, DWORD dwCreateFlags, DWORD dwMaxFileCount, HANDLE * phMpq); +bool WINAPI SFileCreateArchive2(const TCHAR * szMpqName, PSFILE_CREATE_MPQ pCreateInfo, HANDLE * phMpq); + +bool WINAPI SFileSetDownloadCallback(HANDLE hMpq, SFILE_DOWNLOAD_CALLBACK DownloadCB, void * pvUserData); +bool WINAPI SFileFlushArchive(HANDLE hMpq); +bool WINAPI SFileCloseArchive(HANDLE hMpq); + +// Adds another listfile into MPQ. The currently added listfile(s) remain, +// so you can use this API to combining more listfiles. +// Note that this function is internally called by SFileFindFirstFile +int WINAPI SFileAddListFile(HANDLE hMpq, const TCHAR * szListFile); + +// Archive compacting +bool WINAPI SFileSetCompactCallback(HANDLE hMpq, SFILE_COMPACT_CALLBACK CompactCB, void * pvUserData); +bool WINAPI SFileCompactArchive(HANDLE hMpq, const TCHAR * szListFile, bool bReserved); + +// Changing the maximum file count +DWORD WINAPI SFileGetMaxFileCount(HANDLE hMpq); +bool WINAPI SFileSetMaxFileCount(HANDLE hMpq, DWORD dwMaxFileCount); + +// Changing (attributes) file +DWORD WINAPI SFileGetAttributes(HANDLE hMpq); +bool WINAPI SFileSetAttributes(HANDLE hMpq, DWORD dwFlags); +bool WINAPI SFileUpdateFileAttributes(HANDLE hMpq, const char * szFileName); + +//----------------------------------------------------------------------------- +// Functions for manipulation with patch archives + +bool WINAPI SFileOpenPatchArchive(HANDLE hMpq, const TCHAR * szPatchMpqName, const char * szPatchPathPrefix, DWORD dwFlags); +bool WINAPI SFileIsPatchedArchive(HANDLE hMpq); + +//----------------------------------------------------------------------------- +// Functions for file manipulation + +// Reading from MPQ file +bool WINAPI SFileHasFile(HANDLE hMpq, const char * szFileName); +bool WINAPI SFileOpenFileEx(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope, HANDLE * phFile); +DWORD WINAPI SFileGetFileSize(HANDLE hFile, LPDWORD pdwFileSizeHigh); +DWORD WINAPI SFileSetFilePointer(HANDLE hFile, LONG lFilePos, LONG * plFilePosHigh, DWORD dwMoveMethod); +bool WINAPI SFileReadFile(HANDLE hFile, void * lpBuffer, DWORD dwToRead, LPDWORD pdwRead, LPOVERLAPPED lpOverlapped); +bool WINAPI SFileCloseFile(HANDLE hFile); + +// Retrieving info about a file in the archive +bool WINAPI SFileGetFileInfo(HANDLE hMpqOrFile, SFileInfoClass InfoClass, void * pvFileInfo, DWORD cbFileInfo, LPDWORD pcbLengthNeeded); +bool WINAPI SFileGetFileName(HANDLE hFile, char * szFileName); +bool WINAPI SFileFreeFileInfo(void * pvFileInfo, SFileInfoClass InfoClass); + +// High-level extract function +bool WINAPI SFileExtractFile(HANDLE hMpq, const char * szToExtract, const TCHAR * szExtracted, DWORD dwSearchScope); + +//----------------------------------------------------------------------------- +// Functions for file and archive verification + +// Generates file CRC32 +bool WINAPI SFileGetFileChecksums(HANDLE hMpq, const char * szFileName, LPDWORD pdwCrc32, char * pMD5); + +// Verifies file against its checksums stored in (attributes) attributes (depending on dwFlags). +// For dwFlags, use one or more of MPQ_ATTRIBUTE_MD5 +DWORD WINAPI SFileVerifyFile(HANDLE hMpq, const char * szFileName, DWORD dwFlags); + +// Verifies raw data of the archive. Only works for MPQs version 4 or newer +int WINAPI SFileVerifyRawData(HANDLE hMpq, DWORD dwWhatToVerify, const char * szFileName); + +// Verifies the signature, if present +bool WINAPI SFileSignArchive(HANDLE hMpq, DWORD dwSignatureType); +DWORD WINAPI SFileVerifyArchive(HANDLE hMpq); + +//----------------------------------------------------------------------------- +// Functions for file searching + +HANDLE WINAPI SFileFindFirstFile(HANDLE hMpq, const char * szMask, SFILE_FIND_DATA * lpFindFileData, const TCHAR * szListFile); +bool WINAPI SFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SFileFindClose(HANDLE hFind); + +HANDLE WINAPI SListFileFindFirstFile(HANDLE hMpq, const TCHAR * szListFile, const char * szMask, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SListFileFindNextFile(HANDLE hFind, SFILE_FIND_DATA * lpFindFileData); +bool WINAPI SListFileFindClose(HANDLE hFind); + +// Locale support +int WINAPI SFileEnumLocales(HANDLE hMpq, const char * szFileName, LCID * plcLocales, LPDWORD pdwMaxLocales, DWORD dwSearchScope); + +//----------------------------------------------------------------------------- +// Support for adding files to the MPQ + +bool WINAPI SFileCreateFile(HANDLE hMpq, const char * szArchivedName, ULONGLONG FileTime, DWORD dwFileSize, LCID lcLocale, DWORD dwFlags, HANDLE * phFile); +bool WINAPI SFileWriteFile(HANDLE hFile, const void * pvData, DWORD dwSize, DWORD dwCompression); +bool WINAPI SFileFinishFile(HANDLE hFile); + +bool WINAPI SFileAddFileEx(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwCompression, DWORD dwCompressionNext = MPQ_COMPRESSION_NEXT_SAME); +bool WINAPI SFileAddFile(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags); +bool WINAPI SFileAddWave(HANDLE hMpq, const TCHAR * szFileName, const char * szArchivedName, DWORD dwFlags, DWORD dwQuality); +bool WINAPI SFileRemoveFile(HANDLE hMpq, const char * szFileName, DWORD dwSearchScope); +bool WINAPI SFileRenameFile(HANDLE hMpq, const char * szOldFileName, const char * szNewFileName); +bool WINAPI SFileSetFileLocale(HANDLE hFile, LCID lcNewLocale); +bool WINAPI SFileSetDataCompression(DWORD DataCompression); + +bool WINAPI SFileSetAddFileCallback(HANDLE hMpq, SFILE_ADDFILE_CALLBACK AddFileCB, void * pvUserData); + +//----------------------------------------------------------------------------- +// Compression and decompression + +int WINAPI SCompImplode (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompExplode (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompCompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer, unsigned uCompressionMask, int nCmpType, int nCmpLevel); +int WINAPI SCompDecompress (void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int WINAPI SCompDecompress2(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); + +//----------------------------------------------------------------------------- +// Non-Windows support for SetLastError/GetLastError + +#ifndef PLATFORM_WINDOWS + +void SetLastError(DWORD dwErrCode); +DWORD GetLastError(); + +#endif + +//----------------------------------------------------------------------------- +// Functions from Storm.dll. They use slightly different names for keeping +// possibility to use them together with StormLib (StormXXX instead of SFileXXX) + +#ifdef __LINK_STORM_DLL__ + #define STORM_ALTERNATE_NAMES // Force storm_dll.h to use alternate fnc names + #include "..\storm_dll\storm_dll.h" +#endif // __LINK_STORM_DLL__ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __STORMLIB_H__ diff --git a/dep/StormLib/src/StormPort.h b/dep/StormLib/src/StormPort.h new file mode 100644 index 000000000..34151edf4 --- /dev/null +++ b/dep/StormLib/src/StormPort.h @@ -0,0 +1,333 @@ +/*****************************************************************************/ +/* StormPort.h Copyright (c) Marko Friedemann 2001 */ +/*---------------------------------------------------------------------------*/ +/* Portability module for the StormLib library. Contains a wrapper symbols */ +/* to make the compilation under Linux work */ +/* */ +/* Author: Marko Friedemann */ +/* Created at: Mon Jan 29 18:26:01 CEST 2001 */ +/* Computer: whiplash.flachland-chemnitz.de */ +/* System: Linux 2.4.0 on i686 */ +/* */ +/* Author: Sam Wilkins */ +/* System: Mac OS X and port to big endian processor */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 29.01.01 1.00 Mar Created */ +/* 24.03.03 1.01 Lad Some cosmetic changes */ +/* 12.11.03 1.02 Dan Macintosh compatibility */ +/* 24.07.04 1.03 Sam Mac OS X compatibility */ +/* 22.11.06 1.04 Sam Mac OS X compatibility (for StormLib 6.0) */ +/* 31.12.06 1.05 XPinguin Full GNU/Linux compatibility */ +/* 17.10.12 1.05 Lad Moved error codes so they don't overlap with errno.h */ +/*****************************************************************************/ + +#ifndef __STORMPORT_H__ +#define __STORMPORT_H__ + +#ifndef __cplusplus + #define bool char + #define true 1 + #define false 0 +#endif + +//----------------------------------------------------------------------------- +// Defines for Windows + +#if !defined(PLATFORM_DEFINED) && defined(_WIN32) + + // In MSVC 8.0, there are some functions declared as deprecated. + #if _MSC_VER >= 1400 + #define _CRT_SECURE_NO_DEPRECATE + #define _CRT_NON_CONFORMING_SWPRINTFS + #endif + + #include + #include + #include + #include + #include + #include + #define PLATFORM_LITTLE_ENDIAN + + #ifdef _WIN64 + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + #define PLATFORM_WINDOWS + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Defines for Mac + +#if !defined(PLATFORM_DEFINED) && defined(__APPLE__) // Mac BSD API + + // Macintosh + #include + #include + #include + #include + #include + #include + #include + + // Support for PowerPC on Max OS X + #if (__ppc__ == 1) || (__POWERPC__ == 1) || (_ARCH_PPC == 1) + #include + #include + #endif + + #define PKEXPORT + #define __SYS_ZLIB + #define __SYS_BZLIB + + #ifndef __BIG_ENDIAN__ + #define PLATFORM_LITTLE_ENDIAN + #endif + + #define PLATFORM_MAC + #define PLATFORM_DEFINED // The platform is known now + +#endif + +#if !defined(PLATFORM_DEFINED) && defined(__HAIKU__) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #ifndef __BIG_ENDIAN__ + #define PLATFORM_LITTLE_ENDIAN + #endif + + #define PLATFORM_HAIKU + #define PLATFORM_DEFINED // The platform is known now + +#endif + +//----------------------------------------------------------------------------- +// Assumption: we are not on Windows nor Macintosh, so this must be linux *grin* + +#if !defined(PLATFORM_DEFINED) + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #define PLATFORM_LITTLE_ENDIAN + #define PLATFORM_LINUX + # if defined (__FreeBSD__) + # define PLATFORM_FREEBSD + # endif + #define PLATFORM_DEFINED + +#endif + +//----------------------------------------------------------------------------- +// Definition of Windows-specific types for non-Windows platforms + +#ifndef PLATFORM_WINDOWS + #if __LP64__ + #define PLATFORM_64BIT + #else + #define PLATFORM_32BIT + #endif + + // Typedefs for ANSI C + typedef unsigned char BYTE; + typedef unsigned short USHORT; + typedef int LONG; + typedef unsigned int DWORD; + typedef unsigned long DWORD_PTR; + typedef long LONG_PTR; + typedef long INT_PTR; + typedef long long LONGLONG; + typedef unsigned long long ULONGLONG; + typedef void * HANDLE; + typedef void * LPOVERLAPPED; // Unsupported on Linux and Mac + typedef char TCHAR; + typedef unsigned int LCID; + typedef LONG * PLONG; + typedef DWORD * LPDWORD; + typedef BYTE * LPBYTE; + typedef const char * LPCTSTR; + typedef const char * LPCSTR; + typedef char * LPTSTR; + typedef char * LPSTR; + + #ifdef PLATFORM_32BIT + #define _LZMA_UINT32_IS_ULONG + #endif + + // Some Windows-specific defines + #ifndef MAX_PATH + #define MAX_PATH 1024 + #endif + + #ifndef _countof + #define _countof(x) (sizeof(x) / sizeof(x[0])) + #endif + + #define WINAPI + + #define FILE_BEGIN SEEK_SET + #define FILE_CURRENT SEEK_CUR + #define FILE_END SEEK_END + + #define _T(x) x + #define _tcslen strlen + #define _tcscpy strcpy + #define _tcscat strcat + #define _tcschr strchr + #define _tcsrchr strrchr + #define _tcsstr strstr + #define _tcsnicmp strncasecmp + #define _tprintf printf + #define _stprintf sprintf + #define _tremove remove + #define _tmain main + + #define _stricmp strcasecmp + #define _strnicmp strncasecmp + #define _tcsicmp strcasecmp + #define _tcsnicmp strncasecmp + +#endif // !PLATFORM_WINDOWS + +// 64-bit calls are supplied by "normal" calls on Mac +#if defined(PLATFORM_MAC) || defined(PLATFORM_HAIKU) || defined(PLATFORM_FREEBSD) + #define stat64 stat + #define fstat64 fstat + #define lseek64 lseek + #define ftruncate64 ftruncate + #define off64_t off_t + #define O_LARGEFILE 0 +#endif + +#if defined(PLATFORM_FREEBSD) + #define lstat64 lstat +#endif + +// Platform-specific error codes for UNIX-based platforms +#if defined(PLATFORM_MAC) || defined(PLATFORM_LINUX) || defined(PLATFORM_HAIKU) + #define ERROR_SUCCESS 0 + #define ERROR_FILE_NOT_FOUND ENOENT + #define ERROR_ACCESS_DENIED EPERM + #define ERROR_INVALID_HANDLE EBADF + #define ERROR_NOT_ENOUGH_MEMORY ENOMEM + #define ERROR_NOT_SUPPORTED ENOTSUP + #define ERROR_INVALID_PARAMETER EINVAL + #define ERROR_NEGATIVE_SEEK EINVAL + #define ERROR_DISK_FULL ENOSPC + #define ERROR_ALREADY_EXISTS EEXIST + #define ERROR_INSUFFICIENT_BUFFER ENOBUFS + #define ERROR_BAD_FORMAT 1000 // No such error code under Linux + #define ERROR_NO_MORE_FILES 1001 // No such error code under Linux + #define ERROR_HANDLE_EOF 1002 // No such error code under Linux + #define ERROR_CAN_NOT_COMPLETE 1003 // No such error code under Linux + #define ERROR_FILE_CORRUPT 1004 // No such error code under Linux +#endif + +//----------------------------------------------------------------------------- +// Swapping functions + +#ifdef PLATFORM_LITTLE_ENDIAN + #define BSWAP_INT16_UNSIGNED(a) (a) + #define BSWAP_INT16_SIGNED(a) (a) + #define BSWAP_INT32_UNSIGNED(a) (a) + #define BSWAP_INT32_SIGNED(a) (a) + #define BSWAP_INT64_SIGNED(a) (a) + #define BSWAP_INT64_UNSIGNED(a) (a) + #define BSWAP_ARRAY16_UNSIGNED(a,b) {} + #define BSWAP_ARRAY32_UNSIGNED(a,b) {} + #define BSWAP_ARRAY64_UNSIGNED(a,b) {} + #define BSWAP_PART_HEADER(a) {} + #define BSWAP_TMPQHEADER(a,b) {} + #define BSWAP_TMPKHEADER(a) {} +#else + +#ifdef __cplusplus + extern "C" { +#endif + int16_t SwapInt16(uint16_t); + uint16_t SwapUInt16(uint16_t); + int32_t SwapInt32(uint32_t); + uint32_t SwapUInt32(uint32_t); + int64_t SwapInt64(uint64_t); + uint64_t SwapUInt64(uint64_t); + void ConvertUInt16Buffer(void * ptr, size_t length); + void ConvertUInt32Buffer(void * ptr, size_t length); + void ConvertUInt64Buffer(void * ptr, size_t length); + void ConvertTMPQUserData(void *userData); + void ConvertTMPQHeader(void *header, uint16_t wPart); + void ConvertTMPKHeader(void *header); +#ifdef __cplusplus + } +#endif + #define BSWAP_INT16_SIGNED(a) SwapInt16((a)) + #define BSWAP_INT16_UNSIGNED(a) SwapUInt16((a)) + #define BSWAP_INT32_SIGNED(a) SwapInt32((a)) + #define BSWAP_INT32_UNSIGNED(a) SwapUInt32((a)) + #define BSWAP_INT64_SIGNED(a) SwapInt64((a)) + #define BSWAP_INT64_UNSIGNED(a) SwapUInt64((a)) + #define BSWAP_ARRAY16_UNSIGNED(a,b) ConvertUInt16Buffer((a),(b)) + #define BSWAP_ARRAY32_UNSIGNED(a,b) ConvertUInt32Buffer((a),(b)) + #define BSWAP_ARRAY64_UNSIGNED(a,b) ConvertUInt64Buffer((a),(b)) + #define BSWAP_TMPQHEADER(a,b) ConvertTMPQHeader((a),(b)) + #define BSWAP_TMPKHEADER(a) ConvertTMPKHeader((a)) +#endif + +//----------------------------------------------------------------------------- +// Macro for deprecated symbols + +/* +#ifdef _MSC_VER + #if _MSC_FULL_VER >= 140050320 + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated(_Text)) + #else + #define STORMLIB_DEPRECATED(_Text) __declspec(deprecated) + #endif +#else + #ifdef __GNUC__ + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated)) + #else + #define STORMLIB_DEPRECATED(_Text) __attribute__((deprecated(_Text))) + #endif +#endif + +// When a flag is deprecated, use this macro +#ifndef _STORMLIB_NO_DEPRECATE + #define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) \ + const STORMLIB_DEPRECATED(#oldflag " is deprecated. Use " #newflag ". To supress this warning, define _STORMLIB_NO_DEPRECATE") static type oldflag = (type)newflag; +#else +#define STORMLIB_DEPRECATED_FLAG(type, oldflag, newflag) static type oldflag = (type)newflag; +#endif +*/ + +#endif // __STORMPORT_H__ diff --git a/dep/StormLib/src/adpcm/adpcm.cpp b/dep/StormLib/src/adpcm/adpcm.cpp new file mode 100644 index 000000000..c8086ab6b --- /dev/null +++ b/dep/StormLib/src/adpcm/adpcm.cpp @@ -0,0 +1,401 @@ +/*****************************************************************************/ +/* adpcm.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* This module contains implementation of adpcm decompression method used by */ +/* Storm.dll to decompress WAVE files. Thanks to Tom Amigo for releasing */ +/* his sources. */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ +/* 20.05.03 2.00 Lad Added compression */ +/* 19.11.03 2.01 Dan Big endian handling */ +/* 10.01.13 3.00 Lad Refactored, beautified, documented :-) */ +/*****************************************************************************/ + +#include + +#include "adpcm.h" + +//----------------------------------------------------------------------------- +// Tables necessary dor decompression + +static int NextStepTable[] = +{ + -1, 0, -1, 4, -1, 2, -1, 6, + -1, 1, -1, 5, -1, 3, -1, 7, + -1, 1, -1, 5, -1, 3, -1, 7, + -1, 2, -1, 4, -1, 6, -1, 8 +}; + +static int StepSizeTable[] = +{ + 7, 8, 9, 10, 11, 12, 13, 14, + 16, 17, 19, 21, 23, 25, 28, 31, + 34, 37, 41, 45, 50, 55, 60, 66, + 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, + 724, 796, 876, 963, 1060, 1166, 1282, 1411, + 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, + 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, + 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767 +}; + +//----------------------------------------------------------------------------- +// Helper class for writing output ADPCM data + +class TADPCMStream +{ + public: + + TADPCMStream(void * pvBuffer, size_t cbBuffer) + { + pbBufferEnd = (unsigned char *)pvBuffer + cbBuffer; + pbBuffer = (unsigned char *)pvBuffer; + } + + bool ReadByteSample(unsigned char & ByteSample) + { + // Check if there is enough space in the buffer + if(pbBuffer >= pbBufferEnd) + return false; + + ByteSample = *pbBuffer++; + return true; + } + + bool WriteByteSample(unsigned char ByteSample) + { + // Check if there is enough space in the buffer + if(pbBuffer >= pbBufferEnd) + return false; + + *pbBuffer++ = ByteSample; + return true; + } + + bool ReadWordSample(short & OneSample) + { + // Check if we have enough space in the output buffer + if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short)) + return false; + + // Write the sample + OneSample = pbBuffer[0] + (((short)pbBuffer[1]) << 0x08); + pbBuffer += sizeof(short); + return true; + } + + bool WriteWordSample(short OneSample) + { + // Check if we have enough space in the output buffer + if((size_t)(pbBufferEnd - pbBuffer) < sizeof(short)) + return false; + + // Write the sample + *pbBuffer++ = (unsigned char)(OneSample & 0xFF); + *pbBuffer++ = (unsigned char)(OneSample >> 0x08); + return true; + } + + int LengthProcessed(void * pvOutBuffer) + { + return (int)((unsigned char *)pbBuffer - (unsigned char *)pvOutBuffer); + } + + unsigned char * pbBufferEnd; + unsigned char * pbBuffer; +}; + +//---------------------------------------------------------------------------- +// Local functions + +static inline short GetNextStepIndex(int StepIndex, unsigned int EncodedSample) +{ + // Get the next step index + StepIndex = StepIndex + NextStepTable[EncodedSample & 0x1F]; + + // Don't make the step index overflow + if(StepIndex < 0) + StepIndex = 0; + else if(StepIndex > 88) + StepIndex = 88; + + return (short)StepIndex; +} + +static inline int UpdatePredictedSample(int PredictedSample, int EncodedSample, int Difference) +{ + // Is the sign bit set? + if(EncodedSample & 0x40) + { + PredictedSample -= Difference; + if(PredictedSample <= -32768) + PredictedSample = -32768; + } + else + { + PredictedSample += Difference; + if(PredictedSample >= 32767) + PredictedSample = 32767; + } + + return PredictedSample; +} + +static inline int DecodeSample(int PredictedSample, int EncodedSample, int StepSize, int Difference) +{ + if(EncodedSample & 0x01) + Difference += (StepSize >> 0); + + if(EncodedSample & 0x02) + Difference += (StepSize >> 1); + + if(EncodedSample & 0x04) + Difference += (StepSize >> 2); + + if(EncodedSample & 0x08) + Difference += (StepSize >> 3); + + if(EncodedSample & 0x10) + Difference += (StepSize >> 4); + + if(EncodedSample & 0x20) + Difference += (StepSize >> 5); + + return UpdatePredictedSample(PredictedSample, EncodedSample, Difference); +} + +//---------------------------------------------------------------------------- +// Compression routine + +int CompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount, int CompressionLevel) +{ + TADPCMStream os(pvOutBuffer, cbOutBuffer); // The output stream + TADPCMStream is(pvInBuffer, cbInBuffer); // The input stream + unsigned char BitShift = (unsigned char)(CompressionLevel - 1); + short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT];// Predicted samples for each channel + short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Step indexes for each channel + short InputSample; // Input sample for the current channel + int TotalStepSize; + int ChannelIndex; + int AbsDifference; + int Difference; + int MaxBitMask; + int StepSize; + +// _tprintf(_T("== CMPR Started ==============\n")); + + // First byte in the output stream contains zero. The second one contains the compression level + os.WriteByteSample(0); + if(!os.WriteByteSample(BitShift)) + return 2; + + // Set the initial step index for each channel + PredictedSamples[0] = PredictedSamples[1] = 0; + StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX; + + // Next, InitialSample value for each channel follows + for(int i = 0; i < ChannelCount; i++) + { + // Get the initial sample from the input stream + if(!is.ReadWordSample(InputSample)) + return os.LengthProcessed(pvOutBuffer); + + // Store the initial sample to our sample array + PredictedSamples[i] = InputSample; + + // Also store the loaded sample to the output stream + if(!os.WriteWordSample(InputSample)) + return os.LengthProcessed(pvOutBuffer); + } + + // Get the initial index + ChannelIndex = ChannelCount - 1; + + // Now keep reading the input data as long as there is something in the input buffer + while(is.ReadWordSample(InputSample)) + { + int EncodedSample = 0; + + // If we have two channels, we need to flip the channel index + ChannelIndex = (ChannelIndex + 1) % ChannelCount; + + // Get the difference from the previous sample. + // If the difference is negative, set the sign bit to the encoded sample + AbsDifference = InputSample - PredictedSamples[ChannelIndex]; + if(AbsDifference < 0) + { + AbsDifference = -AbsDifference; + EncodedSample |= 0x40; + } + + // If the difference is too low (higher that difference treshold), + // write a step index modifier marker + StepSize = StepSizeTable[StepIndexes[ChannelIndex]]; + if(AbsDifference < (StepSize >> CompressionLevel)) + { + if(StepIndexes[ChannelIndex] != 0) + StepIndexes[ChannelIndex]--; + + os.WriteByteSample(0x80); + } + else + { + // If the difference is too high, write marker that + // indicates increase in step size + while(AbsDifference > (StepSize << 1)) + { + if(StepIndexes[ChannelIndex] >= 0x58) + break; + + // Modify the step index + StepIndexes[ChannelIndex] += 8; + if(StepIndexes[ChannelIndex] > 0x58) + StepIndexes[ChannelIndex] = 0x58; + + // Write the "modify step index" marker + StepSize = StepSizeTable[StepIndexes[ChannelIndex]]; + os.WriteByteSample(0x81); + } + + // Get the limit bit value + MaxBitMask = (1 << (BitShift - 1)); + MaxBitMask = (MaxBitMask > 0x20) ? 0x20 : MaxBitMask; + Difference = StepSize >> BitShift; + TotalStepSize = 0; + + for(int BitVal = 0x01; BitVal <= MaxBitMask; BitVal <<= 1) + { + if((TotalStepSize + StepSize) <= AbsDifference) + { + TotalStepSize += StepSize; + EncodedSample |= BitVal; + } + StepSize >>= 1; + } + + PredictedSamples[ChannelIndex] = (short)UpdatePredictedSample(PredictedSamples[ChannelIndex], + EncodedSample, + Difference + TotalStepSize); + // Write the encoded sample to the output stream + if(!os.WriteByteSample((unsigned char)EncodedSample)) + break; + + // Calculates the step index to use for the next encode + StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndexes[ChannelIndex], EncodedSample); + } + } + +// _tprintf(_T("== CMPR Ended ================\n")); + return os.LengthProcessed(pvOutBuffer); +} + +//---------------------------------------------------------------------------- +// Decompression routine + +int DecompressADPCM(void * pvOutBuffer, int cbOutBuffer, void * pvInBuffer, int cbInBuffer, int ChannelCount) +{ + TADPCMStream os(pvOutBuffer, cbOutBuffer); // Output stream + TADPCMStream is(pvInBuffer, cbInBuffer); // Input stream + unsigned char EncodedSample; + unsigned char BitShift; + short PredictedSamples[MAX_ADPCM_CHANNEL_COUNT]; // Predicted sample for each channel + short StepIndexes[MAX_ADPCM_CHANNEL_COUNT]; // Predicted step index for each channel + int ChannelIndex; // Current channel index + + // Initialize the StepIndex for each channel + PredictedSamples[0] = PredictedSamples[1] = 0; + StepIndexes[0] = StepIndexes[1] = INITIAL_ADPCM_STEP_INDEX; + +// _tprintf(_T("== DCMP Started ==============\n")); + + // The first byte is always zero, the second one contains bit shift (compression level - 1) + is.ReadByteSample(BitShift); + is.ReadByteSample(BitShift); +// _tprintf(_T("DCMP: BitShift = %u\n"), (unsigned int)(unsigned char)BitShift); + + // Next, InitialSample value for each channel follows + for(int i = 0; i < ChannelCount; i++) + { + // Get the initial sample from the input stream + short InitialSample; + + // Attempt to read the initial sample + if(!is.ReadWordSample(InitialSample)) + return os.LengthProcessed(pvOutBuffer); + +// _tprintf(_T("DCMP: Loaded InitialSample[%u]: %04X\n"), i, (unsigned int)(unsigned short)InitialSample); + + // Store the initial sample to our sample array + PredictedSamples[i] = InitialSample; + + // Also store the loaded sample to the output stream + if(!os.WriteWordSample(InitialSample)) + return os.LengthProcessed(pvOutBuffer); + } + + // Get the initial index + ChannelIndex = ChannelCount - 1; + + // Keep reading as long as there is something in the input buffer + while(is.ReadByteSample(EncodedSample)) + { +// _tprintf(_T("DCMP: Loaded Encoded Sample: %02X\n"), (unsigned int)(unsigned char)EncodedSample); + + // If we have two channels, we need to flip the channel index + ChannelIndex = (ChannelIndex + 1) % ChannelCount; + + if(EncodedSample == 0x80) + { + if(StepIndexes[ChannelIndex] != 0) + StepIndexes[ChannelIndex]--; + +// _tprintf(_T("DCMP: Writing Decoded Sample: %04lX\n"), (unsigned int)(unsigned short)PredictedSamples[ChannelIndex]); + if(!os.WriteWordSample(PredictedSamples[ChannelIndex])) + return os.LengthProcessed(pvOutBuffer); + } + else if(EncodedSample == 0x81) + { + // Modify the step index + StepIndexes[ChannelIndex] += 8; + if(StepIndexes[ChannelIndex] > 0x58) + StepIndexes[ChannelIndex] = 0x58; + +// _tprintf(_T("DCMP: New value of StepIndex: %04lX\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]); + + // Next pass, keep going on the same channel + ChannelIndex = (ChannelIndex + 1) % ChannelCount; + } + else + { + int StepIndex = StepIndexes[ChannelIndex]; + int StepSize = StepSizeTable[StepIndex]; + + // Encode one sample + PredictedSamples[ChannelIndex] = (short)DecodeSample(PredictedSamples[ChannelIndex], + EncodedSample, + StepSize, + StepSize >> BitShift); + +// _tprintf(_T("DCMP: Writing decoded sample: %04X\n"), (unsigned int)(unsigned short)PredictedSamples[ChannelIndex]); + + // Write the decoded sample to the output stream + if(!os.WriteWordSample(PredictedSamples[ChannelIndex])) + break; + + // Calculates the step index to use for the next encode + StepIndexes[ChannelIndex] = GetNextStepIndex(StepIndex, EncodedSample); +// _tprintf(_T("DCMP: New step index: %04X\n"), (unsigned int)(unsigned short)StepIndexes[ChannelIndex]); + } + } + +// _tprintf(_T("DCMP: Total length written: %u\n"), (unsigned int)os.LengthProcessed(pvOutBuffer)); +// _tprintf(_T("== DCMP Ended ================\n")); + + // Return total bytes written since beginning of the output buffer + return os.LengthProcessed(pvOutBuffer); +} diff --git a/dep/StormLib/src/adpcm/adpcm.h b/dep/StormLib/src/adpcm/adpcm.h new file mode 100644 index 000000000..b1bf36143 --- /dev/null +++ b/dep/StormLib/src/adpcm/adpcm.h @@ -0,0 +1,26 @@ +/*****************************************************************************/ +/* adpcm.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Header file for adpcm decompress functions */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.03.03 1.00 Lad The first version of adpcm.h */ +/*****************************************************************************/ + +#ifndef __ADPCM_H__ +#define __ADPCM_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define MAX_ADPCM_CHANNEL_COUNT 2 +#define INITIAL_ADPCM_STEP_INDEX 0x2C + +//----------------------------------------------------------------------------- +// Public functions + +int CompressADPCM (void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int nCmpType, int ChannelCount); +int DecompressADPCM(void * pvOutBuffer, int dwOutLength, void * pvInBuffer, int dwInLength, int ChannelCount); + +#endif // __ADPCM_H__ diff --git a/dep/StormLib/src/adpcm/adpcm_old.cpp b/dep/StormLib/src/adpcm/adpcm_old.cpp new file mode 100644 index 000000000..916fa3811 --- /dev/null +++ b/dep/StormLib/src/adpcm/adpcm_old.cpp @@ -0,0 +1,358 @@ +/*****************************************************************************/ +/* adpcm.cpp Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* This module contains implementation of adpcm decompression method used by */ +/* Storm.dll to decompress WAVE files. Thanks to Tom Amigo for releasing */ +/* his sources. */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ +/* 20.05.03 2.00 Lad Added compression */ +/* 19.11.03 2.01 Dan Big endian handling */ +/*****************************************************************************/ + +#include "adpcm.h" + +//------------------------------------------------------------------------------ +// Structures + +typedef union _BYTE_AND_WORD_PTR +{ + short * pw; + unsigned char * pb; +} BYTE_AND_WORD_PTR; + +typedef union _WORD_AND_BYTE_ARRAY +{ + short w; + unsigned char b[2]; +} WORD_AND_BYTE_ARRAY; + +//----------------------------------------------------------------------------- +// Tables necessary dor decompression + +static long Table1503F120[] = +{ + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000006, + 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007, + 0xFFFFFFFF, 0x00000001, 0xFFFFFFFF, 0x00000005, 0xFFFFFFFF, 0x00000003, 0xFFFFFFFF, 0x00000007, + 0xFFFFFFFF, 0x00000002, 0xFFFFFFFF, 0x00000004, 0xFFFFFFFF, 0x00000006, 0xFFFFFFFF, 0x00000008 +}; + +static long step_table[] = +{ + 0x00000007, 0x00000008, 0x00000009, 0x0000000A, 0x0000000B, 0x0000000C, 0x0000000D, 0x0000000E, + 0x00000010, 0x00000011, 0x00000013, 0x00000015, 0x00000017, 0x00000019, 0x0000001C, 0x0000001F, + 0x00000022, 0x00000025, 0x00000029, 0x0000002D, 0x00000032, 0x00000037, 0x0000003C, 0x00000042, + 0x00000049, 0x00000050, 0x00000058, 0x00000061, 0x0000006B, 0x00000076, 0x00000082, 0x0000008F, + 0x0000009D, 0x000000AD, 0x000000BE, 0x000000D1, 0x000000E6, 0x000000FD, 0x00000117, 0x00000133, + 0x00000151, 0x00000173, 0x00000198, 0x000001C1, 0x000001EE, 0x00000220, 0x00000256, 0x00000292, + 0x000002D4, 0x0000031C, 0x0000036C, 0x000003C3, 0x00000424, 0x0000048E, 0x00000502, 0x00000583, + 0x00000610, 0x000006AB, 0x00000756, 0x00000812, 0x000008E0, 0x000009C3, 0x00000ABD, 0x00000BD0, + 0x00000CFF, 0x00000E4C, 0x00000FBA, 0x0000114C, 0x00001307, 0x000014EE, 0x00001706, 0x00001954, + 0x00001BDC, 0x00001EA5, 0x000021B6, 0x00002515, 0x000028CA, 0x00002CDF, 0x0000315B, 0x0000364B, + 0x00003BB9, 0x000041B2, 0x00004844, 0x00004F7E, 0x00005771, 0x0000602F, 0x000069CE, 0x00007462, + 0x00007FFF +}; + +//---------------------------------------------------------------------------- +// CompressWave + +// 1500EF70 +int CompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nChannels, int nCmpLevel) +// ECX EDX +{ + WORD_AND_BYTE_ARRAY Wcmp; + BYTE_AND_WORD_PTR out; // Pointer to the output buffer + long SInt32Array1[2]; + long SInt32Array2[2]; + long SInt32Array3[2]; + long nBytesRemains = dwOutLength; // Number of bytes remaining + long nWordsRemains; // Number of words remaining +// unsigned char * pbSaveOutBuffer; // Copy of output buffer (actually not used) + unsigned long dwBitBuff; + unsigned long dwStopBit; + unsigned long dwBit; + unsigned long ebx; + unsigned long esi; + long nTableValue; + long nOneWord; + long var_1C; + long var_2C; + int nLength; + int nIndex; + int nValue; + int i, chnl; + + // If less than 2 bytes remain, don't decompress anything +// pbSaveOutBuffer = pbOutBuffer; + out.pb = pbOutBuffer; + if(nBytesRemains < 2) + return 2; + + Wcmp.b[1] = (unsigned char)(nCmpLevel - 1); + Wcmp.b[0] = (unsigned char)0; + + *out.pw++ = BSWAP_INT16_SIGNED(Wcmp.w); + if((out.pb - pbOutBuffer + (nChannels * 2)) > nBytesRemains) + return (int)(out.pb - pbOutBuffer + (nChannels * 2)); + + SInt32Array1[0] = SInt32Array1[1] = 0x2C; + + for(i = 0; i < nChannels; i++) + { + nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++); + *out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord); + SInt32Array2[i] = nOneWord; + } + + // Weird. But it's there + nLength = dwInLength; + if(nLength < 0) // mov eax, dwInLength; cdq; sub eax, edx; + nLength++; + + nLength = (nLength / 2) - (int)(out.pb - pbOutBuffer); + nLength = (nLength < 0) ? 0 : nLength; + + nIndex = nChannels - 1; // edi + nWordsRemains = dwInLength / 2; // eax + + // ebx - nChannels + // ecx - pwOutPos + for(chnl = nChannels; chnl < nWordsRemains; chnl++) + { + // 1500F030 + if((out.pb - pbOutBuffer + 2) > nBytesRemains) + return (int)(out.pb - pbOutBuffer + 2); + + // Switch index + if(nChannels == 2) + nIndex = (nIndex == 0) ? 1 : 0; + + // Load one word from the input stream + nOneWord = BSWAP_INT16_SIGNED(*pwInBuffer++); // ecx - nOneWord + SInt32Array3[nIndex] = nOneWord; + + // esi - SInt32Array2[nIndex] + // eax - nValue + nValue = nOneWord - SInt32Array2[nIndex]; + nValue = (nValue < 0) ? ((nValue ^ 0xFFFFFFFF) + 1) : nValue; + + ebx = (nOneWord >= SInt32Array2[nIndex]) ? 0 : 0x40; + + // esi - SInt32Array2[nIndex] + // edx - step_table[SInt32Array2[nIndex]] + // edi - (step_table[SInt32Array1[nIndex]] >> nCmpLevel) + nTableValue = step_table[SInt32Array1[nIndex]]; + dwStopBit = (unsigned long)nCmpLevel; + + // edi - nIndex; + if(nValue < (nTableValue >> nCmpLevel)) + { + if(SInt32Array1[nIndex] != 0) + SInt32Array1[nIndex]--; + *out.pb++ = 0x80; + } + else + { + while(nValue > nTableValue * 2) + { + if(SInt32Array1[nIndex] >= 0x58 || nLength == 0) + break; + + SInt32Array1[nIndex] += 8; + if(SInt32Array1[nIndex] > 0x58) + SInt32Array1[nIndex] = 0x58; + + nTableValue = step_table[SInt32Array1[nIndex]]; + *out.pb++ = 0x81; + nLength--; + } + + var_2C = nTableValue >> Wcmp.b[1]; + dwBitBuff = 0; + + esi = (1 << (dwStopBit - 2)); + dwStopBit = (esi <= 0x20) ? esi : 0x20; + + for(var_1C = 0, dwBit = 1; ; dwBit <<= 1) + { +// esi = var_1C + nTableValue; + if((var_1C + nTableValue) <= nValue) + { + var_1C += nTableValue; + dwBitBuff |= dwBit; + } + if(dwBit == dwStopBit) + break; + + nTableValue >>= 1; + } + + nValue = SInt32Array2[nIndex]; + if(ebx != 0) + { + nValue -= (var_1C + var_2C); + if(nValue < -32768) + nValue = -32768; + } + else + { + nValue += (var_1C + var_2C); + if(nValue > 32767) + nValue = 32767; + } + + SInt32Array2[nIndex] = nValue; + *out.pb++ = (unsigned char)(dwBitBuff | ebx); + nTableValue = Table1503F120[dwBitBuff & 0x1F]; + SInt32Array1[nIndex] = SInt32Array1[nIndex] + nTableValue; + if(SInt32Array1[nIndex] < 0) + SInt32Array1[nIndex] = 0; + else if(SInt32Array1[nIndex] > 0x58) + SInt32Array1[nIndex] = 0x58; + } + } + + return (int)(out.pb - pbOutBuffer); +} + +//---------------------------------------------------------------------------- +// DecompressADPCM + +// 1500F230 +int DecompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels) +{ + BYTE_AND_WORD_PTR out; // Output buffer + BYTE_AND_WORD_PTR in; + unsigned char * pbInBufferEnd = (pbInBuffer + dwInLength); + long SInt32Array1[2]; + long SInt32Array2[2]; + long nOneWord; + int nIndex; + int i; + + SInt32Array1[0] = SInt32Array1[1] = 0x2C; + out.pb = pbOutBuffer; + in.pb = pbInBuffer; + in.pw++; + + // Fill the Uint32Array2 array by channel values. + for(i = 0; i < nChannels; i++) + { + nOneWord = BSWAP_INT16_SIGNED(*in.pw++); + SInt32Array2[i] = nOneWord; + if(dwOutLength < 2) + return (int)(out.pb - pbOutBuffer); + + *out.pw++ = BSWAP_INT16_SIGNED((short)nOneWord); + dwOutLength -= sizeof(short); + } + + // Get the initial index + nIndex = nChannels - 1; + + // Perform the decompression + while(in.pb < pbInBufferEnd) + { + unsigned char nOneByte = *in.pb++; + + // Switch index + if(nChannels == 2) + nIndex = (nIndex == 0) ? 1 : 0; + + // 1500F2A2: Get one byte from input buffer + if(nOneByte & 0x80) + { + switch(nOneByte & 0x7F) + { + case 0: // 1500F315 + if(SInt32Array1[nIndex] != 0) + SInt32Array1[nIndex]--; + + if(dwOutLength < 2) + return (int)(out.pb - pbOutBuffer); + + *out.pw++ = BSWAP_INT16_SIGNED((unsigned short)SInt32Array2[nIndex]); + dwOutLength -= sizeof(unsigned short); + break; + + case 1: // 1500F2E8 + SInt32Array1[nIndex] += 8; + if(SInt32Array1[nIndex] > 0x58) + SInt32Array1[nIndex] = 0x58; + + if(nChannels == 2) + nIndex = (nIndex == 0) ? 1 : 0; + break; + + case 2: // 1500F41E + break; + + default: // 1500F2C4 + SInt32Array1[nIndex] -= 8; + if(SInt32Array1[nIndex] < 0) + SInt32Array1[nIndex] = 0; + + if(nChannels == 2) + nIndex = (nIndex == 0) ? 1 : 0; + break; + } + } + else + { + // 1500F349 + long temp1 = step_table[SInt32Array1[nIndex]]; // EDI + long temp2 = temp1 >> pbInBuffer[1]; // ESI + long temp3 = SInt32Array2[nIndex]; // ECX + + if(nOneByte & 0x01) // EBX = nOneByte + temp2 += (temp1 >> 0); + + if(nOneByte & 0x02) + temp2 += (temp1 >> 1); + + if(nOneByte & 0x04) + temp2 += (temp1 >> 2); + + if(nOneByte & 0x08) + temp2 += (temp1 >> 3); + + if(nOneByte & 0x10) + temp2 += (temp1 >> 4); + + if(nOneByte & 0x20) + temp2 += (temp1 >> 5); + + if(nOneByte & 0x40) + { + temp3 = temp3 - temp2; + if(temp3 <= -32768) + temp3 = -32768; + } + else + { + temp3 = temp3 + temp2; + if(temp3 >= 32767) + temp3 = 32767; + } + + SInt32Array2[nIndex] = temp3; + if(dwOutLength < 2) + break; + + // Store the output 16-bit value + *out.pw++ = BSWAP_INT16_SIGNED((short)SInt32Array2[nIndex]); + dwOutLength -= 2; + + SInt32Array1[nIndex] += Table1503F120[nOneByte & 0x1F]; + + if(SInt32Array1[nIndex] < 0) + SInt32Array1[nIndex] = 0; + else if(SInt32Array1[nIndex] > 0x58) + SInt32Array1[nIndex] = 0x58; + } + } + return (int)(out.pb - pbOutBuffer); +} diff --git a/dep/StormLib/src/adpcm/adpcm_old.h b/dep/StormLib/src/adpcm/adpcm_old.h new file mode 100644 index 000000000..7b76affac --- /dev/null +++ b/dep/StormLib/src/adpcm/adpcm_old.h @@ -0,0 +1,22 @@ +/*****************************************************************************/ +/* adpcm.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Header file for adpcm decompress functions */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.03.03 1.00 Lad The first version of adpcm.h */ +/*****************************************************************************/ + +#ifndef __ADPCM_H__ +#define __ADPCM_H__ + +//----------------------------------------------------------------------------- +// Functions + +#include + +int CompressADPCM (unsigned char * pbOutBuffer, int dwOutLength, short * pwInBuffer, int dwInLength, int nCmpType, int nChannels); +int DecompressADPCM(unsigned char * pbOutBuffer, int dwOutLength, unsigned char * pbInBuffer, int dwInLength, int nChannels); + +#endif // __ADPCM_H__ diff --git a/dep/StormLib/src/huffman/huff.cpp b/dep/StormLib/src/huffman/huff.cpp new file mode 100644 index 000000000..9de5acb51 --- /dev/null +++ b/dep/StormLib/src/huffman/huff.cpp @@ -0,0 +1,873 @@ +/*****************************************************************************/ +/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */ +/*---------------------------------------------------------------------------*/ +/* This module contains Huffmann (de)compression methods */ +/* */ +/* Authors : Ladislav Zezula (ladik@zezula.net) */ +/* ShadowFlare (BlakFlare@hotmail.com) */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */ +/* 03.05.03 1.00 Lad Added compression methods */ +/* 19.11.03 1.01 Dan Big endian handling */ +/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */ +/* 09.01.13 3.00 Lad Refactored, beautified, documented :-) */ +/*****************************************************************************/ + +#include +#include + +#include "huff.h" + +//----------------------------------------------------------------------------- +// Table of byte-to-weight values + +// Table for (de)compression. Every compression type has 258 entries +static unsigned char ByteToWeight_00[] = +{ + 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00 +}; + +// Data for compression type 0x01 +static unsigned char ByteToWeight_01[] = +{ + 0x54, 0x16, 0x16, 0x0D, 0x0C, 0x08, 0x06, 0x05, 0x06, 0x05, 0x06, 0x03, 0x04, 0x04, 0x03, 0x05, + 0x0E, 0x0B, 0x14, 0x13, 0x13, 0x09, 0x0B, 0x06, 0x05, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, + 0x0D, 0x07, 0x09, 0x06, 0x06, 0x04, 0x03, 0x02, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, + 0x09, 0x06, 0x04, 0x04, 0x04, 0x04, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x02, 0x04, + 0x08, 0x03, 0x04, 0x07, 0x09, 0x05, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, 0x02, 0x02, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, + 0x06, 0x0A, 0x08, 0x08, 0x06, 0x07, 0x04, 0x03, 0x04, 0x04, 0x02, 0x02, 0x04, 0x02, 0x03, 0x03, + 0x04, 0x03, 0x07, 0x07, 0x09, 0x06, 0x04, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x0A, 0x02, 0x02, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x03, 0x05, 0x02, 0x03, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x04, 0x04, 0x04, 0x07, 0x09, 0x08, 0x0C, 0x02, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x03, + 0x04, 0x01, 0x02, 0x04, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, + 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x06, 0x4B, + 0x00, 0x00 +}; + +// Data for compression type 0x02 +static unsigned char ByteToWeight_02[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x27, 0x00, 0x00, 0x23, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x06, 0x0E, 0x10, 0x04, + 0x06, 0x08, 0x05, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01, + 0x01, 0x04, 0x02, 0x04, 0x02, 0x02, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0x02, 0x03, 0x03, 0x02, + 0x03, 0x01, 0x03, 0x06, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, + 0x01, 0x29, 0x07, 0x16, 0x12, 0x40, 0x0A, 0x0A, 0x11, 0x25, 0x01, 0x03, 0x17, 0x10, 0x26, 0x2A, + 0x10, 0x01, 0x23, 0x23, 0x2F, 0x10, 0x06, 0x07, 0x02, 0x09, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +// Data for compression type 0x03 +static unsigned char ByteToWeight_03[] = +{ + 0xFF, 0x0B, 0x07, 0x05, 0x0B, 0x02, 0x02, 0x02, 0x06, 0x02, 0x02, 0x01, 0x04, 0x02, 0x01, 0x03, + 0x09, 0x01, 0x01, 0x01, 0x03, 0x04, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, + 0x05, 0x01, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x0A, 0x04, 0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, + 0x05, 0x02, 0x03, 0x04, 0x03, 0x03, 0x03, 0x02, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x03, + 0x01, 0x03, 0x01, 0x01, 0x02, 0x05, 0x01, 0x01, 0x04, 0x03, 0x05, 0x01, 0x03, 0x01, 0x03, 0x03, + 0x02, 0x01, 0x04, 0x03, 0x0A, 0x06, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x01, 0x0A, 0x02, 0x05, 0x01, 0x01, 0x02, 0x07, 0x02, 0x17, 0x01, 0x05, 0x01, 0x01, + 0x0E, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x02, 0x01, 0x04, 0x05, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x07, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x11, + 0x00, 0x00 +}; + +// Data for compression type 0x04 +static unsigned char ByteToWeight_04[] = +{ + 0xFF, 0xFB, 0x98, 0x9A, 0x84, 0x85, 0x63, 0x64, 0x3E, 0x3E, 0x22, 0x22, 0x13, 0x13, 0x18, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +// Data for compression type 0x05 +static unsigned char ByteToWeight_05[] = +{ + 0xFF, 0xF1, 0x9D, 0x9E, 0x9A, 0x9B, 0x9A, 0x97, 0x93, 0x93, 0x8C, 0x8E, 0x86, 0x88, 0x80, 0x82, + 0x7C, 0x7C, 0x72, 0x73, 0x69, 0x6B, 0x5F, 0x60, 0x55, 0x56, 0x4A, 0x4B, 0x40, 0x41, 0x37, 0x37, + 0x2F, 0x2F, 0x27, 0x27, 0x21, 0x21, 0x1B, 0x1C, 0x17, 0x17, 0x13, 0x13, 0x10, 0x10, 0x0D, 0x0D, + 0x0B, 0x0B, 0x09, 0x09, 0x08, 0x08, 0x07, 0x07, 0x06, 0x05, 0x05, 0x04, 0x04, 0x04, 0x19, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + + // Data for compression type 0x06 +static unsigned char ByteToWeight_06[] = +{ + 0xC3, 0xCB, 0xF5, 0x41, 0xFF, 0x7B, 0xF7, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBF, 0xCC, 0xF2, 0x40, 0xFD, 0x7C, 0xF7, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7A, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +// Data for compression type 0x07 +static unsigned char ByteToWeight_07[] = +{ + 0xC3, 0xD9, 0xEF, 0x3D, 0xF9, 0x7C, 0xE9, 0x1E, 0xFD, 0xAB, 0xF1, 0x2C, 0xFC, 0x5B, 0xFE, 0x17, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xBD, 0xD9, 0xEC, 0x3D, 0xF5, 0x7D, 0xE8, 0x1D, 0xFB, 0xAE, 0xF0, 0x2C, 0xFB, 0x5C, 0xFF, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +// Data for compression type 0x08 +static unsigned char ByteToWeight_08[] = +{ + 0xBA, 0xC5, 0xDA, 0x33, 0xE3, 0x6D, 0xD8, 0x18, 0xE5, 0x94, 0xDA, 0x23, 0xDF, 0x4A, 0xD1, 0x10, + 0xEE, 0xAF, 0xE4, 0x2C, 0xEA, 0x5A, 0xDE, 0x15, 0xF4, 0x87, 0xE9, 0x21, 0xF6, 0x43, 0xFC, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xB0, 0xC7, 0xD8, 0x33, 0xE3, 0x6B, 0xD6, 0x18, 0xE7, 0x95, 0xD8, 0x23, 0xDB, 0x49, 0xD0, 0x11, + 0xE9, 0xB2, 0xE2, 0x2B, 0xE8, 0x5C, 0xDD, 0x15, 0xF1, 0x87, 0xE7, 0x20, 0xF7, 0x44, 0xFF, 0x13, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5F, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 +}; + +static unsigned char * WeightTables[0x09] = +{ + ByteToWeight_00, + ByteToWeight_01, + ByteToWeight_02, + ByteToWeight_03, + ByteToWeight_04, + ByteToWeight_05, + ByteToWeight_06, + ByteToWeight_07, + ByteToWeight_08 +}; + +//----------------------------------------------------------------------------- +// Debug/diagnostics + +#ifdef _DEBUG +void DumpHuffmannTree(THTreeItem * pItem) +{ + THTreeItem * pChildLo; // Item with the lower weight + THTreeItem * pChildHi; // Item with the higher weight + + // Get the lower-weight branch + pChildLo = pItem->pChildLo; + if(pChildLo != NULL) + { + // Get the higher-weight branch + pChildHi = pChildLo->pPrev; + + // Parse the lower-weight branch + DumpHuffmannTree(pChildHi); + DumpHuffmannTree(pChildLo); + } +} +#endif + +//----------------------------------------------------------------------------- +// TInputStream functions + +TInputStream::TInputStream(void * pvInBuffer, size_t cbInBuffer) +{ + pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer; + pbInBuffer = (unsigned char *)pvInBuffer; + BitBuffer = 0; + BitCount = 0; +} + +// Gets 7 bits from the stream. DOES NOT remove the bits from input stream +unsigned int TInputStream::Peek7Bits() +{ + unsigned int dwReloadByte = 0; + + // If there is not enough bits to get the value, + // we have to add 8 more bits from the input buffer + if(BitCount < 7) + { + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; + } + + // Return the first available 7 bits. DO NOT remove them from the input stream + return (BitBuffer & 0x7F); +} + +// Gets one bit from input stream +unsigned int TInputStream::Get1Bit() +{ + unsigned int OneBit = 0; + + // Ensure that the input stream is reloaded, if there are no bits left + if(BitCount == 0) + { + // Refill the bit buffer + BitBuffer = *pbInBuffer++; + BitCount = 8; + } + + // Copy the bit from bit buffer to the variable + OneBit = (BitBuffer & 0x01); + BitBuffer >>= 1; + BitCount--; + + return OneBit; +} + +// Gets the whole byte from the input stream. +unsigned int TInputStream::Get8Bits() +{ + unsigned int dwReloadByte = 0; + unsigned int dwOneByte = 0; + + // If there is not enough bits to get the value, + // we have to add 8 more bits from the input buffer + if(BitCount < 8) + { + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; + } + + // Return the lowest 8 its + dwOneByte = (BitBuffer & 0xFF); + BitBuffer >>= 8; + BitCount -= 8; + return dwOneByte; +} + +void TInputStream::SkipBits(unsigned int dwBitsToSkip) +{ + unsigned int dwReloadByte = 0; + + // If there is not enough bits in the buffer, + // we have to add 8 more bits from the input buffer + if(BitCount < dwBitsToSkip) + { + dwReloadByte = *pbInBuffer++; + BitBuffer |= dwReloadByte << BitCount; + BitCount += 8; + } + + // Skip the remaining bits + BitBuffer >>= dwBitsToSkip; + BitCount -= dwBitsToSkip; +} + +//----------------------------------------------------------------------------- +// TOutputStream functions + +TOutputStream::TOutputStream(void * pvOutBuffer, size_t cbOutLength) +{ + pbOutBufferEnd = (unsigned char *)pvOutBuffer + cbOutLength; + pbOutBuffer = (unsigned char *)pvOutBuffer; + BitBuffer = 0; + BitCount = 0; +} + +void TOutputStream::PutBits(unsigned int dwValue, unsigned int nBitCount) +{ + BitBuffer |= (dwValue << BitCount); + BitCount += nBitCount; + + // Flush completed bytes + while(BitCount >= 8) + { + if(pbOutBuffer < pbOutBufferEnd) + *pbOutBuffer++ = (unsigned char)BitBuffer; + + BitBuffer >>= 8; + BitCount -= 8; + } +} + +void TOutputStream::Flush() +{ + while(BitCount != 0) + { + if(pbOutBuffer < pbOutBufferEnd) + *pbOutBuffer++ = (unsigned char)BitBuffer; + + BitBuffer >>= 8; + BitCount -= ((BitCount > 8) ? 8 : BitCount); + } +} + +//----------------------------------------------------------------------------- +// Methods of the THTreeItem struct + +void THTreeItem::RemoveItem() +{ + if(pNext != NULL) + { + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + pNext = pPrev = NULL; + } +} + +//----------------------------------------------------------------------------- +// THuffmannTree class functions + +THuffmannTree::THuffmannTree(bool bCompression) +{ + pFirst = pLast = LIST_HEAD(); + MinValidValue = 1; + ItemsUsed = 0; + bIsCmp0 = 0; + + memset(ItemsByByte, 0, sizeof(ItemsByByte)); + + // If we are going to decompress data, we need to invalidate all item links + // We do so by zeroing their ValidValue, so it becomes lower MinValidValue + if(bCompression == false) + { + memset(QuickLinks, 0, sizeof(QuickLinks)); + } +} + +THuffmannTree::~THuffmannTree() +{ + // Our Huffmann tree does not use any memory allocations, + // so we don't need to do eny code in the destructor +} + +void THuffmannTree::LinkTwoItems(THTreeItem * pItem1, THTreeItem * pItem2) +{ + pItem2->pNext = pItem1->pNext; + pItem2->pPrev = pItem1->pNext->pPrev; + pItem1->pNext->pPrev = pItem2; + pItem1->pNext = pItem2; +} + +// Inserts item into the tree (?) +void THuffmannTree::InsertItem(THTreeItem * pNewItem, TInsertPoint InsertPoint, THTreeItem * pInsertPoint) +{ + // Remove the item from the tree + pNewItem->RemoveItem(); + + if(pInsertPoint == NULL) + pInsertPoint = LIST_HEAD(); + + switch(InsertPoint) + { + case InsertAfter: + LinkTwoItems(pInsertPoint, pNewItem); + return; + + case InsertBefore: + pNewItem->pNext = pInsertPoint; // Set next item (or pointer to pointer to first item) + pNewItem->pPrev = pInsertPoint->pPrev; // Set prev item (or last item in the tree) + pInsertPoint->pPrev->pNext = pNewItem; + pInsertPoint->pPrev = pNewItem; // Set the next/last item + return; + } +} + +THTreeItem * THuffmannTree::FindHigherOrEqualItem(THTreeItem * pItem, unsigned int Weight) +{ + // Parse all existing items + if(pItem != NULL) + { + while(pItem != LIST_HEAD()) + { + if(pItem->Weight >= Weight) + return pItem; + + pItem = pItem->pPrev; + } + } + + // If not found, we just get the first item + return LIST_HEAD(); +} + +THTreeItem * THuffmannTree::CreateNewItem(unsigned int DecompressedValue, unsigned int Weight, TInsertPoint InsertPoint) +{ + THTreeItem * pNewItem; + + // Allocate new item from the item pool + pNewItem = &ItemBuffer[ItemsUsed++]; + + // Insert this item to the top of the tree + InsertItem(pNewItem, InsertPoint, NULL); + + // Fill the rest of the item + pNewItem->DecompressedValue = DecompressedValue; + pNewItem->Weight = Weight; + pNewItem->pParent = NULL; + pNewItem->pChildLo = NULL; + return pNewItem; +} + +unsigned int THuffmannTree::FixupItemPosByWeight(THTreeItem * pNewItem, unsigned int MaxWeight) +{ + THTreeItem * pHigherItem; + + if(pNewItem->Weight < MaxWeight) + { + // Find an item that has higher weight than this one + pHigherItem = FindHigherOrEqualItem(pLast, pNewItem->Weight); + + // Remove the item and put it to the new position + pNewItem->RemoveItem(); + LinkTwoItems(pHigherItem, pNewItem); + } + else + { + MaxWeight = pNewItem->Weight; + } + + // Return the (updated) maximum weight + return MaxWeight; +} + +// Builds Huffman tree. Called with the first 8 bits loaded from input stream +bool THuffmannTree::BuildTree(unsigned int CompressionType) +{ + THTreeItem * pNewItem; + THTreeItem * pChildLo; + THTreeItem * pChildHi; + unsigned char * WeightTable; + unsigned int MaxWeight; // [ESP+10] - The greatest character found in table + + // Clear all pointers in HTree item array + memset(ItemsByByte, 0, sizeof(ItemsByByte)); + MaxWeight = 0; + + // Ensure that the compression type is in range + if((CompressionType & 0x0F) > 0x08) + return false; + WeightTable = WeightTables[CompressionType & 0x0F]; + + // Build the linear list of entries that is sorted by byte weight + for(unsigned int i = 0; i < 0x100; i++) + { + // Skip all the bytes which are zero. + if(WeightTable[i] != 0) + { + // Create new tree item + ItemsByByte[i] = pNewItem = CreateNewItem(i, WeightTable[i], InsertAfter); + + // We need to put the item to the right place in the list + MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight); + } + } + + // Insert termination entries at the end of the list + ItemsByByte[0x100] = CreateNewItem(0x100, 1, InsertBefore); + ItemsByByte[0x101] = CreateNewItem(0x101, 1, InsertBefore); + + // Now we need to build the tree. We start at the last entry + // and go backwards to the first one + pChildLo = pLast; + + // Work as long as both children are valid + // pChildHi is child with higher weight, pChildLo is the one with lower weight + while(pChildLo != LIST_HEAD()) + { + // Also get and verify the higher-weight child + pChildHi = pChildLo->pPrev; + if(pChildHi == LIST_HEAD()) + break; + + // Create new parent item for the children + pNewItem = CreateNewItem(0, pChildHi->Weight + pChildLo->Weight, InsertAfter); + + // Link both child items to their new parent + pChildLo->pParent = pNewItem; + pChildHi->pParent = pNewItem; + pNewItem->pChildLo = pChildLo; + + // Fixup the item's position by its weight + MaxWeight = FixupItemPosByWeight(pNewItem, MaxWeight); + + // Get the previous lower-weight child + pChildLo = pChildHi->pPrev; + } + + // Initialize the MinValidValue to 1, which invalidates all quick-link items + MinValidValue = 1; + return true; +} + +void THuffmannTree::IncWeightsAndRebalance(THTreeItem * pItem) +{ + THTreeItem * pHigherItem; // A previous item with greater or equal weight + THTreeItem * pChildHi; // The higher-weight child + THTreeItem * pChildLo; // The lower-weight child + THTreeItem * pParent; + + // Climb up the tree and increment weight of each tree item + for(; pItem != NULL; pItem = pItem->pParent) + { + // Increment the item's weight + pItem->Weight++; + + // Find a previous item with equal or greater weight, which is not equal to this item + pHigherItem = FindHigherOrEqualItem(pItem->pPrev, pItem->Weight); + pChildHi = pHigherItem->pNext; + + // If the item is not equal to the tree item, we need to rebalance the tree + if(pChildHi != pItem) + { + // Move the previous item to the RIGHT from the given item + pChildHi->RemoveItem(); + LinkTwoItems(pItem, pChildHi); + + // Move the given item AFTER the greater-weight tree item + pItem->RemoveItem(); + LinkTwoItems(pHigherItem, pItem); + + // We need to maintain the tree so that pChildHi->Weight is >= pChildLo->Weight. + // Rebalance the tree accordingly. + pChildLo = pChildHi->pParent->pChildLo; + pParent = pItem->pParent; + if(pParent->pChildLo == pItem) + pParent->pChildLo = pChildHi; + if(pChildLo == pChildHi) + pChildHi->pParent->pChildLo = pItem; + pParent = pItem->pParent; + pItem->pParent = pChildHi->pParent; + pChildHi->pParent = pParent; + + // Increment the global valid value. This invalidates all quick-link items. + MinValidValue++; + } + } +} + +void THuffmannTree::InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2) +{ + THTreeItem * pLastItem = pLast; + THTreeItem * pChildHi; + THTreeItem * pChildLo; + + // Create higher-weight child + pChildHi = CreateNewItem(Value1, pLastItem->Weight, InsertBefore); + pChildHi->pParent = pLastItem; + ItemsByByte[Value1] = pChildHi; + + // Create lower-weight child + pChildLo = CreateNewItem(Value2, 0, InsertBefore); + pChildLo->pParent = pLastItem; + pLastItem->pChildLo = pChildLo; + ItemsByByte[Value2] = pChildLo; + + IncWeightsAndRebalance(pChildLo); +} + +void THuffmannTree::EncodeOneByte(TOutputStream * os, THTreeItem * pItem) +{ + THTreeItem * pParent = pItem->pParent; + unsigned int BitBuffer = 0; + unsigned int BitCount = 0; + + // Put 1's as long as there is parent + while(pParent != NULL) + { + // Fill the bit buffer + BitBuffer = (BitBuffer << 1) | ((pParent->pChildLo != pItem) ? 1 : 0); + BitCount++; + + // Move to the parent + pItem = pParent; + pParent = pParent->pParent; + } + + // Write the bits to the output stream + os->PutBits(BitBuffer, BitCount); +} + +unsigned int THuffmannTree::DecodeOneByte(TInputStream * is) +{ + THTreeItem * pItemLink = NULL; + THTreeItem * pItem; + unsigned int ItemLinkIndex; + unsigned int BitCount = 0; + + // Check for the end of the input stream + if(is->pbInBuffer >= is->pbInBufferEnd && is->BitCount < 7) + return 0x1FF; + + // Get the eventual quick-link index + ItemLinkIndex = is->Peek7Bits(); + + // Is the quick-link item valid? + if(QuickLinks[ItemLinkIndex].ValidValue > MinValidValue) + { + // If that item needs less than 7 bits, we can get decompressed value directly + if(QuickLinks[ItemLinkIndex].ValidBits <= 7) + { + is->SkipBits(QuickLinks[ItemLinkIndex].ValidBits); + return QuickLinks[ItemLinkIndex].DecompressedValue; + } + + // Otherwise we cannot get decompressed value directly + // but we can skip 7 levels of tree parsing + pItem = QuickLinks[ItemLinkIndex].pItem; + is->SkipBits(7); + } + else + { + // Just a sanity check + if(pFirst == LIST_HEAD()) + return 0x1FF; + + // We don't have the quick-link item, we need to parse the tree from its root + pItem = pFirst; + } + + // Step down the tree until we find a terminal item + while(pItem->pChildLo != NULL) + { + // If the next bit in the compressed stream is set, we get the higher-weight + // child. Otherwise, get the lower-weight child. + pItem = is->Get1Bit() ? pItem->pChildLo->pPrev : pItem->pChildLo; + BitCount++; + + // If the number of loaded bits reached 7, + // remember the current item for storing into quick-link item array + if(BitCount == 7) + pItemLink = pItem; + } + + // If we didn't get the item from the quick-link array, + // set the entry in it + if(QuickLinks[ItemLinkIndex].ValidValue < MinValidValue) + { + // If the current compressed byte was more than 7 bits, + // set a quick-link item with pointer to tree item + if(BitCount > 7) + { + QuickLinks[ItemLinkIndex].ValidValue = MinValidValue; + QuickLinks[ItemLinkIndex].ValidBits = BitCount; + QuickLinks[ItemLinkIndex].pItem = pItemLink; + } + else + { + // Limit the quick-decompress item to lower amount of bits + // Coverity fix 84457: (x >> 32) has undefined behavior + ItemLinkIndex = (BitCount != 0) ? ItemLinkIndex & (0xFFFFFFFF >> (32 - BitCount)) : 0; + while(ItemLinkIndex < LINK_ITEM_COUNT) + { + // Fill the quick-decompress item + QuickLinks[ItemLinkIndex].ValidValue = MinValidValue; + QuickLinks[ItemLinkIndex].ValidBits = BitCount; + QuickLinks[ItemLinkIndex].DecompressedValue = pItem->DecompressedValue; + + // Increment the index + ItemLinkIndex += (1 << BitCount); + } + } + } + + // Return the decompressed value from the found item + return pItem->DecompressedValue; +} + +unsigned int THuffmannTree::Compress(TOutputStream * os, void * pvInBuffer, int cbInBuffer, int CompressionType) +{ + unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + unsigned char * pbOutBuff = os->pbOutBuffer; + unsigned char InputByte; + + if(!BuildTree(CompressionType)) + return 0; + bIsCmp0 = (CompressionType == 0); + + // Store the compression type into output buffer + os->PutBits(CompressionType, 8); + + // Process the entire input buffer + while(pbInBuffer < pbInBufferEnd) + { + // Get the (next) byte from the input buffer + InputByte = *pbInBuffer++; + + // Do we have an item for such input value? + if(ItemsByByte[InputByte] == NULL) + { + // Encode the relationship + EncodeOneByte(os, ItemsByByte[0x101]); + + // Store the loaded byte into output stream + os->PutBits(InputByte, 8); + + InsertNewBranchAndRebalance(pLast->DecompressedValue, InputByte); + + if(bIsCmp0) + { + IncWeightsAndRebalance(ItemsByByte[InputByte]); + continue; + } + + IncWeightsAndRebalance(ItemsByByte[InputByte]); + } + else + { + EncodeOneByte(os, ItemsByByte[InputByte]); + } + + if(bIsCmp0) + { + IncWeightsAndRebalance(ItemsByByte[InputByte]); + } + } + + // Put the termination mark to the compressed stream + EncodeOneByte(os, ItemsByByte[0x100]); + + // Flush the remaining bits + os->Flush(); + return (unsigned int)(os->pbOutBuffer - pbOutBuff); +} + +// Decompression using Huffman tree (1500E450) +unsigned int THuffmannTree::Decompress(void * pvOutBuffer, unsigned int cbOutLength, TInputStream * is) +{ + unsigned char * pbOutBufferEnd = (unsigned char *)pvOutBuffer + cbOutLength; + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned int DecompressedValue = 0; + unsigned int CompressionType = 0; + + // Test the output length. Must not be NULL. + if(cbOutLength == 0) + return 0; + + // Get the compression type from the input stream + CompressionType = is->Get8Bits(); + bIsCmp0 = (CompressionType == 0) ? 1 : 0; + + // Build the Huffman tree + if(!BuildTree(CompressionType)) + return 0; + + // Process the entire input buffer until end of the stream + while((DecompressedValue = DecodeOneByte(is)) != 0x100) + { + // Did an error occur? + if(DecompressedValue == 0x1FF) // An error occurred + return 0; + + // Huffman tree needs to be modified + if(DecompressedValue == 0x101) + { + // The decompressed byte is stored in the next 8 bits + DecompressedValue = is->Get8Bits(); + + InsertNewBranchAndRebalance(pLast->DecompressedValue, DecompressedValue); + + if(bIsCmp0 == 0) + IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); + } + + // A byte successfully decoded - store it in the output stream + *pbOutBuffer++ = (unsigned char)DecompressedValue; + if(pbOutBuffer >= pbOutBufferEnd) + break; + + if(bIsCmp0) + { + IncWeightsAndRebalance(ItemsByByte[DecompressedValue]); + } + } + + return (unsigned int)(pbOutBuffer - (unsigned char *)pvOutBuffer); +} + diff --git a/dep/StormLib/src/huffman/huff.h b/dep/StormLib/src/huffman/huff.h new file mode 100644 index 000000000..89993fdef --- /dev/null +++ b/dep/StormLib/src/huffman/huff.h @@ -0,0 +1,143 @@ +/*****************************************************************************/ +/* huffman.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Description : */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of huffman.h */ +/* 03.05.03 2.00 Lad Added compression */ +/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */ +/*****************************************************************************/ + +#ifndef __HUFFMAN_H__ +#define __HUFFMAN_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define HUFF_ITEM_COUNT 0x203 // Number of items in the item pool +#define LINK_ITEM_COUNT 0x80 // Maximum number of quick-link items + +//----------------------------------------------------------------------------- +// Structures and classes + +// Input stream for Huffmann decompression +class TInputStream +{ + public: + + TInputStream(void * pvInBuffer, size_t cbInBuffer); + unsigned int Get1Bit(); + unsigned int Peek7Bits(); + unsigned int Get8Bits(); + void SkipBits(unsigned int BitCount); + + unsigned char * pbInBufferEnd; // End position in the the input buffer + unsigned char * pbInBuffer; // Current position in the the input buffer + unsigned int BitBuffer; // Input bit buffer + unsigned int BitCount; // Number of bits remaining in 'dwBitBuff' +}; + + +// Output stream for Huffmann compression +class TOutputStream +{ + public: + + TOutputStream(void * pvOutBuffer, size_t cbOutLength); + void PutBits(unsigned int dwValue, unsigned int nBitCount); + void Flush(); + + unsigned char * pbOutBufferEnd; // End position in the output buffer + unsigned char * pbOutBuffer; // Current position in the output buffer + unsigned int BitBuffer; // Bit buffer + unsigned int BitCount; // Number of bits in the bit buffer +}; + +// A virtual tree item that represents the head of the item list +#define LIST_HEAD() ((THTreeItem *)(&pFirst)) + +enum TInsertPoint +{ + InsertAfter = 1, + InsertBefore = 2 +}; + +// Huffmann tree item +struct THTreeItem +{ + THTreeItem() { pPrev = pNext = NULL; DecompressedValue = 0; Weight = 0; pParent = pChildLo = NULL; } +// ~THTreeItem() { RemoveItem(); } + + void RemoveItem(); +// void RemoveEntry(); + + THTreeItem * pNext; // Pointer to lower-weight tree item + THTreeItem * pPrev; // Pointer to higher-weight item + unsigned int DecompressedValue; // 08 - Decompressed byte value (also index in the array) + unsigned int Weight; // 0C - Weight + THTreeItem * pParent; // 10 - Pointer to parent item (NULL if none) + THTreeItem * pChildLo; // 14 - Pointer to the child with lower-weight child ("left child") +}; + + +// Structure used for quick navigating in the huffmann tree. +// Allows skipping up to 7 bits in the compressed stream, thus +// decompressing a bit faster. Sometimes it can even get the decompressed +// byte directly. +struct TQuickLink +{ + unsigned int ValidValue; // If greater than THuffmannTree::MinValidValue, the entry is valid + unsigned int ValidBits; // Number of bits that are valid for this item link + union + { + THTreeItem * pItem; // Pointer to the item within the Huffmann tree + unsigned int DecompressedValue; // Value for direct decompression + }; +}; + + +// Structure for Huffman tree (Size 0x3674 bytes). Because I'm not expert +// for the decompression, I do not know actually if the class is really a Hufmann +// tree. If someone knows the decompression details, please let me know +class THuffmannTree +{ + public: + + THuffmannTree(bool bCompression); + ~THuffmannTree(); + + void LinkTwoItems(THTreeItem * pItem1, THTreeItem * pItem2); + void InsertItem(THTreeItem * item, TInsertPoint InsertPoint, THTreeItem * item2); + + THTreeItem * FindHigherOrEqualItem(THTreeItem * pItem, unsigned int Weight); + THTreeItem * CreateNewItem(unsigned int DecompressedValue, unsigned int Weight, TInsertPoint InsertPoint); + + unsigned int FixupItemPosByWeight(THTreeItem * pItem, unsigned int MaxWeight); + bool BuildTree(unsigned int CompressionType); + + void IncWeightsAndRebalance(THTreeItem * pItem); + void InsertNewBranchAndRebalance(unsigned int Value1, unsigned int Value2); + + void EncodeOneByte(TOutputStream * os, THTreeItem * pItem); + unsigned int DecodeOneByte(TInputStream * is); + + unsigned int Compress(TOutputStream * os, void * pvInBuffer, int cbInBuffer, int nCmpType); + unsigned int Decompress(void * pvOutBuffer, unsigned int cbOutLength, TInputStream * is); + + THTreeItem ItemBuffer[HUFF_ITEM_COUNT]; // Buffer for tree items. No memory allocation is needed + unsigned int ItemsUsed; // Number of tree items used from ItemBuffer + + // Head of the linear item list + THTreeItem * pFirst; // Pointer to the highest weight item + THTreeItem * pLast; // Pointer to the lowest weight item + + THTreeItem * ItemsByByte[0x102]; // Array of item pointers, one for each possible byte value + TQuickLink QuickLinks[LINK_ITEM_COUNT]; // Array of quick-link items + + unsigned int MinValidValue; // A minimum value of TQDecompress::ValidValue to be considered valid + unsigned int bIsCmp0; // 1 if compression type 0 +}; + +#endif // __HUFFMAN_H__ diff --git a/dep/StormLib/src/jenkins/lookup.h b/dep/StormLib/src/jenkins/lookup.h new file mode 100644 index 000000000..54ccc979c --- /dev/null +++ b/dep/StormLib/src/jenkins/lookup.h @@ -0,0 +1,24 @@ +#ifndef __LOOKUP3_H__ +#define __LOOKUP3_H__ + +#ifdef WIN32 +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +#else +#include /* defines uint32_t etc */ +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +uint32_t hashlittle(const void *key, size_t length, uint32_t initval); +void hashlittle2(const void *key, size_t length, uint32_t *pc, uint32_t *pb); + +#ifdef __cplusplus +} +#endif + +#endif // __LOOKUP3_H__ diff --git a/dep/StormLib/src/jenkins/lookup3.c b/dep/StormLib/src/jenkins/lookup3.c new file mode 100644 index 000000000..6af56b481 --- /dev/null +++ b/dep/StormLib/src/jenkins/lookup3.c @@ -0,0 +1,1003 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ +//#define SELF_TEST 1 + +#include /* defines printf for tests */ +#include /* defines time_t for timings in the test */ + +#ifdef linux +#include /* attempt to define endianness */ +#include /* attempt to define endianness */ +#endif + +#include "lookup.h" + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +-------------------------------------------------------------------- + This works on all machines. To be useful, it requires + -- that the key be an array of uint32_t's, and + -- that the length be the number of uint32_t's in the key + + The function hashword() is identical to hashlittle() on little-endian + machines, and identical to hashbig() on big-endian machines, + except that the length has to be measured in uint32_ts rather than in + bytes. hashlittle() is more complicated than hashword() only because + hashlittle() has to dance around fitting the key bytes into registers. +-------------------------------------------------------------------- +*/ +uint32_t hashword( +const uint32_t *k, /* the key, an array of uint32_t values */ +size_t length, /* the length of the key, in uint32_ts */ +uint32_t initval) /* the previous hash, or an arbitrary value */ +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch(length) /* all the case statements fall through */ + { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + final(a,b,c); + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + return c; +} + + +/* +-------------------------------------------------------------------- +hashword2() -- same as hashword(), but take two seeds and return two +32-bit values. pc and pb must both be nonnull, and *pc and *pb must +both be initialized with seeds. If you pass in (*pb)==0, the output +(*pc) will be the same as the return value from hashword(). +-------------------------------------------------------------------- +*/ +void hashword2 ( +const uint32_t *k, /* the key, an array of uint32_t values */ +size_t length, /* the length of the key, in uint32_ts */ +uint32_t *pc, /* IN: seed OUT: primary hash value */ +uint32_t *pb) /* IN: more seed OUT: secondary hash value */ +{ + uint32_t a,b,c; + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc; + c += *pb; + + /*------------------------------------------------- handle most of the key */ + while (length > 3) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 3; + k += 3; + } + + /*------------------------------------------- handle the last 3 uint32_t's */ + switch(length) /* all the case statements fall through */ + { + case 3 : c+=k[2]; + case 2 : b+=k[1]; + case 1 : a+=k[0]; + final(a,b,c); + case 0: /* case 0: nothing left to add */ + break; + } + /*------------------------------------------------------ report the result */ + *pc=c; *pb=b; +} + + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + +/* + * hashlittle2: return 2 32-bit hash values + * + * This is identical to hashlittle(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + */ +void hashlittle2( + const void *key, /* the key to hash */ + size_t length, /* length of the key */ + uint32_t *pc, /* IN: primary initval, OUT: primary hash */ + uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */ +{ + uint32_t a,b,c; /* internal state */ + union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc; + c += *pb; + + u.ptr = key; + if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + const uint8_t *k8; + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; + case 11: c+=((uint32_t)k[10])<<16; + case 10: c+=((uint32_t)k[9])<<8; + case 9 : c+=k[8]; + case 8 : b+=((uint32_t)k[7])<<24; + case 7 : b+=((uint32_t)k[6])<<16; + case 6 : b+=((uint32_t)k[5])<<8; + case 5 : b+=k[4]; + case 4 : a+=((uint32_t)k[3])<<24; + case 3 : a+=((uint32_t)k[2])<<16; + case 2 : a+=((uint32_t)k[1])<<8; + case 1 : a+=k[0]; + break; + case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */ + } + } + + final(a,b,c); + *pc=c; *pb=b; +} + + + +/* + * hashbig(): + * This is the same as hashword() on big-endian machines. It is different + * from hashlittle() on all machines. hashbig() takes advantage of + * big-endian byte ordering. + */ +uint32_t hashbig( const void *key, size_t length, uint32_t initval) +{ + uint32_t a,b,c; + union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */ + + /* Set up the internal state */ + a = b = c = 0xdeadbeef + ((uint32_t)length) + initval; + + u.ptr = key; + if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) { + const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ + const uint8_t *k8; + + /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]<<8" actually reads beyond the end of the string, but + * then shifts out the part it's not allowed to read. Because the + * string is aligned, the illegal read is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef VALGRIND + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff00; a+=k[0]; break; + case 6 : b+=k[1]&0xffff0000; a+=k[0]; break; + case 5 : b+=k[1]&0xff000000; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff00; break; + case 2 : a+=k[0]&0xffff0000; break; + case 1 : a+=k[0]&0xff000000; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<8; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<16; /* fall through */ + case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */ + case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */ + case 1 : a+=((uint32_t)k8[0])<<24; break; + case 0 : return c; + } + +#endif /* !VALGRIND */ + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += ((uint32_t)k[0])<<24; + a += ((uint32_t)k[1])<<16; + a += ((uint32_t)k[2])<<8; + a += ((uint32_t)k[3]); + b += ((uint32_t)k[4])<<24; + b += ((uint32_t)k[5])<<16; + b += ((uint32_t)k[6])<<8; + b += ((uint32_t)k[7]); + c += ((uint32_t)k[8])<<24; + c += ((uint32_t)k[9])<<16; + c += ((uint32_t)k[10])<<8; + c += ((uint32_t)k[11]); + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=k[11]; + case 11: c+=((uint32_t)k[10])<<8; + case 10: c+=((uint32_t)k[9])<<16; + case 9 : c+=((uint32_t)k[8])<<24; + case 8 : b+=k[7]; + case 7 : b+=((uint32_t)k[6])<<8; + case 6 : b+=((uint32_t)k[5])<<16; + case 5 : b+=((uint32_t)k[4])<<24; + case 4 : a+=k[3]; + case 3 : a+=((uint32_t)k[2])<<8; + case 2 : a+=((uint32_t)k[1])<<16; + case 1 : a+=((uint32_t)k[0])<<24; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} + + +#ifdef SELF_TEST + +/* used for timings */ +void driver1() +{ + uint8_t buf[256]; + uint32_t i; + uint32_t h=0; + time_t a,z; + + time(&a); + for (i=0; i<256; ++i) buf[i] = 'x'; + for (i=0; i<1; ++i) + { + h = hashlittle(&buf[0],1,h); + } + time(&z); + if (z-a > 0) printf("time %d %.8x\n", z-a, h); +} + +/* check that every input bit changes every output bit half the time */ +#define HASHSTATE 1 +#define HASHLEN 1 +#define MAXPAIR 60 +#define MAXLEN 70 +void driver2() +{ + uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1]; + uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z; + uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE]; + uint32_t x[HASHSTATE],y[HASHSTATE]; + uint32_t hlen; + + printf("No more than %d trials should ever be needed \n",MAXPAIR/2); + for (hlen=0; hlen < MAXLEN; ++hlen) + { + z=0; + for (i=0; i>(8-j)); + c[0] = hashlittle(a, hlen, m); + b[i] ^= ((k+1)<>(8-j)); + d[0] = hashlittle(b, hlen, m); + /* check every bit is 1, 0, set, and not set at least once */ + for (l=0; lz) z=k; + if (k==MAXPAIR) + { + printf("Some bit didn't change: "); + printf("%.8x %.8x %.8x %.8x %.8x %.8x ", + e[0],f[0],g[0],h[0],x[0],y[0]); + printf("i %d j %d m %d len %d\n", i, j, m, hlen); + } + if (z==MAXPAIR) goto done; + } + } + } + done: + if (z < MAXPAIR) + { + printf("Mix success %2d bytes %2d initvals ",i,m); + printf("required %d trials\n", z/2); + } + } + printf("\n"); +} + +/* Check for reading beyond the end of the buffer and alignment problems */ +void driver3() +{ + uint8_t buf[MAXLEN+20], *b; + uint32_t len; + uint8_t q[] = "This is the time for all good men to come to the aid of their country..."; + uint32_t h; + uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country..."; + uint32_t i; + uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country..."; + uint32_t j; + uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country..."; + uint32_t ref,x,y; + uint8_t *p; + + printf("Endianness. These lines should all be the same (for values filled in):\n"); + printf("%.8x %.8x %.8x\n", + hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13), + hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13), + hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13)); + p = q; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qq[1]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqq[2]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + p = &qqqq[3]; + printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n", + hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13), + hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13), + hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13), + hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13), + hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13), + hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13)); + printf("\n"); + + /* check that hashlittle2 and hashlittle produce the same results */ + i=47; j=0; + hashlittle2(q, sizeof(q), &i, &j); + if (hashlittle(q, sizeof(q), 47) != i) + printf("hashlittle2 and hashlittle mismatch\n"); + + /* check that hashword2 and hashword produce the same results */ + len = 0xdeadbeef; + i=47, j=0; + hashword2(&len, 1, &i, &j); + if (hashword(&len, 1, 47) != i) + printf("hashword2 and hashword mismatch %x %x\n", + i, hashword(&len, 1, 47)); + + /* check hashlittle doesn't read before or after the ends of the string */ + for (h=0, b=buf+1; h<8; ++h, ++b) + { + for (i=0; i + +#include "LzFind.h" +#include "LzHash.h" + +#define kEmptyHashValue 0 +#define kMaxValForNormalize ((UInt32)0xFFFFFFFF) +#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */ +#define kNormalizeMask (~(kNormalizeStepMin - 1)) +#define kMaxHistorySize ((UInt32)3 << 30) + +#define kStartMaxLen 3 + +static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + if (!p->directInput) + { + alloc->Free(alloc, p->bufferBase); + p->bufferBase = 0; + } +} + +/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */ + +static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc) +{ + UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv; + if (p->directInput) + { + p->blockSize = blockSize; + return 1; + } + if (p->bufferBase == 0 || p->blockSize != blockSize) + { + LzInWindow_Free(p, alloc); + p->blockSize = blockSize; + p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize); + } + return (p->bufferBase != 0); +} + +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; } +Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; } + +UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; } + +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue) +{ + p->posLimit -= subValue; + p->pos -= subValue; + p->streamPos -= subValue; +} + +static void MatchFinder_ReadBlock(CMatchFinder *p) +{ + if (p->streamEndWasReached || p->result != SZ_OK) + return; + if (p->directInput) + { + UInt32 curSize = 0xFFFFFFFF - p->streamPos; + if (curSize > p->directInputRem) + curSize = (UInt32)p->directInputRem; + p->directInputRem -= curSize; + p->streamPos += curSize; + if (p->directInputRem == 0) + p->streamEndWasReached = 1; + return; + } + for (;;) + { + Byte *dest = p->buffer + (p->streamPos - p->pos); + size_t size = (p->bufferBase + p->blockSize - dest); + if (size == 0) + return; + p->result = p->stream->Read(p->stream, dest, &size); + if (p->result != SZ_OK) + return; + if (size == 0) + { + p->streamEndWasReached = 1; + return; + } + p->streamPos += (UInt32)size; + if (p->streamPos - p->pos > p->keepSizeAfter) + return; + } +} + +void MatchFinder_MoveBlock(CMatchFinder *p) +{ + memmove(p->bufferBase, + p->buffer - p->keepSizeBefore, + (size_t)(p->streamPos - p->pos + p->keepSizeBefore)); + p->buffer = p->bufferBase + p->keepSizeBefore; +} + +int MatchFinder_NeedMove(CMatchFinder *p) +{ + if (p->directInput) + return 0; + /* if (p->streamEndWasReached) return 0; */ + return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter); +} + +void MatchFinder_ReadIfRequired(CMatchFinder *p) +{ + if (p->streamEndWasReached) + return; + if (p->keepSizeAfter >= p->streamPos - p->pos) + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p) +{ + if (MatchFinder_NeedMove(p)) + MatchFinder_MoveBlock(p); + MatchFinder_ReadBlock(p); +} + +static void MatchFinder_SetDefaultSettings(CMatchFinder *p) +{ + p->cutValue = 32; + p->btMode = 1; + p->numHashBytes = 4; + p->bigHash = 0; +} + +#define kCrcPoly 0xEDB88320 + +void MatchFinder_Construct(CMatchFinder *p) +{ + UInt32 i; + p->bufferBase = 0; + p->directInput = 0; + p->hash = 0; + MatchFinder_SetDefaultSettings(p); + + for (i = 0; i < 256; i++) + { + UInt32 r = i; + int j; + for (j = 0; j < 8; j++) + r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1)); + p->crc[i] = r; + } +} + +static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hash); + p->hash = 0; +} + +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc) +{ + MatchFinder_FreeThisClassMemory(p, alloc); + LzInWindow_Free(p, alloc); +} + +static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc) +{ + size_t sizeInBytes = (size_t)num * sizeof(CLzRef); + if (sizeInBytes / sizeof(CLzRef) != num) + return 0; + return (CLzRef *)alloc->Alloc(alloc, sizeInBytes); +} + +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc) +{ + UInt32 sizeReserv; + if (historySize > kMaxHistorySize) + { + MatchFinder_Free(p, alloc); + return 0; + } + sizeReserv = historySize >> 1; + if (historySize > ((UInt32)2 << 30)) + sizeReserv = historySize >> 2; + sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19); + + p->keepSizeBefore = historySize + keepAddBufferBefore + 1; + p->keepSizeAfter = matchMaxLen + keepAddBufferAfter; + /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */ + if (LzInWindow_Create(p, sizeReserv, alloc)) + { + UInt32 newCyclicBufferSize = historySize + 1; + UInt32 hs; + p->matchMaxLen = matchMaxLen; + { + p->fixedHashSize = 0; + if (p->numHashBytes == 2) + hs = (1 << 16) - 1; + else + { + hs = historySize - 1; + hs |= (hs >> 1); + hs |= (hs >> 2); + hs |= (hs >> 4); + hs |= (hs >> 8); + hs >>= 1; + hs |= 0xFFFF; /* don't change it! It's required for Deflate */ + if (hs > (1 << 24)) + { + if (p->numHashBytes == 3) + hs = (1 << 24) - 1; + else + hs >>= 1; + } + } + p->hashMask = hs; + hs++; + if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size; + if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size; + if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size; + hs += p->fixedHashSize; + } + + { + UInt32 prevSize = p->hashSizeSum + p->numSons; + UInt32 newSize; + p->historySize = historySize; + p->hashSizeSum = hs; + p->cyclicBufferSize = newCyclicBufferSize; + p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize); + newSize = p->hashSizeSum + p->numSons; + if (p->hash != 0 && prevSize == newSize) + return 1; + MatchFinder_FreeThisClassMemory(p, alloc); + p->hash = AllocRefs(newSize, alloc); + if (p->hash != 0) + { + p->son = p->hash + p->hashSizeSum; + return 1; + } + } + } + MatchFinder_Free(p, alloc); + return 0; +} + +static void MatchFinder_SetLimits(CMatchFinder *p) +{ + UInt32 limit = kMaxValForNormalize - p->pos; + UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos; + if (limit2 < limit) + limit = limit2; + limit2 = p->streamPos - p->pos; + if (limit2 <= p->keepSizeAfter) + { + if (limit2 > 0) + limit2 = 1; + } + else + limit2 -= p->keepSizeAfter; + if (limit2 < limit) + limit = limit2; + { + UInt32 lenLimit = p->streamPos - p->pos; + if (lenLimit > p->matchMaxLen) + lenLimit = p->matchMaxLen; + p->lenLimit = lenLimit; + } + p->posLimit = p->pos + limit; +} + +void MatchFinder_Init(CMatchFinder *p) +{ + UInt32 i; + for (i = 0; i < p->hashSizeSum; i++) + p->hash[i] = kEmptyHashValue; + p->cyclicBufferPos = 0; + p->buffer = p->bufferBase; + p->pos = p->streamPos = p->cyclicBufferSize; + p->result = SZ_OK; + p->streamEndWasReached = 0; + MatchFinder_ReadBlock(p); + MatchFinder_SetLimits(p); +} + +static UInt32 MatchFinder_GetSubValue(CMatchFinder *p) +{ + return (p->pos - p->historySize - 1) & kNormalizeMask; +} + +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems) +{ + UInt32 i; + for (i = 0; i < numItems; i++) + { + UInt32 value = items[i]; + if (value <= subValue) + value = kEmptyHashValue; + else + value -= subValue; + items[i] = value; + } +} + +static void MatchFinder_Normalize(CMatchFinder *p) +{ + UInt32 subValue = MatchFinder_GetSubValue(p); + MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons); + MatchFinder_ReduceOffsets(p, subValue); +} + +static void MatchFinder_CheckLimits(CMatchFinder *p) +{ + if (p->pos == kMaxValForNormalize) + MatchFinder_Normalize(p); + if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos) + MatchFinder_CheckAndMoveAndRead(p); + if (p->cyclicBufferPos == p->cyclicBufferSize) + p->cyclicBufferPos = 0; + MatchFinder_SetLimits(p); +} + +static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + son[_cyclicBufferPos] = curMatch; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + return distances; + { + const Byte *pb = cur - delta; + curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)]; + if (pb[maxLen] == cur[maxLen] && *pb == *cur) + { + UInt32 len = 0; + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + return distances; + } + } + } + } +} + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue, + UInt32 *distances, UInt32 maxLen) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return distances; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return distances; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue) +{ + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + return; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + { + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + return; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } +} + +#define MOVE_POS \ + ++p->cyclicBufferPos; \ + p->buffer++; \ + if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p); + +#define MOVE_POS_RET MOVE_POS return offset; + +static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; } + +#define GET_MATCHES_HEADER2(minLen, ret_op) \ + UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \ + lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \ + cur = p->buffer; + +#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0) +#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue) + +#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue + +#define GET_MATCHES_FOOTER(offset, maxLen) \ + offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \ + distances + offset, maxLen) - distances); MOVE_POS_RET; + +#define SKIP_FOOTER \ + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS; + +static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 1) +} + +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = 0; + GET_MATCHES_FOOTER(offset, 2) +} + +static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, delta2, maxLen, offset; + GET_MATCHES_HEADER(3) + + HASH3_CALC; + + delta2 = p->pos - p->hash[hash2Value]; + curMatch = p->hash[kFix3HashSize + hashValue]; + + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + + + maxLen = 2; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[0] = maxLen; + distances[1] = delta2 - 1; + offset = 2; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + GET_MATCHES_FOOTER(offset, maxLen) +} + +static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset; + GET_MATCHES_HEADER(4) + + HASH4_CALC; + + delta2 = p->pos - p->hash[ hash2Value]; + delta3 = p->pos - p->hash[kFix3HashSize + hash3Value]; + curMatch = p->hash[kFix4HashSize + hashValue]; + + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + + maxLen = 1; + offset = 0; + if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur) + { + distances[0] = maxLen = 2; + distances[1] = delta2 - 1; + offset = 2; + } + if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur) + { + maxLen = 3; + distances[offset + 1] = delta3 - 1; + offset += 2; + delta2 = delta3; + } + if (offset != 0) + { + for (; maxLen != lenLimit; maxLen++) + if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen]) + break; + distances[offset - 2] = maxLen; + if (maxLen == lenLimit) + { + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS_RET; + } + } + if (maxLen < 3) + maxLen = 3; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances + offset, maxLen) - (distances)); + MOVE_POS_RET +} + +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances) +{ + UInt32 offset; + GET_MATCHES_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p), + distances, 2) - (distances)); + MOVE_POS_RET +} + +static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(2) + HASH2_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value; + SKIP_HEADER(3) + HASH3_CALC; + curMatch = p->hash[kFix3HashSize + hashValue]; + p->hash[hash2Value] = + p->hash[kFix3HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = p->pos; + p->hash[kFix4HashSize + hashValue] = p->pos; + SKIP_FOOTER + } + while (--num != 0); +} + +static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + UInt32 hash2Value, hash3Value; + SKIP_HEADER(4) + HASH4_CALC; + curMatch = p->hash[kFix4HashSize + hashValue]; + p->hash[ hash2Value] = + p->hash[kFix3HashSize + hash3Value] = + p->hash[kFix4HashSize + hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num) +{ + do + { + SKIP_HEADER(3) + HASH_ZIP_CALC; + curMatch = p->hash[hashValue]; + p->hash[hashValue] = p->pos; + p->son[p->cyclicBufferPos] = curMatch; + MOVE_POS + } + while (--num != 0); +} + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinder_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos; + if (!p->btMode) + { + vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip; + } + else if (p->numHashBytes == 2) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip; + } + else if (p->numHashBytes == 3) + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip; + } + else + { + vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches; + vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip; + } +} diff --git a/dep/StormLib/src/lzma/C/LzFind.h b/dep/StormLib/src/lzma/C/LzFind.h new file mode 100644 index 000000000..010c4b92b --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzFind.h @@ -0,0 +1,115 @@ +/* LzFind.h -- Match finder for LZ algorithms +2009-04-22 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_H +#define __LZ_FIND_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef UInt32 CLzRef; + +typedef struct _CMatchFinder +{ + Byte *buffer; + UInt32 pos; + UInt32 posLimit; + UInt32 streamPos; + UInt32 lenLimit; + + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */ + + UInt32 matchMaxLen; + CLzRef *hash; + CLzRef *son; + UInt32 hashMask; + UInt32 cutValue; + + Byte *bufferBase; + ISeqInStream *stream; + int streamEndWasReached; + + UInt32 blockSize; + UInt32 keepSizeBefore; + UInt32 keepSizeAfter; + + UInt32 numHashBytes; + int directInput; + size_t directInputRem; + int btMode; + int bigHash; + UInt32 historySize; + UInt32 fixedHashSize; + UInt32 hashSizeSum; + UInt32 numSons; + SRes result; + UInt32 crc[256]; +} CMatchFinder; + +#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer) +#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)]) + +#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos) + +int MatchFinder_NeedMove(CMatchFinder *p); +Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); +void MatchFinder_MoveBlock(CMatchFinder *p); +void MatchFinder_ReadIfRequired(CMatchFinder *p); + +void MatchFinder_Construct(CMatchFinder *p); + +/* Conditions: + historySize <= 3 GB + keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB +*/ +int MatchFinder_Create(CMatchFinder *p, UInt32 historySize, + UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter, + ISzAlloc *alloc); +void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc); +void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems); +void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue); + +UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *distances, UInt32 maxLen); + +/* +Conditions: + Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func. + Mf_GetPointerToCurrentPos_Func's result must be used only before any other function +*/ + +typedef void (*Mf_Init_Func)(void *object); +typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index); +typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object); +typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object); +typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances); +typedef void (*Mf_Skip_Func)(void *object, UInt32); + +typedef struct _IMatchFinder +{ + Mf_Init_Func Init; + Mf_GetIndexByte_Func GetIndexByte; + Mf_GetNumAvailableBytes_Func GetNumAvailableBytes; + Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos; + Mf_GetMatches_Func GetMatches; + Mf_Skip_Func Skip; +} IMatchFinder; + +void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable); + +void MatchFinder_Init(CMatchFinder *p); +UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances); +void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); +void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/StormLib/src/lzma/C/LzFindMt.c b/dep/StormLib/src/lzma/C/LzFindMt.c new file mode 100644 index 000000000..aa41ed98a --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzFindMt.c @@ -0,0 +1,793 @@ +/* LzFindMt.c -- multithreaded Match finder for LZ algorithms +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzHash.h" + +#include "LzFindMt.h" + +void MtSync_Construct(CMtSync *p) +{ + p->wasCreated = False; + p->csWasInitialized = False; + p->csWasEntered = False; + Thread_Construct(&p->thread); + Event_Construct(&p->canStart); + Event_Construct(&p->wasStarted); + Event_Construct(&p->wasStopped); + Semaphore_Construct(&p->freeSemaphore); + Semaphore_Construct(&p->filledSemaphore); +} + +void MtSync_GetNextBlock(CMtSync *p) +{ + if (p->needStart) + { + p->numProcessedBlocks = 1; + p->needStart = False; + p->stopWriting = False; + p->exit = False; + Event_Reset(&p->wasStarted); + Event_Reset(&p->wasStopped); + + Event_Set(&p->canStart); + Event_Wait(&p->wasStarted); + } + else + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + p->numProcessedBlocks++; + Semaphore_Release1(&p->freeSemaphore); + } + Semaphore_Wait(&p->filledSemaphore); + CriticalSection_Enter(&p->cs); + p->csWasEntered = True; +} + +/* MtSync_StopWriting must be called if Writing was started */ + +void MtSync_StopWriting(CMtSync *p) +{ + UInt32 myNumBlocks = p->numProcessedBlocks; + if (!Thread_WasCreated(&p->thread) || p->needStart) + return; + p->stopWriting = True; + if (p->csWasEntered) + { + CriticalSection_Leave(&p->cs); + p->csWasEntered = False; + } + Semaphore_Release1(&p->freeSemaphore); + + Event_Wait(&p->wasStopped); + + while (myNumBlocks++ != p->numProcessedBlocks) + { + Semaphore_Wait(&p->filledSemaphore); + Semaphore_Release1(&p->freeSemaphore); + } + p->needStart = True; +} + +void MtSync_Destruct(CMtSync *p) +{ + if (Thread_WasCreated(&p->thread)) + { + MtSync_StopWriting(p); + p->exit = True; + if (p->needStart) + Event_Set(&p->canStart); + Thread_Wait(&p->thread); + Thread_Close(&p->thread); + } + if (p->csWasInitialized) + { + CriticalSection_Delete(&p->cs); + p->csWasInitialized = False; + } + + Event_Close(&p->canStart); + Event_Close(&p->wasStarted); + Event_Close(&p->wasStopped); + Semaphore_Close(&p->freeSemaphore); + Semaphore_Close(&p->filledSemaphore); + + p->wasCreated = False; +} + +#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; } + +static SRes MtSync_Create2(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +{ + if (p->wasCreated) + return SZ_OK; + + RINOK_THREAD(CriticalSection_Init(&p->cs)); + p->csWasInitialized = True; + + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted)); + RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped)); + + RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks)); + RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks)); + + p->needStart = True; + + RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj)); + p->wasCreated = True; + return SZ_OK; +} + +static SRes MtSync_Create(CMtSync *p, unsigned (MY_STD_CALL *startAddress)(void *), void *obj, UInt32 numBlocks) +{ + SRes res = MtSync_Create2(p, startAddress, obj, numBlocks); + if (res != SZ_OK) + MtSync_Destruct(p); + return res; +} + +void MtSync_Init(CMtSync *p) { p->needStart = True; } + +#define kMtMaxValForNormalize 0xFFFFFFFF + +#define DEF_GetHeads2(name, v, action) \ +static void GetHeads ## name(const Byte *p, UInt32 pos, \ +UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \ +{ action; for (; numHeads != 0; numHeads--) { \ +const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } } + +#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;) + +DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), hashMask = hashMask; crc = crc; ) +DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask) +DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask) +DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask) +/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */ + +void HashThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->hashSync; + for (;;) + { + UInt32 numProcessedBlocks = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = numProcessedBlocks; + Event_Set(&p->wasStopped); + break; + } + + { + CMatchFinder *mf = mt->MatchFinder; + if (MatchFinder_NeedMove(mf)) + { + CriticalSection_Enter(&mt->btSync.cs); + CriticalSection_Enter(&mt->hashSync.cs); + { + const Byte *beforePtr = MatchFinder_GetPointerToCurrentPos(mf); + const Byte *afterPtr; + MatchFinder_MoveBlock(mf); + afterPtr = MatchFinder_GetPointerToCurrentPos(mf); + mt->pointerToCurPos -= beforePtr - afterPtr; + mt->buffer -= beforePtr - afterPtr; + } + CriticalSection_Leave(&mt->btSync.cs); + CriticalSection_Leave(&mt->hashSync.cs); + continue; + } + + Semaphore_Wait(&p->freeSemaphore); + + MatchFinder_ReadIfRequired(mf); + if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize)) + { + UInt32 subValue = (mf->pos - mf->historySize - 1); + MatchFinder_ReduceOffsets(mf, subValue); + MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, mf->hashMask + 1); + } + { + UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize; + UInt32 num = mf->streamPos - mf->pos; + heads[0] = 2; + heads[1] = num; + if (num >= mf->numHashBytes) + { + num = num - mf->numHashBytes + 1; + if (num > kMtHashBlockSize - 2) + num = kMtHashBlockSize - 2; + mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc); + heads[0] += num; + } + mf->pos += num; + mf->buffer += num; + } + } + + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p) +{ + MtSync_GetNextBlock(&p->hashSync); + p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize; + p->hashBufPosLimit += p->hashBuf[p->hashBufPos++]; + p->hashNumAvail = p->hashBuf[p->hashBufPos++]; +} + +#define kEmptyHashValue 0 + +/* #define MFMT_GM_INLINE */ + +#ifdef MFMT_GM_INLINE + +#define NO_INLINE MY_FAST_CALL + +Int32 NO_INLINE GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son, + UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue, + UInt32 *_distances, UInt32 _maxLen, const UInt32 *hash, Int32 limit, UInt32 size, UInt32 *posRes) +{ + do + { + UInt32 *distances = _distances + 1; + UInt32 curMatch = pos - *hash++; + + CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1; + CLzRef *ptr1 = son + (_cyclicBufferPos << 1); + UInt32 len0 = 0, len1 = 0; + UInt32 cutValue = _cutValue; + UInt32 maxLen = _maxLen; + for (;;) + { + UInt32 delta = pos - curMatch; + if (cutValue-- == 0 || delta >= _cyclicBufferSize) + { + *ptr0 = *ptr1 = kEmptyHashValue; + break; + } + { + CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1); + const Byte *pb = cur - delta; + UInt32 len = (len0 < len1 ? len0 : len1); + if (pb[len] == cur[len]) + { + if (++len != lenLimit && pb[len] == cur[len]) + while (++len != lenLimit) + if (pb[len] != cur[len]) + break; + if (maxLen < len) + { + *distances++ = maxLen = len; + *distances++ = delta - 1; + if (len == lenLimit) + { + *ptr1 = pair[0]; + *ptr0 = pair[1]; + break; + } + } + } + if (pb[len] < cur[len]) + { + *ptr1 = curMatch; + ptr1 = pair + 1; + curMatch = *ptr1; + len1 = len; + } + else + { + *ptr0 = curMatch; + ptr0 = pair; + curMatch = *ptr0; + len0 = len; + } + } + } + pos++; + _cyclicBufferPos++; + cur++; + { + UInt32 num = (UInt32)(distances - _distances); + *_distances = num - 1; + _distances += num; + limit -= num; + } + } + while (limit > 0 && --size != 0); + *posRes = pos; + return limit; +} + +#endif + +void BtGetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + UInt32 numProcessed = 0; + UInt32 curPos = 2; + UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); + distances[1] = p->hashNumAvail; + while (curPos < limit) + { + if (p->hashBufPos == p->hashBufPosLimit) + { + MatchFinderMt_GetNextBlock_Hash(p); + distances[1] = numProcessed + p->hashNumAvail; + if (p->hashNumAvail >= p->numHashBytes) + continue; + for (; p->hashNumAvail != 0; p->hashNumAvail--) + distances[curPos++] = 0; + break; + } + { + UInt32 size = p->hashBufPosLimit - p->hashBufPos; + UInt32 lenLimit = p->matchMaxLen; + UInt32 pos = p->pos; + UInt32 cyclicBufferPos = p->cyclicBufferPos; + if (lenLimit >= p->hashNumAvail) + lenLimit = p->hashNumAvail; + { + UInt32 size2 = p->hashNumAvail - lenLimit + 1; + if (size2 < size) + size = size2; + size2 = p->cyclicBufferSize - cyclicBufferPos; + if (size2 < size) + size = size2; + } + #ifndef MFMT_GM_INLINE + while (curPos < limit && size-- != 0) + { + UInt32 *startDistances = distances + curPos; + UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++], + pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + startDistances + 1, p->numHashBytes - 1) - startDistances); + *startDistances = num - 1; + curPos += num; + cyclicBufferPos++; + pos++; + p->buffer++; + } + #else + { + UInt32 posRes; + curPos = limit - GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue, + distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos, (Int32)(limit - curPos) , size, &posRes); + p->hashBufPos += posRes - pos; + cyclicBufferPos += posRes - pos; + p->buffer += posRes - pos; + pos = posRes; + } + #endif + + numProcessed += pos - p->pos; + p->hashNumAvail -= pos - p->pos; + p->pos = pos; + if (cyclicBufferPos == p->cyclicBufferSize) + cyclicBufferPos = 0; + p->cyclicBufferPos = cyclicBufferPos; + } + } + distances[0] = curPos; +} + +void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex) +{ + CMtSync *sync = &p->hashSync; + if (!sync->needStart) + { + CriticalSection_Enter(&sync->cs); + sync->csWasEntered = True; + } + + BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize); + + if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize) + { + UInt32 subValue = p->pos - p->cyclicBufferSize; + MatchFinder_Normalize3(subValue, p->son, p->cyclicBufferSize * 2); + p->pos -= subValue; + } + + if (!sync->needStart) + { + CriticalSection_Leave(&sync->cs); + sync->csWasEntered = False; + } +} + +void BtThreadFunc(CMatchFinderMt *mt) +{ + CMtSync *p = &mt->btSync; + for (;;) + { + UInt32 blockIndex = 0; + Event_Wait(&p->canStart); + Event_Set(&p->wasStarted); + for (;;) + { + if (p->exit) + return; + if (p->stopWriting) + { + p->numProcessedBlocks = blockIndex; + MtSync_StopWriting(&mt->hashSync); + Event_Set(&p->wasStopped); + break; + } + Semaphore_Wait(&p->freeSemaphore); + BtFillBlock(mt, blockIndex++); + Semaphore_Release1(&p->filledSemaphore); + } + } +} + +void MatchFinderMt_Construct(CMatchFinderMt *p) +{ + p->hashBuf = 0; + MtSync_Construct(&p->hashSync); + MtSync_Construct(&p->btSync); +} + +void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->hashBuf); + p->hashBuf = 0; +} + +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc) +{ + MtSync_Destruct(&p->hashSync); + MtSync_Destruct(&p->btSync); + MatchFinderMt_FreeMem(p, alloc); +} + +#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks) +#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks) + +static unsigned MY_STD_CALL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; } +static unsigned MY_STD_CALL BtThreadFunc2(void *p) +{ + Byte allocaDummy[0x180]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + BtThreadFunc((CMatchFinderMt *)p); + return 0; +} + +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc) +{ + CMatchFinder *mf = p->MatchFinder; + p->historySize = historySize; + if (kMtBtBlockSize <= matchMaxLen * 4) + return SZ_ERROR_PARAM; + if (p->hashBuf == 0) + { + p->hashBuf = (UInt32 *)alloc->Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32)); + if (p->hashBuf == 0) + return SZ_ERROR_MEM; + p->btBuf = p->hashBuf + kHashBufferSize; + } + keepAddBufferBefore += (kHashBufferSize + kBtBufferSize); + keepAddBufferAfter += kMtHashBlockSize; + if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc)) + return SZ_ERROR_MEM; + + RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks)); + RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks)); + return SZ_OK; +} + +/* Call it after ReleaseStream / SetStream */ +void MatchFinderMt_Init(CMatchFinderMt *p) +{ + CMatchFinder *mf = p->MatchFinder; + p->btBufPos = p->btBufPosLimit = 0; + p->hashBufPos = p->hashBufPosLimit = 0; + MatchFinder_Init(mf); + p->pointerToCurPos = MatchFinder_GetPointerToCurrentPos(mf); + p->btNumAvailBytes = 0; + p->lzPos = p->historySize + 1; + + p->hash = mf->hash; + p->fixedHashSize = mf->fixedHashSize; + p->crc = mf->crc; + + p->son = mf->son; + p->matchMaxLen = mf->matchMaxLen; + p->numHashBytes = mf->numHashBytes; + p->pos = mf->pos; + p->buffer = mf->buffer; + p->cyclicBufferPos = mf->cyclicBufferPos; + p->cyclicBufferSize = mf->cyclicBufferSize; + p->cutValue = mf->cutValue; +} + +/* ReleaseStream is required to finish multithreading */ +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p) +{ + MtSync_StopWriting(&p->btSync); + /* p->MatchFinder->ReleaseStream(); */ +} + +void MatchFinderMt_Normalize(CMatchFinderMt *p) +{ + MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize); + p->lzPos = p->historySize + 1; +} + +void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p) +{ + UInt32 blockIndex; + MtSync_GetNextBlock(&p->btSync); + blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask); + p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize; + p->btBufPosLimit += p->btBuf[p->btBufPos++]; + p->btNumAvailBytes = p->btBuf[p->btBufPos++]; + if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize) + MatchFinderMt_Normalize(p); +} + +const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p) +{ + return p->pointerToCurPos; +} + +#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p); + +UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p) +{ + GET_NEXT_BLOCK_IF_REQUIRED; + return p->btNumAvailBytes; +} + +Byte MatchFinderMt_GetIndexByte(CMatchFinderMt *p, Int32 index) +{ + return p->pointerToCurPos[index]; +} + +UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, curMatch2; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH2_CALC + + curMatch2 = hash[hash2Value]; + hash[hash2Value] = lzPos; + + if (curMatch2 >= matchMinPos) + if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + *distances++ = 2; + *distances++ = lzPos - curMatch2 - 1; + } + return distances; +} + +UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, curMatch2, curMatch3; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH3_CALC + + curMatch2 = hash[ hash2Value]; + curMatch3 = hash[kFix3HashSize + hash3Value]; + + hash[ hash2Value] = + hash[kFix3HashSize + hash3Value] = + lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + *distances++ = 3; + *distances++ = lzPos - curMatch3 - 1; + } + return distances; +} + +/* +UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances) +{ + UInt32 hash2Value, hash3Value, hash4Value, curMatch2, curMatch3, curMatch4; + UInt32 *hash = p->hash; + const Byte *cur = p->pointerToCurPos; + UInt32 lzPos = p->lzPos; + MT_HASH4_CALC + + curMatch2 = hash[ hash2Value]; + curMatch3 = hash[kFix3HashSize + hash3Value]; + curMatch4 = hash[kFix4HashSize + hash4Value]; + + hash[ hash2Value] = + hash[kFix3HashSize + hash3Value] = + hash[kFix4HashSize + hash4Value] = + lzPos; + + if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch2 - 1; + if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2]) + { + distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3; + return distances + 2; + } + distances[0] = 2; + distances += 2; + } + if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0]) + { + distances[1] = lzPos - curMatch3 - 1; + if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3]) + { + distances[0] = 4; + return distances + 2; + } + distances[0] = 3; + distances += 2; + } + + if (curMatch4 >= matchMinPos) + if ( + cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] && + cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3] + ) + { + *distances++ = 4; + *distances++ = lzPos - curMatch4 - 1; + } + return distances; +} +*/ + +#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++; + +UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + p->btNumAvailBytes--; + { + UInt32 i; + for (i = 0; i < len; i += 2) + { + *distances++ = *btBuf++; + *distances++ = *btBuf++; + } + } + INCREASE_LZ_POS + return len; +} + +UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances) +{ + const UInt32 *btBuf = p->btBuf + p->btBufPos; + UInt32 len = *btBuf++; + p->btBufPos += 1 + len; + + if (len == 0) + { + if (p->btNumAvailBytes-- >= 4) + len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances)); + } + else + { + /* Condition: there are matches in btBuf with length < p->numHashBytes */ + UInt32 *distances2; + p->btNumAvailBytes--; + distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances); + do + { + *distances2++ = *btBuf++; + *distances2++ = *btBuf++; + } + while ((len -= 2) != 0); + len = (UInt32)(distances2 - (distances)); + } + INCREASE_LZ_POS + return len; +} + +#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED +#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash; +#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0); + +void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER2_MT { p->btNumAvailBytes--; + SKIP_FOOTER_MT +} + +void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(2) + UInt32 hash2Value; + MT_HASH2_CALC + hash[hash2Value] = p->lzPos; + SKIP_FOOTER_MT +} + +void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(3) + UInt32 hash2Value, hash3Value; + MT_HASH3_CALC + hash[kFix3HashSize + hash3Value] = + hash[ hash2Value] = + p->lzPos; + SKIP_FOOTER_MT +} + +/* +void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num) +{ + SKIP_HEADER_MT(4) + UInt32 hash2Value, hash3Value, hash4Value; + MT_HASH4_CALC + hash[kFix4HashSize + hash4Value] = + hash[kFix3HashSize + hash3Value] = + hash[ hash2Value] = + p->lzPos; + SKIP_FOOTER_MT +} +*/ + +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable) +{ + vTable->Init = (Mf_Init_Func)MatchFinderMt_Init; + vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinderMt_GetIndexByte; + vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes; + vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches; + switch(p->MatchFinder->numHashBytes) + { + case 2: + p->GetHeadsFunc = GetHeads2; + p->MixMatchesFunc = (Mf_Mix_Matches)0; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip; + vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches; + break; + case 3: + p->GetHeadsFunc = GetHeads3; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip; + break; + default: + /* case 4: */ + p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4; + /* p->GetHeadsFunc = GetHeads4; */ + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip; + break; + /* + default: + p->GetHeadsFunc = GetHeads5; + p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4; + vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip; + break; + */ + } +} diff --git a/dep/StormLib/src/lzma/C/LzFindMt.h b/dep/StormLib/src/lzma/C/LzFindMt.h new file mode 100644 index 000000000..b985af5fe --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzFindMt.h @@ -0,0 +1,105 @@ +/* LzFindMt.h -- multithreaded Match finder for LZ algorithms +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZ_FIND_MT_H +#define __LZ_FIND_MT_H + +#include "LzFind.h" +#include "Threads.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define kMtHashBlockSize (1 << 13) +#define kMtHashNumBlocks (1 << 3) +#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1) + +#define kMtBtBlockSize (1 << 14) +#define kMtBtNumBlocks (1 << 6) +#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1) + +typedef struct _CMtSync +{ + Bool wasCreated; + Bool needStart; + Bool exit; + Bool stopWriting; + + CThread thread; + CAutoResetEvent canStart; + CAutoResetEvent wasStarted; + CAutoResetEvent wasStopped; + CSemaphore freeSemaphore; + CSemaphore filledSemaphore; + Bool csWasInitialized; + Bool csWasEntered; + CCriticalSection cs; + UInt32 numProcessedBlocks; +} CMtSync; + +typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances); + +/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */ +#define kMtCacheLineDummy 128 + +typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos, + UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc); + +typedef struct _CMatchFinderMt +{ + /* LZ */ + const Byte *pointerToCurPos; + UInt32 *btBuf; + UInt32 btBufPos; + UInt32 btBufPosLimit; + UInt32 lzPos; + UInt32 btNumAvailBytes; + + UInt32 *hash; + UInt32 fixedHashSize; + UInt32 historySize; + const UInt32 *crc; + + Mf_Mix_Matches MixMatchesFunc; + + /* LZ + BT */ + CMtSync btSync; + Byte btDummy[kMtCacheLineDummy]; + + /* BT */ + UInt32 *hashBuf; + UInt32 hashBufPos; + UInt32 hashBufPosLimit; + UInt32 hashNumAvail; + + CLzRef *son; + UInt32 matchMaxLen; + UInt32 numHashBytes; + UInt32 pos; + Byte *buffer; + UInt32 cyclicBufferPos; + UInt32 cyclicBufferSize; /* it must be historySize + 1 */ + UInt32 cutValue; + + /* BT + Hash */ + CMtSync hashSync; + /* Byte hashDummy[kMtCacheLineDummy]; */ + + /* Hash */ + Mf_GetHeads GetHeadsFunc; + CMatchFinder *MatchFinder; +} CMatchFinderMt; + +void MatchFinderMt_Construct(CMatchFinderMt *p); +void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAlloc *alloc); +SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore, + UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAlloc *alloc); +void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable); +void MatchFinderMt_ReleaseStream(CMatchFinderMt *p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/StormLib/src/lzma/C/LzHash.h b/dep/StormLib/src/lzma/C/LzHash.h new file mode 100644 index 000000000..f3e89966c --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzHash.h @@ -0,0 +1,54 @@ +/* LzHash.h -- HASH functions for LZ algorithms +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZ_HASH_H +#define __LZ_HASH_H + +#define kHash2Size (1 << 10) +#define kHash3Size (1 << 16) +#define kHash4Size (1 << 20) + +#define kFix3HashSize (kHash2Size) +#define kFix4HashSize (kHash2Size + kHash3Size) +#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size) + +#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8); + +#define HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; } + +#define HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; } + +#define HASH5_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \ + hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \ + hash4Value &= (kHash4Size - 1); } + +/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */ +#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF; + + +#define MT_HASH2_CALC \ + hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1); + +#define MT_HASH3_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); } + +#define MT_HASH4_CALC { \ + UInt32 temp = p->crc[cur[0]] ^ cur[1]; \ + hash2Value = temp & (kHash2Size - 1); \ + hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \ + hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); } + +#endif diff --git a/dep/StormLib/src/lzma/C/LzmaDec.c b/dep/StormLib/src/lzma/C/LzmaDec.c new file mode 100644 index 000000000..2036761bf --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzmaDec.c @@ -0,0 +1,999 @@ +/* LzmaDec.c -- LZMA Decoder +2009-09-20 : Igor Pavlov : Public domain */ + +#include "LzmaDec.h" + +#include + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 + +#define RC_INIT_SIZE 5 + +#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits)); +#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); +#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \ + { UPDATE_0(p); i = (i + i); A0; } else \ + { UPDATE_1(p); i = (i + i) + 1; A1; } +#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;) + +#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); } +#define TREE_DECODE(probs, limit, i) \ + { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; } + +/* #define _LZMA_SIZE_OPT */ + +#ifdef _LZMA_SIZE_OPT +#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i) +#else +#define TREE_6_DECODE(probs, i) \ + { i = 1; \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + TREE_GET_BIT(probs, i); \ + i -= 0x40; } +#endif + +#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); } + +#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound) +#define UPDATE_0_CHECK range = bound; +#define UPDATE_1_CHECK range -= bound; code -= bound; +#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \ + { UPDATE_0_CHECK; i = (i + i); A0; } else \ + { UPDATE_1_CHECK; i = (i + i) + 1; A1; } +#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;) +#define TREE_DECODE_CHECK(probs, limit, i) \ + { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; } + + +#define kNumPosBitsMax 4 +#define kNumPosStatesMax (1 << kNumPosBitsMax) + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define LenChoice 0 +#define LenChoice2 (LenChoice + 1) +#define LenLow (LenChoice2 + 1) +#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits)) +#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits)) +#define kNumLenProbs (LenHigh + kLenNumHighSymbols) + + +#define kNumStates 12 +#define kNumLitStates 7 + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#define kNumPosSlotBits 6 +#define kNumLenToPosStates 4 + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) + +#define kMatchMinLen 2 +#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define IsMatch 0 +#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax)) +#define IsRepG0 (IsRep + kNumStates) +#define IsRepG1 (IsRepG0 + kNumStates) +#define IsRepG2 (IsRepG1 + kNumStates) +#define IsRep0Long (IsRepG2 + kNumStates) +#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax)) +#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits)) +#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex) +#define LenCoder (Align + kAlignTableSize) +#define RepLenCoder (LenCoder + kNumLenProbs) +#define Literal (RepLenCoder + kNumLenProbs) + +#define LZMA_BASE_SIZE 1846 +#define LZMA_LIT_SIZE 768 + +#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp))) + +#if Literal != LZMA_BASE_SIZE +StopCompilingDueBUG +#endif + +#define LZMA_DIC_MIN (1 << 12) + +/* First LZMA-symbol is always decoded. +And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization +Out: + Result: + SZ_OK - OK + SZ_ERROR_DATA - Error + p->remainLen: + < kMatchSpecLenStart : normal remain + = kMatchSpecLenStart : finished + = kMatchSpecLenStart + 1 : Flush marker + = kMatchSpecLenStart + 2 : State Init Marker +*/ + +static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + CLzmaProb *probs = p->probs; + + unsigned state = p->state; + UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3]; + unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1; + unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1; + unsigned lc = p->prop.lc; + + Byte *dic = p->dic; + SizeT dicBufSize = p->dicBufSize; + SizeT dicPos = p->dicPos; + + UInt32 processedPos = p->processedPos; + UInt32 checkDicSize = p->checkDicSize; + unsigned len = 0; + + const Byte *buf = p->buf; + UInt32 range = p->range; + UInt32 code = p->code; + + do + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = processedPos & pbMask; + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + unsigned symbol; + UPDATE_0(prob); + prob = probs + Literal; + if (checkDicSize != 0 || processedPos != 0) + prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) + + (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc)))); + + if (state < kNumLitStates) + { + state -= (state < 4) ? state : 3; + symbol = 1; + do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + unsigned offs = 0x100; + state -= (state < 10) ? 3 : 6; + symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + dic[dicPos++] = (Byte)symbol; + processedPos++; + continue; + } + else + { + UPDATE_1(prob); + prob = probs + IsRep + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + state += kNumStates; + prob = probs + LenCoder; + } + else + { + UPDATE_1(prob); + if (checkDicSize == 0 && processedPos == 0) + return SZ_ERROR_DATA; + prob = probs + IsRepG0 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0(prob) + { + UPDATE_0(prob); + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + processedPos++; + state = state < kNumLitStates ? 9 : 11; + continue; + } + UPDATE_1(prob); + } + else + { + UInt32 distance; + UPDATE_1(prob); + prob = probs + IsRepG1 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep1; + } + else + { + UPDATE_1(prob); + prob = probs + IsRepG2 + state; + IF_BIT_0(prob) + { + UPDATE_0(prob); + distance = rep2; + } + else + { + UPDATE_1(prob); + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < kNumLitStates ? 8 : 11; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = (1 << kLenNumLowBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenChoice2; + IF_BIT_0(probLen) + { + UPDATE_0(probLen); + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = (1 << kLenNumMidBits); + } + else + { + UPDATE_1(probLen); + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = (1 << kLenNumHighBits); + } + } + TREE_DECODE(probLen, limit, len); + len += offset; + } + + if (state >= kNumStates) + { + UInt32 distance; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits); + TREE_6_DECODE(prob, distance); + if (distance >= kStartPosModelIndex) + { + unsigned posSlot = (unsigned)distance; + int numDirectBits = (int)(((distance >> 1) - 1)); + distance = (2 | (distance & 1)); + if (posSlot < kEndPosModelIndex) + { + distance <<= numDirectBits; + prob = probs + SpecPos + distance - posSlot - 1; + { + UInt32 mask = 1; + unsigned i = 1; + do + { + GET_BIT2(prob + i, i, ; , distance |= mask); + mask <<= 1; + } + while (--numDirectBits != 0); + } + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE + range >>= 1; + + { + UInt32 t; + code -= range; + t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */ + distance = (distance << 1) + (t + 1); + code += range & t; + } + /* + distance <<= 1; + if (code >= range) + { + code -= range; + distance |= 1; + } + */ + } + while (--numDirectBits != 0); + prob = probs + Align; + distance <<= kNumAlignBits; + { + unsigned i = 1; + GET_BIT2(prob + i, i, ; , distance |= 1); + GET_BIT2(prob + i, i, ; , distance |= 2); + GET_BIT2(prob + i, i, ; , distance |= 4); + GET_BIT2(prob + i, i, ; , distance |= 8); + } + if (distance == (UInt32)0xFFFFFFFF) + { + len += kMatchSpecLenStart; + state -= kNumStates; + break; + } + } + } + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + rep0 = distance + 1; + if (checkDicSize == 0) + { + if (distance >= processedPos) + return SZ_ERROR_DATA; + } + else if (distance >= checkDicSize) + return SZ_ERROR_DATA; + state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3; + } + + len += kMatchMinLen; + + if (limit == dicPos) + return SZ_ERROR_DATA; + { + SizeT rem = limit - dicPos; + unsigned curLen = ((rem < len) ? (unsigned)rem : len); + SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0); + + processedPos += curLen; + + len -= curLen; + if (pos + curLen <= dicBufSize) + { + Byte *dest = dic + dicPos; + ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos; + const Byte *lim = dest + curLen; + dicPos += curLen; + do + *(dest) = (Byte)*(dest + src); + while (++dest != lim); + } + else + { + do + { + dic[dicPos++] = dic[pos]; + if (++pos == dicBufSize) + pos = 0; + } + while (--curLen != 0); + } + } + } + } + while (dicPos < limit && buf < bufLimit); + NORMALIZE; + p->buf = buf; + p->range = range; + p->code = code; + p->remainLen = len; + p->dicPos = dicPos; + p->processedPos = processedPos; + p->reps[0] = rep0; + p->reps[1] = rep1; + p->reps[2] = rep2; + p->reps[3] = rep3; + p->state = state; + + return SZ_OK; +} + +static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit) +{ + if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart) + { + Byte *dic = p->dic; + SizeT dicPos = p->dicPos; + SizeT dicBufSize = p->dicBufSize; + unsigned len = p->remainLen; + UInt32 rep0 = p->reps[0]; + if (limit - dicPos < len) + len = (unsigned)(limit - dicPos); + + if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len) + p->checkDicSize = p->prop.dicSize; + + p->processedPos += len; + p->remainLen -= len; + while (len-- != 0) + { + dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)]; + dicPos++; + } + p->dicPos = dicPos; + } +} + +static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit) +{ + do + { + SizeT limit2 = limit; + if (p->checkDicSize == 0) + { + UInt32 rem = p->prop.dicSize - p->processedPos; + if (limit - p->dicPos > rem) + limit2 = p->dicPos + rem; + } + RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit)); + if (p->processedPos >= p->prop.dicSize) + p->checkDicSize = p->prop.dicSize; + LzmaDec_WriteRem(p, limit); + } + while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart); + + if (p->remainLen > kMatchSpecLenStart) + { + p->remainLen = kMatchSpecLenStart; + } + return 0; +} + +typedef enum +{ + DUMMY_ERROR, /* unexpected end of input stream */ + DUMMY_LIT, + DUMMY_MATCH, + DUMMY_REP +} ELzmaDummy; + +static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize) +{ + UInt32 range = p->range; + UInt32 code = p->code; + const Byte *bufLimit = buf + inSize; + CLzmaProb *probs = p->probs; + unsigned state = p->state; + ELzmaDummy res; + + { + CLzmaProb *prob; + UInt32 bound; + unsigned ttt; + unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1); + + prob = probs + IsMatch + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK + + /* if (bufLimit - buf >= 7) return DUMMY_LIT; */ + + prob = probs + Literal; + if (p->checkDicSize != 0 || p->processedPos != 0) + prob += (LZMA_LIT_SIZE * + ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) + + (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc)))); + + if (state < kNumLitStates) + { + unsigned symbol = 1; + do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100); + } + else + { + unsigned matchByte = p->dic[p->dicPos - p->reps[0] + + ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)]; + unsigned offs = 0x100; + unsigned symbol = 1; + do + { + unsigned bit; + CLzmaProb *probLit; + matchByte <<= 1; + bit = (matchByte & offs); + probLit = prob + offs + bit + symbol; + GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit) + } + while (symbol < 0x100); + } + res = DUMMY_LIT; + } + else + { + unsigned len; + UPDATE_1_CHECK; + + prob = probs + IsRep + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + state = 0; + prob = probs + LenCoder; + res = DUMMY_MATCH; + } + else + { + UPDATE_1_CHECK; + res = DUMMY_REP; + prob = probs + IsRepG0 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + NORMALIZE_CHECK; + return DUMMY_REP; + } + else + { + UPDATE_1_CHECK; + } + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG1 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + prob = probs + IsRepG2 + state; + IF_BIT_0_CHECK(prob) + { + UPDATE_0_CHECK; + } + else + { + UPDATE_1_CHECK; + } + } + } + state = kNumStates; + prob = probs + RepLenCoder; + } + { + unsigned limit, offset; + CLzmaProb *probLen = prob + LenChoice; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenLow + (posState << kLenNumLowBits); + offset = 0; + limit = 1 << kLenNumLowBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenChoice2; + IF_BIT_0_CHECK(probLen) + { + UPDATE_0_CHECK; + probLen = prob + LenMid + (posState << kLenNumMidBits); + offset = kLenNumLowSymbols; + limit = 1 << kLenNumMidBits; + } + else + { + UPDATE_1_CHECK; + probLen = prob + LenHigh; + offset = kLenNumLowSymbols + kLenNumMidSymbols; + limit = 1 << kLenNumHighBits; + } + } + TREE_DECODE_CHECK(probLen, limit, len); + len += offset; + } + + if (state < 4) + { + unsigned posSlot; + prob = probs + PosSlot + + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << + kNumPosSlotBits); + TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot); + if (posSlot >= kStartPosModelIndex) + { + int numDirectBits = ((posSlot >> 1) - 1); + + /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */ + + if (posSlot < kEndPosModelIndex) + { + prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1; + } + else + { + numDirectBits -= kNumAlignBits; + do + { + NORMALIZE_CHECK + range >>= 1; + code -= range & (((code - range) >> 31) - 1); + /* if (code >= range) code -= range; */ + } + while (--numDirectBits != 0); + prob = probs + Align; + numDirectBits = kNumAlignBits; + } + { + unsigned i = 1; + do + { + GET_BIT_CHECK(prob + i, i); + } + while (--numDirectBits != 0); + } + } + } + } + } + NORMALIZE_CHECK; + return res; +} + + +static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data) +{ + p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]); + p->range = 0xFFFFFFFF; + p->needFlush = 0; +} + +void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState) +{ + p->needFlush = 1; + p->remainLen = 0; + p->tempBufSize = 0; + + if (initDic) + { + p->processedPos = 0; + p->checkDicSize = 0; + p->needInitState = 1; + } + if (initState) + p->needInitState = 1; +} + +void LzmaDec_Init(CLzmaDec *p) +{ + p->dicPos = 0; + LzmaDec_InitDicAndState(p, True, True); +} + +static void LzmaDec_InitStateReal(CLzmaDec *p) +{ + UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp)); + UInt32 i; + CLzmaProb *probs = p->probs; + for (i = 0; i < numProbs; i++) + probs[i] = kBitModelTotal >> 1; + p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1; + p->state = 0; + p->needInitState = 0; +} + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen, + ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT inSize = *srcLen; + (*srcLen) = 0; + LzmaDec_WriteRem(p, dicLimit); + + *status = LZMA_STATUS_NOT_SPECIFIED; + + while (p->remainLen != kMatchSpecLenStart) + { + int checkEndMarkNow; + + if (p->needFlush != 0) + { + for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--) + p->tempBuf[p->tempBufSize++] = *src++; + if (p->tempBufSize < RC_INIT_SIZE) + { + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (p->tempBuf[0] != 0) + return SZ_ERROR_DATA; + + LzmaDec_InitRc(p, p->tempBuf); + p->tempBufSize = 0; + } + + checkEndMarkNow = 0; + if (p->dicPos >= dicLimit) + { + if (p->remainLen == 0 && p->code == 0) + { + *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK; + return SZ_OK; + } + if (finishMode == LZMA_FINISH_ANY) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_OK; + } + if (p->remainLen != 0) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + checkEndMarkNow = 1; + } + + if (p->needInitState) + LzmaDec_InitStateReal(p); + + if (p->tempBufSize == 0) + { + SizeT processed; + const Byte *bufLimit; + if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, src, inSize); + if (dummyRes == DUMMY_ERROR) + { + memcpy(p->tempBuf, src, inSize); + p->tempBufSize = (unsigned)inSize; + (*srcLen) += inSize; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + bufLimit = src; + } + else + bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX; + p->buf = src; + if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0) + return SZ_ERROR_DATA; + processed = (SizeT)(p->buf - src); + (*srcLen) += processed; + src += processed; + inSize -= processed; + } + else + { + unsigned rem = p->tempBufSize, lookAhead = 0; + while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize) + p->tempBuf[rem++] = src[lookAhead++]; + p->tempBufSize = rem; + if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow) + { + int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem); + if (dummyRes == DUMMY_ERROR) + { + (*srcLen) += lookAhead; + *status = LZMA_STATUS_NEEDS_MORE_INPUT; + return SZ_OK; + } + if (checkEndMarkNow && dummyRes != DUMMY_MATCH) + { + *status = LZMA_STATUS_NOT_FINISHED; + return SZ_ERROR_DATA; + } + } + p->buf = p->tempBuf; + if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0) + return SZ_ERROR_DATA; + lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf)); + (*srcLen) += lookAhead; + src += lookAhead; + inSize -= lookAhead; + p->tempBufSize = 0; + } + } + if (p->code == 0) + *status = LZMA_STATUS_FINISHED_WITH_MARK; + return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA; +} + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status) +{ + SizeT outSize = *destLen; + SizeT inSize = *srcLen; + *srcLen = *destLen = 0; + for (;;) + { + SizeT inSizeCur = inSize, outSizeCur, dicPos; + ELzmaFinishMode curFinishMode; + SRes res; + if (p->dicPos == p->dicBufSize) + p->dicPos = 0; + dicPos = p->dicPos; + if (outSize > p->dicBufSize - dicPos) + { + outSizeCur = p->dicBufSize; + curFinishMode = LZMA_FINISH_ANY; + } + else + { + outSizeCur = dicPos + outSize; + curFinishMode = finishMode; + } + + res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status); + src += inSizeCur; + inSize -= inSizeCur; + *srcLen += inSizeCur; + outSizeCur = p->dicPos - dicPos; + memcpy(dest, p->dic + dicPos, outSizeCur); + dest += outSizeCur; + outSize -= outSizeCur; + *destLen += outSizeCur; + if (res != 0) + return res; + if (outSizeCur == 0 || outSize == 0) + return SZ_OK; + } +} + +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->probs); + p->probs = 0; +} + +static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->dic); + p->dic = 0; +} + +void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc) +{ + LzmaDec_FreeProbs(p, alloc); + LzmaDec_FreeDict(p, alloc); +} + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size) +{ + UInt32 dicSize; + Byte d; + + if (size < LZMA_PROPS_SIZE) + return SZ_ERROR_UNSUPPORTED; + else + dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24); + + if (dicSize < LZMA_DIC_MIN) + dicSize = LZMA_DIC_MIN; + p->dicSize = dicSize; + + d = data[0]; + if (d >= (9 * 5 * 5)) + return SZ_ERROR_UNSUPPORTED; + + p->lc = d % 9; + d /= 9; + p->pb = d / 5; + p->lp = d % 5; + + return SZ_OK; +} + +static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc) +{ + UInt32 numProbs = LzmaProps_GetNumProbs(propNew); + if (p->probs == 0 || numProbs != p->numProbs) + { + LzmaDec_FreeProbs(p, alloc); + p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb)); + p->numProbs = numProbs; + if (p->probs == 0) + return SZ_ERROR_MEM; + } + return SZ_OK; +} + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc) +{ + CLzmaProps propNew; + SizeT dicBufSize; + RINOK(LzmaProps_Decode(&propNew, props, propsSize)); + RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc)); + dicBufSize = propNew.dicSize; + if (p->dic == 0 || dicBufSize != p->dicBufSize) + { + LzmaDec_FreeDict(p, alloc); + p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize); + if (p->dic == 0) + { + LzmaDec_FreeProbs(p, alloc); + return SZ_ERROR_MEM; + } + } + p->dicBufSize = dicBufSize; + p->prop = propNew; + return SZ_OK; +} + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc) +{ + CLzmaDec p; + SRes res; + SizeT inSize = *srcLen; + SizeT outSize = *destLen; + *srcLen = *destLen = 0; + if (inSize < RC_INIT_SIZE) + return SZ_ERROR_INPUT_EOF; + + LzmaDec_Construct(&p); + res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc); + if (res != 0) + return res; + p.dic = dest; + p.dicBufSize = outSize; + + LzmaDec_Init(&p); + + *srcLen = inSize; + res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status); + + if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT) + res = SZ_ERROR_INPUT_EOF; + + (*destLen) = p.dicPos; + LzmaDec_FreeProbs(&p, alloc); + return res; +} diff --git a/dep/StormLib/src/lzma/C/LzmaDec.h b/dep/StormLib/src/lzma/C/LzmaDec.h new file mode 100644 index 000000000..bf7f084ba --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzmaDec.h @@ -0,0 +1,231 @@ +/* LzmaDec.h -- LZMA Decoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_DEC_H +#define __LZMA_DEC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* #define _LZMA_PROB32 */ +/* _LZMA_PROB32 can increase the speed on some CPUs, + but memory usage for CLzmaDec::probs will be doubled in that case */ + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + + +/* ---------- LZMA Properties ---------- */ + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaProps +{ + unsigned lc, lp, pb; + UInt32 dicSize; +} CLzmaProps; + +/* LzmaProps_Decode - decodes properties +Returns: + SZ_OK + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size); + + +/* ---------- LZMA Decoder state ---------- */ + +/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case. + Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */ + +#define LZMA_REQUIRED_INPUT_MAX 20 + +typedef struct +{ + CLzmaProps prop; + CLzmaProb *probs; + Byte *dic; + const Byte *buf; + UInt32 range, code; + SizeT dicPos; + SizeT dicBufSize; + UInt32 processedPos; + UInt32 checkDicSize; + unsigned state; + UInt32 reps[4]; + unsigned remainLen; + int needFlush; + int needInitState; + UInt32 numProbs; + unsigned tempBufSize; + Byte tempBuf[LZMA_REQUIRED_INPUT_MAX]; +} CLzmaDec; + +#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; } + +void LzmaDec_Init(CLzmaDec *p); + +/* There are two types of LZMA streams: + 0) Stream with end mark. That end mark adds about 6 bytes to compressed size. + 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */ + +typedef enum +{ + LZMA_FINISH_ANY, /* finish at any point */ + LZMA_FINISH_END /* block must be finished at the end */ +} ELzmaFinishMode; + +/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!! + + You must use LZMA_FINISH_END, when you know that current output buffer + covers last bytes of block. In other cases you must use LZMA_FINISH_ANY. + + If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK, + and output value of destLen will be less than output buffer size limit. + You can check status result also. + + You can use multiple checks to test data integrity after full decompression: + 1) Check Result and "status" variable. + 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize. + 3) Check that output(srcLen) = compressedSize, if you know real compressedSize. + You must use correct finish mode in that case. */ + +typedef enum +{ + LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */ + LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */ + LZMA_STATUS_NOT_FINISHED, /* stream was not finished */ + LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */ + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */ +} ELzmaStatus; + +/* ELzmaStatus is used only as output value for function call */ + + +/* ---------- Interfaces ---------- */ + +/* There are 3 levels of interfaces: + 1) Dictionary Interface + 2) Buffer Interface + 3) One Call Interface + You can select any of these interfaces, but don't mix functions from different + groups for same object. */ + + +/* There are two variants to allocate state for Dictionary Interface: + 1) LzmaDec_Allocate / LzmaDec_Free + 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs + You can use variant 2, if you set dictionary buffer manually. + For Buffer Interface you must always use variant 1. + +LzmaDec_Allocate* can return: + SZ_OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties +*/ + +SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc); + +SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc); +void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc); + +/* ---------- Dictionary Interface ---------- */ + +/* You can use it, if you want to eliminate the overhead for data copying from + dictionary to some other external buffer. + You must work with CLzmaDec variables directly in this interface. + + STEPS: + LzmaDec_Constr() + LzmaDec_Allocate() + for (each new stream) + { + LzmaDec_Init() + while (it needs more decompression) + { + LzmaDec_DecodeToDic() + use data from CLzmaDec::dic and update CLzmaDec::dicPos + } + } + LzmaDec_Free() +*/ + +/* LzmaDec_DecodeToDic + + The decoding to internal dictionary buffer (CLzmaDec::dic). + You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!! + +finishMode: + It has meaning only if the decoding reaches output limit (dicLimit). + LZMA_FINISH_ANY - Decode just dicLimit bytes. + LZMA_FINISH_END - Stream must be finished after dicLimit. + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_NEEDS_MORE_INPUT + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error +*/ + +SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- Buffer Interface ---------- */ + +/* It's zlib-like interface. + See LzmaDec_DecodeToDic description for information about STEPS and return results, + but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need + to work with CLzmaDec variables manually. + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). +*/ + +SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, + const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status); + + +/* ---------- One Call Interface ---------- */ + +/* LzmaDecode + +finishMode: + It has meaning only if the decoding reaches output limit (*destLen). + LZMA_FINISH_ANY - Decode just destLen bytes. + LZMA_FINISH_END - Stream must be finished after (*destLen). + +Returns: + SZ_OK + status: + LZMA_STATUS_FINISHED_WITH_MARK + LZMA_STATUS_NOT_FINISHED + LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + SZ_ERROR_DATA - Data error + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_UNSUPPORTED - Unsupported properties + SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src). +*/ + +SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, + const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode, + ELzmaStatus *status, ISzAlloc *alloc); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/StormLib/src/lzma/C/LzmaEnc.c b/dep/StormLib/src/lzma/C/LzmaEnc.c new file mode 100644 index 000000000..169d4f463 --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzmaEnc.c @@ -0,0 +1,2268 @@ +/* LzmaEnc.c -- LZMA Encoder +2009-11-24 : Igor Pavlov : Public domain */ + +#include + +/* #define SHOW_STAT */ +/* #define SHOW_STAT2 */ + +#if defined(SHOW_STAT) || defined(SHOW_STAT2) +#include +#endif + +#include "LzmaEnc.h" + +#include "LzFind.h" +#ifndef _7ZIP_ST +#include "LzFindMt.h" +#endif + +#ifdef SHOW_STAT +static int ttt = 0; +#endif + +#define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1) + +#define kBlockSize (9 << 10) +#define kUnpackBlockSize (1 << 18) +#define kMatchArraySize (1 << 21) +#define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX) + +#define kNumMaxDirectBits (31) + +#define kNumTopBits 24 +#define kTopValue ((UInt32)1 << kNumTopBits) + +#define kNumBitModelTotalBits 11 +#define kBitModelTotal (1 << kNumBitModelTotalBits) +#define kNumMoveBits 5 +#define kProbInitValue (kBitModelTotal >> 1) + +#define kNumMoveReducingBits 4 +#define kNumBitPriceShiftBits 4 +#define kBitPrice (1 << kNumBitPriceShiftBits) + +void LzmaEncProps_Init(CLzmaEncProps *p) +{ + p->level = 5; + p->dictSize = p->mc = 0; + p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1; + p->writeEndMark = 0; +} + +void LzmaEncProps_Normalize(CLzmaEncProps *p) +{ + int level = p->level; + if (level < 0) level = 5; + p->level = level; + if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26))); + if (p->lc < 0) p->lc = 3; + if (p->lp < 0) p->lp = 0; + if (p->pb < 0) p->pb = 2; + if (p->algo < 0) p->algo = (level < 5 ? 0 : 1); + if (p->fb < 0) p->fb = (level < 7 ? 32 : 64); + if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1); + if (p->numHashBytes < 0) p->numHashBytes = 4; + if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1); + if (p->numThreads < 0) + p->numThreads = + #ifndef _7ZIP_ST + ((p->btMode && p->algo) ? 2 : 1); + #else + 1; + #endif +} + +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2) +{ + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + return props.dictSize; +} + +/* #define LZMA_LOG_BSR */ +/* Define it for Intel's CPU */ + + +#ifdef LZMA_LOG_BSR + +#define kDicLogSizeMaxCompress 30 + +#define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); } + +UInt32 GetPosSlot1(UInt32 pos) +{ + UInt32 res; + BSR2_RET(pos, res); + return res; +} +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); } + +#else + +#define kNumLogBits (9 + (int)sizeof(size_t) / 2) +#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7) + +void LzmaEnc_FastPosInit(Byte *g_FastPos) +{ + int c = 2, slotFast; + g_FastPos[0] = 0; + g_FastPos[1] = 1; + + for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++) + { + UInt32 k = (1 << ((slotFast >> 1) - 1)); + UInt32 j; + for (j = 0; j < k; j++, c++) + g_FastPos[c] = (Byte)slotFast; + } +} + +#define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \ + (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \ + res = p->g_FastPos[pos >> i] + (i * 2); } +/* +#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \ + p->g_FastPos[pos >> 6] + 12 : \ + p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; } +*/ + +#define GetPosSlot1(pos) p->g_FastPos[pos] +#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); } +#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); } + +#endif + + +#define LZMA_NUM_REPS 4 + +typedef unsigned CState; + +typedef struct +{ + UInt32 price; + + CState state; + int prev1IsChar; + int prev2; + + UInt32 posPrev2; + UInt32 backPrev2; + + UInt32 posPrev; + UInt32 backPrev; + UInt32 backs[LZMA_NUM_REPS]; +} COptimal; + +#define kNumOpts (1 << 12) + +#define kNumLenToPosStates 4 +#define kNumPosSlotBits 6 +#define kDicLogSizeMin 0 +#define kDicLogSizeMax 32 +#define kDistTableSizeMax (kDicLogSizeMax * 2) + + +#define kNumAlignBits 4 +#define kAlignTableSize (1 << kNumAlignBits) +#define kAlignMask (kAlignTableSize - 1) + +#define kStartPosModelIndex 4 +#define kEndPosModelIndex 14 +#define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex) + +#define kNumFullDistances (1 << (kEndPosModelIndex >> 1)) + +#ifdef _LZMA_PROB32 +#define CLzmaProb UInt32 +#else +#define CLzmaProb UInt16 +#endif + +#define LZMA_PB_MAX 4 +#define LZMA_LC_MAX 8 +#define LZMA_LP_MAX 4 + +#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX) + + +#define kLenNumLowBits 3 +#define kLenNumLowSymbols (1 << kLenNumLowBits) +#define kLenNumMidBits 3 +#define kLenNumMidSymbols (1 << kLenNumMidBits) +#define kLenNumHighBits 8 +#define kLenNumHighSymbols (1 << kLenNumHighBits) + +#define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols) + +#define LZMA_MATCH_LEN_MIN 2 +#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1) + +#define kNumStates 12 + +typedef struct +{ + CLzmaProb choice; + CLzmaProb choice2; + CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits]; + CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits]; + CLzmaProb high[kLenNumHighSymbols]; +} CLenEnc; + +typedef struct +{ + CLenEnc p; + UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal]; + UInt32 tableSize; + UInt32 counters[LZMA_NUM_PB_STATES_MAX]; +} CLenPriceEnc; + +typedef struct +{ + UInt32 range; + Byte cache; + UInt64 low; + UInt64 cacheSize; + Byte *buf; + Byte *bufLim; + Byte *bufBase; + ISeqOutStream *outStream; + UInt64 processed; + SRes res; +} CRangeEnc; + +typedef struct +{ + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; +} CSaveState; + +typedef struct +{ + IMatchFinder matchFinder; + void *matchFinderObj; + + #ifndef _7ZIP_ST + Bool mtMode; + CMatchFinderMt matchFinderMt; + #endif + + CMatchFinder matchFinderBase; + + #ifndef _7ZIP_ST + Byte pad[128]; + #endif + + UInt32 optimumEndIndex; + UInt32 optimumCurrentIndex; + + UInt32 longestMatchLength; + UInt32 numPairs; + UInt32 numAvail; + COptimal opt[kNumOpts]; + + #ifndef LZMA_LOG_BSR + Byte g_FastPos[1 << kNumLogBits]; + #endif + + UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1]; + UInt32 numFastBytes; + UInt32 additionalOffset; + UInt32 reps[LZMA_NUM_REPS]; + UInt32 state; + + UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax]; + UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances]; + UInt32 alignPrices[kAlignTableSize]; + UInt32 alignPriceCount; + + UInt32 distTableSize; + + unsigned lc, lp, pb; + unsigned lpMask, pbMask; + + CLzmaProb *litProbs; + + CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX]; + CLzmaProb isRep[kNumStates]; + CLzmaProb isRepG0[kNumStates]; + CLzmaProb isRepG1[kNumStates]; + CLzmaProb isRepG2[kNumStates]; + CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX]; + + CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits]; + CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex]; + CLzmaProb posAlignEncoder[1 << kNumAlignBits]; + + CLenPriceEnc lenEnc; + CLenPriceEnc repLenEnc; + + unsigned lclp; + + Bool fastMode; + + CRangeEnc rc; + + Bool writeEndMark; + UInt64 nowPos64; + UInt32 matchPriceCount; + Bool finished; + Bool multiThread; + + SRes result; + UInt32 dictSize; + UInt32 matchFinderCycles; + + int needInit; + + CSaveState saveState; +} CLzmaEnc; + +void LzmaEnc_SaveState(CLzmaEncHandle pp) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CSaveState *dest = &p->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb)); +} + +void LzmaEnc_RestoreState(CLzmaEncHandle pp) +{ + CLzmaEnc *dest = (CLzmaEnc *)pp; + const CSaveState *p = &dest->saveState; + int i; + dest->lenEnc = p->lenEnc; + dest->repLenEnc = p->repLenEnc; + dest->state = p->state; + + for (i = 0; i < kNumStates; i++) + { + memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i])); + memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i])); + } + for (i = 0; i < kNumLenToPosStates; i++) + memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i])); + memcpy(dest->isRep, p->isRep, sizeof(p->isRep)); + memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0)); + memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1)); + memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2)); + memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders)); + memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder)); + memcpy(dest->reps, p->reps, sizeof(p->reps)); + memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb)); +} + +SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + CLzmaEncProps props = *props2; + LzmaEncProps_Normalize(&props); + + if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX || + props.dictSize > (1 << kDicLogSizeMaxCompress) || props.dictSize > (1 << 30)) + return SZ_ERROR_PARAM; + p->dictSize = props.dictSize; + p->matchFinderCycles = props.mc; + { + unsigned fb = props.fb; + if (fb < 5) + fb = 5; + if (fb > LZMA_MATCH_LEN_MAX) + fb = LZMA_MATCH_LEN_MAX; + p->numFastBytes = fb; + } + p->lc = props.lc; + p->lp = props.lp; + p->pb = props.pb; + p->fastMode = (props.algo == 0); + p->matchFinderBase.btMode = props.btMode; + { + UInt32 numHashBytes = 4; + if (props.btMode) + { + if (props.numHashBytes < 2) + numHashBytes = 2; + else if (props.numHashBytes < 4) + numHashBytes = props.numHashBytes; + } + p->matchFinderBase.numHashBytes = numHashBytes; + } + + p->matchFinderBase.cutValue = props.mc; + + p->writeEndMark = props.writeEndMark; + + #ifndef _7ZIP_ST + /* + if (newMultiThread != _multiThread) + { + ReleaseMatchFinder(); + _multiThread = newMultiThread; + } + */ + p->multiThread = (props.numThreads > 1); + #endif + + return SZ_OK; +} + +static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +static const int kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +static const int kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +#define IsCharState(s) ((s) < 7) + +#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1) + +#define kInfinityPrice (1 << 30) + +static void RangeEnc_Construct(CRangeEnc *p) +{ + p->outStream = 0; + p->bufBase = 0; +} + +#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize) + +#define RC_BUF_SIZE (1 << 16) +static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc) +{ + if (p->bufBase == 0) + { + p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE); + if (p->bufBase == 0) + return 0; + p->bufLim = p->bufBase + RC_BUF_SIZE; + } + return 1; +} + +static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->bufBase); + p->bufBase = 0; +} + +static void RangeEnc_Init(CRangeEnc *p) +{ + /* Stream.Init(); */ + p->low = 0; + p->range = 0xFFFFFFFF; + p->cacheSize = 1; + p->cache = 0; + + p->buf = p->bufBase; + + p->processed = 0; + p->res = SZ_OK; +} + +static void RangeEnc_FlushStream(CRangeEnc *p) +{ + size_t num; + if (p->res != SZ_OK) + return; + num = p->buf - p->bufBase; + if (num != p->outStream->Write(p->outStream, p->bufBase, num)) + p->res = SZ_ERROR_WRITE; + p->processed += num; + p->buf = p->bufBase; +} + +static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p) +{ + if ((UInt32)p->low < (UInt32)0xFF000000 || (int)(p->low >> 32) != 0) + { + Byte temp = p->cache; + do + { + Byte *buf = p->buf; + *buf++ = (Byte)(temp + (Byte)(p->low >> 32)); + p->buf = buf; + if (buf == p->bufLim) + RangeEnc_FlushStream(p); + temp = 0xFF; + } + while (--p->cacheSize != 0); + p->cache = (Byte)((UInt32)p->low >> 24); + } + p->cacheSize++; + p->low = (UInt32)p->low << 8; +} + +static void RangeEnc_FlushData(CRangeEnc *p) +{ + int i; + for (i = 0; i < 5; i++) + RangeEnc_ShiftLow(p); +} + +static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, int numBits) +{ + do + { + p->range >>= 1; + p->low += p->range & (0 - ((value >> --numBits) & 1)); + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } + } + while (numBits != 0); +} + +static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol) +{ + UInt32 ttt = *prob; + UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt; + if (symbol == 0) + { + p->range = newBound; + ttt += (kBitModelTotal - ttt) >> kNumMoveBits; + } + else + { + p->low += newBound; + p->range -= newBound; + ttt -= ttt >> kNumMoveBits; + } + *prob = (CLzmaProb)ttt; + if (p->range < kTopValue) + { + p->range <<= 8; + RangeEnc_ShiftLow(p); + } +} + +static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol) +{ + symbol |= 0x100; + do + { + RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); +} + +static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte) +{ + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); +} + +void LzmaEnc_InitPriceTables(UInt32 *ProbPrices) +{ + UInt32 i; + for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits)) + { + const int kCyclesBits = kNumBitPriceShiftBits; + UInt32 w = i; + UInt32 bitCount = 0; + int j; + for (j = 0; j < kCyclesBits; j++) + { + w = w * w; + bitCount <<= 1; + while (w >= ((UInt32)1 << 16)) + { + w >>= 1; + bitCount++; + } + } + ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount); + } +} + + +#define GET_PRICE(prob, symbol) \ + p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICEa(prob, symbol) \ + ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]; + +#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +#define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits] +#define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits] + +static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= 0x100; + do + { + price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1); + symbol <<= 1; + } + while (symbol < 0x10000); + return price; +} + +static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 offs = 0x100; + symbol |= 0x100; + do + { + matchByte <<= 1; + price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1); + symbol <<= 1; + offs &= ~(matchByte ^ symbol); + } + while (symbol < 0x10000); + return price; +} + + +static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0;) + { + UInt32 bit; + i--; + bit = (symbol >> i) & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + } +} + +static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol) +{ + UInt32 m = 1; + int i; + for (i = 0; i < numBitLevels; i++) + { + UInt32 bit = symbol & 1; + RangeEnc_EncodeBit(rc, probs + m, bit); + m = (m << 1) | bit; + symbol >>= 1; + } +} + +static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + symbol |= (1 << numBitLevels); + while (symbol != 1) + { + price += GET_PRICEa(probs[symbol >> 1], symbol & 1); + symbol >>= 1; + } + return price; +} + +static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices) +{ + UInt32 price = 0; + UInt32 m = 1; + int i; + for (i = numBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += GET_PRICEa(probs[m], bit); + m = (m << 1) | bit; + } + return price; +} + + +static void LenEnc_Init(CLenEnc *p) +{ + unsigned i; + p->choice = p->choice2 = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++) + p->low[i] = kProbInitValue; + for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++) + p->mid[i] = kProbInitValue; + for (i = 0; i < kLenNumHighSymbols; i++) + p->high[i] = kProbInitValue; +} + +static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState) +{ + if (symbol < kLenNumLowSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice, 0); + RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice, 1); + if (symbol < kLenNumLowSymbols + kLenNumMidSymbols) + { + RangeEnc_EncodeBit(rc, &p->choice2, 0); + RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols); + } + else + { + RangeEnc_EncodeBit(rc, &p->choice2, 1); + RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols); + } + } +} + +static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices) +{ + UInt32 a0 = GET_PRICE_0a(p->choice); + UInt32 a1 = GET_PRICE_1a(p->choice); + UInt32 b0 = a1 + GET_PRICE_0a(p->choice2); + UInt32 b1 = a1 + GET_PRICE_1a(p->choice2); + UInt32 i = 0; + for (i = 0; i < kLenNumLowSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices); + } + for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++) + { + if (i >= numSymbols) + return; + prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices); + } + for (; i < numSymbols; i++) + prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices); +} + +static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices) +{ + LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices); + p->counters[posState] = p->tableSize; +} + +static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices) +{ + UInt32 posState; + for (posState = 0; posState < numPosStates; posState++) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + +static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices) +{ + LenEnc_Encode(&p->p, rc, symbol, posState); + if (updatePrice) + if (--p->counters[posState] == 0) + LenPriceEnc_UpdateTable(p, posState, ProbPrices); +} + + + + +static void MovePos(CLzmaEnc *p, UInt32 num) +{ + #ifdef SHOW_STAT + ttt += num; + printf("\n MovePos %d", num); + #endif + if (num != 0) + { + p->additionalOffset += num; + p->matchFinder.Skip(p->matchFinderObj, num); + } +} + +static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes) +{ + UInt32 lenRes = 0, numPairs; + p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); + numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches); + #ifdef SHOW_STAT + printf("\n i = %d numPairs = %d ", ttt, numPairs / 2); + ttt++; + { + UInt32 i; + for (i = 0; i < numPairs; i += 2) + printf("%2d %6d | ", p->matches[i], p->matches[i + 1]); + } + #endif + if (numPairs > 0) + { + lenRes = p->matches[numPairs - 2]; + if (lenRes == p->numFastBytes) + { + const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + UInt32 distance = p->matches[numPairs - 1] + 1; + UInt32 numAvail = p->numAvail; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + { + const Byte *pby2 = pby - distance; + for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++); + } + } + } + p->additionalOffset++; + *numDistancePairsRes = numPairs; + return lenRes; +} + + +#define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False; +#define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False; +#define IsShortRep(p) ((p)->backPrev == 0) + +static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState) +{ + return + GET_PRICE_0(p->isRepG0[state]) + + GET_PRICE_0(p->isRep0Long[state][posState]); +} + +static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState) +{ + UInt32 price; + if (repIndex == 0) + { + price = GET_PRICE_0(p->isRepG0[state]); + price += GET_PRICE_1(p->isRep0Long[state][posState]); + } + else + { + price = GET_PRICE_1(p->isRepG0[state]); + if (repIndex == 1) + price += GET_PRICE_0(p->isRepG1[state]); + else + { + price += GET_PRICE_1(p->isRepG1[state]); + price += GET_PRICE(p->isRepG2[state], repIndex - 2); + } + } + return price; +} + +static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState) +{ + return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] + + GetPureRepPrice(p, repIndex, state, posState); +} + +static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur) +{ + UInt32 posMem = p->opt[cur].posPrev; + UInt32 backMem = p->opt[cur].backPrev; + p->optimumEndIndex = cur; + do + { + if (p->opt[cur].prev1IsChar) + { + MakeAsChar(&p->opt[posMem]) + p->opt[posMem].posPrev = posMem - 1; + if (p->opt[cur].prev2) + { + p->opt[posMem - 1].prev1IsChar = False; + p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2; + p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2; + } + } + { + UInt32 posPrev = posMem; + UInt32 backCur = backMem; + + backMem = p->opt[posPrev].backPrev; + posMem = p->opt[posPrev].posPrev; + + p->opt[posPrev].backPrev = backCur; + p->opt[posPrev].posPrev = cur; + cur = posPrev; + } + } + while (cur != 0); + *backRes = p->opt[0].backPrev; + p->optimumCurrentIndex = p->opt[0].posPrev; + return p->optimumCurrentIndex; +} + +#define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300) + +static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur; + UInt32 matchPrice, repMatchPrice, normalMatchPrice; + UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS]; + UInt32 *matches; + const Byte *data; + Byte curByte, matchByte; + if (p->optimumEndIndex != p->optimumCurrentIndex) + { + const COptimal *opt = &p->opt[p->optimumCurrentIndex]; + UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex; + *backRes = opt->backPrev; + p->optimumCurrentIndex = opt->posPrev; + return lenRes; + } + p->optimumCurrentIndex = p->optimumEndIndex = 0; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + if (numAvail < 2) + { + *backRes = (UInt32)(-1); + return 1; + } + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + repMaxIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 lenTest; + const Byte *data2; + reps[i] = p->reps[i]; + data2 = data - (reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + { + repLens[i] = 0; + continue; + } + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + repLens[i] = lenTest; + if (lenTest > repLens[repMaxIndex]) + repMaxIndex = i; + } + if (repLens[repMaxIndex] >= p->numFastBytes) + { + UInt32 lenRes; + *backRes = repMaxIndex; + lenRes = repLens[repMaxIndex]; + MovePos(p, lenRes - 1); + return lenRes; + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2) + { + *backRes = (UInt32)-1; + return 1; + } + + p->opt[0].state = (CState)p->state; + + posState = (position & p->pbMask); + + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) + + (!IsCharState(p->state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + MakeAsChar(&p->opt[1]); + + matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]); + + if (matchByte == curByte) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState); + if (shortRepPrice < p->opt[1].price) + { + p->opt[1].price = shortRepPrice; + MakeAsShortRep(&p->opt[1]); + } + } + lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]); + + if (lenEnd < 2) + { + *backRes = p->opt[1].backPrev; + return 1; + } + + p->opt[1].posPrev = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + p->opt[0].backs[i] = reps[i]; + + len = lenEnd; + do + p->opt[len--].price = kInfinityPrice; + while (len >= 2); + + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 repLen = repLens[i]; + UInt32 price; + if (repLen < 2) + continue; + price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2]; + COptimal *opt = &p->opt[repLen]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = i; + opt->prev1IsChar = False; + } + } + while (--repLen >= 2); + } + + normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]); + + len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2); + if (len <= mainLen) + { + UInt32 offs = 0; + while (len > matches[offs]) + offs += 2; + for (; ; len++) + { + COptimal *opt; + UInt32 distance = matches[offs + 1]; + + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(len); + if (distance < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][distance]; + else + { + UInt32 slot; + GetPosSlot2(distance, slot); + curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot]; + } + opt = &p->opt[len]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = 0; + opt->backPrev = distance + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + if (len == matches[offs]) + { + offs += 2; + if (offs == numPairs) + break; + } + } + } + + cur = 0; + + #ifdef SHOW_STAT2 + if (position >= 0) + { + unsigned i; + printf("\n pos = %4X", position); + for (i = cur; i <= lenEnd; i++) + printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price); + } + #endif + + for (;;) + { + UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen; + UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice; + Bool nextIsChar; + Byte curByte, matchByte; + const Byte *data; + COptimal *curOpt; + COptimal *nextOpt; + + cur++; + if (cur == lenEnd) + return Backward(p, backRes, cur); + + newLen = ReadMatchDistances(p, &numPairs); + if (newLen >= p->numFastBytes) + { + p->numPairs = numPairs; + p->longestMatchLength = newLen; + return Backward(p, backRes, cur); + } + position++; + curOpt = &p->opt[cur]; + posPrev = curOpt->posPrev; + if (curOpt->prev1IsChar) + { + posPrev--; + if (curOpt->prev2) + { + state = p->opt[curOpt->posPrev2].state; + if (curOpt->backPrev2 < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + else + state = p->opt[posPrev].state; + state = kLiteralNextStates[state]; + } + else + state = p->opt[posPrev].state; + if (posPrev == cur - 1) + { + if (IsShortRep(curOpt)) + state = kShortRepNextStates[state]; + else + state = kLiteralNextStates[state]; + } + else + { + UInt32 pos; + const COptimal *prevOpt; + if (curOpt->prev1IsChar && curOpt->prev2) + { + posPrev = curOpt->posPrev2; + pos = curOpt->backPrev2; + state = kRepNextStates[state]; + } + else + { + pos = curOpt->backPrev; + if (pos < LZMA_NUM_REPS) + state = kRepNextStates[state]; + else + state = kMatchNextStates[state]; + } + prevOpt = &p->opt[posPrev]; + if (pos < LZMA_NUM_REPS) + { + UInt32 i; + reps[0] = prevOpt->backs[pos]; + for (i = 1; i <= pos; i++) + reps[i] = prevOpt->backs[i - 1]; + for (; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i]; + } + else + { + UInt32 i; + reps[0] = (pos - LZMA_NUM_REPS); + for (i = 1; i < LZMA_NUM_REPS; i++) + reps[i] = prevOpt->backs[i - 1]; + } + } + curOpt->state = (CState)state; + + curOpt->backs[0] = reps[0]; + curOpt->backs[1] = reps[1]; + curOpt->backs[2] = reps[2]; + curOpt->backs[3] = reps[3]; + + curPrice = curOpt->price; + nextIsChar = False; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + curByte = *data; + matchByte = *(data - (reps[0] + 1)); + + posState = (position & p->pbMask); + + curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]); + { + const CLzmaProb *probs = LIT_PROBS(position, *(data - 1)); + curAnd1Price += + (!IsCharState(state) ? + LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) : + LitEnc_GetPrice(probs, curByte, p->ProbPrices)); + } + + nextOpt = &p->opt[cur + 1]; + + if (curAnd1Price < nextOpt->price) + { + nextOpt->price = curAnd1Price; + nextOpt->posPrev = cur; + MakeAsChar(nextOpt); + nextIsChar = True; + } + + matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]); + repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]); + + if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0)) + { + UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState); + if (shortRepPrice <= nextOpt->price) + { + nextOpt->price = shortRepPrice; + nextOpt->posPrev = cur; + MakeAsShortRep(nextOpt); + nextIsChar = True; + } + } + numAvailFull = p->numAvail; + { + UInt32 temp = kNumOpts - 1 - cur; + if (temp < numAvailFull) + numAvailFull = temp; + } + + if (numAvailFull < 2) + continue; + numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes); + + if (!nextIsChar && matchByte != curByte) /* speed optimization */ + { + /* try Literal + rep0 */ + UInt32 temp; + UInt32 lenTest2; + const Byte *data2 = data - (reps[0] + 1); + UInt32 limit = p->numFastBytes + 1; + if (limit > numAvailFull) + limit = numAvailFull; + + for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++); + lenTest2 = temp - 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kLiteralNextStates[state]; + UInt32 posStateNext = (position + 1) & p->pbMask; + UInt32 nextRepMatchPrice = curAnd1Price + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = False; + } + } + } + } + + startLen = 2; /* speed optimization */ + { + UInt32 repIndex; + for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++) + { + UInt32 lenTest; + UInt32 lenTestTemp; + UInt32 price; + const Byte *data2 = data - (reps[repIndex] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++); + while (lenEnd < cur + lenTest) + p->opt[++lenEnd].price = kInfinityPrice; + lenTestTemp = lenTest; + price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState); + do + { + UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2]; + COptimal *opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = repIndex; + opt->prev1IsChar = False; + } + } + while (--lenTest >= 2); + lenTest = lenTestTemp; + + if (repIndex == 0) + startLen = lenTest + 1; + + /* if (_maxMode) */ + { + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kRepNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = + price + p->repLenEnc.prices[posState][lenTest - 2] + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (position + lenTest + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 curAndLenPrice; + COptimal *opt; + UInt32 offset = cur + lenTest + 1 + lenTest2; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = repIndex; + } + } + } + } + } + } + /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */ + if (newLen > numAvail) + { + newLen = numAvail; + for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2); + matches[numPairs] = newLen; + numPairs += 2; + } + if (newLen >= startLen) + { + UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]); + UInt32 offs, curBack, posSlot; + UInt32 lenTest; + while (lenEnd < cur + newLen) + p->opt[++lenEnd].price = kInfinityPrice; + + offs = 0; + while (startLen > matches[offs]) + offs += 2; + curBack = matches[offs + 1]; + GetPosSlot2(curBack, posSlot); + for (lenTest = /*2*/ startLen; ; lenTest++) + { + UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN]; + UInt32 lenToPosState = GetLenToPosState(lenTest); + COptimal *opt; + if (curBack < kNumFullDistances) + curAndLenPrice += p->distancesPrices[lenToPosState][curBack]; + else + curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask]; + + opt = &p->opt[cur + lenTest]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur; + opt->backPrev = curBack + LZMA_NUM_REPS; + opt->prev1IsChar = False; + } + + if (/*_maxMode && */lenTest == matches[offs]) + { + /* Try Match + Literal + Rep0 */ + const Byte *data2 = data - (curBack + 1); + UInt32 lenTest2 = lenTest + 1; + UInt32 limit = lenTest2 + p->numFastBytes; + UInt32 nextRepMatchPrice; + if (limit > numAvailFull) + limit = numAvailFull; + for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++); + lenTest2 -= lenTest + 1; + if (lenTest2 >= 2) + { + UInt32 state2 = kMatchNextStates[state]; + UInt32 posStateNext = (position + lenTest) & p->pbMask; + UInt32 curAndLenCharPrice = curAndLenPrice + + GET_PRICE_0(p->isMatch[state2][posStateNext]) + + LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]), + data[lenTest], data2[lenTest], p->ProbPrices); + state2 = kLiteralNextStates[state2]; + posStateNext = (posStateNext + 1) & p->pbMask; + nextRepMatchPrice = curAndLenCharPrice + + GET_PRICE_1(p->isMatch[state2][posStateNext]) + + GET_PRICE_1(p->isRep[state2]); + + /* for (; lenTest2 >= 2; lenTest2--) */ + { + UInt32 offset = cur + lenTest + 1 + lenTest2; + UInt32 curAndLenPrice; + COptimal *opt; + while (lenEnd < offset) + p->opt[++lenEnd].price = kInfinityPrice; + curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext); + opt = &p->opt[offset]; + if (curAndLenPrice < opt->price) + { + opt->price = curAndLenPrice; + opt->posPrev = cur + lenTest + 1; + opt->backPrev = 0; + opt->prev1IsChar = True; + opt->prev2 = True; + opt->posPrev2 = cur; + opt->backPrev2 = curBack + LZMA_NUM_REPS; + } + } + } + offs += 2; + if (offs == numPairs) + break; + curBack = matches[offs + 1]; + if (curBack >= kNumFullDistances) + GetPosSlot2(curBack, posSlot); + } + } + } + } +} + +#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist)) + +static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes) +{ + UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i; + const Byte *data; + const UInt32 *matches; + + if (p->additionalOffset == 0) + mainLen = ReadMatchDistances(p, &numPairs); + else + { + mainLen = p->longestMatchLength; + numPairs = p->numPairs; + } + + numAvail = p->numAvail; + *backRes = (UInt32)-1; + if (numAvail < 2) + return 1; + if (numAvail > LZMA_MATCH_LEN_MAX) + numAvail = LZMA_MATCH_LEN_MAX; + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + + repLen = repIndex = 0; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + for (len = 2; len < numAvail && data[len] == data2[len]; len++); + if (len >= p->numFastBytes) + { + *backRes = i; + MovePos(p, len - 1); + return len; + } + if (len > repLen) + { + repIndex = i; + repLen = len; + } + } + + matches = p->matches; + if (mainLen >= p->numFastBytes) + { + *backRes = matches[numPairs - 1] + LZMA_NUM_REPS; + MovePos(p, mainLen - 1); + return mainLen; + } + + mainDist = 0; /* for GCC */ + if (mainLen >= 2) + { + mainDist = matches[numPairs - 1]; + while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1) + { + if (!ChangePair(matches[numPairs - 3], mainDist)) + break; + numPairs -= 2; + mainLen = matches[numPairs - 2]; + mainDist = matches[numPairs - 1]; + } + if (mainLen == 2 && mainDist >= 0x80) + mainLen = 1; + } + + if (repLen >= 2 && ( + (repLen + 1 >= mainLen) || + (repLen + 2 >= mainLen && mainDist >= (1 << 9)) || + (repLen + 3 >= mainLen && mainDist >= (1 << 15)))) + { + *backRes = repIndex; + MovePos(p, repLen - 1); + return repLen; + } + + if (mainLen < 2 || numAvail <= 2) + return 1; + + p->longestMatchLength = ReadMatchDistances(p, &p->numPairs); + if (p->longestMatchLength >= 2) + { + UInt32 newDistance = matches[p->numPairs - 1]; + if ((p->longestMatchLength >= mainLen && newDistance < mainDist) || + (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) || + (p->longestMatchLength > mainLen + 1) || + (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist))) + return 1; + } + + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1; + for (i = 0; i < LZMA_NUM_REPS; i++) + { + UInt32 len, limit; + const Byte *data2 = data - (p->reps[i] + 1); + if (data[0] != data2[0] || data[1] != data2[1]) + continue; + limit = mainLen - 1; + for (len = 2; len < limit && data[len] == data2[len]; len++); + if (len >= limit) + return 1; + } + *backRes = mainDist + LZMA_NUM_REPS; + MovePos(p, mainLen - 2); + return mainLen; +} + +static void WriteEndMarker(CLzmaEnc *p, UInt32 posState) +{ + UInt32 len; + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + len = LZMA_MATCH_LEN_MIN; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1); + RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask); +} + +static SRes CheckErrors(CLzmaEnc *p) +{ + if (p->result != SZ_OK) + return p->result; + if (p->rc.res != SZ_OK) + p->result = SZ_ERROR_WRITE; + if (p->matchFinderBase.result != SZ_OK) + p->result = SZ_ERROR_READ; + if (p->result != SZ_OK) + p->finished = True; + return p->result; +} + +static SRes Flush(CLzmaEnc *p, UInt32 nowPos) +{ + /* ReleaseMFStream(); */ + p->finished = True; + if (p->writeEndMark) + WriteEndMarker(p, nowPos & p->pbMask); + RangeEnc_FlushData(&p->rc); + RangeEnc_FlushStream(&p->rc); + return CheckErrors(p); +} + +static void FillAlignPrices(CLzmaEnc *p) +{ + UInt32 i; + for (i = 0; i < kAlignTableSize; i++) + p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices); + p->alignPriceCount = 0; +} + +static void FillDistancesPrices(CLzmaEnc *p) +{ + UInt32 tempPrices[kNumFullDistances]; + UInt32 i, lenToPosState; + for (i = kStartPosModelIndex; i < kNumFullDistances; i++) + { + UInt32 posSlot = GetPosSlot1(i); + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices); + } + + for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++) + { + UInt32 posSlot; + const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState]; + UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState]; + for (posSlot = 0; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices); + for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++) + posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits); + + { + UInt32 *distancesPrices = p->distancesPrices[lenToPosState]; + UInt32 i; + for (i = 0; i < kStartPosModelIndex; i++) + distancesPrices[i] = posSlotPrices[i]; + for (; i < kNumFullDistances; i++) + distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i]; + } + } + p->matchPriceCount = 0; +} + +void LzmaEnc_Construct(CLzmaEnc *p) +{ + RangeEnc_Construct(&p->rc); + MatchFinder_Construct(&p->matchFinderBase); + #ifndef _7ZIP_ST + MatchFinderMt_Construct(&p->matchFinderMt); + p->matchFinderMt.MatchFinder = &p->matchFinderBase; + #endif + + { + CLzmaEncProps props; + LzmaEncProps_Init(&props); + LzmaEnc_SetProps(p, &props); + } + + #ifndef LZMA_LOG_BSR + LzmaEnc_FastPosInit(p->g_FastPos); + #endif + + LzmaEnc_InitPriceTables(p->ProbPrices); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc) +{ + void *p; + p = alloc->Alloc(alloc, sizeof(CLzmaEnc)); + if (p != 0) + LzmaEnc_Construct((CLzmaEnc *)p); + return p; +} + +void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc) +{ + alloc->Free(alloc, p->litProbs); + alloc->Free(alloc, p->saveState.litProbs); + p->litProbs = 0; + p->saveState.litProbs = 0; +} + +void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + #ifndef _7ZIP_ST + MatchFinderMt_Destruct(&p->matchFinderMt, allocBig); + #endif + MatchFinder_Free(&p->matchFinderBase, allocBig); + LzmaEnc_FreeLits(p, alloc); + RangeEnc_Free(&p->rc, alloc); +} + +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig); + alloc->Free(alloc, p); +} + +static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize) +{ + UInt32 nowPos32, startPos32; + if (p->needInit) + { + p->matchFinder.Init(p->matchFinderObj); + p->needInit = 0; + } + + if (p->finished) + return p->result; + RINOK(CheckErrors(p)); + + nowPos32 = (UInt32)p->nowPos64; + startPos32 = nowPos32; + + if (p->nowPos64 == 0) + { + UInt32 numPairs; + Byte curByte; + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + return Flush(p, nowPos32); + ReadMatchDistances(p, &numPairs); + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0); + p->state = kLiteralNextStates[p->state]; + curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset); + LitEnc_Encode(&p->rc, p->litProbs, curByte); + p->additionalOffset--; + nowPos32++; + } + + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0) + for (;;) + { + UInt32 pos, len, posState; + + if (p->fastMode) + len = GetOptimumFast(p, &pos); + else + len = GetOptimum(p, nowPos32, &pos); + + #ifdef SHOW_STAT2 + printf("\n pos = %4X, len = %d pos = %d", nowPos32, len, pos); + #endif + + posState = nowPos32 & p->pbMask; + if (len == 1 && pos == (UInt32)-1) + { + Byte curByte; + CLzmaProb *probs; + const Byte *data; + + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0); + data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; + curByte = *data; + probs = LIT_PROBS(nowPos32, *(data - 1)); + if (IsCharState(p->state)) + LitEnc_Encode(&p->rc, probs, curByte); + else + LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1)); + p->state = kLiteralNextStates[p->state]; + } + else + { + RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1); + if (pos < LZMA_NUM_REPS) + { + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1); + if (pos == 0) + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0); + RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1)); + } + else + { + UInt32 distance = p->reps[pos]; + RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1); + if (pos == 1) + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0); + else + { + RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1); + RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2); + if (pos == 3) + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + } + p->reps[1] = p->reps[0]; + p->reps[0] = distance; + } + if (len == 1) + p->state = kShortRepNextStates[p->state]; + else + { + LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + p->state = kRepNextStates[p->state]; + } + } + else + { + UInt32 posSlot; + RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0); + p->state = kMatchNextStates[p->state]; + LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices); + pos -= LZMA_NUM_REPS; + GetPosSlot(pos, posSlot); + RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot); + + if (posSlot >= kStartPosModelIndex) + { + UInt32 footerBits = ((posSlot >> 1) - 1); + UInt32 base = ((2 | (posSlot & 1)) << footerBits); + UInt32 posReduced = pos - base; + + if (posSlot < kEndPosModelIndex) + RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced); + else + { + RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits); + RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask); + p->alignPriceCount++; + } + } + p->reps[3] = p->reps[2]; + p->reps[2] = p->reps[1]; + p->reps[1] = p->reps[0]; + p->reps[0] = pos; + p->matchPriceCount++; + } + } + p->additionalOffset -= len; + nowPos32 += len; + if (p->additionalOffset == 0) + { + UInt32 processed; + if (!p->fastMode) + { + if (p->matchPriceCount >= (1 << 7)) + FillDistancesPrices(p); + if (p->alignPriceCount >= kAlignTableSize) + FillAlignPrices(p); + } + if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0) + break; + processed = nowPos32 - startPos32; + if (useLimits) + { + if (processed + kNumOpts + 300 >= maxUnpackSize || + RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize) + break; + } + else if (processed >= (1 << 15)) + { + p->nowPos64 += nowPos32 - startPos32; + return CheckErrors(p); + } + } + } + p->nowPos64 += nowPos32 - startPos32; + return Flush(p, nowPos32); +} + +#define kBigHashDicLimit ((UInt32)1 << 24) + +static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 beforeSize = kNumOpts; + Bool btMode; + if (!RangeEnc_Alloc(&p->rc, alloc)) + return SZ_ERROR_MEM; + btMode = (p->matchFinderBase.btMode != 0); + #ifndef _7ZIP_ST + p->mtMode = (p->multiThread && !p->fastMode && btMode); + #endif + + { + unsigned lclp = p->lc + p->lp; + if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp) + { + LzmaEnc_FreeLits(p, alloc); + p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb)); + if (p->litProbs == 0 || p->saveState.litProbs == 0) + { + LzmaEnc_FreeLits(p, alloc); + return SZ_ERROR_MEM; + } + p->lclp = lclp; + } + } + + p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit); + + if (beforeSize + p->dictSize < keepWindowSize) + beforeSize = keepWindowSize - p->dictSize; + + #ifndef _7ZIP_ST + if (p->mtMode) + { + RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)); + p->matchFinderObj = &p->matchFinderMt; + MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder); + } + else + #endif + { + if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig)) + return SZ_ERROR_MEM; + p->matchFinderObj = &p->matchFinderBase; + MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder); + } + return SZ_OK; +} + +void LzmaEnc_Init(CLzmaEnc *p) +{ + UInt32 i; + p->state = 0; + for (i = 0 ; i < LZMA_NUM_REPS; i++) + p->reps[i] = 0; + + RangeEnc_Init(&p->rc); + + + for (i = 0; i < kNumStates; i++) + { + UInt32 j; + for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++) + { + p->isMatch[i][j] = kProbInitValue; + p->isRep0Long[i][j] = kProbInitValue; + } + p->isRep[i] = kProbInitValue; + p->isRepG0[i] = kProbInitValue; + p->isRepG1[i] = kProbInitValue; + p->isRepG2[i] = kProbInitValue; + } + + { + UInt32 num = 0x300 << (p->lp + p->lc); + for (i = 0; i < num; i++) + p->litProbs[i] = kProbInitValue; + } + + { + for (i = 0; i < kNumLenToPosStates; i++) + { + CLzmaProb *probs = p->posSlotEncoder[i]; + UInt32 j; + for (j = 0; j < (1 << kNumPosSlotBits); j++) + probs[j] = kProbInitValue; + } + } + { + for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + p->posEncoders[i] = kProbInitValue; + } + + LenEnc_Init(&p->lenEnc.p); + LenEnc_Init(&p->repLenEnc.p); + + for (i = 0; i < (1 << kNumAlignBits); i++) + p->posAlignEncoder[i] = kProbInitValue; + + p->optimumEndIndex = 0; + p->optimumCurrentIndex = 0; + p->additionalOffset = 0; + + p->pbMask = (1 << p->pb) - 1; + p->lpMask = (1 << p->lp) - 1; +} + +void LzmaEnc_InitPrices(CLzmaEnc *p) +{ + if (!p->fastMode) + { + FillDistancesPrices(p); + FillAlignPrices(p); + } + + p->lenEnc.tableSize = + p->repLenEnc.tableSize = + p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN; + LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices); + LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices); +} + +static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + UInt32 i; + for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++) + if (p->dictSize <= ((UInt32)1 << i)) + break; + p->distTableSize = i * 2; + + p->finished = False; + p->result = SZ_OK; + RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig)); + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + p->nowPos64 = 0; + return SZ_OK; +} + +static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + p->rc.outStream = outStream; + return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig); +} + +SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, + ISeqInStream *inStream, UInt32 keepWindowSize, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + p->matchFinderBase.stream = inStream; + p->needInit = 1; + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen) +{ + p->matchFinderBase.directInput = 1; + p->matchFinderBase.bufferBase = (Byte *)src; + p->matchFinderBase.directInputRem = srcLen; +} + +SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, + UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + LzmaEnc_SetInputBuf(p, src, srcLen); + p->needInit = 1; + + return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig); +} + +void LzmaEnc_Finish(CLzmaEncHandle pp) +{ + #ifndef _7ZIP_ST + CLzmaEnc *p = (CLzmaEnc *)pp; + if (p->mtMode) + MatchFinderMt_ReleaseStream(&p->matchFinderMt); + #else + pp = pp; + #endif +} + +typedef struct +{ + ISeqOutStream funcTable; + Byte *data; + SizeT rem; + Bool overflow; +} CSeqOutStreamBuf; + +static size_t MyWrite(void *pp, const void *data, size_t size) +{ + CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp; + if (p->rem < size) + { + size = p->rem; + p->overflow = True; + } + memcpy(p->data, data, size); + p->rem -= size; + p->data += size; + return size; +} + + +UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj); +} + +const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp) +{ + const CLzmaEnc *p = (CLzmaEnc *)pp; + return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset; +} + +SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, + Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + UInt64 nowPos64; + SRes res; + CSeqOutStreamBuf outStream; + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = False; + p->finished = False; + p->result = SZ_OK; + + if (reInit) + LzmaEnc_Init(p); + LzmaEnc_InitPrices(p); + nowPos64 = p->nowPos64; + RangeEnc_Init(&p->rc); + p->rc.outStream = &outStream.funcTable; + + res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize); + + *unpackSize = (UInt32)(p->nowPos64 - nowPos64); + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + + return res; +} + +static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress) +{ + SRes res = SZ_OK; + + #ifndef _7ZIP_ST + Byte allocaDummy[0x300]; + int i = 0; + for (i = 0; i < 16; i++) + allocaDummy[i] = (Byte)i; + #endif + + for (;;) + { + res = LzmaEnc_CodeOneBlock(p, False, 0, 0); + if (res != SZ_OK || p->finished != 0) + break; + if (progress != 0) + { + res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc)); + if (res != SZ_OK) + { + res = SZ_ERROR_PROGRESS; + break; + } + } + } + LzmaEnc_Finish(p); + return res; +} + +SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress, + ISzAlloc *alloc, ISzAlloc *allocBig) +{ + RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig)); + return LzmaEnc_Encode2((CLzmaEnc *)pp, progress); +} + +SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size) +{ + CLzmaEnc *p = (CLzmaEnc *)pp; + int i; + UInt32 dictSize = p->dictSize; + if (*size < LZMA_PROPS_SIZE) + return SZ_ERROR_PARAM; + *size = LZMA_PROPS_SIZE; + props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc); + + for (i = 11; i <= 30; i++) + { + if (dictSize <= ((UInt32)2 << i)) + { + dictSize = (2 << i); + break; + } + if (dictSize <= ((UInt32)3 << i)) + { + dictSize = (3 << i); + break; + } + } + + for (i = 0; i < 4; i++) + props[1 + i] = (Byte)(dictSize >> (8 * i)); + return SZ_OK; +} + +SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + SRes res; + CLzmaEnc *p = (CLzmaEnc *)pp; + + CSeqOutStreamBuf outStream; + + LzmaEnc_SetInputBuf(p, src, srcLen); + + outStream.funcTable.Write = MyWrite; + outStream.data = dest; + outStream.rem = *destLen; + outStream.overflow = False; + + p->writeEndMark = writeEndMark; + + p->rc.outStream = &outStream.funcTable; + res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig); + if (res == SZ_OK) + res = LzmaEnc_Encode2(p, progress); + + *destLen -= outStream.rem; + if (outStream.overflow) + return SZ_ERROR_OUTPUT_EOF; + return res; +} + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig) +{ + CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc); + SRes res; + if (p == 0) + return SZ_ERROR_MEM; + + res = LzmaEnc_SetProps(p, props); + if (res == SZ_OK) + { + res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize); + if (res == SZ_OK) + res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen, + writeEndMark, progress, alloc, allocBig); + } + + LzmaEnc_Destroy(p, alloc, allocBig); + return res; +} diff --git a/dep/StormLib/src/lzma/C/LzmaEnc.h b/dep/StormLib/src/lzma/C/LzmaEnc.h new file mode 100644 index 000000000..200d60eb8 --- /dev/null +++ b/dep/StormLib/src/lzma/C/LzmaEnc.h @@ -0,0 +1,80 @@ +/* LzmaEnc.h -- LZMA Encoder +2009-02-07 : Igor Pavlov : Public domain */ + +#ifndef __LZMA_ENC_H +#define __LZMA_ENC_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define LZMA_PROPS_SIZE 5 + +typedef struct _CLzmaEncProps +{ + int level; /* 0 <= level <= 9 */ + UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version + (1 << 12) <= dictSize <= (1 << 30) for 64-bit version + default = (1 << 24) */ + int lc; /* 0 <= lc <= 8, default = 3 */ + int lp; /* 0 <= lp <= 4, default = 0 */ + int pb; /* 0 <= pb <= 4, default = 2 */ + int algo; /* 0 - fast, 1 - normal, default = 1 */ + int fb; /* 5 <= fb <= 273, default = 32 */ + int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */ + int numHashBytes; /* 2, 3 or 4, default = 4 */ + UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */ + unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */ + int numThreads; /* 1 or 2, default = 2 */ +} CLzmaEncProps; + +void LzmaEncProps_Init(CLzmaEncProps *p); +void LzmaEncProps_Normalize(CLzmaEncProps *p); +UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2); + + +/* ---------- CLzmaEncHandle Interface ---------- */ + +/* LzmaEnc_* functions can return the following exit codes: +Returns: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater in props + SZ_ERROR_WRITE - Write callback error. + SZ_ERROR_PROGRESS - some break from progress callback + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +typedef void * CLzmaEncHandle; + +CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc); +void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props); +SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size); +SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); +SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +/* ---------- One Call Interface ---------- */ + +/* LzmaEncode +Return code: + SZ_OK - OK + SZ_ERROR_MEM - Memory allocation error + SZ_ERROR_PARAM - Incorrect paramater + SZ_ERROR_OUTPUT_EOF - output buffer overflow + SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version) +*/ + +SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen, + const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark, + ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/StormLib/src/lzma/C/Threads.c b/dep/StormLib/src/lzma/C/Threads.c new file mode 100644 index 000000000..7af1da2e2 --- /dev/null +++ b/dep/StormLib/src/lzma/C/Threads.c @@ -0,0 +1,84 @@ +/* Threads.c -- multithreading library +2009-09-20 : Igor Pavlov : Public domain */ + +#ifndef _WIN32_WCE +#include +#endif + +#include "Threads.h" + +static WRes GetError() +{ + DWORD res = GetLastError(); + return (res) ? (WRes)(res) : 1; +} + +WRes HandleToWRes(HANDLE h) { return (h != 0) ? 0 : GetError(); } +WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); } + +WRes HandlePtr_Close(HANDLE *p) +{ + if (*p != NULL) + if (!CloseHandle(*p)) + return GetError(); + *p = NULL; + return 0; +} + +WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); } + +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param) +{ + unsigned threadId; /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */ + *p = + #ifdef UNDER_CE + CreateThread(0, 0, func, param, 0, &threadId); + #else + (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId); + #endif + /* maybe we must use errno here, but probably GetLastError() is also OK. */ + return HandleToWRes(*p); +} + +WRes Event_Create(CEvent *p, BOOL manualReset, int signaled) +{ + *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL); + return HandleToWRes(*p); +} + +WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); } +WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); } + +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); } +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); } +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); } +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); } + + +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount) +{ + *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL); + return HandleToWRes(*p); +} + +static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount) + { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); } +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num) + { return Semaphore_Release(p, (LONG)num, NULL); } +WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); } + +WRes CriticalSection_Init(CCriticalSection *p) +{ + /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */ + #ifdef _MSC_VER + __try + #endif + { + InitializeCriticalSection(p); + /* InitializeCriticalSectionAndSpinCount(p, 0); */ + } + #ifdef _MSC_VER + __except (EXCEPTION_EXECUTE_HANDLER) { return 1; } + #endif + return 0; +} diff --git a/dep/StormLib/src/lzma/C/Threads.h b/dep/StormLib/src/lzma/C/Threads.h new file mode 100644 index 000000000..d0ddd80e2 --- /dev/null +++ b/dep/StormLib/src/lzma/C/Threads.h @@ -0,0 +1,59 @@ +/* Threads.h -- multithreading library +2009-03-27 : Igor Pavlov : Public domain */ + +#ifndef __7Z_THREADS_H +#define __7Z_THREADS_H + +#include "Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +WRes HandlePtr_Close(HANDLE *h); +WRes Handle_WaitObject(HANDLE h); + +typedef HANDLE CThread; +#define Thread_Construct(p) *(p) = NULL +#define Thread_WasCreated(p) (*(p) != NULL) +#define Thread_Close(p) HandlePtr_Close(p) +#define Thread_Wait(p) Handle_WaitObject(*(p)) +typedef unsigned THREAD_FUNC_RET_TYPE; +#define THREAD_FUNC_CALL_TYPE MY_STD_CALL +#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE +typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *); +WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param); + +typedef HANDLE CEvent; +typedef CEvent CAutoResetEvent; +typedef CEvent CManualResetEvent; +#define Event_Construct(p) *(p) = NULL +#define Event_IsCreated(p) (*(p) != NULL) +#define Event_Close(p) HandlePtr_Close(p) +#define Event_Wait(p) Handle_WaitObject(*(p)) +WRes Event_Set(CEvent *p); +WRes Event_Reset(CEvent *p); +WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled); +WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p); +WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled); +WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p); + +typedef HANDLE CSemaphore; +#define Semaphore_Construct(p) (*p) = NULL +#define Semaphore_Close(p) HandlePtr_Close(p) +#define Semaphore_Wait(p) Handle_WaitObject(*(p)) +WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount); +WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num); +WRes Semaphore_Release1(CSemaphore *p); + +typedef CRITICAL_SECTION CCriticalSection; +WRes CriticalSection_Init(CCriticalSection *p); +#define CriticalSection_Delete(p) DeleteCriticalSection(p) +#define CriticalSection_Enter(p) EnterCriticalSection(p) +#define CriticalSection_Leave(p) LeaveCriticalSection(p) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/dep/StormLib/src/lzma/C/Types.h b/dep/StormLib/src/lzma/C/Types.h new file mode 100644 index 000000000..0526cb47b --- /dev/null +++ b/dep/StormLib/src/lzma/C/Types.h @@ -0,0 +1,236 @@ +/* Types.h -- Basic types +2010-03-11 : Igor Pavlov : Public domain */ + +#ifndef __7Z_TYPES_H +#define __7Z_TYPES_H + +#include + +#ifdef _WIN32 +#include +#endif + +#ifndef EXTERN_C_BEGIN +#ifdef __cplusplus +#define EXTERN_C_BEGIN extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_BEGIN +#define EXTERN_C_END +#endif +#endif + +EXTERN_C_BEGIN + +#define SZ_OK 0 + +#define SZ_ERROR_DATA 1 +#define SZ_ERROR_MEM 2 +#define SZ_ERROR_CRC 3 +#define SZ_ERROR_UNSUPPORTED 4 +#define SZ_ERROR_PARAM 5 +#define SZ_ERROR_INPUT_EOF 6 +#define SZ_ERROR_OUTPUT_EOF 7 +#define SZ_ERROR_READ 8 +#define SZ_ERROR_WRITE 9 +#define SZ_ERROR_PROGRESS 10 +#define SZ_ERROR_FAIL 11 +#define SZ_ERROR_THREAD 12 + +#define SZ_ERROR_ARCHIVE 16 +#define SZ_ERROR_NO_ARCHIVE 17 + +typedef int SRes; + +#ifdef _WIN32 +typedef DWORD WRes; +#else +typedef int WRes; +#endif + +#ifndef RINOK +#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; } +#endif + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef long Int32; +typedef unsigned long UInt32; +#else +typedef int Int32; +typedef unsigned int UInt32; +#endif + +#ifdef _SZ_NO_INT_64 + +/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers. + NOTES: Some code will work incorrectly in that case! */ + +typedef long Int64; +typedef unsigned long UInt64; + +#else + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif + +#ifdef _LZMA_NO_SYSTEM_SIZE_T +typedef UInt32 SizeT; +#else +typedef size_t SizeT; +#endif + +typedef int Bool; +#define True 1 +#define False 0 + + +#ifdef _WIN32 +#define MY_STD_CALL __stdcall +#else +#define MY_STD_CALL +#endif + +#ifdef _MSC_VER + +#if _MSC_VER >= 1300 +#define MY_NO_INLINE __declspec(noinline) +#else +#define MY_NO_INLINE +#endif + +#define MY_CDECL __cdecl +#define MY_FAST_CALL __fastcall + +#else + +#define MY_CDECL +#define MY_FAST_CALL + +#endif + + +/* The following interfaces use first parameter as pointer to structure */ + +typedef struct +{ + Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */ +} IByteIn; + +typedef struct +{ + void (*Write)(void *p, Byte b); +} IByteOut; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) < input(*size)) is allowed */ +} ISeqInStream; + +/* it can return SZ_ERROR_INPUT_EOF */ +SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size); +SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType); +SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf); + +typedef struct +{ + size_t (*Write)(void *p, const void *buf, size_t size); + /* Returns: result - the number of actually written bytes. + (result < size) means error */ +} ISeqOutStream; + +typedef enum +{ + SZ_SEEK_SET = 0, + SZ_SEEK_CUR = 1, + SZ_SEEK_END = 2 +} ESzSeek; + +typedef struct +{ + SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ISeekInStream; + +typedef struct +{ + SRes (*Look)(void *p, const void **buf, size_t *size); + /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream. + (output(*size) > input(*size)) is not allowed + (output(*size) < input(*size)) is allowed */ + SRes (*Skip)(void *p, size_t offset); + /* offset must be <= output(*size) of Look */ + + SRes (*Read)(void *p, void *buf, size_t *size); + /* reads directly (without buffer). It's same as ISeqInStream::Read */ + SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin); +} ILookInStream; + +SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size); +SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset); + +/* reads via ILookInStream::Read */ +SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType); +SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size); + +#define LookToRead_BUF_SIZE (1 << 14) + +typedef struct +{ + ILookInStream s; + ISeekInStream *realStream; + size_t pos; + size_t size; + Byte buf[LookToRead_BUF_SIZE]; +} CLookToRead; + +void LookToRead_CreateVTable(CLookToRead *p, int lookahead); +void LookToRead_Init(CLookToRead *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToLook; + +void SecToLook_CreateVTable(CSecToLook *p); + +typedef struct +{ + ISeqInStream s; + ILookInStream *realStream; +} CSecToRead; + +void SecToRead_CreateVTable(CSecToRead *p); + +typedef struct +{ + SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize); + /* Returns: result. (result != SZ_OK) means break. + Value (UInt64)(Int64)-1 for size means unknown value. */ +} ICompressProgress; + +typedef struct +{ + void *(*Alloc)(void *p, size_t size); + void (*Free)(void *p, void *address); /* address can be 0 */ +} ISzAlloc; + +#define IAlloc_Alloc(p, size) (p)->Alloc((p), size) +#define IAlloc_Free(p, a) (p)->Free((p), a) + +EXTERN_C_END + +#endif diff --git a/dep/StormLib/src/lzma/info.txt b/dep/StormLib/src/lzma/info.txt new file mode 100644 index 000000000..4cee86e35 --- /dev/null +++ b/dep/StormLib/src/lzma/info.txt @@ -0,0 +1 @@ +Taken from LZMA SDK v 9.11 \ No newline at end of file diff --git a/dep/StormLib/src/pklib/crc32.c b/dep/StormLib/src/pklib/crc32.c new file mode 100644 index 000000000..cd47b1d4a --- /dev/null +++ b/dep/StormLib/src/pklib/crc32.c @@ -0,0 +1,66 @@ +/*****************************************************************************/ +/* crc32.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Pkware Data Compression Library Version 1.11 */ +/* Dissassembled method crc32 - cdecl version */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 09.04.03 1.00 Lad The first version of crc32.c */ +/* 02.05.03 1.00 Lad Stress test done */ +/*****************************************************************************/ + +#include "pklib.h" + +static unsigned long crc_table[] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + + +unsigned long PKEXPORT crc32_pklib(char * buffer, unsigned int * psize, unsigned long * old_crc) +{ + unsigned int size = *psize; + unsigned long ch; + unsigned long crc_value = *old_crc; + + while(size-- != 0) + { + ch = *buffer++ ^ (char)crc_value; + crc_value >>= 8; + + crc_value = crc_table[ch & 0x0FF] ^ crc_value; + } + return crc_value; +} diff --git a/dep/StormLib/src/pklib/explode.c b/dep/StormLib/src/pklib/explode.c new file mode 100644 index 000000000..979617399 --- /dev/null +++ b/dep/StormLib/src/pklib/explode.c @@ -0,0 +1,522 @@ +/*****************************************************************************/ +/* explode.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.03.03 1.00 Lad Splitted from Pkware.cpp */ +/* 08.04.03 1.01 Lad Renamed to explode.c to be compatible with pklib */ +/* 02.05.03 1.01 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pklib.h" + +#define PKDCL_OK 0 +#define PKDCL_STREAM_END 1 // All data from the input stream is read +#define PKDCL_NEED_DICT 2 // Need more data (dictionary) +#define PKDCL_CONTINUE 10 // Internal flag, not returned to user +#define PKDCL_GET_INPUT 11 // Internal flag, not returned to user + +char CopyrightPkware[] = "PKWARE Data Compression Library for Win32\r\n" + "Copyright 1989-1995 PKWARE Inc. All Rights Reserved\r\n" + "Patent No. 5,051,745\r\n" + "PKWARE Data Compression Library Reg. U.S. Pat. and Tm. Off.\r\n" + "Version 1.11\r\n"; + +//----------------------------------------------------------------------------- +// Tables + +static unsigned char DistBits[] = +{ + 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static unsigned char DistCode[] = +{ + 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, + 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 +}; + +static unsigned char ExLenBits[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +static unsigned short LenBase[] = +{ + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x000A, 0x000E, 0x0016, 0x0026, 0x0046, 0x0086, 0x0106 +}; + +static unsigned char LenBits[] = +{ + 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 +}; + +static unsigned char LenCode[] = +{ + 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 +}; + +static unsigned char ChBitsAsc[] = +{ + 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, + 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, + 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, + 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D +}; + +static unsigned short ChCodeAsc[] = +{ + 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, + 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, + 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, + 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, + 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, + 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, + 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, + 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, + 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, + 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, + 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, + 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, + 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, + 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, + 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, + 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, + 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, + 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, + 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, + 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, + 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, + 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, + 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, + 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, + 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, + 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, + 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, + 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, + 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, + 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, + 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, + 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000 +}; + +//----------------------------------------------------------------------------- +// Local functions + +static void GenDecodeTabs( + unsigned char * positions, // [out] Table of positions + unsigned char * start_indexes, // [in] Table of start indexes + unsigned char * length_bits, // [in] Table of lengths. Each length is stored as number of bits + size_t elements) // [in] Number of elements in start_indexes and length_bits +{ + unsigned int index; + unsigned int length; + size_t i; + + for(i = 0; i < elements; i++) + { + length = 1 << length_bits[i]; // Get the length in bytes + + for(index = start_indexes[i]; index < 0x100; index += length) + { + positions[index] = (unsigned char)i; + } + } +} + +static void GenAscTabs(TDcmpStruct * pWork) +{ + unsigned short * pChCodeAsc = &ChCodeAsc[0xFF]; + unsigned int acc, add; + unsigned short count; + + for(count = 0x00FF; pChCodeAsc >= ChCodeAsc; pChCodeAsc--, count--) + { + unsigned char * pChBitsAsc = pWork->ChBitsAsc + count; + unsigned char bits_asc = *pChBitsAsc; + + if(bits_asc <= 8) + { + add = (1 << bits_asc); + acc = *pChCodeAsc; + + do + { + pWork->offs2C34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else if((acc = (*pChCodeAsc & 0xFF)) != 0) + { + pWork->offs2C34[acc] = 0xFF; + + if(*pChCodeAsc & 0x3F) + { + bits_asc -= 4; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 4; + do + { + pWork->offs2D34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + else + { + bits_asc -= 6; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 6; + do + { + pWork->offs2E34[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x80); + } + } + else + { + bits_asc -= 8; + *pChBitsAsc = bits_asc; + + add = (1 << bits_asc); + acc = *pChCodeAsc >> 8; + do + { + pWork->offs2EB4[acc] = (unsigned char)count; + acc += add; + } + while(acc < 0x100); + } + } +} + +//----------------------------------------------------------------------------- +// Removes given number of bits in the bit buffer. New bits are reloaded from +// the input buffer, if needed. +// Returns: PKDCL_OK: Operation was successful +// PKDCL_STREAM_END: There are no more bits in the input buffer + +static int WasteBits(TDcmpStruct * pWork, unsigned int nBits) +{ + // If number of bits required is less than number of (bits in the buffer) ? + if(nBits <= pWork->extra_bits) + { + pWork->extra_bits -= nBits; + pWork->bit_buff >>= nBits; + return PKDCL_OK; + } + + // Load input buffer if necessary + pWork->bit_buff >>= pWork->extra_bits; + if(pWork->in_pos == pWork->in_bytes) + { + pWork->in_pos = sizeof(pWork->in_buff); + if((pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param)) == 0) + return PKDCL_STREAM_END; + pWork->in_pos = 0; + } + + // Update bit buffer + pWork->bit_buff |= (pWork->in_buff[pWork->in_pos++] << 8); + pWork->bit_buff >>= (nBits - pWork->extra_bits); + pWork->extra_bits = (pWork->extra_bits - nBits) + 8; + return PKDCL_OK; +} + +//----------------------------------------------------------------------------- +// Decodes next literal from the input (compressed) data. +// Returns : 0x000: One byte 0x00 +// 0x001: One byte 0x01 +// ... +// 0x0FF: One byte 0xFF +// 0x100: Repetition, length of 0x02 bytes +// 0x101: Repetition, length of 0x03 bytes +// ... +// 0x304: Repetition, length of 0x206 bytes +// 0x305: End of stream +// 0x306: Error + +static unsigned int DecodeLit(TDcmpStruct * pWork) +{ + unsigned int extra_length_bits; // Number of bits of extra literal length + unsigned int length_code; // Length code + unsigned int value; + + // Test the current bit in byte buffer. If is not set, simply return the next 8 bits. + if(pWork->bit_buff & 1) + { + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // The next 8 bits hold the index to the length code table + length_code = pWork->LengthCodes[pWork->bit_buff & 0xFF]; + + // Remove the apropriate number of bits + if(WasteBits(pWork, pWork->LenBits[length_code])) + return 0x306; + + // Are there some extra bits for the obtained length code ? + if((extra_length_bits = pWork->ExLenBits[length_code]) != 0) + { + unsigned int extra_length = pWork->bit_buff & ((1 << extra_length_bits) - 1); + + if(WasteBits(pWork, extra_length_bits)) + { + if((length_code + extra_length) != 0x10E) + return 0x306; + } + length_code = pWork->LenBase[length_code] + extra_length; + } + + // In order to distinguish uncompressed byte from repetition length, + // we have to add 0x100 to the length. + return length_code + 0x100; + } + + // Remove one bit from the input data + if(WasteBits(pWork, 1)) + return 0x306; + + // If the binary compression type, read 8 bits and return them as one byte. + if(pWork->ctype == CMP_BINARY) + { + unsigned int uncompressed_byte = pWork->bit_buff & 0xFF; + + if(WasteBits(pWork, 8)) + return 0x306; + return uncompressed_byte; + } + + // When ASCII compression ... + if(pWork->bit_buff & 0xFF) + { + value = pWork->offs2C34[pWork->bit_buff & 0xFF]; + + if(value == 0xFF) + { + if(pWork->bit_buff & 0x3F) + { + if(WasteBits(pWork, 4)) + return 0x306; + + value = pWork->offs2D34[pWork->bit_buff & 0xFF]; + } + else + { + if(WasteBits(pWork, 6)) + return 0x306; + + value = pWork->offs2E34[pWork->bit_buff & 0x7F]; + } + } + } + else + { + if(WasteBits(pWork, 8)) + return 0x306; + + value = pWork->offs2EB4[pWork->bit_buff & 0xFF]; + } + + return WasteBits(pWork, pWork->ChBitsAsc[value]) ? 0x306 : value; +} + +//----------------------------------------------------------------------------- +// Decodes the distance of the repetition, backwards relative to the +// current output buffer position + +static unsigned int DecodeDist(TDcmpStruct * pWork, unsigned int rep_length) +{ + unsigned int dist_pos_code; // Distance position code + unsigned int dist_pos_bits; // Number of bits of distance position + unsigned int distance; // Distance position + + // Next 2-8 bits in the input buffer is the distance position code + dist_pos_code = pWork->DistPosCodes[pWork->bit_buff & 0xFF]; + dist_pos_bits = pWork->DistBits[dist_pos_code]; + if(WasteBits(pWork, dist_pos_bits)) + return 0; + + if(rep_length == 2) + { + // If the repetition is only 2 bytes length, + // then take 2 bits from the stream in order to get the distance + distance = (dist_pos_code << 2) | (pWork->bit_buff & 0x03); + if(WasteBits(pWork, 2)) + return 0; + } + else + { + // If the repetition is more than 2 bytes length, + // then take "dsize_bits" bits in order to get the distance + distance = (dist_pos_code << pWork->dsize_bits) | (pWork->bit_buff & pWork->dsize_mask); + if(WasteBits(pWork, pWork->dsize_bits)) + return 0; + } + return distance + 1; +} + +static unsigned int Expand(TDcmpStruct * pWork) +{ + unsigned int next_literal; // Literal decoded from the compressed data + unsigned int result; // Value to be returned + unsigned int copyBytes; // Number of bytes to copy to the output buffer + + pWork->outputPos = 0x1000; // Initialize output buffer position + + // Decode the next literal from the input data. + // The returned literal can either be an uncompressed byte (next_literal < 0x100) + // or an encoded length of the repeating byte sequence that + // is to be copied to the current buffer position + while((result = next_literal = DecodeLit(pWork)) < 0x305) + { + // If the literal is greater than 0x100, it holds length + // of repeating byte sequence + // literal of 0x100 means repeating sequence of 0x2 bytes + // literal of 0x101 means repeating sequence of 0x3 bytes + // ... + // literal of 0x305 means repeating sequence of 0x207 bytes + if(next_literal >= 0x100) + { + unsigned char * source; + unsigned char * target; + unsigned int rep_length; // Length of the repetition, in bytes + unsigned int minus_dist; // Backward distance to the repetition, relative to the current buffer position + + // Get the length of the repeating sequence. + // Note that the repeating block may overlap the current output position, + // for example if there was a sequence of equal bytes + rep_length = next_literal - 0xFE; + + // Get backward distance to the repetition + if((minus_dist = DecodeDist(pWork, rep_length)) == 0) + { + result = 0x306; + break; + } + + // Target and source pointer + target = &pWork->out_buff[pWork->outputPos]; + source = target - minus_dist; + + // Update buffer output position + pWork->outputPos += rep_length; + + // Copy the repeating sequence + while(rep_length-- > 0) + *target++ = *source++; + } + else + { + pWork->out_buff[pWork->outputPos++] = (unsigned char)next_literal; + } + + // Flush the output buffer, if number of extracted bytes has reached the end + if(pWork->outputPos >= 0x2000) + { + // Copy decompressed data into user buffer + copyBytes = 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + + // Now copy the decompressed data to the first half of the buffer. + // This is needed because the decompression might reuse them as repetitions. + // Note that if the output buffer overflowed previously, the extra decompressed bytes + // are stored in "out_buff_overflow", and they will now be + // within decompressed part of the output buffer. + memmove(pWork->out_buff, &pWork->out_buff[0x1000], pWork->outputPos - 0x1000); + pWork->outputPos -= 0x1000; + } + } + + // Flush any remaining decompressed bytes + copyBytes = pWork->outputPos - 0x1000; + pWork->write_buf((char *)&pWork->out_buff[0x1000], ©Bytes, pWork->param); + return result; +} + + +//----------------------------------------------------------------------------- +// Main exploding function. + +unsigned int explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param) +{ + TDcmpStruct * pWork = (TDcmpStruct *)work_buf; + + // Initialize work struct and load compressed data + // Note: The caller must zero the "work_buff" before passing it to explode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->param = param; + pWork->in_pos = sizeof(pWork->in_buff); + pWork->in_bytes = pWork->read_buf((char *)pWork->in_buff, &pWork->in_pos, pWork->param); + if(pWork->in_bytes <= 4) + return CMP_BAD_DATA; + + pWork->ctype = pWork->in_buff[0]; // Get the compression type (CMP_BINARY or CMP_ASCII) + pWork->dsize_bits = pWork->in_buff[1]; // Get the dictionary size + pWork->bit_buff = pWork->in_buff[2]; // Initialize 16-bit bit buffer + pWork->extra_bits = 0; // Extra (over 8) bits + pWork->in_pos = 3; // Position in input buffer + + // Test for the valid dictionary size + if(4 > pWork->dsize_bits || pWork->dsize_bits > 6) + return CMP_INVALID_DICTSIZE; + + pWork->dsize_mask = 0xFFFF >> (0x10 - pWork->dsize_bits); // Shifted by 'sar' instruction + + if(pWork->ctype != CMP_BINARY) + { + if(pWork->ctype != CMP_ASCII) + return CMP_INVALID_MODE; + + memcpy(pWork->ChBitsAsc, ChBitsAsc, sizeof(pWork->ChBitsAsc)); + GenAscTabs(pWork); + } + + memcpy(pWork->LenBits, LenBits, sizeof(pWork->LenBits)); + GenDecodeTabs(pWork->LengthCodes, LenCode, pWork->LenBits, sizeof(pWork->LenBits)); + memcpy(pWork->ExLenBits, ExLenBits, sizeof(pWork->ExLenBits)); + memcpy(pWork->LenBase, LenBase, sizeof(pWork->LenBase)); + memcpy(pWork->DistBits, DistBits, sizeof(pWork->DistBits)); + GenDecodeTabs(pWork->DistPosCodes, DistCode, pWork->DistBits, sizeof(pWork->DistBits)); + if(Expand(pWork) != 0x306) + return CMP_NO_ERROR; + + return CMP_ABORT; +} diff --git a/dep/StormLib/src/pklib/implode.c b/dep/StormLib/src/pklib/implode.c new file mode 100644 index 000000000..f29f54d64 --- /dev/null +++ b/dep/StormLib/src/pklib/implode.c @@ -0,0 +1,769 @@ +/*****************************************************************************/ +/* implode.c Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Implode function of PKWARE Data Compression library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 11.04.03 1.00 Lad First version of implode.c */ +/* 02.05.03 1.00 Lad Stress test done */ +/* 22.04.10 1.01 Lad Documented */ +/*****************************************************************************/ + +#include +#include + +#include "pklib.h" + +#if ((1200 < _MSC_VER) && (_MSC_VER < 1400)) +#pragma optimize("", off) // Fucking Microsoft VS.NET 2003 compiler !!! (_MSC_VER=1310) +#endif + +//----------------------------------------------------------------------------- +// Defines + +#define MAX_REP_LENGTH 0x204 // The longest allowed repetition + +//----------------------------------------------------------------------------- +// Tables + +static unsigned char DistBits[] = +{ + 0x02, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 +}; + +static unsigned char DistCode[] = +{ + 0x03, 0x0D, 0x05, 0x19, 0x09, 0x11, 0x01, 0x3E, 0x1E, 0x2E, 0x0E, 0x36, 0x16, 0x26, 0x06, 0x3A, + 0x1A, 0x2A, 0x0A, 0x32, 0x12, 0x22, 0x42, 0x02, 0x7C, 0x3C, 0x5C, 0x1C, 0x6C, 0x2C, 0x4C, 0x0C, + 0x74, 0x34, 0x54, 0x14, 0x64, 0x24, 0x44, 0x04, 0x78, 0x38, 0x58, 0x18, 0x68, 0x28, 0x48, 0x08, + 0xF0, 0x70, 0xB0, 0x30, 0xD0, 0x50, 0x90, 0x10, 0xE0, 0x60, 0xA0, 0x20, 0xC0, 0x40, 0x80, 0x00 +}; + +static unsigned char ExLenBits[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 +}; + +static unsigned char LenBits[] = +{ + 0x03, 0x02, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07 +}; + +static unsigned char LenCode[] = +{ + 0x05, 0x03, 0x01, 0x06, 0x0A, 0x02, 0x0C, 0x14, 0x04, 0x18, 0x08, 0x30, 0x10, 0x20, 0x40, 0x00 +}; + +static unsigned char ChBitsAsc[] = +{ + 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x08, 0x07, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x04, 0x0A, 0x08, 0x0C, 0x0A, 0x0C, 0x0A, 0x08, 0x07, 0x07, 0x08, 0x09, 0x07, 0x06, 0x07, 0x08, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x0C, 0x0B, 0x07, 0x09, 0x0B, + 0x0C, 0x06, 0x07, 0x06, 0x06, 0x05, 0x07, 0x08, 0x08, 0x06, 0x0B, 0x09, 0x06, 0x07, 0x06, 0x06, + 0x07, 0x0B, 0x06, 0x06, 0x06, 0x07, 0x09, 0x08, 0x09, 0x09, 0x0B, 0x08, 0x0B, 0x09, 0x0C, 0x08, + 0x0C, 0x05, 0x06, 0x06, 0x06, 0x05, 0x06, 0x06, 0x06, 0x05, 0x0B, 0x07, 0x05, 0x06, 0x05, 0x05, + 0x06, 0x0A, 0x05, 0x05, 0x05, 0x05, 0x08, 0x07, 0x08, 0x08, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, + 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0C, 0x0D, + 0x0D, 0x0D, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D +}; + +static unsigned short ChCodeAsc[] = +{ + 0x0490, 0x0FE0, 0x07E0, 0x0BE0, 0x03E0, 0x0DE0, 0x05E0, 0x09E0, + 0x01E0, 0x00B8, 0x0062, 0x0EE0, 0x06E0, 0x0022, 0x0AE0, 0x02E0, + 0x0CE0, 0x04E0, 0x08E0, 0x00E0, 0x0F60, 0x0760, 0x0B60, 0x0360, + 0x0D60, 0x0560, 0x1240, 0x0960, 0x0160, 0x0E60, 0x0660, 0x0A60, + 0x000F, 0x0250, 0x0038, 0x0260, 0x0050, 0x0C60, 0x0390, 0x00D8, + 0x0042, 0x0002, 0x0058, 0x01B0, 0x007C, 0x0029, 0x003C, 0x0098, + 0x005C, 0x0009, 0x001C, 0x006C, 0x002C, 0x004C, 0x0018, 0x000C, + 0x0074, 0x00E8, 0x0068, 0x0460, 0x0090, 0x0034, 0x00B0, 0x0710, + 0x0860, 0x0031, 0x0054, 0x0011, 0x0021, 0x0017, 0x0014, 0x00A8, + 0x0028, 0x0001, 0x0310, 0x0130, 0x003E, 0x0064, 0x001E, 0x002E, + 0x0024, 0x0510, 0x000E, 0x0036, 0x0016, 0x0044, 0x0030, 0x00C8, + 0x01D0, 0x00D0, 0x0110, 0x0048, 0x0610, 0x0150, 0x0060, 0x0088, + 0x0FA0, 0x0007, 0x0026, 0x0006, 0x003A, 0x001B, 0x001A, 0x002A, + 0x000A, 0x000B, 0x0210, 0x0004, 0x0013, 0x0032, 0x0003, 0x001D, + 0x0012, 0x0190, 0x000D, 0x0015, 0x0005, 0x0019, 0x0008, 0x0078, + 0x00F0, 0x0070, 0x0290, 0x0410, 0x0010, 0x07A0, 0x0BA0, 0x03A0, + 0x0240, 0x1C40, 0x0C40, 0x1440, 0x0440, 0x1840, 0x0840, 0x1040, + 0x0040, 0x1F80, 0x0F80, 0x1780, 0x0780, 0x1B80, 0x0B80, 0x1380, + 0x0380, 0x1D80, 0x0D80, 0x1580, 0x0580, 0x1980, 0x0980, 0x1180, + 0x0180, 0x1E80, 0x0E80, 0x1680, 0x0680, 0x1A80, 0x0A80, 0x1280, + 0x0280, 0x1C80, 0x0C80, 0x1480, 0x0480, 0x1880, 0x0880, 0x1080, + 0x0080, 0x1F00, 0x0F00, 0x1700, 0x0700, 0x1B00, 0x0B00, 0x1300, + 0x0DA0, 0x05A0, 0x09A0, 0x01A0, 0x0EA0, 0x06A0, 0x0AA0, 0x02A0, + 0x0CA0, 0x04A0, 0x08A0, 0x00A0, 0x0F20, 0x0720, 0x0B20, 0x0320, + 0x0D20, 0x0520, 0x0920, 0x0120, 0x0E20, 0x0620, 0x0A20, 0x0220, + 0x0C20, 0x0420, 0x0820, 0x0020, 0x0FC0, 0x07C0, 0x0BC0, 0x03C0, + 0x0DC0, 0x05C0, 0x09C0, 0x01C0, 0x0EC0, 0x06C0, 0x0AC0, 0x02C0, + 0x0CC0, 0x04C0, 0x08C0, 0x00C0, 0x0F40, 0x0740, 0x0B40, 0x0340, + 0x0300, 0x0D40, 0x1D00, 0x0D00, 0x1500, 0x0540, 0x0500, 0x1900, + 0x0900, 0x0940, 0x1100, 0x0100, 0x1E00, 0x0E00, 0x0140, 0x1600, + 0x0600, 0x1A00, 0x0E40, 0x0640, 0x0A40, 0x0A00, 0x1200, 0x0200, + 0x1C00, 0x0C00, 0x1400, 0x0400, 0x1800, 0x0800, 0x1000, 0x0000 +}; + +//----------------------------------------------------------------------------- +// Macros + +// Macro for calculating hash of the current byte pair. +// Note that most exact byte pair hash would be buffer[0] + buffer[1] << 0x08, +// but even this way gives nice indication of equal byte pairs, with significantly +// smaller size of the array that holds numbers of those hashes +#define BYTE_PAIR_HASH(buffer) ((buffer[0] * 4) + (buffer[1] * 5)) + +//----------------------------------------------------------------------------- +// Local functions + +// Builds the "hash_to_index" table and "pair_hash_offsets" table. +// Every element of "hash_to_index" will contain lowest index to the +// "pair_hash_offsets" table, effectively giving offset of the first +// occurence of the given PAIR_HASH in the input data. +static void SortBuffer(TCmpStruct * pWork, unsigned char * buffer_begin, unsigned char * buffer_end) +{ + unsigned short * phash_to_index; + unsigned char * buffer_ptr; + unsigned short total_sum = 0; + unsigned long byte_pair_hash; // Hash value of the byte pair + unsigned short byte_pair_offs; // Offset of the byte pair, relative to "work_buff" + + // Zero the entire "phash_to_index" table + memset(pWork->phash_to_index, 0, sizeof(pWork->phash_to_index)); + + // Step 1: Count amount of each PAIR_HASH in the input buffer + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 + // offs 0x001: Number of occurences of PAIR_HASH 1 + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 (the highest hash value) + for(buffer_ptr = buffer_begin; buffer_ptr < buffer_end; buffer_ptr++) + pWork->phash_to_index[BYTE_PAIR_HASH(buffer_ptr)]++; + + // Step 2: Convert the table to the array of PAIR_HASH amounts. + // Each element contains count of PAIR_HASHes that is less or equal + // to element index + // The table will look like this: + // offs 0x000: Number of occurences of PAIR_HASH 0 or lower + // offs 0x001: Number of occurences of PAIR_HASH 1 or lower + // ... + // offs 0x8F7: Number of occurences of PAIR_HASH 0x8F7 or lower + for(phash_to_index = pWork->phash_to_index; phash_to_index < &pWork->phash_to_index_end; phash_to_index++) + { + total_sum = total_sum + phash_to_index[0]; + phash_to_index[0] = total_sum; + } + + // Step 3: Convert the table to the array of indexes. + // Now, each element contains index to the first occurence of given PAIR_HASH + for(buffer_end--; buffer_end >= buffer_begin; buffer_end--) + { + byte_pair_hash = BYTE_PAIR_HASH(buffer_end); + byte_pair_offs = (unsigned short)(buffer_end - pWork->work_buff); + + pWork->phash_to_index[byte_pair_hash]--; + pWork->phash_offs[pWork->phash_to_index[byte_pair_hash]] = byte_pair_offs; + } +} + +static void FlushBuf(TCmpStruct * pWork) +{ + unsigned char save_ch1; + unsigned char save_ch2; + unsigned int size = 0x800; + + pWork->write_buf(pWork->out_buff, &size, pWork->param); + + save_ch1 = pWork->out_buff[0x800]; + save_ch2 = pWork->out_buff[pWork->out_bytes]; + pWork->out_bytes -= 0x800; + + memset(pWork->out_buff, 0, sizeof(pWork->out_buff)); + + if(pWork->out_bytes != 0) + pWork->out_buff[0] = save_ch1; + if(pWork->out_bits != 0) + pWork->out_buff[pWork->out_bytes] = save_ch2; +} + +static void OutputBits(TCmpStruct * pWork, unsigned int nbits, unsigned long bit_buff) +{ + unsigned int out_bits; + + // If more than 8 bits to output, do recursion + if(nbits > 8) + { + OutputBits(pWork, 8, bit_buff); + bit_buff >>= 8; + nbits -= 8; + } + + // Add bits to the last out byte in out_buff; + out_bits = pWork->out_bits; + pWork->out_buff[pWork->out_bytes] |= (unsigned char)(bit_buff << out_bits); + pWork->out_bits += nbits; + + // If 8 or more bits, increment number of bytes + if(pWork->out_bits > 8) + { + pWork->out_bytes++; + bit_buff >>= (8 - out_bits); + + pWork->out_buff[pWork->out_bytes] = (unsigned char)bit_buff; + pWork->out_bits &= 7; + } + else + { + pWork->out_bits &= 7; + if(pWork->out_bits == 0) + pWork->out_bytes++; + } + + // If there is enough compressed bytes, flush them + if(pWork->out_bytes >= 0x800) + FlushBuf(pWork); +} + +// This function searches for a repetition +// (a previous occurence of the current byte sequence) +// Returns length of the repetition, and stores the backward distance +// to pWork structure. +static unsigned int FindRep(TCmpStruct * pWork, unsigned char * input_data) +{ + unsigned short * phash_to_index; // Pointer into pWork->phash_to_index table + unsigned short * phash_offs; // Pointer to the table containing offsets of each PAIR_HASH + unsigned char * repetition_limit; // An eventual repetition must be at position below this pointer + unsigned char * prev_repetition; // Pointer to the previous occurence of the current PAIR_HASH + unsigned char * prev_rep_end; // End of the previous repetition + unsigned char * input_data_ptr; + unsigned short phash_offs_index; // Index to the table with PAIR_HASH positions + unsigned short min_phash_offs; // The lowest allowed hash offset + unsigned short offs_in_rep; // Offset within found repetition + unsigned int equal_byte_count; // Number of bytes that are equal to the previous occurence + unsigned int rep_length = 1; // Length of the found repetition + unsigned int rep_length2; // Secondary repetition + unsigned char pre_last_byte; // Last but one byte from a repetion + unsigned short di_val; + + // Calculate the previous position of the PAIR_HASH + phash_to_index = pWork->phash_to_index + BYTE_PAIR_HASH(input_data); + min_phash_offs = (unsigned short)((input_data - pWork->work_buff) - pWork->dsize_bytes + 1); + phash_offs_index = phash_to_index[0]; + + // If the PAIR_HASH offset is below the limit, find a next one + phash_offs = pWork->phash_offs + phash_offs_index; + if(*phash_offs < min_phash_offs) + { + while(*phash_offs < min_phash_offs) + { + phash_offs_index++; + phash_offs++; + } + *phash_to_index = phash_offs_index; + } + + // Get the first location of the PAIR_HASH, + // and thus the first eventual location of byte repetition + phash_offs = pWork->phash_offs + phash_offs_index; + prev_repetition = pWork->work_buff + phash_offs[0]; + repetition_limit = input_data - 1; + + // If the current PAIR_HASH was not encountered before, + // we haven't found a repetition. + if(prev_repetition >= repetition_limit) + return 0; + + // We have found a match of a PAIR_HASH. Now we have to make sure + // that it is also a byte match, because PAIR_HASH is not unique. + // We compare the bytes and count the length of the repetition + input_data_ptr = input_data; + for(;;) + { + // If the first byte of the repetition and the so-far-last byte + // of the repetition are equal, we will compare the blocks. + if(*input_data_ptr == *prev_repetition && input_data_ptr[rep_length-1] == prev_repetition[rep_length-1]) + { + // Skip the current byte + prev_repetition++; + input_data_ptr++; + equal_byte_count = 2; + + // Now count how many more bytes are equal + while(equal_byte_count < MAX_REP_LENGTH) + { + prev_repetition++; + input_data_ptr++; + + // Are the bytes different ? + if(*prev_repetition != *input_data_ptr) + break; + + equal_byte_count++; + } + + // If we found a repetition of at least the same length, take it. + // If there are multiple repetitions in the input buffer, this will + // make sure that we find the most recent one, which in turn allows + // us to store backward length in less amount of bits + input_data_ptr = input_data; + if(equal_byte_count >= rep_length) + { + // Calculate the backward distance of the repetition. + // Note that the distance is stored as decremented by 1 + pWork->distance = (unsigned int)(input_data - prev_repetition + equal_byte_count - 1); + + // Repetitions longer than 10 bytes will be stored in more bits, + // so they need a bit different handling + if((rep_length = equal_byte_count) > 10) + break; + } + } + + // Move forward in the table of PAIR_HASH repetitions. + // There might be a more recent occurence of the same repetition. + phash_offs_index++; + phash_offs++; + prev_repetition = pWork->work_buff + phash_offs[0]; + + // If the next repetition is beyond the minimum allowed repetition, we are done. + if(prev_repetition >= repetition_limit) + { + // A repetition must have at least 2 bytes, otherwise it's not worth it + return (rep_length >= 2) ? rep_length : 0; + } + } + + // If the repetition has max length of 0x204 bytes, we can't go any fuhrter + if(equal_byte_count == MAX_REP_LENGTH) + { + pWork->distance--; + return equal_byte_count; + } + + // Check for possibility of a repetition that occurs at more recent position + phash_offs = pWork->phash_offs + phash_offs_index; + if(pWork->work_buff + phash_offs[1] >= repetition_limit) + return rep_length; + + // + // The following part checks if there isn't a longer repetition at + // a latter offset, that would lead to better compression. + // + // Example of data that can trigger this optimization: + // + // "EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // "XYZ" + // "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ"; + // + // Description of data in this buffer + // [0x00] Single byte "E" + // [0x01] Single byte "E" + // [0x02] Repeat 0x1E bytes from [0x00] + // [0x20] Single byte "X" + // [0x21] Single byte "Y" + // [0x22] Single byte "Z" + // [0x23] 17 possible previous repetitions of length at least 0x10 bytes: + // - Repetition of 0x10 bytes from [0x00] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x01] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x10 bytes from [0x02] "EEEEEEEEEEEEEEEE" + // ... + // - Repetition of 0x10 bytes from [0x0F] "EEEEEEEEEEEEEEEE" + // - Repetition of 0x1C bytes from [0x10] "EEEEEEEEEEEEEEEEQQQQQQQQQQQQ" + // The last repetition is the best one. + // + + pWork->offs09BC[0] = 0xFFFF; + pWork->offs09BC[1] = 0x0000; + di_val = 0; + + // Note: I failed to figure out what does the table "offs09BC" mean. + // If anyone has an idea, let me know to zezula_at_volny_dot_cz + for(offs_in_rep = 1; offs_in_rep < rep_length; ) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + + // + // Now go through all the repetitions from the first found one + // to the current input data, and check if any of them migh be + // a start of a greater sequence match. + // + + prev_repetition = pWork->work_buff + phash_offs[0]; + prev_rep_end = prev_repetition + rep_length; + rep_length2 = rep_length; + + for(;;) + { + rep_length2 = pWork->offs09BC[rep_length2]; + if(rep_length2 == 0xFFFF) + rep_length2 = 0; + + // Get the pointer to the previous repetition + phash_offs = pWork->phash_offs + phash_offs_index; + + // Skip those repetitions that don't reach the end + // of the first found repetition + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition + rep_length2 < prev_rep_end); + + // Verify if the last but one byte from the repetition matches + // the last but one byte from the input data. + // If not, find a next repetition + pre_last_byte = input_data[rep_length - 2]; + if(pre_last_byte == prev_repetition[rep_length - 2]) + { + // If the new repetition reaches beyond the end + // of previously found repetition, reset the repetition length to zero. + if(prev_repetition + rep_length2 != prev_rep_end) + { + prev_rep_end = prev_repetition; + rep_length2 = 0; + } + } + else + { + phash_offs = pWork->phash_offs + phash_offs_index; + do + { + phash_offs++; + phash_offs_index++; + prev_repetition = pWork->work_buff + *phash_offs; + if(prev_repetition >= repetition_limit) + return rep_length; + } + while(prev_repetition[rep_length - 2] != pre_last_byte || prev_repetition[0] != input_data[0]); + + // Reset the length of the repetition to 2 bytes only + prev_rep_end = prev_repetition + 2; + rep_length2 = 2; + } + + // Find out how many more characters are equal to the first repetition. + while(*prev_rep_end == input_data[rep_length2]) + { + if(++rep_length2 >= 0x204) + break; + prev_rep_end++; + } + + // Is the newly found repetion at least as long as the previous one ? + if(rep_length2 >= rep_length) + { + // Calculate the distance of the new repetition + pWork->distance = (unsigned int)(input_data - prev_repetition - 1); + if((rep_length = rep_length2) == 0x204) + return rep_length; + + // Update the additional elements in the "offs09BC" table + // to reflect new rep length + while(offs_in_rep < rep_length2) + { + if(input_data[offs_in_rep] != input_data[di_val]) + { + di_val = pWork->offs09BC[di_val]; + if(di_val != 0xFFFF) + continue; + } + pWork->offs09BC[++offs_in_rep] = ++di_val; + } + } + } +} + +static void WriteCmpData(TCmpStruct * pWork) +{ + unsigned char * input_data_end; // Pointer to the end of the input data + unsigned char * input_data = pWork->work_buff + pWork->dsize_bytes + 0x204; + unsigned int input_data_ended = 0; // If 1, then all data from the input stream have been already loaded + unsigned int save_rep_length; // Saved length of current repetition + unsigned int save_distance = 0; // Saved distance of current repetition + unsigned int rep_length; // Length of the found repetition + unsigned int phase = 0; // + + // Store the compression type and dictionary size + pWork->out_buff[0] = (char)pWork->ctype; + pWork->out_buff[1] = (char)pWork->dsize_bits; + pWork->out_bytes = 2; + + // Reset output buffer to zero + memset(&pWork->out_buff[2], 0, sizeof(pWork->out_buff) - 2); + pWork->out_bits = 0; + + while(input_data_ended == 0) + { + unsigned int bytes_to_load = 0x1000; + int total_loaded = 0; + int bytes_loaded; + + // Load the bytes from the input stream, up to 0x1000 bytes + while(bytes_to_load != 0) + { + bytes_loaded = pWork->read_buf((char *)pWork->work_buff + pWork->dsize_bytes + 0x204 + total_loaded, + &bytes_to_load, + pWork->param); + if(bytes_loaded == 0) + { + if(total_loaded == 0 && phase == 0) + goto __Exit; + input_data_ended = 1; + break; + } + else + { + bytes_to_load -= bytes_loaded; + total_loaded += bytes_loaded; + } + } + + input_data_end = pWork->work_buff + pWork->dsize_bytes + total_loaded; + if(input_data_ended) + input_data_end += 0x204; + + // + // Warning: The end of the buffer passed to "SortBuffer" is actually 2 bytes beyond + // valid data. It is questionable if this is actually a bug or not, + // but it might cause the compressed data output to be dependent on random bytes + // that are in the buffer. + // To prevent that, the calling application must always zero the compression + // buffer before passing it to "implode" + // + + // Search the PAIR_HASHes of the loaded blocks. Also, include + // previously compressed data, if any. + switch(phase) + { + case 0: + SortBuffer(pWork, input_data, input_data_end + 1); + phase++; + if(pWork->dsize_bytes != 0x1000) + phase++; + break; + + case 1: + SortBuffer(pWork, input_data - pWork->dsize_bytes + 0x204, input_data_end + 1); + phase++; + break; + + default: + SortBuffer(pWork, input_data - pWork->dsize_bytes, input_data_end + 1); + break; + } + + // Perform the compression of the current block + while(input_data < input_data_end) + { + // Find if the current byte sequence wasn't there before. + rep_length = FindRep(pWork, input_data); + while(rep_length != 0) + { + // If we found repetition of 2 bytes, that is 0x100 or fuhrter back, + // don't bother. Storing the distance of 0x100 bytes would actually + // take more space than storing the 2 bytes as-is. + if(rep_length == 2 && pWork->distance >= 0x100) + break; + + // When we are at the end of the input data, we cannot allow + // the repetition to go past the end of the input data. + if(input_data_ended && input_data + rep_length > input_data_end) + { + // Shorten the repetition length so that it only covers valid data + rep_length = (unsigned long)(input_data_end - input_data); + if(rep_length < 2) + break; + + // If we got repetition of 2 bytes, that is 0x100 or more backward, don't bother + if(rep_length == 2 && pWork->distance >= 0x100) + break; + goto __FlushRepetition; + } + + if(rep_length >= 8 || input_data + 1 >= input_data_end) + goto __FlushRepetition; + + // Try to find better repetition 1 byte later. + // Example: "ARROCKFORT" "AROCKFORT" + // When "input_data" points to the second string, FindRep + // returns the occurence of "AR". But there is longer repetition "ROCKFORT", + // beginning 1 byte after. + save_rep_length = rep_length; + save_distance = pWork->distance; + rep_length = FindRep(pWork, input_data + 1); + + // Only use the new repetition if it's length is greater than the previous one + if(rep_length > save_rep_length) + { + // If the new repetition if only 1 byte better + // and the previous distance is less than 0x80 bytes, use the previous repetition + if(rep_length > save_rep_length + 1 || save_distance > 0x80) + { + // Flush one byte, so that input_data will point to the secondary repetition + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; + continue; + } + } + + // Revert to the previous repetition + rep_length = save_rep_length; + pWork->distance = save_distance; + + __FlushRepetition: + + OutputBits(pWork, pWork->nChBits[rep_length + 0xFE], pWork->nChCodes[rep_length + 0xFE]); + if(rep_length == 2) + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> 2], + pWork->dist_codes[pWork->distance >> 2]); + OutputBits(pWork, 2, pWork->distance & 3); + } + else + { + OutputBits(pWork, pWork->dist_bits[pWork->distance >> pWork->dsize_bits], + pWork->dist_codes[pWork->distance >> pWork->dsize_bits]); + OutputBits(pWork, pWork->dsize_bits, pWork->dsize_mask & pWork->distance); + } + + // Move the begin of the input data by the length of the repetition + input_data += rep_length; + goto _00402252; + } + + // If there was no previous repetition for the current position in the input data, + // just output the 9-bit literal for the one character + OutputBits(pWork, pWork->nChBits[*input_data], pWork->nChCodes[*input_data]); + input_data++; +_00402252:; + } + + if(input_data_ended == 0) + { + input_data -= 0x1000; + memmove(pWork->work_buff, pWork->work_buff + 0x1000, pWork->dsize_bytes + 0x204); + } + } + +__Exit: + + // Write the termination literal + OutputBits(pWork, pWork->nChBits[0x305], pWork->nChCodes[0x305]); + if(pWork->out_bits != 0) + pWork->out_bytes++; + pWork->write_buf(pWork->out_buff, &pWork->out_bytes, pWork->param); + return; +} + +//----------------------------------------------------------------------------- +// Main imploding function + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize) +{ + TCmpStruct * pWork = (TCmpStruct *)work_buf; + unsigned int nChCode; + unsigned int nCount; + unsigned int i; + int nCount2; + + // Fill the work buffer information + // Note: The caller must zero the "work_buff" before passing it to implode + pWork->read_buf = read_buf; + pWork->write_buf = write_buf; + pWork->dsize_bytes = *dsize; + pWork->ctype = *type; + pWork->param = param; + pWork->dsize_bits = 4; + pWork->dsize_mask = 0x0F; + + // Test dictionary size + switch(*dsize) + { + case CMP_IMPLODE_DICT_SIZE3: // 0x1000 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x20; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE2: // 0x800 bytes + pWork->dsize_bits++; + pWork->dsize_mask |= 0x10; + // No break here !!! + + case CMP_IMPLODE_DICT_SIZE1: // 0x400 + break; + + default: + return CMP_INVALID_DICTSIZE; + } + + // Test the compression type + switch(*type) + { + case CMP_BINARY: // We will compress data with binary compression type + for(nChCode = 0, nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = 9; + pWork->nChCodes[nCount] = (unsigned short)nChCode; + nChCode = (nChCode & 0x0000FFFF) + 2; + } + break; + + + case CMP_ASCII: // We will compress data with ASCII compression type + for(nCount = 0; nCount < 0x100; nCount++) + { + pWork->nChBits[nCount] = (unsigned char )(ChBitsAsc[nCount] + 1); + pWork->nChCodes[nCount] = (unsigned short)(ChCodeAsc[nCount] * 2); + } + break; + + default: + return CMP_INVALID_MODE; + } + + for(i = 0; i < 0x10; i++) + { + if(1 << ExLenBits[i]) + { + for(nCount2 = 0; nCount2 < (1 << ExLenBits[i]); nCount2++) + { + pWork->nChBits[nCount] = (unsigned char)(ExLenBits[i] + LenBits[i] + 1); + pWork->nChCodes[nCount] = (unsigned short)((nCount2 << (LenBits[i] + 1)) | ((LenCode[i] & 0xFFFF00FF) * 2) | 1); + nCount++; + } + } + } + + // Copy the distance codes and distance bits and perform the compression + memcpy(&pWork->dist_codes, DistCode, sizeof(DistCode)); + memcpy(&pWork->dist_bits, DistBits, sizeof(DistBits)); + WriteCmpData(pWork); + return CMP_NO_ERROR; +} diff --git a/dep/StormLib/src/pklib/pklib.h b/dep/StormLib/src/pklib/pklib.h new file mode 100644 index 000000000..9eb2915b7 --- /dev/null +++ b/dep/StormLib/src/pklib/pklib.h @@ -0,0 +1,146 @@ +/*****************************************************************************/ +/* pklib.h Copyright (c) Ladislav Zezula 2003 */ +/*---------------------------------------------------------------------------*/ +/* Header file for PKWARE Data Compression Library */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 31.03.03 1.00 Lad The first version of pkware.h */ +/*****************************************************************************/ + +#ifndef __PKLIB_H__ +#define __PKLIB_H__ + +//----------------------------------------------------------------------------- +// Defines + +#define CMP_BINARY 0 // Binary compression +#define CMP_ASCII 1 // Ascii compression + +#define CMP_NO_ERROR 0 +#define CMP_INVALID_DICTSIZE 1 +#define CMP_INVALID_MODE 2 +#define CMP_BAD_DATA 3 +#define CMP_ABORT 4 + +#define CMP_IMPLODE_DICT_SIZE1 1024 // Dictionary size of 1024 +#define CMP_IMPLODE_DICT_SIZE2 2048 // Dictionary size of 2048 +#define CMP_IMPLODE_DICT_SIZE3 4096 // Dictionary size of 4096 + +//----------------------------------------------------------------------------- +// Define calling convention + +#ifndef PKEXPORT +#ifdef WIN32 +#define PKEXPORT __cdecl // Use for normal __cdecl calling +#else +#define PKEXPORT +#endif +#endif + +//----------------------------------------------------------------------------- +// Internal structures + +// Compression structure +typedef struct +{ + unsigned int distance; // 0000: Backward distance of the currently found repetition, decreased by 1 + unsigned int out_bytes; // 0004: # bytes available in out_buff + unsigned int out_bits; // 0008: # of bits available in the last out byte + unsigned int dsize_bits; // 000C: Number of bits needed for dictionary size. 4 = 0x400, 5 = 0x800, 6 = 0x1000 + unsigned int dsize_mask; // 0010: Bit mask for dictionary. 0x0F = 0x400, 0x1F = 0x800, 0x3F = 0x1000 + unsigned int ctype; // 0014: Compression type (CMP_ASCII or CMP_BINARY) + unsigned int dsize_bytes; // 0018: Dictionary size in bytes + unsigned char dist_bits[0x40]; // 001C: Distance bits + unsigned char dist_codes[0x40]; // 005C: Distance codes + unsigned char nChBits[0x306]; // 009C: Table of literal bit lengths to be put to the output stream + unsigned short nChCodes[0x306]; // 03A2: Table of literal codes to be put to the output stream + unsigned short offs09AE; // 09AE: + + void * param; // 09B0: User parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // 9B4 + void (*write_buf)(char *buf, unsigned int *size, void *param); // 9B8 + + unsigned short offs09BC[0x204]; // 09BC: + unsigned long offs0DC4; // 0DC4: + unsigned short phash_to_index[0x900]; // 0DC8: Array of indexes (one for each PAIR_HASH) to the "pair_hash_offsets" table + unsigned short phash_to_index_end; // 1FC8: End marker for "phash_to_index" table + char out_buff[0x802]; // 1FCA: Compressed data + unsigned char work_buff[0x2204]; // 27CC: Work buffer + // + DICT_OFFSET => Dictionary + // + UNCMP_OFFSET => Uncompressed data + unsigned short phash_offs[0x2204]; // 49D0: Table of offsets for each PAIR_HASH +} TCmpStruct; + +#define CMP_BUFFER_SIZE sizeof(TCmpStruct) // Size of compression structure. + // Defined as 36312 in pkware header file + + +// Decompression structure +typedef struct +{ + unsigned long offs0000; // 0000 + unsigned long ctype; // 0004: Compression type (CMP_BINARY or CMP_ASCII) + unsigned long outputPos; // 0008: Position in output buffer + unsigned long dsize_bits; // 000C: Dict size (4, 5, 6 for 0x400, 0x800, 0x1000) + unsigned long dsize_mask; // 0010: Dict size bitmask (0x0F, 0x1F, 0x3F for 0x400, 0x800, 0x1000) + unsigned long bit_buff; // 0014: 16-bit buffer for processing input data + unsigned long extra_bits; // 0018: Number of extra (above 8) bits in bit buffer + unsigned int in_pos; // 001C: Position in in_buff + unsigned long in_bytes; // 0020: Number of bytes in input buffer + void * param; // 0024: Custom parameter + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param); // Pointer to function that reads data from the input stream + void (*write_buf)(char *buf, unsigned int *size, void *param);// Pointer to function that writes data to the output stream + + unsigned char out_buff[0x2204]; // 0030: Output circle buffer. + // 0x0000 - 0x0FFF: Previous uncompressed data, kept for repetitions + // 0x1000 - 0x1FFF: Currently decompressed data + // 0x2000 - 0x2203: Reserve space for the longest possible repetition + unsigned char in_buff[0x800]; // 2234: Buffer for data to be decompressed + unsigned char DistPosCodes[0x100]; // 2A34: Table of distance position codes + unsigned char LengthCodes[0x100]; // 2B34: Table of length codes + unsigned char offs2C34[0x100]; // 2C34: Buffer for + unsigned char offs2D34[0x100]; // 2D34: Buffer for + unsigned char offs2E34[0x80]; // 2EB4: Buffer for + unsigned char offs2EB4[0x100]; // 2EB4: Buffer for + unsigned char ChBitsAsc[0x100]; // 2FB4: Buffer for + unsigned char DistBits[0x40]; // 30B4: Numbers of bytes to skip copied block length + unsigned char LenBits[0x10]; // 30F4: Numbers of bits for skip copied block length + unsigned char ExLenBits[0x10]; // 3104: Number of valid bits for copied block + unsigned short LenBase[0x10]; // 3114: Buffer for +} TDcmpStruct; + +#define EXP_BUFFER_SIZE sizeof(TDcmpStruct) // Size of decompression structure + // Defined as 12596 in pkware headers + +//----------------------------------------------------------------------------- +// Public functions + +#ifdef __cplusplus + extern "C" { +#endif + +unsigned int PKEXPORT implode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param, + unsigned int *type, + unsigned int *dsize); + + +unsigned int PKEXPORT explode( + unsigned int (*read_buf)(char *buf, unsigned int *size, void *param), + void (*write_buf)(char *buf, unsigned int *size, void *param), + char *work_buf, + void *param); + +// The original name "crc32" was changed to "crc32pk" due +// to compatibility with zlib +unsigned long PKEXPORT crc32_pklib(char *buffer, unsigned int *size, unsigned long *old_crc); + +#ifdef __cplusplus + } // End of 'extern "C"' declaration +#endif + +#endif // __PKLIB_H__ diff --git a/dep/StormLib/src/rsa/rsa_verify_simple.c b/dep/StormLib/src/rsa/rsa_verify_simple.c new file mode 100644 index 000000000..74dd792ee --- /dev/null +++ b/dep/StormLib/src/rsa/rsa_verify_simple.c @@ -0,0 +1,87 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ +#include "rsa_verify_simple.h" + +/** + @file rsa_verify_simple.c + Created by Ladislav Zezula (zezula@volny.cz) as modification + for Blizzard strong signature verification +*/ + +#ifdef LTC_MRSA + +/** + Simple RSA decryption + @param sig The signature data + @param siglen The length of the signature data (octets) + @param hash The hash of the message that was signed + @param hashlen The length of the hash of the message that was signed (octets) + @param stat [out] The result of the signature comparison, 1==valid, 0==invalid + @param key The public RSA key corresponding + @return Error code +*/ +int rsa_verify_simple(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, + rsa_key *key) +{ + unsigned long modulus_bitlen, modulus_bytelen, x; + unsigned char *tmpbuf; + int err; + + LTC_ARGCHK(sig != NULL); + LTC_ARGCHK(hash != NULL); + LTC_ARGCHK(stat != NULL); + LTC_ARGCHK(key != NULL); + + /* default to invalid */ + *stat = 0; + + /* get modulus len in bits */ + modulus_bitlen = mp_count_bits( (key->N)); + + /* outlen must be at least the size of the modulus */ + modulus_bytelen = mp_unsigned_bin_size( (key->N)); + if (modulus_bytelen != siglen) { + return CRYPT_INVALID_PACKET; + } + + /* allocate temp buffer for decoded sig */ + tmpbuf = XMALLOC(siglen); + if (tmpbuf == NULL) { + return CRYPT_MEM; + } + + /* RSA decode it */ + x = siglen; + if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) { + XFREE(tmpbuf); + return err; + } + + /* make sure the output is the right size */ + if (x != siglen) { + XFREE(tmpbuf); + return CRYPT_INVALID_PACKET; + } + + /* compare the decrypted signature with the given hash */ + if(x == hashlen && XMEMCMP(tmpbuf, hash, hashlen) == 0) + *stat = 1; + +#ifdef LTC_CLEAN_STACK + zeromem(tmpbuf, siglen); +#endif + XFREE(tmpbuf); + return CRYPT_OK; +} + +#endif /* LTC_MRSA */ diff --git a/dep/StormLib/src/rsa/rsa_verify_simple.h b/dep/StormLib/src/rsa/rsa_verify_simple.h new file mode 100644 index 000000000..a87b98026 --- /dev/null +++ b/dep/StormLib/src/rsa/rsa_verify_simple.h @@ -0,0 +1,40 @@ +/* LibTomCrypt, modular cryptographic library -- Tom St Denis + * + * LibTomCrypt is a library that provides various cryptographic + * algorithms in a highly modular and flexible manner. + * + * The library is free for all purposes without any express + * guarantee it works. + * + * Tom St Denis, tomstdenis@gmail.com, http://libtom.org + */ +#ifndef __RSA_VERIFY_SIMPLE_H +#define __RSA_VERIFY_SIMPLE_H + +#include "tomcrypt.h" + +/** + @file rsa_verify_simple.c + Created by Ladislav Zezula (zezula@volny.cz) as modification + for Blizzard strong signature verification +*/ + +#ifdef LTC_MRSA + +/** + Simple RSA decryption + @param sig The signature data + @param siglen The length of the signature data (octets) + @param hash The hash of the message that was signed + @param hashlen The length of the hash of the message that was signed (octets) + @param stat [out] The result of the signature comparison, 1==valid, 0==invalid + @param key The public RSA key corresponding + @return Error code +*/ +int rsa_verify_simple(const unsigned char *sig, unsigned long siglen, + const unsigned char *hash, unsigned long hashlen, + int *stat, + rsa_key *key); +#endif /* LTC_MRSA */ + +#endif \ No newline at end of file diff --git a/dep/StormLib/src/sparse/sparse.cpp b/dep/StormLib/src/sparse/sparse.cpp new file mode 100644 index 000000000..4fe09810e --- /dev/null +++ b/dep/StormLib/src/sparse/sparse.cpp @@ -0,0 +1,282 @@ +/*****************************************************************************/ +/* huffman.cpp Copyright (c) Ladislav Zezula 1998-2003 */ +/*---------------------------------------------------------------------------*/ +/* This module contains Huffmann (de)compression methods */ +/* */ +/* Authors : Ladislav Zezula (ladik.zezula.net) */ +/* ShadowFlare (BlakFlare@hotmail.com) */ +/* */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* xx.xx.xx 1.00 Lad The first version of dcmp.cpp */ +/* 03.05.03 1.00 Lad Added compression methods */ +/* 19.11.03 1.01 Dan Big endian handling */ +/* 08.12.03 2.01 Dan High-memory handling (> 0x80000000) */ +/*****************************************************************************/ + +#include +#include + +#include "sparse.h" + +//----------------------------------------------------------------------------- +// Public functions + +void CompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + unsigned char * pbOutBufferEnd = (unsigned char *)pvOutBuffer + *pcbOutBuffer; + unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer; + unsigned char * pbLastNonZero = (unsigned char *)pvInBuffer; + unsigned char * pbOutBuffer0 = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffPtr = (unsigned char *)pvInBuffer; + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + size_t NumberOfNonZeros; + size_t NumberOfZeros; + + // There must be at least 4 bytes of free space in the output buffer now + if((pbInBuffer + 4) >= pbInBufferEnd) + return; + + // Put the original data length (in little endian) + *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x18); + *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x10); + *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x08); + *pbOutBuffer++ = (unsigned char)(cbInBuffer >> 0x00); + + // If there is at least 3 bytes in the input buffer, do this loop + while(pbInBuffer < (pbInBufferEnd - 3)) + { + // Reset the zero count and frontal pointer + pbLastNonZero = pbInBuffer; + pbInBuffPtr = pbInBuffer; + NumberOfZeros = 0; + + if(pbInBuffPtr < pbInBufferEnd) + { + do + { + // Count number of zeros + if(*pbInBuffPtr == 0) + { + NumberOfZeros++; + } + else + { + // Were there at least 3 zeros before? If yes, we need to flush the data + if(NumberOfZeros >= 3) + break; + pbLastNonZero = pbInBuffPtr + 1; + NumberOfZeros = 0; + } + } + while(++pbInBuffPtr < pbInBufferEnd); + } + + // Get number of nonzeros that we found so far and flush them + NumberOfNonZeros = pbLastNonZero - pbInBuffer; + if(NumberOfNonZeros != 0) + { + // Process blocks that are longer than 0x81 nonzero bytes + while(NumberOfNonZeros > 0x81) + { + // Verify if we still have enough space in output buffer + if((pbOutBuffer + 0x81) >= pbOutBufferEnd) + return; + + // Put marker that means "0x80 of nonzeros" + *pbOutBuffer++ = 0xFF; + memcpy(pbOutBuffer, pbInBuffer, 0x80); + + // Adjust counter of nonzeros and both pointers + NumberOfNonZeros -= 0x80; + pbOutBuffer += 0x80; + pbInBuffer += 0x80; + } + + // BUGBUG: The following code will be triggered if the NumberOfNonZeros + // was 0x81 before. It will copy just one byte. This seems like a bug to me, + // but since I want StormLib to be exact like Blizzard code is, I will keep + // it that way here + if(NumberOfNonZeros > 0x80) + { + // Verify if we still have enough space in output buffer + if((pbOutBuffer + 2) >= pbOutBufferEnd) + return; + + // Put marker that means "1 nonzero byte" + *pbOutBuffer++ = 0x80; + memcpy(pbOutBuffer, pbInBuffer, 1); + + // Adjust counter of nonzeros and both pointers + NumberOfNonZeros--; + pbOutBuffer++; + pbInBuffer++; + } + + // If there is 1 nonzero or more, put the block + if(NumberOfNonZeros >= 0x01) + { + // Verify if we still have enough space in output buffer + if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd) + return; + + // Put marker that means "Several nonzero bytes" + *pbOutBuffer++ = (unsigned char)(0x80 | (NumberOfNonZeros - 1)); + memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros); + + // Adjust pointers + pbOutBuffer += NumberOfNonZeros; + pbInBuffer += NumberOfNonZeros; + } + } + + // Now flush all zero bytes + while(NumberOfZeros > 0x85) + { + // Do we have at least 2 bytes in the output buffer ? + if((pbOutBuffer + 1) >= pbOutBufferEnd) + return; + + // Put marker that means "0x82 zeros" + *pbOutBuffer++ = 0x7F; + + // Adjust zero counter and input pointer + NumberOfZeros -= 0x82; + pbInBuffer += 0x82; + } + + // If we got more than 0x82 zeros, flush 3 of them now + if(NumberOfZeros > 0x82) + { + // Do we have at least 2 bytes in the output buffer ? + if((pbOutBuffer + 1) >= pbOutBufferEnd) + return; + + // Put marker that means "0x03 zeros" + *pbOutBuffer++ = 0; + + // Adjust zero counter and input pointer + NumberOfZeros -= 0x03; + pbInBuffer += 0x03; + } + + // Is there at least three zeros ? + if(NumberOfZeros >= 3) + { + // Do we have at least 2 bytes in the output buffer ? + if((pbOutBuffer + 1) >= pbOutBufferEnd) + return; + + // Put marker that means "Several zeros" + *pbOutBuffer++ = (unsigned char)(NumberOfZeros - 3); + + // Adjust pointer + pbInBuffer += NumberOfZeros; + } + } + + // Flush last three bytes + if(pbInBuffer < pbInBufferEnd) + { + pbInBuffPtr = pbInBuffer; + + for(;;) + { + if(*pbInBuffPtr++ != 0) + { + // Get number of bytes remaining + NumberOfNonZeros = (pbInBufferEnd - pbInBuffer); + + // Not enough space in the output buffer ==> exit + if((pbOutBuffer + NumberOfNonZeros + 1) >= pbOutBufferEnd) + return; + + // Terminate with a marker that means "0x80 of nonzeros" + *pbOutBuffer++ = 0xFF; + memcpy(pbOutBuffer, pbInBuffer, NumberOfNonZeros); + + // Adjust pointer + pbOutBuffer += NumberOfNonZeros; + break; + } + else + { + // Is there are more chars in the input buffer + if(pbInBuffPtr < pbInBufferEnd) + continue; + + // If the compression will not compress it by even 1 byte, do nothing + if((pbOutBuffer + 1) >= pbOutBufferEnd) + return; + + // Terminate with a chunk that means "0x82 of zeros" + *pbOutBuffer++ = 0x7F; + break; + } + } + } + + // Out the length of the output buffer + *pcbOutBuffer = (int)(pbOutBuffer - pbOutBuffer0); +} + +int DecompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer) +{ + unsigned char * pbInBufferEnd = (unsigned char *)pvInBuffer + cbInBuffer; + unsigned char * pbOutBuffer = (unsigned char *)pvOutBuffer; + unsigned char * pbInBuffer = (unsigned char *)pvInBuffer; + unsigned int cbChunkSize; + unsigned int cbOutBuffer = 0; + unsigned int OneByte; + + // Don't decompress anything that is shorter than 5 bytes + if(cbInBuffer < 5) + return 0; + + // Get the 32-bits from the input stream + OneByte = *pbInBuffer++; + cbOutBuffer |= (OneByte << 0x18); + OneByte = *pbInBuffer++; + cbOutBuffer |= (OneByte << 0x10); + OneByte = *pbInBuffer++; + cbOutBuffer |= (OneByte << 0x08); + OneByte = *pbInBuffer++; + cbOutBuffer |= (OneByte << 0x00); + + // Verify the size of the stream against the output buffer size + if(cbOutBuffer > (unsigned int)*pcbOutBuffer) + return 0; + + // Put the output size to the buffer + *pcbOutBuffer = cbOutBuffer; + + // Process the input buffer + while(pbInBuffer < pbInBufferEnd) + { + // Get (next) byte from the stream + OneByte = *pbInBuffer++; + + // If highest bit, it means that that normal data follow + if(OneByte & 0x80) + { + cbChunkSize = (OneByte & 0x7F) + 1; + cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer; + memcpy(pbOutBuffer, pbInBuffer, cbChunkSize); + pbInBuffer += cbChunkSize; + } + else + { + cbChunkSize = (OneByte & 0x7F) + 3; + cbChunkSize = (cbChunkSize < cbOutBuffer) ? cbChunkSize : cbOutBuffer; + memset(pbOutBuffer, 0, cbChunkSize); + } + + // Increment output buffer pointer + pbOutBuffer += cbChunkSize; + cbOutBuffer -= cbChunkSize; + } + + return 1; +} diff --git a/dep/StormLib/src/sparse/sparse.h b/dep/StormLib/src/sparse/sparse.h new file mode 100644 index 000000000..12f62b526 --- /dev/null +++ b/dep/StormLib/src/sparse/sparse.h @@ -0,0 +1,17 @@ +/*****************************************************************************/ +/* sparse.h Copyright (c) Ladislav Zezula 2010 */ +/*---------------------------------------------------------------------------*/ +/* implementation of Sparse compression, used in Starcraft II */ +/*---------------------------------------------------------------------------*/ +/* Date Ver Who Comment */ +/* -------- ---- --- ------- */ +/* 05.03.10 1.00 Lad The first version of sparse.h */ +/*****************************************************************************/ + +#ifndef __SPARSE_H__ +#define __SPARSE_H__ + +void CompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); +int DecompressSparse(void * pvOutBuffer, int * pcbOutBuffer, void * pvInBuffer, int cbInBuffer); + +#endif // __SPARSE_H__ diff --git a/dep/acelite/AUTHORS b/dep/acelite/AUTHORS new file mode 100644 index 000000000..3e474e06c --- /dev/null +++ b/dep/acelite/AUTHORS @@ -0,0 +1,13 @@ +Douglas C. Schmidt +d.schmidt@vanderbilt.edu + +Professor of Computer Science +Associate Chair of Computer Science and Engineering +Department of Electrical Engineering and Computer Science +Senior Researcher at the Institute for Software Integrated Systems (ISIS) +Vanderbilt University +Nashville, TN 37203 + +www.dre.vanderbilt.edu/~schmidt +TEL: (615) 343-8197 +FAX: (615) 343-7440 diff --git a/dep/acelite/CMakeLists.txt b/dep/acelite/CMakeLists.txt new file mode 100644 index 000000000..7cc577c21 --- /dev/null +++ b/dep/acelite/CMakeLists.txt @@ -0,0 +1,355 @@ +# +# This code is part of MaNGOS. Contributor & Copyright details are in AUTHORS/THANKS. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# + +project(ACE VERSION 6.5.5) + +set(ACE_SOURCES + ace/ACE.cpp + ace/ACE_crc32.cpp + ace/ACE_crc_ccitt.cpp + ace/ATM_Acceptor.cpp + ace/ATM_Addr.cpp + ace/ATM_Connector.cpp + ace/ATM_Params.cpp + ace/ATM_QoS.cpp + ace/ATM_Stream.cpp + ace/Activation_Queue.cpp + ace/Active_Map_Manager.cpp + ace/Addr.cpp + ace/Argv_Type_Converter.cpp + ace/Assert.cpp + ace/Asynch_IO.cpp + ace/Asynch_IO_Impl.cpp + ace/Asynch_Pseudo_Task.cpp + ace/Atomic_Op.cpp + ace/Barrier.cpp + ace/Base_Thread_Adapter.cpp + ace/Based_Pointer_Repository.cpp + ace/Basic_Stats.cpp + ace/Basic_Types.cpp + ace/CDR_Base.cpp + ace/CDR_Size.cpp + ace/CDR_Stream.cpp + ace/Capabilities.cpp + ace/Cleanup.cpp + ace/Codecs.cpp + ace/Codeset_IBM1047.cpp + ace/Codeset_Registry.cpp + ace/Codeset_Registry_db.cpp + ace/Condition_Attributes.cpp + ace/Condition_Recursive_Thread_Mutex.cpp + ace/Condition_Thread_Mutex.cpp + ace/Configuration.cpp + ace/Configuration_Import_Export.cpp + ace/Connection_Recycling_Strategy.cpp + ace/Containers.cpp + ace/Copy_Disabled.cpp + ace/DEV.cpp + ace/DEV_Addr.cpp + ace/DEV_Connector.cpp + ace/DEV_IO.cpp + ace/DLL.cpp + ace/DLL_Manager.cpp + ace/Date_Time.cpp + ace/Dev_Poll_Reactor.cpp + ace/Dirent.cpp + ace/Dirent_Selector.cpp + ace/Dump.cpp + ace/Dynamic.cpp + ace/Dynamic_Message_Strategy.cpp + ace/Dynamic_Service_Base.cpp + ace/Dynamic_Service_Dependency.cpp + ace/Encoding_Converter.cpp + ace/Encoding_Converter_Factory.cpp + ace/Event_Base.cpp + ace/Event_Handler.cpp + ace/Event_Handler_Handle_Timeout_Upcall.cpp + ace/FIFO.cpp + ace/FIFO_Recv.cpp + ace/FIFO_Recv_Msg.cpp + ace/FIFO_Send.cpp + ace/FIFO_Send_Msg.cpp + ace/FILE.cpp + ace/FILE_Addr.cpp + ace/FILE_Connector.cpp + ace/FILE_IO.cpp + ace/File_Lock.cpp + ace/Filecache.cpp + ace/Flag_Manip.cpp + ace/Framework_Component.cpp + ace/Functor.cpp + ace/Functor_String.cpp + ace/Get_Opt.cpp + ace/Handle_Ops.cpp + ace/Handle_Set.cpp + ace/Hashable.cpp + ace/High_Res_Timer.cpp + ace/ICMP_Socket.cpp + ace/INET_Addr.cpp + ace/IOStream.cpp + ace/IO_Cntl_Msg.cpp + ace/IO_SAP.cpp + ace/IPC_SAP.cpp + ace/Init_ACE.cpp + ace/LSOCK.cpp + ace/LSOCK_Acceptor.cpp + ace/LSOCK_CODgram.cpp + ace/LSOCK_Connector.cpp + ace/LSOCK_Dgram.cpp + ace/LSOCK_Stream.cpp + ace/Lib_Find.cpp + ace/Local_Memory_Pool.cpp + ace/Local_Name_Space.cpp + ace/Local_Tokens.cpp + ace/Lock.cpp + ace/Log_Category.cpp + ace/Log_Msg.cpp + ace/Log_Msg_Android_Logcat.cpp + ace/Log_Msg_Backend.cpp + ace/Log_Msg_Callback.cpp + ace/Log_Msg_IPC.cpp + ace/Log_Msg_NT_Event_Log.cpp + ace/Log_Msg_UNIX_Syslog.cpp + ace/Log_Record.cpp + ace/Logging_Strategy.cpp + ace/MEM_Acceptor.cpp + ace/MEM_Addr.cpp + ace/MEM_Connector.cpp + ace/MEM_IO.cpp + ace/MEM_SAP.cpp + ace/MEM_Stream.cpp + ace/MMAP_Memory_Pool.cpp + ace/Malloc.cpp + ace/Malloc_Allocator.cpp + ace/Mem_Map.cpp + ace/Message_Block.cpp + ace/Message_Queue.cpp + ace/Message_Queue_NT.cpp + ace/Message_Queue_Vx.cpp + ace/Method_Request.cpp + ace/Monitor_Admin.cpp + ace/Monitor_Admin_Manager.cpp + ace/Monitor_Base.cpp + ace/Monitor_Control_Action.cpp + ace/Monitor_Control_Types.cpp + ace/Monitor_Point_Registry.cpp + ace/Monitor_Size.cpp + ace/Monotonic_Time_Policy.cpp + ace/Msg_WFMO_Reactor.cpp + ace/Multihomed_INET_Addr.cpp + ace/Mutex.cpp + ace/NT_Service.cpp + ace/Name_Proxy.cpp + ace/Name_Request_Reply.cpp + ace/Name_Space.cpp + ace/Naming_Context.cpp + ace/Netlink_Addr.cpp + ace/Notification_Queue.cpp + ace/Notification_Strategy.cpp + ace/Null_Mutex.cpp + ace/OS_Errno.cpp + ace/OS_Log_Msg_Attributes.cpp + ace/OS_NS_Thread.cpp + ace/OS_NS_arpa_inet.cpp + ace/OS_NS_ctype.cpp + ace/OS_NS_devctl.cpp + ace/OS_NS_dirent.cpp + ace/OS_NS_dlfcn.cpp + ace/OS_NS_errno.cpp + ace/OS_NS_fcntl.cpp + ace/OS_NS_math.cpp + ace/OS_NS_netdb.cpp + ace/OS_NS_poll.cpp + ace/OS_NS_pwd.cpp + ace/OS_NS_regex.cpp + ace/OS_NS_signal.cpp + ace/OS_NS_stdio.cpp + ace/OS_NS_stdlib.cpp + ace/OS_NS_string.cpp + ace/OS_NS_strings.cpp + ace/OS_NS_stropts.cpp + ace/OS_NS_sys_mman.cpp + ace/OS_NS_sys_msg.cpp + ace/OS_NS_sys_resource.cpp + ace/OS_NS_sys_select.cpp + ace/OS_NS_sys_sendfile.cpp + ace/OS_NS_sys_shm.cpp + ace/OS_NS_sys_socket.cpp + ace/OS_NS_sys_stat.cpp + ace/OS_NS_sys_time.cpp + ace/OS_NS_sys_uio.cpp + ace/OS_NS_sys_utsname.cpp + ace/OS_NS_sys_wait.cpp + ace/OS_NS_time.cpp + ace/OS_NS_unistd.cpp + ace/OS_NS_wchar.cpp + ace/OS_NS_wctype.cpp + ace/OS_QoS.cpp + ace/OS_TLI.cpp + ace/OS_Thread_Adapter.cpp + ace/OS_main.cpp + ace/Obchunk.cpp + ace/Object_Manager.cpp + ace/Object_Manager_Base.cpp + ace/Obstack.cpp + ace/PI_Malloc.cpp + ace/POSIX_Asynch_IO.cpp + ace/POSIX_CB_Proactor.cpp + ace/POSIX_Proactor.cpp + ace/Pagefile_Memory_Pool.cpp + ace/Parse_Node.cpp + ace/Ping_Socket.cpp + ace/Pipe.cpp + ace/Priority_Reactor.cpp + ace/Proactor.cpp + ace/Proactor_Impl.cpp + ace/Process.cpp + ace/Process_Manager.cpp + ace/Process_Mutex.cpp + ace/Process_Semaphore.cpp + ace/Profile_Timer.cpp + ace/RW_Mutex.cpp + ace/RW_Process_Mutex.cpp + ace/RW_Thread_Mutex.cpp + ace/Reactor.cpp + ace/Reactor_Impl.cpp + ace/Reactor_Notification_Strategy.cpp + ace/Reactor_Timer_Interface.cpp + ace/Read_Buffer.cpp + ace/Recursive_Thread_Mutex.cpp + ace/Recyclable.cpp + ace/Registry.cpp + ace/Registry_Name_Space.cpp + ace/Remote_Name_Space.cpp + ace/Remote_Tokens.cpp + ace/SOCK.cpp + ace/SOCK_Acceptor.cpp + ace/SOCK_CODgram.cpp + ace/SOCK_Connector.cpp + ace/SOCK_Dgram.cpp + ace/SOCK_Dgram_Bcast.cpp + ace/SOCK_Dgram_Mcast.cpp + ace/SOCK_IO.cpp + ace/SOCK_Netlink.cpp + ace/SOCK_SEQPACK_Acceptor.cpp + ace/SOCK_SEQPACK_Association.cpp + ace/SOCK_SEQPACK_Connector.cpp + ace/SOCK_Stream.cpp + ace/SPIPE.cpp + ace/SPIPE_Acceptor.cpp + ace/SPIPE_Addr.cpp + ace/SPIPE_Connector.cpp + ace/SPIPE_Stream.cpp + ace/SString.cpp + ace/SUN_Proactor.cpp + ace/SV_Message.cpp + ace/SV_Message_Queue.cpp + ace/SV_Semaphore_Complex.cpp + ace/SV_Semaphore_Simple.cpp + ace/SV_Shared_Memory.cpp + ace/Sample_History.cpp + ace/Sbrk_Memory_Pool.cpp + ace/Sched_Params.cpp + ace/Select_Reactor_Base.cpp + ace/Semaphore.cpp + ace/Service_Config.cpp + ace/Service_Gestalt.cpp + ace/Service_Manager.cpp + ace/Service_Object.cpp + ace/Service_Repository.cpp + ace/Service_Types.cpp + ace/Shared_Memory.cpp + ace/Shared_Memory_MM.cpp + ace/Shared_Memory_Pool.cpp + ace/Shared_Memory_SV.cpp + ace/Shared_Object.cpp + ace/Sig_Adapter.cpp + ace/Sig_Handler.cpp + ace/Signal.cpp + ace/Sock_Connect.cpp + ace/Stack_Trace.cpp + ace/Stats.cpp + ace/String_Base_Const.cpp + ace/Svc_Conf_Lexer.cpp + ace/Svc_Conf_y.cpp + ace/Synch_Options.cpp + ace/System_Time.cpp + ace/TLI.cpp + ace/TLI_Acceptor.cpp + ace/TLI_Connector.cpp + ace/TLI_Stream.cpp + ace/TP_Reactor.cpp + ace/TSS_Adapter.cpp + ace/TTY_IO.cpp + ace/Task.cpp + ace/Thread.cpp + ace/Thread_Adapter.cpp + ace/Thread_Control.cpp + ace/Thread_Exit.cpp + ace/Thread_Hook.cpp + ace/Thread_Manager.cpp + ace/Thread_Mutex.cpp + ace/Thread_Semaphore.cpp + ace/Throughput_Stats.cpp + ace/Time_Policy.cpp + ace/Time_Value.cpp + ace/Timeprobe.cpp + ace/Token.cpp + ace/Token_Collection.cpp + ace/Token_Invariants.cpp + ace/Token_Manager.cpp + ace/Token_Request_Reply.cpp + ace/Trace.cpp + ace/UNIX_Addr.cpp + ace/UPIPE_Acceptor.cpp + ace/UPIPE_Connector.cpp + ace/UPIPE_Stream.cpp + ace/UTF16_Encoding_Converter.cpp + ace/UTF32_Encoding_Converter.cpp + ace/UTF8_Encoding_Converter.cpp + ace/UUID.cpp + ace/WFMO_Reactor.cpp + ace/WIN32_Asynch_IO.cpp + ace/WIN32_Proactor.cpp + ace/XML_Svc_Conf.cpp + ace/XTI_ATM_Mcast.cpp + ace/ace_wchar.cpp + $<$: + pch.cpp + pch.h + > +) + +add_library(ace STATIC + ${ACE_SOURCES} +) + +target_include_directories(ace + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_compile_definitions(ace + PUBLIC + ACE_AS_STATIC_LIBS + $<$:_WANT_SEMUN> +) + +if(PCH) + add_cxx_pch(ace ${CMAKE_CURRENT_SOURCE_DIR}/pch.h ${CMAKE_CURRENT_SOURCE_DIR}/pch.cpp) +endif() \ No newline at end of file diff --git a/dep/acelite/COPYING b/dep/acelite/COPYING new file mode 100644 index 000000000..a8a5eda0c --- /dev/null +++ b/dep/acelite/COPYING @@ -0,0 +1,111 @@ + + _________________________________________________________________ + + Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), + DAnCE(TM), and CoSMIC(TM) + + [1]ACE(TM), [2]TAO(TM), [3]CIAO(TM), DAnCE(TM), and [4]CoSMIC(TM) + (henceforth referred to as "DOC software") are copyrighted by + [5]Douglas C. Schmidt and his [6]research group at [7]Washington + University, [8]University of California, Irvine, and [9]Vanderbilt + University, Copyright (c) 1993-2014, all rights reserved. Since DOC + software is open-source, freely available software, you are free to + use, modify, copy, and distribute--perpetually and irrevocably--the + DOC software source code and object code produced from the source, as + well as copy and distribute modified versions of this software. You + must, however, include this copyright statement along with any code + built using DOC software that you release. No copyright statement + needs to be provided if you just ship binary executables of your + software products. + + You can use DOC software in commercial and/or binary software releases + and are under no obligation to redistribute any of your source code + that is built using DOC software. Note, however, that you may not + misappropriate the DOC software code, such as copyrighting it yourself + or claiming authorship of the DOC software code, in a way that will + prevent DOC software from being distributed freely using an + open-source development model. You needn't inform anyone that you're + using DOC software in your software, though we encourage you to let + [10]us know so we can promote your project in the [11]DOC software + success stories. + + The [12]ACE, [13]TAO, [14]CIAO, [15]DAnCE, and [16]CoSMIC web sites + are maintained by the [17]DOC Group at the [18]Institute for Software + Integrated Systems (ISIS) and the [19]Center for Distributed Object + Computing of Washington University, St. Louis for the development of + open-source software as part of the open-source software community. + Submissions are provided by the submitter ``as is'' with no warranties + whatsoever, including any warranty of merchantability, noninfringement + of third party intellectual property, or fitness for any particular + purpose. In no event shall the submitter be liable for any direct, + indirect, special, exemplary, punitive, or consequential damages, + including without limitation, lost profits, even if advised of the + possibility of such damages. Likewise, DOC software is provided as is + with no warranties of any kind, including the warranties of design, + merchantability, and fitness for a particular purpose, + noninfringement, or arising from a course of dealing, usage or trade + practice. Washington University, UC Irvine, Vanderbilt University, + their employees, and students shall have no liability with respect to + the infringement of copyrights, trade secrets or any patents by DOC + software or any part thereof. Moreover, in no event will Washington + University, UC Irvine, or Vanderbilt University, their employees, or + students be liable for any lost revenue or profits or other special, + indirect and consequential damages. + + DOC software is provided with no support and without any obligation on + the part of Washington University, UC Irvine, Vanderbilt University, + their employees, or students to assist in its use, correction, + modification, or enhancement. A [20]number of companies around the + world provide commercial support for DOC software, however. DOC + software is Y2K-compliant, as long as the underlying OS platform is + Y2K-compliant. Likewise, DOC software is compliant with the new US + daylight savings rule passed by Congress as "The Energy Policy Act of + 2005," which established new daylight savings times (DST) rules for + the United States that expand DST as of March 2007. Since DOC software + obtains time/date and calendaring information from operating systems + users will not be affected by the new DST rules as long as they + upgrade their operating systems accordingly. + + The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), + Washington University, UC Irvine, and Vanderbilt University, may not + be used to endorse or promote products or services derived from this + source without express written permission from Washington University, + UC Irvine, or Vanderbilt University. This license grants no permission + to call products or services derived from this source ACE(TM), + TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM), nor does it grant + permission for the name Washington University, UC Irvine, or + Vanderbilt University to appear in their names. + + If you have any suggestions, additions, comments, or questions, please + let [21]me know. + + [22]Douglas C. Schmidt + _________________________________________________________________ + + Back to the [23]ACE home page. + +References + + 1. http://www.cs.wustl.edu/~schmidt/ACE.html + 2. http://www.cs.wustl.edu/~schmidt/TAO.html + 3. http://www.dre.vanderbilt.edu/CIAO/ + 4. http://www.dre.vanderbilt.edu/cosmic/ + 5. http://www.dre.vanderbilt.edu/~schmidt/ + 6. http://www.cs.wustl.edu/~schmidt/ACE-members.html + 7. http://www.wustl.edu/ + 8. http://www.uci.edu/ + 9. http://www.vanderbilt.edu/ + 10. mailto:doc_group@cs.wustl.edu + 11. http://www.cs.wustl.edu/~schmidt/ACE-users.html + 12. http://www.cs.wustl.edu/~schmidt/ACE.html + 13. http://www.cs.wustl.edu/~schmidt/TAO.html + 14. http://www.dre.vanderbilt.edu/CIAO/ + 15. http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/DAnCE/ + 16. http://www.dre.vanderbilt.edu/cosmic/ + 17. http://www.dre.vanderbilt.edu/ + 18. http://www.isis.vanderbilt.edu/ + 19. http://www.cs.wustl.edu/~schmidt/doc-center.html + 20. http://www.cs.wustl.edu/~schmidt/commercial-support.html + 21. mailto:d.schmidt@vanderbilt.edu + 22. http://www.dre.vanderbilt.edu/~schmidt/ + 23. http://www.cs.wustl.edu/ACE.html diff --git a/dep/acelite/ChangeLog b/dep/acelite/ChangeLog new file mode 100644 index 000000000..28f4fc60d --- /dev/null +++ b/dep/acelite/ChangeLog @@ -0,0 +1,256 @@ +Fri Nov 14 08:38:16 CET 2014 Johnny Willemsen + + * ACE version 6.3.0 released. + +Thu Nov 13 11:31:37 UTC 2014 Steve Huston + + * ace/config-lite.h: Adjust ACE_DECLARE_STL_REVERSE_ITERATORS to + work with Solaris Studio 12.4. + + * NEWS: Note support for Solaris Studio 12.4. + +Mon Nov 10 15:45:42 UTC 2014 Johnny Willemsen + + * ace/CDR_Stream.h: + Doxygen fixes + +Mon Nov 10 12:39:18 UTC 2014 Martin Corino + + * NEWS: + Updated. + +Thu Nov 6 19:45:38 UTC 2014 Johnny Willemsen + + * bin/MakeProjectCreator/config/vc_warnings.mpb: + Visual Studio 2013 Update 3 gives a lot of warnings on deprecated + ascii winsock calls but they just work, so no need to change our + code. Added new feature vc_avoid_winsock_warnings which is enabled + by default, this adds _WINSOCK_DEPRECATED_NO_WARNINGS to the + compiler falgs. If you want to see all warnings, set + vc_avoid_winsock_warnings to 0 in your default.features file before + generatin the project files + +Tue Nov 4 14:37:56 UTC 2014 Johnny Willemsen + + * etc/ace_inet.doxygen: + * etc/ace_qos.doxygen: + * etc/ace_rmcast.doxygen: + * etc/ace_ssl.doxygen: + * etc/acexml.doxygen: + Set UML_LOOK to NO, with UML look all members/methods are shown + in the diagrams making them unusable + +Mon Nov 3 12:50:28 UTC 2014 Martin Corino + + * ace/WIN32_Asynch_IO.cpp: + Do not pass holder for bytes written when using OVERLAPPED IO. + Pass NULL instead. Recommended by MSDN. + + * tests/Proactor_File_Test.cpp: + Circumvent problems with unreliable Async IO on older Win32 + (WinXP, Win2003/2008). + +Fri Oct 31 14:10:52 UTC 2014 Johnny Willemsen + + * rpmbuild/ace-tao.spec: + No need for lsb + +Fri Oct 31 13:49:11 UTC 2014 Martin Corino + + * ace/WIN32_Asynch_IO.h: + * ace/WIN32_Asynch_IO.cpp: + Changed ACE_WIN32_Asynch_Write classes to not use shared_write() method + for Stream and File IO but use specific write() implementations instead. + This fixes Asynch File IO support (specifically writing) for Windows. + Fixes Bugzilla #3762 and #3992. + + * tests/Proactor_File_Test.cpp: + * tests/run_test.lst: + * tests/tests.mpc: + Added new example/regression test for Asynch File IO using Proactor. + +Wed Oct 29 20:22:38 UTC 2014 Steve Huston + + * bin/MakeProjectCreator/templates/gnu.mpd: Change LDFLAGS for HP-UX to do install_rpath correctly. + Fixes Bugzilla #4170. + +Tue Oct 28 09:51:14 UTC 2014 Martin Corino + + * bin/MakeProjectCreator/docs/templates/gnu.txt: + * bin/MakeProjectCreator/templates/gnu.mpd: + * include/makeinclude/wrapper_macros.GNU: + Added (optional) support for per project output directories for + object files. Fixes Bugzilla #3868. + +Tue Oct 28 08:00:15 UTC 2014 Johnny Willemsen + + * tests/Bug_4189_Regression_Test.cpp: + Use PF_INET, that is the default argument of ACE_SOCK_Dgram_Bcast + +Mon Oct 27 18:06:17 UTC 2014 Johnny Willemsen + + * ace/config-win32-common.h: + Don't define SO_REUSEPORT when it is not defined, the code + that uses this as argument to call ACE_OS::setsockopt only works + when this has been defined. Defining it here to a dummy value + causes us to call the Windows API with an invalid argument + +Mon Oct 27 12:32:17 UTC 2014 Johnny Willemsen + + * ace/config-win32-common.h: + * ace/os_include/sys/os_types.h: + Introduce new ACE_LACKS_PID_T which is set on Windows, but + not with MinGW + +Mon Oct 27 07:57:57 UTC 2014 Johnny Willemsen + + * ace/OS_NS_sys_socket.inl: + Removed the ignore of SO_REUSEADDR on windows, this is needed + for ACE_SOCK_Dgram_Bcast to work, see bugzilla 4189. Also removed + the Windows specific change of SO_REUSEPORT to SO_REUSEADDR, this + are different flags that we should not merge at this level. + +Fri Oct 24 18:41:42 UTC 2014 Johnny Willemsen + + * tests/Bug_4189_Regression_Test.cpp: + * tests/run_test.lst: + * tests/tests.mpc: + New test for bugzilla 4189, on Windows it is not possible + at this moment to open a ACE_SOCK_Dgram_Bcast multiple times + on the same port, even when reuse_addr has been set to 1 + +Thu Oct 23 19:41:00 UTC 2014 Steve Huston + + * tests/Naming_Test.cpp: Fixed data type warning for conversion on + %d formatting for Mingw. + +Tue Oct 21 15:45:59 UTC 2014 Phil Mesnier + + * ace/ETCL/ETCL_l.cpp: + Scoreboard cleanup. + +Mon Oct 20 15:37:35 UTC 2014 Phil Mesnier + + * ACEXML/common/XMLFilterImpl.h: + * ACEXML/common/XMLFilterImpl.cpp: + * ACEXML/parser/parser/Entity_Manager.h: + * ace/ETCL/ETCL_l.cpp: + * protocols/ace/RMCast/Flow.h: + * protocols/ace/RMCast/Flow.cpp: + * protocols/ace/RMCast/Reassemble.h: + * protocols/ace/RMCast/Reassemble.cpp: + * protocols/ace/TMCast/TransactionController.hpp: + Clean up unused member warnings identified by clang 6.0. + + * bin/PerlACE/Process_Unix.pm: + increase the valgrind wait factor to accommodate slower machines. + +Mon Oct 13 18:59:00 UTC 2014 Steve Huston + + * apps/mkcsregdb/mkcsregdb.cpp: Fix data type error on Windows. + +Mon Oct 13 17:24:21 UTC 2014 Johnny Willemsen + + * docs/bczar/bczar.html: + Added package for killall + +Sat Oct 11 21:09:07 UTC 2014 Steve Huston + + * ace/Process.cpp (ACE_Process_Options::setenv (const ACE_TCHAR *, ...): + Avoid the secret, magic number buried in ACE_OS::vsprintf() for + platforms that support ACE_OS::vsnprintf. Allows full use of + DEFAULT_COMMAND_LINE_BUF_LEN as well as customizing that value + to a higher size. Thanks to John Lilley for this improvement. + +Sat Oct 11 20:45:03 UTC 2014 Steve Huston + + * apps/drwho/File_Manager.cpp: Fixed const-ness compile warning. + +Thu Oct 9 16:21:38 UTC 2014 Steve Huston + + * NEWS: Add description of the below changes. + + * ace/OS_NS_stdlib.{h inl cpp}: + * ace/OS_NS_stdio.{h inl}: + * ace/README: + Added new feature config macros ACE_DISABLE_MKTEMP and + ACE_DISABLE_TEMPNAM. These disable the ACE wrappers for + mktemp() and tempnam(), respectively. Those functions are + considered insecure and better replaced by the use of mkstemp(). + + * ace/FILE_Addr.cpp (set): Call to set(const ACE_FILE_Addr&) using + the default "any" address will now fail if ACE_DISABLE_MKTEMP is + set. + + * ace/FILE_Connector.cpp (connect): Specifying 'any' for the + address now uses ACE_OS::mkstemp(). Contrast this with setting a + ACE_FILE_Addr with 'any', above. + + * ace/MMAP_Memory_Pool.cpp (constructor): Using the 'unique' option + will no longer work if ACE_DISABLE_MKTEMP is set. + + * tests/MM_Shared_Memory_Test.cpp: + Will not work if ACE_DISABLE_MKTEMP is set. + + * tests/Naming_Test.cpp: + Changed to avoid use of ACE_OS::tempnam. + + * tests/Svc_Handler_Test.cpp: Modified to work with or without + ACE_DISABLE_MKTEMP. + + * apps/mkcsregdb/mkcsregdb.cpp: + * apps/drwho/File_Manager.cpp: + Use ACE_OS::mkstemp. + + * examples/OS/Process/imore.cpp: + * examples/Service_Configurator/IPC-tests/client/local_dgram_client.cpp: + Won't work if ACE_DISABLE_TEMPNAM is set. + +Tue Oct 7 21:55:51 UTC 2014 Steve Huston + + Set of changes applicable to VxWorks, particularly 6.9. These changes + were contributed by Jeff Fowler and Gordon Hulpieu at NetApp. Feel + free to contact me with any issues. + + * ace/OS_NS_Thread.{h cpp inl}: Change from using the VxWorks TCB + spare4 value to a new static member of ACE_TSS_Emulation. This + mechanism covers both VxWorks multicore (SMP) using the __thread + attribute and single core using Task Var. This change gets ACE out + of the way of the applications that use spare4 for their own + purposes. + Also fixes for various compiler warnings. + + * ace/OS_NS_sys_socket.inl (accept): Add IPv6 case to the + ACE_HAS_BROKEN_ACCEPT_ADDR case. + + * ace/config-vxworks6.9.h: Correct the ACE_HAS_BROKEN_ACCEPT_ADDR + setting for VxWorks 6.9+. + + * ace/OS_NS_dlfcn.inl (dlsym): For VxWorks, use the symFind() call + instead of the deprecated symFindByName(). + + * ace/Process.cpp: Fix a weird compile diagnostic by adding what should + be a needless space. + + * include/makeinclude/platform_vxworks6.9.GNU: Update MUNCH_FLAGS + for this version. + +Tue Sep 30 13:34:34 UTC 2014 Johnny Willemsen + + * include/makeinclude/platform_g++_common.GNU: + Add -Wnon-virtual-dtor to the default CCFLAGS + +Fri Sep 26 09:58:57 UTC 2014 Olli Savia + + * tests/Message_Block_Large_Copy_Test.cpp: + Fixed compile error on LynxOS. + +Wed Sep 24 19:51:44 CEST 2014 Johnny Willemsen + + * ACE version 6.2.8 released. + +Local Variables: +mode: change-log +add-log-time-format: (lambda () (progn (setq tz (getenv "TZ")) (set-time-zone-rule "UTC") (setq time (format-time-string "%a %b %e %H:%M:%S %Z %Y" (current-time))) (set-time-zone-rule tz) time)) +indent-tabs-mode: nil +End: diff --git a/dep/acelite/NEWS b/dep/acelite/NEWS new file mode 100644 index 000000000..e6d4d3dbb --- /dev/null +++ b/dep/acelite/NEWS @@ -0,0 +1,2048 @@ +USER VISIBLE CHANGES BETWEEN ACE-6.2.8 and ACE-6.3.0 +==================================================== + +. ACE now supports Oracle Solaris Studio 12.4 on Solaris. + +. New config macros were added: + ACE_DISABLE_MKTEMP: Disables the availability of ACE_OS::mktemp(). + ACE_DISABLE_TEMPNAM: Disables the availability of ACE_OS::tempnam(). + These can be added to your $ACE_ROOT/ace/config.h to disable these + wrappers which are considered to be a potential security risk. Disabling + one or both will also disable the following: + - ACE_FILE_Addr::set () with the 'any' address specified. + - ACE_MMAP_Memory_Pool use of the 'unique' option. + +. Reduced size of all doxygen documentation by changing the + type of diagrams shown + +. Removed Windows specific workarounds from ACE_OS::setsockopt, as a + result SO_REUSEPORT is not defined anymore on Windows and SO_REUSEADDR + is passed directly to the OS + +. By adding a 'specific' section to a MPC (base) project it is now possible + to have object file output directories per project for GNUACE projects. + The following should be added to MPC projects (bugzilla #3868): + specific(gnuace) { + build_dir_per_project=1 + } + +. ACE_Asynch_Write_File will now correctly accept non-socket (file, TTY ..) + handles (bugzilla #3762 and #3992) + +. Fixes for VxWorks 6.9 + +USER VISIBLE CHANGES BETWEEN ACE-6.2.7 and ACE-6.2.8 +==================================================== + +. Add new ACE::make_event_handler() which is similar + to std::make_shared but than for allocation of ACE + event handlers. This template method is only enabled + when ACE_HAS_CPP11 has been defined, which is set + automatically when a C++ compiler with adequate + C++11 support is used. Also ACE_Event_Handler_var is + extended with some C++11 specific operations + +. For all reactor types calling cancel_timer with a + nullptr is now allowed, will result in a return of 0 + +. ACE_DLL and ACE_DLL_Manager have been extended with + the support to retrieve any dynamic loader errors + +USER VISIBLE CHANGES BETWEEN ACE-6.2.6 and ACE-6.2.7 +==================================================== + +. Added configuration files for Microsoft Visual Studio 2014 + +. Added configuration files for MacOSX Yosemite + +. Added configuration files for IBM AIX XL C++ 12.1 + +USER VISIBLE CHANGES BETWEEN ACE-6.2.5 and ACE-6.2.6 +==================================================== + +. Resolved several data races reported by Intel Inspector XE + +. Added optional socket connection optimization for Windows + +. Improve functionality and stability of running tests on + Android Virtual Device (AVD). + +USER VISIBLE CHANGES BETWEEN ACE-6.2.4 and ACE-6.2.5 +==================================================== + +. Added the ability to build RPMs for just ACE, using an ACE-src tarball. + To do this add "--without tao" to the rpmbuild command line. + +. Added support for Embarcadero C++Builder XE5 using + bcc32 in debug and release mode + +. Added support for Embarcadero C++Builder XE6 using + bcc32 in debug and release mode + +. When Intel C++ 2013 SP1 Update 2 is used with C++11 enabled + as compiler feature now also ACE_HAS_CPP11 will be defined, + this compiler is now able to compile all our C++11 feature + tests + +. Fixed several boundary bugs in the ACE RLE Compressor + +USER VISIBLE CHANGES BETWEEN ACE-6.2.3 and ACE-6.2.4 +==================================================== + +. Added support for FC20 and ended support for FC19 + +. Extended C++11 feature test suite + +. Improved support for MingW64 + +. Improvements to IPv6 support on Windows + +USER VISIBLE CHANGES BETWEEN ACE-6.2.2 and ACE-6.2.3 +==================================================== + +. The ACE_OS::thr_join() method will detect if the thread to be waited on is + the calling thread and avert that deadlock. The support needed for this + method is available at Vista/Windows Server 2003 and higher; to enable + the deadlock prevention, compile ACE with _WIN32_WINNT=0x0502 or higher. + +. Ended maintenance and support for FC12 CEEL + +. Further improvements of the Android port: Added new define + ACE_HAS_EXPLICIT_TEMPLATE_CLASS_INSTANTIATION and related macros + ACE_SINGLETON_TEMPLATE_INSTANTIATION and ACE_SINGLETON_TEMPLATE_INSTANTIATE + providing a cleaner way to support explicit template (static member or class) + instantiation. + +' Improvements of the test framework for running tests in a mixed environment + where different targets run on different physiscal devices (possibly having + different OS). + +USER VISIBLE CHANGES BETWEEN ACE-6.2.1 and ACE-6.2.2 +==================================================== + +. The max_len argument to ACE_Process::command_line_buf changed from int* + to size_t*. This corrects a mismatch between the argument type and the + data member in ACE_Process from which the value comes. + +. Removed some include files from ACE.h. These were not required for ACE. + The removed includes are OS_NS_math, Flag_Manip, Handle_Ops, Lib_Find, + Init_ACE, Sock_Connect.h. You may have to explicitly add one of these + in your own code to restore compiling. + +. Further improvements of the Android port, still work in progress. + +USER VISIBLE CHANGES BETWEEN ACE-6.2.0 and ACE-6.2.1 +==================================================== + +. Added support for Fedora 19, ended daily maintenance + for Fedora 17 and 18 + +. Added support for Embarcadero C++BuilderXE4 using + bcc32 in debug and release mode + +. Improved support for Android + +USER VISIBLE CHANGES BETWEEN ACE-6.1.9 and ACE-6.2.0 +==================================================== + +. None + +USER VISIBLE CHANGES BETWEEN ACE-6.1.8 and ACE-6.1.9 +==================================================== + +. Added MinGW64 as supported platform + +. Added support for GCC 4.8.0 + +USER VISIBLE CHANGES BETWEEN ACE-6.1.7 and ACE-6.1.8 +==================================================== + +. Small bug fixes + +USER VISIBLE CHANGES BETWEEN ACE-6.1.6 and ACE-6.1.7 +==================================================== + +. Integrated several patches to simplify Debian/Ubuntu + packaging + +USER VISIBLE CHANGES BETWEEN ACE-6.1.5 and ACE-6.1.6 +==================================================== + +. Added new event and sema initialization methods to OS_NS_Thread + to allow passing pre-initialized condition attributes providing + basic support for using time policies in ACE Event classes. + +. Added TIME_POLICY support to ACE_Event classes to allow for + monotonic timer support for ACE Events. + +. Added new regression test: + Monotonic_Manual_Event_Test + +USER VISIBLE CHANGES BETWEEN ACE-6.1.4 and ACE-6.1.5 +==================================================== + +. When a ACE_Event_Handler registered for signals is unregistered, + whether by unregistering, returning -1 from handle_signal(), or by + the reactor closing, the ACE_Event_Handler::handle_close() hook will + be called. The close_mask passed will be ACE_Event_Handler::SIGNAL_MASK. + In previous versions, handle_close() would only be called when the + handle_signal() callback returned -1. This resolves Bugzilla #2368. + +. Some initial ACE unit tests to validate the C++11 support of various + compilers + +. Added support for OpenSuSE 12.2 + +USER VISIBLE CHANGES BETWEEN ACE-6.1.3 and ACE-6.1.4 +==================================================== + +. Added a new ACE_Time_Value derived template class (Time_Value_T.h): + + template class ACE_Time_Value_T + + This template class overloads 4 new virtual methods from + the ACE_Time_Value base class to provide time policy aware + time values: + to_relative_time () + to_absolute_time () + now () + duplicate () + +. Updated time policy classes to return ACE_Time_Value_T<> instantiations + for the corresponding time policy instead of 'common' time values. + +. Added new ACE_Monotonic_Time_Policy (Monotonic_Time_Policy.h). + This class provides a monotonic time source for supported + platforms (Windows and POSIX platforms providing the required + clock_gettime() time source; currently verified for Windows and + Linux) + +. Updated OS_NS_Thread to use the new time policy support in ACE_Time_Value + for (relative) time calculations and added new ACE_OS::condattr_setclock () + method. + +. Added TIME_POLICY support to ACE_Condition_Attributes to allow for + monotonic timer support for ACE_Condition. + +. Added TIME_POLICY support to ACE_Message_Queue-s, ACE_Task-s and + related classes to enable support for monotonic timers in the timed + wait methods (ACE_Condition based). See docs/ACE-monotonic-timer.html + for how to use this. + +. Added two new regression tests: + Monotonic_Task_Test + Monotonic_Message_Queue_Test + and updated the Bug_4055_Regression_Test to a fixed state. + +USER VISIBLE CHANGES BETWEEN ACE-6.1.2 and ACE-6.1.3 +==================================================== + +. Added support for Oracle Solaris Studio 12 Update 3 (SunCC 5.12) + +. Added new XML_Utils library which comes from DAnCE but is now also used + by OpenDDS + +USER VISIBLE CHANGES BETWEEN ACE-6.1.1 and ACE-6.1.2 +==================================================== + +. Added compile time support for Windows CE 7, no runtime testing has + been performed + +. The High Res Timer global scale factor on Windows is now 64bit, see bugzilla + 3703 for the background of this. If you use the gsf in your code, use the + new ACE_High_Res_Timer::global_scale_factor_type type trait to not get + any conversion warnings + +. Removed Tandem NSK v2/v3 support which resulted in cleanup throughout all + code. The emulations for ACE_INT64/ACE_UINT64 have been removed because no + platform is using them anymore + +USER VISIBLE CHANGES BETWEEN ACE-6.1.0 and ACE-6.1.1 +==================================================== + +. Minor bug fixes + +USER VISIBLE CHANGES BETWEEN ACE-6.0.8 and ACE-6.1.0 +==================================================== + +. Added compilation support for VxWorks 6.9, no runtime + testing has been performed + +. Added ACE Run-length encoding compressor + +. Fixed several Coverity reported issues + +USER VISIBLE CHANGES BETWEEN ACE-6.0.7 and ACE-6.0.8 +==================================================== + +. Added support for MPC's new feature that creates dependency files for IDL + files when generating '-type gnuace' projects. Turned off by default, it + can be enabled in a features file or on the command line with + '-features ace_idl_dependencies=1'. + +USER VISIBLE CHANGES BETWEEN ACE-6.0.6 and ACE-6.0.7 +==================================================== + +. Added a new method to ACE_Atomic_Op, TYPE exchange (TYPE newval) + which does an atomic exchange of the new value with ACE_Atomic_Op's value + and returns the old value. The tests/Atomic_Op_Test.cpp test program has a + test case that exemplifies its usage; see the Exchange_Tester class. + +. Added a new feature to timer queue templates classes: TIME_POLICY. + This feature is specified through a new template argument and provides the + timer queue with a policy for a timer (time of day) value. This feature is + intended to replace (in time) the gettimeofday setter method which has been + marked @deprecated. For now backwards compatibility is guaranteed. + The TIME_POLICY feature provides flexibility with regards to providing a timer + source to the timer queues as well as the possibility for a fully optimized + calling path. + A number of standard time policies are provided in ace/Time_Policy.h. + The tests/Timer_Queue_Test.cpp has been updated to reflect and exemplify these + changes. + +. Added the TIME_POLICY feature also to countdown time class which has now + become a template (ace/Countdown_Time_T.h) + +. Initial support for Microsoft Visual Studio 11 + +. Increased overall code quality by using Coverity and Klocwork + +USER VISIBLE CHANGES BETWEEN ACE-6.0.5 and ACE-6.0.6 +==================================================== + +. Removed autoconf support, only traditional way of + compilation is shipped from now + +. Add support for RHEL 6.1 64bit + +USER VISIBLE CHANGES BETWEEN ACE-6.0.4 and ACE-6.0.5 +==================================================== + +. Improved support for Android and added the ability to run all ACE/TAO tests + automatically using the Android emulator + +USER VISIBLE CHANGES BETWEEN ACE-6.0.3 and ACE-6.0.4 +==================================================== + +. Removed support for C++ Builder + +. Added support for building with the Android NDK, at least r5c. This + is currently available for linux host platforms. + +USER VISIBLE CHANGES BETWEEN ACE-6.0.2 and ACE-6.0.3 +==================================================== + +. Added support for GCC 4.6 + +USER VISIBLE CHANGES BETWEEN ACE-6.0.1 and ACE-6.0.2 +==================================================== + +. The ACE_wrappers/ace/OS.h file has been restored in order to ensure + build-time compatibility with older ACE versions. Its use will still + cause your build to incur more processing time than using the needed + ace/OS_NS_*.h files; however, you should be able to build OS.h-including + code without needing to replace it with OS_NS_* includes. + +. Improved and simplified QNX support + +. Changed rand_r() and getpwnam_r() to conform Single UNIX Specification. + +. Fixed performance of send_v on windows when individual iovec elements + are particularly large. + +USER VISIBLE CHANGES BETWEEN ACE-6.0.0 and ACE-6.0.1 +==================================================== + +. Added support for MinGW with GCC 4.5 + +USER VISIBLE CHANGES BETWEEN ACE-5.8.3 and ACE-6.0.0 +==================================================== + +. Changed the string format produced by ACE::timestamp() from the ctime + format "Day Mon dd hh:mm:ss yyyy" to ISO-8601 yyyy-mm-dd hh:mm:ss.mmmmmm. + This makes the time easier to collate and removes any dependence on locale. + The change affects the output from ACE_Log_Msg's %D format and both VERBOSE + and VERBOSE_LIGHT timestamps in addition to application-made direct calls + to ACE::timestamp(). + +. Removed GCC < 3 support + +. A new build system hook was added for users to include site-private rules + in a build. If a file named "rules.private.GNU" in located in any build + directory it will get included from + $ACE_ROOT/include/makeinclude/rules.local.GNU. The "private_rules_file" + make variable can be set to override the name and/or location of the file. + If no such rules file exists, its absence is silently ignored. This + facility can be used, for example, to integrate a specialized code checker + into the build process. + +USER VISIBLE CHANGES BETWEEN ACE-5.8.2 and ACE-5.8.3 +==================================================== + +. Two new methods were added to ACE_Pipe: close_read() and close_write(). + These methods can be used to close individual pipe handles. + +. The ACE::handle_ready() family of methods was changed to prefer using + poll() over select() on platforms where poll() is available. This + preference was previously only used if ACE_HAS_LIMITED_SELECT was set. + The ACE_HAS_LIMITED_SELECT choice is removed, making ACE_HAS_POLL the + setting that switches this preference. The driving reason for this + is that if select() is called to detect changes on a handle whose + values falls outside that which can safely be stored in an fdset, + the handle-setting macros/functions will set/clear bits outside + of the fdset. This results in very weird memory changes, often in + the stack, which are very hard to diagnose. poll()'s operation + does not suffer from this affect. With the growing use of large + numbers of handles and use of ACE_Dev_Poll_Reactor on Linux, + the rate at which this problem was cropping up was increasing. + +. Added a simple helper ACE::is_equal() which compares equality of two + objects without using operator==. This is useful for comparing floating + point values. + +. Removed all deprecated methods, arguments, files, classes, macros and + anything else we kept for years. + +. Removed Irix/Tru64/SCO/Uniware/Cray support + +. ACE_Pair has been removed. Users should now use std::pair. + +. This is the last micro release that will work with GCC < 3, after x.8.3 + support for GCC < 3 will be removed + +USER VISIBLE CHANGES BETWEEN ACE-5.8.1 and ACE-5.8.2 +==================================================== + +. Added support for the Microsoft Visual Studio 2010 IDE (vc10) + +. Removed complete support for emulated C++ exceptions + +USER VISIBLE CHANGES BETWEEN ACE-5.8.0 and ACE-5.8.1 +==================================================== + +. Added support for Microsoft Visual Studio 2010 using nmake + +. Reduced the amount of doxygen pages generated, the original settings caused + a doxygen generated html package of 1.4GB which was way too large + +. Extended ACE INet addon library with: + * HTTP Basic Authentication + * SSL/HTTPS support. + * Proxy CONNECT tunneling. + +USER VISIBLE CHANGES BETWEEN ACE-5.7.9 and ACE-5.8.0 +==================================================== + +. There are two new ACE_Time_Value methods for getting and setting millisecond + values to/from ACE_UINT64 values: + + ACE_UINT64 ACE_Time_Value::get_msec () const + void ACE_Time_Value::set_msec (const ACE_UINT64 &ms) + + The former is a replacement for the existing msec(ACE_UINT64&) methods that + are "getter" methods whose signatures look confusingly like "setters". See + Bugzilla #3336 for the history behind this change. + + The latter is for consistency and clarity. + +. Added ACE INet addon library for Inet protocol clients (and possibly + servers at some point) like http://, ftp:// etc. + The library implements standard C++ iostream wrapper classes for + ACE Svc_Handler and Reactor based input/output handling, URL classes + and protocol handler classes. + NOTE: This is work in progress! There is no guarentee that the API + won't change in the next few releases. + Protocol handling is currently restricted to client side download + requests for HTTP and FTP. + Handling for upload requests should be added in the near future as well + as HTTP Basic Authentication. + +USER VISIBLE CHANGES BETWEEN ACE-5.7.8 and ACE-5.7.9 +==================================================== + +. ACE's default makefiles (traditional ACE/GNU, not autoconf/automake) + now support installation with "make install". + Please see the ACE-INSTALL.html file for instructions. + +. Support for the ARCH make variable has been enhanced to apply to executables + (in addition to libraries and object files), and the ARCH feature has been + integrated into the MPC-generated makefiles (to work with MPC's requires + and avoids features). + +USER VISIBLE CHANGES BETWEEN ACE-5.7.7 and ACE-5.7.8 +==================================================== + +. ACE now uses GCC builtin Atomic instructions for short, + unsigned short, long, unsigned long, int, unsigned int, + and bool. This makes our Atomic_Op around 7 times faster + +. ACE Service Configuration Framework now process first service + configuration files and then command-line directives. Thus if + application uses both service configuration files and command-line + directives then the command-line directives may override results of + directives in the configuration files. At the same time if the + application uses only the default svc.conf file and command-line + directives then the directives from svc.conf can not override + results of the user provided command-line directives. + +. ACE_Dev_Poll_Reactor now dispatches notifications in only one thread at + a time. This brings notification handling more in line with behavior in + other Reactor implementations. + +USER VISIBLE CHANGES BETWEEN ACE-5.7.6 and ACE-5.7.7 +==================================================== + +. Integrated fix for bug 3104 and regression test for + interval timers. + +. Added support for GCC builtin Atomic instructions which + are enabled with GCC >= 4.1 for PPC32/PPC64/IA64 + +. Improved autoconf support for debian + +. Added support for -mcpu and -mtune. Add TCPU=.. to your + environment/platform_macros.GNU to specify you cpu and + than add cpumodelflag=1 and/or tunemodelflag=1. Using + this with IBM Cell increased the performance significantly + +USER VISIBLE CHANGES BETWEEN ACE-5.7.5 and ACE-5.7.6 +==================================================== + +. Added support for iPhone/iPod Touch/iPad. The following + environment variables are needed: + + IPHONE_TARGET, should be set to either SIMULATOR or + HARDWARE. Set to HARDWARE if you want to deploy + on the iPhone/iPod Touch/iPad device. + + IPHONE_VERSION, should be set to 3.1.2 or 3.2. One can + set the version to any future or past versions, but + only 3.1.2 and 3.2 have been tried. + + Note that one has to compile ACE/TAO statically as + it is believed that the iPhone OS does not support + dynamic loading of external libraries. The usual + procedure of cross compiling ACE/TAO applies + (such as setting HOST_ROOT environment variable). + +. Added support for Embarcadero C++ Builder 2010 + +. Added option to print a given ACE_Time_Value in the log + message instead of system supplied timestamp as in %T + and %D. + The option is implemented as a variant of the %D/%T + options by using the '#' flag character like '%#D' or + '%#T'. When using this flag an ACE_Time_Value pointer is + expected in the argument list supplied with the log message. + This fixed Bugzilla #3221. + +. Fixed problems with ACE_INET_Addr::is_multicast() on + little endian platforms. This fixed bugzilla #3729. + +. Added compilation support for VxWorks 6.8, no runtime + testing has been performed + +USER VISIBLE CHANGES BETWEEN ACE-5.7.4 and ACE-5.7.5 +==================================================== + +. Added MacOSX Snow Leopard support + +. Added strsignal() wrapper + +. Improved LynxOS support + +. Updated Interix port + +. Fixed MinGW compilation problems + +USER VISIBLE CHANGES BETWEEN ACE-5.7.3 and ACE-5.7.4 +==================================================== + +. ACE_CDR::consolidate now returns an int, 0 is ok, -1 is failure + +. Fixed a bug in the realclean feature of the GNU makefiles + +. Improved Sun Studio for Linux support + +. Improved OpenBSD support + +USER VISIBLE CHANGES BETWEEN ACE-5.7.2 and ACE-5.7.3 +==================================================== + +. C++ Builder 2009 Update 3 is the only C++Builder that is supported, older + and newer compilers are not supported anymore + +. Made final changes for the CEGCC port + +. Added a set of tests to validate C++ compiler and the stl implementation + they ship. + +. HP-UX PARISC aCC < 3.80 are deprecated and can't be used anymore. Upgrade + to aCC 3.80 or newer + +USER VISIBLE CHANGES BETWEEN ACE-5.7.1 and ACE-5.7.2 +==================================================== + +. Borland C++ makefiles aren't shipped anymore as part of the release + but have to be generated by the user + +. Refactored gperf to have its own shared library so that we can reuse + that in TAO + +. Added support for SuSE Enterprise 10 + +. ACE_Configuration_Heap::open() now returns -1 with errno EBUSY if it is + called multiple times. Previous versions would allow multiple calls to + open() but leak resources. + +USER VISIBLE CHANGES BETWEEN ACE-5.7.0 and ACE-5.7.1 +==================================================== + +. Added support for Sun Studio 12 Update Pack 1 + +. Fixed compile problems when using Windows CE x86 release mode + +. Fixed compile problems for FreeBSD + +USER VISIBLE CHANGES BETWEEN ACE-5.6.9 and ACE-5.7.0 +==================================================== + +. Added support for the VxWorks vxAtomicLib which is available with VxWorks 6.6 + and newer. If you don't want to use this library undef ACE_HAS_VXATOMICLIB + in your config.h file + +. Added support for C++ Builder 2009 Update 3 + +. Added support for ACE/TAO using the CEGCC project + +. Added support for upcoming Fedora 11 and OpenSuSE Factory + +USER VISIBLE CHANGES BETWEEN ACE-5.6.8 and ACE-5.6.9 +==================================================== + +. Removed Borland/CodeGear C++ Builder 2007 support. If you'd like to + fund this support please let us know. + +. Removed VxWorks 5.5.x, 6.2, and 6.3 support. If you'd like to fund + this support please let us know. + +. Improved Unicode support. + +. Added support for the native Windows Vista and Windows Server 2008 + condition variables. These has to be enabled at compile time, and when + enabled the application can only run on Vista or Server 2008. Add + ACE_HAS_WTHREADS_CONDITION_VARIABLE to your config.h file to enable + these + +. Fixed a bug when trying to read a file of 1 byte when unicode is + enabled + +. Improved the Windows CE port + +. Fixed several Klocwork reported issues + +. Added support for MinGW 3.15 + +. Added support for Incredibuild, which is an MSVC++ feature that + optimizes compiles via distributing builds. + +USER VISIBLE CHANGES BETWEEN ACE-5.6.7 and ACE-5.6.8 +==================================================== + +. Added a new function ACE::isdotdir() which determines if a specified + pathname is "dot dir" (ie. "." or ".."). ACE::isdotdir() is significantly + faster than pair of strcmp() calls. + +. Last micro release that is maintained for Borland/CodeGear C++ + Builder 2007 and Intel C++ on Windows. + +. Fixed crash when ACE thread tries to inherit the logging attributes + from non ACE threads. + +. Fixed many small compile and test errors that occur on some platforms. + +. Fixed log output formatting on some platforms. + +. Bugs fixed: 2748, 3164, 3480, 3494, 3502, 3541, 3542, 3544, 3557. + +USER VISIBLE CHANGES BETWEEN ACE-5.6.6 and ACE-5.6.7 +==================================================== + +. Changed the automake build's feature test for a "usable" config + to warn on failure instead of exiting with an error. This should + make it easier to diagnose configure failures, as the script will + now generate a config.h file even when the test fails. + +. Removed borland MPC template, use the bmake template from now + +. Added Windows Mobile 6 support and improved the WinCE port + +. Removed BCB6 and BCB2006 support + +. Added BCB2009 MPC template + +. Updated stat struct on Windows CE to match the stat struct on other + platforms so that application code can be written portable + +. Added new ACE_OS wrappers: raise, atof, atol, isblank, isascii, + isctype, and iswctype + +. Added ACE_OS wrapper for narrow-char version of strtoll. + +. ACE_OS wrappers for wide-char versions of strtol, strtoul, + strtoll, and strtoll. + +. Added Visual Studio 2010 (vc10) support + +. Added a new feature for the "Traditional Make" build facility to allow + building for multiple architectures out of a single source directory. + To use this facility, set the ARCH make variable. The ARCH value will be + used to add a subdirectory layer below the source directory where the + traditional .shobj, .obj, etc. directories will be placed. + +. Added support for HP-UX 11iv3 on Integrity using aC++ + +. ACE (and TAO) can now be built using GNU make and the Microsoft Visual C++ + compiler and linker. See include/makeinclude/platform_win32_msvc.GNU for + more details. + +. Added support for FC10 + +USER VISIBLE CHANGES BETWEEN ACE-5.6.5 and ACE-5.6.6 +==================================================== + +. Added an option to the ACE_Process_Options class to use a wchar_t + environment buffer on Windows. + +. A new configure option, --enable-rcsid, was added to the autoconf build. + This is used to embed RCS IDs in object files. + +. A new method was added: void ACE_Time_Value::msec (ACE_UINT64&) + This method, like the existing msec(ACE_UINT64&)const method, obtains the + time value in milliseconds and stores it in the passed ACE_UINT64 object. + This method was added so that msec(ACE_UINT64&) can be called on both + const and non-const ACE_Time_Value objects without triggering compile errors. + Fixes Bugzilla #3336. + +. Added ACE_Stack_Trace class to allow users to obtain a stack trace + within their application on supported platforms. A new conversion + character, the question mark, was added to ACE_Log_Msg for stack + trace logging. + +. Added iterator support to ACE_Message_Queue_Ex class. The resulted in + the addition of ACE_Message_Queue_Ex_Iterator class and + ACE_Message_Queue_Ex_Reverse_Iterator class. + +. Renamed gperf to ace_gperf to prevent clashes with the regular gperf + tool that is available in linux distributions + +. Added support for FC9 + +. Added support for OpenSuSE 11.0 + +. Improved support for GCC 4.2 and 4.3 + +. Added support for CodeGear C++ Builder 2009 + +USER VISIBLE CHANGES BETWEEN ACE-5.6.4 and ACE-5.6.5 +==================================================== + +. Added new Monitoring lib that can be used to store and retrieve + counters. This is disabled by default because it is not 100% + finished yet, with the next release it will be enabled by default + +. Fixed bug in ACE_Service_Config when it was used from a thread + not spawned by ACE + +. Add VxWorks 6.x kernel mode with shared library support to ACE + +. Extended the implementation of Unbounded_Set, which has been + renamed Unbounded_Set_Ex, to accept a second parameter which is + a comparator that implements operator() which returns true if + the items are equivalent. Unbounded_Set has been reimplemented + in terms of Unbounded_Set_Ex using a comparator that uses operator==, + which captures the previous behavior. + +. Added support for Intel C++ on MacOSX + +USER VISIBLE CHANGES BETWEEN ACE-5.6.3 and ACE-5.6.4 +==================================================== + +. Reworked the relationship between ACE_Service_Config and + ACE_Service_Gestalt + +. Improved autoconf support + +. Improved AIX with gcc support + +. Improved OpenVMS support + +. Improved VxWorks support + +USER VISIBLE CHANGES BETWEEN ACE-5.6.2 and ACE-5.6.3 +==================================================== + +. Deprecated Visual Age 5 and older + +. Closed a rare race condition hole whereby ACE_Atomic_Op<> function + pointers would not be fully initialized prior to use. See bugzilla + 3185 for details. + +. Tweaks to support MacOS X Leopard (10.5 and 10.5.1) on Intel + +. Fixed compile problems with MinGW with GCC 4.2. Do note that we do see + much more test failures then when using GCC 3.4. + +. Changed to use synchronous exception handling with msvc 8/9 which is the + default. Asynchrous exception handling does catch access violations but + it leads to lower performance and other problems. See also bugzilla 3169 + +. Make ace_main extern C with VxWorks so that it doesn't get mangled + +. Fixed compile errors and warnings for VxWorks 6.6 + +. Added an MPC generator for the WindRiver Workbench 2.6 which is shipped + with VxWorks 6.4 + +. Added support for CodeGear C++ Builder 2007 with December 2007 update + installed + +. Added support for VxWorks 5.5.1 + +. Implemented the const reverse iterator for ACE_Hash_Map_Manager_Ex + +. Increased support for using ACE_Hash_Map_Manager_Ex with STL + functions based on latest standard C++ draft + +USER VISIBLE CHANGES BETWEEN ACE-5.6.1 and ACE-5.6.2 +==================================================== + +. ACE-ified the UUID class, which will change user applications slightly. + +. Added support for Sun Studio 12 + +. Added support for Intel C++ 10.1 + +. Fixed runtime problems with VxWorks 6.x in kernel mode, several improvements + have been made to ACE, but also some problems in the VxWorks kernel have + been found for which WindRiver has made patches. + +. Added support for VxWorks 6.5 kernel mode + +. Added support for MacOS 10.5 + +. Support for MacOS 10.4 is now deprecated. + +. Added support for OpenSuSE 10.3 + +. Added support for RedHat 5.1 + +. Added support for Microsoft Visual Studio 2008 + +. Added support for Fedora Core 8 + +. Added support for Ubuntu 7.10 + +. With Ubuntu 7.04 and 7.10 we can't use visibility, that results in + unresolved externals when building some tests. With lsb_release we + now detect Ubuntu 7.04 and 7.10 automatically and then we disable + visibility + +. Removed deprecated (un)subscribe methods from ACE_SOCK_Dgram_Mcast + +. Added an additional replace() method to ACE_OuptutCDR for replacing a + ACE_CDR::Short value. Also added write_long_placeholder() and + write_short_placeholder() to properly align the stream's write pointer, + write a placeholder value and return the placeholder's pointer. The pointer + can later be used in a call to replace() to replace the placeholder with a + different value. + +. Initial support for VxWorks 6.6 + +. Removed support for pthread draft 4, 6, & 7. This makes the ACE threading + code much cleaner + +. Improved autoconf support + +. Fixed TSS emulation problems + +. Changed ACE_thread_t and ACE_hthread_t to int for VxWorks kernel mode. All + thread creation methods do have an additional const char* argument to + specify the task name, this now also works with pthread support enabled + +. Use bool in much more interfaces where this is possible + +. Added support for Debian Etch + +. Fixed ACE CDR LongDouble support on VxWorks 6.x + +. Added Microsoft Visual Studio 2008 project files to the release packages + +. Fixed a few bugs in the ACE_Vector template + +USER VISIBLE CHANGES BETWEEN ACE-5.6 and ACE-5.6.1 +==================================================== + +. Added support for CodeGear RAD Studio 2007 + +. Added support for CodeGear C++ Builder 2007 Update 3 + +. Modified the definiton of ACE_DEFAULT_THREAD_KEYS on Windows so it + is based on the version of the OS as defined by Microsoft in this web + page: http://tinyurl.com/2jqcmd + This fixes bugzilla #2753 + +USER VISIBLE CHANGES BETWEEN ACE-5.5.10 and ACE-5.6 +==================================================== + +. OpenVMS 8.3 on IA64 port + +. Added autoconf support for Intel C++ 10.0 + +. Improved autoconf support on Linux, Solaris, NetBSD and HPUX + +. CodeGear C++ Builder 2007 Update 2 support + +. The netsvcs's client logging daemon has a new configuration option, + -llocal-ip[:local-port], which can be used to specify the local IP + address and port number for the client logging daemon's connection to + the server logging daemon. If the -l option is specified with an IP + address but not a port number, an unused port number is selected. + +. A new ACE+TAO port to LabVIEW RT 8.2 with Pharlap ETS. The host build + environment is Windows with Microsoft Visual Studio .NET 2003 (VC7.1). + Please see the ACE-INSTALL.html file for build instructions. + +USER VISIBLE CHANGES BETWEEN ACE-5.5.9 and ACE-5.5.10 +==================================================== + +. The ACE_utsname struct, used in the ACE_OS::uname() function when the + platform doesn't provide the standard utsname struct, was changed. It + defines a number of text fields and their types were changed from + ACE_TCHAR[] to char[] in order to be consistent with all other platforms. + This removes the need to write different code for platforms where + ACE_LACKS_UTSNAME_T is set and that have wide characters (most probably + Windows). Fixes Bugzilla #2665. + +. The ACE::daemonize() "close_all_handles" parameter was changed from + an "int" to a "bool" to better reflect how it is used. + +. VxWorks 6.5 support. Compilation of the core libraries has been validated + but no runtime testing has been performed. + +. CodeGear C++ Builder 2007 support. + +. The FaCE utility was moved from the ACE_wrappers/apps directory to + ACE_wrappers/contrib. It is used for testing ACE+TAO apps on WinCE. + See the ACE_wrappers/contrib/FaCE/README file for more information. + +. ACE_INET_Addr::set (u_short port, char *host_name, ...) now favors IPv6 + addresses when compiled with ACE_HAS_IPV6 defined and the supplied address + family is AF_UNSPEC. This means that if host_name has an IPv6 address in + DNS or /etc/hosts, that will be used over an IPv4 address. If no IPv6 + address exists for host_name, then its IPv4 address will be used. + +. Intel C++ 10.0 support + +. Support for the version of vc8 for 64-bit (AMD64) shipped with the Microsoft + Platform SDK. + +. Fixed ACE_Vector::swap() (bugzilla #2951). + +. Make use of the Atomic_Op optimizations on Intel EM64T processors. The + Atomic_Op is now several times faster on EM64T then with previous versions + of ACE + +USER VISIBLE CHANGES BETWEEN ACE-5.5.8 and ACE-5.5.9 +==================================================== + +. Use Intel C++ specific optimizations for Linux on IA64 + +. Improved support for ACE_OS::fgetc. Added support for ACE_OS::fputc, + ACE_OS::getc, ACE_OS::putc and ACE_OS::ungetc. + +. Added support for ACE_OS::log2(double) and improved support for + ACE::log2(u_long). + +. Shared library builds on AIX now produce a libxxx.so file instead of the + previous practice of producing libxxx.a(shr.o). + +. GCC 4.1.2 that comes with Fedora 7 seems to have a fix for the visibility + attribute we use for the singletons. F7 users will therefore need to + define the following in your config.h file. + ACE_GCC_HAS_TEMPLATE_INSTANTIATION_VISIBILITY_ATTRS 1 + +. Fixed (rare) problem in TP_Reactor where incorrect event handler was + resumed. + +. Reduced footprint on some platforms, particularly those that use + g++ >= 3.3. + +USER VISIBLE CHANGES BETWEEN ACE-5.5.7 and ACE-5.5.8 +==================================================== + +. Extended ACE_Event constructor with optional LPSECURITY_ATTRIBUTES + argument + +. Added support for QT4 + +. Added support to integrate with the FOX Toolkit (www.fox-toolkit.org) + +. Added support for Microsoft Visual Studio Code Name "Orcas", which is + the msvc9 beta + +. Added ability to provide an optional priority when calling + ACE_Message_Queue_Ex::enqueue_prio(). There was previously no way + to specify a priority for queueing. + +. Removed support for Visual Age on Windows. + +. ACE will compile once again with ACE_LACKS_CDR_ALIGNMENT #defined. + +. ACE_Process_Manager::terminate() no longer removes the process from the + process descriptor table; the pid remains available in order to call + ACE_Process_Manager::wait(). + +USER VISIBLE CHANGES BETWEEN ACE-5.5.6 and ACE-5.5.7 +==================================================== + +. ACE 5.5 contained a set of pragmas which prevented Visual Studio 2005 (VC8) + from issuing warnings where C run-time functions are used but a more + secure alternative is available. For more information on the C run-time + issues and Microsoft's response, please see the following MSDN page: + http://msdn2.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx. + In this beta, the pragmas which prevented the warnings have been removed. + The ACE library has been reviewed and most of the use of "unsafe" functions + has been fixed where possible. Since not all of the warnings emanating from + ACE are situations that can or should be fixed, the ACE VC8 projects will + prevent the warnings while building the ACE kit and its contained examples, + tests, etc. The warnings are disabled by adding Microsoft-specified macros + to the compile line via MPC. If desired, the warnings can be re-enabled by + regenerating the project files with different MPC features. Note, however, + that while ACE without warnings caused by the new C run-time functions, your + application builds may trigger these warnings either by use of the "unsafe" + C run-time functions or via use of an inlined ACE_OS method which uses it. + If the warning is caused by an ACE_OS method, there is a more safe alternate + available, probably located by appending _r to the method name (e.g., + instead of using ACE_OS::ctime(), use ACE_OS::ctime_r()). + There are other cases where the compiler may have issued warnings and ACE + prevented this via a #pragma. These #pragmas have been removed as well. + This may cause your application builds to trigger more warnings from VC8 + than past ACE versions. You should review your code and either correct + the code or disable the warnings locally, as appropriate. + +. The "release" argument to a number of ACE_String_Base<> methods was changed + from int to bool to more accurately reflect its purpose. The following + methods were changed: + + ACE_String_Base (const CHAR *s, + ACE_Allocator *the_allocator = 0, + int release = 1); + to + ACE_String_Base (const CHAR *s, + ACE_Allocator *the_allocator = 0, + bool release = true); + + ACE_String_Base (const CHAR *s, + size_type len, + ACE_Allocator *the_allocator = 0, + int release = 1); + to + ACE_String_Base (const CHAR *s, + size_type len, + ACE_Allocator *the_allocator = 0, + bool release = true); + + void set (const CHAR * s, int release = 1); + to + void set (const CHAR * s, bool release = true); + + void set (const CHAR * s, size_type len, int release); + to + void set (const CHAR * s, size_type len, bool release); + + void clear (int release = 0); + to + void clear (bool release = false); + + Since ACE_String_Base forms the basis of the ACE_CString and ACE_TString + classes, this may ripple out to user application code. If you encounter + errors in this area while building your applications, replace the + int argument you are passing to the method now with either true or false. + +. Solutions for the eVC3/4 platform have been removed from this + release. Note that we package WinCE projects/workspaces for use + with VC8. + +. There were 3 new ACE_Log_Msg logging format specifiers added to make logging + easier for types that may change sizes across platforms. These all take one + argument, and the new formats are: + %b - format a ssize_t value + %B - format a size_t value + %: - format a time_t value + +. The ace/Time_Request_Reply.h and ace/Time_Request_Reply.cpp files were + moved from $ACE_ROOT/ace to $ACE_ROOT/netsvcs/lib. The time arguments in + the public API to ACE_Time_Request were changed from ACE_UINT32 to time_t + and the portions of the on-wire protocol that contains time was changed from + ACE_UINT32 to ACE_UINT64. Thus, code that uses the ACE_Time_Request class + to transfer time information will not interoperate properly with prior + ACE versions. This will affect uses of the netsvcs time clerk/server. + +. The portion of the ACE_Name_Request class that carries the on-wire seconds + portion of a timeout value was changed from ACE_UINT32 to ACE_UINT64. This + means that Name server/clients at ACE 5.5.7 and higher will not interoperate + properly with previous ACE versions' name servers/clients. + +. In the ACE_Log_Record (ACE_Log_Priority, long, long) constructor, the + second argument, long time_stamp, was changed to be of type time_t. This + aligns the type with the expected value, a time stamp such as that returned + from ACE_OS::time(). + +. Added support for VxWorks 6.x cross compilation using a Windows host + system + +. Added support for VxWorks 6.x using the diab compiler + +. The destructor of ACE_Event_Handler no longer calls + purge_pending_notifications(). Please see bugzilla #2845 for the full + rationale. + (http://deuce.doc.wustl.edu/bugzilla/show_bug.cgi?id=2845) + +USER VISIBLE CHANGES BETWEEN ACE-5.5.5 and ACE-5.5.6 +==================================================== + +. The ACE_TYPENAME macro has been added to those that are not + available when the ACE_LACKS_DEPRECATED_MACROS config option is set + (it is not set by default). You are encouraged to replace the use of + ACE_TYPENAME with the C++ typename keyword before the ACE_TYPENAME + macros is removed from ACE in the future. + +. A new script, rm_exception_macros.pl, has been added to help users + remove the use of the ACE exception macros from their own code. + +USER VISIBLE CHANGES BETWEEN ACE-5.5.4 and ACE-5.5.5 +==================================================== + +. The prebuild MPC keyword is now supported by the gnuace project type. + This fixes Bugzilla #2713. + +. Support for Windows earlier than NT 4 SP2 was removed. ACE will not build + for Windows 95, 98, Me, etc. out of the box any longer. + +. Reformat stringified IPv6 addresses to use [addr]:port when printing + addresses that contain ':' such as "::1". + +. Added method to ACE_INET_Addr to determine if address is IPv6 or + IPv4 multicast. + +. Fixed a bug in ACE_Async_Timer_Adapter_Timer_Queue_Adapter where the + gettimeofday function of the timer queue was ignored when setting the alarm. + +. Fixed a problem where, on Solaris 9 onwards, calling + ACE_OS::thr_create(THR_NEW_LWP) more than 2^15 (65535) times in a + process will fail. See changelog entry from "Wed Jan 3 22:31:05 UTC + 2007 Chris Cleeland " for more information. + +. Fixed a bug in ACE_QtReactor where the two select() calls in that function + might select on different handler sets. + +. ACE_SOCK_IO::recvv(iovec[], size_t, const ACE_Time_Value* = 0) and + ACE_SOCK_IO::sendv (const iovec[], size_t, const ACE_Time_Value* = 0) methods + were changed to specify the iovec count argument as int instead of size_t + since it gets reduced to int in the underlying OS calls (usually). + +. The following deprecated methods were removed: + + ssize_t ACE_SOCK_IO::recv (iovec iov[], + size_t n, + const ACE_Time_Value *timeout = 0) const; + + ssize_t ACE_SOCK_IO::recv (iovec *io_vec, + const ACE_Time_Value *timeout = 0) const; + + ssize_t ACE_SOCK_IO::send (const iovec iov[], + size_t n, + const ACE_Time_Value *timeout = 0) const; + + These were previously replaced with more specific recvv() and sendv() + methods. + +. The ACE_Service_Repository::find(const ACE_TCHAR name[], + const ACE_Service_Type **srp = 0, + int ignore_suspended = true) const + method's 'ignore_suspended' parameter was changed from int to bool to + reflect it's purpose as a yes/no indicator. + +. Added --enable-ace-reactor-notification-queue configure script + option to the autoconf build for enabling the Reactor's userspace + notification queue (defines ACE_HAS_REACTOR_NOTIFICATION_QUEUE in + config.h). + +. The int ACE_OutputCDR::consolidate(void) method was contributed by + Howard Finer at Sonus Networks. This method consolidates any continuation + blocks used by an ACE_OutputCDR object into a single block. It's useful for + situations which require access to a single memory area containing the + encoded stream, regardless of its length, when the length cannot be known + in advance. + +. There are a number of new methods defined on ACE_String_Base: + + size_t capacity (void) const: This method returns the number + of allocated CHAR units in the string object. + + void fast_resize (size_t): This method manage the sizing/reallocating + of the string, but doesn't do the memory setting of resize(). + + bool operator!= (const CHAR *) const + bool operator== (const CHAR *) const: These methods compare the + string with a nul-terminated CHAR* string. + + nonmember functions operator== and operator!= where also added + that compare const ACE_String_Base and const CHAR*; these make + it possible to switch ACE_String and CHAR* on either side of + the operator. + + Thank you to Kelly Hickel for these additions. + +. There are 2 new build options on the traditional make command: + dmalloc and mtrace. When specified at build time (e.g. make mtrace=1) + the PLATFORM_DMALLOC_CPPFLAGS and/or PLATFORM_MTRACE_CPPFLAGS values + are added to CPPFLAGS. For dmalloc, the PLATFORM_DMALLOC_LDFLAGS and + PLATFORM_DMALLOC_LIBS are added to LDFLAGS and LIBS, respectively. + Thank you to Howard Finer for supplying these additions. + +. Added the ability to specify additional purify and quantify command-line + options by setting PLATFORM_PURIFY_OPTIONS and PLATFORM_QUANTIFY_OPTIONS, + respectively. Thank you to Howard Finer for supplying these additions. + +. Added the ability to use trio (http://sourceforge.net/projects/ctrio/) + if platform lacks decent support for vsnprintf. trio support is + enabled by defining trio=1 in plaform_macros.GNU + +. Removed Irix 5, DGUX, and m88k support + +. Improved LynxOS 4.2 support + +. VxWorks 6.4 support + +. Added support for FC6. Because the GCC 4.1.1 version that gets shipped + has a fix for the visibility attribute we use for the singletons + you will need to define the following in your config.h file. This can't be + done automatically because SuSE 10.2 gets shipped with GCC 4.1.2 but + doesn't have the same fix + ACE_GCC_HAS_TEMPLATE_INSTANTIATION_VISIBILITY_ATTRS 1 + +. RTEMS port + +USER VISIBLE CHANGES BETWEEN ACE-5.5.3 and ACE-5.5.4 +==================================================== + +. Added appropriate intptr_t and uintptr_t typedefs on platforms that + don't provide them (i.e. when ACE_LACKS_INTPTR_T is defined). + +. Added ability to explicitly choose support for 32 bit or 64 bit file + offsets on all platforms. Define the _FILE_OFFSET_BITS preprocessor + symbol to either 32 or 64 to choose the desired number of file + offset bits. This preprocessor symbol is supported natively by most + UNIX and UNIX-like operating systems, and supported by ACE on + Windows. Use the new ACE_OFF_T typedef to refer to file offsets + across UNIX and Windows portably. + +. 64-bit file offsets are now enabled by default in Win64 + configurations. + +. Improved support for 64 bit platforms (64 bit addresses, etc). + +. Added STL-style traits, iterators and a swap() method to the + ACE_Array_Base<> class template. + +. Added STL-style traits and iterator accessors to the + ACE_Hash_Map_Manager_Ex<> class template, as well as new find() and + unbind() methods that return (as an "out" parameter) and accept + iterators, respectively. + +. Greatly improved event handler dispatch performance in + select()-based reactors (e.g. ACE_Select_Reactor and ACE_TP_Reactor) + for large handle sets on Windows. Previous event handler search + were linear, and are now constant on average. + +. Addressed a number of Coverity errors (CHECKED_RETURN, DEADCODE, + LOCK, USE_AFTER_FREE, RESOURCE_LEAK, FORWARD_NULL). + +. Added STL-style "element_type" trait to all ACE auto_ptr class + templates. + +. Removed support for LynxOS 3.x. + +. Resolved Bugzilla #2701 to ensure fini() is called for all + Service Objects upon calling ACE_Service_Config::close() + +. VxWorks 5.5.2 has been tested, for ACE the support is exactly + the same as for VxWorks 5.5.1. No specific defines or flags have + to be used. + +USER VISIBLE CHANGES BETWEEN ACE-5.5.2 and ACE-5.5.3 +==================================================== + +. Added the base projects for executionmanager_stub and plan_generator. + +. Added the ACE_Hash_MultiMap_Manager class and its test file. + +. Changed the ACE_Synch_Options::operator[] method to return bool rather than + int. The value returned is a yes/no indication of whether or not the + specified option(s) are set in the object. + +. Changed the prototype(s) for ACE::debug () to return (and take) a + bool. This is consistent with the original intent for this + feature. If you have been using it like 'ACE::debug () > 0' or + 'ACE::debug (1)', you may have to rebuild ACE. The value of the + ACE_DEBUG environment variable can be used to specify the initial + value for ACE::debug(), at the process start up. + +. An assembler (within a C source file) based implementation for SPARC + of atomic operations suitable for use with the + ACE_Atomic_Op and + ACE_Atomic_Op specializations has + been added. Currently, it can only be enabled by setting the + atomic_ops_sparc make macro to 1 when using the GNUACE build system with + the Solaris SunCC compiler. It should be noted that this requires the + -xarch=v8plus (or higher) be added to the CFLAGS make macro or the + assembler code will not compile. + +. The ACE_Message_Queue_Ex_N class + is new, contributed by Guy Peleg . + ACE_Message_Queue_Ex_N is + similar to ACE_Message_Queue_Ex in that the object queued is a + template parameter. However, ACE_Message_Queue_Ex_N allows the + enqueueing and dequeueing of multiple chained objects at once. This + wasn't added to ACE_Message_Queue_Ex because the chained object + functionality requires the ACE_MESSAGE_TYPE class to have a + ACE_MESSAGE_TYPE *next (void) const method, analogous to + ACE_Message_Block::next(), to follow the chain and this would + probably break existing applications using ACE_Message_Queue_Ex. + The ACE_wrappers/tests/Message_Queue_Test_Ex.cpp test has an example of + how to use the new class. + +. The selector and comparator function pointer arguments to ACE_OS::scandir() + and ACE_Dirent_Selector are now marked as extern "C" to enforce their + use with a C RTL function. User code that defines functions which are + passed as the selector or comparator arguments which are not declared + extern "C" may generate compile warnings. To resolve this, add extern "C" + to the function's signature. See ACE_wrappers/tests/Dirent_Test.cpp for + an example. + +. To address a problem in the ACE string interface that prevented + substring or character searches in very large strings (e.g. greater + than the maximum value of an ssize_t type) from being correctly + reported to the caller, the find(), rfind() and strstr() methods now + return an unsigned integer (size_t) instead of a signed one + (ssize_t). Affected classes include: + + * ACE_CString + * ACE_WString + * ACE_TString + * ACE_NS_WString + + Unless you have been explicitly using -1 instead of npos when + comparing the return value of find(), rfind() and strstr(), and/or + assigning the return value to ssize_t you should not see any + difference. A new size_type typedef has been added to the ACE string + class to aid developers. This typedef is analogous to the standard + C++ string::size_type typedef. + + The ACE_String_Base<>::strstr() documentation and the default + rfind() argument erroneously referred to -1 instead of npos. Those + instances have been corrected. + + To summarize, a "no position" condition is denoted using the npos + constant, not -1. It can be referred directly by scoping it with the + appropriate string class (e.g. ACE_CString::npos, ACE_WString::npos, + etc). + +. Changing the shared library extension for hpux ia64 to ".so". On + HP-UX 11i Version 1.5 the naming scheme is lib*.sl for PA and + lib*.so on IPF. + +. The ACE_Refcounted_Auto_Ptr reset() and release() methods were changed + per Bugzilla #1925. They will both now detach from the underlying + ACE_Refcounted_Auto_Ptr_Rep object; reset() will create a new one for + the new pointer specified as its argument. This change may cause referenced + objects to be deleted in cases where previous ACE versions would not have. + +. The return type of "ACE_Refcounted_Auto_Ptr::null (void) const" changed + from int to bool. It's possible values, true and false, have not changed. + +. TTY_IO now accepts "none" as a valid parity value. Due to this change + 'parityenb' member is now deprecated and will be removed in the future. + The users of TTY_IO class should change their code to use only 'paritymode' + member for parity control and leave 'parityenb' unchanged (it is + enabled by default in class constructor). + +. Support for Intel C++ 9.1 on Windows and Linux + +. VxWorks 6.3 support + +. Fixed Bugzilla #2648 to make sure ACE_Service_Object::fini() + is called iff ACE_Service_Object::init() succeeded, as per + C++NPv2. + +. Added preliminary support for Mac OS X 10.4 on Intel CPU's. + +. Fixed Bugzilla #2602 to re-enable XML Service Configurator + file support. + +USER VISIBLE CHANGES BETWEEN ACE-5.5.1 and ACE-5.5.2 +==================================================== + +. Added support for: + - VxWorks 6.2 for the rtp model using pthread support + - OpenVMS 8.2 for Alpha + +. Removed code and configurations that provided support for: + - Visual C++ 6.0 and 7.0 + - Chorus + - pSOS + - KAI C++ on all platforms + +. Explicit template instantiation support has been removed. This effectively + removes support for Sun Forte 6 and 7 which required explicit template + instantiation to build ACE reliably. + +. Added support for multiple independent Service Repositories through + configuration contexts called "Gestalt". Full backwards compatibility + is maintained through the existing ACE_Service_Config static methods, + while direct individual repository access is enabled through instances + of the new ACE_Service_Gestalt class. ACE_Service_Config has changed to + a specialization of ACE_Service_Gestalt and is only responsible for the + process-wide configuration. + +. To support dynamically-sized ACE_Log_Record messages, the netsvcs + logging components now use ACE CDR encoding and transfer mechanisms + inspired by the examples in Chapter 4 of the C++NPv1 book. + The client and server logging daemons in ACE 5.5.2 and forward will + not interoperate with those in previous ACE versions. + +. Added a wrapper for the sendfile API (ACE_OS::sendfile()). + +. Added support for netlink sockets on Linux. + +. Added a new method, ACE_Task::last_thread(). This method returns the thread + ID (ACE_thread_t) of the last thread to exit from the ACE_Task object. + Users checking to see if a thread is the last one out (for example, to know + when to perform cleanup operations) should compare the current thread ID to + the return value from last_thread(). This is a change from the previously + recommended practice (C++NPv2, page 189) of comparing the return value of + thr_count() with 0. + +. Changed the first argument to ACE_OS::strptime() to be 'const' which + matches its usual usage in POSIX strptime(). This change allows users to + pass const strings in - a common use case. + +. Made part of the file support in ACE 64bit but we have some places where + 32bit types are used, this could lead to some conversion warnings which + will be addressed in the near future, but getting everything 64bit + compliant is a lot of work. + +USER VISIBLE CHANGES BETWEEN ACE-5.5 and ACE-5.5.1 +==================================================== + +. Added support for the --enable-symbol-visibility configure option + to the autoconf build infrastructure instead of solely relying on + feature tests to enable/disable symbol visibility support. This + avoids build problems with icc, etc. + +. Added support for the --enable-fl-reactor configure option to the + autoconf build infrastructure to build the ACE_FlReactor library. + +. Added support for the --enable-qt-reactor configure option to the + autoconf build infrastructure to build the ACE_QtReactor library. + +. Added support for the --enable-xt-reactor configure option to the + autoconf build infrastructure to build the ACE_XtReactor library. + +. Fixed a bug that would cause timer IDs from ACE_Timer_Heap to be + improperly duplicated under certain conditions (Bugzilla #2447). + +. Fixed ACE_SSL_Context::private_key(), context(), and dh_params() methods + to allow retrying a file load after a failed call. + +. Fixed ACE_SSL_Asynch_Stream so it can be instantiated; also moved the + declarations for ACE_SSL_Asynch_Read_Stream_Result, + ACE_SSL_Asynch_Write_Stream_Result, and ACE_SSL_Asynch_Result classes + to the ace/SSL/SSL_Asynch_Stream.h file so applications can see them. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.10 and ACE-5.5 +==================================================== + +. Added a platform macros option "templates=manual", currently only + applies to AIX 5.3 with XL 7 compiler. It allows the user to tell the + compiler to set -qnotempinc and -qnotemplateregistry and works well + in static builds. + +. ACE and its tests compile error free with GCC 4.1 pre release. + +. ACE_Recursive_Thread_Mutex::get_nesting_level() fixed for 64-bit Windows + XP on amd64/EM64T hardware. + +. Many build-time fixes for Windows Mobile 5 and Windows PocketPC 2003 using + Visual Studio .NET 2005 (VC8). + +. Added support for the --enable-tk-reactor configure option to the + autoconf build infrastructure to build the ACE_TkReactor library. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.9 and ACE-5.4.10 +==================================================== + +. Fixed a bug in ACE_Timer_Heap_T::cancel(). + +. Improved ACE_Time_Value support for boundary conditions. + +. Fixed problems with operator placement delete on certain C++ compilers. + +. Fixed a bug with the ACE_SPIPE_Acceptor on Windows. + +. Correctly set sockaddr_in.sin_len and sockaddr_in6.sin6_len on + platforms that have these fields. + +. Avoided problems with namespace pollution for max() macros. + +. Many fixes for ACE_LACKS* and ACE_HAS* macros for autoconfig. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.8 and ACE-5.4.9 +==================================================== + +. Added dozens of new ACE_LACKS and ACE_HAS defines which are used to + simplify the ACE_OS layer + +. Constructors of ACE_Time_Value have been made explicit to prevent + implicit conversions. + +. Added a shutdown() method to ACE_Barrier. The new method aborts the + wait by all threads. + +. Changed the behavior of ACE_Message_Queue::enqueue_head() and + enqueue_tail(). If the enqueued message block has other blocks + chained to it via its next() pointer, the entire chain of blocks + will be enqueued at once. + +. Improved the support for high-resolution timers with + ACE_Timer_Queue_Adapter. + +. Make it possible to disable file caching in JAWS. + +. Improved ACE_Pipe implementation so that it uses localhost to avoid + firewall problems. + +. Added Unicode support to the Service Configurator. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.7 and ACE-5.4.8 +==================================================== + +. Improved IPv6 support + +. Improved 64bit portability + +. TTY_IO overhaul + - Improved documentation. + - It is now possible to request infinite timeout in portable manner. + This can be achieved by setting negative value to readtimeoutmsec. + - Various bugs fixed and portability issues resolved. + +. Subset ACE for TAO and TAO Services + +. Support for Intel C++ 9.0 on Windows and Linux + +. Support for Microsoft Visual Studio 2005 (aka VC8) for Win32 as well + as the Windows CE platforms Pocket PC 2003 and Windows Mobile 5. + Solution/project files are generated with an appended "_vc8" for + Win32 and "_WinCE" for the CE platforms. See + ACE_wrappers/docs/CE-status.txt for more information. + +. Completed implementation of ACE_Dev_Poll_Reactor using the Linux epoll + facility; tested on Red Hat Enterprise Linux 4. + +. The in-memory size of an ACE_RB_Tree will be smaller due to rearranged + placement of pointers. + +. Added an optimization to CDR stream to ignores alignment when marshaling + data. Use this new ACE_LACKS_CDR_ALIGNMENT compile-time option only + when the ACE_DISABLE_SWAP_ON_READ macro is enabled. This new option + requires ACE CDR engine to do both marshaling and demarshaling, and + when this option is enabled the encoded streams are no longer + compliant with the CORBA CDR specification. + +. Developed Feature Oriented Customizer (FOCUS) tool to enable + specialization of middleware frameworks such as Reactor and Protocol + framework. FOCUS provides an XML based transformation engine, where + the transformations to specialize the components are captured in XML + file and a weaver specializes the code. + +. Added support for unrolling ACE_OS::memcpy copy loop where + applicable to improve performance. Autoconf tests empirically + determine whether loop unrolling is at least 10% better than default + version. + +. Added support for an ACE "versioned" namespace. When enabled, ACE + library sources will be placed within a namespace of the user's + choice or a namespace of the form ACE_5_4_7 by default, where + "5_4_7" is the ACE major, minor and beta versions. The default may + be overridden by defining the ACE_VERSIONED_NAMESPACE_NAME + preprocessor symbol. Enable overall versioned namespace support by + adding "versioned_namespace=1" to your MPC default.features file. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.6 and ACE-5.4.7 +==================================================== + +. Support for shared libraries with VxWorks + +. Support for Solaris 10 on x86 with Sun Studio 10 (C++ 5.7). + +. Extended ACE_OS::event_xxx implementation to support platforms + having either PThread support with Process Shared condition + variables or POSIX semaphores with named (process shared) + semaphore support or using the new FIFO based semaphores. + +. ACE_OS::closesocket() no longer calls ACE_OS::shutdown() on any platform + while closing the socket. It previously called ACE_OS::shutdown() on + HP-UX. Removing this call fixes the fork-and-close programming paradigm + that's common to many networked applications. + +. RMCast + - Support for message fragmentation. This will allow + for messages larger than 64K. + - Support for flow control. + - Timed recv() in RMCast::Socket. + - Per-instance configurable protocol parameters (e.g., message + retention time, NAK timeout, etc). + +USER VISIBLE CHANGES BETWEEN ACE-5.4.5 and ACE-5.4.6 +==================================================== + +. Updated RMCast to include + - Reactor-compatible interface. + - Message unavailability reporting. + - Protocol documentation. + +. Added support for 64bit Visual Age on AIX + +. Improved g++ 4.0 support. A number of RTTI related problems have been + fixed. + +. Smaller footprint. + +. Fixed memory leaks ACE_DLL and ACE_Log_Msg classes. + +. The ACE::ICMP_Socket and ACE::Ping_Socket classes were moved out of + the ACE namespace and "flattened" to ACE_ICMP_Socket and + ACE_Ping_Socket to be consistent with the rest of ACE. + +. ACE_INET_Addr::set_address() - fixed a possible struct member + alignment issue when building an IPv4-mapped IPv6 address. + +. Added a new ACE::wild_match() function to match a string based on + wildcards. + +. Added efficient overloads for string concatenation to the + ACE_String_Base class. + +. Added support for the use of pthread_getschedparam on MacOS X. + +. Fixed an issue with static initialization of TSS related classes on + static builds for Windows. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.4 and ACE-5.4.5 +==================================================== + +. Remove special handling in the Thread Specific Storage(TSS) code + that released the TSS key for ACE_TSS. ACE_TSS has + been changed to explicitly free the TSS key when necessary. + +. On Win32 systems: detect thread termination via a hook in DLLMain + for ACE.dll. This allows cleanup of TSS objects for non-ACE threads + that use ACE functions. The most common case was threads that used + ACE logging. Formerly any TSS objects created by these threads would + be leaked. + +. Added support for GNU G++ 4.0. The x.4.5 beta takes advantage of + g++ 4.0's symbol visibility. This feature is conceptually similar + to MS Windows "__declspec(dllexport)" DLL functionality. Using this + new g++ feature results in substantially improved ACE/TAO/CIAO + shared library binaries. A subset of the improvements include the + following: + + * The number of unnecessarily exported DSO/DLL symbols is + greatly reduced, resulting in faster program start times. + * Smaller footprint. + * Improved performance since run-time indirection of internal + symbols is no longer needed. + + No changes to the ACE/TAO sources were necessary to support this + feature since the required visibility attributes were hidden behind + the various "*_Export" macros (formerly only useful for MS Windows + DLLs) used throughout ACE/TAO. + +. The ACE_Reactor destructor will now call close() on the referenced reactor + implementation. This assures that all handlers are notified before the + ACE_Reactor object that's most likely referenced in these handlers is + invalid. Although this should not be a user-visible change, it did catch + some ACE tests off guard destroying reactor implementations and ACE_Reactor + interfaces in the wrong order, so it may come up in the field as well. + When using dynamically allocated reactor implementations, do not destroy + the implementation object before the ACE_Reactor interface object. Use of + the ACE_Reactor constructor's delete_implementation argument (with a value + of 1) is recommended when dynamically allocating reactor implementations. + +. Improved performance of HTBP by not requiring a lookup of peer hostname. + +. Added new ACE_SizeCDR stream which allows one to calculate size of the + representation without writing anything. + +. Number of improvements in RMCast, reliable multicast implementation. + +USER VISIBLE CHANGES BETWEEN ACE-5.4.3 and ACE-5.4.4 +==================================================== + +. The ace-config script has been replaced by pkg-config metadata files + which are installed in ${prefix}/lib/pkgconfig by the automake build. + +. Remove ACE_OS::gets() implementation. While this ACE implementation + of gets() did not contain the security holes that all standard + gets() implementations have, keeping it around only serves to foster + confusion since (1) some may incorrectly assume that this + ACE-specific gets() implementation has the same holes as standard + ones, and (2) invoking it with a default size argument so that it + looks like a standard gets() call results in behavior that is + different from the standard. Use ACE_OS::fgets() instead. + +. Removed ACE_Unbounded_Set_Ex, this gave the false idea that it had + thread safe iterators. Use ACE_Unbounded_Set instead + +. Improved VxWorks support for static libraries. Shared libraries do cause + several known problems which will be fixed in the x.4.5 release. + +. Removed the usage of the ACE_x_cast macros, we are using the C++ casts + from now on. The ACE_x_cast macros are deprecated and will be removed + after the x.5.1 release + +. Some improvements in autoconf support; better detection of available + OS and compiler features. + +. Fixed bugs in ACE TSS emulation + +USER VISIBLE CHANGES BETWEEN ACE-5.4.2 and ACE-5.4.3 +==================================================== + +. Improved Cygwin 1.5.12 support, 90% of the tests now succeed + +. Improved OpenVMS support. + +. Added ability to use fltk with Cygwin/MinGW + +. Added ACE_INT64 that defines a native 64 bit type. + +. Added 'q' as usable specifier for ACE_Log_Msg to print out int64 bit number. + +. Added better support for Intel C++ compilers. + +. Improved HPUX support. + +. Added a new directory ("ACE_wrappers/protocols/ace") for new protocols + that are not directly components of ACE, but are relate to ACE and + defined a new protocol, HTBP (Hypertext Tunneling, Bidirectional + Protocol) providing ACE_Acceptor/Connector/Stream semantics over a + connection owned by an HTTP proxy. Test cases in + ACE_wrappers/tests/HTBP provide examples of use. + +. Performace enhancement in TP_Reactor's handle_timer_events method [Bug + 1971]. + +. Various changes to permit ACE to execute on HP NonStop platform (e.g + support for its pthreads version). + +. Updated HP NonStop configuration files (config-tandem-nsk). + +. The "ACE" pseudo-namespace is now a true C++ namespace. Transitional + pseudo-namespaces that were only meant to be used internally by ACE, + such as "ACE_Sock_Connect", no longer exist. + +. ACE_CDR::Boolean type is now a true C++ "bool" on all platforms except + MSVC++ 6. We plan to deprecate MSVC++ 6 support sometime after the + x.5 release of ACE+TAO+CIAO, so we recommend you start migrating to a + later version of MSVC++. + +. More GNU g++ 3.4.x fixes. + +. Added ICMP and "ping" socket support. + +. Added mkstemp() emulation. + +. Fixed problem on Linux < 2.5.47 platforms where equality comparison of + two logically equal sockaddr_in structure instances would incorrectly + fail. + +. Support for wide characters has been improved on non-Windows + platforms. + +. A number of Windows CE problems have been fixed. + +. ACE's loading of DLLs (for example, as a result of loading synamic + services) has been changed to use the native OS's facilities for + locating the DLL instead of searching LD_LIBRARY_PATH (or its + equivalent) then loading the DLL using a full pathname. This restores + enforcement of a platform's loading and security policy. To use the + old DLL locating method, add ACE_MUST_HELP_DLOPEN_SEARCH_PATH to your + config.h file before building ACE. + +. A number of errors in the APG example programs have been corrected. + +. Select_Reactor and Priority_Reactor performance improved. [Bug 1890] + +. Wide-char functionality on POSIX (Linux, etc.) + +. TSS memory leak fixes [Bug 1542] + +. Ported to HPUX 11i v2 on Itanium + +. Added code to ACE for platform RedHat AS 3.0 on Opteron. + +. Changed ACE::crc32() family of functions to NOT fold in the length of + the string/buffer/iovec into the CRC. + + +USER VISIBLE CHANGES BETWEEN ACE-5.4.1 and ACE-5.4.2 +==================================================== + +. Support for g++ 3.4.1. + +. All ACE Makefiles, project files, etc, are now generated by OCI's + "MakeProjectCreator" (MPC) tool. Makefiles and project files for + commonly used configurations have been pre-generated and distributed + with the beta(s). Please see: + + $ACE_ROOT/ACE-INSTALL.html + + for information on how to use MPC with ACE. + +. Improved Doxygen documentation. + +. Reduced header file dependencies, which should speedup compilation + and help minimize static footprint. + +. ACE now requires support for the following standard C++ features: + + - "bool" keyword + + - "mutable" keyword + + - "explicit" keyword + + - C++ casts (e.g. static_cast<>, reinterpret_cast<>, dynamic_cast<> + and const_cast<>) + + If you're using a compiler that does NOT support these features + please contact Steve Huston for support. + +. Changed the select()-based reactor implementations to scan for + broken handles to remove based on the registered handles, not on + event handlers. This allows for bad handles to be removed from the + reactor even if the event handler doesn't implement get_handle() the + way we expect. + +. Support for Pthreads native recursive mutexes was added. This + capability is specified to ACE_OS::mutex_init() as an optional + argument, lock_type. To fix confusion from an earlier attempt to add + this functionality, the meaning of the old 'type' argument to + ACE_OS::thread_mutex_init() is changed. It previously combined the + scope and type. Now it is just the type (e.g. recursive), as the + scope is inherent in the method used. For clarification on + ACE_HAS_RECURSIVE_MUTEXES, it means that the platform is capable of + them, not that they always are, as one would expect. However, before + Pthreads had recursion added, it was never optional. Now it is. + +. Initial support for new Linux sys_epoll() interface in + Dev_Poll_Reactor. The obsolete Linux /dev/epoll interface is no + longer supported. + +. Improved Cygwin support. + - Threading works without problems. + - Problems with shared memory, process shared mutexes, multicast and + some other small things still exist. + +. New OpenVMS port. + - This is for the latest version of OpenVMS with all available ECOs + applied. Basic stuff works without problems. Advanced features + still need some work. + +. Usage of ASYS_INLINE is deprecated in ACE. Use ACE_INLINE instead. + +. All inline source files now end in ".inl". The previous ".i" + extension is generally used for preprocessed C sources. + +. Autoconf support has been improved and fixed on a number of + platforms, including the BSD variants (e.g. FreeBSD). It is still + not the preferred way to configure most platforms, but it is ready + for wider testing. Please report any problems found to + ace-bugs@cs.wustl.edu. + +. A number of fixes were made to quiet compile errors and warnings on + 64-bit Windows. + +. For builds on AIX using Visual Age C++, the make rtti option default + was changed to 1, enabling RTTI by default. + +. ACE_Service_Repository::remove() has a new, optional argument that + can receive the service record pointer for the removed service. If + the pointer is returned to the caller, it is not deleted. If the + pointer is not returned to the caller (the default) it is deleted + (this is the historic behavior). + +. The tutorials in ACE_wrappers/docs have been removed. They were not + being maintained and caused confusion in a number of cases. Now that + there are complete examples that match the printed books (C++NPv1, + C++NPv2, APG), the older tutorials are no longer useful. Please see + + $ACE_ROOT/examples/C++NPv1/ + $ACE_ROOT/examples/C++NPv2/ + $ACE_ROOT/examples/APG/ + + for the source code of the examples in those books. + +. ACE_String_Base::fast_clear() is a new method which sets the string + length to 0. Doesn't release string-allocated memory, but if the + memory was externally supplied, it is no longer referenced from the + string object. + +. A true C++ "bool" is now used as the CDR stream boolean type, if + supported by the compiler. + +. Renamed AIX 5L configuration header from config-aix5.1.h to + config-aix-5.x.h. + +. All C++ equality, relational and logical operators now return bool + instead of int, as is the norm for modern C++. + +. Added new ACE_OS::realpath() implementation. Contributed by Olli + Savia + + +USER VISIBLE CHANGES BETWEEN ACE-5.4 and ACE-5.4.1 +==================================================== + +ACE +--- + +. Fixed "make install" support in ACE+autoconf configurations. + +. Fixed autoconf support on Solaris. + +. Corrected invalid `aux' directory (on MS Windows) found in ACE + distribution. + +. ACE/TAO build now without problems with MinGW and all ACE tests run + now without problems + +. Added some more support for the new CBuilderX Preview compiler, this + is not 100% ready yet because the compiler is still a preview and + has its own problems. + +. Added Visual SlickEdit 8.1 MPC template + +. Added workaround for compile problems in Borland Release builds + +. Cygwin 1.5.9 is now supported + +. Tests for IPV6 have been added + +. Implement lstat() so that it'll use stat() on platforms that don't + support lstat(). + +. Problems related to ACE_Event_Handler usage in WFMO_Reactor was + fixed. + +. A wrapper for rmdir () has been added. + +. Threads spawned in thread-per-connection mode never inherited the + priority. This problem was fixed and this fix is consistent with the + C++ NPV* books. + +. Fixed memory leaks with ACE_String_Base::resize () + +. Enable the usage of native recursive mutexes for the implementation + of ACE recursive mutexes on Linux. + +. The ACE Proactor framework can now be enabled for AIX 5.2. Since AIO + functionality is not run-time enabled by default on AIX 5.2, the ACE + Proactor code is not built by default on AIX. To enable it, the + config.h file must contain #define ACE_HAS_AIO_CALLS before + including the config-aix-5.1.h file. + +. The ACE_POSIX_CB_Proactor implementation is now built on all + platforms except LynxOS. + + +USER VISIBLE CHANGES BETWEEN ACE-5.3.6 and ACE-5.4 +================================================== + +ACE: +--- +. Added a new makefile commandline flag, static_link, that can be + used to force static linking when static_libs_only is turned on. It + uses the new STATIC_LINK_FLAG variable and is currently only + implemented for for GNU ld, i.e., it adds the "-static" option to + LDFLAGS. It's turned off by default since using it causes the + footprint to go up by almost 1 MB on Linux, since it links all the + system and compiler .a files, but can be turned on if users + want/need to use it, by enabling both static_libs_only and static_link. + + +. Added macros ACE_USES_GPROF which enables users to use gprof in a + multithreaded environment with ACE libs. + +. Added a new functor template class, ACE_Malloc_Lock_Adapter_T, + that's used by ACE_Malloc_T as a factory for the ACE_LOCK template + parameter, and allows the use of locking strategy classes, like + ACE_Process_Semaphore and ACE_Thread_Semaphore that don't have a + satisfactory ctor taking a single required ACE_TCHAR* parameter, to + be adapted to work with ACE_Malloc_T. + +. The source code examples from "The ACE Programmer's Guide" book by + Huston, Syyid, and Johnston, are now located in + $ACE_ROOT/examples/APG. + +. Support for GNU autoconf is now in ACE. Please see ACE-INSTALL.html + for details. + +. Fixed problems that prevented ACE from being compiled on LynxOS + 4.0.0. + +. Fixed compilation error which prevented ACE from being compiled when + ACE_COMPILE_TIMEPROBES was set to 1. + +. Preliminary support for Tandem NSK has been added. + +. Lots of bug fixes with TLI and XPG5. Please see $ACE_ROOT/ChangeLog + for details. + +. Fixed ACE_OS::event_timedwait() and ACE_OS::event_wait() so that + they use a while loop around the ACE_OS::cond_[timed]wait() calls to + avoid problems with spurious wakeups, etc. + +. ACE's wrapper around getipnodebyname() and getipnodebyaddr () has + been made go through the IPv4-only case on ACE_WIN32. Since Windows + IPv6 implementation doesn't offer support (at thistime) for + getipnodebyname() the code has been changed to use the IPV4 part of + the code. + +. Install with Borland C++ of ACE library fixed + +ACEXML: +------- + +. Fixed memory leak in ACEXML parser. + +. Fixed implementations of rewind() in all the CharStreams. They were + broken previously. + +. Fixed bugs in the parser associated with incorrect handling of PE + References for keywords. diff --git a/dep/acelite/PROBLEM-REPORT-FORM b/dep/acelite/PROBLEM-REPORT-FORM new file mode 100644 index 000000000..139fa83ad --- /dev/null +++ b/dep/acelite/PROBLEM-REPORT-FORM @@ -0,0 +1,87 @@ +[Please use the PRF form below to submit bug reports, problem reports, + etc., to the ACE developers and interested users. Send it to + ace-bugs@list.isis.vanderbilt.edu, you must be subscribed to the list + in order to be able to post to it. If you are using OCI, PrismTech, or + Riverace's versions of ACE do not send bugs to this mailing list, but + instead contact those companies for support. Please also send your + PRF as plain ASCII text, _not_ uuencoded or as an attachment. + + We prefer that all bug reports be submitted through our bug tracking + system. See $ACE_ROOT/docs/usage-bugzilla.html for more information + about how to do this. If you are unsure as to whether your problem + is a real bug or not then please submit your question to the mailing + list using the following form. Not using the problem report form + will make it harder or impossible to identify the problem, and in + many cases we will be unable to help at all. Also please try to + browse bugzilla and the ChangeLog files to find out if your problem + has been solved in a more recent version of ACE. + + To subscribe to the list see + http://www.dre.vanderbilt.edu/~schmidt/ACE-mail.html + + Replace/remove all the explanatory text in brackets before mailing. + + Please send this form as ASCII text only. Do _not_ send it as an + attachment, or as tar'ed, compressed and/or uuencoded text. And + limit line lengths to less than 80 characters. + + PLEASE make your Subject: line as descriptive as possible. + Subjects like "ACE bug" or "bug report" are not helpful! + Also, do _not_ include the word "help" in the Subject!] + + When including your config.h and platform_macros.GNU files as requested + below, only include the contents if you use the recommended method of + including the platform-specific file in your file. If you use a link + to the platform-specific file, simply state which one - DO NOT + include an entire platform-specific configuration file in the form. + +8<----------8<----------8<----------8<----------8<----------8<----------8<---- + +To: ace-bugs@list.isis.vanderbilt.edu +Subject: [area]: [synopsis] + + ACE VERSION: 6.3.0 + + HOST MACHINE and OPERATING SYSTEM: + If on Windows based OS's, which version of WINSOCK do you + use?: + + TARGET MACHINE and OPERATING SYSTEM, if different from HOST: + COMPILER NAME AND VERSION (AND PATCHLEVEL): + + THE $ACE_ROOT/ace/config.h FILE [if you use a link to a platform- + specific file, simply state which one]: + + THE $ACE_ROOT/include/makeinclude/platform_macros.GNU FILE [if you + use a link to a platform-specific file, simply state which one + (unless this isn't used in this case, e.g., with Microsoft Visual + C++)]: + + CONTENTS OF $ACE_ROOT/bin/MakeProjectCreator/config/default.features + (used by MPC when you generate your own makefiles): + + AREA/CLASS/EXAMPLE AFFECTED: +[What example failed? What module failed to compile?] + + DOES THE PROBLEM AFFECT: + COMPILATION? + LINKING? + On Unix systems, did you run make realclean first? + EXECUTION? + OTHER (please specify)? +[Please indicate whether ACE, your application, or both are affected.] + + SYNOPSIS: +[Brief description of the problem] + + DESCRIPTION: +[Detailed description of problem. Don't just say " +doesn't work, here's a fix," explain what your program does +to get to the state. ] + + REPEAT BY: +[What you did to get the error; include test program or session +transcript if at all possible. ] + + SAMPLE FIX/WORKAROUND: +[If available ] diff --git a/dep/acelite/README b/dep/acelite/README new file mode 100644 index 000000000..fe9a7d2d9 --- /dev/null +++ b/dep/acelite/README @@ -0,0 +1,222 @@ +$Id: README 96983 2013-04-11 11:14:11Z schmidt $ + +This document is also available at the following URL: + +http://www.dre.vanderbilt.edu/~schmidt/ACE.html + +All software and documentation is available via both anonymous ftp and +the http.] + +THE ADAPTIVE COMMUNICATION ENVIRONMENT (ACE) + +An Object-Oriented Network Programming Toolkit + +---------------------------------------- + +Overview of ACE + +The ADAPTIVE Communication Environment (ACE) is an object-oriented +(OO) toolkit that implements fundamental design patterns for +communication software. ACE provides a rich set of reusable C++ +wrappers and frameworks that perform common communication software +tasks across a range of OS platforms, including Win32/Win64, most +versions of UNIX (e.g., SunOS, HP-UX , AIX, Linux, NetBSD, and FreeBSD), +real-time operating systems (e.g., VxWorks, Chorus, LynxOS, and QNX), +OpenVMS, and MVS OpenEdition. A single source tree is used for all +these platforms and porting ACE to other platforms is relatively easy. + +The communication software components provided by ACE include event +demultiplexing and event handler dispatching, service initialization, +interprocess communication, shared memory management, message routing, +dynamic (re)configuration of distributed services, multi-threading, +and concurrency control. There are both C++ and Java versions of ACE +available. + +ACE is targeted for developers of high-performance and real-time +communication services and applications on UNIX, POSIX, and Win32 +platforms. ACE simplifies the development of OO network applications +and services that utilize interprocess communication, event +demultiplexing, explicit dynamic linking, and concurrency. ACE +automates system configuration and reconfiguration by dynamically +linking services into applications at run-time and executing these +services in one or more processes or threads. + +ACE is currently used in commercial projects and products by dozens of +companies including Ericsson, Bellcore, Siemens, Motorola, Kodak, +Boeing, Lucent, DEC, Lockheed Martin, and SAIC. Commercial support +for ACE is available from several companies as listed at +http://www.cs.wustl.edu/~schmidt/commercial-support.html + +---------------------------------------- + +C++ Wrappers for OS Interfaces + +The lower-level portions of ACE provide a set of portable and +type-secure C++ wrappers that encapsulate the following C language OS +interfaces: + + . IPC mechanisms + -- e.g., Internet- and UNIX-domain sockets, TLI, Named + Pipes (for UNIX and Win32) and STREAM pipes; + + . Event demultiplexing + -- e.g., select(), poll(), and Win32 + WaitForMultipleObjects and I/O completion ports; + + . Multi-threading and synchronization + -- e.g., Solaris threads, POSIX Pthreads, and Win32 + threads; + + . Explicit dynamic linking + -- e.g., dlopen/dlsym on UNIX and LoadLibrary/GetProc + on Win32; + + . Memory-mapped files and shared memory management + -- e.g., BSD mmap(), SYSV shared memory, and Win32 + shared memory; + + . System V IPC + -- e.g., shared memory, semaphores, message queues. + +The OS Adaptation Layer shields the upper levels of ACE from platform +dependencies associated with the underlying OS interfaces. + +---------------------------------------- + +Frameworks and Class Categories + +ACE also contains a higher-level network programming framework that +integrates and enhances the lower-level C++ wrappers. This framework +supports the dynamic configuration of concurrent distributed services +into applications. The framework portion of ACE contains the +following class categories: + + . The Reactor + -- Supports both Reactive and Proactive I/O; + + . The Service Configurator + -- Support dynamic (re)configuration of objects; + + . The ADAPTIVE Service Executive + -- A user-level implementation of System V STREAMS, + that supports modular integration of + hierarchically-related communicaion services; + + . Concurrency + -- Various types of higher-level concurrency + control and synchronization patterns (such as + Polymorphic Futures and Active Objects); + + . Shared Malloc + -- Components for managing dynamically allocation + of shared and local memory; + +---------------------------------------- + +Distributed Services and Components + +Finally, ACE provides a standard library of distributed services that +are packaged as components. These service components play two roles +in ACE: + + 1. They provide reusable components for common distributed + system tasks such as logging, naming, locking, and time + synchronization. + + 2. They illustrate how to utilize ACE features such as the + Reactor, Service Configurator, Service Initialization, + Concurrency, and IPC components. + +---------------------------------------- + +Middleware Applications + +ACE has been used in research and development projects at many +universities and companies. For instance, it has been used to build +avionics systems at Boeing, telecommunication systems at Bellcore, +Ericsson, Motorola, and Lucent; medical imaging systems at Siemens and +Kodak; and many academic research projects. Two example middleware +applications provided with the ACE release include: + + 1. The ACE ORB (TAO) -- TAO is a real-time implementation of + CORBA built using the framework components and patterns + provided by ACE. + + 2. JAWS -- JAWS is a high-performance, adaptive Web server + built using the components in ACE. + +---------------------------------------- + +OBTAINING ACE + +ACE may be obtained electronically from +http://download.dre.vanderbilt.edu. This release contains the source +code, test drivers, and example applications (including JAWS) for C++ +wrapper libraries and the higher-level ACE network programming +framework developed as part of the ADAPTIVE project at the University +of California, Irvine, Washington University, St. Louis, and +Vanderbilt University. + +You can get The ACE ORB (TAO) in a companion release at the same URL. + +---------------------------------------- + +ACE DOCUMENTATION AND TUTORIALS + +Many of the C++ wrappers and higher-level components have been +described in issues of the C++ Report, as well as in proceedings of +many journals, conferences, and workshops. + +A collection of white papers and tutorial handouts are included at + +http://www.dre.vanderbilt.edu/~schmidt/ACE-papers.html + +This page contains PDF versions of various papers that describe +different aspects of ACE. + +This material is also available available via the WWW at URL: + +http://www.dre.vanderbilt.edu/~schmidt/ACE.html + +---------------------------------------- + +ACE MAILING LIST AND NEWSGROUP + +A mailing list, ace-users@list.isis.vanderbilt.edu, is available for +discussing bug fixes, enhancements, and porting issues regarding ACE. +Please send mail to me at the +ace-users-request@list.isis.vanderbilt.edu if you'd like to join the +mailing list. There is also a USENET newsgroup called +comp.soft-sys.ace. Please see +http://www.dre.vanderbilt.edu/~schmidt/ACE-mail.html for details on +how to subscribe to the mailing list. + +---------------------------------------- + +BUILDING AND INSTALLING ACE + +Please refer to the +http://www.dre.vanderbilt.edu/~schmidt/ACE-install.html file for +information on how to build and test the ACE wrappers. The +BIBLIOGRAPHY file contains information on where to obtain articles +that describe the ACE wrappers and the ADAPTIVE system in more detail. + +The current release has been tested extensively, but if you find any +bugs, please report them to the ACE mailing list +ace-users@list.isis.vanderbilt.edu using the +$ACE_ROOT/PROBLEM-REPORT-FORM. Please use the same form to submit +questions, comments, etc. To ensure that you see responses, please do +one of the following: + + 1) Subscribe to the ace-users mail list, by sending email with + contents "subscribe ace-users" to + ace-users-request@list.isis.vanderbilt.edu. + + 2) Or, monitor the comp.soft-sys.ace newsgroup for responses. + +---------------------------------------- + +ACKNOWLEDGEMENTS + +Please see the file `$ACE_ROOT/THANKS' for a list of the thousands of +people who've contributed to ACE and TAO over the years. diff --git a/dep/acelite/THANKS b/dep/acelite/THANKS new file mode 100644 index 000000000..360df16d7 --- /dev/null +++ b/dep/acelite/THANKS @@ -0,0 +1,2422 @@ +ACKNOWLEDGEMENTS + +ACE, TAO, CIAO, and DAnCE have been deeply influenced and improved by the +following members of my research group at Washington University in St. Louis, +the University of California at Irvine, and Vanderbilt University in Nashville. + +Everett Anderson +Alexander Babu Arulanthu +Shawn Atkins +Jaiganesh Balasubramanian +Krishnakumar Balasubramanian +Matt Braun +Darrell Brunsch +Dante J. Cannarozzi +Sharath R. Cholleti +Chris Cleeland +Angelo Corsaro +Gan Deng +Mayur Deshpande +Eric Ding +George Edwards +Sergio Flores-Gaitan +Chris Gill +Andrew G. Gilpin +Aniruddha Gokhale +Priyanka Gontla +Pradeep Gore +Matthew P. Hampton +Tim Harrison +John Heitmann +James Hill +Shawn Hannan +Don Hinton +Joe Hoffert +James Hu +Huang-Ming Huang +Frank A. Hunleth +Prashant Jain +Shanshan Jiang +Vishal Kachroo +Michael Kircher +Boris Kolpackov +Arvind S. Krishna +Yamuna Krishnamurthy +Fred Kuhns +David Levine +Tao Lu +Mike Moran +Sumedh Mungee +Balachandran Natarajan +Will Otte +Kirthika Parameswaran +Krishnakumar Pathayapura +Stoyan Paunov +Carlos O'Ryan +Ossama Othman +Jeff Parsons +Irfan Pyarali +Nilabja Roy +Lucas Seibert +Diego Sevilla Ruiz +Nishanth Shankaran +Marina Spivak +Venkita Subramonian +Nagarajan Surendran +Cassia Tatibana +Sumant Tambe +Gabriele Trombetti +Emre Turkay +Nanbor Wang +Seth Widoff +Jules White +Friedhelm Wolf +Torben Worm +Ming Xiong + +I would also like to thank all the following people who have also +contributed to ACE, TAO, CIAO, and DAnCE over the years: + +Paul Stephenson +Olaf Kruger +Ed Brown +Lee Baker +Alex Ranous +Mark Patton +Steffen Winther Sorensen +Troy Warner +Stacy Mahlon +Charles Eads +Mark Frutig +Todd Hoff +George +Brad Needham +Leslee Xu +Detlef Becker +Bruce Worden +Chris Tarr +Bill Sears +Greg Lavender +Steve Warwick +Mats Sundvall +Andreas Ueltschi +Nigel Hooke +Medhi Tabatabai +Stuart Powell +Bin Mu +Andrew McGowan +Ken Konecki +John P. Hearn +Giang Hoang Nguyen +Carlos Garcia Braschi +Jam Hamidi +Eric Vaughan +Karlheinz Dorn +Gerhard Lenzer +Steve Ritter +Chandra Venkatapathy +Matt Stevens +Bob Vistica +David Trumble +George Reynolds +Hans Rohnert +Alex V. Maclinovsky +Todd Blanchard +Rob Clairmont +Christian Millour +Neil B. Cohen +Dieter Quehl +Reginald S. Perry +James Morris +Mark Seaborn +Phil Brooks +E. Jason Scheck +Daniel Proulx +Bill Tang +John Huchinson +Jack Erickson +Byron Walton +Bill Lear +Mark Zusman +Aurelio Nocerino +Walt Akers +Greg Baker +Alexandre Karev +Pramod Kumar Singh +Bryon Rigg +Brad Brown +Patty Genualdi +Eshel Liran +Mick Adams +Chris Eich +Mike Flinn +Audun Tornquist +Sandeep Joshi +Bernd Hofner +Craig Perras +Kirk Sinnard +Matthew Newhook +Gerolf Wendland +Phil Mesnier +Ross Dargahi +Richard Orr +Rich Ryan +Jan Rychter +Tom Marrs <0002104588 at mcimail dot com> +Bob Olson +Jean-Francois Ripouteau +Ajit Sagar +Ashish Singhai +David Sames +Gonzalo Diethelm +Raj +Darrin Edelman +Steve Weismuller +Eric C. Newton +Andres Kruse +Ramesh Nagabushnam +Antonio Tortorici +Nigel Lowe +Tom Leith +Michael Fortinsky +Marco Sommerau +Gary Salsbery +Eric Beser +Alfred Keller +John Lu +James Mansion +Jesper S. M|ller +Chris Lahey +Michael R"uger +Istvan Buki +Greg Wilson +Garrett Conaty +Brad Flood +Marius Kjeldahl +Steve Huston +Eugene K. Plaude +Joseph DeAngelis +Kim Gillies +Luca Priorelli +Alan Stewart +Hani Yakan +William L. Gerecke +Craig Johnston +Pierre-Yves Duval +Rochi Febo Dommarco +Jonathan Biggar +Scott Shupe +Chuck Gehr +Avi Nash +Padhu Ramalingam +Jay Denkberg +Ayman Farahat +Tilo Christ +rev +Hamutal Yanay +Vital Aza +Alex Villazon +David Artus +Todd Barkalow +Alexander Smundak +Thilo Kielmann +Matthias Kerkhoff +Fred LaBar +Hanan Herzog +Eric Parker +James Michael Dwyer +Arun Katkere +Bob Dunmire +Sandro Doro +Robert Lyng +Phil Logan +John Cosby +Wayne Vucenic +Harry Gunnarsson +James CE Johnson +Samuel_Bercovici +Per Andersson +Anthony McConnell +Mark Rabotnikov +John Bossom +Rino Simioni +Slawomir Kuzniar +Rob Jordan +Michael Maxie +John Cosby +Nigel Owen +Jorn Jensen +Paul Roman +Dave Mayerhoefer +Bert Craytor +Joey Zhu +Arthur J. Lewis +Michael R. MacFaden +Paul Han +Jeff Morgan +Arturo Montes +Elliot Lau +Mark Wright +Michael Newton +Kumar Neelakantan +Scott Halstead +Jean-Marc Strauss +Adam Porter +Hakan Kallberg +Eric Dean Russell +Daniel Montalibet +Norbert Rapp +Ganesh Pai +Berni Merkle +Tom Wright +Torbjorn Lindgren +Mike Bernat +Brian Mendel +Jeremy Buch +Kevin Boyle +Kevin Martindale +Luis Lopes +Adrian Salt +Hongbo Xu +Michael Hartman +Tom Dobridge +Rich Christy +Satoshi Ueno +Eugene R. Somdahl +Robert Head +Ivan Murphy +Jan Perman +Shankar Krishnamoorthy +Reza Roodsari +Jim Crossley +Johannes Gutleber +Yigong Liu +Erik Urdang +Mike Schweiger +Anthony Mutiso +Jeff R. Hayes +David Brackman +Dave Moore +Joseph Cross +Cherif Sleiman +Stefan Ericsson +Thanh Ma +Oleg Krivosheev +Stephen Coy +Bob Laferriere +Satheesh Kumar MG +Karen Amestoy +Jeff Richard +Samuel Melamed +Vladimir Schipunov +Felix Popp +Billy Quinn +Michael McKnight +Huiying Shen +Alex Chan +Aaron Valdivia +Edan Ayal +Jeffrey Peterson +Neil Lavelle +Steven Wohlever +Manojkumar Acharya +Evgeny Beskrovny +Kirill Rybaltchenko +Laura Paterno +Ben Eng +Mike Kamrad +Marios Zikos +Mark L Boriack +Mark Hyett +Valik Solrzano Barboza +John Connett +Tom Arbuckle +Stephen Henry +Dani Flexer +Michael Hoffman +John Lindal +Dustin Laurence +Ernie Makris +Timothy A. Brown +Pat McNerthney +Lori Anderson +Erik Margraf +Bryan Doerr +Adam Miller +Thomas Jordan +Keith Nicewarner +Frederic Andres +Achint Sandhu +Mitch Kuninsky +Alex Chan +Jeff Hellzen +Thomas Venturella +Philippe O'Reilly +Stan Leeson +Richard Keizer +Edgar Villanueva +Oliver Kellogg +Dave Meyer +Thomas Hampson +Jay Kistler +Scott Snyder +Mark Evans +Todd Pack +Mark Maris +Jason Katz +Jim Penny +Chris Ryan +J dot Russell Noseworthy +Carol Sanders +Jerry Bickle +Paul von Behren +Sudish Joseph +Loren Rittle +Alexander Ovsiankin +Ravi Nagabhyru +Tom Brusehaver +Dave Tallman +Monish Rajpal +Garry Brother +Andreas Schuelke +Ganapathi +James Garrison +Brad Walton +Paul Motuzenko +Kurt Sussman +Rob Thornton +Chanaka Liyanaarachchi +Saneyasu +Steve Kay +Greg White +Ki-hyun Yoon +Umar Syyid +Bill Fulton +Amancio Hasty +Zoran Ivanovic +Sree Oggu +James Risinger +Leo Modica +Bob Scott +Mark Kettner +Kent Watsen +Chris Healey +Philippe Klein +William S. Lear +John Geiss +Ernesto Guisado +Stuart Myles +Lothar Werzinger +Andrew Harbick +Pavel Motuzenko +Ross J. Lillie +Sam Hauer +Frank J. Hodum +David Miron +Anton van Straaten +Joe Covalesky +Bill Backstrom +Jeff Franks +John Mulhern <9107 at mn3 dot lawson dot lawson dot com> +Johan Lundin +Eric Powers +Gabriel Lima +Doug Anderson +Hongyin Quan +Maximilian Hoferer +Kevin Stanley +Jeff Greif +Jeff McDaniel +Andreas Geisler +Bob McWhirter +Daniel Winder +Zheng Han +Christa Schwanninger +Byron Harris +Barney Dalton +Peter Gorgia +Dirk Broer +Joseph E. LaPrade +Goran Lowkrantz +Susan Liebeskind +Dana Hackman +Margherita Vittone Wiersma +Priya Narasimhan +Jeff Hopper +Mats Nilsson +Dongwook Kim +Don Davis +Alberto Villarica +XuYifeng +Tom Shields +Krishna Padmasola +Andre Folkers +Paul Sexton +Marc Lehmann +Anne Blankert +Raja Ati +Clinton Carr +Peter Liqun Na +Frank Adcock +Xu Yifeng +Valery Arkhangorodsky +Alan Scheinine +Andrew G. Harvey +Dann Corbit +James +Jason Milley +Ulf Jaehrig +Peter Nordlund +Mark Weel +Tres Seaver +Erik Koerber +Eric R. Medley +David O'Farrell +Amir Bahmanyari +Ian Wright +David Janello +Rich Wellner +Fernando D. Mato Mira +Jonathan Reis +Seung-Lee Hoon +Russell L. Carter +Bill Hall +Brian Gilstrap +Balaji Srinivasan +Anders W. Tell +Larry Lachman +Terry Rosenbaum +Rainer Blome +Kirk Ellett +Sunil Kumar +T Stach +Ron Barack +Daniel Nieten +Paul K. Fisher +Jim Buck +Olivier Lau +Achim Stindt +Fredrik Lindahl +Joseph Weihs +Serge Kolgan +James Megquier +Martin Krumpolec +Michael Thomas +Vicentini Emanuele +Bob Price +Ramiro Penataro Blanco +Sigg Pascal +Ivan Leong +Virginie Amar +Tom Ziomek +Hamish Friedlander +Mark De Jong +Knut Johannessen +Leif Jakobsmeier +Jon Lindgren +Steve Vinoski +Christian Mueffling +Victor Yu +Jeff Donner +Joe Loyall +Stanislav Meduna +Christian Korn +Ron Barack +Steve Totten +Faron Dutton +Gary York +Patty Hair +Ivan Pascal +William A. Hoffman +Mark Lucovsky +Greg Holtmeyer +Jody Hagins +Patrice Bensoussan +Keith Brown +Barry Hoggard +Peter J. Mason +Jerry D. De Master +Greg Gallant +wym +Karel Zuiderveld +Mike Goldman +Peter Gross +Greg Ross +Stanford S. Guillory +Peter Weat +Magnus Karlsson +Andreas Tobler +John Aughey +Knut-Havard Aksnes +Eric Mitchell +Tommy Andreasen +Slava Galperin +Jeff Olszewski +Sudhanshu Garg +Mike Preradovic +Greg Harrison +Sangwoo Jin +Jacques Salerian +Steve Coleman +Diethard Ohrt +Jacob Jones +Phil Ruelle +Sush Bankapura +Eric Covington +Darren Whobrey +Mason Taube +Rod Joseph +Hans Horsmann +Kevin Royalty +Souhad Mcheik +Mark Little +Tim Stack +Marc Engel +Uma Markandu +Henrik Nordberg +Tad Jarosinski +Andy Marchewka +Neal Norwitz +Frederic Maria +David Hooker +Christian Destor +Andrew Hobson +Andre Folkers +Torsten Kuepper +Hao Ruan +Alexander Davidovich +Cristian Ferretti +N Becker +Yaolong Lan +Elias Sreih +Liang Chen +Mark Laffoon +Ti Z +Brian Dance +Alexey Gadzhiev +Francois Bernier +Bill Rizzi +Peter Windle +Jaepil Kim +Dmitry Goldshtain +Carl Grinstead +Henric Jungheim +Michael Preobrazhensky +Gregory D. Fee +Roland Gigler +Frank Buschmann +Eric Eide +Don Busch +Thomas Lockhart +David Hauck +Keith Rohrer +Tim Rose +Sam Rhine +Chris Schleicher +Margaret Reitz +Thomas Mehrkam +Erik Ivanenko +Sarmeesha Reddy +Steven Tine +Dave Steele +Simeon Simeonov +David H. Whittington +Ian MacDonald +Hans Ridder +Todd Mullanix +Hai Vu +Paul Francis +Kristopher Johnson +Dave Butenhof +Dominic Williams +Srikumar Kareti +Ian Pepper +Kevin Lyda +James D. Rucker +Brian Wallis +Sandeep Goyal +English Malc +Frank O'Dwyer +Long Hoang +Steven D. Chen +Alain Magloire +Jim Rogers +Nick Sawadsky +David Brownell +Richard Stallman +Casey Lucas +Brian C. Olson +Joseph A. Condlin +Serge Du +Mike Mazurek +Christian Schuderer +John R. Taylor +Bill Tovrea +Wallace Owen +Vyacheslav A. Batenin +Edwin D. Windes +Christopher Kohlhoff +Andreas Terstegge +Stefaan Kiebooms +Keith Nichol +Rebecca Sanford +Ram Vishnuvajjala +Tom Bradley +Shaun Ohagan +Dale Wood +Robert Flanders +Gul Onural +Stephen E Blake +Eric S Rosenthal +Sridevi Subramanian +Bruce Trask +Jake Hamby +Rick Weisner +Dennis C. De Mars +V dot Lakshmanan +Hata Yoshiaki +Vidya Narayanan +Sean Landis +Youzhong Liu +John Weald +Gilbert Roulot +Gildo Medeiros Junior +Brian Peterson +Fabrice Podlyski +Darren DeRidder +John Tucker +Oleg Orlov +Timothy Canham +Randy Heiland +Joyce Fu +Surender Kumar +Pradeep Avasthi +Guicheney Christophe +Madhu Konety +Isaac Stoddard +Alvarez +Peter Brandstrom +Eugene Surovegin +Thaddeus Olczyk +John Chludzinski +Pedro Alves Ferreira +Bruce Edge +Dan Butler +Ron MacKenzie +Craig Rodrigues +Phil Y. Wang +David Brock +John Morey +Dwayne Burns +Denis Ouellet +Stefan Ullrich +Brian Raven +Gheorghe Aprotosoaie +Carsten Zerbst +Paul Calabrese +Stephane Chatre +James Whitledge +Erik Johannes +Alex Hornby +Riaz Syed +Clarence M. Weaver +Roger Egbers +Ralf Kluthe +Ruud Diterwich +Bill Nesbitt +Will Skunk +David Digby +Timothy Schimke +Jim Robinson +Peter Mueller +Raghu Nambiath +Mike Gingell +David McCann +Ruediger Franke +Brian Jones +Michael Garvin +Mike Vitalo +Kirk Davies +Arno Pernozzoli +Trey Grubbs +Matthias Schumann +John Gathright +Alexander Villatora +Hoang Duong +Michael Roth +Craig Anderson +Mitsuhiko Hara +Weihai Yu +Tal Lev-Ami +Chris Zimman +Rick Wesson +Sridhara Rao Dasu +Walter Welzel +Anthony Shipman +Tobin Bergen-Hill +Toshio Hori +John Mink +Duane Binder +Randall Sharo +Dave Madden +Cliff_H_Campbell +Narendra Ravi +Krishnakumar B. +David Sunwall +Brian Wright +Yosi Sarusi +Robert Shewan +Skye Sweeney +Lars Immisch +Stefan Wendt +Herbert +Clarence Bishop +Giga Giguashvili +Philipp Slusallek +Matthew Davis +Janusz Stopa +Rusty Conover +Phillippe Merle +Mark Winrock +Boris Kaminer +Martin Botzler +Lorin Hochstein +Wenli Bai +Harry Forry +Jose Rubio +Joerg Pommnitz +Mogens Hansen +Shafiek Savahl +Pierre Grondin +John Masiyowski +Uwe Landrock +Klaus Banzer +Probal Bhattacharjya +Dmitri Katchalov +Alok Gupta +Chien Yueh +John K. Black +Kamen Penev +Gregory Yarmit +Jarek Tomaszewski +Siegurd Weber +Fabrizio Giannotti +Harald Finster +Fritz Bosch +Charles Frasch +Chris Hafey +Rick Hess +David Dunn +Jaymes Galvin +Marat +Sergey Nemanov +Vladimir Kondratiev +John Glynn +Raymond Wiker +Michael Pitman +Joseph Jefferson +Engelbert Staller +George Ball +Dennis Noll +Ronald Fischer +Marvin Allen Wolfthal +Dan Gilboa +Sean Boudreau +Shalini Yajnik +Matt Thompson +Peter C Chien +Bruce Alderson +Christoph Poggemann +Travis Shirk +Alain Sauron +David Delano +Boris Sukholitko +Brian Mason +Thomas Groth +Damien Dufour +Paulo Breda Vieira +Samuel Stickland +Bryan Van de Ven +Greg Siebers +Rob Gabbot +Paul Carreiro +Jovan Kilibarda +Derek Dominish +Devesh Kothari +Stephen Moon +Hani Mawlawi +Benedikt Eric Heinen +Jason Topaz +Alexander Dergatch +Airat A. Sadreev +Klaus Hofmann +Miroslav Koncar +Extern Chatterji +Zach Frey +Ruibiao Qiu +Marcelo Matus +R Seshardi +Stephan Kulow +Alexander Belopolsky +Ben Bourner +Lalitha Chinthamani +Thomas Huang +Sankaranarayanan K. V +Ephraim Vider +Reid Spencer +Kevin Dalley +Jan Nielsen +Jochen Linkohr +Mirko Brandner +Yuval Yosef +Chad Elliott +David X. Callaway +Soren Ilsoe +Eric Hopper +Martin Johnson +Pierre Oberson +Chris Uzdavinis +Ishay Green +Andrey Nechypurenko +Charlie Duke +Jonathan Luellen +Andrew Psaltis +Erik Jones +Ted Burghart +Mike Winter +Judy Ward +Ken Block +Jamshid Afshar +Jerry Jiang +Rob Ruff +Hugh Arnold +Hessel Idzenga +Mark C. Barnes +Suresh Kannan +Alex Scholte +Greg Jansen +Raj Narayanaswamy +Iain Melville +Daniel Lang
+Chris Leishman +Klemen Zagar +Rick Ohnemus +Adamo, Vince +Defang Zhou +Dave Zumbro +Ted Nolan +Jianfei Xu +Alvin C. Shih +J dot Scott Evans +Alex Luk +Kenneth Osenbroch +Jason Czavislak +Alex Chachanashvili +Gilbert Grosdidier +James Briggs +Herbert Wang +Anders Olsson +Sergey Gnilitsky +David Wicks +Girish Birajdar +Hajdukiewicz Markus +Gerwin Robert +Alia Atlas +David Hall +Todd Gruhn +John Hickin +Alex Brown +Rich Seibel +Jim Scheller +Bob Bouterse +Sandeep Adwankar +W Craig Trader +Bruce McIntosh +Natarajan Kalpathy +David O'Farrell +Bob Bouterse +Malcolm Spence +Dong-Yueh Liu +Craig Ball +Norbert Krain +Adrian Miranda +Cody Dean +Hans Scharkowitz +Charles Meier +Tim Sim +Shalabh Bhatnagar +Charles Scott +Espen Harlinn +mulder +Richard L. Johnson +Tam Nguyen +Jeff Graham +Ralph Loader +Ji Wuliu +Wada Hiroshi +Sal Amander +Torsten Pfuetzenreuter +John M. Mills +David McWeeny +Florian Lackerbauer +Manuel Benche +Steve Luoma +Roger Tragin +Alex Bangs +Yangfen Qiu +Johnny Chen +John Foresteire +Larry Peacock +Francisco Bravo +Antti Valtokari +John Smyder +Mathew Samuel +Conrad Hughes +John Rodgers +Charles Taurines +James Lacey +Nick Pratt +Xiaojun Wu +George Lafortune +Aoxiang Xu +Dima Skvortsov +Moore Y. Cao +Wai Keung Fung +Michael Laing +Benoit Viaud +Ken Weinert +Ferran Boladeres Salvad +Steve Vranyes +Jim Melton +Ron Klein +Anuj Singhal +Henrik Kai +Dominic Hughes +Lior Shalev +Charlie Duke +William Horn +Greg Hall +Aviad Eden +Vianney Lecroart +Russell Mora +Samir Shaikh +Eric Yee +Matt Emerson +Yiu L. Lee +Pedro Brandao +Hakon Innerdal +Sami Aario +Ingo Dahm +Vijay Aswadhati +Xiaowen Wang + +Warren Miller +Youngkwan Cho +Dorr H. Clark +Dave McNeely +Eric Malenfant +Roland Fischer +Alexander Libman +Roger Larsson +Martin Stack +Michael Ravits +Derek Viljoen +Hamed Azizadah +Keo Kelly +Joachim Achtzehnter +Tomer Amiaz +Sergey Osokin +Nick Logvinov +Viatcheslav Batenine +Shashi Bhushan +Javier Corrales +J dot Randy Pitz +Richard Reitmeyer +Xavier Montet +Letha Etzkorn +James Dabbs +Matej Sekoranja +Mattias Eriksson +Nicoletta Viale +George Reid +Kim Lester +Wilson Chan +William Rucklidge +Victor Krebss +Chander P. Thareja +John Mills +Haifeng Lee +Hans Utz +Askok Kumar Kalanithi +Chris Able +John Hiltenbrand +Steve Hespelt +Peter Fischer +Madhu Ramachandran +Caleb Epstein +Bruno Marconi +Ken Childress +Michael Kramer +Johnny Willemsen +Jonathan Astle +Javier Lopez Sanchez +Nir Drang +Albert Wijnja +Marcel Van Der Weert +Mervyn Quah +Giovanni Zito +Matthew Adams +Sameer Schabungbam +Jeff Butler +Roland R�denauer +John Buckman +Guy Rosen + +Bennett R. Stabile +Paul Caffrey +Low Aik long +Michael Rinne +Jaffar Shaikh +Roger Beck +Trueman Bill +Harold Bien +Mateu Batle +Philip Miller +Base V Paul +Evghenii Filippov +Mike Curtis +Jessie Ragsdale +Shourya Sarcar +Eric Crampton +Sandip Patel +ChenXu +Vsevolod Novikov +Brendan Corcoran +Steve Sivier +Rick Schneeman +Klaus H. Wolf +Jean-Christophe Dubois +Michael Hampel +Wei Zheng +Bernd Annamaier +Joachim Tremouroux +Momchil Velikov +Munagala Ramanath +Kevin Marshall +David Channon +Andy Guy +Oscar Rodriquez +Jonathan Cano +Alain Decamps +Paul Rubel +Jon Loeliger +Ricardo Chan +Sarabjeet Duhra +Michael Rushton +Arno Pernozzoli +Calum Mitchell +Jerry Odenwelder +Kent Stewart +Alexander Kogan +Michael Lindner +Arnaud Compan +Michael Searles +Bogdan Jeram +Sebastian Schubert +Li Zhou +Shivakumar Patil +Steve Olson +Allen Broadman +Yuriy Zaporozhets +Joe Guan +Attilio Dona +McGanahan Skjellifetti +Matthias Wittig +David Allen +Edwin McKay +Scott Bolin +Mike Anderson +David Singer +Nick Lin +Ron Hashimshony +Max Khon +Jonas Nordin +Jonathan Stockdale +Jean-Francois Daune +Wei Chiang +Rick Stille +Kirill Kuolechov +Edwin Wrench +Yung Trinh +Richard Eperjesi +Ben Strong +David Karr +Sathish Tiptur +Lu Yunhai +Christian Ewald +Samuel Qi Luo +Sergey Logvin +Orlando Ribeiro +Doug Warner +Kevin Regan +Andy Olson +Max Voronoy +Alexandr Gavrilov +Scott Gunn +Mason Deaver +Richard Huber +Glen Osterhout +YingLi +Haka +Sam Chong +Virgilijus Globis +Stefan Scherer +Pim Philipse +Michael Grove +John Mackenzie +Ricky Marek +Patrick Maassen +Christian Schuhegger +David L Smith +Rainer Doerntge +Tompa +Derek Horton +Shameek Basu +Dipti Jain +Eric Zuur +Jeffrey J. Persch +Rahul Shukla +Pierre Fayolle +Greg McCain +Matt Cheers +Benjamin Fry +Ram Ben-Yakir +Eric Desamore +John Ashmun +Przemyslaw Marciniak +Carsten Madsen +David Sperry +Ted Horst +Diana Arroyo +Benny Prijono +Roland Ziegler +Stelios Sfakianakis +Mike Letchworth +Brian Gilmer +James Dunham +Juergen Pfreundt +Joel Sherrill +Jules Colding +Stephane Pion +Raghu Narayan +Richard Goold +Nathalie D'Amours +Albert Pariante +Stephen Torri +Philippe Perrin +Gunnar Buason +David Hanvey +Jeff McNiel +Georg Lohrer +Rachel G Smith +Tom Lake +Logan Modahala +Jean Malenfant +Victor Poznyak +Juan Jose Comellas +James Dorsey +Benot Desmeules +Tom Moog +Stan Pinte +Dayisi +Peter Georgakakis +Richard Hardgrave +Mark Drijver +Guy Bolton King +Carlton Teel +Alexandre Cervieri +Darren Griffith +Sam Mok +Josh Curry +Norman Wilson +Itzhak Briskman +James Kanyok +Corey Trager +Kirat Singh +Oleg Pavliv +Frederick Niemi +Andrew Munro +Nicolas Huynh +Kevin Burge +Wayne Erchak +Yew Khong See +Greg Thompson +Mike Pyle +Kobi Cohen-Arazi +Israel Illescas Gomez +Brodie Thiesfield +Erik Toubro Nielsen +Masaoud T. Moonim +Steve Witten +Gil Rapaport +Boris Temkin +Steve Perkins +Jerry Thomas +cuma +Ron Heald +Andrew Finnell +Dan Levi +Rob Andzik +James Maynard +Francois Rioux +Ophir Bleiberg +Allen Kelly +Victor Pitchouc +Srikanth Vedire +J Shane Culpepper +Steffen Hieber +Craig L. Ching +Ben Howard +Rich Newman +Kelly F. Hickel +David Trusty +Burkhard Neppert +Crawford Lodge +Scott Gaa +Jenny Kowald +Oren Zeev-Ben-Mordehai +Holger P. Krekel +Glenn Popelka +Tibor Kiss +Robert Davidson +Peter Crowther +Mouna Seri +Vladimir Chovanec +Alexander Rieger +Glen Coakley +Scott Plant +Wilfried Reinoehl +Sangeetha Ramadurai +Victor Chernenko +Frank Wolf +Christophe Galerne +Scott Harris +Stefan Kluehspies +Egon Wuchner +Ugendreshwar Kudupudi +Ekkehard Hoffmann +Ted Krovetz +Grzegorz Sikora +Fabris +Christina Junru +Patrick Rabau +Hyman Rosen +Torbjorn Backstrom +Robert Burke +Olivier Brunet +Bret Clark +Steve Rahn +Bertrand Motuelle +Blair Zajac +Gary Duzan +Garry Shamis +Eamonn Saunders +Yev Omenzel +John E Hein +Tino Schwarze +Gergely Timar +Peter Phillips +Yury Kuznesov +Daniel Manfis +Massimo Pichini +Eyal Neuman +Dave Hale +Giulio Agostini +Werner Buchert +Kevin Cline +Mahesh Varadarajan +Olof Lindfors +Tom Wagner +Kyle Brost +Vincent Nicolas +Jonathan Wackley +Jan Kalin +Andreas Huggel +Alain Totouom +Tushar Nair +Sunny Leung +Bonifides Bautista +Brad Hoskins +Donald Acton +Hagen Ulrich +Adrian Mercieca +Lars Steubesand +Heping He +Leo Kov +Suresh N +David Arndt +Tad Hetke +Graeme Clark +Gu Song +Chris Hughes +Fikri Pribadi +Ioulia Passynkova +Steve Osselton +Doron Rajwan +Stuart Jones +Guillaume Renaud +Tommy Svensson +Jstwo +Hartmut Quast +Ulrich Voigt +Syed Wasim Ali +Bo Balder +Michael Sawczyn +Ildar Gabdulline +David Yongqiang Wang +Shahzad Aslam-Mir +Andrew Foster +C Chan +Alexey Chalimov +Andrea Bernicchia +Praphul Menon +Patrick N +Garth Watney +Jim Connelly +Eyal Lubetzky +Gaoyan Xie +Michael Brinkmann +Chatchai Khumboa +Andrey Shkinev +Michael Graf +Justin Michel +Robert Martin +Charles Meidinger +Petr Tuma +Greg Burley +Marvin Greenberg +Mike Connors +Ben Flight +Bob Jolliffe +Jesse +Robert Handl +Keith Snively +Ahmed Riza +Miljenko Norsic +David Robison +Preston Elder +Eric Peters +Edward A Thompson +Eugene Alterman +Patrick Cosmo +Ran Kohavi +Harvinder Sawhney +Sorin Iordachescu +Mahesh Vedantam +Brian Olson +Roy Sharon +Charlie Grames +Tom Howard +Michael Gillmann +Yaniv Ben Ari +Victor Terber +David Sanders +Yoram Zini +Sean McCauliff +Shmulik Regev +Andrew L. Shwaika +Gerhard Voss +Gregor Bruce +Ian Cahoon +Alexei I. Adamovich +Sohail Husain +Jerome Julius +William R Volz +Koushik Banerjee +Zoran Cetusic +Patrick Bennett +Felix Wyss +Tim Rydell +Petr Shelomovsky +Juliana Diniz +Yuval Cohen +Timothy Kilbourn +Marc Walrave +Petru Marginean +Paresh Raote +Donna Maskell +Steve Ige +Marco Kranawetter +Christian Veleba +Olli Savia +Bhaskara Rao G +M Schulze +John Michael Zorko +Ami Bar +David Smith +Peter van Merkerk +Bill Dyer +Rodney Morris +Mark Hoffmann +Markus Wild +Joe Hayes +Chip Jones +Patrick J Lardieri +Ken O'Brien +Daniel Troesser +Ivan Pazymenko +Dan Green +Cyrille Chepelov +Peter Heitman +Paxton Mason +Yan Dai +Sean I. Luzader +Renjie Tang +Max V. Zinal +Stan Sosnovsky +Ariel Peltz +Carsten Prescher +Raghuram Shetty +Val Dumiterscu +Oleg Kraynov +Stephan Gudmundson +Frank Kuhlman +Denis Otchenashko +Marc M Adkins +Jon Lambert +Rainer Lucas +Allan S Iverson +Jeffrey Shaffer +Oleg Burlachenko +Jian Chen +Jeff Paciga +Laurent Sabourin +Frank Rybak +Tim Iskander +Michele Amoretti +Ido Yellin +Eric Page +Kevin Heifner +James Haiar +Pavel Repin +Whitney Kew +Tom Phan +Andrew Guy +Bharathi Kangatharan +Jean Quinsat +Ma Ting Chong +Andrew Sutton +Ansgar Konermann +Amir Kunst +Daniel Garrido +Andy Alvarez +Soeren Gerlach +Vitaly Prapirny +Sasha Agranov +Ruwanganie Gunatilleke +Peter Kullmann

+Lyn Headley +Jeff Adams +Alexander Maack +Timothy Culp +Oleg Terletsky +Bill Tonseth +Frank Pilhofer +Eric Quere +Keith Thornton +Nathan Krasney +Marek Maleta +David Smith +Dimitrije Jankovic +Frank O. Flemisch +Cary Steinmetz +Ty Tenait +Nitin Mallya +Nick Cross +Christopher W. Midgley +Wanjia +Shanliang Cheng +Andy Ling +Stephen Howard +Carsten T. Nielsen +Adee Ran + +Davide Pasetto +Michael Hornok +Wim van den Boogaard +Carol Hunsicker +Joseph Sarbak +Ruslan Zasukhin +Colin Weaver +Kew Whitney +Sean Ogle +Tim Bradley +Kier Schmitt +George Varsamis +Alan Tanga +Bertin Colpron +Jeff Wilson +Dmitry Khrapov +Francois +Laxmikant Bopalkar +Steven Gardner +Ronald Berger +Jeremy Altavilla +Brian Appel +Lan Zhineng +Leen Van Kampen +James Beale +Mark Xu +Umberto Mascia +Marcel Loose +Christian Klutz +Ville Lehtiniemi +Chumsu Kim +Schone Mullerin +Cemal Yimaz +Newton Aird +Frederic Motte +Roger Weeks +Gautam Thaker +Christophe Juniet +Jeff W +Geir Berset +Ken Sedgwick +Vince Mounts +Vladislav Zverev +Erich Hochmuth +Nick S. Petrov +Dmitry Botcharnikov +Philippe Haussy

+K2 +Eric Frias +Antonio Saraiva +Sean M. Paus +Yuanfang Zhang +Jonathan Franklin +Cristian Ungureanu +Tommy Persson +Christian Barheine +Ole Husgaard +Victor Kirk +Sandeep Neema +Mike Curtis +Artashes Ghazaryan +Ashok Sadasivan +Andreas Koehler +Thomas Devanneaux +Paul Marquis +Ed Skees +Marc Alter +Martin Geliot +Simon McQueen +Jason Pasion +Philipp Leibfried +Erwin Rol +Dirk Moermans +Huseyin Calgin +Jaroslaw Nozderko +Sharon Caspi +Thomas Natterer +Wilbur Lang +Rick Marlborough +David-A O-Brien +Shelton Tang +Frederic Langlet +Antonio Leonforte +Pablo d'Angelo +Christophe Vedel +Uwe Jaeger +Viktor Ransmayr +Daniel Bell +Mathias Waack +Mike Nordell +Tufan Oruk +Tim Smith +Andy King +Eric Strennen +Abhay Kulkarni +Ron Muck +Ma Weida +Terry Lao +Volker Boerchers +Tim Pullen +Marc Tardif +Guan Joe +Petr Ferschmann +Greg Mulyar +Max F. Bilyk +Danile White +Andrew Marlow +Michael F"olsl +Vincent Chau +Theo Landman +Igor Pisarenko +Dima Scub +Volodymyr Orlenko +Grigory +Michael Soden +Dennis Sporcic +Emmanuel Thevenot Beaufort +Denis Parnaland +Matthias Blankenhaus +Wolfgang Schroeder +Mario Hofmann +Bruce MacDonald +Jeffrey Graham +Otis Nyandoro +Ray Limpus +Dmitri Belogaj +Will Christof +Ferran Boladeres Salvad +Juan Carlos Montes Costa +Edward Scott +Steve Spencer +Fukasawa Mitsuo +Martin Brown +Terry Mihm +Jeff Gray +Rob Eger +Leonid Kvetnyi +Rudolf Weber +Sergei Pimenov +David Kinder +Sebastien Lalonde +Jia Wan +Bertin Colpron +Weston Markham +Bryan Thrall +Subhabrata Biswas +Dave Ryan +Zsolt Zsoldos +Tongzhe Cui +Braden McDaniel +Richard Woodring +Andras Lang +Scott Gammil +Nick Lewycky +Ira Burton +Thomas Wiegert +Craig Watcham +Pit Linnartz +Peder Norgaard +David Ohlemacher +Ken Kane +Bill Church +Udo Berninger +Vincent Korkos +Martin Corino +Terry Lacy +Branko Mijic +Jeff Kelley +Daniel Hannum +Jason Cohen +Nick Kukuczka +Andrew Voumard +Anand +D.J. Dwyer +Douglas A Stuart +Victor N. +Francesco Baldi +Michael Rice +Jesse Greenwald +Raymond Hoofman +Jason Smith +Danta Cannarozzi +Valery Salamakha +Karim Fodil-Lemelin +Wenlong Tang +Manish Jain +Robin Farine +Roland Schimmack +Roy Pollock +Eric Held +Kees van Marle +Dieter Knueppel +Amol Tambe +Emiliano Berenbaum +Scott Clarke +Sunil Rottoo +Martin Habets +Todd Cooper +Serkan Unsal +Milan Cvetkovic +Didier Becu +Dan Halbert +Jerome Waibel +Stephan Frenzel +Bruce Jones +Tim Hawes +Philip Leishman +Alexander Jasper +Gerard Grant +Trevor Fields +Jeff Dugan +Jeff Mirwaisi +Alain Dupont +Stephan Bettermann +David McKen +Adam Fanello +Matthieu Vansteene +Sean Rooney +Enrico Detoma +Onopin V. Mikhail +Edward R. Mulholland +Brian Buesker +Vladimir Naylov +Ted Mules +Mike Hepburn +Dale Wilson +Thomas Girard +Malcolm McRoberts +Dror Tirosh +Chris Sontag +Moran Levi +UV Wildner +Alan l Batongbacal +Gary Maxey +Yoav Borer +Andre Kleibeuker +Andy Bellafaire +John Fletcher +Terry Ware +Pierre Pacchioni +Roger Beathard +Konstantinos Margaritis +Stephen Procter +Christoph Liebig +Andre Kostur +Markus Stenberg +Jonathan Pollack +Si Mong Park +Hakim Souami +Paul Morrison +John Poplett +Heiko Bachmann +Andrew Metcalfe +Simon Dutkowski +Mickael P. Golovin +Shannon Barber +Brad Orner +Michelangelo Nottoli +Peter Bekiesch +Martin Kaul +Lukas Gruetzmacher +Robert Schiele +Matthew Grosso +Akim Boyko +Nils Sandoy +Daniel Miranda +Hans-Peter Bock +Dmitri Hrapof +Denny Kolb +Daniel Buchs +Matt Murphy +Brian Nelson +Avi Ouziel +Matthew Gillen +Chris Reed +Andrew Reid +Praveen Sharma +Yi Zuo +Raphael Bossek +Richard G. Hash +Karl Tredwell +Norm Whitehead +Jiang Wei +Kevin Bryan +Zvika Ashani +Thomas Costa +Dom Monteiro +Jean-Marc Prud'homme +Yury Osadchy +Pavan Mandalkar +Scott Willey +David Calkins +Wu Yongwei +Karen L. Regner +Michel Drapeau +Hans Bos +Kevin Stacy +Liat +Andreas Wagner +Steven Xie +Kris Dekeyser +Matthew Harris +Abhijit Sachdev +Mikael Lundqvist +Peter Hercek +Jay Welch +Angel Roman +Jessica Pistole +Paolo Carlini +Eric Whorter +Vincent Seignole +Jingbin An +Roland Meub +Marek Brudka +Levente Torok +Panagiotis Issaris +Mehrdad Nazari +Pierre Bisaillon +Rob Boyer +Scott Gammill +Bayu Hendradjaya +Randy Hammon +Bill Cassanova +Matthew Corey +Vinod Kumar +Mirek Pabich +Christian Egeler +J.T. Conklin +Dale Hawkins +Bill Hopkins +David Fleeman +Merlin Ran +Kevin Christian +Trina Wisler +Bae-Sik Chon +Benjamin Bronk +Dave Craig +Ofira Shaer +Ciaran Moran +Thomas Rohner +Ken Descoteaux +Claas-Hinrich Dommreis +Yateen Joshi +Sergei Kuchin +Theckla Louchios +Randy Secrest +Patrice Marques +Stanislaw Trytek +Mattias Nilsson +Michael Hollins +Dave Knox +Lance Paine +Brian Waltersdorf +Johann Kandlbauer +Adam Rymarczuk +Heiko Nardmann +J. Abelardo Gutierrez +Roger Sala +Razi Ben-Yehuda +Geo Sebastian +Simon Massey +Rich Shapiro +Ramiro Morales +Andrew Athan +Sebastien Roy +Matthew Townsend +Rick Robinson +John D. Robertson +Paul Lew +Eider Oliveira +Jeff Jones +Jean-Christophe Cota +Paul +Vincent Newsum +Vasili Goutas +Iliyan Jeliazkov +Shlomi Yaakobovich +Todd Marshall +Ciju John +Yuk Ming Kwok +Honorato Saavedra +Domingos Monteiro +Bill Somerville +Bjorn Roald +Michi Henning +Xue Yong Zhi +Ertugrul Sorar +Simone Viani +Rohan Mars +Robert S. Iakobashvili +Chris Hammond +Vincent Spano +Nuno Silva +Greg Bostrum +Dipa Suri +Adam Howell +Steven Frare +Dave Dalapati +Arjun Thounaojam +Michael Altmann +Steven Patrick +Pete McCann +William Nagel +M. C. Gahan +Thia Chang Chao +Gao Xianchao +Huang Rui +Sam Abbe +Mike McGahan +David Michael +Steve D. Baker +Martina Yen +Kim ByeongSu +Doug McCorkle +YiQing Xiong +Peter Falsh +Don Sharp +Arto Jalkanen +Scott Zionic +Diana Ukleja +Shaun Cooley +Aapo M�kinen +Matt Emerson +Sean Parker +Mark Wilson +Joerg Rockel +Phil Chen +Stefan Morrow +Bruce Elliot +Mitscher Dubreus +Brian O'Connor +Ron Wilson +Peter Grotrian +Alex Ott +D. J. Stachniak +Slava Gorelik +Wolfgang Fischer +Nicholas Todd +Arno Wilhelm +Andreas Schuler +Altaf Aali +Vemund Handeland +Mario Di Giacomo +Raoul Gough +Aaron +Rohini Madhavan +Alan Balasuar +Will Chai +Paul Koch +Dave Giovannini +Dave Varnell +Howard Finer +Mark Callaghan +Hanson Lu +Gavin Yu +Srikanth Gopal +Like Ma +Alvin Msg +Angela Ziegenhorn +Sam Mesh +Felix Perez Alamillo +Steven T. Hatton +Yevgen Galchenko +Timothy Wayne Gomez +Ventimiglia Chere +Frederick Heckel +Ian Zagorskih +Olivier Gu�rin +Abdel Rigumye +James Damour +Alan Anderson +Vito Bico +Aldo Texier +J H Choi +Mike Chartier +Nikolay Metchev +Anand Rathi +Vitaly Belekhov +Dorian Hileaga +Steve Williams +Paul Friberg

+Zachi Klopman +Jin Zhi Ye +David Carlton +Feng Li +Michael van der Westhuizen +Jan Zima +Francesco Salvestrini +Sandeep Deshpande +Hubert Talbot +Oh Yoon Sik +Anton Bakanovskiy +Toha Bakanovsky +David Faure +Robert Hancock +Peter Oslej +Yongming Wang +Vadim Iosevich +Mike Knight +Nathan Anderson +Eyal Car +Jonathan Sprinkle +Vladimir Panov +Volker Lukas +Bryan Cassell +Guy Peleg +Wallace Zhang +Richard Ward +Alan Stokes +Rick Taylor +Tobias Herzke +Paul Felix +Jan Ohlenburg +Eric Tiangang +David Hawkins +Michael Klein +Sandro Santos Andrade +Richard Spence +Thomas E Lackey +luxi78 at gmail dot com +John Lilley +Abdullah Sowayan +Nathan Bamford +Zoltan Molnar +William Byrne +Karl Schmitt +Ron DeAngelis +Alex Sheh +Daniel Wagner <__daniel___ at icg do tu-graz dot ac dot at> +Nemoy Michael +Marc Brown +Andrew Keane +Martin Kolleck +Tino Riethmueller +Adam Mitz +Frank Rehberger +Aaron Scamehorn +Alan Kierstead +Sven-Uwe Sieler-Hornke +Spencer Vanroekel +Dan Pozdol +Yauheni Akhotnikau +Axter +Roopa Pundaleeka +JR Andreassen +Mockey Chen +Vincent Joseph +Igor Mammedov +Yuan +Adrian Tulloch +Dmitriy Kuznetsov +Steve Orner +Bob Ronak +Aleksandar Vukajlovic +esIgnacio Alvarez +Sergey Zubarev +Qingbo Cai +David White +Jason Zhang +Mark Paulus +Willie Chen +Martin Cornelius +Mohit Kapoor +David Gibbs +Gary Fernandez +Jason Zhao +Keith Muzzioli +John Black +David Chu +Kevin Hu +Yasser Zabuair +Phlip +Michelle Zheng +Gerolf Reinwardt +Paul Robinson +Popeye Cai +David Highley +Sonicfly Zhou +Phil Billingham +Paul Daugherty +Robert Schwebel +William Cote +Ben Creech +Michael Reed +Heesuk Shin +Hong Xing +Winston Zhang +Stefan Naewe +Graeme Bell +Eric Danielou +Wei Jiang +Dale Boan +Christoph Schmalhofer +Amnon Berger +Ephy Levy +Don Meek +Liu Qian +Nzer Zaidenberg +Birgit Platt +Andy Salnikov +Hieu Ngyuen +Andriy Gapon +Andy Wang +Zhamak Dehghani +Charles Calkins +Manuel Traut +Drew Reynaud +Artur DeEsperanto +Scott Mitchell +Thomas Vanier +N Johnson +Adam Nagel +Robert Neumann +Venkat +Juraj Ivancic +Daniel Black +Richard Ridgway +Vadym Ridosh +Viola Wang +Ray Lischner +Sergey Kosenko +Pavel Zaichenko +Paul Riley +Nelson Filipe Ferreira Gon�alves +Harry Goldschmitt +Sail Zeng +Markus Henschel +Asif Lodhi +Andrew Schnable +Grigoriy Zeleniy +Yves Alloyer +Waba +Scott Mark +Bjoern Rasmussen +Ian C White +Dennis Chernoivanov +Werner Burger +Andres Hurtis +Joe French +M. Arshad Khan +Hans van't Hag +Roland Sun +Vance Maverick +John McCabe +Andres Oportus +Olof Granered +Eric Hughes +Zhenghao Shi +Alexander Kornienko +Ben Mohlenhoff +Bill Bruns +Dmitriy Nikitinskiy +Ravi Kanth +Ian Roberts +Patrick Spiering +Duane Beck +Kanghee Yoon +Xu Liang +Leo Lei +Jules d'Entremont +Rajiv K. Shukla +Haibin Zhang +Vikram Karandikar +Kim J. Schmock +Venkat Forums +James Marsh +Shaolong Xiang +Christoph Hofmann +Vladimir Zykov +Daniel de Angelis Cordeiro +Hal Black +Peter Korf +Norbert Thoden +Premkumar P +David Beck +Hayim Shaul +Erman Balcik +Torsten Saliwada +Nathan Glasser +Gr�gor Boirie +Alex Solan +Venkat Sidhabathuni +Nathan Ernst +Kun Niu +Karl-Heinz Wind +Oliver Spang +Hu Yi +Joe Seward +Tom Callaway +Alick Nie +Douglas Atique +Nayeem Khan +Sorin Voicu-Comendant +Andi Heusser +Paul Carter +Michael Carter +Alain Kocelniak +Alvaro Vega Garcia +Fernando C. Jeronymo +Stephen Mouring +Tim +Thomas Brownridge +June Fang +Bill Kendall +Ittehad Shaikh +Michael Doubez +Namrata Gandhi <...> +Michael Guntli +Frank F�rster +Roger Leblanc +Bob Fiske +Julien Vintrou +Jonathan Brannan +antred +Nathalie D'Amours +Mele Giovanni +Philipp Thomas +Mark Hebbel +Tim Pollock +Jack Lavender +Alexandre Skrzyniarz +E Vahala +Christian Fromme +Daniel Lang +Greg Bothe +Anand Kumar +Joe Pallas +Marcel Smit +Florent Vial +Pan Kai Luna +Jesus Martinez +Martin Gaus +Steve Stallion +Ron van Hoof +Joe Lihn +Jani Hakala +Marcus Monaghan +Kashif Khan +JD Robertson +Andreas Drescher +Alon Diamant +Igor Rayak +Shai Kedem +Steve Ramsay + +Skrzyniarz Alexandre +Rob Beekmans +Steven Hartmann +Dicky +Boyan Kasarov +Brendan Murphy +Ryan Carmichael +Koh Onishi +Markus Gaugusch +Annette Wilson +Sharon Mizrahi +William Glenn +Christian Ehrlicher +Hui Zhang +Marijke Hengstmengel +Christian Freund +Chris Shaw +Matthew Carter +Denis Budko +Gaurav Kulshreshtha +Wolfgang Pickartz +Joost Kraaijeveld +Pau Garcia i Quiles +Sail Zeng +Dirk Bonekaemper +Sreejith +Guillaume Lahaye +Andrew Kaplan +Alexander Mintz +Jennifer Kahng +Trent Nadeau +Nick Meyer +Olivier Langlois +Patrick Soboljew +Tim Pinkawa +Ed Blackmond +Dave +Inma Perea +David Ward +Anatoli Sakhnik +Max Zhou +Daynesh Mangal +Robert Shectman +Rafi +Kannan Ramaswamy +Brian Johnson +Catherine L. Paquin +Susan Finster +Frank Preischl +Matthew Waller +Elez +Ranjit Hande +Van Vuong +Mark +Wendsomde Yameogo +Shi John +Helmut Böing +Andrew Hill +Henk Jan Priester +Glenn Zickert +Chris Galli +Laura Autn Garca +Jonathan Saxton +Remko Duppen +Paul Fitzpatrick +Chad Beaulac +Jochen Meier +Thomas Pauli +Qiao Zhiqiang +JaeSung Lee +Chong Wuk Pak +Michael Frommberger +Andrey Karpov +Dmytro Ovdiienko +Andrea Sormanni +Thomas Stegemann +David Simmonds +Andreas Drscher +Markus Manck +Deux deVille +Mohsin Zaidi +Milind Pangarkar +Ali Akbar Zarezadeh +Andrs Senac Gonzlez +Peng Xu +Sergey Onuchin +Michael Ganz +Phillip LaBanca +Journeyer J. Joh +Rudy Pot +Neil Youngman +Andreas Florath +Clyde Gerber +George Chen +Piotr Kow +Yogesh Sharma +Mike McKnerney +Mike Ketchen +Erik Sohns +Winston Jenks +Colin Shen +Alexey Zubko +Michael Dille +Sebastian Perk +David Lifshitz +Milo H. Fields + +I would particularly like to thank Paul Stephenson, who worked with me +at Ericsson in the early 1990's. Paul devised the recursive Makefile +scheme that underlies the ACE distribution and also spent countless +hours with me discussing object-oriented techniques for developing +distributed application frameworks. + +Finally, I'd also like to thank Todd L. Montgomery , +fellow heavy metal head, for fulfilling his quest to get ACE to +compile with GCC! + +In conclusion, our goal is to see ACE+TAO+CIAO continue to evolve and +become a more comprehensive, robust, and well-documented C++ class +library that is freely available to researchers and developers. If +you have any improvements, suggestions, and or comments, we'd like to +hear about it. Please see the instructions in + +$ACE_ROOT/PROBLEM-REPORT-FORM +$TAO_ROOT/PROBLEM-REPORT-FORM +$CIAO_ROOT/PROBLEM-REPORT-FORM +$DANCE_ROOT/PROBLEM-REPORT-FORM + +for instructions on submitting suggestions or fixes. + + Thanks, + + Douglas C. Schmidt + d.schmidt at vanderbilt.edu diff --git a/dep/acelite/VERSION b/dep/acelite/VERSION new file mode 100644 index 000000000..85eb6995d --- /dev/null +++ b/dep/acelite/VERSION @@ -0,0 +1,8 @@ +This is ACE version 6.3.0, released Fri Nov 14 08:38:16 CET 2014 + +If you have any problems with or questions about ACE, please send +e-mail to the ACE mailing list (ace-bugs@list.isis.vanderbilt.edu), +using the form found in the file PROBLEM-REPORT-FORM. In order +to post to the list you must subscribe to it. + +See http://www.dre.vanderbilt.edu/~schmidt/ACE-mail.html diff --git a/dep/acelite/ace/ACE.cpp b/dep/acelite/ace/ACE.cpp new file mode 100644 index 000000000..7a26dff29 --- /dev/null +++ b/dep/acelite/ace/ACE.cpp @@ -0,0 +1,3499 @@ +#include "ace/ACE.h" + +#include "ace/Basic_Types.h" +#include "ace/Handle_Set.h" +#include "ace/Auto_Ptr.h" +#include "ace/SString.h" +#include "ace/Version.h" +#include "ace/Message_Block.h" +#include "ace/Log_Category.h" +#include "ace/Flag_Manip.h" +#include "ace/OS_NS_sys_select.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_strings.h" +#include "ace/OS_NS_signal.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_sys_resource.h" +#include "ace/OS_NS_sys_wait.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_sys_uio.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/OS_TLI.h" +#include "ace/Truncate.h" + +#if !defined (__ACE_INLINE__) +#include "ace/ACE.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_POLL) +# include "ace/OS_NS_poll.h" +#endif /* ACE_HAS_POLL */ + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + // private: + // Used internally so not exported. + + // Size of allocation granularity. + size_t allocation_granularity_ = 0; + + // Size of a VM page. + size_t pagesize_ = 0; + + // Are we debugging ACE? + // Keeps track of whether we're in some global debug mode. + char debug_; +} + + +int +ACE::out_of_handles (int error) +{ + // EMFILE is common to all platforms. + if (error == EMFILE || +#if defined (ACE_WIN32) + // On Win32, we need to check for ENOBUFS also. + error == ENOBUFS || +#elif defined (HPUX) + // On HPUX, we need to check for EADDRNOTAVAIL also. + error == EADDRNOTAVAIL || +#elif defined (ACE_LINUX) + // On linux, we need to check for ENOENT also. + error == ENOENT || + // For RedHat5.2, need to check for EINVAL too. + error == EINVAL || + // Without threads check for EOPNOTSUPP + error == EOPNOTSUPP || +#elif defined (sun) + // On sun, we need to check for ENOSR also. + error == ENOSR || + // Without threads check for ENOTSUP + error == ENOTSUP || +#elif defined (__FreeBSD__) + // On FreeBSD we need to check for EOPNOTSUPP (LinuxThreads) or + // ENOSYS (libc_r threads) also. + error == EOPNOTSUPP || + error == ENOSYS || +#elif defined (__OpenBSD__) + // OpenBSD appears to return EBADF. + error == EBADF || +#endif /* ACE_WIN32 */ + error == ENFILE) + return 1; + else + return 0; +} + +u_int +ACE::major_version (void) +{ + return ACE_MAJOR_VERSION; +} + +u_int +ACE::minor_version (void) +{ + return ACE_MINOR_VERSION; +} + +u_int +ACE::beta_version (void) +{ + return ACE_BETA_VERSION; +} + +u_int +ACE::micro_version (void) +{ + return ACE_MICRO_VERSION; +} + +const ACE_TCHAR * +ACE::compiler_name (void) +{ +#ifdef ACE_CC_NAME + return ACE_CC_NAME; +#else + return ACE_TEXT (""); +#endif +} + +u_int +ACE::compiler_major_version (void) +{ +#ifdef ACE_CC_MAJOR_VERSION + return ACE_CC_MAJOR_VERSION; +#else + return 0; +#endif +} + +u_int +ACE::compiler_minor_version (void) +{ +#ifdef ACE_CC_MINOR_VERSION + return ACE_CC_MINOR_VERSION; +#else + return 0; +#endif +} + +u_int +ACE::compiler_beta_version (void) +{ +#ifdef ACE_CC_BETA_VERSION + return ACE_CC_BETA_VERSION; +#else + return 0; +#endif +} + +ACE_TCHAR +ACE::nibble2hex (u_int n) +{ + // Yes, this works for UNICODE + return ACE_TEXT ("0123456789abcdef")[n & 0x0f]; +} + +bool +ACE::debug (void) +{ + //FUZZ: disable check_for_ace_log_categories + static const char *debug = ACE_OS::getenv ("ACE_DEBUG"); + //FUZZ: enable check_for_ace_log_categories + return (ACE::debug_ != 0) ? ACE::debug_ : (debug != 0 ? (*debug != '0') : false); +} + +void +ACE::debug (bool onoff) +{ + ACE::debug_ = onoff; +} + +int +ACE::select (int width, + ACE_Handle_Set *readfds, + ACE_Handle_Set *writefds, + ACE_Handle_Set *exceptfds, + const ACE_Time_Value *timeout) +{ + int result = ACE_OS::select (width, + readfds ? readfds->fdset () : 0, + writefds ? writefds->fdset () : 0, + exceptfds ? exceptfds->fdset () : 0, + timeout); + if (result > 0) + { +# if !defined (ACE_WIN32) + // This isn't needed for Windows... it's a no-op anyway. + if (readfds) + readfds->sync ((ACE_HANDLE) width); + if (writefds) + writefds->sync ((ACE_HANDLE) width); + if (exceptfds) + exceptfds->sync ((ACE_HANDLE) width); +#endif /* ACE_WIN32 */ + } + return result; +} + +int +ACE::select (int width, + ACE_Handle_Set &readfds, + const ACE_Time_Value *timeout) +{ + int result = ACE_OS::select (width, + readfds.fdset (), + 0, + 0, + timeout); + +#if !defined (ACE_WIN32) + if (result > 0) + readfds.sync ((ACE_HANDLE) width); +#endif /* ACE_WIN32 */ + return result; +} + +int +ACE::terminate_process (pid_t pid) +{ +#if defined (ACE_HAS_PHARLAP) + ACE_UNUSED_ARG (pid); + ACE_NOTSUP_RETURN (-1); +#elif defined (ACE_WIN32) + // Create a handle for the given process id. + ACE_HANDLE process_handle = + ::OpenProcess (PROCESS_TERMINATE, + FALSE, // New handle is not inheritable. + pid); + + if (process_handle == ACE_INVALID_HANDLE + || process_handle == 0) + return -1; + else + { + // Kill the process associated with process_handle. + BOOL terminate_result = + ::TerminateProcess (process_handle, 0); + // Free up the kernel resources. + ACE_OS::close (process_handle); + return terminate_result ? 0 : -1; + } +#else + return ACE_OS::kill (pid, 9); +#endif /* ACE_HAS_PHARLAP */ +} + +int +ACE::process_active (pid_t pid) +{ +#if !defined(ACE_WIN32) + if (ACE_OS::kill (pid, 0) == 0) + return 1; + else if (errno == ESRCH) + return 0; + else + return -1; +#else + // Create a handle for the given process id. + ACE_HANDLE process_handle = + ::OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, pid); + if (process_handle == ACE_INVALID_HANDLE || process_handle == 0) + return 0; + else + { + DWORD status; + int result = 1; + if (::GetExitCodeProcess (process_handle, + &status) == 0 + || status != STILL_ACTIVE) + result = 0; + + ::CloseHandle (process_handle); + return result; + } +#endif /* !ACE_WIN32 */ +} + +const ACE_TCHAR * +ACE::execname (const ACE_TCHAR *old_name) +{ +#if defined (ACE_WIN32) + const ACE_TCHAR *suffix = ACE_OS::strrchr (old_name, ACE_TEXT ('.')); + if (suffix == 0 || ACE_OS::strcasecmp (suffix, ACE_TEXT (".exe")) != 0) + { + ACE_TCHAR *new_name = 0; + + size_t size = + ACE_OS::strlen (old_name) + + ACE_OS::strlen (ACE_TEXT (".exe")) + + 1; + + ACE_NEW_RETURN (new_name, + ACE_TCHAR[size], + 0); + ACE_TCHAR *end = new_name; + + end = ACE_OS::strecpy (new_name, old_name); + + // Concatenate the .exe suffix onto the end of the executable. + // end points _after_ the terminating nul. + ACE_OS::strcpy (end - 1, ACE_TEXT (".exe")); + + return new_name; + } +#endif /* ACE_WIN32 */ + return old_name; +} + +u_long +ACE::hash_pjw (const char *str, size_t len) +{ + u_long hash = 0; + + for (size_t i = 0; i < len; i++) + { + const char temp = str[i]; + hash = (hash << 4) + (temp * 13); + + u_long g = hash & 0xf0000000; + + if (g) + { + hash ^= (g >> 24); + hash ^= g; + } + } + + return hash; +} + +u_long +ACE::hash_pjw (const char *str) +{ + return ACE::hash_pjw (str, ACE_OS::strlen (str)); +} + +#if defined (ACE_HAS_WCHAR) +u_long +ACE::hash_pjw (const wchar_t *str, size_t len) +{ + u_long hash = 0; + + for (size_t i = 0; i < len; i++) + { + // @@ UNICODE: Does this function do the correct thing with wchar's? + + const wchar_t temp = str[i]; + hash = (hash << 4) + (temp * 13); + + u_long g = hash & 0xf0000000; + + if (g) + { + hash ^= (g >> 24); + hash ^= g; + } + } + + return hash; +} + +u_long +ACE::hash_pjw (const wchar_t *str) +{ + return ACE::hash_pjw (str, ACE_OS::strlen (str)); +} +#endif /* ACE_HAS_WCHAR */ + +ACE_TCHAR * +ACE::strenvdup (const ACE_TCHAR *str) +{ + ACE_TRACE ("ACE::strenvdup"); + + return ACE_OS::strenvdup (str); +} + +/* + +Examples: + +Source NT UNIX +================================================================== +netsvc netsvc.dll libnetsvc.so +(PATH will be (LD_LIBRARY_PATH +evaluated) evaluated) + +libnetsvc.dll libnetsvc.dll libnetsvc.dll + warning +netsvc.so netsvc.so + warning libnetsvc.so + +..\../libs/netsvc ..\..\libs\netsvc.dll ../../libs/netsvc.so +(absolute path used) (absolute path used) + +*/ + +const ACE_TCHAR * +ACE::basename (const ACE_TCHAR *pathname, ACE_TCHAR delim) +{ + ACE_TRACE ("ACE::basename"); + const ACE_TCHAR *temp = ACE_OS::strrchr (pathname, delim); + + if (temp == 0) + return pathname; + else + return temp + 1; +} + +const ACE_TCHAR * +ACE::dirname (const ACE_TCHAR *pathname, ACE_TCHAR delim) +{ + ACE_TRACE ("ACE::dirname"); + static ACE_TCHAR return_dirname[MAXPATHLEN + 1]; + + const ACE_TCHAR *temp = ACE_OS::strrchr (pathname, delim); + + if (temp == 0) + { + return_dirname[0] = '.'; + return_dirname[1] = '\0'; + + return return_dirname; + } + else + { + // When the len is truncated, there are problems! This should + // not happen in normal circomstances + size_t len = temp - pathname + 1; + if (len > (sizeof return_dirname / sizeof (ACE_TCHAR))) + len = sizeof return_dirname / sizeof (ACE_TCHAR); + + ACE_OS::strsncpy (return_dirname, + pathname, + len); + return return_dirname; + } +} + +ssize_t +ACE::recv (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::recv (handle, (char *) buf, len, flags); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) ==-1) + return -1; + else + { + ssize_t bytes_transferred = + ACE_OS::recv (handle, (char *) buf, len, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +#if defined (ACE_HAS_TLI) + +ssize_t +ACE::t_rcv (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::t_rcv (handle, (char *) buf, len, flags); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) ==-1) + return -1; + else + { + ssize_t bytes_transferred = + ACE_OS::t_rcv (handle, (char *) buf, len, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +#endif /* ACE_HAS_TLI */ + +ssize_t +ACE::recv (ACE_HANDLE handle, + void *buf, + size_t n, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE::recv_i (handle, buf, n); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t bytes_transferred = ACE::recv_i (handle, buf, n); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::recvmsg (ACE_HANDLE handle, + struct msghdr *msg, + int flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::recvmsg (handle, msg, flags); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t bytes_transferred = ACE_OS::recvmsg (handle, msg, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::recvfrom (ACE_HANDLE handle, + char *buf, + int len, + int flags, + struct sockaddr *addr, + int *addrlen, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::recvfrom (handle, buf, len, flags, addr, addrlen); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t bytes_transferred = + ACE_OS::recvfrom (handle, buf, len, flags, addr, addrlen); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE_OS::recv (handle, + static_cast (buf) + bytes_transferred, + len - bytes_transferred, + flags); + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK) + { + // Wait for the blocking to subside. + int const result = ACE::handle_read_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return static_cast (bytes_transferred); +} + +ssize_t +ACE::recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE_OS::recv (handle, + static_cast (buf) + bytes_transferred, + len - bytes_transferred, + flags); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + errno == EWOULDBLOCK) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_read_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + return result; + else + return static_cast (bytes_transferred); +} + +#if defined (ACE_HAS_TLI) + +ssize_t +ACE::t_rcv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE_OS::t_rcv (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK) + { + // Wait for the blocking to subside. + int const result = ACE::handle_read_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return bytes_transferred; +} + +ssize_t +ACE::t_rcv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE_OS::t_rcv (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + errno == EWOULDBLOCK) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_read_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + return result; + else + return bytes_transferred; +} + +#endif /* ACE_HAS_TLI */ + +ssize_t +ACE::recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE::recv_i (handle, + static_cast (buf) + bytes_transferred, + len - bytes_transferred); + // Check EOF. + if (n == 0) + { + return 0; + } + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK) + { + // Wait for the blocking to subside. + int const result = ACE::handle_read_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return static_cast (bytes_transferred); +} + +ssize_t +ACE::recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE::recv_i (handle, + static_cast (buf) + bytes_transferred, + len - bytes_transferred); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + errno == EWOULDBLOCK) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_read_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + return result; + else + return static_cast (bytes_transferred); +} + +// This is basically an interface to ACE_OS::readv, that doesn't use +// the struct iovec explicitly. The ... can be passed as an arbitrary +// number of (char *ptr, int len) tuples. However, the count N is the +// *total* number of trailing arguments, *not* a couple of the number +// of tuple pairs! +#if !defined (ACE_LACKS_VA_FUNCTIONS) +ssize_t +ACE::recv (ACE_HANDLE handle, size_t n, ...) +{ + va_list argp; + int const total_tuples = static_cast (n / 2); + iovec *iovp = 0; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t const result = ACE_OS::recvv (handle, iovp, total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +} +#endif /* ACE_LACKS_VA_FUNCTIONS */ + + +ssize_t +ACE::recvv (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::recvv (handle, iov, iovcnt); + else + { + int val = 0; + if (ACE::enter_recv_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t bytes_transferred = ACE_OS::recvv (handle, iov, iovcnt); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::recvv_n_i (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + for (int s = 0; s < iovcnt; ) + { + // Try to transfer as much of the remaining data as possible. + ssize_t n = ACE_OS::recvv (handle, iov + s, iovcnt - s); + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK) + { + // Wait for the blocking to subside. + int const result = ACE::handle_read_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = static_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::recvv_n_i (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (int s = 0; s < iovcnt; ) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + ssize_t n = ACE_OS::recvv (handle, iov + s, iovcnt - s); + + // Check for errors. + if (n == 0 || n == -1) + { + // Check for possible blocking. + if (n == -1 && errno == EWOULDBLOCK) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_read_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = reinterpret_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + { + return result; + } + else + { + return ACE_Utils::truncate_cast (bytes_transferred); + } +} + +ssize_t +ACE::recv_n (ACE_HANDLE handle, + ACE_Message_Block *message_block, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + iovec iov[ACE_IOV_MAX]; + int iovcnt = 0; + + while (message_block != 0) + { + // Our current message block chain. + const ACE_Message_Block *current_message_block = message_block; + + while (current_message_block != 0) + { + size_t current_message_block_length = + current_message_block->length (); + char *this_rd_ptr = current_message_block->rd_ptr (); + + // Check if this block has any space for incoming data. + while (current_message_block_length > 0) + { + u_long const this_chunk_length = + ACE_Utils::truncate_cast ( + current_message_block_length); + + // Collect the data in the iovec. + iov[iovcnt].iov_base = this_rd_ptr; + iov[iovcnt].iov_len = this_chunk_length; + current_message_block_length -= this_chunk_length; + this_rd_ptr += this_chunk_length; + + // Increment iovec counter. + ++iovcnt; + + // The buffer is full make a OS call. @@ TODO find a way to + // find ACE_IOV_MAX for platforms that do not define it rather + // than simply setting ACE_IOV_MAX to some arbitrary value such + // as 16. + if (iovcnt == ACE_IOV_MAX) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::recvv_n (handle, + iov, + iovcnt, + timeout, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + return result; + + // Reset iovec counter. + iovcnt = 0; + } + } + + // Select the next message block in the chain. + current_message_block = current_message_block->cont (); + } + + // Selection of the next message block chain. + message_block = message_block->next (); + } + + // Check for remaining buffers to be sent. This will happen when + // ACE_IOV_MAX is not a multiple of the number of message blocks. + if (iovcnt != 0) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::recvv_n (handle, + iov, + iovcnt, + timeout, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + { + return result; + } + } + + // Return total bytes transferred. + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::send (ACE_HANDLE handle, + const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::send (handle, (const char *) buf, n, flags); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t const bytes_transferred = + ACE_OS::send (handle, (const char *) buf, n, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +#if defined (ACE_HAS_TLI) + +ssize_t +ACE::t_snd (ACE_HANDLE handle, + const void *buf, + size_t n, + int flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::t_snd (handle, (const char *) buf, n, flags); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t const bytes_transferred = + ACE_OS::t_snd (handle, (const char *) buf, n, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +#endif /* ACE_HAS_TLI */ + +ssize_t +ACE::send (ACE_HANDLE handle, + const void *buf, + size_t n, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE::send_i (handle, buf, n); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t const bytes_transferred = ACE::send_i (handle, buf, n); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::sendmsg (ACE_HANDLE handle, + const struct msghdr *msg, + int flags, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::sendmsg (handle, msg, flags); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t const bytes_transferred = + ACE_OS::sendmsg (handle, msg, flags); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::sendto (ACE_HANDLE handle, + const char *buf, + int len, + int flags, + const struct sockaddr *addr, + int addrlen, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::sendto (handle, buf, len, flags, addr, addrlen); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t const bytes_transferred = + ACE_OS::sendto (handle, buf, len, flags, addr, addrlen); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE_OS::send (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. +#if defined (ACE_WIN32) + if (errno == EWOULDBLOCK) // If enobufs no need to loop +#else + if (errno == EWOULDBLOCK || errno == ENOBUFS) +#endif /* ACE_WIN32 */ + { + // Wait for the blocking to subside. + int const result = ACE::handle_write_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE_OS::send (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && (errno == EWOULDBLOCK || errno == ENOBUFS)) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_write_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + { + return result; + } + else + { + return ACE_Utils::truncate_cast (bytes_transferred); + } +} + +#if defined (ACE_HAS_TLI) + +ssize_t +ACE::t_snd_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE_OS::t_snd (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK || errno == ENOBUFS) + { + // Wait for the blocking to subside. + int const result = ACE::handle_write_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return bytes_transferred; +} + +ssize_t +ACE::t_snd_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE_OS::t_snd (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred, + flags); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + (errno == EWOULDBLOCK || errno == ENOBUFS)) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_write_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + return result; + else + return bytes_transferred; +} + +#endif /* ACE_HAS_TLI */ + +ssize_t +ACE::send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + n = ACE::send_i (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred); + // Check EOF. + if (n == 0) + { + return 0; + } + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK || errno == ENOBUFS) + { + // Wait for the blocking to subside. + int const result = ACE::handle_write_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + ssize_t n; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + for (bytes_transferred = 0; + bytes_transferred < len; + bytes_transferred += n) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + n = ACE::send_i (handle, + (char *) buf + bytes_transferred, + len - bytes_transferred); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + (errno == EWOULDBLOCK || errno == ENOBUFS)) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_write_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + { + return result; + } + else + { + return ACE_Utils::truncate_cast (bytes_transferred); + } +} + +// Send N char *ptrs and int lengths. Note that the char *'s precede +// the ints (basically, an varargs version of writev). The count N is +// the *total* number of trailing arguments, *not* a couple of the +// number of tuple pairs! +#if !defined (ACE_LACKS_VA_FUNCTIONS) +ssize_t +ACE::send (ACE_HANDLE handle, size_t n, ...) +{ + va_list argp; + int total_tuples = static_cast (n / 2); + iovec *iovp; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t result = ACE_OS::sendv (handle, iovp, total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +} +#endif /* ACE_LACKS_VA_FUNCTIONS */ + +ssize_t +ACE::sendv (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout) +{ + if (timeout == 0) + return ACE_OS::sendv (handle, iov, iovcnt); + else + { + int val = 0; + if (ACE::enter_send_timedwait (handle, timeout, val) == -1) + return -1; + else + { + ssize_t bytes_transferred = ACE_OS::sendv (handle, iov, iovcnt); + ACE::restore_non_blocking_mode (handle, val); + return bytes_transferred; + } + } +} + +ssize_t +ACE::sendv_n_i (ACE_HANDLE handle, + const iovec *i, + int iovcnt, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + iovec *iov = const_cast (i); + + for (int s = 0; + s < iovcnt; + ) + { + // Try to transfer as much of the remaining data as possible. + ssize_t n = ACE_OS::sendv (handle, iov + s, iovcnt - s); + + // Check EOF. + if (n == 0) + return 0; + + // Check for other errors. + if (n == -1) + { + // Check for possible blocking. + if (errno == EWOULDBLOCK || errno == ENOBUFS) + { + // Wait for the blocking to subside. + int const result = ACE::handle_write_ready (handle, 0); + + // Did select() succeed? + if (result != -1) + { + // Blocking subsided. Continue data transfer. + n = 0; + continue; + } + } + + // Other data transfer or select() failures. + return -1; + } + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = reinterpret_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::sendv_n_i (ACE_HANDLE handle, + const iovec *i, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + ssize_t result = 0; + int error = 0; + + int val = 0; + ACE::record_and_set_non_blocking_mode (handle, val); + + iovec *iov = const_cast (i); + + for (int s = 0; + s < iovcnt; + ) + { + // Try to transfer as much of the remaining data as possible. + // Since the socket is in non-blocking mode, this call will not + // block. + ssize_t n = ACE_OS::sendv (handle, iov + s, iovcnt - s); + + // Check for errors. + if (n == 0 || + n == -1) + { + // Check for possible blocking. + if (n == -1 && + (errno == EWOULDBLOCK || errno == ENOBUFS)) + { + // Wait upto for the blocking to subside. + int const rtn = ACE::handle_write_ready (handle, timeout); + + // Did select() succeed? + if (rtn != -1) + { + // Blocking subsided in period. Continue + // data transfer. + n = 0; + continue; + } + } + + // Wait in select() timed out or other data transfer or + // select() failures. + error = 1; + result = n; + break; + } + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = reinterpret_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + ACE::restore_non_blocking_mode (handle, val); + + if (error) + { + return result; + } + else + { + return ACE_Utils::truncate_cast (bytes_transferred); + } +} + +ssize_t +ACE::write_n (ACE_HANDLE handle, + const ACE_Message_Block *message_block, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + iovec iov[ACE_IOV_MAX]; + int iovcnt = 0; + + while (message_block != 0) + { + // Our current message block chain. + const ACE_Message_Block *current_message_block = message_block; + + while (current_message_block != 0) + { + size_t current_message_block_length = + current_message_block->length (); + char *this_block_ptr = current_message_block->rd_ptr (); + + // Check if this block has any data to be sent. + while (current_message_block_length > 0) + { + u_long const this_chunk_length = + ACE_Utils::truncate_cast ( + current_message_block_length); + + // Collect the data in the iovec. + iov[iovcnt].iov_base = this_block_ptr; + iov[iovcnt].iov_len = this_chunk_length; + current_message_block_length -= this_chunk_length; + this_block_ptr += this_chunk_length; + + // Increment iovec counter. + ++iovcnt; + + // The buffer is full make a OS call. @@ TODO find a way to + // find ACE_IOV_MAX for platforms that do not define it rather + // than simply setting ACE_IOV_MAX to some arbitrary value such + // as 16. + if (iovcnt == ACE_IOV_MAX) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::writev_n (handle, + iov, + iovcnt, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + return result; + + // Reset iovec counter. + iovcnt = 0; + } + } + + // Select the next message block in the chain. + current_message_block = current_message_block->cont (); + } + + // Selection of the next message block chain. + message_block = message_block->next (); + } + + // Check for remaining buffers to be sent. This will happen when + // ACE_IOV_MAX is not a multiple of the number of message blocks. + if (iovcnt != 0) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::writev_n (handle, + iov, + iovcnt, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + return result; + } + + // Return total bytes transferred. + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::send_n (ACE_HANDLE handle, + const ACE_Message_Block *message_block, + const ACE_Time_Value *timeout, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + iovec iov[ACE_IOV_MAX]; + int iovcnt = 0; + + while (message_block != 0) + { + // Our current message block chain. + const ACE_Message_Block *current_message_block = message_block; + + while (current_message_block != 0) + { + char *this_block_ptr = current_message_block->rd_ptr (); + size_t current_message_block_length = + current_message_block->length (); + + // Check if this block has any data to be sent. + while (current_message_block_length > 0) + { + u_long const this_chunk_length = + ACE_Utils::truncate_cast ( + current_message_block_length); + + // Collect the data in the iovec. + iov[iovcnt].iov_base = this_block_ptr; + iov[iovcnt].iov_len = this_chunk_length; + current_message_block_length -= this_chunk_length; + this_block_ptr += this_chunk_length; + + // Increment iovec counter. + ++iovcnt; + + // The buffer is full make a OS call. @@ TODO find a way to + // find ACE_IOV_MAX for platforms that do not define it rather + // than simply setting ACE_IOV_MAX to some arbitrary value such + // as 16. + if (iovcnt == ACE_IOV_MAX) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::sendv_n (handle, + iov, + iovcnt, + timeout, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + return result; + + // Reset iovec counter. + iovcnt = 0; + } + } + + // Select the next message block in the chain. + current_message_block = current_message_block->cont (); + } + + // Selection of the next message block chain. + message_block = message_block->next (); + } + + // Check for remaining buffers to be sent. This will happen when + // ACE_IOV_MAX is not a multiple of the number of message blocks. + if (iovcnt != 0) + { + size_t current_transfer = 0; + + ssize_t const result = ACE::sendv_n (handle, + iov, + iovcnt, + timeout, + ¤t_transfer); + + // Add to total bytes transferred. + bytes_transferred += current_transfer; + + // Errors. + if (result == -1 || result == 0) + { + return result; + } + } + + // Return total bytes transferred. + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::readv_n (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + for (int s = 0; + s < iovcnt; + ) + { + ssize_t n = ACE_OS::readv (handle, + iov + s, + iovcnt - s); + + if (n == -1 || n == 0) + return n; + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = reinterpret_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +ssize_t +ACE::writev_n (ACE_HANDLE handle, + const iovec *i, + int iovcnt, + size_t *bt) +{ + size_t temp; + size_t &bytes_transferred = bt == 0 ? temp : *bt; + bytes_transferred = 0; + + iovec *iov = const_cast (i); + + for (int s = 0; + s < iovcnt; + ) + { + ssize_t n = ACE_OS::writev (handle, + iov + s, + iovcnt - s); + + if (n == -1 || n == 0) + { + return n; + } + + for (bytes_transferred += n; + s < iovcnt + && n >= static_cast (iov[s].iov_len); + s++) + n -= iov[s].iov_len; + + if (n != 0) + { + char *base = reinterpret_cast (iov[s].iov_base); + iov[s].iov_base = base + n; + // This blind cast is safe because n < iov_len, after above loop. + iov[s].iov_len = iov[s].iov_len - static_cast (n); + } + } + + return ACE_Utils::truncate_cast (bytes_transferred); +} + +int +ACE::handle_ready (ACE_HANDLE handle, + const ACE_Time_Value *timeout, + int read_ready, + int write_ready, + int exception_ready) +{ +#if defined (ACE_HAS_POLL) + ACE_UNUSED_ARG (exception_ready); + + struct pollfd fds; + + fds.fd = handle; + fds.events = read_ready ? POLLIN : 0; + + if( write_ready ) + { + fds.events |= POLLOUT; + } + + fds.revents = 0; + + int const result = ACE_OS::poll (&fds, 1, timeout); +#else + ACE_Handle_Set handle_set; + handle_set.set_bit (handle); + + // Wait for data or for the timeout to elapse. + int select_width = 0; +#if !defined (ACE_WIN32) + select_width = int (handle) + 1; +# endif /* ACE_WIN64 */ + int result = ACE_OS::select (select_width, + read_ready ? handle_set.fdset () : 0, // read_fds. + write_ready ? handle_set.fdset () : 0, // write_fds. + exception_ready ? handle_set.fdset () : 0, // exception_fds. + timeout); + +#endif /* ACE_HAS_POLL */ + switch (result) + { + case 0: // Timer expired. + errno = ETIME; + /* FALLTHRU */ + case -1: // we got here directly - select() returned -1. + return -1; + case 1: // Handle has data. + /* FALLTHRU */ + default: // default is case result > 0; return a + // ACE_ASSERT (result == 1); + return result; + } +} + +int +ACE::enter_recv_timedwait (ACE_HANDLE handle, + const ACE_Time_Value *timeout, + int &val) +{ + int const result = ACE::handle_read_ready (handle, timeout); + + if (result == -1) + return -1; + + ACE::record_and_set_non_blocking_mode (handle, val); + + return result; +} + +int +ACE::enter_send_timedwait (ACE_HANDLE handle, + const ACE_Time_Value *timeout, + int &val) +{ + int const result = ACE::handle_write_ready (handle, timeout); + + if (result == -1) + return -1; + + ACE::record_and_set_non_blocking_mode (handle, val); + + return result; +} + +void +ACE::record_and_set_non_blocking_mode (ACE_HANDLE handle, int &val) +{ + // We need to record whether we are already *in* nonblocking mode, + // so that we can correctly reset the state when we're done. + val = ACE::get_flags (handle); + + if (ACE_BIT_DISABLED (val, ACE_NONBLOCK)) + // Set the handle into non-blocking mode if it's not already in + // it. + ACE::set_flags (handle, ACE_NONBLOCK); +} + +void +ACE::restore_non_blocking_mode (ACE_HANDLE handle, int val) +{ + if (ACE_BIT_DISABLED (val, ACE_NONBLOCK)) + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + // Only disable ACE_NONBLOCK if we weren't in non-blocking mode + // originally. + ACE::clr_flags (handle, ACE_NONBLOCK); + } +} + +/// Format buffer into printable format. This is useful for debugging. +/// Portions taken from mdump by J.P. Knight (J.P.Knight@lut.ac.uk) +/// Modifications by Todd Montgomery. +size_t +ACE::format_hexdump (const char *buffer, + size_t size, + ACE_TCHAR *obuf, + size_t obuf_sz) +{ + ACE_TRACE ("ACE::format_hexdump"); + + u_char c; + ACE_TCHAR textver[16 + 1]; + + // We can fit 16 bytes output in text mode per line, 4 chars per byte. + size_t maxlen = (obuf_sz / 68) * 16; + const ACE_TCHAR *const obuf_start = obuf; + + if (size > maxlen) + size = maxlen; + + size_t i; + + size_t const lines = size / 16; + for (i = 0; i < lines; i++) + { + size_t j; + + for (j = 0 ; j < 16; j++) + { + c = (u_char) buffer[(i << 4) + j]; // or, buffer[i*16+j] + ACE_OS::snprintf (obuf, obuf_sz - (obuf - obuf_start), + ACE_TEXT ("%02x "), + c); + obuf += 3; + if (j == 7) + { + *obuf++ = ACE_TEXT (' '); + } + textver[j] = ACE_OS::ace_isprint (c) ? c : u_char ('.'); + } + + textver[j] = 0; + + ACE_OS::snprintf (obuf, obuf_sz - (obuf - obuf_start), +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_TEXT (" %ls\n"), +#else + ACE_TEXT (" %s\n"), +#endif + textver); + + while (*obuf != '\0') + ++obuf; + } + + if (size % 16) + { + for (i = 0 ; i < size % 16; i++) + { + c = (u_char) buffer[size - size % 16 + i]; + ACE_OS::snprintf (obuf, obuf_sz - (obuf - obuf_start), + ACE_TEXT ("%02x "), + c); + obuf += 3; + if (i == 7) + { + *obuf++ = ACE_TEXT (' '); + } + textver[i] = ACE_OS::ace_isprint (c) ? c : u_char ('.'); + } + + for (i = size % 16; i < 16; i++) + { + ACE_OS::snprintf (obuf, obuf_sz - (obuf - obuf_start), + ACE_TEXT (" ")); + obuf += 3; + if (i == 7) + { + *obuf++ = ACE_TEXT (' '); + } + textver[i] = ' '; + } + + textver[i] = 0; + ACE_OS::snprintf (obuf, obuf_sz - (obuf - obuf_start), +#if !defined (ACE_WIN32) && defined (ACE_USES_WCHAR) + ACE_TEXT (" %ls\n"), +#else + ACE_TEXT (" %s\n"), +#endif + textver); + } + return size; +} + +/// Returns the current timestamp in the form +/// "hour:minute:second:microsecond." The month, day, and year are +/// also stored in the beginning of the date_and_time array +/// using ISO-8601 format. +ACE_TCHAR * +ACE::timestamp (ACE_TCHAR date_and_time[], + size_t date_and_timelen, + bool return_pointer_to_first_digit) +{ + return ACE::timestamp (ACE_Time_Value::zero, + date_and_time, + date_and_timelen, + return_pointer_to_first_digit); +} + +/// Returns the given timestamp in the form +/// "hour:minute:second:microsecond." The month, day, and year are +/// also stored in the beginning of the date_and_time array +/// using ISO-8601 format. +/// 012345678901234567890123456 +/// 2010-12-02 12:56:00.123456 +ACE_TCHAR * +ACE::timestamp (const ACE_Time_Value& time_value, + ACE_TCHAR date_and_time[], + size_t date_and_timelen, + bool return_pointer_to_first_digit) +{ + //ACE_TRACE ("ACE::timestamp"); + + // This magic number is from the formatting statement + // farther down this routine. + if (date_and_timelen < 27) + { + errno = EINVAL; + return 0; + } + + ACE_Time_Value cur_time = + (time_value == ACE_Time_Value::zero) ? + ACE_Time_Value (ACE_OS::gettimeofday ()) : time_value; + time_t secs = cur_time.sec (); + struct tm tms; + ACE_OS::localtime_r (&secs, &tms); + ACE_OS::snprintf (date_and_time, + date_and_timelen, + ACE_TEXT ("%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d.%06ld"), + tms.tm_year + 1900, + tms.tm_mon + 1, + tms.tm_mday, + tms.tm_hour, + tms.tm_min, + tms.tm_sec, + static_cast (cur_time.usec())); + date_and_time[date_and_timelen - 1] = '\0'; + return &date_and_time[10 + (return_pointer_to_first_digit != 0)]; +} + +/// This function rounds the request to a multiple of the page size. +size_t +ACE::round_to_pagesize (size_t len) +{ + ACE_TRACE ("ACE::round_to_pagesize"); + + if (ACE::pagesize_ == 0) + ACE::pagesize_ = ACE_OS::getpagesize (); + + return (len + (ACE::pagesize_ - 1)) & ~(ACE::pagesize_ - 1); +} + +size_t +ACE::round_to_allocation_granularity (size_t len) +{ + ACE_TRACE ("ACE::round_to_allocation_granularity"); + + if (ACE::allocation_granularity_ == 0) + ACE::allocation_granularity_ = ACE_OS::allocation_granularity (); + + return (len + (ACE::allocation_granularity_ - 1)) & ~(ACE::allocation_granularity_ - 1); +} + +ACE_HANDLE +ACE::handle_timed_complete (ACE_HANDLE h, + const ACE_Time_Value *timeout, + int is_tli) +{ + ACE_TRACE ("ACE::handle_timed_complete"); + +#if !defined (ACE_WIN32) && defined (ACE_HAS_POLL) + + struct pollfd fds; + + fds.fd = h; + fds.events = POLLIN | POLLOUT; + fds.revents = 0; + +#else + ACE_Handle_Set rd_handles; + ACE_Handle_Set wr_handles; + rd_handles.set_bit (h); + wr_handles.set_bit (h); +#endif /* !ACE_WIN32 && ACE_HAS_POLL */ + +#if defined (ACE_WIN32) + // Winsock is different - it sets the exception bit for failed connect, + // unlike other platforms, where the write bit is set for both success + // and fail. + ACE_Handle_Set ex_handles; + ex_handles.set_bit (h); +#endif /* ACE_WIN32 */ + + bool need_to_check = false; + bool known_failure = false; + +#if defined (ACE_WIN32) + int n = ACE_OS::select (0, // Ignored on Windows: int (h) + 1, + 0, + wr_handles, + ex_handles, + timeout); +#else +# if defined (ACE_HAS_POLL) + + int n = ACE_OS::poll (&fds, 1, timeout); + +# else + int n = 0; + if (is_tli) + n = ACE_OS::select (int (h) + 1, + rd_handles, + wr_handles, + 0, + timeout); + else + n = ACE_OS::select (int (h) + 1, + 0, + wr_handles, + 0, + timeout); +# endif /* ACE_HAS_POLL */ +#endif /* ACE_WIN32 */ + + // If we failed to connect within the time period allocated by the + // caller, then we fail (e.g., the remote host might have been too + // busy to accept our call). + if (n <= 0) + { + if (n == 0 && timeout != 0) + errno = ETIME; + return ACE_INVALID_HANDLE; + } + + // On Windows, a ready-for-write handle is successfully connected, and + // ready-for-exception is a failure. On fails, we need to grab the error + // code via getsockopt. + // On BSD sockets using select(), the handle becomes writable on + // completion either success or fail, so if the select() does not time + // out, we need to check for success/fail. + // It is believed that TLI sockets use the readable=fail, writeable=success + // but that hasn't been as well tested. +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (is_tli); + + // On Win32, ex_handle set indicates a failure. We'll do the check + // to try and get an errno value, but the connect failed regardless of + // what getsockopt says about the error. + if (ex_handles.is_set (h)) + { + need_to_check = true; + known_failure = true; + } +#else + if (is_tli) +# if defined (ACE_HAS_POLL) + need_to_check = (fds.revents & POLLIN) && !(fds.revents & POLLOUT); +# else + need_to_check = rd_handles.is_set (h) && !wr_handles.is_set (h); +# endif /* ACE_HAS_POLL */ + + else +# if defined (ACE_HAS_POLL) + { + // The "official" bit for failed connect is POLLIN. However, POLLERR + // is often set and there are occasional cases seen with some kernels + // where only POLLERR is set on a failed connect. + need_to_check = (fds.revents & POLLIN) || (fds.revents & POLLERR); + known_failure = (fds.revents & POLLERR); + } +# else + need_to_check = true; +# endif /* ACE_HAS_POLL */ +#endif /* ACE_WIN32 */ + + if (need_to_check) + { +#if defined (SOL_SOCKET) && defined (SO_ERROR) + int sock_err = 0; + int sock_err_len = sizeof (sock_err); + int sockopt_ret = ACE_OS::getsockopt (h, SOL_SOCKET, SO_ERROR, + (char *)&sock_err, &sock_err_len); + if (sockopt_ret < 0) + { + h = ACE_INVALID_HANDLE; + } + + if (sock_err != 0 || known_failure) + { + h = ACE_INVALID_HANDLE; + errno = sock_err; + } +#else + char dummy; + + // The following recv() won't block provided that the + // ACE_NONBLOCK flag has not been turned off . + n = ACE::recv (h, &dummy, 1, MSG_PEEK); + + // If no data was read/peeked at, check to see if it's because + // of a non-connected socket (and therefore an error) or there's + // just no data yet. + if (n <= 0) + { + if (n == 0) + { + errno = ECONNREFUSED; + h = ACE_INVALID_HANDLE; + } + else if (errno != EWOULDBLOCK && errno != EAGAIN) + h = ACE_INVALID_HANDLE; + } +#endif + } + + // 1. The HANDLE is ready for writing and doesn't need to be checked or + // 2. recv() returned an indication of the state of the socket - if there is + // either data present, or a recv is legit but there's no data yet, + // the connection was successfully established. + return h; +} + +/// Wait up to @a timeout amount of time to accept a connection. +int +ACE::handle_timed_accept (ACE_HANDLE listener, + ACE_Time_Value *timeout, + bool restart) +{ + ACE_TRACE ("ACE::handle_timed_accept"); + // Make sure we don't bomb out on erroneous values. + if (listener == ACE_INVALID_HANDLE) + return -1; + +#if defined (ACE_HAS_POLL) + + struct pollfd fds; + + fds.fd = listener; + fds.events = POLLIN; + fds.revents = 0; + +#else + // Use the select() implementation rather than poll(). + ACE_Handle_Set rd_handle; + rd_handle.set_bit (listener); +#endif /* ACE_HAS_POLL */ + + // We need a loop here if is enabled. + + for (;;) + { +#if defined (ACE_HAS_POLL) + + int n = ACE_OS::poll (&fds, 1, timeout); + +#else + int select_width = 0; +# if !defined (ACE_WIN32) + select_width = int (listener) + 1; +# endif /* ACE_WIN32 */ + int n = ACE_OS::select (select_width, + rd_handle, 0, 0, + timeout); +#endif /* ACE_HAS_POLL */ + + switch (n) + { + case -1: + if (errno == EINTR && restart) + continue; + else + return -1; + /* NOTREACHED */ + case 0: + if (timeout != 0 && *timeout == ACE_Time_Value::zero) + errno = EWOULDBLOCK; + else + errno = ETIMEDOUT; + return -1; + /* NOTREACHED */ + case 1: + return 0; + /* NOTREACHED */ + default: + errno = EINVAL; + return -1; + /* NOTREACHED */ + } + } +} + +/// Make the current process a UNIX daemon. This is based on Stevens +/// code from APUE. +int +ACE::daemonize (const ACE_TCHAR pathname[], + bool close_all_handles, + const ACE_TCHAR program_name[]) +{ + ACE_TRACE ("ACE::daemonize"); +#if !defined (ACE_LACKS_FORK) + pid_t pid = ACE_OS::fork (); + + if (pid == -1) + return -1; + else if (pid != 0) + ACE_OS::exit (0); // Parent exits. + + // 1st child continues. + ACE_OS::setsid (); // Become session leader. + + ACE_OS::signal (SIGHUP, SIG_IGN); + + pid = ACE_OS::fork (program_name); + + if (pid != 0) + ACE_OS::exit (0); // First child terminates. + + // Second child continues. + + if (pathname != 0) + // change working directory. + ACE_OS::chdir (pathname); + + ACE_OS::umask (0); // clear our file mode creation mask. + + // Close down the I/O handles. + if (close_all_handles) + { + for (int i = ACE::max_handles () - 1; i >= 0; i--) + ACE_OS::close (i); + + int fd = ACE_OS::open ("/dev/null", O_RDWR, 0); + if (fd != -1) + { + ACE_OS::dup2 (fd, ACE_STDIN); + ACE_OS::dup2 (fd, ACE_STDOUT); + ACE_OS::dup2 (fd, ACE_STDERR); + + if (fd > ACE_STDERR) + ACE_OS::close (fd); + } + } + + return 0; +#else + ACE_UNUSED_ARG (pathname); + ACE_UNUSED_ARG (close_all_handles); + ACE_UNUSED_ARG (program_name); + + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_LACKS_FORK */ +} + +pid_t +ACE::fork (const ACE_TCHAR *program_name, + int avoid_zombies) +{ + if (avoid_zombies == 0) + return ACE_OS::fork (program_name); + else + { + // This algorithm is adapted from an example in the Stevens book + // "Advanced Programming in the Unix Environment" and an item in + // Andrew Gierth's Unix Programming FAQ. It creates an orphan + // process that's inherited by the init process; init cleans up + // when the orphan process terminates. + // + // Another way to avoid zombies is to ignore or catch the + // SIGCHLD signal; we don't use that approach here. + + pid_t pid = ACE_OS::fork (); + if (pid == 0) + { + // The child process forks again to create a grandchild. + switch (ACE_OS::fork (program_name)) + { + case 0: // grandchild returns 0. + return 0; + case -1: // assumes all errnos are < 256 + ACE_OS::_exit (errno); + default: // child terminates, orphaning grandchild + ACE_OS::_exit (0); + } + } + + // Parent process waits for child to terminate. + ACE_exitcode status; + if (pid < 0 || ACE_OS::waitpid (pid, &status, 0) < 0) + return -1; + + // child terminated by calling exit()? + if (WIFEXITED ((status))) + { + // child terminated normally? + if (WEXITSTATUS ((status)) == 0) + return 1; + else + errno = WEXITSTATUS ((status)); + } + else + // child didn't call exit(); perhaps it received a signal? + errno = EINTR; + + return -1; + } +} + +int +ACE::max_handles (void) +{ + ACE_TRACE ("ACE::max_handles"); +#if defined (RLIMIT_NOFILE) && !defined (ACE_LACKS_RLIMIT) + rlimit rl; + int const r = ACE_OS::getrlimit (RLIMIT_NOFILE, &rl); +# if !defined (RLIM_INFINITY) + if (r == 0) + return rl.rlim_cur; +# else + if (r == 0 && rl.rlim_cur != RLIM_INFINITY) + return rl.rlim_cur; + // If == RLIM_INFINITY, fall through to the ACE_LACKS_RLIMIT sections +# endif /* RLIM_INFINITY */ +#endif /* RLIMIT_NOFILE && !ACE_LACKS_RLIMIT */ + +#if defined (_SC_OPEN_MAX) && !defined (ACE_LACKS_SYSCONF) + return static_cast (ACE_OS::sysconf (_SC_OPEN_MAX)); +#elif defined (FD_SETSIZE) + return FD_SETSIZE; +#else + ACE_NOTSUP_RETURN (-1); +#endif /* _SC_OPEN_MAX */ +} + +// Set the number of currently open handles in the process. +// +// If NEW_LIMIT == -1 set the limit to the maximum allowable. +// Otherwise, set it to be the value of NEW_LIMIT. + +int +ACE::set_handle_limit (int new_limit, + int increase_limit_only) +{ + ACE_TRACE ("ACE::set_handle_limit"); + int cur_limit = ACE::max_handles (); + int max_limit = cur_limit; + + if (cur_limit == -1) + return -1; + +#if !defined (ACE_LACKS_RLIMIT) && defined (RLIMIT_NOFILE) + struct rlimit rl; + + ACE_OS::memset ((void *) &rl, 0, sizeof rl); + int r = ACE_OS::getrlimit (RLIMIT_NOFILE, &rl); + if (r == 0) + max_limit = rl.rlim_max; +#endif /* ACE_LACKS_RLIMIT */ + + if (new_limit == -1) + new_limit = max_limit; + + if (new_limit < 0) + { + errno = EINVAL; + return -1; + } + else if (new_limit > cur_limit) + { + // Increase the limit. +#if !defined (ACE_LACKS_RLIMIT) && defined (RLIMIT_NOFILE) + rl.rlim_cur = new_limit; + return ACE_OS::setrlimit (RLIMIT_NOFILE, &rl); +#elif !defined (RLIMIT_NOFILE) + return 0; +#else + // Must return EINVAL errno. + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_LACKS_RLIMIT */ + } + else if (increase_limit_only == 0) + { + // Decrease the limit. +#if !defined (ACE_LACKS_RLIMIT) && defined (RLIMIT_NOFILE) + rl.rlim_cur = new_limit; + return ACE_OS::setrlimit (RLIMIT_NOFILE, &rl); +#else + // We give a chance to platforms without RLIMIT to work. + // Instead of ACE_NOTSUP_RETURN (0), just return 0 because + // new_limit is <= cur_limit, so it's a no-op. + return 0; +#endif /* ACE_LACKS_RLIMIT */ + } + + return 0; +} + +/// Euclid's greatest common divisor algorithm. +u_long +ACE::gcd (u_long x, u_long y) +{ + while (y != 0) + { + u_long r = x % y; + x = y; + y = r; + } + + return x; +} + + +/// Calculates the minimum enclosing frame size for the given values. +u_long +ACE::minimum_frame_size (u_long period1, u_long period2) +{ + // if one of the periods is zero, treat it as though it as + // uninitialized and return the other period as the frame size + if (0 == period1) + { + return period2; + } + if (0 == period2) + { + return period1; + } + + // if neither is zero, find the greatest common divisor of the two periods + u_long greatest_common_divisor = ACE::gcd (period1, period2); + + // explicitly consider cases to reduce risk of possible overflow errors + if (greatest_common_divisor == 1) + { + // periods are relative primes: just multiply them together + return period1 * period2; + } + else if (greatest_common_divisor == period1) + { + // the first period divides the second: return the second + return period2; + } + else if (greatest_common_divisor == period2) + { + // the second period divides the first: return the first + return period1; + } + else + { + // the current frame size and the entry's effective period + // have a non-trivial greatest common divisor: return the + // product of factors divided by those in their gcd. + return (period1 * period2) / greatest_common_divisor; + } +} + + +u_long +ACE::is_prime (const u_long n, + const u_long min_factor, + const u_long max_factor) +{ + if (n > 3) + for (u_long factor = min_factor; + factor <= max_factor; + ++factor) + if (n / factor * factor == n) + return factor; + + return 0; +} + +const ACE_TCHAR * +ACE::sock_error (int error) +{ +#if defined (ACE_WIN32) + static ACE_TCHAR unknown_msg[64]; + + switch (error) + { + case WSAVERNOTSUPPORTED: + return ACE_TEXT ("version of WinSock not supported"); + /* NOTREACHED */ + case WSASYSNOTREADY: + return ACE_TEXT ("WinSock not present or not responding"); + /* NOTREACHED */ + case WSAEINVAL: + return ACE_TEXT ("app version not supported by DLL"); + /* NOTREACHED */ + case WSAHOST_NOT_FOUND: + return ACE_TEXT ("Authoritive: Host not found"); + /* NOTREACHED */ + case WSATRY_AGAIN: + return ACE_TEXT ("Non-authoritive: host not found or server failure"); + /* NOTREACHED */ + case WSANO_RECOVERY: + return ACE_TEXT ("Non-recoverable: refused or not implemented"); + /* NOTREACHED */ + case WSANO_DATA: + return ACE_TEXT ("Valid name, no data record for type"); + /* NOTREACHED */ + /* + case WSANO_ADDRESS: + return "Valid name, no MX record"; + */ + case WSANOTINITIALISED: + return ACE_TEXT ("WSA Startup not initialized"); + /* NOTREACHED */ + case WSAENETDOWN: + return ACE_TEXT ("Network subsystem failed"); + /* NOTREACHED */ + case WSAEINPROGRESS: + return ACE_TEXT ("Blocking operation in progress"); + /* NOTREACHED */ + case WSAEINTR: + return ACE_TEXT ("Blocking call cancelled"); + /* NOTREACHED */ + case WSAEAFNOSUPPORT: + return ACE_TEXT ("address family not supported"); + /* NOTREACHED */ + case WSAEMFILE: + return ACE_TEXT ("no file handles available"); + /* NOTREACHED */ + case WSAENOBUFS: + return ACE_TEXT ("no buffer space available"); + /* NOTREACHED */ + case WSAEPROTONOSUPPORT: + return ACE_TEXT ("specified protocol not supported"); + /* NOTREACHED */ + case WSAEPROTOTYPE: + return ACE_TEXT ("protocol wrong type for this socket"); + /* NOTREACHED */ + case WSAESOCKTNOSUPPORT: + return ACE_TEXT ("socket type not supported for address family"); + /* NOTREACHED */ + case WSAENOTSOCK: + return ACE_TEXT ("handle is not a socket"); + /* NOTREACHED */ + case WSAEWOULDBLOCK: + return ACE_TEXT ("resource temporarily unavailable"); + /* NOTREACHED */ + case WSAEADDRINUSE: + return ACE_TEXT ("address already in use"); + /* NOTREACHED */ + case WSAECONNABORTED: + return ACE_TEXT ("connection aborted"); + /* NOTREACHED */ + case WSAECONNRESET: + return ACE_TEXT ("connection reset"); + /* NOTREACHED */ + case WSAENOTCONN: + return ACE_TEXT ("not connected"); + /* NOTREACHED */ + case WSAETIMEDOUT: + return ACE_TEXT ("connection timed out"); + /* NOTREACHED */ + case WSAECONNREFUSED: + return ACE_TEXT ("connection refused"); + /* NOTREACHED */ + case WSAEHOSTDOWN: + return ACE_TEXT ("host down"); + /* NOTREACHED */ + case WSAEHOSTUNREACH: + return ACE_TEXT ("host unreachable"); + /* NOTREACHED */ + case WSAEADDRNOTAVAIL: + return ACE_TEXT ("address not available"); + /* NOTREACHED */ + case WSAEISCONN: + return ACE_TEXT ("socket is already connected"); + /* NOTREACHED */ + case WSAENETRESET: + return ACE_TEXT ("network dropped connection on reset"); + /* NOTREACHED */ + case WSAEMSGSIZE: + return ACE_TEXT ("message too long"); + /* NOTREACHED */ + case WSAENETUNREACH: + return ACE_TEXT ("network is unreachable"); + /* NOTREACHED */ + case WSAEFAULT: + return ACE_TEXT ("bad address"); + /* NOTREACHED */ + case WSAEDISCON: + return ACE_TEXT ("graceful shutdown in progress"); + /* NOTREACHED */ + case WSAEACCES: + return ACE_TEXT ("permission denied"); + /* NOTREACHED */ + case WSAESHUTDOWN: + return ACE_TEXT ("cannot send after socket shutdown"); + /* NOTREACHED */ + case WSAEPROCLIM: + return ACE_TEXT ("too many processes"); + /* NOTREACHED */ + case WSAEALREADY: + return ACE_TEXT ("operation already in progress"); + /* NOTREACHED */ + case WSAEPFNOSUPPORT: + return ACE_TEXT ("protocol family not supported"); + /* NOTREACHED */ + case WSAENOPROTOOPT: + return ACE_TEXT ("bad protocol option"); + /* NOTREACHED */ + case WSATYPE_NOT_FOUND: + return ACE_TEXT ("class type not found"); + /* NOTREACHED */ + case WSAEOPNOTSUPP: + return ACE_TEXT ("operation not supported"); + /* NOTREACHED */ + case WSAEDESTADDRREQ: + return ACE_TEXT ("destination address required"); + /* NOTREACHED */ + default: + ACE_OS::snprintf (unknown_msg, + sizeof unknown_msg / sizeof unknown_msg[0], + ACE_TEXT ("unknown error: %d"), error); + return unknown_msg; + /* NOTREACHED */ + } +#else + ACE_UNUSED_ARG (error); + ACE_NOTSUP_RETURN (0); +#endif /* ACE_WIN32 */ +} + +bool +ACE::is_sock_error (int error) +{ +#if defined (ACE_WIN32) + switch (error) + { + case WSAVERNOTSUPPORTED: + case WSASYSNOTREADY: + case WSAEINVAL: + case WSAHOST_NOT_FOUND: + case WSATRY_AGAIN: + case WSANO_RECOVERY: + case WSANO_DATA: + /* + case WSANO_ADDRESS: + */ + case WSANOTINITIALISED: + case WSAENETDOWN: + case WSAEINPROGRESS: + case WSAEINTR: + case WSAEAFNOSUPPORT: + case WSAEMFILE: + case WSAENOBUFS: + case WSAEPROTONOSUPPORT: + case WSAEPROTOTYPE: + case WSAESOCKTNOSUPPORT: + case WSAENOTSOCK: + case WSAEWOULDBLOCK: + case WSAEADDRINUSE: + case WSAECONNABORTED: + case WSAECONNRESET: + case WSAENOTCONN: + case WSAETIMEDOUT: + case WSAECONNREFUSED: + case WSAEHOSTDOWN: + case WSAEHOSTUNREACH: + case WSAEADDRNOTAVAIL: + case WSAEISCONN: + case WSAENETRESET: + case WSAEMSGSIZE: + case WSAENETUNREACH: + case WSAEFAULT: + case WSAEDISCON: + case WSAEACCES: + case WSAESHUTDOWN: + case WSAEPROCLIM: + case WSAEALREADY: + case WSAEPFNOSUPPORT: + case WSAENOPROTOOPT: + case WSATYPE_NOT_FOUND: + case WSAEOPNOTSUPP: + return true; + } +#else + ACE_UNUSED_ARG (error); +#endif /* ACE_WIN32 */ + return false; +} + +char * +ACE::strndup (const char *str, size_t n) +{ + const char *t = str; + size_t len; + + // Figure out how long this string is (remember, it might not be + // NUL-terminated). + + for (len = 0; + len < n && *t++ != '\0'; + len++) + continue; + + char *s; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (s, + (char *) ACE_Allocator::instance()->malloc (len + 1), + 0); +#else + ACE_ALLOCATOR_RETURN (s, + (char *) ACE_OS::malloc (len + 1), + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + return ACE_OS::strsncpy (s, str, len + 1); +} + +#if defined (ACE_HAS_WCHAR) +wchar_t * +ACE::strndup (const wchar_t *str, size_t n) +{ + const wchar_t *t = str; + size_t len; + + // Figure out how long this string is (remember, it might not be + // NUL-terminated). + + for (len = 0; + len < n && *t++ != '\0'; + len++) + continue; + + size_t const size = (len + 1) * sizeof (wchar_t); + wchar_t *s = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (s, + static_cast ( + ACE_Allocator::instance ()->malloc (size)), + 0); +#else + ACE_ALLOCATOR_RETURN (s, + static_cast (ACE_OS::malloc (size)), + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + return ACE_OS::strsncpy (s, str, len + 1); +} +#endif /* ACE_HAS_WCHAR */ + +char * +ACE::strnnew (const char *str, size_t n) +{ + const char *t = str; + size_t len; + + // Figure out how long this string is (remember, it might not be + // NUL-terminated). + + for (len = 0; + len < n && *t++ != L'\0'; + len++) + continue; + + char *s; + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (s, + static_cast (ACE_Allocator::instance ()->malloc (sizeof (char) * (len + 1))), + 0); +#else + ACE_NEW_RETURN (s, + char[len + 1], + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + return ACE_OS::strsncpy (s, str, len + 1); +} + +#if defined (ACE_HAS_WCHAR) +wchar_t * +ACE::strnnew (const wchar_t *str, size_t n) +{ + const wchar_t *t = str; + size_t len; + + // Figure out how long this string is (remember, it might not be + // NUL-terminated). + + for (len = 0; + len < n && *t++ != ACE_TEXT_WIDE ('\0'); + len++) + continue; + + wchar_t *s; + ACE_NEW_RETURN (s, + wchar_t[len + 1], + 0); + return ACE_OS::strsncpy (s, str, len + 1); +} +#endif /* ACE_HAS_WCHAR */ + +const char * +ACE::strend (const char *s) +{ + while (*s++ != '\0') + continue; + + return s; +} + +#if defined ACE_HAS_WCHAR +const wchar_t * +ACE::strend (const wchar_t *s) +{ + while (*s++ != ACE_TEXT_WIDE ('\0')) + continue; + + return s; +} +#endif + +char * +ACE::strnew (const char *s) +{ + if (s == 0) + return 0; + char *t = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (t, + static_cast (ACE_Allocator::instance ()->malloc (sizeof (char) * (ACE_OS::strlen (s) + 1))), + 0); +#else + ACE_NEW_RETURN (t, + char [ACE_OS::strlen (s) + 1], + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + return ACE_OS::strcpy (t, s); +} + +#if defined (ACE_HAS_WCHAR) +wchar_t * +ACE::strnew (const wchar_t *s) +{ + if (s == 0) + return 0; + + size_t const n = ACE_OS::strlen (s) + 1; + wchar_t *t = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (t, + static_cast ( + ACE_Allocator::instance ()->malloc ( + sizeof (wchar_t) * (n))), + 0); +#else + ACE_NEW_RETURN (t, wchar_t[n], 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + return ACE_OS::strcpy (t, s); +} +#endif /* ACE_HAS_WCHAR */ + +// helper functions for ACE::wild_match() +namespace +{ + + inline bool equal_char (char a, char b, bool case_sensitive) + { + if (case_sensitive) + return a == b; + return ACE_OS::ace_tolower (a) == ACE_OS::ace_tolower (b); + } + + // precond: *p == '[' start of char class + // postcond: *p == ']' end of the char class + inline bool equal_class (char s, const char *&p, bool case_sensitive) + { + ++p; + bool negate = false; + if (*p == '!') + { + negate = true; + ++p; + } + // ] and - are regular in 1st position + for (bool first = true; *p && (first || *p != ']'); ++p) + { + if (!first && *p == '-' && p[1] != ']') + { + if (!p[1] || p[1] <= p[-1]) // invalid range + { + continue; + } + // Since we are in the POSIX locale, only the basic ASCII + // characters are allowed as the range endpoints. These characters + // are the same values in both signed and unsigned chars so we + // don't have to account for any "pathological cases." + for (char range = static_cast (p[-1] + 1); range <= p[1]; ++range) + { + if (equal_char (s, range, case_sensitive)) + { + while (*++p != ']') {} + return !negate; + } + } + ++p; // consume the character 1 past the - + } + else if (equal_char (s, *p, case_sensitive)) + { + while (*++p != ']') {} + return !negate; + } + first = false; + } + return negate; + } +} + +bool +ACE::wild_match(const char *str, const char *pat, bool case_sensitive, + bool character_classes) +{ + if (str == pat) + return true; + if (pat == 0 || str == 0) + return false; + + bool star = false, escape = false; + const char *s = str; + const char *p = pat; + while (*s != '\0') + { + if (!escape && *p == '\\') + { + ++p; + escape = true; + } + else if (!escape && *p == '*') + { + star = true; + pat = p; + while (*++pat == '*') {} + + if (*pat == '\0') + return true; + p = pat; + } + else if (!escape && *p == '?') + { + ++s; + ++p; + } + else if (!escape && character_classes && *p == '[') + { + if (equal_class (*s, p, case_sensitive)) + { + ++p; + } + else + { + if (!star) + return false; + p = pat; + } + ++s; + } + else if (!equal_char (*s, *p, case_sensitive)) + { + if (!star) + return false; + ++s; + p = pat; + escape = false; + } + else + { + ++s; + ++p; + escape = false; + } + } + if (*p == '*') + while (*++p == '*') {} + + return *p == '\0'; +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ACE.h b/dep/acelite/ace/ACE.h new file mode 100644 index 000000000..711363019 --- /dev/null +++ b/dep/acelite/ace/ACE.h @@ -0,0 +1,892 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file ACE.h + * + * This file contains value added ACE functions that extend the + * behavior of the UNIX and Win32 OS calls. + * + * All these ACE static functions are consolidated in a single place + * in order to manage the namespace better. These functions are put + * here rather than in @c ACE_OS in order to separate concerns. + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ACE_H +#define ACE_ACE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-lite.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Types.h" +#include "ace/Default_Constants.h" + +#if defined (ACE_EXPORT_MACRO) +# undef ACE_EXPORT_MACRO +#endif +#define ACE_EXPORT_MACRO ACE_Export + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations. +class ACE_Time_Value; +class ACE_Message_Block; +class ACE_Handle_Set; + +/** + * @namespace ACE + * + * @brief The namespace containing the ACE framework itself. + * + * The ACE namespace contains all types (classes, structures, + * typedefs, etc), and global functions and variables in the ACE + * framework. + */ +namespace ACE +{ + // = ACE version information. + /// e.g., the "6" in ACE 6.3.4 + extern ACE_Export u_int major_version (void); + + /// e.g., the "3" in ACE 6.3.4 + extern ACE_Export u_int minor_version (void); + + /// e.g., the "4" in ACE 6.3.4 + /// Returns 0 for "stable" (non-micro) releases. + extern ACE_Export u_int micro_version (void); + + /// e.g., the "4" in ACE 6.3.4 + /// Returns 0 for "stable" (non-micro) releases. + extern ACE_Export u_int beta_version (void); + + // = C++ compiler version information. + /// E.g., the "SunPro C++" in SunPro C++ 4.32.0 + extern ACE_Export const ACE_TCHAR * compiler_name (void); + + /// E.g., the "4" in SunPro C++ 4.32.0 + extern ACE_Export u_int compiler_major_version (void); + + /// E.g., the "32" in SunPro C++ 4.32.0 + extern ACE_Export u_int compiler_minor_version (void); + + /// E.g., the "0" in SunPro C++ 4.32.0 + extern ACE_Export u_int compiler_beta_version (void); + + /// Check if error indicates the process being out of handles (file + /// descriptors). + extern ACE_Export int out_of_handles (int error); + + /// Simple wildcard matching function supporting '*' and '?' + /// return true if string s matches pattern. + /// If @a character_classes is true, '[' is treated as a wildcard character + /// as described in the fnmatch() POSIX API. The following POSIX "bracket + /// expression" features are not implemented: collating symbols, equivalence + /// class expressions, and character class expressions. The POSIX locale is + /// assumed. + extern ACE_Export bool wild_match(const char* s, const char* pattern, + bool case_sensitive = true, bool character_classes = false); + + /** + * @name I/O operations + * + * Notes on common parameters: + * + * @a handle is the connected endpoint that will be used for I/O. + * + * @a buf is the buffer to write from or receive into. + * + * @a len is the number of bytes to transfer. + * + * The @a timeout parameter in the following methods indicates how + * long to blocking trying to transfer data. If @a timeout == 0, + * then the call behaves as a normal send/recv call, i.e., for + * blocking sockets, the call will block until action is possible; + * for non-blocking sockets, @c EWOULDBLOCK will be returned if no + * action is immediately possible. + * + * If @a timeout != 0, the call will wait until the relative time + * specified in @a *timeout elapses. + * + * The "_n()" I/O methods keep looping until all the data has been + * transferred. These methods also work for sockets in non-blocking + * mode i.e., they keep looping on @c EWOULDBLOCK. @a timeout is + * used to make sure we keep making progress, i.e., the same timeout + * value is used for every I/O operation in the loop and the timeout + * is not counted down. + * + * The return values for the "*_n()" methods match the return values + * from the non "_n()" methods and are specified as follows: + * + * - On complete transfer, the number of bytes transferred is returned. + * - On timeout, -1 is returned, @c errno == @c ETIME. + * - On error, -1 is returned, @c errno is set to appropriate error. + * - On @c EOF, 0 is returned, @c errno is irrelevant. + * + * On partial transfers, i.e., if any data is transferred before + * timeout / error / @c EOF, @a bytes_transferred> will contain the + * number of bytes transferred. + * + * Methods with @a iovec parameter are I/O vector variants of the + * I/O operations. + * + * Methods with the extra @a flags argument will always result in + * @c send getting called. Methods without the extra @a flags + * argument will result in @c send getting called on Win32 + * platforms, and @c write getting called on non-Win32 platforms. + */ + //@{ + extern ACE_Export ssize_t recv (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0); + +#if defined (ACE_HAS_TLI) + + extern ACE_Export ssize_t t_rcv (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout = 0); + +#endif /* ACE_HAS_TLI */ + + extern ACE_Export ssize_t recv (ACE_HANDLE handle, + void *buf, + size_t len, + const ACE_Time_Value *timeout = 0); + + extern ACE_Export ssize_t recvmsg (ACE_HANDLE handle, + struct msghdr *msg, + int flags, + const ACE_Time_Value *timeout = 0); + + extern ACE_Export ssize_t recvfrom (ACE_HANDLE handle, + char *buf, + int len, + int flags, + struct sockaddr *addr, + int *addrlen, + const ACE_Time_Value *timeout = 0); + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t recv_n (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + +#if defined (ACE_HAS_TLI) + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t t_rcv_n (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + +#endif /* ACE_HAS_TLI */ + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t recv_n (ACE_HANDLE handle, + void *buf, + size_t len, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + /// Receive into a variable number of pieces. + /** + * Accepts a variable, caller-specified, number of pointer/length + * pairs. Arguments following @a n are char *, size_t pairs. + * + * @param handle The I/O handle to receive on + * @param n The total number of char *, size_t pairs following @a n. + * + * @return -1 on error, else total number of bytes received. + */ +#if !defined (ACE_LACKS_VA_FUNCTIONS) + extern ACE_Export ssize_t recv (ACE_HANDLE handle, size_t n, ...); +#endif /* ACE_LACKS_VA_FUNCTIONS */ + + extern ACE_Export ssize_t recvv (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout = 0); + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t recvv_n (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + extern ACE_Export ssize_t recv_n (ACE_HANDLE handle, + ACE_Message_Block *message_block, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + extern ACE_Export ssize_t send (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0); + +#if defined (ACE_HAS_TLI) + + extern ACE_Export ssize_t t_snd (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0); + +#endif /* ACE_HAS_TLI */ + + extern ACE_Export ssize_t send (ACE_HANDLE handle, + const void *buf, + size_t len, + const ACE_Time_Value *timeout = 0); + + extern ACE_Export ssize_t sendmsg (ACE_HANDLE handle, + const struct msghdr *msg, + int flags, + const ACE_Time_Value *timeout = 0); + + extern ACE_Export ssize_t sendto (ACE_HANDLE handle, + const char *buf, + int len, + int flags, + const struct sockaddr *addr, + int addrlen, + const ACE_Time_Value *timeout = 0); + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t send_n (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + +#if defined (ACE_HAS_TLI) + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t t_snd_n (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + +#endif /* ACE_HAS_TLI */ + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t send_n (ACE_HANDLE handle, + const void *buf, + size_t len, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + /// Varargs variant. +#if !defined (ACE_LACKS_VA_FUNCTIONS) + extern ACE_Export ssize_t send (ACE_HANDLE handle, size_t n, ...); +#endif /* ACE_LACKS_VA_FUNCTIONS */ + + extern ACE_Export ssize_t sendv (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout = 0); + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t sendv_n (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + /// Send all the @a message_blocks chained through their @c next and + /// @c cont pointers. This call uses the underlying OS gather-write + /// operation to reduce the domain-crossing penalty. + extern ACE_Export ssize_t send_n (ACE_HANDLE handle, + const ACE_Message_Block *message_block, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + // = File system I/O functions (these don't support timeouts). + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t read_n (ACE_HANDLE handle, + void *buf, + size_t len, + size_t *bytes_transferred = 0); + + ACE_NAMESPACE_INLINE_FUNCTION + ssize_t write_n (ACE_HANDLE handle, + const void *buf, + size_t len, + size_t *bytes_transferred = 0); + + /// Write all the @a message_blocks chained through their @c next + /// and @c cont pointers. This call uses the underlying OS + /// gather-write operation to reduce the domain-crossing penalty. + extern ACE_Export ssize_t write_n (ACE_HANDLE handle, + const ACE_Message_Block *message_block, + size_t *bytes_transferred = 0); + + extern ACE_Export ssize_t readv_n (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + size_t *bytes_transferred = 0); + + extern ACE_Export ssize_t writev_n (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + size_t *bytes_transferred = 0); + //@} + + /** + * Wait up to @a timeout amount of time to passively establish a + * connection. This method doesn't perform the @c accept, it just + * does the timed wait. + */ + extern ACE_Export int handle_timed_accept (ACE_HANDLE listener, + ACE_Time_Value *timeout, + bool restart); + + /** + * Wait up to @a timeout amount of time to complete an actively + * established non-blocking connection. If @a is_tli is non-0 then + * we are being called by a TLI wrapper (which behaves slightly + * differently from a socket wrapper). + */ + extern ACE_Export ACE_HANDLE handle_timed_complete ( + ACE_HANDLE listener, + const ACE_Time_Value *timeout, + int is_tli = 0); + + /** + * Reset the limit on the number of open handles. If @a new_limit + * == -1 set the limit to the maximum allowable. Otherwise, set + * the limit value to @a new_limit. If @a increase_limit_only is + * non-0 then only allow increases to the limit. + */ + extern ACE_Export int set_handle_limit (int new_limit = -1, + int increase_limit_only = 0); + + /** + * Returns the maximum number of open handles currently permitted in + * this process. This maximum may be extended using + * @c ACE::set_handle_limit. + */ + extern ACE_Export int max_handles (void); + + // = String functions + /** + * Return a dynamically allocated duplicate of @a str, substituting + * the environment variable if @c str[0] @c == @c '$'. Note that + * the pointer is allocated with @c ACE_OS::malloc and must be freed + * by @c ACE_OS::free. + */ + extern ACE_Export ACE_TCHAR *strenvdup (const ACE_TCHAR *str); + + /// Returns a pointer to the "end" of the string, i.e., the character + /// past the '\0'. + extern ACE_Export const char *strend (const char *s); + + /// This method is just like @c strdup, except that it uses + /// @c operator @c new rather than @c malloc. If @a s is NULL + /// returns NULL rather than segfaulting. + extern ACE_Export char *strnew (const char *s); + + /// Delete the memory allocated by @c strnew. + ACE_NAMESPACE_INLINE_FUNCTION void strdelete (char *s); + + /// Create a fresh new copy of @a str, up to @a n chars long. Uses + /// @c ACE_OS::malloc to allocate the new string. + extern ACE_Export char *strndup (const char *str, size_t n); + + /// Create a fresh new copy of @a str, up to @a n chars long. Uses + /// @c ACE_OS::malloc to allocate the new string. + extern ACE_Export char *strnnew (const char *str, size_t n); + + /// Determine if a specified pathname is "dot dir" (ie. "." or ".."). + ACE_NAMESPACE_INLINE_FUNCTION bool isdotdir (const char *s); + +#if defined (ACE_HAS_WCHAR) + extern ACE_Export const wchar_t *strend (const wchar_t *s); + + extern ACE_Export wchar_t *strnew (const wchar_t *s); + + ACE_NAMESPACE_INLINE_FUNCTION void strdelete (wchar_t *s); + + extern ACE_Export wchar_t *strndup (const wchar_t *str, size_t n); + + extern ACE_Export wchar_t *strnnew (const wchar_t *str, size_t n); + + ACE_NAMESPACE_INLINE_FUNCTION bool isdotdir (const wchar_t *s); + +#endif /* ACE_HAS_WCHAR */ + + /** + * On Windows, determines if a specified pathname ends with ".exe" + * (not case sensitive). If on Windows and there is no ".exe" suffix, + * a new ACE_TCHAR array is allocated and a copy of @c pathname with + * the ".exe" suffix is copied into it. In this case, the caller is + * responsible for calling delete [] on the returned pointer. + * + * @param pathname The name to check for a proper suffix. + * + * @retval @c pathname if there is a proper suffix for Windows. This is + * always the return value for non-Windows platforms. + * @retval If a suffix needs to be added, returns a pointer to new[] + * allocated memory containing the original @c pathname plus + * a ".exe" suffix. The caller is responsible for freeing the + * memory using delete []. + */ + extern ACE_Export const ACE_TCHAR *execname (const ACE_TCHAR *pathname); + + /** + * Returns the "basename" of a @a pathname separated by @a delim. + * For instance, the basename of "/tmp/foo.cpp" is "foo.cpp" when + * @a delim is @a '/'. + */ + extern ACE_Export const ACE_TCHAR *basename (const ACE_TCHAR *pathname, + ACE_TCHAR delim = + ACE_DIRECTORY_SEPARATOR_CHAR); + + /** + * Returns the "dirname" of a @a pathname. For instance, the + * dirname of "/tmp/foo.cpp" is "/tmp" when @a delim is @a '/'. If + * @a pathname has no @a delim ".\0" is returned. This method does + * not modify @a pathname and is not reentrant. + */ + extern ACE_Export const ACE_TCHAR *dirname (const ACE_TCHAR *pathname, + ACE_TCHAR delim = + ACE_DIRECTORY_SEPARATOR_CHAR); + + /** + * Translate the given timestamp to ISO-8601 format. + * + * @param time_value ACE_Time_Value to format. This is assumed to be + * an absolute time value. + * @param date_and_time Array to hold the timestamp. + * @param time_len Size of @a date_and_time in ACE_TCHARs. + * Must be greater than or equal to 27. + * @param return_pointer_to_first_digit If true, returned pointer value + * is to the first time digit, else to the space + * prior to the first time digit. See Return Values. + * + * @retval 0 if unsuccessful, with errno set. If @a time_len is less than + * 27 errno will be EINVAL. + * @retval If successful, pointer to beginning of the "time" portion of + * @a date_and_time. If @a return_pointer_to_first_digit is false + * the pointer is actually to the space before the time, else + * the pointer is to the first time digit. + */ + extern ACE_Export ACE_TCHAR *timestamp (const ACE_Time_Value& time_value, + ACE_TCHAR date_and_time[], + size_t time_len, + bool return_pointer_to_first_digit = false); + + /** + * Translate the current time to ISO-8601 timestamp format. + * + * @param date_and_time Array to hold the timestamp. + * @param time_len Size of @a date_and_time in ACE_TCHARs. + * Must be greater than or equal to 27. + * @param return_pointer_to_first_digit If true, returned pointer value + * is to the first time digit, else to the space + * prior to the first time digit. See Return Values. + * + * @retval 0 if unsuccessful, with errno set. If @a time_len is less than + * 27 errno will be EINVAL. + * @retval If successful, pointer to beginning of the "time" portion of + * @a date_and_time. If @a return_pointer_to_first_digit is false + * the pointer is actually to the space before the time, else + * the pointer is to the first time digit. + */ + extern ACE_Export ACE_TCHAR *timestamp (ACE_TCHAR date_and_time[], + size_t time_len, + bool return_pointer_to_first_digit = false); + + /** + * if @a avoid_zombies == 0 call @c ACE_OS::fork directly, else + * create an orphan process that's inherited by the init process; + * init cleans up when the orphan process terminates so we don't + * create zombies. Returns -1 on failure and either the child PID + * on success if @a avoid_zombies == 0 or 1 on success if @a + * avoid_zombies != 0 (this latter behavior is a known bug that + * needs to be fixed). + */ + extern ACE_Export pid_t fork ( + const ACE_TCHAR *program_name = ACE_TEXT (""), + int avoid_zombies = 0); + + /** + * Become a daemon process using the algorithm in Richard Stevens + * "Advanced Programming in the UNIX Environment." If + * @a close_all_handles is non-zero then all open file handles are + * closed. + */ + extern ACE_Export int daemonize ( + const ACE_TCHAR pathname[] = ACE_TEXT ("/"), + bool close_all_handles = ACE_DEFAULT_CLOSE_ALL_HANDLES, + const ACE_TCHAR program_name[] = ACE_TEXT ("")); + + // = Miscellaneous functions. + /// Rounds the request to a multiple of the page size. + extern ACE_Export size_t round_to_pagesize (size_t len); + + /// Rounds the request to a multiple of the allocation granularity. + extern ACE_Export size_t round_to_allocation_granularity (size_t len); + + // @@ UNICODE what about buffer? + /// Format buffer into printable format. This is useful for + /// debugging. + extern ACE_Export size_t format_hexdump (const char *buffer, size_t size, + ACE_TCHAR *obuf, size_t obuf_sz); + + /// Computes the hash value of {str} using the "Hash PJW" routine. + extern ACE_Export u_long hash_pjw (const char *str); + + /// Computes the hash value of {str} using the "Hash PJW" routine. + extern ACE_Export u_long hash_pjw (const char *str, size_t len); + +#if defined (ACE_HAS_WCHAR) + /// Computes the hash value of {str} using the "Hash PJW" routine. + extern ACE_Export u_long hash_pjw (const wchar_t *str); + + /// Computes the hash value of {str} using the "Hash PJW" routine. + extern ACE_Export u_long hash_pjw (const wchar_t *str, size_t len); +#endif /* ACE_HAS_WCHAR */ + + /// Computes CRC-CCITT for the string. + extern ACE_Export ACE_UINT16 crc_ccitt(const char *str); + + /// Computes CRC-CCITT for the buffer. + extern ACE_Export ACE_UINT16 crc_ccitt(const void *buf, size_t len, + ACE_UINT16 crc = 0); + + /// Computes CRC-CCITT for the @ len iovec buffers. + extern ACE_Export ACE_UINT16 crc_ccitt(const iovec *iov, int len, + ACE_UINT16 crc = 0); + + /// Computes the ISO 8802-3 standard 32 bits CRC for the string. + extern ACE_Export ACE_UINT32 crc32 (const char *str); + + /// Computes the ISO 8802-3 standard 32 bits CRC for the buffer. + extern ACE_Export ACE_UINT32 crc32 (const void *buf, size_t len, + ACE_UINT32 crc = 0); + + /// Computes the ISO 8802-3 standard 32 bits CRC for the + /// @ len iovec buffers. + extern ACE_Export ACE_UINT32 crc32 (const iovec *iov, int len, + ACE_UINT32 crc = 0); + + /// Euclid's greatest common divisor algorithm. + extern ACE_Export u_long gcd (u_long x, u_long y); + + /// Calculates the minimum enclosing frame size for the given values. + extern ACE_Export u_long minimum_frame_size (u_long period1, u_long period2); + + /** + * Function that can burn up noticeable CPU time: brute-force + * determination of whether number @a n is prime. Returns 0 if + * it is prime, or the smallest factor if it is not prime. + * @a min_factor and @a max_factor can be used to partition the work + * among threads. For just one thread, typical values are 2 and + * n/2. + */ + extern ACE_Export u_long is_prime (const u_long n, + const u_long min_factor, + const u_long max_factor); + + /// Map troublesome win32 errno values to values that standard C + /// strerr function understands. Thank you Microsoft. + extern ACE_Export int map_errno (int error); + + /// Returns a string containing the error message corresponding to a + /// WinSock error. This works around an omission in the Win32 API. + /// @internal + extern ACE_Export const ACE_TCHAR * sock_error (int error); + + /// Determins whether the given error code corresponds to to a + /// WinSock error. If so returns true, false otherwise. + /// @internal + extern ACE_Export bool is_sock_error (int error); + + /** + * Checks if process with {pid} is still alive. Returns 1 if it is + * still alive, 0 if it isn't alive, and -1 if something weird + * happened. + */ + extern ACE_Export int process_active (pid_t pid); + + /** + * Terminate the process abruptly with id @a pid. On Win32 platforms + * this uses {TerminateProcess} and on POSIX platforms is uses + * {kill} with the -9 (SIGKILL) signal, which cannot be caught or + * ignored. Note that this call is potentially dangerous to use + * since the process being terminated may not have a chance to + * cleanup before it shuts down. + */ + extern ACE_Export int terminate_process (pid_t pid); + + /** + * This method uses process id and object pointer to come up with a + * machine wide unique name. The process ID will provide uniqueness + * between processes on the same machine. The "this" pointer of the + * {object} will provide uniqueness between other "live" objects in + * the same process. The uniqueness of this name is therefore only + * valid for the life of {object}. + */ + ACE_NAMESPACE_INLINE_FUNCTION void unique_name (const void *object, + ACE_TCHAR *name, + size_t length); + + /// Computes the base 2 logarithm of {num}. + ACE_NAMESPACE_INLINE_FUNCTION u_long log2 (u_long num); + + /// Helper to avoid comparing floating point values with == + /// (uses < and > operators). + template + bool is_equal (const T& a, const T& b) + { + return !((a < b) || (a > b)); + } + + /// Helper to avoid comparing floating point values with != + /// (uses < and > operators). + template + bool is_inequal (const T& a, const T& b) + { + return !is_equal (a, b); + } + + /// Hex conversion utility. + extern ACE_Export ACE_TCHAR nibble2hex (u_int n); + + /// Convert a hex character to its byte representation. + ACE_NAMESPACE_INLINE_FUNCTION u_char hex2byte (ACE_TCHAR c); + + // = Set/get the debug level. + extern ACE_Export bool debug (void); + extern ACE_Export void debug (bool onoff); + + /// Wrapper facade for @c select that uses @c ACE_Handle_Sets. + extern ACE_Export int select (int width, + ACE_Handle_Set *readfds, + ACE_Handle_Set *writefds = 0, + ACE_Handle_Set *exceptfds = 0, + const ACE_Time_Value *timeout = 0); + + /// Wrapper facade for the most common use of @c select that uses + /// @c ACE_Handle_Sets. + extern ACE_Export int select (int width, + ACE_Handle_Set &readfds, + const ACE_Time_Value *timeout = 0); + + /// Timed wait for handle to get read ready. + /// @retval -1 for error + /// @retval 0 for timeout + /// @retval 1 the handle is ready + ACE_NAMESPACE_INLINE_FUNCTION + int handle_read_ready (ACE_HANDLE handle, + const ACE_Time_Value *timeout); + + /// Timed wait for handle to get write ready. + /// @retval -1 for error + /// @retval 0 for timeout + /// @retval 1 the handle is ready + ACE_NAMESPACE_INLINE_FUNCTION + int handle_write_ready (ACE_HANDLE handle, + const ACE_Time_Value *timeout); + + /// Timed wait for handle to get exception ready. + /// @retval -1 for error + /// @retval 0 for timeout + /// @retval 1 the handle is ready + ACE_NAMESPACE_INLINE_FUNCTION + int handle_exception_ready (ACE_HANDLE handle, + const ACE_Time_Value *timeout); + + /// Timed wait for handle to get read, write, or exception ready. + /// @retval -1 for error + /// @retval 0 for timeout + /// @retval 1 the handle is ready + extern ACE_Export int handle_ready (ACE_HANDLE handle, + const ACE_Time_Value *timeout, + int read_ready, + int write_ready, + int exception_ready); + + /// Wait for @a timeout before proceeding to a @c recv operation. + /// @a val keeps track of whether we're in non-blocking mode or + /// not. + extern ACE_Export int enter_recv_timedwait (ACE_HANDLE handle, + const ACE_Time_Value *timeout, + int &val); + + /// Wait for @a timeout before proceeding to a @c send operation. + /// @a val keeps track of whether we're in non-blocking mode or + /// not. + extern ACE_Export int enter_send_timedwait (ACE_HANDLE handle, + const ACE_Time_Value* timeout, + int &val); + + /// This makes sure that @a handle is set into non-blocking mode. + /// @a val keeps track of whether were in non-blocking mode or not. + extern ACE_Export void record_and_set_non_blocking_mode (ACE_HANDLE handle, + int &val); + + /// Cleanup after a timed operation, restore the appropriate + /// non-blocking status of @a handle. + extern ACE_Export void restore_non_blocking_mode (ACE_HANDLE handle, + int val); + + // private: + // These functions aren't meant to be used internally, so they are + // not exported. + + // + // = Recv_n helpers + // + + ACE_NAMESPACE_INLINE_FUNCTION ssize_t recv_i (ACE_HANDLE handle, + void *buf, + size_t len); + + extern ACE_Export ssize_t recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + size_t *bytes_transferred); + + extern ACE_Export ssize_t recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + +#if defined (ACE_HAS_TLI) + + extern ACE_Export ssize_t t_rcv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + size_t *bytes_transferred); + + extern ACE_Export ssize_t t_rcv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + +#endif /* ACE_HAS_TLI */ + + extern ACE_Export ssize_t recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + size_t *bytes_transferred); + + extern ACE_Export ssize_t recv_n_i (ACE_HANDLE handle, + void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + + extern ACE_Export ssize_t recvv_n_i (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + size_t *bytes_transferred); + + extern ACE_Export ssize_t recvv_n_i (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + + // + // = Send_n helpers + // + + ACE_NAMESPACE_INLINE_FUNCTION ssize_t send_i (ACE_HANDLE handle, + const void *buf, + size_t len); + + extern ACE_Export ssize_t send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + size_t *bytes_transferred); + + extern ACE_Export ssize_t send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + +#if defined (ACE_HAS_TLI) + + extern ACE_Export ssize_t t_snd_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + size_t *bytes_transferred); + + extern ACE_Export ssize_t t_snd_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + +#endif /* ACE_HAS_TLI */ + + extern ACE_Export ssize_t send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + size_t *bytes_transferred); + + extern ACE_Export ssize_t send_n_i (ACE_HANDLE handle, + const void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + + extern ACE_Export ssize_t sendv_n_i (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + size_t *bytes_transferred); + + extern ACE_Export ssize_t sendv_n_i (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bytes_transferred); + +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ACE.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ACE_H */ diff --git a/dep/acelite/ace/ACE.inl b/dep/acelite/ace/ACE.inl new file mode 100644 index 000000000..f95982d73 --- /dev/null +++ b/dep/acelite/ace/ACE.inl @@ -0,0 +1,334 @@ +// -*- C++ -*- +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_Thread.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_sys_socket.h" + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + + +// Wrappers for methods that have been moved to ACE_OS. + +ACE_INLINE ssize_t +ACE::read_n (ACE_HANDLE handle, + void *buf, + size_t len, + size_t *bytes_transferred) +{ + return ACE_OS::read_n (handle, + buf, + len, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::write_n (ACE_HANDLE handle, + const void *buf, + size_t len, + size_t *bytes_transferred) +{ + return ACE_OS::write_n (handle, + buf, + len, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::recv_n (ACE_HANDLE handle, + void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::recv_n_i (handle, + buf, + len, + flags, + bytes_transferred); + else + return ACE::recv_n_i (handle, + buf, + len, + flags, + timeout, + bytes_transferred); +} + +#if defined (ACE_HAS_TLI) + +ACE_INLINE ssize_t +ACE::t_rcv_n (ACE_HANDLE handle, + void *buf, + size_t len, + int *flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::t_rcv_n_i (handle, + buf, + len, + flags, + bytes_transferred); + else + return ACE::t_rcv_n_i (handle, + buf, + len, + flags, + timeout, + bytes_transferred); +} + +#endif /* ACE_HAS_TLI */ + +ACE_INLINE ssize_t +ACE::recv_n (ACE_HANDLE handle, + void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::recv_n_i (handle, + buf, + len, + bytes_transferred); + else + return ACE::recv_n_i (handle, + buf, + len, + timeout, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::recvv_n (ACE_HANDLE handle, + iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::recvv_n_i (handle, + iov, + iovcnt, + bytes_transferred); + else + return ACE::recvv_n_i (handle, + iov, + iovcnt, + timeout, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::send_n (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::send_n_i (handle, + buf, + len, + flags, + bytes_transferred); + else + return ACE::send_n_i (handle, + buf, + len, + flags, + timeout, + bytes_transferred); +} + +#if defined (ACE_HAS_TLI) + +ACE_INLINE ssize_t +ACE::t_snd_n (ACE_HANDLE handle, + const void *buf, + size_t len, + int flags, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::t_snd_n_i (handle, + buf, + len, + flags, + bytes_transferred); + else + return ACE::t_snd_n_i (handle, + buf, + len, + flags, + timeout, + bytes_transferred); +} + +#endif /* ACE_HAS_TLI */ + +ACE_INLINE ssize_t +ACE::send_n (ACE_HANDLE handle, + const void *buf, + size_t len, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::send_n_i (handle, + buf, + len, + bytes_transferred); + else + return ACE::send_n_i (handle, + buf, + len, + timeout, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::sendv_n (ACE_HANDLE handle, + const iovec *iov, + int iovcnt, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + if (timeout == 0) + return ACE::sendv_n_i (handle, + iov, + iovcnt, + bytes_transferred); + else + return ACE::sendv_n_i (handle, + iov, + iovcnt, + timeout, + bytes_transferred); +} + +ACE_INLINE ssize_t +ACE::send_i (ACE_HANDLE handle, const void *buf, size_t len) +{ +#if defined (ACE_WIN32) || defined (HPUX) + return ACE_OS::send (handle, (const char *) buf, len); +#else + return ACE_OS::write (handle, (const char *) buf, len); +#endif /* ACE_WIN32 */ +} + +ACE_INLINE ssize_t +ACE::recv_i (ACE_HANDLE handle, void *buf, size_t len) +{ +#if defined (ACE_WIN32) || defined (ACE_OPENVMS) + return ACE_OS::recv (handle, (char *) buf, len); +#else + return ACE_OS::read (handle, (char *) buf, len); +#endif /* ACE_WIN32 */ +} + +ACE_INLINE int +ACE::handle_read_ready (ACE_HANDLE handle, const ACE_Time_Value *timeout) +{ + return ACE::handle_ready (handle, timeout, 1, 0, 0); +} + +ACE_INLINE int +ACE::handle_write_ready (ACE_HANDLE handle, const ACE_Time_Value *timeout) +{ + return ACE::handle_ready (handle, timeout, 0, 1, 0); +} + +ACE_INLINE int +ACE::handle_exception_ready (ACE_HANDLE handle, const ACE_Time_Value *timeout) +{ + return ACE::handle_ready (handle, timeout, 0, 0, 1); +} + +ACE_INLINE void +ACE::strdelete (char *s) +{ +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(s); +#else + delete [] s; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +#if defined (ACE_HAS_WCHAR) +ACE_INLINE void +ACE::strdelete (wchar_t *s) +{ + delete [] s; +} +#endif /* ACE_HAS_WCHAR */ + +ACE_INLINE bool +ACE::isdotdir (const char *s) +{ + return (s[0] == '.' && + ((s[1] == 0) || (s[1] == '.' && s[2] == 0))); +} + +#if defined (ACE_HAS_WCHAR) +ACE_INLINE bool +ACE::isdotdir (const wchar_t *s) +{ + return (s[0] == ACE_TEXT ('.') && + ((s[1] == 0) || (s[1] == ACE_TEXT ('.') && s[2] == 0))); +} +#endif /* ACE_HAS_WCHAR */ + +ACE_INLINE void +ACE::unique_name (const void *object, + ACE_TCHAR *name, + size_t length) +{ + ACE_OS::unique_name (object, name, length); +} + +ACE_INLINE u_long +ACE::log2 (u_long num) +{ + u_long log = 0; + + for (; num > 1; ++log) + num >>= 1; + + return log; +} + +ACE_INLINE int +ACE::map_errno (int error) +{ +#if defined (ACE_WIN32) + switch (error) + { + case WSAEWOULDBLOCK: + return EAGAIN; // Same as UNIX errno EWOULDBLOCK. + } +#endif /* ACE_WIN32 */ + + return error; +} + +ACE_INLINE u_char +ACE::hex2byte (ACE_TCHAR c) +{ + if (ACE_OS::ace_isdigit (c)) + return (u_char) (c - ACE_TEXT ('0')); + else if (ACE_OS::ace_islower (c)) + return (u_char) (10 + c - ACE_TEXT ('a')); + else + return (u_char) (10 + c - ACE_TEXT ('A')); +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ACE_crc32.cpp b/dep/acelite/ace/ACE_crc32.cpp new file mode 100644 index 000000000..d3e994305 --- /dev/null +++ b/dep/acelite/ace/ACE_crc32.cpp @@ -0,0 +1,154 @@ +#include "ace/ACE.h" + +namespace +{ + /*****************************************************************/ + /* */ + /* CRC LOOKUP TABLE */ + /* ================ */ + /* The following CRC lookup table was generated automagically */ + /* by the Rocksoft^tm Model CRC Algorithm Table Generation */ + /* Program V1.0 using the following model parameters: */ + /* */ + /* Width : 4 bytes. */ + /* Poly : 0x04C11DB7L */ + /* Reverse : TRUE. */ + /* */ + /* For more information on the Rocksoft^tm Model CRC Algorithm, */ + /* see the document titled "A Painless Guide to CRC Error */ + /* Detection Algorithms" by Ross Williams */ + /* (ross@guest.adelaide.edu.au.). This document is likely to be */ + /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ + /* */ + /*****************************************************************/ + + const ACE_UINT32 crc_table[] = + { + 0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL, + 0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L, + 0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L, + 0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L, + 0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL, + 0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L, + 0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL, + 0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L, + 0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L, + 0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL, + 0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L, + 0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L, + 0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L, + 0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL, + 0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L, + 0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL, + 0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL, + 0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L, + 0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L, + 0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L, + 0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL, + 0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L, + 0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL, + 0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L, + 0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L, + 0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL, + 0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L, + 0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L, + 0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L, + 0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL, + 0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L, + 0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL, + 0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL, + 0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L, + 0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L, + 0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L, + 0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL, + 0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L, + 0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL, + 0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L, + 0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L, + 0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL, + 0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L, + 0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L, + 0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L, + 0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL, + 0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L, + 0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL, + 0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL, + 0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L, + 0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L, + 0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L, + 0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL, + 0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L, + 0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL, + 0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L, + 0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L, + 0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL, + 0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L, + 0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L, + 0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L, + 0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL, + 0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L, + 0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL + }; + + /*****************************************************************/ + /* End of CRC Lookup Table */ + /*****************************************************************/ +} + +#define COMPUTE(var, ch) (var) = (crc_table[(var ^ ch) & 0xFF] ^ (var >> 8)) + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_UINT32 +ACE::crc32 (const char *string) +{ + ACE_UINT32 crc = 0xFFFFFFFF; + + for (const char *p = string; + *p != 0; + ++p) + { + COMPUTE (crc, *p); + } + + return ~crc; +} + +ACE_UINT32 +ACE::crc32 (const void *buffer, size_t len, ACE_UINT32 crc) +{ + crc = ~crc; + + for (const char *p = (const char *) buffer, + *e = (const char *) buffer + len; + p != e; + ++p) + { + COMPUTE (crc, *p); + } + + return ~crc; +} + +ACE_UINT32 +ACE::crc32 (const iovec *iov, int len, ACE_UINT32 crc) +{ + crc = ~crc; + + for (int i = 0; i < len; ++i) + { + for (const char *p = (const char *) iov[i].iov_base, + *e = (const char *) iov[i].iov_base + iov[i].iov_len; + p != e; + ++p) + COMPUTE (crc, *p); + } + + return ~crc; +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#undef COMPUTE diff --git a/dep/acelite/ace/ACE_crc_ccitt.cpp b/dep/acelite/ace/ACE_crc_ccitt.cpp new file mode 100644 index 000000000..374637e3d --- /dev/null +++ b/dep/acelite/ace/ACE_crc_ccitt.cpp @@ -0,0 +1,122 @@ +#include "ace/ACE.h" + +namespace +{ + /*****************************************************************/ + /* */ + /* CRC LOOKUP TABLE */ + /* ================ */ + /* The following CRC lookup table was generated automagically */ + /* by the Rocksoft^tm Model CRC Algorithm Table Generation */ + /* Program V1.0 using the following model parameters: */ + /* */ + /* Width : 2 bytes. */ + /* Poly : 0x1021 */ + /* Reverse : TRUE. */ + /* */ + /* For more information on the Rocksoft^tm Model CRC Algorithm, */ + /* see the document titled "A Painless Guide to CRC Error */ + /* Detection Algorithms" by Ross Williams */ + /* (ross@guest.adelaide.edu.au.). This document is likely to be */ + /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */ + /* */ + /*****************************************************************/ + + const ACE_UINT16 crc_table[] = + { + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7, + 0x1081, 0x0108, 0x3393, 0x221A, 0x56A5, 0x472C, 0x75B7, 0x643E, + 0x9CC9, 0x8D40, 0xBFDB, 0xAE52, 0xDAED, 0xCB64, 0xF9FF, 0xE876, + 0x2102, 0x308B, 0x0210, 0x1399, 0x6726, 0x76AF, 0x4434, 0x55BD, + 0xAD4A, 0xBCC3, 0x8E58, 0x9FD1, 0xEB6E, 0xFAE7, 0xC87C, 0xD9F5, + 0x3183, 0x200A, 0x1291, 0x0318, 0x77A7, 0x662E, 0x54B5, 0x453C, + 0xBDCB, 0xAC42, 0x9ED9, 0x8F50, 0xFBEF, 0xEA66, 0xD8FD, 0xC974, + 0x4204, 0x538D, 0x6116, 0x709F, 0x0420, 0x15A9, 0x2732, 0x36BB, + 0xCE4C, 0xDFC5, 0xED5E, 0xFCD7, 0x8868, 0x99E1, 0xAB7A, 0xBAF3, + 0x5285, 0x430C, 0x7197, 0x601E, 0x14A1, 0x0528, 0x37B3, 0x263A, + 0xDECD, 0xCF44, 0xFDDF, 0xEC56, 0x98E9, 0x8960, 0xBBFB, 0xAA72, + 0x6306, 0x728F, 0x4014, 0x519D, 0x2522, 0x34AB, 0x0630, 0x17B9, + 0xEF4E, 0xFEC7, 0xCC5C, 0xDDD5, 0xA96A, 0xB8E3, 0x8A78, 0x9BF1, + 0x7387, 0x620E, 0x5095, 0x411C, 0x35A3, 0x242A, 0x16B1, 0x0738, + 0xFFCF, 0xEE46, 0xDCDD, 0xCD54, 0xB9EB, 0xA862, 0x9AF9, 0x8B70, + 0x8408, 0x9581, 0xA71A, 0xB693, 0xC22C, 0xD3A5, 0xE13E, 0xF0B7, + 0x0840, 0x19C9, 0x2B52, 0x3ADB, 0x4E64, 0x5FED, 0x6D76, 0x7CFF, + 0x9489, 0x8500, 0xB79B, 0xA612, 0xD2AD, 0xC324, 0xF1BF, 0xE036, + 0x18C1, 0x0948, 0x3BD3, 0x2A5A, 0x5EE5, 0x4F6C, 0x7DF7, 0x6C7E, + 0xA50A, 0xB483, 0x8618, 0x9791, 0xE32E, 0xF2A7, 0xC03C, 0xD1B5, + 0x2942, 0x38CB, 0x0A50, 0x1BD9, 0x6F66, 0x7EEF, 0x4C74, 0x5DFD, + 0xB58B, 0xA402, 0x9699, 0x8710, 0xF3AF, 0xE226, 0xD0BD, 0xC134, + 0x39C3, 0x284A, 0x1AD1, 0x0B58, 0x7FE7, 0x6E6E, 0x5CF5, 0x4D7C, + 0xC60C, 0xD785, 0xE51E, 0xF497, 0x8028, 0x91A1, 0xA33A, 0xB2B3, + 0x4A44, 0x5BCD, 0x6956, 0x78DF, 0x0C60, 0x1DE9, 0x2F72, 0x3EFB, + 0xD68D, 0xC704, 0xF59F, 0xE416, 0x90A9, 0x8120, 0xB3BB, 0xA232, + 0x5AC5, 0x4B4C, 0x79D7, 0x685E, 0x1CE1, 0x0D68, 0x3FF3, 0x2E7A, + 0xE70E, 0xF687, 0xC41C, 0xD595, 0xA12A, 0xB0A3, 0x8238, 0x93B1, + 0x6B46, 0x7ACF, 0x4854, 0x59DD, 0x2D62, 0x3CEB, 0x0E70, 0x1FF9, + 0xF78F, 0xE606, 0xD49D, 0xC514, 0xB1AB, 0xA022, 0x92B9, 0x8330, + 0x7BC7, 0x6A4E, 0x58D5, 0x495C, 0x3DE3, 0x2C6A, 0x1EF1, 0x0F78 + }; + + /*****************************************************************/ + /* End of CRC Lookup Table */ + /*****************************************************************/ +} + +#define COMPUTE(var, ch) (var) = static_cast (crc_table[(var ^ ch) & 0xFF] ^ (var >> 8)) + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_UINT16 +ACE::crc_ccitt (const char *string) +{ + ACE_UINT16 crc = 0xFFFF; + + for (const char *p = string; + *p != 0; + ++p) + { + COMPUTE (crc, *p); + } + + return static_cast (~crc); +} + +ACE_UINT16 +ACE::crc_ccitt (const void *buffer, size_t len, ACE_UINT16 crc) +{ + crc = static_cast (~crc); + + for (const char *p = (const char *) buffer, + *e = (const char *) buffer + len; + p != e; + ++p) + { + COMPUTE (crc, *p); + } + + return static_cast (~crc); +} + +ACE_UINT16 +ACE::crc_ccitt (const iovec *iov, int len, ACE_UINT16 crc) +{ + crc = static_cast (~crc); + + for (int i = 0; i < len; ++i) + { + for (const char *p = (const char *) iov[i].iov_base, + *e = (const char *) iov[i].iov_base + iov[i].iov_len; + p != e; + ++p) + COMPUTE (crc, *p); + } + + return static_cast (~crc); +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#undef COMPUTE diff --git a/dep/acelite/ace/ACE_export.h b/dep/acelite/ace/ACE_export.h new file mode 100644 index 000000000..700e562f7 --- /dev/null +++ b/dep/acelite/ace/ACE_export.h @@ -0,0 +1,67 @@ +// -*- C++ -*- +// Definition for Win32 Export directives. +// This file is generated automatically by +// generate_export_file.pl +// ------------------------------ + +#ifndef ACE_EXPORT_H +#define ACE_EXPORT_H + +#include /**/ "ace/config-lite.h" + +#if defined (ACE_AS_STATIC_LIBS) + +# if !defined (ACE_HAS_DLL) +# define ACE_HAS_DLL 0 +# endif /* ! ACE_HAS_DLL */ +#else +# if !defined (ACE_HAS_DLL) +# define ACE_HAS_DLL 1 +# endif /* ! ACE_HAS_DLL */ +#endif /* ACE_AS_STATIC_LIB */ + +#if defined (ACE_HAS_DLL) +# if (ACE_HAS_DLL == 1) +# if defined (ACE_BUILD_DLL) +# define ACE_Export ACE_Proper_Export_Flag +# define ACE_SINGLETON_DECLARATION(T) ACE_EXPORT_SINGLETON_DECLARATION (T) +# define ACE_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_EXPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# else +# define ACE_Export ACE_Proper_Import_Flag +# define ACE_SINGLETON_DECLARATION(T) ACE_IMPORT_SINGLETON_DECLARATION (T) +# define ACE_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) ACE_IMPORT_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* ACE_BUILD_DLL */ +# else +# define ACE_Export +# define ACE_SINGLETON_DECLARATION(T) +# define ACE_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +# endif /* ! ACE_HAS_DLL == 1 */ +#else +# define ACE_Export +# define ACE_SINGLETON_DECLARATION(T) +# define ACE_SINGLETON_DECLARE(SINGLETON_TYPE, CLASS, LOCK) +#endif /* ACE_HAS_DLL */ + +// Added by hand to help with ACE_OS namespace +#if defined (__TANDEM) && defined (USE_EXPLICIT_EXPORT) +#define ACE_NAMESPACE_STORAGE_CLASS ACE_EXPORT_MACRO extern +#else +#define ACE_NAMESPACE_STORAGE_CLASS extern ACE_EXPORT_MACRO +#endif + +#if defined (__ACE_INLINE__) +# define ACE_NAMESPACE_INLINE_FUNCTION inline +# define ACE_INLINE_TEMPLATE_FUNCTION inline +#else +# define ACE_NAMESPACE_INLINE_FUNCTION ACE_NAMESPACE_STORAGE_CLASS +// Microsoft Visual C++ will accept 'extern'; others refuse. +# if defined (_MSC_VER) || defined (__BORLANDC__) +# define ACE_INLINE_TEMPLATE_FUNCTION ACE_Export +# else +# define ACE_INLINE_TEMPLATE_FUNCTION +# endif +#endif + +#endif /* ACE_EXPORT_H */ + +// End of auto generated file. diff --git a/dep/acelite/ace/ARGV.cpp b/dep/acelite/ace/ARGV.cpp new file mode 100644 index 000000000..18790043e --- /dev/null +++ b/dep/acelite/ace/ARGV.cpp @@ -0,0 +1,419 @@ +#ifndef ACE_ARGV_CPP +#define ACE_ARGV_CPP + +#include "ace/Log_Category.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_Memory.h" + +#if !defined (__ACE_INLINE__) +#include "ace/ARGV.inl" +#endif /* __ACE_INLINE__ */ + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tt (ACE_ARGV_Queue_Entry_T) +ACE_ALLOC_HOOK_DEFINE_Tt (ACE_ARGV_T) + +template +void +ACE_ARGV_Queue_Entry_T::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ARGV_Queue_Entry_T::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("arg_ = %s"), this->arg_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("quote_arg_ = %d"), (int)this->quote_arg_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +void +ACE_ARGV_T::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ARGV_T::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("argc_ = %d"), this->argc_)); + + ACE_ARGV *this_obj = const_cast (this); + + for (int i = 0; i < this->argc_; i++) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("\nargv_[%i] = %s"), + i, + this_obj->argv ()[i])); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nbuf = %s\n"), this->buf_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Creates this->argv_ out of this->buf_. New memory is allocated for +// each element of the array. This is used by the array-to-string +// style constructor and for creating this->argv_ when in iterative +// mode. + +template +int +ACE_ARGV_T::string_to_argv (void) +{ + ACE_TRACE ("ACE_ARGV_T::string_to_argv"); + + return ACE_OS::string_to_argv (this->buf_, + this->argc_, + this->argv_, + this->substitute_env_args_); +} + +template +ACE_ARGV_T::ACE_ARGV_T (const CHAR_TYPE buf[], + bool substitute_env_args) + : substitute_env_args_ (substitute_env_args), + iterative_ (false), + argc_ (0), + argv_ (0), + buf_ (0), + length_ (0), + queue_ () +{ + ACE_TRACE ("ACE_ARGV_T::ACE_ARGV_T CHAR_TYPE[] to CHAR_TYPE *[]"); + + if (buf == 0 || buf[0] == 0) + return; + + // Make an internal copy of the string. +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR(this->buf_, + static_cast (ACE_Allocator::instance()->malloc(sizeof (CHAR_TYPE) * (ACE_OS::strlen (buf) + 1)))); +#else + ACE_NEW (this->buf_, + CHAR_TYPE[ACE_OS::strlen (buf) + 1]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_OS::strcpy (this->buf_, buf); + + // Create this->argv_. + if (this->string_to_argv () == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("string_to_argv"))); +} + +template +ACE_ARGV_T::ACE_ARGV_T (CHAR_TYPE *argv[], + bool substitute_env_args, + bool quote_arg) + : substitute_env_args_ (substitute_env_args), + iterative_ (false), + argc_ (0), + argv_ (0), + buf_ (0), + length_ (0), + queue_ () +{ + ACE_TRACE ("ACE_ARGV_T::ACE_ARGV_T CHAR_TYPE*[] to CHAR_TYPE[]"); + + if (argv == 0 || argv[0] == 0) + return; + + this->argc_ = ACE_OS::argv_to_string (argv, + this->buf_, + substitute_env_args, + quote_arg); +} + +template +ACE_ARGV_T::ACE_ARGV_T (int argc, + CHAR_TYPE *argv[], + bool substitute_env_args, + bool quote_arg) + : substitute_env_args_ (substitute_env_args), + iterative_ (false), + argc_ (0), + argv_ (0), + buf_ (0), + length_ (0), + queue_ () +{ + ACE_TRACE ("ACE_ARGV_T::ACE_ARGV_T int,CHAR_TYPE*[] to CHAR_TYPE[]"); + + this->argc_ = ACE_OS::argv_to_string (argc, + argv, + this->buf_, + substitute_env_args, + quote_arg); +} + + +template +ACE_ARGV_T::ACE_ARGV_T (CHAR_TYPE *first_argv[], + CHAR_TYPE *second_argv[], + bool substitute_env_args, + bool quote_args) + : substitute_env_args_ (substitute_env_args), + iterative_ (false), + argc_ (0), + argv_ (0), + buf_ (0), + length_ (0), + queue_ () +{ + ACE_TRACE ("ACE_ARGV_T::ACE_ARGV_T CHAR_TYPE*[] + CHAR_TYPE *[] to CHAR_TYPE[]"); + + int first_argc = 0; + int second_argc = 0; + + CHAR_TYPE *first_buf = 0; + CHAR_TYPE *second_buf = 0; + size_t buf_len = 1; + + // convert the first argv to a string + if (first_argv != 0 && first_argv[0] != 0) + { + first_argc = ACE_OS::argv_to_string (first_argv, + first_buf, + substitute_env_args, + quote_args); + buf_len += ACE_OS::strlen (first_buf); + } + + // convert the second argv to a string + if (second_argv != 0 && second_argv[0] != 0) + { + second_argc = ACE_OS::argv_to_string (second_argv, + second_buf, + substitute_env_args, + quote_args); + buf_len += ACE_OS::strlen (second_buf); + } + + // Add the number of arguments in both the argvs. + this->argc_ = first_argc + second_argc; + + // Allocate memory to the lenght of the combined argv string. + ACE_NEW (this->buf_, + CHAR_TYPE[buf_len + 1]); + + // copy the first argv string to the buffer + ACE_OS::strcpy (this->buf_, first_buf); + + // concatenate the second argv string to the buffer + ACE_OS::strcat (this->buf_, second_buf); + + // Delete the first and second buffers +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (first_buf); + ACE_Allocator::instance()->free (second_buf); +#else + delete [] first_buf; + delete [] second_buf; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +template +ACE_ARGV_T::ACE_ARGV_T (bool substitute_env_args) + : substitute_env_args_ (substitute_env_args), + iterative_ (true), + argc_ (0), + argv_ (0), + buf_ (0), + length_ (0), + queue_ () +{ + ACE_TRACE ("ACE_ARGV_T::ACE_ARGV_T Iterative"); + + // Nothing to do yet -- the user puts in arguments via add () +} + +template +int +ACE_ARGV_T::add (const CHAR_TYPE *next_arg, bool quote_arg) +{ + // Only allow this to work in the "iterative" verion -- the + // ACE_ARGVs created with the one argument constructor. + if (!this->iterative_) + { + errno = EINVAL; + return -1; + } + + this->length_ += ACE_OS::strlen (next_arg); + if (quote_arg && ACE_OS::strchr (next_arg, ' ') != 0) + { + this->length_ += 2; + if (ACE_OS::strchr (next_arg, '"') != 0) + for (const CHAR_TYPE * p = next_arg; *p != '\0'; ++p) + if (*p == '"') ++this->length_; + } + else + { + quote_arg = false; + } + + // Put the new argument at the end of the queue. + if (this->queue_.enqueue_tail (ACE_ARGV_Queue_Entry_T (next_arg, quote_arg)) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Can't add more to ARGV queue")), + -1); + + ++this->argc_; + + // Wipe argv_ and buf_ away so that they will be recreated if the + // user calls argv () or buf (). + if (this->argv_ != 0) + { + for (int i = 0; this->argv_[i] != 0; i++) + ACE_OS::free ((void *) this->argv_[i]); + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->argv_); +#else + delete [] this->argv_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + this->argv_ = 0; + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->buf_); +#else + delete [] this->buf_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + this->buf_ = 0; + + return 0; +} + +template +int +ACE_ARGV_T::add (CHAR_TYPE *argv[], bool quote_args) +{ + for (int i = 0; argv[i] != 0; i++) + if (this->add (argv[i], quote_args) == -1) + return -1; + + return 0; +} + +// Free up argv_ and buf_ + +template +ACE_ARGV_T::~ACE_ARGV_T (void) +{ + ACE_TRACE ("ACE_ARGV_T::~ACE_ARGV_T"); + + if (this->argv_ != 0) + for (int i = 0; this->argv_[i] != 0; i++) +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free ((void *) this->argv_[i]); +#else + ACE_OS::free ((void *) this->argv_[i]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->argv_); + ACE_Allocator::instance()->free (this->buf_); +#else + delete [] this->argv_; + delete [] this->buf_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +// Create buf_ out of the queue_. This is only used in the +// "iterative" mode. + +template +int +ACE_ARGV_T::create_buf_from_queue (void) +{ + ACE_TRACE ("ACE_ARGV_T::create_buf_from_queue"); + + // If the are no arguments, don't do anything + if (this->argc_ <= 0) + return -1; + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->buf_); +#else + delete [] this->buf_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (this->buf_, + static_cast (ACE_Allocator::instance()->malloc(sizeof (CHAR_TYPE) * (this->length_ + this->argc_))), + -1); +#else + ACE_NEW_RETURN (this->buf_, + CHAR_TYPE[this->length_ + this->argc_], + -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + // Get an iterator over the queue + ACE_Unbounded_Queue_Iterator > iter (this->queue_); + + ACE_ARGV_Queue_Entry_T *arg = 0; + CHAR_TYPE *ptr = this->buf_; + size_t len; + + while (!iter.done ()) + { + // Get next argument from the queue. + iter.next (arg); + iter.advance (); + + if (arg->quote_arg_) + { + *ptr++ = '"'; + if (ACE_OS::strchr (arg->arg_, '"') != 0) + { + CHAR_TYPE prev = 0; + for (const CHAR_TYPE * p = arg->arg_; *p != '\0'; ++p) + { + if (*p == '"' && prev != '\\') *ptr++ = '\\'; + prev = *ptr++ = *p; + } + } + else + { + len = ACE_OS::strlen (arg->arg_); + // Copy the argument into buf_ + ACE_OS::memcpy ((void *) ptr, + (const void *) (arg->arg_), + len * sizeof (CHAR_TYPE)); + // Move the pointer down. + ptr += len; + } + *ptr++ = '"'; + } + else + { + len = ACE_OS::strlen (arg->arg_); + // Copy the argument into buf_ + ACE_OS::memcpy ((void *) ptr, + (const void *) (arg->arg_), + len * sizeof (CHAR_TYPE)); + // Move the pointer down. + ptr += len; + } + + // Put in an argument separating space. + *ptr++ = ' '; + } + + // Put in the NUL terminator + ptr[-1] = '\0'; + + return 0; +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ARGV_CPP */ diff --git a/dep/acelite/ace/ARGV.h b/dep/acelite/ace/ARGV.h new file mode 100644 index 000000000..962b453c7 --- /dev/null +++ b/dep/acelite/ace/ARGV.h @@ -0,0 +1,331 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file ARGV.h + * + * @author Doug Schmidt + * @author Everett Anderson + */ +//========================================================================== + +#ifndef ACE_ARGUMENT_VECTOR_H +#define ACE_ARGUMENT_VECTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/Unbounded_Queue.h" + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_ARGV_Queue_Entry_T + * + * @brief An entry in the queue which keeps user supplied arguments. + */ +template +class ACE_ARGV_Queue_Entry_T +{ +public: + // = Initialization and termination. + /// Initialize a ACE_ARGV_Queue_Entry_T. + ACE_ARGV_Queue_Entry_T (void); + + /** + * Initialize a ACE_ARGV_Queue_Entry_T. + * + * @param arg Pointer to an argument + * + * @param quote_arg The argument @a arg need to be quoted + * while adding to the vector. + */ + ACE_ARGV_Queue_Entry_T (const CHAR_TYPE *arg, + bool quote_arg); + + /** + * Initialize a ACE_ARGV_Queue_Entry_T. + * + * @param entry Pointer to a queue entry + */ + ACE_ARGV_Queue_Entry_T (const ACE_ARGV_Queue_Entry_T &entry); + + /// We need this destructor to keep some compilers from complaining. + /// It's just a no-op, however. + ~ACE_ARGV_Queue_Entry_T (void); + + /// Dump the state of this object. + void dump (void) const; + + // Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Pointer to the argument. + const CHAR_TYPE * arg_; + + /// The argument need to be quoted while adding to the vector. + bool quote_arg_; +}; + +/** + * @class ACE_ARGV_T + * + * @brief Builds a counted argument vector (ala argc/argv) from either + * a string or a set of separate tokens. This class preserves whitespace + * within tokens only if the whitespace-containing token is enclosed in + * either single (') or double (") quotes. This is consistent with the + * expected behavior if an argument vector obtained using this class is + * passed to, for example, ACE_Get_Opt. + * + * This class can substitute environment variable values for tokens that + * are environment variable references (e.g., @c $VAR). This only works + * if the token is an environment variable reference and nothing else; it + * doesn't substitute environment variable references within a token. + * For example, @c $HOME/file will not substitute the value of the HOME + * environment variable. + */ +template +class ACE_ARGV_T +{ +public: + // = Initialization and termination. + /** + * Splits the specified string into an argument vector. Arguments in the + * string are delimited by whitespace. Whitespace-containing arguments + * must be enclosed in quotes, either single (') or double ("). + * + * @param buf A nul-terminated CHAR_TYPE array to split into arguments + * for the vector. + * + * @param substitute_env_args If non-zero, any token that is an + * environment variable reference (e.g., @c $VAR) will have + * its environment variable value in the resultant vector + * in place of the environment variable name. + */ + explicit ACE_ARGV_T (const CHAR_TYPE buf[], + bool substitute_env_args = true); + + /** + * Initializes the argument vector from a set of arguments. Any environment + * variable references are translated (if applicable) during execution of + * this method. In contrast with ACE_ARGV_T(CHAR_TYPE *[], bool, bool), this + * ctor does not require argv to be 0-terminated as the number of arguments + * is provided explicitely. + * + * @param argc The number of arguments in the argv array. + * + * @param argv An array of tokens to initialize the object with. All needed + * data is copied from @a argv during this call; the pointers + * in @a argv are not needed after this call, and the memory + * referred to by @a argv is not referenced by this object. + * + * @param substitute_env_args If non-zero, any element of @a argv that is + * an environment variable reference (e.g., @c $VAR) will have + * its environment variable value in the resultant vector + * in place of the environment variable name. + * + * @param quote_args If non-zero each argument @a argv[i] needs to + * be enclosed in double quotes ('"'). + */ + explicit ACE_ARGV_T (int argc, + CHAR_TYPE *argv[], + bool substitute_env_args = true, + bool quote_args = false); + + /** + * Initializes the argument vector from a set of arguments. Any environment + * variable references are translated (if applicable) during execution of + * this method. + * + * @param argv An array of tokens to initialize the object with. The + * array must be terminated with a 0 pointer. All needed + * data is copied from @a argv during this call; the pointers + * in @a argv are not needed after this call, and the memory + * referred to by @a argv is not referenced by this object. + * + * @param substitute_env_args If non-zero, any element of @a argv that is + * an environment variable reference (e.g., @c $VAR) will have + * its environment variable value in the resultant vector + * in place of the environment variable name. + * + * @param quote_args If non-zero each argument @a argv[i] needs to + * be enclosed in double quotes ('"'). + */ + explicit ACE_ARGV_T (CHAR_TYPE *argv[], + bool substitute_env_args = true, + bool quote_args = false); + + /** + * Initializes the argument vector from two combined argument vectors. + * + * @param first_argv An array of tokens to initialize the object with. + * The array must be terminated with a 0 pointer. + * @param second_argv An array of tokens that is concatenated with the + * the tokens in @a first_argv. The array must be + * terminated with a 0 pointer. + * @param substitute_env_args If non-zero, any element of @a first_argv + * or @a second_argv that is an environment variable + * reference (e.g., @c $VAR) will have its environment + * variable value in the resultant vector in place + * of the environment variable name. + * + * @param quote_args If non-zero each arguments @a first_argv[i] and + * @a second_argv[i] needs to be enclosed + * in double quotes ('"'). + */ + ACE_ARGV_T (CHAR_TYPE *first_argv[], + CHAR_TYPE *second_argv[], + bool substitute_env_args = true, + bool quote_args = false); + + /** + * Initialize this object so arguments can be added later using one + * of the add methods. This is referred to as the @i iterative method + * of adding arguments to this object. + */ + explicit ACE_ARGV_T (bool substitute_env_args = true); + + /// Destructor. + ~ACE_ARGV_T (void); + + /** @name Accessor methods + * + * These methods access the argument vector contained in this object. + */ + //@{ + /** + * Returns the specified element of the current argument vector. + * + * @param index Index to the desired element. + * + * @retval Pointer to the indexed string. + * @retval 0 if @a index is out of bounds. + */ + const CHAR_TYPE *operator[] (size_t index); + + /** + * Returns the current argument vector. The returned pointers are to data + * maintained internally to this class. Do not change or delete either the + * pointers or the memory to which they refer. + */ + CHAR_TYPE **argv (void); + + /// Returns the current number of arguments. + int argc (void) const; + + /** + * Returns a single string form of the current arguments. The returned + * pointer refers to memory maintained internally to this class. Do not + * change or delete it. + */ + const CHAR_TYPE *buf (void); + + //@} + + /// Dump the state of this object. + void dump (void) const; + + // Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /** + * Add another argument. This only works in the iterative mode. + * + * @note This method copies the specified pointer, but not the data + * contained in the referenced memory. Thus, if the content of + * the memory referred to by @a next_arg are changed after this + * method returns, the results are undefined. + * + * @param next_arg Pointer to the next argument to add to the vector. + * + * @param quote_arg The argument @a next_arg need to be quoted while + * adding to the vector. + * + * @retval 0 on success; -1 on failure. Most likely @c errno values are: + * - EINVAL: This object is not in iterative mode. + * - ENOMEM: Not enough memory available to save @a next_arg. + */ + int add (const CHAR_TYPE *next_arg, bool quote_arg = false); + + /** + * Add an array of arguments. This only works in the iterative mode. + * + * @note This method copies the specified pointers, but not the data + * contained in the referenced memory. Thus, if the content of + * the memory referred to by any of the @a argv elements is + * changed after this method returns, the results are undefined. + * + * @param argv Pointers to the arguments to add to the vector. + * @a argv must be terminated by a 0 pointer. + * + * @param quote_args If non-zero each argument @a argv[i] needs to + * be enclosed in double quotes ('"'). + * + * @retval 0 on success; -1 on failure. Most likely @c errno values are: + * - EINVAL: This object is not in iterative mode. + * - ENOMEM: Not enough memory available to save @a next_arg. + */ + int add (CHAR_TYPE *argv[], bool quote_args = false); + +private: + /// Copy constructor not implemented. + ACE_UNIMPLEMENTED_FUNC (ACE_ARGV_T (const ACE_ARGV_T&)) + + /// Assignment operator not implemented. + ACE_UNIMPLEMENTED_FUNC (ACE_ARGV_T operator= (const ACE_ARGV_T&)) + + /// Creates buf_ from the queue of added args, deletes previous buf_. + int create_buf_from_queue (void); + + /// Converts buf_ into the CHAR_TYPE *argv[] format. + int string_to_argv (void); + + /// Replace args with environment variable values? + bool substitute_env_args_; + + bool iterative_; + + /// Number of arguments in the ARGV array. + int argc_; + + /// The array of string arguments. + CHAR_TYPE **argv_; + + /// Buffer containing the argv contents. + CHAR_TYPE *buf_; + + /// Total length of the arguments in the queue, not counting + /// separating spaces + size_t length_; + + /// Queue which keeps user supplied arguments. This is only + /// active in the "iterative" mode. + ACE_Unbounded_Queue > queue_; +}; + +typedef ACE_ARGV_Queue_Entry_T ACE_ARGV_Queue_Entry; +typedef ACE_ARGV_T ACE_ARGV; + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ARGV.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/ARGV.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("ARGV.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_ARGUMENT_VECTOR_H */ diff --git a/dep/acelite/ace/ARGV.inl b/dep/acelite/ace/ARGV.inl new file mode 100644 index 000000000..cd538e9ec --- /dev/null +++ b/dep/acelite/ace/ARGV.inl @@ -0,0 +1,102 @@ +/* -*- C++ -*- */ +#include "ace/Global_Macros.h" + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_ARGV_Queue_Entry_T::ACE_ARGV_Queue_Entry_T (void) + : arg_(0), + quote_arg_(false) +{ + // No-op +} + +template ACE_INLINE +ACE_ARGV_Queue_Entry_T::ACE_ARGV_Queue_Entry_T (const CHAR_TYPE *arg, + bool quote_arg) + : arg_(arg), + quote_arg_(quote_arg) +{ + // No-op +} + +template ACE_INLINE +ACE_ARGV_Queue_Entry_T::ACE_ARGV_Queue_Entry_T (const ACE_ARGV_Queue_Entry_T &entry) + : arg_(entry.arg_), + quote_arg_(entry.quote_arg_) +{ + // No-op +} + +template ACE_INLINE +ACE_ARGV_Queue_Entry_T::~ACE_ARGV_Queue_Entry_T (void) +{ + // No-op just to keep some compilers happy... +} + +// Return the number of args +template +ACE_INLINE int +ACE_ARGV_T::argc (void) const +{ + ACE_TRACE ("ACE_ARGV_T::argc"); + // Try to create the argv_ if it isn't there + ACE_ARGV_T *nonconst_this = + const_cast *> (this); + (void) nonconst_this->argv (); + return this->argc_; +} + +// Return the arguments in a space-separated string +template +ACE_INLINE const CHAR_TYPE * +ACE_ARGV_T::buf (void) +{ + ACE_TRACE ("ACE_ARGV_T::buf"); + + if (this->buf_ == 0 && this->iterative_) + this->create_buf_from_queue (); + + return (const CHAR_TYPE *) this->buf_; +} + +// Return the arguments in an entry-per-argument array + +template +ACE_INLINE CHAR_TYPE ** +ACE_ARGV_T::argv (void) +{ + ACE_TRACE ("ACE_ARGV_T::argv"); + + // Try to create the argv_ if it isn't there + if (this->argv_ == 0) + { + if (this->iterative_ && this->buf_ == 0) + this->create_buf_from_queue (); + + // Convert buf_ to argv_ + if (this->string_to_argv () == -1) + return (CHAR_TYPE **) 0; + } + + return (CHAR_TYPE **) this->argv_; +} + +// Subscript operator. + +template +ACE_INLINE const CHAR_TYPE * +ACE_ARGV_T::operator[] (size_t i) +{ + ACE_TRACE ("ACE_ARGV_T::operator[]"); + + // Don't go out of bounds. + if (i >= static_cast (this->argc_)) + return 0; + + return (const CHAR_TYPE *) this->argv ()[i]; +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_Acceptor.cpp b/dep/acelite/ace/ATM_Acceptor.cpp new file mode 100644 index 000000000..db7d67658 --- /dev/null +++ b/dep/acelite/ace/ATM_Acceptor.cpp @@ -0,0 +1,307 @@ +#include "ace/ATM_Acceptor.h" + + + +#if defined (ACE_HAS_ATM) + +#if defined (ACE_HAS_LINUX_ATM) +#include /**/ "linux/atmdev.h" +#endif /* ACE_HAS_LINUX_ATM */ + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_Acceptor.inl" +#endif /* __ACE_INLINE__ */ + + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Put the actual definitions of the ACE_ATM_Request and +// ACE_ATM_Request_Queue classes here to hide them from clients... + +ACE_ALLOC_HOOK_DEFINE(ACE_ATM_Acceptor) + +ACE_ATM_Acceptor::ACE_ATM_Acceptor (void) +{ + ACE_TRACE ("ACE_ATM_Acceptor::ACE_ATM_Acceptor"); +} + +ACE_ATM_Acceptor::~ACE_ATM_Acceptor (void) +{ + ACE_TRACE ("ACE_ATM_Acceptor::~ACE_ATM_Acceptor"); +} + +int +ACE_ATM_Acceptor::get_local_addr (ACE_ATM_Addr &local_addr) +{ + ACE_TRACE ("ACE_ATM_Acceptor::get_local_addr"); + +#if defined (ACE_HAS_FORE_ATM_WS2) + unsigned long ret = 0; + DWORD deviceID = 0; + ATM_ADDRESS addr; + struct sockaddr_atm *laddr; + + if (::WSAIoctl ((int) ((ACE_SOCK_Acceptor *)this) -> get_handle (), + SIO_GET_ATM_ADDRESS, + (LPVOID) &deviceID, + sizeof (DWORD), + (LPVOID)&addr, + sizeof (ATM_ADDRESS), + &ret, + 0, + 0) == SOCKET_ERROR) { + ACE_OS::printf ("ATM_Acceptor (get_local_addr): WSIoctl: %d\n", + ::WSAGetLastError ()); + return -1; + } + + laddr = (struct sockaddr_atm *)local_addr.get_addr (); + ACE_OS::memcpy ((void *)& (laddr -> satm_number), + (void *)&addr, + ATM_ADDR_SIZE - 1); + + return 0; +#elif defined (ACE_HAS_FORE_ATM_XTI) + ACE_UNUSED_ARG (local_addr); + + return 0; +#elif defined (ACE_HAS_LINUX_ATM) + ATM_Addr *myaddr = (ATM_Addr *)local_addr.get_addr (); + int addrlen = sizeof (myaddr->sockaddratmsvc); + + if (ACE_OS::getsockname (acceptor_.get_handle (), + (struct sockaddr *) & (myaddr->sockaddratmsvc), + &addrlen) < 0) { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ATM_Acceptor (get_local_addr): ioctl: %d\n"), + errno)); + return -1; + } + + return 0; +#else + ACE_UNUSED_ARG (local_addr); + + return 0; +#endif /* ACE_HAS_FORE_ATM_WS2 && ACE_HAS_FORE_ATM_XTI */ +} + +ACE_HANDLE +ACE_ATM_Acceptor::open (const ACE_Addr &remote_sap, + int backlog, + ACE_ATM_Params params) +{ + ACE_TRACE ("ACE_ATM_Acceptor::open"); +#if defined (ACE_HAS_FORE_ATM_XTI) + ACE_HANDLE handle = acceptor_.open (remote_sap, + params.get_reuse_addr (), + params.get_oflag (), + params.get_info (), + backlog, + params.get_device ()); + return (handle == ACE_INVALID_HANDLE ? -1 : 0); +#elif defined (ACE_HAS_FORE_ATM_WS2) + struct sockaddr_atm local_atm_addr; + ACE_HANDLE ret; + DWORD flags = 0; + + /* Create a local endpoint of communication */ + + // Only leaves can listen. + flags = ACE_FLAG_MULTIPOINT_C_LEAF | ACE_FLAG_MULTIPOINT_D_LEAF; + + if ((ret = ACE_OS::socket (AF_ATM, + SOCK_RAW, + ATMPROTO_AAL5, + 0, + 0, + flags)) + == ACE_INVALID_HANDLE) { + ACE_OS::printf ("Acceptor (open): socket %d\n", + ::WSAGetLastError ()); + return (ret); + } + + ((ACE_SOCK_Acceptor *)this) -> set_handle (ret); + + /* Set up the address information to become a server */ + ACE_OS::memset ((void *) &local_atm_addr, 0, sizeof local_atm_addr); + local_atm_addr.satm_family = AF_ATM; + local_atm_addr.satm_number.AddressType = SAP_FIELD_ANY_AESA_REST; + local_atm_addr.satm_number.Addr[ ATM_ADDR_SIZE - 1 ] + = ((ACE_ATM_Addr *)&remote_sap) -> get_selector (); + local_atm_addr.satm_blli.Layer2Protocol = SAP_FIELD_ANY; + local_atm_addr.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT; + local_atm_addr.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT; + + /* Associate address with endpoint */ + if (ACE_OS::bind (((ACE_SOCK_Acceptor *)this) -> get_handle (), + reinterpret_cast (&local_atm_addr), + sizeof local_atm_addr) == -1) { + ACE_OS::printf ("Acceptor (open): bind %d\n", ::WSAGetLastError ()); + return (ACE_INVALID_HANDLE); + } + + /* Make endpoint listen for service requests */ + if (ACE_OS::listen (( (ACE_SOCK_Acceptor *)this) -> get_handle (), + backlog) + == -1) { + ACE_OS::printf ("Acceptor (open): listen %d\n", ::WSAGetLastError ()); + return (ACE_INVALID_HANDLE); + } + + return 0; +#elif defined (ACE_HAS_LINUX_ATM) + //we need to set the qos before binding to the socket + //use remote_sap as local_sap + + ACE_ATM_Addr local_sap; + ATM_Addr *local_sap_addr = (ATM_Addr*)local_sap.get_addr (); + ACE_ATM_QoS def_qos; + ATM_QoS qos = def_qos.get_qos (); + + ACE_HANDLE handle; + if ((handle = ACE_OS::socket (params.get_protocol_family (), + params.get_type (), + params.get_protocol (), + params.get_protocol_info (), + params.get_sock_group (), + params.get_flags () + )) + == ACE_INVALID_HANDLE) { + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("Acceptor (socket): socket %d\n"), + errno); + return (ACE_INVALID_HANDLE); + } + + ((ACE_SOCK_Acceptor *)this) -> set_handle (handle); + if (ACE_OS::setsockopt (handle, + SOL_ATM, + SO_ATMQOS, + reinterpret_cast (&qos), + sizeof (qos)) < 0) { + ACE_OS::printf ("Acceptor (setsockopt): setsockopt:%d\n", + errno); + } + + struct atmif_sioc req; + struct sockaddr_atmsvc aux_addr[1024]; + + req.number = 0; + req.arg = aux_addr; + req.length = sizeof (aux_addr); + if (ACE_OS::ioctl (handle, + ATM_GETADDR, + &req) < 0) { + ACE_OS::perror ("Acceptor (setsockopt): ioctl:"); + } + else { + local_sap_addr->sockaddratmsvc = aux_addr[0]; + } + local_sap.set_selector (( (ACE_ATM_Addr*)&remote_sap)->get_selector ()); + + if (ACE_OS::bind (handle, + reinterpret_cast ( + &(local_sap_addr->sockaddratmsvc)), + sizeof (local_sap_addr->sockaddratmsvc) + ) == -1) { + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("Acceptor (open): bind %d\n"), + errno); + return -1; + } + // Make endpoint listen for service requests + if (ACE_OS::listen (handle, + backlog) + == -1) { + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("Acceptor (listen): listen %d\n"), + errno); + return -1; + } + + return 0; +#else + ACE_UNUSED_ARG (remote_sap); + ACE_UNUSED_ARG (backlog); + ACE_UNUSED_ARG (params); +#endif /* ACE_HAS_FORE_ATM_XTI/ACE_HAS_FORE_ATM_WS2/ACE_HAS_LINUX_ATM */ +} + +int +ACE_ATM_Acceptor::accept (ACE_ATM_Stream &new_sap, + ACE_Addr *remote_addr, + ACE_Time_Value *timeout, + bool restart, + bool reset_new_handle, + ACE_ATM_Params params, + ACE_ATM_QoS qos) +{ + ACE_TRACE ("ACE_ATM_Acceptor::accept"); +#if defined (ACE_HAS_FORE_ATM_XTI) + ATM_QoS optbuf = qos.get_qos (); + + return (acceptor_.accept (new_sap.get_stream (), + remote_addr, + timeout, + restart, + reset_new_handle, + params.get_rw_flag (), + params.get_user_data (), + &optbuf)); +#elif defined (ACE_HAS_FORE_ATM_WS2) + ACE_HANDLE n_handle; + ACE_HANDLE s_handle = ((ACE_SOCK_Acceptor *) this) -> get_handle (); + struct sockaddr_atm *cli_addr + = (struct sockaddr_atm *)remote_addr -> get_addr (); + int caddr_len = sizeof (struct sockaddr_atm); + + do { + n_handle = ACE_OS::accept (s_handle, + reinterpret_cast (cli_addr), + &caddr_len); + } while (n_handle == ACE_INVALID_HANDLE && errno == EINTR); + + ((ACE_ATM_Addr *)remote_addr) -> set (cli_addr, + ((ACE_ATM_Addr *)remote_addr) -> get_selector ()); + ((ACE_IPC_SAP *)&new_sap) -> set_handle (n_handle); + + return 0; +#elif defined (ACE_HAS_LINUX_ATM) + ACE_UNUSED_ARG (params); + + ACE_HANDLE s_handle = ((ACE_SOCK_Acceptor *) this) -> get_handle (); + struct atm_qos accept_qos = qos.get_qos (); + + if (ACE_OS::setsockopt (s_handle, + SOL_ATM, + SO_ATMQOS, + reinterpret_cast (&accept_qos), + sizeof (accept_qos)) < 0) { + ACE_OS::printf ("Acceptor (accept): error setting Qos"); + } + + return (acceptor_.accept (new_sap.get_stream (), + remote_addr, + timeout, + restart, + reset_new_handle)); +#else + ACE_UNUSED_ARG (new_sap); + ACE_UNUSED_ARG (remote_addr); + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (restart); + ACE_UNUSED_ARG (reset_new_handle); + ACE_UNUSED_ARG (params); + ACE_UNUSED_ARG (qos); + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI */ +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + + +#endif /* ACE_HAS_ATM */ diff --git a/dep/acelite/ace/ATM_Acceptor.h b/dep/acelite/ace/ATM_Acceptor.h new file mode 100644 index 000000000..736c980d6 --- /dev/null +++ b/dep/acelite/ace/ATM_Acceptor.h @@ -0,0 +1,121 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file ATM_Acceptor.h + * + * @author Joe Hoffert + */ +//============================================================================= + + +#ifndef ACE_ATM_ACCEPTOR_H +#define ACE_ATM_ACCEPTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#include "ace/ATM_Stream.h" +#include "ace/ATM_Params.h" +#include "ace/ATM_QoS.h" + +#if defined (ACE_HAS_LINUX_ATM) +#include /**/ "atm.h" +#endif /* ACE_HAS_LINUX_ATM */ + +#if defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) +#include "ace/SOCK_Acceptor.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_SOCK_Acceptor ATM_Acceptor; +ACE_END_VERSIONED_NAMESPACE_DECL +#elif defined (ACE_HAS_FORE_ATM_XTI) +#include "ace/TLI_Acceptor.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_TLI_Acceptor ATM_Acceptor; +ACE_END_VERSIONED_NAMESPACE_DECL +#endif // ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations. +class ACE_Time_Value; + +/** + * @class ACE_ATM_Acceptor + * + * @brief Defines the member functions for ACE_ATM_Acceptor abstraction. + * + * This class wraps up the ACE_SOCK_Acceptor and ACE_TLI_Acceptor + * to make the mechanism for the ATM protocol transparent. + */ +class ACE_Export ACE_ATM_Acceptor +{ + +public: + // = Initialization and termination methods. + /// Default constructor. + ACE_ATM_Acceptor (void); + + ~ACE_ATM_Acceptor (); + + /// Initiate a passive mode connection. + ACE_ATM_Acceptor (const ACE_Addr &remote_sap, + int backlog = ACE_DEFAULT_BACKLOG, + ACE_ATM_Params params = ACE_ATM_Params()); + + /// Initiate a passive mode socket. + ACE_HANDLE open (const ACE_Addr &remote_sap, + int backlog = ACE_DEFAULT_BACKLOG, + ACE_ATM_Params params = ACE_ATM_Params()); + + /// Close down the acceptor and release resources. + int close (void); + + // = Passive connection acceptance method. + + /// Accept a new data transfer connection. A @a timeout of 0 means + /// block forever, a @a timeout of {0, 0} means poll. @a restart == 1 + /// means "restart if interrupted." + int accept (ACE_ATM_Stream &new_sap, + ACE_Addr *remote_addr = 0, + ACE_Time_Value *timeout = 0, + bool restart = true, + bool reset_new_handle = false, + ACE_ATM_Params params = ACE_ATM_Params(), + ACE_ATM_QoS qos = ACE_ATM_QoS()); + + /// Get the local address currently listening on + int get_local_addr( ACE_ATM_Addr &local_addr ); + + // = Meta-type info + typedef ACE_ATM_Addr PEER_ADDR; + typedef ACE_ATM_Stream PEER_STREAM; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + ATM_Acceptor acceptor_; +}; + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + + +#if defined (__ACE_INLINE__) +#include "ace/ATM_Acceptor.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_ACCEPTOR_H */ diff --git a/dep/acelite/ace/ATM_Acceptor.inl b/dep/acelite/ace/ATM_Acceptor.inl new file mode 100644 index 000000000..8e4aef7fa --- /dev/null +++ b/dep/acelite/ace/ATM_Acceptor.inl @@ -0,0 +1,40 @@ +// -*- C++ -*- +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_ATM_Acceptor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_Acceptor::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_ATM_Acceptor::ACE_ATM_Acceptor (const ACE_Addr &remote_sap, + int backlog, + ACE_ATM_Params params) +{ + ACE_TRACE ("ACE_ATM_Acceptor::ACE_ATM_Acceptor"); + + //FUZZ: disable check_for_lack_ACE_OS + if (open (remote_sap, backlog, params) < 0) + //FUZZ: enable check_for_lack_ACE_OS + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_ATM_Acceptor::ACE_ATM_Acceptor"))); +} + +ACE_INLINE +int +ACE_ATM_Acceptor::close (void) +{ +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) + return (acceptor_.close()); +#else + return 0; +#endif // ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_Addr.cpp b/dep/acelite/ace/ATM_Addr.cpp new file mode 100644 index 000000000..afe10cc8f --- /dev/null +++ b/dep/acelite/ace/ATM_Addr.cpp @@ -0,0 +1,519 @@ +// Defines the Internet domain address family address format. + +#include "ace/ATM_Addr.h" +#if defined (ACE_HAS_ATM) + +#include "ace/Log_Category.h" + +#if defined (ACE_HAS_FORE_ATM_WS2) +#include /**/ "forews2.h" +#endif /* ACE_HAS_FORE_ATM_WS2 */ + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_Addr.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_ATM_Addr) + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) +#define BHLI_MAGIC "FORE_ATM" +// This is line rate in cells/s for an OC-3 MM interface. +const long ACE_ATM_Addr::LINE_RATE = 353207; +const int ACE_ATM_Addr::OPT_FLAGS_CPID = 0x1; +const int ACE_ATM_Addr::OPT_FLAGS_PMP = 0x2; +const int ACE_ATM_Addr::DEFAULT_SELECTOR = 0x99; +#elif defined (ACE_HAS_LINUX_ATM) +//pbrandao:for Linux: +//pbrandao:for now stick with current definitions +//pbrandao:see if later need to change +const long ACE_ATM_Addr::LINE_RATE = 353207; +const int ACE_ATM_Addr::OPT_FLAGS_CPID = 0; +const int ACE_ATM_Addr::OPT_FLAGS_PMP = 0; +const int ACE_ATM_Addr::DEFAULT_SELECTOR = 0x99; +#else +const long ACE_ATM_Addr::LINE_RATE = 0L; +const int ACE_ATM_Addr::OPT_FLAGS_CPID = 0; +const int ACE_ATM_Addr::OPT_FLAGS_PMP = 0; +const int ACE_ATM_Addr::DEFAULT_SELECTOR = 0x0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + +// Default constructor + +ACE_ATM_Addr::ACE_ATM_Addr (u_char selector) +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + : ACE_Addr (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + : ACE_Addr (PF_ATMSVC, +#else + : ACE_Addr (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + sizeof this->atm_addr_) +{ + // ACE_TRACE ("ACE_ATM_Addr::ACE_ATM_Addr"); + (void) ACE_OS::memset ((void *) &this->atm_addr_, + 0, + sizeof this->atm_addr_); + this->init (selector); +} + +// Copy constructor. + +ACE_ATM_Addr::ACE_ATM_Addr (const ACE_ATM_Addr &sap, + u_char selector) +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + : ACE_Addr (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + : ACE_Addr (PF_ATMSVC, +#else + : ACE_Addr (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + sizeof this->atm_addr_) +{ + ACE_TRACE ("ACE_ATM_Addr::ACE_ATM_Addr"); + this->set (sap, selector); +#if defined (ACE_HAS_LINUX_ATM) + this->atm_addr_.sockaddratmsvc.sas_family = PF_ATMSVC; + this->atm_addr_.atmsap.blli[0].l3_proto = ATM_L3_NONE; + this->atm_addr_.atmsap.blli[0].l2_proto = ATM_L2_NONE; + this->atm_addr_.atmsap.bhli.hl_type = ATM_HL_NONE; +#endif /* ACE_HAS_LINUX_ATM */ +} + +ACE_ATM_Addr::ACE_ATM_Addr (const ATM_Addr *sap, + u_char selector) +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + : ACE_Addr (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + : ACE_Addr (PF_ATMSVC, +#else + : ACE_Addr (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + sizeof this->atm_addr_) +{ + ACE_TRACE ("ACE_ATM_Addr::ACE_ATM_Addr"); + this->set (sap, selector); +} + + +ACE_ATM_Addr::ACE_ATM_Addr (const ACE_TCHAR sap[], + u_char selector) +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + : ACE_Addr (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + : ACE_Addr (PF_ATMSVC, +#else + : ACE_Addr (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + sizeof this->atm_addr_) +{ + ACE_TRACE ("ACE_ATM_Addr::ACE_ATM_Addr"); + this->set (sap, selector); +} + +ACE_ATM_Addr::~ACE_ATM_Addr (void) +{ +} + +// Return the address. + +void * +ACE_ATM_Addr::get_addr (void) const +{ + ACE_TRACE ("ACE_ATM_Addr::get_addr"); + return (void *) &this->atm_addr_; +} + +void +ACE_ATM_Addr::init (u_char selector) +{ +#if defined (ACE_HAS_FORE_ATM_XTI) + // Note: this approach may be FORE implementation-specific. When we + // bind with tag_addr ABSENT and tag_selector PRESENT, only the + // selector (i.e. address[19]) is used by the TP. The rest of the + // local address is filled in by the TP and can be obtained via the + // 'ret' parameter or with t_getname ()/t_getprotaddr (). + + atm_addr_.addressType = (u_int16_t) AF_ATM; + + atm_addr_.sap.t_atm_sap_addr.SVE_tag_addr = (int8_t) T_ATM_ABSENT; + atm_addr_.sap.t_atm_sap_addr.SVE_tag_selector = (int8_t) T_ATM_PRESENT; + + atm_addr_.sap.t_atm_sap_addr.address_format = (u_int8_t) T_ATM_ENDSYS_ADDR; + atm_addr_.sap.t_atm_sap_addr.address_length = ATMNSAP_ADDR_LEN; + atm_addr_.sap.t_atm_sap_addr.address[ATMNSAP_ADDR_LEN - 1] = selector; + + atm_addr_.sap.t_atm_sap_layer2.SVE_tag = (int8_t) T_ATM_ABSENT; + atm_addr_.sap.t_atm_sap_layer3.SVE_tag = (int8_t) T_ATM_ABSENT; + + atm_addr_.sap.t_atm_sap_appl.SVE_tag = (int8_t) T_ATM_PRESENT; + atm_addr_.sap.t_atm_sap_appl.ID_type = (u_int8_t) T_ATM_USER_APP_ID; + + ACE_OS::memcpy (atm_addr_.sap.t_atm_sap_appl.ID.user_defined_ID, + BHLI_MAGIC, + sizeof atm_addr_.sap.t_atm_sap_appl.ID); +#elif defined (ACE_HAS_FORE_ATM_WS2) + ACE_OS::memset ((void *)&atm_addr_, 0, sizeof atm_addr_); + atm_addr_.satm_number.Addr[ ATM_ADDR_SIZE - 1 ] = (char)selector; + atm_addr_.satm_family = AF_ATM; + atm_addr_.satm_number.AddressType = ATM_NSAP; + atm_addr_.satm_number.NumofDigits = ATM_ADDR_SIZE; + atm_addr_.satm_blli.Layer2Protocol = SAP_FIELD_ABSENT; + atm_addr_.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT; + atm_addr_.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT; + + // Need to know the correspondence. + //atm_addr_.sap.t_atm_sap_appl.SVE_tag = (int8_t) T_ATM_PRESENT; + //atm_addr_.sap.t_atm_sap_appl.ID_type = (u_int8_t) T_ATM_USER_APP_ID; + //ACE_OS::memcpy (atm_addr_.sap.t_atm_sap_appl.ID.user_defined_ID, + // BHLI_MAGIC, + // sizeof atm_addr_.sap.t_atm_sap_appl.ID); +#elif defined (ACE_HAS_LINUX_ATM) + atm_addr_.sockaddratmsvc.sas_family = AF_ATMSVC; + atm_addr_.sockaddratmsvc.sas_addr.prv[ATM_ESA_LEN - 1] = (char)selector; + atm_addr_.atmsap.blli[0].l3_proto = ATM_L3_NONE; + atm_addr_.atmsap.blli[0].l2_proto = ATM_L2_NONE; + atm_addr_.atmsap.bhli.hl_type = ATM_HL_NONE; +#else + ACE_UNUSED_ARG (selector); +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +int +ACE_ATM_Addr::set (const ACE_ATM_Addr &sap, + u_char selector) +{ + ACE_TRACE ("ACE_ATM_Addr::set"); + + this->init (selector); + + this->ACE_Addr::base_set (sap.get_type (), + sap.get_size ()); + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + ACE_ASSERT (sap.get_type () == AF_ATM); +#elif defined (ACE_HAS_LINUX_ATM) + ACE_ASSERT (sap.get_type () == PF_ATMSVC); +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 */ + + (void) ACE_OS::memcpy ((void *) &this->atm_addr_, + (void *) &sap.atm_addr_, + sizeof this->atm_addr_); + return 0; +} + +int +ACE_ATM_Addr::set (const ATM_Addr *sap, + u_char selector) +{ + ACE_TRACE ("ACE_ATM_Addr::set"); + + this->init (selector); + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + this->ACE_Addr::base_set (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + this->ACE_Addr::base_set (PF_ATMSVC, +#else + this->ACE_Addr::base_set (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 */ + sizeof (*sap)); + + (void) ACE_OS::memcpy ((void *) &this->atm_addr_, + (void *) sap, + sizeof this->atm_addr_); + return 0; +} + +int +ACE_ATM_Addr::set (const ACE_TCHAR address[], + u_char selector) +{ + ACE_TRACE ("ACE_ATM_Addr::set"); + int ret; + + this->init (selector); + +#if defined (ACE_HAS_FORE_ATM_XTI) + atm_addr_.sap.t_atm_sap_addr.SVE_tag_addr = + (int8_t) T_ATM_PRESENT; +#endif /* ACE_HAS_FORE_ATM_XTI */ + + ret = this -> string_to_addr (address); + this -> set_selector (selector); + return ret; +} + +// Transform the string into the current addressing format. + +int +ACE_ATM_Addr::string_to_addr (const ACE_TCHAR sap[]) +{ + ACE_TRACE ("ACE_ATM_Addr::string_to_addr"); + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + this->ACE_Addr::base_set (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + this->ACE_Addr::base_set (PF_ATMSVC, +#else + this->ACE_Addr::base_set (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + sizeof this->atm_addr_); +#if defined (ACE_HAS_FORE_ATM_XTI) + struct hostent *entry; + struct atmnsap_addr *nsap; + + // Yow, someone gave us a NULL ATM address! + if (sap == 0) + { + errno = EINVAL; + return -1; + } + else if ((entry = gethostbyname_atmnsap ((ACE_TCHAR *)sap)) != 0) + { + ACE_OS::memcpy (atm_addr_.sap.t_atm_sap_addr.address, + entry->h_addr_list[0], + ATMNSAP_ADDR_LEN - 1); + } + else if ((nsap = atmnsap_addr (sap)) != 0) + { + ACE_OS::memcpy (atm_addr_.sap.t_atm_sap_addr.address, + nsap->atmnsap, + ATMNSAP_ADDR_LEN); + } + else { + errno = EINVAL; + return -1; + } +#elif defined (ACE_HAS_FORE_ATM_WS2) + DWORD dwValue; + HANDLE hLookup; + WSAQUERYSETW qsRestrictions; + CSADDR_INFO csaBuffer; + WCHAR tmpWStr[100]; + + MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED, sap, -1, tmpWStr, 100); + + csaBuffer.LocalAddr.iSockaddrLength = sizeof (struct sockaddr_atm); + csaBuffer.LocalAddr.lpSockaddr = (struct sockaddr *)&atm_addr_; + csaBuffer.RemoteAddr.iSockaddrLength = sizeof (struct sockaddr_atm); + csaBuffer.RemoteAddr.lpSockaddr = (struct sockaddr *)&atm_addr_; + + qsRestrictions.dwSize = sizeof (WSAQUERYSETW); + qsRestrictions.lpszServiceInstanceName = 0; + qsRestrictions.lpServiceClassId = &FORE_NAME_CLASS; + qsRestrictions.lpVersion = 0; + qsRestrictions.lpszComment = 0; + qsRestrictions.dwNameSpace = FORE_NAME_SPACE; + qsRestrictions.lpNSProviderId = 0; + qsRestrictions.lpszContext = L""; + qsRestrictions.dwNumberOfProtocols = 0; + qsRestrictions.lpafpProtocols = 0; + qsRestrictions.lpszQueryString = tmpWStr; + qsRestrictions.dwNumberOfCsAddrs = 1; + qsRestrictions.lpcsaBuffer = &csaBuffer; + qsRestrictions.lpBlob = 0; //&blob; + + if (::WSALookupServiceBeginW (&qsRestrictions, LUP_RETURN_ALL, &hLookup) + == SOCKET_ERROR) { + ACE_OS::printf ("Error: WSALookupServiceBeginW failed! %d\n", + ::WSAGetLastError ()); + return -1; + } + + dwValue = sizeof (WSAQUERYSETW); + + if (::WSALookupServiceNextW (hLookup, 0, &dwValue, &qsRestrictions) + == SOCKET_ERROR) { + if (WSAGetLastError () != WSA_E_NO_MORE) { + ACE_OS::printf ("Error: WSALookupServiceNextW failed! %d\n", + ::WSAGetLastError ()); + return -1; + } + } + + if (WSALookupServiceEnd (hLookup) == SOCKET_ERROR) { + ACE_OS::printf ("Error : WSALookupServiceEnd failed! %d\n", + ::WSAGetLastError ()); + errno = EINVAL; + return -1; + } +#elif defined (ACE_HAS_LINUX_ATM) + if (sap == 0 || !ACE_OS::strcmp (sap,"")) { + errno = EINVAL; + return -1; + } + + if (text2atm ((ACE_TCHAR *)sap, + (struct sockaddr *)& (atm_addr_.sockaddratmsvc), + sizeof (atm_addr_.sockaddratmsvc), + T2A_SVC | T2A_NAME) < 0) { + ACELIB_DEBUG (LM_DEBUG, + "Error : text2atm failed!\n"); + errno = EINVAL; + return -1; + } +#else + ACE_UNUSED_ARG (sap); + + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 */ +} + +// Transform the current address into string format. + +int +ACE_ATM_Addr::addr_to_string (ACE_TCHAR addr[], + size_t addrlen) const +{ + ACE_TRACE ("ACE_ATM_Addr::addr_to_string"); + +#if defined (ACE_HAS_FORE_ATM_XTI) + ACE_TCHAR buffer[MAXNAMELEN + 1]; + struct atmnsap_addr nsap; + ACE_OS::memcpy (nsap.atmnsap, + atm_addr_.sap.t_atm_sap_addr.address, + ATMNSAP_ADDR_LEN); + ACE_OS::sprintf (buffer, + ACE_TEXT ("%s"), + atmnsap_ntoa (nsap)); + + size_t total_len = ACE_OS::strlen (buffer) + sizeof ('\0'); + + if (addrlen < total_len) + return -1; + else + ACE_OS::strcpy (addr, buffer); + + return 0; +#elif defined (ACE_HAS_FORE_ATM_WS2) + ACE_TCHAR buffer[MAXNAMELEN + 1]; + int i; + + if (addrlen < ATM_ADDR_SIZE + 1) + return -1; + + for (i = 0; i < ATM_ADDR_SIZE; i++) { + buffer[ i * 3 ] = '\0'; + ACE_OS::sprintf (buffer, ACE_TEXT ("%s%02x."), + buffer, + atm_addr_.satm_number.Addr[ i ]); + } + + buffer[ ATM_ADDR_SIZE * 3 - 1 ] = '\0'; + ACE_OS::strcpy (addr, buffer); + + return 0; +#elif defined (ACE_HAS_LINUX_ATM) + ACE_TCHAR buffer[MAX_ATM_ADDR_LEN + 1]; + int total_len; + if ((total_len = atm2text (buffer, + sizeof buffer, + (struct sockaddr *)& (atm_addr_.sockaddratmsvc), + A2T_PRETTY)) < 0) { + ACELIB_DEBUG ((LM_DEBUG,"ACE_ATM_Addr (addr_to_string): atm2text failed\n")); + return -1; + } + if (addrlen < (size_t)total_len) + return -1; + else + ACE_OS::strcpy (addr, + buffer); + + return 0; +#else + ACE_UNUSED_ARG (addr); + ACE_UNUSED_ARG (addrlen); + return -1; +#endif /* ACE_HAS_FORE_ATM_XTI && ACE_HAS_FORE_ATM_WS2 */ +} + +const ACE_TCHAR * +ACE_ATM_Addr::addr_to_string (void) const +{ + ACE_TRACE ("ACE_ATM_Addr::addr_to_string"); + + static ACE_TCHAR addr[MAXHOSTNAMELEN + 1]; + if (this->addr_to_string (addr, + MAXHOSTNAMELEN + 1) < 0) + return 0; + + return addr; +} + +// Set a pointer to the address. +void +ACE_ATM_Addr::set_addr (const void *addr, int len) +{ + ACE_TRACE ("ACE_ATM_Addr::set_addr"); + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + this->ACE_Addr::base_set (AF_ATM, +#elif defined (ACE_HAS_LINUX_ATM) + this->ACE_Addr::base_set (PF_ATMSVC, +#else + this->ACE_Addr::base_set (AF_UNSPEC, +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_WS2 */ + len); + ACE_OS::memcpy (&this->atm_addr_, addr, len); +} + +// Compare two addresses for inequality. + +bool +ACE_ATM_Addr::operator != (const ACE_ATM_Addr &sap) const +{ + ACE_TRACE ("ACE_ATM_Addr::operator !="); + return ! ((*this) == sap); +} + +// Compare two addresses for equality. + +bool +ACE_ATM_Addr::operator == (const ACE_ATM_Addr &sap) const +{ + ACE_TRACE ("ACE_ATM_Addr::operator =="); + +#if defined (ACE_HAS_LINUX_ATM) + return (atm_equal ((const struct sockaddr *)& (this->atm_addr_.sockaddratmsvc), + (const struct sockaddr *)& (sap.atm_addr_.sockaddratmsvc), + 0, + 0) + && + sap_equal (& (this->atm_addr_.atmsap), + & (sap.atm_addr_.atmsap), + 0)); +#else + return ACE_OS::memcmp (&atm_addr_, + &sap.atm_addr_, + sizeof (ATM_Addr)) == 0; +#endif /* ACE_HAS_LINUX_ATM */ +} + +void +ACE_ATM_Addr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_Addr::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACE_TCHAR s[ACE_MAX_FULLY_QUALIFIED_NAME_LEN + 16]; + ACE_OS::sprintf (s, + ACE_TEXT ("%s"), + this->addr_to_string ()); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("%s"), s)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_ATM */ diff --git a/dep/acelite/ace/ATM_Addr.h b/dep/acelite/ace/ATM_Addr.h new file mode 100644 index 000000000..8f8aac81d --- /dev/null +++ b/dep/acelite/ace/ATM_Addr.h @@ -0,0 +1,195 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file ATM_Addr.h + * + * @author Joe Hoffert + */ +//========================================================================== + +#ifndef ACE_ATM_ADDR_H +#define ACE_ATM_ADDR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#include /**/ "ace/ACE_export.h" +#include "ace/Addr.h" + +#if defined (ACE_HAS_FORE_ATM_XTI) +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ATMSAPAddress ATM_Addr; +ACE_END_VERSIONED_NAMESPACE_DECL +#elif defined (ACE_HAS_FORE_ATM_WS2) +#define FORE_NAME_SPACE NS_ALL +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef struct sockaddr_atm ATM_Addr; +ACE_END_VERSIONED_NAMESPACE_DECL +#elif defined (ACE_HAS_LINUX_ATM) + +#include /**/ "atm.h" + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +//pbrandao:as Linux has this 2 structs separeted we "link it" here +typedef struct _linux_atm_addr +{ + struct sockaddr_atmsvc sockaddratmsvc; + struct atm_sap atmsap; +} ATM_Addr; +#else +typedef int ATM_Addr; +#endif /* ACE_HAS_FORE_ATM_XTI/ACE_HAS_FORE_ATM_WS2/ACE_HAS_LINUX_ATM */ + +/** + * @class ACE_ATM_Addr + * + * @brief Defines the ATM domain address family address format. + */ +class ACE_Export ACE_ATM_Addr : public ACE_Addr +{ +public: + // Constants used for ATM options + static const long LINE_RATE; + static const int OPT_FLAGS_CPID; + static const int OPT_FLAGS_PMP; + static const int DEFAULT_SELECTOR; + + // = Initialization methods. + /// Default constructor. + ACE_ATM_Addr (u_char selector = DEFAULT_SELECTOR); + + /// Copy constructor. + ACE_ATM_Addr (const ACE_ATM_Addr &, + u_char selector = DEFAULT_SELECTOR); + + /** + * Creates an ACE_ATM_Addr from an ATMSAPAddress structure. This + * is vendor specific (FORE systems). May need to change when other + * vendors are supported. + */ + ACE_ATM_Addr (const ATM_Addr *, + u_char selector = DEFAULT_SELECTOR); + + /** + * Initializes an ACE_ATM_Addr from the which can be + * "atm-address" (e.g., + * "47.0005.80.ffe100.0000.f20f.2200.0020480694f9.00") or "hostname" + * (e.g., "frisbee.cs.wustl.edu"). + */ + ACE_ATM_Addr (const ACE_TCHAR sap[], + u_char selector = DEFAULT_SELECTOR); + + /// Default dtor. + ~ACE_ATM_Addr (void); + + // = Initialization methods (useful after object construction). + /// Default initialization for non-address values (e.g., + /// t_atm_sap_addr.SVE_tag_addr, t_atm_sap_addr.SVE_tag_selector) + void init (u_char selector = DEFAULT_SELECTOR); + + /// Initializes from another ACE_ATM_Addr. + int set (const ACE_ATM_Addr &, + u_char selector = DEFAULT_SELECTOR); + + /** + * Initializes an ACE_ATM_Addr from an ATMSAPAddress/sockaddr_atm + * structure. This is vendor specific (FORE systems). May need to + * change when other vendors are supported. + */ + int set (const ATM_Addr *, + u_char selector = DEFAULT_SELECTOR); + + /** + * Initializes an ACE_ATM_Addr from the which can be + * "atm-address" (e.g., + * "47.0005.80.ffe100.0000.f20f.2200.0020480694f9.00") or "hostname" + * (e.g., "frisbee.cs.wustl.edu"). + */ + int set (const ACE_TCHAR sap[], + u_char selector = DEFAULT_SELECTOR); + + /** + * Initializes an ACE_ATM_Addr from the which can be + * "atm-address" (e.g., + * "47.0005.80.ffe100.0000.f20f.2200.0020480694f9.00") or "hostname" + * (e.g., "frisbee.cs.wustl.edu"). + */ + virtual int string_to_addr (const ACE_TCHAR sap[]); + + /** + * Return the character representation of the ATM address (e.g., + * "47.0005.80.ffe100.0000.f20f.2200.0020480694f9.00") storing it in + * the @a addr (which is assumed to be bytes long). This + * version is reentrant. Returns -1 if the of the @a addr + * is too small, else 0. + */ + virtual int addr_to_string (ACE_TCHAR addr[], + size_t addrlen) const; + + /** + * Return the character representation of the ATM address (e.g., + * "47.0005.80.ffe100.0000.f20f.2200.0020480694f9.00"). Returns -1 + * if the of the is too small, else 0.(This version + * is non-reentrant since it returns a pointer to a static data + * area.) + */ + const ACE_TCHAR *addr_to_string (void) const; + + /// Return a pointer to the underlying network address. + virtual void *get_addr (void) const; + + /// Set a pointer to the address. + virtual void set_addr (const void *, int); + + /// Return the selector for network address. + u_char get_selector (void) const; + + /// Set the selector for the network address. + void set_selector (u_char selector); + + /** + * Compare two addresses for equality. The addresses are considered + * equal if they contain the same ATM address. Q: Is there any + * other check for equality needed for ATM? + */ + bool operator == (const ACE_ATM_Addr &SAP) const; + + /// Compare two addresses for inequality. + bool operator != (const ACE_ATM_Addr &SAP) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +// char *construct_options (ACE_HANDLE fd, +// int qos_kb, +// int flags, +// long *optsize); +// // Construct options for ATM connections + +private: + ATM_Addr atm_addr_; +}; + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + + +#if defined (__ACE_INLINE__) +#include "ace/ATM_Addr.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_ADDR_H */ diff --git a/dep/acelite/ace/ATM_Addr.inl b/dep/acelite/ace/ATM_Addr.inl new file mode 100644 index 000000000..d1f7e2c4d --- /dev/null +++ b/dep/acelite/ace/ATM_Addr.inl @@ -0,0 +1,34 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE u_char +ACE_ATM_Addr::get_selector (void) const +{ + ACE_TRACE ("ACE_ATM_Addr::get_selector"); +#if defined (ACE_HAS_FORE_ATM_XTI) + return atm_addr_.sap.t_atm_sap_addr.address[ATMNSAP_ADDR_LEN - 1]; +#elif defined (ACE_HAS_FORE_ATM_WS2) + return atm_addr_.satm_number.Addr[ ATM_ADDR_SIZE - 1 ]; +#elif defined (ACE_HAS_LINUX_ATM) + return atm_addr_.sockaddratmsvc.sas_addr.prv[ATM_ESA_LEN - 1]; +#else + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +ACE_INLINE void +ACE_ATM_Addr::set_selector (u_char selector) +{ + ACE_TRACE ("ACE_ATM_Addr::set_selector"); +#if defined (ACE_HAS_FORE_ATM_XTI) + atm_addr_.sap.t_atm_sap_addr.address[ATMNSAP_ADDR_LEN - 1] = selector; +#elif defined (ACE_HAS_FORE_ATM_WS2) + atm_addr_.satm_number.Addr[ ATM_ADDR_SIZE - 1 ] = selector; +#elif defined (ACE_HAS_LINUX_ATM) + atm_addr_.sockaddratmsvc.sas_addr.prv[ATM_ESA_LEN - 1] = selector; +#else + ACE_UNUSED_ARG (selector); +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_Connector.cpp b/dep/acelite/ace/ATM_Connector.cpp new file mode 100644 index 000000000..b05860557 --- /dev/null +++ b/dep/acelite/ace/ATM_Connector.cpp @@ -0,0 +1,136 @@ +// ATM_Connector.cpp +#include "ace/ATM_Connector.h" +#if defined (ACE_HAS_ATM) + +#include "ace/Handle_Set.h" + + + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_Connector.inl" +#endif /* __ACE_INLINE__ */ + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_ATM_Connector) + +ACE_ATM_Connector::ACE_ATM_Connector (void) +{ + ACE_TRACE ("ACE_ATM_Connector::ACE_ATM_Connector"); +} + +// Actively connect and produce a new ACE_ATM_Stream if things go well... +// Connect the to the , waiting up to +// amount of time if necessary. + +int +ACE_ATM_Connector::connect (ACE_ATM_Stream &new_stream, + const ACE_ATM_Addr &remote_sap, + ACE_ATM_Params params, + ACE_ATM_QoS options, + ACE_Time_Value *timeout, + const ACE_ATM_Addr &local_sap, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_ATM_Connector::connect"); +#if defined (ACE_HAS_FORE_ATM_XTI) + return connector_.connect(new_stream.get_stream(), + remote_sap, + timeout, + local_sap, + reuse_addr, + flags, + perms, + params.get_device(), + params.get_info(), + params.get_rw_flag(), + params.get_user_data(), + &options.get_qos()); +#elif defined (ACE_HAS_FORE_ATM_WS2) + ACELIB_DEBUG(LM_DEBUG, + ACE_TEXT ("ATM_Connector(connect): set QoS parameters\n" )); + + ACE_HANDLE s = new_stream.get_handle(); + struct sockaddr_atm *saddr = ( struct sockaddr_atm *)remote_sap.get_addr(); + ACE_QoS cqos = options.get_qos(); + + ACE_QoS_Params qos_params = ACE_QoS_Params(0, + 0, + &cqos, + 0, + 0); + + ACELIB_DEBUG(LM_DEBUG, + ACE_TEXT ("ATM_Connector(connect): connecting...\n")); + + int result = ACE_OS::connect( s, + ( struct sockaddr *)saddr, + sizeof( struct sockaddr_atm ), + qos_params ); + + if ( result != 0 ) + ACE_OS::printf( "ATM_Connector(connect): connection failed, %d\n", + ::WSAGetLastError()); + + return result; +#elif defined (ACE_HAS_LINUX_ATM) + ACE_UNUSED_ARG (params); + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (reuse_addr); + ACE_UNUSED_ARG (perms); + ACE_UNUSED_ARG (flags); + + ACE_HANDLE handle = new_stream.get_handle(); + ATM_QoS qos =options.get_qos(); + ATM_Addr *local_addr=(ATM_Addr*)local_sap.get_addr(), + *remote_addr=(ATM_Addr*)remote_sap.get_addr(); + + if (ACE_OS::setsockopt(handle, + SOL_ATM, + SO_ATMSAP, + reinterpret_cast (&(local_addr->atmsap)), + sizeof(local_addr->atmsap)) < 0) { + ACE_OS::printf( "ATM_Connector(connect): unable to set atmsap %d\nContinuing...", + errno); + } + if (ACE_OS::setsockopt(handle, + SOL_ATM, + SO_ATMQOS, + reinterpret_cast (&qos), + sizeof(qos)) < 0) { + ACELIB_DEBUG((LM_DEBUG,ACE_TEXT ("ATM_Connector(connect): unable to set qos %d\n"), + errno)); + return -1; + } + + int result = ACE_OS::connect(handle, + (struct sockaddr *)&(remote_addr->sockaddratmsvc), + sizeof( remote_addr->sockaddratmsvc)); + + if ( result != 0 ) + ACELIB_DEBUG(LM_DEBUG, + ACE_TEXT ("ATM_Connector(connect): connection failed, %d\n"), + errno); + + return result; +#else + ACE_UNUSED_ARG (new_stream); + ACE_UNUSED_ARG (remote_sap); + ACE_UNUSED_ARG (params); + ACE_UNUSED_ARG (options); + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (local_sap); + ACE_UNUSED_ARG (reuse_addr); + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (perms); + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_ATM */ diff --git a/dep/acelite/ace/ATM_Connector.h b/dep/acelite/ace/ATM_Connector.h new file mode 100644 index 000000000..2bca5b61d --- /dev/null +++ b/dep/acelite/ace/ATM_Connector.h @@ -0,0 +1,162 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file ATM_Connector.h + * + * @author Joe Hoffert + */ +//============================================================================= + +#ifndef ACE_ATM_CONNECTOR_H +#define ACE_ATM_CONNECTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#include "ace/ATM_Stream.h" +#include "ace/ATM_Params.h" +#include "ace/ATM_QoS.h" + +#if defined (ACE_WIN32) || defined (ACE_HAS_LINUX_ATM) +#include "ace/SOCK_Connector.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_SOCK_Connector ATM_Connector; +ACE_END_VERSIONED_NAMESPACE_DECL +#else +#include "ace/XTI_ATM_Mcast.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_XTI_ATM_Mcast ATM_Connector; +// Open versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL +#endif + +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_ATM_Connector + * + * @brief Defines an active connection factory for the ACE_ATM C++ + * wrappers. + */ +class ACE_Export ACE_ATM_Connector +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_ATM_Connector (void); + + /** + * Actively connect and produce a @a new_stream if things go well. + * The @a remote_sap is the address that we are trying to connect + * with. The are the parameters needed for either socket + * or XTI/ATM connections. The @a timeout is the amount of time to + * wait to connect. If it's 0 then we block indefinitely. If + * *timeout == {0, 0} then the connection is done using non-blocking + * mode. In this case, if the connection can't be made immediately + * the value of -1 is returned with @c errno == EWOULDBLOCK. If + * *timeout > {0, 0} then this is the maximum amount of time to wait before + * timing out. If the time expires before the connection is made + * @c errno == ETIME. The @a local_sap is the value of local address + * to bind to. If it's the default value of then + * the user is letting the OS do the binding. If @a reuse_addr == 1 + * then the is reused, even if it hasn't been cleanedup yet. + */ + ACE_ATM_Connector (ACE_ATM_Stream &new_stream, + const ACE_ATM_Addr &remote_sap, + ACE_ATM_Params params = ACE_ATM_Params(), + ACE_ATM_QoS options = ACE_ATM_QoS(), + ACE_Time_Value *timeout = 0, + const ACE_ATM_Addr &local_sap = ACE_ATM_Addr( "", 0 ), + int reuse_addr = 0, +#if defined (ACE_WIN32) + int flags = 0, +#else + int flags = O_RDWR, +#endif /* ACE_WIN32 */ + int perms = 0); + + /** + * Actively connect and produce a @a new_stream if things go well. + * The @a remote_sap is the address that we are trying to connect + * with. The are the parameters needed for either socket + * or XTI/ATM connections. The @a timeout is the amount of time to + * wait to connect. If it's 0 then we block indefinitely. If + * *timeout == {0, 0} then the connection is done using non-blocking + * mode. In this case, if the connection can't be made immediately + * the value of -1 is returned with @c errno == EWOULDBLOCK. If + * *timeout > {0, 0} then this is the maximum amount of time to wait before + * timing out. If the time expires before the connection is made + * @c errno == ETIME. The @a local_sap is the value of local address + * to bind to. If it's the default value of then + * the user is letting the OS do the binding. If @a reuse_addr == 1 + * then the is reused, even if it hasn't been cleanedup yet. + */ + int connect (ACE_ATM_Stream &new_stream, + const ACE_ATM_Addr &remote_sap, + ACE_ATM_Params params = ACE_ATM_Params(), + ACE_ATM_QoS options = ACE_ATM_QoS(), + ACE_Time_Value *timeout = 0, + const ACE_ATM_Addr &local_sap = ACE_ATM_Addr( "", + 0 ), + int reuse_addr = 0, +#if defined (ACE_WIN32) + int flags = 0, +#else + int flags = O_RDWR, +#endif /* ACE_WIN32 */ + int perms = 0); + + /** + * Try to complete a non-blocking connection. + * If connection completion is successful then @a new_stream contains + * the connected ACE_SOCK_Stream. If @a remote_sap is non-NULL then it + * will contain the address of the connected peer. + */ + int complete (ACE_ATM_Stream &new_stream, + ACE_ATM_Addr *remote_sap, + ACE_Time_Value *tv); + + /** + * Actively add a leaf to the root (i.e., point-to-multipoint). The + * @a remote_sap is the address of the leaf that we + * are trying to add. + */ + int add_leaf (ACE_ATM_Stream ¤t_stream, + const ACE_Addr &remote_sap, + ACE_ATM_QoS &qos); + + /// Resets any event associations on this handle + bool reset_new_handle (ACE_HANDLE handle); + + // = Meta-type info + typedef ACE_ATM_Addr PEER_ADDR; + typedef ACE_ATM_Stream PEER_STREAM; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + ATM_Connector connector_; +}; + +// Open versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ATM_Connector.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_CONNECTOR_H */ diff --git a/dep/acelite/ace/ATM_Connector.inl b/dep/acelite/ace/ATM_Connector.inl new file mode 100644 index 000000000..e35f40854 --- /dev/null +++ b/dep/acelite/ace/ATM_Connector.inl @@ -0,0 +1,129 @@ +// -*- C++ -*- +// Open versioned namespace, if enabled by the user. +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_ATM_Connector::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_Connector::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_ATM_Connector::ACE_ATM_Connector (ACE_ATM_Stream &new_stream, + const ACE_ATM_Addr &remote_sap, + ACE_ATM_Params params, + ACE_ATM_QoS options, + ACE_Time_Value *timeout, + const ACE_ATM_Addr &local_sap, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_ATM_Connector::ACE_ATM_Connector"); + if ((ACE_HANDLE)this->connect (new_stream, + remote_sap, + params, + options, + timeout, + local_sap, + reuse_addr, + flags, + perms) == ACE_INVALID_HANDLE + && timeout != 0 && !(errno == EWOULDBLOCK || errno == ETIME)) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_ATM_Stream::ACE_ATM_Stream"))); +} + +// Try to complete a non-blocking connection. + +ACE_INLINE +int +ACE_ATM_Connector::complete (ACE_ATM_Stream &new_stream, + ACE_ATM_Addr *remote_sap, + ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_ATM_Connector::complete"); +#if defined (ACE_HAS_ATM) + return connector_.complete(new_stream.get_stream(), + remote_sap, + tv); +#else + ACE_UNUSED_ARG(new_stream); + ACE_UNUSED_ARG(remote_sap); + ACE_UNUSED_ARG(tv); + return 0; +#endif +} + +ACE_INLINE +int +ACE_ATM_Connector::add_leaf (ACE_ATM_Stream ¤t_stream, + const ACE_Addr &remote_sap, + ACE_ATM_QoS &qos) +{ + ACE_TRACE ("ACE_ATM_Connector::add_leaf"); +#if defined (ACE_HAS_FORE_ATM_XTI) + return connector_.add_leaf(current_stream.get_stream(), + remote_sap, + leaf_id, + timeout); +#elif defined (ACE_HAS_FORE_ATM_WS2) + struct sockaddr_atm *saddr = (struct sockaddr_atm *)remote_sap.get_addr(); + ACE_QoS cqos = qos.get_qos(); + int addr_len = sizeof( struct sockaddr_atm ); + + ACE_QoS_Params qos_params(0, + 0, + &cqos, + 0, + (JL_SENDER_ONLY)); + + ACE_OS::printf( "ATM_Connector::add_leaf: connecting...\n" ); + + ACE_HANDLE result = ACE_OS::join_leaf(current_stream.get_handle(), + (struct sockaddr *)saddr, + addr_len, + qos_params); + + if ( result == ACE_INVALID_HANDLE ) + ACE_OS::printf( "ATM_Connector(add_leaf): connection failed, %d\n", + ::WSAGetLastError()); + + return (result != ACE_INVALID_HANDLE); +#elif defined (ACE_HAS_LINUX_ATM) + ACE_OS::printf("ATM_Connector(add_leaf): not yet implemented in Linux\n"); + + ACE_UNUSED_ARG(current_stream); + ACE_UNUSED_ARG(remote_sap); + ACE_UNUSED_ARG(leaf_id); + ACE_UNUSED_ARG(timeout); + + return 0; +#else + ACE_UNUSED_ARG(current_stream); + ACE_UNUSED_ARG(remote_sap); + ACE_UNUSED_ARG(leaf_id); + ACE_UNUSED_ARG(timeout); + return 0; +#endif +} + +ACE_INLINE +bool +ACE_ATM_Connector::reset_new_handle (ACE_HANDLE handle) +{ +#if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) + // Reset the event association + return ::WSAEventSelect ((SOCKET) handle, + 0, + 0); +#else /* !defined ACE_HAS_WINSOCK2 */ + ACE_UNUSED_ARG (handle); + return false; +#endif /* ACE_WIN32 */ +} + +// Close versioned namespace, if enabled by the user. +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_Params.cpp b/dep/acelite/ace/ATM_Params.cpp new file mode 100644 index 000000000..ac8a996e5 --- /dev/null +++ b/dep/acelite/ace/ATM_Params.cpp @@ -0,0 +1,18 @@ +#include "ace/ATM_Params.h" + +#if defined (ACE_HAS_ATM) + + + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_Params.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_ATM_Params) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_ATM */ + diff --git a/dep/acelite/ace/ATM_Params.h b/dep/acelite/ace/ATM_Params.h new file mode 100644 index 000000000..34db50248 --- /dev/null +++ b/dep/acelite/ace/ATM_Params.h @@ -0,0 +1,212 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file ATM_Params.h + * + * @author Joe Hoffert + */ +//========================================================================== + + +#ifndef ACE_ATM_PARAMS_H +#define ACE_ATM_PARAMS_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#include /**/ "ace/ACE_export.h" + +#if defined (ACE_HAS_FORE_ATM_XTI) +#include "ace/TLI.h" +#define ATM_PROTOCOL_DEFAULT 0 +typedef struct t_info Param_Info; +typedef struct netbuf Param_Udata; +#elif defined (ACE_HAS_FORE_ATM_WS2) +#include "ace/SOCK.h" +#define ATM_PROTOCOL_DEFAULT ATMPROTO_AAL5 +#define ACE_XTI_ATM_DEVICE "" +typedef int Param_Info; +typedef int Param_Udata; +#elif defined (ACE_HAS_LINUX_ATM) +#include /**/ "atm.h" +#define AF_ATM PF_ATMSVC +#define ACE_XTI_ATM_DEVICE "" +#define ATM_PROTOCOL_DEFAULT ATM_AAL5 +typedef int Param_Info; +typedef int Param_Udata; +#else +#define ACE_XTI_ATM_DEVICE "" +typedef int Param_Info; +typedef int Param_Udata; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_ATM_Params + * + * @brief Wrapper class that simplifies the information passed to the ATM + * enabled ACE_ATM_Connector class. + */ +class ACE_Export ACE_ATM_Params +{ +public: + /** + * Initialize the data members. This class combines options from + * ACE_SOCK_Connector (@a protocol_family, @a protocol, , + * @a protocol_info, , and @a flags) and + * ACE_TLI_Connector (, , , , and ) + * so that either mechanism can be used transparently for ATM. + */ + ACE_ATM_Params (int rw_flag = 1, + const char device[] = ACE_XTI_ATM_DEVICE, + Param_Info *info = 0, + Param_Udata *udata = 0, + int oflag = O_RDWR, + int protocol_family = AF_ATM, + int protocol = ATM_PROTOCOL_DEFAULT, + int type = +#if defined (ACE_HAS_LINUX_ATM) + SOCK_DGRAM, +#else + SOCK_RAW, +#endif /* ACE_HAS_LINUX_ATM */ + ACE_Protocol_Info *protocol_info = 0, + ACE_SOCK_GROUP g = 0, + u_long flags + = ACE_FLAG_MULTIPOINT_C_ROOT + | ACE_FLAG_MULTIPOINT_D_ROOT, // connector by default + int reuse_addr = 0); + + /// Destructor. + ~ACE_ATM_Params (); + + /// Get protocol family. + int get_protocol_family (void) const; + + /// Set protocol family. + void set_protocol_family (int); + + /// Get protocol. + int get_protocol (void) const; + + /// Set protocol. + void set_protocol (int); + + /// Get type. + int get_type (void) const; + + /// Set type. + void set_type (int); + + /// Get protocol info. + ACE_Protocol_Info *get_protocol_info( void ); + + /// Set protocol info. + void set_protocol_info( ACE_Protocol_Info *); + + /// Get socket group. + ACE_SOCK_GROUP get_sock_group( void ); + + /// Set socket group. + void set_sock_group( ACE_SOCK_GROUP ); + + /// Get socket flags. + u_long get_flags( void ); + + /// Set socket flags. + void set_flags( u_long ); + + /// Get reuse_addr flag. + int get_reuse_addr (void) const; + + /// Set reuse_addr flag. + void set_reuse_addr (int); + + /// Get device. + const char* get_device (void) const; + + /// Get info. + Param_Info* get_info (void) const; + + /// Set info. + void set_info (Param_Info *); + + /// Get r/w flag. + int get_rw_flag (void) const; + + /// Set r/w flag. + void set_rw_flag (int); + + /// Get user data. + Param_Udata* get_user_data (void) const; + + /// Set user data. + void set_user_data (Param_Udata*); + + /// Get open flag. + int get_oflag (void) const; + + /// Set open flag. + void set_oflag (int); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Protocol family for sockets connections. + int protocol_family_; + + /// Protocol for sockets connections. + int protocol_; + + /// Type for opening sockets. + int type_; + + /// Information about the protocol. + ACE_Protocol_Info *protocol_info_; + + /// Socket group used (for sockets only). + ACE_SOCK_GROUP group_; + + /// Flags for sockets (for sockets only). + u_long flags_; + + /// Flag for reusing address for opening sockets. + int reuse_addr_; + + /// Device name for XTI/ATM connections. + const char *device_; + + /// Info for XTI/ATM connections. + Param_Info *info_; + + /// R/W flag for XTI/ATM connections. + int rw_flag_; + + /// User data for XTI/ATM connections. + Param_Udata *udata_; + + /// Open flag for XTI/ATM connections. + int oflag_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ATM_Params.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_PARAMS_H */ diff --git a/dep/acelite/ace/ATM_Params.inl b/dep/acelite/ace/ATM_Params.inl new file mode 100644 index 000000000..59ec331b5 --- /dev/null +++ b/dep/acelite/ace/ATM_Params.inl @@ -0,0 +1,232 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_ATM_Params::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_Params::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_ATM_Params::ACE_ATM_Params (int rw_flag, + const char device[], + Param_Info *info, + Param_Udata *udata, + int oflag, + int protocol_family, + int protocol, + int type, + ACE_Protocol_Info *protocol_info, + ACE_SOCK_GROUP g, + u_long flags, + int reuse_addr) + : protocol_family_(protocol_family), + protocol_(protocol), + type_(type), + protocol_info_(protocol_info), + group_(g), + flags_(flags), + reuse_addr_(reuse_addr), + device_(device), + info_(info), + rw_flag_(rw_flag), + udata_(udata), + oflag_(oflag) +{ + ACE_TRACE ("ACE_ATM_Params::ACE_ATM_Params"); +} + +// Default dtor. +ACE_INLINE +ACE_ATM_Params::~ACE_ATM_Params (void) +{ + ACE_TRACE ("ACE_ATM_Params::~ACE_ATM_Params"); +} + +ACE_INLINE +int +ACE_ATM_Params::get_protocol_family (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_protocol_family"); + return protocol_family_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_protocol_family (int family) +{ + ACE_TRACE ("ACE_ATM_Params::set_protocol_family"); + protocol_family_ = family; +} + +ACE_INLINE +int +ACE_ATM_Params::get_protocol (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_protocol"); + return protocol_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_protocol (int protocol) +{ + ACE_TRACE ("ACE_ATM_Params::set_protocol"); + protocol_ = protocol; +} + +ACE_INLINE +int +ACE_ATM_Params::get_type (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_type"); + return type_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_type (int type) +{ + ACE_TRACE ("ACE_ATM_Params::set_type"); + type_ = type; +} + +ACE_INLINE +ACE_Protocol_Info* +ACE_ATM_Params::get_protocol_info( void ) +{ + ACE_TRACE ("ACE_ATM_Params::get_protocol_info"); + return protocol_info_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_protocol_info( ACE_Protocol_Info *protocol_info ) +{ + ACE_TRACE ("ACE_ATM_Params::set_protocol_info"); + protocol_info_ = protocol_info; +} + +ACE_INLINE +ACE_SOCK_GROUP +ACE_ATM_Params::get_sock_group( void ) +{ + ACE_TRACE ("ACE_ATM_Params::get_sock_group"); + return group_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_sock_group( ACE_SOCK_GROUP g ) +{ + ACE_TRACE ("ACE_ATM_Params::set_sock_group"); + group_ = g; +} + +ACE_INLINE +u_long +ACE_ATM_Params::get_flags( void ) +{ + ACE_TRACE ("ACE_ATM_Params::get_flags"); + return flags_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_flags( u_long flags) +{ + ACE_TRACE ("ACE_ATM_Params::set_flags"); + flags_ = flags; +} + +ACE_INLINE +int +ACE_ATM_Params::get_reuse_addr (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_reuse_addr"); + return reuse_addr_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_reuse_addr (int reuse_addr) +{ + ACE_TRACE ("ACE_ATM_Params::set_reuse_addr"); + reuse_addr_ = reuse_addr; +} + +ACE_INLINE +const char* +ACE_ATM_Params::get_device (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_device"); + return device_; +} + +ACE_INLINE +Param_Info* +ACE_ATM_Params::get_info (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_info"); + return info_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_info (Param_Info* info) +{ + ACE_TRACE ("ACE_ATM_Params::set_info"); + info_ = info; +} + +ACE_INLINE +int +ACE_ATM_Params::get_rw_flag (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_rw_flag"); + return rw_flag_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_rw_flag (int rw_flag) +{ + ACE_TRACE ("ACE_ATM_Params::set_rw_flag"); + rw_flag_ = rw_flag; +} + +ACE_INLINE +Param_Udata* +ACE_ATM_Params::get_user_data (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_user_data"); + return udata_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_user_data (Param_Udata *udata) +{ + ACE_TRACE ("ACE_ATM_Params::set_user_data"); + udata_ = udata; +} + +ACE_INLINE +int +ACE_ATM_Params::get_oflag (void) const +{ + ACE_TRACE ("ACE_ATM_Params::get_oflag"); + return oflag_; +} + +ACE_INLINE +void +ACE_ATM_Params::set_oflag (int oflag) +{ + ACE_TRACE ("ACE_ATM_Params::set_oflag"); + oflag_ = oflag; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_QoS.cpp b/dep/acelite/ace/ATM_QoS.cpp new file mode 100644 index 000000000..a6b097326 --- /dev/null +++ b/dep/acelite/ace/ATM_QoS.cpp @@ -0,0 +1,629 @@ +#include "ace/ATM_QoS.h" + + + +#if defined (ACE_HAS_ATM) + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_QoS.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) +#define BHLI_MAGIC "FORE_ATM" +// This is line rate in cells/s for an OC-3 MM interface. +const long ACE_ATM_QoS::LINE_RATE = 353207; +const int ACE_ATM_QoS::OPT_FLAGS_CPID = 0x1; +const int ACE_ATM_QoS::OPT_FLAGS_PMP = 0x2; +const int ACE_ATM_QoS::DEFAULT_SELECTOR = 0x99; +const int ACE_ATM_QoS::DEFAULT_PKT_SIZE = 8192; +#elif defined (ACE_HAS_LINUX_ATM) +//pbrandao:for Linux: +//pbrandao:for now stick with current definitions +//pbrandao:see if later need to change +const long ACE_ATM_QoS::LINE_RATE = 353207; +const int ACE_ATM_QoS::OPT_FLAGS_CPID = 0x1; +const int ACE_ATM_QoS::OPT_FLAGS_PMP = 0x2; +const int ACE_ATM_QoS::DEFAULT_SELECTOR = 0x99; +const int ACE_ATM_QoS::DEFAULT_PKT_SIZE = 8192; +#else +const long ACE_ATM_QoS::LINE_RATE = 0L; +const int ACE_ATM_QoS::OPT_FLAGS_CPID = 0; +const int ACE_ATM_QoS::OPT_FLAGS_PMP = 0; +const int ACE_ATM_QoS::DEFAULT_SELECTOR = 0x0; +const int ACE_ATM_QoS::DEFAULT_PKT_SIZE = 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ + +ACE_ALLOC_HOOK_DEFINE(ACE_ATM_QoS) + +ACE_ATM_QoS::ACE_ATM_QoS (int pktSize) +{ + ACE_TRACE ("ACE_ATM_QoS::ACE_ATM_QoS"); +#if defined (ACE_HAS_LINUX_ATM) + ACE_OS::memset(&qos_, 0, sizeof(qos_)); + qos_.aal = ATM_PROTOCOL_DEFAULT; + qos_.rxtp.traffic_class = ATM_ANYCLASS; + qos_.rxtp.max_sdu = pktSize; + qos_.txtp.traffic_class = ATM_ANYCLASS; + qos_.txtp.max_sdu = pktSize; +#else + ACE_UNUSED_ARG (pktSize); +#endif /* ACE_HAS_LINUX_ATM */ +} + +ACE_ATM_QoS::ACE_ATM_QoS(int rate, + int pktSize) +{ + ACE_TRACE( "ACE_ATM_QoS::ACE_ATM_QoS" ); +#if defined (ACE_HAS_FORE_ATM_WS2) + AAL_PARAMETERS_IE ie_aalparams; + ATM_TRAFFIC_DESCRIPTOR_IE ie_td; + ATM_BROADBAND_BEARER_CAPABILITY_IE ie_bbc; + ATM_QOS_CLASS_IE ie_qos; + Q2931_IE *ie_ptr; + int size; + + // Setting up cbr parameters ... + ie_aalparams.AALType = AALTYPE_5; + ie_aalparams.AALSpecificParameters.AAL5Parameters.ForwardMaxCPCSSDUSize + = pktSize; // was 1516; + ie_aalparams.AALSpecificParameters.AAL5Parameters.BackwardMaxCPCSSDUSize + = pktSize; // was 1516; + ie_aalparams.AALSpecificParameters.AAL5Parameters.Mode = AAL5_MODE_MESSAGE; + ie_aalparams.AALSpecificParameters.AAL5Parameters.SSCSType = AAL5_SSCS_NULL; + + size = sizeof(Q2931_IE_TYPE) + sizeof(ULONG) + sizeof(AAL_PARAMETERS_IE); + + ie_td.Forward.PeakCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.PeakCellRate_CLP01 = rate; + ie_td.Forward.SustainableCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.SustainableCellRate_CLP01 = SAP_FIELD_ABSENT; + ie_td.Forward.MaxBurstSize_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.MaxBurstSize_CLP01 = SAP_FIELD_ABSENT; + ie_td.Forward.Tagging = SAP_FIELD_ABSENT; + + ie_td.Backward.PeakCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.PeakCellRate_CLP01 = rate; + ie_td.Backward.SustainableCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.SustainableCellRate_CLP01 = SAP_FIELD_ABSENT; + ie_td.Backward.MaxBurstSize_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.MaxBurstSize_CLP01 = SAP_FIELD_ABSENT; + ie_td.Backward.Tagging = SAP_FIELD_ABSENT; + + ie_td.BestEffort = 0; // Note: this must be set to zero for CBR. + + size += sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_TRAFFIC_DESCRIPTOR_IE ); + + ie_bbc.BearerClass = BCOB_X; + ie_bbc.TrafficType = TT_CBR; + ie_bbc.TimingRequirements = TR_END_TO_END; + ie_bbc.ClippingSusceptability = CLIP_NOT; + ie_bbc.UserPlaneConnectionConfig = UP_P2P; + + size += sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_BROADBAND_BEARER_CAPABILITY_IE ); + + ie_qos.QOSClassForward = QOS_CLASS1; + ie_qos.QOSClassBackward = QOS_CLASS1; // This may not be really used + // since we do only simplex data xfer. + + size += sizeof(Q2931_IE_TYPE) + sizeof(ULONG) + sizeof(ATM_QOS_CLASS_IE); + + qos_.ProviderSpecific.buf = (char *) ACE_OS::malloc(size); + if (qos_.ProviderSpecific.buf == 0) { + ACELIB_ERROR((LM_ERROR, + ACE_TEXT ("ACE_ATM_QoS::ACE_ATM_QoS: Unable to allocate %d bytes for qos_.ProviderSpecific.buf\n"), + size)); + return; + } + qos_.ProviderSpecific.len = size; + ACE_OS::memset(qos_.ProviderSpecific.buf, 0, size); + + ie_ptr = (Q2931_IE *) qos_.ProviderSpecific.buf; + ie_ptr->IEType = IE_AALParameters; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( AAL_PARAMETERS_IE ); + ACE_OS::memcpy(ie_ptr->IE, &ie_aalparams, sizeof(AAL_PARAMETERS_IE)); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_TrafficDescriptor; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_TRAFFIC_DESCRIPTOR_IE ); + ACE_OS::memcpy(ie_ptr->IE, &ie_td, sizeof(ATM_TRAFFIC_DESCRIPTOR_IE)); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_BroadbandBearerCapability; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_BROADBAND_BEARER_CAPABILITY_IE ); + ACE_OS::memcpy(ie_ptr->IE, + &ie_bbc, + sizeof(ATM_BROADBAND_BEARER_CAPABILITY_IE)); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_QOSClass; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_QOS_CLASS_IE ); + ACE_OS::memcpy(ie_ptr->IE, &ie_qos, sizeof(ATM_QOS_CLASS_IE)); + + // qos_.SendingFlowspec.TokenRate = 0xffffffff; + // qos_.SendingFlowspec.TokenBucketSize = 0xffffffff; + // qos_.SendingFlowspec.PeakBandwidth = 0xffffffff; + // qos_.SendingFlowspec.Latency = 0xffffffff; + // qos_.SendingFlowspec.DelayVariation = 0xffffffff; + // qos_.SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; + // This will most probably be ignored by the service provider. + // qos_.SendingFlowspec.MaxSduSize = 0xffffffff; + // qos_.SendingFlowspec.MinimumPolicedSize = 0xffffffff; + + // qos_.ReceivingFlowspec.TokenRate = 0xffffffff; + // qos_.ReceivingFlowspec.TokenBucketSize = 0xffffffff; + // qos_.ReceivingFlowspec.PeakBandwidth = 0xffffffff; + // qos_.ReceivingFlowspec.Latency = 0xffffffff; + // qos_.ReceivingFlowspec.DelayVariation = 0xffffffff; + // qos_.ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; + // This will most probably be ignored by the service provider. + // qos_.ReceivingFlowspec.MaxSduSize = 0xffffffff; + // qos_.ReceivingFlowspec.MinimumPolicedSize = 0; + + ACE_Flow_Spec send_fspec( 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + SERVICETYPE_BESTEFFORT, + // This will most probably ignored by SP. + 0xffffffff, + 0xffffffff, + 15, + ACE_DEFAULT_THREAD_PRIORITY ), + recv_fspec( 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + SERVICETYPE_BESTEFFORT, + // This will most probably ignored by SP. + 0xffffffff, + 0, + 15, + ACE_DEFAULT_THREAD_PRIORITY ); + + qos_.sending_flowspec (send_fspec); + qos_.receiving_flowspec (recv_fspec); +#elif defined (ACE_HAS_FORE_ATM_XTI) + ACE_UNUSED_ARG (rate); + ACE_UNUSED_ARG (pktSize); +#elif defined (ACE_HAS_LINUX_ATM) + ACE_OS::memset(&qos_, + 0, + sizeof(qos_)); + qos_.aal = ATM_PROTOCOL_DEFAULT; + qos_.rxtp.max_sdu = pktSize; + + if (rate > 0) { + qos_.rxtp.pcr = rate; + qos_.rxtp.traffic_class = ATM_CBR; + qos_.txtp.traffic_class = ATM_CBR; + qos_.txtp.pcr = rate; + } + else { + qos_.rxtp.traffic_class = ATM_UBR; + qos_.txtp.traffic_class = ATM_UBR; + } + + qos_.txtp.max_sdu = pktSize; +#else + ACE_UNUSED_ARG (rate); +#endif /* ACE_HAS_FORE_ATM_WS2 || ACE_HAS_FORE_ATM_XTI || ACE_HAS_LINUX_ATM */ +} + +void +ACE_ATM_QoS::set_cbr_rate (int rate, + int pktSize) +{ + ACE_TRACE ("ACE_ATM_QoS::set_cbr_rate"); +#if defined (ACE_HAS_FORE_ATM_WS2) + /* + AAL_PARAMETERS_IE ie_aalparams; + ATM_TRAFFIC_DESCRIPTOR_IE ie_td; + ATM_BROADBAND_BEARER_CAPABILITY_IE ie_bbc; + ATM_QOS_CLASS_IE ie_qos; + Q2931_IE *ie_ptr; + int size; + */ + + ACE_OS::printf( "ATM_QoS(set_cbr_rate): set rate to %d c/s\n", rate ); + + // Setting up cbr parameters ... + /* + FORE has changed this - we no longer specify QoS this way + ie_aalparams.AALType = AALTYPE_5; + ie_aalparams.AALSpecificParameters.AAL5Parameters.ForwardMaxCPCSSDUSize + = pktSize; // was 1516; + ie_aalparams.AALSpecificParameters.AAL5Parameters.BackwardMaxCPCSSDUSize + = pktSize; // was 1516; + ie_aalparams.AALSpecificParameters.AAL5Parameters.Mode = AAL5_MODE_MESSAGE; + ie_aalparams.AALSpecificParameters.AAL5Parameters.SSCSType = AAL5_SSCS_NULL; + + size = sizeof(Q2931_IE_TYPE) + sizeof(ULONG) + sizeof(AAL_PARAMETERS_IE); + + ie_td.Forward.PeakCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.PeakCellRate_CLP01 = rate; + ie_td.Forward.SustainableCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.SustainableCellRate_CLP01 = SAP_FIELD_ABSENT; + ie_td.Forward.MaxBurstSize_CLP0 = SAP_FIELD_ABSENT; + ie_td.Forward.MaxBurstSize_CLP01 = SAP_FIELD_ABSENT; + ie_td.Forward.Tagging = SAP_FIELD_ABSENT; + + ie_td.Backward.PeakCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.PeakCellRate_CLP01 = rate; + ie_td.Backward.SustainableCellRate_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.SustainableCellRate_CLP01 = SAP_FIELD_ABSENT; + ie_td.Backward.MaxBurstSize_CLP0 = SAP_FIELD_ABSENT; + ie_td.Backward.MaxBurstSize_CLP01 = SAP_FIELD_ABSENT; + ie_td.Backward.Tagging = SAP_FIELD_ABSENT; + + ie_td.BestEffort = 0; // Note: this must be set to zero for CBR. + + size += sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_TRAFFIC_DESCRIPTOR_IE ); + + ie_bbc.BearerClass = BCOB_X; + ie_bbc.TrafficType = TT_CBR; + ie_bbc.TimingRequirements = TR_END_TO_END; + ie_bbc.ClippingSusceptability = CLIP_NOT; + ie_bbc.UserPlaneConnectionConfig = UP_P2P; + + size += sizeof(Q2931_IE_TYPE) + + sizeof(ULONG) + + sizeof(ATM_BROADBAND_BEARER_CAPABILITY_IE); + + ie_qos.QOSClassForward = QOS_CLASS1; + ie_qos.QOSClassBackward = QOS_CLASS1; // This may not be really used + // since we only simplex data xfer. + + size += sizeof(Q2931_IE_TYPE) + sizeof(ULONG) + sizeof(ATM_QOS_CLASS_IE); + + qos_.ProviderSpecific.buf = (char *) ACE_OS::malloc(size); + if (qos_.ProviderSpecific.buf == 0) { + ACELIB_ERROR((LM_ERROR, + ACE_TEXT ("ACE_ATM_QoS::ACE_ATM_QoS: Unable to allocate %d bytes for qos_.ProviderSpecific.buf\n"), + size)); + return; + } + qos_.ProviderSpecific.len = size; + ACE_OS::memset(qos_.ProviderSpecific.buf, 0, size); + + ie_ptr = (Q2931_IE *) qos_.ProviderSpecific.buf; + ie_ptr->IEType = IE_AALParameters; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( AAL_PARAMETERS_IE ); + ACE_OS::memcpy(ie_ptr->IE, &ie_aalparams, sizeof(AAL_PARAMETERS_IE)); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_TrafficDescriptor; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_TRAFFIC_DESCRIPTOR_IE ); + ACE_OS::memcpy(ie_ptr->IE, &ie_td, sizeof(ATM_TRAFFIC_DESCRIPTOR_IE)); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_BroadbandBearerCapability; + ie_ptr->IELength = sizeof( Q2931_IE_TYPE ) + + sizeof( ULONG ) + + sizeof( ATM_BROADBAND_BEARER_CAPABILITY_IE ); + ACE_OS::memcpy( ie_ptr->IE, + &ie_bbc, + sizeof( ATM_BROADBAND_BEARER_CAPABILITY_IE )); + + ie_ptr = (Q2931_IE *) ((char *)ie_ptr + ie_ptr->IELength); + ie_ptr->IEType = IE_QOSClass; + ie_ptr->IELength = sizeof(Q2931_IE_TYPE) + sizeof(ULONG) + + sizeof(ATM_QOS_CLASS_IE); + ACE_OS::memcpy(ie_ptr->IE, &ie_qos, sizeof(ATM_QOS_CLASS_IE)); + */ + + const int BYTES_PER_ATM_CELL = 53; + ACE_OS::memset(&qos_, 0, sizeof(ATM_QoS)); + // Setting the token rate sets the minimum rate. 3 Mbits/sec seems too high. + // Certainly for Vaudeville audio, we only need about 1000 c/s which is + // 424000 bits/sec which is 53000 bytes/sec. + //qos_.SendingFlowspec.TokenRate = 3*(1024*128); // 3Mbits/sec + qos_.SendingFlowspec.TokenRate = 53000; // 1000 cells/sec + qos_.SendingFlowspec.TokenBucketSize = 32*1024; // our block size + //ourQos.SendingFlowspec.PeakBandwidth = ourQos.SendingFlowspec.TokenRate; + qos_.SendingFlowspec.ServiceType = SERVICETYPE_GUARANTEED; + // Peak bandwidth is in bytes/sec. The rate is specified in cells/sec so + // we need to convert from cells/sec to bytes/sec (i.e., multiply by 53). + qos_.SendingFlowspec.PeakBandwidth = rate * BYTES_PER_ATM_CELL; + qos_.SendingFlowspec.Latency = -1; // we don't care too much + qos_.SendingFlowspec.DelayVariation = -1; // we don't care too much + // no provider-specific data allowed on ATM + qos_.ProviderSpecific.buf=0; + qos_.ProviderSpecific.len=0; + // unidirectional P2MP; we don't need to setup the Receiving flowspec + + //qos_.SendingFlowspec.TokenRate = 0xffffffff; + //qos_.SendingFlowspec.TokenBucketSize = 0xffffffff; + //qos_.SendingFlowspec.PeakBandwidth = 0xffffffff; + //qos_.SendingFlowspec.Latency = 0xffffffff; + //qos_.SendingFlowspec.DelayVariation = 0xffffffff; + //qos_.SendingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; + // This will most probably be ignored by the service provider. + //qos_.SendingFlowspec.MaxSduSize = 0xffffffff; + //qos_.SendingFlowspec.MinimumPolicedSize = 0xffffffff; + + //qos_.ReceivingFlowspec.TokenRate = 0xffffffff; + //qos_.ReceivingFlowspec.TokenBucketSize = 0xffffffff; + //qos_.ReceivingFlowspec.PeakBandwidth = 0xffffffff; + //qos_.ReceivingFlowspec.Latency = 0xffffffff; + //qos_.ReceivingFlowspec.DelayVariation = 0xffffffff; + //qos_.ReceivingFlowspec.ServiceType = SERVICETYPE_BESTEFFORT; + // This will most probably be ignored by the service provider. + //qos_.ReceivingFlowspec.MaxSduSize = 0xffffffff; + //qos_.ReceivingFlowspec.MinimumPolicedSize = 0; + + /* + ACE_Flow_Spec send_fspec( 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + SERVICETYPE_BESTEFFORT, + // This will most probably ignored by SP. + 0xffffffff, + 0xffffffff, + 15, + ACE_DEFAULT_THREAD_PRIORITY ), + recv_fspec( 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + 0xffffffff, + SERVICETYPE_BESTEFFORT, + // This will most probably ignored by SP. + 0xffffffff, + 0, + 15, + ACE_DEFAULT_THREAD_PRIORITY ); + + qos_.sending_flowspec( send_fspec ); + qos_.receiving_flowspec( recv_fspec ); + */ +#elif defined (ACE_HAS_FORE_ATM_XTI) + ACE_UNUSED_ARG (rate); + ACE_UNUSED_ARG (pktSize); +#elif defined (ACE_HAS_LINUX_ATM) + ACE_UNUSED_ARG (pktSize); + + qos_.rxtp.traffic_class = ATM_CBR; + qos_.rxtp.pcr = rate; + qos_.txtp.traffic_class = ATM_CBR; + qos_.txtp.pcr = rate; +#else + ACE_UNUSED_ARG (rate); +#endif /* ACE_HAS_FORE_ATM_WS2 || ACE_HAS_FORE_ATM_XTI || ACE_HAS_LINUX_ATM */ +} + +void +ACE_ATM_QoS::set_rate (ACE_HANDLE fd, + int rate, + int flags) +{ + ACE_TRACE ("ACE_ATM_QoS::set_rate"); +#if defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) + set_cbr_rate( rate ); + + ACE_UNUSED_ARG( fd ); + ACE_UNUSED_ARG( flags ); +#elif defined (ACE_HAS_FORE_ATM_XTI) + long optlen = 0; + qos_.buf = construct_options(fd, + rate, + flags, + &optlen); + qos_.len = optlen; +#else + ACE_UNUSED_ARG (rate); +#endif /* ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM || ACE_HAS_FORE_ATM_XTI */ +} + +char* +ACE_ATM_QoS::construct_options (ACE_HANDLE fd, + int rate, + int flags, + long *len) +{ +#if defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) + ACE_UNUSED_ARG (fd); + ACE_UNUSED_ARG (rate); + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (len); + return 0; +#elif defined (ACE_HAS_FORE_ATM_XTI) + struct t_opthdr *popt; + char *buf; + int qos_cells; + struct t_info info; + + if (ACE_OS::t_getinfo (fd, &info) == -1) + { + ACE_OS::t_error ("t_getinfo"); + return 0; + } + + buf = (char *) ACE_OS::malloc (info.options); + + if (buf == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Unable to allocate %d bytes for options\n"), + info.options), + 0); + + popt = (struct t_opthdr *) buf; + + if (flags & OPT_FLAGS_CPID) + { + // This constructs the T_ATM_ORIG_ADDR option, which is used to + // signal the UNI 3.1 Calling Party ID Information Element. + t_atm_addr *source_addr; + + popt->len = sizeof (struct t_opthdr) + sizeof (t_atm_addr); + popt->level = T_ATM_SIGNALING; + popt->name = T_ATM_ORIG_ADDR; + popt->status = 0; + + source_addr = + (t_atm_addr *)((char *) popt + sizeof (struct t_opthdr)); + + source_addr->address_format = T_ATM_ENDSYS_ADDR; + source_addr->address_length = ATMNSAP_ADDR_LEN; + + ATMSAPAddress local_addr; + struct t_bind boundaddr; + + boundaddr.addr.maxlen = sizeof(local_addr); + boundaddr.addr.buf = (char *) &local_addr; + + //if (ACE_OS::t_getprotaddr(fd, &boundaddr, 0) < 0) { + if (ACE_OS::t_getname(fd, + &boundaddr.addr, + LOCALNAME) < 0) + { + ACE_OS::t_error("t_getname (local_address)"); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("Can't get local address!\n"))); + ACE_OS::free (buf); + return 0; + } + + ACE_OS::memcpy(source_addr->address, + local_addr.sap.t_atm_sap_addr.address, + ATMNSAP_ADDR_LEN); + + popt = T_OPT_NEXTHDR (buf, info.options , popt); + } + + // This constructs all options necessary (bearer cap., QoS, and + // Traffic Descriptor) to signal for a CBR connection with the + // specified QoS in kbit/sec., and/or specify a PMP connection. + + // For FORE 200e cards, the adapter shapes traffic to CBR with rate + // equal to PCR CLP=0+1 (traffic.forward.PCR_all_traffic) + + qos_cells = (rate * 1000) / (48*8); + + if ((qos_cells > 0 && qos_cells < LINE_RATE) + || (ACE_BIT_ENABLED (flags, OPT_FLAGS_PMP))) + { + struct t_atm_bearer *bearer; + struct t_atm_traffic *traffic; + + // T_ATM_BEARER_CAP: Broadband bearer capability + popt->len = sizeof (struct t_opthdr) + sizeof (struct t_atm_bearer); + popt->level = T_ATM_SIGNALING; + popt->name = T_ATM_BEARER_CAP; + popt->status = 0; + + bearer = (struct t_atm_bearer *)((char *) popt + + sizeof (struct t_opthdr)); + bearer->bearer_class = T_ATM_CLASS_X; + + if (qos_cells) + { + bearer->traffic_type = T_ATM_CBR; + bearer->timing_requirements = T_ATM_END_TO_END; + } + else + { + bearer->traffic_type = 0; // UBR + bearer->timing_requirements = 0; + } + bearer->clipping_susceptibility = T_ATM_NULL; + + if (ACE_BIT_ENABLED (flags, OPT_FLAGS_PMP)) + bearer->connection_configuration = T_ATM_1_TO_MANY; + else + bearer->connection_configuration = T_ATM_1_TO_1; + + popt = T_OPT_NEXTHDR (buf, info.options, popt); + + // T_ATM_TRAFFIC: traffic descriptor + popt->len = sizeof (struct t_opthdr) + sizeof (struct t_atm_traffic); + popt->level = T_ATM_SIGNALING; + popt->name = T_ATM_TRAFFIC; + popt->status = 0; + + traffic = (struct t_atm_traffic *)((char *) popt + + sizeof (struct t_opthdr)); + + traffic->forward.PCR_high_priority = T_ATM_ABSENT; + traffic->forward.PCR_all_traffic = qos_cells ? qos_cells : LINE_RATE; + traffic->forward.SCR_high_priority = T_ATM_ABSENT; + traffic->forward.SCR_all_traffic = T_ATM_ABSENT; + traffic->forward.MBS_high_priority = T_ATM_ABSENT; + traffic->forward.MBS_all_traffic = T_ATM_ABSENT; + traffic->forward.tagging = T_NO; + + traffic->backward.PCR_high_priority = T_ATM_ABSENT; + traffic->backward.PCR_all_traffic = + (ACE_BIT_ENABLED (flags, OPT_FLAGS_PMP)) + ? 0 : qos_cells ? qos_cells : LINE_RATE; + traffic->backward.SCR_high_priority = T_ATM_ABSENT; + traffic->backward.SCR_all_traffic = T_ATM_ABSENT; + traffic->backward.MBS_high_priority = T_ATM_ABSENT; + traffic->backward.MBS_all_traffic = T_ATM_ABSENT; + traffic->backward.tagging = T_NO; + + traffic->best_effort = qos_cells ? T_NO : T_YES; + + popt = T_OPT_NEXTHDR (buf, + info.options, + popt); + } + + if (qos_cells > 0 && qos_cells < LINE_RATE) + { + struct t_atm_qos *qos; + + // T_ATM_QOS: Quality of Service + popt->len = sizeof (struct t_opthdr) + sizeof (struct t_atm_qos); + popt->level = T_ATM_SIGNALING; + popt->name = T_ATM_QOS; + popt->status = 0; + + qos = (struct t_atm_qos *)((char *) popt + sizeof (struct t_opthdr)); + qos->coding_standard = T_ATM_ITU_CODING; + qos->forward.qos_class = T_ATM_QOS_CLASS_1; + qos->backward.qos_class = T_ATM_QOS_CLASS_1; + + popt = T_OPT_NEXTHDR (buf, info.options, popt); + } + + // Return actual size of options and option buffer to user. + *len = (char *) popt - buf; + + return buf; +#else + ACE_UNUSED_ARG (fd); + ACE_UNUSED_ARG (rate); + ACE_UNUSED_ARG (flag); + ACE_UNUSED_ARG (len); + return 0; +#endif /* ACE_HAS_FORE_ATM_WS2 */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_ATM */ + diff --git a/dep/acelite/ace/ATM_QoS.h b/dep/acelite/ace/ATM_QoS.h new file mode 100644 index 000000000..02aa7d7c9 --- /dev/null +++ b/dep/acelite/ace/ATM_QoS.h @@ -0,0 +1,113 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file ATM_QoS.h + * + * @author Joe Hoffert + */ +//========================================================================== + + +#ifndef ACE_ATM_QoS_H +#define ACE_ATM_QoS_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined(ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#if defined (ACE_HAS_FORE_ATM_WS2) +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +// just map to WS2 GQOS struct +typedef ACE_QoS ATM_QoS; +ACE_END_VERSIONED_NAMESPACE_DECL +#elif defined (ACE_HAS_FORE_ATM_XTI) +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef struct netbuf ATM_QoS; +ACE_END_VERSIONED_NAMESPACE_DECL +#elif defined (ACE_HAS_LINUX_ATM) +#include /**/ "atm.h" +#include "ace/ATM_Params.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef struct atm_qos ATM_QoS; +ACE_END_VERSIONED_NAMESPACE_DECL +#else +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef int ATM_QoS; +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* ACE_HAS_FORE_ATM_WS2 || ACE_HAS_FORE_ATM_XTI || ACE_HAS_LINUX_ATM */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_ATM_QoS + * + * @brief Define the QoS parameters for ATM + * + * This class wraps up QoS parameters for both ATM/XTI and + * ATM/WinSock2 to make the mechanism for the ATM protocol + * transparent. + */ +class ACE_Export ACE_ATM_QoS +{ +public: + // Constants used for ATM options + static const long LINE_RATE; + static const int OPT_FLAGS_CPID; + static const int OPT_FLAGS_PMP; + static const int DEFAULT_SELECTOR; + static const int DEFAULT_PKT_SIZE; + + // = Initializattion and termination methods. + /// Default constructor. + ACE_ATM_QoS(int = DEFAULT_PKT_SIZE); + + /// Constructor with a CBR rate. + ACE_ATM_QoS(int, + int = DEFAULT_PKT_SIZE); + + ~ACE_ATM_QoS (); + + /// Set the rate. + void set_rate (ACE_HANDLE, + int, + int); + + /// Set CBR rate in cells per second. + void set_cbr_rate (int, + int = DEFAULT_PKT_SIZE); + + /// Get ATM_QoS struct. + ATM_QoS get_qos (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Construct QoS options. + char* construct_options(ACE_HANDLE, + int, + int, + long*); + +private: + ATM_QoS qos_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ATM_QoS.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_QoS_H */ diff --git a/dep/acelite/ace/ATM_QoS.inl b/dep/acelite/ace/ATM_QoS.inl new file mode 100644 index 000000000..479079e99 --- /dev/null +++ b/dep/acelite/ace/ATM_QoS.inl @@ -0,0 +1,26 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_ATM_QoS::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_QoS::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_ATM_QoS::~ACE_ATM_QoS () +{ + ACE_TRACE ("ACE_ATM_QoS::~ACE_ATM_QoS"); +} + +ACE_INLINE +ATM_QoS +ACE_ATM_QoS::get_qos (void) +{ + ACE_TRACE ("ACE_ATM_QoS::get_qos"); + return qos_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/ATM_Stream.cpp b/dep/acelite/ace/ATM_Stream.cpp new file mode 100644 index 000000000..f87ac4def --- /dev/null +++ b/dep/acelite/ace/ATM_Stream.cpp @@ -0,0 +1,288 @@ +#include "ace/ATM_Stream.h" + +#if defined (ACE_HAS_ATM) + +#include "ace/OS_NS_string.h" + +#if !defined (__ACE_INLINE__) +#include "ace/ATM_Stream.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE (ACE_ATM_Stream) + +char* +ACE_ATM_Stream::get_peer_name (void) const +{ + ACE_TRACE ("ACE_ATM_Stream::get_peer_name"); +#if defined (ACE_HAS_FORE_ATM_XTI) + // // Use t_getprotaddr for XTI/ATM + // struct t_bind *localaddr + // = (struct t_bind *) ACE_OS::t_alloc (get_handle (), + // T_BIND, + // T_ADDR); + // struct t_bind *peeraddr + // = (struct t_bind *) ACE_OS::t_alloc (get_handle (), + // T_BIND, + // T_ADDR); + // ::t_getprotaddr (get_handle (), + // localaddr, + // peeraddr); + + // char* connected_name = (char*) ACE_OS::malloc (peeraddr->addr.len + 1); + // ACE_OS::strcpy (connected_name, + // peeraddr->addr.buf); + // ACE_OS::t_free ((char *) localaddr, + // T_BIND); + // ACE_OS::t_free ((char *) peeraddr, + // T_BIND); + // return (connected_name); + +#error "This doesn't seem to work. May need to jimmy-rig something with the" +#error "/etc/xti_hosts file - Ugh!" + + ACE_ATM_Addr sa; + struct netbuf name; + name.maxlen = sa.get_size (); + name.buf = (char *) sa.get_addr (); + ACE_OS::t_getname (this->get_handle (), &name, REMOTENAME); + // ACE_OS::ioctl (this->get_handle (), + // TI_GETPEERNAME, + // &name); + return (name.buf); + +#elif defined (ACE_HAS_FORE_ATM_WS2) + // Use getpeername for WinSock2. + struct sockaddr_atm name; + ACE_OS::memset (&name, 0, sizeof (name)); + int nameSize = sizeof (name); + + if (ACE_OS::getpeername (this->get_handle (), + (struct sockaddr *) &name, + &nameSize) != 0) { + return 0; + } + + char buffer[256]; + for (unsigned int index = 0; index < ATM_ADDR_SIZE - 1; index++) { + buffer[ index * 3 ] = '\0'; + ACE_OS::sprintf (buffer, "%s%02x.", buffer, name.satm_number.Addr[ index ]); + } + buffer[ (ATM_ADDR_SIZE - 1) * 3 ] = '\0'; + ACE_OS::sprintf (buffer, "%s%02x.", buffer, 0); + buffer[ ATM_ADDR_SIZE * 3 - 1 ] = '\0'; + for (index = 0; index < ACE_OS::strlen (buffer); ++index) + buffer[index] = ACE_OS::ace_tolower (buffer[index]); + + ifstream atm_hosts ("C:/WINNT/atmhosts"); + assert (atm_hosts.is_open ()); + + // Find the host address in the ATM hosts file and return the + // host name + char line[256]; + char *host_ptr, *host_name = 0; + ACE_NEW_RETURN (host_name, char[256], 0); + while (!atm_hosts.eof ()) { + atm_hosts.getline (line, 256); + // Convert the line to lower case to ease comparison + for (index = 0; index < ACE_OS::strlen (line); ++index) + line[index] = ACE_OS::ace_tolower (line[index]); + if (ACE_OS::strstr (line, buffer) != 0) + { + char *strtok_p; + // Grab the second token which is the host name + ACE_OS::strtok_r (line, " \t", &strtok_p); + host_ptr = ACE_OS::strtok (0, " \t", &strtok_p); + ACE_OS::strcpy (host_name, host_ptr); + break; + } + } + + return host_name; +#elif defined (ACE_HAS_LINUX_ATM) + ATM_Addr name; + int nameSize = sizeof (name.sockaddratmsvc); + + if (ACE_OS::getpeername (this->get_handle (), + (struct sockaddr *) & (name.sockaddratmsvc), + &nameSize) < 0) { + ACE_OS::perror ("ACE_ATM_Stream (get_peer_name) : "); + return 0; + } + + static ACE_TCHAR buffer[MAX_ATM_ADDR_LEN + 1]; + int total_len; + if ((total_len = atm2text (buffer,sizeof buffer, + (struct sockaddr *) & (name.sockaddratmsvc), + A2T_PRETTY|A2T_NAME)) < 0) { + ACELIB_DEBUG ((LM_DEBUG,ACE_TEXT ("ACE_ATM_Stream (get_peer_name) :%d"),errno)); + return 0; + } + + return (char*) buffer; +#else + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +ACE_HANDLE +ACE_ATM_Stream::get_handle (void) const +{ + ACE_TRACE ("ACE_ATM_Stream::get_handle"); +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) || defined (ACE_HAS_LINUX_ATM) + return stream_.get_handle (); +#else + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +int +ACE_ATM_Stream::get_vpi_vci (ACE_UINT16 &vpi, + ACE_UINT16 &vci) const +{ + ACE_TRACE ("ACE_ATM_Stream::get_vpi_vci"); +#if defined (ACE_HAS_FORE_ATM_XTI) + struct t_atm_conn_prop conn_prop; + char* connect_opts = (char *) &conn_prop; + int opt_size = sizeof (t_atm_conn_prop); + struct t_info info; + struct t_optmgmt opt_req, opt_ret; + + if (ACE_OS::t_getinfo (stream_.get_handle (), + &info) < 0) + { + ACE_OS::t_error ("t_getinfo"); + return -1; + } + + char *buf_req = (char *) ACE_OS::malloc (info.options); + if (buf_req == 0) + { + ACE_OS::fprintf (stderr, + "Unable to allocate %ld bytes for options\n", + info.options); + return -1; + } + + char *buf_ret = (char *) ACE_OS::malloc (info.options); + if (buf_ret == 0) + { + ACE_OS::fprintf (stderr, + "Unable to allocate %ld bytes for options\n", + info.options); + return -1; + } + + ACE_OS::memset (&opt_req, 0, sizeof (opt_req)); + ACE_OS::memset (&opt_ret, 0, sizeof (opt_ret)); + + struct t_opthdr *popt = (struct t_opthdr *) buf_req; + struct t_opthdr *popt_ret = (struct t_opthdr *) buf_ret; + + popt->len= sizeof (struct t_opthdr) + opt_size; + + // We are only concerned with SVCs so no other check or values are needed + // here. + popt->level = T_ATM_SIGNALING; + popt->name = T_ATM_CONN_PROP; + popt->status = 0; + + opt_req.opt.len = popt->len; + opt_req.opt.buf = (char *) popt; + opt_req.flags = T_CURRENT; + + popt = T_OPT_NEXTHDR (buf_req, + info.options, + popt); + opt_ret.opt.maxlen = info.options; + opt_ret.opt.buf = (char *) popt_ret; + + if (ACE_OS::t_optmgmt (stream_.get_handle (), + &opt_req, + &opt_ret) < 0) { + ACE_OS::t_error ("t_optmgmt"); + return -1; + } + + ACE_OS::memcpy (connect_opts, + (char *) popt_ret + sizeof (struct t_opthdr), + opt_size); + + ACE_OS::free (buf_ret); + ACE_OS::free (buf_req); + + vpi = conn_prop.vpi; + vci = conn_prop.vci; + return 0; +#elif defined (ACE_HAS_FORE_ATM_WS2) + ATM_CONNECTION_ID connID; + DWORD bytes = 0; + + if (::WSAIoctl ((int) this -> get_handle (), + SIO_GET_ATM_CONNECTION_ID, + 0, + 0, + (LPVOID) &connID, + sizeof (ATM_CONNECTION_ID), + &bytes, + 0, + 0) + == SOCKET_ERROR) { + ACE_OS::printf ("Error: WSAIoctl %d\n", WSAGetLastError ()); + } + + vpi = (ACE_UINT16) connID.VPI; + vci = (ACE_UINT16) connID.VCI; + + return 0; +#elif defined (ACE_HAS_LINUX_ATM) +#if defined (SO_ATMPVC) /* atm version>=0.62 */ + struct sockaddr_atmpvc mypvcaddr; + int addrpvclen = sizeof (mypvcaddr); + if (ACE_OS::getsockopt (stream_.get_handle (), + SOL_ATM, + SO_ATMPVC, + reinterpret_cast (&mypvcaddr), + &addrpvclen) < 0) { + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("ACE_ATM_Stream::get_vpi_vci: getsockopt %d\n"), + errno); + return -1; + } + vpi = (ACE_UINT16) mypvcaddr.sap_addr.vpi; + vci = (ACE_UINT16) mypvcaddr.sap_addr.vci; + + return 0; +#elif defined (SO_VCID) /* patch for atm version 0.59 */ + struct atm_vcid mypvcid; + int pvcidlen = sizeof (mypvcid); + if (ACE_OS::getsockopt (stream_.get_handle (), + SOL_ATM,SO_VCID, + reinterpret_cast (&mypvcid), + &pvcidlen) < 0) { + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("ACE_ATM_Stream::get_vpi_vci: getsockopt %d\n"), + errno); + return -1; + } + vpi = (ACE_UINT16) mypvcid.vpi; + vci = (ACE_UINT16) mypvcid.vci; + + return 0; +#else + ACELIB_DEBUG (LM_DEBUG, + ACE_TEXT ("ACE_ATM_Stream::get_vpi_vci: Not implemented in this ATM version. Update to >= 0.62\n Or patch 0.59")); + ACE_UNUSED_ARG (vci); + ACE_UNUSED_ARG (vpi); + + return -1; +#endif /* SO_ATMPVC || SO_VCID */ +#else + return -1; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 || ACE_HAS_LINUX_ATM */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_ATM */ diff --git a/dep/acelite/ace/ATM_Stream.h b/dep/acelite/ace/ATM_Stream.h new file mode 100644 index 000000000..10bd3e700 --- /dev/null +++ b/dep/acelite/ace/ATM_Stream.h @@ -0,0 +1,105 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file ATM_Stream.h + * + * @author Joe Hoffert + */ +//============================================================================= + + +#ifndef ACE_ATM_STREAM_H +#define ACE_ATM_STREAM_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_ATM) + +#include "ace/ATM_Addr.h" +#include "ace/ATM_Params.h" + +#if defined (ACE_WIN32) +#include "ace/SOCK_Stream.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_SOCK_Stream ATM_Stream; +ACE_END_VERSIONED_NAMESPACE_DECL +#else +#include "ace/TLI_Stream.h" +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +typedef ACE_TLI_Stream ATM_Stream; +ACE_END_VERSIONED_NAMESPACE_DECL +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_ATM_Stream + * + * @brief Defines the member functions for ACE_ATM_Stream abstraction. + */ +class ACE_Export ACE_ATM_Stream +{ +public: + // = Initialization and termination methods. + /// Default constructor. + ACE_ATM_Stream (void); + + // = ATM-specific open and shutdown operations. + /// open the stream. + int open (ACE_ATM_Params params = ACE_ATM_Params()); + + /// Close down and release resources. + int close (void); + + /// Get the underlying handle. + ACE_HANDLE get_handle (void) const; + + /// Get the underlying stream. + ATM_Stream& get_stream (void); + + /// Get the name of the connected host. + char* get_peer_name (void) const; + + /// Get the VPI and VCI of the stream. + int get_vpi_vci (ACE_UINT16 &vpi, + ACE_UINT16 &vci) const; + + /// Recv an n byte buffer from the connected transport mechanism. + ssize_t recv (void *buf, + size_t n, + int *flags = 0) const; + + /// Send exactly n bytes to the connected transport mechanism. + ssize_t send_n (const void *buf, + size_t n, + int flags) const; + + // = Meta-type info + typedef ACE_ATM_Addr PEER_ADDR; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Typedef'd to the appropriate stream mechanism above. + ATM_Stream stream_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/ATM_Stream.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_ATM */ +#include /**/ "ace/post.h" +#endif /* ACE_ATM_STREAM_H */ diff --git a/dep/acelite/ace/ATM_Stream.inl b/dep/acelite/ace/ATM_Stream.inl new file mode 100644 index 000000000..eda7ca9bc --- /dev/null +++ b/dep/acelite/ace/ATM_Stream.inl @@ -0,0 +1,130 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_ATM_Stream::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_ATM_Stream::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_ATM_Stream::ACE_ATM_Stream (void) +{ + ACE_TRACE ("ACE_ATM_Stream::ACE_ATM_Stream"); +} + +ACE_INLINE +int +ACE_ATM_Stream::open (ACE_ATM_Params params) +{ + ACE_TRACE ("ACE_ATM_Stream::open"); +#if defined (ACE_HAS_FORE_ATM_XTI) + ACE_HANDLE handle = stream_.open (params.get_device(), + params.get_oflag(), + params.get_info()); + return (handle == ACE_INVALID_HANDLE ? -1 : 0); +#elif defined (ACE_HAS_FORE_ATM_WS2) + params.set_flags( ACE_FLAG_MULTIPOINT_C_ROOT | ACE_FLAG_MULTIPOINT_D_ROOT ); + + int retval = stream_.open (params.get_type(), + params.get_protocol_family(), + params.get_protocol(), + params.get_protocol_info(), + params.get_sock_group(), + params.get_flags(), + params.get_reuse_addr()); + if (retval == -1) + return -1; + + struct sockaddr_atm sock_addr; + + ACE_OS::memset(&sock_addr, 0, sizeof(struct sockaddr_atm)); + sock_addr.satm_family = AF_ATM; + sock_addr.satm_number.AddressType=ADDR_ANY; + sock_addr.satm_number.NumofDigits = ATM_ADDR_SIZE; + sock_addr.satm_blli.Layer2Protocol = SAP_FIELD_ABSENT; + sock_addr.satm_blli.Layer3Protocol = SAP_FIELD_ABSENT; + sock_addr.satm_bhli.HighLayerInfoType = SAP_FIELD_ABSENT; + if (ACE_OS::bind(get_handle(), + (struct sockaddr FAR *)&sock_addr, + sizeof(struct sockaddr_atm)) < 0) + { + ACE_OS::printf("Error binding local address: %d",WSAGetLastError()); + return -1; + } + + return 0; +#else + ACE_UNUSED_ARG(params); + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI */ +} + +ACE_INLINE +int +ACE_ATM_Stream::close (void) +{ + ACE_TRACE ("ACE_ATM_Stream::close"); +#if defined (ACE_HAS_FORE_ATM_XTI) || defined (ACE_HAS_FORE_ATM_WS2) + return stream_.close (); +#else + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI || ACE_HAS_FORE_ATM_WS2 */ +} + +ACE_INLINE +ATM_Stream& +ACE_ATM_Stream::get_stream (void) +{ + ACE_TRACE ("ACE_ATM_Stream::get_stream"); + return stream_; +} + +ACE_INLINE +ssize_t +ACE_ATM_Stream::recv (void *buf, + size_t n, + int *flags) const +{ + ACE_TRACE ("ACE_ATM_Stream::recv"); +#if defined (ACE_HAS_FORE_ATM_XTI) + return stream_.recv (buf, + n, + flags); +#elif defined (ACE_HAS_FORE_ATM_WS2) + return stream_.recv (buf, + n); +#else + ACE_UNUSED_ARG(buf); + ACE_UNUSED_ARG(n); + ACE_UNUSED_ARG(flags); + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI */ +} + +ACE_INLINE +ssize_t +ACE_ATM_Stream::send_n (const void *buf, + size_t n, + int flags) const +{ + ACE_TRACE ("ACE_ATM_Stream::send_n"); +#if defined (ACE_HAS_FORE_ATM_XTI) + return stream_.send_n (buf, + n, + flags); +#elif defined (ACE_HAS_FORE_ATM_WS2) + return stream_.send_n (buf, + n, + flags); +#else + ACE_UNUSED_ARG(buf); + ACE_UNUSED_ARG(n); + ACE_UNUSED_ARG(flags); + return 0; +#endif /* ACE_HAS_FORE_ATM_XTI */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Abstract_Timer_Queue.cpp b/dep/acelite/ace/Abstract_Timer_Queue.cpp new file mode 100644 index 000000000..021c637fe --- /dev/null +++ b/dep/acelite/ace/Abstract_Timer_Queue.cpp @@ -0,0 +1,24 @@ +#ifndef ACE_ABSTRACT_TIMER_QUEUE_CPP +#define ACE_ABSTRACT_TIMER_QUEUE_CPP +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Abstract_Timer_Queue.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Even though the destructor is pure virtual you must provide an +// implementation. Most people know this, but sometimes we all +// forget, and we might be tempted to remove this code. +template +ACE_Abstract_Timer_Queue:: +~ACE_Abstract_Timer_Queue () +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ABSTRACT_TIMER_QUEUE_CPP */ diff --git a/dep/acelite/ace/Abstract_Timer_Queue.h b/dep/acelite/ace/Abstract_Timer_Queue.h new file mode 100644 index 000000000..7dbbf7b4b --- /dev/null +++ b/dep/acelite/ace/Abstract_Timer_Queue.h @@ -0,0 +1,230 @@ +#ifndef ACE_ABSTRACT_TIMER_QUEUE_H +#define ACE_ABSTRACT_TIMER_QUEUE_H + +#include /**/ "ace/pre.h" +/** + * @file Abstract_Timer_Queue.h + * + * @author Carlos O'Ryan + * + * Based on classes and files developed by Doug Schmidt, Darrell + * Brunsch, Irfan Pyarali and a cast of thousands. + */ + +#include "ace/Versioned_Namespace.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declares +class ACE_Time_Value; +class ACE_Command_Base; +template class ACE_Timer_Queue_Iterator_T; +template class ACE_Timer_Node_T; + +/** + * @class ACE_Abstract_Timer_Queue + * + * @brief Base class for all timer queues of a single type. + * + * This is a base class for all the timer queues, regardless of + * locking strategy, upcall mechanism, internal implementation, etc. + * The class was motivated by bug 3706: + * http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=3706 + * In short, the Reactor (and potentially other classes) want to refer + * to timer queues regardless of the implementation internals. + */ +template +class ACE_Abstract_Timer_Queue +{ +public: + /// Destructor + virtual ~ACE_Abstract_Timer_Queue (void) = 0; + + /// True if queue is empty, else false. + virtual bool is_empty (void) const = 0; + + /// Returns the time of the earlier node in the Timer_Queue. Must + /// be called on a non-empty queue. + virtual const ACE_Time_Value &earliest_time (void) const = 0; + + /** + * Schedule @a type that will expire at @a future_time, which is + * specified in absolute time. If it expires then @a act is passed + * in as the value to the . If @a interval is != to + * ACE_Time_Value::zero then it is used to reschedule the @a type + * automatically, using relative time to the current . + * This method returns a that uniquely identifies the the + * @a type entry in an internal list. This can be used to + * cancel the timer before it expires. The cancellation ensures + * that are unique up to values of greater than 2 + * billion timers. As long as timers don't stay around longer than + * this there should be no problems with accidentally deleting the + * wrong timer. Returns -1 on failure (which is guaranteed never to + * be a valid ). + */ + virtual long schedule (const TYPE &type, + const void *act, + const ACE_Time_Value &future_time, + const ACE_Time_Value &interval = ACE_Time_Value::zero) = 0; + + /** + * Run the for all timers whose values are <= @a current_time. + * This does not account for . Returns the number of + * timers canceled. + */ + virtual int expire (const ACE_Time_Value ¤t_time) = 0; + + /** + * Run the for all timers whose values are <= + * . Also accounts for . + * + * Depending on the resolution of the underlying OS the system calls + * like select()/poll() might return at time different than that is + * specified in the timeout. Suppose the OS guarantees a resolution of t ms. + * The timeline will look like + * + * A B + * | | + * V V + * |-------------|-------------|-------------|-------------| + * t t t t t + * + * + * If you specify a timeout value of A, then the timeout will not occur + * at A but at the next interval of the timer, which is later than + * that is expected. Similarly, if your timeout value is equal to B, + * then the timeout will occur at interval after B. Now depending upon the + * resolution of your timeouts and the accuracy of the timeouts + * needed for your application, you should set the value of + * . In the above case, if you want the timeout A to fire + * no later than A, then you should specify your to be + * A % t. + * + * The timeout value should be specified via the macro ACE_TIMER_SKEW + * in your config.h file. The default value is zero. + * + * Things get interesting if the t before the timeout value B is zero + * i.e your timeout is less than the interval. In that case, you are + * almost sure of not getting the desired timeout behaviour. Maybe you + * should look for a better OS :-) + * + * Returns the number of timers canceled. + */ + virtual int expire (void) = 0; + + /** + * A couple of classes using Timer_Queues need to dispatch a single + * event at a time. But before they dispatch the event they need to + * release a lock, signal other threads, etc. + * + * This member function should be used in that case. The additional + * operations to be called just before dispatching the event, and + * only if an event will be dispatched, are encapsulated in the + * ACE_Command_Base object. + */ + virtual int expire_single(ACE_Command_Base & pre_dispatch_command) = 0; + + /** + * Resets the interval of the timer represented by @a timer_id to + * @a interval, which is specified in relative time to the current + * . If @a interval is equal to + * ACE_Time_Value::zero, the timer will become a non-rescheduling + * timer. Returns 0 if successful, -1 if not. + */ + virtual int reset_interval (long timer_id, + const ACE_Time_Value &interval) = 0; + + /** + * Cancel all timer associated with @a type. If + * @a dont_call_handle_close is 0 then the will be invoked, + * which typically invokes the hook. Returns number + * of timers cancelled. + */ + virtual int cancel (const TYPE &type, + int dont_call_handle_close = 1) = 0; + + /** + * Cancel the single timer that matches the @a timer_id value (which + * was returned from the method). If act is non-NULL + * then it will be set to point to the ``magic cookie'' argument + * passed in when the timer was registered. This makes it possible + * to free up the memory and avoid memory leaks. If + * @a dont_call_handle_close is 0 then the will be invoked, + * which typically calls the hook. Returns 1 if + * cancellation succeeded and 0 if the @a timer_id wasn't found. + */ + virtual int cancel (long timer_id, + const void **act = 0, + int dont_call_handle_close = 1) = 0; + + /** + * Close timer queue. Cancels all timers. + */ + virtual int close (void) = 0; + + /** + * Returns the current time of day. This method allows different + * implementations of the timer queue to use special high resolution + * timers. + */ + virtual ACE_Time_Value gettimeofday (void) = 0; + + /** + * Allows applications to control how the timer queue gets the time + * of day. + * @deprecated Use TIME_POLICY support instead. See Timer_Queue_T.h + */ + virtual void gettimeofday (ACE_Time_Value (*gettimeofday)(void)) = 0; + + /// Determine the next event to timeout. Returns @a max if there are + /// no pending timers or if all pending timers are longer than max. + /// This method acquires a lock internally since it modifies internal state. + virtual ACE_Time_Value *calculate_timeout (ACE_Time_Value *max) = 0; + + /** + * Determine the next event to timeout. Returns @a max if there are + * no pending timers or if all pending timers are longer than max. + * @a the_timeout should be a pointer to storage for the timeout value, + * and this value is also returned. This method does not acquire a + * lock internally since it doesn't modify internal state. If you + * need to call this method when the queue is being modified + * concurrently, however, you should make sure to acquire the + * externally before making the call. + */ + virtual ACE_Time_Value *calculate_timeout (ACE_Time_Value *max, + ACE_Time_Value *the_timeout) = 0; + + /** + * Return the current time, using the right time policy and any + * timer skew defined in derived classes. + */ + virtual ACE_Time_Value current_time() = 0; + + /// Type of Iterator. + typedef ACE_Timer_Queue_Iterator_T ITERATOR; + + /// Returns a pointer to this ACE_Timer_Queue's iterator. + virtual ITERATOR & iter (void) = 0; + + /// Removes the earliest node from the queue and returns it + virtual ACE_Timer_Node_T *remove_first (void) = 0; + + /// Reads the earliest node from the queue and returns it. + virtual ACE_Timer_Node_T *get_first (void) = 0; + + /// Dump the state of a object. + virtual void dump (void) const = 0; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Abstract_Timer_Queue.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Abstract_Timer_Queue.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_ABSTRACT_TIMER_QUEUE_H */ diff --git a/dep/acelite/ace/Acceptor.cpp b/dep/acelite/ace/Acceptor.cpp new file mode 100644 index 000000000..6b0f8fdc2 --- /dev/null +++ b/dep/acelite/ace/Acceptor.cpp @@ -0,0 +1,1254 @@ +#ifndef ACE_ACCEPTOR_CPP +#define ACE_ACCEPTOR_CPP + +#include "ace/ACE.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Acceptor.h" +#include "ace/Svc_Handler.h" +#include "ace/WFMO_Reactor.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tca(ACE_Acceptor) + +template void +ACE_Acceptor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Acceptor::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->peer_acceptor_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Acceptor::operator PEER_ACCEPTOR & () const +{ + ACE_TRACE ("ACE_Acceptor::operator PEER_ACCEPTOR &"); + return (PEER_ACCEPTOR &) this->peer_acceptor_; +} + +template PEER_ACCEPTOR & +ACE_Acceptor::acceptor (void) const +{ + ACE_TRACE ("ACE_Acceptor::acceptor"); + return const_cast (this->peer_acceptor_); +} + +// Returns ACE_HANDLE of the underlying Acceptor_Strategy. + +template ACE_HANDLE +ACE_Acceptor::get_handle (void) const +{ + ACE_TRACE ("ACE_Acceptor::get_handle"); + return this->peer_acceptor_.get_handle (); +} + +// Initialize the appropriate strategies for creation, passive +// connection acceptance, and concurrency, and then register +// with the Reactor and listen for connection requests at the +// designated . + +template int +ACE_Acceptor::open + (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor, + int flags, + int use_select, + int reuse_addr) +{ + ACE_TRACE ("ACE_Acceptor::open"); + this->flags_ = flags; + this->use_select_ = use_select; + this->reuse_addr_ = reuse_addr; + this->peer_acceptor_addr_ = local_addr; + + // Must supply a valid Reactor to Acceptor::open()... + + if (reactor == 0) + { + errno = EINVAL; + return -1; + } + + // Open the underlying PEER_ACCEPTOR. + if (this->peer_acceptor_.open (local_addr, reuse_addr) == -1) + return -1; + + // Set the peer acceptor's handle into non-blocking mode. This is a + // safe-guard against the race condition that can otherwise occur + // between the time when indicates that a passive-mode + // socket handle is "ready" and when we call . During this + // interval, the client can shutdown the connection, in which case, + // the call can hang! + if (this->accept_strategy_->acceptor ().enable (ACE_NONBLOCK) != 0) + return -1; + + // Initialize the concurrency strategy. + + if (con_s == 0) + { + ACE_NEW_RETURN (con_s, + CONCURRENCY_STRATEGY, + -1); + this->delete_concurrency_strategy_ = true; + } + this->concurrency_strategy_ = con_s; + + // Initialize the scheduling strategy. + + if (sch_s == 0) + { + ACE_NEW_RETURN (sch_s, + SCHEDULING_STRATEGY, + -1); + this->delete_scheduling_strategy_ = true; + } + this->scheduling_strategy_ = sch_s; + + this->use_select_ = use_select; + + return this->reactor ()->register_handler + (this, + ACE_Event_Handler::ACCEPT_MASK); +} + +// Simple constructor. + +template +ACE_Strategy_Acceptor::ACE_Strategy_Acceptor + (const ACE_TCHAR service_name[], + const ACE_TCHAR service_description[], + int use_select, + int reuse_addr) + : creation_strategy_ (0), + delete_creation_strategy_ (false), + accept_strategy_ (0), + delete_accept_strategy_ (false), + concurrency_strategy_ (0), + delete_concurrency_strategy_ (false), + scheduling_strategy_ (0), + delete_scheduling_strategy_ (false), + service_name_ (0), + service_description_ (0) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"); + + if (service_name != 0) + ACE_ALLOCATOR (this->service_name_, + ACE_OS::strdup (service_name)); + if (service_description != 0) + ACE_ALLOCATOR (this->service_description_, + ACE_OS::strdup (service_description)); + this->use_select_ = use_select; + this->reuse_addr_ = reuse_addr; +} + +template +ACE_Strategy_Acceptor::ACE_Strategy_Acceptor + (const typename PEER_ACCEPTOR::PEER_ADDR &addr, + ACE_Reactor *reactor, + ACE_Creation_Strategy *cre_s, + ACE_Accept_Strategy *acc_s, + ACE_Concurrency_Strategy *con_s, + ACE_Scheduling_Strategy *sch_s, + const ACE_TCHAR service_name[], + const ACE_TCHAR service_description[], + int use_select, + int reuse_addr) + : creation_strategy_ (0), + delete_creation_strategy_ (false), + accept_strategy_ (0), + delete_accept_strategy_ (false), + concurrency_strategy_ (0), + delete_concurrency_strategy_ (false), + scheduling_strategy_ (0), + delete_scheduling_strategy_ (false), + service_name_ (0), + service_description_ (0) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"); + + if (this->open (addr, + reactor, + cre_s, + acc_s, + con_s, + sch_s, + service_name, + service_description, + use_select, + reuse_addr) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Strategy_Acceptor::ACE_Strategy_Acceptor"))); +} + +// Perform termination activities when is removed from the +// . + +template int +ACE_Strategy_Acceptor::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::handle_close"); + // Guard against multiple closes. + if (this->reactor () != 0) + { + ACE_HANDLE handle = this->get_handle (); + + if (this->delete_creation_strategy_) + delete this->creation_strategy_; + this->delete_creation_strategy_ = false; + this->creation_strategy_ = 0; + + if (this->delete_accept_strategy_) + delete this->accept_strategy_; + this->delete_accept_strategy_ = false; + this->accept_strategy_ = 0; + + if (this->delete_concurrency_strategy_) + delete this->concurrency_strategy_; + this->delete_concurrency_strategy_ = false; + this->concurrency_strategy_ = 0; + + if (this->delete_scheduling_strategy_) + delete this->scheduling_strategy_; + this->delete_scheduling_strategy_ = false; + this->scheduling_strategy_ = 0; + + // We must use the obtained *before* we deleted the + // accept_strategy_... + + this->reactor ()->remove_handler + (handle, + ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); + + // Set the Reactor to 0 so that we don't try to close down + // again. + this->reactor (0); + } + return 0; +} + +// Bridge method for creating a . The strategy for +// creating a are configured into the Acceptor via it's +// . The default is to create a new +// . However, subclasses can override this strategy to +// perform creation in any way that they like (such as +// creating subclass instances of , using a singleton, +// dynamically linking the handler, etc.). + +template int +ACE_Strategy_Acceptor::make_svc_handler (SVC_HANDLER *&sh) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::make_svc_handler"); + return this->creation_strategy_->make_svc_handler (sh); +} + +// Bridge method for accepting the new connection into the +// . The default behavior delegates to the +// in the Acceptor_Strategy. + +template int +ACE_Strategy_Acceptor::accept_svc_handler + (SVC_HANDLER *svc_handler) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::accept_svc_handler"); + return this->accept_strategy_->accept_svc_handler (svc_handler); +} + +// Bridge method for activating a with the appropriate +// concurrency strategy. The default behavior of this method is to +// activate the SVC_HANDLER by calling its open() method (which allows +// the SVC_HANDLER to define its own concurrency strategy). However, +// subclasses can override this strategy to do more sophisticated +// concurrency activations (such as creating the SVC_HANDLER as an +// "active object" via multi-threading or multi-processing). + +template int +ACE_Strategy_Acceptor::activate_svc_handler + (SVC_HANDLER *svc_handler) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::activate_svc_handler"); + return this->concurrency_strategy_->activate_svc_handler + (svc_handler, + (void *) this); +} + +template +ACE_Strategy_Acceptor::~ACE_Strategy_Acceptor (void) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::~ACE_Strategy_Acceptor"); + ACE_OS::free ((void *) this->service_name_); + ACE_OS::free ((void *) this->service_description_); + this->handle_close (); +} + +// Signal the server to shutdown gracefully. + +template int +ACE_Strategy_Acceptor::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_Reactor::instance()->end_reactor_event_loop (); + return 0; +} + +template int +ACE_Strategy_Acceptor::info (ACE_TCHAR **strp, + size_t length) const +{ + ACE_TRACE ("ACE_Strategy_Acceptor::info"); + + ACE_TCHAR buf[BUFSIZ]; + ACE_TCHAR service_addr_str[BUFSIZ]; + typename PEER_ACCEPTOR::PEER_ADDR addr; + + if (this->acceptor ().get_local_addr (addr) == -1) + return -1; + else if (addr.addr_to_string (service_addr_str, + sizeof service_addr_str) == -1) + return -1; + + // @@ Should add the protocol in... + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%s\t %s #%s\n"), + this->service_name_ == 0 + ? ACE_TEXT ("") + : this->service_name_, + service_addr_str, + this->service_description_ == 0 + ? ACE_TEXT ("") + : this->service_description_); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strsncpy (*strp, buf, length); + return static_cast (ACE_OS::strlen (buf)); +} + +template int +ACE_Strategy_Acceptor::fini (void) +{ + ACE_TRACE ("ACE_Strategy_Acceptor::fini"); + return this->ACE_Strategy_Acceptor::handle_close (); +} + +ACE_ALLOC_HOOK_DEFINE_Tca(ACE_Oneshot_Acceptor) + +template void +ACE_Oneshot_Acceptor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Oneshot_Acceptor::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nsvc_handler_ = %x"), this->svc_handler_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nrestart_ = %d"), this->restart_)); + this->peer_acceptor_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("delete_concurrency_strategy_ = %d"), + delete_concurrency_strategy_)); + this->concurrency_strategy_->dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template int +ACE_Oneshot_Acceptor::open + (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor, + ACE_Concurrency_Strategy *con_s) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::open"); + this->reactor (reactor); + + // Initialize the concurrency strategy. + + if (con_s == 0) + { + ACE_NEW_RETURN (con_s, + ACE_Concurrency_Strategy, + -1); + this->delete_concurrency_strategy_ = true; + } + this->concurrency_strategy_ = con_s; + + // Reuse the addr, even if it is already in use...! + return this->peer_acceptor_.open (local_addr, 1); +} + +template +ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor (void) + : svc_handler_ (0), + restart_ (false), + concurrency_strategy_ (0), + delete_concurrency_strategy_ (false) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"); + this->reactor (0); +} + +template +ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor + (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor, + ACE_Concurrency_Strategy *cs) + : svc_handler_ (0), + restart_ (false), + concurrency_strategy_ (0), + delete_concurrency_strategy_ (false) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"); + if (this->open (local_addr, reactor, cs) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Oneshot_Acceptor::ACE_Oneshot_Acceptor"))); +} + +template +ACE_Oneshot_Acceptor::~ACE_Oneshot_Acceptor (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::~ACE_Oneshot_Acceptor"); + this->handle_close (); +} + +template int +ACE_Oneshot_Acceptor::close (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::close"); + return this->handle_close (); +} + +template int +ACE_Oneshot_Acceptor::handle_close (ACE_HANDLE, + ACE_Reactor_Mask) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::handle_close"); + + // Guard against multiple closes. + if (this->delete_concurrency_strategy_) + { + delete this->concurrency_strategy_; + this->delete_concurrency_strategy_ = false; + this->concurrency_strategy_ = 0; + } + // Note that if we aren't actually registered with the + // ACE_Reactor then it's ok for this call to fail... + + if (this->reactor ()) + this->reactor ()->remove_handler + (this, + ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); + + if (this->peer_acceptor_.close () == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("close\n"))); + return 0; +} + +template int +ACE_Oneshot_Acceptor::handle_timeout + (const ACE_Time_Value &tv, + const void *arg) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::handle_timeout"); + errno = ETIME; + + if (this->svc_handler_->handle_timeout (tv, arg) == -1) + this->svc_handler_->handle_close (this->svc_handler_->get_handle (), + ACE_Event_Handler::TIMER_MASK); + + // Since we aren't necessarily registered with the Reactor, don't + // bother to check the return value here... + if (this->reactor ()) + this->reactor ()->remove_handler (this, + ACE_Event_Handler::ACCEPT_MASK); + return 0; +} + +template int +ACE_Oneshot_Acceptor::cancel (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::cancel"); + return this->reactor () && this->reactor ()->cancel_timer (this); +} + +template int +ACE_Oneshot_Acceptor::register_handler + (SVC_HANDLER *svc_handler, + const ACE_Synch_Options &synch_options, + bool restart) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::register_handler"); + // Can't do this if we don't have a Reactor. + if (this->reactor () == 0) + { + errno = EINVAL; + return -1; + } + else + { + this->svc_handler_ = svc_handler; + this->restart_ = restart; + ACE_Time_Value *tv = (ACE_Time_Value *) synch_options.time_value (); + + if (tv != 0 + && this->reactor ()->schedule_timer (this, + synch_options.arg (), + *tv) == -1) + return -1; + else + return this->reactor ()->register_handler + (this, + ACE_Event_Handler::ACCEPT_MASK); + } +} + +// Bridge method for activating a with the appropriate +// concurrency strategy. The default behavior of this method is to +// activate the SVC_HANDLER by calling its open() method (which allows +// the SVC_HANDLER to define its own concurrency strategy). However, +// subclasses can override this strategy to do more sophisticated +// concurrency activations (such as creating the SVC_HANDLER as an +// "active object" via multi-threading or multi-processing). + +template int +ACE_Oneshot_Acceptor::activate_svc_handler + (SVC_HANDLER *svc_handler) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::activate_svc_handler"); + return this->concurrency_strategy_->activate_svc_handler + (svc_handler, + (void *) this); +} + +// Factors out the code shared between the and +// methods. + +template int +ACE_Oneshot_Acceptor::shared_accept + (SVC_HANDLER *svc_handler, + typename PEER_ACCEPTOR::PEER_ADDR *remote_addr, + ACE_Time_Value *timeout, + bool restart, + bool reset_new_handle) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::shared_accept"); + if (svc_handler == 0) + return -1; + + // Accept connection into the Svc_Handler. + else if (this->peer_acceptor_.accept (svc_handler->peer (), // stream + remote_addr, // remote address + timeout, // timeout + restart, // restart + reset_new_handle // reset new handle + ) == -1) + { + // Check whether we just timed out or whether we failed... + if (!(errno == EWOULDBLOCK || errno == ETIME)) + // Close down handler to avoid memory leaks. + svc_handler->close (CLOSE_DURING_NEW_CONNECTION); + return -1; + } + // Activate the using the designated concurrency + // strategy (note that this method becomes responsible for handling + // errors and freeing up the memory if things go awry...) + else + return this->activate_svc_handler (svc_handler); +} + +// Make a SVC_HANDLER, accept the connection into the SVC_HANDLER, and +// then activate the SVC_HANDLER. Note that SVC_HANDLER::open() +// decides what type of concurrency strategy to use. + +template int +ACE_Oneshot_Acceptor::accept + (SVC_HANDLER *svc_handler, + typename PEER_ACCEPTOR::PEER_ADDR *remote_addr, + const ACE_Synch_Options &synch_options, + bool restart, + bool reset_new_handle) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::accept"); + // Note that if timeout == ACE_Time_Value (x, y) where (x > 0 || y > + // 0) then this->connector_.connect() will block synchronously. If + // is set then we don't want this to happen (since we + // want the ACE_Reactor to do the timeout asynchronously). + // Therefore, we'll force this->connector_ to use ACE_Time_Value (0, + // 0) in this case... + + ACE_Time_Value *timeout; + int use_reactor = synch_options[ACE_Synch_Options::USE_REACTOR]; + + if (use_reactor) + timeout = (ACE_Time_Value *) &ACE_Time_Value::zero; + else + timeout = (ACE_Time_Value *) synch_options.time_value (); + + if (this->shared_accept (svc_handler, // stream + remote_addr, // remote address + timeout, // timeout + restart, // restart + reset_new_handle // reset new handler + ) == -1) + { + if (use_reactor && errno == EWOULDBLOCK) + // We couldn't accept right away, so let's wait in the + // . + this->register_handler (svc_handler, + synch_options, + restart); + return -1; + } + return 0; +} + +// Accepts one pending connection from a client (since we're the +// "oneshot" Acceptor). + +template int +ACE_Oneshot_Acceptor::handle_input (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::handle_input"); + int result = 0; + + // Cancel any timer that might be pending. + this->cancel (); + + // Try to find out if the implementation of the reactor that we are + // using requires us to reset the event association for the newly + // created handle. This is because the newly created handle will + // inherit the properties of the listen handle, including its event + // associations. + ACE_Reactor *reactor = this->reactor (); + bool reset_new_handle = false; + + // There is a use-case whereby this object will be gone upon return + // from shared_accept - if the Svc_Handler deletes this Oneshot_Acceptor + // during the shared_accept/activation steps. So, do whatever we need + // to do with this object before calling shared_accept. + if (reactor) + { + reset_new_handle = reactor->uses_event_associations (); + reactor->remove_handler + (this, + ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); + } + + if (this->shared_accept (this->svc_handler_, // stream + 0, // remote address + 0, // timeout + this->restart_, // restart + reset_new_handle // reset new handle + ) == -1) + result = -1; + + return result; +} + +// Hook called by the explicit dynamic linking facility. + +template int +ACE_Oneshot_Acceptor::init (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::init"); + return -1; +} + +template int +ACE_Oneshot_Acceptor::fini (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::fini"); + return this->handle_close (); +} + +template int +ACE_Oneshot_Acceptor::info (ACE_TCHAR **strp, + size_t length) const +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::info"); + ACE_TCHAR buf[BUFSIZ]; + ACE_TCHAR addr_str[BUFSIZ]; + typename PEER_ACCEPTOR::PEER_ADDR addr; + + if (this->peer_acceptor_.get_local_addr (addr) == -1) + return -1; + else if (addr.addr_to_string (addr_str, sizeof addr_str) == -1) + return -1; + + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%s\t %s %s"), + ACE_TEXT ("ACE_Oneshot_Acceptor"), + addr_str, + ACE_TEXT ("#oneshot acceptor factory\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strsncpy (*strp, buf, length); + return static_cast (ACE_OS::strlen (buf)); +} + +template int +ACE_Oneshot_Acceptor::suspend (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::suspend"); + return this->reactor () && this->reactor ()->suspend_handler (this); +} + +template int +ACE_Oneshot_Acceptor::resume (void) +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::resume"); + return this->reactor () && this->reactor ()->resume_handler (this); +} + +// Returns ACE_HANDLE of the underlying peer_acceptor. + +template ACE_HANDLE +ACE_Oneshot_Acceptor::get_handle (void) const +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::get_handle"); + return this->peer_acceptor_.get_handle (); +} + +template PEER_ACCEPTOR & +ACE_Oneshot_Acceptor::acceptor (void) const +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::acceptor"); + return (PEER_ACCEPTOR &) this->peer_acceptor_; +} + +template +ACE_Oneshot_Acceptor::operator PEER_ACCEPTOR & () const +{ + ACE_TRACE ("ACE_Oneshot_Acceptor::operator PEER_ACCEPTOR &"); + return (PEER_ACCEPTOR &) this->peer_acceptor_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ACCEPTOR_CPP */ diff --git a/dep/acelite/ace/Acceptor.h b/dep/acelite/ace/Acceptor.h new file mode 100644 index 000000000..f4c7754f8 --- /dev/null +++ b/dep/acelite/ace/Acceptor.h @@ -0,0 +1,701 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Acceptor.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ACCEPTOR_H +#define ACE_ACCEPTOR_H + +#include /**/ "ace/pre.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Strategies_T.h" +#include "ace/Synch_Options.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Acceptor + * + * @brief Abstract factory for creating a service handler + * (SVC_HANDLER), accepting into the SVC_HANDLER, and + * activating the SVC_HANDLER. + * + * Implements the basic strategy for passively establishing + * connections with clients. An ACE_Acceptor inherits from + * ACE_Service_Object, which in turn inherits from ACE_Event_Handler. + * This enables the ACE_Reactor to dispatch the ACE_Acceptor's + * handle_input method when connection events occur. The handle_input + * method performs the ACE_Acceptor's default creation, connection + * establishment, and service activation strategies. These strategies + * can be overridden by subclasses individually or as a group. + * + * An ACE_Acceptor is parameterized by concrete types that conform to + * the interfaces of SVC_HANDLER and PEER_ACCEPTOR described below. + * + * @tparam SVC_HANDLER The name of the concrete type that performs the + * application-specific service. The SVC_HANDLER typically + * inherits from ACE_Svc_Handler. @see Svc_Handler.h. + * + * @tparam PEER_ACCEPTOR The name of the class that implements the + * PEER_ACCEPTOR endpoint (e.g., ACE_SOCK_Acceptor) to + * passively establish connections. A PEER_ACCEPTOR + * implementation must provide a PEER_STREAM and PEER_ADDR + * trait to identify the type of stream (e.g., + * ACE_SOCK_Stream) and type of address (e.g., ACE_INET_Addr) + * used by the endpoint. + */ +template +class ACE_Acceptor : public ACE_Service_Object +{ +public: + + // Useful STL-style traits. + typedef typename PEER_ACCEPTOR::PEER_ADDR addr_type; + typedef PEER_ACCEPTOR acceptor_type; + typedef SVC_HANDLER handler_type; + typedef typename SVC_HANDLER::stream_type stream_type; + + /// "Do-nothing" constructor. + ACE_Acceptor (ACE_Reactor * = 0, + int use_select = 1); + + /** + * Open the contained @c PEER_ACCEPTOR object to begin listening, and + * register with the specified reactor for accept events. An + * acceptor can only listen to one port at a time, so make sure to + * @c close() the acceptor before calling @c open() again. + * + * The @c PEER_ACCEPTOR handle is put into non-blocking mode as a + * safeguard against the race condition that can otherwise occur + * between the time when the passive-mode socket handle is "ready" + * and when the actual @c accept() call is made. During this + * interval, the client can shutdown the connection, in which case, + * the @c accept() call can hang. + * + * @param local_addr The address to listen at. + * @param reactor Pointer to the ACE_Reactor instance to register + * this object with. The default is the singleton. + * @param flags Flags to control what mode an accepted socket + * will be put into after it is accepted. The only + * legal value for this argument is @c ACE_NONBLOCK, + * which enables non-blocking mode on the accepted + * peer stream object in @c SVC_HANDLER. The default + * is 0. + * @param use_select Affects behavior when called back by the reactor + * when a connection can be accepted. If non-zero, + * this object will accept all pending connections, + * instead of just the one that triggered the reactor + * callback. Uses ACE_OS::select() internally to + * detect any remaining acceptable connections. + * The default is 1. + * @param reuse_addr Passed to the @c PEER_ACCEPTOR::open() method with + * @p local_addr. Generally used to request that the + * OS allow reuse of the listen port. The default is 1. + */ + ACE_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor = ACE_Reactor::instance (), + int flags = 0, + int use_select = 1, + int reuse_addr = 1); + + /** + * Open the contained @c PEER_ACCEPTOR object to begin listening, and + * register with the specified reactor for accept events. An + * acceptor can only listen to one port at a time, so make sure to + * @c close() the acceptor before calling @c open() again. + * + * The @c PEER_ACCEPTOR handle is put into non-blocking mode as a + * safeguard against the race condition that can otherwise occur + * between the time when the passive-mode socket handle is "ready" + * and when the actual @c accept() call is made. During this + * interval, the client can shutdown the connection, in which case, + * the @c accept() call can hang. + * + * @param local_addr The address to listen at. + * @param reactor Pointer to the ACE_Reactor instance to register + * this object with. The default is the singleton. + * @param flags Flags to control what mode an accepted socket + * will be put into after it is accepted. The only + * legal value for this argument is @c ACE_NONBLOCK, + * which enables non-blocking mode on the accepted + * peer stream object in @c SVC_HANDLER. The default + * is 0. + * @param use_select Affects behavior when called back by the reactor + * when a connection can be accepted. If non-zero, + * this object will accept all pending connections, + * instead of just the one that triggered the reactor + * callback. Uses ACE_OS::select() internally to + * detect any remaining acceptable connections. + * The default is 1. + * @param reuse_addr Passed to the @c PEER_ACCEPTOR::open() method with + * @p local_addr. Generally used to request that the + * OS allow reuse of the listen port. The default is 1. + * + * @retval 0 Success + * @retval -1 Failure, @c errno contains an error code. + */ + virtual int open (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor = ACE_Reactor::instance (), + int flags = 0, + int use_select = 1, + int reuse_addr = 1); + + /// Close down the Acceptor's resources. + virtual ~ACE_Acceptor (void); + + /// Return the underlying PEER_ACCEPTOR object. + virtual operator PEER_ACCEPTOR &() const; + + /// Return the underlying PEER_ACCEPTOR object. + virtual PEER_ACCEPTOR &acceptor (void) const; + + /// Returns the listening acceptor's {ACE_HANDLE}. + virtual ACE_HANDLE get_handle (void) const; + + /// Close down the Acceptor + virtual int close (void); + + /// In the event that an accept fails, this method will be called and + /// the return value will be returned from handle_input(). + virtual int handle_accept_error (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = The following three methods define the Acceptor's strategies + // for creating, accepting, and activating SVC_HANDLER's, + // respectively. + + /** + * Bridge method for creating a SVC_HANDLER. The default is to + * create a new {SVC_HANDLER} if {sh} == 0, else {sh} is unchanged. + * However, subclasses can override this policy to perform + * SVC_HANDLER creation in any way that they like (such as creating + * subclass instances of SVC_HANDLER, using a singleton, dynamically + * linking the handler, etc.). Returns -1 on failure, else 0. + */ + virtual int make_svc_handler (SVC_HANDLER *&sh); + + /** + * Bridge method for accepting the new connection into the + * @a svc_handler. The default behavior delegates to the + * PEER_ACCEPTOR::accept. + */ + virtual int accept_svc_handler (SVC_HANDLER *svc_handler); + + /** + * Bridge method for activating a @a svc_handler with the appropriate + * concurrency strategy. The default behavior of this method is to + * activate the SVC_HANDLER by calling its open() method (which + * allows the SVC_HANDLER to define its own concurrency strategy). + * However, subclasses can override this strategy to do more + * sophisticated concurrency activations (such as making the + * SVC_HANDLER as an "active object" via multi-threading or + * multi-processing). + */ + virtual int activate_svc_handler (SVC_HANDLER *svc_handler); + + // = Demultiplexing hooks. + /// Perform termination activities when {this} is removed from the + /// {reactor}. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /// Accepts all pending connections from clients, and creates and + /// activates SVC_HANDLERs. + virtual int handle_input (ACE_HANDLE); + + // = Dynamic linking hooks. + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int init (int argc, ACE_TCHAR *argv[]); + + /// Calls {handle_close}. + virtual int fini (void); + + /// Default version returns address info in {buf}. + virtual int info (ACE_TCHAR **buf, size_t) const; + +public: + // = Service management hooks. + /// This method calls {Reactor::suspend}. + virtual int suspend (void); + + /// This method calls {Reactor::resume}. + virtual int resume (void); + +protected: + /// Concrete factory for accepting connections from clients... + PEER_ACCEPTOR peer_acceptor_; + + /// Needed to reopen the socket if {accept} fails. + typename PEER_ACCEPTOR::PEER_ADDR peer_acceptor_addr_; + + /** + * Flags that indicate how {SVC_HANDLER}'s should be initialized + * prior to being activated. Right now, the only flag that is + * processed is {ACE_NONBLOCK}, which enabled non-blocking I/O on + * the {SVC_HANDLER} when it is opened. + */ + int flags_; + + /// Flag that indicates whether it shall use {select} in the + /// {accept}-loop. + int use_select_; + + /// Needed to reopen the socket if {accept} fails. + int reuse_addr_; +}; + +/** + * @class ACE_Strategy_Acceptor + * + * @brief Abstract factory for creating a service handler + * (SVC_HANDLER), accepting into the SVC_HANDLER, and activating + * the SVC_HANDLER. + * + * Implements a flexible and extensible set of strategies for + * passively establishing connections with clients. There are + * three main strategies: (1) creating a SVC_HANDLER, (2) + * passively accepting a new connection from a client into the + * SVC_HANDLER, and (3) activating the SVC_HANDLER with a + * particular concurrency mechanism. + */ +template +class ACE_Strategy_Acceptor + : public ACE_Acceptor +{ +public: + + // Useful STL-style traits. + typedef ACE_Creation_Strategy + creation_strategy_type; + typedef ACE_Accept_Strategy + accept_strategy_type; + typedef ACE_Concurrency_Strategy + concurrency_strategy_type; + typedef ACE_Scheduling_Strategy scheduling_strategy_type; + typedef ACE_Acceptor + base_type; + + // = Define some useful (old style) traits. + typedef ACE_Creation_Strategy CREATION_STRATEGY; + typedef ACE_Accept_Strategy ACCEPT_STRATEGY; + typedef ACE_Concurrency_Strategy CONCURRENCY_STRATEGY; + typedef ACE_Scheduling_Strategy SCHEDULING_STRATEGY; + + /// Default constructor. + ACE_Strategy_Acceptor (const ACE_TCHAR service_name[] = 0, + const ACE_TCHAR service_description[] = 0, + int use_select = 1, + int reuse_addr = 1); + + /** + * Initialize the appropriate strategies for creation, passive + * connection acceptance, and concurrency, and then register {this} + * with the Reactor and listen for connection requests at the + * designated {local_addr}. + */ + ACE_Strategy_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor * = ACE_Reactor::instance (), + ACE_Creation_Strategy * = 0, + ACE_Accept_Strategy * = 0, + ACE_Concurrency_Strategy * = 0, + ACE_Scheduling_Strategy * = 0, + const ACE_TCHAR service_name[] = 0, + const ACE_TCHAR service_description[] = 0, + int use_select = 1, + int reuse_addr = 1); + + /** + * Open the contained @c PEER_ACCEPTOR object to begin listening, and + * register with the specified reactor for accept events. + * + * The @c PEER_ACCEPTOR handle is put into non-blocking mode as a + * safeguard against the race condition that can otherwise occur + * between the time when the passive-mode socket handle is "ready" + * and when the actual @c accept call is made. During this + * interval, the client can shutdown the connection, in which case, + * the {accept} call can hang. + * + * @param local_addr The address to listen at. + * @param reactor Pointer to the ACE_Reactor instance to register + * this object with. The default is the singleton. + * @param flags Flags to control what mode an accepted socket + * will be put into after it is accepted. The only + * legal value for this argument is @c ACE_NONBLOCK, + * which enables non-blocking mode on the accepted + * peer stream object in @c SVC_HANDLER. The default + * is 0. + * @param use_select Affects behavior when called back by the reactor + * when a connection can be accepted. If non-zero, + * this object will accept all pending connections, + * instead of just the one that triggered the reactor + * callback. Uses ACE_OS::select() internally to + * detect any remaining acceptable connections. + * The default is 1. + * @param reuse_addr Passed to the @c PEER_ACCEPTOR::open() method with + * @p local_addr. Generally used to request that the + * OS allow reuse of the listen port. The default is 1. + * + * @retval 0 Success + * @retval -1 Failure, @c errno contains an error code. + */ + virtual int open (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor, + int flags = 0, + int use_select = 1, + int reuse_addr = 1); + + /** + * Initialize the appropriate strategies for creation, passive + * connection acceptance, and concurrency, and then register {this} + * with the Reactor and listen for connection requests at the + * designated {local_addr}. + */ + virtual int open (const typename PEER_ACCEPTOR::PEER_ADDR &, + ACE_Reactor * = ACE_Reactor::instance (), + ACE_Creation_Strategy * = 0, + ACE_Accept_Strategy * =0, + ACE_Concurrency_Strategy * = 0, + ACE_Scheduling_Strategy * = 0, + const ACE_TCHAR *service_name = 0, + const ACE_TCHAR *service_description = 0, + int use_select = 1, + int reuse_addr = 1); + + /// Close down the Strategy_Acceptor's resources. + virtual ~ACE_Strategy_Acceptor (void); + + /// Return the underlying PEER_ACCEPTOR object. + virtual operator PEER_ACCEPTOR &() const; + + /// Return the underlying PEER_ACCEPTOR object. + virtual PEER_ACCEPTOR &acceptor (void) const; + + /// Returns the listening acceptor's {ACE_HANDLE}. + virtual ACE_HANDLE get_handle (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Service management hooks. + + /// This method delegates to the {Scheduling_Strategy}'s {suspend} + /// method. + virtual int suspend (void); + + /// This method delegates to the {Scheduling_Strategy}'s {resume} + /// method. + virtual int resume (void); + +protected: + + /// Calls {handle_close} when dynamically unlinked. + virtual int fini (void); + + /// Default version returns address info in {buf}. + virtual int info (ACE_TCHAR **buf, size_t) const; + + // = The following three methods define the {Acceptor}'s strategies + // for creating, accepting, and activating {SVC_HANDLER}'s, + // respectively. + + /** + * Bridge method for creating a {SVC_HANDLER}. The strategy for + * creating a {SVC_HANDLER} are configured into the Acceptor via + * it's {creation_strategy_}. The default is to create a new + * {SVC_HANDLER} if {sh} == 0, else {sh} is unchanged. However, + * subclasses can override this policy to perform {SVC_HANDLER} + * creation in any way that they like (such as creating subclass + * instances of {SVC_HANDLER}, using a singleton, dynamically + * linking the handler, etc.). Returns -1 on failure, else 0. + */ + virtual int make_svc_handler (SVC_HANDLER *&); + + /** + * Bridge method for accepting the new connection into the + * {SVC_HANDLER}. The default behavior delegates to the + * {PEER_ACCEPTOR::accept} in the {Acceptor_Strategy}. + */ + virtual int accept_svc_handler (SVC_HANDLER *svc_handler); + + /** + * Bridge method for activating a {SVC_HANDLER} with the appropriate + * concurrency strategy. The default behavior of this method is to + * activate the {SVC_HANDLER} by calling its {open} method (which + * allows the {SVC_HANDLER} to define its own concurrency strategy). + * However, subclasses can override this strategy to do more + * sophisticated concurrency activations (such as creating the + * {SVC_HANDLER} as an "active object" via multi-threading or + * multi-processing). + */ + virtual int activate_svc_handler (SVC_HANDLER *svc_handler); + + // = Demultiplexing hooks. + /// Perform termination activities when {this} is removed from the + /// {Reactor}. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /// Handle SIGINT. + virtual int handle_signal (int signum, siginfo_t *, ucontext_t *); + + // = These data members are "logically private" but are put in the + // protected part in case subclasses want to access them. + + // = Strategy objects. + + /// Creation strategy for an Acceptor. + CREATION_STRATEGY *creation_strategy_; + + /// true if {Acceptor} created the creation strategy and thus should + /// delete it, else false. + bool delete_creation_strategy_; + + /// Accept strategy for an {Acceptor}. + ACCEPT_STRATEGY *accept_strategy_; + + /// true if {Acceptor} created the accept strategy and thus should delete + /// it, else false. + bool delete_accept_strategy_; + + /// Concurrency strategy for an {Acceptor}. + CONCURRENCY_STRATEGY *concurrency_strategy_; + + /// true if {Acceptor} created the concurrency strategy and thus should + /// delete it, else false. + bool delete_concurrency_strategy_; + + /// Scheduling strategy for an {Acceptor}. + SCHEDULING_STRATEGY *scheduling_strategy_; + + /// true if {Acceptor} created the scheduling strategy and thus should + /// delete it, else false. + bool delete_scheduling_strategy_; + + // = Service information objects. + + /// Name of the service. + ACE_TCHAR *service_name_; + + /// Description of the service. + ACE_TCHAR *service_description_; + + /// Address that the {Strategy_Acceptor} uses to listen for + /// connections. + typename PEER_ACCEPTOR::PEER_ADDR service_addr_; +}; + +/** + * @class ACE_Oneshot_Acceptor + * + * @brief Generic factory for passively connecting clients and creating + * exactly one service handler of the type SVC_HANDLER specified in the + * template. + * + * This class works similarly to the regular ACE_Acceptor, but + * with the following differences: + * -# ACE_Oneshot_Acceptor doesn't automatically register itself with the + * ACE_Reactor; the caller is expected to call the accept() method + * directly. Since a later call to accept() may require a reactor, + * the constructor and open() methods both accept an ACE_Reactor pointer + * which is saved in case it's needed in accept(). + * -# ACE_Oneshot_Acceptor doesn't need an ACE_Creation_Strategy (because + * the user supplies the SVC_HANDLER) or an ACE_Accept_Strategy (because + * this class only accepts one connection and then removes all traces of + * itself from the ACE_Reactor if it was registered for asynchronous + * accepts). + * + * The usage model for ACE_Oneshot_Acceptor is: + * - Instantiate an object and establish its local address to listen at. + * This can be accomplished using either the address-accepting constructor + * (but there's no error indication) or the default constructor followed + * by a call to open(). + * - Call the accept() method. This will attempt to accept a connection + * immediately. If there is no immediately available connection to accept, + * behavior is governed by the ACE_Synch_Options argument passed to open(). + */ +template +class ACE_Oneshot_Acceptor : public ACE_Service_Object +{ +public: + + // Useful STL-style traits. + typedef typename PEER_ACCEPTOR::PEER_ADDR addr_type; + typedef PEER_ACCEPTOR acceptor_type; + typedef SVC_HANDLER handler_type; + typedef typename SVC_HANDLER::stream_type stream_type; + + /// Constructor. + ACE_Oneshot_Acceptor (void); + + /** + * Initialize the appropriate strategies for concurrency and then + * open the acceptor at the designated @a local_addr. Note + * that unlike ACE_Acceptor and ACE_Strategy_Acceptor, this + * method does NOT register this acceptor with the @a reactor at + * this point -- the @a reactor parameter is saved in case it's + * needed later. + */ + ACE_Oneshot_Acceptor (const typename PEER_ACCEPTOR::PEER_ADDR &local_addr, + ACE_Reactor *reactor = ACE_Reactor::instance (), + ACE_Concurrency_Strategy * = 0); + + /** + * Initialize the appropriate strategies for concurrency and then + * open the acceptor at the designated @a local_addr. Note + * that unlike ACE_Acceptor and ACE_Strategy_Acceptor, this + * method does NOT register this acceptor with the @a reactor at + * this point -- the @a reactor parameter is saved in case it's + * needed later. + */ + int open (const typename PEER_ACCEPTOR::PEER_ADDR &, + ACE_Reactor *reactor = ACE_Reactor::instance (), + ACE_Concurrency_Strategy * = 0); + + /// Close down the {Oneshot_Acceptor}. + virtual ~ACE_Oneshot_Acceptor (void); + + // = Explicit factory operation. + /// Create a {SVC_HANDLER}, accept the connection into the + /// {SVC_HANDLER}, and activate the {SVC_HANDLER}. + virtual int accept (SVC_HANDLER * = 0, + typename PEER_ACCEPTOR::PEER_ADDR *remote_addr = 0, + const ACE_Synch_Options &synch_options = ACE_Synch_Options::defaults, + bool restart = true, + bool reset_new_handle = false); + + /// Cancel a oneshot acceptor that was started asynchronously. + virtual int cancel (void); + + /// Return the underlying {PEER_ACCEPTOR} object. + virtual operator PEER_ACCEPTOR &() const; + + /// Return the underlying {PEER_ACCEPTOR} object. + virtual PEER_ACCEPTOR &acceptor (void) const; + + /// Close down the {Oneshot_Acceptor}. + virtual int close (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /** + * Bridge method for activating a {svc_handler} with the appropriate + * concurrency strategy. Default behavior is to activate the + * {SVC_HANDLER} as a "passive object." However, subclasses can + * override this strategy to do more sophisticated concurrency + * activations (such as creating the {SVC_HANDLER} as an "active + * object" via multi-threading or multi-processing). + */ + virtual int activate_svc_handler (SVC_HANDLER *svc_handler); + + /// Factors out the code shared between the {accept} and + /// {handle_input} methods. + int shared_accept (SVC_HANDLER *svc_handler, + typename PEER_ACCEPTOR::PEER_ADDR *remote_addr, + ACE_Time_Value *timeout, + bool restart, + bool reset_new_handle); + + // = Demultiplexing hooks. + /// Returns the listening acceptor's {ACE_HANDLE}. + virtual ACE_HANDLE get_handle (void) const; + + /// Perform termination activities when {this} is removed from the + /// {reactor}. + virtual int handle_close (ACE_HANDLE = ACE_INVALID_HANDLE, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /// Accept one connection from a client and activates the + /// SVC_HANDLER. + virtual int handle_input (ACE_HANDLE); + + /// Called when an acceptor times out... + virtual int handle_timeout (const ACE_Time_Value &tv, + const void *arg); + + // = Dynamic linking hooks. + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int init (int argc, ACE_TCHAR *argv[]); + + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int fini (void); + + /// Default version returns address info in {buf}. + virtual int info (ACE_TCHAR **, size_t) const; + + // = Service management hooks. + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int suspend (void); + + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int resume (void); + +private: + /** + * Insert ourselves into the {ACE_Reactor} so that we can continue + * accepting this connection asynchronously. This method should NOT + * be called by developers directly. + */ + int register_handler (SVC_HANDLER *svc_handler, + const ACE_Synch_Options &options, + bool restart); + + /// Hold the svc_handler_ across asynchrony boundaries. + SVC_HANDLER *svc_handler_; + + /// Hold the restart flag across asynchrony boundaries. + bool restart_; + + /// Factory that establishes connections passively. + PEER_ACCEPTOR peer_acceptor_; + + /// Concurrency strategy for an Acceptor. + ACE_Concurrency_Strategy *concurrency_strategy_; + + /// true if Acceptor created the concurrency strategy and thus should + /// delete it, else false. + bool delete_concurrency_strategy_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Acceptor.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Acceptor.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ACCEPTOR_H */ diff --git a/dep/acelite/ace/Activation_Queue.cpp b/dep/acelite/ace/Activation_Queue.cpp new file mode 100644 index 000000000..61683993c --- /dev/null +++ b/dep/acelite/ace/Activation_Queue.cpp @@ -0,0 +1,136 @@ +#include "ace/Activation_Queue.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Activation_Queue.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/Method_Request.h" +#include "ace/Malloc_Base.h" +#include "ace/Time_Value.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE (ACE_Activation_Queue) + +void +ACE_Activation_Queue::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("delete_queue_ = %d\n"), + this->delete_queue_)); + ACELIB_DEBUG ((LM_INFO, ACE_TEXT ("queue_:\n"))); + if (this->queue_) + this->queue_->dump(); + else + //FUZZ: disable check_for_NULL + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(NULL)\n"))); + //FUZZ: enable check_for_NULL + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Activation_Queue::ACE_Activation_Queue (ACE_Message_Queue *new_queue, + ACE_Allocator *alloc, + ACE_Allocator *db_alloc) + : delete_queue_ (false) + , allocator_(alloc) + , data_block_allocator_(db_alloc) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + if (new_queue) + this->queue_ = new_queue; + else + { + ACE_NEW (this->queue_, + ACE_Message_Queue); + this->delete_queue_ = true; + } +} + +void +ACE_Activation_Queue::queue (ACE_Message_Queue *q) +{ + // Destroy the internal queue if one exist. + if (this->delete_queue_) + { + // Destroy the current queue. + delete this->queue_; + + // Set the flag to false. NOTE that the delete_queue_ flag is a + // flag used to only indicate whether or not if an internal + // ACE_Message_Queue has been created, therefore, it will not + // affect the user if the user decided to replace the queue with + // their own queue no matter how many time they call on this + // function. + this->delete_queue_ = false; + } + + queue_ = q; +} + +ACE_Activation_Queue::~ACE_Activation_Queue (void) +{ + if (this->delete_queue_) + delete this->queue_; +} + +ACE_Method_Request * +ACE_Activation_Queue::dequeue (ACE_Time_Value *tv) +{ + ACE_Message_Block *mb = 0; + + // Dequeue the message. + if (this->queue_->dequeue_head (mb, tv) != -1) + { + // Get the next . + ACE_Method_Request *mr = + reinterpret_cast (mb->base ()); + // Delete the message block. + mb->release (); + return mr; + } + else + return 0; +} + +int +ACE_Activation_Queue::enqueue (ACE_Method_Request *mr, + ACE_Time_Value *tv) +{ + ACE_Message_Block *mb = 0; + + // We pass sizeof (*mr) here so that flow control will work + // correctly. Since we also pass note that no unnecessary + // memory is actually allocated -- just the size field is set. + ACE_NEW_MALLOC_RETURN (mb, + static_cast (this->allocator_->malloc (sizeof (ACE_Message_Block))), + ACE_Message_Block (sizeof (*mr), // size + ACE_Message_Block::MB_DATA, // type + 0, // cont + (char *) mr, // data + 0, // allocator + 0, // locking strategy + mr->priority (), // priority + ACE_Time_Value::zero, // execution time + ACE_Time_Value::max_time, // absolute time of deadline + this->data_block_allocator_, // data_block allocator + this->allocator_), // message_block allocator + -1); + + // Enqueue in priority order. + int const result = this->queue_->enqueue_prio (mb, tv); + + // Free ACE_Message_Block if enqueue_prio failed. + if (result == -1) + ACE_DES_FREE (mb, this->allocator_->free, ACE_Message_Block); + + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Activation_Queue.h b/dep/acelite/ace/Activation_Queue.h new file mode 100644 index 000000000..7317c43d0 --- /dev/null +++ b/dep/acelite/ace/Activation_Queue.h @@ -0,0 +1,168 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Activation_Queue.h + * + * @author Andres Kruse + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ACTIVATION_QUEUE_H +#define ACE_ACTIVATION_QUEUE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Message_Queue.h" +#include "ace/Copy_Disabled.h" +#include "ace/Condition_Thread_Mutex.h" + +/// Define to be compatible with the terminology in the POSA2 book! +#define ACE_Activation_List ACE_Activation_Queue + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Method_Request; + +/** + * @class ACE_Activation_Queue + * + * @brief + * Reifies a method into a request. Subclasses typically + * represent necessary state and behavior. + * + * Maintains a priority-ordered queue of ACE_Method_Request objects. + * A scheduler class (often derived from ACE_Task) subsequently removes + * each method request and invokes its @c call() method. + * + * This class is discussed in depth in the Active Object chapter + * of POSA2. In that book, it is referred to as an Activation List. + * + * @sa ACE_Method_Request + */ +class ACE_Export ACE_Activation_Queue +{ +public: + /// Constructor. + /** + * Initializes a new activation queue. + * + * @param new_queue The activation queue uses an ACE_Message_Queue to + * queue and order the method requests. If this argument + * is 0, a new ACE_Message_Queue is created for this + * object's use and will be deleted when this object is + * destroyed. If a non-zero pointer is supplied, the + * passed object will be used and will not be deleted when + * this object is destroyed. If an ACE_Task is being created + * to act as the scheduler, for instance, its + * ACE_Message_Queue pointer can be passed to this object. + * @param alloc Optional, the allocator to use when allocating + * ACE_Message_Block instances that wrap the method requests + * queued to this activation queue. Defaults to + * ACE_Allocator::instance(). + * @param db_alloc Optional, the allocator to use when allocating + * data blocks for the ACE_Message_Block instances that + * wrap the method requests queued to this activation queue. + * Defaults to ACE_Allocator::instance(). + */ + ACE_Activation_Queue (ACE_Message_Queue *new_queue = 0, + ACE_Allocator *alloc = 0, + ACE_Allocator *db_alloc = 0); + + /// Destructor. + virtual ~ACE_Activation_Queue (void); + + // = Activate Queue operations. + + /// Dequeue the next available ACE_Method_Request. + /** + * @param tv If 0, the method will block until a method request is + * available, else will wait until the absolute time specified + * in the referenced ACE_Time_Value. This method will return, + * earlier, however, if queue is closed, deactivated, or when + * a signal occurs. + * + * @retval Pointer to the dequeued ACE_Method_Request object. + * @retval 0 an error occurs; errno contains further information. If + * the specified timeout elapses, errno will be @c EWOULDBLOCK. + */ + ACE_Method_Request *dequeue (ACE_Time_Value *tv = 0); + + /// Enqueue the ACE_Method_Request in priority order. + /** + * The priority of the method request is obtained via the @c priority() + * method of the queued method request. Priority ordering is determined + * by the ACE_Message_Queue class; 0 is the lowest priority. + * + * @param new_method_request Pointer to the ACE_Method_Request object to + * queue. This object's @c priority() method is called to obtain + * the priority. + * @param tv If 0, the method will block until the method request can + * be queued, else will wait until the absolute time specified + * in the referenced ACE_Time_Value. This method will return, + * earlier, however, if queue is closed, deactivated, or when + * a signal occurs. + * + * @retval >0 The number of method requests on the queue after adding + * the specified request. + * @retval -1 if an error occurs; errno contains further information. If + * the specified timeout elapses, errno will be @c EWOULDBLOCK. + */ + int enqueue (ACE_Method_Request *new_method_request, ACE_Time_Value *tv = 0); + + /// Get the current number of method objects in the queue. + size_t method_count (void) const; + + /// Returns 1 if the queue is empty, 0 otherwise. + int is_empty (void) const; + + /// Returns 1 if the queue is full, 0 otherwise. + int is_full (void) const; + + /// Dump the state of an request. + void dump (void) const; + + /// Get a pointer to the underlying queue. + ACE_Message_Queue *queue (void) const; + + /// Set the pointer to the underlying queue. + void queue (ACE_Message_Queue *q); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// Stores the Method_Requests. + ACE_Message_Queue *queue_; + + /// Keeps track of whether we need to delete the queue. + bool delete_queue_; + +private: + + /// Allocation strategy of the queue. + ACE_Allocator *allocator_; + + /// Allocation strategy of the message blocks. + ACE_Allocator *data_block_allocator_; + + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Activation_Queue &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Activation_Queue (const ACE_Activation_Queue &)) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Activation_Queue.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_ACTIVATION_QUEUE_H */ diff --git a/dep/acelite/ace/Activation_Queue.inl b/dep/acelite/ace/Activation_Queue.inl new file mode 100644 index 000000000..b464dbdef --- /dev/null +++ b/dep/acelite/ace/Activation_Queue.inl @@ -0,0 +1,28 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE size_t +ACE_Activation_Queue::method_count (void) const +{ + return queue_->message_count (); +} + +ACE_INLINE int +ACE_Activation_Queue::is_full (void) const +{ + return queue_->is_full (); +} + +ACE_INLINE int +ACE_Activation_Queue::is_empty (void) const +{ + return queue_->is_empty (); +} + +ACE_INLINE ACE_Message_Queue * +ACE_Activation_Queue::queue (void) const +{ + return queue_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Active_Map_Manager.cpp b/dep/acelite/ace/Active_Map_Manager.cpp new file mode 100644 index 000000000..b8813a0dd --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager.cpp @@ -0,0 +1,5 @@ +#include "ace/Active_Map_Manager.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Active_Map_Manager.inl" +#endif /* __ACE_INLINE__ */ diff --git a/dep/acelite/ace/Active_Map_Manager.h b/dep/acelite/ace/Active_Map_Manager.h new file mode 100644 index 000000000..e0dbb7d55 --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager.h @@ -0,0 +1,114 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Active_Map_Manager.h + * + * @author Irfan Pyarali + */ +//============================================================================= + + +#ifndef ACE_ACTIVE_MAP_MANAGER_H +#define ACE_ACTIVE_MAP_MANAGER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Types.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Active_Map_Manager_Key + * + * @brief Key used in the Active Object Map. + * + * This key keeps information of the index and the generation + * count of the slot it represents. Since the index information + * is part of the key, lookups are super fast and predictable, + */ +class ACE_Export ACE_Active_Map_Manager_Key +{ +public: + /// Default constructor. + ACE_Active_Map_Manager_Key (void); + + /** + * Constructor given the @a slot_index and @a slot_generation number. + * This is useful once the user has somehow recovered the + * @a slot_index and @a slot_generation number from the client. + */ + ACE_Active_Map_Manager_Key (ACE_UINT32 slot_index, + ACE_UINT32 slot_generation); + + /// Get the slot_index. + ACE_UINT32 slot_index (void) const; + + /// Set the slot_index. + void slot_index (ACE_UINT32 i); + + /// Get the slot_generation number. + ACE_UINT32 slot_generation (void) const; + + /// Set the slot_generation number. + void slot_generation (ACE_UINT32 g); + + /// Size required to store information about active key. + static size_t size (void); + + /// Recover state of active key from @a data. User must make sure + /// that @a data encoded using the encode() method. + void decode (const void *data); + + /// Encode state of the active key into @a data. @a data must be as + /// big as the value returned from size(). + void encode (void *data) const; + + /// Compare keys. + bool operator== (const ACE_Active_Map_Manager_Key &rhs) const; + bool operator!= (const ACE_Active_Map_Manager_Key &rhs) const; + + // = This really should be protected but because of template + // friends, they are not. + + /// Increment the slot_generation number. + void increment_slot_generation_count (void); + +private: + + /** + * @brief Data for the Active Object Map Key. + * + * This separate structure makes it easier to manage copying + * the index and the generation to and from the user buffer. + * + */ + struct key_data + { + /// Slot index in the active map. + ACE_UINT32 slot_index_; + + /// Slot generation number of @c slot_index_ slot in the active map. + ACE_UINT32 slot_generation_; + }; + + /// Data for the Active Object Map Key. + key_data key_data_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Active_Map_Manager.inl" +#endif /* __ACE_INLINE__ */ + +// Include the templates here. +#include "ace/Active_Map_Manager_T.h" + +#include /**/ "ace/post.h" +#endif /* ACE_ACTIVE_MAP_MANAGER_H */ diff --git a/dep/acelite/ace/Active_Map_Manager.inl b/dep/acelite/ace/Active_Map_Manager.inl new file mode 100644 index 000000000..2fc8c13e5 --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager.inl @@ -0,0 +1,92 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Active_Map_Manager_Key::ACE_Active_Map_Manager_Key (void) +{ + // If you change ~0, please change ACE_Map_Manager::free_list_id() + // accordingly. + this->key_data_.slot_index_ = (ACE_UINT32) ~0; + this->key_data_.slot_generation_ = 0; +} + +ACE_INLINE +ACE_Active_Map_Manager_Key::ACE_Active_Map_Manager_Key (ACE_UINT32 slot_index, + ACE_UINT32 slot_generation) +{ + this->key_data_.slot_index_ = slot_index; + this->key_data_.slot_generation_ = slot_generation; +} + +ACE_INLINE ACE_UINT32 +ACE_Active_Map_Manager_Key::slot_index (void) const +{ + return this->key_data_.slot_index_; +} + +ACE_INLINE ACE_UINT32 +ACE_Active_Map_Manager_Key::slot_generation (void) const +{ + return this->key_data_.slot_generation_; +} + +ACE_INLINE bool +ACE_Active_Map_Manager_Key::operator== (const ACE_Active_Map_Manager_Key &rhs) const +{ + return + this->key_data_.slot_index_ == rhs.key_data_.slot_index_ && + this->key_data_.slot_generation_ == rhs.key_data_.slot_generation_; +} + +ACE_INLINE bool +ACE_Active_Map_Manager_Key::operator!= (const ACE_Active_Map_Manager_Key &rhs) const +{ + return !this->operator== (rhs); +} + +ACE_INLINE void +ACE_Active_Map_Manager_Key::slot_index (ACE_UINT32 i) +{ + this->key_data_.slot_index_ = i; +} + +ACE_INLINE void +ACE_Active_Map_Manager_Key::slot_generation (ACE_UINT32 g) +{ + this->key_data_.slot_generation_ = g; +} + +ACE_INLINE void +ACE_Active_Map_Manager_Key::increment_slot_generation_count (void) +{ + ++this->key_data_.slot_generation_; +} + +/* static */ +ACE_INLINE size_t +ACE_Active_Map_Manager_Key::size (void) +{ + return sizeof (ACE_UINT32) + sizeof (ACE_UINT32); +} + +ACE_INLINE void +ACE_Active_Map_Manager_Key::decode (const void *data) +{ + // Copy the information from the user buffer into the key. + ACE_OS::memcpy (&this->key_data_, + data, + sizeof this->key_data_); +} + +ACE_INLINE void +ACE_Active_Map_Manager_Key::encode (void *data) const +{ + // Copy the key data to the user buffer. + ACE_OS::memcpy (data, + &this->key_data_, + sizeof this->key_data_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Active_Map_Manager_T.cpp b/dep/acelite/ace/Active_Map_Manager_T.cpp new file mode 100644 index 000000000..6341ca711 --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager_T.cpp @@ -0,0 +1,20 @@ +#ifndef ACE_ACTIVE_MAP_MANAGER_T_CPP +#define ACE_ACTIVE_MAP_MANAGER_T_CPP + +#include "ace/Active_Map_Manager_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Active_Map_Manager_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Active_Map_Manager) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ACTIVE_MAP_MANAGER_T_CPP */ diff --git a/dep/acelite/ace/Active_Map_Manager_T.h b/dep/acelite/ace/Active_Map_Manager_T.h new file mode 100644 index 000000000..11c7da37a --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager_T.h @@ -0,0 +1,209 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Active_Map_Manager_T.h + * + * @author Irfan Pyarali + */ +//============================================================================= + + +#ifndef ACE_ACTIVE_MAP_MANAGER_T_H +#define ACE_ACTIVE_MAP_MANAGER_T_H +#include /**/ "ace/pre.h" + +#include "ace/Map_Manager.h" +#include "ace/Active_Map_Manager.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Null_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Active_Map_Manager + * + * @brief Define a map abstraction that associates system generated + * keys with user specified values. + * + * Since the key is system generated, searches are very fast and + * take a constant amount of time. + */ +template +class ACE_Active_Map_Manager : public ACE_Map_Manager +{ +public: + + // = Traits. + typedef ACE_Active_Map_Manager_Key key_type; + typedef T mapped_type; + + typedef ACE_Map_Entry ENTRY; + typedef ACE_Map_Iterator ITERATOR; + typedef ACE_Map_Reverse_Iterator REVERSE_ITERATOR; + + typedef ENTRY entry; + typedef ITERATOR iterator; + typedef REVERSE_ITERATOR reverse_iterator; + + // = Initialization and termination methods. + /// Initialize a Active_Map_Manager with the ACE_DEFAULT_MAP_SIZE. + ACE_Active_Map_Manager (ACE_Allocator *alloc = 0); + + /// Initialize a Active_Map_Manager with @a size entries. + ACE_Active_Map_Manager (size_t size, + ACE_Allocator *alloc = 0); + + /// Close down a Active_Map_Manager and release dynamically + /// allocated resources. + ~ACE_Active_Map_Manager (void); + + /// Initialize a Active_Map_Manager with size @a length. + int open (size_t length = ACE_DEFAULT_MAP_SIZE, + ACE_Allocator *alloc = 0); + + /// Close down a Active_Map_Manager and release dynamically + /// allocated resources. + int close (void); + + /// Add @a value to the map, and the corresponding key produced by the + /// Active_Map_Manager is returned through @a key. + int bind (const T &value, + ACE_Active_Map_Manager_Key &key); + + /// Add @a value to the map. The user does not care about the + /// corresponding key produced by the Active_Map_Manager. + int bind (const T &value); + + /** + * Reserves a slot in the internal structure and returns the key and + * a pointer to the value. User should place their @a value into + * @a internal_value. This method is useful in reducing the number + * of copies required in some cases. Note that @a internal_value is + * only a temporary pointer and will change when the map resizes. + * Therefore, the user should use the pointer immediately and not + * hold on to it. + */ + int bind (ACE_Active_Map_Manager_Key &key, + T *&internal_value); + + /// Reassociate @a key with @a value. The function fails if @a key is + /// not in the map. + int rebind (const ACE_Active_Map_Manager_Key &key, + const T &value); + + /** + * Reassociate @a key with @a value, storing the old value into the + * "out" parameter @a old_value. The function fails if @a key is not + * in the map. + */ + int rebind (const ACE_Active_Map_Manager_Key &key, + const T &value, + T &old_value); + + /** + * Reassociate @a key with @a value, storing the old key and value + * into the "out" parameter @a old_key and @a old_value. The function + * fails if @a key is not in the map. + */ + int rebind (const ACE_Active_Map_Manager_Key &key, + const T &value, + ACE_Active_Map_Manager_Key &old_key, + T &old_value); + + /// Locate @a value associated with @a key. + int find (const ACE_Active_Map_Manager_Key &key, + T &value) const; + + /// Is @a key in the map? + int find (const ACE_Active_Map_Manager_Key &key) const; + + /** + * Locate @a value associated with @a key. The value is returned via + * @a internal_value and hence a copy is saved. Note that + * @a internal_value is only a temporary pointer and will change when + * the map resizes. Therefore, the user should use the pointer + * immediately and not hold on to it. + */ + int find (const ACE_Active_Map_Manager_Key &key, + T *&internal_value) const; + + // Creates a key. User should place their @a value into + // <*internal_value>. This method is useful in reducing the number + // of copies required in some cases. + + /// Remove @a key from the map. + int unbind (const ACE_Active_Map_Manager_Key &key); + + /// Remove @a key from the map, and return the @a value associated with + /// @a key. + int unbind (const ACE_Active_Map_Manager_Key &key, + T &value); + + /** + * Locate @a value associated with @a key. The value is returned via + * @a internal_value and hence a copy is saved. Note that + * @a internal_value is only a temporary pointer and will change when + * the map resizes or when this slot is reused. Therefore, the user + * should use the pointer immediately and not hold on to it. + */ + int unbind (const ACE_Active_Map_Manager_Key &key, + T *&internal_value); + + /// Return the current size of the map. + size_t current_size (void) const; + + /// Return the total size of the map. + size_t total_size (void) const; + + /// Returns a key that cannot be found in the map. + static const ACE_Active_Map_Manager_Key npos (void); + + /// Dump the state of an object. + void dump (void) const; + + // = STL styled iterator factory functions. + + /// Return forward iterator. + ACE_Map_Iterator begin (void); + ACE_Map_Iterator end (void); + + /// Return reverse iterator. + ACE_Map_Reverse_Iterator rbegin (void); + ACE_Map_Reverse_Iterator rend (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// Private base class + typedef ACE_Map_Manager ACE_AMM_BASE; + +private: + + // = Disallow these operations. + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Active_Map_Manager &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Active_Map_Manager (const ACE_Active_Map_Manager &)) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Active_Map_Manager_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Active_Map_Manager_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Active_Map_Manager_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_ACTIVE_MAP_MANAGER_T_H */ diff --git a/dep/acelite/ace/Active_Map_Manager_T.inl b/dep/acelite/ace/Active_Map_Manager_T.inl new file mode 100644 index 000000000..c8a6caf9b --- /dev/null +++ b/dep/acelite/ace/Active_Map_Manager_T.inl @@ -0,0 +1,308 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE int +ACE_Active_Map_Manager::bind (ACE_Active_Map_Manager_Key &key, + T *&internal_value) +{ + ACE_UINT32 slot_index; + int result = this->next_free (slot_index); + + if (result == 0) + { + // Move from free list to occupied list + this->move_from_free_list_to_occupied_list (slot_index); + + // Reset the key. + this->search_structure_[slot_index].ext_id_.increment_slot_generation_count (); + this->search_structure_[slot_index].ext_id_.slot_index (slot_index); + + // Copy the key for the user. + key = this->search_structure_[slot_index].ext_id_; + + // This is where the user should place the value. + internal_value = &this->search_structure_[slot_index].int_id_; + + // Update the current size. + ++this->cur_size_; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::bind (const T &value, + ACE_Active_Map_Manager_Key &key) +{ + T *internal_value = 0; + int result = this->bind (key, + internal_value); + + if (result == 0) + { + // Store new value. + *internal_value = value; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::bind (const T &value) +{ + ACE_Active_Map_Manager_Key key; + return this->bind (value, key); +} + +template ACE_INLINE int +ACE_Active_Map_Manager::find (const ACE_Active_Map_Manager_Key &key, + T *&internal_value) const +{ + ACE_UINT32 slot_index = key.slot_index (); + ACE_UINT32 slot_generation = key.slot_generation (); + + if (slot_index > this->total_size_ || +#if defined (ACE_HAS_LAZY_MAP_MANAGER) + this->search_structure_[slot_index].free_ || +#endif /* ACE_HAS_LAZY_MAP_MANAGER */ + this->search_structure_[slot_index].ext_id_.slot_generation () != slot_generation || + this->search_structure_[slot_index].ext_id_.slot_index () == + (ACE_UINT32)this->free_list_id ()) + { + return -1; + } + else + { + // This is where the user value is. + internal_value = &this->search_structure_[slot_index].int_id_; + } + + return 0; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::find (const ACE_Active_Map_Manager_Key &key) const +{ + T *internal_value = 0; + return this->find (key, + internal_value); +} + +template ACE_INLINE int +ACE_Active_Map_Manager::find (const ACE_Active_Map_Manager_Key &key, + T &value) const +{ + T *internal_value = 0; + int result = this->find (key, + internal_value); + + if (result == 0) + value = *internal_value; + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::rebind (const ACE_Active_Map_Manager_Key &key, + const T &value) +{ + int result = this->find (key); + + if (result == 0) + { + // Store new value. + this->search_structure_[key.slot_index ()].int_id_ = value; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::rebind (const ACE_Active_Map_Manager_Key &key, + const T &value, + T &old_value) +{ + int result = this->find (key); + + if (result == 0) + { + // Copy old value. + old_value = this->search_structure_[key.slot_index ()].int_id_; + + // Store new value. + this->search_structure_[key.slot_index ()].int_id_ = value; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::rebind (const ACE_Active_Map_Manager_Key &key, + const T &value, + ACE_Active_Map_Manager_Key &old_key, + T &old_value) +{ + int result = this->find (key); + + if (result == 0) + { + // Copy old key. + old_key = this->search_structure_[key.slot_index ()].ext_id_; + + // Copy old value. + old_value = this->search_structure_[key.slot_index ()].int_id_; + + // Store new value. + this->search_structure_[key.slot_index ()].int_id_ = value; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::unbind (const ACE_Active_Map_Manager_Key &key, + T *&internal_value) +{ + int result = this->find (key, + internal_value); + + if (result == 0) + { + ACE_UINT32 slot_index = key.slot_index (); + +#if defined (ACE_HAS_LAZY_MAP_MANAGER) + + // + // In the case of lazy map managers, the movement of free slots + // from the occupied list to the free list is delayed until we + // run out of free slots in the free list. + // + + this->search_structure_[slot_index].free_ = 1; + +#else + + // Move from occupied list to free list. + this->move_from_occupied_list_to_free_list (slot_index); + +#endif /* ACE_HAS_LAZY_MAP_MANAGER */ + + // Reset the slot_index. This will tell us that this entry is free. + this->search_structure_[slot_index].ext_id_.slot_index (this->free_list_id ()); + + // Update the current size. + --this->cur_size_; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::unbind (const ACE_Active_Map_Manager_Key &key, + T &value) +{ + T *internal_value; + int result = this->unbind (key, + internal_value); + + if (result == 0) + { + // Copy old value. + value = *internal_value; + } + + return result; +} + +template ACE_INLINE int +ACE_Active_Map_Manager::unbind (const ACE_Active_Map_Manager_Key &key) +{ + T *internal_value; + return this->unbind (key, + internal_value); +} + +template ACE_INLINE +ACE_Active_Map_Manager::ACE_Active_Map_Manager (ACE_Allocator *alloc) + : ACE_AMM_BASE (alloc) +{ +} + +template ACE_INLINE +ACE_Active_Map_Manager::ACE_Active_Map_Manager (size_t size, + ACE_Allocator *alloc) + : ACE_AMM_BASE (size, + alloc) +{ +} + +template ACE_INLINE +ACE_Active_Map_Manager::~ACE_Active_Map_Manager (void) +{ +} + +template ACE_INLINE int +ACE_Active_Map_Manager::open (size_t length, + ACE_Allocator *alloc) +{ + return ACE_AMM_BASE::open (length, alloc); +} + +template ACE_INLINE int +ACE_Active_Map_Manager::close (void) +{ + return ACE_AMM_BASE::close (); +} + +template ACE_INLINE size_t +ACE_Active_Map_Manager::current_size (void) const +{ + return ACE_AMM_BASE::current_size (); +} + +template ACE_INLINE size_t +ACE_Active_Map_Manager::total_size (void) const +{ + return ACE_AMM_BASE::total_size (); +} + +/* static */ +template ACE_INLINE const ACE_Active_Map_Manager_Key +ACE_Active_Map_Manager::npos (void) +{ + return ACE_Active_Map_Manager_Key (~0, ~0); +} + +template ACE_INLINE void +ACE_Active_Map_Manager::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_AMM_BASE::dump (); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_Map_Iterator +ACE_Active_Map_Manager::begin (void) +{ + return ACE_AMM_BASE::begin (); +} + +template ACE_INLINE ACE_Map_Iterator +ACE_Active_Map_Manager::end (void) +{ + return ACE_AMM_BASE::end (); +} + +template ACE_INLINE ACE_Map_Reverse_Iterator +ACE_Active_Map_Manager::rbegin (void) +{ + return ACE_AMM_BASE::rbegin (); +} + +template ACE_INLINE ACE_Map_Reverse_Iterator +ACE_Active_Map_Manager::rend (void) +{ + return ACE_AMM_BASE::rend (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Addr.cpp b/dep/acelite/ace/Addr.cpp new file mode 100644 index 000000000..85f3523cf --- /dev/null +++ b/dep/acelite/ace/Addr.cpp @@ -0,0 +1,68 @@ +#include "ace/Addr.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Addr.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/os_include/sys/os_socket.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Note: this object requires static construction and destruction. +/* static */ +const ACE_Addr ACE_Addr::sap_any (AF_ANY, -1); + +ACE_ALLOC_HOOK_DEFINE(ACE_Addr) + + +// Initializes instance variables. Note that 0 is an unspecified +// protocol family type... + +ACE_Addr::ACE_Addr (int type, int size) : + addr_type_ (type), + addr_size_ (size) +{ +} + +ACE_Addr::~ACE_Addr (void) +{ +} + +void * +ACE_Addr::get_addr (void) const +{ + return 0; +} + +void +ACE_Addr::set_addr (const void *, int) +{ +} + +// Initializes instance variables. + +void +ACE_Addr::base_set (int type, int size) +{ + this->addr_type_ = type; + this->addr_size_ = size; +} + +void +ACE_Addr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Addr::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("addr_type_ = %d"), this->addr_type_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\naddr_size_ = %d"), this->addr_size_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Addr.h b/dep/acelite/ace/Addr.h new file mode 100644 index 000000000..82c2d8335 --- /dev/null +++ b/dep/acelite/ace/Addr.h @@ -0,0 +1,101 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Addr.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ADDR_H +#define ACE_ADDR_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Addr + * + * @brief Defines the base class for the "address family independent" + * address format. + */ +class ACE_Export ACE_Addr +{ +public: + // = Initialization and termination methods. + /// Initializes instance variables. + ACE_Addr (int type = -1, int size = -1); + + /// Destructor. + virtual ~ACE_Addr (void); + + // = Get/set the size of the address. + + /// Return the size of the address. + int get_size (void) const; + + /// Sets the size of the address. + void set_size (int size); + + // = Get/set the type of the address. + + /// Get the type of the address. + int get_type (void) const; + + /// Set the type of the address. + void set_type (int type); + + /// Return a pointer to the address. + virtual void *get_addr (void) const; + + /// Set a pointer to the address. + virtual void set_addr (const void *, int len); + + // = Equality/inequality tests + /// Check for address equality. + bool operator == (const ACE_Addr &sap) const; + + /// Check for address inequality. + bool operator != (const ACE_Addr &sap) const; + + /// Initializes instance variables. + void base_set (int type, int size); + + /// Wild-card address. + static const ACE_Addr sap_any; + + /// Returns a hash value. This should be overwritten by a subclass + /// that can produce a better hash value. + virtual unsigned long hash (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// e.g., AF_UNIX, AF_INET, AF_SPIPE, etc. + int addr_type_; + + /// Number of bytes in the address. + int addr_size_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Addr.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ADDR_H */ diff --git a/dep/acelite/ace/Addr.inl b/dep/acelite/ace/Addr.inl new file mode 100644 index 000000000..ad6f03e21 --- /dev/null +++ b/dep/acelite/ace/Addr.inl @@ -0,0 +1,54 @@ +// -*- C++ -*- +// Return the address of the address. + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE bool +ACE_Addr::operator == (const ACE_Addr &sap) const +{ + return (sap.addr_type_ == this->addr_type_ && + sap.addr_size_ == this->addr_size_ ); +} + +ACE_INLINE bool +ACE_Addr::operator != (const ACE_Addr &sap) const +{ + return (sap.addr_type_ != this->addr_type_ || + sap.addr_size_ != this->addr_size_ ); +} + +/// Return the size of the address. +ACE_INLINE int +ACE_Addr::get_size (void) const +{ + return this->addr_size_; +} + +/// Sets the size of the address. +ACE_INLINE void +ACE_Addr::set_size (int size) +{ + this->addr_size_ = size; +} + +/// Return the type of the address. +ACE_INLINE int +ACE_Addr::get_type (void) const +{ + return this->addr_type_; +} + +/// Set the type of the address. +ACE_INLINE void +ACE_Addr::set_type (int type) +{ + this->addr_type_ = type; +} + +ACE_INLINE unsigned long +ACE_Addr::hash (void) const +{ + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Arg_Shifter.cpp b/dep/acelite/ace/Arg_Shifter.cpp new file mode 100644 index 000000000..29eace272 --- /dev/null +++ b/dep/acelite/ace/Arg_Shifter.cpp @@ -0,0 +1,223 @@ +#ifndef ACE_ARG_SHIFTER_T_CPP +#define ACE_ARG_SHIFTER_T_CPP + +#include "ace/Arg_Shifter.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_strings.h" +#include "ace/OS_Errno.h" +#include "ace/OS_Memory.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Arg_Shifter_T::ACE_Arg_Shifter_T (int& argc, + const CHAR_TYPE** argv, + const CHAR_TYPE** temp) + : argc_ (argc), + total_size_ (argc), + temp_ (temp), + argv_ (argv), + current_index_ (0), + back_ (argc - 1), + front_ (0) +{ + this->init (); +} + +template +ACE_Arg_Shifter_T::ACE_Arg_Shifter_T (int& argc, + CHAR_TYPE** argv, + CHAR_TYPE** temp) + : argc_ (argc), + total_size_ (argc), + temp_ ((const CHAR_TYPE **) temp), + argv_ ((const CHAR_TYPE **) argv), + current_index_ (0), + back_ (argc - 1), + front_ (0) +{ + this->init (); +} + +template +void +ACE_Arg_Shifter_T::init (void) +{ + // If not provided with one, allocate a temporary array. + if (this->temp_ == 0) +#if defined (ACE_HAS_ALLOC_HOOKS) + this->temp_ = reinterpret_cast + (ACE_Allocator::instance ()->malloc (sizeof (CHAR_TYPE*) * this->total_size_)); +#else + ACE_NEW (this->temp_, + const CHAR_TYPE *[this->total_size_]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + if (this->temp_ != 0) + { + // Fill the temporary array. + this->argc_ = 0; + for (int i = 0; i < this->total_size_; i++) + { + this->temp_[i] = this->argv_[i]; + this->argv_[i] = 0; + } + } + else + { + // Allocation failed, prohibit iteration. + this->current_index_ = this->argc_; + this->front_ = this->argc_; + } +} + +template +ACE_Arg_Shifter_T::~ACE_Arg_Shifter_T (void) +{ + // Delete the temporary vector. +#if defined (ACE_HAS_ALLOC_HOOKS) + if (this->temp_) + ACE_Allocator::instance ()->free (this->temp_); +#else + delete [] temp_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +template +const CHAR_TYPE * +ACE_Arg_Shifter_T::get_current (void) const +{ + const CHAR_TYPE * retval = 0; + + if (this->is_anything_left ()) + retval = this->temp_[current_index_]; + + return retval; +} + +template +const CHAR_TYPE * +ACE_Arg_Shifter_T::get_the_parameter (const CHAR_TYPE *flag) +{ + // the return 0's abound because this method + // would otherwise be a deep if { } else { } + + // check to see if any arguments still exist + if (!this->is_anything_left()) + return 0; + + // check to see if the flag is the argument + int const offset = this->cur_arg_strncasecmp (flag); + if (offset == -1) + return 0; + + if (offset == 0) + { + this->consume_arg (); + + if (!this->is_parameter_next()) + { + return 0; + } + } + // the parameter is in the middle somewhere... + return this->temp_[current_index_] + offset; +} + +template +int +ACE_Arg_Shifter_T::cur_arg_strncasecmp (const CHAR_TYPE *flag) +{ + if (!this->is_anything_left ()) + return -1; + + const size_t flag_length = ACE_OS::strlen (flag); + const CHAR_TYPE *arg = this->temp_[this->current_index_]; + + if (ACE_OS::strncasecmp (arg, flag, flag_length) != 0) + return -1; + + const size_t arg_length = ACE_OS::strlen (arg); + size_t remaining = flag_length; + while (remaining < arg_length && arg[remaining] == CHAR_TYPE (' ')) + ++remaining; + return (arg_length == flag_length) ? 0 : static_cast (remaining); +} + +template +int +ACE_Arg_Shifter_T::consume_arg (int number) +{ + int retval = 0; + + // Stick knowns at the end of the vector (consumed). + if (this->is_anything_left() >= number) + { + for (int i = 0, j = this->back_ - (number - 1); + i < number; + ++i, ++j, ++this->current_index_) + this->argv_[j] = this->temp_[this->current_index_]; + + this->back_ -= number; + retval = 1; + } + + return retval; +} + +template +int +ACE_Arg_Shifter_T::ignore_arg (int number) +{ + int retval = 0; + + // Keep unknowns at the head of the vector. + if (this->is_anything_left () >= number) + { + for (int i = 0; + i < number; + i++, this->current_index_++, this->front_++) + this->argv_[this->front_] = this->temp_[this->current_index_]; + + retval = 1; + this->argc_ += number; + } + + return retval; +} + +template +int +ACE_Arg_Shifter_T::is_anything_left (void) const +{ + return this->total_size_ - this->current_index_; +} + +template +int +ACE_Arg_Shifter_T::is_option_next (void) const +{ + return this->is_anything_left () && + this->temp_[this->current_index_][0] == '-'; +} + +template +int +ACE_Arg_Shifter_T::is_parameter_next (void) const +{ + return this->is_anything_left () + && this->temp_[this->current_index_][0] != '-'; +} + +template +int +ACE_Arg_Shifter_T::num_ignored_args (void) const +{ + return this->front_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ATOMIC_OP_T_CPP */ diff --git a/dep/acelite/ace/Arg_Shifter.h b/dep/acelite/ace/Arg_Shifter.h new file mode 100644 index 000000000..1ed6f1367 --- /dev/null +++ b/dep/acelite/ace/Arg_Shifter.h @@ -0,0 +1,240 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Arg_Shifter.h + * + * @author Seth Widoff + */ +//============================================================================= + +#ifndef ACE_ARG_SHIFTER_H +#define ACE_ARG_SHIFTER_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Arg_Shifter_T + * + * @brief This ADT operates on a specified set of arguments (@a argv). + * As known arguments are scanned, they are shifted to the back of the + * @a argv vector, so deeper levels of argument parsing can locate the yet + * unprocessed arguments at the beginning of the vector. + * + * Nomenclature: + * argument - a member of the argv array + * option - an argument starting with '-' + * flag - synonym for "option" + * parameter value - an argument not starting with '-' + * parameter - synonym for "parameter value" + * + * The @c ACE_Arg_Shifter copies the pointers of the @a argv vector + * into a temporary array, emptying the original. As the @c ACE_Arg_Shifter + * iterates over the temporary array, it places known arguments in the rear + * of the original array and places the unknown ones in the beginning of the + * original array. It modifies argc to be the number of unknown arguments, + * so it looks to the caller as if the original array contains only unknown + * arguments. So, after @c ACE_Arg_Shifter has visited all the arguments + * in the temporary array, the original @a argv array appears to contain + * only the unknown arguments in their original order (but it actually has + * all the known arguments, too, beyond argc). + */ +template +class ACE_Arg_Shifter_T +{ +public: + // = Initialization and termination methods. + /** + * Initialize the ACE_Arg_Shifter to the vector over which to + * iterate. Optionally, also provide the temporary array for + * use in shifting the arguments. If ACE_Arg_Shifter must allocate + * the temporary vector internally and dynamic allocation fails, the + * ACE_Arg_Shifter will set all indicators to end of the vector, + * forbidding iteration. Following iteration over @a argv, the + * @a argc value will be updated to contain the number of + * unconsumed arguments. + * @param argc The number of strings in @a argv. @a argc will be + * updated to reflect the number of unconsumed arguments. + * @param argv The argument vector to shift. The string pointers in + * the vector will be reordered to place the @a argc unconsumed + * arguments at the front of the vector. + * @param temp A vector of @c CHAR_TYPE pointers at least @a argc + * elements long. The vector will be used for argument shifting as + * the specified @a argv vector is consumed. The vector must not + * be modified while this object exists. If this argument is 0 + * (the default) the object will allocate and free the temporary + * vector transparently. + */ + ACE_Arg_Shifter_T (int &argc, + const CHAR_TYPE **argv, + const CHAR_TYPE **temp = 0); + + /// Same behavior as the preceding constructor, but without the + /// "const" qualifier. + ACE_Arg_Shifter_T (int &argc, + CHAR_TYPE **argv, + CHAR_TYPE **temp = 0); + + /// Destructor. + ~ACE_Arg_Shifter_T (void); + + /// Get the current head of the vector. + const CHAR_TYPE *get_current (void) const; + + /** + * If the @a flag matches the current_arg of arg shifter + * this method will attempt to return the associated + * parameter value + * + * Safe to call without checking that a current arg exists + * + * In the following examples, a pointer to the char* "value" is returned + * + * eg: main -foobar value, main -FooBar value + * main -FOOBARvalue + * + * all of the above will match the @a flag == -FooBar + * and will return a char* to "value" + * + * main -foobar 4 would succeed and return a char* to "4" + * main -foobar -4 does not succeed (-4 is not a parameter) + * but instead, would return 0 + * + * 0 is returned: + * If the current argument does not match flag + * If there is no parameter found after a 'matched' flag + * + * If the flag is matched and the flag and parameter DO NOT RUN + * together, the flag is consumed, the parameter is returned, + * and the new current argument is the parameter value. + * ie '-foobarflag VALUE' leaves the new cur arg == "VALUE" + * + * If the flag is matched and the flag and parameter RUN + * together '-foobarflagVALUE', the flag is NOT consumed + * and the cur arg is left pointing to the entire flag/value pair + */ + const CHAR_TYPE *get_the_parameter (const CHAR_TYPE *flag); + + /** + * Check if the current argument matches (case insensitive) @a flag + * + * ------------------------------------------------------------ + * + * Case A: Perfect Match (case insensitive) + * 0 is returned. + * + * ie: when current_arg = "-foobar" or "-FOOBAR" or "-fooBAR" + * this->cur_arg_strncasecmp ("-FooBar"); + * will return 0 + * + * ------------------------------------------------------------ + * + * Case B: Perfect Match (case insensitive) but the current_arg + * is longer than the flag. Returns a number equal to the index + * in the char* indicating the start of the extra characters + * after any initial spaces (see below). + * + * ie: when current_arg = "-foobar98023" + * this->cur_arg_strncasecmp ("-FooBar"); + * will return 7 + * + * Spaces separating the flag from its value (that are still part + * of the same argv element) are counted as part of the return value + * + * ie: when current_arg = "-foobar 98023" + * this->cur_arg_strncasecmp ("-FooBar"); + * will return 8 + * + * Notice: this number will always be > 0 + * + * ------------------------------------------------------------ + * + * Case C: If neither of Case A or B is met (no match) + * then -1 is returned + */ + int cur_arg_strncasecmp (const CHAR_TYPE *flag); + + /// Consume @a number argument(s) by sticking them/it on the end of + /// the vector. + int consume_arg (int number = 1); + + /// Place @a number arguments in the same relative order ahead of the + /// known arguments in the vector. + int ignore_arg (int number = 1); + + /// Returns the number of args left to see in the vector. + int is_anything_left (void) const; + + /// Returns 1 if there's a next item in the vector and it begins with + /// '-'. + int is_option_next (void) const; + + /// Returns 1 if there's a next item in the vector and it doesn't + /// begin with '-'. + int is_parameter_next (void) const; + + /// Returns the number of irrelevant args seen. + int num_ignored_args (void) const; + +private: + /// Copy Constructor should not be used. + ACE_UNIMPLEMENTED_FUNC (ACE_Arg_Shifter_T (const ACE_Arg_Shifter_T &)) + + /// Assignment '=' operator should not be used. + ACE_UNIMPLEMENTED_FUNC (ACE_Arg_Shifter_T operator= (const ACE_Arg_Shifter_T &)) + + /// Refactor the constructor logic. + void init (void); + + /// The size of the argument vector. + int &argc_; + + /// The size of argv_. + int total_size_; + + /// The temporary array over which we traverse. + const CHAR_TYPE **temp_; + + /// The array in which the arguments are reordered. + const CHAR_TYPE **argv_; + + /// The element in we're currently examining. + int current_index_; + + /// The index of in which we'll stick the next unknown + /// argument. + int back_; + + /// The index of in which we'll stick the next known + /// argument. + /** This is not really the "front" at all. It's the point after + * which the unknown arguments end and at which the known arguments begin. + */ + int front_; +}; + +typedef ACE_Arg_Shifter_T ACE_Arg_Shifter; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Arg_Shifter.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Arg_Shifter.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ARG_SHIFTER_H */ diff --git a/dep/acelite/ace/Argv_Type_Converter.cpp b/dep/acelite/ace/Argv_Type_Converter.cpp new file mode 100644 index 000000000..4c8e4fbb9 --- /dev/null +++ b/dep/acelite/ace/Argv_Type_Converter.cpp @@ -0,0 +1,190 @@ +#include "ace/Argv_Type_Converter.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Argv_Type_Converter.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_string.h" +#include "ace/OS_Errno.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_USES_WCHAR) +ACE_Argv_Type_Converter::ACE_Argv_Type_Converter (int &argc, wchar_t** argv) + : saved_argc_ (argc), + char_argv_ (0), + wchar_argv_ (argv), + before_pass_argc_ (argc), + original_type_ (true), + wchar_passed_ (false), + char_passed_ (false) +{ + this->initialize (); + + for (int i = 0; i < argc; ++i) + this->char_argv_[i] = ACE_OS::strdup (ACE_TEXT_ALWAYS_CHAR (argv[i])); +} +#endif // ACE_USES_WCHAR + + +ACE_Argv_Type_Converter::ACE_Argv_Type_Converter (int &argc, char **argv) + : saved_argc_(argc), + char_argv_(argv) +#if defined (ACE_USES_WCHAR) + , wchar_argv_(0), + before_pass_argc_(argc), + original_type_(false), + wchar_passed_(false), + char_passed_(false) +{ + this->initialize(); + + for (int i = 0; i < argc; ++i) + this->wchar_argv_[i] = ACE_OS::strdup (ACE_TEXT_ANTI_TO_TCHAR (argv[i])); +} +#else +{ +} +#endif // ACE_USES_WCHAR + +ACE_Argv_Type_Converter::~ACE_Argv_Type_Converter (void) +{ +#if defined (ACE_USES_WCHAR) + // selectively delete the 'copy' of argv + if (this->original_type_) + { + // if original type is wchar_t + if (this->char_passed_) + this->align_wchar_with_char (); + + for (int i = 0; i < this->before_pass_argc_; ++i) + ACE_OS::free (this->char_argv_[i]); + + delete [] this->char_argv_; + } + else + { + // if original type is char + if (this->wchar_passed_) + this->align_char_with_wchar (); + + for (int i = 0; i < this->before_pass_argc_; ++i) + ACE_OS::free (this->wchar_argv_[i]); + + delete [] this->wchar_argv_; + } +#endif // ACE_USES_WCHAR +} + +#if defined (ACE_USES_WCHAR) +void +ACE_Argv_Type_Converter::initialize (void) +{ + if (this->original_type_) + { + // Make a copy of argv in 'char'. type Create one more argv entry + // than original argc for the NULL. + ACE_NEW (char_argv_, + char *[this->saved_argc_ + 1]); + this->char_argv_[saved_argc_] = 0; // last entry of argv is + // always a NULL + } + else + { + // make a copy of argv in 'wchar_t' type + ACE_NEW (this->wchar_argv_, + wchar_t*[this->saved_argc_ + 1]); + this->wchar_argv_[saved_argc_] = 0; + } +} + + +void +ACE_Argv_Type_Converter::align_char_with_wchar (void) +{ + for (int wchar_argv_index = 0; wchar_argv_index < this->saved_argc_; + ++wchar_argv_index) + { + wchar_t *match_argv = this->wchar_argv_[wchar_argv_index]; + // if n'th entries of both argv lists are different + if (ACE_OS::strcmp (this->char_argv_[wchar_argv_index], + ACE_TEXT_ALWAYS_CHAR (match_argv)) != 0) + { + // loop through the wchar argv list entries that are after + // wchar_argv_index + for (int i = wchar_argv_index + 1; i < before_pass_argc_; ++i) + { + if (ACE_OS::strcmp (this->char_argv_[i], + ACE_TEXT_ALWAYS_CHAR (match_argv)) == 0) + { + // swap the pointers in the char argv list + char *temp = this->char_argv_[wchar_argv_index]; + this->char_argv_[wchar_argv_index] = this->char_argv_[i]; + this->char_argv_[i] = temp; + break; + } + } + } + } + + this->cleanup (); +} + +void +ACE_Argv_Type_Converter::align_wchar_with_char (void) +{ + for (int char_argv_index = 0; char_argv_index < saved_argc_; + ++char_argv_index) + { + char* match_argv = this->char_argv_[char_argv_index]; + // if n'th entries of both argv lists are different + if (ACE_OS::strcmp ( + ACE_TEXT_ALWAYS_CHAR (this->wchar_argv_[char_argv_index]), + match_argv) != 0) + { + // loop through the wchar argv list entries that are after + // wchar_argv_index + for (int i = char_argv_index + 1; i < this->before_pass_argc_; ++i) + { + if (ACE_OS::strcmp ( + ACE_TEXT_ALWAYS_CHAR(this->wchar_argv_[i]), + match_argv) == 0) { + // swap the pointers in the char argv list + wchar_t* temp = this->wchar_argv_[char_argv_index]; + this->wchar_argv_[char_argv_index] = this->wchar_argv_[i]; + this->wchar_argv_[i] = temp; + break; + } + } + } + } + + this->cleanup(); +} + +void +ACE_Argv_Type_Converter::cleanup (void) +{ + for (int i = this->saved_argc_; i < this->before_pass_argc_; ++i) + { + // Check whether it's ours to delete. + if (original_type_) + { + ACE_OS::free (this->char_argv_[i]); + this->char_argv_[i] = 0; + } + else + { + ACE_OS::free (this->wchar_argv_[i]); + this->wchar_argv_[i] = 0; + } + } + + this->before_pass_argc_ = this->saved_argc_; + + this->wchar_passed_ = false; + this->char_passed_ = false; +} +#endif // ACE_USES_WCHAR + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Argv_Type_Converter.h b/dep/acelite/ace/Argv_Type_Converter.h new file mode 100644 index 000000000..9734a1de0 --- /dev/null +++ b/dep/acelite/ace/Argv_Type_Converter.h @@ -0,0 +1,117 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Argv_Type_Converter.h + * + * @author Si Mong Park + */ +//============================================================================= + +#ifndef ACE_ARGV_TYPE_CONVERTER_H +#define ACE_ARGV_TYPE_CONVERTER_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" +#include "ace/OS_Memory.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Argv_Type_Converter + * + * @brief To convert 'char' input/command line parameter to 'wchar_t'. + * + * This class is to convert 'char' type command line parameter to + * wide-character (wchar_t) format and stores the copy of it. + * This is useful for all classes that use 'char**' argv but cannot + * be converted into 'ACE_TCHAR**' version. + * Note that the converted data will be lost upon destruction, so + * classes should use this class as their data member. + */ +class ACE_Export ACE_Argv_Type_Converter +{ +public: + + ACE_Argv_Type_Converter (int &argc, char** argv); + +#if defined (ACE_USES_WCHAR) + ACE_Argv_Type_Converter (int &argc, wchar_t** argv); +#endif // ACE_USES_WCHAR + + ~ACE_Argv_Type_Converter (void); + + /// Returns the pointer of converted command line. + ACE_TCHAR** get_TCHAR_argv (void); + + /// Returns the pointer of ASCII (char) command line. + char** get_ASCII_argv (void); + + /// Returns the number of sub parameters (argc). + int& get_argc (void); + +private: + + /// Copy Constructor should not be used. + ACE_Argv_Type_Converter (const ACE_Argv_Type_Converter&); + + /// Assignment '=' operator should not be used. + ACE_Argv_Type_Converter operator= (const ACE_Argv_Type_Converter&); + +#if defined (ACE_USES_WCHAR) + + /// Perform common initialization for two Ctor's. + void initialize (void); + + /// Align all entries in the char type argv list with wchar_t type + /// argv list. + void align_char_with_wchar (void); + + /// Align all entries in the wchar_t type argv list with char type + /// argv list. + void align_wchar_with_char (void); + + /// Clean up removed (consumed) argv entries and reset the pass flags. + void cleanup (void); +#endif // ACE_USES_WCHAR + +private: + /// Original number of input parameter, same as 'argc'. + int &saved_argc_; + + /// Data member pointer that contains converted argv in ACE_ANTI_TCHAR. + char** char_argv_; + +#if defined (ACE_USES_WCHAR) + /// Data member pointer that contains converted argv in ACE_TCHAR. + wchar_t** wchar_argv_; + + /// argc value before any argv has been passed. + int before_pass_argc_; + + /// false represents original argv passed in is char, and true + /// represents wchar_t. + bool const original_type_; + + /// true indicates wchar_t type argv has been passed. + bool wchar_passed_; + + /// true indicates char type argv has been passed. + bool char_passed_; +#endif /* ACE_USES_WCHAR */ +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Argv_Type_Converter.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ARGV_TYPE_CONVERTER_H */ diff --git a/dep/acelite/ace/Argv_Type_Converter.inl b/dep/acelite/ace/Argv_Type_Converter.inl new file mode 100644 index 000000000..8c7bc89ca --- /dev/null +++ b/dep/acelite/ace/Argv_Type_Converter.inl @@ -0,0 +1,41 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ACE_TCHAR** +ACE_Argv_Type_Converter::get_TCHAR_argv (void) +{ +#if defined (ACE_USES_WCHAR) + if (this->char_passed_) + { + this->align_wchar_with_char (); + } + + this->wchar_passed_ = true; + return this->wchar_argv_; +#else + return this->char_argv_; +#endif // ACE_USES_WCHAR +} + +ACE_INLINE char** +ACE_Argv_Type_Converter::get_ASCII_argv (void) +{ +#if defined (ACE_USES_WCHAR) + if (this->wchar_passed_) + { + this->align_char_with_wchar (); + } + + this->char_passed_ = true; +#endif // ACE_USES_WCHAR + + return this->char_argv_; +} + +ACE_INLINE int& +ACE_Argv_Type_Converter::get_argc (void) +{ + return this->saved_argc_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Array_Base.cpp b/dep/acelite/ace/Array_Base.cpp new file mode 100644 index 000000000..830634f7b --- /dev/null +++ b/dep/acelite/ace/Array_Base.cpp @@ -0,0 +1,233 @@ +#ifndef ACE_ARRAY_BASE_CPP +#define ACE_ARRAY_BASE_CPP + +#include "ace/Array_Base.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Array_Base.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Malloc_Base.h" +#include "ace/os_include/os_errno.h" + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Dynamically initialize an array. +template +ACE_Array_Base::ACE_Array_Base (typename ACE_Array_Base::size_type size, + ACE_Allocator *alloc) + : max_size_ (size), + cur_size_ (size), + allocator_ (alloc) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + if (size != 0) + { + ACE_ALLOCATOR (this->array_, + (T *) this->allocator_->malloc (size * sizeof (T))); + for (size_type i = 0; i < size; ++i) + new (&array_[i]) T; + } + else + this->array_ = 0; +} + +template +ACE_Array_Base::ACE_Array_Base (typename ACE_Array_Base::size_type size, + const T &default_value, + ACE_Allocator *alloc) + : max_size_ (size), + cur_size_ (size), + allocator_ (alloc) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + if (size != 0) + { + ACE_ALLOCATOR (this->array_, + (T *) this->allocator_->malloc (size * sizeof (T))); + for (size_type i = 0; i < size; ++i) + new (&array_[i]) T (default_value); + } + else + this->array_ = 0; +} + +// The copy constructor (performs initialization). + +template +ACE_Array_Base::ACE_Array_Base (const ACE_Array_Base &s) + : max_size_ (s.size ()), + cur_size_ (s.size ()), + allocator_ (s.allocator_) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + ACE_ALLOCATOR (this->array_, + (T *) this->allocator_->malloc (s.size () * sizeof (T))); + for (size_type i = 0; i < this->size (); ++i) + new (&this->array_[i]) T (s.array_[i]); +} + +// Assignment operator (performs assignment). + +template void +ACE_Array_Base::operator= (const ACE_Array_Base &s) +{ + // Check for "self-assignment". + + if (this != &s) + { + if (this->max_size_ < s.size ()) + { + // Need to reallocate memory. + + // Strongly exception-safe assignment. + // + // Note that we're swapping the allocators here, too. + // Should we? Probably. "*this" should be a duplicate of + // the "right hand side". + ACE_Array_Base tmp (s); + this->swap (tmp); + } + else + { + // Underlying array is large enough. No need to reallocate + // memory. + // + // "*this" still owns the memory for the underlying array. + // Do not swap out the allocator. + // + // @@ Why don't we just drop the explicit destructor and + // placement operator new() calls with a straight + // element-by-element assignment? Is the existing + // approach more efficient? + // -Ossama + + ACE_DES_ARRAY_NOFREE (this->array_, + s.size (), + T); + + this->cur_size_ = s.size (); + + for (size_type i = 0; i < this->size (); ++i) + new (&this->array_[i]) T (s.array_[i]); + } + } +} + +// Set an item in the array at location slot. + +template int +ACE_Array_Base::set (const T &new_item, + typename ACE_Array_Base::size_type slot) +{ + if (this->in_range (slot)) + { + this->array_[slot] = new_item; + return 0; + } + else + return -1; +} + +// Get an item in the array at location slot. + +template int +ACE_Array_Base::get (T &item, + typename ACE_Array_Base::size_type slot) const +{ + if (this->in_range (slot)) + { + // Copies the item. If you don't want to copy, use operator [] + // instead (but then you'll be responsible for range checking). + item = this->array_[slot]; + return 0; + } + else + return -1; +} + +template int +ACE_Array_Base::max_size (typename ACE_Array_Base::size_type new_size) +{ + if (new_size > this->max_size_) + { + T *tmp = 0; + + ACE_ALLOCATOR_RETURN (tmp, + (T *) this->allocator_->malloc (new_size * sizeof (T)), + -1); + for (size_type i = 0; i < this->cur_size_; ++i) + new (&tmp[i]) T (this->array_[i]); + + // Initialize the new portion of the array that exceeds the + // previously allocated section. + for (size_type j = this->cur_size_; j < new_size; ++j) + new (&tmp[j]) T; + + ACE_DES_ARRAY_FREE (this->array_, + this->max_size_, + this->allocator_->free, + T); + this->array_ = tmp; + this->max_size_ = new_size; + this->cur_size_ = new_size; + } + + return 0; +} + +template int +ACE_Array_Base::size (typename ACE_Array_Base::size_type new_size) +{ + int const r = this->max_size (new_size); + + if (r == 0) + this->cur_size_ = new_size; + + return r; +} + +template +void +ACE_Array_Base::swap (ACE_Array_Base & rhs) +{ + std::swap (this->max_size_ , rhs.max_size_); + std::swap (this->cur_size_ , rhs.cur_size_); + std::swap (this->array_ , rhs.array_); + std::swap (this->allocator_, rhs.allocator_); +} + +// **************************************************************** + +template int +ACE_Array_Iterator::next (T *&item) +{ + // ACE_TRACE ("ACE_Array_Iterator::next"); + + if (this->done ()) + { + item = 0; + return 0; + } + else + { + item = &array_[current_]; + return 1; + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ARRAY_BASE_CPP */ diff --git a/dep/acelite/ace/Array_Base.h b/dep/acelite/ace/Array_Base.h new file mode 100644 index 000000000..ceb6a7edc --- /dev/null +++ b/dep/acelite/ace/Array_Base.h @@ -0,0 +1,254 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Array_Base.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ARRAY_BASE_H +#define ACE_ARRAY_BASE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/Malloc_Base.h" +#include /* For reverse_iterator adapters */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declaration. +template class ACE_Array_Iterator; + +/** + * @class ACE_Array_Base + * + * @brief Implement a simple dynamic array + * + * This parametric class implements a simple dynamic array; + * resizing must be controlled by the user. No comparison or find + * operations are implemented. + */ +template +class ACE_Array_Base +{ +public: + + // Old/ACE-style traits. + typedef T TYPE; + typedef ACE_Array_Iterator ITERATOR; + + // STL-style typedefs/traits. + typedef T value_type; + typedef value_type * iterator; + typedef value_type const * const_iterator; + typedef value_type & reference; + typedef value_type const & const_reference; + typedef value_type * pointer; + typedef value_type const * const_pointer; + typedef ptrdiff_t difference_type; + typedef ACE_Allocator::size_type size_type; + + ACE_DECLARE_STL_REVERSE_ITERATORS + + // = Initialization and termination methods. + + /// Dynamically create an uninitialized array. + ACE_Array_Base (size_type size = 0, + ACE_Allocator * the_allocator = 0); + + /// Dynamically initialize the entire array to the @a default_value. + ACE_Array_Base (size_type size, + T const & default_value, + ACE_Allocator * the_allocator = 0); + + /** + * The copy constructor performs initialization by making an exact + * copy of the contents of parameter @a s, i.e., *this == s will + * return true. + */ + ACE_Array_Base (ACE_Array_Base const & s); + + /** + * Assignment operator performs an assignment by making an exact + * copy of the contents of parameter @a s, i.e., *this == s will + * return true. Note that if the of is >= than + * we can copy it without reallocating. However, if + * is < we must delete the , + * reallocate a new , and then copy the contents of . + */ + void operator= (ACE_Array_Base const & s); + + /// Clean up the array (e.g., delete dynamically allocated memory). + ~ACE_Array_Base (void); + + // = Set/get methods. + + /// Set item in the array at location @a slot. Doesn't + /// perform range checking. + T & operator[] (size_type slot); + + /// Get item in the array at location @a slot. Doesn't + /// perform range checking. + T const & operator[] (size_type slot) const; + + /// Set an item in the array at location @a slot. Returns + /// -1 if @a slot is not in range, else returns 0. + int set (T const & new_item, size_type slot); + + /** + * Get an item in the array at location @a slot. Returns -1 if + * @a slot is not in range, else returns 0. Note that this function + * copies the item. If you want to avoid the copy, you can use + * the const operator [], but then you'll be responsible for range checking. + */ + int get (T & item, size_type slot) const; + + /// Returns the of the array. + size_type size (void) const; + + /** + * Changes the size of the array to match @a new_size. + * It copies the old contents into the new array. + * Return -1 on failure. + */ + int size (size_type new_size); + + /// Returns the of the array. + size_type max_size (void) const; + + /** + * Changes the size of the array to match @a new_size. + * It copies the old contents into the new array. + * Return -1 on failure. + * It does not affect new_size + */ + int max_size (size_type new_size); + + /** + * @name Forward Iterator Accessors + * + * Forward iterator accessors. + */ + //@{ + iterator begin (void); + iterator end (void); + const_iterator begin (void) const; + const_iterator end (void) const; + //@} + + /** + * @name Reverse Iterator Accessors + * + * Reverse iterator accessors. + */ + //@{ + reverse_iterator rbegin (void); + reverse_iterator rend (void); + const_reverse_iterator rbegin (void) const; + const_reverse_iterator rend (void) const; + //@} + + /// Swap the contents of this array with the given @a array in + /// an exception-safe manner. + void swap (ACE_Array_Base & array); + +protected: + + /// Returns 1 if @a slot is within range, i.e., 0 >= @a slot < + /// @c cur_size_, else returns 0. + bool in_range (size_type slot) const; + + /// Maximum size of the array, i.e., the total number of @c T elements + /// in @c array_. + size_type max_size_; + + /** + * Current size of the array. This starts out being == to + * . However, if we are assigned a smaller array, then + * will become less than . The purpose of + * keeping track of both sizes is to avoid reallocating memory if we + * don't have to. + */ + size_type cur_size_; + + /// Pointer to the array's storage buffer. + value_type * array_; + + /// Allocation strategy of the ACE_Array_Base. + ACE_Allocator * allocator_; + + friend class ACE_Array_Iterator; +}; + +// **************************************************************** + +/** + * @class ACE_Array_Iterator + * + * @brief Implement an iterator over an ACE_Array. + * + * This iterator is safe in the face of array element deletions. + * But it is NOT safe if the array is resized (via the ACE_Array + * assignment operator) during iteration. That would be very + * odd, and dangerous. + */ +template +class ACE_Array_Iterator +{ +public: + // = Initialization method. + ACE_Array_Iterator (ACE_Array_Base &); + + // = Iteration methods. + + /// Pass back the @a next_item that hasn't been seen in the Array. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item); + + /// Move forward by one element in the Array. Returns 0 when all the + /// items in the Array have been seen, else 1. + int advance (void); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Pointer to the current item in the iteration. + size_t current_; + + /// Pointer to the Array we're iterating over. + ACE_Array_Base &array_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Array_Base.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Array_Base.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Array_Base.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ARRAY_BASE_H */ diff --git a/dep/acelite/ace/Array_Base.inl b/dep/acelite/ace/Array_Base.inl new file mode 100644 index 000000000..ccd367f2d --- /dev/null +++ b/dep/acelite/ace/Array_Base.inl @@ -0,0 +1,143 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Clean up the array (e.g., delete dynamically allocated memory). +template ACE_INLINE +ACE_Array_Base::~ACE_Array_Base (void) +{ + ACE_DES_ARRAY_FREE (this->array_, + this->max_size_, + this->allocator_->free, + T); +} + +template +ACE_INLINE typename ACE_Array_Base::iterator +ACE_Array_Base::begin (void) +{ + return this->array_; +} + +template +ACE_INLINE typename ACE_Array_Base::iterator +ACE_Array_Base::end (void) +{ + return this->array_ + this->cur_size_; +} + +template +ACE_INLINE typename ACE_Array_Base::const_iterator +ACE_Array_Base::begin (void) const +{ + return this->array_; +} + +template +ACE_INLINE typename ACE_Array_Base::const_iterator +ACE_Array_Base::end (void) const +{ + return this->array_ + this->cur_size_; +} + +template +ACE_INLINE typename ACE_Array_Base::reverse_iterator +ACE_Array_Base::rbegin (void) +{ + return reverse_iterator (this->end ()); +} + +template +ACE_INLINE typename ACE_Array_Base::reverse_iterator +ACE_Array_Base::rend (void) +{ + return reverse_iterator (this->begin ()); +} + +template +ACE_INLINE typename ACE_Array_Base::const_reverse_iterator +ACE_Array_Base::rbegin (void) const +{ + return const_reverse_iterator (this->end ()); +} + +template +ACE_INLINE typename ACE_Array_Base::const_reverse_iterator +ACE_Array_Base::rend (void) const +{ + return const_reverse_iterator (this->begin ()); +} + +template ACE_INLINE typename ACE_Array_Base::size_type +ACE_Array_Base::size (void) const +{ + return this->cur_size_; +} + +template ACE_INLINE typename ACE_Array_Base::size_type +ACE_Array_Base::max_size (void) const +{ + return this->max_size_; +} + +template ACE_INLINE bool +ACE_Array_Base::in_range (typename ACE_Array_Base::size_type index) const +{ + return index < this->cur_size_; +} + +template ACE_INLINE T & +ACE_Array_Base::operator[] (typename ACE_Array_Base::size_type index) +{ + return this->array_[index]; +} + +template ACE_INLINE const T & +ACE_Array_Base::operator[] (typename ACE_Array_Base::size_type index) const +{ + return this->array_[index]; +} + +// **************************************************************** + +template ACE_INLINE void +ACE_Array_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // ACE_TRACE ("ACE_Array_Iterator::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE +ACE_Array_Iterator::ACE_Array_Iterator (ACE_Array_Base &a) + : current_ (0), + array_ (a) +{ + // ACE_TRACE ("ACE_Array_Iterator::ACE_Array_Iterator"); +} + +template ACE_INLINE int +ACE_Array_Iterator::advance (void) +{ + // ACE_TRACE ("ACE_Array_Iterator::advance"); + + if (this->current_ < array_.size ()) + { + ++this->current_; + return 1; + } + else + { + // Already finished iterating. + return 0; + } +} + +template ACE_INLINE int +ACE_Array_Iterator::done (void) const +{ + ACE_TRACE ("ACE_Array_Iterator::done"); + + return this->current_ >= array_.size (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Array_Map.cpp b/dep/acelite/ace/Array_Map.cpp new file mode 100644 index 000000000..4917c51e4 --- /dev/null +++ b/dep/acelite/ace/Array_Map.cpp @@ -0,0 +1,259 @@ +#ifndef ACE_ARRAY_MAP_CPP +#define ACE_ARRAY_MAP_CPP + +#include "ace/Array_Map.h" + +#ifndef __ACE_INLINE__ +# include "ace/Array_Map.inl" +#endif /* !__ACE_INLINE__ */ + +#include "ace/checked_iterator.h" + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +template +ACE_Array_Map::ACE_Array_Map (InputIterator f, + InputIterator l) + : size_ (l - f) + , capacity_ (size_) + , nodes_ (size_ == 0 ? 0 : this->alloc_.allocate (size_)) +{ + (void) std::uninitialized_copy (f, + l, + ACE_make_checked_array_iterator (this->begin (), + this->size_)); +} + +template +ACE_Array_Map::ACE_Array_Map ( + ACE_Array_Map const & map) + : size_ (map.size_) + , capacity_ (map.size_) + , nodes_ (size_ == 0 ? 0 : this->alloc_.allocate (size_)) +{ + (void) std::uninitialized_copy (map.begin (), + map.end (), + ACE_make_checked_array_iterator (this->begin (), + this->size_)); +} + +template +ACE_Array_Map::~ACE_Array_Map (void) +{ + for (size_t idx = 0; idx != capacity_; ++idx) + { +#if defined (ACE_HAS_BCC32) + using std::pair; + (nodes_ + idx)->~pair(); +#else + (nodes_ + idx)->~value_type(); +#endif + + } + + alloc_.deallocate(this->nodes_, capacity_); +} + +template +void +ACE_Array_Map::swap ( + ACE_Array_Map & map) +{ + std::swap (this->size_, map.size_); + std::swap (this->capacity_, map.capacity_); + std::swap (this->nodes_, map.nodes_); +} + +template +std::pair::iterator, bool> +ACE_Array_Map::insert ( + typename ACE_Array_Map::value_type const & x) +{ + // Linear insertion due to linear duplicate key search. + + bool inserted = false; + iterator i = this->find (x.first); + + if (i == this->end ()) + { + // Add the element to the array. + + size_type const old_size = this->size (); + this->grow (1); // Increase size by at least one. + + i = this->begin () + old_size; + *i = x; + + ++this->size_; + + inserted = true; + } + + return std::make_pair (i, inserted); +} + +template +template +void +ACE_Array_Map::insert (InputIterator f, InputIterator l) +{ + this->grow (l - f); // Preallocate storage. + + for (InputIterator i = f; i != l; ++i) + { + (void) this->insert (*i); + } +} + +template +void +ACE_Array_Map::erase ( + typename ACE_Array_Map::iterator pos) +{ + iterator const first = this->begin (); + iterator const last = this->end (); + + if (pos >= first && pos < last) + { + if (pos != last - 1) + { + // Relocate the tail element to the location of the erased + // element to prevent introduction of "holes" in the + // underlying array. + *pos = *(last - 1); + } + + // Explicitly destroy the tail element by assigning a default + // constructed instance to it. Note that this also works for + // the case of a map of size 1. + *(last - 1) = value_type (); + + --this->size_; + } +} + +template +typename ACE_Array_Map::size_type +ACE_Array_Map::erase ( + typename ACE_Array_Map::key_type const & k) +{ + iterator pos = this->find (k); + + size_type const old_size = this->size_; + + this->erase (pos); + + return old_size - this->size_; +} + +template +void +ACE_Array_Map::erase ( + typename ACE_Array_Map::iterator first, + typename ACE_Array_Map::iterator last) +{ + if (this->begin () <= first && first < last && last < this->end ()) + for (iterator i = first; i != last; ++i) + this->erase (i); +} + +template +void +ACE_Array_Map::clear (void) +{ + this->size_ = 0; // No need to deallocate array nor destroy elements. +} + +template +typename ACE_Array_Map::iterator +ACE_Array_Map::find ( + typename ACE_Array_Map::key_type const & k) +{ + iterator const the_end = this->end (); + + EqualTo eq; + + for (iterator i = this->begin (); i != the_end; ++i) + if (eq (k, i->first)) + return i; + + return this->end (); +} + +template +typename ACE_Array_Map::const_iterator +ACE_Array_Map::find ( + typename ACE_Array_Map::key_type const & k) const +{ + const_iterator const the_end = this->end (); + + EqualTo eq; + + for (const_iterator i = this->begin (); i != the_end; ++i) + if (eq (k, i->first)) + return i; + + return this->end (); +} + +template +void +ACE_Array_Map::grow ( + typename ACE_Array_Map::size_type s) +{ + if (this->size () + s > this->capacity_) + { + // This implementation focuses more on static footprint than + // speed. + + // Strongly exception safe. + + ACE_Array_Map temp (this->size () + s); + + std::copy (this->begin (), + this->end (), + ACE_make_checked_array_iterator (temp.begin (), + temp.capacity_)); + + size_type const n = this->size (); // Do not swap out the size + // since we bypassed the + // temporary map's element + // counting code. + this->swap (temp); + + this->size_ = n; + } +} + +// --------------------------------------------------------------- + +template +bool +operator== (ACE_Array_Map const & lhs, + ACE_Array_Map const & rhs) +{ + // Do not include Array_Map capacity in comparison. It isn't useful + // in this case. + + return (lhs.size () == rhs.size () + && std::equal (lhs.begin (), + lhs.end (), + ACE_make_checked_array_iterator (rhs.begin (), + rhs.size ()))); +} + +template +bool +operator< (ACE_Array_Map const & lhs, + ACE_Array_Map const & rhs) +{ + return std::lexicographical_compare (lhs.begin (), lhs.end (), + rhs.begin (), rhs.end ()); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ARRAY_MAP_CPP */ diff --git a/dep/acelite/ace/Array_Map.h b/dep/acelite/ace/Array_Map.h new file mode 100644 index 000000000..c68e7a1fe --- /dev/null +++ b/dep/acelite/ace/Array_Map.h @@ -0,0 +1,303 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Array_Map.h + * + * Light weight array-based map with fast iteration but linear + * (i.e. O(n)) search times. STL-style interface is exposed. + * + * @note This class requires the STL generic algorithms and + * reverse_iterator adapter. + * + * @author Ossama Othman + */ +//============================================================================= + + +#ifndef ACE_ARRAY_MAP_H +#define ACE_ARRAY_MAP_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-lite.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include +#include +#include +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined __SUNPRO_CC && !defined _RWSTD_ALLOCATOR +# define ACE_ARRAY_MAP_DEFAULT_ALLOCATOR(K, V) std::allocator_interface< \ + std::allocator, \ + std::pair > +#else +# define ACE_ARRAY_MAP_DEFAULT_ALLOCATOR(K, V) std::allocator > +#endif + +/** + * @class ACE_Array_Map + * + * @brief Light weight array-based map with fast iteration, but linear + * (i.e. O(n)) search times. + * + * Map implementation that focuses on small footprint and fast + * iteration. Search times are, however, linear (O(n)) meaning that + * this map isn't suitable for large data sets that will be searched + * in performance critical areas of code. Iteration over large data + * sets, however, is faster than linked list-based maps, for example, + * since spatial locality is maximized through the use of contiguous + * arrays as the underlying storage. + * @par + * An @c ACE_Array_Map is a unique associative container, meaning that + * duplicate values may not be added to the map. It is also pair + * associative (value_type is a std::pair<>). It is not a sorted + * container. + * @par + * An STL @c std::map -like interface is exposed by this class + * portability. Furthermore, this map's iterators are compatible with + * STL algorithms. + * @par + * Requirements and Performance Characteristics + * - Internal Structure + * Array + * - Duplicates allowed? + * No + * - Random access allowed? + * Yes + * - Search speed + * O(n) + * - Insert/replace speed + * O(n), can be longer if the map has to resize + * - Iterator still valid after change to container? + * No + * - Frees memory for removed elements? + * Yes + * - Items inserted by + * Value + * - Requirements for key type + * -# Default constructor + * -# Copy constructor + * -# operator= + * -# operator== + * - Requirements for object type + * -# Default constructor + * -# Copy constructor + * -# operator= + */ +template, + class Alloc = ACE_ARRAY_MAP_DEFAULT_ALLOCATOR (Key, Value) > +class ACE_Array_Map +{ +public: + + // STL-style typedefs/traits. + typedef Key key_type; + typedef Value mapped_type; + typedef Value data_type; + typedef std::pair value_type; + typedef Alloc allocator_type; + typedef value_type & reference; + typedef value_type const & const_reference; + typedef value_type * pointer; + typedef value_type const * const_pointer; + typedef value_type * iterator; + typedef value_type const * const_iterator; + typedef ptrdiff_t difference_type; + typedef size_t size_type; + ACE_DECLARE_STL_REVERSE_ITERATORS + + /// Default Constructor. + /** + * Create an empty map with a preallocated buffer of size @a s. + */ + ACE_Array_Map (size_type s = 0); + + template + ACE_Array_Map (InputIterator f, InputIterator l); + + ACE_Array_Map (ACE_Array_Map const & map); + ACE_Array_Map & operator= (ACE_Array_Map const & map); + + /// Destructor. + ~ACE_Array_Map (void); + + /** + * @name Forward Iterator Accessors + * + * Forward iterator accessors. + */ + //@{ + iterator begin (void); + iterator end (void); + const_iterator begin (void) const; + const_iterator end (void) const; + //@} + + /** + * @name Reverse Iterator Accessors + * + * Reverse iterator accessors. + */ + //@{ + reverse_iterator rbegin (void); + reverse_iterator rend (void); + const_reverse_iterator rbegin (void) const; + const_reverse_iterator rend (void) const; + //@} + + /// Return current size of map. + /** + * @return The number of elements in the map. + */ + size_type size (void) const; + + /// Maximum number of elements the map can hold. + size_type max_size (void) const; + + /// Return @c true if the map is empty, else @c false. + bool is_empty (void) const; // ACE style + + /** + * Return @c true if the map is empty, else @c false. We recommend + * using @c is_empty() instead since it's more consistent with the + * ACE container naming conventions. + */ + bool empty (void) const; // STL style + + /// Swap the contents of this map with the given @a map in an + /// exception-safe manner. + void swap (ACE_Array_Map & map); + + /// Insert the value @a x into the map. + /** + * STL-style map insertion method. + * + * @param x @c std::pair containing key and datum. + * + * @return @c std::pair::second will be @c false if the map already + * contains a value with the same key as @a x. + */ + std::pair insert (value_type const & x); + + /// Insert range of elements into map. + template + void insert (InputIterator f, InputIterator l); + + /// Remove element at position @a pos from the map. + void erase (iterator pos); + + /// Remove element corresponding to key @a k from the map. + /** + * @return Number of elements that were erased. + */ + size_type erase (key_type const & k); + + /// Remove range of elements [@a first, @a last) from the map. + /** + * @note [@a first, @a last) must be valid range within the map. + */ + void erase (iterator first, iterator last); + + /// Clear contents of map. + /** + * @note This a constant time (O(1)) operation. + */ + void clear (void); + + /** + * @name Search Operations + * + * Search the map for data corresponding to key @a k. + */ + //@{ + /** + * @return @c end() if data corresponding to key @a k is not in the + * map. + */ + iterator find (key_type const & k); + + /** + * @return @c end() if data corresponding to key @a k is not in the + * map. + */ + const_iterator find (key_type const & k) const; + //@} + + /// Count the number of elements corresponding to key @a k. + /** + * @return In the case of this map, the count will always be one if + * such exists in the map. + */ + size_type count (key_type const & k); + + /// Convenience array index operator. + /** + * Array index operator that allows insertion and retrieval of + * elements using an array index syntax, such as: + * @par + * map["Foo"] = 12; + */ + mapped_type & operator[] (key_type const & k); + + allocator_type get_allocator() const { return alloc_; } + +private: + + /// Increase size of underlying buffer by @a s. + void grow (size_type s); + +private: + /// The allocator. + allocator_type alloc_; + + /// Number of elements in the map. + size_type size_; + + /// Current size of underlying array. + /** + * @note @c capacity_ is always greater than or equal to @c size_; + */ + size_type capacity_; + + /// Underlying array containing keys and data. + value_type * nodes_; +}; + +// -------------------------------------------------------------- + +/// @c ACE_Array_Map equality operator. +template +bool operator== (ACE_Array_Map const & lhs, + ACE_Array_Map const & rhs); + +/// @c ACE_Array_Map lexicographical comparison operator. +template +bool operator< (ACE_Array_Map const & lhs, + ACE_Array_Map const & rhs); + +// -------------------------------------------------------------- + +ACE_END_VERSIONED_NAMESPACE_DECL + +#ifdef __ACE_INLINE__ +# include "ace/Array_Map.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +# include "ace/Array_Map.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Array_Map.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ARRAY_MAP_H */ diff --git a/dep/acelite/ace/Array_Map.inl b/dep/acelite/ace/Array_Map.inl new file mode 100644 index 000000000..32e7848c0 --- /dev/null +++ b/dep/acelite/ace/Array_Map.inl @@ -0,0 +1,131 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_INLINE +ACE_Array_Map::ACE_Array_Map ( + typename ACE_Array_Map::size_type s) + : size_ (0) + , capacity_ (s) + , nodes_ (s == 0 ? 0 : this->alloc_.allocate (s)) +{ + std::uninitialized_fill_n (this->nodes_, s, value_type ()); +} + +template +ACE_INLINE ACE_Array_Map & +ACE_Array_Map::operator= ( + ACE_Array_Map const & map) +{ + // Strongly exception-safe assignment. + + ACE_Array_Map temp (map); + this->swap (temp); + return *this; +} + +template +ACE_INLINE typename ACE_Array_Map::iterator +ACE_Array_Map::begin (void) +{ + return this->nodes_; +} + +template +ACE_INLINE typename ACE_Array_Map::iterator +ACE_Array_Map::end (void) +{ + return this->nodes_ + this->size_; +} + +template +ACE_INLINE typename ACE_Array_Map::const_iterator +ACE_Array_Map::begin (void) const +{ + return this->nodes_; +} + +template +ACE_INLINE typename ACE_Array_Map::const_iterator +ACE_Array_Map::end (void) const +{ + return this->nodes_ + this->size_; +} + +template +ACE_INLINE typename ACE_Array_Map::reverse_iterator +ACE_Array_Map::rbegin (void) +{ + return reverse_iterator (this->end ()); +} + +template +ACE_INLINE typename ACE_Array_Map::reverse_iterator +ACE_Array_Map::rend (void) +{ + return reverse_iterator (this->begin ()); +} + +template +ACE_INLINE typename ACE_Array_Map::const_reverse_iterator +ACE_Array_Map::rbegin (void) const +{ + return const_reverse_iterator (this->end ()); +} + +template +ACE_INLINE typename ACE_Array_Map::const_reverse_iterator +ACE_Array_Map::rend (void) const +{ + return const_reverse_iterator (this->begin ()); +} + +template +ACE_INLINE typename ACE_Array_Map::size_type +ACE_Array_Map::size (void) const +{ + return this->size_; +} + +template +ACE_INLINE typename ACE_Array_Map::size_type +ACE_Array_Map::max_size (void) const +{ + return size_type (-1) / sizeof (value_type); +} + +template +ACE_INLINE bool +ACE_Array_Map::is_empty (void) const +{ + return this->size_ == 0; +} + +// The following method is deprecated. + +template +ACE_INLINE bool +ACE_Array_Map::empty (void) const +{ + return this->is_empty (); +} + +template +ACE_INLINE typename ACE_Array_Map::size_type +ACE_Array_Map::count ( + typename ACE_Array_Map::key_type const & k) +{ + return + (this->find (k) == this->end () ? 0 : 1); // Only one datum per key. +} + +template +ACE_INLINE typename ACE_Array_Map::mapped_type & +ACE_Array_Map::operator[] ( + typename ACE_Array_Map::key_type const & k) +{ + iterator i = (this->insert (value_type (k, mapped_type ()))).first; + return (*i).second; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Assert.cpp b/dep/acelite/ace/Assert.cpp new file mode 100644 index 000000000..45524c643 --- /dev/null +++ b/dep/acelite/ace/Assert.cpp @@ -0,0 +1,25 @@ +#include "ace/Assert.h" +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// The following ASSERT macro is courtesy of Alexandre Karev +// . +void +__ace_assert(const char *file, int line, const ACE_TCHAR *expression) +{ + int error = ACE_Log_Msg::last_error_adapter (); + ACE_Log_Msg *log = ACE_Log_Msg::instance (); + + log->set (file, line, -1, error, log->restart (), + log->msg_ostream (), log->msg_callback ()); + +#ifdef ACE_LACKS_VA_FUNCTIONS +#define LOG_ARGS +#else +#define LOG_ARGS(X) X +#endif + log->log LOG_ARGS ((LM_ERROR, ACE_TEXT ("ACE_ASSERT: file %N, line %l assertion failed for '%s'.%a\n"), expression, -1)); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Assert.h b/dep/acelite/ace/Assert.h new file mode 100644 index 000000000..33c5a4c25 --- /dev/null +++ b/dep/acelite/ace/Assert.h @@ -0,0 +1,38 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Assert.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ASSERT_H +#define ACE_ASSERT_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#include /**/ "ace/config-all.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +ACE_Export void __ace_assert(const char *file, int line, const ACE_TCHAR *expression); +ACE_END_VERSIONED_NAMESPACE_DECL + +#define ACE_TEST_ASSERT(X) \ + ((X) \ + ? static_cast(0) \ + : ACE_VERSIONED_NAMESPACE_NAME::__ace_assert(__FILE__, __LINE__, ACE_TEXT_CHAR_TO_TCHAR (#X))) + +#if defined (ACE_NDEBUG) +#define ACE_ASSERT(x) \ + (static_cast(0)) +#else +#define ACE_ASSERT(X) ACE_TEST_ASSERT(X) +#endif /* ACE_NDEBUG */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ASSERT */ diff --git a/dep/acelite/ace/Asynch_Acceptor.cpp b/dep/acelite/ace/Asynch_Acceptor.cpp new file mode 100644 index 000000000..c518c3a62 --- /dev/null +++ b/dep/acelite/ace/Asynch_Acceptor.cpp @@ -0,0 +1,506 @@ +/* -*- C++ -*- */ +#ifndef ACE_ASYNCH_ACCEPTOR_C +#define ACE_ASYNCH_ACCEPTOR_C + +#include "ace/Asynch_Acceptor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) +// This only works on platforms that support async i/o. + +#include "ace/OS_Errno.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/Log_Category.h" +#include "ace/Message_Block.h" +#include "ace/INET_Addr.h" +#include "ace/SOCK_Stream.h" +#include "ace/Sock_Connect.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Asynch_Acceptor::ACE_Asynch_Acceptor (void) + : listen_handle_ (ACE_INVALID_HANDLE), + pass_addresses_ (false), + validate_new_connection_ (false), + reissue_accept_ (1), + bytes_to_read_ (0), + addr_family_ (0) +{ +} + +template +ACE_Asynch_Acceptor::~ACE_Asynch_Acceptor (void) +{ + // Close down the listen socket + if (this->listen_handle_ != ACE_INVALID_HANDLE) + { + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + } +} + +template int +ACE_Asynch_Acceptor::open (const ACE_INET_Addr &address, + size_t bytes_to_read, + bool pass_addresses, + int backlog, + int reuse_addr, + ACE_Proactor *proactor, + bool validate_new_connection, + int reissue_accept, + int number_of_initial_accepts) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::open"); + + this->proactor (proactor); + this->pass_addresses_ = pass_addresses; + this->bytes_to_read_ = bytes_to_read; + this->validate_new_connection_ = validate_new_connection; + this->reissue_accept_ = reissue_accept; + this->addr_family_ = address.get_type (); + + // Create the listener socket + this->listen_handle_ = ACE_OS::socket (address.get_type (), SOCK_STREAM, 0); + if (this->listen_handle_ == ACE_INVALID_HANDLE) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::socket")), + -1); + // Initialize the ACE_Asynch_Accept + if (this->asynch_accept_.open (*this, + this->listen_handle_, + 0, + this->proactor ()) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::open"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + + if (reuse_addr) + { + // Reuse the address + int one = 1; + if (ACE_OS::setsockopt (this->listen_handle_, + SOL_SOCKET, + SO_REUSEADDR, + (const char*) &one, + sizeof one) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::setsockopt"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + } + + // If port is not specified, bind to any port. + static ACE_INET_Addr sa (ACE_sap_any_cast (const ACE_INET_Addr &)); + + if (address == sa && + ACE::bind_port (this->listen_handle_, + INADDR_ANY, + address.get_type()) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::bind_port"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + + // Bind to the specified port. + if (ACE_OS::bind (this->listen_handle_, + reinterpret_cast (address.get_addr ()), + address.get_size ()) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::bind"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + + // Start listening. + if (ACE_OS::listen (this->listen_handle_, backlog) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::listen"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + + // For the number of . + if (number_of_initial_accepts == -1) + number_of_initial_accepts = backlog; + + for (int i = 0; i < number_of_initial_accepts; i++) + { + // Initiate accepts. + if (this->accept (bytes_to_read) == -1) + { + ACE_Errno_Guard g (errno); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Acceptor::accept"))); + ACE_OS::closesocket (this->listen_handle_); + this->listen_handle_ = ACE_INVALID_HANDLE; + return -1; + } + } + + return 0; +} + +template int +ACE_Asynch_Acceptor::set_handle (ACE_HANDLE listen_handle) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::set_handle"); + + // Take ownership of the + this->listen_handle_ = listen_handle; + + // Reinitialize the ACE_Asynch_Accept + if (this->asynch_accept_.open (*this, + this->listen_handle_, + 0, + this->proactor ()) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Accept::open")), + -1); + return 0; +} + +template ACE_HANDLE +ACE_Asynch_Acceptor::get_handle (void) const +{ + return this->listen_handle_; +} + +template int +ACE_Asynch_Acceptor::accept (size_t bytes_to_read, const void *act) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::accept"); + + ACE_Message_Block *message_block = 0; + // The space_needed calculation is drive by needs of Windows. POSIX doesn't + // need to extra 16 bytes, but it doesn't hurt. + size_t space_needed = sizeof (sockaddr_in) + 16; +#if defined (ACE_HAS_IPV6) + if (PF_INET6 == this->addr_family_) + space_needed = sizeof (sockaddr_in6) + 16; +#endif /* ACE_HAS_IPV6 */ + space_needed = (2 * space_needed) + bytes_to_read; + + // Create a new message block big enough for the addresses and data + ACE_NEW_RETURN (message_block, + ACE_Message_Block (space_needed), + -1); + + // Initiate asynchronous accepts + if (this->asynch_accept_.accept (*message_block, + bytes_to_read, + ACE_INVALID_HANDLE, + act, + 0, + ACE_SIGRTMIN, + this->addr_family_) == -1) + { + // Cleanup on error + message_block->release (); + return -1; + } + return 0; +} + +template void +ACE_Asynch_Acceptor::handle_accept (const ACE_Asynch_Accept::Result &result) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::handle_accept"); + + // Variable for error tracking + int error = 0; + + // If the asynchronous accept fails. + if (!result.success () || result.accept_handle () == ACE_INVALID_HANDLE) + { + error = 1; + } + +#if defined (ACE_WIN32) + // In order to use accept handle with other Window Sockets 1.1 + // functions, we call the setsockopt function with the + // SO_UPDATE_ACCEPT_CONTEXT option. This option initializes the + // socket so that other Windows Sockets routines to access the + // socket correctly. + if (!error && + ACE_OS::setsockopt (result.accept_handle (), + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char *) &this->listen_handle_, + sizeof (this->listen_handle_)) == -1) + { + error = 1; + } +#endif /* ACE_WIN32 */ + + // Parse address. + ACE_INET_Addr local_address; + ACE_INET_Addr remote_address; + if (!error && + (this->validate_new_connection_ || this->pass_addresses_)) + // Parse the addresses. + this->parse_address (result, + remote_address, + local_address); + + // Validate remote address + if (!error && + this->validate_new_connection_ && + (this->validate_connection (result, remote_address, local_address) == -1)) + { + error = 1; + } + + HANDLER *new_handler = 0; + if (!error) + { + // The Template method + new_handler = this->make_handler (); + if (new_handler == 0) + { + error = 1; + } + } + + // If no errors + if (!error) + { + // Update the Proactor unless make_handler() or constructed handler + // set up its own. + if (new_handler->proactor () == 0) + new_handler->proactor (this->proactor ()); + + // Pass the addresses + if (this->pass_addresses_) + new_handler->addresses (remote_address, + local_address); + + // Pass the ACT + if (result.act () != 0) + new_handler->act (result.act ()); + + // Set up the handler's new handle value + new_handler->handle (result.accept_handle ()); + + // Initiate the handler + new_handler->open (result.accept_handle (), + result.message_block ()); + } + + // On failure, no choice but to close the socket + if (error && + result.accept_handle() != ACE_INVALID_HANDLE ) + ACE_OS::closesocket (result.accept_handle ()); + + // Delete the dynamically allocated message_block + result.message_block ().release (); + + // Start off another asynchronous accept to keep the backlog going, + // unless we closed the listen socket already (from the destructor), + // or this callback is the result of a canceled/aborted accept. + if (this->should_reissue_accept () && + this->listen_handle_ != ACE_INVALID_HANDLE +#if defined (ACE_WIN32) + && result.error () != ERROR_OPERATION_ABORTED +#else + && result.error () != ECANCELED +#endif + ) + this->accept (this->bytes_to_read_, result.act ()); +} + +template int +ACE_Asynch_Acceptor::validate_connection + (const ACE_Asynch_Accept::Result& /* result */, + const ACE_INET_Addr& /* remote */, + const ACE_INET_Addr& /* local */) +{ + // Default implementation always validates the remote address. + return 0; +} + +template int +ACE_Asynch_Acceptor::cancel (void) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::cancel"); + + // All I/O operations that are canceled will complete with the error + // ERROR_OPERATION_ABORTED. All completion notifications for the I/O + // operations will occur normally. +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) + return (int) ::CancelIo (this->listen_handle_); +#else + // Supported now + return this->asynch_accept_.cancel(); +#endif /* defined (ACE_HAS_WIN32_OVERLAPPED_IO) */ +} + +template void +ACE_Asynch_Acceptor::parse_address (const + ACE_Asynch_Accept::Result &result, + ACE_INET_Addr &remote_address, + ACE_INET_Addr &local_address) +{ + ACE_TRACE ("ACE_Asynch_Acceptor<>::parse_address"); + +#if defined (ACE_HAS_AIO_CALLS) + + // Use an ACE_SOCK to get the addresses - it knows how to deal with + // ACE_INET_Addr objects and get IPv4/v6 addresses. + ACE_SOCK_Stream str (result.accept_handle ()); + str.get_local_addr (local_address); + str.get_remote_addr (remote_address); + +#elif defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) + + ACE_Message_Block &message_block = result.message_block (); + + sockaddr *local_addr = 0; + sockaddr *remote_addr = 0; + int local_size = 0; + int remote_size = 0; + // This matches setup in accept(). + size_t addr_size = sizeof (sockaddr_in) + 16; +#if defined (ACE_HAS_IPV6) + if (this->addr_family_ == PF_INET6) + addr_size = sizeof (sockaddr_in6) + 16; +#endif /* ACE_HAS_IPV6 */ + + ::GetAcceptExSockaddrs (message_block.rd_ptr (), + static_cast (this->bytes_to_read_), + static_cast (addr_size), + static_cast (addr_size), + &local_addr, + &local_size, + &remote_addr, + &remote_size); + + local_address.set (reinterpret_cast (local_addr), + local_size); + remote_address.set (reinterpret_cast (remote_addr), + remote_size); +#else + // just in case + errno = ENOTSUP; +#endif /* defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) */ + return; +} + +template ACE_HANDLE +ACE_Asynch_Acceptor::handle (void) const +{ + return this->listen_handle_; +} + +template void +ACE_Asynch_Acceptor::handle (ACE_HANDLE h) +{ + ACE_Handler::handle (h); +} + +template ACE_Asynch_Accept & +ACE_Asynch_Acceptor::asynch_accept (void) +{ + return this->asynch_accept_; +} + +template HANDLER * +ACE_Asynch_Acceptor::make_handler (void) +{ + // Default behavior + HANDLER *handler = 0; + ACE_NEW_RETURN (handler, + HANDLER, + 0); + return handler; +} + +template bool +ACE_Asynch_Acceptor::pass_addresses (void) const +{ + return this->pass_addresses_; +} + +template void +ACE_Asynch_Acceptor::pass_addresses (bool new_value) +{ + this->pass_addresses_ = new_value; +} + +template bool +ACE_Asynch_Acceptor::validate_new_connection (void) const +{ + return this->validate_new_connection_; +} + +template void +ACE_Asynch_Acceptor::validate_new_connection (bool new_value) +{ + this->validate_new_connection_ = new_value; +} + +template int +ACE_Asynch_Acceptor::reissue_accept (void) const +{ + return this->reissue_accept_; +} + +template void +ACE_Asynch_Acceptor::reissue_accept (int new_value) +{ + this->reissue_accept_ = new_value; +} + +template size_t +ACE_Asynch_Acceptor::bytes_to_read (void) const +{ + return this->bytes_to_read_; +} + +template void +ACE_Asynch_Acceptor::bytes_to_read (size_t new_value) +{ + this->bytes_to_read_ = new_value; +} + +template int +ACE_Asynch_Acceptor::should_reissue_accept (void) +{ + return this->reissue_accept_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS */ +#endif /* ACE_ASYNCH_ACCEPTOR_C */ diff --git a/dep/acelite/ace/Asynch_Acceptor.h b/dep/acelite/ace/Asynch_Acceptor.h new file mode 100644 index 000000000..03efa702e --- /dev/null +++ b/dep/acelite/ace/Asynch_Acceptor.h @@ -0,0 +1,274 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Asynch_Acceptor.h + * + * @author Irfan Pyarali (irfan@cs.wustl.edu) + */ +//============================================================================= + +#ifndef ACE_ASYNCH_ACCEPTOR_H +#define ACE_ASYNCH_ACCEPTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) +// This only works on platforms that support async i/o. + +#include "ace/Default_Constants.h" +#include "ace/Asynch_IO.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations +class ACE_Message_Block; +class ACE_INET_Addr; + +/** + * @class ACE_Asynch_Acceptor + * + * @brief This class is an example of the Acceptor Pattern. This class + * will accept new connections and create new HANDLER to handle + * the new connections. + * + * Unlike the ACE_Acceptor, however, this class is designed to + * be used asynchronously. + */ +template +class ACE_Asynch_Acceptor : public ACE_Handler +{ +public: + /// A do nothing constructor. + ACE_Asynch_Acceptor (void); + + /// Virtual destruction + virtual ~ACE_Asynch_Acceptor (void); + + /** + * @c open starts one or more asynchronous accept requests on a + * @a address. Each accept operation may optionally read an + * initial buffer from the new connection when accepted. + * + * @param address The address to listen/accept connections on. + * If the address does not specify a port, a random + * port is selected and bound. + * @param bytes_to_read Optional, specifies the maximum number of bytes + * to read with the accept. The buffer for the initial + * data is allocated internally and passed to the + * @c ACE_Service_Handler::open() hook method. It is + * legitimate only during the @c open() method and must + * be copied if required after @c open() returns. + * This pre-read function works only on Windows. + * @param pass_addresses Optional, a non-zero value indicates that + * the local and peer addresses should be passed to the + * associated @c ACE_Service_Handler::addresses() method + * after any call to @c validate_new_connection() and prior + * to the @c open() hook method call. + * @param backlog Optional, defaulting to @c ACE_DEFAULT_ASYNCH_BACKLOG (which + * can be adjusted in your platform's @c config.h file). + * Specifies the listening backlog for the listening socket. + * @param reuse_addr Optional, indicates whether the @c SO_REUSEADDR + * option is set on the listening socket or not. + * @param proactor Optional, pointer to the @c ACE_Proactor to use for + * demultiplexing asynchronous accepts. If 0, the + * process's singleton @c ACE_Proactor is used. + * @param validate_new_connection Optional, if true, this object's + * @c validate_connection() method is called after + * the accept completes, but before the service handler's + * @c open() hook method is called. If @c + * validate_connection() returns -1, the newly-accepted + * socket is immediately closed, and the @c addresses() + * method is not called. + * @param reissue_accept Optional, if non-zero (the default), a new + * asynchronous accept operation is started after each + * completion, whether the completion is for success or + * failure, and whether or not a successfully-accepted + * connection is subsequently refused. + * @param number_of_initial_accepts Optional, the number of asynchronous + * accepts that are started immediately. If -1 (the + * default), the value of @a backlog is used. + * + * @note On Windows, the peer address is only available at the time + * the connection is accepted. Therefore, if you require the peer + * address on Windows, do not rely on the + * @c ACE_SOCK::get_remote_addr() method - it won't work. You must + * supply a non-zero value for @a pass_addresses and obtain the + * peer address in the @c ACE_Service_Handler::addresses() method. + * + * @see ACE_INET_Addr + * @see ACE_Service_Handler + */ + virtual int open (const ACE_INET_Addr &address, + size_t bytes_to_read = 0, + bool pass_addresses = false, + int backlog = ACE_DEFAULT_ASYNCH_BACKLOG, + int reuse_addr = 1, + ACE_Proactor *proactor = 0, + bool validate_new_connection = false, + int reissue_accept = 1, + int number_of_initial_accepts = -1); + + /// Get the underlying handle. + virtual ACE_HANDLE get_handle (void) const; + + /** + * Set the underlying listen handle. It is the user's responsibility + * to make sure that the old listen handle has been appropriately + * closed and the all outstanding asynchronous operations have + * either completed or have been canceled on the old listen handle. + */ + virtual int set_handle (ACE_HANDLE handle); + + /// This initiates a new asynchronous accept operation. + /** + * You need only call this method if the @a reissue_accept argument + * passed to @c open() was 0. + */ + virtual int accept (size_t bytes_to_read = 0, const void *act = 0); + + /** + * Cancels all pending accepts operations issued by this object. + * + * @note On Windows, only accept operations initiated by the calling thread + * are canceled. + */ + virtual int cancel (void); + + /** + * Template method to validate peer before service is opened. + * This method is called after a new connection is accepted if the + * @a validate_connection argument to @c open() was non-zero or + * the @c validate_new_connection() method is called to turn this + * feature on. The default implementation returns 0. Users can + * reimplement this method to perform validation of the peer + * using it's address, running an authentication procedure (such as + * SSL) or anything else necessary or desireable. The return value + * from this method determines whether or not ACE will continue + * opening the service or abort the connection. + * + * @param result Result of the connection acceptance. + * @param remote Peer's address. + * @param local Local address connection was accepted at. + * + * @retval -1 ACE_Asynch_Acceptor will close the connection, and + * the service will not be opened. + * @retval 0 Service opening will proceeed. + */ + virtual int validate_connection (const ACE_Asynch_Accept::Result& result, + const ACE_INET_Addr &remote, + const ACE_INET_Addr& local); + + /** + * Template method for deciding whether to reissue accept. + * + * This hook method is called after each accept completes to decide if + * another accept should be initiated. If the method returns a non-zero + * value, another accept is initiated. + * + * The default implementation always returns the value passed as the + * @c open() method's @a reissue_accept argument. That value can also + * be changed using the @c reissue_accept() method. + */ + virtual int should_reissue_accept (void); + + // + // These are low level tweaking methods + // + + /// Get flag that indicates if parsing and passing of addresses to + /// the service_handler is necessary. + virtual bool pass_addresses (void) const; + + /// Set flag that indicates if parsing and passing of addresses to + /// the service_handler is necessary. + virtual void pass_addresses (bool new_value); + + /// Get flag that indicates if address validation is required. + virtual bool validate_new_connection (void) const; + + /// Set flag that indicates if address validation is required. + virtual void validate_new_connection (bool new_value); + + /// Get flag that indicates if a new accept should be reissued when a accept + /// completes. + virtual int reissue_accept (void) const; + + /// Set flag that indicates if a new accept should be reissued when a accept + /// completes. + virtual void reissue_accept (int new_value); + + /// Get bytes to be read with the call. + virtual size_t bytes_to_read (void) const; + + /// Set bytes to be read with the call. + virtual void bytes_to_read (size_t new_value); + +protected: + + /// This is called when an outstanding accept completes. + virtual void handle_accept (const ACE_Asynch_Accept::Result &result); + + /// Return the listen handle. + ACE_HANDLE handle (void) const; + /// Set the listen handle. + void handle (ACE_HANDLE h); + + /// This parses the address from read buffer. + void parse_address (const ACE_Asynch_Accept::Result &result, + ACE_INET_Addr &remote_address, + ACE_INET_Addr &local_address); + + /// Return the asynch accept object. + ACE_Asynch_Accept &asynch_accept (void); + + /** + * This is the template method used to create new handler. + * Subclasses must overwrite this method if a new handler creation + * strategy is required. + */ + virtual HANDLER *make_handler (void); + +private: + /// Handle used to listen for new connections. + ACE_HANDLE listen_handle_; + + /// Asynch_Accept used to make life easier :-) + ACE_Asynch_Accept asynch_accept_; + + /// Flag that indicates if parsing of addresses is necessary. + bool pass_addresses_; + + /// Flag that indicates if address validation is required. + bool validate_new_connection_; + + /// Flag that indicates if a new accept should be reissued when a + /// accept completes. + int reissue_accept_; + + /// Bytes to be read with the call. + size_t bytes_to_read_; + + /// Address family used to open this object. Obtained from @a address passed + /// to @c open(). + int addr_family_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Asynch_Acceptor.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Asynch_Acceptor.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ +#include /**/ "ace/post.h" +#endif /* ACE_ASYNCH_ACCEPTOR_H */ diff --git a/dep/acelite/ace/Asynch_Connector.cpp b/dep/acelite/ace/Asynch_Connector.cpp new file mode 100644 index 000000000..5391ca5ad --- /dev/null +++ b/dep/acelite/ace/Asynch_Connector.cpp @@ -0,0 +1,268 @@ +#ifndef ACE_ASYNCH_CONNECTOR_CPP +#define ACE_ASYNCH_CONNECTOR_CPP + +#include "ace/Asynch_Connector.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if (defined (ACE_WIN32) || defined (ACE_HAS_AIO_CALLS)) && !defined(ACE_HAS_WINCE) +// This only works on platforms that support async I/O. + +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_Memory.h" +#include "ace/Flag_Manip.h" +#include "ace/Log_Category.h" +#include "ace/Message_Block.h" +#include "ace/INET_Addr.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Asynch_Connector::ACE_Asynch_Connector (void) + : pass_addresses_ (false), + validate_new_connection_ (false) +{ +} + +template +ACE_Asynch_Connector::~ACE_Asynch_Connector (void) +{ + //this->asynch_connect_.close (); +} + +template int +ACE_Asynch_Connector::open (bool pass_addresses, + ACE_Proactor *proactor, + bool validate_new_connection) +{ + this->proactor (proactor); + this->pass_addresses_ = pass_addresses; + this->validate_new_connection_ = validate_new_connection; + + // Initialize the ACE_Asynch_Connect + if (this->asynch_connect_.open (*this, + ACE_INVALID_HANDLE, + 0, + this->proactor ()) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Connect::open")), + -1); + return 0; +} + +template int +ACE_Asynch_Connector::connect (const ACE_INET_Addr & remote_sap, + const ACE_INET_Addr & local_sap, + int reuse_addr, + const void *act) +{ + // Initiate asynchronous connect + if (this->asynch_connect_.connect (ACE_INVALID_HANDLE, + remote_sap, + local_sap, + reuse_addr, + act) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Connect::connect")), + -1); + return 0; +} + +template void +ACE_Asynch_Connector::handle_connect (const ACE_Asynch_Connect::Result &result) +{ + // Variable for error tracking + int error = 0; + + // If the asynchronous connect fails. + if (!result.success () || + result.connect_handle () == ACE_INVALID_HANDLE) + { + error = 1; + } + + if (result.error () != 0) + { + error = 1; + } + + // set blocking mode + if (!error && + ACE::clr_flags + (result.connect_handle (), ACE_NONBLOCK) != 0) + { + error = 1; + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Connector::handle_connect : Set blocking mode"))); + } + + // Parse the addresses. + ACE_INET_Addr local_address; + ACE_INET_Addr remote_address; + if (!error && + (this->validate_new_connection_ || this->pass_addresses_)) + this->parse_address (result, + remote_address, + local_address); + + // Call validate_connection even if there was an error - it's the only + // way the application can learn the connect disposition. + if (this->validate_new_connection_ && + this->validate_connection (result, remote_address, local_address) == -1) + { + error = 1; + } + + HANDLER *new_handler = 0; + if (!error) + { + // The Template method + new_handler = this->make_handler (); + if (new_handler == 0) + { + error = 1; + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Asynch_Connector::handle_connect : Making of new handler failed"))); + } + } + + // If no errors + if (!error) + { + // Update the Proactor. + new_handler->proactor (this->proactor ()); + + // Pass the addresses + if (this->pass_addresses_) + new_handler->addresses (remote_address, + local_address); + + // Pass the ACT + if (result.act () != 0) + new_handler->act (result.act ()); + + // Set up the handler's new handle value + new_handler->handle (result.connect_handle ()); + + ACE_Message_Block mb; + + // Initiate the handler with empty message block; + new_handler->open (result.connect_handle (), mb); + } + + // On failure, no choice but to close the socket + if (error && + result.connect_handle() != ACE_INVALID_HANDLE) + ACE_OS::closesocket (result.connect_handle ()); +} + +template int +ACE_Asynch_Connector::validate_connection + (const ACE_Asynch_Connect::Result &, + const ACE_INET_Addr & /* remote_address */, + const ACE_INET_Addr & /* local_address */) +{ + // Default implementation always validates the remote address. + return 0; +} + +template int +ACE_Asynch_Connector::cancel (void) +{ + return this->asynch_connect_.cancel (); +} + +template void +ACE_Asynch_Connector::parse_address (const ACE_Asynch_Connect::Result &result, + ACE_INET_Addr &remote_address, + ACE_INET_Addr &local_address) +{ +#if defined (ACE_HAS_IPV6) + // Getting the addresses. + sockaddr_in6 local_addr; + sockaddr_in6 remote_addr; +#else + // Getting the addresses. + sockaddr_in local_addr; + sockaddr_in remote_addr; +#endif /* ACE_HAS_IPV6 */ + + // Get the length. + int local_size = sizeof (local_addr); + int remote_size = sizeof (remote_addr); + + // Get the local address. + if (ACE_OS::getsockname (result.connect_handle (), + reinterpret_cast (&local_addr), + &local_size) < 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("%p\n"), + ACE_TEXT("ACE_Asynch_Connector:: failed"))); + + // Get the remote address. + if (ACE_OS::getpeername (result.connect_handle (), + reinterpret_cast (&remote_addr), + &remote_size) < 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT("%p\n"), + ACE_TEXT("ACE_Asynch_Connector:: failed"))); + + // Set the addresses. + local_address.set (reinterpret_cast (&local_addr), + local_size); + remote_address.set (reinterpret_cast (&remote_addr), + remote_size); + + return; +} + + +template ACE_Asynch_Connect & +ACE_Asynch_Connector::asynch_connect (void) +{ + return this->asynch_connect_; +} + +template HANDLER * +ACE_Asynch_Connector::make_handler (void) +{ + // Default behavior + HANDLER *handler = 0; + ACE_NEW_RETURN (handler, HANDLER, 0); + return handler; +} + +template bool +ACE_Asynch_Connector::pass_addresses (void) const +{ + return this->pass_addresses_; +} + +template void +ACE_Asynch_Connector::pass_addresses (bool new_value) +{ + this->pass_addresses_ = new_value; +} + +template bool +ACE_Asynch_Connector::validate_new_connection (void) const +{ + return this->validate_new_connection_; +} + +template void +ACE_Asynch_Connector::validate_new_connection (bool new_value) +{ + this->validate_new_connection_ = new_value; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS */ +#endif /* ACE_ASYNCH_CONNECTOR_CPP */ diff --git a/dep/acelite/ace/Asynch_Connector.h b/dep/acelite/ace/Asynch_Connector.h new file mode 100644 index 000000000..8706fd222 --- /dev/null +++ b/dep/acelite/ace/Asynch_Connector.h @@ -0,0 +1,169 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Asynch_Connector.h + * + * @author Alexander Libman + */ +//============================================================================= + +#ifndef ACE_ASYNCH_CONNECTOR_H +#define ACE_ASYNCH_CONNECTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if (defined (ACE_WIN32) || defined (ACE_HAS_AIO_CALLS)) && !defined(ACE_HAS_WINCE) +// This only works on platforms that support async i/o. + +#include "ace/Asynch_IO.h" +#include "ace/INET_Addr.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations +class ACE_Message_Block; + +/** + * @class ACE_Asynch_Connector + * + * @brief This class is an example of the Connector pattern. This class + * will establish new connections and create new HANDLER objects to handle + * the new connections. + * + * Unlike the ACE_Connector, however, this class is designed to + * be used asynchronously with the ACE Proactor framework. + */ + +template +class ACE_Asynch_Connector : public ACE_Handler +{ +public: + /// A do nothing constructor. + ACE_Asynch_Connector (void); + + /// Virtual destruction + virtual ~ACE_Asynch_Connector (void); + + /** + * This opens asynch connector + */ + virtual int open (bool pass_addresses = false, + ACE_Proactor *proactor = 0, + bool validate_new_connection = true); + + /// This initiates a new asynchronous connect + virtual int connect (const ACE_INET_Addr &remote_sap, + const ACE_INET_Addr &local_sap = + (const ACE_INET_Addr &)ACE_Addr::sap_any, + int reuse_addr = 1, + const void *act = 0); + + /** + * This cancels all pending accepts operations that were issued by + * the calling thread. + * + * @note On Windows, this method does not cancel connect operations + * issued by other threads. + * + * @note On POSIX, delegates cancelation to ACE_POSIX_Asynch_Connect. + */ + virtual int cancel (void); + + + /** + * Template method to validate peer before service is opened. + * This method is called when the connection attempt completes, + * whether it succeeded or failed, if the @a validate_connection + * argument to @c open() was non-zero or the @c validate_new_connection() + * method is called to turn this feature on. The default implementation + * returns 0. Users can (and probably should) reimplement this method + * to learn about the success or failure of the connection attempt. + * If the connection completed successfully, this method can be used to + * perform validation of the peer using it's address, running an + * authentication procedure (such as SSL) or anything else necessary or + * desireable. The return value from this method determines whether or + * not ACE will continue opening the service or abort the connection. + * + * @param result Result of the connection acceptance. Use + * result.success() to determine success or failure of + * the connection attempt. + * @param remote Peer's address. If the connection failed, this object + * is undefined. + * @param local Local address connection was completed from. If the + * connection failed, this object is undefined. + * + * @retval -1 ACE_Asynch_Connector will close the connection, and + * the service will not be opened. + * @retval 0 Service opening will proceeed. + * @return Return value is ignored if the connection attempt failed. + */ + virtual int validate_connection (const ACE_Asynch_Connect::Result& result, + const ACE_INET_Addr &remote, + const ACE_INET_Addr& local); + + // + // These are low level tweaking methods + // + + /// Set and get flag that indicates if parsing and passing of + /// addresses to the service_handler is necessary. + virtual bool pass_addresses (void) const; + virtual void pass_addresses (bool new_value); + + /// Set and get flag that indicates if address validation is + /// required. + virtual bool validate_new_connection (void) const; + virtual void validate_new_connection (bool new_value); + +protected: + + /// This is called when an outstanding accept completes. + virtual void handle_connect (const ACE_Asynch_Connect::Result &result); + + + /// This parses the address from read buffer. + void parse_address (const ACE_Asynch_Connect::Result &result, + ACE_INET_Addr &remote_address, + ACE_INET_Addr &local_address); + + /// Return the asynch Connect object. + ACE_Asynch_Connect & asynch_connect (void); + + /** + * This is the template method used to create new handler. + * Subclasses must overwrite this method if a new handler creation + * strategy is required. + */ + virtual HANDLER *make_handler (void); + +private: + + /// Asynch_Connect used to make life easier :-) + ACE_Asynch_Connect asynch_connect_; + + /// Flag that indicates if parsing of addresses is necessary. + bool pass_addresses_; + + /// Flag that indicates if address validation is required. + bool validate_new_connection_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Asynch_Connector.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Asynch_Connector.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS */ +#include /**/ "ace/post.h" +#endif /* ACE_ASYNCH_CONNECTOR_H */ diff --git a/dep/acelite/ace/Asynch_IO.cpp b/dep/acelite/ace/Asynch_IO.cpp new file mode 100644 index 000000000..f50cdc33d --- /dev/null +++ b/dep/acelite/ace/Asynch_IO.cpp @@ -0,0 +1,1410 @@ +#include "ace/Asynch_IO.h" + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) +// This only works on platforms with Asynchronous IO + +#include "ace/Proactor.h" +#include "ace/Message_Block.h" +#include "ace/INET_Addr.h" +#include "ace/Asynch_IO_Impl.h" +#include "ace/os_include/os_errno.h" +#include "ace/Truncate.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +size_t +ACE_Asynch_Result::bytes_transferred (void) const +{ + return this->implementation ()->bytes_transferred (); +} + +const void * +ACE_Asynch_Result::act (void) const +{ + return this->implementation ()->act (); +} + +int +ACE_Asynch_Result::success (void) const +{ + return this->implementation ()->success (); +} + +const void * +ACE_Asynch_Result::completion_key (void) const +{ + return this->implementation ()->completion_key (); +} + +unsigned long +ACE_Asynch_Result::error (void) const +{ + return this->implementation ()->error (); +} + +ACE_HANDLE +ACE_Asynch_Result::event (void) const +{ + return this->implementation ()->event (); +} + +unsigned long +ACE_Asynch_Result::offset (void) const +{ + return this->implementation ()->offset (); +} + +unsigned long +ACE_Asynch_Result::offset_high (void) const +{ + return this->implementation ()->offset_high (); +} + +int +ACE_Asynch_Result::priority (void) const +{ + return this->implementation ()->priority (); +} + +int +ACE_Asynch_Result::signal_number (void) const +{ + return this->implementation ()->signal_number (); +} + +ACE_Asynch_Result::ACE_Asynch_Result (ACE_Asynch_Result_Impl *implementation) + : implementation_ (implementation) +{ +} + +ACE_Asynch_Result::~ACE_Asynch_Result (void) +{ + // Proactor deletes the implementation when the finishes. +} + +ACE_Asynch_Result_Impl * +ACE_Asynch_Result::implementation (void) const +{ + return this->implementation_; +} + +// ********************************************************************* + +int +ACE_Asynch_Operation::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + return this->implementation ()->open (handler.proxy (), + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Operation::cancel (void) +{ + if (0 == this->implementation ()) + { + errno = EFAULT; + return -1; + } + return this->implementation ()->cancel (); +} + +ACE_Proactor * +ACE_Asynch_Operation::proactor (void) const +{ + if (0 == this->implementation ()) + { + errno = EFAULT; + return 0; + } + return this->implementation ()->proactor (); +} + +ACE_Asynch_Operation::ACE_Asynch_Operation (void) +{ +} + +ACE_Asynch_Operation::~ACE_Asynch_Operation (void) +{ +} + +ACE_Proactor * +ACE_Asynch_Operation::get_proactor (ACE_Proactor *user_proactor, + ACE_Handler &handler) const +{ + if (user_proactor == 0) + { + // Grab the singleton proactor if proactor> is zero + user_proactor = handler.proactor (); + if (user_proactor == 0) + user_proactor = ACE_Proactor::instance (); + } + + return user_proactor; +} + +// ************************************************************ + +ACE_Asynch_Read_Stream::ACE_Asynch_Read_Stream (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Read_Stream::~ACE_Asynch_Read_Stream (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Read_Stream::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_read_stream ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Read_Stream::read (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->read (message_block, + bytes_to_read, + act, + priority, + signal_number); +} + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) +int +ACE_Asynch_Read_Stream::readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->readv (message_block, + bytes_to_read, + act, + priority, + signal_number); +} +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO */ + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Read_Stream::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +size_t +ACE_Asynch_Read_Stream::Result::bytes_to_read (void) const +{ + return this->implementation ()->bytes_to_read (); +} + +ACE_Message_Block & +ACE_Asynch_Read_Stream::Result::message_block (void) const +{ + return this->implementation ()->message_block (); +} + +ACE_HANDLE +ACE_Asynch_Read_Stream::Result::handle (void) const +{ + return this->implementation ()->handle (); +} + +ACE_Asynch_Read_Stream::Result::Result (ACE_Asynch_Read_Stream_Result_Impl *implementation) + : ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Read_Stream::Result::~Result (void) +{ + // Proactor will delete the implementation after is + // finished. +} + +ACE_Asynch_Read_Stream_Result_Impl * +ACE_Asynch_Read_Stream::Result::implementation (void) const +{ + return this->implementation_; +} + +// *************************************************** + +ACE_Asynch_Write_Stream::ACE_Asynch_Write_Stream (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Write_Stream::~ACE_Asynch_Write_Stream (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Write_Stream::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_write_stream ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Write_Stream::write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->write (message_block, + bytes_to_write, + act, + priority, + signal_number); +} + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) +int +ACE_Asynch_Write_Stream::writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->writev (message_block, + bytes_to_write, + act, + priority, + signal_number); +} +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO */ + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Write_Stream::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +size_t +ACE_Asynch_Write_Stream::Result::bytes_to_write (void) const +{ + return this->implementation ()->bytes_to_write (); +} + +ACE_Message_Block & +ACE_Asynch_Write_Stream::Result::message_block (void) const +{ + return this->implementation ()->message_block (); +} + +ACE_HANDLE +ACE_Asynch_Write_Stream::Result::handle (void) const +{ + return this->implementation ()->handle (); +} + +ACE_Asynch_Write_Stream::Result::Result (ACE_Asynch_Write_Stream_Result_Impl *implementation) + : ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Write_Stream::Result::~Result (void) +{ + // Proactor will delte the implementation when the call + // finishes. +} + +ACE_Asynch_Write_Stream_Result_Impl * +ACE_Asynch_Write_Stream::Result::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Read_File::ACE_Asynch_Read_File (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Read_File::~ACE_Asynch_Read_File (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Read_File::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_read_file ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Read_File::read (ACE_Message_Block &message_block, + size_t bytes_to_read, + unsigned long offset, + unsigned long offset_high, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->read (message_block, + bytes_to_read, + offset, + offset_high, + act, + priority, + signal_number); +} + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) +int +ACE_Asynch_Read_File::readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + unsigned long offset, + unsigned long offset_high, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->readv (message_block, + bytes_to_read, + offset, + offset_high, + act, + priority, + signal_number); +} +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Read_File::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Read_File::Result::Result (ACE_Asynch_Read_File_Result_Impl *implementation) + : ACE_Asynch_Read_Stream::Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Read_File::Result::~Result (void) +{ + // Proactor will delete the implementation when call + // completes. +} + +ACE_Asynch_Read_File_Result_Impl * +ACE_Asynch_Read_File::Result::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Write_File::ACE_Asynch_Write_File (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Write_File::~ACE_Asynch_Write_File (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Write_File::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_write_file ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Write_File::write (ACE_Message_Block &message_block, + size_t bytes_to_write, + unsigned long offset, + unsigned long offset_high, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->write (message_block, + bytes_to_write, + offset, + offset_high, + act, + priority, + signal_number); +} + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) +int +ACE_Asynch_Write_File::writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + unsigned long offset, + unsigned long offset_high, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->writev (message_block, + bytes_to_write, + offset, + offset_high, + act, + priority, + signal_number); +} +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Write_File::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Write_File::Result::Result (ACE_Asynch_Write_File_Result_Impl *implementation) + : ACE_Asynch_Write_Stream::Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Write_File::Result::~Result (void) +{ + // Proactor will delete the implementation when the call + // completes. +} + +ACE_Asynch_Write_File_Result_Impl * +ACE_Asynch_Write_File::Result::implementation (void) const +{ + return this->implementation_; +} + +// ********************************************************************* + +ACE_Asynch_Accept::ACE_Asynch_Accept (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Accept::~ACE_Asynch_Accept (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Accept::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_accept ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Accept::accept (ACE_Message_Block &message_block, + size_t bytes_to_read, + ACE_HANDLE accept_handle, + const void *act, + int priority, + int signal_number, + int addr_family) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->accept (message_block, + bytes_to_read, + accept_handle, + act, + priority, + signal_number, + addr_family); +} + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Accept::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +size_t +ACE_Asynch_Accept::Result::bytes_to_read (void) const +{ + return this->implementation ()->bytes_to_read (); +} + +ACE_Message_Block & +ACE_Asynch_Accept::Result::message_block (void) const +{ + return this->implementation ()->message_block (); +} + +ACE_HANDLE +ACE_Asynch_Accept::Result::listen_handle (void) const +{ + return this->implementation ()->listen_handle (); +} + +ACE_HANDLE +ACE_Asynch_Accept::Result::accept_handle (void) const +{ + return this->implementation ()->accept_handle (); +} + +ACE_Asynch_Accept::Result::Result (ACE_Asynch_Accept_Result_Impl *implementation) + : ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Accept::Result::~Result (void) +{ + // Proactor will delete the implementation when the call + // completes. +} + +ACE_Asynch_Accept_Result_Impl * +ACE_Asynch_Accept::Result::implementation (void) const +{ + return this->implementation_; +} + + + +// ********************************************************************* + +ACE_Asynch_Connect::ACE_Asynch_Connect (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Connect::~ACE_Asynch_Connect (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Connect::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_connect ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Connect::connect (ACE_HANDLE connect_handle, + const ACE_Addr & remote_sap, + const ACE_Addr & local_sap, + int reuse_addr, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->connect (connect_handle, + remote_sap, + local_sap, + reuse_addr, + act, + priority, + signal_number); +} + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Connect::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Connect::Result::Result (ACE_Asynch_Connect_Result_Impl *implementation) + : ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Connect::Result::~Result (void) +{ + // Proactor will delete the implementation when the call + // completes. +} + +ACE_HANDLE +ACE_Asynch_Connect::Result::connect_handle (void) const +{ + return this->implementation ()->connect_handle (); +} + + +ACE_Asynch_Connect_Result_Impl * +ACE_Asynch_Connect::Result::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Transmit_File::ACE_Asynch_Transmit_File (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Transmit_File::~ACE_Asynch_Transmit_File (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Transmit_File::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_transmit_file ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +int +ACE_Asynch_Transmit_File::transmit_file (ACE_HANDLE file, + Header_And_Trailer *header_and_trailer, + size_t bytes_to_write, + unsigned long offset, + unsigned long offset_high, + size_t bytes_per_send, + unsigned long flags, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->transmit_file (file, + header_and_trailer, + bytes_to_write, + offset, + offset_high, + bytes_per_send, + flags, + act, + priority, + signal_number); +} + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Transmit_File::implementation (void) const +{ + return this->implementation_; +} + +// **************************************************************************** + +ACE_HANDLE +ACE_Asynch_Transmit_File::Result::socket (void) const +{ + return this->implementation ()->socket (); +} + +ACE_HANDLE +ACE_Asynch_Transmit_File::Result::file (void) const +{ + return this->implementation ()->file (); +} + +ACE_Asynch_Transmit_File::Header_And_Trailer * +ACE_Asynch_Transmit_File::Result::header_and_trailer (void) const +{ + return this->implementation ()->header_and_trailer (); +} + +size_t +ACE_Asynch_Transmit_File::Result::bytes_to_write (void) const +{ + return this->implementation ()->bytes_to_write (); +} + +size_t +ACE_Asynch_Transmit_File::Result::bytes_per_send (void) const +{ + return this->implementation ()->bytes_per_send (); +} + +unsigned long +ACE_Asynch_Transmit_File::Result::flags (void) const +{ + return this->implementation ()->flags (); +} + +ACE_Asynch_Transmit_File::Result::Result (ACE_Asynch_Transmit_File_Result_Impl *implementation) + : ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Transmit_File::Result::~Result (void) +{ +} + +ACE_Asynch_Transmit_File_Result_Impl * +ACE_Asynch_Transmit_File::Result::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +ACE_Asynch_Transmit_File::Header_And_Trailer::Header_And_Trailer (ACE_Message_Block *header, + size_t header_bytes, + ACE_Message_Block *trailer, + size_t trailer_bytes) + : header_ (header), + header_bytes_ (header_bytes), + trailer_ (trailer), + trailer_bytes_ (trailer_bytes) +{ +} + +ACE_Asynch_Transmit_File::Header_And_Trailer::~Header_And_Trailer (void) +{ +} + +void +ACE_Asynch_Transmit_File::Header_And_Trailer::header_and_trailer (ACE_Message_Block *header, + size_t header_bytes, + ACE_Message_Block *trailer, + size_t trailer_bytes) +{ + this->header (header); + this->header_bytes (header_bytes); + this->trailer (trailer); + this->trailer_bytes (trailer_bytes); +} + +ACE_Message_Block * +ACE_Asynch_Transmit_File::Header_And_Trailer::header (void) const +{ + return this->header_; +} + +void +ACE_Asynch_Transmit_File::Header_And_Trailer::header (ACE_Message_Block *message_block) +{ + this->header_ = message_block; +} + +size_t +ACE_Asynch_Transmit_File::Header_And_Trailer::header_bytes (void) const +{ + return this->header_bytes_; +} + +void +ACE_Asynch_Transmit_File::Header_And_Trailer::header_bytes (size_t bytes) +{ + this->header_bytes_ = bytes; +} + +ACE_Message_Block * +ACE_Asynch_Transmit_File::Header_And_Trailer::trailer (void) const +{ + return this->trailer_; +} + +void +ACE_Asynch_Transmit_File::Header_And_Trailer::trailer (ACE_Message_Block *message_block) +{ + this->trailer_ = message_block; +} + +size_t +ACE_Asynch_Transmit_File::Header_And_Trailer::trailer_bytes (void) const +{ + return this->trailer_bytes_; +} + +void +ACE_Asynch_Transmit_File::Header_And_Trailer::trailer_bytes (size_t bytes) +{ + this->trailer_bytes_ = bytes; +} + +ACE_LPTRANSMIT_FILE_BUFFERS +ACE_Asynch_Transmit_File::Header_And_Trailer::transmit_buffers (void) +{ + // If both are zero, return zero + if (this->header_ == 0 && this->trailer_ == 0) + { + return 0; + } + else + { + // Something is valid + + // If header is valid, set the fields + if (this->header_ != 0) + { + this->transmit_buffers_.Head = this->header_->rd_ptr (); +#if defined (ACE_WIN64) || defined (ACE_WIN32) + this->transmit_buffers_.HeadLength = + ACE_Utils::truncate_cast (this->header_bytes_); +#else + this->transmit_buffers_.HeadLength = this->header_bytes_; +#endif /* ACE_WIN64 || ACE_WIN32 */ + } + else + { + this->transmit_buffers_.Head = 0; + this->transmit_buffers_.HeadLength = 0; + } + + // If trailer is valid, set the fields + if (this->trailer_ != 0) + { + this->transmit_buffers_.Tail = this->trailer_->rd_ptr (); +#if defined(ACE_WIN64) || defined (ACE_WIN32) + this->transmit_buffers_.TailLength = + ACE_Utils::truncate_cast (this->trailer_bytes_); +#else + this->transmit_buffers_.TailLength = this->trailer_bytes_; +#endif /* ACE_WIN64 || ACE_WIN32 */ + } + else + { + this->transmit_buffers_.Tail = 0; + this->transmit_buffers_.TailLength = 0; + } + + // Return the transmit buffers + return &this->transmit_buffers_; + } +} + +// ********************************************************************* + +ACE_Handler::ACE_Handler (void) + : proactor_ (0), handle_ (ACE_INVALID_HANDLE) +{ + ACE_Handler::Proxy *p; + ACE_NEW (p, ACE_Handler::Proxy (this)); + this->proxy_.reset (p); +} + +ACE_Handler::ACE_Handler (ACE_Proactor *d) + : proactor_ (d), handle_ (ACE_INVALID_HANDLE) +{ + ACE_Handler::Proxy *p; + ACE_NEW (p, ACE_Handler::Proxy (this)); + this->proxy_.reset (p); +} + +ACE_Handler::~ACE_Handler (void) +{ + ACE_Handler::Proxy *p = this->proxy_.get (); + if (p) + p->reset (); +} + +void +ACE_Handler::handle_read_stream (const ACE_Asynch_Read_Stream::Result & /* result */) +{ +} + +void +ACE_Handler::handle_write_stream (const ACE_Asynch_Write_Stream::Result & /* result */) +{ +} + +void +ACE_Handler::handle_write_dgram (const ACE_Asynch_Write_Dgram::Result & /* result */) +{ +} + +void +ACE_Handler::handle_read_dgram (const ACE_Asynch_Read_Dgram::Result & /* result */) +{ +} + +void +ACE_Handler::handle_accept (const ACE_Asynch_Accept::Result & /* result */) +{ +} + +void +ACE_Handler::handle_connect (const ACE_Asynch_Connect::Result & /* result */) +{ +} + +void +ACE_Handler::handle_transmit_file (const ACE_Asynch_Transmit_File::Result & /* result */) +{ +} + +void +ACE_Handler::handle_read_file (const ACE_Asynch_Read_File::Result & /* result */) +{ +} + +void +ACE_Handler::handle_write_file (const ACE_Asynch_Write_File::Result & /* result */) +{ +} + +void +ACE_Handler::handle_time_out (const ACE_Time_Value & /* tv */, + const void * /* act */) +{ +} + +void +ACE_Handler::handle_wakeup (void) +{ +} + +ACE_Proactor * +ACE_Handler::proactor (void) +{ + return this->proactor_; +} + +void +ACE_Handler::proactor (ACE_Proactor *p) +{ + this->proactor_ = p; +} + +ACE_HANDLE +ACE_Handler::handle (void) const +{ + return this->handle_; +} + +void +ACE_Handler::handle (ACE_HANDLE h) +{ + this->handle_ = h; +} + +ACE_Refcounted_Auto_Ptr & +ACE_Handler::proxy (void) +{ + return this->proxy_; +} + +// ************************************************************ + +ACE_Service_Handler::ACE_Service_Handler (void) +{ +} + +ACE_Service_Handler::~ACE_Service_Handler (void) +{ +} + +void +ACE_Service_Handler::addresses (const ACE_INET_Addr & /* remote_address */, + const ACE_INET_Addr & /* local_address */ ) +{ +} + +void +ACE_Service_Handler::act (const void *) +{ +} + +void +ACE_Service_Handler::open (ACE_HANDLE, + ACE_Message_Block &) +{ +} + + +// ************************************************************ + +ACE_Asynch_Read_Dgram::ACE_Asynch_Read_Dgram (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Read_Dgram::~ACE_Asynch_Read_Dgram (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Read_Dgram::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_read_dgram ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +ssize_t +ACE_Asynch_Read_Dgram::recv (ACE_Message_Block *message_block, + size_t &number_of_bytes_recvd, + int flags, + int protocol_family, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->recv (message_block, + number_of_bytes_recvd, + flags, + protocol_family, + act, + priority, + signal_number); +} + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Read_Dgram::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +int +ACE_Asynch_Read_Dgram::Result::remote_address (ACE_Addr& addr) const +{ + return this->implementation ()->remote_address (addr); +} + +ACE_Message_Block* +ACE_Asynch_Read_Dgram::Result::message_block (void) const +{ + return this->implementation ()->message_block (); +} + +int +ACE_Asynch_Read_Dgram::Result::flags (void) const +{ + return this->implementation ()->flags (); +} + +size_t +ACE_Asynch_Read_Dgram::Result::bytes_to_read (void) const +{ + return this->implementation ()->bytes_to_read (); +} + +ACE_HANDLE +ACE_Asynch_Read_Dgram::Result::handle (void) const +{ + return this->implementation ()->handle(); +} + +ACE_Asynch_Read_Dgram::Result::Result (ACE_Asynch_Read_Dgram_Result_Impl *implementation) +: ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Read_Dgram::Result::~Result (void) +{ +} + +ACE_Asynch_Read_Dgram_Result_Impl * +ACE_Asynch_Read_Dgram::Result::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + + +ACE_Asynch_Write_Dgram::ACE_Asynch_Write_Dgram (void) + : implementation_ (0) +{ +} + +ACE_Asynch_Write_Dgram::~ACE_Asynch_Write_Dgram (void) +{ + // Delete the implementation. + delete this->implementation_; + this->implementation_ = 0; +} + +int +ACE_Asynch_Write_Dgram::open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) +{ + // Get a proactor for/from the user. + proactor = this->get_proactor (proactor, handler); + + // Now let us get the implementation initialized. + if ((this->implementation_ = proactor->create_asynch_write_dgram ()) == 0) + return -1; + + // Call the method of the base class. + return ACE_Asynch_Operation::open (handler, + handle, + completion_key, + proactor); +} + +ssize_t +ACE_Asynch_Write_Dgram::send (ACE_Message_Block *message_block, + size_t &number_of_bytes_sent, + int flags, + const ACE_Addr& remote_addr, + const void *act, + int priority, + int signal_number) +{ + if (0 == this->implementation_) + { + errno = EFAULT; + return -1; + } + return this->implementation_->send (message_block, + number_of_bytes_sent, + flags, + remote_addr, + act, + priority, + signal_number); +} + +ACE_Asynch_Operation_Impl * +ACE_Asynch_Write_Dgram::implementation (void) const +{ + return this->implementation_; +} + +// ************************************************************ + +size_t +ACE_Asynch_Write_Dgram::Result::bytes_to_write (void) const +{ + return this->implementation ()->bytes_to_write (); +} + +ACE_Message_Block* +ACE_Asynch_Write_Dgram::Result::message_block () const +{ + return this->implementation ()->message_block (); +} + +int +ACE_Asynch_Write_Dgram::Result::flags (void) const +{ + return this->implementation ()->flags (); +} + +ACE_HANDLE +ACE_Asynch_Write_Dgram::Result::handle (void) const +{ + return this->implementation ()->handle (); +} + +ACE_Asynch_Write_Dgram_Result_Impl * +ACE_Asynch_Write_Dgram::Result::implementation (void) const +{ + return this->implementation_; +} + +ACE_Asynch_Write_Dgram::Result::Result (ACE_Asynch_Write_Dgram_Result_Impl *implementation) +: ACE_Asynch_Result (implementation), + implementation_ (implementation) +{ +} + +ACE_Asynch_Write_Dgram::Result::~Result (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ diff --git a/dep/acelite/ace/Asynch_IO.h b/dep/acelite/ace/Asynch_IO.h new file mode 100644 index 000000000..1c7d5e4b8 --- /dev/null +++ b/dep/acelite/ace/Asynch_IO.h @@ -0,0 +1,1760 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Asynch_IO.h + * + * This works on Win32 (defined (ACE_WIN32) && !defined + * (ACE_HAS_WINCE)) platforms and on POSIX4 platforms with {aio_*} + * routines (defined (ACE_HAS_AIO_CALLS)) + * + * On Win32 platforms, the implementation of + * {ACE_Asynch_Transmit_File} and {ACE_Asynch_Accept} are only + * supported if ACE_HAS_WINSOCK2 is defined or you are on WinNT 4.0 + * or higher. + * + * @author Irfan Pyarali + * @author Tim Harrison + * @author Alexander Babu Arulanthu + * @author Roger Tragin + * @author Alexander Libman + */ +//============================================================================= + +#ifndef ACE_ASYNCH_IO_H +#define ACE_ASYNCH_IO_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) + +#include "ace/Synch_Traits.h" +#if defined (ACE_HAS_THREADS) +# include "ace/Thread_Mutex.h" +#else +# include "ace/Null_Mutex.h" +#endif /* ACE_HAS_THREADS */ +#include "ace/Refcounted_Auto_Ptr.h" + +#include "ace/os_include/os_signal.h" +#include "ace/os_include/sys/os_socket.h" +#include "ace/os_include/sys/os_types.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +# if defined (ACE_HAS_WIN32_OVERLAPPED_IO) +typedef TRANSMIT_FILE_BUFFERS ACE_TRANSMIT_FILE_BUFFERS; +typedef LPTRANSMIT_FILE_BUFFERS ACE_LPTRANSMIT_FILE_BUFFERS; +typedef PTRANSMIT_FILE_BUFFERS ACE_PTRANSMIT_FILE_BUFFERS; + +# define ACE_INFINITE INFINITE +# define ACE_STATUS_TIMEOUT STATUS_TIMEOUT +# define ACE_WAIT_FAILED WAIT_FAILED +# define ACE_WAIT_TIMEOUT WAIT_TIMEOUT +# else /* ACE_HAS_WIN32_OVERLAPPED_IO */ +struct ACE_TRANSMIT_FILE_BUFFERS +{ + void *Head; + size_t HeadLength; + void *Tail; + size_t TailLength; +}; +typedef ACE_TRANSMIT_FILE_BUFFERS* ACE_PTRANSMIT_FILE_BUFFERS; +typedef ACE_TRANSMIT_FILE_BUFFERS* ACE_LPTRANSMIT_FILE_BUFFERS; + +# if !defined (ACE_INFINITE) +# define ACE_INFINITE LONG_MAX +# endif /* ACE_INFINITE */ +# define ACE_STATUS_TIMEOUT LONG_MAX +# define ACE_WAIT_FAILED LONG_MAX +# define ACE_WAIT_TIMEOUT LONG_MAX +# endif /* ACE_HAS_WIN32_OVERLAPPED_IO */ + +// Forward declarations +class ACE_Proactor; +class ACE_Handler; +class ACE_Message_Block; +class ACE_INET_Addr; +class ACE_Addr; + +// Forward declarations +class ACE_Asynch_Result_Impl; +class ACE_Time_Value; + +/** + * @class ACE_Asynch_Result + * + * @brief An interface base class which allows users access to common + * information related to an asynchronous operation. + * + * An interface base class from which you can obtain some basic + * information like the number of bytes transferred, the ACT + * associated with the asynchronous operation, indication of + * success or failure, etc. Subclasses may want to store more + * information that is particular to the asynchronous operation + * it represents. + */ +class ACE_Export ACE_Asynch_Result +{ + +public: + /// Number of bytes transferred by the operation. + size_t bytes_transferred (void) const; + + /// ACT associated with the operation. + const void *act (void) const; + + /// Did the operation succeed? + int success (void) const; + + /** + * This is the ACT associated with the handle on which the + * Asynch_Operation takes place. + * + * On WIN32, this returns the ACT associated with the handle when it + * was registered with the I/O completion port. + * + * @@ This is not implemented for POSIX4 platforms. Returns 0. + */ + const void *completion_key (void) const; + + /// Error value if the operation fails. + unsigned long error (void) const; + + /** + * On WIN32, this returns the event associated with the OVERLAPPED + * structure. + * + * This returns ACE_INVALID_HANDLE on POSIX4-Unix platforms. + */ + ACE_HANDLE event (void) const; + + /** + * This really makes sense only when doing file I/O. + * + * On WIN32, these are represented in the OVERLAPPED datastructure. + * + * @@ On POSIX4-Unix, offset_high should be supported using + * aiocb64. + */ + unsigned long offset (void) const; + unsigned long offset_high (void) const; + + /** + * Priority of the operation. + * + * On POSIX4-Unix, this is supported. Priority works like {nice} in + * Unix. Negative values are not allowed. 0 means priority of the + * operation same as the process priority. 1 means priority of the + * operation is one less than process. And so forth. + * + * On Win32, this is a no-op. + */ + int priority (void) const; + + /** + * POSIX4 real-time signal number to be used for the + * operation. {signal_number} ranges from ACE_SIGRTMIN to ACE_SIGRTMAX. By + * default, ACE_SIGRTMIN is used to issue {aio_} calls. This is a no-op + * on non-POSIX4 systems and returns 0. + */ + int signal_number (void) const; + + + /// Destructor. + virtual ~ACE_Asynch_Result (void); + +protected: + /// Constructor. This implementation will not be deleted. The + /// implementation will be deleted by the Proactor. + ACE_Asynch_Result (ACE_Asynch_Result_Impl *implementation); + + /// Get the implementation class. + ACE_Asynch_Result_Impl *implementation (void) const; + + /// Implementation class. + ACE_Asynch_Result_Impl *implementation_; +}; + +// Forward declarations +class ACE_Asynch_Operation_Impl; + +/** + * @class ACE_Asynch_Operation + * + * @brief This is an interface base class for all asynch + * operations. The resposiblility of this class is to forward + * all methods to its delegation/implementation class, e.g., + * ACE_WIN32_Asynch_Operation or ACE_POSIX_Asynch_Operation. + * + * There are some attributes and functionality which is common + * to all asychronous operations. The delegation classes of this + * class will factor out this code. + */ +class ACE_Export ACE_Asynch_Operation +{ + +public: + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor); + + /** + * (Attempts to) cancel the asynchronous operation pending against + * the {handle} registered with this Operation. + * + * All completion notifications for the I/O operations will occur + * normally. + * + * = Return Values: + * + * -1 : Operation failed. (can get only in POSIX). + * 0 : All the operations were cancelled. + * 1 : All the operations were already finished in this + * handle. Unable to cancel them. + * 2 : Atleast one of the requested operations cannot be + * cancelled. + * + * There is slight difference in the semantics between NT and POSIX + * platforms which is given below. + * + * = Win32 : + * + * cancels all pending accepts operations that were issued by the + * calling thread. The function does not cancel asynchronous + * operations issued by other threads. + * All I/O operations that are canceled will complete with the + * error ERROR_OPERATION_ABORTED. + * + * = POSIX: + * + * Attempts to cancel one or more asynchronous I/O requests + * currently outstanding against the {handle} registered in this + * operation. + * For requested operations that are successfully canceled, the + * associated error status is set to ECANCELED. + */ + int cancel (void); + + + // = Access methods. + + /// Return the underlying proactor. + ACE_Proactor* proactor (void) const; + + /// Destructor. + virtual ~ACE_Asynch_Operation (void); + +protected: + /// Constructor. + ACE_Asynch_Operation (void); + + /// Return the underlying implementation class. + virtual ACE_Asynch_Operation_Impl *implementation (void) const = 0; + + /// Get a proactor for/from the user + ACE_Proactor *get_proactor (ACE_Proactor *user_proactor, + ACE_Handler &handler) const; +}; + +// Forward declarations +class ACE_Asynch_Read_Stream_Result_Impl; +class ACE_Asynch_Read_Stream_Impl; + +/** + * @class ACE_Asynch_Read_Stream + * + * @brief This class is a factory for starting off asynchronous reads + * on a stream. This class forwards all methods to its + * implementation class. + * + * Once {open} is called, multiple asynchronous {read}s can + * started using this class. An ACE_Asynch_Read_Stream::Result + * will be passed back to the {handler} when the asynchronous + * reads completes through the {ACE_Handler::handle_read_stream} + * callback. + */ +class ACE_Export ACE_Asynch_Read_Stream : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Read_Stream (void); + + /// Destructor + virtual ~ACE_Asynch_Read_Stream (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. + * + * @param handler The ACE_Handler that will be called to handle completions + * for operations initiated using this factory. + * @param handle The handle that future read operations will use. + * If handle == @c ACE_INVALID_HANDLE, + * ACE_Handler::handle() will be called on @ handler + * to get the correct handle. + * + * @retval 0 for success. + * @retval -1 for failure; consult @c errno for further information. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * Initiate an asynchronous read operation. + * + * @param message_block The ACE_Message_Block to receive the data. + * Received bytes will be placed in the block + * beginning at its current write pointer. + * If data is read, the message block's write + * pointer will be advanced by the number of + * bytes read. + * @param num_bytes_to_read The maximum number of bytes to read. + * @param act Asynchronous Completion Token; passed through to + * the completion handler in the Result object. + * @param priority Priority of the operation. On POSIX4-Unix, + * this is supported. Works like @c nice in Unix. + * Negative values are not allowed. 0 means + * priority of the operation same as the process + * priority. 1 means priority of the operation is + * one less than process priority, etc. + * Ignored on Windows. + * @param signal_number The POSIX4 real-time signal number to be used + * to signal completion of the operation. Values + * range from ACE_SIGRTMIN to ACE_SIGRTMAX. + * This argument is ignored on non-POSIX4 systems. + */ + int read (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) + /** + * Same as above but with scatter support, through chaining of composite + * message blocks using the continuation field. + */ + int readv (ACE_Message_Block &message_block, + size_t num_bytes_to_read, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); +#endif /* defined (ACE_HAS_WIN32_OVERLAPPED_IO) */ + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Implementation class that all methods will be forwarded to. + ACE_Asynch_Read_Stream_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is the class which will be passed back to the + * ACE_Handler::handle_read_stream when the asynchronous read completes. + * This class forwards all the methods to the implementation classes. + * + * This class has all the information necessary for the + * handler to uniquiely identify the completion of the + * asynchronous read. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Read_Stream_Result; + friend class ACE_WIN32_Asynch_Read_Stream_Result; + + public: + /// The number of bytes which were requested at the start of the + /// asynchronous read. + size_t bytes_to_read (void) const; + + /// Message block which contains the read data. + ACE_Message_Block &message_block (void) const; + + /// I/O handle used for reading. + ACE_HANDLE handle (void) const; + + /// Get the implementation class. + ACE_Asynch_Read_Stream_Result_Impl *implementation (void) const; + + protected: + /// Constructor. + Result (ACE_Asynch_Read_Stream_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// The implementation class. + ACE_Asynch_Read_Stream_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Read_Stream &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Read_Stream (const ACE_Asynch_Read_Stream &)) +}; + +// Forward declarations +class ACE_Asynch_Write_Stream_Impl; +class ACE_Asynch_Write_Stream_Result_Impl; + +/** + * @class ACE_Asynch_Write_Stream + * + * @brief This class is a factory for initiating asynchronous writes + * on a connected TCP/IP stream. This class forwards all methods to its + * implementation class. + * + * Once open() is called, multiple asynchronous writes can be + * started using this class. An ACE_Asynch_Write_Stream::Result + * will be passed to the ACE_Handler::handle_write_stream() method on the + * opened ACE_Handler object when the asynchronous write completes. + */ +class ACE_Export ACE_Asynch_Write_Stream : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Write_Stream (void); + + /// Destructor. + virtual ~ACE_Asynch_Write_Stream (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous operation. + * + * @param handler ACE_Handler to be notified when operations initiated + * via this factory complete. The handle_write_stream() + * method will be called on this object. + * @param handle The socket handle to initiate write operations on. + * If handle is @c ACE_INVALID_HANDLE, + * ACE_Handler::handle() will be called on handler to + * get the handle value. + * @param completion_key A token that is passed to the completion handler. + * @param proactor The ACE_Proactor object which will control operation + * completion and dispatching the results to handler. + * If this is 0, the process's singleton ACE_Proactor + * will be used. + * + * @retval 0 for success. + * @retval -1 for failure; consult @c errno for further information. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * Initiates an asynchronous write on a socket. If the operation completes + * the ACE_Handler object registered in open() will receive a completion + * callback via its handle_write_stream() method. + * + * @param bytes_to_write The number of bytes to write. + * @param message_block The ACE_Message_Block containing data to write. + * Data is written to the socket beginning at the + * block's rd_ptr. Upon successful completion + * of the write operation, the message_block rd_ptr + * is updated to reflect the data that was written. + * @param act Token that is passed through to the completion + * handler. + * @param priority Priority of the operation. This argument only has + * an affect on POSIX4-Unix. Works like @c nice in + * Unix; negative values are not allowed. 0 means + * priority of the operation same as the process + * priority. 1 means priority of the operation is one + * less than the process, and so forth. + * @param signal_number The POSIX4 real-time signal number to be used + * for the operation. signal_number ranges from + * ACE_SIGRTMIN to ACE_SIGRTMAX. This argument is + * not used on other platforms. + * + * @retval 0 for success, and the handle_write_stream associated + * with the opened ACE_Handler will be called. An + * instance of ACE_Asynch_Write_Stream::Result will be + * passed to the completion handler. + * @retval -1 for failure; consult @c errno for further information. + */ + int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) + /** + * Same as above but with gather support, through chaining of composite + * message blocks using the continuation field. + */ + int writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); +#endif /* defined (ACE_HAS_WIN32_OVERLAPPED_IO) */ + + /// Return the underlying implementation class. + /// @todo (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Implementation class that all methods will be forwarded to. + ACE_Asynch_Write_Stream_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * ACE_Handler when the asynchronous write completes. This class + * forwards all the methods to the implementation class. + * + * This class has all the information necessary for the + * handler to uniquiely identify the completion of the + * asynchronous write. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Write_Stream_Result; + friend class ACE_WIN32_Asynch_Write_Stream_Result; + + public: + /// The number of bytes which were requested at the start of the + /// asynchronous write. + size_t bytes_to_write (void) const; + + /// Message block that contains the data to be written. + ACE_Message_Block &message_block (void) const; + + /// I/O handle used for writing. + ACE_HANDLE handle (void) const; + + /// Get the implementation class. + ACE_Asynch_Write_Stream_Result_Impl *implementation (void) const; + + protected: + /// Constructor. + Result (ACE_Asynch_Write_Stream_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// Implementation class. + ACE_Asynch_Write_Stream_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Write_Stream &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Write_Stream (const ACE_Asynch_Write_Stream &)) +}; + +// Forward declarations +class ACE_Asynch_Read_File_Impl; +class ACE_Asynch_Read_File_Result_Impl; + +/** + * @class ACE_Asynch_Read_File + * + * @brief This class is a factory for starting off asynchronous reads + * on a file. This class forwards all methods to its + * implementation class. + * + * Once open() is called, multiple asynchronous reads can + * started using this class. An ACE_Asynch_Read_File::Result + * will be passed back to the completion handler's + * ACE_Handler::handle_read_file() method when each asynchronous + * read completes. + * This class differs slightly from ACE_Asynch_Read_Stream as it + * allows the user to specify an offset for the read. + */ +class ACE_Export ACE_Asynch_Read_File : public ACE_Asynch_Read_Stream +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Read_File (void); + + /// Destructor. + virtual ~ACE_Asynch_Read_File (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous operation. + * + * @param handler ACE_Handler to be notified when operations initiated + * via this factory complete. The + * ACE_Handler::handle_read_file() method will be + * called on this object. + * @param handle The file handle to initiate read operations on. + * If handle is @c ACE_INVALID_HANDLE, + * ACE_Handler::handle() will be called on handler to + * get the handle value. + * @param completion_key A token that is passed to the completion handler. + * @param proactor The ACE_Proactor object which will control operation + * completion and dispatching the results to handler. + * If this is 0, the process's singleton ACE_Proactor + * will be used. + * + * @retval 0 for success. + * @retval -1 for failure; consult @c errno for further information. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * This starts off an asynchronous read. Upto {bytes_to_read} will + * be read and stored in the {message_block}. The read will start + * at {offset} from the beginning of the file. Priority of the + * operation is specified by {priority}. On POSIX4-Unix, this is + * supported. Works like {nice} in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, this argument is a no-op. + * {signal_number} is the POSIX4 real-time signal number to be used + * for the operation. {signal_number} ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + int read (ACE_Message_Block &message_block, + size_t bytes_to_read, + unsigned long offset = 0, + unsigned long offset_high = 0, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with scatter support, through chaining of composite + * message blocks using the continuation field. + * @note In win32 Each data block payload must be at least the size of a system + * memory page and must be aligned on a system memory page size boundary + */ + int readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + unsigned long offset = 0, + unsigned long offset_high = 0, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Delegation/implementation class that all methods will be + /// forwarded to. + ACE_Asynch_Read_File_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * {handler} when the asynchronous read completes. This class + * forwards all the methods to the implementation class. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous read. + * This class differs slightly from + * ACE_Asynch_Read_Stream::Result as it calls back + * {ACE_Handler::handle_read_file} on the {handler} instead of + * {ACE_Handler::handle_read_stream}. No additional state is + * required by this class as ACE_Asynch_Result can store the + * {offset}. + */ + class ACE_Export Result : public ACE_Asynch_Read_Stream::Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Read_File_Result; + friend class ACE_WIN32_Asynch_Read_File_Result; + + public: + /// Get the implementation class. + ACE_Asynch_Read_File_Result_Impl *implementation (void) const; + + protected: + /// Constructor. This implementation will not be deleted. + Result (ACE_Asynch_Read_File_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// The implementation class. + ACE_Asynch_Read_File_Result_Impl *implementation_; + + private: + /// Here just to provide an dummpy implementation, since the + /// one auto generated by MSVC is flagged as infinitely recursive + void operator= (Result &) {} + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Read_File &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Read_File (const ACE_Asynch_Read_File &)) +}; + +// Forward declarations +class ACE_Asynch_Write_File_Impl; +class ACE_Asynch_Write_File_Result_Impl; + +/** + * @class ACE_Asynch_Write_File + * + * @brief This class is a factory for starting off asynchronous writes + * on a file. This class forwards all methods to its + * implementation class. + * + * Once {open} is called, multiple asynchronous {write}s can be + * started using this class. A ACE_Asynch_Write_File::Result + * will be passed back to the {handler} when the asynchronous + * writes completes through the {ACE_Handler::handle_write_file} + * callback. + * This class differs slightly from ACE_Asynch_Write_Stream as + * it allows the user to specify an offset for the write. + */ +class ACE_Export ACE_Asynch_Write_File : public ACE_Asynch_Write_Stream +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Write_File (void); + + /// Destructor. + virtual ~ACE_Asynch_Write_File (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * This starts off an asynchronous write. Upto {bytes_to_write} + * will be written from the {message_block}, starting at the + * block's {rd_ptr}. The write will go to the file, starting + * {offset} bytes from the beginning of the file. Priority of the + * operation is specified by {priority}. On POSIX4-Unix, this is + * supported. Works like {nice} in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, this is a no-op. + * {signal_number} is the POSIX4 real-time signal number to be used + * for the operation. {signal_number} ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + unsigned long offset = 0, + unsigned long offset_high = 0, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with gather support, through chaining of composite + * message blocks using the continuation field. + * @note In win32 Each data block payload must be at least the size of a system + * memory page and must be aligned on a system memory page size boundary + */ + int writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + unsigned long offset = 0, + unsigned long offset_high = 0, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Implementation object. + ACE_Asynch_Write_File_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * {handler} when the asynchronous write completes. This class + * forwards all the methods to the implementation class. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous write. + * This class differs slightly from + * ACE_Asynch_Write_Stream::Result as it calls back + * {ACE_Handler::handle_write_file} on the {handler} instead + * of {ACE_Handler::handle_write_stream}. No additional state + * is required by this class as ACE_Asynch_Result can store + * the {offset}. + */ + class ACE_Export Result : public ACE_Asynch_Write_Stream::Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Write_File_Result; + friend class ACE_WIN32_Asynch_Write_File_Result; + + public: + /// Get the implementation class. + ACE_Asynch_Write_File_Result_Impl *implementation (void) const; + + protected: + /// Constructor. This implementation will not be deleted. + Result (ACE_Asynch_Write_File_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// The implementation class. + ACE_Asynch_Write_File_Result_Impl *implementation_; + + private: + /// Here just to provide an dummpy implementation, since the + /// one auto generated by MSVC is flagged as infinitely recursive + void operator= (Result &) {}; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Write_File &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Write_File (const ACE_Asynch_Write_File &)) +}; + +// Forward declarations +class ACE_Asynch_Accept_Result_Impl; +class ACE_Asynch_Accept_Impl; + +/** + * @class ACE_Asynch_Accept + * + * @brief This class is a factory for starting off asynchronous accepts + * on a listen handle. This class forwards all methods to its + * implementation class. + * + * Once {open} is called, multiple asynchronous {accept}s can + * started using this class. A ACE_Asynch_Accept::Result will + * be passed back to the {handler} when the asynchronous accept + * completes through the {ACE_Handler::handle_accept} + * callback. + */ +class ACE_Export ACE_Asynch_Accept : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Accept (void); + + /// Destructor. + virtual ~ACE_Asynch_Accept (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * This starts off an asynchronous accept. The asynchronous accept + * call also allows any initial data to be returned to the + * handler specified to @c open(). + * @param message_block A message block to receive initial data, as well + * as the local and remote addresses when the + * connection is made. Since the block receives + * the addresses regardless of whether or not + * initial data is available or requested, the + * message block size must be at least + * @a bytes_to_read plus two times the size of + * the addresses used (IPv4 or IPv6). + * @param bytes_to_read The maximum number of bytes of initial data + * to read into @a message_block. + * @param accept_handle The handle that the new connection will be + * accepted on. If @c INVALID_HANDLE, a new + * handle will be created using @a addr_family. + * @param act Value to be passed in result when operation + * completes. + * @param priority Priority of the operation. On POSIX4-Unix, this + * is supported. Works like @c nice in Unix. + * Negative values are not allowed. 0 means + * priority of the operation same as the process + * priority. 1 means priority of the operation is + * one less than process. And so forth. + * On Win32, this argument is ignored. + * @param signal_number The POSIX4 real-time signal number to be used + * for the operation. Value range is from + * @c ACE_SIGRTMIN to @c ACE_SIGRTMAX. + * This argument is ignored on non-POSIX4 systems. + * @param addr_family The address family to use if @a accept_handle + * is @c ACE_INVALID_HANDLE and a new handle must + * be opened. Values are @c AF_INET and @c PF_INET6. + */ + int accept (ACE_Message_Block &message_block, + size_t bytes_to_read, + ACE_HANDLE accept_handle = ACE_INVALID_HANDLE, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN, + int addr_family = AF_INET); + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Delegation/implementation class that all methods will be + /// forwarded to. + ACE_Asynch_Accept_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * {handler} when the asynchronous accept completes. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous accept. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Accept_Result; + friend class ACE_WIN32_Asynch_Accept_Result; + + public: + /// The number of bytes which were requested at the start of the + /// asynchronous accept. + size_t bytes_to_read (void) const; + + /// Message block which contains the read data. + ACE_Message_Block &message_block (void) const; + + /// I/O handle used for accepting new connections. + ACE_HANDLE listen_handle (void) const; + + /// I/O handle for the new connection. + ACE_HANDLE accept_handle (void) const; + + /// Get the implementation. + ACE_Asynch_Accept_Result_Impl *implementation (void) const; + + protected: + /// Constructor. Implementation will not be deleted. + Result (ACE_Asynch_Accept_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// Implementation class. + ACE_Asynch_Accept_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Accept &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Accept (const ACE_Asynch_Accept &)) +}; +// Forward declarations +class ACE_Asynch_Connect_Result_Impl; +class ACE_Asynch_Connect_Impl; + +/** + * @class ACE_Asynch_Connect + * + * @brief This class is a factory for starting off asynchronous connects + * This class forwards all methods to its implementation class. + * + * Once @c open is called, multiple asynchronous connect operationss can + * started using this class. A ACE_Asynch_Connect::Result will + * be passed back to the associated ACE_Handler when the asynchronous connect + * completes through the ACE_Handler::handle_connect() callback. + */ +class ACE_Export ACE_Asynch_Connect : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Connect (void); + + /// Destructor. + virtual ~ACE_Asynch_Connect (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. + * + * @note @arg handle is ignored and should be @c ACE_INVALID_HANDLE. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * This starts off an asynchronous Connect. + */ + int connect (ACE_HANDLE connect_handle, + const ACE_Addr & remote_sap, + const ACE_Addr & local_sap, + int reuse_addr, + const void *act=0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Delegation/implementation class that all methods will be + /// forwarded to. + ACE_Asynch_Connect_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * handler when the asynchronous connect completes. + * + * This class has all the information necessary for the + * handler to uniquely identify the completion of the + * asynchronous connect. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Connect_Result; + friend class ACE_WIN32_Asynch_Connect_Result; + + public: + + /// I/O handle for the connection. + ACE_HANDLE connect_handle (void) const; + + /// Get the implementation. + ACE_Asynch_Connect_Result_Impl *implementation (void) const; + + protected: + /// Constructor. Implementation will not be deleted. + Result (ACE_Asynch_Connect_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// Implementation class. + ACE_Asynch_Connect_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Connect &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Connect (const ACE_Asynch_Connect &)) +}; + +// Forward declarations +class ACE_Asynch_Transmit_File_Result_Impl; +class ACE_Asynch_Transmit_File_Impl; + +/** + * @class ACE_Asynch_Transmit_File + * + * @brief This class is a factory for starting off asynchronous + * transmit files on a stream. + * + * Once {open} is called, multiple asynchronous {transmit_file}s + * can started using this class. A + * ACE_Asynch_Transmit_File::Result will be passed back to the + * {handler} when the asynchronous transmit file completes + * through the {ACE_Handler::handle_transmit_file} callback. + * The transmit_file function transmits file data over a + * connected network connection. The function uses the operating + * system's cache manager to retrieve the file data. This + * function provides high-performance file data transfer over + * network connections. This function would be of great use in + * a Web Server, Image Server, etc. + */ +class ACE_Export ACE_Asynch_Transmit_File : public ACE_Asynch_Operation +{ + +public: + // Forward declarations + class Header_And_Trailer; + + /// A do nothing constructor. + ACE_Asynch_Transmit_File (void); + + /// Destructor. + virtual ~ACE_Asynch_Transmit_File (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** + * This starts off an asynchronous transmit file. The {file} is a + * handle to an open file. {header_and_trailer} is a pointer to a + * data structure that contains pointers to data to send before and + * after the file data is sent. Set this parameter to 0 if you only + * want to transmit the file data. Upto {bytes_to_write} will be + * written to the {socket}. If you want to send the entire file, + * let {bytes_to_write} = 0. {bytes_per_send} is the size of each + * block of data sent per send operation. Please read the Win32 + * documentation on what the flags should be. Priority of the + * operation is specified by {priority}. On POSIX4-Unix, this is + * supported. Works like {nice} in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, this is a no-op. + * {signal_number} is the POSIX4 real-time signal number to be used + * for the operation. {signal_number} ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + int transmit_file (ACE_HANDLE file, + Header_And_Trailer *header_and_trailer = 0, + size_t bytes_to_write = 0, + unsigned long offset = 0, + unsigned long offset_high = 0, + size_t bytes_per_send = 0, + unsigned long flags = 0, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// The implementation class. + ACE_Asynch_Transmit_File_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * {handler} when the asynchronous transmit file completes. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous transmit file. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Transmit_File_Result; + friend class ACE_WIN32_Asynch_Transmit_File_Result; + + public: + /// Socket used for transmitting the file. + ACE_HANDLE socket (void) const; + + /// File from which the data is read. + ACE_HANDLE file (void) const; + + /// Header and trailer data associated with this transmit file. + Header_And_Trailer *header_and_trailer (void) const; + + /// The number of bytes which were requested at the start of the + /// asynchronous transmit file. + size_t bytes_to_write (void) const; + + /// Number of bytes per send requested at the start of the transmit + /// file. + size_t bytes_per_send (void) const; + + /// Flags which were passed into transmit file. + unsigned long flags (void) const; + + /// Get the implementation class. + ACE_Asynch_Transmit_File_Result_Impl *implementation (void) const; + + protected: + /// Constructor. + Result (ACE_Asynch_Transmit_File_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// The implementation class. + ACE_Asynch_Transmit_File_Result_Impl *implementation_; + }; + +/** + * @class Header_And_Trailer + * + * @brief The class defines a data structure that contains pointers + * to data to send before and after the file data is sent. + * + * This class provides a wrapper over TRANSMIT_FILE_BUFFERS + * and provided a consistent use of ACE_Message_Blocks. + */ + class ACE_Export Header_And_Trailer + { + + public: + /// Constructor. + Header_And_Trailer (ACE_Message_Block *header = 0, + size_t header_bytes = 0, + ACE_Message_Block *trailer = 0, + size_t trailer_bytes = 0); + + /// Destructor + virtual ~Header_And_Trailer (void); + + /// This method allows all the member to be set in one fell swoop. + void header_and_trailer (ACE_Message_Block *header = 0, + size_t header_bytes = 0, + ACE_Message_Block *trailer = 0, + size_t trailer_bytes = 0); + + /// Get header which goes before the file data. + ACE_Message_Block *header (void) const; + + /// Set header which goes before the file data. + void header (ACE_Message_Block *message_block); + + /// Get size of the header data. + size_t header_bytes (void) const; + + /// Set size of the header data. + void header_bytes (size_t bytes); + + /// Get trailer which goes after the file data. + ACE_Message_Block *trailer (void) const; + + /// Set trailer which goes after the file data. + void trailer (ACE_Message_Block *message_block); + + /// Get size of the trailer data. + size_t trailer_bytes (void) const; + + /// Set size of the trailer data. + void trailer_bytes (size_t bytes); + + /// Conversion routine. + ACE_LPTRANSMIT_FILE_BUFFERS transmit_buffers (void); + + protected: + /// Header data. + ACE_Message_Block *header_; + + /// Size of header data. + size_t header_bytes_; + + /// Trailer data. + ACE_Message_Block *trailer_; + + /// Size of trailer data. + size_t trailer_bytes_; + + /// Target data structure. + ACE_TRANSMIT_FILE_BUFFERS transmit_buffers_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Transmit_File &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Transmit_File (const ACE_Asynch_Transmit_File &)) +}; + + +// Forward declarations +class ACE_Asynch_Read_Dgram_Result_Impl; +class ACE_Asynch_Read_Dgram_Impl; +class ACE_Addr; + +/** + * @class ACE_Asynch_Read_Dgram + * + * @brief This class is a factory for starting off asynchronous reads + * on a UDP socket. This class forwards all methods to its + * implementation class. + * + * Once {open} is called, multiple asynchronous {read}s can be + * started using this class. An ACE_Asynch_Read_Dgram::Result + * will be passed back to the {handler} when the asynchronous + * reads completes through the {ACE_Handler::handle_read_dgram} + * callback. + */ +class ACE_Export ACE_Asynch_Read_Dgram : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Read_Dgram (void); + + /// Destructor + virtual ~ACE_Asynch_Read_Dgram (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** This starts off an asynchronous read. Upto + * {message_block->total_size()} will be read and stored in the + * {message_block}. {message_block}'s {wr_ptr} will be updated to reflect + * the added bytes if the read operation is successfully completed. + * Return code of 1 means immediate success and {number_of_bytes_recvd} + * will contain number of bytes read. The {ACE_Handler::handle_read_dgram} + * method will still be called. Return code of 0 means the IO will + * complete proactively. Return code of -1 means there was an error, use + * errno to get the error code. + * + * Scatter/gather is supported on WIN32 by using the {message_block->cont()} + * method. Up to ACE_IOV_MAX {message_block}'s are supported. Upto + * {message_block->size()} bytes will be read into each {message block} for + * a total of {message_block->total_size()} bytes. All {message_block}'s + * {wr_ptr}'s will be updated to reflect the added bytes for each + * {message_block} + * + * Priority of the operation is specified by {priority}. On POSIX4-Unix, + * this is supported. Works like {nice} in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, {priority} is a no-op. + * {signal_number} is the POSIX4 real-time signal number to be used + * for the operation. {signal_number} ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + ssize_t recv (ACE_Message_Block *message_block, + size_t &number_of_bytes_recvd, + int flags, + int protocol_family = PF_INET, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Implementation class that all methods will be forwarded to. + ACE_Asynch_Read_Dgram_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is the class which will be passed back to the + * {handler} when the asynchronous read completes. This class + * forwards all the methods to the implementation classes. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous read. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Read_Dgram_Result; + friend class ACE_WIN32_Asynch_Read_Dgram_Result; + + public: + + /// The number of bytes which were requested at the start of the + /// asynchronous read. + size_t bytes_to_read (void) const; + + /// Message block which contains the read data + ACE_Message_Block *message_block (void) const; + + /// The flags used in the read + int flags (void) const; + + /// The address of where the packet came from + int remote_address (ACE_Addr& addr) const; + + /// I/O handle used for reading. + ACE_HANDLE handle (void) const; + + /// Get the implementation class. + ACE_Asynch_Read_Dgram_Result_Impl *implementation (void) const; + + protected: + /// Constructor. + Result (ACE_Asynch_Read_Dgram_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// The implementation class. + ACE_Asynch_Read_Dgram_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Read_Dgram &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Read_Dgram (const ACE_Asynch_Read_Dgram &)) +}; + +// Forward declarations +class ACE_Asynch_Write_Dgram_Impl; +class ACE_Asynch_Write_Dgram_Result_Impl; + +/** + * @class ACE_Asynch_Write_Dgram + * + * @brief This class is a factory for starting off asynchronous writes + * on a UDP socket. This class forwards all methods to its + * implementation class. + * + * Once {open} is called, multiple asynchronous {writes}s can + * started using this class. An ACE_Asynch_Write_Dgram::Result + * will be passed back to the {handler} when the asynchronous + * write completes through the + * {ACE_Handler::handle_write_dgram} callback. + */ +class ACE_Export ACE_Asynch_Write_Dgram : public ACE_Asynch_Operation +{ + +public: + /// A do nothing constructor. + ACE_Asynch_Write_Dgram (void); + + /// Destructor. + virtual ~ACE_Asynch_Write_Dgram (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If ({handle} == ACE_INVALID_HANDLE), + * {ACE_Handler::handle} will be called on the {handler} to get the + * correct handle. + */ + int open (ACE_Handler &handler, + ACE_HANDLE handle = ACE_INVALID_HANDLE, + const void *completion_key = 0, + ACE_Proactor *proactor = 0); + + /** This starts off an asynchronous send. Upto + * {message_block->total_length()} will be sent. {message_block}'s + * {rd_ptr} will be updated to reflect the sent bytes if the send operation + * is successfully completed. + * Return code of 1 means immediate success and {number_of_bytes_sent} + * is updated to number of bytes sent. The {ACE_Handler::handle_write_dgram} + * method will still be called. Return code of 0 means the IO will + * complete proactively. Return code of -1 means there was an error, use + * errno to get the error code. + * + * Scatter/gather is supported on WIN32 by using the {message_block->cont()} + * method. Up to ACE_IOV_MAX {message_block}'s are supported. Upto + * {message_block->length()} bytes will be sent from each {message block} + * for a total of {message_block->total_length()} bytes. All + * {message_block}'s {rd_ptr}'s will be updated to reflect the bytes sent + * from each {message_block}. + * + * Priority of the operation is specified by {priority}. On POSIX4-Unix, + * this is supported. Works like {nice} in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, this argument is a no-op. + * {signal_number} is the POSIX4 real-time signal number to be used + * for the operation. {signal_number} ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + ssize_t send (ACE_Message_Block *message_block, + size_t &number_of_bytes_sent, + int flags, + const ACE_Addr& remote_addr, + const void *act = 0, + int priority = 0, + int signal_number = ACE_SIGRTMIN); + + /// Return the underlying implementation class. + // (this should be protected...) + virtual ACE_Asynch_Operation_Impl *implementation (void) const; + +protected: + /// Implementation class that all methods will be forwarded to. + ACE_Asynch_Write_Dgram_Impl *implementation_; + +public: +/** + * @class Result + * + * @brief This is that class which will be passed back to the + * {handler} when the asynchronous write completes. This class + * forwards all the methods to the implementation class. + * + * This class has all the information necessary for the + * {handler} to uniquiely identify the completion of the + * asynchronous write. + */ + class ACE_Export Result : public ACE_Asynch_Result + { + + /// The concrete implementation result classes only construct this + /// class. + friend class ACE_POSIX_Asynch_Write_Dgram_Result; + friend class ACE_WIN32_Asynch_Write_Dgram_Result; + + public: + + /// The number of bytes which were requested at the start of the + /// asynchronous write. + size_t bytes_to_write (void) const; + + /// Message block which contains the sent data + ACE_Message_Block *message_block (void) const; + + /// The flags using in the write + int flags (void) const; + + /// I/O handle used for writing. + ACE_HANDLE handle (void) const; + + /// Get the implementation class. + ACE_Asynch_Write_Dgram_Result_Impl *implementation (void) const; + + protected: + /// Constructor. + Result (ACE_Asynch_Write_Dgram_Result_Impl *implementation); + + /// Destructor. + virtual ~Result (void); + + /// Implementation class. + ACE_Asynch_Write_Dgram_Result_Impl *implementation_; + }; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Asynch_Write_Dgram &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Asynch_Write_Dgram (const ACE_Asynch_Write_Dgram &)) +}; + + +/** + * @class ACE_Handler + * + * @brief This base class defines the interface for receiving the + * results of asynchronous operations. + * + * Subclasses of this class will fill in appropriate methods. + */ +class ACE_Export ACE_Handler +{ +public: + /// A do nothing constructor. + ACE_Handler (void); + + /// A do nothing constructor which allows proactor to be set to \. + ACE_Handler (ACE_Proactor *p); + + /// Virtual destruction. + virtual ~ACE_Handler (void); + + /// This method will be called when an asynchronous read completes on + /// a stream. + virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result); + + /// This method will be called when an asynchronous write completes + /// on a UDP socket. + virtual void handle_write_dgram (const ACE_Asynch_Write_Dgram::Result &result); + + /// This method will be called when an asynchronous read completes on + /// a UDP socket. + virtual void handle_read_dgram (const ACE_Asynch_Read_Dgram::Result &result); + + /// This method will be called when an asynchronous write completes + /// on a stream. + virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result); + + /// This method will be called when an asynchronous read completes on + /// a file. + virtual void handle_read_file (const ACE_Asynch_Read_File::Result &result); + + /// This method will be called when an asynchronous write completes + /// on a file. + virtual void handle_write_file (const ACE_Asynch_Write_File::Result &result); + + /// This method will be called when an asynchronous accept completes. + virtual void handle_accept (const ACE_Asynch_Accept::Result &result); + + /// This method will be called when an asynchronous connect completes. + virtual void handle_connect (const ACE_Asynch_Connect::Result &result); + + /// This method will be called when an asynchronous transmit file + /// completes. + virtual void handle_transmit_file (const ACE_Asynch_Transmit_File::Result &result); + + /// Called when timer expires. {tv} was the requested time value and + /// {act} is the ACT passed when scheduling the timer. + virtual void handle_time_out (const ACE_Time_Value &tv, + const void *act = 0); + + /** + * This is method works with the {run_event_loop} of the + * ACE_Proactor. A special {Wake_Up_Completion} is used to wake up + * all the threads that are blocking for completions. + */ + virtual void handle_wakeup (void); + + /// Get the proactor associated with this handler. + ACE_Proactor *proactor (void); + + /// Set the proactor. + void proactor (ACE_Proactor *p); + + /** + * Get the I/O handle used by this {handler}. This method will be + * called by the ACE_Asynch_* classes when an ACE_INVALID_HANDLE is + * passed to {open}. + */ + virtual ACE_HANDLE handle (void) const; + + /// Set the ACE_HANDLE value for this Handler. + virtual void handle (ACE_HANDLE); + + /** + * @class Proxy + * + * @brief The Proxy class acts as a proxy for dispatch of completions + * to operations issued for the associated handler. It allows the handler + * to be deleted while operations are outstanding. The proxy must be used + * to get the ACE_Handler pointer for dispatching, and if it's 0, the + * handler is no longer valid and the result should not be dispatched. + */ + class ACE_Export Proxy + { + public: + Proxy (ACE_Handler *handler) : handler_ (handler) {}; + void reset (void) { this->handler_ = 0; }; + ACE_Handler *handler (void) { return this->handler_; }; + private: + ACE_Handler *handler_; + }; + typedef ACE_Refcounted_Auto_Ptr + Proxy_Ptr; + + Proxy_Ptr &proxy (void); + +protected: + /// The proactor associated with this handler. + ACE_Proactor *proactor_; + + /// The ACE_HANDLE in use with this handler. + ACE_HANDLE handle_; + + /// Refers to proxy for this handler. + ACE_Refcounted_Auto_Ptr proxy_; + +private: + ACE_UNIMPLEMENTED_FUNC (ACE_Handler (const ACE_Handler &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Handler operator= (const ACE_Handler &)) +}; + +// Forward declarations +class ACE_INET_Addr; + +// Forward declarations +template +class ACE_Asynch_Acceptor; + +/** + * @class ACE_Service_Handler + * + * @brief This base class defines the interface for the + * ACE_Asynch_Acceptor to call into when new connection are + * accepted. + * + * Subclasses of this class will fill in appropriate methods to + * define application specific behavior. + */ +class ACE_Export ACE_Service_Handler : public ACE_Handler +{ + + /// The Acceptor is the factory and therefore should have special + /// privileges. + friend class ACE_Asynch_Acceptor; + +public: + /// A do nothing constructor. + ACE_Service_Handler (void); + + /// Virtual destruction. + virtual ~ACE_Service_Handler (void); + + /** + * {open} is called by ACE_Asynch_Acceptor to initialize a new + * instance of ACE_Service_Handler that has been created after the + * new connection is accepted. The handle for the new connection is + * passed along with the initial data that may have shown up. + */ + virtual void open (ACE_HANDLE new_handle, + ACE_Message_Block &message_block); + + // protected: + // This should be corrected after the correct semantics of the + // friend has been figured out. + + /// Called by ACE_Asynch_Acceptor to pass the addresses of the new + /// connections. + virtual void addresses (const ACE_INET_Addr &remote_address, + const ACE_INET_Addr &local_address); + + /// Called by ACE_Asynch_Acceptor to pass the act. + virtual void act (const void *); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_WIN32 || ACE_HAS_AIO_CALLS*/ +#include /**/ "ace/post.h" +#endif /* ACE_ASYNCH_IO_H */ diff --git a/dep/acelite/ace/Asynch_IO_Impl.cpp b/dep/acelite/ace/Asynch_IO_Impl.cpp new file mode 100644 index 000000000..1f25a1ee7 --- /dev/null +++ b/dep/acelite/ace/Asynch_IO_Impl.cpp @@ -0,0 +1,115 @@ +#include "ace/Asynch_IO_Impl.h" + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) +// This only works on Win32 platforms and on Unix platforms supporting +// aio calls. + +#if !defined (__ACE_INLINE__) +#include "ace/Asynch_IO_Impl.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Asynch_Result_Impl::~ACE_Asynch_Result_Impl (void) +{ +} + +ACE_Asynch_Operation_Impl::~ACE_Asynch_Operation_Impl (void) +{ +} + +ACE_Asynch_Read_Stream_Impl::~ACE_Asynch_Read_Stream_Impl (void) +{ +} + +ACE_Asynch_Read_Stream_Result_Impl::~ACE_Asynch_Read_Stream_Result_Impl (void) +{ +} + +ACE_Asynch_Write_Stream_Impl::~ACE_Asynch_Write_Stream_Impl (void) +{ +} + +ACE_Asynch_Write_Stream_Result_Impl::~ACE_Asynch_Write_Stream_Result_Impl (void) +{ +} + +ACE_Asynch_Read_File_Impl::~ACE_Asynch_Read_File_Impl (void) +{ +} + +ACE_Asynch_Write_File_Impl::~ACE_Asynch_Write_File_Impl (void) +{ +} + +ACE_Asynch_Read_File_Result_Impl::~ACE_Asynch_Read_File_Result_Impl (void) +{ +} + +ACE_Asynch_Write_File_Result_Impl::~ACE_Asynch_Write_File_Result_Impl (void) +{ +} + +ACE_Asynch_Accept_Result_Impl::~ACE_Asynch_Accept_Result_Impl (void) +{ +} + +ACE_Asynch_Connect_Result_Impl::~ACE_Asynch_Connect_Result_Impl (void) +{ +} + +ACE_Asynch_Accept_Impl::~ACE_Asynch_Accept_Impl (void) +{ +} + +ACE_Asynch_Connect_Impl::~ACE_Asynch_Connect_Impl (void) +{ +} + +ACE_Asynch_Transmit_File_Impl::~ACE_Asynch_Transmit_File_Impl (void) +{ +} + +ACE_Asynch_Transmit_File_Result_Impl::~ACE_Asynch_Transmit_File_Result_Impl (void) +{ +} + +ACE_Asynch_Read_Dgram_Impl::~ACE_Asynch_Read_Dgram_Impl (void) +{ +} + +ACE_Asynch_Read_Dgram_Impl::ACE_Asynch_Read_Dgram_Impl (void) +{ +} + +ACE_Asynch_Write_Dgram_Impl::~ACE_Asynch_Write_Dgram_Impl (void) +{ +} + +ACE_Asynch_Write_Dgram_Impl::ACE_Asynch_Write_Dgram_Impl (void) +{ +} + +//*********************************************** + +ACE_Asynch_Read_Dgram_Result_Impl::~ACE_Asynch_Read_Dgram_Result_Impl (void) +{ +} + +ACE_Asynch_Read_Dgram_Result_Impl::ACE_Asynch_Read_Dgram_Result_Impl (void) +{ +} + +//*********************************************** + +ACE_Asynch_Write_Dgram_Result_Impl::~ACE_Asynch_Write_Dgram_Result_Impl (void) +{ +} + +ACE_Asynch_Write_Dgram_Result_Impl::ACE_Asynch_Write_Dgram_Result_Impl (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ diff --git a/dep/acelite/ace/Asynch_IO_Impl.h b/dep/acelite/ace/Asynch_IO_Impl.h new file mode 100644 index 000000000..a4ec996df --- /dev/null +++ b/dep/acelite/ace/Asynch_IO_Impl.h @@ -0,0 +1,793 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Asynch_IO_Impl.h + * + * This class contains asbtract base classes for all the concrete + * implementation classes for the various asynchronous operations + * that are used with the Praoctor. + * + * @author Irfan Pyarali (irfan@cs.wustl.edu) + * @author Tim Harrison (harrison@cs.wustl.edu) + * @author Alexander Babu Arulanthu + * @author Roger Tragin + * @author Alexander Libman + */ +//============================================================================= + +#ifndef ACE_ASYNCH_IO_IMPL_H +#define ACE_ASYNCH_IO_IMPL_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_WIN32_OVERLAPPED_IO) || defined (ACE_HAS_AIO_CALLS) +// This only works on Win32 platforms and on Unix platforms supporting +// aio calls. + +#include "ace/Asynch_IO.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declaration. +class ACE_Proactor_Impl; + +/** + * @class ACE_Asynch_Result_Impl + * + * @brief Abstract base class for the all the classes that provide + * concrete implementations for ACE_Asynch_Result. + */ +class ACE_Export ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Result_Impl (void); + + /// Number of bytes transferred by the operation. + virtual size_t bytes_transferred (void) const = 0; + + /// ACT associated with the operation. + virtual const void *act (void) const = 0; + + /// Did the operation succeed? + virtual int success (void) const = 0; + + /// This ACT is not the same as the ACT associated with the + /// asynchronous operation. + virtual const void *completion_key (void) const = 0; + + /// Error value if the operation fail. + virtual u_long error (void) const = 0; + + /// Event associated with the OVERLAPPED structure. + virtual ACE_HANDLE event (void) const = 0; + + /// This really make sense only when doing file I/O. + virtual u_long offset (void) const = 0; + virtual u_long offset_high (void) const = 0; + + /// Priority of the operation. + virtual int priority (void) const = 0; + + /** + * POSIX4 real-time signal number to be used for the + * operation. signal_number ranges from SIGRTMIN to SIGRTMAX. By + * default, SIGRTMIN is used to issue calls. This is a no-op + * on non-POSIX4 systems and returns 0. + */ + virtual int signal_number (void) const = 0; + + // protected: + // + // These two should really be protected. But sometimes it + // simplifies code to be able to "fake" a result. Use carefully. + /// This is called when the asynchronous operation completes. + virtual void complete (size_t bytes_transferred, + int success, + const void *completion_key, + u_long error = 0) = 0; + + /// Post @c this to the Proactor's completion port. + virtual int post_completion (ACE_Proactor_Impl *proactor) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Operation_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Operation. + */ +class ACE_Export ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Operation_Impl (void); + + /** + * Initializes the factory with information which will be used with + * each asynchronous call. If @a handle == ACE_INVALID_HANDLE, + * ACE_Handler::handle() will be called on the proxied handler to get the + * correct handle. + */ + virtual int open (const ACE_Handler::Proxy_Ptr &handler_proxy, + ACE_HANDLE handle, + const void *completion_key, + ACE_Proactor *proactor) = 0; + + /** + * This cancels all pending accepts operations that were issued by + * the calling thread. The function does not cancel asynchronous + * operations issued by other threads. + */ + virtual int cancel (void) = 0; + + // = Access methods. + + /// Return the underlying proactor. + virtual ACE_Proactor* proactor (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Operation_Impl (void); +}; + +/** + * @class ACE_Asynch_Read_Stream_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Read_Stream + */ +class ACE_Export ACE_Asynch_Read_Stream_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Read_Stream_Impl (void); + + /// This starts off an asynchronous read. Upto @a bytes_to_read will + /// be read and stored in the @a message_block. + virtual int read (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with scatter support, through chaining of composite + * message blocks using the continuation field. + */ + virtual int readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_Stream_Impl (void); +}; + +/** + * @class ACE_Asynch_Read_Stream_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Read_Stream::Result class. + */ +class ACE_Export ACE_Asynch_Read_Stream_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Read_Stream_Result_Impl (void); + + /// The number of bytes which were requested at the start of the + /// asynchronous read. + virtual size_t bytes_to_read (void) const = 0; + + /// Message block which contains the read data. + virtual ACE_Message_Block &message_block (void) const = 0; + + /// I/O handle used for reading. + virtual ACE_HANDLE handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_Stream_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_Stream_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Write_Stream class. + */ +class ACE_Export ACE_Asynch_Write_Stream_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Write_Stream_Impl (void); + + /// This starts off an asynchronous write. Upto @a bytes_to_write + /// will be written from the @a message_block. + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with gather support, through chaining of composite + * message blocks using the continuation field. + */ + virtual int writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_Stream_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_Stream_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Write_Stream::Result. + */ +class ACE_Export ACE_Asynch_Write_Stream_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Write_Stream_Result_Impl (void); + + /// The number of bytes which were requested at the start of the + /// asynchronous write. + virtual size_t bytes_to_write (void) const = 0; + + /// Message block that contains the data to be written. + virtual ACE_Message_Block &message_block (void) const = 0; + + /// I/O handle used for writing. + virtual ACE_HANDLE handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_Stream_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Read_File_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Read_File::Result. + */ +class ACE_Export ACE_Asynch_Read_File_Impl : public virtual ACE_Asynch_Read_Stream_Impl +{ +public: + virtual ~ACE_Asynch_Read_File_Impl (void); + + /** + * This starts off an asynchronous read. Upto @a bytes_to_read will + * be read and stored in the @a message_block. The read will start + * at @a offset from the beginning of the file. + */ + virtual int read (ACE_Message_Block &message_block, + size_t bytes_to_read, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with scatter support, through chaining of composite + * message blocks using the continuation field. + * @note In win32 Each data block payload must be at least the size of a system + * memory page and must be aligned on a system memory page size boundary + */ + virtual int readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + + /// This starts off an asynchronous read. Upto @a bytes_to_read will + /// be read and stored in the @a message_block. + virtual int read (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with scatter support, through chaining of composite + * message blocks using the continuation field. + */ + virtual int readv (ACE_Message_Block &message_block, + size_t bytes_to_read, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_File_Impl (void); +}; + +/** + * @class ACE_Asynch_Read_File_Result_Impl + * + * @brief This is the abstract base class for all the concrete + * implementation classes for ACE_Asynch_Read_File::Result. + */ +class ACE_Export ACE_Asynch_Read_File_Result_Impl : public virtual ACE_Asynch_Read_Stream_Result_Impl +{ +public: + /// Destructor. + virtual ~ACE_Asynch_Read_File_Result_Impl (void); + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_File_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_File_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Write_File. + */ +class ACE_Export ACE_Asynch_Write_File_Impl : public virtual ACE_Asynch_Write_Stream_Impl +{ +public: + virtual ~ACE_Asynch_Write_File_Impl (void); + + /** + * This starts off an asynchronous write. Upto @a bytes_to_write + * will be write and stored in the @a message_block. The write will + * start at @a offset from the beginning of the file. + */ + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with gather support, through chaining of composite + * message blocks using the continuation field. + * @note In win32 Each data block payload must be at least the size of a system + * memory page and must be aligned on a system memory page size boundary + */ + virtual int writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + + /// This starts off an asynchronous write. Upto @a bytes_to_write + /// will be written from the @a message_block. + virtual int write (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) = 0; + +#if (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) + /** + * Same as above but with gather support, through chaining of composite + * message blocks using the continuation field. + */ + virtual int writev (ACE_Message_Block &message_block, + size_t bytes_to_write, + const void *act, + int priority, + int signal_number) = 0; +#endif /* (defined (ACE_WIN32) && !defined (ACE_HAS_WINCE)) */ + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_File_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_File_Result_Impl + * + * @brief This is the abstract base class for all the concrete + * implementation classes that provide different implementations + * for the ACE_Asynch_Write_File::Result. + */ +class ACE_Export ACE_Asynch_Write_File_Result_Impl : public virtual ACE_Asynch_Write_Stream_Result_Impl +{ +public: + virtual ~ACE_Asynch_Write_File_Result_Impl (void); + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_File_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Accept_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Accept. + */ +class ACE_Export ACE_Asynch_Accept_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Accept_Impl (void); + + /** + * This starts off an asynchronous accept. The asynchronous accept + * call also allows any initial data to be returned to the + * . Upto @a bytes_to_read will be read and stored in the + * @a message_block. The @a accept_handle will be used for the + * call. If (@a accept_handle == INVALID_HANDLE), a new + * handle will be created. + * + * @a message_block must be specified. This is because the address of + * the new connection is placed at the end of this buffer. + */ + virtual int accept (ACE_Message_Block &message_block, + size_t bytes_to_read, + ACE_HANDLE accept_handle, + const void *act, + int priority, + int signal_number, + int addr_family) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Accept_Impl (void); +}; + +/** + * @class ACE_Asynch_Accept_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Accept. + */ +class ACE_Export ACE_Asynch_Accept_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Accept_Result_Impl (void); + + /// The number of bytes which were requested at the start of the + /// asynchronous accept. + virtual size_t bytes_to_read (void) const = 0; + + /// Message block which contains the read data. + virtual ACE_Message_Block &message_block (void) const = 0; + + /// I/O handle used for accepting new connections. + virtual ACE_HANDLE listen_handle (void) const = 0; + + /// I/O handle for the new connection. + virtual ACE_HANDLE accept_handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Accept_Result_Impl (void); +}; + + +/** + * @class ACE_Asynch_Connect_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Connect. + */ +class ACE_Export ACE_Asynch_Connect_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Connect_Impl (void); + + /** + * This starts off an asynchronous connect + */ + virtual int connect (ACE_HANDLE connect_handle, + const ACE_Addr & remote_sap, + const ACE_Addr & local_sap, + int reuse_addr, + const void *act, + int priority, + int signal_number) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Connect_Impl (void); +}; + +/** + * @class ACE_Asynch_Connect_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Connect. + */ +class ACE_Export ACE_Asynch_Connect_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Connect_Result_Impl (void); + + /// I/O handle for the connection. + virtual ACE_HANDLE connect_handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Connect_Result_Impl (void); +}; + + +/** + * @class ACE_Asynch_Transmit_File_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Transmit_File. + */ +class ACE_Asynch_Transmit_File_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Transmit_File_Impl (void); + + /// This starts off an asynchronous transmit file. + virtual int transmit_file (ACE_HANDLE file, + ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer, + size_t bytes_to_write, + u_long offset, + u_long offset_high, + size_t bytes_per_send, + u_long flags, + const void *act, + int priority, + int signal_number) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Transmit_File_Impl (void); +}; + +/** + * @class ACE_Asynch_Transmit_File_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Transmit_File::Result. + */ +class ACE_Export ACE_Asynch_Transmit_File_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Transmit_File_Result_Impl (void); + + /// Socket used for transmitting the file. + virtual ACE_HANDLE socket (void) const = 0; + + /// File from which the data is read. + virtual ACE_HANDLE file (void) const = 0; + + /// Header and trailer data associated with this transmit file. + virtual ACE_Asynch_Transmit_File::Header_And_Trailer *header_and_trailer (void) const = 0; + + /// The number of bytes which were requested at the start of the + /// asynchronous transmit file. + virtual size_t bytes_to_write (void) const = 0; + + /// Number of bytes per send requested at the start of the transmit + /// file. + virtual size_t bytes_per_send (void) const = 0; + + /// Flags which were passed into transmit file. + virtual u_long flags (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Transmit_File_Result_Impl (void); +}; + + +/** + * @class ACE_Asynch_Read_Dgram_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Read_Dgram + */ +class ACE_Export ACE_Asynch_Read_Dgram_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Read_Dgram_Impl (void); + + /** This starts off an asynchronous read. Upto + * total_size()> will be read and stored in the + * @a message_block. @a message_block's will be updated to reflect + * the added bytes if the read operation is successful completed. + * Return code of 1 means immediate success and + * will contain number of bytes read. The + * method will still be called. Return code of 0 means the IO will + * complete proactively. Return code of -1 means there was an error, use + * errno to get the error code. + * + * Scatter/gather is supported on WIN32 by using the cont()> + * method. Up to ACE_IOV_MAX @a message_block's are supported. Upto + * size()> bytes will be read into each for + * a total of total_size()> bytes. All @a message_block's + * 's will be updated to reflect the added bytes for each + * @a message_block + * + * Priority of the operation is specified by @a priority. On POSIX4-Unix, + * this is supported. Works like in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, @a priority is a no-op. + * @a signal_number is the POSIX4 real-time signal number to be used + * for the operation. @a signal_number ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + virtual ssize_t recv (ACE_Message_Block *message_block, + size_t &number_of_bytes_recvd, + int flags, + int protocol_family, + const void *act, + int priority, + int signal_number) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_Dgram_Impl (void); +}; + +/** + * @class ACE_Asynch_Read_Dgram_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Read_Dgram::Result class. + */ +class ACE_Export ACE_Asynch_Read_Dgram_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Read_Dgram_Result_Impl (void); + + /// Message block which contains the read data + virtual ACE_Message_Block *message_block (void) const = 0; + + /// The number of bytes which were requested at the start of the + /// asynchronous read. + virtual size_t bytes_to_read (void) const = 0; + + /// The address of where the packet came from + virtual int remote_address (ACE_Addr& addr) const = 0; + + /// The flags used in the read + virtual int flags (void) const = 0; + + /// I/O handle used for reading. + virtual ACE_HANDLE handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Read_Dgram_Result_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_Dgram_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Write_Dgram class. + */ +class ACE_Export ACE_Asynch_Write_Dgram_Impl : public virtual ACE_Asynch_Operation_Impl +{ +public: + virtual ~ACE_Asynch_Write_Dgram_Impl (void); + + /** This starts off an asynchronous send. Upto + * total_length()> will be sent. @a message_block's + * will be updated to reflect the sent bytes if the send operation + * is successful completed. + * Return code of 1 means immediate success and + * is updated to number of bytes sent. The + * method will still be called. Return code of 0 means the IO will + * complete proactively. Return code of -1 means there was an error, use + * errno to get the error code. + * + * Scatter/gather is supported on WIN32 by using the cont()> + * method. Up to ACE_IOV_MAX @a message_block's are supported. Upto + * length()> bytes will be sent from each + * for a total of total_length()> bytes. All + * @a message_block's 's will be updated to reflect the bytes sent + * from each @a message_block. + * + * Priority of the operation is specified by @a priority. On POSIX4-Unix, + * this is supported. Works like in Unix. Negative values are not + * allowed. 0 means priority of the operation same as the process + * priority. 1 means priority of the operation is one less than + * process. And so forth. On Win32, this argument is a no-op. + * @a signal_number is the POSIX4 real-time signal number to be used + * for the operation. @a signal_number ranges from ACE_SIGRTMIN to + * ACE_SIGRTMAX. This argument is a no-op on non-POSIX4 systems. + */ + virtual ssize_t send (ACE_Message_Block *message_block, + size_t &number_of_bytes_sent, + int flags, + const ACE_Addr &addr, + const void *act, + int priority, + int signal_number) = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_Dgram_Impl (void); +}; + +/** + * @class ACE_Asynch_Write_Dgram_Result_Impl + * + * @brief Abstract base class for all the concrete implementation + * classes that provide different implementations for the + * ACE_Asynch_Write_Dgram::Result class. + */ +class ACE_Export ACE_Asynch_Write_Dgram_Result_Impl : public virtual ACE_Asynch_Result_Impl +{ +public: + virtual ~ACE_Asynch_Write_Dgram_Result_Impl (void); + + /// The number of bytes which were requested at the start of the + /// asynchronous write. + virtual size_t bytes_to_write (void) const = 0; + + /// Message block which contains the sent data + virtual ACE_Message_Block *message_block (void) const = 0; + + /// The flags using in the write + virtual int flags (void) const = 0; + + /// I/O handle used for writing. + virtual ACE_HANDLE handle (void) const = 0; + +protected: + /// Do-nothing constructor. + ACE_Asynch_Write_Dgram_Result_Impl (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Asynch_IO_Impl.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_WIN32_OVERLAPPED_IO || ACE_HAS_AIO_CALLS */ +#include /**/ "ace/post.h" +#endif /* ACE_ASYNCH_IO_IMPL_H */ diff --git a/dep/acelite/ace/Asynch_IO_Impl.inl b/dep/acelite/ace/Asynch_IO_Impl.inl new file mode 100644 index 000000000..e6fce33b3 --- /dev/null +++ b/dep/acelite/ace/Asynch_IO_Impl.inl @@ -0,0 +1,103 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Asynch_Result_Impl::ACE_Asynch_Result_Impl (void) +{ +} + +ACE_INLINE +ACE_Asynch_Operation_Impl::ACE_Asynch_Operation_Impl (void) +{ +} + +ACE_INLINE +ACE_Asynch_Read_Stream_Impl::ACE_Asynch_Read_Stream_Impl (void) + : ACE_Asynch_Operation_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Read_Stream_Result_Impl::ACE_Asynch_Read_Stream_Result_Impl (void) + : ACE_Asynch_Result_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Write_Stream_Impl::ACE_Asynch_Write_Stream_Impl (void) + : ACE_Asynch_Operation_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Write_Stream_Result_Impl::ACE_Asynch_Write_Stream_Result_Impl (void) + : ACE_Asynch_Result_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Read_File_Impl::ACE_Asynch_Read_File_Impl (void) + : ACE_Asynch_Operation_Impl (), + ACE_Asynch_Read_Stream_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Read_File_Result_Impl::ACE_Asynch_Read_File_Result_Impl (void) + : ACE_Asynch_Result_Impl (), + ACE_Asynch_Read_Stream_Result_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Write_File_Impl::ACE_Asynch_Write_File_Impl (void) + : ACE_Asynch_Operation_Impl (), + ACE_Asynch_Write_Stream_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Write_File_Result_Impl::ACE_Asynch_Write_File_Result_Impl (void) + : ACE_Asynch_Result_Impl (), + ACE_Asynch_Write_Stream_Result_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Accept_Impl::ACE_Asynch_Accept_Impl (void) + : ACE_Asynch_Operation_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Accept_Result_Impl::ACE_Asynch_Accept_Result_Impl (void) + : ACE_Asynch_Result_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Connect_Impl::ACE_Asynch_Connect_Impl (void) + : ACE_Asynch_Operation_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Connect_Result_Impl::ACE_Asynch_Connect_Result_Impl (void) + : ACE_Asynch_Result_Impl () +{ +} + + +ACE_INLINE +ACE_Asynch_Transmit_File_Impl::ACE_Asynch_Transmit_File_Impl (void) + : ACE_Asynch_Operation_Impl () +{ +} + +ACE_INLINE +ACE_Asynch_Transmit_File_Result_Impl::ACE_Asynch_Transmit_File_Result_Impl (void) + : ACE_Asynch_Result_Impl () +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Asynch_Pseudo_Task.cpp b/dep/acelite/ace/Asynch_Pseudo_Task.cpp new file mode 100644 index 000000000..0b6a14b60 --- /dev/null +++ b/dep/acelite/ace/Asynch_Pseudo_Task.cpp @@ -0,0 +1,126 @@ +#include "ace/Asynch_Pseudo_Task.h" + +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_signal.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Asynch_Pseudo_Task::ACE_Asynch_Pseudo_Task () + : select_reactor_ (), // should be initialized before reactor_ + reactor_ (&select_reactor_, 0) // don't delete implementation +{ +} + +ACE_Asynch_Pseudo_Task::~ACE_Asynch_Pseudo_Task () +{ + this->stop (); +} + +int +ACE_Asynch_Pseudo_Task::start (void) +{ + if (this->reactor_.initialized () == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%N:%l:%p\n"), + ACE_TEXT ("start reactor is not initialized")), + -1); + + return this->activate () == -1 ? -1 : 0; // If started, return 0 +} + +int +ACE_Asynch_Pseudo_Task::stop (void) +{ + if (this->thr_count () == 0) // already stopped + return 0; + + if (this->reactor_.end_reactor_event_loop () == -1) + return -1; + + this->wait (); + this->reactor_.close (); + return 0; +} + +int +ACE_Asynch_Pseudo_Task::svc (void) +{ +#if !defined (ACE_WIN32) + + sigset_t RT_signals; + + sigemptyset (&RT_signals); + for (int si = ACE_SIGRTMIN; si <= ACE_SIGRTMAX; si++) + sigaddset (&RT_signals, si); + + if (ACE_OS::pthread_sigmask (SIG_BLOCK, &RT_signals, 0) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("Error:(%P | %t):%p\n"), + ACE_TEXT ("pthread_sigmask"))); +#endif + + reactor_.owner (ACE_Thread::self ()); + reactor_.run_reactor_event_loop (); + + return 0; +} + + + +int +ACE_Asynch_Pseudo_Task::register_io_handler (ACE_HANDLE handle, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask, + int flg_suspend) +{ + // Register the handler with the reactor. + if (-1 == this->reactor_.register_handler (handle, handler, mask)) + return -1; + + if (flg_suspend == 0) + return 0; + + // Suspend the handle now. Enable only when the accept is issued + // by the application. + if (this->reactor_.suspend_handler (handle) == -1) + { + ACELIB_ERROR + ((LM_ERROR, + ACE_TEXT ("%N:%l:%p\n"), + ACE_TEXT ("register_io_handler (suspended)"))); + this->reactor_.remove_handler (handle, ACE_Event_Handler::ALL_EVENTS_MASK + | ACE_Event_Handler::DONT_CALL); + return -1; + } + + return 0; +} + +int +ACE_Asynch_Pseudo_Task::remove_io_handler (ACE_HANDLE handle) +{ + return this->reactor_.remove_handler (handle, + ACE_Event_Handler::ALL_EVENTS_MASK + | ACE_Event_Handler::DONT_CALL); +} + +int +ACE_Asynch_Pseudo_Task::remove_io_handler (ACE_Handle_Set &set) +{ + return this->reactor_.remove_handler (set, ACE_Event_Handler::ALL_EVENTS_MASK + | ACE_Event_Handler::DONT_CALL); +} + +int +ACE_Asynch_Pseudo_Task::suspend_io_handler (ACE_HANDLE handle) +{ + return this->reactor_.suspend_handler (handle); +} + +int +ACE_Asynch_Pseudo_Task::resume_io_handler (ACE_HANDLE handle) +{ + return this->reactor_.resume_handler (handle); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Asynch_Pseudo_Task.h b/dep/acelite/ace/Asynch_Pseudo_Task.h new file mode 100644 index 000000000..4337361fe --- /dev/null +++ b/dep/acelite/ace/Asynch_Pseudo_Task.h @@ -0,0 +1,70 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Asynch_Pseudo_Task.h + * + * @author Alexander Libman + */ +//============================================================================= + +#ifndef ACE_ASYNCH_PSEUDO_TASK_H +#define ACE_ASYNCH_PSEUDO_TASK_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Reactor.h" +#include "ace/Select_Reactor.h" +#include "ace/Task.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/* + * Specialization hook to replace the Reactor with the + * concrete Reactor implementation, e.g., select_st, + * select_mt etc. + */ +//@@ REACTOR_SPL_INCLUDE_FORWARD_DECL_ADD_HOOK + +/** + * @class ACE_Asynch_Pseudo_Task + */ +class ACE_Export ACE_Asynch_Pseudo_Task : public ACE_Task +{ +public: + ACE_Asynch_Pseudo_Task(); + virtual ~ACE_Asynch_Pseudo_Task(); + + int start (void); + int stop (void); + + int register_io_handler (ACE_HANDLE handle, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask, + int flg_suspend); + + int remove_io_handler (ACE_HANDLE handle); + int remove_io_handler (ACE_Handle_Set &set); + int resume_io_handler (ACE_HANDLE handle); + int suspend_io_handler (ACE_HANDLE handle); + +protected: + virtual int svc (void); + + /// Should be initialized before reactor_ + ACE_Select_Reactor select_reactor_; + + ACE_Reactor reactor_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_ASYNCH_PSEUDO_TASK_H */ diff --git a/dep/acelite/ace/Atomic_Op.cpp b/dep/acelite/ace/Atomic_Op.cpp new file mode 100644 index 000000000..e1075809b --- /dev/null +++ b/dep/acelite/ace/Atomic_Op.cpp @@ -0,0 +1,304 @@ +#include "ace/Atomic_Op.h" +#include "ace/OS_NS_unistd.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Atomic_Op.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_BUILTIN_ATOMIC_OP) + +#if defined (ACE_INCLUDE_ATOMIC_OP_SPARC) +# include "ace/Atomic_Op_Sparc.h" +#endif /* ACE_INCLUDE_ATOMIC_OP_SPARC */ + +namespace { + +#if defined (_MSC_VER) +// Disable "no return value" warning, as we will be putting +// the return values directly into the EAX register. +#pragma warning (push) +#pragma warning (disable: 4035) +#endif /* _MSC_VER */ + +long +single_cpu_increment (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = 1; + unsigned long addr = reinterpret_cast (value); + asm( "xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp + 1; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_add_long ( + reinterpret_cast (value), 1); +#elif defined(__GNUC__) && defined(__PPC__) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (*value) ); + asm("addi %0,%0,1" : "+r" (tmp) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_decrement (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = -1; + unsigned long addr = reinterpret_cast (value); + asm( "xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp - 1; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_add_long ( + reinterpret_cast (value), -1); +#elif defined(__GNUC__) && defined(__PPC__) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (*value) ); + asm("addi %0,%0,-1" : "+r" (tmp) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_exchange (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast (value); + asm( "xchg %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_swap_long ( + reinterpret_cast (value), rhs); +#elif defined(__GNUC__) && defined(__PPC__) + long tmp; + asm("lwz %0,%1" : "=r" (tmp) : "m" (rhs) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +single_cpu_exchange_add (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast (value); + asm( "xadd %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_swap_add_long ( + reinterpret_cast (value), rhs); +#elif defined(__GNUC__) && defined(__PPC__) + long tmp; + asm("add %0,%1,%2" : "=r" (tmp) : "r" (*value), "r" (rhs) ); + asm("stw %0,%1" : "+r" (tmp), "=m" (*value) ); + return tmp; +#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) +# if defined (_MSC_VER) + __asm + { + mov eax, rhs + mov edx, value + xadd [edx], eax + } + // Return value is already in EAX register. +# elif defined (__BORLANDC__) + _EAX = rhs; + _EDX = reinterpret_cast (value); + __emit__(0x0F, 0xC1, 0x02); // xadd [edx], eax + // Return value is already in EAX register. +# else /* _MSC_VER */ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +# endif /* _MSC_VER */ +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_increment (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = 1; + unsigned long addr = reinterpret_cast (value); + asm( "lock ; xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp + 1; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_add_long ( + reinterpret_cast (value), 1); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_decrement (volatile long *value) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + long tmp = -1; + unsigned long addr = reinterpret_cast (value); + asm( "lock ; xadd %0, (%1)" : "+r"(tmp) : "r"(addr) ); + return tmp - 1; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_add_long ( + reinterpret_cast (value), -1); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_exchange (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast (value); + // The XCHG instruction automatically follows LOCK semantics + asm( "xchg %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_swap_long ( + reinterpret_cast (value), rhs); +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +long +multi_cpu_exchange_add (volatile long *value, long rhs) +{ +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned long addr = reinterpret_cast (value); + asm( "lock ; xadd %0, (%1)" : "+r"(rhs) : "r"(addr) ); + return rhs; +#elif !defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && (defined (sun) || \ + (defined (__SUNPRO_CC) && (defined (__i386) || defined (__x86_64)))) + return ace_atomic_swap_add_long ( + reinterpret_cast (value), rhs); +#elif defined (WIN32) && !defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) +# if defined (_MSC_VER) + __asm + { + mov eax, rhs + mov edx, value + lock xadd [edx], eax + } + // Return value is already in EAX register. +# elif defined (__BORLANDC__) + _EAX = rhs; + _EDX = reinterpret_cast (value); + __emit__(0xF0, 0x0F, 0xC1, 0x02); // lock xadd [edx], eax + // Return value is already in EAX register. +# else /* _MSC_VER */ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +# endif /* _MSC_VER */ +#else /* ACE_HAS_INTEL_ASSEMBLY*/ + ACE_UNUSED_ARG (value); + ACE_UNUSED_ARG (rhs); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_INTEL_ASSEMBLY*/ +} + +#if defined (_MSC_VER) +#pragma warning (pop) +#endif /* _MSC_VER */ + +} // end namespace + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +long (*ACE_Atomic_Op::increment_fn_) (volatile long *) = multi_cpu_increment; +long (*ACE_Atomic_Op::decrement_fn_) (volatile long *) = multi_cpu_decrement; +long (*ACE_Atomic_Op::exchange_fn_) (volatile long *, long) = multi_cpu_exchange; +long (*ACE_Atomic_Op::exchange_add_fn_) (volatile long *, long) = multi_cpu_exchange_add; + +void +ACE_Atomic_Op::init_functions (void) +{ + if (ACE_OS::num_processors () == 1) + { + increment_fn_ = single_cpu_increment; + decrement_fn_ = single_cpu_decrement; + exchange_fn_ = single_cpu_exchange; + exchange_add_fn_ = single_cpu_exchange_add; + } + else + { + increment_fn_ = multi_cpu_increment; + decrement_fn_ = multi_cpu_decrement; + exchange_fn_ = multi_cpu_exchange; + exchange_add_fn_ = multi_cpu_exchange_add; + } +} + +void +ACE_Atomic_Op::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +long (*ACE_Atomic_Op::increment_fn_) (volatile long *) = multi_cpu_increment; +long (*ACE_Atomic_Op::decrement_fn_) (volatile long *) = multi_cpu_decrement; +long (*ACE_Atomic_Op::exchange_fn_) (volatile long *, long) = multi_cpu_exchange; +long (*ACE_Atomic_Op::exchange_add_fn_) (volatile long *, long) = multi_cpu_exchange_add; + +void +ACE_Atomic_Op::init_functions (void) +{ + if (ACE_OS::num_processors () == 1) + { + increment_fn_ = single_cpu_increment; + decrement_fn_ = single_cpu_decrement; + exchange_fn_ = single_cpu_exchange; + exchange_add_fn_ = single_cpu_exchange_add; + } + else + { + increment_fn_ = multi_cpu_increment; + decrement_fn_ = multi_cpu_decrement; + exchange_fn_ = multi_cpu_exchange; + exchange_add_fn_ = multi_cpu_exchange_add; + } +} + +void +ACE_Atomic_Op::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_BUILTIN_ATOMIC_OP */ diff --git a/dep/acelite/ace/Atomic_Op.h b/dep/acelite/ace/Atomic_Op.h new file mode 100644 index 000000000..0b2535e79 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op.h @@ -0,0 +1,384 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Atomic_Op.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ATOMIC_OP_H +#define ACE_ATOMIC_OP_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Thread_Mutex.h" + +// Include the templates here. +#include "ace/Atomic_Op_T.h" + +// Determine whether builtin atomic op support is +// available on this platform. +#if defined (ACE_HAS_THREADS) +# if defined (WIN32) +# if defined (ACE_HAS_INTRINSIC_INTERLOCKED) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# endif /* ACE_HAS_INTRINSIC_INTERLOCKED */ +# if defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# else /* ACE_HAS_INTERLOCKED_EXCHANGEADD */ + // Inline assembly emulation of InterlockedExchangeAdd + // is currently only implemented for MSVC (x86 only) and Borland. +# if (defined (_MSC_VER) && defined (_M_IX86)) || defined (__BORLANDC__) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# endif /* _MSC_VER || __BORLANDC__ */ +# endif /* ACE_HAS_INTERLOCKED_EXCHANGEADD */ +# elif defined (ACE_HAS_INTEL_ASSEMBLY) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# elif defined (ACE_HAS_VXATOMICLIB) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) && !defined (ACE_HAS_BUILTIN_ATOMIC_OP) +# define ACE_HAS_BUILTIN_ATOMIC_OP +# endif /* WIN32 */ +#endif /* ACE_HAS_THREADS */ + +// If we have the GCC Atomic builtin support, use it +#if defined (ACE_HAS_GCC_ATOMIC_BUILTINS) && (ACE_HAS_GCC_ATOMIC_BUILTINS == 1) +# undef ACE_HAS_BUILTIN_ATOMIC_OP +#endif + +// Include the templates here. +#include "ace/Atomic_Op_GCC_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_BUILTIN_ATOMIC_OP) + +/** + * @brief Specialization of ACE_Atomic_Op for platforms that + * support atomic integer operations. + * + * Specialization of ACE_Atomic_Op for platforms that support atomic + * integer operations. + */ +template<> +class ACE_Export ACE_Atomic_Op +{ +public: + /// Initialize @c value_ to 0. + ACE_Atomic_Op (void); + + /// Initialize @c value_ to c. + ACE_Atomic_Op (long c); + + /// Manage copying... + ACE_Atomic_Op (const ACE_Atomic_Op &c); + + /// Atomically pre-increment @c value_. + long operator++ (void); + + /// Atomically post-increment @c value_. + long operator++ (int); + + /// Atomically increment @c value_ by rhs. + long operator+= (long rhs); + + /// Atomically pre-decrement @c value_. + long operator-- (void); + + /// Atomically post-decrement @c value_. + long operator-- (int); + + /// Atomically decrement @c value_ by rhs. + long operator-= (long rhs); + + /// Atomically compare @c value_ with rhs. + bool operator== (long rhs) const; + + /// Atomically compare @c value_ with rhs. + bool operator!= (long rhs) const; + + /// Atomically check if @c value_ greater than or equal to rhs. + bool operator>= (long rhs) const; + + /// Atomically check if @c value_ greater than rhs. + bool operator> (long rhs) const; + + /// Atomically check if @c value_ less than or equal to rhs. + bool operator<= (long rhs) const; + + /// Atomically check if @c value_ less than rhs. + bool operator< (long rhs) const; + + /// Atomically assign rhs to @c value_. + ACE_Atomic_Op &operator= (long rhs); + + /// Atomically assign to @c value_. + ACE_Atomic_Op &operator= (const ACE_Atomic_Op &rhs); + + /// Exchange value with @a newval. + long exchange (long newval); + + /// Explicitly return @c value_. + long value (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Explicitly return @c value_ (by reference). + volatile long &value_i (void); + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. + + /// Used during ACE object manager initialization to optimize the fast + /// atomic op implementation according to the number of CPUs. + static void init_functions (void); + +private: + + /// This function cannot be supported by this template specialization. + /// If you need access to an underlying lock, use the ACE_Atomic_Op_Ex + /// template instead. + ACE_Thread_Mutex &mutex (void); + +private: + + /// Current object decorated by the atomic op. + volatile long value_; + + /// Pointers to selected atomic op implementations. + static long (*increment_fn_) (volatile long *); + static long (*decrement_fn_) (volatile long *); + static long (*exchange_fn_) (volatile long *, long); + static long (*exchange_add_fn_) (volatile long *, long); +}; + +/** + * @brief Specialization of ACE_Atomic_Op for platforms that + * support atomic integer operations. + * + * Specialization of ACE_Atomic_Op for platforms that support atomic + * integer operations. + */ +template<> +class ACE_Export ACE_Atomic_Op +{ +public: + /// Initialize @c value_ to 0. + ACE_Atomic_Op (void); + + /// Initialize @c value_ to c. + ACE_Atomic_Op (unsigned long c); + + /// Manage copying... + ACE_Atomic_Op (const ACE_Atomic_Op &c); + + /// Atomically pre-increment @c value_. + unsigned long operator++ (void); + + /// Atomically post-increment @c value_. + unsigned long operator++ (int); + + /// Atomically increment @c value_ by rhs. + unsigned long operator+= (unsigned long rhs); + + /// Atomically pre-decrement @c value_. + unsigned long operator-- (void); + + /// Atomically post-decrement @c value_. + unsigned long operator-- (int); + + /// Atomically decrement @c value_ by rhs. + unsigned long operator-= (unsigned long rhs); + + /// Atomically compare @c value_ with rhs. + bool operator== (unsigned long rhs) const; + + /// Atomically compare @c value_ with rhs. + bool operator!= (unsigned long rhs) const; + + /// Atomically check if @c value_ greater than or equal to rhs. + bool operator>= (unsigned long rhs) const; + + /// Atomically check if @c value_ greater than rhs. + bool operator> (unsigned long rhs) const; + + /// Atomically check if @c value_ less than or equal to rhs. + bool operator<= (unsigned long rhs) const; + + /// Atomically check if @c value_ less than rhs. + bool operator< (unsigned long rhs) const; + + /// Atomically assign rhs to @c value_. + ACE_Atomic_Op &operator= (unsigned long rhs); + + /// Atomically assign to @c value_. + ACE_Atomic_Op &operator= (const ACE_Atomic_Op &rhs); + + /// Exchange value with @a newval. + unsigned long exchange (unsigned long newval); + + /// Explicitly return @c value_. + unsigned long value (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Explicitly return @c value_ (by reference). + volatile unsigned long &value_i (void); + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. + + /// Used during ACE object manager initialization to optimize the fast + /// atomic op implementation according to the number of CPUs. + static void init_functions (void); + +private: + + /// This function cannot be supported by this template specialization. + /// If you need access to an underlying lock, use the ACE_Atomic_Op_Ex + /// template instead. + ACE_Thread_Mutex &mutex (void); + +private: + + /// Current object decorated by the atomic op. + volatile unsigned long value_; + + // Pointers to selected atomic op implementations. + static long (*increment_fn_) (volatile long *); + static long (*decrement_fn_) (volatile long *); + static long (*exchange_fn_) (volatile long *, long); + static long (*exchange_add_fn_) (volatile long *, long); +}; + +#endif /* !ACE_HAS_BUILTIN_ATOMIC_OP */ + +#if defined (ACE_HAS_GCC_ATOMIC_BUILTINS) && (ACE_HAS_GCC_ATOMIC_BUILTINS == 1) + +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (int c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (int rhs); +}; + +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (unsigned int c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (unsigned int rhs); +}; + +// If we have built in atomic op, use that, the assignment operator +// is faster for a long/unsinged long +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (long c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (long rhs); +}; + +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (unsigned long c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (unsigned long rhs); +}; + +// The long long intrinsics are not available on PPC +#if !defined (__powerpc__) +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (long long c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (long long rhs); +}; + +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (unsigned long long c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (unsigned long long rhs); +}; +#endif /* !__powerpc__ */ + +#if !defined (ACE_LACKS_GCC_ATOMIC_BUILTINS_2) +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (short c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (short rhs); +}; + +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (unsigned short c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (unsigned short rhs); +}; +#endif + +#if !defined (ACE_LACKS_GCC_ATOMIC_BUILTINS_1) +template<> +class ACE_Export ACE_Atomic_Op +: public ACE_Atomic_Op_GCC +{ +public: + ACE_Atomic_Op (void); + ACE_Atomic_Op (bool c); + ACE_Atomic_Op (const ACE_Atomic_Op &c); + ACE_Atomic_Op &operator= (bool rhs); +}; +#endif + +#endif /* ACE_HAS_BUILTIN_ATOMIC_OP */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Atomic_Op.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /*ACE_ATOMIC_OP_H*/ diff --git a/dep/acelite/ace/Atomic_Op.inl b/dep/acelite/ace/Atomic_Op.inl new file mode 100644 index 000000000..2f9ec57ba --- /dev/null +++ b/dep/acelite/ace/Atomic_Op.inl @@ -0,0 +1,666 @@ +// -*- C++ -*- +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) +# include "ace/os_include/os_intrin.h" +# pragma intrinsic (_InterlockedExchange, _InterlockedExchangeAdd, _InterlockedIncrement, _InterlockedDecrement) +#endif /* ACE_HAS_INTRINSIC_INTERLOCKED */ + +#if defined (ACE_HAS_VXATOMICLIB) +# include +#endif + +#if defined (ACE_HAS_SOLARIS_ATOMIC_LIB) +# include +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_BUILTIN_ATOMIC_OP) + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) + : value_ (0) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (long c) + : value_ (c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op ( + const ACE_Atomic_Op &rhs) + : value_ (rhs.value_) +{ +} + +ACE_INLINE long +ACE_Atomic_Op::operator++ (void) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedIncrement (const_cast (&this->value_)); +#elif defined (WIN32) + return ::InterlockedIncrement (const_cast (&this->value_)); +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicInc (reinterpret_cast (const_cast (&this->value_))) + 1; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_inc_ulong_nv (reinterpret_cast(&this->value_)); +#else /* WIN32 */ + return (*increment_fn_) (&this->value_); +#endif /* WIN32 */ +} + +ACE_INLINE long +ACE_Atomic_Op::operator++ (int) +{ + return ++*this - 1; +} + +ACE_INLINE long +ACE_Atomic_Op::operator-- (void) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedDecrement (const_cast (&this->value_)); +#elif defined (WIN32) + return ::InterlockedDecrement (const_cast (&this->value_)); +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicDec (reinterpret_cast (const_cast (&this->value_))) - 1; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_dec_ulong_nv (reinterpret_cast(&this->value_)); +#else /* WIN32 */ + return (*decrement_fn_) (&this->value_); +#endif /* WIN32 */ +} + +ACE_INLINE long +ACE_Atomic_Op::operator-- (int) +{ + return --*this + 1; +} + +ACE_INLINE long +ACE_Atomic_Op::operator+= (long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedExchangeAdd (const_cast (&this->value_), + rhs) + rhs; +#elif defined (WIN32) && defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) + return ::InterlockedExchangeAdd (const_cast (&this->value_), + rhs) + rhs; +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicAdd (reinterpret_cast (const_cast (&this->value_)), rhs) + rhs; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_add_long_nv (reinterpret_cast(&this->value_), rhs); +#else /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ + return (*exchange_add_fn_) (&this->value_, rhs) + rhs; +#endif /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ +} + +ACE_INLINE long +ACE_Atomic_Op::operator-= (long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedExchangeAdd (const_cast (&this->value_), + -rhs) - rhs; +#elif defined (WIN32) && defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) + return ::InterlockedExchangeAdd (const_cast (&this->value_), + -rhs) - rhs; +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicSub (reinterpret_cast (const_cast (&this->value_)), rhs) - rhs; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_add_long_nv (reinterpret_cast(&this->value_), -rhs); +#else /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ + return (*exchange_add_fn_) (&this->value_, -rhs) - rhs; +#endif /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ +} + +ACE_INLINE bool +ACE_Atomic_Op::operator== (long rhs) const +{ + return (this->value_ == rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator!= (long rhs) const +{ + return (this->value_ != rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator>= (long rhs) const +{ + return (this->value_ >= rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator> (long rhs) const +{ + return (this->value_ > rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator<= (long rhs) const +{ + return (this->value_ <= rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator< (long rhs) const +{ + return (this->value_ < rhs); +} + +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= (long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + ::_InterlockedExchange (const_cast (&this->value_), rhs); +#elif defined (WIN32) + ::InterlockedExchange (const_cast (&this->value_), rhs); +#elif defined (ACE_HAS_VXATOMICLIB) + ::vxAtomicSet (reinterpret_cast (const_cast (&this->value_)), rhs); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + ::atomic_swap_ulong (reinterpret_cast(&this->value_), rhs); +#else /* WIN32 */ + (*exchange_fn_) (&this->value_, rhs); +#endif /* WIN32 */ + return *this; +} + +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= ( + const ACE_Atomic_Op &rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + ::_InterlockedExchange (const_cast (&this->value_), rhs.value_); +#elif defined (WIN32) + ::InterlockedExchange (const_cast (&this->value_), rhs.value_); +#elif defined (ACE_HAS_VXATOMICLIB) + ::vxAtomicSet (reinterpret_cast (const_cast (&this->value_)), rhs.value_); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + ::atomic_swap_ulong (reinterpret_cast(&this->value_), rhs.value_); +#else /* WIN32 */ + (*exchange_fn_) (&this->value_, rhs.value_); +#endif /* WIN32 */ + return *this; +} + +ACE_INLINE long +ACE_Atomic_Op::exchange (long newval) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedExchange (const_cast (&this->value_), newval); +#elif defined (WIN32) + return ::InterlockedExchange (const_cast (&this->value_), newval); +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicSet (reinterpret_cast (const_cast (&this->value_)), newval); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_swap_ulong (reinterpret_cast(&this->value_), newval); +#else /* WIN32 */ + return (*exchange_fn_) (&this->value_, newval); +#endif /* WIN32 */ +} + +ACE_INLINE long +ACE_Atomic_Op::value (void) const +{ + return this->value_; +} + +ACE_INLINE volatile long & +ACE_Atomic_Op::value_i (void) +{ + return this->value_; +} + + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) + : value_ (0) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (unsigned long c) + : value_ (c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op ( + const ACE_Atomic_Op &rhs) + : value_ (rhs.value_) +{ +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator++ (void) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return static_cast (::_InterlockedIncrement (const_cast (reinterpret_cast(&this->value_)))); +#elif defined (WIN32) + return static_cast (::InterlockedIncrement (const_cast (reinterpret_cast(&this->value_)))); +#elif defined (ACE_HAS_VXATOMICLIB) + return static_cast (::vxAtomicInc (reinterpret_cast (const_cast (reinterpret_cast(&this->value_))))) + 1; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_inc_ulong_nv (&this->value_); +#else /* WIN32 */ + return static_cast ((*increment_fn_) (reinterpret_cast (&this->value_))); +#endif /* WIN32 */ +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator++ (int) +{ + return ++*this - 1; +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator-- (void) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return static_cast (::_InterlockedDecrement (const_cast (reinterpret_cast(&this->value_)))); +#elif defined (WIN32) + return static_cast (::InterlockedDecrement (const_cast (reinterpret_cast(&this->value_)))); +#elif defined (ACE_HAS_VXATOMICLIB) + return static_cast (::vxAtomicDec (reinterpret_cast (const_cast (reinterpret_cast(&this->value_))))) - 1; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_dec_ulong_nv (&this->value_); +#else /* WIN32 */ + return static_cast ((*decrement_fn_) (reinterpret_cast (&this->value_))); +#endif /* WIN32 */ +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator-- (int) +{ + return --*this + 1; +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator+= (unsigned long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return static_cast (::_InterlockedExchangeAdd (const_cast (reinterpret_cast (&this->value_)), + rhs)) + rhs; +#elif defined (WIN32) && defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) + return static_cast (::InterlockedExchangeAdd (const_cast (reinterpret_cast (&this->value_)), + rhs)) + rhs; +#elif defined (ACE_HAS_VXATOMICLIB) + return static_cast (::vxAtomicAdd (reinterpret_cast (const_cast (reinterpret_cast(&this->value_))), rhs)) + rhs; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_add_long_nv (&this->value_, rhs); +#else /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ + return static_cast ((*exchange_add_fn_) (reinterpret_cast (&this->value_), rhs)) + rhs; +#endif /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::operator-= (unsigned long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return static_cast (::_InterlockedExchangeAdd (const_cast (reinterpret_cast(&this->value_)), + -static_cast(rhs))) - rhs; +#elif defined (WIN32) && defined (ACE_HAS_INTERLOCKED_EXCHANGEADD) + return static_cast (::InterlockedExchangeAdd (const_cast (reinterpret_cast(&this->value_)), + -static_cast(rhs))) - rhs; +#elif defined (ACE_HAS_VXATOMICLIB) + return static_cast (::vxAtomicSub (reinterpret_cast (const_cast (reinterpret_cast(&this->value_))), rhs)) - rhs; +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_add_long_nv (&this->value_, -rhs); +#else /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ + long l_rhs = static_cast (rhs); + return static_cast ((*exchange_add_fn_) (reinterpret_cast (&this->value_), -l_rhs)) - rhs; +#endif /* WIN32 && ACE_HAS_INTERLOCKED_EXCHANGEADD */ +} + +ACE_INLINE bool +ACE_Atomic_Op::operator== (unsigned long rhs) const +{ + return (this->value_ == rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator!= (unsigned long rhs) const +{ + return (this->value_ != rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator>= (unsigned long rhs) const +{ + return (this->value_ >= rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator> (unsigned long rhs) const +{ + return (this->value_ > rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator<= (unsigned long rhs) const +{ + return (this->value_ <= rhs); +} + +ACE_INLINE bool +ACE_Atomic_Op::operator< (unsigned long rhs) const +{ + return (this->value_ < rhs); +} + +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= (unsigned long rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + ::_InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), rhs); +#elif defined (WIN32) + ::InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), rhs); +#elif defined (ACE_HAS_VXATOMICLIB) + ::vxAtomicSet (reinterpret_cast (const_cast (reinterpret_cast (&this->value_))), rhs); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + ::atomic_swap_ulong (&this->value_, rhs); +#else /* WIN32 */ + (*exchange_fn_) (reinterpret_cast (&this->value_), rhs); +#endif /* WIN32 */ + return *this; +} + +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= ( + const ACE_Atomic_Op &rhs) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + ::_InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), rhs.value_); +#elif defined (WIN32) + ::InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), rhs.value_); +#elif defined (ACE_HAS_VXATOMICLIB) + ::vxAtomicSet (reinterpret_cast (const_cast (reinterpret_cast (&this->value_))), rhs.value_); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + ::atomic_swap_ulong (&this->value_, rhs.value_); +#else /* WIN32 */ + (*exchange_fn_) (reinterpret_cast (&this->value_), rhs.value_); +#endif /* WIN32 */ + return *this; +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::exchange (unsigned long newval) +{ +#if defined (ACE_HAS_INTRINSIC_INTERLOCKED) + return ::_InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), newval); +#elif defined (WIN32) + return ::InterlockedExchange (const_cast (reinterpret_cast (&this->value_)), newval); +#elif defined (ACE_HAS_VXATOMICLIB) + return ::vxAtomicSet (reinterpret_cast (const_cast (reinterpret_cast (&this->value_))), newval); +#elif defined (ACE_HAS_SOLARIS_ATOMIC_LIB) + return ::atomic_swap_ulong (&this->value_, newval); +#else /* WIN32 */ + return (*exchange_fn_) (reinterpret_cast (&this->value_), newval); +#endif /* WIN32 */ +} + +ACE_INLINE unsigned long +ACE_Atomic_Op::value (void) const +{ + return this->value_; +} + +ACE_INLINE volatile unsigned long & +ACE_Atomic_Op::value_i (void) +{ + return this->value_; +} + +#endif /* ACE_HAS_BUILTIN_ATOMIC_OP */ + +#if defined (ACE_HAS_GCC_ATOMIC_BUILTINS) && (ACE_HAS_GCC_ATOMIC_BUILTINS == 1) + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC () +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (int c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (int rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC() +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (unsigned int c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (unsigned int rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC() +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (long c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (long rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC () +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (unsigned long c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (unsigned long rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + +// The long long intrinsics are not available on PPC +#if !defined (__powerpc__) +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC() +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (long long c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (long long rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC () +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (unsigned long long c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (unsigned long long rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} +#endif /* !__powerpc__ */ + +#if !defined (ACE_LACKS_GCC_ATOMIC_BUILTINS_2) +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC() +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (short c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (short rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC () +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (unsigned short c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (unsigned short rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} +#endif + +#if !defined (ACE_LACKS_GCC_ATOMIC_BUILTINS_1) +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (void) : + ACE_Atomic_Op_GCC () +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (bool c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op (const ACE_Atomic_Op &c) : + ACE_Atomic_Op_GCC(c) +{ +} + +ACE_INLINE +ACE_Atomic_Op& +ACE_Atomic_Op::operator= (bool rhs) +{ + ACE_Atomic_Op_GCC::operator= (rhs); + return *this; +} +#endif + +#endif /* ACE_HAS_GCC_ATOMIC_BUILTINS==1 */ + +ACE_END_VERSIONED_NAMESPACE_DECL + diff --git a/dep/acelite/ace/Atomic_Op_GCC_T.cpp b/dep/acelite/ace/Atomic_Op_GCC_T.cpp new file mode 100644 index 000000000..3e7e7cada --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_GCC_T.cpp @@ -0,0 +1,23 @@ +#include "ace/OS_NS_unistd.h" + +#if defined (ACE_HAS_GCC_ATOMIC_BUILTINS) && (ACE_HAS_GCC_ATOMIC_BUILTINS == 1) + +#if !defined (__ACE_INLINE__) +#include "ace/Atomic_Op_GCC_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +void +ACE_Atomic_Op_GCC::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_GCC_ATOMIC_BUILTINS */ diff --git a/dep/acelite/ace/Atomic_Op_GCC_T.h b/dep/acelite/ace/Atomic_Op_GCC_T.h new file mode 100644 index 000000000..6a25fe176 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_GCC_T.h @@ -0,0 +1,137 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Atomic_Op_GCC_T.h + * + * @author Johnny Willemsen +class ACE_Export ACE_Atomic_Op_GCC +{ +public: + /// Atomically pre-increment @c value_. + T operator++ (void); + + /// Atomically post-increment @c value_. + T operator++ (int); + + /// Atomically increment @c value_ by rhs. + T operator+= (T rhs); + + /// Atomically pre-decrement @c value_. + T operator-- (void); + + /// Atomically post-decrement @c value_. + T operator-- (int); + + /// Atomically decrement @c value_ by rhs. + T operator-= (T rhs); + + /// Atomically compare @c value_ with rhs. + bool operator== (T rhs) const; + + /// Atomically compare @c value_ with rhs. + bool operator!= (T rhs) const; + + /// Atomically check if @c value_ greater than or equal to rhs. + bool operator>= (T rhs) const; + + /// Atomically check if @c value_ greater than rhs. + bool operator> (T rhs) const; + + /// Atomically check if @c value_ less than or equal to rhs. + bool operator<= (T rhs) const; + + /// Atomically check if @c value_ less than rhs. + bool operator< (T rhs) const; + + /// Exchange value with @a newval. + T exchange (T newval); + + /// Explicitly return @c value_. + T value (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Explicitly return @c value_ (by reference). + volatile T &value_i (void); + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. + +protected: + /// Atomically assign rhs to @c value_. + ACE_Atomic_Op_GCC &operator= (T rhs); + + /// Atomically assign to @c value_. + ACE_Atomic_Op_GCC &operator= (const ACE_Atomic_Op_GCC &rhs); + + /// Initialize @c value_ to 0. + ACE_Atomic_Op_GCC (void); + + /// Initialize @c value_ to c. + ACE_Atomic_Op_GCC (T c); + + /// Manage copying... + ACE_Atomic_Op_GCC (const ACE_Atomic_Op_GCC &c); + +private: + + // This function cannot be supported by this template specialization. + // If you need access to an underlying lock, use the ACE_Atomic_Op_Ex + // template instead. + ACE_Thread_Mutex &mutex (void); + +private: + + /// Current object decorated by the atomic op. + volatile T value_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Atomic_Op_GCC_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Atomic_Op_GCC_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Atomic_Op_GCC_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + + +#endif /* ACE_HAS_GCC_ATOMIC_BUILTINS */ + +#include /**/ "ace/post.h" +#endif /*ACE_ATOMIC_OP_GCC_T_H*/ diff --git a/dep/acelite/ace/Atomic_Op_GCC_T.inl b/dep/acelite/ace/Atomic_Op_GCC_T.inl new file mode 100644 index 000000000..90f7c4839 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_GCC_T.inl @@ -0,0 +1,152 @@ +// -*- C++ -*- +#if defined (ACE_HAS_GCC_ATOMIC_BUILTINS) && (ACE_HAS_GCC_ATOMIC_BUILTINS == 1) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_INLINE +ACE_Atomic_Op_GCC::ACE_Atomic_Op_GCC (void) + : value_ (0) +{ +} + +template +ACE_INLINE +ACE_Atomic_Op_GCC::ACE_Atomic_Op_GCC (T c) + : value_ (c) +{ +} + +template +ACE_INLINE +ACE_Atomic_Op_GCC::ACE_Atomic_Op_GCC ( + const ACE_Atomic_Op_GCC &rhs) + : value_ (rhs.value_) +{ +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator++ (void) +{ + return __sync_add_and_fetch (&this->value_, 1); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator++ (int) +{ + return __sync_fetch_and_add (&this->value_, 1); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator-- (void) +{ + return __sync_sub_and_fetch (&this->value_, 1); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator-- (int) +{ + return __sync_fetch_and_sub (&this->value_, 1); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator+= (T rhs) +{ + return __sync_add_and_fetch (&this->value_, rhs); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::operator-= (T rhs) +{ + return __sync_sub_and_fetch (&this->value_, rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator== (T rhs) const +{ + return (this->value_ == rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator!= (T rhs) const +{ + return (this->value_ != rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator>= (T rhs) const +{ + return (this->value_ >= rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator> (T rhs) const +{ + return (this->value_ > rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator<= (T rhs) const +{ + return (this->value_ <= rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_GCC::operator< (T rhs) const +{ + return (this->value_ < rhs); +} + +template +ACE_INLINE ACE_Atomic_Op_GCC & +ACE_Atomic_Op_GCC::operator= (T rhs) +{ + (void) __sync_lock_test_and_set (&this->value_, rhs); + return *this; +} + +template +ACE_INLINE ACE_Atomic_Op_GCC & +ACE_Atomic_Op_GCC::operator= ( + const ACE_Atomic_Op_GCC &rhs) +{ + (void) __sync_lock_test_and_set (&this->value_, rhs.value_); + return *this; +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::exchange (T newval) +{ + return __sync_val_compare_and_swap (&this->value_, this->value_, newval); +} + +template +ACE_INLINE T +ACE_Atomic_Op_GCC::value (void) const +{ + return this->value_; +} + +template +ACE_INLINE volatile T & +ACE_Atomic_Op_GCC::value_i (void) +{ + return this->value_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_GCC_ATOMIC_BUILTINS */ diff --git a/dep/acelite/ace/Atomic_Op_Sparc.c b/dep/acelite/ace/Atomic_Op_Sparc.c new file mode 100644 index 000000000..9e59864ae --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_Sparc.c @@ -0,0 +1,187 @@ +/* + * + * This is a C file for a reason. The Sun C++ compiler does not accept + * inline assembler. + * + * Portions of this code are based on atomic operations found in the + * linux kernel source code. + */ + +#if defined (ACE_INCLUDE_ATOMIC_OP_SPARC) + +#if defined(__i386) && defined(__SUNPRO_C) +static void +__sunpro_asm_code() { + __asm("\n\ + .globl ace_atomic_add_long \n\ + .type ace_atomic_add_long,@function \n\ + .align 4 \n\ +ace_atomic_add_long: \n\ + movl 0x00000004(%esp), %edx \n\ + movl 0x00000008(%esp), %eax \n\ + lock; xadd %eax, (%edx) \n\ + addl 0x00000008(%esp), %eax \n\ + ret \n\ + "); + + __asm("\n\ + .globl ace_atomic_swap_long \n\ + .type ace_atomic_swap_long,@function \n\ + .align 4 \n\ +ace_atomic_swap_long: \n\ + movl 0x00000004(%esp), %edx \n\ + movl 0x00000008(%esp), %eax \n\ + xchg %eax, (%edx) \n\ + ret \n\ + "); + + __asm("\n\ + .globl ace_atomic_swap_add_long \n\ + .type ace_atomic_swap_add_long,@function \n\ + .align 4 \n\ +ace_atomic_swap_add_long: \n\ + movl 0x00000004(%esp), %edx \n\ + movl 0x00000008(%esp), %eax \n\ + lock; xadd %eax, (%edx) \n\ + ret \n\ + "); +} + +#elif defined(__x86_64) && defined(__SUNPRO_C) + +static void +__sunpro_asm_code() { + __asm("\n\ + .globl ace_atomic_add_long \n\ + .type ace_atomic_add_long,@function \n\ + .align 16 \n\ +ace_atomic_add_long: \n\ + movq %rsi, %rax \n\ + lock; xaddq %rax, (%rdi) \n\ + addq %rsi, %rax \n\ + ret \n\ + "); + + __asm("\n\ + .globl ace_atomic_swap_long \n\ + .type ace_atomic_swap_long,@function \n\ + .align 16 \n\ +ace_atomic_swap_long: \n\ + xchgq %rsi, (%rdi) \n\ + movq %rsi, %rax \n\ + ret \n\ + "); + + __asm("\n\ + .globl ace_atomic_swap_add_long \n\ + .type ace_atomic_swap_add_long,@function \n\ + .align 16 \n\ +ace_atomic_swap_add_long: \n\ + lock; xaddq %rsi, (%rdi) \n\ + movq %rsi, %rax \n\ + ret \n\ + "); +} + +#elif defined (__sparcv9) + +unsigned long +ace_atomic_add_long (volatile unsigned long *dest, long rhs) +{ + __asm ("restore\n" + "ldx [%o0], %o2\n" + ".again_add:\n" + "add %o2, %o1, %o3\n" + "casx [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %xcc, .again_add\n" + "mov %o3, %o2\n" + "retl\n" + "add %o2, %o1, %o0\n"); +} + +unsigned long +ace_atomic_swap_long (volatile unsigned long *dest, unsigned long rhs) +{ + __asm ("restore\n" + "ldx [%o0], %o2\n" + ".again_swap:\n" + "mov %o1, %o3\n" + "casx [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %xcc, .again_swap\n" + "mov %o3, %o2\n" + "retl\n" + "mov %o3, %o0\n"); +} + +unsigned long +ace_atomic_swap_add_long (volatile unsigned long *dest, long rhs) +{ + __asm ("restore\n" + "ldx [%o0], %o2\n" + ".again_swap_add:\n" + "mov %o2, %o4\n" + "add %o2, %o1, %o3\n" + "casx [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %xcc, .again_swap_add\n" + "mov %o3, %o2\n" + "retl\n" + "mov %o4, %o0\n"); +} + +#else + +unsigned long +ace_atomic_add_long (volatile unsigned long *dest, long rhs) +{ + __asm ("restore\n" + "ld [%o0], %o2\n" + ".again_add:\n" + "add %o2, %o1, %o3\n" + "cas [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %icc, .again_add\n" + "mov %o3, %o2\n" + "retl\n" + "add %o2, %o1, %o0\n"); +} + +unsigned long +ace_atomic_swap_long (volatile unsigned long *dest, unsigned long rhs) +{ + __asm ("restore\n" + "ld [%o0], %o2\n" + ".again_swap:\n" + "mov %o1, %o3\n" + "cas [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %icc, .again_swap\n" + "mov %o3, %o2\n" + "retl\n" + "mov %o3, %o0\n"); +} + +unsigned long +ace_atomic_swap_add_long (volatile unsigned long *dest, long rhs) +{ + __asm ("restore\n" + "ld [%o0], %o2\n" + ".again_swap_add:\n" + "mov %o2, %o4\n" + "add %o2, %o1, %o3\n" + "cas [%o0], %o2, %o3\n" + "cmp %o2, %o3\n" + "bne,pn %icc, .again_swap_add\n" + "mov %o3, %o2\n" + "retl\n" + "mov %o4, %o0\n"); +} + +# endif /* __sparcv9 */ + +#elif !defined (__GNUC__) && !defined (__INTEL_COMPILER) +/* Make compilers stop complaining about an empty translation unit */ +static int shut_up_compiler = 0; +#endif /* ACE_INCLUDE_ATOMIC_OP_SPARC */ diff --git a/dep/acelite/ace/Atomic_Op_Sparc.h b/dep/acelite/ace/Atomic_Op_Sparc.h new file mode 100644 index 000000000..3c4d883c2 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_Sparc.h @@ -0,0 +1,12 @@ +/* -*- C++ -*- */ +#ifndef ACE_ATOMIC_OP_SPARC_H +#define ACE_ATOMIC_OP_SPARC_H + +extern "C" +{ + unsigned long ace_atomic_add_long (volatile unsigned long *dest, long rhs); + unsigned long ace_atomic_swap_long (volatile unsigned long *dest, unsigned long rhs); + unsigned long ace_atomic_swap_add_long (volatile unsigned long *dest, long rhs); +} + +#endif /* ACE_ATOMIC_OP_SPARC_H */ diff --git a/dep/acelite/ace/Atomic_Op_T.cpp b/dep/acelite/ace/Atomic_Op_T.cpp new file mode 100644 index 000000000..d925d6e46 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_T.cpp @@ -0,0 +1,84 @@ +#ifndef ACE_ATOMIC_OP_T_CPP +#define ACE_ATOMIC_OP_T_CPP + +#include "ace/Atomic_Op_T.h" + +#ifdef ACE_HAS_DUMP +# include "ace/Log_Category.h" +#endif /* ACE_HAS_DUMP */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Atomic_Op_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Atomic_Op_Ex) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Atomic_Op) + +// ************************************************* +template ACE_LOCK & +ACE_Atomic_Op_Ex::mutex (void) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::mutex"); + return this->mutex_; +} + +template +void +ACE_Atomic_Op_Ex::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // ACE_TRACE ("ACE_Atomic_Op_Ex::dump"); + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->mutex_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex (ACE_LOCK & mtx) + : mutex_ (mtx) + , value_ (0) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex"); +} + +template +ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex ( + ACE_LOCK & mtx, + typename ACE_Atomic_Op_Ex::arg_type c) + : mutex_ (mtx) + , value_ (c) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex"); +} + +// **************************************************************** + +template +ACE_Atomic_Op::ACE_Atomic_Op (void) + : impl_ (this->own_mutex_) +{ + // ACE_TRACE ("ACE_Atomic_Op::ACE_Atomic_Op"); +} + +template +ACE_Atomic_Op::ACE_Atomic_Op ( + typename ACE_Atomic_Op::arg_type c) + : impl_ (own_mutex_, c) +{ + // ACE_TRACE ("ACE_Atomic_Op::ACE_Atomic_Op"); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_ATOMIC_OP_T_CPP */ diff --git a/dep/acelite/ace/Atomic_Op_T.h b/dep/acelite/ace/Atomic_Op_T.h new file mode 100644 index 000000000..8031efb20 --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_T.h @@ -0,0 +1,360 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Atomic_Op_T.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_ATOMIC_OP_T_H +#define ACE_ATOMIC_OP_T_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +struct ACE_Type_Traits +{ + typedef TYPE const & parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef bool parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef char parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef signed char parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef unsigned char parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef short parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef unsigned short parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef int parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef unsigned int parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef long parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef unsigned long parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef long long parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef unsigned long long parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef float parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef double parameter_type; +}; + +template<> +struct ACE_Type_Traits +{ + typedef long double parameter_type; +}; + +template +struct ACE_Type_Traits +{ + typedef TYPE* parameter_type; +}; + +/** + * @class ACE_Atomic_Op_Ex + * + * @brief Transparently parameterizes synchronization into basic + * arithmetic operations. + * + * This class is described in an article in the July/August 1994 + * issue of the C++ Report magazine. It implements a + * templatized version of the Decorator pattern from the GoF book. + * + * ACE_Atomic_Op_Ex objects must be constructed with a reference + * to an existing lock. A single lock can be shared between + * multiple ACE_Atomic_Op_Ex objects. If you do not require this + * ability consider using the ACE_Atomic_Op class instead, which + * may be able to take advantage of platform-specific + * optimisations to provide atomic operations without requiring a + * lock. + */ +template +class ACE_Atomic_Op_Ex +{ +public: + + typedef typename ACE_Type_Traits::parameter_type arg_type; + + // = Initialization methods. + + /// Initialize @c value_ to 0. + ACE_Atomic_Op_Ex (ACE_LOCK & mtx); + + /// Initialize @c value_ to c. + ACE_Atomic_Op_Ex (ACE_LOCK & mtx, arg_type c); + + // = Accessors. + + /// Atomically pre-increment @c value_. + TYPE operator++ (void); + + /// Atomically post-increment @c value_. + TYPE operator++ (int); + + /// Atomically increment @c value_ by rhs. + TYPE operator+= (arg_type rhs); + + /// Atomically pre-decrement @c value_. + TYPE operator-- (void); + + /// Atomically post-decrement @c value_. + TYPE operator-- (int); + + /// Atomically decrement @c value_ by rhs. + TYPE operator-= (arg_type rhs); + + /// Atomically compare @c value_ with rhs. + bool operator== (arg_type rhs) const; + + /// Atomically compare @c value_ with rhs. + bool operator!= (arg_type rhs) const; + + /// Atomically check if @c value_ greater than or equal to rhs. + bool operator>= (arg_type rhs) const; + + /// Atomically check if @c value_ greater than rhs. + bool operator> (arg_type rhs) const; + + /// Atomically check if @c value_ less than or equal to rhs. + bool operator<= (arg_type rhs) const; + + /// Atomically check if @c value_ less than rhs. + bool operator< (arg_type rhs) const; + + /// Atomically assign rhs to @c value_. + ACE_Atomic_Op_Ex &operator= (arg_type rhs); + + /// Atomically assign to @c value_. + ACE_Atomic_Op_Ex &operator= ( + ACE_Atomic_Op_Ex const & rhs); + + /// Exchange value with @a newval. + TYPE exchange (TYPE newval); + + /// Explicitly return @c value_. + TYPE value (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Manage copying... + ACE_Atomic_Op_Ex (ACE_Atomic_Op_Ex const &); + + /** + * Returns a reference to the underlying ACE_LOCK. This makes it + * possible to acquire the lock explicitly, which can be useful in + * some cases if you instantiate the ACE_Atomic_Op_Ex with an + * ACE_Recursive_Mutex or ACE_Process_Mutex. + * + * @note The right name would be lock_, but HP/C++ will choke on that! + */ + ACE_LOCK & mutex (void); + + /** + * Explicitly return @c value_ (by reference). This gives the user + * full, unrestricted access to the underlying value. This method + * will usually be used in conjunction with explicit access to the + * lock. Use with care ;-) + */ + TYPE & value_i (void); + +private: + /// Type of synchronization mechanism. + ACE_LOCK & mutex_; + + /// Current object decorated by the atomic op. + TYPE value_; +}; + +/** + * @class ACE_Atomic_Op + * + * @brief Transparently parameterizes synchronization into basic + * arithmetic operations. + * + * This class is described in an article in the July/August 1994 + * issue of the C++ Report magazine. It implements a + * templatized version of the Decorator pattern from the GoF book. + * + * Certain platforms may provide a template specialization for + * ACE_Atomic_Op that provides optimized + * atomic integer operations without actually requiring a mutex. + */ +template +class ACE_Atomic_Op +{ +public: + + typedef typename ACE_Type_Traits::parameter_type arg_type; + + /// Initialize @c value_ to 0. + ACE_Atomic_Op (void); + + /// Initialize @c value_ to c. + ACE_Atomic_Op (arg_type c); + + /// Manage copying... + ACE_Atomic_Op (ACE_Atomic_Op const & c); + + /// Atomically assign @a rhs to @c value_. + ACE_Atomic_Op & operator= (arg_type rhs); + + /// Atomically assign @a rhs to @c value_. + ACE_Atomic_Op & operator= ( + ACE_Atomic_Op const & rhs); + + /// Atomically pre-increment @c value_. + TYPE operator++ (void); + + /// Atomically post-increment @c value_. + TYPE operator++ (int); + + /// Atomically increment @c value_ by rhs. + TYPE operator+= (arg_type rhs); + + /// Atomically pre-decrement @c value_. + TYPE operator-- (void); + + /// Atomically post-decrement @c value_. + TYPE operator-- (int); + + /// Atomically decrement @c value_ by @a rhs. + TYPE operator-= (arg_type rhs); + + /// Atomically compare @c value_ with @a rhs. + bool operator== (arg_type rhs) const; + + /// Atomically compare @c value_ with @a rhs. + bool operator!= (arg_type rhs) const; + + /// Atomically check if @c value_ greater than or equal to @a rhs. + bool operator>= (arg_type rhs) const; + + /// Atomically check if @c value_ greater than @a rhs. + bool operator> (arg_type rhs) const; + + /// Atomically check if @c value_ less than or equal to @a rhs. + bool operator<= (arg_type rhs) const; + + /// Atomically check if @c value_ less than @a rhs. + bool operator< (arg_type rhs) const; + + /// Exchange value with @a newval. + TYPE exchange (TYPE newval); + + /// Explicitly return @c value_. + TYPE value (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /** + * Explicitly return @c value_ (by reference). This gives the user + * full, unrestricted access to the underlying value. This method + * will usually be used in conjunction with explicit access to the + * lock. Use with care ;-) + */ + TYPE & value_i (void); + +private: + /// Type of synchronization mechanism. + ACE_LOCK own_mutex_; + + /// Underlying atomic op implementation. + ACE_Atomic_Op_Ex impl_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Atomic_Op_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Atomic_Op_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Atomic_Op_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /*ACE_ATOMIC_OP_T_H*/ diff --git a/dep/acelite/ace/Atomic_Op_T.inl b/dep/acelite/ace/Atomic_Op_T.inl new file mode 100644 index 000000000..1b1eb988f --- /dev/null +++ b/dep/acelite/ace/Atomic_Op_T.inl @@ -0,0 +1,346 @@ +// -*- C++ -*- +#include "ace/Guard_T.h" + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// +// ACE_Atomic_Op_Ex inline functions +// + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator++ (void) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator++"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return ++this->value_; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator+= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator+="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return this->value_ += rhs; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator-- (void) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator--"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return --this->value_; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator-= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator-="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return this->value_ -= rhs; +} + +template +ACE_INLINE +ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex ( + ACE_Atomic_Op_Ex const & rhs) + : mutex_ (rhs.mutex_) + , value_ (rhs.value ()) // rhs.value() returns atomically +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::ACE_Atomic_Op_Ex"); +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator++ (int) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator++"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return this->value_++; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::operator-- (int) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator--"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return this->value_--; +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator== ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator=="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, false); + return this->value_ == rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator!= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator!="); + return !(*this == rhs); +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator>= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator>="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, false); + return this->value_ >= rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator> ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator>"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, false); + return this->value_ > rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator<= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator<="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, false); + return this->value_ <= rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op_Ex::operator< ( + typename ACE_Atomic_Op_Ex::arg_type rhs) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator<"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, false); + return this->value_ < rhs; +} + +template +ACE_INLINE ACE_Atomic_Op_Ex & +ACE_Atomic_Op_Ex::operator= ( + ACE_Atomic_Op_Ex const & rhs) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator="); + + ACE_Atomic_Op_Ex tmp (rhs); + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, *this); + std::swap (this->value_, tmp.value_); + + return *this; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::exchange (TYPE newval) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::exchange"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + std::swap (this->value_, newval); + return newval; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op_Ex::value (void) const +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::value"); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, this->value_); + return this->value_; +} + +template +ACE_INLINE TYPE & +ACE_Atomic_Op_Ex::value_i (void) +{ + // Explicitly return (by reference). This gives the user + // full, unrestricted access to the underlying value. This method + // will usually be used in conjunction with explicit access to the + // lock. Use with care ;-) + return this->value_; +} + +template +ACE_INLINE ACE_Atomic_Op_Ex & +ACE_Atomic_Op_Ex::operator= ( + typename ACE_Atomic_Op_Ex::arg_type rhs) +{ + // ACE_TRACE ("ACE_Atomic_Op_Ex::operator="); + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, *this); + this->value_ = rhs; + return *this; +} + +// +// ACE_Atomic_Op inline functions +// + +template ACE_INLINE +ACE_Atomic_Op::ACE_Atomic_Op ( + ACE_Atomic_Op const & rhs) + : impl_ (own_mutex_, rhs.value ()) +{ + // ACE_TRACE ("ACE_Atomic_Op::ACE_Atomic_Op"); +} + + +template +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= ( + typename ACE_Atomic_Op::arg_type i) +{ + this->impl_ = i; + return *this; +} + +template +ACE_INLINE ACE_Atomic_Op & +ACE_Atomic_Op::operator= ( + ACE_Atomic_Op const & rhs) +{ + this->impl_ = rhs.impl_; + return *this; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator++ (void) +{ + return ++this->impl_; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator++ (int) +{ + return this->impl_++; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator+= ( + typename ACE_Atomic_Op::arg_type rhs) +{ + return this->impl_ += rhs; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator-- (void) +{ + return --this->impl_; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator-- (int) +{ + return this->impl_--; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::operator-= ( + typename ACE_Atomic_Op::arg_type rhs) +{ + return this->impl_ -= rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator== ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ == rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator!= ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ != rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator>= ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ >= rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator> ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ > rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator<= ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ <= rhs; +} + +template +ACE_INLINE bool +ACE_Atomic_Op::operator< ( + typename ACE_Atomic_Op::arg_type rhs) const +{ + return this->impl_ < rhs; +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::exchange (TYPE newval) +{ + return this->impl_.exchange (newval); +} + +template +ACE_INLINE TYPE +ACE_Atomic_Op::value (void) const +{ + return this->impl_.value (); +} + +template +ACE_INLINE void +ACE_Atomic_Op::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->impl_.dump (); +#endif /* ACE_HAS_DUMP */ + return; +} +template +ACE_INLINE TYPE & +ACE_Atomic_Op::value_i (void) +{ + return this->impl_.value_i (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Auto_Event.cpp b/dep/acelite/ace/Auto_Event.cpp new file mode 100644 index 000000000..c95c0e855 --- /dev/null +++ b/dep/acelite/ace/Auto_Event.cpp @@ -0,0 +1,54 @@ +#include "ace/Auto_Event.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Auto_Event.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Auto_Event_T) + +template +ACE_Auto_Event_T::ACE_Auto_Event_T ( + int initial_state, + int type, + const char *name, + void *arg) + : ACE_Event_T (0, + initial_state, + type, + ACE_TEXT_CHAR_TO_TCHAR (name), + arg) +{ +} + +#if defined (ACE_HAS_WCHAR) +template +ACE_Auto_Event_T::ACE_Auto_Event_T ( + int initial_state, + int type, + const wchar_t *name, + void *arg) + : ACE_Event_T (0, + initial_state, + type, + ACE_TEXT_WCHAR_TO_TCHAR (name), + arg) +{ +} +#endif /* ACE_HAS_WCHAR */ + +template +void +ACE_Auto_Event_T::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_Event_T::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Auto_Event.h b/dep/acelite/ace/Auto_Event.h new file mode 100644 index 000000000..f01882c62 --- /dev/null +++ b/dep/acelite/ace/Auto_Event.h @@ -0,0 +1,110 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Auto_Event.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_AUTO_EVENT_H +#define ACE_AUTO_EVENT_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Auto_Event + * + * @brief Auto Events. + * + * Specialization of Event mechanism which wakes up one waiting + * thread on @c signal. All platforms support process-scope locking + * support. However, only Win32 platforms support global naming and + * system-scope locking support. + */ +template +class ACE_Auto_Event_T : public ACE_Event_T +{ +public: + /// Constructor which will create auto event + ACE_Auto_Event_T (int initial_state = 0, + int type = USYNC_THREAD, + const char *name = 0, + void *arg = 0); + +#if defined (ACE_HAS_WCHAR) + /// Constructor which will create auto event (wchar_t version) + ACE_Auto_Event_T (int initial_state, + int type, + const wchar_t *name, + void *arg = 0); +#endif /* ACE_HAS_WCHAR */ + + /// Default dtor. + virtual ~ACE_Auto_Event_T (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks + ACE_ALLOC_HOOK_DECLARE; +}; + +class ACE_Auto_Event : + public ACE_Auto_Event_T +{ +public: + /// Constructor which will create auto event + ACE_Auto_Event (int initial_state = 0, + int type = USYNC_THREAD, + const char *name = 0, + void *arg = 0) + : ACE_Auto_Event_T (initial_state, type, name, arg) + { + } + +#if defined (ACE_HAS_WCHAR) + /// Constructor which will create auto event (wchar_t version) + ACE_Auto_Event (int initial_state, + int type, + const wchar_t *name, + void *arg = 0) + : ACE_Auto_Event_T (initial_state, type, name, arg) + { + } +#endif /* ACE_HAS_WCHAR */ + + /// Default dtor. + virtual ~ACE_Auto_Event (void) + { + } +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Auto_Event.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Auto_Event.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Auto_Event.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_AUTO_EVENT_H */ diff --git a/dep/acelite/ace/Auto_Event.inl b/dep/acelite/ace/Auto_Event.inl new file mode 100644 index 000000000..919c048d3 --- /dev/null +++ b/dep/acelite/ace/Auto_Event.inl @@ -0,0 +1,10 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_INLINE +ACE_Auto_Event_T::~ACE_Auto_Event_T (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Auto_Functor.cpp b/dep/acelite/ace/Auto_Functor.cpp new file mode 100644 index 000000000..7310d78d3 --- /dev/null +++ b/dep/acelite/ace/Auto_Functor.cpp @@ -0,0 +1,37 @@ +#ifndef ACE_AUTO_FUNCTOR_CPP +#define ACE_AUTO_FUNCTOR_CPP + +#include "ace/Auto_Functor.h" + +#if !defined(__ACE_INLINE__) +# include "ace/Auto_Functor.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Utils::Auto_Functor::~Auto_Functor() +{ + reset(0); +} + +template void +ACE_Utils::Auto_Functor::reset(X * p) +{ + if(p_ != 0) + { + f_(p_); + } + p_ = p; +} + +templatevoid +ACE_Utils::Auto_Functor::reset(X * p, Functor f) +{ + reset(p); + f_ = f; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /*ACE_AUTO_FUNCTOR_CPP*/ diff --git a/dep/acelite/ace/Auto_Functor.h b/dep/acelite/ace/Auto_Functor.h new file mode 100644 index 000000000..7e75ae7b6 --- /dev/null +++ b/dep/acelite/ace/Auto_Functor.h @@ -0,0 +1,118 @@ +// -*- C++ -*- +//============================================================================= +/** + * @file Auto_Functor.h + * + * @author Carlos O'Ryan + */ +//============================================================================= +#ifndef ACE_AUTO_FUNCTOR_H +#define ACE_AUTO_FUNCTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE_Utils +{ +/** + * @class Auto_Functor_Ref + * + * @brief Helper class to implement assignment and copy-construction + * as expected + */ +template +struct Auto_Functor_Ref +{ + X * p_; + Functor f_; + + Auto_Functor_Ref(X * p, Functor f); +}; + +/** + * @class Auto_Functor + * + * @brief Helper template to implement auto_ptr<>-like classes, but + * executing a functor in the destructor, instead of always + * deleting things. + * + * The functor is called in the destructor, and it must implement: + * + * Functor() throw();
+ * Functor(Functor const &) throw();
+ * Functor & operator=(Functor const &) throw();
+ * void operator()(X * p) throw();
+ */ +template +class Auto_Functor +{ +public: + typedef X element_type; + typedef Functor functor_type; + + /// Constructor + explicit Auto_Functor (X * p = 0, + Functor functor = Functor()); // throw() + + Auto_Functor (Auto_Functor & rhs); // throw() + + Auto_Functor& operator= (Auto_Functor & rhs); // throw() + + template + Auto_Functor(Auto_Functor& rhs); // throw() + + template + Auto_Functor& operator= (Auto_Functor& rhs); // throw() + + ~Auto_Functor(); // throw() + + X & operator*() const; // throw() + + X * operator->() const; // throw() + + X * get(); // throw() + + X * release(); // throw() + + void reset (X * p = 0); // throw() + + void reset (X * p, Functor f); // throw() + + Functor const & functor() const; // throw() + + Auto_Functor(Auto_Functor_Ref rhs); // throw() + + Auto_Functor & operator=(Auto_Functor_Ref rhs); // throw() + + template operator Auto_Functor_Ref(); // throw() + + template operator Auto_Functor(); // throw() + +private: + X * p_; + + Functor f_; +}; + +} // namespace ACE_Utils + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined(__ACE_INLINE__) +# include "ace/Auto_Functor.inl" +#endif /* __ACE_INLINE__ */ + +#if defined(ACE_TEMPLATES_REQUIRE_SOURCE) +# include "ace/Auto_Functor.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#include /**/ "ace/post.h" +#endif /* ACE_AUTO_FUNCTOR_H*/ diff --git a/dep/acelite/ace/Auto_Functor.inl b/dep/acelite/ace/Auto_Functor.inl new file mode 100644 index 000000000..be0c38361 --- /dev/null +++ b/dep/acelite/ace/Auto_Functor.inl @@ -0,0 +1,117 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_Utils::Auto_Functor_Ref:: +Auto_Functor_Ref(X * p, Functor f) + : p_(p) + , f_(f) +{ +} + +template ACE_INLINE +ACE_Utils::Auto_Functor::Auto_Functor(X * p, Functor f) + : p_(p) + , f_(f) +{ +} + +template ACE_INLINE +ACE_Utils::Auto_Functor::Auto_Functor(Auto_Functor & rhs) + : p_(rhs.release()) + , f_(rhs.f_) +{ +} + +template +ACE_INLINE ACE_Utils::Auto_Functor& +ACE_Utils::Auto_Functor:: operator=(Auto_Functor & rhs) +{ + reset(rhs.release()); + f_ = rhs.f_; + return *this; +} + +template template ACE_INLINE +ACE_Utils::Auto_Functor::Auto_Functor(Auto_Functor& rhs) + : p_(rhs.release()) + , f_(rhs.f_) +{ +} + +template template +ACE_INLINE ACE_Utils::Auto_Functor& +ACE_Utils::Auto_Functor::operator=(Auto_Functor& rhs) +{ + reset(rhs.release()); + return *this; +} + +template ACE_INLINE X & +ACE_Utils::Auto_Functor::operator*() const +{ + return *p_; +} + +template +ACE_INLINE X * +ACE_Utils::Auto_Functor::operator->() const +{ + return p_; +} + +template +ACE_INLINE X * +ACE_Utils::Auto_Functor::get() +{ + return p_; +} + +template +ACE_INLINE X * +ACE_Utils::Auto_Functor::release() +{ + X * tmp = p_; + p_ = 0; + return tmp; +} + +template +ACE_INLINE Functor const & +ACE_Utils::Auto_Functor::functor() const +{ + return f_; +} + +template ACE_INLINE +ACE_Utils::Auto_Functor::Auto_Functor(Auto_Functor_Ref rhs) + : p_(rhs.p_) + , f_(rhs.f_) +{ +} + +template +ACE_INLINE ACE_Utils::Auto_Functor & +ACE_Utils::Auto_Functor::operator=(Auto_Functor_Ref rhs) +{ + if(rhs.p_ != p_) + { + reset(rhs.p_); + f_ = rhs.f_; + } + return *this; +} + +template template ACE_INLINE +ACE_Utils::Auto_Functor::operator ACE_Utils::Auto_Functor_Ref() +{ + return ACE_Utils::Auto_Functor_Ref(release(), f_); +} + +template template ACE_INLINE +ACE_Utils::Auto_Functor::operator ACE_Utils::Auto_Functor() +{ + return ACE_Utils::Auto_Functor(release(), f_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Auto_IncDec_T.cpp b/dep/acelite/ace/Auto_IncDec_T.cpp new file mode 100644 index 000000000..5d408c7db --- /dev/null +++ b/dep/acelite/ace/Auto_IncDec_T.cpp @@ -0,0 +1,36 @@ +#ifndef ACE_AUTO_INCDEC_T_CPP +#define ACE_AUTO_INCDEC_T_CPP + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Auto_IncDec_T.h" +#include "ace/Log_Category.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Auto_IncDec_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Auto_IncDec) + +template void +ACE_Auto_IncDec::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Auto_IncDec::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_AUTO_INCDEC_T_CPP */ diff --git a/dep/acelite/ace/Auto_IncDec_T.h b/dep/acelite/ace/Auto_IncDec_T.h new file mode 100644 index 000000000..d8e028344 --- /dev/null +++ b/dep/acelite/ace/Auto_IncDec_T.h @@ -0,0 +1,79 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Auto_IncDec_T.h + * + * @author Edan Ayal + */ +//============================================================================= + + +#ifndef ACE_AUTO_INCDEC_T_H +#define ACE_AUTO_INCDEC_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Auto_IncDec + * + * @brief This class automatically increments and decrements a + * parameterized counter. + * + * This data structure is meant to be used within a method, + * function, or scope. The actual parameter given for the + * @c ACE_SAFELY_INCREMENTABLE_DECREMENTABLE template parameter + * must provide at least operators ++ and --. + */ +template +class ACE_Auto_IncDec +{ +public: + /// Implicitly increment the counter. + ACE_Auto_IncDec (ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter); + + /// Implicitly decrement the counter. + ~ACE_Auto_IncDec (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Reference to the @c ACE_SAFELY_INCREMENTABLE_DECREMENTABLE counter + /// we're incrementing/decrementing. + ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter_; +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Auto_IncDec &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Auto_IncDec (const ACE_Auto_IncDec &)) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Auto_IncDec_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Auto_IncDec_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Auto_IncDec_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_AUTO_INCDEC_T_H */ diff --git a/dep/acelite/ace/Auto_IncDec_T.inl b/dep/acelite/ace/Auto_IncDec_T.inl new file mode 100644 index 000000000..cb2144888 --- /dev/null +++ b/dep/acelite/ace/Auto_IncDec_T.inl @@ -0,0 +1,22 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Implicitly and automatically increment the counter. + +template ACE_INLINE +ACE_Auto_IncDec::ACE_Auto_IncDec + (ACE_SAFELY_INCREMENTABLE_DECREMENTABLE &counter) + : counter_ (counter) +{ + ++this->counter_; +} + +// Implicitly and automatically decrement the counter. + +template ACE_INLINE +ACE_Auto_IncDec::~ACE_Auto_IncDec (void) +{ + --this->counter_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Auto_Ptr.cpp b/dep/acelite/ace/Auto_Ptr.cpp new file mode 100644 index 000000000..09028186a --- /dev/null +++ b/dep/acelite/ace/Auto_Ptr.cpp @@ -0,0 +1,21 @@ +#ifndef ACE_AUTO_PTR_CPP +#define ACE_AUTO_PTR_CPP + +#include "ace/Auto_Ptr.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Auto_Ptr.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tt(ACE_Auto_Basic_Ptr) +ACE_ALLOC_HOOK_DEFINE_Tt(ACE_Auto_Basic_Array_Ptr) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_AUTO_PTR_CPP */ diff --git a/dep/acelite/ace/Auto_Ptr.h b/dep/acelite/ace/Auto_Ptr.h new file mode 100644 index 000000000..02fbddf99 --- /dev/null +++ b/dep/acelite/ace/Auto_Ptr.h @@ -0,0 +1,228 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Auto_Ptr.h + * + * @author Doug Schmidt + * @author Irfan Pyarali + * @author Jack Reeves + * @author Dr. Harald M. Mueller + */ +//============================================================================= + +#ifndef ACE_AUTO_PTR_H +#define ACE_AUTO_PTR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (_MSC_VER) +// Suppress warning e.g. "return type for +// 'ACE_Auto_Array_Pointer::operator ->' is 'type *' (i.e., not a UDT +// or reference to a UDT. Will produce errors if applied using infix +// notation)" +# pragma warning(push) +# pragma warning(disable: 4284) +#endif /* _MSC_VER */ + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Auto_Basic_Ptr + * + * @brief Implements the draft C++ standard auto_ptr abstraction. + * This class allows one to work on non-object (basic) types + */ +template +class ACE_Auto_Basic_Ptr +{ +public: + typedef X element_type; + + // = Initialization and termination methods + explicit ACE_Auto_Basic_Ptr (X * p = 0) : p_ (p) {} + + ACE_Auto_Basic_Ptr (ACE_Auto_Basic_Ptr & ap); + ACE_Auto_Basic_Ptr &operator= (ACE_Auto_Basic_Ptr & rhs); + ~ACE_Auto_Basic_Ptr (void); + + // = Accessor methods. + X &operator *() const; + X *get (void) const; + X *release (void); + void reset (X * p = 0); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + X *p_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if !defined (ACE_LACKS_AUTO_PTR) && \ + defined (ACE_HAS_STANDARD_CPP_LIBRARY) && \ + (ACE_HAS_STANDARD_CPP_LIBRARY != 0) +#include +#if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) && \ + (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB != 0) +#if !defined (ACE_HAS_CPP17) +using std::auto_ptr; +#endif /* !ACE_HAS_CPP17 */ +#endif /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */ +#else /* ACE_HAS_STANDARD_CPP_LIBRARY */ + +/** + * @class auto_ptr + * + * @brief Implements the draft C++ standard auto_ptr abstraction. + */ +template +class auto_ptr : public ACE_Auto_Basic_Ptr +{ +public: + typedef X element_type; + + // = Initialization and termination methods + explicit auto_ptr (X * p = 0) : ACE_Auto_Basic_Ptr (p) {} + auto_ptr (auto_ptr & ap) : ACE_Auto_Basic_Ptr (ap.release ()) {} + + X *operator-> () const; +}; + +#endif /* ACE_HAS_STANDARD_CPP_LIBRARY */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @brief Implements the draft C++ standard auto_ptr abstraction. + * This version can be used instead of auto_ptr + */ +template +class ACE_Auto_Ptr : public ACE_Auto_Basic_Ptr +{ +public: + typedef X element_type; + + // = Initialization and termination methods + explicit ACE_Auto_Ptr (X * p = 0) : ACE_Auto_Basic_Ptr (p) {} + + X *operator-> () const; +}; + +/** + * @class ACE_Auto_Basic_Array_Ptr + * + * @brief Implements an extension to the draft C++ standard auto_ptr + * abstraction. This class allows one to work on non-object + * (basic) types that must be treated as an array, e.g., + * deallocated via "delete [] foo". + */ +template +class ACE_Auto_Basic_Array_Ptr +{ +public: + typedef X element_type; + + // = Initialization and termination methods. + explicit ACE_Auto_Basic_Array_Ptr (X * p = 0) : p_ (p) {} + + ACE_Auto_Basic_Array_Ptr (ACE_Auto_Basic_Array_Ptr & ap); + ACE_Auto_Basic_Array_Ptr &operator= (ACE_Auto_Basic_Array_Ptr & rhs); + ~ACE_Auto_Basic_Array_Ptr (void); + + // = Accessor methods. + X & operator* () const; + X & operator[] (int i) const; + X * get (void) const; + X * release (void); + void reset (X * p = 0); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + X * p_; +}; + +/** + * @class ACE_Auto_Array_Ptr + * + * @brief Implements an extension to the draft C++ standard auto_ptr + * abstraction. + */ +template +class ACE_Auto_Array_Ptr : public ACE_Auto_Basic_Array_Ptr +{ +public: + typedef X element_type; + + // = Initialization and termination methods. + explicit ACE_Auto_Array_Ptr (X *p = 0) + : ACE_Auto_Basic_Array_Ptr (p) {} + + X *operator-> () const; +}; + + +/** + * @brief Reset given @c auto_ptr element to new element. + * + * Some platforms have an older version of auto_ptr support, which + * lacks reset, and cannot be disabled easily. Portability to these + * platforms requires use of this function template. This function + * template also works for the @c ACE_Auto_{Basic_}Array_Ptr class + * template, as well. + */ +template +inline void +ACE_auto_ptr_reset (AUTO_PTR_TYPE & ap, + PTR_TYPE * p) +{ +#if defined (ACE_AUTO_PTR_LACKS_RESET) + // Allow compiler to adjust pointer to potential base class pointer + // of element type found in auto_ptr. + typename AUTO_PTR_TYPE::element_type * const tp = p; + if (tp != ap.get ()) + { + ap = AUTO_PTR_TYPE (tp); + } +#else + ap.reset (p); +#endif /* ACE_AUTO_PTR_LACKS_RESET */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Auto_Ptr.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Auto_Ptr.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Auto_Ptr.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#if defined (_MSC_VER) +// Restore the warning state to what it was before entry. +# pragma warning(pop) +#endif /* _MSC_VER */ + +#include /**/ "ace/post.h" +#endif /* ACE_AUTO_PTR_H */ diff --git a/dep/acelite/ace/Auto_Ptr.inl b/dep/acelite/ace/Auto_Ptr.inl new file mode 100644 index 000000000..1cc93536e --- /dev/null +++ b/dep/acelite/ace/Auto_Ptr.inl @@ -0,0 +1,181 @@ +// -*- C++ -*- +#include "ace/Global_Macros.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE void +ACE_Auto_Basic_Ptr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Auto_Basic_Ptr::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE void +ACE_Auto_Basic_Array_Ptr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE +ACE_Auto_Basic_Ptr::ACE_Auto_Basic_Ptr (ACE_Auto_Basic_Ptr &rhs) + : p_ (rhs.release ()) +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::ACE_Auto_Basic_Ptr"); +} + +template ACE_INLINE X * +ACE_Auto_Basic_Ptr::get (void) const +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::get"); + return this->p_; +} + +template ACE_INLINE X * +ACE_Auto_Basic_Ptr::release (void) +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::release"); + X *old = this->p_; + this->p_ = 0; + return old; +} + +template ACE_INLINE void +ACE_Auto_Basic_Ptr::reset (X *p) +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::reset"); + if (this->get () != p) + delete this->get (); + this->p_ = p; +} + +template ACE_INLINE ACE_Auto_Basic_Ptr & +ACE_Auto_Basic_Ptr::operator= (ACE_Auto_Basic_Ptr &rhs) +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::operator="); + if (this != &rhs) + { + this->reset (rhs.release ()); + } + return *this; +} + +template ACE_INLINE +ACE_Auto_Basic_Ptr::~ACE_Auto_Basic_Ptr (void) +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::~ACE_Auto_Basic_Ptr"); + delete this->get (); +} + +template ACE_INLINE X & +ACE_Auto_Basic_Ptr::operator *() const +{ + ACE_TRACE ("ACE_Auto_Basic_Ptr::operator *()"); + return *this->get (); +} + +#if defined (ACE_LACKS_AUTO_PTR) || \ + !defined (ACE_HAS_STANDARD_CPP_LIBRARY) || \ + (ACE_HAS_STANDARD_CPP_LIBRARY == 0) + +template ACE_INLINE X * +auto_ptr::operator-> () const +{ + ACE_TRACE ("auto_ptr::operator->"); + return this->get (); +} + +#endif /* ACE_HAS_STANDARD_CPP_LIBRARY */ + +template ACE_INLINE X * +ACE_Auto_Ptr::operator-> () const +{ + ACE_TRACE ("ACE_Auto_Ptr::operator->"); + return this->get (); +} + +template ACE_INLINE X * +ACE_Auto_Basic_Array_Ptr::get (void) const +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::get"); + return this->p_; +} + +template ACE_INLINE X * +ACE_Auto_Basic_Array_Ptr::release (void) +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::release"); + X *old = this->p_; + this->p_ = 0; + return old; +} + +template ACE_INLINE void +ACE_Auto_Basic_Array_Ptr::reset (X *p) +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::reset"); + if (this->get () != p) +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(this->get ()); +#else + delete [] this->get (); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + this->p_ = p; +} + +template ACE_INLINE +ACE_Auto_Basic_Array_Ptr::ACE_Auto_Basic_Array_Ptr (ACE_Auto_Basic_Array_Ptr &rhs) + : p_ (rhs.release ()) +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::ACE_Auto_Basic_Array_Ptr"); +} + +template ACE_INLINE ACE_Auto_Basic_Array_Ptr & +ACE_Auto_Basic_Array_Ptr::operator= (ACE_Auto_Basic_Array_Ptr &rhs) +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::operator="); + if (this != &rhs) + { + this->reset (rhs.release ()); + } + return *this; +} + +template ACE_INLINE +ACE_Auto_Basic_Array_Ptr::~ACE_Auto_Basic_Array_Ptr (void) +{ + ACE_TRACE ("ACE_Auto_Basic_Array_Ptr::~ACE_Auto_Basic_Array_Ptr"); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(this->get ()); +#else + delete [] this->get (); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +template ACE_INLINE X & +ACE_Auto_Basic_Array_Ptr::operator *() const +{ + return *this->get (); +} + +template ACE_INLINE X & +ACE_Auto_Basic_Array_Ptr::operator[](int i) const +{ + X *array = this->get (); + return array[i]; +} + +template ACE_INLINE X * +ACE_Auto_Array_Ptr::operator->() const +{ + return this->get (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Barrier.cpp b/dep/acelite/ace/Barrier.cpp new file mode 100644 index 000000000..9eb706785 --- /dev/null +++ b/dep/acelite/ace/Barrier.cpp @@ -0,0 +1,174 @@ +#include "ace/Barrier.h" + +#if defined (ACE_HAS_THREADS) + +#if !defined (__ACE_INLINE__) +#include "ace/Barrier.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Guard_T.h" +#include "ace/OS_NS_errno.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if defined (ACE_HAS_DUMP) +# include "ace/Log_Category.h" +#endif /* ACE_HAS_DUMP */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Sub_Barrier) + +void +ACE_Sub_Barrier::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Sub_Barrier::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->barrier_finished_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("running_threads_ = %d\n"), this->running_threads_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Sub_Barrier::ACE_Sub_Barrier (unsigned int count, + ACE_Thread_Mutex &lock, + const ACE_TCHAR *name, + void *arg) + : barrier_finished_ (lock, name, arg), + running_threads_ (count) +{ +// ACE_TRACE ("ACE_Sub_Barrier::ACE_Sub_Barrier"); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Barrier) + +void +ACE_Barrier::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Barrier::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->lock_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("current_generation_ = %d"), this->current_generation_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncount_ = %d"), this->count_)); + this->sub_barrier_1_.dump (); + this->sub_barrier_2_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Barrier::ACE_Barrier (unsigned int count, + const ACE_TCHAR *name, + void *arg) + : lock_ (name, (ACE_mutexattr_t *) arg), + current_generation_ (0), + count_ (count), + sub_barrier_1_ (count, lock_, name, arg), + sub_barrier_2_ (count, lock_, name, arg) +{ + ACE_TRACE ("ACE_Barrier::ACE_Barrier"); + this->sub_barrier_[0] = &this->sub_barrier_1_; + this->sub_barrier_[1] = &this->sub_barrier_2_; +} + +int +ACE_Barrier::wait (void) +{ + ACE_TRACE ("ACE_Barrier::wait"); + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1); + + ACE_Sub_Barrier *sbp = + this->sub_barrier_[this->current_generation_]; + + // Check for shutdown... + if (sbp == 0) + { + errno = ESHUTDOWN; + return -1; + } + + int retval = 0; + + if (sbp->running_threads_ == 1) + { + // We're the last running thread, so swap generations and tell + // all the threads waiting on the barrier to continue on their + // way. + sbp->running_threads_ = this->count_; + // Swap generations. + this->current_generation_ = 1 - this->current_generation_; + sbp->barrier_finished_.broadcast (); + } + else + { + --sbp->running_threads_; + + // Block until all the other threads wait(). + while (sbp->running_threads_ != this->count_) + sbp->barrier_finished_.wait (); + + // We're awake and the count has completed. See if it completed + // because all threads hit the barrier, or because the barrier + // was shut down. + if (this->sub_barrier_[this->current_generation_] == 0) + { + errno = ESHUTDOWN; + retval = -1; + } + } + + return retval; +} + +int +ACE_Barrier::shutdown (void) +{ + ACE_TRACE ("ACE_Barrier::shutdown"); + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1); + + ACE_Sub_Barrier *sbp = + this->sub_barrier_[this->current_generation_]; + + // Check for shutdown... + if (sbp == 0) + { + errno = ESHUTDOWN; + return -1; + } + + // Flag the shutdown + this->sub_barrier_[0] = 0; + this->sub_barrier_[1] = 0; + // Tell all the threads waiting on the barrier to continue on their way. + sbp->running_threads_ = this->count_; + sbp->barrier_finished_.broadcast (); + + return 0; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Barrier) + +ACE_Thread_Barrier::ACE_Thread_Barrier (unsigned int count, + const ACE_TCHAR *name) + : ACE_Barrier (count, name) +{ +// ACE_TRACE ("ACE_Thread_Barrier::ACE_Thread_Barrier"); +} + +void +ACE_Thread_Barrier::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Thread_Barrier::dump"); + ACE_Barrier::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Barrier.h b/dep/acelite/ace/Barrier.h new file mode 100644 index 000000000..d6efaf2b8 --- /dev/null +++ b/dep/acelite/ace/Barrier.h @@ -0,0 +1,190 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Barrier.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_BARRIER_H +#define ACE_BARRIER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/config-all.h" + +// ACE platform supports some form of threading. +#if !defined (ACE_HAS_THREADS) + +#include "ace/OS_NS_errno.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Barrier + * + * @brief This is a no-op to make ACE "syntactically consistent." + */ +class ACE_Export ACE_Barrier +{ +public: + ACE_Barrier (unsigned int, const ACE_TCHAR * = 0, void * = 0) {} + ~ACE_Barrier (void) {} + int wait (void) { ACE_NOTSUP_RETURN (-1); } + void dump (void) const {} +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#else /* ACE_HAS_THREADS */ + +#include "ace/Condition_Thread_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +struct ACE_Export ACE_Sub_Barrier +{ + // = Initialization. + ACE_Sub_Barrier (unsigned int count, + ACE_Thread_Mutex &lock, + const ACE_TCHAR *name = 0, + void *arg = 0); + + ~ACE_Sub_Barrier (void); + + /// True if this generation of the barrier is done. + ACE_Condition_Thread_Mutex barrier_finished_; + + /// Number of threads that are still running. + int running_threads_; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +/** + * @class ACE_Barrier + * + * @brief Implements "barrier synchronization". + * + * This class allows number of threads to synchronize + * their completion of (one round of) a task, which is known as + * "barrier synchronization". After all the threads call + * on the barrier they are all atomically released and can begin a new + * round. + * + * This implementation uses a "sub-barrier generation numbering" + * scheme to avoid overhead and to ensure that all threads wait to + * leave the barrier correct. This code is based on an article from + * SunOpsis Vol. 4, No. 1 by Richard Marejka + * (Richard.Marejka@canada.sun.com). + */ +class ACE_Export ACE_Barrier +{ +public: + /// Initialize the barrier to synchronize @a count threads. + ACE_Barrier (unsigned int count, + const ACE_TCHAR *name = 0, + void *arg = 0); + + /// Default destructor. + ~ACE_Barrier (void); + + /// Block the caller until all @c count threads have called @c wait and + /// then allow all the caller threads to continue in parallel. + /// + /// @retval 0 after successfully waiting for all threads to wait. + /// @retval -1 if an error occurs or the barrier is shut + /// down (@sa shutdown ()). + int wait (void); + + /// Shut the barrier down, aborting the wait of all waiting threads. + /// Any threads waiting on the barrier when it is shut down will return with + /// value -1, errno ESHUTDOWN. + /// + /// @retval 0 for success, -1 if already shut down. + /// + /// @since ACE beta 5.4.9. + int shutdown (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Serialize access to the barrier state. + ACE_Thread_Mutex lock_; + + /// Either 0 or 1, depending on whether we are the first generation + /// of waiters or the next generation of waiters. + int current_generation_; + + /// Total number of threads that can be waiting at any one time. + int count_; + + /** + * We keep two @c sub_barriers, one for the first "generation" of + * waiters, and one for the next "generation" of waiters. This + * efficiently solves the problem of what to do if all the first + * generation waiters don't leave the barrier before one of the + * threads calls wait() again (i.e., starts up the next generation + * barrier). + */ + ACE_Sub_Barrier sub_barrier_1_; + ACE_Sub_Barrier sub_barrier_2_; + ACE_Sub_Barrier *sub_barrier_[2]; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Barrier &); + ACE_Barrier (const ACE_Barrier &); +}; + +/** + * @class ACE_Thread_Barrier + * + * @brief Implements "barrier synchronization" using ACE_Thread_Mutexes! + * + * This class is just a simple wrapper for ACE_Barrier that + * selects the USYNC_THREAD variant for the locks. + */ +class ACE_Export ACE_Thread_Barrier : public ACE_Barrier +{ +public: + /// Create a Thread_Barrier, passing in the optional @a name. + ACE_Thread_Barrier (unsigned int count, const ACE_TCHAR *name = 0); + + /// Default destructor. + ~ACE_Thread_Barrier (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Barrier.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* !ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_BARRIER_H */ diff --git a/dep/acelite/ace/Barrier.inl b/dep/acelite/ace/Barrier.inl new file mode 100644 index 000000000..f742deeb6 --- /dev/null +++ b/dep/acelite/ace/Barrier.inl @@ -0,0 +1,19 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Sub_Barrier::~ACE_Sub_Barrier (void) +{ +} + +ACE_INLINE +ACE_Barrier::~ACE_Barrier (void) +{ +} + +ACE_INLINE +ACE_Thread_Barrier::~ACE_Thread_Barrier (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Base_Thread_Adapter.cpp b/dep/acelite/ace/Base_Thread_Adapter.cpp new file mode 100644 index 000000000..f965bac12 --- /dev/null +++ b/dep/acelite/ace/Base_Thread_Adapter.cpp @@ -0,0 +1,128 @@ +#include "ace/Base_Thread_Adapter.h" + +#if !defined (ACE_HAS_INLINED_OSCALLS) +# include "ace/Base_Thread_Adapter.inl" +#endif /* ACE_HAS_INLINED_OSCALLS */ + +#if defined (ACE_HAS_TSS_EMULATION) +# include "ace/OS_NS_Thread.h" +#endif /* ACE_HAS_TSS_EMULATION */ + +#include "ace/Service_Config.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INIT_LOG_MSG_HOOK ACE_Base_Thread_Adapter::init_log_msg_hook_ = 0; +ACE_INHERIT_LOG_MSG_HOOK ACE_Base_Thread_Adapter::inherit_log_msg_hook_ = 0; +ACE_CLOSE_LOG_MSG_HOOK ACE_Base_Thread_Adapter::close_log_msg_hook_ = 0; +ACE_SYNC_LOG_MSG_HOOK ACE_Base_Thread_Adapter::sync_log_msg_hook_ = 0; +ACE_THR_DESC_LOG_MSG_HOOK ACE_Base_Thread_Adapter::thr_desc_log_msg_hook_ = 0; + +ACE_Base_Thread_Adapter::ACE_Base_Thread_Adapter ( + ACE_THR_FUNC user_func, + void *arg, + ACE_THR_C_FUNC entry_point, + ACE_OS_Thread_Descriptor *td +#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , ACE_SEH_EXCEPT_HANDLER selector + , ACE_SEH_EXCEPT_HANDLER handler +#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + , long cancel_flags + ) + : user_func_ (user_func) + , arg_ (arg) + , entry_point_ (entry_point) + , thr_desc_ (td) + , ctx_ (ACE_Service_Config::current()) + , flags_ (cancel_flags) +{ + ACE_OS_TRACE ("ACE_Base_Thread_Adapter::ACE_Base_Thread_Adapter"); + + if (ACE_Base_Thread_Adapter::init_log_msg_hook_ != 0) + (*ACE_Base_Thread_Adapter::init_log_msg_hook_) ( + this->log_msg_attributes_ +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , selector + , handler +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + ); +#ifdef ACE_USES_GPROF + getitimer (ITIMER_PROF, &itimer_); +#endif // ACE_USES_GPROF +} + +ACE_Base_Thread_Adapter::~ACE_Base_Thread_Adapter (void) +{ +} + +void +ACE_Base_Thread_Adapter::inherit_log_msg (void) +{ + if (ACE_Base_Thread_Adapter::inherit_log_msg_hook_ != 0) + (*ACE_Base_Thread_Adapter::inherit_log_msg_hook_)( + this->thr_desc_, + this->log_msg_attributes_); + + // Initialize the proper configuration context for the new thread + // Placed here since inherit_log_msg() gets called from any of our + // descendants (before self-destructing) + ACE_Service_Config::current (this->ctx_); +} + +void +ACE_Base_Thread_Adapter::close_log_msg (void) +{ + if (ACE_Base_Thread_Adapter::close_log_msg_hook_ != 0) + (*ACE_Base_Thread_Adapter::close_log_msg_hook_) (); +} + +void +ACE_Base_Thread_Adapter::sync_log_msg (const ACE_TCHAR *prg) +{ + if (ACE_Base_Thread_Adapter::sync_log_msg_hook_ != 0) + (*ACE_Base_Thread_Adapter::sync_log_msg_hook_) (prg); +} + +ACE_OS_Thread_Descriptor::~ACE_OS_Thread_Descriptor (void) +{ +} + +ACE_OS_Thread_Descriptor * +ACE_Base_Thread_Adapter::thr_desc_log_msg (void) +{ + if (ACE_Base_Thread_Adapter::thr_desc_log_msg_hook_ != 0) + return (*ACE_Base_Thread_Adapter::thr_desc_log_msg_hook_) (); + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Run the thread entry point for the . This must +// be an extern "C" to make certain compilers happy... + +extern "C" ACE_THR_FUNC_RETURN +ACE_THREAD_ADAPTER_NAME (void *args) +{ + ACE_OS_TRACE ("ACE_THREAD_ADAPTER_NAME"); + +#if defined (ACE_HAS_TSS_EMULATION) + // As early as we can in the execution of the new thread, allocate + // its local TS storage. Allocate it on the stack, to save dynamic + // allocation/dealloction. + void *ts_storage[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX]; + ACE_TSS_Emulation::tss_open (ts_storage); +#endif /* ACE_HAS_TSS_EMULATION */ + + ACE_Base_Thread_Adapter * const thread_args = + static_cast (args); + +#ifdef ACE_USES_GPROF + setitimer (ITIMER_PROF, thread_args->timerval (), 0); +#endif // ACE_USES_GPROF + + // Invoke the user-supplied function with the args. + ACE_THR_FUNC_RETURN status = thread_args->invoke (); + + return status; +} + diff --git a/dep/acelite/ace/Base_Thread_Adapter.h b/dep/acelite/ace/Base_Thread_Adapter.h new file mode 100644 index 000000000..d45ce6574 --- /dev/null +++ b/dep/acelite/ace/Base_Thread_Adapter.h @@ -0,0 +1,197 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Base_Thread_Adapter.h + * + * @author Nanbor Wang + */ +//============================================================================= + +#ifndef ACE_BASE_THREAD_ADAPTER_H +#define ACE_BASE_THREAD_ADAPTER_H +#include /**/ "ace/pre.h" + +#include "ace/OS_Log_Msg_Attributes.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/ACE_export.h" +#include "ace/OS_Log_Msg_Attributes.h" + +#ifdef ACE_USES_GPROF +#include "os_include/sys/os_time.h" +#endif // ACE_USES_GPROF + +#if (defined (ACE_HAS_VERSIONED_NAMESPACE) && ACE_HAS_VERSIONED_NAMESPACE == 1) +# define ACE_THREAD_ADAPTER_NAME ACE_PREPROC_CONCATENATE(ACE_VERSIONED_NAMESPACE_NAME, _ace_thread_adapter) +#else +# define ACE_THREAD_ADAPTER_NAME ace_thread_adapter +#endif /* ACE_HAS_VERSIONED_NAMESPACE == 1 */ + +/// Run the thread entry point for the ACE_Thread_Adapter. This must +/// be an extern "C" to make certain compilers happy... +extern "C" ACE_Export ACE_THR_FUNC_RETURN ACE_THREAD_ADAPTER_NAME (void *args); + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_OS_Thread_Descriptor + * + * @brief Parent class of all ACE_Thread_Descriptor classes. + * + * Container for ACE_Thread_Descriptor members that are + * used in ACE_OS. + */ +class ACE_Export ACE_OS_Thread_Descriptor +{ +public: + /// Get the thread creation flags. + long flags (void) const; + + virtual ~ACE_OS_Thread_Descriptor (void); + +protected: + /// For use by ACE_Thread_Descriptor. + ACE_OS_Thread_Descriptor (long flags = 0); + + /** + * Keeps track of whether this thread was created "detached" or not. + * If a thread is *not* created detached then if someone calls + * ACE_Thread_Manager::wait(), we need to join with that thread (and + * close down the handle). + */ + long flags_; +}; + +class ACE_Service_Gestalt; + +/** + * @class ACE_Base_Thread_Adapter + * + * @brief Base class for all the Thread_Adapters. + * + * Converts a C++ function into a function that can be + * called from a thread creation routine + * (e.g., pthread_create() or _beginthreadex()) that expects an + * extern "C" entry point. This class also makes it possible to + * transparently provide hooks to register a thread with an + * ACE_Thread_Manager. + * This class is used in ACE_OS::thr_create(). In general, the + * thread that creates an object of this class is different from + * the thread that calls @c invoke() on this object. Therefore, + * the @c invoke() method is responsible for deleting itself. + */ +class ACE_Export ACE_Base_Thread_Adapter +{ +public: + + virtual ~ACE_Base_Thread_Adapter (void); + + /// Virtual method invoked by the thread entry point. + virtual ACE_THR_FUNC_RETURN invoke (void) = 0; + + /// Accessor for the C entry point function to the OS thread creation + /// routine. + ACE_THR_C_FUNC entry_point (void); + +#ifdef ACE_USES_GPROF + /// Accessor to the itimer_ + /// followed http://sam.zoy.org/writings/programming/gprof.html + struct itimerval* timerval (void); +#endif // ACE_USES_PROF + + /// Invoke the close_log_msg_hook, if it is present + static void close_log_msg (void); + + /// Invoke the sync_log_msg_hook, if it is present + static void sync_log_msg (const ACE_TCHAR *prog_name); + + /// Invoke the thr_desc_log_msg_hook, if it is present + static ACE_OS_Thread_Descriptor *thr_desc_log_msg (void); + +protected: + /// Constructor. + ACE_Base_Thread_Adapter (ACE_THR_FUNC user_func, + void *arg, + ACE_THR_C_FUNC entry_point = (ACE_THR_C_FUNC) ACE_THREAD_ADAPTER_NAME, + ACE_OS_Thread_Descriptor *td = 0 +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , ACE_SEH_EXCEPT_HANDLER selector = 0 + , ACE_SEH_EXCEPT_HANDLER handler = 0 +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + , long cancel_flags = 0 + ); + /// Inherit the logging features if the parent thread has an + /// ACE_Log_Msg. + void inherit_log_msg (void); + +private: + /// The hooks to inherit and cleanup the Log_Msg attributes + static ACE_INIT_LOG_MSG_HOOK init_log_msg_hook_; + static ACE_INHERIT_LOG_MSG_HOOK inherit_log_msg_hook_; + static ACE_CLOSE_LOG_MSG_HOOK close_log_msg_hook_; + static ACE_SYNC_LOG_MSG_HOOK sync_log_msg_hook_; + static ACE_THR_DESC_LOG_MSG_HOOK thr_desc_log_msg_hook_; + + /// Set the Log_Msg hooks + static void set_log_msg_hooks (ACE_INIT_LOG_MSG_HOOK init_hook, + ACE_INHERIT_LOG_MSG_HOOK inherit_hook, + ACE_CLOSE_LOG_MSG_HOOK close_hook, + ACE_SYNC_LOG_MSG_HOOK sync_hook, + ACE_THR_DESC_LOG_MSG_HOOK thr_desc); + + /// Allow the ACE_Log_Msg class to set its hooks. + friend class ACE_Log_Msg; + +protected: + /// Thread startup function passed in by the user (C++ linkage). + ACE_THR_FUNC user_func_; + + /// Argument to thread startup function. + void *arg_; + + /// Entry point to the underlying OS thread creation call (C + /// linkage). + ACE_THR_C_FUNC entry_point_; + + /** + * Optional thread descriptor. Passing this pointer in will force + * the spawned thread to cache this location in Log_Msg and wait + * until Thread_Manager fills in all information in thread + * descriptor. + */ + ACE_OS_Thread_Descriptor *thr_desc_; + + /// The ACE_Log_Msg attributes. + ACE_OS_Log_Msg_Attributes log_msg_attributes_; + + /// That is useful for gprof, define itimerval +#ifdef ACE_USES_GPROF + struct itimerval itimer_; +#endif // ACE_USES_GPROF + + /// Keep a reference to the configuration context that spawns the + /// thread so the child can inherit it. + ACE_Service_Gestalt * const ctx_; + + /// Pass through the thread-creation flags that can only be acted on by + /// the spawned thread. Currently this is only the cancellation-related + /// flags. + long flags_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +# if defined (ACE_HAS_INLINED_OSCALLS) +# if defined (ACE_INLINE) +# undef ACE_INLINE +# endif /* ACE_INLINE */ +# define ACE_INLINE inline +# include "ace/Base_Thread_Adapter.inl" +# endif /* ACE_HAS_INLINED_OSCALLS */ + +#include /**/ "ace/post.h" +#endif /* ACE_BASE_THREAD_ADAPTER_H */ diff --git a/dep/acelite/ace/Base_Thread_Adapter.inl b/dep/acelite/ace/Base_Thread_Adapter.inl new file mode 100644 index 000000000..febce6f49 --- /dev/null +++ b/dep/acelite/ace/Base_Thread_Adapter.inl @@ -0,0 +1,45 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE long +ACE_OS_Thread_Descriptor::flags (void) const +{ + return flags_; +} + +ACE_INLINE +ACE_OS_Thread_Descriptor::ACE_OS_Thread_Descriptor (long flags) + : flags_ (flags) +{ +} + +ACE_INLINE void +ACE_Base_Thread_Adapter::set_log_msg_hooks ( + ACE_INIT_LOG_MSG_HOOK init_hook, + ACE_INHERIT_LOG_MSG_HOOK inherit_hook, + ACE_CLOSE_LOG_MSG_HOOK close_hook, + ACE_SYNC_LOG_MSG_HOOK sync_hook, + ACE_THR_DESC_LOG_MSG_HOOK thr_desc_hook) +{ + ACE_Base_Thread_Adapter::init_log_msg_hook_ = init_hook; + ACE_Base_Thread_Adapter::inherit_log_msg_hook_ = inherit_hook; + ACE_Base_Thread_Adapter::close_log_msg_hook_ = close_hook; + ACE_Base_Thread_Adapter::sync_log_msg_hook_ = sync_hook; + ACE_Base_Thread_Adapter::thr_desc_log_msg_hook_ = thr_desc_hook; +} + +ACE_INLINE ACE_THR_C_FUNC +ACE_Base_Thread_Adapter::entry_point (void) +{ + return this->entry_point_; +} + +#ifdef ACE_USES_GPROF +ACE_INLINE itimerval* +ACE_Base_Thread_Adapter::timerval (void) +{ + return &(this->itimer_); +} +#endif // ACE_USES_GPROF + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Based_Pointer_Repository.cpp b/dep/acelite/ace/Based_Pointer_Repository.cpp new file mode 100644 index 000000000..6ec16f555 --- /dev/null +++ b/dep/acelite/ace/Based_Pointer_Repository.cpp @@ -0,0 +1,123 @@ +#include "ace/Map_Manager.h" +#include "ace/Based_Pointer_Repository.h" +#include "ace/Guard_T.h" +#include "ace/Null_Mutex.h" +#include "ace/Synch_Traits.h" +#include "ace/RW_Thread_Mutex.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Based_Pointer_Repository_Rep + * + * @brief Implementation for the ACE_Based_Pointer_Repository. + * + * Every memory pool in ACE binds it's mapping base address and + * the mapped size to this repository every time it maps/remaps a + * new chunk of memory successfully. + */ +class ACE_Based_Pointer_Repository_Rep +{ +public: + // Useful typedefs. + typedef ACE_Map_Manager MAP_MANAGER; + typedef ACE_Map_Iterator MAP_ITERATOR; + typedef ACE_Map_Entry MAP_ENTRY; + + /// Keeps track of the mapping between addresses and their associated + /// values. + MAP_MANAGER addr_map_; + + /// Synchronize concurrent access to the map. + ACE_SYNCH_MUTEX lock_; + + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_ALLOC_HOOK_DEFINE(ACE_Based_Pointer_Repository_Rep); + +ACE_Based_Pointer_Repository::ACE_Based_Pointer_Repository (void) +{ + ACE_TRACE ("ACE_Based_Pointer_Repository::ACE_Based_Pointer_Repository"); + ACE_NEW (this->rep_, + ACE_Based_Pointer_Repository_Rep); +} + +ACE_Based_Pointer_Repository::~ACE_Based_Pointer_Repository (void) +{ + ACE_TRACE ("ACE_Based_Pointer_Repository::~ACE_Based_Pointer_Repository"); + delete this->rep_; +} + +// Search for appropriate base address in repository + +int +ACE_Based_Pointer_Repository::find (void *addr, void *&base_addr) +{ + ACE_TRACE ("ACE_Based_Pointer_Repository::find"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, mon, this->rep_->lock_, -1); + ACE_Based_Pointer_Repository_Rep::MAP_ENTRY *ce = 0; + + for (ACE_Based_Pointer_Repository_Rep::MAP_ITERATOR iter (this->rep_->addr_map_); + iter.next (ce) != 0; + iter.advance ()) + // Check to see if is within any of the regions. + if (addr >= ce->ext_id_ + && addr < ((char *)ce->ext_id_ + ce->int_id_)) + { + // Assign the base address. + base_addr = ce->ext_id_; + return 1; + } + + // Assume base address 0 (e.g., if new'ed). + base_addr = 0; + return 0; +} + +// Bind a new entry to the repository or update the size of an +// existing entry. + +int +ACE_Based_Pointer_Repository::bind (void *addr, size_t size) +{ + ACE_TRACE ("ACE_Based_Pointer_Repository::bind"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, mon, this->rep_->lock_, -1); + + return this->rep_->addr_map_.rebind (addr, size); +} + +// Unbind a base from the repository. + +int +ACE_Based_Pointer_Repository::unbind (void *addr) +{ + ACE_TRACE ("ACE_Based_Pointer_Repository::unbind"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, mon, this->rep_->lock_, -1); + ACE_Based_Pointer_Repository_Rep::MAP_ENTRY *ce = 0; + + // Search for service handlers that requested notification. + + for (ACE_Based_Pointer_Repository_Rep::MAP_ITERATOR iter (this->rep_->addr_map_); + iter.next (ce) != 0; + iter.advance ()) + { + // Check to see if is within any of the regions and if + // so, unbind the key from the map. + if (addr >= ce->ext_id_ + && addr < ((char *)ce->ext_id_ + ce->int_id_)) + // Unbind base address. + return this->rep_->addr_map_.unbind (ce->ext_id_); + } + + return 0; +} + +ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_Singleton, ACE_Based_Pointer_Repository, ACE_SYNCH_RW_MUTEX); + + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Based_Pointer_Repository.h b/dep/acelite/ace/Based_Pointer_Repository.h new file mode 100644 index 000000000..00b6d2c4f --- /dev/null +++ b/dep/acelite/ace/Based_Pointer_Repository.h @@ -0,0 +1,92 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Based_Pointer_Repository.h + * + * @author Dietrich Quehl + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_BASED_POINTER_REPOSITORY_H +#define ACE_BASED_POINTER_REPOSITORY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Singleton.h" +#include "ace/Synch_Traits.h" +#include "ace/os_include/os_stddef.h" + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decl., using the "Cheshire Cat" technique. +class ACE_Based_Pointer_Repository_Rep; + +/** + * @class ACE_Based_Pointer_Repository + * + * @brief Maps pointers to the base address of the region to which each + * pointer belongs. + */ +class ACE_Export ACE_Based_Pointer_Repository +{ +public: + // = Use ACE_Null_Mutex to allow locking while iterating. + + // = Initialization and termination methods. + ACE_Based_Pointer_Repository (void); + ~ACE_Based_Pointer_Repository (void); + + // = Search structure methods. + /** + * Return the appropriate @a base_addr region that contains @a addr. + * Returns 1 on success and 0 if the @a addr isn't contained in any + * @a base_addr region. + */ + int find (void *addr, + void *&base_addr); + + /// Bind a new entry to the repository or update the size of an + /// existing entry. Returns 0 on success and -1 on failure. + int bind (void *addr, + size_t size); + + /// Unbind from the repository the that @a addr is + /// contained within. + int unbind (void *addr); + +private: + + /// Use the "Cheshire-Cat" technique to hide the implementation in + /// order to avoid circular #include dependencies. + ACE_Based_Pointer_Repository_Rep *rep_; + +private: + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Based_Pointer_Repository &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Based_Pointer_Repository (const ACE_Based_Pointer_Repository &)) +}; + +// ---------------------------------- + +/// Declare a process wide singleton +ACE_SINGLETON_DECLARE (ACE_Singleton, + ACE_Based_Pointer_Repository, + ACE_SYNCH_RW_MUTEX) + +/// Provide a Singleton access point to the based pointer repository. +typedef ACE_Singleton + ACE_BASED_POINTER_REPOSITORY; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_BASED_POINTER_REPOSITORY_H */ diff --git a/dep/acelite/ace/Based_Pointer_T.cpp b/dep/acelite/ace/Based_Pointer_T.cpp new file mode 100644 index 000000000..df983903c --- /dev/null +++ b/dep/acelite/ace/Based_Pointer_T.cpp @@ -0,0 +1,121 @@ +#ifndef ACE_BASED_POINTER_T_CPP +#define ACE_BASED_POINTER_T_CPP + +#include "ace/Based_Pointer_T.h" +#include "ace/Based_Pointer_Repository.h" +#include "ace/Log_Category.h" + +# define ACE_TRACEX(X) ACE_Trace ____ (ACE_TEXT (X), __LINE__, ACE_TEXT (__FILE__)) + +#if !defined (__ACE_INLINE__) +#include "ace/Based_Pointer_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Based_Pointer_Basic) + +template +ACE_Based_Pointer::ACE_Based_Pointer (void) +{ + ACE_TRACE ("ACE_Based_Pointer::ACE_Based_Pointer"); +} + +template void +ACE_Based_Pointer_Basic::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Based_Pointer_Basic::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntarget_ = %d\n"), this->target_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("base_offset_ = %d\n"), this->base_offset_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("computed pointer = %x\n"), + (CONCRETE *)(ACE_COMPUTE_BASED_POINTER (this)))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Based_Pointer::ACE_Based_Pointer (CONCRETE *initial) + : ACE_Based_Pointer_Basic (initial) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); +} + +template +ACE_Based_Pointer::ACE_Based_Pointer (const void* base_addr, int) + : ACE_Based_Pointer_Basic (base_addr, 0) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); +} + +template +ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic (void) + : target_ (0), + base_offset_ (0) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); + void *base_addr = 0; + + // Find the base address associated with our pointer. Note + // that it's ok for to return 0, which simply indicates that + // the address is not in memory-mapped virtual address space. + ACE_BASED_POINTER_REPOSITORY::instance ()->find (this, + base_addr); + this->base_offset_ = (char *) this - (char *) base_addr; +} + +template +ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic (const void *base_addr, int) + : target_ (0), + base_offset_ (0) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); + this->base_offset_ = (char *) this - (char *) base_addr; +} + +template +ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic (CONCRETE *rhs) + : target_ (0), + base_offset_ (0) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); + + if (rhs == 0) + // Store a value of that indicate "NULL" pointer. + this->target_ = -1; + else + { + void *base_addr = 0; + + // Find the base address associated with the pointer. + // Note that it's ok for to return 0, which simply + // indicates that the address is not in memory-mapped virtual + // address space. + ACE_BASED_POINTER_REPOSITORY::instance ()->find (this, + base_addr); + this->base_offset_ = (char *) this - (char *) base_addr; + this->target_ = ((char *) rhs - (char *) base_addr); + } +} + +template +ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic (const ACE_Based_Pointer_Basic &) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::ACE_Based_Pointer_Basic"); + + ACE_ASSERT (0); // not implemented. +} + +template +ACE_Based_Pointer::ACE_Based_Pointer (const ACE_Based_Pointer &rhs) + : ACE_Based_Pointer_Basic (rhs) +{ + ACE_TRACE ("ACE_Based_Pointer::ACE_Based_Pointer"); + ACE_ASSERT (0); // not implemented. +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_BASED_POINTER_T_CPP */ diff --git a/dep/acelite/ace/Based_Pointer_T.h b/dep/acelite/ace/Based_Pointer_T.h new file mode 100644 index 000000000..e0211603c --- /dev/null +++ b/dep/acelite/ace/Based_Pointer_T.h @@ -0,0 +1,203 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Based_Pointer_T.h + * + * @author Dietrich Quehl + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_BASED_POINTER_T_H +#define ACE_BASED_POINTER_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Basic_Types.h" + +#if defined (_MSC_VER) +// Suppress warning e.g. "return type for +// 'ACE_Based_Pointer::operator ->' is 'long *' (i.e., not a UDT +// or reference to a UDT. Will produce errors if applied using infix +// notation)" +#pragma warning(disable: 4284) +#endif /* _MSC_VER */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Based_Pointer_Basic + * + * @brief A proxy that keeps track of the relative offset of a "pointer" + * from its base address. + * This class makes it possible to transparently use "pointers" in + * shared memory as easily as programming with pointers to local + * memory. In particular, we don't need to ensure that the base + * addresses of all the pointers are mapped into separate + * processes at the same absolute memory base address. + */ +template +class ACE_Based_Pointer_Basic +{ +public: + /** + * This constructor initializes the by asking the + * Singleton for the base address of + * the memory region within which it is instantiated. Two results + * are possible: + * + * 1. An has stored a base address/size pair and the + * new based-pointer instance is located between the base address and + * the base address + size - 1. In this case, the repository + * returns the base address. + * + * 2. No suitable address/size pair was found. The repository + * assumes an address in the regular (not mapped) virtual address + * space of the process and returns 0. In this case, the + * based-pointer uses its address as an offset to it's base + * address 0. + */ + ACE_Based_Pointer_Basic (void); + + /** + * Initialize this object using the @a initial pointer. This + * constructor initializes the by asking the + * Singleton for the base address of + * the memory region within which it is instantiated. Three results + * are possible: + * + * 1. An has stored a base address/size pair and the + * new based-pointer instance is located between the base address and + * the base address + size - 1. In this case, the repository + * returns the base address. + * + * 2. No suitable address/size pair was found. The repository + * assumes an address in the regular (not mapped) virtual address + * space of the process and returns 0. In this case, the + * based-pointer uses its address as an offset to its base + * address 0. + * + * 3. If @a initial is 0 then set the value of to -1, which + * indicates a "NULL" pointer. + */ + ACE_Based_Pointer_Basic (CONCRETE *initial); + + /// Copy constructor. + ACE_Based_Pointer_Basic (const ACE_Based_Pointer_Basic &); + + /// Constructor for know base address. @a o is only used to + /// resolve overload ambiguity. + ACE_Based_Pointer_Basic (const void *base_addr, int o); + + /// Pseudo-assignment operator. + void operator = (CONCRETE *from); + + /// Pseudo-assignment operator. + void operator = (const ACE_Based_Pointer_Basic &); + + /// Dereference operator. + CONCRETE operator * (void) const; + + /// Less than operator. + bool operator < (const ACE_Based_Pointer_Basic &) const; + + /// Less than or equal operator. + bool operator <= (const ACE_Based_Pointer_Basic &) const; + + /// Greater than operator. + bool operator > (const ACE_Based_Pointer_Basic &) const; + + /// Greater than or equal operator. + bool operator >= (const ACE_Based_Pointer_Basic &) const; + + /// Equality operator. + bool operator == (const ACE_Based_Pointer_Basic &) const; + + /// Inequality operator. + bool operator != (const ACE_Based_Pointer_Basic &) const; + + /// Subscript operator. + CONCRETE operator [](int index) const; + + /// Increment operator. + void operator+= (int index); + + /// Returns the underlying memory address of the smart pointer. + operator CONCRETE *() const; + + /// Returns the underlying memory address of the smart pointer. + CONCRETE *addr (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Dump the state of the object. + void dump (void) const; + +protected: + ptrdiff_t target_; + + /// Keep track of our offset from the base pointer. + ptrdiff_t base_offset_; +}; + +/** + * @class ACE_Based_Pointer + * + * @brief A smart proxy that keeps track of the relative offset of a + * "pointer" from its base address. + * + * This class makes it possible to transparently use "pointers" in + * shared memory as easily as programming with pointers to local + * memory by overloading the C++ delegation operator ->(). + */ +template +class ACE_Based_Pointer : public ACE_Based_Pointer_Basic +{ +public: + // = Initialization method. + /// Constructor. See constructor for ACE_Based_Pointer_Basic for + /// details. + ACE_Based_Pointer (void); + + /// Initialize this object using the pointer. See + /// constructor for ACE_Based_Pointer_Basic for details. + ACE_Based_Pointer (CONCRETE *initial); + + /// Initialize this object with known @a base_addr. @a dummy is + /// a dummy value used to resolve overload ambiguity and it + /// otherwise ignored. + ACE_Based_Pointer (const void *base_addr, int dummy); + + /// Copy constructor (not implemented yet). + ACE_Based_Pointer (const ACE_Based_Pointer &); + + /// Assignment operator. + void operator = (const ACE_Based_Pointer &); + + /// Pseudo-assignment operator. + void operator = (CONCRETE *from); + + /// The C++ "delegation operator". + CONCRETE *operator-> (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Based_Pointer_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Based_Pointer_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Based_Pointer_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_BASED_POINTER_T_H */ diff --git a/dep/acelite/ace/Based_Pointer_T.inl b/dep/acelite/ace/Based_Pointer_T.inl new file mode 100644 index 000000000..04ab75831 --- /dev/null +++ b/dep/acelite/ace/Based_Pointer_T.inl @@ -0,0 +1,136 @@ +// -*- C++ -*- +#define ACE_COMPUTE_BASED_POINTER(P) (((char *) (P) - (P)->base_offset_) + (P)->target_) +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE CONCRETE * +ACE_Based_Pointer::operator->(void) +{ + ACE_TRACE ("ACE_Based_Pointer::operator->"); + return reinterpret_cast (ACE_COMPUTE_BASED_POINTER (this)); +} + +template ACE_INLINE void +ACE_Based_Pointer_Basic::operator = (CONCRETE *rhs) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator ="); + if (rhs == 0) + // Store a value of that indicate "NULL" pointer. + this->target_ = -1; + else + this->target_ = ((char *) rhs + - ((char *) this - this->base_offset_)); +} + +template ACE_INLINE void +ACE_Based_Pointer::operator = (CONCRETE *rhs) +{ + ACE_TRACE ("ACE_Based_Pointer::operator ="); + if (rhs == 0) + // Store a value of that indicate "NULL" pointer. + this->target_ = -1; + else + this->target_ = ((char *) rhs + - ((char *) this - this->base_offset_)); +} + +template ACE_INLINE CONCRETE +ACE_Based_Pointer_Basic::operator *(void) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator *"); + return *reinterpret_cast (ACE_COMPUTE_BASED_POINTER (this)); +} + +template ACE_INLINE CONCRETE * +ACE_Based_Pointer_Basic::addr (void) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::addr"); + + if (this->target_ == -1) + return 0; + else + return reinterpret_cast (ACE_COMPUTE_BASED_POINTER (this)); +} + +template ACE_INLINE +ACE_Based_Pointer_Basic::operator CONCRETE *() const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator CONCRETE *()"); + + return this->addr (); +} + +template ACE_INLINE CONCRETE +ACE_Based_Pointer_Basic::operator [] (int index) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator []"); + CONCRETE *c = + reinterpret_cast (ACE_COMPUTE_BASED_POINTER (this)); + return c[index]; +} + +template ACE_INLINE void +ACE_Based_Pointer_Basic::operator += (int index) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator +="); + this->base_offset_ += (index * sizeof (CONCRETE)); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator == (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator =="); + return ACE_COMPUTE_BASED_POINTER (this) == ACE_COMPUTE_BASED_POINTER (&rhs); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator != (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator !="); + return !(*this == rhs); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator < (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator <"); + return ACE_COMPUTE_BASED_POINTER (this) < ACE_COMPUTE_BASED_POINTER (&rhs); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator <= (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator <="); + return ACE_COMPUTE_BASED_POINTER (this) <= ACE_COMPUTE_BASED_POINTER (&rhs); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator > (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator >"); + return ACE_COMPUTE_BASED_POINTER (this) > ACE_COMPUTE_BASED_POINTER (&rhs); +} + +template ACE_INLINE bool +ACE_Based_Pointer_Basic::operator >= (const ACE_Based_Pointer_Basic &rhs) const +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator >="); + return ACE_COMPUTE_BASED_POINTER (this) >= ACE_COMPUTE_BASED_POINTER (&rhs); +} + +template ACE_INLINE void +ACE_Based_Pointer_Basic::operator= (const ACE_Based_Pointer_Basic &rhs) +{ + ACE_TRACE ("ACE_Based_Pointer_Basic::operator="); + *this = rhs.addr (); +} + +template ACE_INLINE void +ACE_Based_Pointer::operator= (const ACE_Based_Pointer &rhs) +{ + ACE_TRACE ("ACE_Based_Pointer::operator="); + *this = rhs.addr (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Basic_Stats.cpp b/dep/acelite/ace/Basic_Stats.cpp new file mode 100644 index 000000000..98e3193f3 --- /dev/null +++ b/dep/acelite/ace/Basic_Stats.cpp @@ -0,0 +1,74 @@ +#include "ace/Basic_Stats.h" +#include "ace/Log_Category.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Basic_Stats.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +void +ACE_Basic_Stats::accumulate (const ACE_Basic_Stats &rhs) +{ + if (rhs.samples_count_ == 0) + return; + + if (this->samples_count_ == 0) + { + this->min_ = rhs.min_; + this->min_at_ = rhs.min_at_; + + this->max_ = rhs.max_; + this->max_at_ = rhs.max_at_; + } + else + { + if (this->min_ > rhs.min_) + { + this->min_ = rhs.min_; + this->min_at_ = rhs.min_at_; + } + if (this->max_ < rhs.max_) + { + this->max_ = rhs.max_; + this->max_at_ = rhs.max_at_; + } + } + + this->samples_count_ += rhs.samples_count_; + this->sum_ += rhs.sum_; +} + +void +ACE_Basic_Stats::dump_results ( + const ACE_TCHAR *msg, + ACE_Basic_Stats::scale_factor_type sf) const +{ +#ifndef ACE_NLOGGING + if (this->samples_count () == 0u) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("%s : no data collected\n"), msg)); + return; + } + + ACE_UINT64 avg = this->sum_ / this->samples_count_; + + ACE_UINT64 l_min = this->min_ / sf; + ACE_UINT64 l_max = this->max_ / sf; + ACE_UINT64 l_avg = avg / sf; + + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("%s latency : %Q[%d]/%Q/%Q[%d] (min/avg/max)\n"), + msg, + l_min, this->min_at_, + l_avg, + l_max, this->max_at_)); + +#else + ACE_UNUSED_ARG (msg); + ACE_UNUSED_ARG (sf); +#endif /* ACE_NLOGGING */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Basic_Stats.h b/dep/acelite/ace/Basic_Stats.h new file mode 100644 index 000000000..4cc4bd2d6 --- /dev/null +++ b/dep/acelite/ace/Basic_Stats.h @@ -0,0 +1,90 @@ + +//============================================================================= +/** + * @file Basic_Stats.h + * + * @author Carlos O'Ryan + */ +//============================================================================= + +#ifndef ACE_BASIC_STATS_H +#define ACE_BASIC_STATS_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Basic_Types.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Collect basic stats about a series of samples +/** + * Compute the average and standard deviation (aka jitter) for an + * arbitrary number of samples, using constant space. + * Normally used for latency statistics. + */ +class ACE_Export ACE_Basic_Stats +{ +public: +#if !defined (ACE_WIN32) + typedef ACE_UINT32 scale_factor_type; +#else + typedef ACE_UINT64 scale_factor_type; +#endif + + /// Constructor + /** + * The number of samples is pre-allocated, and cannot changes once + * the class is initialized. + */ + ACE_Basic_Stats (void); + + /// The number of samples received so far + ACE_UINT32 samples_count (void) const; + + /// Record one sample. + void sample (ACE_UINT64 value); + + /// Update the values to reflect the stats in @a rhs. + void accumulate (const ACE_Basic_Stats &rhs); + + /// Dump all the samples + /** + * Prints out the results, using @a msg as a prefix for each message and + * scaling all the numbers by @a scale_factor. The latter is useful because + * high resolution timer samples are acquired in clock ticks, but often + * presented in microseconds. + */ + void dump_results (const ACE_TCHAR *msg, + scale_factor_type scale_factor) const; + + /// The number of samples + ACE_UINT32 samples_count_; + + /// The minimum value + ACE_UINT64 min_; + + /// The number of the sample that had the minimum value + ACE_UINT32 min_at_; + + /// The maximum value + ACE_UINT64 max_; + + /// The number of the sample that had the maximum value + ACE_UINT32 max_at_; + + /// The sum of all the values + ACE_UINT64 sum_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Basic_Stats.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_BASIC_STATS_H */ diff --git a/dep/acelite/ace/Basic_Stats.inl b/dep/acelite/ace/Basic_Stats.inl new file mode 100644 index 000000000..185478ab7 --- /dev/null +++ b/dep/acelite/ace/Basic_Stats.inl @@ -0,0 +1,50 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Basic_Stats::ACE_Basic_Stats (void) + : samples_count_ (0) + , min_ (0) + , min_at_ (0) + , max_ (0) + , max_at_ (0) + , sum_ (0) +{ +} + +ACE_INLINE ACE_UINT32 +ACE_Basic_Stats::samples_count (void) const +{ + return this->samples_count_; +} + +ACE_INLINE void +ACE_Basic_Stats::sample (ACE_UINT64 value) +{ + ++this->samples_count_; + + if (this->samples_count_ == 1u) + { + this->min_ = value; + this->min_at_ = this->samples_count_; + this->max_ = value; + this->max_at_ = this->samples_count_; + } + else + { + if (this->min_ > value) + { + this->min_ = value; + this->min_at_ = this->samples_count_; + } + if (this->max_ < value) + { + this->max_ = value; + this->max_at_ = this->samples_count_; + } + } + + this->sum_ += value; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Basic_Types.cpp b/dep/acelite/ace/Basic_Types.cpp new file mode 100644 index 000000000..56867684e --- /dev/null +++ b/dep/acelite/ace/Basic_Types.cpp @@ -0,0 +1 @@ +#include "ace/Basic_Types.h" diff --git a/dep/acelite/ace/Basic_Types.h b/dep/acelite/ace/Basic_Types.h new file mode 100644 index 000000000..b9feefb5e --- /dev/null +++ b/dep/acelite/ace/Basic_Types.h @@ -0,0 +1,676 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Basic_Types.h + * + * @author David L. Levine + * + * #defines the list of preprocessor macros below. The config.h file can + * pre-define any of these to short-cut the definitions. This is usually + * only necessary if the preprocessor does all of its math using integers. + * + * Sizes of built-in types: + * - ACE_SIZEOF_CHAR + * - ACE_SIZEOF_WCHAR + * - ACE_SIZEOF_SHORT + * - ACE_SIZEOF_INT + * - ACE_SIZEOF_LONG + * - ACE_SIZEOF_LONG_LONG + * - ACE_SIZEOF_VOID_P + * - ACE_SIZEOF_FLOAT + * - ACE_SIZEOF_DOUBLE + * - ACE_SIZEOF_LONG_DOUBLE + * + * Wrappers for built-in types of specific sizes: + * - ACE_INT8 + * - ACE_UINT8 + * - ACE_INT16 + * - ACE_UINT16 + * - ACE_INT32 + * - ACE_UINT32 + * - ACE_UINT64 + * - ACE_INT64 + * + * Byte-order (endian-ness) determination: + * ACE_BYTE_ORDER, to either ACE_BIG_ENDIAN or ACE_LITTLE_ENDIAN + */ +//============================================================================= + +#include /**/ "ace/config-lite.h" + +#ifndef ACE_BASIC_TYPES_H +# define ACE_BASIC_TYPES_H + +# include /**/ "ace/pre.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Pull in definitions +# include "ace/os_include/os_limits.h" // Integer limits +# include "ace/os_include/os_float.h" // Floating point limits +# include "ace/os_include/os_stdlib.h" // Other types +# include "ace/os_include/os_stddef.h" // Get ptrdiff_t - see further comments below +# include "ace/os_include/arpa/os_inet.h" // For htons + +# include "ace/os_include/sys/os_types.h" + +# if !defined (ACE_LACKS_SYS_PARAM_H) +# include /**/ +# endif /* ACE_LACKS_SYS_PARAM_H */ + +# include "ace/ACE_export.h" + +# if !defined (ACE_LACKS_STDINT_H) +# include +# endif +# if !defined (ACE_LACKS_INTTYPES_H) +# include +# endif + +#ifdef ACE_LACKS_INTPTR_T +# include "ace/If_Then_Else.h" + +// This intptr_t typedef is here instead of +// since it depends on the template +// metaprogramming in . + +// We could compare ACE_SIZEOF_VOID_P against ACE_SIZEOF_LONG, etc. +// However, that depends on the ACE preprocessor symbol definitions in +// the platform-specific configuration header being correct. +// The template meta-programming approach we take below, +// i.e. determining the type at compile-time rather than at +// preprocessing-time, will work for all platforms, and does not +// depend on ACE developer-defined configuration parameters. + +typedef ACE::If_Then_Else< + (sizeof (void*) == sizeof (signed int)), + signed int, + ACE::If_Then_Else< + (sizeof (void*) == sizeof (signed long)), + signed long, + ACE::If_Then_Else< + (sizeof (void*) == sizeof (signed long long)), + signed long long, + void /* Unknown. Force an invalid type */ + >::result_type + >::result_type + >::result_type intptr_t; + +typedef ACE::If_Then_Else< + (sizeof (void*) == sizeof (unsigned int)), + unsigned int, + ACE::If_Then_Else< + (sizeof (void*) == sizeof (unsigned long)), + unsigned long, + ACE::If_Then_Else< + (sizeof (void*) == sizeof (unsigned long long)), + unsigned long long, + void /* Unknown. Force an invalid type */ + >::result_type + >::result_type + >::result_type uintptr_t; + +#endif /* ACE_LACKS_INTPTR_T */ + +// A char always has 1 byte, by definition. +# define ACE_SIZEOF_CHAR 1 + +// Unfortunately, there isn't a portable way to determine the size of a wchar. +// So we just define them on a platform basis. If the platform doesn't +// define it and it's an XPG4 system, assume wchar_t is 4 bytes. Some code +// uses ACE_SIZEOF_WCHAR in preprocessor statements, so sizeof() isn't valid. +// If the platform config doesn't set this, and this guess is wrong, +// Basic_Types_Test should catch the inconsistency. +# if defined (ACE_HAS_WCHAR) +# if !defined (ACE_SIZEOF_WCHAR) +# if defined (ACE_HAS_XPG4_MULTIBYTE_CHAR) +# define ACE_SIZEOF_WCHAR 4 +# else +// 0 so the Basic_Types test will catch this. +# define ACE_SIZEOF_WCHAR 0 +# endif /* ACE_HAS_XPG4_MULTIBYTE_CHAR */ +# endif /* !ACE_SIZEOF_WCHAR */ +# endif /* ACE_HAS_WCHAR */ + +// The number of bytes in a short. +# if !defined (ACE_SIZEOF_SHORT) +# if (USHRT_MAX) == 255U +# define ACE_SIZEOF_SHORT 1 +# elif (USHRT_MAX) == 65535U +# define ACE_SIZEOF_SHORT 2 +# elif (USHRT_MAX) == 4294967295U +# define ACE_SIZEOF_SHORT 4 +# elif (USHRT_MAX) == 18446744073709551615U +# define ACE_SIZEOF_SHORT 8 +# else +# error: unsupported short size, must be updated for this platform! +# endif /* USHRT_MAX */ +# endif /* !defined (ACE_SIZEOF_SHORT) */ + +// The number of bytes in an int. +# if !defined (ACE_SIZEOF_INT) +# if (UINT_MAX) == 65535U +# define ACE_SIZEOF_INT 2 +# elif (UINT_MAX) == 4294967295U +# define ACE_SIZEOF_INT 4 +# elif (UINT_MAX) == 18446744073709551615U +# define ACE_SIZEOF_INT 8 +# else +# error: unsupported int size, must be updated for this platform! +# endif /* UINT_MAX */ +# endif /* !defined (ACE_SIZEOF_INT) */ + +// The number of bytes in a long. +# if !defined (ACE_SIZEOF_LONG) +# if (ULONG_MAX) == 65535UL +# define ACE_SIZEOF_LONG 2 +# elif ((ULONG_MAX) == 4294967295UL) +# define ACE_SIZEOF_LONG 4 +# elif ((ULONG_MAX) == 18446744073709551615UL) +# define ACE_SIZEOF_LONG 8 +# else +# error: unsupported long size, must be updated for this platform! +# endif /* ULONG_MAX */ +# endif /* !defined (ACE_SIZEOF_LONG) */ + +// The number of bytes in a long long. +# if !defined (ACE_SIZEOF_LONG_LONG) +# if defined (ULLONG_MAX) +# if ((ULLONG_MAX) == 4294967295ULL) +# define ACE_SIZEOF_LONG_LONG 4 +# elif ((ULLONG_MAX) == 18446744073709551615ULL) +# define ACE_SIZEOF_LONG_LONG 8 +# endif +# elif defined (ULONGLONG_MAX) +# if ((ULONGLONG_MAX) == 4294967295ULL) +# define ACE_SIZEOF_LONG_LONG 4 +# elif ((ULONGLONG_MAX) == 18446744073709551615ULL) +# define ACE_SIZEOF_LONG_LONG 8 +# endif +# endif +# // If we can't determine the size of long long, assume it is 8 +# // instead of erroring out. (Either ULLONG_MAX and ULONGLONG_MAX +# // may not be supported; or an extended C/C++ dialect may need to +# // be selected. If this assumption is wrong, it can be addressed +# // in the platform-specific config header. +# if !defined (ACE_SIZEOF_LONG_LONG) +# define ACE_SIZEOF_LONG_LONG 8 +# endif +# endif /* !defined (ACE_SIZEOF_LONG_LONG) */ + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// The sizes of the commonly implemented types are now known. Set up +// typedefs for whatever we can. Some of these are needed for certain +// cases of ACE_UINT64, so do them before the 64-bit stuff. + +#if defined (ACE_INT8_TYPE) + typedef ACE_INT8_TYPE ACE_INT8; +#elif defined (ACE_HAS_INT8_T) + typedef int8_t ACE_INT8; +#elif !defined (ACE_LACKS_SIGNED_CHAR) + typedef signed char ACE_INT8; +#else + typedef char ACE_INT8; +#endif /* defined (ACE_INT8_TYPE) */ + +#if defined (ACE_UINT8_TYPE) + typedef ACE_UINT8_TYPE ACE_UINT8; +#elif defined (ACE_HAS_UINT8_T) + typedef uint8_t ACE_UINT8; +#else + typedef unsigned char ACE_UINT8; +#endif /* defined (ACE_UINT8_TYPE) */ + +#if defined (ACE_INT16_TYPE) + typedef ACE_INT16_TYPE ACE_INT16; +#elif defined (ACE_HAS_INT16_T) + typedef int16_t ACE_INT16; +#elif ACE_SIZEOF_SHORT == 2 + typedef short ACE_INT16; +#elif ACE_SIZEOF_INT == 2 + typedef int ACE_INT16; +#else +# error Have to add to the ACE_INT16 type setting +#endif /* defined (ACE_INT16_TYPE) */ + +#if defined (ACE_UINT16_TYPE) + typedef ACE_UINT16_TYPE ACE_UINT16; +#elif defined (ACE_HAS_UINT16_T) + typedef uint16_t ACE_UINT16; +#elif ACE_SIZEOF_SHORT == 2 + typedef unsigned short ACE_UINT16; +#elif ACE_SIZEOF_INT == 2 + typedef unsigned int ACE_UINT16; +#else +# error Have to add to the ACE_UINT16 type setting +#endif /* defined (ACE_UINT16_TYPE) */ + +#if defined (ACE_INT32_TYPE) + typedef ACE_INT32_TYPE ACE_INT32; +#elif defined (ACE_HAS_INT32_T) + typedef int32_t ACE_INT32; +#elif ACE_SIZEOF_INT == 4 + typedef int ACE_INT32; +#elif ACE_SIZEOF_LONG == 4 + typedef long ACE_INT32; +#else +# error Have to add to the ACE_INT32 type setting +#endif /* defined (ACE_INT32_TYPE) */ + +#if defined (ACE_UINT32_TYPE) + typedef ACE_UINT32_TYPE ACE_UINT32; +#elif defined (ACE_HAS_UINT32_T) + typedef uint32_t ACE_UINT32; +#elif ACE_SIZEOF_INT == 4 + typedef unsigned int ACE_UINT32; +#elif ACE_SIZEOF_LONG == 4 + typedef unsigned long ACE_UINT32; +#else +# error Have to add to the ACE_UINT32 type setting +#endif /* defined (ACE_UINT32_TYPE) */ + +#if defined (ACE_INT64_TYPE) + typedef ACE_INT64_TYPE ACE_INT64; +#elif defined (ACE_HAS_INT64_T) + typedef int64_t ACE_INT64; +#elif ACE_SIZEOF_LONG == 8 + typedef long ACE_INT64; +#elif ACE_SIZEOF_LONG_LONG == 8 +# ifdef __GNUC__ + // Silence g++ "-pedantic" warnings regarding use of "long long" + // type. + __extension__ +# endif /* __GNUC__ */ + typedef long long ACE_INT64; +#endif /* defined (ACE_INT64_TYPE) */ + +#if defined (ACE_UINT64_TYPE) + typedef ACE_UINT64_TYPE ACE_UINT64; +#elif defined (ACE_HAS_UINT64_T) + typedef uint64_t ACE_UINT64; +#elif ACE_SIZEOF_LONG == 8 + typedef unsigned long ACE_UINT64; +#elif ACE_SIZEOF_LONG_LONG == 8 +# ifdef __GNUC__ + // Silence g++ "-pedantic" warnings regarding use of "long long" + // type. + __extension__ +# endif /* __GNUC__ */ + typedef unsigned long long ACE_UINT64; +#endif /* defined (ACE_UINT64_TYPE) */ + +/// Define a generic byte for use in codecs +typedef unsigned char ACE_Byte; + +// Define a pseudo wide character type when wchar is not supported so we +// can support basic wide character string operations. + +#if defined (ACE_HAS_WCHAR) || defined (ACE_HAS_XPG4_MULTIBYTE_CHAR) +# define ACE_WINT_T wint_t +# define ACE_WCHAR_T wchar_t +#else +# define ACE_WINT_T ACE_UINT16 +# define ACE_WCHAR_T ACE_UINT16 +#endif /* ACE_HAS_WCHAR */ + +// The number of bytes in a void *. +#ifndef ACE_SIZEOF_VOID_P +# define ACE_SIZEOF_VOID_P ACE_SIZEOF_LONG +#endif /* ACE_SIZEOF_VOID_P */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Byte-order (endian-ness) determination. +#if defined (BYTE_ORDER) +# if (BYTE_ORDER == LITTLE_ENDIAN) +# define ACE_LITTLE_ENDIAN 0x0123 +# define ACE_BYTE_ORDER ACE_LITTLE_ENDIAN +# elif (BYTE_ORDER == BIG_ENDIAN) +# define ACE_BIG_ENDIAN 0x3210 +# define ACE_BYTE_ORDER ACE_BIG_ENDIAN +# else +# error: unknown BYTE_ORDER! +# endif /* BYTE_ORDER */ +#elif defined (_BYTE_ORDER) +# if (_BYTE_ORDER == _LITTLE_ENDIAN) +# define ACE_LITTLE_ENDIAN 0x0123 +# define ACE_BYTE_ORDER ACE_LITTLE_ENDIAN +# elif (_BYTE_ORDER == _BIG_ENDIAN) +# define ACE_BIG_ENDIAN 0x3210 +# define ACE_BYTE_ORDER ACE_BIG_ENDIAN +# else +# error: unknown _BYTE_ORDER! +# endif /* _BYTE_ORDER */ +#elif defined (__BYTE_ORDER) +# if (__BYTE_ORDER == __LITTLE_ENDIAN) +# define ACE_LITTLE_ENDIAN 0x0123 +# define ACE_BYTE_ORDER ACE_LITTLE_ENDIAN +# elif (__BYTE_ORDER == __BIG_ENDIAN) +# define ACE_BIG_ENDIAN 0x3210 +# define ACE_BYTE_ORDER ACE_BIG_ENDIAN +# else +# error: unknown __BYTE_ORDER! +# endif /* __BYTE_ORDER */ +#else /* ! BYTE_ORDER && ! __BYTE_ORDER */ + // We weren't explicitly told, so we have to figure it out . . . + // Note that Itanium hardware (IA64) can run in either byte order. It's + // selected by the OS when loading; Windows runs little, HP-UX runs big. +# if defined (i386) || defined (__i386__) || defined (_M_IX86) || \ + defined (vax) || defined (__alpha) || defined (__LITTLE_ENDIAN__) || \ + defined (ARM) || defined (_M_IA64) || defined (_M_AMD64) || \ + defined (__amd64) || \ + ((defined (__ia64__) || defined (__ia64)) && !defined (__hpux)) + // We know these are little endian. +# define ACE_LITTLE_ENDIAN 0x0123 +# define ACE_BYTE_ORDER ACE_LITTLE_ENDIAN +# else + // Otherwise, we assume big endian. +# define ACE_BIG_ENDIAN 0x3210 +# define ACE_BYTE_ORDER ACE_BIG_ENDIAN +# endif +#endif /* ! BYTE_ORDER && ! __BYTE_ORDER */ + +// Byte swapping macros to deal with differences between little endian +// and big endian machines. Note that "long" here refers to 32 bit +// quantities. +# define ACE_SWAP_LONG(L) ((ACE_SWAP_WORD ((L) & 0xFFFF) << 16) \ + | ACE_SWAP_WORD(((L) >> 16) & 0xFFFF)) +# define ACE_SWAP_WORD(L) ((((L) & 0x00FF) << 8) | (((L) & 0xFF00) >> 8)) + +# define ACE_HTONL(X) htonl (X) +# define ACE_NTOHL(X) ntohl (X) + +# if defined (ACE_LITTLE_ENDIAN) +# define ACE_IDL_NCTOHL(X) (X) +# define ACE_IDL_NSTOHL(X) (X) +# else +# define ACE_IDL_NCTOHL(X) (X << 24) +# define ACE_IDL_NSTOHL(X) ((X) << 16) +# endif /* ACE_LITTLE_ENDIAN */ + +#define ACE_HTONS(x) htons(x) +#define ACE_NTOHS(x) ntohs(x) + +# define ACE_LONGLONG_TO_PTR(PTR_TYPE, L) \ + reinterpret_cast (static_cast (L)) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +inline ACE_UINT32 +ACE_U64_TO_U32 (ACE_UINT64 n) +{ + return static_cast (n); +} + +inline ACE_UINT32 +ACE_CU64_TO_CU32 (ACE_UINT64 n) +{ + return static_cast (n); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_WIN32) +# if defined (__MINGW32__) +# define ACE_UINT64_LITERAL(n) n ## ull +# define ACE_INT64_LITERAL(n) n ## ll +# else +# define ACE_UINT64_LITERAL(n) n ## ui64 +# define ACE_INT64_LITERAL(n) n ## i64 +# endif /* defined (__MINGW32__) */ +#elif defined (__TANDEM) +# define ACE_UINT64_LITERAL(n) n ## LL +# define ACE_INT64_LITERAL(n) n ## LL +#else /* ! ACE_WIN32 */ +# define ACE_UINT64_LITERAL(n) n ## ull +# define ACE_INT64_LITERAL(n) n ## ll +#endif /* ! ACE_WIN32*/ + +#if !defined (ACE_INT8_FORMAT_SPECIFIER_ASCII) +# if defined (PRId8) +# define ACE_INT8_FORMAT_SPECIFIER_ASCII "%" PRId8 +# else +# define ACE_INT8_FORMAT_SPECIFIER_ASCII "%d" +# endif /* defined (PRId8) */ +#endif /* ACE_INT8_FORMAT_SPECIFIER_ASCII */ + +#if !defined (ACE_INT8_FORMAT_SPECIFIER) +# if defined (PRId8) +# define ACE_INT8_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRId8) +# else +# define ACE_INT8_FORMAT_SPECIFIER ACE_TEXT (ACE_INT8_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRId8) */ +#endif /* ACE_INT8_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT8_FORMAT_SPECIFIER_ASCII) +# if defined (PRIu8) +# define ACE_UINT8_FORMAT_SPECIFIER_ASCII "%" PRIu8 +# else +# define ACE_UINT8_FORMAT_SPECIFIER_ASCII "%u" +# endif /* defined (PRIu8) */ +#endif /* ACE_UINT8_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT8_FORMAT_SPECIFIER) +# if defined (PRIu8) +# define ACE_UINT8_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRIu8) +# else +# define ACE_UINT8_FORMAT_SPECIFIER ACE_TEXT (ACE_UINT8_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRIu8) */ +#endif /* ACE_UINT8_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT16_FORMAT_SPECIFIER_ASCII) +# if defined (PRId16) +# define ACE_INT16_FORMAT_SPECIFIER_ASCII "%" PRId16 +# else +# define ACE_INT16_FORMAT_SPECIFIER_ASCII "%d" +# endif /* defined (PRId16) */ +#endif /* ACE_INT16_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT16_FORMAT_SPECIFIER) +# if defined (PRId16) +# define ACE_INT16_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRId16) +# else +# define ACE_INT16_FORMAT_SPECIFIER ACE_TEXT (ACE_INT16_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRId16) */ +#endif /* ACE_INT16_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT16_FORMAT_SPECIFIER_ASCII) +# if defined (PRIu16) +# define ACE_UINT16_FORMAT_SPECIFIER_ASCII "%" PRIu16 +# else +# define ACE_UINT16_FORMAT_SPECIFIER_ASCII "%u" +# endif /* defined (PRIu16) */ +#endif /* ACE_UINT16_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT16_FORMAT_SPECIFIER) +# if defined (PRIu16) +# define ACE_UINT16_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRIu16) +# else +# define ACE_UINT16_FORMAT_SPECIFIER ACE_TEXT (ACE_UINT16_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRIu16) */ +#endif /* ACE_UINT16_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT32_FORMAT_SPECIFIER_ASCII) +# if defined (PRId32) +# define ACE_INT32_FORMAT_SPECIFIER_ASCII "%" PRId32 +# elif ACE_SIZEOF_INT == 4 +# define ACE_INT32_FORMAT_SPECIFIER_ASCII "%d" +# else +# define ACE_INT32_FORMAT_SPECIFIER_ASCII "%ld" +# endif /* defined (PRId32) */ +#endif /* ACE_INT32_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT32_FORMAT_SPECIFIER) +# if defined (PRId32) +# define ACE_INT32_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRId32) +# else +# define ACE_INT32_FORMAT_SPECIFIER ACE_TEXT (ACE_INT32_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRId32) */ +#endif /* ACE_INT32_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT32_FORMAT_SPECIFIER_ASCII) +# if defined (PRIu32) +# define ACE_UINT32_FORMAT_SPECIFIER_ASCII "%" PRIu32 +# elif ACE_SIZEOF_INT == 4 +# define ACE_UINT32_FORMAT_SPECIFIER_ASCII "%u" +# else +# define ACE_UINT32_FORMAT_SPECIFIER_ASCII "%lu" +# endif /* defined (PRIu32) */ +#endif /* ACE_UINT32_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT32_FORMAT_SPECIFIER) +# if defined (PRIu32) +# define ACE_UINT32_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRIu32) +# else +# define ACE_UINT32_FORMAT_SPECIFIER ACE_TEXT (ACE_UINT32_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRIu32) */ +#endif /* ACE_UINT32_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT64_FORMAT_SPECIFIER_ASCII) +# if defined (PRId64) +# define ACE_INT64_FORMAT_SPECIFIER_ASCII "%" PRId64 +# elif ACE_SIZEOF_LONG == 8 +# define ACE_INT64_FORMAT_SPECIFIER_ASCII "%ld" +# else +# define ACE_INT64_FORMAT_SPECIFIER_ASCII "%lld" +# endif /* defined (PRId64) */ +#endif /* ACE_INT64_FORMAT_SPECIFIER */ + +#if !defined (ACE_INT64_FORMAT_SPECIFIER) +# if defined (PRId64) +# define ACE_INT64_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRId64) +# else +# define ACE_INT64_FORMAT_SPECIFIER ACE_TEXT (ACE_INT64_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRId64) */ +#endif /* ACE_INT64_FORMAT_SPECIFIER */ + +#if !defined (ACE_UINT64_FORMAT_SPECIFIER_ASCII) +# if defined (PRIu64) +# define ACE_UINT64_FORMAT_SPECIFIER_ASCII "%" PRIu64 +# elif ACE_SIZEOF_LONG == 8 +# define ACE_UINT64_FORMAT_SPECIFIER_ASCII "%lu" +# else +# define ACE_UINT64_FORMAT_SPECIFIER_ASCII "%llu" +# endif /* defined (PRIu64) */ +#endif /* ACE_UINT64_FORMAT_SPECIFIER_ASCII */ + +#if !defined (ACE_UINT64_FORMAT_SPECIFIER) +# if defined (PRIu64) +# define ACE_UINT64_FORMAT_SPECIFIER ACE_TEXT ("%") ACE_TEXT (PRIu64) +# else +# define ACE_UINT64_FORMAT_SPECIFIER ACE_TEXT (ACE_UINT64_FORMAT_SPECIFIER_ASCII) +# endif /* defined (PRIu64) */ +#endif /* ACE_UINT64_FORMAT_SPECIFIER */ + +#if !defined (ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII) +# if defined (ACE_WIN64) +# define ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII "%I64d" +# elif defined (_WRS_CONFIG_LP64) +# define ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII "%ld" +# else +# define ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII "%d" +# endif /* ACE_WIN64 */ +#endif /* ACE_SSIZE_T_FORMAT_SPECIFIER */ + +#if !defined (ACE_SSIZE_T_FORMAT_SPECIFIER) +#define ACE_SSIZE_T_FORMAT_SPECIFIER ACE_TEXT (ACE_SSIZE_T_FORMAT_SPECIFIER_ASCII) +#endif /* ACE_SSIZE_T_FORMAT_SPECIFIER */ + +#if !defined (ACE_SIZE_T_FORMAT_SPECIFIER_ASCII) +# if defined (ACE_WIN64) +# define ACE_SIZE_T_FORMAT_SPECIFIER_ASCII "%I64u" +# elif defined (_WRS_CONFIG_LP64) +# define ACE_SIZE_T_FORMAT_SPECIFIER_ASCII "%lu" +# else +# define ACE_SIZE_T_FORMAT_SPECIFIER_ASCII "%u" +# endif /* ACE_WIN64 */ +#endif /* ACE_SIZE_T_FORMAT_SPECIFIER */ + +#if !defined (ACE_SIZE_T_FORMAT_SPECIFIER) +#define ACE_SIZE_T_FORMAT_SPECIFIER ACE_TEXT (ACE_SIZE_T_FORMAT_SPECIFIER_ASCII) +#endif /* ACE_SIZE_T_FORMAT_SPECIFIER */ + +// Cast from UINT64 to a double requires an intermediate cast to INT64 +// on some platforms. +#if defined (ACE_WIN32) +# define ACE_UINT64_DBLCAST_ADAPTER(n) static_cast<__int64> (n) +#else /* ! ACE_WIN32 && */ +# define ACE_UINT64_DBLCAST_ADAPTER(n) (n) +#endif /* ! ACE_WIN32 && */ + + +// The number of bytes in a float. +# ifndef ACE_SIZEOF_FLOAT +# if FLT_MAX_EXP == 128 +# define ACE_SIZEOF_FLOAT 4 +# elif FLT_MAX_EXP == 1024 +# define ACE_SIZEOF_FLOAT 8 +# else +# error: unsupported float size, must be updated for this platform! +# endif /* FLT_MAX_EXP */ +# endif /* ACE_SIZEOF_FLOAT */ + +// The number of bytes in a double. +# ifndef ACE_SIZEOF_DOUBLE +# if DBL_MAX_EXP == 128 +# define ACE_SIZEOF_DOUBLE 4 +# elif DBL_MAX_EXP == 1024 +# define ACE_SIZEOF_DOUBLE 8 +# else +# error: unsupported double size, must be updated for this platform! +# endif /* DBL_MAX_EXP */ +# endif /* ACE_SIZEOF_DOUBLE */ + +// The number of bytes in a long double. +# ifndef ACE_SIZEOF_LONG_DOUBLE +# if LDBL_MAX_EXP == 128 +# define ACE_SIZEOF_LONG_DOUBLE 4 +# elif LDBL_MAX_EXP == 1024 +# if defined (__powerpc64__) +# define ACE_SIZEOF_LONG_DOUBLE 16 +# else +# define ACE_SIZEOF_LONG_DOUBLE 8 +# endif +# elif LDBL_MAX_EXP == 16384 +# if defined (LDBL_DIG) && LDBL_DIG == 18 +# if defined (__ia64) || defined (__x86_64) +# define ACE_SIZEOF_LONG_DOUBLE 16 +# else /* ! __ia64 || __x86_64 */ +# define ACE_SIZEOF_LONG_DOUBLE 12 +# endif /* __ia64 */ +# else /* ! LDBL_DIG || LDBL_DIG != 18 */ +# define ACE_SIZEOF_LONG_DOUBLE 16 +# endif /* ! LDBL_DIG || LDBL_DIG != 18 */ +# else +# error: unsupported double size, must be updated for this platform! +# endif /* LDBL_MAX_EXP */ +# endif /* ACE_SIZEOF_LONG_DOUBLE */ + +// Max and min sizes for the ACE integer types. +#define ACE_CHAR_MAX 0x7F +#define ACE_CHAR_MIN -(ACE_CHAR_MAX)-1 +#define ACE_OCTET_MAX 0xFF +#define ACE_INT16_MAX 0x7FFF +#define ACE_INT16_MIN -(ACE_INT16_MAX)-1 +#define ACE_UINT16_MAX 0xFFFF +#define ACE_WCHAR_MAX ACE_UINT16_MAX +#define ACE_INT32_MAX 0x7FFFFFFF +#define ACE_INT32_MIN -(ACE_INT32_MAX)-1 +#define ACE_UINT32_MAX 0xFFFFFFFF +#define ACE_INT64_MAX ACE_INT64_LITERAL(0x7FFFFFFFFFFFFFFF) +#define ACE_INT64_MIN -(ACE_INT64_MAX)-1 +#define ACE_UINT64_MAX ACE_UINT64_LITERAL (0xFFFFFFFFFFFFFFFF) + +// These use ANSI/IEEE format. +#define ACE_FLT_MAX 3.402823466e+38F +#define ACE_FLT_MIN 1.175494351e-38F +#define ACE_DBL_MAX 1.7976931348623158e+308 +#define ACE_DBL_MIN 2.2250738585072014e-308 + +# include /**/ "ace/post.h" +#endif /* ACE_BASIC_TYPES_H */ diff --git a/dep/acelite/ace/Bound_Ptr.cpp b/dep/acelite/ace/Bound_Ptr.cpp new file mode 100644 index 000000000..930fe6bd4 --- /dev/null +++ b/dep/acelite/ace/Bound_Ptr.cpp @@ -0,0 +1,17 @@ +/* -*- C++ -*- */ +#ifndef ACE_BOUND_PTR_CPP +#define ACE_BOUND_PTR_CPP + +#include "ace/Bound_Ptr.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Bound_Ptr.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Bound_Ptr_Counter) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_BOUND_PTR_CPP */ diff --git a/dep/acelite/ace/Bound_Ptr.h b/dep/acelite/ace/Bound_Ptr.h new file mode 100644 index 000000000..4d07c5417 --- /dev/null +++ b/dep/acelite/ace/Bound_Ptr.h @@ -0,0 +1,402 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Bound_Ptr.h + * + * @author Christopher Kohlhoff + * @author Boris Kolpackov + */ +//============================================================================= + +#ifndef ACE_BOUND_PTR_H +#define ACE_BOUND_PTR_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_HAS_CPP11) +# include "ace/Auto_Ptr.h" +#endif /* !ACE_HAS_CPP11 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Bound_Ptr_Counter + * + * @brief An ACE_Bound_Ptr_Counter object encapsulates an + * object reference count. + * + * Do not use this class directly, use ACE_Strong_Bound_Ptr or + * ACE_Weak_Bound_Ptr instead. + */ +template +class ACE_Bound_Ptr_Counter +{ +public: + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + ACE_Bound_Ptr_Counter (long init_obj_ref_count = 0); + ~ACE_Bound_Ptr_Counter (void); + + /// Create a ACE_Bound_Ptr_Counter and initialize the + /// reference count to indicate ownership by a strong pointer. + static ACE_Bound_Ptr_Counter *create_strong (void); + + /// Increase both the object and counter reference counts and return + /// the new object reference count. A return value of -1 indicates + /// that the object has already been destroyed. + static long attach_strong (ACE_Bound_Ptr_Counter *counter); + + /// Decreases both the object and counter reference counts and + /// deletes whichever has no more references. Returns the new object + /// reference count. + static long detach_strong (ACE_Bound_Ptr_Counter *counter); + + /// Create a ACE_Bound_Ptr_Counter and initialize the + /// reference count to indicate no ownership. + static ACE_Bound_Ptr_Counter *create_weak (void); + + /// Increase the counter reference count and return argument. + static void attach_weak (ACE_Bound_Ptr_Counter *counter); + + /// Decreases the counter reference count and deletes the counter if + /// it has no more references. + static void detach_weak (ACE_Bound_Ptr_Counter *counter); + + /// Determine whether the object has been deleted. + static bool object_was_deleted (ACE_Bound_Ptr_Counter *counter); + +private: + + /// Allocate a new ACE_Bound_Ptr_Counter instance, + /// returning NULL if it cannot be created. + static ACE_Bound_Ptr_Counter *internal_create (long init_obj_ref_count); + +private: + + /// Reference count of underlying object. Is set to -1 once the + /// object has been destroyed to indicate to all weak pointers that + /// it is no longer valid. + long obj_ref_count_; + + /// Reference count of this counter. + long self_ref_count_; + + /// Mutex variable to synchronize access to the reference counts. + ACE_LOCK lock_; +}; + +// Forward decl. +template class ACE_Weak_Bound_Ptr; + +/** + * @class ACE_Strong_Bound_Ptr + * + * @brief This class implements support for a reference counted + * pointer. + * + * Assigning or copying instances of an ACE_Strong_Bound_Ptr will + * automatically increment the reference count of the underlying object. + * When the last instance of an ACE_Strong_Bound_Ptr that references a + * particular object is destroyed or overwritten, it will invoke delete + * on its underlying pointer. + */ +template +class ACE_Strong_Bound_Ptr +{ +public: + /// Constructor that initializes an ACE_Strong_Bound_Ptr to point to the + /// object \ immediately. + explicit ACE_Strong_Bound_Ptr (X *p = 0); + +#if !defined (ACE_HAS_CPP11) + /// Constructor that initializes an ACE_Strong_Bound_Ptr by stealing + /// ownership of an object from an auto_ptr. + explicit ACE_Strong_Bound_Ptr (auto_ptr p); +#endif /* !ACE_HAS_CPP11 */ + + /// Copy constructor binds @c this and @a r to the same object. + ACE_Strong_Bound_Ptr (const ACE_Strong_Bound_Ptr &r); + + /// Constructor binds @c this and @a r to the same object. + ACE_Strong_Bound_Ptr (const ACE_Weak_Bound_Ptr &r); + + /// Copy constructor binds @c this and @a r to the same object if + /// Y* can be implicitly converted to X*. + template + ACE_Strong_Bound_Ptr (const ACE_Strong_Bound_Ptr &r) + : counter_ (r.counter_), + ptr_ (dynamic_cast(r.ptr_)) + { + // This ctor is temporarily defined here to increase our chances + // of being accepted by broken compilers. + // + COUNTER::attach_strong (this->counter_); + } + + /// Destructor. + ~ACE_Strong_Bound_Ptr (void); + + /// Assignment operator that binds @c this and @a r to the same object. + void operator = (const ACE_Strong_Bound_Ptr &r); + + /// Assignment operator that binds @c this and @a r to the same object. + void operator = (const ACE_Weak_Bound_Ptr &r); + + /// Assignment operator that binds @c this and @a r to the same object + /// if Y* can be implicitly converted to X*. + template + ACE_Weak_Bound_Ptr& + operator= (const ACE_Strong_Bound_Ptr &r) + { + // This operator is temporarily defined here to increase our chances + // of being accepted by broken compilers. + // + + // This will work if &r == this, by first increasing the ref count + + COUNTER *new_counter = r.counter_; + X* new_ptr = dynamic_cast (r.ptr_); + COUNTER::attach_strong (new_counter); + if (COUNTER::detach_strong (this->counter_) == 0) + delete this->ptr_; + this->counter_ = new_counter; + this->ptr_ = new_ptr; + + return *this; + } + + /// Equality operator that returns @c true if both + /// ACE_Strong_Bound_Ptr instances point to the same underlying + /// object. + /** + * @note It also returns @c true if both objects have just been + * instantiated and not used yet. + */ + bool operator == (const ACE_Strong_Bound_Ptr &r) const; + + /// Equality operator that returns true if the ACE_Strong_Bound_Ptr + /// and ACE_Weak_Bound_Ptr objects point to the same underlying + /// object. + /** + * @note It also returns @c true if both objects have just been + * instantiated and not used yet. + */ + bool operator == (const ACE_Weak_Bound_Ptr &r) const; + + /// Equality operator that returns @c true if the + /// ACE_Strong_Bound_Ptr and the raw pointer point to the same + /// underlying object. + bool operator == (X *p) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (const ACE_Strong_Bound_Ptr &r) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (const ACE_Weak_Bound_Ptr &r) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (X *p) const; + + /// Redirection operator + X *operator-> (void) const; + + /// Dereference operator + X &operator * (void) const; + + /// Get the pointer value. + X *get (void) const; + + /// Resets the ACE_Strong_Bound_Ptr to refer to a different + /// underlying object. + void reset (X *p = 0); + +#if !defined (ACE_HAS_CPP11) + /// Resets the ACE_Strong_Bound_Ptr to refer to a different + /// underlying object, ownership of which is stolen from the + /// auto_ptr. + void reset (auto_ptr p); +#endif /* !ACE_HAS_CPP11 */ + + /// Allows us to check for NULL on all ACE_Strong_Bound_Ptr + /// objects. + bool null (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + typedef X X_t; // This indirection is for Borland C++. + + friend class ACE_Weak_Bound_Ptr; + + template + friend class ACE_Strong_Bound_Ptr; + + /// The ACE_Bound_Ptr_Counter type. + typedef ACE_Bound_Ptr_Counter COUNTER; + + /// The reference counter. + COUNTER *counter_; + + /// The underlying object. + X *ptr_; +}; + +/** + * @class ACE_Weak_Bound_Ptr + * + * @brief This class implements support for a weak pointer that complements + * ACE_Strong_Bound_Ptr. + * + * Unlike ACE_Strong_Bound_Ptr, assigning or copying instances of an + * ACE_Weak_Bound_Ptr will not automatically increment the reference + * count of the underlying object. What ACE_Weak_Bound_Ptr does is + * preserve the knowledge that the object is in fact reference + * counted, and thus provides an alternative to raw pointers where + * non-ownership associations must be maintained. When the last + * instance of an ACE_Strong_Bound_Ptr that references a particular + * object is destroyed or overwritten, the corresponding + * ACE_Weak_Bound_Ptr instances are set to NULL. + */ +template +class ACE_Weak_Bound_Ptr +{ +public: + /// Constructor that initializes an ACE_Weak_Bound_Ptr to point to + /// the object \ immediately. + explicit ACE_Weak_Bound_Ptr (X *p = 0); + + /// Copy constructor binds @c this and @a r to the same object. + ACE_Weak_Bound_Ptr (const ACE_Weak_Bound_Ptr &r); + + /// Constructor binds @c this and @a r to the same object. + ACE_Weak_Bound_Ptr (const ACE_Strong_Bound_Ptr &r); + + /// Destructor. + ~ACE_Weak_Bound_Ptr (void); + + /// Assignment operator that binds @c this and @a r to the same object. + void operator = (const ACE_Weak_Bound_Ptr &r); + + /// Assignment operator that binds @c this and @a r to the same object. + void operator = (const ACE_Strong_Bound_Ptr &r); + + /// Equality operator that returns @c true if both + /// ACE_Weak_Bound_Ptr objects point to the same underlying object. + /** + * @note It also returns @c true if both objects have just been + * instantiated and not used yet. + */ + bool operator == (const ACE_Weak_Bound_Ptr &r) const; + + /// Equality operator that returns @c true if the ACE_Weak_Bound_Ptr + /// and ACE_Strong_Bound_Ptr objects point to the same underlying + /// object. + /** + * @note It also returns @c true if both objects have just been + * instantiated and not used yet. + */ + bool operator == (const ACE_Strong_Bound_Ptr &r) const; + + /// Equality operator that returns @c true if the ACE_Weak_Bound_Ptr + /// and the raw pointer point to the same underlying object. + bool operator == (X *p) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (const ACE_Weak_Bound_Ptr &r) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (const ACE_Strong_Bound_Ptr &r) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (X *p) const; + + /// Redirection operator. + /** + * It returns a temporary strong pointer and makes use of the + * chaining properties of operator-> to ensure that the underlying + * object does not disappear while you are using it. If you are + * certain of the lifetimes of the object, and do not want to incur + * the locking overhead, then use the unsafe_get method instead. + */ + ACE_Strong_Bound_Ptr operator-> (void) const; + + /// Obtain a strong pointer corresponding to this weak pointer. This + /// function is useful to create a temporary strong pointer for + /// conversion to a reference. + ACE_Strong_Bound_Ptr strong (void) const; + + /// Get the pointer value. Warning: this does not affect the + /// reference count of the underlying object, so it may disappear on + /// you while you are using it if you are not careful. + X *unsafe_get (void) const; + + /// Resets the ACE_Weak_Bound_Ptr to refer to a different underlying + /// object. + void reset (X *p = 0); + + /// Increment the reference count on the underlying object. + /** + * Returns the new reference count on the object. This function may + * be used to integrate the bound pointers into an external + * reference counting mechanism such as those used by COM or CORBA + * servants. + */ + long add_ref (void); + + /// Decrement the reference count on the underlying object, which is deleted + /// if the count has reached zero. + /** + * Returns the new reference count on the object. This function may + * be used to integrate the bound pointers into an external + * reference counting mechanism such as those used by COM or CORBA + * servants. + */ + long remove_ref (void); + + /// Allows us to check for NULL on all ACE_Weak_Bound_Ptr objects. + bool null (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + typedef X X_t; // This indirection is for Borland C++. + + friend class ACE_Strong_Bound_Ptr; + + /// The ACE_Bound_Ptr_Counter type. + typedef ACE_Bound_Ptr_Counter COUNTER; + + /// The reference counter. + COUNTER *counter_; + + /// The underlying object. + X *ptr_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Bound_Ptr.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Bound_Ptr.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Bound_Ptr.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_BOUND_PTR_H */ diff --git a/dep/acelite/ace/Bound_Ptr.inl b/dep/acelite/ace/Bound_Ptr.inl new file mode 100644 index 000000000..826c9aa98 --- /dev/null +++ b/dep/acelite/ace/Bound_Ptr.inl @@ -0,0 +1,494 @@ +/* -*- C++ -*- */ +#include "ace/Guard_T.h" +#if !defined (ACE_NEW_THROWS_EXCEPTIONS) +# include "ace/Log_Category.h" +#endif /* ACE_NEW_THROWS_EXCEPTIONS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template inline ACE_Bound_Ptr_Counter * +ACE_Bound_Ptr_Counter::internal_create (long init_obj_ref_count) +{ + ACE_Bound_Ptr_Counter *temp = 0; + ACE_NEW_RETURN (temp, + ACE_Bound_Ptr_Counter (init_obj_ref_count), + 0); + return temp; +} + +template inline ACE_Bound_Ptr_Counter * +ACE_Bound_Ptr_Counter::create_strong (void) +{ + // Set initial object reference count to 1. + ACE_Bound_Ptr_Counter *temp = internal_create (1); +#if defined (ACE_NEW_THROWS_EXCEPTIONS) + if (temp == 0) + ACE_throw_bad_alloc; +#else + ACE_ASSERT (temp != 0); +#endif /* ACE_NEW_THROWS_EXCEPTIONS */ + return temp; +} + + + +template inline long +ACE_Bound_Ptr_Counter::attach_strong (ACE_Bound_Ptr_Counter* counter) +{ + ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, -1); + + // Can't attach a strong pointer to an object that has already been deleted. + if (counter->obj_ref_count_ == -1) + return -1; + + long new_obj_ref_count = ++counter->obj_ref_count_; + ++counter->self_ref_count_; + + return new_obj_ref_count; +} + +template inline long +ACE_Bound_Ptr_Counter::detach_strong (ACE_Bound_Ptr_Counter* counter) +{ + ACE_Bound_Ptr_Counter *counter_del = 0; + long new_obj_ref_count; + + { + ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, -1); + + if ((new_obj_ref_count = --counter->obj_ref_count_) == 0) + // Change the object reference count to -1 to indicate that the + // object has been deleted, as opposed to a weak pointer that + // simply hasn't had any strong pointers created from it yet. + counter->obj_ref_count_ = -1; + + if (--counter->self_ref_count_ == 0) + // Since counter contains the lock held by the guard, the + // guard needs to be released before freeing the memory holding + // the lock. So save the pointer to free, then release, then + // free. + counter_del = counter; + + } // Release the lock + + delete counter_del; + + return new_obj_ref_count; +} + +template inline ACE_Bound_Ptr_Counter * +ACE_Bound_Ptr_Counter::create_weak (void) +{ + // Set initial object reference count to 0. + + ACE_Bound_Ptr_Counter *temp = internal_create (0); +#if defined (ACE_NEW_THROWS_EXCEPTIONS) + if (temp == 0) + ACE_throw_bad_alloc; +#else + ACE_ASSERT (temp != 0); +#endif /* ACE_NEW_THROWS_EXCEPTIONS */ + return temp; +} + +template inline void +ACE_Bound_Ptr_Counter::attach_weak (ACE_Bound_Ptr_Counter* counter) +{ + ACE_GUARD (ACE_LOCK, guard, counter->lock_); + + ++counter->self_ref_count_; +} + +template inline void +ACE_Bound_Ptr_Counter::detach_weak (ACE_Bound_Ptr_Counter* counter) +{ + ACE_Bound_Ptr_Counter *counter_del = 0; + + { + ACE_GUARD (ACE_LOCK, guard, counter->lock_); + + if (--counter->self_ref_count_ == 0) + // Since counter contains the lock held by the guard, the + // guard needs to be released before freeing the memory holding + // the lock. So save the pointer to free, then release, then + // free. + counter_del = counter; + + } // Release the lock + + delete counter_del; +} + +template inline bool +ACE_Bound_Ptr_Counter::object_was_deleted (ACE_Bound_Ptr_Counter *counter) +{ + ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, 0); + + return counter->obj_ref_count_ == -1; +} + +template inline +ACE_Bound_Ptr_Counter::ACE_Bound_Ptr_Counter (long init_obj_ref_count) + : obj_ref_count_ (init_obj_ref_count), + self_ref_count_ (1) +{ +} + +template inline +ACE_Bound_Ptr_Counter::~ACE_Bound_Ptr_Counter (void) +{ +} + +template inline +ACE_Strong_Bound_Ptr::ACE_Strong_Bound_Ptr (X *p) + : counter_ (COUNTER::create_strong ()), + ptr_ (p) +{ +} + +#if !defined (ACE_HAS_CPP11) +template inline +ACE_Strong_Bound_Ptr::ACE_Strong_Bound_Ptr (auto_ptr p) + : counter_ (COUNTER::create_strong ()), + ptr_ (p.release()) +{ +} +#endif /* !ACE_HAS_CPP11 */ + +template inline +ACE_Strong_Bound_Ptr::ACE_Strong_Bound_Ptr (const ACE_Strong_Bound_Ptr &r) + : counter_ (r.counter_), + ptr_ (r.ptr_) +{ + COUNTER::attach_strong (this->counter_); +} + +template inline +ACE_Strong_Bound_Ptr::ACE_Strong_Bound_Ptr (const ACE_Weak_Bound_Ptr &r) + : counter_ (r.counter_), + ptr_ (r.ptr_) +{ + // When creating a strong pointer from a weak one we can't assume that the + // underlying object still exists. Therefore we must check for a return value + // of -1, which indicates that the object has been destroyed. + if (COUNTER::attach_strong (this->counter_) == -1) + { + // Underlying object has already been deleted, so set this pointer to null. + this->counter_ = COUNTER::create_strong (); + this->ptr_ = 0; + } +} + +template inline +ACE_Strong_Bound_Ptr::~ACE_Strong_Bound_Ptr (void) +{ + if (COUNTER::detach_strong (this->counter_) == 0) + delete this->ptr_; +} + +template inline void +ACE_Strong_Bound_Ptr::operator = (const ACE_Strong_Bound_Ptr &rhs) +{ + // This will work if &r == this, by first increasing the ref count, but + // why go through all that? + if (&rhs == this) + return; + + COUNTER *new_counter = rhs.counter_; + X_t *new_ptr = rhs.ptr_; + COUNTER::attach_strong (new_counter); + if (COUNTER::detach_strong (this->counter_) == 0) + delete this->ptr_; + this->counter_ = new_counter; + this->ptr_ = new_ptr; +} + +template inline void +ACE_Strong_Bound_Ptr::operator = (const ACE_Weak_Bound_Ptr &rhs) +{ + // This will work if &r == this, by first increasing the ref count, but + // why go through all that? + if (&rhs == this) + return; + + COUNTER *new_counter = rhs.counter_; + X_t *new_ptr = rhs.ptr_; + + // When creating a strong pointer from a weak one we can't assume that the + // underlying object still exists. Therefore we must check for a return value + // of -1, which indicates that the object has been destroyed. + if (COUNTER::attach_strong (new_counter) == -1) + { + // Underlying object has already been deleted, so set this pointer to null. + new_counter = COUNTER::create_strong (); + new_ptr = 0; + } + + if (COUNTER::detach_strong (this->counter_) == 0) + delete this->ptr_; + this->counter_ = new_counter; + this->ptr_ = new_ptr; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator== (const ACE_Strong_Bound_Ptr &r) const +{ + return this->ptr_ == r.ptr_; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator== (const ACE_Weak_Bound_Ptr &r) const +{ + // Use the weak pointer's operator== since it will check for null. + return r == *this; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator== (X *p) const +{ + return this->ptr_ == p; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator!= (const ACE_Strong_Bound_Ptr &r) const +{ + return this->ptr_ != r.ptr_; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator!= (const ACE_Weak_Bound_Ptr &r) const +{ + // Use the weak pointer's operator!= since it will check for null. + return r != *this; +} + +template inline bool +ACE_Strong_Bound_Ptr::operator!= (X *p) const +{ + return this->ptr_ != p; +} + +template inline X * +ACE_Strong_Bound_Ptr::operator-> (void) const +{ + return this->ptr_; +} + +template inline X & +ACE_Strong_Bound_Ptr::operator *() const +{ + return *this->ptr_; +} + +template inline X* +ACE_Strong_Bound_Ptr::get (void) const +{ + return this->ptr_; +} + +template inline bool +ACE_Strong_Bound_Ptr::null (void) const +{ + return this->ptr_ == 0; +} + +template inline void +ACE_Strong_Bound_Ptr::reset (X *p) +{ + COUNTER *old_counter = this->counter_; + X_t *old_ptr = this->ptr_; + this->counter_ = COUNTER::create_strong (); + this->ptr_ = p; + if (COUNTER::detach_strong (old_counter) == 0) + delete old_ptr; +} + +#if !defined (ACE_HAS_CPP11) +template inline void +ACE_Strong_Bound_Ptr::reset (auto_ptr p) +{ + COUNTER *old_counter = this->counter_; + X_t *old_ptr = this->ptr_; + this->counter_ = COUNTER::create_strong (); + this->ptr_ = p.release (); + if (COUNTER::detach_strong (old_counter) == 0) + delete old_ptr; +} +#endif /* !ACE_HAS_CPP11 */ + +template inline +ACE_Weak_Bound_Ptr::ACE_Weak_Bound_Ptr (X *p) + : counter_ (COUNTER::create_weak ()), + ptr_ (p) +{ +} + +template inline +ACE_Weak_Bound_Ptr::ACE_Weak_Bound_Ptr (const ACE_Weak_Bound_Ptr &r) + : counter_ (r.counter_), + ptr_ (r.ptr_) +{ + COUNTER::attach_weak (this->counter_); +} + +template inline +ACE_Weak_Bound_Ptr::ACE_Weak_Bound_Ptr (const ACE_Strong_Bound_Ptr &r) + : counter_ (r.counter_), + ptr_ (r.ptr_) +{ + COUNTER::attach_weak (this->counter_); +} + +template inline +ACE_Weak_Bound_Ptr::~ACE_Weak_Bound_Ptr (void) +{ + COUNTER::detach_weak (this->counter_); +} + +template inline void +ACE_Weak_Bound_Ptr::operator = (const ACE_Weak_Bound_Ptr &rhs) +{ + // This will work if &rhs == this, by first increasing the ref count + COUNTER *new_counter = rhs.counter_; + COUNTER::attach_weak (new_counter); + COUNTER::detach_weak (this->counter_); + this->counter_ = new_counter; + this->ptr_ = rhs.ptr_; +} + +template inline void +ACE_Weak_Bound_Ptr::operator = (const ACE_Strong_Bound_Ptr &rhs) +{ + // This will work if &rhs == this, by first increasing the ref count + COUNTER *new_counter = rhs.counter_; + COUNTER::attach_weak (new_counter); + COUNTER::detach_weak (this->counter_); + this->counter_ = new_counter; + this->ptr_ = rhs.ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator== (const ACE_Weak_Bound_Ptr &r) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return r.ptr_ == 0; + + return this->ptr_ == r.ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator== (const ACE_Strong_Bound_Ptr &r) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return r.ptr_ == 0; + + return this->ptr_ == r.ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator== (X *p) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return p == 0; + + return this->ptr_ == p; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator!= (const ACE_Weak_Bound_Ptr &r) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return r.ptr_ != 0; + + return this->ptr_ != r.ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator!= (const ACE_Strong_Bound_Ptr &r) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return r.ptr_ != 0; + + return this->ptr_ != r.ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::operator!= (X *p) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return p != 0; + + return this->ptr_ != p; +} + +template inline ACE_Strong_Bound_Ptr +ACE_Weak_Bound_Ptr::operator-> (void) const +{ + return ACE_Strong_Bound_Ptr (*this); +} + +template inline ACE_Strong_Bound_Ptr +ACE_Weak_Bound_Ptr::strong (void) const +{ + return ACE_Strong_Bound_Ptr (*this); +} + +template inline X* +ACE_Weak_Bound_Ptr::unsafe_get (void) const +{ + // We do not check if the object has been deleted, since this operation + // is defined to be unsafe! + return this->ptr_; +} + +template inline bool +ACE_Weak_Bound_Ptr::null (void) const +{ + // A weak pointer must behave as though it is automatically set to null + // if the underlying object has been deleted. + if (COUNTER::object_was_deleted (this->counter_)) + return true; + + return this->ptr_ == 0; +} + +template inline void +ACE_Weak_Bound_Ptr::reset (X *p) +{ + COUNTER *old_counter = this->counter_; + this->counter_ = COUNTER::create_weak (); + this->ptr_ = p; + COUNTER::detach_weak (old_counter); +} + +template inline long +ACE_Weak_Bound_Ptr::add_ref () +{ + return COUNTER::attach_strong (counter_); +} + +template inline long +ACE_Weak_Bound_Ptr::remove_ref () +{ + long new_obj_ref_count = COUNTER::detach_strong (counter_); + if (new_obj_ref_count == 0) + { + delete this->ptr_; + this->ptr_ = 0; + } + return new_obj_ref_count; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CDR_Base.cpp b/dep/acelite/ace/CDR_Base.cpp new file mode 100644 index 000000000..56b65f080 --- /dev/null +++ b/dep/acelite/ace/CDR_Base.cpp @@ -0,0 +1,1639 @@ +#include "ace/CDR_Base.h" + +#if !defined (__ACE_INLINE__) +# include "ace/CDR_Base.inl" +#endif /* ! __ACE_INLINE__ */ + +#include "ace/Message_Block.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" + +#ifdef ACE_LACKS_IOSTREAM_TOTALLY +#include "ace/OS_NS_stdio.h" +#else +#include "ace/streams.h" +#endif + +#include +#include +#include +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (NONNATIVE_LONGDOUBLE) +static const ACE_INT16 max_eleven_bit = 0x3ff; +static const ACE_INT16 max_fifteen_bit = 0x3fff; +#endif /* NONNATIVE_LONGDOUBLE */ + +// +// See comments in CDR_Base.inl about optimization cases for swap_XX_array. +// + +void +ACE_CDR::swap_2_array (char const * orig, char* target, size_t n) +{ + // ACE_ASSERT(n > 0); The caller checks that n > 0 + + // We pretend that AMD64/GNU G++ systems have a Pentium CPU to + // take advantage of the inline assembly implementation. + + // Later, we try to read in 32 or 64 bit chunks, + // so make sure we don't do that for unaligned addresses. +#if ACE_SIZEOF_LONG == 8 && \ + !((defined(__amd64__) || defined (__x86_64__)) && defined(__GNUG__)) + char const * const o8 = ACE_ptr_align_binary (orig, 8); + while (orig < o8 && n > 0) + { + ACE_CDR::swap_2 (orig, target); + orig += 2; + target += 2; + --n; + } +#else + char const * const o4 = ACE_ptr_align_binary (orig, 4); + // this is an _if_, not a _while_. The mismatch can only be by 2. + if (orig != o4) + { + ACE_CDR::swap_2 (orig, target); + orig += 2; + target += 2; + --n; + } +#endif + if (n == 0) + return; + + // + // Loop unrolling. Here be dragons. + // + + // (n & (~3)) is the greatest multiple of 4 not bigger than n. + // In the while loop ahead, orig will move over the array by 8 byte + // increments (4 elements of 2 bytes). + // end marks our barrier for not falling outside. + char const * const end = orig + 2 * (n & (~3)); + + // See if we're aligned for writing in 64 or 32 bit chunks... +#if ACE_SIZEOF_LONG == 8 && \ + !((defined(__amd64__) || defined (__x86_64__)) && defined(__GNUG__)) + if (target == ACE_ptr_align_binary (target, 8)) +#else + if (target == ACE_ptr_align_binary (target, 4)) +#endif + { + while (orig < end) + { +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned int a = + * reinterpret_cast (orig); + unsigned int b = + * reinterpret_cast (orig + 4); + asm ( "bswap %1" : "=r" (a) : "0" (a) ); + asm ( "bswap %1" : "=r" (b) : "0" (b) ); + asm ( "rol $16, %1" : "=r" (a) : "0" (a) ); + asm ( "rol $16, %1" : "=r" (b) : "0" (b) ); + * reinterpret_cast (target) = a; + * reinterpret_cast (target + 4) = b; +#elif defined(ACE_HAS_PENTIUM) \ + && (defined(_MSC_VER) || defined(__BORLANDC__)) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + __asm mov ecx, orig; + __asm mov edx, target; + __asm mov eax, [ecx]; + __asm mov ebx, 4[ecx]; + __asm bswap eax; + __asm bswap ebx; + __asm rol eax, 16; + __asm rol ebx, 16; + __asm mov [edx], eax; + __asm mov 4[edx], ebx; +#elif ACE_SIZEOF_LONG == 8 + // 64 bit architecture. + unsigned long a = * reinterpret_cast (orig); + + unsigned long a1 = (a & 0x00ff00ff00ff00ffUL) << 8; + unsigned long a2 = (a & 0xff00ff00ff00ff00UL) >> 8; + + a = (a1 | a2); + + * reinterpret_cast (target) = a; +#else + ACE_UINT32 a = * reinterpret_cast (orig); + ACE_UINT32 b = * reinterpret_cast (orig + 4); + + ACE_UINT32 a1 = (a & 0x00ff00ffU) << 8; + ACE_UINT32 b1 = (b & 0x00ff00ffU) << 8; + ACE_UINT32 a2 = (a & 0xff00ff00U) >> 8; + ACE_UINT32 b2 = (b & 0xff00ff00U) >> 8; + + a = (a1 | a2); + b = (b1 | b2); + + * reinterpret_cast (target) = a; + * reinterpret_cast (target + 4) = b; +#endif + orig += 8; + target += 8; + } + } + else + { + // We're out of luck. We have to write in 2 byte chunks. + while (orig < end) + { +#if defined (ACE_HAS_INTEL_ASSEMBLY) + unsigned int a = + * reinterpret_cast (orig); + unsigned int b = + * reinterpret_cast (orig + 4); + asm ( "bswap %1" : "=r" (a) : "0" (a) ); + asm ( "bswap %1" : "=r" (b) : "0" (b) ); + // We're little endian. + * reinterpret_cast (target + 2) + = (unsigned short) (a & 0xffff); + * reinterpret_cast (target + 6) + = (unsigned short) (b & 0xffff); + asm ( "shrl $16, %1" : "=r" (a) : "0" (a) ); + asm ( "shrl $16, %1" : "=r" (b) : "0" (b) ); + * reinterpret_cast (target + 0) + = (unsigned short) (a & 0xffff); + * reinterpret_cast (target + 4) + = (unsigned short) (b & 0xffff); +#elif defined (ACE_HAS_PENTIUM) \ + && (defined (_MSC_VER) || defined (__BORLANDC__)) \ + && !defined (ACE_LACKS_INLINE_ASSEMBLY) + __asm mov ecx, orig; + __asm mov edx, target; + __asm mov eax, [ecx]; + __asm mov ebx, 4[ecx]; + __asm bswap eax; + __asm bswap ebx; + // We're little endian. + __asm mov 2[edx], ax; + __asm mov 6[edx], bx; + __asm shr eax, 16; + __asm shr ebx, 16; + __asm mov 0[edx], ax; + __asm mov 4[edx], bx; +#elif ACE_SIZEOF_LONG == 8 + // 64 bit architecture. + unsigned long a = * reinterpret_cast (orig); + + unsigned long a1 = (a & 0x00ff00ff00ff00ffUL) << 8; + unsigned long a2 = (a & 0xff00ff00ff00ff00UL) >> 8; + + a = (a1 | a2); + + ACE_UINT16 b1 = static_cast (a >> 48); + ACE_UINT16 b2 = static_cast ((a >> 32) & 0xffff); + ACE_UINT16 b3 = static_cast ((a >> 16) & 0xffff); + ACE_UINT16 b4 = static_cast (a & 0xffff); + +#if defined(ACE_LITTLE_ENDIAN) + * reinterpret_cast (target) = b4; + * reinterpret_cast (target + 2) = b3; + * reinterpret_cast (target + 4) = b2; + * reinterpret_cast (target + 6) = b1; +#else + * reinterpret_cast (target) = b1; + * reinterpret_cast (target + 2) = b2; + * reinterpret_cast (target + 4) = b3; + * reinterpret_cast (target + 6) = b4; +#endif +#else + ACE_UINT32 a = * reinterpret_cast (orig); + ACE_UINT32 b = * reinterpret_cast (orig + 4); + + ACE_UINT32 a1 = (a & 0x00ff00ff) << 8; + ACE_UINT32 b1 = (b & 0x00ff00ff) << 8; + ACE_UINT32 a2 = (a & 0xff00ff00) >> 8; + ACE_UINT32 b2 = (b & 0xff00ff00) >> 8; + + a = (a1 | a2); + b = (b1 | b2); + + ACE_UINT32 c1 = static_cast (a >> 16); + ACE_UINT32 c2 = static_cast (a & 0xffff); + ACE_UINT32 c3 = static_cast (b >> 16); + ACE_UINT32 c4 = static_cast (b & 0xffff); + +#if defined(ACE_LITTLE_ENDIAN) + * reinterpret_cast (target) = c2; + * reinterpret_cast (target + 2) = c1; + * reinterpret_cast (target + 4) = c4; + * reinterpret_cast (target + 6) = c3; +#else + * reinterpret_cast (target) = c1; + * reinterpret_cast (target + 2) = c2; + * reinterpret_cast (target + 4) = c3; + * reinterpret_cast (target + 6) = c4; +#endif +#endif + + orig += 8; + target += 8; + } + } + + // (n & 3) == (n % 4). + switch (n&3) { + case 3: + ACE_CDR::swap_2 (orig, target); + orig += 2; + target += 2; + // fallthrough + case 2: + ACE_CDR::swap_2 (orig, target); + orig += 2; + target += 2; + // fallthrough + case 1: + ACE_CDR::swap_2 (orig, target); + } +} + +void +ACE_CDR::swap_4_array (char const * orig, char* target, size_t n) +{ + // ACE_ASSERT (n > 0); The caller checks that n > 0 + +#if ACE_SIZEOF_LONG == 8 + // Later, we read from *orig in 64 bit chunks, + // so make sure we don't generate unaligned readings. + char const * const o8 = ACE_ptr_align_binary (orig, 8); + // The mismatch can only be by 4. + if (orig != o8) + { + ACE_CDR::swap_4 (orig, target); + orig += 4; + target += 4; + --n; + } +#endif /* ACE_SIZEOF_LONG == 8 */ + + if (n == 0) + return; + + // + // Loop unrolling. Here be dragons. + // + + // (n & (~3)) is the greatest multiple of 4 not bigger than n. + // In the while loop, orig will move over the array by 16 byte + // increments (4 elements of 4 bytes). + // ends marks our barrier for not falling outside. + char const * const end = orig + 4 * (n & (~3)); + +#if ACE_SIZEOF_LONG == 8 + // 64 bits architecture. + // See if we can write in 8 byte chunks. + if (target == ACE_ptr_align_binary (target, 8)) + { + while (orig < end) + { + unsigned long a = * reinterpret_cast (orig); + unsigned long b = * reinterpret_cast (orig + 8); + +#if defined(ACE_HAS_INTEL_ASSEMBLY) + asm ("bswapq %1" : "=r" (a) : "0" (a)); + asm ("bswapq %1" : "=r" (b) : "0" (b)); + asm ("rol $32, %1" : "=r" (a) : "0" (a)); + asm ("rol $32, %1" : "=r" (b) : "0" (b)); +#else + unsigned long a84 = (a & 0x000000ff000000ffL) << 24; + unsigned long b84 = (b & 0x000000ff000000ffL) << 24; + unsigned long a73 = (a & 0x0000ff000000ff00L) << 8; + unsigned long b73 = (b & 0x0000ff000000ff00L) << 8; + unsigned long a62 = (a & 0x00ff000000ff0000L) >> 8; + unsigned long b62 = (b & 0x00ff000000ff0000L) >> 8; + unsigned long a51 = (a & 0xff000000ff000000L) >> 24; + unsigned long b51 = (b & 0xff000000ff000000L) >> 24; + + a = (a84 | a73 | a62 | a51); + b = (b84 | b73 | b62 | b51); +#endif + + * reinterpret_cast (target) = a; + * reinterpret_cast (target + 8) = b; + + orig += 16; + target += 16; + } + } + else + { + // We are out of luck, we have to write in 4 byte chunks. + while (orig < end) + { + unsigned long a = * reinterpret_cast (orig); + unsigned long b = * reinterpret_cast (orig + 8); + +#if defined(ACE_HAS_INTEL_ASSEMBLY) + asm ("bswapq %1" : "=r" (a) : "0" (a)); + asm ("bswapq %1" : "=r" (b) : "0" (b)); + asm ("rol $32, %1" : "=r" (a) : "0" (a)); + asm ("rol $32, %1" : "=r" (b) : "0" (b)); +#else + unsigned long a84 = (a & 0x000000ff000000ffL) << 24; + unsigned long b84 = (b & 0x000000ff000000ffL) << 24; + unsigned long a73 = (a & 0x0000ff000000ff00L) << 8; + unsigned long b73 = (b & 0x0000ff000000ff00L) << 8; + unsigned long a62 = (a & 0x00ff000000ff0000L) >> 8; + unsigned long b62 = (b & 0x00ff000000ff0000L) >> 8; + unsigned long a51 = (a & 0xff000000ff000000L) >> 24; + unsigned long b51 = (b & 0xff000000ff000000L) >> 24; + + a = (a84 | a73 | a62 | a51); + b = (b84 | b73 | b62 | b51); +#endif + + ACE_UINT32 c1 = static_cast (a >> 32); + ACE_UINT32 c2 = static_cast (a & 0xffffffff); + ACE_UINT32 c3 = static_cast (b >> 32); + ACE_UINT32 c4 = static_cast (b & 0xffffffff); + +#if defined (ACE_LITTLE_ENDIAN) + * reinterpret_cast (target + 0) = c2; + * reinterpret_cast (target + 4) = c1; + * reinterpret_cast (target + 8) = c4; + * reinterpret_cast (target + 12) = c3; +#else + * reinterpret_cast (target + 0) = c1; + * reinterpret_cast (target + 4) = c2; + * reinterpret_cast (target + 8) = c3; + * reinterpret_cast (target + 12) = c4; +#endif + orig += 16; + target += 16; + } + } + +#else /* ACE_SIZEOF_LONG != 8 */ + + while (orig < end) + { +#if defined (ACE_HAS_PENTIUM) && defined (__GNUG__) + unsigned int a = *reinterpret_cast (orig); + unsigned int b = *reinterpret_cast (orig + 4); + unsigned int c = *reinterpret_cast (orig + 8); + unsigned int d = *reinterpret_cast (orig + 12); + + asm ("bswap %1" : "=r" (a) : "0" (a)); + asm ("bswap %1" : "=r" (b) : "0" (b)); + asm ("bswap %1" : "=r" (c) : "0" (c)); + asm ("bswap %1" : "=r" (d) : "0" (d)); + + *reinterpret_cast (target) = a; + *reinterpret_cast (target + 4) = b; + *reinterpret_cast (target + 8) = c; + *reinterpret_cast (target + 12) = d; +#elif defined (ACE_HAS_PENTIUM) \ + && (defined (_MSC_VER) || defined (__BORLANDC__)) \ + && !defined (ACE_LACKS_INLINE_ASSEMBLY) + __asm mov eax, orig + __asm mov esi, target + __asm mov edx, [eax] + __asm mov ecx, 4[eax] + __asm mov ebx, 8[eax] + __asm mov eax, 12[eax] + __asm bswap edx + __asm bswap ecx + __asm bswap ebx + __asm bswap eax + __asm mov [esi], edx + __asm mov 4[esi], ecx + __asm mov 8[esi], ebx + __asm mov 12[esi], eax +#else + ACE_UINT32 a = * reinterpret_cast (orig); + ACE_UINT32 b = * reinterpret_cast (orig + 4); + ACE_UINT32 c = * reinterpret_cast (orig + 8); + ACE_UINT32 d = * reinterpret_cast (orig + 12); + + // Expect the optimizer reordering this A LOT. + // We leave it this way for clarity. + a = (a << 24) | ((a & 0xff00) << 8) | ((a & 0xff0000) >> 8) | (a >> 24); + b = (b << 24) | ((b & 0xff00) << 8) | ((b & 0xff0000) >> 8) | (b >> 24); + c = (c << 24) | ((c & 0xff00) << 8) | ((c & 0xff0000) >> 8) | (c >> 24); + d = (d << 24) | ((d & 0xff00) << 8) | ((d & 0xff0000) >> 8) | (d >> 24); + + * reinterpret_cast (target) = a; + * reinterpret_cast (target + 4) = b; + * reinterpret_cast (target + 8) = c; + * reinterpret_cast (target + 12) = d; +#endif + + orig += 16; + target += 16; + } + +#endif /* ACE_SIZEOF_LONG == 8 */ + + // (n & 3) == (n % 4). + switch (n & 3) { + case 3: + ACE_CDR::swap_4 (orig, target); + orig += 4; + target += 4; + // fallthrough + case 2: + ACE_CDR::swap_4 (orig, target); + orig += 4; + target += 4; + // fallthrough + case 1: + ACE_CDR::swap_4 (orig, target); + } +} + +// +// We don't benefit from unrolling in swap_8_array and swap_16_array +// (swap_8 and swap_16 are big enough). +// +void +ACE_CDR::swap_8_array (char const * orig, char* target, size_t n) +{ + // ACE_ASSERT(n > 0); The caller checks that n > 0 + + char const * const end = orig + 8*n; + while (orig < end) + { + swap_8 (orig, target); + orig += 8; + target += 8; + } +} + +void +ACE_CDR::swap_16_array (char const * orig, char* target, size_t n) +{ + // ACE_ASSERT(n > 0); The caller checks that n > 0 + + char const * const end = orig + 16*n; + while (orig < end) + { + swap_16 (orig, target); + orig += 16; + target += 16; + } +} + +void +ACE_CDR::mb_align (ACE_Message_Block *mb) +{ +#if !defined (ACE_CDR_IGNORE_ALIGNMENT) + char * const start = ACE_ptr_align_binary (mb->base (), + ACE_CDR::MAX_ALIGNMENT); +#else + char * const start = mb->base (); +#endif /* ACE_CDR_IGNORE_ALIGNMENT */ + mb->rd_ptr (start); + mb->wr_ptr (start); +} + +int +ACE_CDR::grow (ACE_Message_Block *mb, size_t minsize) +{ + size_t newsize = + ACE_CDR::first_size (minsize + ACE_CDR::MAX_ALIGNMENT); + + if (newsize <= mb->size ()) + return 0; + + ACE_Data_Block *db = + mb->data_block ()->clone_nocopy (0, newsize); + + if (db == 0) + return -1; + + // Do the equivalent of ACE_CDR::mb_align() here to avoid having + // to allocate an ACE_Message_Block on the stack thereby avoiding + // the manipulation of the data blocks reference count + size_t mb_len = mb->length (); + char *start = ACE_ptr_align_binary (db->base (), + ACE_CDR::MAX_ALIGNMENT); + + ACE_OS::memcpy (start, mb->rd_ptr (), mb_len); + mb->data_block (db); + + // Setting the data block on the mb resets the read and write + // pointers back to the beginning. We must set the rd_ptr to the + // aligned start and adjust the write pointer to the end + mb->rd_ptr (start); + mb->wr_ptr (start + mb_len); + + // Remove the DONT_DELETE flags from mb + mb->clr_self_flags (ACE_Message_Block::DONT_DELETE); + + return 0; +} + +size_t +ACE_CDR::total_length (const ACE_Message_Block* begin, + const ACE_Message_Block* end) +{ + size_t l = 0; + // Compute the total size. + for (const ACE_Message_Block *i = begin; + i != end; + i = i->cont ()) + l += i->length (); + return l; +} + +int +ACE_CDR::consolidate (ACE_Message_Block *dst, + const ACE_Message_Block *src) +{ + if (src == 0) + return 0; + + size_t const newsize = + ACE_CDR::first_size (ACE_CDR::total_length (src, 0) + + ACE_CDR::MAX_ALIGNMENT); + + if (dst->size (newsize) == -1) + return -1; + +#if !defined (ACE_CDR_IGNORE_ALIGNMENT) + // We must copy the contents of src into the new buffer, but + // respecting the alignment. + ptrdiff_t srcalign = + ptrdiff_t(src->rd_ptr ()) % ACE_CDR::MAX_ALIGNMENT; + ptrdiff_t dstalign = + ptrdiff_t(dst->rd_ptr ()) % ACE_CDR::MAX_ALIGNMENT; + ptrdiff_t offset = srcalign - dstalign; + if (offset < 0) + offset += ACE_CDR::MAX_ALIGNMENT; + dst->rd_ptr (static_cast (offset)); + dst->wr_ptr (dst->rd_ptr ()); +#endif /* ACE_CDR_IGNORE_ALIGNMENT */ + + for (const ACE_Message_Block* i = src; + i != 0; + i = i->cont ()) + { + // If the destination and source are the same, do not + // attempt to copy the data. Just update the write pointer. + if (dst->wr_ptr () != i->rd_ptr ()) + dst->copy (i->rd_ptr (), i->length ()); + else + dst->wr_ptr (i->length ()); + } + return 0; +} + +#if defined (NONNATIVE_LONGLONG) +bool +ACE_CDR::LongLong::operator== (const ACE_CDR::LongLong &rhs) const +{ + return this->h == rhs.h && this->l == rhs.l; +} + +bool +ACE_CDR::LongLong::operator!= (const ACE_CDR::LongLong &rhs) const +{ + return this->l != rhs.l || this->h != rhs.h; +} + +#endif /* NONNATIVE_LONGLONG */ + +#if defined (NONNATIVE_LONGDOUBLE) +ACE_CDR::LongDouble& +ACE_CDR::LongDouble::assign (const ACE_CDR::LongDouble::NativeImpl& rhs) +{ + ACE_OS::memset (this->ld, 0, sizeof (this->ld)); + + if (sizeof (rhs) == 8) + { +#if defined (ACE_LITTLE_ENDIAN) + static const size_t byte_zero = 1; + static const size_t byte_one = 0; + char rhs_ptr[16]; + ACE_CDR::swap_8 (reinterpret_cast (&rhs), rhs_ptr); +#else + static const size_t byte_zero = 0; + static const size_t byte_one = 1; + const char* rhs_ptr = reinterpret_cast (&rhs); +#endif + ACE_INT16 sign = static_cast ( + static_cast (rhs_ptr[0])) & 0x8000; + ACE_INT16 exponent = ((rhs_ptr[0] & 0x7f) << 4) | + ((rhs_ptr[1] >> 4) & 0xf); + const char* exp_ptr = reinterpret_cast (&exponent); + + // Infinity and NaN have an exponent of 0x7ff in 64-bit IEEE + if (exponent == 0x7ff) + { + exponent = 0x7fff; + } + else if (exponent) // exponent 0 stays 0 in 128-bit + { + exponent = (exponent - max_eleven_bit) + max_fifteen_bit; + } + exponent |= sign; + + // Store the sign bit and exponent + this->ld[0] = exp_ptr[byte_zero]; + this->ld[1] = exp_ptr[byte_one]; + + // Store the mantissa. In an 8 byte double, it is split by + // 4 bits (because of the 12 bits for sign and exponent), so + // we have to shift and or the rhs to get the right bytes. + size_t li = 2; + bool direction = true; + for (size_t ri = 1; ri < sizeof (rhs);) + { + if (direction) + { + this->ld[li] |= ((rhs_ptr[ri] << 4) & 0xf0); + direction = false; + ++ri; + } + else + { + this->ld[li] |= ((rhs_ptr[ri] >> 4) & 0xf); + direction = true; + ++li; + } + } +#if defined (ACE_LITTLE_ENDIAN) + ACE_OS::memcpy (rhs_ptr, this->ld, sizeof (this->ld)); + ACE_CDR::swap_16 (rhs_ptr, this->ld); +#endif + } + else + { + ACE_OS::memcpy(this->ld, + reinterpret_cast (&rhs), sizeof (rhs)); + } + return *this; +} + +ACE_CDR::LongDouble& +ACE_CDR::LongDouble::assign (const ACE_CDR::LongDouble& rhs) +{ + if (this != &rhs) + *this = rhs; + return *this; +} + +bool +ACE_CDR::LongDouble::operator== (const ACE_CDR::LongDouble &rhs) const +{ + return ACE_OS::memcmp (this->ld, rhs.ld, 16) == 0; +} + +bool +ACE_CDR::LongDouble::operator!= (const ACE_CDR::LongDouble &rhs) const +{ + return ACE_OS::memcmp (this->ld, rhs.ld, 16) != 0; +} + +ACE_CDR::LongDouble::operator ACE_CDR::LongDouble::NativeImpl () const +{ + ACE_CDR::LongDouble::NativeImpl ret = 0.0; + char* lhs_ptr = reinterpret_cast (&ret); + + if (sizeof (ret) == 8) + { +#if defined (ACE_LITTLE_ENDIAN) + static const size_t byte_zero = 1; + static const size_t byte_one = 0; + char copy[16]; + ACE_CDR::swap_16 (this->ld, copy); +#else + static const size_t byte_zero = 0; + static const size_t byte_one = 1; + const char* copy = this->ld; +#endif + ACE_INT16 exponent = 0; + char* exp_ptr = reinterpret_cast (&exponent); + exp_ptr[byte_zero] = copy[0]; + exp_ptr[byte_one] = copy[1]; + + ACE_INT16 sign = (exponent & 0x8000); + exponent &= 0x7fff; + + // Infinity and NaN have an exponent of 0x7fff in 128-bit IEEE + if (exponent == 0x7fff) + { + exponent = 0x7ff; + } + else if (exponent) // exponent 0 stays 0 in 64-bit + { + exponent = (exponent - max_fifteen_bit) + max_eleven_bit; + } + exponent = (exponent << 4) | sign; + + // Store the sign and exponent + lhs_ptr[0] = exp_ptr[byte_zero]; + lhs_ptr[1] = exp_ptr[byte_one]; + + // Store the mantissa. In an 8 byte double, it is split by + // 4 bits (because of the 12 bits for sign and exponent), so + // we have to shift and or the rhs to get the right bytes. + size_t li = 1; + bool direction = true; + for (size_t ri = 2; li < sizeof (ret);) { + if (direction) + { + lhs_ptr[li] |= ((copy[ri] >> 4) & 0xf); + direction = false; + ++li; + } + else + { + lhs_ptr[li] |= ((copy[ri] & 0xf) << 4); + direction = true; + ++ri; + } + } + +#if defined (ACE_LITTLE_ENDIAN) + ACE_CDR::swap_8 (lhs_ptr, lhs_ptr); +#endif + } + else + { + ACE_OS::memcpy(lhs_ptr, this->ld, sizeof (ret)); + } + + // This bit of code is unnecessary. However, this code is + // necessary to work around a bug in the gcc 4.1.1 optimizer. + ACE_CDR::LongDouble tmp; + tmp.assign (ret); + + return ret; +} +#endif /* NONNATIVE_LONGDOUBLE */ + + +// ACE_CDR::Fixed + +ACE_CDR::Fixed ACE_CDR::Fixed::from_integer (ACE_CDR::LongLong val) +{ + Fixed f; + f.value_[15] = (val < 0) ? NEGATIVE : POSITIVE; + f.digits_ = 0; + f.scale_ = 0; + bool high = true; + int idx = 15; + while (true) + { + const int mod = static_cast (val % 10); + const unsigned int digit = (mod < 0) ? -mod : mod; + if (high) + f.value_[idx--] |= digit << 4; + else + f.value_[idx] = digit; + high = !high; + ++f.digits_; + if (val >= 10 || val <= -10) + val /= 10; + else + break; + } + + ACE_OS::memset (f.value_, 0, idx + !high); + return f; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::from_integer (ACE_CDR::ULongLong val) +{ + Fixed f; + f.value_[15] = POSITIVE; + f.digits_ = 0; + f.scale_ = 0; + bool high = true; + int idx = 15; + while (true) + { + const unsigned int digit = val % 10; + if (high) + f.value_[idx--] |= digit << 4; + else + f.value_[idx] = digit; + high = !high; + ++f.digits_; + if (val >= 10) + val /= 10; + else + break; + } + + ACE_OS::memset (f.value_, 0, idx + !high); + return f; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::from_floating (LongDouble val) +{ +#if defined ACE_OPENVMS || (defined ACE_VXWORKS && !defined __RTP__) + typedef double BigFloat; +#elif defined NONNATIVE_LONGDOUBLE + typedef LongDouble::NativeImpl BigFloat; +#else + typedef LongDouble BigFloat; +#endif + + Fixed f; + f.digits_ = f.scale_ = 0; + bool negative = false; + if (val < 0) + { + val *= -1; + negative = true; + } + + // How many digits are to the left of the decimal point? + const size_t digits_left = + static_cast (1 + ((val > 0) ? std::log10 (val) : 0)); + if (digits_left > MAX_DIGITS) + { + ACE_OS::memset (f.value_, 0, sizeof f.value_); + return f; + } + + f.digits_ = MAX_DIGITS; + f.scale_ = 0; + BigFloat int_part; + BigFloat frac_part = std::modf (val, &int_part); + + // Insert the integer part from least to most significant + int idx = (static_cast (digits_left) + 1) / 2 - 1; + bool high = digits_left % 2; + if (idx >= 0) + f.value_[idx] = 0; + for (size_t i = 0; i < digits_left; ++i, high = !high) + { + const Octet digit = static_cast (std::fmod (int_part, 10)); + if (high) + f.value_[idx--] |= digit << 4; + else + f.value_[idx] = digit; + int_part /= 10; + } + + // Insert the fractional part from most to least significant + idx = static_cast (digits_left / 2); + high = digits_left % 2 == 0; + for (size_t i = digits_left; i < MAX_DIGITS; ++i, high = !high) + { + frac_part *= 10; + const Octet digit = static_cast (frac_part); + frac_part -= digit; + if (high) + f.value_[idx] = digit << 4; + else + f.value_[idx++] |= digit; + } + + if (frac_part >= 0.5) + ++f; // scale set after here so that ++ applies to the fractional part + + f.scale_ = static_cast (MAX_DIGITS - digits_left); + f.normalize (); + f.value_[15] |= negative ? NEGATIVE : POSITIVE; + return f; +} + +void ACE_CDR::Fixed::normalize (UShort min_scale) +{ + if (this->value_[15] & 0xf0 || !this->scale_) + return; + + // Calculate the number of nibbles that can be moved. + ACE_CDR::Octet nibbles = 0; + while (this->digit(nibbles) == 0 && this->scale_ - nibbles > min_scale) + ++nibbles; + + // Move and clear the nibbles. + for (ACE_CDR::Octet idx = nibbles; idx != this->digits_; ++idx) { + this->digit (idx - nibbles, this->digit (idx)); + this->digit (idx, 0); + } + + this->scale_ -= nibbles; + this->digits_ -= nibbles; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::from_string (const char *str) +{ + const bool negative = *str == '-'; + if (negative || *str == '+') + ++str; + + const size_t span = ACE_OS::strspn (str, ".0123456789"); + + Fixed f; + f.value_[15] = negative ? NEGATIVE : POSITIVE; + f.digits_ = 0; + f.scale_ = 0; + + int idx = 15; + bool high = true; + for (size_t iter = span; iter && f.digits_ < MAX_DIGITS; --iter, high = !high) + { + if (str[iter - 1] == '.') + { + f.scale_ = static_cast (span - iter); + if (--iter == 0) + break; // skip '.' + } + + const unsigned int digit = str[iter - 1] - '0'; + if (high) + f.value_[idx--] |= digit << 4; + else + f.value_[idx] = digit; + ++f.digits_; + } + + if (!f.scale_ && str[span - f.digits_ - 1] == '.') + f.scale_ = f.digits_; + + if (idx >= 0) + ACE_OS::memset (f.value_, 0, idx + !high); + return f; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::from_octets (const Octet *array, int len, + unsigned int scale) +{ + Fixed f; + ACE_OS::memcpy (f.value_ + 16 - len, array, len); + ACE_OS::memset (f.value_, 0, 16 - len); + f.scale_ = scale; + + f.digits_ = len * 2 - 1; + if (len > 1 && (array[0] >> 4) == 0) + --f.digits_; + + return f; +} + +ACE_CDR::Fixed::operator ACE_CDR::LongLong () const +{ + LongLong val (0); + + for (int i = this->digits_ - 1; i >= this->scale_; --i) + val = 10 * val + this->digit (i); + + if (this->sign ()) + val *= -1; + + return val; +} + +ACE_CDR::Fixed::operator ACE_CDR::LongDouble () const +{ + LongDouble val = ACE_CDR_LONG_DOUBLE_INITIALIZER; + + for (int i = this->digits_ - 1; i >= this->scale_; --i) + ACE_CDR_LONG_DOUBLE_ASSIGNMENT (val, 10 * val + this->digit (i)); + + for (int i = this->scale_ - 1; i >= 0; --i) + val += this->digit (i) * std::pow (10.0l, i - this->scale_); + + if (this->sign ()) + val *= -1; + + return val; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::round (UShort scale) const +{ + Fixed f = *this; + if (scale < f.scale_) + { + for (UShort i = 0; i < f.scale_ - scale; ++i) + f.digit (i, 0); + f.normalize (scale); + const bool negative = f.sign (); + if (negative) + f.value_[15] = (f.value_[15] & 0xf0) | POSITIVE; + if (this->digit (this->scale_ - scale - 1) >= 5) + { + f.scale_ = 0; + ++f; + f.scale_ = static_cast (scale); + } + if (negative && !!f) + f.value_[15] = (f.value_[15] & 0xf0) | NEGATIVE; + } + return f; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::truncate (UShort scale) const +{ + Fixed f = *this; + if (scale < f.scale_) + { + for (UShort i = 0; i < f.scale_ - scale; ++i) + f.digit (i, 0); + f.normalize (scale); + if (f.sign ()) + { + f.value_[15] = (f.value_[15] & 0xf0) | POSITIVE; + if (!!f) + f.value_[15] = (f.value_[15] & 0xf0) | NEGATIVE; + } + } + return f; +} + +namespace { + struct BufferAppender + { + BufferAppender (char *buffer, size_t buffer_size) + : buffer_ (buffer), buffer_size_ (buffer_size), idx_ (0) {} + + bool operator+= (char ch) + { + if (this->idx_ == this->buffer_size_ - 1) + return false; + this->buffer_[this->idx_++] = ch; + return true; + } + + char *const buffer_; + const size_t buffer_size_; + size_t idx_; + }; +} + +bool ACE_CDR::Fixed::to_string (char *buffer, size_t buffer_size) const +{ + if (!buffer || buffer_size < 2) + return false; + + const bool negative = this->sign (); + if (negative) + *buffer = '-'; + BufferAppender ba (buffer + negative, buffer_size - negative); + + for (int i = 15 - this->digits_ / 2; i < 16; ++i) + { + const Octet high = this->value_[i] >> 4, low = this->value_[i] & 0xf; + + if ((15 - i) * 2 != this->digits_) + { + if (this->scale_ == 1 + 2 * (15 - i)) + { + if (!ba.idx_ && !(ba += '0')) + return false; + + if (!(ba += '.')) + return false; + } + + if ((ba.idx_ || high) && !(ba += '0' + high)) + return false; + } + + if (this->scale_ && this->scale_ == 2 * (15 - i)) + { + if (!ba.idx_ && !(ba += '0')) + return false; + + if (!(ba += '.')) + return false; + } + + if (i < 15 && (ba.idx_ || low) && !(ba += '0' + low)) + return false; + } + + if (!ba.idx_ && !(ba += '0')) + return false; + + buffer[ba.idx_ + negative] = 0; + return true; +} + +const ACE_CDR::Octet *ACE_CDR::Fixed::to_octets (int &n) const +{ + n = (this->digits_ + 2) / 2; + return 16 - n + reinterpret_cast (this->value_); +} + +ACE_CDR::Fixed::ConstIterator ACE_CDR::Fixed::pre_add (const ACE_CDR::Fixed &f) +{ + ConstIterator rhs_iter = f.begin (); + if (f.scale_ > this->scale_) + { + const int scale_diff = f.scale_ - this->scale_; + rhs_iter += scale_diff - this->lshift (scale_diff); + } + + if (f.digits_ - f.scale_ > this->digits_ - this->scale_) + { + ACE_CDR::Octet new_digits = this->digits_ + (f.digits_ - f.scale_) - (this->digits_ - this->scale_); + if (new_digits > MAX_DIGITS) + { + for (size_t i = 0; i < static_cast (new_digits - MAX_DIGITS); ++i) + this->digit (static_cast (i), 0); + this->normalize (this->scale_ - (new_digits - MAX_DIGITS)); + this->digits_ = MAX_DIGITS; + } + else + this->digits_ = new_digits; + } + return rhs_iter; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator+= (const Fixed &rhs) +{ + if (!this->sign () && rhs.sign ()) + return *this -= -rhs; + + if (this->sign () && !rhs.sign ()) + { + Fixed negated = -*this; + negated -= rhs; + return *this = -negated; + } + + ConstIterator rhs_iter = this->pre_add (rhs); + + Iterator lhs_iter = this->begin (); + if (this->scale_ > rhs.scale_) + lhs_iter += this->scale_ - rhs.scale_; + + bool carry = false; + for (; rhs_iter != rhs.end (); ++lhs_iter, ++rhs_iter) + { + const Octet digit = *lhs_iter + *rhs_iter + carry; + carry = digit > 9; + *lhs_iter = digit - (carry ? 10 : 0); + } + + if (carry) + { + if (this->digits_ < MAX_DIGITS) + { + *lhs_iter = 1; + ++this->digits_; + } + else if (this->scale_) + { + this->digit (0, 0); + this->normalize (this->scale_ - 1); + this->digit (MAX_DIGITS - 1, 1); + } + } + + return *this; +} + +int ACE_CDR::Fixed::lshift (int digits) +{ + int bytes = 0; + for (; bytes < digits / 2; ++bytes) + if (this->value_[bytes]) + break; + + int shifted = 0; + if ((digits % 2) && !(this->value_[bytes] & 0xf0)) + { + for (int i = 0; i < 15 - bytes; ++i) + this->value_[i] = (this->value_[i + bytes] & 0xf) << 4 + | (this->value_[i + bytes + 1] >> 4); + std::memset (this->value_ + 15 - bytes, 0, bytes); + this->value_[15] &= 0xf; + shifted = 2 * bytes + 1; + } + else if (bytes) + { + std::memmove (this->value_, this->value_ + bytes, 16 - bytes); + this->value_[15] &= 0xf; + std::memset (this->value_ + 16 - bytes, 0, bytes - 1); + this->value_[15 - bytes] &= 0xf0; + shifted = 2 * bytes; + } + + this->digits_ += shifted; + if (this->digits_ > MAX_DIGITS) + this->digits_ = MAX_DIGITS; + + this->scale_ += shifted; + if (this->scale_ > MAX_DIGITS) + this->scale_ = MAX_DIGITS; + + return shifted; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator-= (const Fixed &rhs) +{ + if (!this->sign () && rhs.sign ()) + return *this += -rhs; + + if (this->sign () && !rhs.sign ()) + { + Fixed negated = -*this; + negated += rhs; + return *this = -negated; + } + + const Fixed before = *this; + ConstIterator rhs_iter = this->pre_add (rhs); + + Iterator lhs_iter = this->begin (); + if (this->scale_ > rhs.scale_) + lhs_iter += this->scale_ - rhs.scale_; + + bool borrow = false; + for (; rhs_iter != rhs.end (); ++lhs_iter, ++rhs_iter) + if (*rhs_iter + borrow <= *lhs_iter) + { + *lhs_iter -= *rhs_iter + borrow; + borrow = false; + } + else + { + *lhs_iter += 10 - *rhs_iter - borrow; + borrow = true; + } + + while (borrow && lhs_iter != this->end ()) + if (*lhs_iter) + { + --*lhs_iter; + borrow = false; + } + else + *lhs_iter = 9; + + if (borrow) + return *this = -(rhs - before); + + this->ltrim (); + return *this; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator*= (const Fixed &rhs) +{ + if (!this->sign () && rhs.sign ()) + this->value_[15] = (this->value_[15] & 0xf0) | NEGATIVE; + else if (this->sign () && rhs.sign ()) + this->value_[15] = (this->value_[15] & 0xf0) | POSITIVE; + + this->ltrim (); + Fixed right = rhs; + right.ltrim (); + + Octet temp[MAX_DIGITS * 2]; + int carry = 0; + + for (int col = 0; col < this->digits_ + right.digits_; ++col) + { + for (int row = (std::max) (0, col - this->digits_ + 1); + row < (std::min) (col + 1, int (right.digits_)); ++row) + carry += this->digit (col - row) * right.digit (row); + temp[col] = carry % 10; + carry /= 10; + } + + this->digits_ += right.digits_; + this->scale_ += right.scale_; + int digit_offset = 0; + + if (this->digits_ > MAX_DIGITS) + { + digit_offset = this->digits_ - MAX_DIGITS; + this->digits_ = MAX_DIGITS; + if (this->scale_ > digit_offset) + this->scale_ -= digit_offset; + } + + for (int i = 0; i < this->digits_; ++i) + this->digit (i, temp[i + digit_offset]); + + this->ltrim (); + return *this; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator/= (const Fixed &rhs) +{ + if (!rhs) + return *this; + + if (rhs.scale_ && rhs.scale_ <= this->scale_) + this->scale_ -= rhs.scale_; + else if (rhs.scale_) + { + const Octet shifted = this->lshift (rhs.scale_ - this->scale_); + this->scale_ -= shifted; + } + + Fixed rhs_no_scale = rhs; + rhs_no_scale.scale_ = 0; + rhs_no_scale.value_[15] = (rhs_no_scale.value_[15] & 0xf0) | POSITIVE; + rhs_no_scale.ltrim (); + + this->ltrim (); + + if (!this->sign () && rhs.sign ()) + this->value_[15] = (this->value_[15] & 0xf0) | NEGATIVE; + else if (this->sign () && rhs.sign ()) + this->value_[15] = (this->value_[15] & 0xf0) | POSITIVE; + + static const Fixed one = from_integer (LongLong (1)), + two = from_integer (LongLong (2)), + three = from_integer (LongLong (3)), + five = from_integer (LongLong (5)); + + if (rhs_no_scale == one) + return *this; + + // Most sig digit of rhs must be >= 5 + switch (rhs_no_scale.digit (rhs_no_scale.digits_ - 1)) + { + case 1: + return *this = (*this * five) / (rhs_no_scale * five); + case 2: + return *this = (*this * three) / (rhs_no_scale * three); + case 3: + case 4: + return *this = (*this * two) / (rhs_no_scale * two); + default: + break; + } + + const bool neg = this->sign (); + if (neg) + this->value_[15] = (this->value_[15] & 0xf0) | POSITIVE; + + Fixed r; + Fixed q = this->div_helper2 (rhs_no_scale, r); + q.scale_ = this->scale_; + + if (!r) { + *this = neg ? -q : q; + this->normalize (); + return *this; + } + + const int shift = q.lshift (MAX_DIGITS); + if (shift) + { + const Octet scale = r.lshift (shift); + r.scale_ = 0; + Fixed r2; + r = r.div_helper2 (rhs_no_scale, r2); + r.scale_ = scale; + q += r; + } + + *this = neg ? -q : q; + this->normalize (); + return *this; +} + +ACE_CDR::Fixed ACE_CDR::Fixed::div_helper2 (const Fixed &rhs, Fixed &r) const +{ + if (this->digits_ < rhs.digits_) + r = *this; + else if (this->digits_ == rhs.digits_) + if (*this < rhs) + r = *this; + else + { + r = *this - rhs; + return from_integer (LongLong (1)); + } + else if (this->digits_ == rhs.digits_ + 1) + return this->div_helper1 (rhs, r); + else + { + const int dig = this->digits_ - rhs.digits_ - 1; + Fixed top = *this, bot = *this; // split with bot having dig digits + for (int i = 0; i < dig; ++i) + top.digit (i, 0); + for (int i = dig; i < this->digits_; ++i) + bot.digit (i, 0); + bot.digits_ = dig; + top.scale_ += dig; + top.normalize (this->scale_); + + Fixed rtop; + const Fixed qtop = top.div_helper1 (rhs, rtop); + const Fixed qbot = rtop.join (dig, bot).div_helper2 (rhs, r); + return qtop.join (dig, qbot); + } + + return from_integer (); +} + +ACE_CDR::Fixed ACE_CDR::Fixed::div_helper1 (const Fixed &rhs, Fixed &r) const +{ + static const Fixed ten = from_integer (LongLong (10)); + if (*this >= rhs * ten) + return ten + (*this - rhs * ten).div_helper1 (rhs, r); + + int q = (this->digit (this->digits_ - 1) * 10 + + this->digit (this->digits_ - 2)) / rhs.digit (rhs.digits_ - 1); + if (q > 9) + q = 9; + Fixed t = from_integer (LongLong (q)) * rhs; + t.scale_ = this->scale_; + for (int i = 0; i < 2 && t > *this; ++i) + { + --q; + t -= rhs; + } + + r = *this - t; + return from_integer (LongLong (q)); +} + +ACE_CDR::Fixed ACE_CDR::Fixed::join (int digits, const Fixed &bot) const +{ + Fixed res = bot; + res.digits_ = this->digits_ + digits; + for (int i = digits; i < MAX_DIGITS && i - digits < this->digits_; ++i) + res.digit (i, this->digit (i - digits)); + return res; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator++ () +{ + if (this->sign ()) + { + this->value_[15] = (this->value_[15] & 0xf0) | POSITIVE; + if (!!--*this) // decrement and check if result is nonzero + this->value_[15] = (this->value_[15] & 0xf0) | NEGATIVE; + } + else + { + Iterator iter = this->begin (); + iter += this->scale_; + for (; iter != this->end (); ++iter) + { + if (*iter < 9) + { + ++*iter; + return *this; + } + *iter = 0; + } + if (this->digits_ < MAX_DIGITS) + { + ++this->digits_; + *iter = 1; + } + } + return *this; +} + +ACE_CDR::Fixed &ACE_CDR::Fixed::operator-- () +{ + if (this->sign ()) + { + this->value_[15] = (this->value_[15] & 0xf0) | POSITIVE; + ++*this; + this->value_[15] = (this->value_[15] & 0xf0) | NEGATIVE; + } + else + { + Fixed before = *this; + Iterator iter = this->begin (); + iter += this->scale_; + for (; iter != this->end (); ++iter) + { + if (*iter) + { + --*iter; + return *this; + } + *iter = 9; + } + *this = before - from_integer (ULongLong (1)); + } + return *this; +} + +bool ACE_CDR::Fixed::operator! () const +{ + static const Octet ZERO[] = {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, POSITIVE}; + return 0 == ACE_OS::memcmp (this->value_, ZERO, sizeof ZERO); +} + +ACE_OSTREAM_TYPE &operator<< (ACE_OSTREAM_TYPE &lhs, const ACE_CDR::Fixed &rhs) +{ + char digits[ACE_CDR::Fixed::MAX_STRING_SIZE]; + rhs.to_string (digits, sizeof digits); + +#ifdef ACE_LACKS_IOSTREAM_TOTALLY + ACE_OS::fputs (digits, &lhs); +#else + lhs << digits; +#endif + return lhs; +} + +#ifndef ACE_LACKS_IOSTREAM_TOTALLY +std::istream &operator>> (std::istream &lhs, ACE_CDR::Fixed &rhs) +{ + double num; + lhs >> num; + ACE_CDR::LongDouble ld; + ACE_CDR_LONG_DOUBLE_ASSIGNMENT (ld, num); + rhs = ACE_CDR::Fixed::from_floating (ld); + return lhs; +} +#endif + +bool ACE_CDR::Fixed::less (const ACE_CDR::Fixed &rhs) const +{ + const Fixed &lhs = *this; + if (lhs.sign () != rhs.sign ()) + return lhs.sign (); + + // signs of lhs and rhs are the same so lhs < rhs reduces to: + // if positive, |lhs| < |rhs| + // if negative, |rhs| < |lhs| + // 'a' will refer to the value left of < and 'b' to the value to the right + const ACE_CDR::Fixed &a = lhs.sign () ? rhs : lhs, + &b = lhs.sign () ? lhs : rhs; + + if (a.scale_ == b.scale_) + return ACE_OS::memcmp (a.value_, b.value_, sizeof a.value_) < 0; + + const int a_int_dig = a.digits_ - a.scale_, b_int_dig = b.digits_ - b.scale_; + + if (a_int_dig > b_int_dig) + { + for (int i = 1; i <= a_int_dig - b_int_dig; ++i) + if (a.digit (a.digits_ - i)) + return false; + } + else if (a_int_dig < b_int_dig) + { + for (int i = 1; i <= b_int_dig - a_int_dig; ++i) + if (b.digit (b.digits_ - i)) + return true; + } + + const int common_frac = (std::min) (a.scale_, b.scale_), + common_dig = (std::min) (a_int_dig, b_int_dig) + common_frac, + a_off = a.scale_ - common_frac, // a's offset (more scale than b) + b_off = b.scale_ - common_frac; // b's offset (more scale than a) + + for (int i = 1; i <= common_dig; ++i) + if (a.digit (a_off + common_dig - i) < b.digit (b_off + common_dig - i)) + return true; + + for (int i = 1; i <= a_off; ++i) + if (a.digit (a_off - i)) + return false; + + for (int i = 1; i <= b_off; ++i) + if (b.digit (b_off - i)) + return true; + + return false; +} + +bool ACE_CDR::Fixed::equal (const ACE_CDR::Fixed &rhs) const +{ + const Fixed &lhs = *this; + if (lhs.sign () != rhs.sign ()) + return false; + + if (lhs.scale_ == rhs.scale_) + return 0 == ACE_OS::memcmp (lhs.value_, rhs.value_, sizeof lhs.value_); + + const ACE_CDR::Fixed &more = (lhs.scale_ > rhs.scale_) ? lhs : rhs, + &fewer = (lhs.scale_ > rhs.scale_) ? rhs : lhs; + + const ACE_CDR::Octet scale_diff = more.scale_ - fewer.scale_; + + ACE_CDR::Fixed::ConstIterator more_iter = more.begin (), + more_end = more.end (); + + for (ACE_CDR::Octet i = 0; i < scale_diff; ++i) + if (more_iter == more_end || *more_iter++) + return false; // digits in more that are missing in fewer must be 0 + + ACE_CDR::Fixed::ConstIterator fewer_iter = fewer.begin (), + fewer_end = fewer.end (); + + while (more_iter != more_end && fewer_iter != fewer_end) + if (*more_iter++ != *fewer_iter++) + return false; // digits in common must match + + while (more_iter != more_end) + if (*more_iter++) + return false; // extra (more significant) digits in more must be 0 + + while (fewer_iter != fewer_end) + if (*fewer_iter++) + return false; // extra (more significant) digits in fewer must be 0 + + return true; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CDR_Base.h b/dep/acelite/ace/CDR_Base.h new file mode 100644 index 000000000..22dd8adf9 --- /dev/null +++ b/dep/acelite/ace/CDR_Base.h @@ -0,0 +1,580 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file CDR_Base.h + * + * ACE Common Data Representation (CDR) basic types. + * + * The current implementation assumes that the host has 1-byte, + * 2-byte and 4-byte integral types, and that it has single + * precision and double precision IEEE floats. + * Those assumptions are pretty good these days, with Crays being + * the only known exception. + * + * @author TAO version by + * @author Aniruddha Gokhale + * @author Carlos O'Ryan + * @author ACE version by + * @author Jeff Parsons + * @author Istvan Buki + */ +//============================================================================= + + +#ifndef ACE_CDR_BASE_H +#define ACE_CDR_BASE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Types.h" +#include "ace/Default_Constants.h" +#include "ace/Global_Macros.h" +#include "ace/iosfwd.h" + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Stuff used by the ACE CDR classes. Watch these values... they're also used +// in the ACE_CDR Byte_Order enum below. +#if defined ACE_LITTLE_ENDIAN +# define ACE_CDR_BYTE_ORDER 1 +// little endian encapsulation byte order has value = 1 +#else /* ! ACE_LITTLE_ENDIAN */ +# define ACE_CDR_BYTE_ORDER 0 +// big endian encapsulation byte order has value = 0 +#endif /* ! ACE_LITTLE_ENDIAN */ + +class ACE_Message_Block; + +/** + * @class ACE_CDR + * + * @brief Keep constants and some routines common to both Output and + * Input CDR streams. + */ +class ACE_Export ACE_CDR +{ +public: + // = Constants defined by the CDR protocol. + // By defining as many of these constants as possible as enums we + // ensure they get inlined and avoid pointless static memory + // allocations. + + enum + { + // Note that some of these get reused as part of the standard + // binary format: unsigned is the same size as its signed cousin, + // float is LONG_SIZE, and double is LONGLONG_SIZE. + + OCTET_SIZE = 1, + SHORT_SIZE = 2, + LONG_SIZE = 4, + LONGLONG_SIZE = 8, + LONGDOUBLE_SIZE = 16, + + OCTET_ALIGN = 1, + SHORT_ALIGN = 2, + LONG_ALIGN = 4, + LONGLONG_ALIGN = 8, + /// @note the CORBA LongDouble alignment requirements do not + /// match its size... + LONGDOUBLE_ALIGN = 8, + + /// Maximal CDR 1.1 alignment: "quad precision" FP (i.e. "CDR::Long + /// double", size as above). + MAX_ALIGNMENT = 8, + + /// The default buffer size. + /** + * @todo We want to add options to control this + * default value, so this constant should be read as the default + * default value ;-) + */ + DEFAULT_BUFSIZE = ACE_DEFAULT_CDR_BUFSIZE, + + /// The buffer size grows exponentially until it reaches this size; + /// afterwards it grows linearly using the next constant + EXP_GROWTH_MAX = ACE_DEFAULT_CDR_EXP_GROWTH_MAX, + + /// Once exponential growth is ruled out the buffer size increases + /// in chunks of this size, note that this constants have the same + /// value right now, but it does not need to be so. + LINEAR_GROWTH_CHUNK = ACE_DEFAULT_CDR_LINEAR_GROWTH_CHUNK + }; + + /** + * @enum Byte_Order + * + * Defines values for the byte_order argument to ACE_OutputCDR and + * ACE_InputCDR. + */ + enum Byte_Order + { + /// Use big-endian order (also known as network byte order). + BYTE_ORDER_BIG_ENDIAN = 0, + /// Use little-endian order. + BYTE_ORDER_LITTLE_ENDIAN = 1, + /// Use whichever byte order is native to this machine. + BYTE_ORDER_NATIVE = ACE_CDR_BYTE_ORDER + }; + + /** + * Do byte swapping for each basic IDL type size. There exist only + * routines to put byte, halfword (2 bytes), word (4 bytes), + * doubleword (8 bytes) and quadword (16 byte); because those are + * the IDL basic type sizes. + */ + static void swap_2 (char const *orig, char *target); + static void swap_4 (char const *orig, char *target); + static void swap_8 (char const *orig, char *target); + static void swap_16 (char const *orig, char *target); + static void swap_2_array (char const *orig, + char *target, + size_t length); + static void swap_4_array (char const *orig, + char *target, + size_t length); + static void swap_8_array (char const *orig, + char *target, + size_t length); + static void swap_16_array (char const *orig, + char *target, + size_t length); + + /// Align the message block to ACE_CDR::MAX_ALIGNMENT, + /// set by the CORBA spec at 8 bytes. + static void mb_align (ACE_Message_Block *mb); + + /** + * Compute the size of the smallest buffer that can contain at least + * @a minsize bytes. + * To understand how a "best fit" is computed look at the + * algorithm in the code. + * Basically the buffers grow exponentially, up to a certain point, + * then the buffer size grows linearly. + * The advantage of this algorithm is that is rapidly grows to a + * large value, but does not explode at the end. + */ + static size_t first_size (size_t minsize); + + /// Compute not the smallest, but the second smallest buffer that + /// will fir @a minsize bytes. + static size_t next_size (size_t minsize); + + /** + * Increase the capacity of mb to contain at least @a minsize bytes. + * If @a minsize is zero the size is increased by an amount at least + * large enough to contain any of the basic IDL types. + * @retval -1 Failure + * @retval 0 Success. + */ + static int grow (ACE_Message_Block *mb, size_t minsize); + + /** + * Copy a message block chain into a single message block, + * preserving the alignment of the first message block of the + * original stream, not the following message blocks. + * @retval -1 Failure + * @retval 0 Success. + */ + static int consolidate (ACE_Message_Block *dst, + const ACE_Message_Block *src); + + static size_t total_length (const ACE_Message_Block *begin, + const ACE_Message_Block *end); + + /** + * @name Basic OMG IDL Types + * + * These types are for use in the CDR classes. The cleanest way to + * avoid complaints from all compilers is to define them all. + */ + //@{ + typedef bool Boolean; + typedef unsigned char Octet; + typedef char Char; + typedef ACE_WCHAR_T WChar; + typedef ACE_INT16 Short; + typedef ACE_UINT16 UShort; + typedef ACE_INT32 Long; + typedef ACE_UINT32 ULong; + typedef ACE_UINT64 ULongLong; + +# if (defined (_MSC_VER)) || (defined (__BORLANDC__)) + typedef __int64 LongLong; +# elif ACE_SIZEOF_LONG == 8 + typedef long LongLong; +# elif defined(__TANDEM) + typedef long long LongLong; +# elif ACE_SIZEOF_LONG_LONG == 8 +# if defined (sun) && !defined (ACE_LACKS_U_LONGLONG_T) + // sun #defines u_longlong_t, maybe other platforms do also. + // Use it, at least with g++, so that its -pedantic doesn't + // complain about no ANSI C++ long long. + typedef longlong_t LongLong; +# else + typedef long long LongLong; +# endif /* sun */ +# else /* no native 64 bit integer type */ +# define NONNATIVE_LONGLONG + struct ACE_Export LongLong + { +# if defined (ACE_BIG_ENDIAN) + ACE_CDR::Long h; + ACE_CDR::Long l; +# else + ACE_CDR::Long l; + ACE_CDR::Long h; +# endif /* ! ACE_BIG_ENDIAN */ + + /** + * @name Overloaded Relation Operators. + * + * The canonical comparison operators. + */ + //@{ + bool operator== (const LongLong &rhs) const; + bool operator!= (const LongLong &rhs) const; + //@} + }; +# endif /* no native 64 bit integer type */ + +# if defined (NONNATIVE_LONGLONG) +# define ACE_CDR_LONGLONG_INITIALIZER {0,0} +# else +# define ACE_CDR_LONGLONG_INITIALIZER 0 +# endif /* NONNATIVE_LONGLONG */ + +# if ACE_SIZEOF_FLOAT == 4 + typedef float Float; +# else /* ACE_SIZEOF_FLOAT != 4 */ + struct Float + { +# if ACE_SIZEOF_INT == 4 + // Use unsigned int to get word alignment. + unsigned int f; +# else /* ACE_SIZEOF_INT != 4 */ + // Applications will probably have trouble with this. + char f[4]; +# endif /* ACE_SIZEOF_INT != 4 */ + }; +# endif /* ACE_SIZEOF_FLOAT != 4 */ + +# if ACE_SIZEOF_DOUBLE == 8 + typedef double Double; +# else /* ACE_SIZEOF_DOUBLE != 8 */ + struct Double + { +# if ACE_SIZEOF_LONG == 8 + // Use u long to get word alignment. + unsigned long f; +# else /* ACE_SIZEOF_INT != 8 */ + // Applications will probably have trouble with this. + char f[8]; +# endif /* ACE_SIZEOF_INT != 8 */ + }; +# endif /* ACE_SIZEOF_DOUBLE != 8 */ + + // 94-9-32 Appendix A defines a 128 bit floating point "long + // double" data type, with greatly extended precision and four + // more bits of exponent (compared to "double"). This is an IDL + // extension, not yet standard. + +# if ACE_SIZEOF_LONG_DOUBLE == 16 + typedef long double LongDouble; +# define ACE_CDR_LONG_DOUBLE_INITIALIZER 0 +# define ACE_CDR_LONG_DOUBLE_ASSIGNMENT(LHS, RHS) LHS = RHS +# else +# define NONNATIVE_LONGDOUBLE +# define ACE_CDR_LONG_DOUBLE_INITIALIZER {{0}} +# define ACE_CDR_LONG_DOUBLE_ASSIGNMENT(LHS, RHS) LHS.assign (RHS) + struct ACE_Export LongDouble + { + // VxWorks' compiler (gcc 2.96) gets confused by the operator long + // double, so we avoid using long double as the NativeImpl. + // Linux's x86 long double format (12 or 16 bytes) is incompatible + // with Windows, Solaris, AIX, MacOS X and HP-UX (and probably others) + // long double format (8 or 16 bytes). If you need 32-bit Linux to + // inter-operate with 64-bit Linux you will want to define this + // macro to 0 so that "long double" is used. Otherwise, do not define + // this macro. +# if defined (ACE_CDR_IMPLEMENT_WITH_NATIVE_DOUBLE) && \ + (ACE_CDR_IMPLEMENT_WITH_NATIVE_DOUBLE == 1) + typedef double NativeImpl; +# else + typedef long double NativeImpl; +# endif /* ACE_CDR_IMPLEMENT_WITH_NATIVE_DOUBLE==1 */ + + char ld[16]; + + LongDouble& assign (const NativeImpl& rhs); + LongDouble& assign (const LongDouble& rhs); + + bool operator== (const LongDouble &rhs) const; + bool operator!= (const LongDouble &rhs) const; + + LongDouble& operator*= (const NativeImpl rhs) { + return this->assign (static_cast (*this) * rhs); + } + LongDouble& operator/= (const NativeImpl rhs) { + return this->assign (static_cast (*this) / rhs); + } + LongDouble& operator+= (const NativeImpl rhs) { + return this->assign (static_cast (*this) + rhs); + } + LongDouble& operator-= (const NativeImpl rhs) { + return this->assign (static_cast (*this) - rhs); + } + LongDouble& operator++ () { + return this->assign (static_cast (*this) + 1); + } + LongDouble& operator-- () { + return this->assign (static_cast (*this) - 1); + } + LongDouble operator++ (int) { + LongDouble ldv = *this; + this->assign (static_cast (*this) + 1); + return ldv; + } + LongDouble operator-- (int) { + LongDouble ldv = *this; + this->assign (static_cast (*this) - 1); + return ldv; + } + + operator NativeImpl () const; + }; +# endif /* ACE_SIZEOF_LONG_DOUBLE != 16 */ + +#define ACE_HAS_CDR_FIXED + /// Fixed-point data type: up to 31 decimal digits and a sign bit + /// + /// See OMG 2011-11-01 CORBA Interfaces v3.2 sections 7.10, 7.11.3.4 + /// See OMG 2011-11-02 CORBA Interoperability v3.2 section 9.3.2.8 + /// See OMG 2012-07-02 IDL-to-C++ Mapping v1.3 section 5.13 + /// This class doesn't exactly match the IDL-to-C++ mapping because + /// it is meant for use inside a union in the IDL compiler and therefore + /// has no constructors. Standards-based middlware libraries such as + /// ORBs and DDSs can wrap this class in a class of their own to provide + /// the exact interface described by the mapping specification. + class ACE_Export Fixed + { + public: + enum + { + MAX_DIGITS = 31, + MAX_STRING_SIZE = 4 + MAX_DIGITS, // includes -, 0, ., terminator + POSITIVE = 0xc, + NEGATIVE = 0xd + }; + + static Fixed from_integer (LongLong val = 0); + static Fixed from_integer (ULongLong val); + static Fixed from_floating (LongDouble val); + static Fixed from_string (const char *str); + static Fixed from_octets (const Octet *array, int len, + unsigned int scale = 0); + + operator LongLong () const; + operator LongDouble () const; + + Fixed round (UShort scale) const; + Fixed truncate (UShort scale) const; + + bool to_string (char *buffer, size_t buffer_size) const; + const Octet *to_octets (int &n) const; + + Fixed &operator+= (const Fixed &rhs); + Fixed &operator-= (const Fixed &rhs); + Fixed &operator*= (const Fixed &rhs); + Fixed &operator/= (const Fixed &rhs); + + Fixed &operator++ (); + Fixed operator++ (int); + Fixed &operator-- (); + Fixed operator-- (int); + + Fixed operator+ () const; + Fixed operator- () const; + bool operator! () const; + + UShort fixed_digits () const; + UShort fixed_scale () const; + + bool sign () const; + Octet digit (int n) const; + void digit (int n, int value); + + bool less (const Fixed &rhs) const; + bool equal (const Fixed &rhs) const; + + class Proxy + { + bool high_nibble_; + Octet &element_; + public: + Proxy (bool high_nibble, Octet &element); + Proxy &operator= (Octet val); + Proxy &operator+= (int rhs); + Proxy &operator-= (int rhs); + Proxy &operator++ (); + Proxy &operator-- (); + operator Octet () const; + }; + + class IteratorBase + { + protected: + explicit IteratorBase (int digit); + bool high_nibble () const; + Octet &storage (Fixed *outer) const; + Octet storage (const Fixed *outer) const; + bool compare (const IteratorBase &rhs) const; + int digit_; + }; + + class Iterator + : public std::iterator + , private IteratorBase + { + public: + explicit Iterator (Fixed *outer, int digit = 0); + Proxy operator* (); + Iterator &operator+= (std::ptrdiff_t n); + Iterator &operator++ (); + Iterator operator++ (int); + Iterator &operator-- (); + Iterator operator-- (int); + bool operator== (const Iterator &rhs) const; + bool operator!= (const Iterator &rhs) const; + private: + Fixed *outer_; + }; + + class ConstIterator + : public std::iterator + , private IteratorBase + { + public: + explicit ConstIterator (const Fixed *outer, int digit = 0); + Octet operator* (); + ConstIterator &operator+= (std::ptrdiff_t n); + ConstIterator &operator++ (); + ConstIterator operator++ (int); + ConstIterator &operator-- (); + ConstIterator operator-- (int); + bool operator== (const ConstIterator &rhs) const; + bool operator!= (const ConstIterator &rhs) const; + private: + const Fixed *outer_; + }; + + Iterator begin (); + ConstIterator begin () const; + ConstIterator cbegin () const; + Iterator end (); + ConstIterator end () const; + ConstIterator cend () const; + + private: + /// CDR wire format for Fixed: marshaled as an octet array with + /// index 0 as the most significant octet and index n the least + /// significant. Each octet contains two decimal digits except for + /// the last octet (least sig) which has one decimal digit in + /// the high nibble and the sign indicator in the low nibble. + Octet value_[16]; + + /// digits_ is not marshaled, the receiver needs to know it + /// from the type information (for example, IDL). The value of + /// digits_ determines how many octets of value_ are masharled. + Octet digits_; + + /// scale_ is not marshaled, the receiver needs to know it + /// from the type information (for example, IDL). + Octet scale_; + + /// remove trailing zeros, shift down and reduce digits and scale + void normalize (UShort min_scale = 0); + + /// Add up to 'digits' of additional scale by shifting left without + /// removing significant digits. Returns number of digits shifted. + int lshift (int digits); + + /// Prepare to add (or subtract) f by changing the digits and scale + /// of *this, returnins an iterator to the least significant + /// digit of f that will influence the sum (or difference). + ConstIterator pre_add (const Fixed &f); + + Fixed div_helper2 (const Fixed &rhs, Fixed &r) const; + Fixed div_helper1 (const Fixed &rhs, Fixed &r) const; + Fixed join (int digits, const Fixed &bottom) const; + void ltrim (); + }; + + //@} + +#if !defined (ACE_CDR_GIOP_MAJOR_VERSION) +# define ACE_CDR_GIOP_MAJOR_VERSION 1 +#endif /*ACE_CDR_GIOP_MAJOR_VERSION */ + +#if !defined (ACE_CDR_GIOP_MINOR_VERSION) +# define ACE_CDR_GIOP_MINOR_VERSION 2 +#endif /* ACE_CDR_GIOP_MINOR_VERSION */ +}; + +ACE_Export +ACE_OSTREAM_TYPE &operator<< (ACE_OSTREAM_TYPE &lhs, const ACE_CDR::Fixed &rhs); + +#ifndef ACE_LACKS_IOSTREAM_TOTALLY +ACE_Export +std::istream &operator>> (std::istream &lhs, ACE_CDR::Fixed &rhs); +#endif + +ACE_Export +bool operator< (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +bool operator> (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +bool operator>= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +bool operator<= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +bool operator== (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +bool operator!= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +ACE_CDR::Fixed operator+ (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +ACE_CDR::Fixed operator- (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +ACE_CDR::Fixed operator* (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_Export +ACE_CDR::Fixed operator/ (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs); + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +# include "ace/CDR_Base.inl" +#endif /* __ACE_INLINE__ */ + + +#include /**/ "ace/post.h" + +#endif /* ACE_CDR_BASE_H */ diff --git a/dep/acelite/ace/CDR_Base.inl b/dep/acelite/ace/CDR_Base.inl new file mode 100644 index 000000000..c31c3b785 --- /dev/null +++ b/dep/acelite/ace/CDR_Base.inl @@ -0,0 +1,629 @@ +// -*- C++ -*- +#if defined (ACE_HAS_INTRINSIC_BYTESWAP) +// Take advantage of MSVC++ byte swapping compiler intrinsics (found +// in ). +# pragma intrinsic (_byteswap_ushort, _byteswap_ulong, _byteswap_uint64) +#endif /* ACE_HAS_INTRINSIC_BYTESWAP */ + +#if defined (ACE_HAS_BSWAP_16) || defined (ACE_HAS_BSWAP_32) || defined (ACE_HAS_BSWAP_64) +# include "ace/os_include/os_byteswap.h" +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// +// The ACE_CDR::swap_X and ACE_CDR::swap_X_array routines are broken +// in 5 cases for optimization: +// +// * MSVC++ 7.1 or better +// => Compiler intrinsics +// +// * AMD64 CPU + gnu g++ +// => gcc amd64 inline assembly. +// +// * x86 Pentium CPU + gnu g++ +// (ACE_HAS_PENTIUM && __GNUG__) +// => gcc x86 inline assembly. +// +// * x86 Pentium CPU and (_MSC_VER) or BORLAND C++) +// (ACE_HAS_PENTIUM && ( _MSC_VER || __BORLANDC__ ) +// => MSC x86 inline assembly. +// +// * 64 bit architecture +// (ACE_SIZEOF_LONG == 8) +// => shift/masks using 64bit words. +// +// * default +// (none of the above) +// => shift/masks using 32bit words. +// +// Some things you could find useful to know if you intend to mess +// with this optimizations for swaps: +// +// * MSVC++ don't assume register values are conserved between +// statements. So you can clobber any register you want, +// whenever you want (well not *anyone* really, see manual). +// The MSVC++ optimizer will try to pick different registers +// for the C++ statements sorrounding your asm block, and if +// it's not possible will use the stack. +// +// * If you clobber registers with asm statements in gcc, you +// better do it in an asm-only function, or save/restore them +// before/after in the stack. If not, sorrounding C statements +// could end using the same registers and big-badda-bum (been +// there, done that...). The big-badda-bum could happen *even +// if you specify the clobbered register in your asm's*. +// Even better, use gcc asm syntax for detecting the register +// asigned to a certain variable so you don't have to clobber any +// register directly. +// + +ACE_INLINE void +ACE_CDR::swap_2 (const char *orig, char* target) +{ +#if defined (ACE_HAS_INTRINSIC_BYTESWAP) + // Take advantage of MSVC++ compiler intrinsic byte swapping + // function. + *reinterpret_cast (target) = + _byteswap_ushort (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BUILTIN_BSWAP16) + *reinterpret_cast (target) = + __builtin_bswap16 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP16) + *reinterpret_cast (target) = + bswap16 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP_16) + *reinterpret_cast (target) = + bswap_16 (*reinterpret_cast (orig)); +#elif defined(ACE_HAS_INTEL_ASSEMBLY) + unsigned short a = + *reinterpret_cast (orig); + asm( "rolw $8, %0" : "=r" (a) : "0" (a) ); + *reinterpret_cast (target) = a; +#elif defined (ACE_HAS_PENTIUM) \ + && (defined(_MSC_VER) || defined(__BORLANDC__)) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + __asm mov ebx, orig; + __asm mov ecx, target; + __asm mov ax, [ebx]; + __asm rol ax, 8; + __asm mov [ecx], ax; +#else + ACE_UINT16 usrc = * reinterpret_cast (orig); + ACE_UINT16* udst = reinterpret_cast (target); + *udst = (usrc << 8) | (usrc >> 8); +#endif /* ACE_HAS_PENTIUM */ +} + +ACE_INLINE void +ACE_CDR::swap_4 (const char* orig, char* target) +{ +#if defined (ACE_HAS_INTRINSIC_BYTESWAP) + // Take advantage of MSVC++ compiler intrinsic byte swapping + // function. + *reinterpret_cast (target) = + _byteswap_ulong (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BUILTIN_BSWAP32) + *reinterpret_cast (target) = + __builtin_bswap32 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP32) + *reinterpret_cast (target) = + bswap32 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP_32) + *reinterpret_cast (target) = + bswap_32 (*reinterpret_cast (orig)); +#elif defined(ACE_HAS_INTEL_ASSEMBLY) + // We have ACE_HAS_PENTIUM, so we know the sizeof's. + unsigned int j = + *reinterpret_cast (orig); + asm ("bswap %1" : "=r" (j) : "0" (j)); + *reinterpret_cast (target) = j; +#elif defined(ACE_HAS_PENTIUM) \ + && (defined(_MSC_VER) || defined(__BORLANDC__)) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + __asm mov ebx, orig; + __asm mov ecx, target; + __asm mov eax, [ebx]; + __asm bswap eax; + __asm mov [ecx], eax; +#else + ACE_UINT32 x = * reinterpret_cast (orig); + x = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24); + * reinterpret_cast (target) = x; +#endif /* ACE_HAS_INTRINSIC_BYTESWAP */ +} + +ACE_INLINE void +ACE_CDR::swap_8 (const char* orig, char* target) +{ +#if defined (ACE_HAS_INTRINSIC_BYTESWAP) + // Take advantage of MSVC++ compiler intrinsic byte swapping + // function. + *reinterpret_cast (target) = + _byteswap_uint64 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BUILTIN_BSWAP64) + *reinterpret_cast (target) = + __builtin_bswap64 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP64) + *reinterpret_cast (target) = + bswap64 (*reinterpret_cast (orig)); +#elif defined (ACE_HAS_BSWAP_64) + *reinterpret_cast (target) = + bswap_64 (*reinterpret_cast (orig)); +#elif (defined (__amd64__) || defined (__x86_64__)) && defined(__GNUG__) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + unsigned long x = + * reinterpret_cast (orig); + asm ("bswapq %1" : "=r" (x) : "0" (x)); + *reinterpret_cast (target) = x; +#elif defined(ACE_HAS_PENTIUM) && defined(__GNUG__) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + unsigned int i =*reinterpret_cast (orig); + unsigned int j = *reinterpret_cast (orig + 4); + asm ("bswap %1" : "=r" (i) : "0" (i)); + asm ("bswap %1" : "=r" (j) : "0" (j)); + *reinterpret_cast (target + 4) = i; + *reinterpret_cast (target) = j; +#elif defined(ACE_HAS_PENTIUM) \ + && (defined(_MSC_VER) || defined(__BORLANDC__)) \ + && !defined(ACE_LACKS_INLINE_ASSEMBLY) + __asm mov ecx, orig; + __asm mov edx, target; + __asm mov eax, [ecx]; + __asm mov ebx, 4[ecx]; + __asm bswap eax; + __asm bswap ebx; + __asm mov 4[edx], eax; + __asm mov [edx], ebx; +#elif ACE_SIZEOF_LONG == 8 + // 64 bit architecture. + unsigned long x = * reinterpret_cast (orig); + unsigned long x84 = (x & 0x000000ff000000ffUL) << 24; + unsigned long x73 = (x & 0x0000ff000000ff00UL) << 8; + unsigned long x62 = (x & 0x00ff000000ff0000UL) >> 8; + unsigned long x51 = (x & 0xff000000ff000000UL) >> 24; + x = (x84 | x73 | x62 | x51); + x = (x << 32) | (x >> 32); + *reinterpret_cast (target) = x; +#else + ACE_UINT32 x = * reinterpret_cast (orig); + ACE_UINT32 y = * reinterpret_cast (orig + 4); + x = (x << 24) | ((x & 0xff00) << 8) | ((x & 0xff0000) >> 8) | (x >> 24); + y = (y << 24) | ((y & 0xff00) << 8) | ((y & 0xff0000) >> 8) | (y >> 24); + * reinterpret_cast (target) = y; + * reinterpret_cast (target + 4) = x; +#endif /* ACE_HAS_INTRINSIC_BYTESWAP */ +} + +ACE_INLINE void +ACE_CDR::swap_16 (const char* orig, char* target) +{ + swap_8 (orig + 8, target); + swap_8 (orig, target + 8); +} + +ACE_INLINE size_t +ACE_CDR::first_size (size_t minsize) +{ + if (minsize == 0) + return ACE_CDR::DEFAULT_BUFSIZE; + + size_t newsize = ACE_CDR::DEFAULT_BUFSIZE; + while (newsize < minsize) + { + if (newsize < ACE_CDR::EXP_GROWTH_MAX) + { + // We grow exponentially at the beginning, this is fast and + // reduces the number of allocations. + + // Quickly multiply by two using a bit shift. This is + // guaranteed to work since the variable is an unsigned + // integer. + newsize <<= 1; + } + else + { + // but continuing with exponential growth can result in over + // allocations and easily yield an allocation failure. + // So we grow linearly when the buffer is too big. + newsize += ACE_CDR::LINEAR_GROWTH_CHUNK; + } + } + return newsize; +} + +ACE_INLINE size_t +ACE_CDR::next_size (size_t minsize) +{ + size_t newsize = ACE_CDR::first_size (minsize); + + if (newsize == minsize) + { + // If necessary increment the size + if (newsize < ACE_CDR::EXP_GROWTH_MAX) + // Quickly multiply by two using a bit shift. This is + // guaranteed to work since the variable is an unsigned + // integer. + newsize <<= 1; + else + newsize += ACE_CDR::LINEAR_GROWTH_CHUNK; + } + + return newsize; +} + +ACE_INLINE ACE_CDR::UShort +ACE_CDR::Fixed::fixed_digits () const +{ + return this->digits_; +} + +ACE_INLINE ACE_CDR::UShort +ACE_CDR::Fixed::fixed_scale () const +{ + return this->scale_; +} + +ACE_INLINE bool +ACE_CDR::Fixed::sign () const +{ + return (this->value_[15] & 0xf) == NEGATIVE; +} + +ACE_INLINE ACE_CDR::Octet +ACE_CDR::Fixed::digit (int n) const +{ + const Octet x = this->value_[15 - (n + 1) / 2]; + return (n % 2) ? x & 0xf : (x >> 4); +} + +ACE_INLINE void +ACE_CDR::Fixed::digit (int n, int val) +{ + const int idx = 15 - (n + 1) / 2; + this->value_[idx] = (n % 2) ? (this->value_[idx] & 0xf0) | val + : ((val << 4) | (this->value_[idx] & 0xf)); +} + +ACE_INLINE +ACE_CDR::Fixed::Proxy::Proxy (bool high_nibble, Octet &element) + : high_nibble_ (high_nibble), element_ (element) {} + +ACE_INLINE ACE_CDR::Fixed::Proxy & +ACE_CDR::Fixed::Proxy::operator= (Octet val) +{ + this->element_ = this->high_nibble_ + ? (val << 4) | (this->element_ & 0xf) + : ((this->element_ & 0xf0) | val); + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::Proxy & +ACE_CDR::Fixed::Proxy::operator+= (int rhs) +{ + const Octet val = static_cast (*this + rhs); + return *this = val; +} + +ACE_INLINE ACE_CDR::Fixed::Proxy & +ACE_CDR::Fixed::Proxy::operator-= (int rhs) +{ + const Octet val = static_cast (*this - rhs); + return *this = val; +} + +ACE_INLINE ACE_CDR::Fixed::Proxy & +ACE_CDR::Fixed::Proxy::operator++ () +{ + const Octet val = static_cast (*this) + 1; + return *this = val; +} + +ACE_INLINE ACE_CDR::Fixed::Proxy & +ACE_CDR::Fixed::Proxy::operator-- () +{ + const Octet val = static_cast(*this) - 1; + return *this = val; +} + +ACE_INLINE +ACE_CDR::Fixed::Proxy::operator ACE_CDR::Octet () const +{ + return this->high_nibble_ ? this->element_ >> 4 : (this->element_ & 0xf); +} + +ACE_INLINE +ACE_CDR::Fixed::IteratorBase::IteratorBase (int digit) + : digit_ (digit) {} + +ACE_INLINE bool +ACE_CDR::Fixed::IteratorBase::high_nibble () const +{ + return this->digit_ % 2 == 0; +} + +ACE_INLINE ACE_CDR::Octet & +ACE_CDR::Fixed::IteratorBase::storage (Fixed *outer) const +{ + return outer->value_[15 - (this->digit_ + 1) / 2]; +} + +ACE_INLINE ACE_CDR::Octet +ACE_CDR::Fixed::IteratorBase::storage (const Fixed *outer) const +{ + return outer->value_[15 - (this->digit_ + 1) / 2]; +} + +ACE_INLINE bool +ACE_CDR::Fixed::IteratorBase::compare (const IteratorBase &rhs) const +{ + return this->digit_ == rhs.digit_; +} + +ACE_INLINE +ACE_CDR::Fixed::Iterator::Iterator (Fixed *outer, int digit) + : IteratorBase (digit), outer_ (outer) {} + +ACE_INLINE ACE_CDR::Fixed::Proxy +ACE_CDR::Fixed::Iterator::operator* () +{ + return Proxy (this->high_nibble (), this->storage (this->outer_)); +} + +ACE_INLINE ACE_CDR::Fixed::Iterator & +ACE_CDR::Fixed::Iterator::operator+= (std::ptrdiff_t n) +{ + this->digit_ += static_cast (n); + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::Iterator & +ACE_CDR::Fixed::Iterator::operator++ () +{ + ++this->digit_; + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::Iterator +ACE_CDR::Fixed::Iterator::operator++ (int) +{ + const Iterator cpy (*this); + ++this->digit_; + return cpy; +} + +ACE_INLINE ACE_CDR::Fixed::Iterator & +ACE_CDR::Fixed::Iterator::operator-- () +{ + --this->digit_; + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::Iterator +ACE_CDR::Fixed::Iterator::operator-- (int) +{ + const Iterator cpy (*this); + --this->digit_; + return cpy; +} + +ACE_INLINE bool +ACE_CDR::Fixed::Iterator::operator== (const Iterator &rhs) const +{ + return this->compare (rhs); +} + +ACE_INLINE bool +ACE_CDR::Fixed::Iterator::operator!= (const Iterator &rhs) const +{ + return !(*this == rhs); +} + +ACE_INLINE +ACE_CDR::Fixed::ConstIterator::ConstIterator (const Fixed *outer, int digit) + : IteratorBase (digit), outer_ (outer) {} + +ACE_INLINE ACE_CDR::Octet +ACE_CDR::Fixed::ConstIterator::operator* () +{ + const Octet storage = this->storage (this->outer_); + return this->high_nibble () ? storage >> 4 : (storage & 0xf); +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator & +ACE_CDR::Fixed::ConstIterator::operator+= (std::ptrdiff_t n) +{ + this->digit_ += static_cast (n); + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator & +ACE_CDR::Fixed::ConstIterator::operator++ () +{ + ++this->digit_; + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::ConstIterator::operator++ (int) +{ + const ConstIterator cpy (*this); + ++this->digit_; + return cpy; +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator & +ACE_CDR::Fixed::ConstIterator::operator-- () +{ + --this->digit_; + return *this; +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::ConstIterator::operator-- (int) +{ + const ConstIterator cpy (*this); + --this->digit_; + return cpy; +} + +ACE_INLINE bool +ACE_CDR::Fixed::ConstIterator::operator== (const ConstIterator &rhs) const +{ + return this->compare (rhs); +} + +ACE_INLINE bool +ACE_CDR::Fixed::ConstIterator::operator!= (const ConstIterator &rhs) const +{ + return !(*this == rhs); +} + +ACE_INLINE ACE_CDR::Fixed::Iterator +ACE_CDR::Fixed::begin () +{ + return Iterator (this); +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::begin () const +{ + return ConstIterator (this); +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::cbegin () const +{ + return ConstIterator (this); +} + +ACE_INLINE ACE_CDR::Fixed::Iterator +ACE_CDR::Fixed::end () +{ + return Iterator (this, this->digits_); +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::end () const +{ + return ConstIterator (this, this->digits_); +} + +ACE_INLINE ACE_CDR::Fixed::ConstIterator +ACE_CDR::Fixed::cend () const +{ + return ConstIterator (this, this->digits_); +} + +ACE_INLINE ACE_CDR::Fixed +ACE_CDR::Fixed::operator++ (int) +{ + const Fixed cpy (*this); + ++*this; + return cpy; +} + +ACE_INLINE ACE_CDR::Fixed +ACE_CDR::Fixed::operator-- (int) +{ + const Fixed cpy (*this); + --*this; + return cpy; +} + +ACE_INLINE ACE_CDR::Fixed +ACE_CDR::Fixed::operator+ () const +{ + return *this; +} + +ACE_INLINE ACE_CDR::Fixed +ACE_CDR::Fixed::operator- () const +{ + Fixed f = *this; + f.value_[15] = (f.value_[15] & 0xf0) | (f.sign () ? POSITIVE : NEGATIVE); + return f; +} + +ACE_INLINE void +ACE_CDR::Fixed::ltrim () +{ + for (int i = this->digits_ - 1; i >= this->scale_ && i > 0; --i) + if (this->digit (i) == 0) + --this->digits_; + else + break; +} + +ACE_INLINE ACE_CDR::Fixed +operator+ (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + ACE_CDR::Fixed f = lhs; + f += rhs; + return f; +} + +ACE_INLINE ACE_CDR::Fixed +operator- (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + ACE_CDR::Fixed f = lhs; + f -= rhs; + return f; +} + +ACE_INLINE ACE_CDR::Fixed +operator* (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + ACE_CDR::Fixed f = lhs; + f *= rhs; + return f; +} + +ACE_INLINE ACE_CDR::Fixed +operator/ (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + ACE_CDR::Fixed f = lhs; + f /= rhs; + return f; +} + +ACE_INLINE bool +operator< (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return lhs.less (rhs); +} + +ACE_INLINE bool +operator> (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return rhs < lhs; +} + +ACE_INLINE bool +operator>= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return !(lhs < rhs); +} + +ACE_INLINE bool +operator<= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return !(rhs < lhs); +} + +ACE_INLINE bool +operator== (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return lhs.equal (rhs); +} + +ACE_INLINE bool +operator!= (const ACE_CDR::Fixed &lhs, const ACE_CDR::Fixed &rhs) +{ + return !(lhs == rhs); +} + + +ACE_END_VERSIONED_NAMESPACE_DECL + +// **************************************************************** diff --git a/dep/acelite/ace/CDR_Size.cpp b/dep/acelite/ace/CDR_Size.cpp new file mode 100644 index 000000000..4263532eb --- /dev/null +++ b/dep/acelite/ace/CDR_Size.cpp @@ -0,0 +1,258 @@ +#include "ace/CDR_Size.h" +#include "ace/SString.h" +#include "ace/OS_Memory.h" +#include "ace/Truncate.h" + +#if !defined (__ACE_INLINE__) +# include "ace/CDR_Size.inl" +#endif /* ! __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_CDR::Boolean +ACE_SizeCDR::write_wchar (ACE_CDR::WChar x) +{ + // Note: translator framework is not supported. + // + if (ACE_OutputCDR::wchar_maxbytes () == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + if (static_cast (major_version_) == 1 + && static_cast (minor_version_) == 2) + { + ACE_CDR::Octet len = + static_cast (ACE_OutputCDR::wchar_maxbytes ()); + + if (this->write_1 (&len)) + { + if (ACE_OutputCDR::wchar_maxbytes () == sizeof(ACE_CDR::WChar)) + { + return + this->write_octet_array ( + reinterpret_cast (&x), + static_cast (len)); + } + else + { + if (ACE_OutputCDR::wchar_maxbytes () == 2) + { + ACE_CDR::Short sx = static_cast (x); + return + this->write_octet_array ( + reinterpret_cast (&sx), + static_cast (len)); + } + else + { + ACE_CDR::Octet ox = static_cast (x); + return + this->write_octet_array ( + reinterpret_cast (&ox), + static_cast (len)); + } + } + } + } + else if (static_cast (minor_version_) == 0) + { // wchar is not allowed with GIOP 1.0. + errno = EINVAL; + return (this->good_bit_ = false); + } + + if (ACE_OutputCDR::wchar_maxbytes () == sizeof (ACE_CDR::WChar)) + { + const void *temp = &x; + return this->write_4 (reinterpret_cast (temp)); + } + else if (ACE_OutputCDR::wchar_maxbytes () == 2) + { + ACE_CDR::Short sx = static_cast (x); + return this->write_2 (reinterpret_cast (&sx)); + } + + ACE_CDR::Octet ox = static_cast (x); + return this->write_1 (reinterpret_cast (&ox)); +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_string (ACE_CDR::ULong len, + const ACE_CDR::Char *x) +{ + // Note: translator framework is not supported. + // + if (len != 0) + { + if (this->write_ulong (len + 1)) + return this->write_char_array (x, len + 1); + } + else + { + // Be nice to programmers: treat nulls as empty strings not + // errors. (OMG-IDL supports languages that don't use the C/C++ + // notion of null v. empty strings; nulls aren't part of the OMG-IDL + // string model.) + if (this->write_ulong (1)) + return this->write_char (0); + } + + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_string (const ACE_CString &x) +{ + // @@ Leave this method in here, not the `.i' file so that we don't + // have to unnecessarily pull in the `ace/SString.h' header. + return this->write_string (static_cast (x.length ()), + x.c_str()); +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_wstring (ACE_CDR::ULong len, + const ACE_CDR::WChar *x) +{ + // Note: translator framework is not supported. + // + if (ACE_OutputCDR::wchar_maxbytes () == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + if (static_cast (this->major_version_) == 1 + && static_cast (this->minor_version_) == 2) + { + if (x != 0) + { + //In GIOP 1.2 the length field contains the number of bytes + //the wstring occupies rather than number of wchars + //Taking sizeof might not be a good way! This is a temporary fix. + ACE_CDR::Boolean good_ulong = + this->write_ulong ( + ACE_Utils::truncate_cast ( + ACE_OutputCDR::wchar_maxbytes () * len)); + + if (good_ulong) + { + return this->write_wchar_array (x, len); + } + } + else + { + //In GIOP 1.2 zero length wstrings are legal + return this->write_ulong (0); + } + } + + else + if (x != 0) + { + if (this->write_ulong (len + 1)) + return this->write_wchar_array (x, len + 1); + } + else if (this->write_ulong (1)) + return this->write_wchar (0); + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_1 (const ACE_CDR::Octet *) +{ + this->adjust (1); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_2 (const ACE_CDR::UShort *) +{ + this->adjust (ACE_CDR::SHORT_SIZE); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_4 (const ACE_CDR::ULong *) +{ + this->adjust (ACE_CDR::LONG_SIZE); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_8 (const ACE_CDR::ULongLong *) +{ + this->adjust (ACE_CDR::LONGLONG_SIZE); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_16 (const ACE_CDR::LongDouble *) +{ + this->adjust (ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_wchar_array_i (const ACE_CDR::WChar *, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + + size_t const align = (ACE_OutputCDR::wchar_maxbytes () == 2) ? + ACE_CDR::SHORT_ALIGN : + ACE_CDR::OCTET_ALIGN; + + this->adjust (ACE_OutputCDR::wchar_maxbytes () * length, align); + return true; +} + + +ACE_CDR::Boolean +ACE_SizeCDR::write_array (const void *, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + + this->adjust (size * length, align); + return true; +} + +ACE_CDR::Boolean +ACE_SizeCDR::write_boolean_array (const ACE_CDR::Boolean*, + ACE_CDR::ULong length) +{ + this->adjust (length, 1); + return true; +} + +void +ACE_SizeCDR::adjust (size_t size) +{ + adjust (size, size); +} + +void +ACE_SizeCDR::adjust (size_t size, + size_t align) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + const size_t offset = ACE_align_binary (size_, align) - size_; + size_ += offset; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + size_ += size; +} + +ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const ACE_CString &x) +{ + ss.write_string (x); + return ss.good_bit (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CDR_Size.h b/dep/acelite/ace/CDR_Size.h new file mode 100644 index 000000000..a791b89bd --- /dev/null +++ b/dep/acelite/ace/CDR_Size.h @@ -0,0 +1,244 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file CDR_Size.h + * + * ACE Common Data Representation (CDR) size-calculating stream. + * + * The current implementation assumes that the host has 1-byte, + * 2-byte and 4-byte integral types, and that it has single + * precision and double precision IEEE floats. + * Those assumptions are pretty good these days, with Crays being + * the only known exception. + * + * @author Boris Kolpackov + */ +//============================================================================= + +#ifndef ACE_CDR_SIZE_H +#define ACE_CDR_SIZE_H + +#include /**/ "ace/pre.h" + +#include "ace/CDR_Base.h" +#include "ace/CDR_Stream.h" // for ACE_OutputCDR::from_* + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SStringfwd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_SizeCDR + * + * @brief A CDR stream for calculating size of the representation. + */ +class ACE_Export ACE_SizeCDR +{ +public: + /// Default constructor. + ACE_SizeCDR (ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Returns @c false if an error has occurred. + bool good_bit (void) const; + + /// Reset current size. + void reset (void); + + /// Return current size. + size_t total_length (void) const; + + // Return 0 on failure and 1 on success. + //@{ @name Size-calculating pseudo-write operations + ACE_CDR::Boolean write_boolean (ACE_CDR::Boolean x); + ACE_CDR::Boolean write_char (ACE_CDR::Char x); + ACE_CDR::Boolean write_wchar (ACE_CDR::WChar x); + ACE_CDR::Boolean write_octet (ACE_CDR::Octet x); + ACE_CDR::Boolean write_short (ACE_CDR::Short x); + ACE_CDR::Boolean write_ushort (ACE_CDR::UShort x); + ACE_CDR::Boolean write_long (ACE_CDR::Long x); + ACE_CDR::Boolean write_ulong (ACE_CDR::ULong x); + ACE_CDR::Boolean write_longlong (const ACE_CDR::LongLong &x); + ACE_CDR::Boolean write_ulonglong (const ACE_CDR::ULongLong &x); + ACE_CDR::Boolean write_float (ACE_CDR::Float x); + ACE_CDR::Boolean write_double (const ACE_CDR::Double &x); + ACE_CDR::Boolean write_longdouble (const ACE_CDR::LongDouble &x); + ACE_CDR::Boolean write_fixed (const ACE_CDR::Fixed &x); + + /// For string we offer methods that accept a precomputed length. + ACE_CDR::Boolean write_string (const ACE_CDR::Char *x); + ACE_CDR::Boolean write_string (ACE_CDR::ULong len, + const ACE_CDR::Char *x); + ACE_CDR::Boolean write_string (const ACE_CString &x); + ACE_CDR::Boolean write_wstring (const ACE_CDR::WChar *x); + ACE_CDR::Boolean write_wstring (ACE_CDR::ULong length, + const ACE_CDR::WChar *x); + ACE_CDR::Boolean write_string (const std::string &x); +#if !defined(ACE_LACKS_STD_WSTRING) + ACE_CDR::Boolean write_wstring (const std::wstring &x); +#endif + //@} + + /// @note the portion written starts at and ends + /// at . + /// The length is *NOT* stored into the CDR stream. + //@{ @name Array write operations + ACE_CDR::Boolean write_boolean_array (const ACE_CDR::Boolean *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_char_array (const ACE_CDR::Char *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_wchar_array (const ACE_CDR::WChar* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_octet_array (const ACE_CDR::Octet* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_short_array (const ACE_CDR::Short *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ushort_array (const ACE_CDR::UShort *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_long_array (const ACE_CDR::Long *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ulong_array (const ACE_CDR::ULong *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_longlong_array (const ACE_CDR::LongLong* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ulonglong_array (const ACE_CDR::ULongLong *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_float_array (const ACE_CDR::Float *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_double_array (const ACE_CDR::Double *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_longdouble_array (const ACE_CDR::LongDouble* x, + ACE_CDR::ULong length); + + /// + /// Adjust to @a size and count octets. + void adjust (size_t size); + + /// As above, but now the size and alignment requirements may be + /// different. + void adjust (size_t size, + size_t align); + +private: + /// disallow copying... + ACE_SizeCDR (const ACE_SizeCDR& rhs); + ACE_SizeCDR& operator= (const ACE_SizeCDR& rhs); + + ACE_CDR::Boolean write_1 (const ACE_CDR::Octet *x); + ACE_CDR::Boolean write_2 (const ACE_CDR::UShort *x); + ACE_CDR::Boolean write_4 (const ACE_CDR::ULong *x); + ACE_CDR::Boolean write_8 (const ACE_CDR::ULongLong *x); + ACE_CDR::Boolean write_16 (const ACE_CDR::LongDouble *x); + + /** + * write an array of @a length elements, each of @a size bytes and the + * start aligned at a multiple of . The elements are assumed + * to be packed with the right alignment restrictions. It is mostly + * designed for buffers of the basic types. + * + * This operation uses ; as explained above it is expected + * that using assignment is faster that for one element, + * but for several elements should be more efficient, it + * could be interesting to find the break even point and optimize + * for that case, but that would be too platform dependent. + */ + ACE_CDR::Boolean write_array (const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + + ACE_CDR::Boolean write_wchar_array_i (const ACE_CDR::WChar* x, + ACE_CDR::ULong length); + +private: + /// Set to false when an error ocurrs. + bool good_bit_; + + /// Current size. + size_t size_; + +protected: + /// GIOP version information + ACE_CDR::Octet major_version_; + ACE_CDR::Octet minor_version_; +}; + +// @@ This operator should not be inlined since they force SString.h +// to be included in this header. +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const ACE_CString &x); + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +# include "ace/CDR_Size.inl" +#else /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Not used by CORBA or TAO +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::Char x); + +// CDR size-calculating output operators for primitive types + +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::Short x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::UShort x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::Long x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::ULong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::LongLong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::ULongLong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR& ss, + ACE_CDR::LongDouble x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::Float x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_CDR::Double x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const ACE_CDR::Fixed &x); + +// CDR size-calculating output operator from helper classes + +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_boolean x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_char x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_wchar x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_octet x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_string x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + ACE_OutputCDR::from_wstring x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const ACE_CDR::Char* x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const ACE_CDR::WChar* x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const std::string& x); +#if !defined(ACE_LACKS_STD_WSTRING) +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_SizeCDR &ss, + const std::wstring& x); +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* __ACE_INLINE__ */ + + +#include /**/ "ace/post.h" + +#endif /* ACE_CDR_SIZE_H */ diff --git a/dep/acelite/ace/CDR_Size.inl b/dep/acelite/ace/CDR_Size.inl new file mode 100644 index 000000000..d138b3de1 --- /dev/null +++ b/dep/acelite/ace/CDR_Size.inl @@ -0,0 +1,471 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_SizeCDR::ACE_SizeCDR (ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : good_bit_ (true), + size_ (0), + major_version_ (major_version), + minor_version_ (minor_version) +{ +} + +ACE_INLINE bool +ACE_SizeCDR::good_bit (void) const +{ + return this->good_bit_; +} + +ACE_INLINE void +ACE_SizeCDR::reset (void) +{ + this->size_ = 0; +} + +ACE_INLINE size_t +ACE_SizeCDR::total_length (void) const +{ + return this->size_; +} + + +// Encode the CDR stream. + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_octet (ACE_CDR::Octet x) +{ + return this->write_1 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_boolean (ACE_CDR::Boolean x) +{ + return (ACE_CDR::Boolean) this->write_octet (x ? (ACE_CDR::Octet) 1 : (ACE_CDR::Octet) 0); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_char (ACE_CDR::Char x) +{ + // Note: translator framework is not supported. + // + return this->write_1 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_short (ACE_CDR::Short x) +{ + return this->write_2 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ushort (ACE_CDR::UShort x) +{ + return this->write_2 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_long (ACE_CDR::Long x) +{ + return this->write_4 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ulong (ACE_CDR::ULong x) +{ + return this->write_4 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_longlong (const ACE_CDR::LongLong &x) +{ + return this->write_8 (reinterpret_cast (&x)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ulonglong (const ACE_CDR::ULongLong &x) +{ + const void *temp = &x; + return this->write_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_float (ACE_CDR::Float x) +{ + const void *temp = &x; + return this->write_4 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_double (const ACE_CDR::Double &x) +{ + const void *temp = &x; + return this->write_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_longdouble (const ACE_CDR::LongDouble &x) +{ + const void *temp = &x; + return this->write_16 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_fixed (const ACE_CDR::Fixed &x) +{ + return this->write_array (&x, ACE_CDR::OCTET_SIZE, ACE_CDR::OCTET_ALIGN, + (x.fixed_digits () + 2) / 2); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_string (const ACE_CDR::Char *x) +{ + if (x != 0) + { + const ACE_CDR::ULong len = + static_cast (ACE_OS::strlen (x)); + return this->write_string (len, x); + } + return this->write_string (0, 0); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_wstring (const ACE_CDR::WChar *x) +{ + if (x != 0) + { + ACE_CDR::ULong len = + static_cast (ACE_OS::strlen (x)); + return this->write_wstring (len, x); + } + return this->write_wstring (0, 0); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_string (const std::string &x) +{ + ACE_CDR::ULong len = + static_cast (x.size ()); + return this->write_string (len, + x.empty () ? 0 : x.c_str ()); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_wstring (const std::wstring &x) +{ + ACE_CDR::ULong len = + static_cast (x.size ()); + return this->write_wstring (len, + x.empty () ? 0 : x.c_str ()); +} +#endif + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_char_array (const ACE_CDR::Char *x, + ACE_CDR::ULong length) +{ + // Note: translator framework is not supported. + // + return this->write_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_wchar_array (const ACE_CDR::WChar* x, + ACE_CDR::ULong length) +{ + // Note: translator framework is not supported. + // + if (ACE_OutputCDR::wchar_maxbytes () == 0) + { + errno = EACCES; + return (ACE_CDR::Boolean) (this->good_bit_ = false); + } + if (ACE_OutputCDR::wchar_maxbytes () == sizeof (ACE_CDR::WChar)) + return this->write_array (x, + sizeof (ACE_CDR::WChar), + sizeof (ACE_CDR::WChar) == 2 + ? ACE_CDR::SHORT_ALIGN + : ACE_CDR::LONG_ALIGN, + length); + return this->write_wchar_array_i (x,length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_octet_array (const ACE_CDR::Octet* x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_short_array (const ACE_CDR::Short *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ushort_array (const ACE_CDR::UShort *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_long_array (const ACE_CDR::Long *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ulong_array (const ACE_CDR::ULong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_longlong_array (const ACE_CDR::LongLong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_ulonglong_array (const ACE_CDR::ULongLong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_float_array (const ACE_CDR::Float *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_double_array (const ACE_CDR::Double *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_SizeCDR::write_longdouble_array (const ACE_CDR::LongDouble* x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN, + length); +} + + +// **************************************************************** + + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::Char x) +{ + ss.write_char (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::Short x) +{ + ss.write_short (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::UShort x) +{ + ss.write_ushort (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::Long x) +{ + ss.write_long (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::ULong x) +{ + ss.write_ulong (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::LongLong x) +{ + ss.write_longlong (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::ULongLong x) +{ + ss.write_ulonglong (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::LongDouble x) +{ + ss.write_longdouble (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::Float x) +{ + ss.write_float (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_CDR::Double x) +{ + ss.write_double (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const ACE_CDR::Fixed &x) +{ + ss.write_fixed (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const ACE_CDR::Char *x) +{ + ss.write_string (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const ACE_CDR::WChar *x) +{ + ss.write_wstring (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const std::string& x) +{ + ss.write_string (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, const std::wstring& x) +{ + ss.write_wstring (x); + return (ACE_CDR::Boolean) ss.good_bit (); +} +#endif + +// The following use the helper classes +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_boolean x) +{ + ss.write_boolean (x.val_); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_char x) +{ + ss.write_char (x.val_); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_wchar x) +{ + ss.write_wchar (x.val_); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_octet x) +{ + ss.write_octet (x.val_); + return (ACE_CDR::Boolean) ss.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_string x) +{ + ACE_CDR::ULong len = 0; + + if (x.val_ != 0) + { + len = static_cast (ACE_OS::strlen (x.val_)); + } + + ss.write_string (len, x.val_); + return + (ACE_CDR::Boolean) (ss.good_bit () && (!x.bound_ || len <= x.bound_)); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_SizeCDR &ss, ACE_OutputCDR::from_wstring x) +{ + ACE_CDR::ULong len = 0; + + if (x.val_ != 0) + { + len = static_cast (ACE_OS::strlen (x.val_)); + } + + ss.write_wstring (len, x.val_); + return + (ACE_CDR::Boolean) (ss.good_bit () && (!x.bound_ || len <= x.bound_)); +} + + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CDR_Stream.cpp b/dep/acelite/ace/CDR_Stream.cpp new file mode 100644 index 000000000..32654aedd --- /dev/null +++ b/dep/acelite/ace/CDR_Stream.cpp @@ -0,0 +1,2452 @@ +#include "ace/CDR_Stream.h" +#include "ace/SString.h" +#include "ace/Auto_Ptr.h" +#include "ace/Truncate.h" + +#if !defined (__ACE_INLINE__) +# include "ace/CDR_Stream.inl" +#endif /* ! __ACE_INLINE__ */ + +// **************************************************************** + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +size_t ACE_OutputCDR::wchar_maxbytes_ = sizeof (ACE_CDR::WChar); + +ACE_OutputCDR::ACE_OutputCDR (size_t size, + int byte_order, + ACE_Allocator *buffer_allocator, + ACE_Allocator *data_block_allocator, + ACE_Allocator *message_block_allocator, + size_t memcpy_tradeoff, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ ((size ? size : (size_t) ACE_CDR::DEFAULT_BUFSIZE) + ACE_CDR::MAX_ALIGNMENT, + ACE_Message_Block::MB_DATA, + 0, + 0, + buffer_allocator, + 0, + 0, + ACE_Time_Value::zero, + ACE_Time_Value::max_time, + data_block_allocator, + message_block_allocator), +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + current_alignment_ (0), +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + current_is_writable_ (true), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + memcpy_tradeoff_ (memcpy_tradeoff), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) + +{ + ACE_CDR::mb_align (&this->start_); + this->current_ = &this->start_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->total_length ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_OutputCDR::ACE_OutputCDR (char *data, + size_t size, + int byte_order, + ACE_Allocator *buffer_allocator, + ACE_Allocator *data_block_allocator, + ACE_Allocator *message_block_allocator, + size_t memcpy_tradeoff, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (size, + ACE_Message_Block::MB_DATA, + 0, + data, + buffer_allocator, + 0, + 0, + ACE_Time_Value::zero, + ACE_Time_Value::max_time, + data_block_allocator, + message_block_allocator), +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + current_alignment_ (0), +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + current_is_writable_ (true), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + memcpy_tradeoff_ (memcpy_tradeoff), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ + // We cannot trust the buffer to be properly aligned + ACE_CDR::mb_align (&this->start_); + this->current_ = &this->start_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->total_length ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_OutputCDR::ACE_OutputCDR (ACE_Data_Block *data_block, + int byte_order, + ACE_Allocator *message_block_allocator, + size_t memcpy_tradeoff, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (data_block, + ACE_Message_Block::DONT_DELETE, + message_block_allocator), +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + current_alignment_ (0), +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + current_is_writable_ (true), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + memcpy_tradeoff_ (memcpy_tradeoff), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ + // We cannot trust the buffer to be properly aligned + ACE_CDR::mb_align (&this->start_); + this->current_ = &this->start_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->total_length ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_OutputCDR::ACE_OutputCDR (ACE_Message_Block *data, + int byte_order, + size_t memcpy_tradeoff, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (data->data_block ()->duplicate ()), +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + current_alignment_ (0), +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + current_is_writable_ (true), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + memcpy_tradeoff_ (memcpy_tradeoff), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ + // We cannot trust the buffer to be properly aligned + ACE_CDR::mb_align (&this->start_); + this->current_ = &this->start_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->total_length ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +/*static*/ void +ACE_OutputCDR::wchar_maxbytes (size_t maxbytes) +{ + ACE_OutputCDR::wchar_maxbytes_ = maxbytes; +} + +/*static*/ size_t +ACE_OutputCDR::wchar_maxbytes () +{ + return ACE_OutputCDR::wchar_maxbytes_; +} + +int +ACE_OutputCDR::grow_and_adjust (size_t size, + size_t align, + char*& buf) +{ + if (!this->current_is_writable_ + || this->current_->cont () == 0 + || this->current_->cont ()->size () < size + ACE_CDR::MAX_ALIGNMENT) + { + // Calculate the new buffer's length; if growing for encode, we + // don't grow in "small" chunks because of the cost. + size_t cursize = this->current_->size (); + if (this->current_->cont () != 0) + cursize = this->current_->cont ()->size (); + size_t minsize = size; + +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + minsize += ACE_CDR::MAX_ALIGNMENT; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + // Make sure that there is enough room for bytes, but + // also make it bigger than whatever our current size is. + if (minsize < cursize) + minsize = cursize; + + size_t const newsize = ACE_CDR::next_size (minsize); + + this->good_bit_ = false; + ACE_Message_Block* tmp = 0; + ACE_NEW_RETURN (tmp, + ACE_Message_Block (newsize, + ACE_Message_Block::MB_DATA, + 0, + 0, + this->current_->data_block ()->allocator_strategy (), + 0, + 0, + ACE_Time_Value::zero, + ACE_Time_Value::max_time, + this->current_->data_block ()->data_block_allocator ()), + -1); + + // Message block initialization may fail while the construction + // succeds. Since as a matter of policy, ACE may throw no + // exceptions, we have to do a separate check like this. + if (tmp != 0 && tmp->size () < newsize) + { + delete tmp; + errno = ENOMEM; + return -1; + } + + this->good_bit_ = true; + +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + // The new block must start with the same alignment as the + // previous block finished. + ptrdiff_t const tmpalign = + reinterpret_cast (tmp->rd_ptr ()) % ACE_CDR::MAX_ALIGNMENT; + ptrdiff_t const curalign = + static_cast (this->current_alignment_) % ACE_CDR::MAX_ALIGNMENT; + ptrdiff_t offset = curalign - tmpalign; + if (offset < 0) + offset += ACE_CDR::MAX_ALIGNMENT; + tmp->rd_ptr (static_cast (offset)); + tmp->wr_ptr (tmp->rd_ptr ()); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + // grow the chain and set the current block. + tmp->cont (this->current_->cont ()); + this->current_->cont (tmp); + } + this->current_ = this->current_->cont (); + this->current_is_writable_ = true; + + return this->adjust (size, align, buf); +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_wchar (ACE_CDR::WChar x) +{ + if (this->wchar_translator_ != 0) + return (this->good_bit_ = this->wchar_translator_->write_wchar (*this, x)); + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + if (static_cast (major_version_) == 1 + && static_cast (minor_version_) == 2) + { + ACE_CDR::Octet len = + static_cast (ACE_OutputCDR::wchar_maxbytes_); + if (this->write_1 (&len)) + { + if (ACE_OutputCDR::wchar_maxbytes_ == sizeof(ACE_CDR::WChar)) + return + this->write_octet_array ( + reinterpret_cast (&x), + static_cast (len)); + else + if (ACE_OutputCDR::wchar_maxbytes_ == 2) + { + ACE_CDR::Short sx = static_cast (x); + return + this->write_octet_array ( + reinterpret_cast (&sx), + static_cast (len)); + } + else + { + ACE_CDR::Octet ox = static_cast (x); + return + this->write_octet_array ( + reinterpret_cast (&ox), + static_cast (len)); + } + } + } + else if (static_cast (minor_version_) == 0) + { // wchar is not allowed with GIOP 1.0. + errno = EINVAL; + return (this->good_bit_ = false); + } + if (ACE_OutputCDR::wchar_maxbytes_ == sizeof (ACE_CDR::WChar)) + { + void const * const temp = &x; + return + this->write_4 (reinterpret_cast (temp)); + } + else if (ACE_OutputCDR::wchar_maxbytes_ == 2) + { + ACE_CDR::Short sx = static_cast (x); + return this->write_2 (reinterpret_cast (&sx)); + } + ACE_CDR::Octet ox = static_cast (x); + return this->write_1 (reinterpret_cast (&ox)); +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_string (ACE_CDR::ULong len, + const ACE_CDR::Char *x) +{ + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + if (this->char_translator_ != 0) + return this->char_translator_->write_string (*this, len, x); + + if (len != 0) + { + if (this->write_ulong (len + 1)) + return this->write_char_array (x, len + 1); + } + else + { + // Be nice to programmers: treat nulls as empty strings not + // errors. (OMG-IDL supports languages that don't use the C/C++ + // notion of null v. empty strings; nulls aren't part of the OMG-IDL + // string model.) + if (this->write_ulong (1)) + return this->write_char (0); + } + + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_string (const ACE_CString &x) +{ + // @@ Leave this method in here, not the `.i' file so that we don't + // have to unnecessarily pull in the `ace/SString.h' header. + return this->write_string (static_cast (x.length ()), + x.c_str()); +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_wstring (ACE_CDR::ULong len, + const ACE_CDR::WChar *x) +{ + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + // What do we do for GIOP 1.2??? + if (this->wchar_translator_ != 0) + return this->wchar_translator_->write_wstring (*this, len, x); + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + if (static_cast (this->major_version_) == 1 + && static_cast (this->minor_version_) == 2) + { + if (x != 0) + { + //In GIOP 1.2 the length field contains the number of bytes + //the wstring occupies rather than number of wchars + //Taking sizeof might not be a good way! This is a temporary fix. + ACE_CDR::Boolean good_ulong = + this->write_ulong ( + ACE_Utils::truncate_cast ( + ACE_OutputCDR::wchar_maxbytes_ * len)); + + if (good_ulong) + { + return this->write_wchar_array (x, len); + } + } + else + { + //In GIOP 1.2 zero length wstrings are legal + return this->write_ulong (0); + } + } + + else + if (x != 0) + { + if (this->write_ulong (len + 1)) + return this->write_wchar_array (x, len + 1); + } + else if (this->write_ulong (1)) + return this->write_wchar (0); + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_octet_array_mb (const ACE_Message_Block* mb) +{ + // If the buffer is small and it fits in the current message + // block it is be cheaper just to copy the buffer. + for (const ACE_Message_Block* i = mb; + i != 0; + i = i->cont ()) + { + size_t const length = i->length (); + + // If the mb does not own its data we are forced to make a copy. + if (ACE_BIT_ENABLED (i->flags (), + ACE_Message_Block::DONT_DELETE)) + { + if (! this->write_array (i->rd_ptr (), + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + static_cast (length))) + return (this->good_bit_ = false); + continue; + } + + if (length < this->memcpy_tradeoff_ + && this->current_->wr_ptr () + length < this->current_->end ()) + { + if (! this->write_array (i->rd_ptr (), + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + static_cast (length))) + return (this->good_bit_ = false); + continue; + } + + ACE_Message_Block* cont = 0; + this->good_bit_ = false; + ACE_NEW_RETURN (cont, + ACE_Message_Block (i->data_block ()->duplicate ()), + false); + this->good_bit_ = true; + + if (this->current_->cont () != 0) + ACE_Message_Block::release (this->current_->cont ()); + cont->rd_ptr (i->rd_ptr ()); + cont->wr_ptr (i->wr_ptr ()); + + this->current_->cont (cont); + this->current_ = cont; + this->current_is_writable_ = false; +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + this->current_alignment_ = + (this->current_alignment_ + cont->length ()) % ACE_CDR::MAX_ALIGNMENT; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + } + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_1 (const ACE_CDR::Octet *x) +{ + char *buf = 0; + if (this->adjust (1, buf) == 0) + { + *reinterpret_cast (buf) = *x; + return true; + } + + return false; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_2 (const ACE_CDR::UShort *x) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::SHORT_SIZE, buf) == 0) + { +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (buf) = *x; + return true; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (buf) = *x; + return true; + } + else + { + ACE_CDR::swap_2 (reinterpret_cast (x), buf); + return true; + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + + return false; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_4 (const ACE_CDR::ULong *x) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONG_SIZE, buf) == 0) + { +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (buf) = *x; + return true; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (buf) = *x; + return true; + } + else + { + ACE_CDR::swap_4 (reinterpret_cast (x), buf); + return true; + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + + return false; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_8 (const ACE_CDR::ULongLong *x) +{ + char *buf = 0; + + if (this->adjust (ACE_CDR::LONGLONG_SIZE, buf) == 0) + { +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (buf) = *x; + return true; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (buf) = *x; + return true; + } + else + { + ACE_CDR::swap_8 (reinterpret_cast (x), buf); + return true; + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + + return false; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_16 (const ACE_CDR::LongDouble *x) +{ + char* buf = 0; + if (this->adjust (ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN, + buf) == 0) + { +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (buf) = *x; + return 1; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (buf) = *x; + return true; + } + else + { + ACE_CDR::swap_16 (reinterpret_cast (x), buf); + return true; + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + + return false; +} + +ACE_CDR::Boolean +ACE_OutputCDR::write_wchar_array_i (const ACE_CDR::WChar *x, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + char* buf = 0; + size_t const align = (ACE_OutputCDR::wchar_maxbytes_ == 2) ? + ACE_CDR::SHORT_ALIGN : + ACE_CDR::OCTET_ALIGN; + + if (this->adjust (ACE_OutputCDR::wchar_maxbytes_ * length, align, buf) == 0) + { + if (ACE_OutputCDR::wchar_maxbytes_ == 2) + { + ACE_CDR::UShort *sb = reinterpret_cast (buf); + for (size_t i = 0; i < length; ++i) +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + sb[i] = static_cast (x[i]); +#else + if (!this->do_byte_swap_) + sb[i] = static_cast (x[i]); + else + { + ACE_CDR::UShort sx = static_cast (x[i]); + ACE_CDR::swap_2 (reinterpret_cast (&sx), &buf[i * 2]); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + else + { + for (size_t i = 0; i < length; ++i) + buf[i] = static_cast (x[i]); + } + return this->good_bit_; + } + return false; +} + + +ACE_CDR::Boolean +ACE_OutputCDR::write_array (const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + char *buf = 0; + if (this->adjust (size * length, align, buf) == 0) + { +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + ACE_OS::memcpy (buf, x, size*length); + return true; +#else + if (!this->do_byte_swap_ || size == 1) + { + ACE_OS::memcpy (buf, x, size*length); + return true; + } + else + { + const char *source = reinterpret_cast (x); + switch (size) + { + case 2: + ACE_CDR::swap_2_array (source, buf, length); + return true; + case 4: + ACE_CDR::swap_4_array (source, buf, length); + return true; + case 8: + ACE_CDR::swap_8_array (source, buf, length); + return true; + case 16: + ACE_CDR::swap_16_array (source, buf, length); + return true; + default: + // TODO: print something? + this->good_bit_ = false; + return false; + } + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + } + this->good_bit_ = false; + return false; +} + + +ACE_CDR::Boolean +ACE_OutputCDR::write_boolean_array (const ACE_CDR::Boolean* x, + ACE_CDR::ULong length) +{ + // It is hard to optimize this, the spec requires that on the wire + // booleans be represented as a byte with value 0 or 1, but in + // memory it is possible (though very unlikely) that a boolean has + // a non-zero value (different from 1). + // We resort to a simple loop. + ACE_CDR::Boolean const * const end = x + length; + + for (ACE_CDR::Boolean const * i = x; + i != end && this->good_bit (); + ++i) + (void) this->write_boolean (*i); + + return this->good_bit (); +} + +char * +ACE_OutputCDR::write_long_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONG_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_short_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::SHORT_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_boolean_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::OCTET_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_char_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::OCTET_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_octet_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::OCTET_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_longlong_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONGLONG_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_float_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONG_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +char * +ACE_OutputCDR::write_double_placeholder (void) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONGLONG_SIZE, buf) == 0) + *reinterpret_cast (buf) = 0; + else + buf = 0; + return buf; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Long x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_4 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::ULong x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_4 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Short x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_2 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::UShort x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_2 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Boolean x, char* loc) +{ + if (this->find (loc) == 0) + return false; + + *reinterpret_cast (loc) = x; + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Char x, char* loc) +{ + if (this->find (loc) == 0) + return false; + + *reinterpret_cast (loc) = x; + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Octet x, char* loc) +{ + if (this->find (loc) == 0) + return false; + + *reinterpret_cast (loc) = x; + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::LongLong x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_8 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::ULongLong x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_8 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Float x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_4 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +ACE_CDR::Boolean +ACE_OutputCDR::replace (ACE_CDR::Double x, char* loc) +{ + if (this->find (loc) == 0) + return false; + +#if !defined (ACE_ENABLE_SWAP_ON_WRITE) + *reinterpret_cast (loc) = x; +#else + if (!this->do_byte_swap_) + { + *reinterpret_cast (loc) = x; + } + else + { + ACE_CDR::swap_8 (reinterpret_cast (&x), loc); + } +#endif /* ACE_ENABLE_SWAP_ON_WRITE */ + + return true; +} + +int +ACE_OutputCDR::consolidate (void) +{ + // Optimize by only doing something if we need to + if (this->current_ != &this->start_) + { + // Set the number of bytes in the top-level block, reallocating + // if necessary. The rd_ptr and wr_ptr remain at the original offsets + // into the buffer, even if it is reallocated. + // Return an error if the allocation failed. + size_t const newsize = + ACE_CDR::first_size (this->total_length () + + ACE_CDR::MAX_ALIGNMENT); + if (this->start_.size (newsize) < 0) + { + return -1; + } + + // Consolidate the chain into the first block. NOTE that + // ACE_CDR::consolidate can not be used since we don't want to + // overwrite what is already in the first block. We just append it since + // the read and write pointers weren't affected by the resizing above. + // We also don't have to worry about alignment since the start block is + // already aligned. + // NOTE also we know there is a continuation since we checked for it + // above. There is therefore no reason to check for a 0 continuation + // field here. + ACE_Message_Block *cont = this->start_.cont (); + for (const ACE_Message_Block* i = cont; i != 0; i = i->cont ()) + { + this->start_.copy (i->rd_ptr (), i->length ()); + } + + // Release the old blocks that were consolidated and reset the + // current_ and current_is_writable_ to reflect the single used block. + ACE_Message_Block::release (cont); + this->start_.cont (0); + this->current_ = &this->start_; + this->current_is_writable_ = true; + } + + return 0; +} + + +ACE_Message_Block* +ACE_OutputCDR::find (char* loc) +{ + ACE_Message_Block* mb = 0; + for (mb = &this->start_; mb != 0; mb = mb->cont ()) + { + if (loc <= mb->wr_ptr () && loc >= mb->rd_ptr ()) + { + break; + } + } + + return mb; +} + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + +void +ACE_OutputCDR::register_monitor (const char *id) +{ + this->monitor_->name (id); + this->monitor_->add_to_registry (); +} + +void +ACE_OutputCDR::unregister_monitor (void) +{ + this->monitor_->remove_from_registry (); +} + +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +// **************************************************************** + +ACE_InputCDR::ACE_InputCDR (const char *buf, + size_t bufsiz, + int byte_order, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (buf, bufsiz), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ + this->start_.wr_ptr (bufsiz); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (bufsiz); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (size_t bufsiz, + int byte_order, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (bufsiz), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (bufsiz); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (const ACE_Message_Block *data, + int byte_order, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version, + ACE_Lock* lock) + : start_ (0, ACE_Message_Block::MB_DATA, 0, 0, 0, lock), + good_bit_ (true), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + this->reset (data, byte_order); +} + +ACE_InputCDR::ACE_InputCDR (ACE_Data_Block *data, + ACE_Message_Block::Message_Flags flag, + int byte_order, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (data, flag), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (data->size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (ACE_Data_Block *data, + ACE_Message_Block::Message_Flags flag, + size_t rd_pos, + size_t wr_pos, + int byte_order, + ACE_CDR::Octet major_version, + ACE_CDR::Octet minor_version) + : start_ (data, flag), + do_byte_swap_ (byte_order != ACE_CDR_BYTE_ORDER), + good_bit_ (true), + major_version_ (major_version), + minor_version_ (minor_version), + char_translator_ (0), + wchar_translator_ (0) +{ + // Set the read pointer + this->start_.rd_ptr (rd_pos); + + // Set the write pointer after doing a sanity check. + char* wrpos = this->start_.base () + wr_pos; + + if (this->start_.end () >= wrpos) + { + this->start_.wr_ptr (wr_pos); + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (data->size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (const ACE_InputCDR& rhs, + size_t size, + ACE_CDR::Long offset) + : start_ (rhs.start_, + ACE_CDR::MAX_ALIGNMENT), + do_byte_swap_ (rhs.do_byte_swap_), + good_bit_ (true), + major_version_ (rhs.major_version_), + minor_version_ (rhs.minor_version_), + char_translator_ (rhs.char_translator_), + wchar_translator_ (rhs.wchar_translator_) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + // Align the base pointer assuming that the incoming stream is also + // aligned the way we are aligned + char *incoming_start = ACE_ptr_align_binary (rhs.start_.base (), + ACE_CDR::MAX_ALIGNMENT); +#else + char *incoming_start = rhs.start_.base (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + const size_t newpos = + (rhs.start_.rd_ptr() - incoming_start) + offset; + + if (newpos <= this->start_.space () + && newpos + size <= this->start_.space ()) + { + this->start_.rd_ptr (newpos); + this->start_.wr_ptr (newpos + size); + } + else + { + this->good_bit_ = false; + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (const ACE_InputCDR& rhs, + size_t size) + : start_ (rhs.start_, + ACE_CDR::MAX_ALIGNMENT), + do_byte_swap_ (rhs.do_byte_swap_), + good_bit_ (true), + major_version_ (rhs.major_version_), + minor_version_ (rhs.minor_version_), + char_translator_ (rhs.char_translator_), + wchar_translator_ (rhs.wchar_translator_) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + // Align the base pointer assuming that the incoming stream is also + // aligned the way we are aligned + char *incoming_start = ACE_ptr_align_binary (rhs.start_.base (), + ACE_CDR::MAX_ALIGNMENT); +#else + char *incoming_start = rhs.start_.base (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + const size_t newpos = + rhs.start_.rd_ptr() - incoming_start; + + if (newpos <= this->start_.space () + && newpos + size <= this->start_.space ()) + { + // Notice that ACE_Message_Block::duplicate may leave the + // wr_ptr() with a higher value than what we actually want. + this->start_.rd_ptr (newpos); + this->start_.wr_ptr (newpos + size); + + ACE_CDR::Octet byte_order = 0; + (void) this->read_octet (byte_order); + this->do_byte_swap_ = (byte_order != ACE_CDR_BYTE_ORDER); + } + else + { + this->good_bit_ = false; + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (const ACE_InputCDR& rhs) + : start_ (rhs.start_, + ACE_CDR::MAX_ALIGNMENT), + do_byte_swap_ (rhs.do_byte_swap_), + good_bit_ (true), + major_version_ (rhs.major_version_), + minor_version_ (rhs.minor_version_), + char_translator_ (rhs.char_translator_), + wchar_translator_ (rhs.wchar_translator_) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + char *buf = ACE_ptr_align_binary (rhs.start_.base (), + ACE_CDR::MAX_ALIGNMENT); +#else + char *buf = rhs.start_.base (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + size_t rd_offset = rhs.start_.rd_ptr () - buf; + size_t wr_offset = rhs.start_.wr_ptr () - buf; + this->start_.rd_ptr (rd_offset); + this->start_.wr_ptr (wr_offset); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR::ACE_InputCDR (ACE_InputCDR::Transfer_Contents x) + : start_ (x.rhs_.start_.data_block ()), + do_byte_swap_ (x.rhs_.do_byte_swap_), + good_bit_ (true), + major_version_ (x.rhs_.major_version_), + minor_version_ (x.rhs_.minor_version_), + char_translator_ (x.rhs_.char_translator_), + wchar_translator_ (x.rhs_.wchar_translator_) +{ + this->start_.rd_ptr (x.rhs_.start_.rd_ptr ()); + this->start_.wr_ptr (x.rhs_.start_.wr_ptr ()); + + ACE_Data_Block* db = this->start_.data_block ()->clone_nocopy (); + (void) x.rhs_.start_.replace_data_block (db); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_InputCDR& +ACE_InputCDR::operator= (const ACE_InputCDR& rhs) +{ + if (this != &rhs) + { + this->start_.data_block (rhs.start_.data_block ()->duplicate ()); + this->start_.rd_ptr (rhs.start_.rd_ptr ()); + this->start_.wr_ptr (rhs.start_.wr_ptr ()); + this->do_byte_swap_ = rhs.do_byte_swap_; + this->good_bit_ = true; + this->char_translator_ = rhs.char_translator_; + this->major_version_ = rhs.major_version_; + this->minor_version_ = rhs.minor_version_; + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + return *this; +} + +ACE_InputCDR::ACE_InputCDR (const ACE_OutputCDR& rhs, + ACE_Allocator* buffer_allocator, + ACE_Allocator* data_block_allocator, + ACE_Allocator* message_block_allocator) + : start_ (rhs.total_length () + ACE_CDR::MAX_ALIGNMENT, + ACE_Message_Block::MB_DATA, + 0, + 0, + buffer_allocator, + 0, + 0, + ACE_Time_Value::zero, + ACE_Time_Value::max_time, + data_block_allocator, + message_block_allocator), + do_byte_swap_ (rhs.do_byte_swap_), + good_bit_ (true), + major_version_ (rhs.major_version_), + minor_version_ (rhs.minor_version_), + char_translator_ (rhs.char_translator_), + wchar_translator_ (rhs.wchar_translator_) +{ + ACE_CDR::mb_align (&this->start_); + for (const ACE_Message_Block *i = rhs.begin (); + i != rhs.end (); + i = i->cont ()) + { + this->start_.copy (i->rd_ptr (), i->length ()); + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE_NEW (this->monitor_, + ACE::Monitor_Control::Size_Monitor); + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_CDR::Boolean +ACE_InputCDR::skip_wchar (void) +{ + if (static_cast (major_version_) == 1 + && static_cast (minor_version_) == 2) + { + ACE_CDR::Octet len; + if (this->read_1 (&len)) + return this->skip_bytes (static_cast (len)); + } + else + { + ACE_CDR::WChar x; + void * const temp = &x; + if (ACE_OutputCDR::wchar_maxbytes_ == 2) + return this->read_2 (reinterpret_cast (temp)); + else + return this->read_4 (reinterpret_cast (temp)); + } + + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_InputCDR::read_wchar (ACE_CDR::WChar& x) +{ + if (this->wchar_translator_ != 0) + { + this->good_bit_ = this->wchar_translator_->read_wchar (*this,x); + return this->good_bit_; + } + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + if (ACE_OutputCDR::wchar_maxbytes_ == sizeof (ACE_CDR::WChar)) + { + if (static_cast (major_version_) == 1 + && static_cast (minor_version_) == 2) + { + ACE_CDR::Octet len; + + if (this->read_1 (&len)) + return this->read_array + (reinterpret_cast (&x), + static_cast (len), + ACE_CDR::OCTET_ALIGN, + 1); + + else + return (this->good_bit_ = false); + } + + void * const temp = &x; + if (sizeof (ACE_CDR::WChar) == 2) + return this->read_2 (reinterpret_cast (temp)); + else + return this->read_4 (reinterpret_cast (temp)); + } + + if (static_cast (major_version_) == 1 + && static_cast (minor_version_) == 2) + { + ACE_CDR::Octet len; + + if (this->read_1 (&len)) + { + if (len == 2) + { + ACE_CDR::Short sx; + if (this->read_array + (reinterpret_cast (&sx), + static_cast (len), + ACE_CDR::OCTET_ALIGN, + 1)) + { + x = static_cast (sx); + return true; + } + } + else + { + ACE_CDR::Octet ox; + if (this->read_array + (reinterpret_cast (&ox), + static_cast (len), + ACE_CDR::OCTET_ALIGN, + 1)) + { + x = static_cast (ox); + return true; + } + } + } + } + else + { + if (ACE_OutputCDR::wchar_maxbytes_ == 2) + { + ACE_CDR::UShort sx; + if (this->read_2 (reinterpret_cast (&sx))) + { + x = static_cast (sx); + return true; + } + } + else + { + ACE_CDR::Octet ox; + if (this->read_1 (&ox)) + { + x = static_cast (ox); + return true; + } + + } + } + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_InputCDR::read_string (ACE_CDR::Char *&x) +{ + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + if (this->char_translator_ != 0) + { + this->good_bit_ = this->char_translator_->read_string (*this, x); + return this->good_bit_; + } + + ACE_CDR::ULong len = 0; + + if (!this->read_ulong (len)) + return false; + + // A check for the length being too great is done later in the + // call to read_char_array but we want to have it done before + // the memory is allocated. + if (len > 0 && len <= this->length()) + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (x, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::Char) * (len))), + 0); +#else + ACE_NEW_RETURN (x, + ACE_CDR::Char[len], + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_Auto_Basic_Array_Ptr safe_data (x); + + if (this->read_char_array (x, len)) + { + (void) safe_data.release (); + return true; + } + } + else if (len == 0) + { + // Convert any null strings to empty strings since empty + // strings can cause crashes. (See bug 58.) +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (x, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::Char) * (1))), + 0); +#else + ACE_NEW_RETURN (x, + ACE_CDR::Char[1], + 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_OS::strcpy (const_cast (x), ""); + return true; + } + + x = 0; + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_InputCDR::read_string (ACE_CString &x) +{ + ACE_CDR::Char * data = 0; + if (this->read_string (data)) + { + ACE_Auto_Basic_Array_Ptr safe_data (data); + x = data; + return true; + } + + x = ""; + return (this->good_bit_ = false); +} + +ACE_CDR::Boolean +ACE_InputCDR::read_wstring (ACE_CDR::WChar*& x) +{ + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + if (this->wchar_translator_ != 0) + { + this->good_bit_ = this->wchar_translator_->read_wstring (*this, x); + return this->good_bit_; + } + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + ACE_CDR::ULong len = 0; + + if (!this->read_ulong (len)) + { + return false; + } + + // A check for the length being too great is done later in the + // call to read_char_array but we want to have it done before + // the memory is allocated. + if (len > 0 && len <= this->length ()) + { + ACE_Auto_Basic_Array_Ptr safe_data; + + if (static_cast (this->major_version_) == 1 + && static_cast (this->minor_version_) == 2) + { + len /= + ACE_Utils::truncate_cast ( + ACE_OutputCDR::wchar_maxbytes_); + + //allocating one extra for the null character needed by applications +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (x, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::WChar) * (len + 1))), + 0); +#else + ACE_NEW_RETURN (x, + ACE_CDR::WChar [len + 1], + false); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_auto_ptr_reset (safe_data, x); + + if (this->read_wchar_array (x, len)) + { + + //Null character used by applications to find the end of + //the wstring + //Is this okay with the GIOP 1.2 spec?? + x[len] = '\x00'; + + (void) safe_data.release (); + + return true; + } + } + else + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (x, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::WChar) * (len))), + 0); +#else + ACE_NEW_RETURN (x, + ACE_CDR::WChar [len], + false); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_auto_ptr_reset (safe_data, x); + + if (this->read_wchar_array (x, len)) + { + (void) safe_data.release (); + + return true; + } + } + } + else if (len == 0) + { + // Convert any null strings to empty strings since empty + // strings can cause crashes. (See bug 58.) +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (x, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::WChar) * (1))), + 0); +#else + ACE_NEW_RETURN (x, + ACE_CDR::WChar [1], + false); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + x[0] = '\x00'; + return true; + } + + this->good_bit_ = false; + x = 0; + return false; +} + +// As of C++11 std::string guarantees contiguous memory storage. +// That provides the opportunity to optimize CDR streaming. +ACE_CDR::Boolean +ACE_InputCDR::read_string (std::string& x) +{ +#if defined (ACE_HAS_CPP11) + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + if (this->char_translator_ != 0) + { + this->good_bit_ = this->char_translator_->read_string (*this, x); + return this->good_bit_; + } + + ACE_CDR::ULong len = 0; + + if (!this->read_ulong (len)) + return false; + + // A check for the length being too great is done later in the + // call to read_char_array but we want to have it done before + // the memory is allocated. + if (len > 0 && len <= this->length()) + { + try + { + x.resize (len-1); // no need to include the terminating '\0' here + } + catch (const std::bad_alloc&) + { + return false; + } + + if (len == 0 || this->read_char_array (&x[0], len-1)) + { + return this->skip_char (); // skip the terminating '\0' + } + } + + this->good_bit_ = false; + x.clear (); + return false; +#else + ACE_CDR::Char *buf = 0; + ACE_CDR::Boolean const marshal_flag = this->read_string (buf); + x.assign (buf); + ACE::strdelete (buf); + return marshal_flag; +#endif +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_CDR::Boolean +ACE_InputCDR::read_wstring (std::wstring& x) +{ +#if defined (ACE_HAS_CPP11) + // @@ This is a slight violation of "Optimize for the common case", + // i.e. normally the translator will be 0, but OTOH the code is + // smaller and should be better for the cache ;-) ;-) + if (this->wchar_translator_ != 0) + { + this->good_bit_ = this->wchar_translator_->read_wstring (*this, x); + return this->good_bit_; + } + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (this->good_bit_ = false); + } + + ACE_CDR::ULong len = 0; + + if (!this->read_ulong (len)) + { + return false; + } + + // A check for the length being too great is done later in the + // call to read_char_array but we want to have it done before + // the memory is allocated. + if (len > 0 && len <= this->length ()) + { + if (static_cast (this->major_version_) == 1 + && static_cast (this->minor_version_) == 2) + { + len /= + ACE_Utils::truncate_cast ( + ACE_OutputCDR::wchar_maxbytes_); + + try + { + x.resize (len); + } + catch (const std::bad_alloc&) + { + return false; + } + + if (this->read_wchar_array (&x[0], len)) + { + return true; + } + } + else + { + try + { + x.resize (len-1); // no need to include the terminating '\0' here + } + catch (const std::bad_alloc&) + { + return false; + } + + if (len == 1 || this->read_wchar_array (&x[0], len-1)) + { + return this->skip_wchar (); // skip the terminating '\0' + } + } + } + else if (len == 0) + { + x.clear (); + return true; + } + + this->good_bit_ = false; + x.clear (); + return false; +#else + ACE_CDR::WChar *buf = 0; + ACE_CDR::Boolean const marshal_flag = this->read_wstring (buf); + x.assign (buf); + ACE::strdelete (buf); + return marshal_flag; +#endif +} +#endif + +ACE_CDR::Boolean +ACE_InputCDR::read_array (void* x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + char* buf = 0; + + if (this->adjust (size * length, align, buf) == 0) + { +#if defined (ACE_DISABLE_SWAP_ON_READ) + ACE_OS::memcpy (x, buf, size*length); +#else + if (!this->do_byte_swap_ || size == 1) + ACE_OS::memcpy (x, buf, size*length); + else + { + char *target = reinterpret_cast (x); + switch (size) + { + case 2: + ACE_CDR::swap_2_array (buf, target, length); + break; + case 4: + ACE_CDR::swap_4_array (buf, target, length); + break; + case 8: + ACE_CDR::swap_8_array (buf, target, length); + break; + case 16: + ACE_CDR::swap_16_array (buf, target, length); + break; + default: + // TODO: print something? + this->good_bit_ = false; + return false; + } + } +#endif /* ACE_DISABLE_SWAP_ON_READ */ + return this->good_bit_; + } + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_wchar_array_i (ACE_CDR::WChar* x, + ACE_CDR::ULong length) +{ + if (length == 0) + return true; + char* buf = 0; + size_t const align = (ACE_OutputCDR::wchar_maxbytes_ == 2) ? + ACE_CDR::SHORT_ALIGN : + ACE_CDR::OCTET_ALIGN; + + if (this->adjust (ACE_OutputCDR::wchar_maxbytes_ * length, align, buf) == 0) + { + if (ACE_OutputCDR::wchar_maxbytes_ == 2) + { + ACE_CDR::UShort *sb = reinterpret_cast (buf); + for (size_t i = 0; i < length; ++i) +#if defined (ACE_DISABLE_SWAP_ON_READ) + x[i] = static_cast (sb[i]); +#else + if (!this->do_byte_swap_) + x[i] = static_cast (sb[i]); + else + { + ACE_CDR::UShort sx; + ACE_CDR::swap_2 (&buf[i * 2], reinterpret_cast (&sx)); + x[i] = static_cast (sx); + } +#endif /* ACE_DISABLE_SWAP_ON_READ */ + } + else + { + for (size_t i = 0; i < length; ++i) + x[i] = static_cast (buf[i]); + } + return this->good_bit_; + } + return false; +} + + +ACE_CDR::Boolean +ACE_InputCDR::read_boolean_array (ACE_CDR::Boolean *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length > this->length ()) + { + this->good_bit_ = false; + return false; + } + + // It is hard to optimize this, the spec requires that on the wire + // booleans be represented as a byte with value 0 or 1, but in + // memory it is possible (though very unlikely) that a boolean has + // a non-zero value (different from 1). + // We resort to a simple loop. + for (ACE_CDR::ULong i = 0; i != length && this->good_bit_; ++i) + (void) this->read_boolean (x[i]); + + return this->good_bit_; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_1 (ACE_CDR::Octet *x) +{ + if (this->rd_ptr () < this->wr_ptr ()) + { + *x = *reinterpret_cast (this->rd_ptr ()); + this->start_.rd_ptr (1); + return true; + } + + this->good_bit_ = false; + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_2 (ACE_CDR::UShort *x) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::SHORT_SIZE, buf) == 0) + { +#if !defined (ACE_DISABLE_SWAP_ON_READ) + if (!this->do_byte_swap_) + *x = *reinterpret_cast (buf); + else + ACE_CDR::swap_2 (buf, reinterpret_cast (x)); +#else + *x = *reinterpret_cast (buf); +#endif /* ACE_DISABLE_SWAP_ON_READ */ + return true; + } + this->good_bit_ = false; + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_4 (ACE_CDR::ULong *x) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONG_SIZE, buf) == 0) + { +#if !defined (ACE_DISABLE_SWAP_ON_READ) + if (!this->do_byte_swap_) + *x = *reinterpret_cast (buf); + else + ACE_CDR::swap_4 (buf, reinterpret_cast (x)); +#else + *x = *reinterpret_cast (buf); +#endif /* ACE_DISABLE_SWAP_ON_READ */ + return true; + } + this->good_bit_ = false; + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_8 (ACE_CDR::ULongLong *x) +{ + char *buf = 0; + + if (this->adjust (ACE_CDR::LONGLONG_SIZE, buf) == 0) + { +#if !defined (ACE_DISABLE_SWAP_ON_READ) + if (!this->do_byte_swap_) + *x = *reinterpret_cast (buf); + else + ACE_CDR::swap_8 (buf, reinterpret_cast (x)); +#else + *x = *reinterpret_cast (buf); +#endif /* ACE_DISABLE_SWAP_ON_READ */ + return true; + } + + this->good_bit_ = false; + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::read_16 (ACE_CDR::LongDouble *x) +{ + char *buf = 0; + if (this->adjust (ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN, + buf) == 0) + { +#if !defined (ACE_DISABLE_SWAP_ON_READ) + if (!this->do_byte_swap_) + *x = *reinterpret_cast (buf); + else + ACE_CDR::swap_16 (buf, reinterpret_cast (x)); +#else + *x = *reinterpret_cast (buf); +#endif /* ACE_DISABLE_SWAP_ON_READ */ + return true; + } + + this->good_bit_ = false; + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::skip_string (void) +{ + ACE_CDR::ULong len = 0; + if (this->read_ulong (len)) + { + if (static_cast (~0u) == len) + { + // Indirection, next Long in stream is signed offset to actual + // string location (backwards in same stream from here). + ACE_CDR::Long offset = 0; + if (this->read_long (offset)) + { + return true; + } + } + else if (this->rd_ptr () + len <= this->wr_ptr ()) + { + this->rd_ptr (len); + return true; + } + this->good_bit_ = false; + } + return false; +} + +ACE_CDR::Boolean +ACE_InputCDR::skip_wstring (void) +{ + ACE_CDR::ULong len = 0; + ACE_CDR::Boolean continue_skipping = read_ulong (len); + + if (continue_skipping && len != 0) + { + if (static_cast (this->major_version_) == 1 + && static_cast (this->minor_version_) == 2) + continue_skipping = this->skip_bytes ((size_t)len); + else + while (continue_skipping && len--) + continue_skipping = this->skip_wchar (); + } + return continue_skipping; +} + +ACE_CDR::Boolean +ACE_InputCDR::skip_bytes (size_t len) +{ + if (this->rd_ptr () + len <= this->wr_ptr ()) + { + this->rd_ptr (len); + return true; + } + this->good_bit_ = false; + return false; +} + +int +ACE_InputCDR::grow (size_t newsize) +{ + if (ACE_CDR::grow (&this->start_, newsize) == -1) + return -1; + + ACE_CDR::mb_align (&this->start_); + this->start_.wr_ptr (newsize); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + if (newsize > this->start_.total_size ()) + { + this->monitor_->receive (newsize); + } +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + return 0; +} + +void +ACE_InputCDR::reset (const ACE_Message_Block* data, + int byte_order) +{ + this->reset_byte_order (byte_order); + ACE_CDR::consolidate (&this->start_, data); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +void +ACE_InputCDR::steal_from (ACE_InputCDR &cdr) +{ + this->do_byte_swap_ = cdr.do_byte_swap_; + this->start_.data_block (cdr.start_.data_block ()->duplicate ()); + + // If the message block had a DONT_DELETE flags, just clear it off.. + this->start_.clr_self_flags (ACE_Message_Block::DONT_DELETE); + this->start_.rd_ptr (cdr.start_.rd_ptr ()); + + this->start_.wr_ptr (cdr.start_.wr_ptr ()); + this->major_version_ = cdr.major_version_; + this->minor_version_ = cdr.minor_version_; + cdr.reset_contents (); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +void +ACE_InputCDR::exchange_data_blocks (ACE_InputCDR &cdr) +{ + // Exchange byte orders + int const byte_order = cdr.do_byte_swap_; + cdr.do_byte_swap_ = this->do_byte_swap_; + this->do_byte_swap_ = byte_order; + + // Get the destination read and write pointers + size_t const drd_pos = + cdr.start_.rd_ptr () - cdr.start_.base (); + size_t const dwr_pos = + cdr.start_.wr_ptr () - cdr.start_.base (); + + // Get the source read & write pointers + size_t const srd_pos = + this->start_.rd_ptr () - this->start_.base (); + size_t const swr_pos = + this->start_.wr_ptr () - this->start_.base (); + + // Exchange data_blocks. Dont release any of the data blocks. + ACE_Data_Block *dnb = + this->start_.replace_data_block (cdr.start_.data_block ()); + cdr.start_.replace_data_block (dnb); + + // Exchange the flags information.. + ACE_Message_Block::Message_Flags df = cdr.start_.self_flags (); + ACE_Message_Block::Message_Flags sf = this->start_.self_flags (); + + cdr.start_.clr_self_flags (df); + this->start_.clr_self_flags (sf); + + cdr.start_.set_self_flags (sf); + this->start_.set_self_flags (df); + + // Reset the pointers to zero before it is set again. + cdr.start_.reset (); + this->start_.reset (); + + // Set the read and write pointers. + if (cdr.start_.size () >= srd_pos) + { + cdr.start_.rd_ptr (srd_pos); + } + + if (cdr.start_.size () >= swr_pos) + { + cdr.start_.wr_ptr (swr_pos); + } + + if (this->start_.size () >= drd_pos) + { + this->start_.rd_ptr (drd_pos); + } + + if (this->start_.size () >= dwr_pos) + { + this->start_.wr_ptr (dwr_pos); + } + + ACE_CDR::Octet const dmajor = cdr.major_version_; + ACE_CDR::Octet const dminor = cdr.minor_version_; + + // Exchange the GIOP version info + cdr.major_version_ = this->major_version_; + cdr.minor_version_ = this->minor_version_; + + this->major_version_ = dmajor; + this->minor_version_ = dminor; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_Data_Block * +ACE_InputCDR::clone_from (ACE_InputCDR &cdr) +{ + this->do_byte_swap_ = cdr.do_byte_swap_; + + // Get the read & write pointer positions in the incoming CDR + // streams + char *rd_ptr = cdr.start_.rd_ptr (); + char *wr_ptr = cdr.start_.wr_ptr (); + + // Now reset the incoming CDR stream + cdr.start_.reset (); + + // As we have reset the stream, try to align the underlying message + // block in the incoming stream + ACE_CDR::mb_align (&cdr.start_); + + // Get the read & write pointer positions again + char *nrd_ptr = cdr.start_.rd_ptr (); + char *nwr_ptr = cdr.start_.wr_ptr (); + + // Actual length of the stream is.. + // @todo: This will look idiotic, but we dont seem to have much of a + // choice. How do we calculate the length of the incoming stream? + // Calling the method before calling reset () would give us the + // wrong length of the stream that needs copying. So we do the + // calulation like this + // (1) We get the and positions of the incoming + // stream. + // (2) Then we reset the stream and then align it. + // (3) We get the and positions again. (Points #1 + // thru #3 has been done already) + // (4) The difference in the and positions gives + // us the following, the actual bytes traversed by the and + // . + // (5) The bytes traversed by the is the actual length of + // the stream. + + // Actual bytes traversed + size_t rd_bytes = rd_ptr - nrd_ptr; + size_t wr_bytes = wr_ptr - nwr_ptr; + + ACE_CDR::mb_align (&this->start_); + + ACE_Data_Block *db = this->start_.data_block (); + + // If the size of the data that needs to be copied are higher than + // what is available, then do a reallocation. + if (wr_bytes > (this->start_.size () - ACE_CDR::MAX_ALIGNMENT)) + { + // @@NOTE: We need to probably add another method to the message + // block interface to simplify this + db = cdr.start_.data_block ()->clone_nocopy (); + + if (db == 0 || db->size ((wr_bytes) + + ACE_CDR::MAX_ALIGNMENT) == -1) + return 0; + + // Replace our data block by using the incoming CDR stream. + db = this->start_.replace_data_block (db); + + // Align the start_ message block. + ACE_CDR::mb_align (&this->start_); + + // Clear the DONT_DELETE flag if it has been set + this->start_.clr_self_flags (ACE_Message_Block::DONT_DELETE); + } + + // Now do the copy + (void) ACE_OS::memcpy (this->start_.wr_ptr (), + cdr.start_.rd_ptr (), + wr_bytes); + + // Set the read pointer position to the same point as that was in + // cdr. + this->start_.rd_ptr (rd_bytes); + this->start_.wr_ptr (wr_bytes); + + // We have changed the read & write pointers for the incoming + // stream. Set them back to the positions that they were before.. + cdr.start_.rd_ptr (rd_bytes); + cdr.start_.wr_ptr (wr_bytes); + + this->major_version_ = cdr.major_version_; + this->minor_version_ = cdr.minor_version_; + + // Copy the char/wchar translators + this->char_translator_ = cdr.char_translator_; + this->wchar_translator_ = cdr.wchar_translator_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + return db; +} + +ACE_Message_Block* +ACE_InputCDR::steal_contents (void) +{ + ACE_Message_Block* block = this->start_.clone (); + this->start_.data_block (block->data_block ()->clone ()); + + // If at all our message had a DONT_DELETE flag set, just clear it + // off. + this->start_.clr_self_flags (ACE_Message_Block::DONT_DELETE); + + ACE_CDR::mb_align (&this->start_); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + return block; +} + +void +ACE_InputCDR::reset_contents (void) +{ + this->start_.data_block (this->start_.data_block ()->clone_nocopy ()); + + // Reset the flags... + this->start_.clr_self_flags (ACE_Message_Block::DONT_DELETE); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + +void +ACE_InputCDR::register_monitor (const char *id) +{ + this->monitor_->name (id); + this->monitor_->add_to_registry (); +} + +void +ACE_InputCDR::unregister_monitor (void) +{ + this->monitor_->remove_from_registry (); +} + +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +// -------------------------------------------------------------- + +ACE_Char_Codeset_Translator::~ACE_Char_Codeset_Translator (void) +{ +} + +ACE_CDR::Boolean +ACE_Char_Codeset_Translator::read_string (ACE_InputCDR &cdr, + std::string &x) +{ + ACE_CDR::Char *buf = 0; + ACE_CDR::Boolean const marshal_flag = this->read_string (cdr, buf); + x.assign (buf); + ACE::strdelete (buf); + return marshal_flag; +} + +// -------------------------------------------------------------- + +ACE_WChar_Codeset_Translator::~ACE_WChar_Codeset_Translator (void) +{ +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::read_wstring (ACE_InputCDR &cdr, + std::wstring &x) +{ + ACE_CDR::WChar *buf = 0; + ACE_CDR::Boolean const marshal_flag = this->read_wstring (cdr, buf); + x.assign (buf); + ACE::strdelete (buf); + return marshal_flag; +} +#endif + +// -------------------------------------------------------------- + +ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const ACE_CString &x) +{ + os.write_string (x); + return os.good_bit (); +} + +ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CString &x) +{ + is.read_string (x); + return is.good_bit (); +} + +#if defined (GEN_OSTREAM_OPS) + +std::ostream& +operator<< (std::ostream &os, ACE_OutputCDR::from_boolean x) +{ + return (x.val_ ? os << "true" : os << "false"); +} + +std::ostream& +operator<< (std::ostream &os, ACE_OutputCDR::from_char x) +{ + return os << '\'' << x.val_ << '\''; +} + +std::ostream& +operator<< (std::ostream &os, ACE_OutputCDR::from_wchar x) +{ + os.setf (ios_base::showbase); + os.setf (ios_base::hex, ios_base::basefield); + os << x.val_; + os.unsetf (ios_base::showbase); + os.setf (ios_base::dec, ios_base::basefield); + return os; +} + +std::ostream& +operator<< (std::ostream &os, ACE_OutputCDR::from_octet x) +{ + // Same format (hex) and no risk of overflow. + ACE_CDR::WChar w = static_cast (x.val_); + ACE_OutputCDR::from_wchar tmp (w); + return os << tmp; +} + +#endif /* GEN_OSTREAM_OPS */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CDR_Stream.h b/dep/acelite/ace/CDR_Stream.h new file mode 100644 index 000000000..be7f7c80e --- /dev/null +++ b/dep/acelite/ace/CDR_Stream.h @@ -0,0 +1,1503 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file CDR_Stream.h + * + * ACE Common Data Representation (CDR) marshaling and demarshaling + * classes. + * + * This implementation was inspired in the CDR class in SunSoft's + * IIOP engine, but has a completely different implementation and a + * different interface too. + * + * The current implementation assumes that the host has 1-byte, + * 2-byte and 4-byte integral types, and that it has single + * precision and double precision IEEE floats. + * Those assumptions are pretty good these days, with Crays being + * the only known exception. + * + * Optimizations + * ------------- + * ACE_LACKS_CDR_ALIGNMENT + * @author Arvind S. Krishna + * + * CDR stream ignores alignment when marshaling data. Use this option + * only when ACE_DISABLE_SWAP_ON_READ can be enabled. This option requires + * ACE CDR engine to do both marshaling and demarshaling. + * + * @author TAO version by Aniruddha Gokhale + * @author Carlos O'Ryan + * @author ACE version by Jeff Parsons + * @author Istvan Buki + * @author Codeset translation by Jim Rogers + */ +//============================================================================= + +#ifndef ACE_CDR_STREAM_H +#define ACE_CDR_STREAM_H + +#include /**/ "ace/pre.h" + +#include "ace/CDR_Base.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SStringfwd.h" +#include "ace/Message_Block.h" + +#if defined (GEN_OSTREAM_OPS) +#include "ace/streams.h" +#endif /* GEN_OSTREAM_OPS */ + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) +#include "Monitor_Size.h" +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Char_Codeset_Translator; +class ACE_WChar_Codeset_Translator; + +class ACE_InputCDR; + +/** + * @class ACE_OutputCDR + * + * @brief A CDR stream for marshalling data, most often for transmission to + * another system which may or may not have the same byte order. + * + * This class is based on the the CORBA spec for Java (98-02-29), + * java class omg.org.CORBA.portable.OutputStream. It diverts in + * a few ways: + * @li Operations taking arrays don't have offsets, because in C++ + * it is easier to describe an array starting from x+offset. + * @li Operations return an error status, because exceptions are + * not widely available in C++ (yet). + */ +class ACE_Export ACE_OutputCDR +{ +public: + /** + * The Codeset translators need access to some private members to + * efficiently marshal arrays + * For reading from an output CDR stream. + */ + friend class ACE_Char_Codeset_Translator; + friend class ACE_WChar_Codeset_Translator; + friend class ACE_InputCDR; + + /** + * Default constructor; allows one to set byte ordering, allocators, and + * tuning information. + * + * @param size Causes constructor to preallocate @a size bytes; if + * @a size is 0 it allocates the default size. + * + * @param byte_order The byte order that data will have within this + * object. Unless otherwise specified, the byte order + * will be the order native to the hardware this is + * executed on. To force the marshalled data to have + * a specific order, specify one of the values defined + * in ACE_CDR::Byte_Order. + * @note The @c ACE_ENABLE_SWAP_ON_WRITE config macro + * must be set for any local byte swapping to occur + * as data is inserted into an ACE_OutputCDR object. + */ + ACE_OutputCDR (size_t size = 0, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_Allocator* buffer_allocator = 0, + ACE_Allocator* data_block_allocator = 0, + ACE_Allocator* message_block_allocator = 0, + size_t memcpy_tradeoff = ACE_DEFAULT_CDR_MEMCPY_TRADEOFF, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Build a CDR stream with an initial buffer, it will *not* remove + /// @a data, since it did not allocated it. It's important to be careful + /// with the alignment of @a data. + /** + * Create an output stream from an arbitrary buffer, care must be + * exercised with alignment, because this constructor will align if + * needed. In this case @a data will not point to the start of the + * output stream. @c begin()->rd_ptr() points to the start of the + * output stream. See @c ACE_ptr_align_binary() to properly align a + * pointer and use ACE_CDR::MAX_ALIGNMENT for the correct alignment. + */ + ACE_OutputCDR (char *data, + size_t size, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_Allocator* buffer_allocator = 0, + ACE_Allocator* data_block_allocator = 0, + ACE_Allocator* message_block_allocator = 0, + size_t memcpy_tradeoff = ACE_DEFAULT_CDR_MEMCPY_TRADEOFF, + ACE_CDR::Octet giop_major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet giop_minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Build a CDR stream with an initial data block, it will *not* remove + /// @a data_block, since it did not allocated it. It's important to be + /// careful with the alignment of . + /** + * Create an output stream from an arbitrary data block, care must be + * exercised with alignment, because this constructor will align if + * needed. In this case @a data_block will not point to the + * start of the output stream. begin()->rd_ptr() points to the start + * off the output stream. See ACE_ptr_align_binary() to properly align a + * pointer and use ACE_CDR::MAX_ALIGNMENT for the correct alignment. + */ + ACE_OutputCDR (ACE_Data_Block *data_block, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_Allocator* message_block_allocator = 0, + size_t memcpy_tradeoff = ACE_DEFAULT_CDR_MEMCPY_TRADEOFF, + ACE_CDR::Octet giop_major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet giop_minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Build a CDR stream with an initial Message_Block chain, it will + /// *not* remove @a data, since it did not allocate it. + ACE_OutputCDR (ACE_Message_Block *data, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + size_t memcpy_tradeoff = ACE_DEFAULT_CDR_MEMCPY_TRADEOFF, + ACE_CDR::Octet giop_major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet giop_minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// destructor + ~ACE_OutputCDR (void); + + /** + * Disambiguate overload when inserting booleans, octets, chars, and + * bounded strings. + */ + //@{ @name Helper classes + + struct ACE_Export from_boolean + { + explicit from_boolean (ACE_CDR::Boolean b); + ACE_CDR::Boolean val_; + }; + + struct ACE_Export from_octet + { + explicit from_octet (ACE_CDR::Octet o); + ACE_CDR::Octet val_; + }; + + struct ACE_Export from_char + { + explicit from_char (ACE_CDR::Char c); + ACE_CDR::Char val_; + }; + + struct ACE_Export from_wchar + { + explicit from_wchar (ACE_CDR::WChar wc); + ACE_CDR::WChar val_; + }; + + struct ACE_Export from_string + { + from_string (ACE_CDR::Char* s, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy = 0); + from_string (const ACE_CDR::Char* s, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy = 0); + ACE_CDR::Char *val_; + ACE_CDR::ULong bound_; + ACE_CDR::Boolean nocopy_; + }; + + struct ACE_Export from_wstring + { + from_wstring (ACE_CDR::WChar* ws, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy = 0); + from_wstring (const ACE_CDR::WChar* ws, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy = 0); + ACE_CDR::WChar *val_; + ACE_CDR::ULong bound_; + ACE_CDR::Boolean nocopy_; + }; + + struct ACE_Export from_std_string + { + from_std_string (const std::string &s, + ACE_CDR::ULong b); + const std::string &val_; + ACE_CDR::ULong bound_; + }; + +#if !defined(ACE_LACKS_STD_WSTRING) + struct ACE_Export from_std_wstring + { + from_std_wstring (const std::wstring &ws, + ACE_CDR::ULong b); + const std::wstring &val_; + ACE_CDR::ULong bound_; + }; +#endif + //@} + + /** + * @{ @name Write operations + * Return 0 on failure and 1 on success. + */ + ACE_CDR::Boolean write_boolean (ACE_CDR::Boolean x); + ACE_CDR::Boolean write_char (ACE_CDR::Char x); + ACE_CDR::Boolean write_wchar (ACE_CDR::WChar x); + ACE_CDR::Boolean write_octet (ACE_CDR::Octet x); + ACE_CDR::Boolean write_short (ACE_CDR::Short x); + ACE_CDR::Boolean write_ushort (ACE_CDR::UShort x); + ACE_CDR::Boolean write_long (ACE_CDR::Long x); + ACE_CDR::Boolean write_ulong (ACE_CDR::ULong x); + ACE_CDR::Boolean write_longlong (const ACE_CDR::LongLong &x); + ACE_CDR::Boolean write_ulonglong (const ACE_CDR::ULongLong &x); + ACE_CDR::Boolean write_float (ACE_CDR::Float x); + ACE_CDR::Boolean write_double (const ACE_CDR::Double &x); + ACE_CDR::Boolean write_longdouble (const ACE_CDR::LongDouble &x); + ACE_CDR::Boolean write_fixed (const ACE_CDR::Fixed &x); + + /// For string we offer methods that accept a precomputed length. + ACE_CDR::Boolean write_string (const ACE_CDR::Char *x); + ACE_CDR::Boolean write_string (ACE_CDR::ULong len, + const ACE_CDR::Char *x); + ACE_CDR::Boolean write_string (const ACE_CString &x); + ACE_CDR::Boolean write_wstring (const ACE_CDR::WChar *x); + ACE_CDR::Boolean write_wstring (ACE_CDR::ULong length, + const ACE_CDR::WChar *x); + ACE_CDR::Boolean write_string (const std::string &x); +#if !defined(ACE_LACKS_STD_WSTRING) + ACE_CDR::Boolean write_wstring (const std::wstring &x); +#endif + + //@} + + /// @note the portion written starts at @a x and ends + /// at @a x + @a length. + /// The length is *NOT* stored into the CDR stream. + //@{ @name Array write operations + ACE_CDR::Boolean write_boolean_array (const ACE_CDR::Boolean *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_char_array (const ACE_CDR::Char *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_wchar_array (const ACE_CDR::WChar* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_octet_array (const ACE_CDR::Octet* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_short_array (const ACE_CDR::Short *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ushort_array (const ACE_CDR::UShort *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_long_array (const ACE_CDR::Long *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ulong_array (const ACE_CDR::ULong *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_longlong_array (const ACE_CDR::LongLong* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_ulonglong_array (const ACE_CDR::ULongLong *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_float_array (const ACE_CDR::Float *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_double_array (const ACE_CDR::Double *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean write_longdouble_array (const ACE_CDR::LongDouble* x, + ACE_CDR::ULong length); + + /// Write an octet array contained inside a MB, this can be optimized + /// to minimize copies. + ACE_CDR::Boolean write_octet_array_mb (const ACE_Message_Block* mb); + //@} + + /** + * @{ @name Placeholder/replace operations + * Facilitates writing a placeholder into a CDR stream to be replaced + * later with a different value. + * + * @note An example use for this facility is: + * @code + ACE_OutputCDR strm; + ... // insert values... + char *pos = strm.write_long_placeholder (); + ... // insert more values + ACE_CDR::Long real_val; // Somehow assign the "correct" value + strm.replace (real_val, pos); // Replace earlier placeholder + @endcode + */ + + /** + * Write a placeholder into the stream. The placeholder's pointer + * is returned so it may later be passed as the @a loc argument to + * replace (). + * These methods align the stream's write pointer properly prior to + * writing the placeholder. + * + * @retval Pointer to the placeholder; 0 if there is not enough space + * in the stream and memory could not be allocated. + */ + char* write_long_placeholder (void); + char* write_short_placeholder (void); + char* write_boolean_placeholder (void); + char* write_char_placeholder (void); + char* write_longlong_placeholder (void); + char* write_octet_placeholder (void); + char* write_float_placeholder (void); + char* write_double_placeholder (void); + + /** + * Writes a new value into a specific location. This is commonly + * used to update a prior "placeholder" location in the stream. + * The specified location is assumed to have proper CDR alignment for the + * type to insert. This requirement is satisfied by using one of the + * placeholder-writing methods to align the stream for the anticipated + * value and obtain the correct location. + * Treatment of @a x with respect to byte swapping is the same as for when + * any value is inserted. + * + * @param x The value to insert into the specified location. + * @param loc The location at which to insert @a x. @a loc must be a valid + * position within the stream's current set of message blocks. + * + * @sa write_long_placeholder(), write_short_placeholder () + */ + ACE_CDR::Boolean replace (ACE_CDR::Long x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::ULong x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Short x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::UShort x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Boolean x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Char x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::LongLong x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::ULongLong x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Octet x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Float x, char* loc); + ACE_CDR::Boolean replace (ACE_CDR::Double x, char* loc); + //@} + + /** + * Return 0 on failure and 1 on success. + */ + //@{ @name Append contents of own CDR stream to another + ACE_CDR::Boolean append_boolean (ACE_InputCDR &); + ACE_CDR::Boolean append_char (ACE_InputCDR &); + ACE_CDR::Boolean append_wchar (ACE_InputCDR &); + ACE_CDR::Boolean append_octet (ACE_InputCDR &); + ACE_CDR::Boolean append_short (ACE_InputCDR &); + ACE_CDR::Boolean append_ushort (ACE_InputCDR &); + ACE_CDR::Boolean append_long (ACE_InputCDR &); + ACE_CDR::Boolean append_ulong (ACE_InputCDR &); + ACE_CDR::Boolean append_longlong (ACE_InputCDR &); + ACE_CDR::Boolean append_ulonglong (ACE_InputCDR &); + ACE_CDR::Boolean append_float (ACE_InputCDR &); + ACE_CDR::Boolean append_double (ACE_InputCDR &); + ACE_CDR::Boolean append_longdouble (ACE_InputCDR &); + ACE_CDR::Boolean append_fixed (ACE_InputCDR &); + + ACE_CDR::Boolean append_wstring (ACE_InputCDR &); + ACE_CDR::Boolean append_string (ACE_InputCDR &); + //@} + + /// Returns @c false if an error has occurred. + /** + * @note The only expected error is to run out of memory. + */ + bool good_bit (void) const; + + /// Reuse the CDR stream to write on the old buffer. + void reset (void); + + /// Add the length of each message block in the chain. + size_t total_length (void) const; + + /** + * Return the start of the message block chain for this CDR stream. + * @note The complete CDR stream is represented by a chain of + * message blocks. + */ + const ACE_Message_Block *begin (void) const; + + /// Return the last message in the chain that is is use. + const ACE_Message_Block *end (void) const; + + /// Return the message block in chain. + const ACE_Message_Block *current (void) const; + + /// Replace the message block chain with a single message block. + /** + * Upon successful completion, there will be a single message block + * containing the data from the complete message block chain. + * + * @note The only expected error is to run out of memory. + */ + int consolidate (void); + + /** + * Access the underlying buffer (read only). @note This + * method only returns a pointer to the first block in the + * chain. + */ + const char *buffer (void) const; + + /** + * Return the size of first message block in the block chain. @note This + * method only returns information about the first block in the + * chain. + */ + size_t length (void) const; + + /** + * Utility function to allow the user more flexibility. + * Pads the stream up to the nearest @a alignment byte boundary. + * Argument MUST be a power of 2. + * Returns 0 on success and -1 on failure. + */ + int align_write_ptr (size_t alignment); + + /// Access the codeset translators. They can be null! + ACE_Char_Codeset_Translator *char_translator (void) const; + ACE_WChar_Codeset_Translator *wchar_translator (void) const; + + /// Set the char codeset translator. + void char_translator (ACE_Char_Codeset_Translator *); + /// Set the wchar codeset translator. + void wchar_translator (ACE_WChar_Codeset_Translator *); + + /// set the global size of serialized wchars. This may be different + /// than the size of a wchar_t. + static void wchar_maxbytes (size_t max_bytes); + + /// access the serialized size of wchars. + static size_t wchar_maxbytes (void); + + /** + * Return alignment of the wr_ptr(), with respect to the start of + * the CDR stream. This is not the same as the alignment of + * current->wr_ptr()! + */ + size_t current_alignment (void) const; + + void current_alignment (size_t current_alignment); + + /** + * Returns (in @a buf) the next position in the buffer aligned to + * @a size, it advances the Message_Block wr_ptr past the data + * (i.e., @a buf + @a size). If necessary it grows the Message_Block + * buffer. Sets the good_bit to false and returns a -1 on failure. + */ + int adjust (size_t size, + char *&buf); + + /// As above, but now the size and alignment requirements may be + /// different. + int adjust (size_t size, + size_t align, + char *&buf); + + /// Returns true if this stream is writing in non-native byte order + /// and false otherwise. For example, it would be true if either + /// ACE_ENABLE_SWAP_ON_WRITE is defined or a specific byte order was + /// specified for this stream. + bool do_byte_swap (void) const; + + /// Returns the byte order this stream is marshaling data in. Will be one + /// of the values in ACE_CDR::Byte_Order. + int byte_order (void) const; + + /// For use by a gateway, which creates the output stream for the + /// reply to the client in its native byte order, but which must + /// send the reply in the byte order of the target's reply to the + /// gateway. + void reset_byte_order (int byte_order); + + /// Set GIOP version info + void set_version (ACE_CDR::Octet major, ACE_CDR::Octet minor); + + /// Set the underlying GIOP version.. + void get_version (ACE_CDR::Octet &major, ACE_CDR::Octet &minor); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + /// Register and unregister our buffer size monitor. + void register_monitor (const char* id); + void unregister_monitor (void); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +private: + + // Find the message block in the chain of message blocks + // that the provide location locates. + ACE_Message_Block* find (char* loc); + + /// disallow copying... + ACE_OutputCDR (const ACE_OutputCDR& rhs); + ACE_OutputCDR& operator= (const ACE_OutputCDR& rhs); + + ACE_CDR::Boolean write_1 (const ACE_CDR::Octet *x); + ACE_CDR::Boolean write_2 (const ACE_CDR::UShort *x); + ACE_CDR::Boolean write_4 (const ACE_CDR::ULong *x); + ACE_CDR::Boolean write_8 (const ACE_CDR::ULongLong *x); + ACE_CDR::Boolean write_16 (const ACE_CDR::LongDouble *x); + + /** + * write an array of @a length elements, each of @a size bytes and the + * start aligned at a multiple of @a align. The elements are assumed + * to be packed with the right alignment restrictions. It is mostly + * designed for buffers of the basic types. + * + * This operation uses @c memcpy; as explained above it is expected + * that using assignment is faster that @c memcpy for one element, + * but for several elements @c memcpy should be more efficient, it + * could be interesting to find the break even point and optimize + * for that case, but that would be too platform dependent. + */ + ACE_CDR::Boolean write_array (const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + + ACE_CDR::Boolean write_wchar_array_i (const ACE_CDR::WChar* x, + ACE_CDR::ULong length); + + + /** + * Grow the CDR stream. When it returns @a buf contains a pointer to + * memory in the CDR stream, with at least @a size bytes ahead of it + * and aligned to an @a align boundary. It moved the to . + */ + int grow_and_adjust (size_t size, + size_t align, + char *&buf); + +private: + /// The start of the chain of message blocks. + ACE_Message_Block start_; + + /// The current block in the chain where we are writing. + ACE_Message_Block *current_; + +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + /** + * The current alignment as measured from the start of the buffer. + * Usually this coincides with the alignment of the buffer in + * memory, but, when we chain another buffer this "quasi invariant" + * is broken. + * The current_alignment is used to readjust the buffer following + * the stolen message block. + */ + size_t current_alignment_; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + /** + * Is the current block writable. When we steal a buffer from the + * user and just chain it into the message block we are not supposed + * to write on it, even if it is past the start and end of the + * buffer. + */ + bool current_is_writable_; + + /** + * If not zero swap bytes at writing so the created CDR stream byte + * order does *not* match the machine byte order. The motivation + * for such a beast is that in some setting a few (fast) machines + * can be serving hundreds of slow machines with the opposite byte + * order, so it makes sense (as a load balancing device) to put the + * responsibility in the writers. + * + * @warning THIS IS NOT A STANDARD IN CORBA, USE AT YOUR OWN RISK + */ + bool do_byte_swap_; + + /// Set to false when an error ocurrs. + bool good_bit_; + + /// Break-even point for copying. + size_t const memcpy_tradeoff_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE::Monitor_Control::Size_Monitor *monitor_; +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +protected: + /// GIOP version information + ACE_CDR::Octet major_version_; + ACE_CDR::Octet minor_version_; + + /// If not nil, invoke for translation of character and string data. + ACE_Char_Codeset_Translator *char_translator_; + ACE_WChar_Codeset_Translator *wchar_translator_; + + /** + * Some wide char codesets may be defined with a maximum number + * of bytes that is smaller than the size of a wchar_t. This means + * that the CDR cannot simply memcpy a block of wchars to and from + * the stream, but must instead realign the bytes appropriately. + * In cases when wchar i/o is not allowed, such as with GIOP 1.0, + * or not having a native wchar codeset defined, the maxbytes is + * set to zero, indicating no wchar data is allowed. + */ + static size_t wchar_maxbytes_; +}; + + +// **************************************************************** + +/** + * @class ACE_InputCDR + * + * @brief A CDR stream for demarshalling CDR-encoded data. + * + * This class is based on the the CORBA spec for Java (98-02-29), + * java class omg.org.CORBA.portable.InputStream. It diverts in a + * few ways: + * @li Operations to retrieve basic types take parameters by + * reference. + * @li Operations taking arrays don't have offsets, because in C++ + * it is easier to describe an array starting from x+offset. + * @li Operations return an error status, because exceptions are + * not widely available in C++ (yet). + */ +class ACE_Export ACE_InputCDR +{ +public: + // The translators need privileged access to efficiently demarshal + // arrays and such. + friend class ACE_Char_Codeset_Translator; + friend class ACE_WChar_Codeset_Translator; + + /** + * Create an input stream from an arbitrary buffer. The buffer must + * be properly aligned because this constructor will *not* work if + * the buffer is aligned unproperly.See ACE_ptr_align_binary() for + * instructions on how to align a pointer properly and use + * ACE_CDR::MAX_ALIGNMENT for the correct alignment. + */ + ACE_InputCDR (const char *buf, + size_t bufsiz, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Create an empty input stream. The caller is responsible for + /// putting the right data and providing the right alignment. + ACE_InputCDR (size_t bufsiz, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Create an input stream from an ACE_Message_Block + /** + * The alignment of the @a data block is carried into the new + * ACE_InputCDR object. This constructor either increments the + * @a data reference count, or copies the data (if it's a compound + * message block) so the caller can release the block immediately + * upon return. + */ + ACE_InputCDR (const ACE_Message_Block *data, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION, + ACE_Lock* lock = 0); + + /// Create an input stream from an ACE_Data_Block. The @a flag + /// indicates whether the @a data can be deleted by the CDR stream + /// or not + ACE_InputCDR (ACE_Data_Block *data, + ACE_Message_Block::Message_Flags flag = 0, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /// Create an input stream from an ACE_Data_Block. It also sets the + /// read and write pointers at the desired positions. This would be + /// helpful if the applications desires to create a new CDR stream + /// from a semi-processed datablock. + ACE_InputCDR (ACE_Data_Block *data, + ACE_Message_Block::Message_Flags flag, + size_t read_pointer_position, + size_t write_pointer_position, + int byte_order = ACE_CDR::BYTE_ORDER_NATIVE, + ACE_CDR::Octet major_version = ACE_CDR_GIOP_MAJOR_VERSION, + ACE_CDR::Octet minor_version = ACE_CDR_GIOP_MINOR_VERSION); + + /** + * These make a copy of the current stream state, but do not copy + * the internal buffer, so the same stream can be read multiple + * times efficiently. + */ + ACE_InputCDR (const ACE_InputCDR& rhs); + + ACE_InputCDR& operator= (const ACE_InputCDR& rhs); + + /// When interpreting indirected TypeCodes it is useful to make a + /// "copy" of the stream starting in the new position. + ACE_InputCDR (const ACE_InputCDR& rhs, + size_t size, + ACE_CDR::Long offset); + + /// This creates an encapsulated stream, the first byte must be (per + /// the spec) the byte order of the encapsulation. + ACE_InputCDR (const ACE_InputCDR& rhs, + size_t size); + + /// Create an input CDR from an output CDR. + ACE_InputCDR (const ACE_OutputCDR& rhs, + ACE_Allocator* buffer_allocator = 0, + ACE_Allocator* data_block_allocator = 0, + ACE_Allocator* message_block_allocator = 0); + + /// Helper class to transfer the contents from one input CDR to + /// another without requiring any extra memory allocations, data + /// copies or too many temporaries. + struct ACE_Export Transfer_Contents + { + Transfer_Contents (ACE_InputCDR &rhs); + + ACE_InputCDR &rhs_; + }; + /// Transfer the contents from @a rhs to a new CDR + ACE_InputCDR (Transfer_Contents rhs); + + /// Destructor + virtual ~ACE_InputCDR (void); + + /// Disambiguate overloading when extracting octets, chars, + /// booleans, and bounded strings + //@{ @name Helper classes + + struct ACE_Export to_boolean + { + explicit to_boolean (ACE_CDR::Boolean &b); + ACE_CDR::Boolean &ref_; + }; + + struct ACE_Export to_char + { + explicit to_char (ACE_CDR::Char &c); + ACE_CDR::Char &ref_; + }; + + struct ACE_Export to_wchar + { + explicit to_wchar (ACE_CDR::WChar &wc); + ACE_CDR::WChar &ref_; + }; + + struct ACE_Export to_octet + { + explicit to_octet (ACE_CDR::Octet &o); + ACE_CDR::Octet &ref_; + }; + + struct ACE_Export to_string + { + /** + * @deprecated The constructor taking a non-const string is now + * deprecated (C++ mapping 00-01-02), but we keep it + * around for backward compatibility. + */ + to_string (ACE_CDR::Char *&s, + ACE_CDR::ULong b); + to_string (const ACE_CDR::Char *&s, + ACE_CDR::ULong b); + const ACE_CDR::Char *&val_; + ACE_CDR::ULong bound_; + }; + + struct ACE_Export to_wstring + { + /// The constructor taking a non-const wstring is + /// now deprecated (C++ mapping 00-01-02), but we + /// keep it around for backward compatibility. + to_wstring (ACE_CDR::WChar *&ws, + ACE_CDR::ULong b); + to_wstring (const ACE_CDR::WChar *&ws, + ACE_CDR::ULong b); + const ACE_CDR::WChar *&val_; + ACE_CDR::ULong bound_; + }; + + /// Helper classes for extracting bounded strings into std::string/wstring. + struct ACE_Export to_std_string + { + to_std_string (std::string &s, + ACE_CDR::ULong b); + std::string &val_; + ACE_CDR::ULong bound_; + }; + +#if !defined(ACE_LACKS_STD_WSTRING) + struct ACE_Export to_std_wstring + { + to_std_wstring (std::wstring &ws, + ACE_CDR::ULong b); + std::wstring &val_; + ACE_CDR::ULong bound_; + }; +#endif /* ACE_LACKS_STD_WSTRING */ + //@} + + /** + * Return @c false on failure and @c true on success. + */ + //@{ @name Read basic IDL types + ACE_CDR::Boolean read_boolean (ACE_CDR::Boolean& x); + ACE_CDR::Boolean read_char (ACE_CDR::Char &x); + ACE_CDR::Boolean read_wchar (ACE_CDR::WChar& x); + ACE_CDR::Boolean read_octet (ACE_CDR::Octet& x); + ACE_CDR::Boolean read_short (ACE_CDR::Short &x); + ACE_CDR::Boolean read_ushort (ACE_CDR::UShort &x); + ACE_CDR::Boolean read_long (ACE_CDR::Long &x); + ACE_CDR::Boolean read_ulong (ACE_CDR::ULong &x); + ACE_CDR::Boolean read_longlong (ACE_CDR::LongLong& x); + ACE_CDR::Boolean read_ulonglong (ACE_CDR::ULongLong& x); + ACE_CDR::Boolean read_float (ACE_CDR::Float &x); + ACE_CDR::Boolean read_double (ACE_CDR::Double &x); + ACE_CDR::Boolean read_longdouble (ACE_CDR::LongDouble &x); + ACE_CDR::Boolean read_fixed (ACE_CDR::Fixed &x); + + ACE_CDR::Boolean read_string (ACE_CDR::Char *&x); + ACE_CDR::Boolean read_string (ACE_CString &x); + ACE_CDR::Boolean read_wstring (ACE_CDR::WChar*& x); + ACE_CDR::Boolean read_string (std::string& x); +#if !defined(ACE_LACKS_STD_WSTRING) + ACE_CDR::Boolean read_wstring (std::wstring& x); +#endif + //@} + + /** + * The buffer @a x must be large enough to contain @a length + * elements. + * Return @c false on failure and @c true on success. + */ + //@{ @name Read basic IDL types arrays + ACE_CDR::Boolean read_boolean_array (ACE_CDR::Boolean* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_char_array (ACE_CDR::Char *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_wchar_array (ACE_CDR::WChar* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_octet_array (ACE_CDR::Octet* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_short_array (ACE_CDR::Short *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_ushort_array (ACE_CDR::UShort *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_long_array (ACE_CDR::Long *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_ulong_array (ACE_CDR::ULong *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_longlong_array (ACE_CDR::LongLong* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_ulonglong_array (ACE_CDR::ULongLong* x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_float_array (ACE_CDR::Float *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_double_array (ACE_CDR::Double *x, + ACE_CDR::ULong length); + ACE_CDR::Boolean read_longdouble_array (ACE_CDR::LongDouble* x, + ACE_CDR::ULong length); + //@} + + /** + * Return @c false on failure and @c true on success. + */ + //@{ @name Skip elements + ACE_CDR::Boolean skip_boolean (void); + ACE_CDR::Boolean skip_char (void); + ACE_CDR::Boolean skip_wchar (void); + ACE_CDR::Boolean skip_octet (void); + ACE_CDR::Boolean skip_short (void); + ACE_CDR::Boolean skip_ushort (void); + ACE_CDR::Boolean skip_long (void); + ACE_CDR::Boolean skip_ulong (void); + ACE_CDR::Boolean skip_longlong (void); + ACE_CDR::Boolean skip_ulonglong (void); + ACE_CDR::Boolean skip_float (void); + ACE_CDR::Boolean skip_double (void); + ACE_CDR::Boolean skip_longdouble (void); + ACE_CDR::Boolean skip_fixed (void); + //@} + + /** + * The next field must be a string, this method skips it. It is + * useful in parsing a TypeCode. + * @return @c false on failure and @c true on success. + */ + ACE_CDR::Boolean skip_wstring (void); + ACE_CDR::Boolean skip_string (void); + + /// Skip @a n bytes in the CDR stream. + /** + * @return @c false on failure and @c true on success. + */ + ACE_CDR::Boolean skip_bytes (size_t n); + + /// returns @c false if a problem has been detected. + bool good_bit (void) const; + + /** + * @return The start of the message block chain for this CDR + * stream. + * + * @note In the current implementation the chain has length 1, but + * we are planning to change that. + */ + const ACE_Message_Block* start (void) const; + + // = The following functions are useful to read the contents of the + // CDR stream from a socket or file. + + /** + * Grow the internal buffer, reset @c rd_ptr to the first byte in + * the new buffer that is properly aligned, and set @c wr_ptr to @c + * rd_ptr @c + @c newsize + */ + int grow (size_t newsize); + + /** + * After reading and partially parsing the contents the user can + * detect a change in the byte order, this method will let him/her + * change it. + */ + void reset_byte_order (int byte_order); + + /// Re-initialize the CDR stream, copying the contents of the chain + /// of message_blocks starting from @a data. + void reset (const ACE_Message_Block *data, + int byte_order); + + /// Steal the contents from the current CDR. + ACE_Message_Block *steal_contents (void); + + /// Steal the contents of @a cdr and make a shallow copy into this + /// stream. + void steal_from (ACE_InputCDR &cdr); + + /// Exchange data blocks with the caller of this method. The read + /// and write pointers are also exchanged. + /** + * @note We now do only with the start_ message block. + */ + void exchange_data_blocks (ACE_InputCDR &cdr); + + /// Copy the data portion from the @a cdr to this cdr and return the + /// data content (ie. the ACE_Data_Block) from this CDR to the + /// caller. + /** + * @note The caller is responsible for managing the memory of the + * returned ACE_Data_Block. + */ + ACE_Data_Block* clone_from (ACE_InputCDR &cdr); + + /// Re-initialize the CDR stream, forgetting about the old contents + /// of the stream and allocating a new buffer (from the allocators). + void reset_contents (void); + + /// Returns the current position for the @c rd_ptr. + char* rd_ptr (void); + + /// Returns the current position for the @c wr_ptr. + char* wr_ptr (void); + + /// Return how many bytes are left in the stream. + size_t length (void) const; + + /** + * Utility function to allow the user more flexibility. + * Skips up to the nearest @a alignment-byte boundary. + * Argument MUST be a power of 2. + * + * @return 0 on success and -1 on failure. + */ + int align_read_ptr (size_t alignment); + + /// If @c true then this stream is writing in non-native byte order. + /// This is only meaningful if ACE_ENABLE_SWAP_ON_WRITE is defined. + bool do_byte_swap (void) const; + + /// If @c do_byte_swap() returns @c false, this returns + /// ACE_CDR_BYTE_ORDER else it returns !ACE_CDR_BYTE_ORDER. + int byte_order (void) const; + + /// Access the codeset translators. They can be nil! + ACE_Char_Codeset_Translator *char_translator (void) const; + ACE_WChar_Codeset_Translator *wchar_translator (void) const; + + /// Set the codeset translators. + void char_translator (ACE_Char_Codeset_Translator *); + void wchar_translator (ACE_WChar_Codeset_Translator *); + + /** + * Returns (in @a buf) the next position in the buffer aligned to + * @a size. It advances the Message_Block @c rd_ptr past the data + * (i.e., @c buf @c + @c size). Sets the good_bit to @c false and + * returns a -1 on failure. + */ + int adjust (size_t size, + char *&buf); + + /// As above, but now the size and alignment requirements may be + /// different. + int adjust (size_t size, + size_t align, + char *&buf); + + /// Set the underlying GIOP version.. + void set_version (ACE_CDR::Octet major, ACE_CDR::Octet minor); + + /// Set the underlying GIOP version.. + void get_version (ACE_CDR::Octet &major, ACE_CDR::Octet &minor); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + /// Register and unregister our buffer size monitor. + void register_monitor (const char* id); + void unregister_monitor (void); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +protected: + + /// The start of the chain of message blocks, even though in the + /// current version the chain always has length 1. + ACE_Message_Block start_; + + /// The CDR stream byte order does not match the one on the machine, + /// swapping is needed while reading. + bool do_byte_swap_; + + /// set to @c false when an error occurs. + bool good_bit_; + + /// The GIOP versions for this stream + ACE_CDR::Octet major_version_; + ACE_CDR::Octet minor_version_; + + /// If not nil, invoke for translation of character and string data. + ACE_Char_Codeset_Translator *char_translator_; + ACE_WChar_Codeset_Translator *wchar_translator_; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + ACE::Monitor_Control::Size_Monitor *monitor_; +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + +private: + + ACE_CDR::Boolean read_1 (ACE_CDR::Octet *x); + ACE_CDR::Boolean read_2 (ACE_CDR::UShort *x); + ACE_CDR::Boolean read_4 (ACE_CDR::ULong *x); + ACE_CDR::Boolean read_8 (ACE_CDR::ULongLong *x); + ACE_CDR::Boolean read_16 (ACE_CDR::LongDouble *x); + + // Several types can be read using the same routines, since TAO + // tries to use native types with known size for each CORBA type. + // We could use void* or char* to make the interface more + // consistent, but using native types let us exploit the strict + // alignment requirements of CDR streams and implement the + // operations using assignment. + + /** + * Read an array of @a length elements, each of @a size bytes and the + * start aligned at a multiple of @a align. The elements are assumed + * to be packed with the right alignment restrictions. It is mostly + * designed for buffers of the basic types. + * + * This operation uses @c memcpy; as explained above it is expected + * that using assignment is faster that @c memcpy for one element, + * but for several elements @c memcpy should be more efficient, it + * could be interesting to find the break even point and optimize + * for that case, but that would be too platform dependent. + */ + ACE_CDR::Boolean read_array (void* x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + /** + * On those occasions when the native codeset for wchar is smaller than + * the size of a wchar_t, such as using UTF-16 with a 4-byte wchar_t, a + * special form of reading the array is needed. Actually, this should be + * a default translator. + */ + ACE_CDR::Boolean read_wchar_array_i (ACE_CDR::WChar * x, + ACE_CDR::ULong length); + + /// Move the rd_ptr ahead by @a offset bytes. + void rd_ptr (size_t offset); + + /// Points to the continuation field of the current message block. + char* end (void); +}; + +// **************************************************************** + +/** + * @class ACE_Char_Codeset_Translator + * + * @brief Codeset translation routines common to both Output and Input + * CDR streams. + * + * This class is a base class for defining codeset translation + * routines to handle the character set translations required by + * both CDR Input streams and CDR Output streams. + * + * Translators are reference counted. This allows for stateful as well + * as stateless translators. Stateless translators will be allocated + * once whereas CDR Streams own their own copy of a stateful translator. + */ +class ACE_Export ACE_Char_Codeset_Translator +{ +public: + virtual ~ACE_Char_Codeset_Translator (); + + /// Read a single character from the stream, converting from the + /// stream codeset to the native codeset + virtual ACE_CDR::Boolean read_char (ACE_InputCDR&, + ACE_CDR::Char&) = 0; + + /// Read a string from the stream, including the length, converting + /// the characters from the stream codeset to the native codeset + virtual ACE_CDR::Boolean read_string (ACE_InputCDR&, + ACE_CDR::Char *&) = 0; + + /// Read a std::string from the stream, including the length, converting + /// the characters from the stream codeset to the native codeset + /// (provide non-optimized default implementation) + virtual ACE_CDR::Boolean read_string (ACE_InputCDR&, + std::string &); + + /// Read an array of characters from the stream, converting the + /// characters from the stream codeset to the native codeset. + virtual ACE_CDR::Boolean read_char_array (ACE_InputCDR&, + ACE_CDR::Char*, + ACE_CDR::ULong) = 0; + + /// Write a single character to the stream, converting from the + /// native codeset to the stream codeset + virtual ACE_CDR::Boolean write_char (ACE_OutputCDR&, + ACE_CDR::Char) = 0; + + /// Write a string to the stream, including the length, converting + /// from the native codeset to the stream codeset + virtual ACE_CDR::Boolean write_string (ACE_OutputCDR&, + ACE_CDR::ULong, + const ACE_CDR::Char*) = 0; + + /// Write an array of characters to the stream, converting from the + /// native codeset to the stream codeset + virtual ACE_CDR::Boolean write_char_array (ACE_OutputCDR&, + const ACE_CDR::Char*, + ACE_CDR::ULong) = 0; + + virtual ACE_CDR::ULong ncs () = 0; + virtual ACE_CDR::ULong tcs () = 0; +protected: + /// Children have access to low-level routines because they cannot + /// use read_char or something similar (it would recurse). + ACE_CDR::Boolean read_1 (ACE_InputCDR& input, + ACE_CDR::Octet *x); + ACE_CDR::Boolean write_1 (ACE_OutputCDR& output, + const ACE_CDR::Octet *x); + + /// Efficiently read @a length elements of size @a size each from + /// @a input into @a x; the data must be aligned to @a align. + ACE_CDR::Boolean read_array (ACE_InputCDR& input, + void* x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + /** + * Efficiently write @a length elements of size @a size from into + * . Before inserting the elements enough padding is added + * to ensure that the elements will be aligned to in the + * stream. + */ + ACE_CDR::Boolean write_array (ACE_OutputCDR& output, + const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + /** + * Exposes the stream implementation of , this is useful in + * many cases to minimize memory allocations during marshaling. + * On success @a buf will contain a contiguous area in the CDR stream + * that can hold @a size bytes aligned to @a align. + * Results + */ + int adjust (ACE_OutputCDR& out, + size_t size, + size_t align, + char *&buf); + + /// Used by derived classes to set errors in the CDR stream. + void good_bit (ACE_OutputCDR& out, bool bit); + + /// Obtain the CDR Stream's major & minor version values. + ACE_CDR::Octet major_version (ACE_InputCDR& input); + ACE_CDR::Octet minor_version (ACE_InputCDR& input); + ACE_CDR::Octet major_version (ACE_OutputCDR& output); + ACE_CDR::Octet minor_version (ACE_OutputCDR& output); +}; + +// **************************************************************** + +/** + * @class ACE_WChar_Codeset_Translator + * + * @brief Codeset translation routines common to both Output and Input + * CDR streams. + * + * This class is a base class for defining codeset translation + * routines to handle the character set translations required by + * both CDR Input streams and CDR Output streams. + */ +class ACE_Export ACE_WChar_Codeset_Translator +{ +public: + virtual ~ACE_WChar_Codeset_Translator (); + + virtual ACE_CDR::Boolean read_wchar (ACE_InputCDR&, + ACE_CDR::WChar&) = 0; + virtual ACE_CDR::Boolean read_wstring (ACE_InputCDR&, + ACE_CDR::WChar *&) = 0; +#if !defined(ACE_LACKS_STD_WSTRING) + /// Read a std::wstring from the stream, including the length, converting + /// the characters from the stream codeset to the native codeset + /// (provide non-optimized default implementation) + virtual ACE_CDR::Boolean read_wstring (ACE_InputCDR&, + std::wstring &); +#endif + virtual ACE_CDR::Boolean read_wchar_array (ACE_InputCDR&, + ACE_CDR::WChar*, + ACE_CDR::ULong) = 0; + virtual ACE_CDR::Boolean write_wchar (ACE_OutputCDR&, + ACE_CDR::WChar) = 0; + virtual ACE_CDR::Boolean write_wstring (ACE_OutputCDR&, + ACE_CDR::ULong, + const ACE_CDR::WChar*) = 0; + virtual ACE_CDR::Boolean write_wchar_array (ACE_OutputCDR&, + const ACE_CDR::WChar*, + ACE_CDR::ULong) = 0; + + virtual ACE_CDR::ULong ncs () = 0; + virtual ACE_CDR::ULong tcs () = 0; +protected: + /// Children have access to low-level routines because they cannot + /// use read_char or something similar (it would recurse). + ACE_CDR::Boolean read_1 (ACE_InputCDR& input, + ACE_CDR::Octet *x); + ACE_CDR::Boolean read_2 (ACE_InputCDR& input, + ACE_CDR::UShort *x); + ACE_CDR::Boolean read_4 (ACE_InputCDR& input, + ACE_CDR::ULong *x); + ACE_CDR::Boolean write_1 (ACE_OutputCDR& output, + const ACE_CDR::Octet *x); + ACE_CDR::Boolean write_2 (ACE_OutputCDR& output, + const ACE_CDR::UShort *x); + ACE_CDR::Boolean write_4 (ACE_OutputCDR& output, + const ACE_CDR::ULong *x); + + /// Efficiently read @a length elements of size @a size each from + /// @a input into @a x; the data must be aligned to @a align. + ACE_CDR::Boolean read_array (ACE_InputCDR& input, + void* x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + /** + * Efficiently write @a length elements of size @a size from @a x into + * @a output. Before inserting the elements enough padding is added + * to ensure that the elements will be aligned to @a align in the + * stream. + */ + ACE_CDR::Boolean write_array (ACE_OutputCDR& output, + const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length); + + /** + * Exposes the stream implementation of @a adjust, this is useful in + * many cases to minimize memory allocations during marshaling. + * On success @a buf will contain a contiguous area in the CDR stream + * that can hold @a size bytes aligned to @a align. + * Results + */ + int adjust (ACE_OutputCDR& out, + size_t size, + size_t align, + char *&buf); + + /// Used by derived classes to set errors in the CDR stream. + void good_bit (ACE_OutputCDR& out, bool bit); + + /// Obtain the CDR Stream's major & minor version values. + ACE_CDR::Octet major_version (ACE_InputCDR& input); + ACE_CDR::Octet minor_version (ACE_InputCDR& input); + ACE_CDR::Octet major_version (ACE_OutputCDR& output); + ACE_CDR::Octet minor_version (ACE_OutputCDR& output); + +}; + +// @@ These operators should not be inlined since they force SString.h +// to be included in this header. +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const ACE_CString &x); + +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CString &x); + + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +# include "ace/CDR_Stream.inl" +#else /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Not used by CORBA or TAO +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::Char x); +// CDR output operators for primitive types + +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::Short x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::UShort x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::Long x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::ULong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::LongLong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::ULongLong x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR& os, + ACE_CDR::LongDouble x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::Float x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_CDR::Double x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const ACE_CDR::Fixed &x); + +// CDR output operator from helper classes + +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_boolean x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_char x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_wchar x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_octet x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_string x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_wstring x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const ACE_CDR::Char* x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const ACE_CDR::WChar* x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_std_string x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const std::string& x); +#if !defined(ACE_LACKS_STD_WSTRING) +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + ACE_OutputCDR::from_std_wstring x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_OutputCDR &os, + const std::wstring& x); +#endif + +// Not used by CORBA or TAO +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Char &x); +// CDR input operators for primitive types + +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Short &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::UShort &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Long &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::ULong &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::LongLong &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::ULongLong &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::LongDouble &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Float &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Double &x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Fixed &x); + +// CDR input operator from helper classes + +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_boolean x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_char x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_wchar x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_octet x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_string x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_InputCDR::to_wstring x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::Char*& x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + ACE_CDR::WChar*& x); +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_InputCDR &os, + ACE_InputCDR::to_std_string x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + std::string& x); +#if !defined(ACE_LACKS_STD_WSTRING) +extern ACE_Export ACE_CDR::Boolean operator<< (ACE_InputCDR &os, + ACE_InputCDR::to_std_wstring x); +extern ACE_Export ACE_CDR::Boolean operator>> (ACE_InputCDR &is, + std::wstring& x); +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* __ACE_INLINE__ */ + +#if defined (GEN_OSTREAM_OPS) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// ostream insertion operators for debugging code generated from IDL. All +// but these below are either in generated code itself or are unambiguous +// primitive types. + +ACE_Export std::ostream& operator<< (std::ostream &os, + ACE_OutputCDR::from_boolean x); + +ACE_Export std::ostream& operator<< (std::ostream &os, + ACE_OutputCDR::from_char x); + +ACE_Export std::ostream& operator<< (std::ostream &os, + ACE_OutputCDR::from_wchar x); + +ACE_Export std::ostream& operator<< (std::ostream &os, + ACE_OutputCDR::from_octet x); + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* GEN_OSTREAM_OPS */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CDR_STREAM_H */ diff --git a/dep/acelite/ace/CDR_Stream.inl b/dep/acelite/ace/CDR_Stream.inl new file mode 100644 index 000000000..fe25108da --- /dev/null +++ b/dep/acelite/ace/CDR_Stream.inl @@ -0,0 +1,1926 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" +#include "ace/OS_Memory.h" + +// **************************************************************** + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// implementing the special types +ACE_INLINE +ACE_OutputCDR::from_boolean::from_boolean (ACE_CDR::Boolean b) + : val_ (b) +{ +} + +ACE_INLINE +ACE_InputCDR::to_boolean::to_boolean (ACE_CDR::Boolean &b) + : ref_ (b) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_octet::from_octet (ACE_CDR::Octet o) + : val_ (o) +{ +} + +ACE_INLINE +ACE_InputCDR::to_octet::to_octet (ACE_CDR::Octet &o) + : ref_ (o) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_char::from_char (ACE_CDR::Char c) + : val_ (c) +{ +} + +ACE_INLINE +ACE_InputCDR::to_char::to_char (ACE_CDR::Char &c) + : ref_ (c) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_wchar::from_wchar (ACE_CDR::WChar wc) + : val_ (wc) +{ +} + +ACE_INLINE +ACE_InputCDR::to_wchar::to_wchar (ACE_CDR::WChar &wc) + : ref_ (wc) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_string::from_string (ACE_CDR::Char *s, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy) + : val_ (s), + bound_ (b), + nocopy_ (nocopy) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_string::from_string (const ACE_CDR::Char *s, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy) + : val_ (const_cast (s)), + bound_ (b), + nocopy_ (nocopy) +{ +} + +ACE_INLINE +ACE_InputCDR::to_string::to_string (ACE_CDR::Char *&s, + ACE_CDR::ULong b) + : val_ (const_cast (s)), + bound_ (b) +{ +} + +ACE_INLINE +ACE_InputCDR::to_string::to_string (const ACE_CDR::Char *&s, + ACE_CDR::ULong b) + : val_ (s), + bound_ (b) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_wstring::from_wstring (ACE_CDR::WChar *ws, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy) + : val_ (ws), + bound_ (b), + nocopy_ (nocopy) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_wstring::from_wstring (const ACE_CDR::WChar *ws, + ACE_CDR::ULong b, + ACE_CDR::Boolean nocopy) + : val_ (const_cast (ws)), + bound_ (b), + nocopy_ (nocopy) +{ +} + +ACE_INLINE +ACE_InputCDR::to_wstring::to_wstring (ACE_CDR::WChar *&ws, + ACE_CDR::ULong b) + : val_ (const_cast (ws)), + bound_ (b) +{ +} + +ACE_INLINE +ACE_InputCDR::to_wstring::to_wstring (const ACE_CDR::WChar *&ws, + ACE_CDR::ULong b) + : val_ (ws), + bound_ (b) +{ +} + +ACE_INLINE +ACE_InputCDR::to_std_string::to_std_string (std::string &s, + ACE_CDR::ULong b) + : val_ (s), + bound_ (b) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_std_string::from_std_string (const std::string &ws, + ACE_CDR::ULong b) + : val_ (ws), + bound_ (b) +{ +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE +ACE_InputCDR::to_std_wstring::to_std_wstring (std::wstring &s, + ACE_CDR::ULong b) + : val_ (s), + bound_ (b) +{ +} + +ACE_INLINE +ACE_OutputCDR::from_std_wstring::from_std_wstring (const std::wstring &ws, + ACE_CDR::ULong b) + : val_ (ws), + bound_ (b) +{ +} +#endif + +ACE_INLINE +ACE_InputCDR::Transfer_Contents::Transfer_Contents (ACE_InputCDR &rhs) + : rhs_ (rhs) +{ +} + +// **************************************************************** + +ACE_INLINE +ACE_OutputCDR::~ACE_OutputCDR (void) +{ + if (this->start_.cont () != 0) + { + ACE_Message_Block::release (this->start_.cont ()); + this->start_.cont (0); + } + + this->current_ = 0; + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->remove_ref (); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_INLINE void +ACE_OutputCDR::reset (void) +{ + this->current_ = &this->start_; + this->current_is_writable_ = true; + ACE_CDR::mb_align (&this->start_); + +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + this->current_alignment_ = 0; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + // It is tempting not to remove the memory, but we need to do so to + // release any potential user buffers chained in the continuation + // field. + + ACE_Message_Block * const cont = this->start_.cont (); + if (cont) + { + ACE_Message_Block::release (cont); + this->start_.cont (0); + } + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->start_.total_size ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +// Encode the CDR stream. + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_octet (ACE_CDR::Octet x) +{ + return this->write_1 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_boolean (ACE_CDR::Boolean x) +{ + return + static_cast ( + this->write_octet ( + x + ? static_cast (1) + : static_cast (0))); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_char (ACE_CDR::Char x) +{ + if (this->char_translator_ == 0) + { + ACE_CDR::Octet temp = static_cast (x); + return this->write_1 (&temp); + } + return this->char_translator_->write_char (*this, x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_short (ACE_CDR::Short x) +{ + ACE_CDR::UShort temp = static_cast (x); + return this->write_2 (&temp); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ushort (ACE_CDR::UShort x) +{ + return this->write_2 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_long (ACE_CDR::Long x) +{ + ACE_CDR::ULong temp = static_cast (x); + return this->write_4 (&temp); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ulong (ACE_CDR::ULong x) +{ + return this->write_4 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_longlong (const ACE_CDR::LongLong &x) +{ + void const * const temp = &x; + return this->write_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ulonglong (const ACE_CDR::ULongLong &x) +{ + return this->write_8 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_float (ACE_CDR::Float x) +{ + void const * const temp = &x; + return this->write_4 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_double (const ACE_CDR::Double &x) +{ + void const * const temp = &x; + return this->write_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_longdouble (const ACE_CDR::LongDouble &x) +{ + return this->write_16 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_fixed (const ACE_CDR::Fixed &x) +{ + int n; + const ACE_CDR::Octet *arr = x.to_octets (n); + return this->write_array (arr, ACE_CDR::OCTET_SIZE, ACE_CDR::OCTET_ALIGN, n); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_string (const ACE_CDR::Char *x) +{ + if (x) + { + ACE_CDR::ULong const len = + static_cast (ACE_OS::strlen (x)); + return this->write_string (len, x); + } + + return this->write_string (0, 0); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_wstring (const ACE_CDR::WChar *x) +{ + if (x) + { + ACE_CDR::ULong const len = + static_cast (ACE_OS::strlen (x)); + return this->write_wstring (len, x); + } + + return this->write_wstring (0, 0); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_string (const std::string &x) +{ + ACE_CDR::ULong const len = + static_cast (x.size ()); + return this->write_string (len, + x.empty () ? 0 : x.c_str ()); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_wstring (const std::wstring &x) +{ + ACE_CDR::ULong const len = + static_cast (x.size ()); + return this->write_wstring (len, + x.empty () ? 0 : x.c_str ()); +} +#endif + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_char_array (const ACE_CDR::Char *x, + ACE_CDR::ULong length) +{ + if (this->char_translator_ == 0) + return this->write_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); + return this->char_translator_->write_char_array (*this, x, length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_wchar_array (const ACE_CDR::WChar* x, + ACE_CDR::ULong length) +{ + if (this->wchar_translator_) + return this->wchar_translator_->write_wchar_array (*this, x, length); + + if (ACE_OutputCDR::wchar_maxbytes_ == 0) + { + errno = EACCES; + return (ACE_CDR::Boolean) (this->good_bit_ = false); + } + + if (ACE_OutputCDR::wchar_maxbytes_ == sizeof (ACE_CDR::WChar)) + return this->write_array (x, + sizeof (ACE_CDR::WChar), + sizeof (ACE_CDR::WChar) == 2 + ? ACE_CDR::SHORT_ALIGN + : ACE_CDR::LONG_ALIGN, + length); + return this->write_wchar_array_i (x,length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_octet_array (const ACE_CDR::Octet* x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_short_array (const ACE_CDR::Short *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ushort_array (const ACE_CDR::UShort *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_long_array (const ACE_CDR::Long *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ulong_array (const ACE_CDR::ULong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_longlong_array (const ACE_CDR::LongLong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_ulonglong_array (const ACE_CDR::ULongLong *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_float_array (const ACE_CDR::Float *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_double_array (const ACE_CDR::Double *x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::write_longdouble_array (const ACE_CDR::LongDouble* x, + ACE_CDR::ULong length) +{ + return this->write_array (x, + ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN, + length); +} + +ACE_INLINE bool +ACE_OutputCDR::good_bit (void) const +{ + return this->good_bit_; +} + +ACE_INLINE int +ACE_OutputCDR::adjust (size_t size, + size_t align, + char*& buf) +{ + if (!this->current_is_writable_) + return this->grow_and_adjust (size, align, buf); + +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + size_t const offset = + ACE_align_binary (this->current_alignment_, align) + - this->current_alignment_; + + buf = this->current_->wr_ptr () + offset; +#else + buf = this->current_->wr_ptr (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + char * const end = buf + size; + + if (end <= this->current_->end () && + end >= buf) + { +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + this->current_alignment_ += offset + size; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + this->current_->wr_ptr (end); + +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->receive (this->total_length ()); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ + + return 0; + } + + return this->grow_and_adjust (size, align, buf); +} + +ACE_INLINE int +ACE_OutputCDR::adjust (size_t size, char*& buf) +{ + return this->adjust (size, size, buf); +} + +ACE_INLINE void +ACE_OutputCDR::set_version (ACE_CDR::Octet major, ACE_CDR::Octet minor) +{ + this->major_version_ = major; + this->minor_version_ = minor; +} + +ACE_INLINE void +ACE_OutputCDR::get_version (ACE_CDR::Octet &major, ACE_CDR::Octet &minor) +{ + major = this->major_version_; + minor = this->minor_version_; +} + + +ACE_INLINE const ACE_Message_Block* +ACE_OutputCDR::begin (void) const +{ + return &this->start_; +} + +ACE_INLINE const ACE_Message_Block* +ACE_OutputCDR::end (void) const +{ + return this->current_->cont (); +} + +ACE_INLINE const ACE_Message_Block* +ACE_OutputCDR::current (void) const +{ + return this->current_; +} + +ACE_INLINE size_t +ACE_OutputCDR::total_length (void) const +{ + return ACE_CDR::total_length (this->begin (), this->end ()); +} + +ACE_INLINE const char* +ACE_OutputCDR::buffer (void) const +{ + return this->start_.rd_ptr (); +} + +ACE_INLINE size_t +ACE_OutputCDR::length (void) const +{ + return this->start_.length (); +} + +ACE_INLINE bool +ACE_OutputCDR::do_byte_swap (void) const +{ + return this->do_byte_swap_; +} + +ACE_INLINE int +ACE_OutputCDR::byte_order (void) const +{ + if (this->do_byte_swap ()) + return !ACE_CDR_BYTE_ORDER; + else + return ACE_CDR_BYTE_ORDER; +} + +ACE_INLINE void +ACE_OutputCDR::reset_byte_order (int byte_order) +{ + this->do_byte_swap_ = (byte_order != ACE_CDR_BYTE_ORDER); +} + +ACE_INLINE size_t +ACE_OutputCDR::current_alignment (void) const +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + return this->current_alignment_; +#else + // Default value set to 0 + return 0; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ +} + +ACE_INLINE void +ACE_OutputCDR::current_alignment (size_t current_alignment) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + this->current_alignment_ = current_alignment; +#else + ACE_UNUSED_ARG (current_alignment); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ +} + +ACE_INLINE int +ACE_OutputCDR::align_write_ptr (size_t alignment) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + char *dummy; + return this->adjust (0, alignment, dummy); +#else + ACE_UNUSED_ARG (alignment); + // A return value of -1 from this function is used + // to indicate failure, returning 0 + return 0; +#endif /* ACE_LACKS_CDR_ALIGNMENT */ +} + +ACE_INLINE ACE_Char_Codeset_Translator * +ACE_OutputCDR::char_translator (void) const +{ + return this->char_translator_; +} + +ACE_INLINE ACE_WChar_Codeset_Translator * +ACE_OutputCDR::wchar_translator (void) const +{ + return this->wchar_translator_; +} + +ACE_INLINE void +ACE_OutputCDR::char_translator (ACE_Char_Codeset_Translator * ctran) +{ + this->char_translator_ = ctran; +} + +ACE_INLINE void +ACE_OutputCDR::wchar_translator (ACE_WChar_Codeset_Translator * wctran) +{ + this->wchar_translator_ = wctran; +} + +// **************************************************************** + +ACE_INLINE +ACE_InputCDR::~ACE_InputCDR (void) +{ +#if defined (ACE_HAS_MONITOR_POINTS) && (ACE_HAS_MONITOR_POINTS == 1) + this->monitor_->remove_ref (); +#endif /* ACE_HAS_MONITOR_POINTS==1 */ +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_octet (ACE_CDR::Octet& x) +{ + return this->read_1 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_boolean (ACE_CDR::Boolean& x) +{ + ACE_CDR::Octet tmp = 0; + (void) this->read_octet (tmp); + x = tmp ? true : false; + return (ACE_CDR::Boolean) this->good_bit_; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_char (ACE_CDR::Char &x) +{ + if (this->char_translator_ == 0) + { + void *temp = &x; + return this->read_1 (reinterpret_cast (temp)); + } + return this->char_translator_->read_char (*this, x); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_short (ACE_CDR::Short &x) +{ + void *temp = &x; + return this->read_2 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ushort (ACE_CDR::UShort &x) +{ + return this->read_2 (&x); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_long (ACE_CDR::Long &x) +{ + void *temp = &x; + return this->read_4 (reinterpret_cast (temp)); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ulong (ACE_CDR::ULong &x) +{ + return this->read_4 (&x); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_longlong (ACE_CDR::LongLong &x) +{ + void *temp = &x; + return this->read_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ulonglong (ACE_CDR::ULongLong &x) +{ + return this->read_8 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_float (ACE_CDR::Float &x) +{ + void *temp = &x; + return this->read_4 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_double (ACE_CDR::Double &x) +{ + void *temp = &x; + return this->read_8 (reinterpret_cast (temp)); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_longdouble (ACE_CDR::LongDouble &x) +{ + return this->read_16 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_fixed (ACE_CDR::Fixed &x) +{ + ACE_CDR::Octet a[16]; + for (int i = 0; i < 16; ++i) + { + if (!this->read_1 (a + i)) + return false; + const unsigned low = a[i] & 0xf; + if (low == ACE_CDR::Fixed::POSITIVE || + low == ACE_CDR::Fixed::NEGATIVE) + { + x = ACE_CDR::Fixed::from_octets (a, i + 1); + return true; + } + } + + return false; +} + +ACE_INLINE size_t +ACE_InputCDR::length (void) const +{ + return this->start_.length (); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_char_array (ACE_CDR::Char* x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length > this->length ()) + { + this->good_bit_ = false; + return false; + } + + if (this->char_translator_ == 0) + return this->read_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); + return this->char_translator_->read_char_array (*this, x, length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_wchar_array (ACE_CDR::WChar* x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_OutputCDR::wchar_maxbytes_ > this->length ()) + { + this->good_bit_ = false; + return false; + } + + if (this->wchar_translator_ != 0) + return this->wchar_translator_->read_wchar_array (*this, x, length); + if (ACE_OutputCDR::wchar_maxbytes_ != sizeof (ACE_CDR::WChar)) + return this->read_wchar_array_i (x, length); + return this->read_array (x, + sizeof (ACE_CDR::WChar), + sizeof (ACE_CDR::WChar) == 2 + ? ACE_CDR::SHORT_ALIGN + : ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_octet_array (ACE_CDR::Octet* x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::OCTET_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_short_array (ACE_CDR::Short *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::SHORT_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ushort_array (ACE_CDR::UShort *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::SHORT_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::SHORT_SIZE, + ACE_CDR::SHORT_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_long_array (ACE_CDR::Long *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ulong_array (ACE_CDR::ULong *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_longlong_array (ACE_CDR::LongLong *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONGLONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_ulonglong_array (ACE_CDR::ULongLong *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONGLONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_float_array (ACE_CDR::Float *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONG_SIZE, + ACE_CDR::LONG_ALIGN, + length); +} + + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_double_array (ACE_CDR::Double *x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONGLONG_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + + return this->read_array (x, + ACE_CDR::LONGLONG_SIZE, + ACE_CDR::LONGLONG_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::read_longdouble_array (ACE_CDR::LongDouble* x, + ACE_CDR::ULong length) +{ + // Make sure the length of the array isn't greater than the length of + // the stream. + if (length * ACE_CDR::LONGDOUBLE_SIZE > this->length ()) + { + this->good_bit_ = false; + return false; + } + return this->read_array (x, + ACE_CDR::LONGDOUBLE_SIZE, + ACE_CDR::LONGDOUBLE_ALIGN, + length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_octet (void) +{ + ACE_CDR::Octet x; + return this->read_1 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_char (void) +{ + return this->skip_octet (); // sizeof (Char) == sizeof (Octet) +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_boolean (void) +{ + return this->skip_octet () && this->good_bit_; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_ushort (void) +{ + ACE_CDR::UShort x; + return this->read_2 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_short (void) +{ + return this->skip_ushort (); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_ulong (void) +{ + ACE_CDR::ULong x; + return this->read_4 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_long (void) +{ + return this->skip_ulong (); // sizeof (Long) == sizeof (ULong) +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_ulonglong (void) +{ + ACE_CDR::ULongLong x; + return this->read_8 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_longlong (void) +{ + return this->skip_ulonglong (); // sizeof (LongLong) == sizeof (ULongLong) +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_float (void) +{ + return this->skip_ulong (); // sizeof(Float) == sizeof (ULong) +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_double (void) +{ + return this->skip_ulonglong (); // sizeof(Double) == sizeof (ULongLong) +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_longdouble (void) +{ + ACE_CDR::LongDouble x; + return this->read_16 (&x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_InputCDR::skip_fixed (void) +{ + for (int i = 0; i < 16; ++i) + { + ACE_CDR::Octet x; + if (!this->read_1 (&x)) + return false; + const unsigned low = x & 0xf; + if (low == 0xc || low == 0xd) + return true; + } + return false; +} + +ACE_INLINE char* +ACE_InputCDR::end (void) +{ + return this->start_.end (); +} + +ACE_INLINE void +ACE_InputCDR::rd_ptr (size_t offset) +{ + this->start_.rd_ptr (offset); +} + +ACE_INLINE char* +ACE_InputCDR::rd_ptr (void) +{ + return this->start_.rd_ptr (); +} + +ACE_INLINE char* +ACE_InputCDR::wr_ptr (void) +{ + return this->start_.wr_ptr (); +} + +ACE_INLINE int +ACE_InputCDR::adjust (size_t size, + size_t align, + char*& buf) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + buf = ACE_ptr_align_binary (this->rd_ptr (), align); +#else + buf = this->rd_ptr (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + char * const end = buf + size; + if (end <= this->wr_ptr ()) + { + this->start_.rd_ptr (end); + return 0; + } + + this->good_bit_ = false; + return -1; +#if defined (ACE_LACKS_CDR_ALIGNMENT) + ACE_UNUSED_ARG (align); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ +} + +ACE_INLINE int +ACE_InputCDR::adjust (size_t size, + char*& buf) +{ + return this->adjust (size, size, buf); +} + +ACE_INLINE const ACE_Message_Block* +ACE_InputCDR::start (void) const +{ + return &this->start_; +} + +ACE_INLINE bool +ACE_InputCDR::good_bit (void) const +{ + return this->good_bit_; +} + +// **************************************************************** + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::Char x) +{ + os.write_char (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::Short x) +{ + os.write_short (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::UShort x) +{ + os.write_ushort (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::Long x) +{ + os.write_long (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::ULong x) +{ + os.write_ulong (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::LongLong x) +{ + os.write_longlong (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::ULongLong x) +{ + os.write_ulonglong (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::LongDouble x) +{ + os.write_longdouble (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::Float x) +{ + os.write_float (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_CDR::Double x) +{ + os.write_double (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const ACE_CDR::Fixed &x) +{ + os.write_fixed (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const ACE_CDR::Char *x) +{ + os.write_string (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const ACE_CDR::WChar *x) +{ + os.write_wstring (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_std_string x) +{ + ACE_CDR::ULong len = + static_cast (x.val_.size ()); + + os.write_string (len, x.val_.c_str ()); + return + (ACE_CDR::Boolean) (os.good_bit () && (!x.bound_ || len <= x.bound_)); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_std_wstring x) +{ + ACE_CDR::ULong len = + static_cast (x.val_.size ()); + + os.write_wstring (len, x.val_.c_str ()); + return + (ACE_CDR::Boolean) (os.good_bit () && (!x.bound_ || len <= x.bound_)); +} +#endif + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const std::string& x) +{ + os.write_string (x); + return (ACE_CDR::Boolean) os.good_bit (); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, const std::wstring& x) +{ + os.write_wstring (x); + return (ACE_CDR::Boolean) os.good_bit (); +} +#endif + +// The following use the helper classes +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_boolean x) +{ + (void) os.write_boolean (x.val_); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_char x) +{ + os.write_char (x.val_); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_wchar x) +{ + os.write_wchar (x.val_); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_octet x) +{ + os.write_octet (x.val_); + return (ACE_CDR::Boolean) os.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_string x) +{ + ACE_CDR::ULong len = 0; + + if (x.val_ != 0) + { + len = static_cast (ACE_OS::strlen (x.val_)); + } + + os.write_string (len, x.val_); + return + (ACE_CDR::Boolean) (os.good_bit () && (!x.bound_ || len <= x.bound_)); +} + +ACE_INLINE ACE_CDR::Boolean +operator<< (ACE_OutputCDR &os, ACE_OutputCDR::from_wstring x) +{ + ACE_CDR::ULong len = 0; + + if (x.val_ != 0) + { + len = static_cast (ACE_OS::strlen (x.val_)); + } + + os.write_wstring (len, x.val_); + return + (ACE_CDR::Boolean) (os.good_bit () && (!x.bound_ || len <= x.bound_)); +} + +// **************************************************************** + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Char &x) +{ + return is.read_char (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Short &x) +{ + return is.read_short (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::UShort &x) +{ + return is.read_ushort (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>>(ACE_InputCDR &is, ACE_CDR::Long &x) +{ + return is.read_long (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::ULong &x) +{ + return is.read_ulong (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR& is, ACE_CDR::LongLong &x) +{ + return is.read_longlong (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR& is, ACE_CDR::ULongLong &x) +{ + return is.read_ulonglong (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR& is, ACE_CDR::LongDouble &x) +{ + return is.read_longdouble (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Float &x) +{ + return is.read_float (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Double &x) +{ + return is.read_double (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Fixed &x) +{ + return is.read_fixed (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::Char *&x) +{ + return is.read_string (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_CDR::WChar *&x) +{ + return is.read_wstring (x) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, std::string& x) +{ + return is.read_string (x) && is.good_bit (); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, std::wstring& x) +{ + return is.read_wstring (x) && is.good_bit (); +} +#endif + +// The following use the helper classes +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_boolean x) +{ + return is.read_boolean (x.ref_); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_char x) +{ + return is.read_char (x.ref_) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_wchar x) +{ + return is.read_wchar (x.ref_) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_octet x) +{ + return is.read_octet (x.ref_) && is.good_bit (); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_string x) +{ + // check if the bounds are satisfied + return + (is.read_string (const_cast (x.val_)) + && is.good_bit () + && (!x.bound_ + || ACE_OS::strlen (x.val_) <= x.bound_)); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_wstring x) +{ + // check if the bounds are satisfied + return + (is.read_wstring (const_cast (x.val_)) + && is.good_bit () + && (!x.bound_ + || ACE_OS::strlen (x.val_) <= x.bound_)); +} + +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_std_string x) +{ + // check if the bounds are satisfied + return + (is.read_string (x.val_) + && is.good_bit () + && (!x.bound_ + || static_cast (x.val_.size ()) <= x.bound_)); +} + +#if !defined(ACE_LACKS_STD_WSTRING) +ACE_INLINE ACE_CDR::Boolean +operator>> (ACE_InputCDR &is, ACE_InputCDR::to_std_wstring x) +{ + // check if the bounds are satisfied + return + (is.read_wstring (x.val_) + && is.good_bit () + && (!x.bound_ + || static_cast (x.val_.size ()) <= x.bound_)); +} +#endif +// *************************************************************************** +// We must define these methods here because they use the "read_*" inlined +// methods of the ACE_InputCDR class +// *************************************************************************** + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_boolean (ACE_InputCDR &stream) +{ + ACE_CDR::Boolean x; + return stream.read_boolean (x) ? this->write_boolean (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_char (ACE_InputCDR &stream) +{ + ACE_CDR::Char x; + return stream.read_char (x) ? this->write_char (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_wchar (ACE_InputCDR &stream) +{ + ACE_CDR::WChar x; + return stream.read_wchar (x) ? this->write_wchar (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_octet (ACE_InputCDR &stream) +{ + ACE_CDR::Octet x; + return stream.read_octet (x) ? this->write_octet (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_short (ACE_InputCDR &stream) +{ + ACE_CDR::Short x; + return stream.read_short (x) ? this->write_short (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_ushort (ACE_InputCDR &stream) +{ + ACE_CDR::UShort x; + return stream.read_ushort (x) ? this->write_ushort (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_long (ACE_InputCDR &stream) +{ + ACE_CDR::Long x; + return stream.read_long (x) ? this->write_long (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_ulong (ACE_InputCDR &stream) +{ + ACE_CDR::ULong x; + return stream.read_ulong (x) ? this->write_ulong (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_longlong (ACE_InputCDR &stream) +{ + ACE_CDR::LongLong x; + return stream.read_longlong (x) ? this->write_longlong (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_ulonglong (ACE_InputCDR &stream) +{ + ACE_CDR::ULongLong x; + return stream.read_ulonglong (x) ? this->write_ulonglong (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_float (ACE_InputCDR &stream) +{ + ACE_CDR::Float x; + return stream.read_float (x) ? this->write_float (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_double (ACE_InputCDR &stream) +{ + ACE_CDR::Double x; + return stream.read_double (x) ? this->write_double (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_longdouble (ACE_InputCDR &stream) +{ + ACE_CDR::LongDouble x; + return stream.read_longdouble (x) ? this->write_longdouble (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_fixed (ACE_InputCDR &stream) +{ + ACE_CDR::Fixed x; + return stream.read_fixed (x) ? this->write_fixed (x) : false; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_string (ACE_InputCDR &stream) +{ + ACE_CDR::Char *x = 0; + ACE_CDR::Boolean const flag = + (stream.read_string (x) ? this->write_string (x) : false); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(x); +#else + delete [] x; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return flag; +} + +ACE_INLINE ACE_CDR::Boolean +ACE_OutputCDR::append_wstring (ACE_InputCDR &stream) +{ + ACE_CDR::WChar *x = 0; + ACE_CDR::Boolean const flag = + (stream.read_wstring (x) ? this->write_wstring (x) : false); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(x); +#else + delete [] x; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return flag; +} + +ACE_INLINE void +ACE_InputCDR::reset_byte_order (int byte_order) +{ + this->do_byte_swap_ = (byte_order != ACE_CDR_BYTE_ORDER); +} + +ACE_INLINE bool +ACE_InputCDR::do_byte_swap (void) const +{ + return this->do_byte_swap_; +} + +ACE_INLINE int +ACE_InputCDR::byte_order (void) const +{ + return this->do_byte_swap () ? !ACE_CDR_BYTE_ORDER : ACE_CDR_BYTE_ORDER; +} + +ACE_INLINE int +ACE_InputCDR::align_read_ptr (size_t alignment) +{ +#if !defined (ACE_LACKS_CDR_ALIGNMENT) + char *buf = ACE_ptr_align_binary (this->rd_ptr (), + alignment); +#else + char *buf = this->rd_ptr (); +#endif /* ACE_LACKS_CDR_ALIGNMENT */ + + if (buf <= this->wr_ptr ()) + { + this->start_.rd_ptr (buf); + return 0; + } + + this->good_bit_ = false; + return -1; +} + +ACE_INLINE void +ACE_InputCDR::set_version (ACE_CDR::Octet major, ACE_CDR::Octet minor) +{ + this->major_version_ = major; + this->minor_version_ = minor; +} + +ACE_INLINE void +ACE_InputCDR::get_version (ACE_CDR::Octet &major, ACE_CDR::Octet &minor) +{ + major = this->major_version_; + minor = this->minor_version_; +} + +ACE_INLINE ACE_Char_Codeset_Translator * +ACE_InputCDR::char_translator (void) const +{ + return this->char_translator_; +} + +ACE_INLINE ACE_WChar_Codeset_Translator * +ACE_InputCDR::wchar_translator (void) const +{ + return this->wchar_translator_; +} + + +ACE_INLINE void +ACE_InputCDR::char_translator (ACE_Char_Codeset_Translator * ctran) +{ + this->char_translator_ = ctran; +} + +ACE_INLINE void +ACE_InputCDR::wchar_translator (ACE_WChar_Codeset_Translator * wctran) +{ + this->wchar_translator_ = wctran; +} + +// **************************************************************** + +ACE_INLINE ACE_CDR::Boolean +ACE_Char_Codeset_Translator::read_1 (ACE_InputCDR& input, + ACE_CDR::Octet *x) +{ + return input.read_1 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_Char_Codeset_Translator::write_1 (ACE_OutputCDR& output, + const ACE_CDR::Octet *x) +{ + return output.write_1 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_Char_Codeset_Translator::read_array (ACE_InputCDR& in, + void* x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + return in.read_array (x, size, align, length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_Char_Codeset_Translator::write_array (ACE_OutputCDR& out, + const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + return out.write_array(x, size, align, length); +} + +ACE_INLINE int +ACE_Char_Codeset_Translator::adjust (ACE_OutputCDR& out, + size_t size, + size_t align, + char *&buf) +{ + return out.adjust(size, align, buf); +} + +ACE_INLINE void +ACE_Char_Codeset_Translator::good_bit (ACE_OutputCDR& out, bool bit) +{ + out.good_bit_ = bit; +} + +ACE_INLINE ACE_CDR::Octet +ACE_Char_Codeset_Translator::major_version (ACE_InputCDR& input) +{ + return input.major_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_Char_Codeset_Translator::minor_version (ACE_InputCDR& input) +{ + return input.minor_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_Char_Codeset_Translator::major_version (ACE_OutputCDR& output) +{ + return output.major_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_Char_Codeset_Translator::minor_version (ACE_OutputCDR& output) +{ + return output.minor_version_; +} + +// **************************************************************** + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::read_1 (ACE_InputCDR& input, + ACE_CDR::Octet *x) +{ + return input.read_1 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::read_2 (ACE_InputCDR& input, + ACE_CDR::UShort *x) +{ + return input.read_2 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::read_4 (ACE_InputCDR& input, + ACE_CDR::ULong *x) +{ + return input.read_4 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::write_1 (ACE_OutputCDR& output, + const ACE_CDR::Octet *x) +{ + return output.write_1 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::write_2 (ACE_OutputCDR& output, + const ACE_CDR::UShort *x) +{ + return output.write_2 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::write_4 (ACE_OutputCDR& output, + const ACE_CDR::ULong *x) +{ + return output.write_4 (x); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::read_array (ACE_InputCDR& in, + void* x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + return in.read_array (x, size, align, length); +} + +ACE_INLINE ACE_CDR::Boolean +ACE_WChar_Codeset_Translator::write_array (ACE_OutputCDR& out, + const void *x, + size_t size, + size_t align, + ACE_CDR::ULong length) +{ + return out.write_array(x, size, align, length); +} + +ACE_INLINE int +ACE_WChar_Codeset_Translator::adjust (ACE_OutputCDR& out, + size_t size, + size_t align, + char *&buf) +{ + return out.adjust(size, align, buf); +} + +ACE_INLINE void +ACE_WChar_Codeset_Translator::good_bit (ACE_OutputCDR& out, bool bit) +{ + out.good_bit_ = bit; +} + +ACE_INLINE ACE_CDR::Octet +ACE_WChar_Codeset_Translator::major_version (ACE_InputCDR& input) +{ + return input.major_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_WChar_Codeset_Translator::minor_version (ACE_InputCDR& input) +{ + return input.minor_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_WChar_Codeset_Translator::major_version (ACE_OutputCDR& output) +{ + return output.major_version_; +} + +ACE_INLINE ACE_CDR::Octet +ACE_WChar_Codeset_Translator::minor_version (ACE_OutputCDR& output) +{ + return output.minor_version_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/CE_Screen_Output.cpp b/dep/acelite/ace/CE_Screen_Output.cpp new file mode 100644 index 000000000..8711f1e57 --- /dev/null +++ b/dep/acelite/ace/CE_Screen_Output.cpp @@ -0,0 +1,156 @@ +#include "ace/CE_Screen_Output.h" +#if defined (ACE_HAS_WINCE) + +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_CE_Screen_Output::ACE_CE_Screen_Output(HWND hEdit) +: handler_(hEdit) +, pFile_(0) +{ +} + +ACE_CE_Screen_Output::ACE_CE_Screen_Output() +: handler_(0) +, pFile_(0) +{ +} + +ACE_CE_Screen_Output::~ACE_CE_Screen_Output() +{ + if (pFile_ != 0) { + fclose(pFile_); + } +} + +void ACE_CE_Screen_Output::log(ACE_Log_Record &log_record) +{ + ACE_TCHAR verbose_msg[ACE_Log_Record::MAXVERBOSELOGMSGLEN]; + int result = log_record.format_msg (ACE_TEXT("WindozeCE"), // host name + 0, // verbose flag + verbose_msg); + + if (result == 0) + { + verbose_msg[ ACE_OS::strlen(verbose_msg) - 1 ] = 0; // CE does not like '\n' by itself. + *this << verbose_msg << endl; + } +} + +void ACE_CE_Screen_Output::SetOutputWindow(HWND hEdit) +{ + handler_ = hEdit; +} + +void ACE_CE_Screen_Output::clear() +{ + SetWindowText(handler_, 0); +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (ACE_TCHAR* output) +{ + int length = GetWindowTextLength(handler_); + SendMessage(handler_, EM_SETSEL, length, length); + SendMessage(handler_, EM_REPLACESEL, 0, (LPARAM)output); + + if (pFile_ != 0) + { + fwprintf(pFile_, L"%s", output); + } + + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (const ACE_TCHAR* output) +{ + ACE_TCHAR* buffer = ACE_OS::strdup(output); + if (buffer != 0) + { + *this << buffer; + delete buffer; + } + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (ACE_ANTI_TCHAR* output) +{ + *this << ACE_TEXT_CHAR_TO_TCHAR(output); + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (const ACE_ANTI_TCHAR* output) +{ + *this << ACE_TEXT_CHAR_TO_TCHAR(output); + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (char output) +{ + *this << (int)output; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (unsigned char output) +{ + *this << (int)output; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (unsigned short output) +{ + ACE_TCHAR buffer[20]; + wsprintf(buffer, ACE_TEXT("%u"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (int output) +{ + ACE_TCHAR buffer[20]; + wsprintf(buffer, ACE_TEXT("%d"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (unsigned int output) +{ + ACE_TCHAR buffer[20]; + wsprintf(buffer, ACE_TEXT("%du"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (float output) +{ + ACE_TCHAR buffer[20]; + swprintf(buffer, ACE_TEXT("%f"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (long output) +{ + ACE_TCHAR buffer[20]; + wsprintf(buffer, ACE_TEXT("%l"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (unsigned long output) +{ + ACE_TCHAR buffer[20]; + wsprintf(buffer, ACE_TEXT("%lu"), output); + *this << buffer; + return *this; +} + +ACE_CE_Screen_Output& ACE_CE_Screen_Output::operator << (FILE* pFile) +{ + pFile_ = pFile; + return *this; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif // ACE_HAS_WINCE diff --git a/dep/acelite/ace/CE_Screen_Output.h b/dep/acelite/ace/CE_Screen_Output.h new file mode 100644 index 000000000..65c697daa --- /dev/null +++ b/dep/acelite/ace/CE_Screen_Output.h @@ -0,0 +1,107 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file CE_Screen_Output.h + * + * @author Si Mong Park + */ +//============================================================================= + +#ifndef ACE_CE_SCREEN_OUTPUT_H +#define ACE_CE_SCREEN_OUTPUT_H + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_WINCE) + +#include "ace/Log_Msg_Callback.h" +#include "ace/Log_Record.h" + +namespace +{ + const ACE_TCHAR endl[] = ACE_TEXT("\r\n"); + const ACE_TCHAR tab[] = ACE_TEXT("\t"); +} + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_CE_Screen_Output + * + * @brief Replacement of text output for Windows CE. + * + * This class allows standard text output to be displayed on + * text window for Windows CE. Generally, all ACE output will + * go through under CE if and only if user uses Windows CE + * implementation by using main_ce instead of main. + * Also, for the easier debugging purpose, object pointer of + * this class can be gotten from ACE_Log_Msg::msg_callback() + * and then can be used directly by user just like cout stream. + */ +class ACE_Export ACE_CE_Screen_Output : public ACE_Log_Msg_Callback +{ +public: + + ACE_CE_Screen_Output (HWND hEdit); + + ACE_CE_Screen_Output (void); + + virtual ~ACE_CE_Screen_Output(); + + /// Implementation of pure virtual function from ACE_Log_Msg_Callback. + virtual void log (ACE_Log_Record &log_record); + + /// Interface to specify active window handle. + void SetOutputWindow (HWND hWnd); + + void clear (void); + + /// Stream insertion operator that performs actual print out. + /** + * @note This is the only one operator that performs output. All + * other perators convert the type and use this operator + * underneath. + */ + ACE_CE_Screen_Output& operator << (ACE_TCHAR*); + ACE_CE_Screen_Output& operator << (const ACE_TCHAR*); + + ACE_CE_Screen_Output& operator << (ACE_ANTI_TCHAR* output); + ACE_CE_Screen_Output& operator << (const ACE_ANTI_TCHAR* output); + + ACE_CE_Screen_Output& operator << (char output); + ACE_CE_Screen_Output& operator << (unsigned char output); + + ACE_CE_Screen_Output& operator << (unsigned short output); + + ACE_CE_Screen_Output& operator << (int output); + ACE_CE_Screen_Output& operator << (unsigned int output); + + ACE_CE_Screen_Output& operator << (float output); + + ACE_CE_Screen_Output& operator << (long output); + ACE_CE_Screen_Output& operator << (unsigned long output); + + ACE_CE_Screen_Output& operator << (FILE* pFile); + +private: + + ACE_CE_Screen_Output (ACE_CE_Screen_Output&); + +private: + + HWND handler_; + + /// FILE pointer that used to save output to file. This class does + /// not own the file handler pointer. + FILE* pFile_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif // ACE_HAS_WINCE +#endif // ACE_CE_SCREEN_OUTPUT_H diff --git a/dep/acelite/ace/CORBA_macros.h b/dep/acelite/ace/CORBA_macros.h new file mode 100644 index 000000000..9cd55e26d --- /dev/null +++ b/dep/acelite/ace/CORBA_macros.h @@ -0,0 +1,88 @@ +// -*- C++ -*- + +// ============================================================================ +/** + * @file CORBA_macros.h + * + * Writing code that is portable between platforms with or without + * native C++ exceptions is hard. The following macros offer some + * help on this task, mostly oriented to making the ORB code and the + * IDL generated code portable. + * + * @author Nanbor Wang + * @author Aniruddha Gokhale + * @author Carlos O'Ryan , et al. + */ +// ============================================================================ + +// Macros for handling CORBA exceptions. + +#ifndef ACE_CORBA_MACROS_H +#define ACE_CORBA_MACROS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +// The Windows MFC exception mechanism requires that a caught CException +// (including the CMemoryException in use here) be freed using its Delete() +// method. Thus, when MFC is in use and we're catching exceptions as a result +// of new(), the exception's Delete() method has to be called. No other +// platform imposes this sort of restriction/requirement. The Windows +// config stuff (at least for MSVC/MFC) defines a ACE_del_bad_alloc macro +// that works with its ACE_bad_alloc macro to implement this cleanup +// requirement. Since no other platform requires this, define it as +// empty here. +#if !defined (ACE_del_bad_alloc) +# define ACE_del_bad_alloc +#endif + +// ACE_HAS_EXCEPTIONS is not the same as ACE_NEW_THROWS_EXCEPTIONS. +#if defined(ACE_NEW_THROWS_EXCEPTIONS) + +# if defined (ACE_HAS_NEW_NOTHROW) + +# define ACE_NEW_THROW_EX(POINTER,CONSTRUCTOR,EXCEPTION) \ + do { POINTER = new (ACE_nothrow) CONSTRUCTOR; \ + if (POINTER == 0) { throw EXCEPTION; } \ + } while (0) + +# else + +# define ACE_NEW_THROW_EX(POINTER,CONSTRUCTOR,EXCEPTION) \ + do { try { POINTER = new CONSTRUCTOR; } \ + catch (ACE_bad_alloc) { ACE_del_bad_alloc throw EXCEPTION; } \ + } while (0) + +# endif /* ACE_HAS_NEW_NOTHROW */ + +#else /* ! ACE_NEW_THROWS_EXCEPTIONS */ + +# define ACE_NEW_THROW_EX(POINTER,CONSTRUCTOR,EXCEPTION) \ + do { POINTER = new CONSTRUCTOR; \ + if (POINTER == 0) { throw EXCEPTION; } \ + } while (0) + +#endif /* ACE_NEW_THROWS_EXCEPTIONS */ + +// FUZZ: disable check_for_ACE_Guard +# define ACE_GUARD_THROW_EX(MUTEX,OBJ,LOCK,EXCEPTION) \ + ACE_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) throw EXCEPTION; + +# define ACE_READ_GUARD_THROW_EX(MUTEX,OBJ,LOCK,EXCEPTION) \ + ACE_Read_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) throw EXCEPTION; + +# define ACE_WRITE_GUARD_THROW_EX(MUTEX,OBJ,LOCK,EXCEPTION) \ + ACE_Write_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) throw EXCEPTION; +// FUZZ: enable check_for_ACE_Guard + +#include /**/ "ace/post.h" + +#endif /* ACE_CORBA_MACROS_H */ diff --git a/dep/acelite/ace/Cache_Map_Manager_T.cpp b/dep/acelite/ace/Cache_Map_Manager_T.cpp new file mode 100644 index 000000000..b92876a7f --- /dev/null +++ b/dep/acelite/ace/Cache_Map_Manager_T.cpp @@ -0,0 +1,410 @@ +#ifndef ACE_CACHE_MAP_MANAGER_T_CPP +#define ACE_CACHE_MAP_MANAGER_T_CPP + +#include "ace/Cache_Map_Manager_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Log_Category.h" +#include "ace/Malloc_Base.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Cache_Map_Manager_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc7(ACE_Cache_Map_Manager) +ACE_ALLOC_HOOK_DEFINE_Tc5(ACE_Cache_Map_Iterator) +ACE_ALLOC_HOOK_DEFINE_Tc5(ACE_Cache_Map_Reverse_Iterator) + +template +ACE_Cache_Map_Manager::ACE_Cache_Map_Manager (CACHING_STRATEGY &caching_s, + size_t size, + ACE_Allocator *alloc) + : caching_strategy_ (caching_s) +{ + if (this->open (size, alloc) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Cache_Map_Manager::ACE_Cache_Map_Manager"))); + +} + +template +ACE_Cache_Map_Manager::~ACE_Cache_Map_Manager (void) +{ + this->close (); +} + +template int +ACE_Cache_Map_Manager::open (size_t length, + ACE_Allocator *alloc) +{ + return this->map_.open (length, + alloc); +} + +template int +ACE_Cache_Map_Manager::close (void) +{ + return this->map_.close (); +} + +template int +ACE_Cache_Map_Manager::bind (const KEY &key, + const VALUE &value) +{ + // Insert an entry which has the and the which + // is the combination of the and the attributes of the + // caching strategy. + CACHE_VALUE cache_value (value, + this->caching_strategy_.attributes ()); + + int bind_result = this->map_.bind (key, + cache_value); + + if (bind_result != -1) + { + + int result = this->caching_strategy_.notify_bind (bind_result, + cache_value.second); + + if (result == -1) + { + + this->map_.unbind (key); + + // Unless the notification goes thru the bind operation is + // not complete. + bind_result = -1; + + } + + } + + return bind_result; +} + + +template int +ACE_Cache_Map_Manager::rebind (const KEY &key, + const VALUE &value) +{ + CACHE_VALUE cache_value (value, + this->caching_strategy_.attributes ()); + + int rebind_result = this->map_.rebind (key, + cache_value); + + if (rebind_result != -1) + { + + int result = this->caching_strategy_.notify_rebind (rebind_result, + cache_value.second ()); + + if (result == -1) + { + + // Make sure the unbind operation is done only when the + // notification fails after a bind which is denoted by + // rebind_result = 0 + if (rebind_result == 0) + this->map_.unbind (key); + + // Unless the notification goes thru the rebind operation is + // not complete. + rebind_result = -1; + + } + + } + + return rebind_result; +} + + +template int +ACE_Cache_Map_Manager::rebind (const KEY &key, + const VALUE &value, + VALUE &old_value) +{ + CACHE_VALUE cache_value (value, + this->caching_strategy_.attributes ()); + + CACHE_VALUE old_cache_value (old_value, + this->caching_strategy_.attributes ()); + + int rebind_result = this->map_.rebind (key, + cache_value, + old_cache_value); + + if (rebind_result != -1) + { + + int result = this->caching_strategy_.notify_rebind (rebind_result, + cache_value.second ()); + + if (result == -1) + { + + // Make sure the unbind operation is done only when the + // notification fails after a bind which is denoted by + // rebind_result = 0 + if (rebind_result == 0) + this->map_.unbind (key); + + // Unless the notification goes thru the rebind operation is + // not complete. + rebind_result = -1; + + } + else + { + + old_value = old_cache_value.first (); + + } + + } + + return rebind_result; +} + +template int +ACE_Cache_Map_Manager::rebind (const KEY &key, + const VALUE &value, + KEY &old_key, + VALUE &old_value) +{ + CACHE_VALUE cache_value (value, + this->caching_strategy_.attributes ()); + + CACHE_VALUE old_cache_value (old_value, + this->caching_strategy_.attributes ()); + + int rebind_result = this->map_.rebind (key, + cache_value, + old_key, + old_cache_value); + + if (rebind_result != -1) + { + + int result = this->caching_strategy_.notify_rebind (rebind_result, + cache_value.second ()); + + if (result == -1) + { + + // Make sure the unbind operation is done only when the + // notification fails after a bind which is denoted by + // rebind_result = 0 + if (rebind_result == 0) + this->map_.unbind (key); + + // Unless the notification goes thru the rebind operation is + // not complete. + rebind_result = -1; + + } + else + { + + old_value = old_cache_value.first (); + + } + + } + + return rebind_result; +} + +template int +ACE_Cache_Map_Manager::trybind (const KEY &key, + VALUE &value) +{ + CACHE_VALUE cache_value (value, + this->caching_strategy_.attributes ()); + + int trybind_result = this->map_.trybind (key, + cache_value); + + if (trybind_result != -1) + { + + int result = this->caching_strategy_.notify_trybind (trybind_result, + cache_value.second ()); + + if (result == -1) + { + + // If the entry has got inserted into the map, it is removed + // due to failure. + if (trybind_result == 0) + this->map_.unbind (key); + + trybind_result = -1; + + } + else + { + + // If an attempt is made to bind an existing entry the value + // is overwritten with the value from the map. + if (trybind_result == 1) + value = cache_value.first (); + + } + + } + + return trybind_result; +} + +template int +ACE_Cache_Map_Manager::find (const KEY &key, + VALUE &value) +{ + // Lookup the key and populate the . + CACHE_VALUE cache_value; + + int find_result = this->map_.find (key, + cache_value); + + if (find_result != -1) + { + + int result = this->caching_strategy_.notify_find (find_result, + cache_value.second); + + // Unless the find and notification operations go thru, this + // method is not successful. + if (result == -1) + find_result = -1; + else + { + + // Since the has now changed after the + // notification, we need to bind to the map again. + int rebind_result = this->map_.rebind (key, + cache_value); + if (rebind_result == -1) + find_result = -1; + else + value = cache_value.first; + + } + + } + + return find_result; +} + +template int +ACE_Cache_Map_Manager::find (const KEY &key) +{ + // Lookup the key and populate the . + CACHE_VALUE cache_value; + + int find_result = this->map_.find (key, + cache_value); + + if (find_result != -1) + { + + int result = this->caching_strategy_.notify_find (find_result, + cache_value.second); + + // Unless the find and notification operations go thru, this + // method is not successful. + if (result == -1) + find_result = -1; + else + { + + // Since the has now changed after the + // notification, we need to bind to the map again. + int rebind_result = this->map_.rebind (key, + cache_value); + + if (rebind_result == -1) + find_result = -1; + + } + + } + + return find_result; +} + + +template int +ACE_Cache_Map_Manager::unbind (const KEY &key) +{ + // Remove the entry from the cache. + CACHE_VALUE cache_value; + + int unbind_result = this->map_.unbind (key, + cache_value); + + if (unbind_result != -1) + { + + int result = this->caching_strategy_.notify_unbind (unbind_result, + cache_value.second); + + if (result == -1) + unbind_result = -1; + + } + + return unbind_result; +} + +template int +ACE_Cache_Map_Manager::unbind (const KEY &key, + VALUE &value) +{ + // Remove the entry from the cache. + CACHE_VALUE cache_value; + + int unbind_result = this->map_.unbind (key, + cache_value); + + if (unbind_result != -1) + { + + int result = this->caching_strategy_.notify_unbind (unbind_result, + cache_value.second ()); + + if (result == -1) + unbind_result = -1; + else + value = cache_value.first (); + + } + + return unbind_result; +} + +template void +ACE_Cache_Map_Manager::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->map_.dump (); + + this->caching_strategy_.dump (); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Cache_Map_Iterator::~ACE_Cache_Map_Iterator (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CACHE_MAP_MANAGER_T_CPP */ diff --git a/dep/acelite/ace/Cache_Map_Manager_T.h b/dep/acelite/ace/Cache_Map_Manager_T.h new file mode 100644 index 000000000..f76faec05 --- /dev/null +++ b/dep/acelite/ace/Cache_Map_Manager_T.h @@ -0,0 +1,406 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Cache_Map_Manager_T.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + +#ifndef ACE_CACHE_MAP_MANAGER_T_H +#define ACE_CACHE_MAP_MANAGER_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Default_Constants.h" +#include "ace/Global_Macros.h" +#include "ace/Pair_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declaration. +class ACE_Allocator; + +#define ACE_Cache_Map_Iterator ACMI +#define ACE_Cache_Map_Reverse_Iterator ACMRI + +template +class ACE_Cache_Map_Iterator; + +template +class ACE_Cache_Map_Reverse_Iterator; + +// For linkers that cant grok long names. +#define ACE_Cache_Map_Manager ACMM + +/** + * @class ACE_Cache_Map_Manager + * + * @brief Defines a abstraction that will purge entries from a map. + * + * The will manage the map it contains + * and provide purging on demand from the map. The strategy for + * caching is decided by the user and provided to the Cache + * Manager. The Cache Manager acts as a agent and communicates + * between the Map and the Strategy for purging entries from the + * map. + * No locking mechanism provided since locking at this level + * isn't efficient. Locking has to be provided by the + * application. + */ +template +class ACE_Cache_Map_Manager +{ +public: + + // = Traits. + typedef KEY key_type; + typedef VALUE mapped_type; + typedef CMAP_TYPE map_type; + typedef CACHING_STRATEGY caching_strategy_type; + + typedef ITERATOR_IMPL ITERATOR_IMPLEMENTATION; + typedef REVERSE_ITERATOR_IMPL REVERSE_ITERATOR_IMPLEMENTATION; + + friend class ACE_Cache_Map_Iterator; + friend class ACE_Cache_Map_Reverse_Iterator; + + // = ACE-style iterator typedefs. + typedef ACE_Cache_Map_Iterator + ITERATOR; + typedef ACE_Cache_Map_Reverse_Iterator + REVERSE_ITERATOR; + + // = STL-style iterator typedefs. + typedef ITERATOR + iterator; + typedef REVERSE_ITERATOR + reverse_iterator; + + /** + * The actual value mapped to the key in the map. The + * are used by the strategy and is transparent to the user of this + * class. + */ + typedef std::pair CACHE_VALUE; + + // = Initialization and termination methods. + + /// Initialize a with and + /// @a size entries. + ACE_Cache_Map_Manager (CACHING_STRATEGY &caching_strategy, + size_t size = ACE_DEFAULT_MAP_SIZE, + ACE_Allocator *alloc = 0); + + /// Close down a and release dynamically allocated + /// resources. + virtual ~ACE_Cache_Map_Manager (void); + + /// Initialize a cache with size @a length. + int open (size_t length = ACE_DEFAULT_MAP_SIZE, + ACE_Allocator *alloc = 0); + + /// Close down a cache and release dynamically allocated resources. + int close (void); + + /** + * Associate @a key with @a value. If @a key is already in the CMAP_TYPE + * then the ENTRY is not changed. Returns 0 if a new entry is bound + * successfully, returns 1 if an attempt is made to bind an existing + * entry, and returns -1 if failures occur. + */ + int bind (const KEY &key, + const VALUE &value); + + /** + * Lookup entry in the cache. If it is not found, returns -1. + * If the @a key is located in the CMAP_TYPE object, the CACHING_STRATEGY is + * notified of it via notify_find (int result, ATTRIBUTES &attribute). + * If notify_find also returns 0 (success), then this function returns + * 0 (success) and sets the cached value in @a value. + */ + int find (const KEY &key, + VALUE &value); + + /** + * Lookup entry in the cache. If it is not found, returns -1. + * If the @a key is located in the CMAP_TYPE object, the CACHING_STRATEGY is + * notified of it via notify_find (int result, ATTRIBUTES &attribute). + * If notify_find also returns 0 (success), then this function returns + * 0 (success). + */ + int find (const KEY &key); + + /** + * Reassociate the @a key with @a value. If the @a key already exists + * in the cache then returns 1, on a new bind returns 0 and returns + * -1 in case of any failures. + */ + int rebind (const KEY &key, + const VALUE &value); + + /** + * Reassociate @a key with @a value, storing the old value into the + * "out" parameter @a old_value. The function fails if @a key is not + * in the cache for caches that do not allow user specified keys. + * However, for caches that allow user specified keys, if the key is + * not in the cache, a new @a key / @a value association is created. + */ + int rebind (const KEY &key, + const VALUE &value, + VALUE &old_value); + + /** + * Reassociate @a key with @a value, storing the old key and value + * into the "out" parameters @a old_key and @a old_value. The + * function fails if @a key is not in the cache for caches that do + * not allow user specified keys. However, for caches that allow + * user specified keys, if the key is not in the cache, a new + * @a key / @a value association is created. + */ + int rebind (const KEY &key, + const VALUE &value, + KEY &old_key, + VALUE &old_value); + + /** + * Associate @a key with @a value if and only if @a key is not in the + * cache. If @a key is already in the cache, then the @a value + * parameter is overwritten with the existing value in the + * cache. Returns 0 if a new @a key / @a value association is created. + * Returns 1 if an attempt is made to bind an existing entry. This + * function fails for maps that do not allow user specified keys. + */ + int trybind (const KEY &key, + VALUE &value); + + /// Remove @a key from the cache. + int unbind (const KEY &key); + + /// Remove @a key from the cache, and return the @a value associated with + /// @a key. + int unbind (const KEY &key, + VALUE &value); + + /// Remove entries from the cache depending upon the strategy. + int purge (void); + + /// Return the current size of the cache. + size_t current_size (void) const; + + /// Return the total size of the cache. + size_t total_size (void) const; + + /// Dumps the state of the object. + void dump (void) const; + + // = STL styled iterator factory functions. + + /// Return forward iterator. + ITERATOR begin (void); + ITERATOR end (void); + + /// Return reverse iterator. + REVERSE_ITERATOR rbegin (void); + REVERSE_ITERATOR rend (void); + + /// The map managed by the Cache_Map_Manager. + CMAP_TYPE &map (void); + + /// The caching strategy used on the cache. + CACHING_STRATEGY &caching_strategy (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// The underlying map which needs to be cached. + CMAP_TYPE map_; + + /// The strategy to be followed for caching entries in the map. + CACHING_STRATEGY &caching_strategy_; + +private: + + // = Disallow these operations. + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Cache_Map_Manager &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Cache_Map_Manager (const ACE_Cache_Map_Manager &)) + +}; + +/** + * @class ACE_Cache_Map_Iterator + * + * @brief Defines a iterator for the Cache_Map_Manager. + * + * Implementation to be provided by the iterator of the map + * managed by the ACE_Cache_Map_Manager. + */ +template +class ACE_Cache_Map_Iterator +{ + +public: + + // = Traits. + /// The actual value mapped to the key in the cache. The + /// are used by the strategy and is transparent to the cache user. + typedef ACE_Reference_Pair + value_type; + typedef std::pair + CACHE_VALUE; + + // = Initialisation and termination methods. + + ACE_Cache_Map_Iterator (const IMPLEMENTATION &iterator_impl); + + /// Copy constructor. + ACE_Cache_Map_Iterator (const ACE_Cache_Map_Iterator &rhs); + + virtual ~ACE_Cache_Map_Iterator (void); + + // = Iteration methods. + + /// assignment operator. + ACE_Cache_Map_Iterator &operator= + (const ACE_Cache_Map_Iterator &rhs); + + /// Comparison operators. + bool operator== (const ACE_Cache_Map_Iterator &rhs) const; + bool operator!= (const ACE_Cache_Map_Iterator &rhs) const; + + /// Returns a reference to the internal element @c this is pointing + /// to. + ACE_Reference_Pair operator* (void) const; + + // = STL styled iteration, compare, and reference functions. + + /// Prefix advance + ACE_Cache_Map_Iterator &operator++ (void); + + /// Postfix advance. + ACE_Cache_Map_Iterator operator++ (int); + + /// Prefix reverse. + ACE_Cache_Map_Iterator &operator-- (void); + + /// Postfix reverse. + ACE_Cache_Map_Iterator operator-- (int); + + /// Returns the iterator of the internal map in the custody of the + /// Cache_Map_Manager. + IMPLEMENTATION &iterator_implementation (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// The actual iterator which iterates internally on the map + /// belonging to the Cache_Map_Manager. + IMPLEMENTATION iterator_implementation_; +}; + +/** + * @class ACE_Cache_Map_Reverse_Iterator + * + * @brief Defines a reverse iterator for the Cache_Map_Manager. + * + * Implementation to be provided by the reverse iterator of the map + * managed by thr Cache_Map_manager. + */ +template +class ACE_Cache_Map_Reverse_Iterator +{ +public: + + // = Traits. + /// The actual value mapped to the key in the cache. The + /// are used by the strategy and is transparent to the cache user. + typedef ACE_Reference_Pair value_type; + typedef std::pair CACHE_VALUE; + + // = Initialisation and termination methods. + + ACE_Cache_Map_Reverse_Iterator (const REVERSE_IMPLEMENTATION &iterator_impl); + + /// Copy constructor. + ACE_Cache_Map_Reverse_Iterator (const ACE_Cache_Map_Reverse_Iterator &rhs); + + ~ACE_Cache_Map_Reverse_Iterator (void); + + // = Iteration methods. + + /// Assignment operator. + ACE_Cache_Map_Reverse_Iterator &operator= + (const ACE_Cache_Map_Reverse_Iterator &rhs); + + /// Comparison operators. + bool operator== (const ACE_Cache_Map_Reverse_Iterator &rhs) const; + bool operator!= (const ACE_Cache_Map_Reverse_Iterator &rhs) const; + + /// Returns a reference to the internal element @c this is pointing + /// to. + ACE_Reference_Pair operator* (void) const; + + // = STL styled iteration, compare, and reference functions. + + /// Prefix advance + ACE_Cache_Map_Reverse_Iterator &operator++ (void); + + /// Postfix advance. + ACE_Cache_Map_Reverse_Iterator operator++ (int); + + /// Prefix reverse. + ACE_Cache_Map_Reverse_Iterator &operator-- (void); + + /// Postfix reverse. + ACE_Cache_Map_Reverse_Iterator operator-- (int); + + /// Returns the iterator of the internal map in the custody of the + /// Cache_Map_Manager. + REVERSE_IMPLEMENTATION &iterator_implementation (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// The actual iterator which iterates internally on the map + /// belonging to the Cache_Map_Manager. + REVERSE_IMPLEMENTATION reverse_iterator_implementation_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Cache_Map_Manager_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Cache_Map_Manager_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Cache_Map_Manager_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CACHE_MAP_MANAGER_T_H */ diff --git a/dep/acelite/ace/Cache_Map_Manager_T.inl b/dep/acelite/ace/Cache_Map_Manager_T.inl new file mode 100644 index 000000000..dc2a42ef0 --- /dev/null +++ b/dep/acelite/ace/Cache_Map_Manager_T.inl @@ -0,0 +1,243 @@ +// -*- C++ -*- +// +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE int +ACE_Cache_Map_Manager::purge (void) +{ + return this->caching_strategy ().caching_utility ().clear_cache (this->map_, + this->caching_strategy ().purge_percent ()); +} + +template ACE_INLINE size_t +ACE_Cache_Map_Manager::current_size (void) const +{ + return this->map_.current_size (); +} + +template ACE_INLINE size_t +ACE_Cache_Map_Manager::total_size (void) const +{ + return this->map_.total_size (); +} + +template ACE_INLINE CMAP_TYPE & +ACE_Cache_Map_Manager::map (void) +{ + return this->map_; +} + +template ACE_INLINE CACHING_STRATEGY & +ACE_Cache_Map_Manager::caching_strategy (void) +{ + return this->caching_strategy_; +} + +template ACE_INLINE ACE_Cache_Map_Iterator +ACE_Cache_Map_Manager::begin (void) +{ + return ITERATOR (this->map_.begin ()); +} + +template ACE_INLINE ACE_Cache_Map_Iterator +ACE_Cache_Map_Manager::end (void) +{ + return ITERATOR (this->map_.end ()); +} + +template ACE_INLINE ACE_Cache_Map_Reverse_Iterator +ACE_Cache_Map_Manager::rbegin (void) +{ + return REVERSE_ITERATOR (this->map_.rbegin ()); +} +template ACE_INLINE ACE_Cache_Map_Reverse_Iterator +ACE_Cache_Map_Manager::rend (void) +{ + return REVERSE_ITERATOR (this->map_.rend ()); +} + +//////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE +ACE_Cache_Map_Iterator::ACE_Cache_Map_Iterator (const ACE_Cache_Map_Iterator &rhs) + : iterator_implementation_ (rhs.iterator_implementation_) +{ +} + +template ACE_INLINE ACE_Cache_Map_Iterator & +ACE_Cache_Map_Iterator::operator= (const ACE_Cache_Map_Iterator &rhs) +{ + this->iterator_implementation_ = rhs.iterator_implementation_; + return *this; +} + +template ACE_INLINE bool +ACE_Cache_Map_Iterator::operator== (const ACE_Cache_Map_Iterator &rhs) const +{ + return this->iterator_implementation_ == rhs.iterator_implementation_; +} + +template ACE_INLINE bool +ACE_Cache_Map_Iterator::operator!= (const ACE_Cache_Map_Iterator &rhs) const +{ + return this->iterator_implementation_ != rhs.iterator_implementation_; +} + +template ACE_INLINE ACE_Reference_Pair +ACE_Cache_Map_Iterator::operator* (void) const +{ + value_type retn ((*this->iterator_implementation_).ext_id_, + (*this->iterator_implementation_).int_id_.first); + return retn; +} + +template ACE_INLINE +ACE_Cache_Map_Iterator & +ACE_Cache_Map_Iterator::operator++ (void) +{ + ++this->iterator_implementation_; + return *this; +} + +template ACE_INLINE +ACE_Cache_Map_Iterator +ACE_Cache_Map_Iterator::operator++ (int) +{ + ACE_Cache_Map_Iterator retn = *this; + ++this->iterator_implementation_; + return retn; +} + +template ACE_INLINE +ACE_Cache_Map_Iterator & +ACE_Cache_Map_Iterator::operator-- (void) +{ + --this->iterator_implementation_; + return *this; +} + +template ACE_INLINE +ACE_Cache_Map_Iterator +ACE_Cache_Map_Iterator::operator-- (int) +{ + ACE_Cache_Map_Iterator retn = *this; + --this->iterator_implementation_; + return retn; +} + +template ACE_INLINE void +ACE_Cache_Map_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->iterator_implementation_.dump (); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE +ACE_Cache_Map_Iterator::ACE_Cache_Map_Iterator (const IMPLEMENTATION &iterator_impl) + : iterator_implementation_ (iterator_impl) +{ +} + +template ACE_INLINE IMPLEMENTATION & +ACE_Cache_Map_Iterator::iterator_implementation (void) +{ + return this->iterator_implementation_; +} + +//////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator::ACE_Cache_Map_Reverse_Iterator (const ACE_Cache_Map_Reverse_Iterator &rhs) + : reverse_iterator_implementation_ (rhs.reverse_iterator_implementation_) +{ +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator::~ACE_Cache_Map_Reverse_Iterator (void) +{ +} + +template ACE_INLINE ACE_Cache_Map_Reverse_Iterator & +ACE_Cache_Map_Reverse_Iterator::operator= (const ACE_Cache_Map_Reverse_Iterator &rhs) +{ + this->reverse_iterator_implementation_ = rhs.reverse_iterator_implementation_; + return *this; +} + +template ACE_INLINE bool +ACE_Cache_Map_Reverse_Iterator::operator== (const ACE_Cache_Map_Reverse_Iterator &rhs) const +{ + return this->reverse_iterator_implementation_ == rhs.reverse_iterator_implementation_; +} + +template ACE_INLINE bool +ACE_Cache_Map_Reverse_Iterator::operator!= (const ACE_Cache_Map_Reverse_Iterator &rhs) const +{ + return this->reverse_iterator_implementation_ != rhs.reverse_iterator_implementation_; +} + +template ACE_INLINE ACE_Reference_Pair +ACE_Cache_Map_Reverse_Iterator::operator* (void) const +{ + value_type retv ((*this->reverse_iterator_implementation_).ext_id_, + (*this->reverse_iterator_implementation_).int_id_.first); + return retv; +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator & +ACE_Cache_Map_Reverse_Iterator::operator++ (void) +{ + ++this->reverse_iterator_implementation_; + return *this; +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator +ACE_Cache_Map_Reverse_Iterator::operator++ (int) +{ + ACE_Cache_Map_Reverse_Iterator retn = *this; + ++this->reverse_iterator_implementation_; + return retn; +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator & +ACE_Cache_Map_Reverse_Iterator::operator-- (void) +{ + --this->reverse_iterator_implementation_; + return *this; +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator +ACE_Cache_Map_Reverse_Iterator::operator-- (int) +{ + ACE_Cache_Map_Reverse_Iterator retn = *this; + --this->reverse_iterator_implementation_; + return retn; +} + + +template ACE_INLINE void +ACE_Cache_Map_Reverse_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->reverse_iterator_implementation_.dump (); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE +ACE_Cache_Map_Reverse_Iterator::ACE_Cache_Map_Reverse_Iterator (const REVERSE_IMPLEMENTATION &iterator_impl) + : reverse_iterator_implementation_(iterator_impl) +{ +} + +template ACE_INLINE REVERSE_IMPLEMENTATION & +ACE_Cache_Map_Reverse_Iterator::iterator_implementation (void) +{ + return this->reverse_iterator_implementation_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Cached_Connect_Strategy_T.cpp b/dep/acelite/ace/Cached_Connect_Strategy_T.cpp new file mode 100644 index 000000000..7a563edee --- /dev/null +++ b/dep/acelite/ace/Cached_Connect_Strategy_T.cpp @@ -0,0 +1,728 @@ +#ifndef ACE_CACHED_CONNECT_STRATEGY_T_CPP +#define ACE_CACHED_CONNECT_STRATEGY_T_CPP + +#include "ace/Cached_Connect_Strategy_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/ACE.h" +#include "ace/Service_Repository.h" +#include "ace/Service_Types.h" +#include "ace/Thread_Manager.h" +#include "ace/WFMO_Reactor.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tcoccc (ACE_Cached_Connect_Strategy_Ex) +ACE_ALLOC_HOOK_DEFINE_Tcoccc (ACE_Bounded_Cached_Connect_Strategy) + +template +ACE_Cached_Connect_Strategy_Ex::ACE_Cached_Connect_Strategy_Ex +(CACHING_STRATEGY &caching_s, + ACE_Creation_Strategy *cre_s, + ACE_Concurrency_Strategy *con_s, + ACE_Recycling_Strategy *rec_s, + MUTEX *lock, + int delete_lock) + : CCSBASE (cre_s, con_s, rec_s, lock, delete_lock), + connection_cache_ (caching_s) +{ + if (this->open (cre_s, con_s, rec_s) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Cached_Connect_Strategy_Ex\n"))); +} + +template +ACE_Cached_Connect_Strategy_Ex::~ACE_Cached_Connect_Strategy_Ex (void) +{ + cleanup (); +} + + +template int +ACE_Cached_Connect_Strategy_Ex::check_hint_i +(SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, std::pair > *&entry, + int &found) +{ + ACE_UNUSED_ARG (remote_addr); + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (local_addr); + ACE_UNUSED_ARG (reuse_addr); + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (perms); + + found = 0; + + // Get the recycling act for the svc_handler + CONNECTION_CACHE_ENTRY *possible_entry = + (CONNECTION_CACHE_ENTRY *) sh->recycling_act (); + + // Check to see if the hint svc_handler has been closed down + if (possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_CLOSED) + { + // If close, decrement refcount + if (possible_entry->ext_id_.decrement () == 0) + { + // If refcount goes to zero, close down the svc_handler + possible_entry->int_id_.first->recycler (0, 0); + possible_entry->int_id_.first->close (); + this->purge_i (possible_entry); + } + + // Hint not successful + found = 0; + + // Reset hint + sh = 0; + } + + // If hint is not closed, see if it is connected to the correct + // address and is recyclable + else if ((possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE || + possible_entry->ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_BUT_NOT_PURGABLE) && + possible_entry->ext_id_.subject () == remote_addr) + { + // Hint successful + found = 1; + + // Tell the that it should prepare itself for + // being recycled. + this->prepare_for_recycling (sh); + + // + // Update the caching attributes directly since we don't do a + // find() on the cache map. + // + + // Indicates successful find. + int find_result = 0; + + int result = this->caching_strategy ().notify_find (find_result, + possible_entry->int_id_.second); + + if (result == -1) + return result; + } + else + { + // This hint will not be used. + possible_entry->ext_id_.decrement (); + + // Hint not successful + found = 0; + + // If is not connected to the correct address or is busy, + // we will not use it. + sh = 0; + } + + if (found) + entry = possible_entry; + + return 0; +} + +template int +ACE_Cached_Connect_Strategy_Ex::find_or_create_svc_handler_i +(SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, std::pair > *&entry, + int &found) +{ + REFCOUNTED_HASH_RECYCLABLE_ADDRESS search_addr (remote_addr); + + // Try to find the address in the cache. Only if we don't find it + // do we create a new and connect it with the server. + while (this->find (search_addr, entry) != -1) + { + // We found a cached svc_handler. + // Get the cached + sh = entry->int_id_.first; + + // Is the connection clean? + int state_result = + ACE::handle_ready (sh->peer ().get_handle (), + &ACE_Time_Value::zero, + 1, // read ready + 0, // write ready + 1);// exception ready + + if (state_result == 1) + { + + if (sh->close () == -1) + return -1; + + sh = 0; + + // Cycle it once again.. + } + else if ((state_result == -1) && (errno == ETIME)) + { + // Found!!! + // Set the flag + found = 1; + + // Tell the that it should prepare itself for + // being recycled. + if (this->prepare_for_recycling (sh) == -1) + return -1; + + return 0; + } + else + { + return -1; + } + } + + // Not found... + + // Set the flag + found = 0; + + // We need to use a temporary variable here since we are not + // allowed to change because other threads may use this + // when we let go of the lock during the OS level connect. + // + // Note that making a new svc_handler, connecting remotely, + // binding to the map, and assigning of the hint and recycler + // should be atomic to the outside world. + SVC_HANDLER *potential_handler = 0; + + // Create a new svc_handler + if (this->make_svc_handler (potential_handler) == -1) + return -1; + + // Connect using the svc_handler. + if (this->cached_connect (potential_handler, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms) == -1) + { + // Close the svc handler. + potential_handler->close (0); + + return -1; + } + else + { + // Insert the new SVC_HANDLER instance into the cache. + if (this->connection_cache_.bind (search_addr, + potential_handler, + entry) == -1) + { + // Close the svc handler and reset . + potential_handler->close (0); + + return -1; + } + + // Everything succeeded as planned. Assign to + // . + sh = potential_handler; + + // Set the recycler and the recycling act + + this->assign_recycler (sh, this, entry); + } + + return 0; +} + +template int +ACE_Cached_Connect_Strategy_Ex::cached_connect (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms) +{ + // Actively establish the connection. This is a timed blocking + // connect. + if (this->new_connection (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms) == -1) + { + // If connect() failed because of timeouts, we have to reject + // the connection entirely. This is necessary since currently + // there is no way for the non-blocking connects to complete and + // for the to notify the cache of the completion of + // connect(). + + if (errno == EWOULDBLOCK || errno == ETIMEDOUT) + errno = ENOTSUP; + else if (ACE::out_of_handles (errno) || errno == EADDRINUSE) + { + // If the connect failed due to the process running out of + // file descriptors then, auto_purging of some connections + // are done from the CONNECTION_CACHE. This frees the + // descriptors which get used in the connect process and + // hence the same method is called again! + if (this->purge_connections () == -1) + return -1; + + // Try connecting again. + if (this->new_connection (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms) == -1) + { + if (errno == EWOULDBLOCK || errno == ETIMEDOUT) + errno = ENOTSUP; + return -1; + } + } + else + { + return -1; + } + } + + return 0; + +} + + +template int +ACE_Cached_Connect_Strategy_Ex::connect_svc_handler_i +(SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + int& found) +{ + CONNECTION_CACHE_ENTRY *entry = 0; + + // Check if the user passed a hint svc_handler + if (sh != 0) + { + int result = this->check_hint_i (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms, + entry, + found); + if (result != 0) + return result; + } + + // If not found + if (!found) + { + int result = this->find_or_create_svc_handler_i (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms, + entry, + found); + + if (result != 0) + return result; + + // Increment the refcount + entry->ext_id_.increment (); + } + + if (entry) + { + // For all successful cases: mark the in the cache + // as being . Therefore recyclable is BUSY. + entry->ext_id_.recycle_state (ACE_RECYCLABLE_BUSY); + } + + return 0; +} + + +template int +ACE_Cached_Connect_Strategy_Ex::cache_i (const void *recycling_act) +{ + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + // Mark the in the cache as not being . + // Therefore recyclable is IDLE. + entry->ext_id_.recycle_state (ACE_RECYCLABLE_IDLE_AND_PURGABLE); + + return 0; +} + +template int +ACE_Cached_Connect_Strategy_Ex::recycle_state_i (const void *recycling_act, + ACE_Recyclable_State new_state) +{ + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + // Mark the in the cache as not being . + // Therefore recyclable is IDLE. + entry->ext_id_.recycle_state (new_state); + + return 0; +} + +template ACE_Recyclable_State +ACE_Cached_Connect_Strategy_Ex::recycle_state_i (const void *recycling_act) const +{ + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + // Mark the in the cache as not being . + // Therefore recyclable is IDLE. + return entry->ext_id_.recycle_state (); +} + +template int +ACE_Cached_Connect_Strategy_Ex::purge_i (const void *recycling_act) +{ + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + return this->connection_cache_.unbind (entry); +} + + +template int +ACE_Cached_Connect_Strategy_Ex::mark_as_closed_i (const void *recycling_act) +{ + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + // Mark the in the cache as CLOSED. + entry->ext_id_.recycle_state (ACE_RECYCLABLE_CLOSED); + + return 0; +} + +template int +ACE_Cached_Connect_Strategy_Ex::cleanup_hint_i (const void *recycling_act, + void **act_holder) +{ + // Reset the <*act_holder> in the confines and protection of the + // lock. + if (act_holder) + *act_holder = 0; + + // The wonders and perils of ACT + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) recycling_act; + + // Decrement the refcount on the . + int refcount = entry->ext_id_.decrement (); + + // If the svc_handler state is closed and the refcount == 0, call + // close() on svc_handler. + if (entry->ext_id_.recycle_state () == ACE_RECYCLABLE_CLOSED && + refcount == 0) + { + entry->int_id_.first->recycler (0, 0); + entry->int_id_.first->close (); + this->purge_i (entry); + } + + return 0; +} + +template int +ACE_Cached_Connect_Strategy_Ex::purge_connections (void) +{ + return this->connection_cache_.purge (); +} + +template CACHING_STRATEGY & +ACE_Cached_Connect_Strategy_Ex::caching_strategy (void) +{ + return this->connection_cache_.caching_strategy (); +} + +template int +ACE_Cached_Connect_Strategy_Ex::find (ACE_Refcounted_Hash_Recyclable &search_addr, + ACE_Hash_Map_Entry, std::pair > *&entry) +{ + typedef ACE_Hash_Map_Bucket_Iterator, + ACE_Hash, + ACE_Equal_To, + ACE_Null_Mutex> + CONNECTION_CACHE_BUCKET_ITERATOR; + + CONNECTION_CACHE_BUCKET_ITERATOR iterator (this->connection_cache_.map (), + search_addr); + + CONNECTION_CACHE_BUCKET_ITERATOR end (this->connection_cache_.map (), + search_addr, + 1); + + for (; + iterator != end; + ++iterator) + { + REFCOUNTED_HASH_RECYCLABLE_ADDRESS &addr = (*iterator).ext_id_; + + if (addr.recycle_state () != ACE_RECYCLABLE_IDLE_AND_PURGABLE && + addr.recycle_state () != ACE_RECYCLABLE_IDLE_BUT_NOT_PURGABLE) + continue; + + if (addr.subject () != search_addr.subject ()) + continue; + + entry = &(*iterator); + + // + // Update the caching attributes directly since we don't do a + // find() on the cache map. + // + + // Indicates successful find. + int find_result = 0; + + int result = this->caching_strategy ().notify_find (find_result, + entry->int_id_.second); + + if (result == -1) + return result; + + return 0; + } + + return -1; +} + +template void +ACE_Cached_Connect_Strategy_Ex::cleanup (void) +{ + // Excluded other threads from changing the cache while we cleanup + ACE_GUARD (MUTEX, ace_mon, *this->lock_); + + // Close down all cached service handlers. + typename CONNECTION_CACHE::ITERATOR iter = this->connection_cache_.begin (); + while (iter != this->connection_cache_.end ()) + { + if ((*iter).second () != 0) + { + // save entry for future use + CONNECTION_CACHE_ENTRY *entry = (CONNECTION_CACHE_ENTRY *) + (*iter).second ()->recycling_act (); + + // close handler + (*iter).second ()->recycler (0, 0); + (*iter).second ()->close (); + + // remember next iter + typename CONNECTION_CACHE::ITERATOR next_iter = iter; + ++next_iter; + + // purge the item from the hash + this->purge_i (entry); + + // assign next iter + iter = next_iter; + } + else + ++iter; + } +} + +///////////////////////////////////////////////////////////////////////// + +template +ACE_Bounded_Cached_Connect_Strategy::ACE_Bounded_Cached_Connect_Strategy +(size_t max_size, + CACHING_STRATEGY &caching_s, + ACE_Creation_Strategy *cre_s, + ACE_Concurrency_Strategy *con_s, + ACE_Recycling_Strategy *rec_s, + MUTEX *lock, + int delete_lock) + : CCSEBASE (caching_s, cre_s, con_s, rec_s, lock, delete_lock), + max_size_ (max_size) +{ +} + +template +ACE_Bounded_Cached_Connect_Strategy::~ACE_Bounded_Cached_Connect_Strategy(void) +{ +} + +template +int +ACE_Bounded_Cached_Connect_Strategy::find_or_create_svc_handler_i +(SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, + std::pair > *&entry, + int &found) +{ + + REFCOUNTED_HASH_RECYCLABLE_ADDRESS search_addr (remote_addr); + + // Try to find the address in the cache. Only if we don't find it + // do we create a new and connect it with the server. + while (this->find (search_addr, entry) != -1) + { + // We found a cached svc_handler. + // Get the cached + sh = entry->int_id_.first (); + + // Is the connection clean? + int state_result= ACE::handle_ready (sh->peer ().get_handle (), + &ACE_Time_Value::zero, + 1, // read ready + 0, // write ready + 1);// exception ready + + if (state_result == 1) + { + // The connection was disconnected during idle. + // close the svc_handler down. + if (sh->close () == -1) + { + ACE_ASSERT (0); + return -1; + } + sh = 0; + // and rotate once more... + } + else if ((state_result == -1) && (errno == ETIME)) + { + // Found!!! + // Set the flag + found = 1; + + // Tell the that it should prepare itself for + // being recycled. + if (this->prepare_for_recycling (sh) == -1) + { + ACE_ASSERT (0); + return -1; + } + + return 0; + } + else // some other return value or error... + { + ACE_ASSERT (0); // just to see it coming + + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%t)ACE_Bounded_Cached_Connect_Strategy<>::") + ACE_TEXT ("find_or_create_svc_handler_i - ") + ACE_TEXT ("error polling server socket state.\n"))); + + return -1; + } + } + + // Not found... + + // Set the flag + found = 0; + + // Check the limit of handlers... + if ((this->max_size_ > 0) && + (this->connection_cache_.current_size () >= this->max_size_)) + { + // Try to purge idle connections + if (this->purge_connections () == -1) + return -1; + + // Check limit again. + if (this->connection_cache_.current_size () >= this->max_size_) + // still too much! + return -1; + + // OK, we have room now... + } + + // We need to use a temporary variable here since we are not + // allowed to change because other threads may use this + // when we let go of the lock during the OS level connect. + // + // Note that making a new svc_handler, connecting remotely, + // binding to the map, and assigning of the hint and recycler + // should be atomic to the outside world. + SVC_HANDLER *potential_handler = 0; + + // Create a new svc_handler + if (this->make_svc_handler (potential_handler) == -1) + return -1; + + // Connect using the svc_handler. + if (this->cached_connect (potential_handler, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms) == -1) + { + // Close the svc handler. + potential_handler->close (0); + return -1; + } + else + { + // Insert the new SVC_HANDLER instance into the cache. + if (this->connection_cache_.bind (search_addr, + potential_handler, + entry) == -1) + { + // Close the svc handler and reset . + potential_handler->close (0); + + return -1; + } + + // Everything succeeded as planned. Assign to + // . + sh = potential_handler; + + // Set the recycler and the recycling act + this->assign_recycler (sh, this, entry); + } + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CACHED_CONNECT_STRATEGY_T_CPP */ diff --git a/dep/acelite/ace/Cached_Connect_Strategy_T.h b/dep/acelite/ace/Cached_Connect_Strategy_T.h new file mode 100644 index 000000000..32d9289e4 --- /dev/null +++ b/dep/acelite/ace/Cached_Connect_Strategy_T.h @@ -0,0 +1,264 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Cached_Connect_Strategy_T.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + +#ifndef CACHED_CONNECT_STRATEGY_T_H +#define CACHED_CONNECT_STRATEGY_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Strategies_T.h" +#include "ace/Hash_Cache_Map_Manager_T.h" +#include "ace/Caching_Strategies_T.h" +#include "ace/Functor_T.h" +#include "ace/Pair_T.h" + +// For linkers which cant grok long names... +#define ACE_Cached_Connect_Strategy_Ex ACCSE + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Cached_Connect_Strategy_Ex + * + * @brief A connection strategy which caches connections to peers + * (represented by SVC_HANDLER instances), thereby allowing + * subsequent re-use of unused, but available, connections. + * + * is intended to be used as a + * plug-in connection strategy for ACE_Strategy_Connector. + * It's added value is re-use of established connections and + * tweaking the role of the cache as per the caching strategy. + */ +template +class ACE_Cached_Connect_Strategy_Ex + : public ACE_Cached_Connect_Strategy +{ +public: + /// Constructor + ACE_Cached_Connect_Strategy_Ex ( + CACHING_STRATEGY &caching_s, + ACE_Creation_Strategy *cre_s = 0, + ACE_Concurrency_Strategy *con_s = 0, + ACE_Recycling_Strategy *rec_s = 0, + MUTEX *lock = 0, + int delete_lock = 0); + + /// Destructor + virtual ~ACE_Cached_Connect_Strategy_Ex (void); + + /// Explicit purging of connection entries from the connection cache. + virtual int purge_connections (void); + + /// Mark as closed (non-locking version). This is used during the cleanup of the + /// connections purged. + virtual int mark_as_closed_i (const void *recycling_act); + + /** + * Since g++ version < 2.8 arent happy with templates, this special + * method had to be devised to avoid memory leaks and perform + * cleanup of the . + */ + void cleanup (void); + + // = Typedefs for managing the map + typedef ACE_Refcounted_Hash_Recyclable + REFCOUNTED_HASH_RECYCLABLE_ADDRESS; + typedef ACE_Hash_Cache_Map_Manager, + ACE_Equal_To, + CACHING_STRATEGY, + ATTRIBUTES> + CONNECTION_CACHE; + typedef typename CONNECTION_CACHE::CACHE_ENTRY CONNECTION_CACHE_ENTRY; + typedef typename CONNECTION_CACHE::key_type KEY; + typedef typename CONNECTION_CACHE::mapped_type VALUE; + + typedef ACE_Recyclable_Handler_Cleanup_Strategy, + ACE_Hash_Map_Manager_Ex, + ACE_Hash, + ACE_Equal_To, + MUTEX> > + CLEANUP_STRATEGY; + + typedef ACE_Cached_Connect_Strategy + CCSBASE; + + // = Accessor. + CACHING_STRATEGY &caching_strategy (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// Find an idle handle. + int find (ACE_Refcounted_Hash_Recyclable &search_addr, + ACE_Hash_Map_Entry, std::pair > *&entry); + + /// Remove from cache (non-locking version). + virtual int purge_i (const void *recycling_act); + + /// Add to cache (non-locking version). + virtual int cache_i (const void *recycling_act); + + /// Get/Set recycle_state (non-locking version). + virtual int recycle_state_i (const void *recycling_act, + ACE_Recyclable_State new_state); + virtual ACE_Recyclable_State recycle_state_i (const void *recycling_act) const; + + /// Cleanup hint and reset @c *act_holder to zero if @a act_holder != 0. + virtual int cleanup_hint_i (const void *recycling_act, + void **act_holder); + + // = Helpers + int check_hint_i (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, std::pair > *&entry, + int &found); + + virtual int find_or_create_svc_handler_i (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, std::pair > *&entry, + int &found); + + virtual int connect_svc_handler_i (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + int &found); + + /** + * Connection of the svc_handler with the remote host. This method + * also encapsulates the connection done with auto_purging under the + * hood. If the connect failed due to the process running out of + * file descriptors then, auto_purging of some connections are done + * from the CONNECTION_CACHE. This frees the descriptors which get + * used in the connect process and hence the connect operation can + * succeed. + */ + virtual int cached_connect (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms); + + /// Table that maintains the cache of connected SVC_HANDLERs. + CONNECTION_CACHE connection_cache_; +}; + +///////////////////////////////////////////////////////////////////////////// + +// For linkers which cant grok long names... +#define ACE_Bounded_Cached_Connect_Strategy ABCCS + +/** + * @class ACE_Bounded_Cached_Connect_Strategy + * + * @brief + * A connection strategy which caches connections to peers + * (represented by SVC_HANDLER instances), thereby allowing + * subsequent re-use of unused, but available, connections. + * This strategy should be used when the cache is bounded by + * maximum size. + * + * Bounded_Cached_Connect_Strategy is intended to be used as a + * plug-in connection strategy for ACE_Strategy_Connector. + * It's added value is re-use of established connections and + * tweaking the role of the cache as per the caching strategy. + * Thanks to Edan Ayal for contributing this + * class and Susan Liebeskind for + * brainstorming about it. + */ +template +class ACE_Bounded_Cached_Connect_Strategy + : public ACE_Cached_Connect_Strategy_Ex +{ + + typedef ACE_Cached_Connect_Strategy_Ex + CCSEBASE; + + // = Typedefs for managing the map + typedef ACE_Refcounted_Hash_Recyclable + REFCOUNTED_HASH_RECYCLABLE_ADDRESS; + +public: + + /// Constructor + ACE_Bounded_Cached_Connect_Strategy (size_t max_size, + CACHING_STRATEGY &caching_s, + ACE_Creation_Strategy *cre_s = 0, + ACE_Concurrency_Strategy *con_s = 0, + ACE_Recycling_Strategy *rec_s = 0, + MUTEX *lock = 0, + int delete_lock = 0); + + /// Destructor + virtual ~ACE_Bounded_Cached_Connect_Strategy (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + virtual int find_or_create_svc_handler_i (SVC_HANDLER *&sh, + const ACE_PEER_CONNECTOR_ADDR &remote_addr, + ACE_Time_Value *timeout, + const ACE_PEER_CONNECTOR_ADDR &local_addr, + bool reuse_addr, + int flags, + int perms, + ACE_Hash_Map_Entry, + std::pair > *&entry, + int &found); + +protected: + + /// Max items in the cache, used as a bound for the creation of svc_handlers. + size_t max_size_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Cached_Connect_Strategy_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Cached_Connect_Strategy_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* CACHED_CONNECT_STRATEGY_T_H */ diff --git a/dep/acelite/ace/Caching_Strategies_T.cpp b/dep/acelite/ace/Caching_Strategies_T.cpp new file mode 100644 index 000000000..0cc25407a --- /dev/null +++ b/dep/acelite/ace/Caching_Strategies_T.cpp @@ -0,0 +1,58 @@ +#ifndef ACE_CACHING_STRATEGIES_T_CPP +#define ACE_CACHING_STRATEGIES_T_CPP + +#include "ace/Caching_Strategies_T.h" +#include "ace/Log_Category.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Caching_Strategies_T.inl" +#endif /* __ACE_INLINE__ */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Caching_Strategy::~ACE_Caching_Strategy (void) +{ +} + +////////////////////////////////////////////////////////////////////////////////// + +template +ACE_LRU_Caching_Strategy::ACE_LRU_Caching_Strategy (void) + : timer_ (0), + purge_percent_ (10) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +template +ACE_LFU_Caching_Strategy::ACE_LFU_Caching_Strategy (void) + : purge_percent_ (10) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +template +ACE_FIFO_Caching_Strategy::ACE_FIFO_Caching_Strategy (void) + : order_ (0), + purge_percent_ (10) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +ACE_ALLOC_HOOK_DEFINE_Tccc(ACE_Caching_Strategy_Adapter) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_LRU_Caching_Strategy) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_LFU_Caching_Strategy) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_FIFO_Caching_Strategy) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Null_Caching_Strategy) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CACHING_STRATEGIES_T_CPP */ diff --git a/dep/acelite/ace/Caching_Strategies_T.h b/dep/acelite/ace/Caching_Strategies_T.h new file mode 100644 index 000000000..2f58b2ab4 --- /dev/null +++ b/dep/acelite/ace/Caching_Strategies_T.h @@ -0,0 +1,565 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Caching_Strategies_T.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + +#ifndef ACE_CACHING_STRATEGIES_H +#define ACE_CACHING_STRATEGIES_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Caching_Utility_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined(_MSC_VER) +#pragma warning(disable:4503) +#endif /* _MSC_VER */ + +// For linkers that cant grok long names. +#define ACE_Caching_Strategy ACS + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Caching_Strategy + * + * @brief This class is an abstract base class for a caching strategy. + * + * This class consists of all the interfaces a caching strategy should + * have and is used in association with the + * ACE_Caching_Strategy_Adaptor. + */ +template +class ACE_Caching_Strategy +{ +public: + /// Destructor. + virtual ~ACE_Caching_Strategy (void); + + /// Accessor method for the timer attributes. + virtual ATTRIBUTES attributes (void) = 0; + + /// Get the percentage of entries to purge. + virtual double purge_percent (void) = 0; + + /// Set the percentage of entries to purge. + virtual void purge_percent (double percentage) = 0; + + // = Strategy related Operations + + /// This method acts as a notification about the CONTAINERs bind + /// method call. + virtual int notify_bind (int result, + const ATTRIBUTES &attr) = 0; + + /// This method acts as a notification about the CONTAINERs find + /// method call + virtual int notify_find (int result, + ATTRIBUTES &attr) = 0; + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + virtual int notify_unbind (int result, + const ATTRIBUTES &attr) = 0; + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + virtual int notify_trybind (int result, + ATTRIBUTES &attr) = 0; + + /// This method acts as a notification about the CONTAINERs rebind + /// method call + virtual int notify_rebind (int result, + const ATTRIBUTES &attr) = 0; + + /// Purge the cache. + virtual CACHING_UTILITY &caching_utility (void) = 0; + + /// Dumps the state of the object. + virtual void dump (void) const = 0; +}; + +////////////////////////////////////////////////////////////////////////// + +#define ACE_Caching_Strategy_Adapter ACSA + +/** + * @class ACE_Caching_Strategy_Adapter + * + * @brief This class follows the Adaptor pattern and is used to provide + * External Polymorphism by deriving from ACE_Caching_Strategy. + * + * This class simply delegates all requests to the + * IMPLEMNETATION object within. This class should be passed in + * place of the the abstract base ACE_Caching_Strategy class as + * part of the External Polymorphism pattern. + */ +template +class ACE_Caching_Strategy_Adapter + : public ACE_Caching_Strategy +{ + +public: + + /// Constructor. + ACE_Caching_Strategy_Adapter (IMPLEMENTATION *implementation = 0, + bool delete_implementation = false); + + /// Destructor. + ~ACE_Caching_Strategy_Adapter (void); + + /// Accessor method for the timer attributes. + ATTRIBUTES attributes (void); + + /// Get the percentage of entries to purge. + double purge_percent (void); + + /// Set the percentage of entries to purge. + void purge_percent (double percentage); + + // = Strategy related Operations + + /// This method acts as a notification about the CONTAINERs bind + /// method call. + int notify_bind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs find + /// method call + int notify_find (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + int notify_unbind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + int notify_trybind (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs rebind + /// method call + int notify_rebind (int result, + const ATTRIBUTES &attr); + + /// Accessor to the implementation. + IMPLEMENTATION &implementation (void); + + /// Purge the cache. + CACHING_UTILITY &caching_utility (void); + + /// Dumps the state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// Implementation class. + IMPLEMENTATION *implementation_; + + /// Do we need to delete the implementation? + bool delete_implementation_; +}; + +////////////////////////////////////////////////////////////////////////// +#define ACE_LRU_Caching_Strategy ALRU + +/** + * @class ACE_LRU_Caching_Strategy + * + * @brief Defines a Least Recently Used strategy which will decide on + * the item to be removed from the cache. + * + * This is a strategy which makes use of a virtual timer which + * is updated whenever an item is inserted or looked up in the + * container. When the need of purging entries arises, the items + * with the lowest timer values are removed. + * Explanation of the template parameter list: + * CONTAINER is any map with entries of type . + * The ATTRIBUTES are the deciding factor for purging of entries + * and should logically be included with the VALUE. Some ways of + * doing this are: As being a member of the VALUE or VALUE being + * std::pair. The CACHING_UTILITY is the + * class which can be plugged in and which decides the entries + * to purge. + */ +template +class ACE_LRU_Caching_Strategy +{ +public: + + // Traits. + typedef ATTRIBUTES CACHING_ATTRIBUTES; + + // = Initialisation and termination. + + /** + * The is the map in which the entries reside. The + * timer attribute is initialed to zero in this constructor. And + * the field denotes the percentage of the entries + * in the cache which can be purged automagically and by default is + * set to 10%. + */ + ACE_LRU_Caching_Strategy (void); + + // = Operations of the strategy. + + /// Accessor method for the timer attributes. + ATTRIBUTES attributes (void); + + /// Get the percentage of entries to purge. + double purge_percent (void); + + /// Set the percentage of entries to purge. + void purge_percent (double percentage); + + // = Strategy related Operations + + /// This method acts as a notification about the CONTAINERs bind + /// method call. + int notify_bind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs find + /// method call + int notify_find (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + int notify_unbind (int result, + const ATTRIBUTES &attr); + + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + int notify_trybind (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs rebind + /// method call + int notify_rebind (int result, + const ATTRIBUTES &attr); + + /// Purge the cache. + CACHING_UTILITY &caching_utility (void); + + /// Dumps the state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// This element is the one which is the deciding factor for purging + /// of an ITEM. + ATTRIBUTES timer_; + + /// The level about which the purging will happen automagically. + double purge_percent_; + + /// This is the helper class which will decide and expunge entries + /// from the cache. + CACHING_UTILITY caching_utility_; +}; + +////////////////////////////////////////////////////////////////////////// +#define ACE_LFU_Caching_Strategy ALFU + +/** + * @class ACE_LFU_Caching_Strategy + * + * @brief Defines a Least Frequently Used strategy for which will decide on + * the item to be removed from the cache. + * + * A attribute is tagged to each item which increments whenever + * the item is bound or looked up in the cache. Thus it denotes + * the frequency of use. According to the value of the attribute + * the item is removed from the CONTAINER i.e cache. + * Explanation of the template parameter list: + * CONTAINER is any map with entries of type . + * The ATTRIBUTES are the deciding factor for purging of entries + * and should logically be included with the VALUE. Some ways of + * doing this are: As being a member of the VALUE or VALUE being + * std::pair. The CACHING_UTILITY is the + * class which can be plugged in and which decides the entries + * to purge. + */ +template +class ACE_LFU_Caching_Strategy +{ + +public: + + // Traits. + typedef ATTRIBUTES CACHING_ATTRIBUTES; + + // = Initialisation and termination methods. + + /** + * The is the map in which the entries reside. The + * timer attribute is initialed to zero in this constructor. And + * the field denotes the percentage of the entries + * in the cache which can be purged automagically and by default is + * set to 10%. + */ + ACE_LFU_Caching_Strategy (void); + + // = Strategy methods. + + /// Access the attributes. + ATTRIBUTES attributes (void); + + /// Get the percentage of entries to purge. + double purge_percent (void); + + /// Set the percentage of entries to purge. + void purge_percent (double percentage); + + // = Strategy related Operations + + /// This method acts as a notification about the CONTAINERs bind + /// method call. + int notify_bind (int result, + const ATTRIBUTES &attr); + + /// Lookup notification. + int notify_find (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + int notify_unbind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + int notify_trybind (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs rebind + /// method call + int notify_rebind (int result, + const ATTRIBUTES &attr); + + /// Purge the cache. + CACHING_UTILITY &caching_utility (void); + + /// Dumps the state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// The level about which the purging will happen automagically. + double purge_percent_; + + /// This is the helper class which will decide and expunge entries + /// from the cache. + CACHING_UTILITY caching_utility_; +}; + +///////////////////////////////////////////////////////////// +#define ACE_FIFO_Caching_Strategy AFIFO + +/** + * @class ACE_FIFO_Caching_Strategy + * + * @brief The First In First Out strategy is implemented wherein each + * item is ordered. + * + * The order tag of each item is used to decide the item to be + * removed from the cache. The items with least order are removed. + * Explanation of the template parameter list: + * CONTAINER is any map with entries of type . + * The ATTRIBUTES are the deciding factor for purging of entries + * and should logically be included with the VALUE. Some ways of + * doing this are: As being a member of the VALUE or VALUE being + * std::pair. The CACHING_UTILITY is the + * class which can be plugged in and which decides the entries + * to purge. + */ +template +class ACE_FIFO_Caching_Strategy +{ + +public: + + typedef ATTRIBUTES CACHING_ATTRIBUTES; + + // = Initialisation and termination. + + /** + * The is the map in which the entries reside. The + * timer attribute is initialed to zero in this constructor. And + * the field denotes the percentage of the entries + * in the cache which can be purged automagically and by default is + * set to 10%. + */ + ACE_FIFO_Caching_Strategy (void); + + // = Strategy methods. + + /// Accessor method. + ATTRIBUTES attributes (void); + + /// Get the percentage of entries to purge. + double purge_percent (void); + + /// Set the percentage of entries to purge. + void purge_percent (double percentage); + + // = Strategy related Operations + + /// Notification for an item getting bound into the cache. + int notify_bind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs find + /// method call + int notify_find (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + int notify_unbind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + int notify_trybind (int result, + ATTRIBUTES &attr); + + /// Notification for an item getting bound again into the cache. + int notify_rebind (int result, + const ATTRIBUTES &attr); + + /// Purge the cache. + CACHING_UTILITY &caching_utility (void); + + /// Dumps the state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// The order is the deciding factor for the item to be removed from + /// the cache. + ATTRIBUTES order_; + + /// The level about which the purging will happen automagically. + double purge_percent_; + + /// This is the helper class which will decide and expunge entries + /// from the cache. + CACHING_UTILITY caching_utility_; +}; + +////////////////////////////////////////////////////////////////////// +#define ACE_Null_Caching_Strategy ANULL + +/** + * @class ACE_Null_Caching_Strategy + * + * @brief The is a special caching strategy which doesnt have the purging + * feature. + * + * No purging provided. To be used when purging might be too expensive + * an operation. + */ +template +class ACE_Null_Caching_Strategy +{ + +public: + + // = Traits. + typedef ATTRIBUTES CACHING_ATTRIBUTES; + + // = Strategy methods. All are NO_OP methods!!! + + /// Accessor method. + ATTRIBUTES attributes (void); + + /// Get the percentage of entries to purge. + double purge_percent (void); + + /// Set the percentage of entries to purge. + void purge_percent (double percentage); + + // = Strategy related Operations + + /// Notification for an item getting bound into the cache. + int notify_bind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs find + /// method call + int notify_find (int result, + ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs unbind + /// method call + int notify_unbind (int result, + const ATTRIBUTES &attr); + + /// This method acts as a notification about the CONTAINERs trybind + /// method call + int notify_trybind (int result, + ATTRIBUTES &attr); + + /// Notification for an item getting bound again into the cache. + int notify_rebind (int result, + const ATTRIBUTES &attr); + + /// Purge the cache. + CACHING_UTILITY &caching_utility (void); + + /// Dumps the state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// This is the helper class which will decide and expunge entries + /// from the cache. + CACHING_UTILITY caching_utility_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Caching_Strategies_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Caching_Strategies_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Caching_Strategies_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CACHING_STRATEGIES_H */ diff --git a/dep/acelite/ace/Caching_Strategies_T.inl b/dep/acelite/ace/Caching_Strategies_T.inl new file mode 100644 index 000000000..dd9c98513 --- /dev/null +++ b/dep/acelite/ace/Caching_Strategies_T.inl @@ -0,0 +1,454 @@ +// -*-C++-*- +// +////////////////////////////////////////////////////////////////////////////////// + +#include "ace/OS_Memory.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_Caching_Strategy_Adapter::ACE_Caching_Strategy_Adapter (IMPLEMENTATION *implementation, + bool delete_implementation) + : implementation_ (implementation), + delete_implementation_ (delete_implementation) +{ + if (this->implementation_ == 0) + { + ACE_NEW (this->implementation_, + IMPLEMENTATION); + this->delete_implementation_ = true; + } +} + +template ACE_INLINE +ACE_Caching_Strategy_Adapter::~ACE_Caching_Strategy_Adapter (void) +{ + if (this->delete_implementation_) + { + delete this->implementation_; + this->delete_implementation_ = false; + this->implementation_ = 0; + } +} + +template ACE_INLINE ATTRIBUTES +ACE_Caching_Strategy_Adapter::attributes (void) +{ + return this->implementation_->attributes (); +} + +template ACE_INLINE double +ACE_Caching_Strategy_Adapter::purge_percent (void) +{ + return this->implementation_->purge_percent (); +} + +template ACE_INLINE void +ACE_Caching_Strategy_Adapter::purge_percent (double percentage) +{ + this->implementation_->purge_percent (percentage); +} + +template ACE_INLINE int +ACE_Caching_Strategy_Adapter::notify_bind (int result, + const ATTRIBUTES &attr) +{ + return this->implementation_->notify_bind (result, + attr); +} + +template ACE_INLINE int +ACE_Caching_Strategy_Adapter::notify_find (int result, + ATTRIBUTES &attr) +{ + return this->implementation_->notify_find (result, + attr); +} + +template ACE_INLINE int +ACE_Caching_Strategy_Adapter::notify_unbind (int result, + const ATTRIBUTES &attr) +{ + return this->implementation_->notify_unbind (result, + attr); +} + +template ACE_INLINE int +ACE_Caching_Strategy_Adapter::notify_trybind (int result, + ATTRIBUTES &attr) +{ + return this->implementation_->notify_trybind (result, + attr); +} + +template ACE_INLINE int +ACE_Caching_Strategy_Adapter::notify_rebind (int result, + const ATTRIBUTES &attr) +{ + return this->implementation_->notify_rebind (result, + attr); +} + +template ACE_INLINE IMPLEMENTATION & +ACE_Caching_Strategy_Adapter::implementation (void) +{ + return *this->implementation_; +} + +template ACE_INLINE CACHING_UTILITY & +ACE_Caching_Strategy_Adapter::caching_utility (void) +{ + return this->implementation_->caching_utility (); +} + +template ACE_INLINE void +ACE_Caching_Strategy_Adapter::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Caching_Strategy_Adapter::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +////////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE ATTRIBUTES +ACE_LRU_Caching_Strategy::attributes (void) +{ + return this->timer_; +} + +template ACE_INLINE double +ACE_LRU_Caching_Strategy::purge_percent (void) +{ + return this->purge_percent_; +} + +template ACE_INLINE void +ACE_LRU_Caching_Strategy::purge_percent (double percentage) +{ + this->purge_percent_ = percentage; +} + +template ACE_INLINE int +ACE_LRU_Caching_Strategy::notify_bind ( + int result, + const ATTRIBUTES & /* attr */) +{ + if (result == 0) + ++this->timer_; + + return result; +} + +template ACE_INLINE int +ACE_LRU_Caching_Strategy::notify_find ( + int result, + ATTRIBUTES &attr) +{ + if (result == 0) + { + attr = this->timer_; + ++this->timer_; + } + + return result; +} + +template ACE_INLINE int +ACE_LRU_Caching_Strategy::notify_unbind ( + int result, + const ATTRIBUTES & /* attr */) +{ + return result; +} + +template ACE_INLINE int +ACE_LRU_Caching_Strategy::notify_trybind ( + int result, + ATTRIBUTES & /* attr */) +{ + return result; +} + +template ACE_INLINE int +ACE_LRU_Caching_Strategy::notify_rebind ( + int result, + const ATTRIBUTES & /* attr */) +{ + if (result == 0) + ++this->timer_; + + return result; +} + +template ACE_INLINE CACHING_UTILITY & +ACE_LRU_Caching_Strategy::caching_utility (void) +{ + return this->caching_utility_; +} + +template ACE_INLINE void +ACE_LRU_Caching_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_LRU_Caching_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("timer_ = %d "), this->timer_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +////////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE ATTRIBUTES +ACE_LFU_Caching_Strategy::attributes (void) +{ + return 0; +} + +template ACE_INLINE double +ACE_LFU_Caching_Strategy::purge_percent (void) +{ + return this->purge_percent_; +} + +template ACE_INLINE void +ACE_LFU_Caching_Strategy::purge_percent (double percentage) +{ + this->purge_percent_ = percentage; +} + +template ACE_INLINE int +ACE_LFU_Caching_Strategy::notify_bind (int result, + const ATTRIBUTES & /* attr */) +{ + + return result; +} + +template ACE_INLINE int +ACE_LFU_Caching_Strategy::notify_find (int result, + ATTRIBUTES &attr) +{ + if (result == 0) + ++attr; + + return result; +} + +template ACE_INLINE int +ACE_LFU_Caching_Strategy::notify_trybind (int result, + ATTRIBUTES & /* attr */) +{ + return result; +} + +template ACE_INLINE int +ACE_LFU_Caching_Strategy::notify_rebind (int result, + const ATTRIBUTES & /* attr */) +{ + return result; +} + +template ACE_INLINE int +ACE_LFU_Caching_Strategy::notify_unbind (int result, + const ATTRIBUTES & /* attr */) +{ + return result; +} + +template ACE_INLINE CACHING_UTILITY & +ACE_LFU_Caching_Strategy::caching_utility (void) +{ + return this->caching_utility_; +} + +template ACE_INLINE void +ACE_LFU_Caching_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_LFU_Caching_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +////////////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE ATTRIBUTES +ACE_FIFO_Caching_Strategy::attributes (void) +{ + return this->order_; +} + +template ACE_INLINE double +ACE_FIFO_Caching_Strategy::purge_percent (void) +{ + return this->purge_percent_; +} + +template ACE_INLINE void +ACE_FIFO_Caching_Strategy::purge_percent (double percentage) +{ + this->purge_percent_ = percentage; +} + +template ACE_INLINE int +ACE_FIFO_Caching_Strategy::notify_bind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + if (result == 0) + ++this->order_; + + return result; +} + +template ACE_INLINE int +ACE_FIFO_Caching_Strategy::notify_find (int result, + ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_FIFO_Caching_Strategy::notify_unbind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_FIFO_Caching_Strategy::notify_trybind (int result, + ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_FIFO_Caching_Strategy::notify_rebind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + if (result == 0) + ++this->order_; + + return result; +} + +template ACE_INLINE CACHING_UTILITY & +ACE_FIFO_Caching_Strategy::caching_utility (void) +{ + return this->caching_utility_; +} + +template ACE_INLINE void +ACE_FIFO_Caching_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO_Caching_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("order_ = %d "), this->order_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +////////////////////////////////////////////////////////////////////////////////// + +template ACE_INLINE ATTRIBUTES +ACE_Null_Caching_Strategy::attributes (void) +{ + return 0; +} + +template ACE_INLINE double +ACE_Null_Caching_Strategy::purge_percent (void) +{ + return 0; +} + +template ACE_INLINE void +ACE_Null_Caching_Strategy::purge_percent (double percentage) +{ + ACE_UNUSED_ARG (percentage); +} + +template ACE_INLINE int +ACE_Null_Caching_Strategy::notify_bind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_Null_Caching_Strategy::notify_find (int result, + ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_Null_Caching_Strategy::notify_unbind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_Null_Caching_Strategy::notify_trybind (int result, + ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE int +ACE_Null_Caching_Strategy::notify_rebind (int result, + const ATTRIBUTES &attr) +{ + ACE_UNUSED_ARG (attr); + + return result; +} + +template ACE_INLINE CACHING_UTILITY & +ACE_Null_Caching_Strategy::caching_utility (void) +{ + return this->caching_utility_; +} + +template ACE_INLINE void +ACE_Null_Caching_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Null_Caching_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +////////////////////////////////////////////////////////////////////////////////// diff --git a/dep/acelite/ace/Caching_Utility_T.cpp b/dep/acelite/ace/Caching_Utility_T.cpp new file mode 100644 index 000000000..aa344562d --- /dev/null +++ b/dep/acelite/ace/Caching_Utility_T.cpp @@ -0,0 +1,498 @@ +#ifndef ACE_CACHING_UTILITY_T_CPP +#define ACE_CACHING_UTILITY_T_CPP + +#include "ace/Caching_Utility_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/ACE.h" +#include "ace/Min_Max.h" +#include "ace/OS_Memory.h" +#include "ace/Recyclable.h" + +////////////////////////////////////////////////////////////////////////////// + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Pair_Caching_Utility::ACE_Pair_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy, + bool delete_cleanup_strategy) + : cleanup_strategy_ (cleanup_strategy), + delete_cleanup_strategy_ (delete_cleanup_strategy) +{ + if (cleanup_strategy == 0) + { + ACE_NEW (this->cleanup_strategy_, + CLEANUP_STRATEGY); + this->delete_cleanup_strategy_ = true; + } +} + +template +ACE_Pair_Caching_Utility::~ACE_Pair_Caching_Utility (void) +{ + if (this->delete_cleanup_strategy_) + delete this->cleanup_strategy_; +} + +template int +ACE_Pair_Caching_Utility::clear_cache (CONTAINER &container, + double purge_percent) +{ + // Check that the purge_percent is non-zero. + if (ACE::is_equal (purge_percent, 0.0)) + return 0; + + // Get the number of entries in the container. + size_t current_map_size = container.current_size (); + + // Also whether the number of entries in the cache! + // Oops! then there is no way out but exiting. So return an error. + if (current_map_size == 0) + return 0; + + // Calculate the no of entries to remove from the cache depending + // upon the . + size_t const entries_to_remove + = ACE_MAX (static_cast (1), + static_cast (static_cast (purge_percent) + / 100 * current_map_size)); + KEY *key_to_remove = 0; + VALUE *value_to_remove = 0; + + for (size_t i = 0; i < entries_to_remove ; ++i) + { + this->minimum (container, + key_to_remove, + value_to_remove); + + // Simply verifying that the key is non-zero. + // This is important for strategies where the minimum + // entry cant be found due to constraints on the type of entry + // to remove. + if (key_to_remove == 0) + return 0; + + if (this->cleanup_strategy_->cleanup (container, + key_to_remove, + value_to_remove) == -1) + return -1; + + } + + return 0; +} + +template void +ACE_Pair_Caching_Utility::minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove) +{ + // Starting values. + ITERATOR iter = container.begin (); + ITERATOR end = container.end (); + ATTRIBUTES min = (*iter).int_id_.second; + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + + // The iterator moves thru the container searching for the entry + // with the lowest ATTRIBUTES. + for (++iter; + iter != end; + ++iter) + { + if (min > (*iter).int_id_.second) + { + // Ah! an item with lower ATTTRIBUTES... + min = (*iter).int_id_.second; + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +ACE_Recyclable_Handler_Caching_Utility::ACE_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy, + bool delete_cleanup_strategy) + : cleanup_strategy_ (cleanup_strategy), + delete_cleanup_strategy_ (delete_cleanup_strategy) +{ + if (cleanup_strategy == 0) + { + ACE_NEW (this->cleanup_strategy_, + CLEANUP_STRATEGY); + this->delete_cleanup_strategy_ = true; + } +} + +template +ACE_Recyclable_Handler_Caching_Utility::~ACE_Recyclable_Handler_Caching_Utility (void) +{ + if (this->delete_cleanup_strategy_) + delete this->cleanup_strategy_; +} + +template int +ACE_Recyclable_Handler_Caching_Utility::clear_cache (CONTAINER &container, + double purge_percent) +{ + // Check that the purge_percent is non-zero. + if (ACE::is_equal (purge_percent, 0.0)) + return 0; + + // Get the number of entries in the container. + size_t current_map_size = container.current_size (); + + // Also whether the number of entries in the cache is just one! + // Oops! then there is no way out but exiting. So return an error. + // if (current_map_size <= 1) + if (current_map_size == 0) + return 0; + + // Calculate the no of entries to remove from the cache depending + // upon the . + size_t const entries_to_remove + = ACE_MAX (static_cast (1), + static_cast (static_cast (purge_percent) + / 100 * current_map_size)); + + KEY *key_to_remove = 0; + VALUE *value_to_remove = 0; + + for (size_t i = 0; i < entries_to_remove ; ++i) + { + this->minimum (container, + key_to_remove, + value_to_remove); + + // Simply verifying that the key is non-zero. + // This is important for strategies where the minimum + // entry cant be found due to constraints on the type of entry + // to remove. + if (key_to_remove == 0) + return 0; + + if (this->cleanup_strategy_->cleanup (container, + key_to_remove, + value_to_remove) == -1) + return -1; + } + + return 0; +} + +template void +ACE_Recyclable_Handler_Caching_Utility::minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove) +{ + // Starting values. + ITERATOR end = container.end (); + ITERATOR iter = container.begin (); + ATTRIBUTES min = (*iter).int_id_.second; + key_to_remove = 0; + value_to_remove = 0; + // Found the minimum entry to be purged? + int found = 0; + + // The iterator moves thru the container searching for the entry + // with the lowest ATTRIBUTES. + for (; + iter != end; + ++iter) + { + // If the entry isnt IDLE_AND_PURGABLE continue until you reach + // the first entry which can be purged. This is the minimum with + // which you will compare the rest of the purgable entries. + if ((*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE || + (*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE) + { + if (found == 0) + { + min = (*iter).int_id_.second; + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + found = 1; + } + else + { + // Ah! an entry with lower ATTTRIBUTES... + if (min > (*iter).int_id_.second) + { + min = (*iter).int_id_.second; + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + } + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +template +ACE_Refcounted_Recyclable_Handler_Caching_Utility::ACE_Refcounted_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy, + bool delete_cleanup_strategy) + : cleanup_strategy_ (cleanup_strategy), + delete_cleanup_strategy_ (delete_cleanup_strategy), + marked_as_closed_entries_ (0) +{ + if (cleanup_strategy == 0) + { + ACE_NEW (this->cleanup_strategy_, + CLEANUP_STRATEGY); + this->delete_cleanup_strategy_ = true; + } +} + +template +ACE_Refcounted_Recyclable_Handler_Caching_Utility::~ACE_Refcounted_Recyclable_Handler_Caching_Utility (void) +{ + if (this->delete_cleanup_strategy_) + delete this->cleanup_strategy_; +} + +template int +ACE_Refcounted_Recyclable_Handler_Caching_Utility::clear_cache (CONTAINER &container, + double purge_percent) +{ + // Check that the purge_percent is non-zero. + if (ACE::is_equal (purge_percent, 0.0)) + return 0; + + // Get the number of entries in the container which can be considered for purging. + size_t const available_entries = + container.current_size () - this->marked_as_closed_entries_; + + // Also whether the number of entries in the cache zero. + // Oops! then there is no way out but exiting. + if (available_entries <= 0) + return 0; + + // Calculate the no of entries to remove from the cache depending + // upon the . + size_t entries_to_remove + = ACE_MAX (static_cast (1), + static_cast (static_cast (purge_percent) + / 100 * available_entries)); + + if (entries_to_remove >= available_entries || entries_to_remove == 0) + entries_to_remove = available_entries - 1; + + KEY *key_to_remove = 0; + VALUE *value_to_remove = 0; + + for (size_t i = 0; i < entries_to_remove ; ++i) + { + this->minimum (container, + key_to_remove, + value_to_remove); + + // Simply verifying that the key is non-zero. + // This is important for strategies where the minimum + // entry cant be found due to constraints on the type of entry + // to remove. + if (key_to_remove == 0) + return 0; + + if (this->cleanup_strategy_->cleanup (container, + key_to_remove, + value_to_remove) == -1) + return -1; + + ++this->marked_as_closed_entries_; + } + + return 0; +} + +template void +ACE_Refcounted_Recyclable_Handler_Caching_Utility::minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove) +{ + // Starting values. + ITERATOR end = container.end (); + ITERATOR iter = container.begin (); + ATTRIBUTES min = (*iter).int_id_.second (); + key_to_remove = 0; + value_to_remove = 0; + // Found the minimum entry to be purged? + int found = 0; + + // The iterator moves thru the container searching for the entry + // with the lowest ATTRIBUTES. + for (; + iter != end; + ++iter) + { + // If the entry isnt IDLE_AND_PURGABLE continue until you reach + // the first entry which can be purged. This is the minimum with + // which you will compare the rest of the purgable entries. + if ((*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_IDLE_AND_PURGABLE || + (*iter).ext_id_.recycle_state () == ACE_RECYCLABLE_PURGABLE_BUT_NOT_IDLE) + { + if (found == 0) + { + min = (*iter).int_id_.second (); + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + found = 1; + } + else + { + // Ah! an entry with lower ATTTRIBUTES... + if (min > (*iter).int_id_.second ()) + { + min = (*iter).int_id_.second (); + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + } + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// + +template +ACE_Handler_Caching_Utility::ACE_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy, + bool delete_cleanup_strategy) + : cleanup_strategy_ (cleanup_strategy), + delete_cleanup_strategy_ (delete_cleanup_strategy) +{ + if (cleanup_strategy == 0) + { + ACE_NEW (this->cleanup_strategy_, + CLEANUP_STRATEGY); + this->delete_cleanup_strategy_ = true; + } +} + +template +ACE_Handler_Caching_Utility::~ACE_Handler_Caching_Utility (void) +{ + if (this->delete_cleanup_strategy_) + delete this->cleanup_strategy_; +} + +template int +ACE_Handler_Caching_Utility::clear_cache (CONTAINER &container, + double purge_percent) +{ + // Check that the purge_percent is non-zero. + if (ACE::is_equal (purge_percent, 0.0)) + return 0; + + // Get the number of entries in the container. + size_t current_map_size = container.current_size (); + + // Also whether the number of entries in the cache is just one! + // Oops! then there is no way out but exiting. So return an error. + if (current_map_size == 0) + return 0; + + // Calculate the no of entries to remove from the cache depending + // upon the . + size_t entries_to_remove + = ACE_MAX (static_cast (1), + static_cast (static_cast (purge_percent) + / 100 * current_map_size)); + + KEY *key_to_remove = 0; + VALUE *value_to_remove = 0; + + for (size_t i = 0; i < entries_to_remove ; ++i) + { + this->minimum (container, + key_to_remove, + value_to_remove); + + if (this->cleanup_strategy_->cleanup (container, + key_to_remove, + value_to_remove) == -1) + return -1; + } + + return 0; +} + +template void +ACE_Handler_Caching_Utility::minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove) +{ + // Starting values. + ITERATOR iter = container.begin (); + ITERATOR end = container.end (); + ATTRIBUTES min = (*iter).int_id_->caching_attributes (); + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + + // The iterator moves thru the container searching for the entry + // with the lowest ATTRIBUTES. + for (++iter; + iter != end; + ++iter) + { + if (min > (*iter).int_id_->caching_attributes () && + (*iter).int_id_->active () != 1) + { + // Ah! an item with lower ATTTRIBUTES... + min = (*iter).int_id_->caching_attributes (); + key_to_remove = &(*iter).ext_id_; + value_to_remove = &(*iter).int_id_; + } + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////// + +template +ACE_Null_Caching_Utility::ACE_Null_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy, + bool delete_cleanup_strategy) + : cleanup_strategy_ (cleanup_strategy), + delete_cleanup_strategy_ (delete_cleanup_strategy) +{ + if (cleanup_strategy == 0) + { + ACE_NEW (this->cleanup_strategy_, + CLEANUP_STRATEGY); + this->delete_cleanup_strategy_ = true; + } +} + +template +ACE_Null_Caching_Utility::~ACE_Null_Caching_Utility (void) +{ + if (this->delete_cleanup_strategy_) + delete this->cleanup_strategy_; +} + +template int +ACE_Null_Caching_Utility::clear_cache (CONTAINER &container, + double purge_percent) +{ + ACE_UNUSED_ARG (container); + ACE_UNUSED_ARG (purge_percent); + + return 0; +} + +template void +ACE_Null_Caching_Utility::minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove) +{ + ACE_UNUSED_ARG (container); + ACE_UNUSED_ARG (key_to_remove); + ACE_UNUSED_ARG (value_to_remove); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CACHING_UTILITY_T_CPP */ diff --git a/dep/acelite/ace/Caching_Utility_T.h b/dep/acelite/ace/Caching_Utility_T.h new file mode 100644 index 000000000..bdeb165fb --- /dev/null +++ b/dep/acelite/ace/Caching_Utility_T.h @@ -0,0 +1,311 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Caching_Utility_T.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + +#ifndef ACE_CACHING_UTILITY_H +#define ACE_CACHING_UTILITY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/Cleanup_Strategies_T.h" +#include "ace/Copy_Disabled.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Pair_Caching_Utility + * + * @brief Defines a helper class for the Caching Strategies. + * + * This class defines the methods commonly used by the different + * caching strategies. For instance: clear_cache() method which + * decides and purges the entry from the container. @note This + * class helps in the caching_strategies using a container + * containing entries of > + * kind. The attributes helps in deciding the entries to be + * purged. The Cleanup_Strategy is the callback class to which the + * entries to be cleaned up will be delegated. + */ +template +class ACE_Pair_Caching_Utility : private ACE_Copy_Disabled +{ +public: + + typedef ACE_Cleanup_Strategy CLEANUP_STRATEGY; + + /// Constructor. + ACE_Pair_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy = 0, + bool delete_cleanup_strategy = false); + + /// Destructor. + ~ACE_Pair_Caching_Utility (void); + + /** + * Purge entries from the @a container. The Cleanup_Strategy will do the + * actual job of cleanup once the entries to be cleaned up are decided. + */ + int clear_cache (CONTAINER &container, double purge_percent); + +protected: + + /// Find the entry with minimum caching attributes. + void minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove); + + /// The cleanup strategy which can be used to destroy the entries of + /// the container. + CLEANUP_STRATEGY *cleanup_strategy_; + + /// Whether the cleanup_strategy should be destroyed or not. + bool delete_cleanup_strategy_; +}; + +/** + * @class ACE_Recyclable_Handler_Caching_Utility + * + * @brief Defines a helper class for the Caching Strategies. + * + * This class defines the methods commonly used by the different + * caching strategies. For instance: clear_cache() method which + * decides and purges the entry from the container. @note This + * class helps in the caching_strategies using a container + * containing entries of kind. The attributes + * helps in deciding the entries to be purged. The + * Cleanup_Strategy is the callback class to which the entries to + * be cleaned up will be delegated. + */ +template +class ACE_Recyclable_Handler_Caching_Utility : private ACE_Copy_Disabled +{ + +public: + + typedef ACE_Recyclable_Handler_Cleanup_Strategy CLEANUP_STRATEGY; + typedef ACE_Cleanup_Strategy CLEANUP_STRATEGY_BASE; + + /// Constructor. + ACE_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy = 0, + bool delete_cleanup_strategy = false); + + /// Destructor. + ~ACE_Recyclable_Handler_Caching_Utility (void); + + /** + * Purge entries from the @a container. The Cleanup_Strategy will do + * the actual job of cleanup once the entries to be cleaned up are + * decided. + */ + int clear_cache (CONTAINER &container, + double purge_percent); + +protected: + + /// Find the entry with minimum caching attributes. + void minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove); + + /// This is the default Cleanup Strategy for this utility. + CLEANUP_STRATEGY_BASE *cleanup_strategy_; + + /// Whether the cleanup_strategy should be destroyed or not. + bool delete_cleanup_strategy_; +}; + +/** + * @class ACE_Refcounted_Recyclable_Handler_Caching_Utility + * + * @brief Defines a helper class for the Caching Strategies. + * + * This class defines the methods commonly used by the different + * caching strategies. For instance: clear_cache () method which + * decides and purges the entry from the container. @note This + * class helps in the caching_strategies using a container + * containing entries of kind. The attributes helps in + * deciding the entries to be purged. The Cleanup_Strategy is the + * callback class to which the entries to be cleaned up will be + * delegated. + */ +template +class ACE_Refcounted_Recyclable_Handler_Caching_Utility : private ACE_Copy_Disabled +{ +public: + typedef ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy CLEANUP_STRATEGY; + typedef ACE_Cleanup_Strategy CLEANUP_STRATEGY_BASE; + + /// Constructor. + ACE_Refcounted_Recyclable_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy = 0, + bool delete_cleanup_strategy = false); + + /// Destructor. + ~ACE_Refcounted_Recyclable_Handler_Caching_Utility (void); + + /** + * Purge entries from the @a container. The Cleanup_Strategy will do + * the actual job of cleanup once the entries to be cleaned up are + * decided. + */ + int clear_cache (CONTAINER &container, + double purge_percent); + +protected: + + /// Find the entry with minimum caching attributes. + void minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove); + + /// This is the default Cleanup Strategy for this utility. + CLEANUP_STRATEGY_BASE *cleanup_strategy_; + + /// Whether the cleanup_strategy should be destroyed or not. + bool delete_cleanup_strategy_; + + /** + * This figure denotes the number of entries are there in the + * container which have been marked as closed already but might + * not have been unbound from the container. + */ + size_t marked_as_closed_entries_; +}; + +/** + * @class ACE_Handler_Caching_Utility + * + * @brief Defines a helper class for the Caching Strategies. + * + * This class defines the methods commonly used by the different + * caching strategies. For instance: clear_cache() method which + * decides and purges the entry from the container. @note This + * class helps in the caching_strategies using a container + * containing entries of kind where the HANDLER + * contains the caching attributes which help in deciding the + * entries to be purged. The Cleanup_Strategy is the callback + * class to which the entries to be cleaned up will be delegated. + */ +template +class ACE_Handler_Caching_Utility : private ACE_Copy_Disabled +{ +public: + + typedef ACE_Handler_Cleanup_Strategy CLEANUP_STRATEGY; + typedef ACE_Cleanup_Strategy CLEANUP_STRATEGY_BASE; + + /// Constructor. + ACE_Handler_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy = 0, + bool delete_cleanup_strategy = false); + + /// Destructor. + ~ACE_Handler_Caching_Utility (void); + + /** + * Purge entries from the @a container. The Cleanup_Strategy will do + * the actual job of cleanup once the entries to be cleaned up are + * decided. + */ + int clear_cache (CONTAINER &container, + double purge_percent); + +protected: + + /** + * Find the entry with minimum caching attributes. This is handler + * specific since this utility is to be used very specifically for + * handler who have caching_attributes for server side acched + * connection management. + */ + void minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove); + + /// The cleanup strategy which can be used to destroy the entries of + /// the container. + CLEANUP_STRATEGY_BASE *cleanup_strategy_; + + /// Whether the cleanup_strategy should be destroyed or not. + bool delete_cleanup_strategy_; +}; + +/** + * @class ACE_Null_Caching_Utility + * + * @brief Defines a dummy helper class for the Caching Strategies. + * + * This class defines the methods commonly used by the different + * caching strategies. For instance: clear_cache() method which + * decides and purges the entry from the container. @note This + * class is be used with the Null_Caching_Strategy. The + * Cleanup_Strategy is the callback class to which the entries to + * be cleaned up will be delegated. + */ +template +class ACE_Null_Caching_Utility : private ACE_Copy_Disabled +{ +public: + + typedef ACE_Null_Cleanup_Strategy CLEANUP_STRATEGY; + typedef ACE_Cleanup_Strategy CLEANUP_STRATEGY_BASE; + + /// Constructor. + ACE_Null_Caching_Utility (ACE_Cleanup_Strategy *cleanup_strategy = 0, + bool delete_cleanup_strategy = false); + + /// Destructor. + ~ACE_Null_Caching_Utility (void); + + /** + * Purge entries from the @a container. The Cleanup_Strategy will do + * the actual job of cleanup once the entries to be cleaned up are + * decided. @note Here it is a no-op. + */ + int clear_cache (CONTAINER &container, + double purge_percent); + +protected: + + /** + * Find the entry with minimum caching attributes. This is handler + * specific since this utility is to be used very specifically for + * handler who have caching_attributes for server side acched + * connection management.@note Here it is a no-op. + */ + void minimum (CONTAINER &container, + KEY *&key_to_remove, + VALUE *&value_to_remove); + + /// The cleanup strategy which can be used to destroy the entries of + /// the container. + CLEANUP_STRATEGY_BASE *cleanup_strategy_; + + /// Whether the cleanup_strategy should be destroyed or not. + bool delete_cleanup_strategy_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Caching_Utility_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Caching_Utility_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CACHING_UTILITY_H */ diff --git a/dep/acelite/ace/Capabilities.cpp b/dep/acelite/ace/Capabilities.cpp new file mode 100644 index 000000000..9ffceda2a --- /dev/null +++ b/dep/acelite/ace/Capabilities.cpp @@ -0,0 +1,352 @@ +#include "ace/Capabilities.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Capabilities.inl" +#endif /* !__ACE_INLINE__ */ + +#include "ace/OS_NS_stdio.h" + +#define ACE_ESC ((ACE_TCHAR)0x1b) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_CapEntry::~ACE_CapEntry (void) +{ +} + +ACE_Capabilities::ACE_Capabilities (void) + : caps_ () +{ +} + +ACE_Capabilities::~ACE_Capabilities (void) +{ + this->resetcaps (); +} + +const ACE_TCHAR * +ACE_Capabilities::parse (const ACE_TCHAR *buf, ACE_TString &cap) +{ + while (*buf != ACE_TEXT ('\0') && *buf != ACE_TEXT (',')) + { + if (*buf == ACE_TEXT ('\\')) + { + ++buf; + if (*buf == ACE_TEXT ('E') || *buf == ACE_TEXT ('e')) + { + cap += ACE_ESC; + ++buf; + continue; + } + else if (*buf == ACE_TEXT ('r')) + { + cap += ACE_TEXT ('\r'); + ++buf; + continue; + } + else if (*buf == ACE_TEXT ('n')) + { + cap += ACE_TEXT ('\n'); + ++buf; + continue; + } + else if (*buf == ACE_TEXT ('t')) + { + cap += ACE_TEXT ('\t'); + ++buf; + continue; + } + else if (*buf == ACE_TEXT ('\\')) + { + cap += *buf++; + continue; + } + if (ACE_OS::ace_isdigit(*buf)) + { + // @@ UNICODE Does this work with unicode? + int oc = 0; + for (int i = 0; + i < 3 && *buf && ACE_OS::ace_isdigit (*buf); + i++) + oc = oc * 8 + (*buf++ - ACE_TEXT ('0')); + + cap += (ACE_TCHAR) oc; + continue; + } + } + cap += *buf++; + } + return buf; +} + +const ACE_TCHAR * +ACE_Capabilities::parse (const ACE_TCHAR *buf, int &cap) +{ + int n = 0; + + while (*buf && ACE_OS::ace_isdigit (*buf)) + n = n * 10 + (*buf++ - ACE_TEXT ('0')); + + cap = n; + + return buf; +} + +void +ACE_Capabilities::resetcaps (void) +{ + for (CAPABILITIES_MAP::ITERATOR iter (this->caps_); + !iter.done (); + iter.advance ()) + { + CAPABILITIES_MAP::ENTRY *entry = 0; + iter.next (entry); + delete entry->int_id_; + } + + this->caps_.close (); + this->caps_.open (); +} + +int +ACE_Capabilities::fillent (const ACE_TCHAR *buf) +{ + this->resetcaps (); + while (*buf) + { + ACE_TString s; + int n; + ACE_TString name; + ACE_CapEntry *ce; + + // Skip blanks + while (*buf && ACE_OS::ace_isspace(*buf)) buf++; + // If we get end of line return + + if (*buf == ACE_TEXT ('\0')) + break; + + if (*buf == ACE_TEXT ('#')) + { + while (*buf && *buf != ACE_TEXT ('\n')) + buf++; + if (*buf == ACE_TEXT ('\n')) + buf++; + continue; + } + while(*buf && *buf != ACE_TEXT ('=') + && *buf!= ACE_TEXT ('#') + && *buf != ACE_TEXT (',')) + name += *buf++; + + // If name is null. + switch (*buf) + { + case ACE_TEXT ('='): + // String property + buf = this->parse (buf + 1, s); + ACE_NEW_RETURN (ce, + ACE_StringCapEntry (s), + -1); + if (this->caps_.bind (name, ce) == -1) + { + delete ce; + return -1; + } + break; + case ACE_TEXT ('#'): + // Integer property + buf = this->parse (buf + 1, n); + ACE_NEW_RETURN (ce, + ACE_IntCapEntry (n), + -1); + if (this->caps_.bind (name, ce) == -1) + { + delete ce; + return -1; + } + break; + case ACE_TEXT (','): + // Boolean + ACE_NEW_RETURN (ce, + ACE_BoolCapEntry (1), + -1); + if (this->caps_.bind (name, ce) == -1) + { + delete ce; + return -1; + } + break; + default: + return 0; + } + + if (*buf++ != ACE_TEXT (',')) + return -1; + } + + return 0; +} + +int +ACE_Capabilities::is_entry (const ACE_TCHAR *name, const ACE_TCHAR *line) +{ + for (;;) + { + // Skip blanks or irrelevant characters + while (*line && ACE_OS::ace_isspace(*line)) + ++line; + + // End of line reached + if (*line == ACE_TEXT ('\0')) + break; + + // Build the entry name + ACE_TString nextname; + while (*line && *line != ACE_TEXT ('|') && *line != ACE_TEXT (',')) + nextname += *line++; + + // We have found the required entry? + if (ACE_OS::strcmp (nextname.c_str (), name) == 0) + return 1; + + // Skip puntuaction char if neccesary. + if (*line == ACE_TEXT ('|') || *line == ACE_TEXT (',')) + ++line; + else + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("Invalid entry\n"))); + break; + } + } + return 0; +} + +int +ACE_Capabilities::getline (FILE *fp, ACE_TString &line) +{ + int ch; + + line.set (0, 0); + + while ((ch = ACE_OS::fgetc (fp)) != EOF && ch != ACE_TEXT ('\n')) + line += (ACE_TCHAR) ch; + + if (ch == EOF && line.length () == 0) + return -1; + else + return 0; +} + +int +ACE_Capabilities::getval (const ACE_TCHAR *keyname, ACE_TString &val) +{ + ACE_CapEntry* cap = 0; + if (this->caps_.find (keyname, cap) == -1) + return -1; + + ACE_StringCapEntry *scap = + dynamic_cast (cap); + if (scap == 0) + return -1; + + val = scap->getval (); + return 0; +} + +int +ACE_Capabilities::getval (const ACE_TCHAR *keyname, int &val) +{ + ACE_CapEntry *cap = 0; + if (this->caps_.find (keyname, cap) == -1) + return -1; + + ACE_IntCapEntry *icap = + dynamic_cast (cap); + if (icap != 0) + { + val = icap->getval (); + return 0; + } + + ACE_BoolCapEntry *bcap = + dynamic_cast (cap); + + if (bcap == 0) + return -1; + + val = bcap->getval (); + return 0; +} + +static int +is_empty (const ACE_TCHAR *line) +{ + while (*line && ACE_OS::ace_isspace (*line)) + ++line; + + return *line == ACE_TEXT ('\0') || *line == ACE_TEXT ('#'); +} + +static int +is_line (const ACE_TCHAR *line) +{ + while (*line && ACE_OS::ace_isspace (*line)) + ++line; + + return *line != ACE_TEXT ('\0'); +} + +int +ACE_Capabilities::getent (const ACE_TCHAR *fname, const ACE_TCHAR *name) +{ + FILE *fp = ACE_OS::fopen (fname, ACE_TEXT ("r")); + + if (fp == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("Can't open %s file\n"), + fname), + -1); + + int done; + ACE_TString line; + + while (0 == (done = (this->getline (fp, line) == -1)) + && is_empty (line.c_str ())) + continue; + + while (!done) + { + ACE_TString newline; + ACE_TString description; + + while (0 == (done = (this->getline (fp, newline) == -1))) + if (is_line (newline.c_str ())) + description += newline; + else + break; + + if (this->is_entry (name, line.c_str())) + { + ACE_OS::fclose (fp); + return this->fillent (description.c_str ()); + } + + line = newline; + while (!done && is_empty (line.c_str ())) + done = this->getline (fp, line) == -1; + } + + ACE_OS::fclose (fp); + return -1; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_StringCapEntry) +ACE_ALLOC_HOOK_DEFINE(ACE_IntCapEntry) +ACE_ALLOC_HOOK_DEFINE(ACE_BoolCapEntry) + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Capabilities.h b/dep/acelite/ace/Capabilities.h new file mode 100644 index 000000000..c3939f407 --- /dev/null +++ b/dep/acelite/ace/Capabilities.h @@ -0,0 +1,197 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Capabilities.h + * + * @author Arturo Montes + */ +//============================================================================= + + +#ifndef ACE_CAPABILITIES_H +#define ACE_CAPABILITIES_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Null_Mutex.h" +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Containers.h" +#include "ace/SString.h" +#include "ace/Functor_String.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_CapEntry + * + * @brief This class is the base class for all ACE Capabilities entry + * subclasses. + * + * This class is not instantiable and does not provide accessors + * or methods. If you want to add a new kind of attribute subclass + * this class and dynamic_cast to proper subclass. + */ +class ACE_Export ACE_CapEntry +{ +public: + + virtual ~ACE_CapEntry (void); + +protected: + + enum + { + ACE_INTCAP = 0, + ACE_STRINGCAP = 1, + ACE_BOOLCAP = 2 + }; + + ACE_CapEntry (int captype); + +protected: + + int captype_; + +}; + +/** + * @class ACE_IntCapEntry + * + * @brief This class implement the ACE Integer Capability subclass. + * + * This is a container class for ACE Capabilities integer container + * values. + */ +class ACE_Export ACE_IntCapEntry : public ACE_CapEntry +{ +public: + ACE_IntCapEntry (int val); + int getval (void) const; + ACE_ALLOC_HOOK_DECLARE; + +protected: + int val_; +}; + +/** + * @class ACE_StringCapEntry + * + * @brief This class implement the ACE String Capability subclass. + * + * This is a container class for ACE Capabilities String container + * values. + */ +class ACE_Export ACE_StringCapEntry : public ACE_CapEntry +{ +public: + ACE_StringCapEntry (const ACE_TString &val); + ACE_TString getval (void) const; + ACE_ALLOC_HOOK_DECLARE; + +protected: + ACE_TString val_; +}; + +/** + * @class ACE_BoolCapEntry + * + * @brief This class implement the ACE Bool Capability subclass. + * + * This is a container class for ACE Capabilities bool container + * values. + */ +class ACE_Export ACE_BoolCapEntry : public ACE_CapEntry +{ +public: + ACE_BoolCapEntry (int val); + int getval (void) const; + ACE_ALLOC_HOOK_DECLARE; + +protected: + int val_; +}; + +/** + * @class ACE_Capabilities + * + * @brief + * This class implement the ACE Capabilities. + * + * This is a container class for ACE Capabilities + * values. Currently exist three different capability values: + * ACE_IntCapEntry (integer), ACE_BoolCapEntry (bool) and + * ACE_StringCapEntry (String). An ACE_Capabilities is a + * unordered set of pair = (String, ACE_CapEntry *). Where + * the first component is the name of capability and the second + * component is a pointer to the capability value container. A + * FILE is a container for ACE_Capabilities, the + * ACE_Capabilities has a name in the file, as a termcap file. + */ +class ACE_Export ACE_Capabilities +{ +public: + + typedef ACE_Hash_Map_Manager_Ex, ACE_Equal_To, ACE_Null_Mutex> CAPABILITIES_MAP; + + /// The Constructor + ACE_Capabilities (void); + + /// The Destructor + ~ACE_Capabilities(void); + +public: + + /// Get a string entry. + int getval (const ACE_TCHAR *ent, ACE_TString &val); + + /// Get an integer entry. + int getval (const ACE_TCHAR *ent, int &val); + + /// Get the ACE_Capabilities name from FILE fname and load the + /// associated capabitily entries in map. + int getent (const ACE_TCHAR *fname, const ACE_TCHAR *name); + +protected: + + /// Parse an integer property + const ACE_TCHAR *parse (const ACE_TCHAR *buf, int &cap); + + /// Parse a string property + const ACE_TCHAR *parse (const ACE_TCHAR *buf, ACE_TString &cap); + + /// Fill the ACE_Capabilities with description in ent. + int fillent(const ACE_TCHAR *ent); + + /// Parse a cap entry + int parseent (const ACE_TCHAR *name, ACE_TCHAR *line); + + /// Get a line from FILE input stream + int getline (FILE* fp, + ACE_TString &line); + + /// Is a valid entry + int is_entry (const ACE_TCHAR *name, const ACE_TCHAR *line); + + /// Reset the set of capabilities + void resetcaps (void); + +private: + + /// This is the set of ACE_CapEntry. + CAPABILITIES_MAP caps_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Capabilities.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* __ACE_CAPABILITIES_H__ */ diff --git a/dep/acelite/ace/Capabilities.inl b/dep/acelite/ace/Capabilities.inl new file mode 100644 index 000000000..0579ae6cd --- /dev/null +++ b/dep/acelite/ace/Capabilities.inl @@ -0,0 +1,49 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_CapEntry::ACE_CapEntry (int captype) + : captype_ (captype) +{ +} + +ACE_INLINE +ACE_IntCapEntry::ACE_IntCapEntry (int val) + : ACE_CapEntry (ACE_INTCAP), + val_ (val) +{ +} + +ACE_INLINE int +ACE_IntCapEntry::getval (void) const +{ + return val_; +} + +ACE_INLINE +ACE_StringCapEntry::ACE_StringCapEntry (const ACE_TString &val) + : ACE_CapEntry (ACE_STRINGCAP), + val_ (val) +{ +} + +ACE_INLINE ACE_TString +ACE_StringCapEntry::getval (void) const +{ + return val_; +} + +ACE_INLINE +ACE_BoolCapEntry::ACE_BoolCapEntry (int val) + : ACE_CapEntry (ACE_BOOLCAP), + val_(val) +{ +} + +ACE_INLINE int +ACE_BoolCapEntry::getval (void) const +{ + return val_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Cleanup.cpp b/dep/acelite/ace/Cleanup.cpp new file mode 100644 index 000000000..0e162c8cf --- /dev/null +++ b/dep/acelite/ace/Cleanup.cpp @@ -0,0 +1,185 @@ +#include "ace/Cleanup.h" + +#if !defined (ACE_HAS_INLINED_OSCALLS) +# include "ace/Cleanup.inl" +#endif /* ACE_HAS_INLINED_OSCALLS */ + +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/os_typeinfo.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +void +ACE_Cleanup::cleanup (void *) +{ + delete this; +} + +ACE_Cleanup::~ACE_Cleanup (void) +{ +} + +/*****************************************************************************/ + +extern "C" void +ACE_CLEANUP_DESTROYER_NAME (ACE_Cleanup *object, void *param) +{ + object->cleanup (param); +} + +/*****************************************************************************/ + +ACE_Cleanup_Info_Node::ACE_Cleanup_Info_Node (void) + : object_ (0), + cleanup_hook_ (0), + param_ (0), + name_ (0) +{ +} + +ACE_Cleanup_Info_Node::ACE_Cleanup_Info_Node (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param, + const char *name) + : object_ (object), + cleanup_hook_ (cleanup_hook), + param_ (param), + name_ (name ? ACE_OS::strdup (name) : 0) +{ +} + +ACE_Cleanup_Info_Node::~ACE_Cleanup_Info_Node (void) +{ + if (this->name_) +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free ((void *) name_); +#else + ACE_OS::free ((void *) name_); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Cleanup_Info_Node) + +bool +ACE_Cleanup_Info_Node::operator== (const ACE_Cleanup_Info_Node &o) const +{ + return o.object_ == this->object_ + && o.cleanup_hook_ == this->cleanup_hook_ + && o.param_ == this->param_; +} + +bool +ACE_Cleanup_Info_Node::operator!= (const ACE_Cleanup_Info_Node &o) const +{ + return !(*this == o); +} + + +/*****************************************************************************/ + +ACE_OS_Exit_Info::ACE_OS_Exit_Info (void) +{ +} + +ACE_OS_Exit_Info::~ACE_OS_Exit_Info (void) +{ +} + +int +ACE_OS_Exit_Info::at_exit_i (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param, + const char* name) +{ + // Return -1 and sets errno if unable to allocate storage. Enqueue + // at the head and dequeue from the head to get LIFO ordering. + ACE_Cleanup_Info_Node *new_node = 0; + + ACE_NEW_RETURN (new_node, + ACE_Cleanup_Info_Node (object, cleanup_hook, param, name), + -1); + + registered_objects_.push_front (new_node); + + return 0; +} + +bool +ACE_OS_Exit_Info::find (void *object) +{ + for (ACE_Cleanup_Info_Node *iter = registered_objects_.head (); + iter != 0; + iter = iter->next ()) + { + if (iter->object () == object) + { + // The object has already been registered. + return true; + } + } + + return false; +} + +bool +ACE_OS_Exit_Info::remove (void *object) +{ + ACE_Cleanup_Info_Node *node = 0; + for (ACE_Cleanup_Info_Node *iter = registered_objects_.head (); + iter != 0; + iter = iter->next ()) + { + if (iter->object () == object) + { + node = iter; + break; + } + } + + if (node) + { + registered_objects_.remove (node); + delete node; + return true; + } + + return false; +} + + +void +ACE_OS_Exit_Info::call_hooks (void) +{ + // Call all registered cleanup hooks, in reverse order of + // registration. + for (ACE_Cleanup_Info_Node *iter = registered_objects_.pop_front (); + iter != 0; + iter = registered_objects_.pop_front ()) + { + if (iter->cleanup_hook () == reinterpret_cast ( + ACE_CLEANUP_DESTROYER_NAME)) + { + // The object is an ACE_Cleanup. + ACE_CLEANUP_DESTROYER_NAME ( + reinterpret_cast (iter->object ()), + iter->param ()); + } + else if (iter->object () == &ace_exit_hook_marker) + { + // The hook is an ACE_EXIT_HOOK. + (* reinterpret_cast (iter->cleanup_hook ())) (); + } + else + { + (*iter->cleanup_hook ()) (iter->object (), iter->param ()); + } + delete iter; + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Cleanup.h b/dep/acelite/ace/Cleanup.h new file mode 100644 index 000000000..86044c85c --- /dev/null +++ b/dep/acelite/ace/Cleanup.h @@ -0,0 +1,161 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Cleanup.h + * + * @author Douglas C. Schmidt + * @author Jesper S. M|ller + * @author and a cast of thousands... + * + * Originally in OS.h. + */ +//============================================================================= + +#ifndef ACE_CLEANUP_H +# define ACE_CLEANUP_H + +# include /**/ "ace/pre.h" + +# include "ace/config-lite.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/ACE_export.h" + +# include "ace/Intrusive_List.h" +# include "ace/Intrusive_List_Node.h" + +#if (defined (ACE_HAS_VERSIONED_NAMESPACE) && ACE_HAS_VERSIONED_NAMESPACE == 1) +# include "ace/Global_Macros.h" +# define ACE_CLEANUP_DESTROYER_NAME ACE_PREPROC_CONCATENATE(ACE_VERSIONED_NAMESPACE_NAME, _ace_cleanup_destroyer) +#else +# define ACE_CLEANUP_DESTROYER_NAME ace_cleanup_destroyer +#endif /* ACE_HAS_VERSIONED_NAMESPACE == 1 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Cleanup + * + * @brief Base class for objects that are cleaned by ACE_Object_Manager. + */ +class ACE_Export ACE_Cleanup +{ +public: + /// No-op constructor. + ACE_Cleanup (void); + + /// Destructor. + virtual ~ACE_Cleanup (void); + + /// Cleanup method that, by default, simply deletes itself. + virtual void cleanup (void *param = 0); +}; + +/// Adapter for cleanup, used by ACE_Object_Manager. +extern "C" ACE_Export +void ACE_CLEANUP_DESTROYER_NAME (ACE_Cleanup *, void *param = 0); + +/** + * @class ACE_Cleanup_Info_Node + * + * @brief For maintaining a list of ACE_Cleanup_Info items. + * + * For internal use by ACE_Object_Manager. + */ +class ACE_Cleanup_Info_Node : public ACE_Intrusive_List_Node +{ +public: + ACE_Cleanup_Info_Node (void); + ACE_Cleanup_Info_Node (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param, + const char *name); + ~ACE_Cleanup_Info_Node (void); + + /// Equality operator. + bool operator== (const ACE_Cleanup_Info_Node &o) const; + + /// Inequality operator. + bool operator!= (const ACE_Cleanup_Info_Node &o) const; + + void* object(void); + + ACE_CLEANUP_FUNC cleanup_hook (void); + + void *param (void); + + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Point to object that gets passed into the . + void *object_; + + /// Cleanup hook that gets called back. + ACE_CLEANUP_FUNC cleanup_hook_; + + /// Parameter passed to the . + void *param_; + + /// Name of the cleanup object + const char *name_; +}; + +typedef ACE_Intrusive_List ACE_Cleanup_Info_Node_List; + +/** + * @class ACE_OS_Exit_Info + * + * @brief Hold Object Manager cleanup (exit) information. + * + * @internal + * + * For internal use by the ACE library, only. + */ +class ACE_Export ACE_OS_Exit_Info +{ +public: + /// Default constructor. + ACE_OS_Exit_Info (void); + + /// Destructor. + ~ACE_OS_Exit_Info (void); + + /// Use to register a cleanup hook. + int at_exit_i (void *object, ACE_CLEANUP_FUNC cleanup_hook, void *param, const char* name = 0); + + /// Look for a registered cleanup hook object. Returns true if already + /// registered, false if not. + bool find (void *object); + + /// Remove a registered cleanup hook object. Returns true if removed + /// false if not. + bool remove (void *object); + + /// Call all registered cleanup hooks, in reverse order of + /// registration. + void call_hooks (); + +private: + /** + * Keeps track of all registered objects. + */ + ACE_Cleanup_Info_Node_List registered_objects_; +}; + + +ACE_END_VERSIONED_NAMESPACE_DECL + +# if defined (ACE_HAS_INLINED_OSCALLS) +# if defined (ACE_INLINE) +# undef ACE_INLINE +# endif /* ACE_INLINE */ +# define ACE_INLINE inline +# include "ace/Cleanup.inl" +# endif /* ACE_HAS_INLINED_OSCALLS */ + +# include /**/ "ace/post.h" +#endif /* ACE_CLEANUP_H */ diff --git a/dep/acelite/ace/Cleanup.inl b/dep/acelite/ace/Cleanup.inl new file mode 100644 index 000000000..fdae3412f --- /dev/null +++ b/dep/acelite/ace/Cleanup.inl @@ -0,0 +1,27 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Cleanup::ACE_Cleanup (void) +{ +} + +ACE_INLINE void* +ACE_Cleanup_Info_Node::object(void) +{ + return this->object_; +} + +ACE_INLINE ACE_CLEANUP_FUNC +ACE_Cleanup_Info_Node::cleanup_hook (void) +{ + return this->cleanup_hook_; +} + +ACE_INLINE void * +ACE_Cleanup_Info_Node::param (void) +{ + return this->param_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Cleanup_Strategies_T.cpp b/dep/acelite/ace/Cleanup_Strategies_T.cpp new file mode 100644 index 000000000..53cf0b876 --- /dev/null +++ b/dep/acelite/ace/Cleanup_Strategies_T.cpp @@ -0,0 +1,93 @@ +#ifndef ACE_CLEANUP_STRATEGIES_T_CPP +#define ACE_CLEANUP_STRATEGIES_T_CPP + +#include "ace/Cleanup_Strategies_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +//////////////////////////////////////////////////////////////////////////// + +template +ACE_Cleanup_Strategy::~ACE_Cleanup_Strategy (void) +{ +} + +template int +ACE_Cleanup_Strategy::cleanup (CONTAINER &container, + KEY *key, + VALUE *) +{ + return container.unbind (*key); +} + +//////////////////////////////////////////////////////////////////////////// + +template int +ACE_Recyclable_Handler_Cleanup_Strategy::cleanup ( + CONTAINER &container, + KEY *key, + VALUE *) +{ + VALUE value; + + if (container.unbind (*key, value) == -1) + return -1; + + value.first->recycler (0, 0); + + value.first->close (); + + return 0; +} + +///////////////////////////////////////////////////////////////////////////// + +template int +ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy::cleanup ( + CONTAINER &, + KEY *, + VALUE *value) +{ + return value->first ()->handle_close_i (); +} + +//////////////////////////////////////////////////////////////////////////// + +template int +ACE_Handler_Cleanup_Strategy::cleanup ( + CONTAINER &container, + KEY *key, + VALUE *value) +{ + // Remove the item from cache only if the handler isnt in use. + if ((*value)->active () == 0) + { + (*value)->close (); + + if (container.unbind (*key) == -1) + return -1; + + } + + return 0; +} + +//////////////////////////////////////////////////////////////////////////// + +template int +ACE_Null_Cleanup_Strategy::cleanup (CONTAINER &, + KEY *, + VALUE *) +{ + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CLEANUP_STRATEGIES_T_CPP */ diff --git a/dep/acelite/ace/Cleanup_Strategies_T.h b/dep/acelite/ace/Cleanup_Strategies_T.h new file mode 100644 index 000000000..96900418a --- /dev/null +++ b/dep/acelite/ace/Cleanup_Strategies_T.h @@ -0,0 +1,147 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Cleanup_Strategies_T.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + + +#ifndef CLEANUP_STRATEGIES_H +#define CLEANUP_STRATEGIES_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// For linkers that cant grok long names. +#define ACE_Cleanup_Strategy ACLE + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Cleanup_Strategy + * + * @brief Defines a default strategy to be followed for cleaning up + * entries from a map which is the container. + * + * By default the entry to be cleaned up is removed from the + * container. + */ +template +class ACE_Cleanup_Strategy +{ + +public: + + /// Destructor. + virtual ~ACE_Cleanup_Strategy (void); + + /// The method which will do the cleanup of the entry in the container. + virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value); +}; + +////////////////////////////////////////////////////////////////////// +#define ACE_Recyclable_Handler_Cleanup_Strategy ARHCLE + +/** + * @class ACE_Recyclable_Handler_Cleanup_Strategy + * + * @brief Defines a strategy to be followed for cleaning up + * entries which are svc_handlers from a container. + * + * The entry to be cleaned up is removed from the container. + * Here, since we are dealing with svc_handlers specifically, we + * perform a couple of extra operations. @note To be used when + * the handler is recyclable. + */ +template +class ACE_Recyclable_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy +{ + +public: + + /// The method which will do the cleanup of the entry in the container. + virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value); +}; + +////////////////////////////////////////////////////////////////////// +#define ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy ARRHCLE + +/** + * @class ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy + * + * @brief Defines a strategy to be followed for cleaning up + * entries which are svc_handlers from a container. + * + * The entry to be cleaned up is removed from the container. + * Here, since we are dealing with recyclable svc_handlers with + * addresses which are refcountable specifically, we perform a + * couple of extra operations and do so without any locking. + */ +template +class ACE_Refcounted_Recyclable_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy +{ +public: + /// The method which will do the cleanup of the entry in the container. + virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value); +}; + +////////////////////////////////////////////////////////////////////// + +/** + * @class ACE_Handler_Cleanup_Strategy + * + * @brief Defines a strategy to be followed for cleaning up + * entries which are svc_handlers from a container. + * + * The entry to be cleaned up is removed from the container. + * Here, since we are dealing with svc_handlers specifically, we + * perform a couple of extra operations. @note This cleanup strategy + * should be used in the case when the handler has the caching + * attributes. + */ +template +class ACE_Handler_Cleanup_Strategy : public ACE_Cleanup_Strategy +{ +public: + /// The method which will do the cleanup of the entry in the container. + virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value); +}; + +////////////////////////////////////////////////////////////////////// +#define ACE_Null_Cleanup_Strategy ANCLE + +/** + * @class ACE_Null_Cleanup_Strategy + * + * @brief Defines a do-nothing implementation of the cleanup strategy. + * + * This class simply does nothing at all! Can be used to nullify + * the effect of the Cleanup Strategy. + */ +template +class ACE_Null_Cleanup_Strategy : public ACE_Cleanup_Strategy +{ +public: + /// The dummy cleanup method. + virtual int cleanup (CONTAINER &container, KEY *key, VALUE *value); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Cleanup_Strategies_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Cleanup_Strategies_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* CLEANUP_STRATEGIES_H */ diff --git a/dep/acelite/ace/Codecs.cpp b/dep/acelite/ace/Codecs.cpp new file mode 100644 index 000000000..7b22f2735 --- /dev/null +++ b/dep/acelite/ace/Codecs.cpp @@ -0,0 +1,247 @@ +#include "ace/Codecs.h" +#include "ace/Log_Category.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_ctype.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +namespace +{ + // Just in case ... +#undef alphabet +#undef pad +#undef max_columns + + // Symbols which form the Base64 alphabet (Defined as per RFC 2045) + ACE_Byte const alphabet[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + // The padding character used in the encoding + ACE_Byte const pad = '='; + + // Number of columns per line of encoded output (Can have a maximum + // value of 76). + int const max_columns = 72; +} + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +bool ACE_Base64::init_ = false; + +ACE_Byte ACE_Base64::decoder_[256]; + +ACE_Byte ACE_Base64::member_[256]; + +ACE_Byte* +ACE_Base64::encode (const ACE_Byte* input, + const size_t input_len, + size_t* output_len, + bool is_chunked) +{ + if (!ACE_Base64::init_) + ACE_Base64::init(); + + if (!input) + return 0; + + ACE_Byte* result = 0; + + size_t length = ((input_len + 2) / 3) * 4; + size_t num_lines = length / max_columns + 1; + length += num_lines + 1; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (result, static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_Byte) * length)), 0); +#else + ACE_NEW_RETURN (result, ACE_Byte[length], 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + int char_count = 0; + int bits = 0; + size_t pos = 0; + int cols = 0; + + for (size_t i = 0; i < input_len; ++i) + { + bits += input[i]; + ++char_count; + + if (char_count == 3) + { + result[pos++] = alphabet[bits >> 18]; + result[pos++] = alphabet[(bits >> 12) & 0x3f]; + result[pos++] = alphabet[(bits >> 6) & 0x3f]; + result[pos++] = alphabet[bits & 0x3f]; + cols += 4; + if (cols == max_columns) { + if (is_chunked) + result[pos++] = '\n'; + cols = 0; + } + bits = 0; + char_count = 0; + } + else + { + bits <<= 8; + } + } + + if (char_count != 0) + { + bits <<= (16 - (8 * char_count)); + result[pos++] = alphabet[bits >> 18]; + result[pos++] = alphabet[(bits >> 12) & 0x3f]; + cols += 2; + if (char_count == 1) + { + result[pos++] = pad; + result[pos++] = pad; + cols += 2; + } + else + { + result[pos++] = alphabet[(bits >> 6) & 0x3f]; + result[pos++] = pad; + cols += 2; + } + } + + if (cols > 0 && is_chunked) + result[pos++] = '\n'; + + result[pos] = 0; + *output_len = pos; + return result; +} + +size_t +ACE_Base64::length (const ACE_Byte* input) +{ + if (!ACE_Base64::init_) + ACE_Base64::init(); + + ACE_Byte* ptr = const_cast (input); + while (*ptr != 0 && + (member_[*(ptr)] == 1 || *ptr == pad + || ACE_OS::ace_isspace (*ptr))) + ++ptr; + size_t len = ptr - input; + len = ((len + 3) / 4) * 3 + 1 ; + return len; +} + +ACE_Byte* +ACE_Base64::decode (const ACE_Byte* input, size_t* output_len) +{ + if (!ACE_Base64::init_) + ACE_Base64::init(); + + if (!input) + return 0; + + size_t result_len = ACE_Base64::length (input); + ACE_Byte* result = 0; + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (result, static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_Byte) * result_len)), 0); +#else + ACE_NEW_RETURN (result, ACE_Byte[result_len], 0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACE_Byte* ptr = const_cast (input); + while (*ptr != 0 && + (member_[*(ptr)] == 1 || *ptr == pad + || ACE_OS::ace_isspace (*ptr))) + ++ptr; + size_t input_len = ptr - input; + + int char_count = 0; + int bits = 0; + size_t pos = 0; + + size_t i = 0; + for (; i < input_len; ++i) + { + if (input[i] == pad) + break; + if (!ACE_Base64::member_[input[i]]) + continue; + bits += decoder_[input[i]]; + ++char_count; + + if (char_count == 4) + { + result[pos++] = static_cast (bits >> 16); + result[pos++] = static_cast ((bits >> 8) & 0xff); + result[pos++] = static_cast (bits & 0xff); + bits = 0; + char_count = 0; + } + else + { + bits <<= 6; + } + } + + int errors = 0; + if ( i == input_len) + { + if (char_count) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("Decoding incomplete: atleast %d bits truncated\n"), + (4 - char_count) * 6)); + ++errors; + } + } + else + { + switch (char_count) + { + case 1: + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("Decoding incomplete: atleast 2 bits missing\n"))); + ++errors; + break; + case 2: + result[pos++] = static_cast (bits >> 10); + break; + case 3: + result[pos++] = static_cast (bits >> 16); + result[pos++] = static_cast ((bits >> 8) & 0xff); + break; + } + } + + if (errors) + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(result); +#else + delete[] result; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return 0; + } + result[pos] = 0; + *output_len = pos; + return result; +} + +void +ACE_Base64::init () +{ + if (!ACE_Base64::init_) + { + for (ACE_Byte i = 0; i < sizeof (alphabet); ++i) + { + ACE_Base64::decoder_[alphabet[i]] = i; + ACE_Base64::member_ [alphabet[i]] = 1; + } + ACE_Base64::init_ = true; + } + return; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Codecs.h b/dep/acelite/ace/Codecs.h new file mode 100644 index 000000000..f8d686397 --- /dev/null +++ b/dep/acelite/ace/Codecs.h @@ -0,0 +1,116 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Codecs.h + * + * @author Krishnakumar B + * + * Codecs is a generic wrapper for various encoding and decoding + * mechanisms. Currently it includes Base64 content transfer-encoding as + * specified by RFC 2045, Multipurpose Internet Mail Extensions (MIME) Part + * One: Format of Internet Message Bodies. + */ +//============================================================================= + +#ifndef ACE_CODECS_H +#define ACE_CODECS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Types.h" +#include "ace/Global_Macros.h" + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Base64 + * + * @brief Encode/Decode a stream of bytes according to Base64 encoding. + * + * This class provides methods to encode or decode a stream of bytes + * to/from Base64 encoding. It doesn't convert the input stream to a + * canonical form before encoding. + */ +class ACE_Export ACE_Base64 +{ +public: + + //@{ + + /** + * Encodes a stream of bytes to Base64 data + * + * @param input Binary data in byte stream. + * @param input_len Length of the byte stream. + * @param output_len Length of the encoded Base64 byte stream. + * @param is_chunked If true, terminate 72 character blocks with newline + * @return Encoded Base64 data in byte stream or NULL if input data cannot + * be encoded. + */ + static ACE_Byte* encode (const ACE_Byte* input, + const size_t input_len, + size_t* output_len, + bool is_chunked = true); + /** + * Decodes a stream of Base64 to bytes data + * + * @param input Encoded Base64 data in byte stream. + * @param output_len Length of the binary byte stream. + * @return Binary data in byte stream or NULL if input data cannot + * be encoded. + */ + static ACE_Byte* decode (const ACE_Byte* input, + size_t* output_len); + + /** + * Return the length of the encoded input data + * + * @param input Encoded Base64 data in byte stream. + * @return Length of the encoded Base64 data. + * + */ + static size_t length (const ACE_Byte* input); + + //@} + +protected: + + // Prevent default construction. + ACE_Base64 (void) {} + +private: + + // Preventing copying and assignment. + ACE_Base64 (ACE_Base64 const &); + ACE_Base64 & operator= (ACE_Base64 const &); + + /// Initialize the tables for encoding/decoding. + static void init (void); + +private: + + /// Alphabet used for decoding i.e decoder_[alphabet_[i = 0..63]] = i + static ACE_Byte decoder_[]; + + /// Alphabet used to check valid range of encoded input i.e + /// member_[alphabet_[0..63]] = 1 + static ACE_Byte member_[]; + + /// Boolean to denote whether initialization is complete + static bool init_; + +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_CODECS_H */ diff --git a/dep/acelite/ace/Codeset_IBM1047.cpp b/dep/acelite/ace/Codeset_IBM1047.cpp new file mode 100644 index 000000000..edfd2bab4 --- /dev/null +++ b/dep/acelite/ace/Codeset_IBM1047.cpp @@ -0,0 +1,374 @@ + +//============================================================================= +/** + * @file Codeset_IBM1047.cpp + * + * Defines the arrays required to convert between ISO8859 (aka + * Latin/1) and IBM1047 (aka EBCDIC). + * + * @author Jim Rogers (jrogers@viasoft.com) + */ +//============================================================================= + + +#include "ace/Codeset_IBM1047.h" + +#if defined (ACE_HAS_EBCDIC) + +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" + +namespace +{ + char const to_IBM1047[] = + { + "\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F" // 00-0F + "\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x22\x1D\x35\x1F" // 10-1F + "\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61" // 20-2F + "\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F" // 30-3F + "\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6" // 40-4F + "\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D" // 50-5F + "\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96" // 60-6F + "\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07" // 70-7F + "\x43\x20\x21\x1C\x23\xEB\x24\x9B\x71\x28\x38\x49\x90\xBA\xEC\xDF" // 80-8F + "\x45\x29\x2A\x9D\x72\x2B\x8A\x9A\x67\x56\x64\x4A\x53\x68\x59\x46" // 90-9F + "\xEA\xDA\x2C\xDE\x8B\x55\x41\xFE\x58\x51\x52\x48\x69\xDB\x8E\x8D" // A0-AF + "\x73\x74\x75\xFA\x15\xB0\xB1\xB3\xB4\xB5\x6A\xB7\xB8\xB9\xCC\xBC" // B0-BF + "\xAB\x3E\x3B\x0A\xBF\x8F\x3A\x14\xA0\x17\xCB\xCA\x1A\x1B\x9C\x04" // C0-CF + "\x34\xEF\x1E\x06\x08\x09\x77\x70\xBE\xBB\xAC\x54\x63\x65\x66\x62" // D0-DF + "\x30\x42\x47\x57\xEE\x33\xB6\xE1\xCD\xED\x36\x44\xCE\xCF\x31\xAA" // E0-EF + "\xFC\x9E\xAE\x8C\xDD\xDC\x39\xFB\x80\xAF\xFD\x78\x76\xB2\x9F\xFF" // F0-FF +}; + + char const from_IBM1047[] = + { + "\x00\x01\x02\x03\xCF\x09\xD3\x7F\xD4\xD5\xC3\x0B\x0C\x0D\x0E\x0F" // 00-0F + "\x10\x11\x12\x13\xC7\xB4\x08\xC9\x18\x19\xCC\xCD\x83\x1D\xD2\x1F" // 10-1F + "\x81\x82\x1C\x84\x86\x0A\x17\x1B\x89\x91\x92\x95\xA2\x05\x06\x07" // 20-2F + "\x20\xEE\x16\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\xC1\x1A" // 30-3F + "\x20\xA6\xE1\x80\xEB\x90\x9F\xE2\xAB\x8B\x9B\x2E\x3C\x28\x2B\x7C" // 40-4F + "\x26\xA9\xAA\x9C\xDB\xA5\x99\xE3\xA8\x9E\x21\x24\x2A\x29\x3B\x5E" // 50-5F + "\x2D\x2F\xDF\xDC\x9A\xDD\xDE\x98\x9D\xAC\xBA\x2C\x25\x5F\x3E\x3F" // 60-6F + "\xD7\x88\x94\xB0\xB1\xB2\xFC\xD6\xFB\x60\x3A\x23\x40\x27\x3D\x22" // 70-7F + "\xF8\x61\x62\x63\x64\x65\x66\x67\x68\x69\x96\xA4\xF3\xAF\xAE\xC5" // 80-8F + "\x8C\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x97\x87\xCE\x93\xF1\xFE" // 90-9F + "\xC8\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xEF\xC0\xDA\x5B\xF2\xF9" // A0-AF + "\xB5\xB6\xFD\xB7\xB8\xB9\xE6\xBB\xBC\xBD\x8D\xD9\xBF\x5D\xD8\xC4" // B0-BF + "\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCB\xCA\xBE\xE8\xEC\xED" // C0-CF + "\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xA1\xAD\xF5\xF4\xA3\x8F" // D0-DF + "\x5C\xE7\x53\x54\x55\x56\x57\x58\x59\x5A\xA0\x85\x8E\xE9\xE4\xD1" // E0-EF + "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xB3\xF7\xF0\xFA\xA7\xFF" // F0-FF + }; +} + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_IBM1047_ISO8859::ACE_IBM1047_ISO8859 (void) +{ +} + +ACE_IBM1047_ISO8859::~ACE_IBM1047_ISO8859 (void) +{ +} + +ACE_CDR::ULong +ACE_IBM1047_ISO8859::ncs () +{ + return 0x10020417; +} + +ACE_CDR::ULong +ACE_IBM1047_ISO8859::tcs () +{ + return 0x00010001; +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::read_char (ACE_InputCDR &in, + ACE_CDR::Char &x) +{ + if (this->read_1 (in, reinterpret_cast (&x))) + { + x = to_IBM1047[x]; + return 1; + } + return 0; +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::read_string (ACE_InputCDR& in, + ACE_CDR::Char *& x) +{ + ACE_CDR::ULong len; + + in.read_ulong (len); + + if (len > 0) + { + ACE_NEW_RETURN (x, + ACE_CDR::Char[len], + 0); + + if (this->read_char_array (in, x, len)) + return 1; + + delete [] x; + } + + x = 0; + return 0; +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::read_string (ACE_InputCDR& in, + std::string & x) +{ +#if defined (ACE_HAS_CPP11) + ACE_CDR::ULong len; + + in.read_ulong (len); + + if (len > 0) + { + try + { + x.resize (len); + } + catch (const std::bad_alloc&) + { + return false; + } + + if (this->read_char_array (in, &x[0], len)) + { + x.resize (len-1); // drop terminating '\0' read from stream + return true; + } + + delete [] x; + } + + x.clear (); + return false; +#else + return this->ACE_Char_Codeset_Translator::read_string (in, x); +#endif +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::read_char_array (ACE_InputCDR& in, + ACE_CDR::Char* x, + ACE_CDR::ULong len) +{ + if (this->read_array (in, + x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + len)) + { + for (ACE_CDR::ULong i = 0; i != len; ++i) + x[i] = to_IBM1047[x[i]]; + + return 1; + } + + return 0; +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::write_char (ACE_OutputCDR& out, + ACE_CDR::Char x) +{ + return + this->write_1 (out, + reinterpret_cast (&from_IBM1047[x])); +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::write_string (ACE_OutputCDR& out, + ACE_CDR::ULong len, + const ACE_CDR::Char* x) +{ + if (out.write_ulong (len + 1)) + return this->write_char_array (out, x, len + 1); + return 0; +} + +ACE_CDR::Boolean +ACE_IBM1047_ISO8859::write_char_array (ACE_OutputCDR& out, + const ACE_CDR::Char* x, + ACE_CDR::ULong len) +{ + char *buf = 0; + if (this->adjust (out, len, 1, buf) == 0) + { + ACE_OS::memcpy (buf, x, len); + + for (ACE_CDR::ULong i = 0; i != len; ++i) + buf[i] = from_IBM1047[buf[i]]; + + return 1; + } + + this->good_bit(out, 0); + return 0; +} + +// **************************************************************** + +ACE_ISO8859_IBM1047::ACE_ISO8859_IBM1047 (void) +{ +} + +ACE_ISO8859_IBM1047::~ACE_ISO8859_IBM1047 (void) +{ +} + +ACE_CDR::ULong +ACE_ISO8859_IBM1047::ncs () +{ + return 0x00010001; +} + +ACE_CDR::ULong +ACE_ISO8859_IBM1047::tcs () +{ + return 0x10020417; +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::read_char (ACE_InputCDR& in, + ACE_CDR::Char& x) +{ + if (this->read_1 (in, reinterpret_cast (&x))) + { + x = from_IBM1047[x]; + return 1; + } + return 0; +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::read_string (ACE_InputCDR &in, + ACE_CDR::Char *&x) +{ + ACE_CDR::ULong len; + + in.read_ulong (len); + + if (len > 0) + { + ACE_NEW_RETURN (x, + ACE_CDR::Char[len], + 0); + + if (this->read_char_array (in, x, len)) + return 1; + + delete [] x; + } + + x = 0; + return 0; +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::read_string (ACE_InputCDR& in, + std::string & x) +{ +#if defined (ACE_HAS_CPP11) + ACE_CDR::ULong len; + + in.read_ulong (len); + + if (len > 0) + { + try + { + x.resize (len); + } + catch (const std::bad_alloc&) + { + return false; + } + + if (this->read_char_array (in, &x[0], len)) + { + x.resize (len-1); // drop terminating '\0' read from stream + return true; + } + + delete [] x; + } + + x.clear (); + return false; +#else + return this->ACE_Char_Codeset_Translator::read_string (in, x); +#endif +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::read_char_array (ACE_InputCDR &in, + ACE_CDR::Char *x, + ACE_CDR::ULong len) +{ + if (this->read_array (in, + x, + ACE_CDR::OCTET_SIZE, + ACE_CDR::OCTET_ALIGN, + len)) + { + for (ACE_CDR::ULong i = 0; i != len; ++i) + x[i] = from_IBM1047[x[i]]; + + return 1; + } + + return 0; +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::write_char (ACE_OutputCDR &out, + ACE_CDR::Char x) +{ + return + this->write_1 (out, + reinterpret_cast (&to_IBM1047[x])); +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::write_string (ACE_OutputCDR& out, + ACE_CDR::ULong len, + const ACE_CDR::Char* x) +{ + if (out.write_ulong (len + 1)) + return this->write_char_array (out, x, len + 1); + else + return 0; +} + +ACE_CDR::Boolean +ACE_ISO8859_IBM1047::write_char_array (ACE_OutputCDR &out, + const ACE_CDR::Char *x, + ACE_CDR::ULong len) +{ + char *buf = 0; + + if (this->adjust (out, len, 1, buf) == 0) + { + ACE_OS::memcpy (buf, x, len); + + for (ACE_CDR::ULong i = 0; i != len; ++i) + buf[i] = to_IBM1047[buf[i]]; + + return 1; + } + + this->good_bit (out, 0); + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_EBCDIC */ diff --git a/dep/acelite/ace/Codeset_IBM1047.h b/dep/acelite/ace/Codeset_IBM1047.h new file mode 100644 index 000000000..d9d84aa40 --- /dev/null +++ b/dep/acelite/ace/Codeset_IBM1047.h @@ -0,0 +1,129 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Codeset_IBM1047.h + * + * Declares the arrays required to convert between ISO8859 (aka + * Latin/1) and IBM1047 (aka EBCDIC). + * + * @author Jim Rogers (jrogers@viasoft.com) + */ +//============================================================================= + + +#ifndef ACE_CODESET_IMB1047_H +#define ACE_CODESET_IMB1047_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_EBCDIC) + +#include "ace/CDR_Stream.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// **************************************************************** + +/** + * @class ACE_IBM1047_ISO8859 + * + * @brief Codeset translation specialization. + * + * This class performs the codeset translation: + * - Native: IBM_1047 (i.e. EBCDIC) + * - Stream: ISO-8859 (i.e. Latin/1) + */ +class ACE_Export ACE_IBM1047_ISO8859 : public ACE_Char_Codeset_Translator +{ +public: + /// A do nothing constructor. + ACE_IBM1047_ISO8859 (void); + + /// Virtual destruction + virtual ~ACE_IBM1047_ISO8859 (void); + + // = Documented in $ACE_ROOT/ace/CDR_Stream.h + virtual ACE_CDR::Boolean read_char (ACE_InputCDR &, + ACE_CDR::Char &); + virtual ACE_CDR::Boolean read_string (ACE_InputCDR &, + ACE_CDR::Char *&); + virtual ACE_CDR::Boolean read_string (ACE_InputCDR &, + std::string &); + virtual ACE_CDR::Boolean read_char_array (ACE_InputCDR &, + ACE_CDR::Char *, + ACE_CDR::ULong); + virtual ACE_CDR::Boolean write_char (ACE_OutputCDR &, + ACE_CDR::Char); + virtual ACE_CDR::Boolean write_string (ACE_OutputCDR &, + ACE_CDR::ULong, + const ACE_CDR::Char *); + virtual ACE_CDR::Boolean write_char_array (ACE_OutputCDR &, + const ACE_CDR::Char *, + ACE_CDR::ULong); + + /// Return the native codeset ID as defined in the OSF code and character + /// set registry, 0x10020417 + virtual ACE_CDR::ULong ncs (); + /// Return the translated codeset ID as defined in the OSF code and character + /// set registry, 0x00010001 + virtual ACE_CDR::ULong tcs (); +}; + +/** + * @class ACE_ISO8859_IBM1047 + * + * @brief Codeset translation specialization. + * + * This class performs the codeset translation: + * - Native: ISO-8859 (i.e. Latin/1) + * - Stream: IBM-1047 (i.e. EBCDIC) + */ +class ACE_Export ACE_ISO8859_IBM1047 : public ACE_Char_Codeset_Translator +{ +public: + /// A do nothing constructor. + ACE_ISO8859_IBM1047 (void); + + /// Virtual destruction + virtual ~ACE_ISO8859_IBM1047 (void); + + // = Documented in $ACE_ROOT/ace/CDR_Stream.h + virtual ACE_CDR::Boolean read_char (ACE_InputCDR &, + ACE_CDR::Char &); + virtual ACE_CDR::Boolean read_string (ACE_InputCDR &, + ACE_CDR::Char *&); + virtual ACE_CDR::Boolean read_string (ACE_InputCDR &, + std::string &); + virtual ACE_CDR::Boolean read_char_array (ACE_InputCDR &, + ACE_CDR::Char *, + ACE_CDR::ULong); + virtual ACE_CDR::Boolean write_char (ACE_OutputCDR &, + ACE_CDR::Char); + virtual ACE_CDR::Boolean write_string (ACE_OutputCDR &, + ACE_CDR::ULong, + const ACE_CDR::Char *); + virtual ACE_CDR::Boolean write_char_array (ACE_OutputCDR &, + const ACE_CDR::Char *, + ACE_CDR::ULong); + + /// Return the native codeset ID as defined in the OSF code and character + /// set registry, 0x00010001 + virtual ACE_CDR::ULong ncs (); + /// Return the translated codeset ID as defined in the OSF code and character + /// set registry, 0x10020417 + virtual ACE_CDR::ULong tcs (); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_EBCDIC */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CODESET_IMB1047_H */ diff --git a/dep/acelite/ace/Codeset_Registry.cpp b/dep/acelite/ace/Codeset_Registry.cpp new file mode 100644 index 000000000..7ae55118d --- /dev/null +++ b/dep/acelite/ace/Codeset_Registry.cpp @@ -0,0 +1,110 @@ +//============================================================================= +/** + * @file Codeset_Registry.cpp + * + * emulated codset regstry functions + * + * @author Phil Mesnier + */ +//============================================================================= + +#include "ace/Codeset_Registry.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Codeset_Registry.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +int +ACE_Codeset_Registry::locale_to_registry_i (const ACE_CString &locale, + ACE_CDR::ULong &codeset_id, + ACE_CDR::UShort *num_sets, + ACE_CDR::UShort **char_sets) +{ + registry_entry const *element = 0; + for (size_t i = 0; element == 0 && i < num_registry_entries_; i++) + if (ACE_OS::strcmp (registry_db_[i].loc_name_, locale.c_str ()) == 0) + element = ®istry_db_[i]; + if (element == 0) + return 0; + codeset_id = element->codeset_id_; + if (num_sets != 0) + *num_sets = element->num_sets_; + if (char_sets != 0) + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (*char_sets,static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::UShort) * (element->num_sets_))),0); +#else + ACE_NEW_RETURN (*char_sets,ACE_CDR::UShort[element->num_sets_],0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + ACE_OS::memcpy (*char_sets, element->char_sets_, + element->num_sets_ * sizeof (ACE_CDR::UShort)); + } + return 1; +} + +int +ACE_Codeset_Registry::registry_to_locale_i (ACE_CDR::ULong codeset_id, + ACE_CString &locale, + ACE_CDR::UShort *num_sets, + ACE_CDR::UShort **char_sets) +{ + registry_entry const *element = 0; + for (size_t i = 0; element == 0 && i < num_registry_entries_; i++) + if (codeset_id == registry_db_[i].codeset_id_) + element = ®istry_db_[i]; + if (element == 0) + return 0; + locale.set (element->loc_name_); + if (num_sets != 0) + *num_sets = element->num_sets_; + if (char_sets != 0) + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (*char_sets,static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_CDR::UShort) * (element->num_sets_))),0); +#else + ACE_NEW_RETURN (*char_sets,ACE_CDR::UShort[element->num_sets_],0); +#endif /* ACE_HAS_ALLOC_HOOKS */ + ACE_OS::memcpy (*char_sets, element->char_sets_, + element->num_sets_ * sizeof (ACE_CDR::UShort)); + } + return 1; +} + +int +ACE_Codeset_Registry::is_compatible_i (ACE_CDR::ULong codeset_id, + ACE_CDR::ULong other) +{ + registry_entry const *lhs = 0; + registry_entry const *rhs = 0; + for (size_t i = 0; (lhs == 0 || rhs == 0) && i < num_registry_entries_; i++) + { + if (codeset_id == registry_db_[i].codeset_id_) + lhs = ®istry_db_[i]; + if (other == registry_db_[i].codeset_id_) + rhs = ®istry_db_[i]; + } + + if (lhs == 0 || rhs == 0) + return 0; + + for (ACE_CDR::UShort l = 0; l < lhs->num_sets_; l++) + for (ACE_CDR::UShort r = 0; r < rhs->num_sets_; r++) + if (rhs->char_sets_[r] == lhs->char_sets_[l]) + return 1; + return 0; +} + +ACE_CDR::Short +ACE_Codeset_Registry::get_max_bytes_i (ACE_CDR::ULong codeset_id) +{ + for (size_t i = 0; i < num_registry_entries_; i++) + if (codeset_id == registry_db_[i].codeset_id_) + return registry_db_[i].max_bytes_; + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Codeset_Registry.h b/dep/acelite/ace/Codeset_Registry.h new file mode 100644 index 000000000..86599663f --- /dev/null +++ b/dep/acelite/ace/Codeset_Registry.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//============================================================================= +/** + * @file Codeset_Registry.h + * + * ACE wrapper around access functions for the OSF's DCE codeset registry + * access functions + * + * For environments that intrinsicly support the DCE defined access functions, + * the methods in this class are simply wrappers. On other platforms, emulation + * is provided. The motivation for this class is to support interoperability + * via translators and the CDR streams, primarily in TAO, but this capability + * is not restricted to CORBA. + * + * The emulated functionality supports Open Group RFC #40, currently RFC 40.2, + * www.opengroup.org/tech/rfc/rfc40.2.html + * + * @author Phil Mesnier + */ +//============================================================================= + +#ifndef ACE_CODESET_REGISTRY_H +#define ACE_CODESET_REGISTRY_H + +#include /**/ "ace/pre.h" +#include "ace/SString.h" +#include "ace/CDR_Base.h" +#include "ace/Codeset_Symbols.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Export ACE_Codeset_Registry +{ +public: + + /// Based on a locale string, find the registry value and optional codeset + /// collection. This wraps the dce_cs_loc_to_rgy function, or emulates it. + static int locale_to_registry (const ACE_CString &locale, + ACE_CDR::ULong &codeset_id, + ACE_CDR::UShort * = 0, + ACE_CDR::UShort ** = 0); + + /// Based on a registry value, find the locale string and optional codeset + /// collection. This wraps the dce_cs_rgy_to_loc function, or emulates it. + static int registry_to_locale (ACE_CDR::ULong codeset_id, + ACE_CString &locale, + ACE_CDR::UShort * = 0, + ACE_CDR::UShort ** = 0); + + /// Tell if two codesets are compatible. This wraps the + /// rpc_cs_char_set_compat_check function. + static int is_compatible (ACE_CDR::ULong codeset_id, + ACE_CDR::ULong other); + + /// Return the max number of bytes required to represent a single character. + /// This wraps the rpc_rgy_get_max_bytes function. + static ACE_CDR::Short get_max_bytes (ACE_CDR::ULong codeset_id); + + enum {max_charsets_ = 5}; +protected: + typedef struct { + const char * desc_; + const char * loc_name_; + ACE_CDR::ULong codeset_id_; + ACE_CDR::UShort num_sets_; + ACE_CDR::UShort char_sets_[max_charsets_]; + ACE_CDR::UShort max_bytes_; + } registry_entry; + +private: + static size_t const num_registry_entries_; + static registry_entry const registry_db_[]; + + static int locale_to_registry_i (const ACE_CString &locale, + ACE_CDR::ULong &codeset_id, + ACE_CDR::UShort * = 0, + ACE_CDR::UShort ** = 0); + static int registry_to_locale_i (ACE_CDR::ULong codeset_id, + ACE_CString &locale, + ACE_CDR::UShort * = 0, + ACE_CDR::UShort ** = 0); + static int is_compatible_i (ACE_CDR::ULong codeset_id, + ACE_CDR::ULong other); + static ACE_CDR::Short get_max_bytes_i (ACE_CDR::ULong codeset_id); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Codeset_Registry.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_CODESET_REGISTRY_H */ diff --git a/dep/acelite/ace/Codeset_Registry.inl b/dep/acelite/ace/Codeset_Registry.inl new file mode 100644 index 000000000..f459d4d83 --- /dev/null +++ b/dep/acelite/ace/Codeset_Registry.inl @@ -0,0 +1,63 @@ +// -*- C++ -*- +//============================================================================= +/** + * @file Codeset_Registry.inl + * + * ACE wrapper around access functions for the OSF's DCE codeset registry + * access functions - the inline functions either call the system supplied + * DCE based codeset regsitry function, or calls the emulation + * + * @author Phil Mesnier + */ +//============================================================================= + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +int +ACE_Codeset_Registry::locale_to_registry(const ACE_CString &locale, + ACE_CDR::ULong &codeset_id, + ACE_CDR::UShort *num_sets, + ACE_CDR::UShort **char_sets) +{ + return ACE_Codeset_Registry::locale_to_registry_i (locale, + codeset_id, + num_sets, + char_sets); +} + +// based on a registry value, find the locale string and optional codeset +// collection. This wraps the dce_cs_rgy_to_loc function, or emulates it. +ACE_INLINE +int +ACE_Codeset_Registry::registry_to_locale(ACE_CDR::ULong codeset_id, + ACE_CString &locale, + ACE_CDR::UShort *num_sets, + ACE_CDR::UShort **char_sets) +{ + return ACE_Codeset_Registry::registry_to_locale_i (codeset_id, + locale, + num_sets, + char_sets); +} + +// Tell if two codesets are compatible. This wraps the +// rpc_cs_char_set_compat_check function. +ACE_INLINE +int +ACE_Codeset_Registry::is_compatible (ACE_CDR::ULong codeset_id, + ACE_CDR::ULong other) +{ + return ACE_Codeset_Registry::is_compatible_i (codeset_id,other); +} + +// Return the max number of bytes required to represent a single character. +// This wraps the rpc_rgy_get_max_bytes function. +ACE_INLINE +ACE_CDR::Short +ACE_Codeset_Registry::get_max_bytes (ACE_CDR::ULong codeset_id) +{ + return ACE_Codeset_Registry::get_max_bytes_i (codeset_id); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Codeset_Registry_db.cpp b/dep/acelite/ace/Codeset_Registry_db.cpp new file mode 100644 index 000000000..53b719d87 --- /dev/null +++ b/dep/acelite/ace/Codeset_Registry_db.cpp @@ -0,0 +1,33 @@ +/* + * Codeset registry DB, generated Fri Feb 28 21:01:30 2003 + * source: code_set_registry1.2g.txt + * + * To populate the registry_db, construct a codeset registry text file based + * on the OSF's Character and Code Set Registry. See DCE RFC 40.1 for details + * on obtaining the full text for the current registry. Once you have composed + * a text file containing all the desired codeset information, build and run + * mkcsregdb. The source is in $ACE_ROOT/apps/mkcsregdb. It will generate a new + * copy of this file, with the registry_db_ array properly initialized. + */ + +#include "ace/Codeset_Registry.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Codeset_Registry::registry_entry const +ACE_Codeset_Registry::registry_db_[] = +{ + {"ISO/IEC 10646-1:1993; UCS-2, Level 1","UCS-2",0x00010100,1,{0x1000},2}, + {"ISO 8859-1:1987; Latin Alphabet No. 1","ISO8859_1",0x00010001,1,{0x0011},1}, + {"IBM-1047 (CCSID 01047); Latin-1 Open System","EBCDIC",0x10020417,1,{0x0011},1}, + {"ISO/IEC 10646-1:1993; UCS-4, Level 1","UCS-4",0x00010104,1,{0x1000},4}, + {"ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form","UTF-16",0x00010109,1,{0x1000},2}, + {"X/Open UTF-8; UCS Transformation Format 8 (UTF-8)","UTF-8",0x05010001,1,{0x1000},6}, + {"ISO/IEC 8859-5:1988; Latin-Cyrillic Alphabet","ISO-8859-5",0x00010005,1,{0x0015},1}, + {"IBM-1251 (CCSID 01251); MS Windows Cyrillic","CP1251",0x100204e3,1,{0x0015},1}, + {"IBM-855 (CCSID 04951); Cyrillic Personal Computer","CP855",0x10021357,1,{0x0015},1} +}; + +size_t const ACE_Codeset_Registry::num_registry_entries_ = 9; + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Codeset_Symbols.h b/dep/acelite/ace/Codeset_Symbols.h new file mode 100644 index 000000000..f57935f8c --- /dev/null +++ b/dep/acelite/ace/Codeset_Symbols.h @@ -0,0 +1,218 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Codeset_Symbols.h + * + * Symbolic names for codeset ids. + * + * @author Dale Wilson (wilson_d@ociweb.com) + */ +//============================================================================= +#ifndef CODESET_SYMBOLS_H +#define CODESET_SYMBOLS_H + +// These numbers are assigned by the OpenGroup, a database is +// available at +// +// ftp://ftp.opengroup.org/pub/code_set_registry/ +// +// Alas, the database is in a semi-regular text file -- difficult to use. +// The following C/C++-friendly version of the codeset ids was captured +// from Version 1.2g of the registry. +// +#define ACE_CODESET_ID_ISO_8859_1 0x00010001U +#define ACE_CODESET_ID_ISO_8859_2 0x00010002U +#define ACE_CODESET_ID_ISO_8859_3 0x00010003U +#define ACE_CODESET_ID_ISO_8859_4 0x00010004U +#define ACE_CODESET_ID_ISO_8859_5 0x00010005U +#define ACE_CODESET_ID_ISO_8859_6 0x00010006U +#define ACE_CODESET_ID_ISO_8859_7 0x00010007U +#define ACE_CODESET_ID_ISO_8859_8 0x00010008U +#define ACE_CODESET_ID_ISO_8859_9 0x00010009U +#define ACE_CODESET_ID_ISO_8859_10 0x0001000AU +#define ACE_CODESET_ID_ISO_8859_15 0x0001000FU +#define ACE_CODESET_ID_ISO_646 0x00010020U +#define ACE_CODESET_ID_ISO_UCS_2_LEVEL_1 0x00010100U +#define ACE_CODESET_ID_ISO_UCS_2_LEVEL_2 0x00010101U +#define ACE_CODESET_ID_ISO_UCS_2_LEVEL_3 0x00010102U +#define ACE_CODESET_ID_ISO_UCS_4_LEVEL_1 0x00010104U +#define ACE_CODESET_ID_ISO_UCS_4_LEVEL_2 0x00010105U +#define ACE_CODESET_ID_ISO_UCS_4_LEVEL_3 0x00010106U +#define ACE_CODESET_ID_ISO_UTF_8 0x00010108U +#define ACE_CODESET_ID_ISO_UTF_16 0x00010109U +#define ACE_CODESET_ID_JIS_X0201 0x00030001U +#define ACE_CODESET_ID_JIS_X0208_1978 0x00030004U +#define ACE_CODESET_ID_JIS_X0208_1983 0x00030005U +#define ACE_CODESET_ID_JIS_X0208_1990 0x00030006U +#define ACE_CODESET_ID_JIS_X0212 0x0003000AU +#define ACE_CODESET_ID_JIS_EUCJP 0x00030010U +#define ACE_CODESET_ID_KS_C5601 0x00040001U +#define ACE_CODESET_ID_KS_C5657 0x00040002U +#define ACE_CODESET_ID_KS_EUCKR 0x0004000AU +#define ACE_CODESET_ID_CNS_11643_1986 0x00050001U +#define ACE_CODESET_ID_CNS_11643_1992 0x00050002U +#define ACE_CODESET_ID_CNS_EUCTW_1991 0x0005000AU +#define ACE_CODESET_ID_CNS_EUCTW_1993 0x00050010U +#define ACE_CODESET_ID_TIS_620_25290X000B0001U +#define ACE_CODESET_ID_TTB_CCDC 0x000D0001U +#define ACE_CODESET_ID_OSF_JAPANESE_UJIS 0x05000010U +#define ACE_CODESET_ID_OSF_JAPANESE_SJIS_1 0x05000011U +#define ACE_CODESET_ID_OSF_JAPANESE_SJIS_2 0x05000012U +#define ACE_CODESET_ID_XOPEN_UTF_8 0x05010001U +#define ACE_CODESET_ID_JVC_EUCJP 0x05020001U +#define ACE_CODESET_ID_JVC_SJIS 0x05020002U +#define ACE_CODESET_ID_DEC_KANJI 0x10000001U +#define ACE_CODESET_ID_SUPER_DEC_KANJI 0x10000002U +#define ACE_CODESET_ID_DEC_SHIFT_JIS 0x10000003U +#define ACE_CODESET_ID_HP_ROMAN8 0x10010001U +#define ACE_CODESET_ID_HP_KANA8 0x10010002U +#define ACE_CODESET_ID_HP_ARABIC8 0x10010003U +#define ACE_CODESET_ID_HP_GREEK8 0x10010004U +#define ACE_CODESET_ID_HP_HEBREW8 0x10010005U +#define ACE_CODESET_ID_HP_TURKISH8 0x10010006U +#define ACE_CODESET_ID_HP15CN 0x10010007U +#define ACE_CODESET_ID_HP_BIG5 0x10010008U +#define ACE_CODESET_ID_HP_JAPANESE15__SJIS_ 0x10010009U +#define ACE_CODESET_ID_HP_SJISHI 0x1001000AU +#define ACE_CODESET_ID_HP_SJISPC 0x1001000BU +#define ACE_CODESET_ID_HP_UJIS 0x1001000CU +#define ACE_CODESET_ID_IBM_037 0x10020025U +#define ACE_CODESET_ID_IBM_273 0x10020111U +#define ACE_CODESET_ID_IBM_277 0x10020115U +#define ACE_CODESET_ID_IBM_278 0x10020116U +#define ACE_CODESET_ID_IBM_280 0x10020118U +#define ACE_CODESET_ID_IBM_282 0x1002011AU +#define ACE_CODESET_ID_IBM_284 0x1002011CU +#define ACE_CODESET_ID_IBM_285 0x1002011DU +#define ACE_CODESET_ID_IBM_290 0x10020122U +#define ACE_CODESET_ID_IBM_297 0x10020129U +#define ACE_CODESET_ID_IBM_300 0x1002012CU +#define ACE_CODESET_ID_IBM_301 0x1002012DU +#define ACE_CODESET_ID_IBM_420 0x100201A4U +#define ACE_CODESET_ID_IBM_424 0x100201A8U +#define ACE_CODESET_ID_IBM_437 0x100201B5U +#define ACE_CODESET_ID_IBM_500 0x100201F4U +#define ACE_CODESET_ID_IBM_833 0x10020341U +#define ACE_CODESET_ID_IBM_834 0x10020342U +#define ACE_CODESET_ID_IBM_835 0x10020343U +#define ACE_CODESET_ID_IBM_836 0x10020344U +#define ACE_CODESET_ID_IBM_837 0x10020345U +#define ACE_CODESET_ID_IBM_838 0x10020346U +#define ACE_CODESET_ID_IBM_839 0x10020347U +#define ACE_CODESET_ID_IBM_850 0x10020352U +#define ACE_CODESET_ID_IBM_852 0x10020354U +#define ACE_CODESET_ID_IBM_855 0x10020357U +#define ACE_CODESET_ID_IBM_856 0x10020358U +#define ACE_CODESET_ID_IBM_857 0x10020359U +#define ACE_CODESET_ID_IBM_861 0x1002035DU +#define ACE_CODESET_ID_IBM_862 0x1002035EU +#define ACE_CODESET_ID_IBM_863 0x1002035FU +#define ACE_CODESET_ID_IBM_864 0x10020360U +#define ACE_CODESET_ID_IBM_866 0x10020362U +#define ACE_CODESET_ID_IBM_868 0x10020364U +#define ACE_CODESET_ID_IBM_869 0x10020365U +#define ACE_CODESET_ID_IBM_870 0x10020366U +#define ACE_CODESET_ID_IBM_871 0x10020367U +#define ACE_CODESET_ID_IBM_874 0x1002036AU +#define ACE_CODESET_ID_IBM_875 0x1002036BU +#define ACE_CODESET_ID_IBM_880 0x10020370U +#define ACE_CODESET_ID_IBM_891 0x1002037BU +#define ACE_CODESET_ID_IBM_896 0x10020380U +#define ACE_CODESET_ID_IBM_897 0x10020381U +#define ACE_CODESET_ID_IBM_903 0x10020387U +#define ACE_CODESET_ID_IBM_904 0x10020388U +#define ACE_CODESET_ID_IBM_918 0x10020396U +#define ACE_CODESET_ID_IBM_921 0x10020399U +#define ACE_CODESET_ID_IBM_922 0x1002039AU +#define ACE_CODESET_ID_IBM_926 0x1002039EU +#define ACE_CODESET_ID_IBM_927 0x1002039FU +#define ACE_CODESET_ID_IBM_928 0x100203A0U +#define ACE_CODESET_ID_IBM_929 0x100203A1U +#define ACE_CODESET_ID_IBM_930 0x100203A2U +#define ACE_CODESET_ID_IBM_932 0x100203A4U +#define ACE_CODESET_ID_IBM_933 0x100203A5U +#define ACE_CODESET_ID_IBM_934 0x100203A6U +#define ACE_CODESET_ID_IBM_935 0x100203A7U +#define ACE_CODESET_ID_IBM_936 0x100203A8U +#define ACE_CODESET_ID_IBM_937 0x100203A9U +#define ACE_CODESET_ID_IBM_938 0x100203AAU +#define ACE_CODESET_ID_IBM_939 0x100203ABU +#define ACE_CODESET_ID_IBM_941 0x100203ADU +#define ACE_CODESET_ID_IBM_942 0x100203AEU +#define ACE_CODESET_ID_IBM_943 0x100203AFU +#define ACE_CODESET_ID_IBM_946 0x100203B2U +#define ACE_CODESET_ID_IBM_947 0x100203B3U +#define ACE_CODESET_ID_IBM_948 0x100203B4U +#define ACE_CODESET_ID_IBM_949 0x100203B5U +#define ACE_CODESET_ID_IBM_950 0x100203B6U +#define ACE_CODESET_ID_IBM_951 0x100203B7U +#define ACE_CODESET_ID_IBM_955 0x100203BBU +#define ACE_CODESET_ID_IBM_964 0x100203C4U +#define ACE_CODESET_ID_IBM_970 0x100203CAU +#define ACE_CODESET_ID_IBM_1006 0x100203EEU +#define ACE_CODESET_ID_IBM_1025 0x10020401U +#define ACE_CODESET_ID_IBM_1026 0x10020402U +#define ACE_CODESET_ID_IBM_1027 0x10020403U +#define ACE_CODESET_ID_IBM_1040 0x10020410U +#define ACE_CODESET_ID_IBM_1041 0x10020411U +#define ACE_CODESET_ID_IBM_1043 0x10020413U +#define ACE_CODESET_ID_IBM_1046 0x10020416U +#define ACE_CODESET_ID_IBM_1047 0x10020417U +#define ACE_CODESET_ID_IBM_1088 0x10020440U +#define ACE_CODESET_ID_IBM_1097 0x10020449U +#define ACE_CODESET_ID_IBM_1098 0x1002044AU +#define ACE_CODESET_ID_IBM_1112 0x10020458U +#define ACE_CODESET_ID_IBM_1114 0x1002045AU +#define ACE_CODESET_ID_IBM_1115 0x1002045BU +#define ACE_CODESET_ID_IBM_1122 0x10020462U +#define ACE_CODESET_ID_IBM_1250 0x100204E2U +#define ACE_CODESET_ID_IBM_1251 0x100204E3U +#define ACE_CODESET_ID_IBM_1252 0x100204E4U +#define ACE_CODESET_ID_IBM_1253 0x100204E5U +#define ACE_CODESET_ID_IBM_1254 0x100204E6U +#define ACE_CODESET_ID_IBM_1255 0x100204E7U +#define ACE_CODESET_ID_IBM_1256 0x100204E8U +#define ACE_CODESET_ID_IBM_1257 0x100204E9U +#define ACE_CODESET_ID_IBM_1380 0x10020564U +#define ACE_CODESET_ID_IBM_1381 0x10020565U +#define ACE_CODESET_ID_IBM_1383 0x10020567U +#define ACE_CODESET_ID_IBM_4396 0x1002112CU +#define ACE_CODESET_ID_IBM_4946 0x10021352U +#define ACE_CODESET_ID_IBM_4948 0x10021354U +#define ACE_CODESET_ID_IBM_4951 0x10021357U +#define ACE_CODESET_ID_IBM_4952 0x10021358U +#define ACE_CODESET_ID_IBM_4953 0x10021359U +#define ACE_CODESET_ID_IBM_4960 0x10021360U +#define ACE_CODESET_ID_IBM_4964 0x10021364U +#define ACE_CODESET_ID_IBM_4965 0x10021365U +#define ACE_CODESET_ID_IBM_5026 0x100213A2U +#define ACE_CODESET_ID_IBM_5031 0x100213A7U +#define ACE_CODESET_ID_IBM_5035 0x100213ABU +#define ACE_CODESET_ID_IBM_5048 0x100213B8U +#define ACE_CODESET_ID_IBM_5049 0x100213B9U +#define ACE_CODESET_ID_IBM_5067 0x100213CBU +#define ACE_CODESET_ID_IBM_8612 0x100221A4U +#define ACE_CODESET_ID_IBM_9025 0x10022341U +#define ACE_CODESET_ID_IBM_9026 0x10022342U +#define ACE_CODESET_ID_IBM_9030 0x10022346U +#define ACE_CODESET_ID_IBM_9056 0x10022360U +#define ACE_CODESET_ID_IBM_9066 0x1002236AU +#define ACE_CODESET_ID_IBM_9125 0x100223A5U +#define ACE_CODESET_ID_IBM_25426 0x10026352U +#define ACE_CODESET_ID_IBM_25432 0x10026358U +#define ACE_CODESET_ID_IBM_1042 0x10026412U +#define ACE_CODESET_ID_IBM_28709 0x10027025U +#define ACE_CODESET_ID_IBM_33624 0x10028358U +#define ACE_CODESET_ID_IBM_33722 0x100283BAU +#define ACE_CODESET_ID_HTCSJIS 0x10030001U +#define ACE_CODESET_ID_HTCUJIS 0x10030002U +#define ACE_CODESET_ID_FUJITSU_U90 0x10040001U +#define ACE_CODESET_ID_FUJITSU_S90 0x10040002U +#define ACE_CODESET_ID_FUJITSU_R90 0x10040003U +#define ACE_CODESET_ID_EBCDIC_ASCII_AND_JEF 0x10040004U +#define ACE_CODESET_ID_EBCDIC_KATAKANA_AND_JEF 0x10040005U +#define ACE_CODESET_ID_EBCDIC_JAPANESE_ENGLISH_AND_JEF 0x10040006U + +#define ACE_CODESET_ID_TAO_BACKWARD_COMPATIBLE 0xf54414F0U +#endif // CODESET_SYMBOLS_H diff --git a/dep/acelite/ace/Condition_Attributes.cpp b/dep/acelite/ace/Condition_Attributes.cpp new file mode 100644 index 000000000..9257b602d --- /dev/null +++ b/dep/acelite/ace/Condition_Attributes.cpp @@ -0,0 +1,15 @@ +/* -*- C++ -*- */ +/** + * @file Condition_Attributes.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/Condition_Thread_Mutex.h" +#include "ace/Condition_Attributes.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Condition_Attributes.inl" +#endif /* __ACE_INLINE__ */ diff --git a/dep/acelite/ace/Condition_Attributes.h b/dep/acelite/ace/Condition_Attributes.h new file mode 100644 index 000000000..06b2676d8 --- /dev/null +++ b/dep/acelite/ace/Condition_Attributes.h @@ -0,0 +1,93 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Condition_Attributes.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_CONDITION_ATTRIBUTES_H +#define ACE_CONDITION_ATTRIBUTES_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_Thread.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Export ACE_Condition_Attributes +{ +public: + /// Constructor + ACE_Condition_Attributes (int type = ACE_DEFAULT_SYNCH_TYPE); + + /// Destructor + ~ACE_Condition_Attributes (void); + + /// Accessor for retrieving the current attributes + const ACE_condattr_t& attributes (void) const; + +protected: + /// The attributes + ACE_condattr_t attributes_; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Condition_Attributes &); + ACE_Condition_Attributes (const ACE_Condition_Attributes &); +}; + +template +class ACE_Condition_Attributes_T : public ACE_Condition_Attributes +{ +public: + /// Constructor + ACE_Condition_Attributes_T (int type = ACE_DEFAULT_SYNCH_TYPE) + : ACE_Condition_Attributes (type) + {} + + /// Destructor + ~ACE_Condition_Attributes_T (void) {} + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Condition_Attributes_T &); + ACE_Condition_Attributes_T (const ACE_Condition_Attributes_T &); +}; + +class ACE_Monotonic_Time_Policy; + +template <> +class ACE_Export ACE_Condition_Attributes_T + : public ACE_Condition_Attributes +{ +public: + /// Constructor + ACE_Condition_Attributes_T (int type = ACE_DEFAULT_SYNCH_TYPE); + + /// Destructor + ~ACE_Condition_Attributes_T (void); + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Condition_Attributes_T &); + ACE_Condition_Attributes_T (const ACE_Condition_Attributes_T &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Condition_Attributes.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_CONDITION_ATTRIBUTES_H */ diff --git a/dep/acelite/ace/Condition_Attributes.inl b/dep/acelite/ace/Condition_Attributes.inl new file mode 100644 index 000000000..7fecc4aaf --- /dev/null +++ b/dep/acelite/ace/Condition_Attributes.inl @@ -0,0 +1,37 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Condition_Attributes::ACE_Condition_Attributes (int type) +{ + (void) ACE_OS::condattr_init (this->attributes_, type); +} + +ACE_INLINE +ACE_Condition_Attributes::~ACE_Condition_Attributes (void) +{ + ACE_OS::condattr_destroy (this->attributes_); +} + +ACE_INLINE +const ACE_condattr_t& +ACE_Condition_Attributes::attributes (void) const +{ + return this->attributes_; +} + +ACE_INLINE +ACE_Condition_Attributes_T::ACE_Condition_Attributes_T (int type) + : ACE_Condition_Attributes (type) +{ +#if (defined (_POSIX_MONOTONIC_CLOCK) && !defined (ACE_LACKS_MONOTONIC_TIME)) || defined (ACE_HAS_CLOCK_GETTIME_MONOTONIC) + (void) ACE_OS::condattr_setclock (this->attributes_, CLOCK_MONOTONIC); +#endif +} + +ACE_INLINE +ACE_Condition_Attributes_T::~ACE_Condition_Attributes_T (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Condition_Recursive_Thread_Mutex.cpp b/dep/acelite/ace/Condition_Recursive_Thread_Mutex.cpp new file mode 100644 index 000000000..e7a23dfe7 --- /dev/null +++ b/dep/acelite/ace/Condition_Recursive_Thread_Mutex.cpp @@ -0,0 +1,131 @@ +// -*- C++ -*- + +/** + * @file Condition_Recursive_Thread_Mutex.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/Condition_Recursive_Thread_Mutex.h" + +#if defined (ACE_HAS_THREADS) + +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +int +ACE_Condition::remove (void) +{ + return ACE_OS::cond_destroy (&this->cond_); +} + +void +ACE_Condition::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Condition::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + // No dump method for ACE_cond_t even in emulated mode. + // cond_.dump (); + this->mutex_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Condition::~ACE_Condition (void) +{ + this->remove (); +} + +ACE_Condition::ACE_Condition (ACE_Recursive_Thread_Mutex &m) + : mutex_ (m) +{ + if (ACE_OS::cond_init (&this->cond_) != 0) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +ACE_Condition::ACE_Condition (ACE_Recursive_Thread_Mutex &m, + const ACE_Condition_Attributes &attributes) + : mutex_ (m) +{ + if (ACE_OS::cond_init (&this->cond_, + const_cast (attributes.attributes ())) != 0) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +int +ACE_Condition::wait (const ACE_Time_Value *abstime) +{ + return this->wait (this->mutex_, abstime); +} + +int +ACE_Condition::wait (ACE_Recursive_Thread_Mutex &mutex, + const ACE_Time_Value *abstime) +{ + ACE_recursive_mutex_state mutex_state_holder; + ACE_recursive_thread_mutex_t &recursive_mutex = mutex.lock (); + + if (ACE_OS::recursive_mutex_cond_unlock (&recursive_mutex, + mutex_state_holder) == -1) + return -1; + + // We wait on the condition, specifying the nesting mutex. For platforms + // with ACE_HAS_RECURSIVE_MUTEXES, this is the recursive mutex itself, + // and is the same as recursive_mutex, above. The caller should have been + // holding the lock on entry to this method, and it is still held. + // For other platforms, this is the nesting mutex that guards the + // ACE_recursive_mutex_t internals, and recursive_mutex_cond_unlock() + // returned with the lock held, but waiters primed and waiting to be + // released. At cond_wait below, the mutex will be released. + // On return, it will be reacquired. + int const result = abstime == 0 + ? ACE_OS::cond_wait (&this->cond_, + &mutex.get_nesting_mutex ()) + : ACE_OS::cond_timedwait (&this->cond_, + &mutex.get_nesting_mutex (), + const_cast (abstime)); + // We are holding the mutex, whether the wait succeeded or failed. + // Stash errno (in case it failed) and then we need to reset the + // recursive mutex state to what it was on entry to this method. + // Resetting it may require a wait for another thread to release + // the ACE_recursive_thread_mutex_t if this is a platform without + // ACE_HAS_RECURSIVE_MUTEXES, and recursive_mutex_cond_relock() takes + // care of that. + { + ACE_Errno_Guard error (errno); + ACE_OS::recursive_mutex_cond_relock (&recursive_mutex, + mutex_state_holder); + } + + return result; +} + +int +ACE_Condition::signal (void) +{ + return ACE_OS::cond_signal (&this->cond_); +} + +int +ACE_Condition::broadcast (void) +{ + return ACE_OS::cond_broadcast (&this->cond_); +} + +ACE_Recursive_Thread_Mutex & +ACE_Condition::mutex (void) +{ + return this->mutex_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Condition_Recursive_Thread_Mutex.h b/dep/acelite/ace/Condition_Recursive_Thread_Mutex.h new file mode 100644 index 000000000..f53ab12eb --- /dev/null +++ b/dep/acelite/ace/Condition_Recursive_Thread_Mutex.h @@ -0,0 +1,109 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Condition_Recursive_Thread_Mutex.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_CONDITION_RECURSIVE_THREAD_MUTEX_H +#define ACE_CONDITION_RECURSIVE_THREAD_MUTEX_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_HAS_THREADS) +# include "ace/Null_Condition.h" +#else /* ACE_HAS_THREADS */ +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Condition_Attributes.h" +#include "ace/Condition_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @brief ACE_Condition template specialization written using + * @a ACE_Recursive_Thread_Mutex. This allows threads to block until + * shared data changes state using recursive mutexes. + */ +template<> +class ACE_Export ACE_Condition +{ +public: + /// Initialize the condition variable with a recursive mutex. + ACE_Condition (ACE_Recursive_Thread_Mutex &m); + + /// Initialize the condition variable. + ACE_Condition (ACE_Recursive_Thread_Mutex &m, + const ACE_Condition_Attributes &attributes); + + /// Implicitly destroy the condition variable. + ~ACE_Condition (void); + + /** + * Explicitly destroy the condition variable. Note that only one + * thread should call this method since it doesn't protect against + * race conditions. + */ + int remove (void); + + /** + * Block on condition, or until absolute time-of-day has passed. If + * abstime == 0 use "blocking" semantics. Else, if @a abstime + * != 0 and the call times out before the condition is signaled + * returns -1 and sets errno to ETIME. + */ + int wait (const ACE_Time_Value *abstime = 0); + + /** + * Block on condition or until absolute time-of-day has passed. If + * abstime == 0 use "blocking" wait() semantics on the recursive @a mutex + * passed as a parameter (this is useful if you need to store the + * in shared memory). Else, if @a abstime != 0 and the + * call times out before the condition is signaled returns -1 + * and sets errno to ETIME. + */ + int wait (ACE_Recursive_Thread_Mutex &mutex, + const ACE_Time_Value *abstime = 0); + + /// Signal one waiting thread. + int signal (void); + + /// Signal *all* waiting threads. + int broadcast (void); + + /// Returns a reference to the underlying mutex; + ACE_Recursive_Thread_Mutex &mutex (void); + + /// Dump the state of an object. + void dump (void) const; + +private: + // = Prevent assignment and copying. + void operator= (const ACE_Condition &); + ACE_Condition (const ACE_Condition &); + +private: + /// A normal (i.e., non-recursive) condition variable. + ACE_cond_t cond_; + + /// Reference to the recursive mutex. + ACE_Recursive_Thread_Mutex &mutex_; +}; + +typedef ACE_Condition ACE_Condition_Recursive_Thread_Mutex; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* !ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_CONDITION_RECURSIVE_THREAD_MUTEX_H */ diff --git a/dep/acelite/ace/Condition_T.cpp b/dep/acelite/ace/Condition_T.cpp new file mode 100644 index 000000000..7f6b16737 --- /dev/null +++ b/dep/acelite/ace/Condition_T.cpp @@ -0,0 +1,146 @@ +#ifndef ACE_CONDITION_T_CPP +#define ACE_CONDITION_T_CPP + +#include "ace/Condition_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Condition_T.inl" +#include "ace/Time_Value.h" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Condition) +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Thread_Condition) + +template void +ACE_Condition::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Condition::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Thread_Condition::ACE_Thread_Condition (MUTEX &m, + const ACE_TCHAR *name, + void *arg) + : ACE_Condition (m, USYNC_THREAD, name, arg) +{ +// ACE_TRACE ("ACE_Thread_Condition::ACE_Thread_Condition"); +} + +template void +ACE_Thread_Condition::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Thread_Condition::dump"); + + ACE_Condition::dump (); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Condition::ACE_Condition (MUTEX &m, + int type, + const ACE_TCHAR *name, + void *arg) + : + mutex_ (m) +{ + // ACE_TRACE ("ACE_Condition::ACE_Condition"); + + if (ACE_OS::cond_init (&this->cond_, + (short) type, + name, + arg) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +template +ACE_Condition::ACE_Condition (MUTEX &m, + const ACE_Condition_Attributes &attributes, + const ACE_TCHAR *name, + void *arg) + : mutex_ (m) +{ +// ACE_TRACE ("ACE_Condition::ACE_Condition"); + if (ACE_OS::cond_init (&this->cond_, + const_cast (attributes.attributes ()), + name, arg) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +template +ACE_Condition::~ACE_Condition (void) +{ + // ACE_TRACE ("ACE_Condition::~ACE_Condition"); + + if (this->remove () == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::~ACE_Condition"))); +} + +template int +ACE_Condition::wait (void) +{ + // ACE_TRACE ("ACE_Condition::wait"); + return ACE_OS::cond_wait (&this->cond_, + &this->mutex_.lock ()); +} + +template int +ACE_Condition::wait (MUTEX &mutex, + const ACE_Time_Value *abstime) +{ +// ACE_TRACE ("ACE_Condition::wait"); + if (abstime == 0) + { + return ACE_OS::cond_wait (&this->cond_, + &mutex.lock ()); + } + else + { + ACE_Time_Value tv = *abstime; + return ACE_OS::cond_timedwait (&this->cond_, + &mutex.lock (), + &tv); + } +} + +// Peform an "alertable" timed wait. If the argument ABSTIME == 0 +// then we do a regular cond_wait(), else we do a timed wait for up to +// ABSTIME using the Solaris cond_timedwait() function. + +template int +ACE_Condition::wait (const ACE_Time_Value *abstime) +{ +// ACE_TRACE ("ACE_Condition::wait"); + return this->wait (this->mutex_, abstime); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ + +#endif /* ACE_CONDITION_T_CPP */ diff --git a/dep/acelite/ace/Condition_T.h b/dep/acelite/ace/Condition_T.h new file mode 100644 index 000000000..b0e4140d8 --- /dev/null +++ b/dep/acelite/ace/Condition_T.h @@ -0,0 +1,170 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Condition_T.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_CONDITION_T_H +#define ACE_CONDITION_T_H + +#include /**/ "ace/pre.h" + +#include "ace/OS_NS_Thread.h" +#include "ace/Condition_Attributes.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) /* ACE platform supports some form of threading. */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @class ACE_Condition + * + * @brief ACE_Condition variable wrapper, which allows threads to block + * until shared data changes state. + * + * A condition variable enables threads to atomically block and + * test the condition under the protection of a mutual exclusion + * lock (mutex) until the condition is satisfied. That is, + * the mutex must have been held by the thread before calling + * wait or signal on the condition. If the condition is false, + * a thread blocks on a condition variable and atomically + * releases the mutex that is waiting for the condition to + * change. If another thread changes the condition, it may wake + * up waiting threads by signaling the associated condition + * variable. The waiting threads, upon awakening, reacquire the + * mutex and re-evaluate the condition. + * Note, you can only parameterize with + * @a ACE_Thread_Mutex, @a ACE_Recursive_Thread_Mutex, or @a ACE_Null_Mutex. + */ +template +class ACE_Condition +{ +public: + /// Initialize the condition variable. + ACE_Condition (MUTEX &m, int type = USYNC_THREAD, + const ACE_TCHAR *name = 0, void *arg = 0); + + /// Initialize the condition variable. + ACE_Condition (MUTEX &m, + const ACE_Condition_Attributes &attributes, + const ACE_TCHAR *name = 0, + void *arg = 0); + + /// Implicitly destroy the condition variable. + ~ACE_Condition (void); + + // = Lock accessors. + /** + * Block on condition, or until absolute time-of-day has passed. If + * @a abstime == 0 use "blocking" semantics. Else, if @a abstime + * != 0 and the call times out before the condition is signaled + * wait() returns -1 and sets errno to ETIME. + */ + int wait (const ACE_Time_Value *abstime); + + /// Block on condition. + int wait (void); + + /** + * Block on condition or until absolute time-of-day has passed. If + * @a abstime == 0 use "blocking" wait() semantics on the @a mutex + * passed as a parameter (this is useful if you need to store the + * in shared memory). Else, if @a abstime != 0 and the + * call times out before the condition is signaled wait() returns -1 + * and sets errno to ETIME. + */ + int wait (MUTEX &mutex, const ACE_Time_Value *abstime = 0); + + /// Signal one waiting thread. + int signal (void); + + /// Signal *all* waiting threads. + int broadcast (void); + + // = Utility methods. + /// Explicitly destroy the condition variable. + int remove (void); + + /// Returns a reference to the underlying mutex_; + MUTEX &mutex (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Condition variable. + ACE_cond_t cond_; + + /// Reference to mutex lock. + MUTEX &mutex_; + +private: + // = Prevent assignment and initialization. + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Condition &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Condition (const ACE_Condition &)) +}; + +/** + * @class ACE_Thread_Condition + * + * @brief ACE_Condition variable wrapper that works within processes. + * + * A condition variable enables threads to atomically block and + * test the condition under the protection of a mutual exclu- + * sion lock (mutex) until the condition is satisfied. That is, + * the mutex must have been held by the thread before calling + * wait or signal on the condition. If the condition is false, + * a thread blocks on a condition variable and atomically + * releases the mutex that is waiting for the condition to + * change. If another thread changes the condition, it may wake + * up waiting threads by signaling the associated condition + * variable. The waiting threads, upon awakening, reacquire the + * mutex and re-evaluate the condition. + */ +template +class ACE_Thread_Condition : public ACE_Condition +{ +public: + // = Initialization method. + ACE_Thread_Condition (MUTEX &m, const ACE_TCHAR *name = 0, void *arg = 0); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Condition_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Condition_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Condition_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_CONDITION_T_H */ diff --git a/dep/acelite/ace/Condition_T.inl b/dep/acelite/ace/Condition_T.inl new file mode 100644 index 000000000..dc4266229 --- /dev/null +++ b/dep/acelite/ace/Condition_T.inl @@ -0,0 +1,48 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE int +ACE_Condition::remove (void) +{ + // ACE_TRACE ("ACE_Condition::remove"); + + // cond_destroy() is called in a loop if the condition variable is + // BUSY. This avoids a condition where a condition is signaled and + // because of some timing problem, the thread that is to be signaled + // has called the cond_wait routine after the signal call. Since + // the condition signal is not queued in any way, deadlock occurs. + + int result = 0; + + while ((result = ACE_OS::cond_destroy (&this->cond_)) == -1 + && errno == EBUSY) + { + ACE_OS::cond_broadcast (&this->cond_); + ACE_OS::thr_yield (); + } + + return result; +} + +template ACE_INLINE MUTEX & +ACE_Condition::mutex (void) +{ + // ACE_TRACE ("ACE_Condition::mutex"); + return this->mutex_; +} + +template ACE_INLINE int +ACE_Condition::signal (void) +{ +// ACE_TRACE ("ACE_Condition::signal"); + return ACE_OS::cond_signal (&this->cond_); +} + +template ACE_INLINE int +ACE_Condition::broadcast (void) +{ +// ACE_TRACE ("ACE_Condition::broadcast"); + return ACE_OS::cond_broadcast (&this->cond_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Condition_Thread_Mutex.cpp b/dep/acelite/ace/Condition_Thread_Mutex.cpp new file mode 100644 index 000000000..7e9c505d4 --- /dev/null +++ b/dep/acelite/ace/Condition_Thread_Mutex.cpp @@ -0,0 +1,122 @@ +/* -*- C++ -*- */ +/** + * @file Condition_Thread_Mutex.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/Condition_Thread_Mutex.h" + +#if defined (ACE_HAS_THREADS) + +#if !defined (__ACE_INLINE__) +#include "ace/Condition_Thread_Mutex.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Condition) + +void +ACE_Condition::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Condition::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); +#if defined (ACE_WIN32) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("waiters = %d\n"), + this->cond_.waiters ())); +#endif /* ACE_WIN32 */ + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Condition::ACE_Condition (ACE_Thread_Mutex &m, + const ACE_TCHAR *name, + void *arg) + : mutex_ (m), + removed_ (false) +{ +// ACE_TRACE ("ACE_Condition::ACE_Condition"); + if (ACE_OS::cond_init (&this->cond_, + (short) USYNC_THREAD, + name, + arg) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +ACE_Condition::ACE_Condition (ACE_Thread_Mutex &m, + const ACE_Condition_Attributes &attributes, + const ACE_TCHAR *name, + void *arg) + : mutex_ (m), + removed_ (false) +{ +// ACE_TRACE ("ACE_Condition::ACE_Condition"); + if (ACE_OS::cond_init (&this->cond_, + const_cast (attributes.attributes ()), + name, arg) != 0) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Condition::ACE_Condition"))); +} + +ACE_Condition::~ACE_Condition (void) +{ +// ACE_TRACE ("ACE_Condition::~ACE_Condition"); + this->remove (); +} + +// Peform an "alertable" timed wait. If the argument == 0 +// then we do a regular , else we do a timed wait for up to +// using the function. + +int +ACE_Condition::wait (void) +{ +// ACE_TRACE ("ACE_Condition::wait"); + return ACE_OS::cond_wait (&this->cond_, &this->mutex_.lock ()); +} + +int +ACE_Condition::wait (ACE_Thread_Mutex &mutex, + const ACE_Time_Value *abstime) +{ +// ACE_TRACE ("ACE_Condition::wait"); + return ACE_OS::cond_timedwait (&this->cond_, + &mutex.lock (), + const_cast (abstime)); +} + +int +ACE_Condition::wait (const ACE_Time_Value *abstime) +{ +// ACE_TRACE ("ACE_Condition::wait"); + return this->wait (this->mutex_, abstime); +} + +int +ACE_Condition::signal (void) +{ +// ACE_TRACE ("ACE_Condition::signal"); + return ACE_OS::cond_signal (&this->cond_); +} + +int +ACE_Condition::broadcast (void) +{ +// ACE_TRACE ("ACE_Condition::broadcast"); + return ACE_OS::cond_broadcast (&this->cond_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Condition_Thread_Mutex.h b/dep/acelite/ace/Condition_Thread_Mutex.h new file mode 100644 index 000000000..898e683fa --- /dev/null +++ b/dep/acelite/ace/Condition_Thread_Mutex.h @@ -0,0 +1,144 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Condition_Thread_Mutex.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_CONDITION_THREAD_MUTEX_H +#define ACE_CONDITION_THREAD_MUTEX_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_HAS_THREADS) +# include "ace/Null_Condition.h" +#else /* ACE_HAS_THREADS */ +// ACE platform supports some form of threading. + +#include "ace/Thread_Mutex.h" +#include "ace/Condition_Attributes.h" +#include "ace/Condition_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @brief ACE_Condition template specialization written using + * ACE_Mutexes. This allows threads to block until shared data + * changes state. + * A condition variable enables threads to atomically block and + * test the condition under the protection of a mutual exclu- + * sion lock (mutex) until the condition is satisfied. That is, + * the mutex must have been held by the thread before calling + * wait or signal on the condition. If the condition is false, + * a thread blocks on a condition variable and atomically + * releases the mutex that is waiting for the condition to + * change. If another thread changes the condition, it may wake + * up waiting threads by signaling the associated condition + * variable. The waiting threads, upon awakening, reacquire the + * mutex and re-evaluate the condition. + */ +template <> +class ACE_Export ACE_Condition +{ +public: + /// Initialize the condition variable. + ACE_Condition (ACE_Thread_Mutex &m, + const ACE_TCHAR *name = 0, + void *arg = 0); + + /// Initialize the condition variable. + ACE_Condition (ACE_Thread_Mutex &m, + const ACE_Condition_Attributes &attributes, + const ACE_TCHAR *name = 0, + void *arg = 0); + + /// Implicitly destroy the condition variable. + ~ACE_Condition (void); + + /** + * Explicitly destroy the condition variable. Note that only one + * thread should call this method since it doesn't protect against + * race conditions. + */ + int remove (void); + + /** + * Block on condition, or until absolute time-of-day has passed. If + * abstime == 0 use "blocking" wait semantics. Else, if @a abstime + * != 0 and the call times out before the condition is signaled + * wait() returns -1 and sets errno to ETIME. + */ + int wait (const ACE_Time_Value *abstime); + + /// Block on condition. + int wait (void); + + /** + * Block on condition or until absolute time-of-day has passed. If + * abstime == 0 use "blocking" wait() semantics on the @a mutex + * passed as a parameter (this is useful if you need to store the + * in shared memory). Else, if @a abstime != 0 and the + * call times out before the condition is signaled returns -1 + * and sets errno to ETIME. + */ + int wait (ACE_Thread_Mutex &mutex, const ACE_Time_Value *abstime = 0); + + /// Signal one waiting thread. + int signal (void); + + /// Signal *all* waiting threads. + int broadcast (void); + + /// Returns a reference to the underlying mutex; + ACE_Thread_Mutex &mutex (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Condition variable. + ACE_cond_t cond_; + + /// Reference to mutex lock. + ACE_Thread_Mutex &mutex_; + + /// Keeps track of whether remove() has been called yet to avoid + /// multiple remove() calls, e.g., explicitly and implicitly in the + /// destructor. This flag isn't protected by a lock, so make sure + /// that you don't have multiple threads simultaneously calling + /// remove() on the same object, which is a bad idea anyway... + bool removed_; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Condition &); + ACE_Condition (const ACE_Condition &); +}; + +typedef ACE_Condition ACE_Condition_Thread_Mutex; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Condition_Thread_Mutex.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* !ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_CONDITION_THREAD_MUTEX_H */ diff --git a/dep/acelite/ace/Condition_Thread_Mutex.inl b/dep/acelite/ace/Condition_Thread_Mutex.inl new file mode 100644 index 000000000..5db2808d1 --- /dev/null +++ b/dep/acelite/ace/Condition_Thread_Mutex.inl @@ -0,0 +1,38 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_Condition::remove (void) +{ +// ACE_TRACE ("ACE_Condition::remove"); + + // is called in a loop if the condition variable is + // BUSY. This avoids a condition where a condition is signaled and + // because of some timing problem, the thread that is to be signaled + // has called the cond_wait routine after the signal call. Since + // the condition signal is not queued in any way, deadlock occurs. + + int result = 0; + + if (!this->removed_) + { + this->removed_ = true; + + while ((result = ACE_OS::cond_destroy (&this->cond_)) == -1 + && errno == EBUSY) + { + ACE_OS::cond_broadcast (&this->cond_); + ACE_OS::thr_yield (); + } + } + return result; +} + +ACE_INLINE ACE_Thread_Mutex & +ACE_Condition::mutex (void) +{ +// ACE_TRACE ("ACE_Condition::mutex"); + return this->mutex_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Configuration.cpp b/dep/acelite/ace/Configuration.cpp new file mode 100644 index 000000000..196281078 --- /dev/null +++ b/dep/acelite/ace/Configuration.cpp @@ -0,0 +1,2150 @@ +#include "ace/Configuration.h" +#include "ace/Auto_Ptr.h" +#include "ace/SString.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_strings.h" +#include "ace/Tokenizer_T.h" + +#if !defined (ACE_LACKS_ACCESS) +# include "ace/OS_NS_unistd.h" +#endif /* ACE_LACKS_ACCESS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Configuration.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Section_Key_Internal::ACE_Section_Key_Internal (void) + : ref_count_ (0) +{ +} + +ACE_Section_Key_Internal::~ACE_Section_Key_Internal (void) +{ +} + +int +ACE_Section_Key_Internal::add_ref (void) +{ + ++ref_count_; + return 0; +} + +int +ACE_Section_Key_Internal::dec_ref (void) +{ + if (!--ref_count_) + delete this; + return 0; +} + +ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (void) + : key_ (0) +{ +} + +ACE_Configuration_Section_Key::~ACE_Configuration_Section_Key (void) +{ + if (key_) + key_->dec_ref (); +} + +ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (ACE_Section_Key_Internal* key) + : key_ (key) +{ + if (key_) + key_->add_ref (); +} + +ACE_Configuration_Section_Key::ACE_Configuration_Section_Key (const ACE_Configuration_Section_Key& rhs) + : key_ (rhs.key_) +{ + if (key_) + key_->add_ref (); +} + +ACE_Configuration_Section_Key& +ACE_Configuration_Section_Key::operator= (const ACE_Configuration_Section_Key& rhs) +{ + if (this != &rhs) + { + if (key_) + key_->dec_ref (); + + key_ = rhs.key_; + + if (key_) + key_->add_ref (); + } + return *this; +} + +////////////////////////////////////////////////////////////////////////////// + +ACE_TCHAR ACE_Configuration::NULL_String_ = '\0'; + +ACE_Configuration::ACE_Configuration (void) + : root_ () +{ +} + +ACE_Configuration::~ACE_Configuration (void) +{ +} + +ACE_Section_Key_Internal* +ACE_Configuration::get_internal_key (const ACE_Configuration_Section_Key& key) +{ + return key.key_; +} + +int +ACE_Configuration::expand_path (const ACE_Configuration_Section_Key& key, + const ACE_TString& path_in, + ACE_Configuration_Section_Key& key_out, + int create) +{ + // Make a copy of key + ACE_Configuration_Section_Key current_section = key; + ACE_Auto_Basic_Array_Ptr pData (path_in.rep ()); + ACE_Tokenizer parser (pData.get ()); + parser.delimiter_replace ('\\', '\0'); + parser.delimiter_replace ('/', '\0'); + + for (ACE_TCHAR *temp = parser.next (); + temp != 0; + temp = parser.next ()) + { + // Open the section + if (open_section (current_section, + temp, + create, + key_out)) + return -1; + + current_section = key_out; + } + + return 0; + +} + +int +ACE_Configuration::validate_name (const ACE_TCHAR* name, int allow_path) +{ + // Invalid character set + const ACE_TCHAR* reject = + allow_path ? ACE_TEXT ("][") : ACE_TEXT ("\\]["); + + // Position of the first invalid character or terminating null. + size_t const pos = ACE_OS::strcspn (name, reject); + + // Check if it is an invalid character. + if (name[pos] != ACE_TEXT ('\0')) + { + errno = EINVAL; + return -1; + } + + // The first character can never be a path separator. + if (name[0] == ACE_TEXT ('\\')) + { + errno = EINVAL; + return -1; + } + + // Validate length. + if (pos == 0 || pos > 255) + { + errno = ENAMETOOLONG; + return -1; + } + + return 0; +} + +int +ACE_Configuration::validate_value_name (const ACE_TCHAR* name) +{ + if (name == 0 || *name == this->NULL_String_) + return 0; + + return this->validate_name (name); +} + +const ACE_Configuration_Section_Key& +ACE_Configuration::root_section (void) const +{ + return root_; +} + +/** + * Determine if the contents of this object is the same as the + * contents of the object on the right hand side. + * Returns 1 (True) if they are equal and 0 (False) if they are not equal + */ +bool +ACE_Configuration::operator== (const ACE_Configuration& rhs) const +{ + bool rc = true; + int sectionIndex = 0; + ACE_TString sectionName; + ACE_Configuration *nonconst_this = const_cast (this); + ACE_Configuration &nonconst_rhs = const_cast (rhs); + + const ACE_Configuration_Section_Key& rhsRoot = rhs.root_section (); + ACE_Configuration_Section_Key rhsSection; + ACE_Configuration_Section_Key thisSection; + + // loop through each section in this object + while ((rc) && (nonconst_this->enumerate_sections (this->root_, + sectionIndex, + sectionName) == 0)) + { + // find that section in the rhs object + if (nonconst_rhs.open_section (rhsRoot, + sectionName.c_str (), + 0, + rhsSection) != 0) + { + // If the rhs object does not contain the section then we are + // not equal. + rc = false; + } + else if (nonconst_this->open_section (this->root_, + sectionName.c_str (), + 0, + thisSection) != 0) + { + // if there is some error opening the section in this object + rc = false; + } + else + { + // Well the sections match + int valueIndex = 0; + ACE_TString valueName; + VALUETYPE valueType; + VALUETYPE rhsType; + + // Enumerate each value in this section + while ((rc) && nonconst_this->enumerate_values (thisSection, + valueIndex, + valueName, + valueType) == 0) + { + // look for the same value in the rhs section + if (nonconst_rhs.find_value (rhsSection, + valueName.c_str (), + rhsType) != 0) + { + // We're not equal if the same value cannot + // be found in the rhs object. + rc = false; + } + else if (valueType != rhsType) + { + // we're not equal if the types do not match. + rc = false; + } + else + { + // finally compare values. + if (valueType == STRING) + { + ACE_TString thisString, rhsString; + if (nonconst_this->get_string_value (thisSection, + valueName.c_str (), + thisString) != 0) + { + // we're not equal if we cannot get this string + rc = false; + } + else if (nonconst_rhs.get_string_value ( + rhsSection, + valueName.c_str (), + rhsString) != 0) + { + // we're not equal if we cannot get rhs string + rc = false; + } + rc = (thisString == rhsString); + } + else if (valueType == INTEGER) + { + u_int thisInt = 0; + u_int rhsInt = 0; + if (nonconst_this->get_integer_value ( + thisSection, + valueName.c_str (), + thisInt) != 0) + { + // we're not equal if we cannot get this int + rc = false; + } + else if (nonconst_rhs.get_integer_value ( + rhsSection, + valueName.c_str (), + rhsInt) != 0) + { + // we're not equal if we cannot get rhs int + rc = false; + } + rc = (thisInt == rhsInt); + } + else if (valueType == BINARY) + { + void* thisData = 0; + void* rhsData = 0; + size_t thisLength = 0; + size_t rhsLength = 0; + if (nonconst_this->get_binary_value (thisSection, + valueName.c_str (), + thisData, + thisLength) != 0) + { + // we're not equal if we cannot get this data + rc = false; + } + else if (nonconst_rhs.get_binary_value ( + rhsSection, + valueName.c_str (), + rhsData, + rhsLength) != 0) + { + // we're not equal if we cannot get this data + rc = false; + } + + rc = (thisLength == rhsLength); + // are the length's the same? + + if (rc) + { + unsigned char* thisCharData = + (unsigned char*)thisData; + unsigned char* rhsCharData = (unsigned char*)rhsData; + // yes, then check each element + for (size_t count = 0; + (rc) && (count < thisLength); + count++) + { + rc = (* (thisCharData + count) == * (rhsCharData + count)); + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(thisCharData); + ACE_Allocator::instance()->free(rhsCharData); +#else + delete [] thisCharData; + delete [] rhsCharData; +#endif /* ACE_HAS_ALLOC_HOOKS */ + }// end if the length's match + } + // We should never have valueTypes of INVALID, therefore + // we're not comparing them. How would we since we have + // no get operation for invalid types. + // So, if we have them, we guess they are equal. + + }// end else if values match. + + ++valueIndex; + + }// end value while loop + + // look in the rhs for values not in this + valueIndex = 0; + while ((rc) && (nonconst_rhs.enumerate_values (rhsSection, + valueIndex, + valueName, + rhsType) == 0)) + { + // look for the same value in this section + if (nonconst_this->find_value (thisSection, + valueName.c_str (), + valueType) != 0) + { + // We're not equal if the same value cannot + // be found in the rhs object. + rc = false; + } + ++valueIndex; + }// end while for rhs values not in this. + + }// end else if sections match. + + ++sectionIndex; + + }// end section while loop + + // Finally, make sure that there are no sections in rhs that do not + // exist in this + sectionIndex = 0; + while ((rc) + && (nonconst_rhs.enumerate_sections (rhsRoot, + sectionIndex, + sectionName) == 0)) + { + // find the section in this + if (nonconst_this->open_section (this->root_, + sectionName.c_str (), + 0, + thisSection) != 0) + { + // if there is some error opening the section in this object + rc = false; + } + else if (nonconst_rhs.open_section (rhsRoot, + sectionName.c_str (), + 0, + rhsSection) != 0) + { + // If the rhs object does not contain the section then we + // are not equal. + rc = false; + } + ++sectionIndex; + } + return rc; +} + +bool +ACE_Configuration::operator!= (const ACE_Configuration& rhs) const +{ + return !(*this == rhs); +} + +////////////////////////////////////////////////////////////////////////////// + +#if defined (ACE_WIN32) && !defined (ACE_LACKS_WIN32_REGISTRY) + +static const int ACE_DEFAULT_BUFSIZE = 256; + +static const ACE_TCHAR *temp_name (const ACE_TCHAR *name) +{ + if (name && *name == ACE_Configuration::NULL_String_) + return 0; + return name; +} + +ACE_Section_Key_Win32::ACE_Section_Key_Win32 (HKEY hKey) + : hKey_ (hKey) +{ +} + +ACE_Section_Key_Win32::~ACE_Section_Key_Win32 (void) +{ + ::RegCloseKey (hKey_); +} + +////////////////////////////////////////////////////////////////////////////// + +bool +ACE_Configuration_Win32Registry::operator== (const ACE_Configuration_Win32Registry &rhs) const +{ + ACE_UNUSED_ARG (rhs); + return true; +} + +bool +ACE_Configuration_Win32Registry::operator!= (const ACE_Configuration_Win32Registry &rhs) const +{ + ACE_UNUSED_ARG (rhs); + return true; +} + +ACE_Configuration_Win32Registry::ACE_Configuration_Win32Registry (HKEY hKey) +{ + ACE_Section_Key_Win32 *temp = 0; + + ACE_NEW (temp, ACE_Section_Key_Win32 (hKey)); + + root_ = ACE_Configuration_Section_Key (temp); +} + + +ACE_Configuration_Win32Registry::~ACE_Configuration_Win32Registry (void) +{ +} + +int +ACE_Configuration_Win32Registry::open_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + int create, + ACE_Configuration_Section_Key& result) +{ + if (validate_name (sub_section, 1)) + return -1; + + HKEY base_key; + if (load_key (base, base_key)) + return -1; + + int errnum; + HKEY result_key; + if ((errnum = ACE_TEXT_RegOpenKeyEx (base_key, + sub_section, + 0, + KEY_ALL_ACCESS, + &result_key)) != ERROR_SUCCESS) + { + if (!create) + { + errno = errnum; + return -1; + } + + if ((errnum = ACE_TEXT_RegCreateKeyEx (base_key, + sub_section, + 0, + 0, + REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, + 0, + &result_key, + (PDWORD) 0 + )) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + } + + ACE_Section_Key_Win32 *temp; + + ACE_NEW_RETURN (temp, ACE_Section_Key_Win32 (result_key), -1); + result = ACE_Configuration_Section_Key (temp); + return 0; +} + +int +ACE_Configuration_Win32Registry::remove_section (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* sub_section, + bool recursive) +{ + if (validate_name (sub_section)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + if (recursive) + { + ACE_Configuration_Section_Key section; + if (open_section (key, sub_section, 0, section)) + return -1; + + HKEY sub_key; + if (load_key (section, sub_key)) + return -1; + + ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE]; + DWORD buffer_size = ACE_DEFAULT_BUFSIZE; + // Note we don't increment the index because the + // enumeration becomes invalid if we change the + // subkey, which we do when we delete it. By leaving + // it 0, we always delete the top entry + while (ACE_TEXT_RegEnumKeyEx (sub_key, + 0, + name_buffer, + &buffer_size, + 0, + 0, + 0, + 0) == ERROR_SUCCESS) + { + remove_section (section, name_buffer, true); + buffer_size = ACE_DEFAULT_BUFSIZE; + } + } + + int const errnum = ACE_TEXT_RegDeleteKey (base_key, sub_section); + if (errnum != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::enumerate_values (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name, + VALUETYPE& type) +{ + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE]; + DWORD buffer_size = ACE_DEFAULT_BUFSIZE; + DWORD value_type; + + int rc = ACE_TEXT_RegEnumValue (base_key, + index, + name_buffer, + &buffer_size, + 0, + &value_type, + 0, + 0); + if (rc == ERROR_NO_MORE_ITEMS) + return 1; + else if (rc != ERROR_SUCCESS) + { + errno = rc; + return -1; + } + + name = name_buffer; + + switch (value_type) + { + case REG_BINARY: + type = BINARY; + break; + case REG_SZ: + type = STRING; + break; + case REG_DWORD: + type = INTEGER; + break; + default: + type = INVALID; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::enumerate_sections (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name) +{ + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + ACE_TCHAR name_buffer[ACE_DEFAULT_BUFSIZE]; + DWORD buffer_size = ACE_DEFAULT_BUFSIZE; + int rc = ACE_TEXT_RegEnumKeyEx (base_key, + index, + name_buffer, + &buffer_size, + 0, + 0, + 0, + 0); + if (rc == ERROR_NO_MORE_ITEMS) + return 1; + else if (rc != ERROR_MORE_DATA && rc != ERROR_SUCCESS) + { + errno = rc; + return -1; + } + + name = name_buffer; + + return 0; +} + +int +ACE_Configuration_Win32Registry::set_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const ACE_TString& value) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + int errnum; + DWORD len = static_cast (value.length () + 1); + len *= sizeof (ACE_TCHAR); + if ((errnum = ACE_TEXT_RegSetValueEx (base_key, + t_name, + 0, + REG_SZ, + (BYTE *) value.fast_rep (), + len)) + != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::set_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int value) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + int errnum; + if ((errnum = ACE_TEXT_RegSetValueEx (base_key, + t_name, + 0, + REG_DWORD, + (BYTE *) &value, + sizeof (value))) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::set_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const void* data, + size_t length) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + int errnum; + if ((errnum = ACE_TEXT_RegSetValueEx (base_key, + t_name, + 0, + REG_BINARY, + (BYTE *) data, + static_cast (length))) + != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::get_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + ACE_TString& value) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + // Get the size of the binary data from windows + int errnum; + DWORD buffer_length = 0; + DWORD type; + if ((errnum = ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + (BYTE *) 0, + &buffer_length)) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + if (type != REG_SZ) + { + errno = ERROR_INVALID_DATATYPE; + return -1; + } + + ACE_TCHAR *temp = 0; + ACE_NEW_RETURN (temp, + ACE_TCHAR[buffer_length], + -1); + + ACE_Auto_Basic_Array_Ptr buffer (temp); + + if ((errnum = ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + (BYTE *) buffer.get (), + &buffer_length)) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + value = buffer.get (); + return 0; +} + +int +ACE_Configuration_Win32Registry::get_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int& value) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + int errnum; + DWORD length = sizeof (value); + DWORD type; + if ((errnum = ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + (BYTE *) &value, + &length)) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + if (type != REG_DWORD) + { + errno = ERROR_INVALID_DATATYPE; + return -1; + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::get_binary_value ( + const ACE_Configuration_Section_Key &key, + const ACE_TCHAR *name, + void *&data, + size_t &length) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + // Get the size of the binary data from windows + int errnum; + DWORD buffer_length = 0; + DWORD type; + if ((errnum = ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + (BYTE *) 0, + &buffer_length)) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + if (type != REG_BINARY) + { + errno = ERROR_INVALID_DATATYPE; + return -1; + } + + length = buffer_length; + + BYTE * the_data = 0; + ACE_NEW_RETURN (the_data, BYTE[length], -1); + ACE_Auto_Basic_Array_Ptr safe_data (the_data); + + if ((errnum = ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + the_data, + &buffer_length)) != ERROR_SUCCESS) + { + data = 0; + errno = errnum; + return -1; + } + + data = safe_data.release (); + + return 0; +} + +int +ACE_Configuration_Win32Registry::find_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type_out) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + DWORD buffer_length=0; + DWORD type; + int result=ACE_TEXT_RegQueryValueEx (base_key, + t_name, + 0, + &type, + 0, + &buffer_length); + if (result != ERROR_SUCCESS) + { + errno = result; + return -1; + } + + switch (type) + { + case REG_SZ: + type_out = STRING; + break; + case REG_DWORD: + type_out = INTEGER; + break; + case REG_BINARY: + type_out = BINARY; + break; + default: + return -1; // unknown type + } + + return 0; +} + +int +ACE_Configuration_Win32Registry::remove_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name) +{ + const ACE_TCHAR *t_name = temp_name (name); + if (validate_value_name (t_name)) + return -1; + + HKEY base_key; + if (load_key (key, base_key)) + return -1; + + int errnum; + if ((errnum = ACE_TEXT_RegDeleteValue (base_key, t_name)) != ERROR_SUCCESS) + { + errno = errnum; + return -1; + } + + return 0; +} + + +int +ACE_Configuration_Win32Registry::load_key (const ACE_Configuration_Section_Key& key, + HKEY& hKey) +{ + ACE_Section_Key_Win32* pKey = dynamic_cast (get_internal_key (key)); + if (!pKey) + return -1; + + hKey = pKey->hKey_; + return 0; +} + +HKEY +ACE_Configuration_Win32Registry::resolve_key (HKEY hKey, + const ACE_TCHAR* path, + int create) +{ + HKEY result = 0; + // Make a copy of hKey + int errnum; +#if defined (ACE_HAS_WINCE) + if ((errnum = RegOpenKeyEx (hKey, 0, 0, 0, &result)) != ERROR_SUCCESS) +#else + if ((errnum = RegOpenKey (hKey, 0, &result)) != ERROR_SUCCESS) +#endif // ACE_HAS_WINCE + { + errno = errnum; + return 0; + } + + // recurse through the path + ACE_TCHAR *temp_path = 0; + ACE_NEW_RETURN (temp_path, + ACE_TCHAR[ACE_OS::strlen (path) + 1], + 0); + ACE_Auto_Basic_Array_Ptr pData (temp_path); + ACE_OS::strcpy (pData.get (), path); + ACE_Tokenizer parser (pData.get ()); + parser.delimiter_replace ('\\', '\0'); + parser.delimiter_replace ('/', '\0'); + + for (ACE_TCHAR *temp = parser.next (); + temp != 0; + temp = parser.next ()) + { + // Open the key + HKEY subkey; + +#if defined (ACE_HAS_WINCE) + if ((errnum = ACE_TEXT_RegOpenKeyEx (result, + temp, + 0, + 0, + &subkey)) != ERROR_SUCCESS) +#else + if ((errnum = ACE_TEXT_RegOpenKey (result, + temp, + &subkey)) != ERROR_SUCCESS) +#endif // ACE_HAS_WINCE + { + // try creating it + if (!create || (errnum = ACE_TEXT_RegCreateKeyEx (result, + temp, + 0, + 0, + 0, + KEY_ALL_ACCESS, + 0, + &subkey, + (PDWORD) 0 + )) !=ERROR_SUCCESS) + { + errno = errnum; + // error + ::RegCloseKey (result); + return 0; + } + } + // release our open key handle + ::RegCloseKey (result); + result = subkey; + } + + return result; +} + +#endif /* ACE_WIN32 && !ACE_LACKS_WIN32_REGISTRY */ + +/////////////////////////////////////////////////////////////// + +ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (void) + : type_ (ACE_Configuration::INVALID), + length_ (0) +{ + this->data_.ptr_ = 0; +} + +ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (ACE_TCHAR* string) + : type_ (ACE_Configuration::STRING), + length_ (0) +{ + this->data_.ptr_ = string; +} + +ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (u_int integer) + : type_ (ACE_Configuration::INTEGER), + length_ (0) +{ + this->data_.int_ = integer; +} + +ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (void* data, size_t length) + : type_ (ACE_Configuration::BINARY), + length_ (length) +{ + this->data_.ptr_ = data; +} + +ACE_Configuration_Value_IntId::ACE_Configuration_Value_IntId (const ACE_Configuration_Value_IntId& rhs) + : type_ (rhs.type_), + data_ (rhs.data_), + length_ (rhs.length_) +{ +} + +ACE_Configuration_Value_IntId::~ACE_Configuration_Value_IntId (void) +{ +} + +ACE_Configuration_Value_IntId& ACE_Configuration_Value_IntId::operator= (const ACE_Configuration_Value_IntId& rhs) +{ + if (this != &rhs) + { + type_ = rhs.type_; + data_ = rhs.data_; + length_ = rhs.length_; + } + return *this; +} + +void +ACE_Configuration_Value_IntId::free (ACE_Allocator *alloc) +{ + if (this->type_ == ACE_Configuration::STRING + || this->type_ == ACE_Configuration::BINARY) + alloc->free (data_.ptr_); + // Do nothing in other cases... +} + +ACE_Configuration_ExtId::ACE_Configuration_ExtId (void) + : name_ (0) +{ +} + +ACE_Configuration_ExtId::ACE_Configuration_ExtId (const ACE_TCHAR* name) + : name_ (name) +{ +} + +ACE_Configuration_ExtId::ACE_Configuration_ExtId (const ACE_Configuration_ExtId& rhs) + : name_ (rhs.name_) +{ +} + +ACE_Configuration_ExtId::~ACE_Configuration_ExtId (void) +{ +} + +ACE_Configuration_ExtId& ACE_Configuration_ExtId::operator= (const ACE_Configuration_ExtId& rhs) +{ + if (this != &rhs) + name_ = rhs.name_; + + return *this; +} + +bool +ACE_Configuration_ExtId::operator== (const ACE_Configuration_ExtId& rhs) const +{ + return (ACE_OS::strcasecmp (name_, rhs.name_) == 0); +} + +bool +ACE_Configuration_ExtId::operator!= (const ACE_Configuration_ExtId& rhs) const +{ + return !this->operator== (rhs); +} + +u_long +ACE_Configuration_ExtId::hash (void) const +{ + ACE_TString temp (name_, 0, false); + return temp.hash (); +} + +void +ACE_Configuration_ExtId::free (ACE_Allocator *alloc) +{ + alloc->free ((void *) (name_)); +} + +/////////////////////////////////////////////////////////////////////// + +ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (void) + : value_hash_map_ (0), + section_hash_map_ (0) +{ +} + +ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (VALUE_MAP* value_hash_map, SUBSECTION_MAP* section_hash_map) + : value_hash_map_ (value_hash_map), + section_hash_map_ (section_hash_map) +{ +} + +ACE_Configuration_Section_IntId::ACE_Configuration_Section_IntId (const ACE_Configuration_Section_IntId& rhs) + : value_hash_map_ (rhs.value_hash_map_), + section_hash_map_ (rhs.section_hash_map_) +{ + +} + +ACE_Configuration_Section_IntId::~ACE_Configuration_Section_IntId () +{ +} + +ACE_Configuration_Section_IntId& +ACE_Configuration_Section_IntId::operator= (const ACE_Configuration_Section_IntId& rhs) +{ + if (this != &rhs) + { + value_hash_map_ = rhs.value_hash_map_; + section_hash_map_ = rhs.section_hash_map_; + } + return *this; +} + +void +ACE_Configuration_Section_IntId::free (ACE_Allocator *alloc) +{ + alloc->free ((void *) (value_hash_map_)); + alloc->free ((void *) (section_hash_map_)); +} + +ACE_Configuration_Section_Key_Heap::ACE_Configuration_Section_Key_Heap (const ACE_TCHAR* path) + : path_ (0), + value_iter_ (0), + section_iter_ (0) +{ + path_ = ACE_OS::strdup (path); +} + +ACE_Configuration_Section_Key_Heap::~ACE_Configuration_Section_Key_Heap () +{ + delete value_iter_; + delete section_iter_; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (path_); +#else + ACE_OS::free (path_); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Configuration_Section_Key_Heap) + +////////////////////////////////////////////////////////////////////////////// + +ACE_Configuration_Heap::ACE_Configuration_Heap (void) + : allocator_ (0), + index_ (0), + default_map_size_ (0) +{ + ACE_Configuration_Section_Key_Heap *temp = 0; + + ACE_NEW (temp, ACE_Configuration_Section_Key_Heap (ACE_TEXT (""))); + root_ = ACE_Configuration_Section_Key (temp); +} + +ACE_Configuration_Heap::~ACE_Configuration_Heap (void) +{ + if (allocator_) + allocator_->sync (); + + delete allocator_; +} + +int +ACE_Configuration_Heap::open (size_t default_map_size) +{ + if (this->allocator_ != 0) + { + errno = EBUSY; + return -1; + } + + default_map_size_ = default_map_size; + // Create the allocator with the appropriate options. + // The name used for the lock is the same as one used + // for the file. + ACE_NEW_RETURN (this->allocator_, + HEAP_ALLOCATOR (), + -1); + return create_index (); +} + + +int +ACE_Configuration_Heap::open (const ACE_TCHAR* file_name, + void* base_address, + size_t default_map_size) +{ + if (this->allocator_ != 0) + { + errno = EBUSY; + return -1; + } + + default_map_size_ = default_map_size; + + // Make sure that the file name is of the legal length. + if (ACE_OS::strlen (file_name) >= MAXNAMELEN + MAXPATHLEN) + { + errno = ENAMETOOLONG; + return -1; + } + + ACE_MMAP_Memory_Pool::OPTIONS options (base_address); + + // Create the allocator with the appropriate options. The name used + // for the lock is the same as one used for the file. + ACE_NEW_RETURN (this->allocator_, + PERSISTENT_ALLOCATOR (file_name, + file_name, + &options), + -1); + +#if !defined (ACE_LACKS_ACCESS) + // Now check if the backing store has been created successfully. + if (ACE_OS::access (file_name, F_OK) != 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("create_index\n")), + -1); +#endif /* ACE_LACKS_ACCESS */ + + return create_index (); +} + +int +ACE_Configuration_Heap::create_index (void) +{ + void *section_index = 0; + + // This is the easy case since if we find hash table in the + // memory-mapped file we know it's already initialized. + if (this->allocator_->find (ACE_CONFIG_SECTION_INDEX, section_index) == 0) + this->index_ = (SECTION_MAP *) section_index; + + // Create a new (because we've just created a new + // memory-mapped file). + else + { + size_t index_size = sizeof (SECTION_MAP); + section_index = this->allocator_->malloc (index_size); + + if (section_index == 0 + || create_index_helper (section_index) == -1 + || this->allocator_->bind (ACE_CONFIG_SECTION_INDEX, + section_index) == -1) + { + // Attempt to clean up. + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("create_index failed\n"))); + this->allocator_->remove (); + return -1; + } + // Add the root section + return new_section (ACE_TEXT (""), root_); + } + return 0; +} + +int +ACE_Configuration_Heap::create_index_helper (void *buffer) +{ + ACE_ASSERT (this->allocator_); + this->index_ = new (buffer) SECTION_MAP (this->allocator_); + return 0; +} + +int +ACE_Configuration_Heap::load_key (const ACE_Configuration_Section_Key& key, + ACE_TString& name) +{ + ACE_ASSERT (this->allocator_); + ACE_Configuration_Section_Key_Heap* pKey = + dynamic_cast (get_internal_key (key)); + + if (!pKey) + { + return -1; + } + + ACE_TString temp (pKey->path_, 0, false); + name.assign_nocopy (temp); + return 0; +} + + +int +ACE_Configuration_Heap::add_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + ACE_Configuration_Section_Key& result) +{ + ACE_ASSERT (this->allocator_); + ACE_TString section; + if (load_key (base, section)) + return -1; + + // Find the base section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; + + // See if this section already exists + ACE_Configuration_ExtId SubSectionExtId (sub_section); + int ignored = 0; + + if (!IntId.section_hash_map_->find (SubSectionExtId, ignored, allocator_)) + { + // already exists! + errno = EEXIST; + return -1; + } + + // Create the new section name + // only prepend a separater if were not at the root + if (section.length ()) + section += ACE_TEXT ("\\"); + + section += sub_section; + + // Add it to the base section + ACE_TCHAR* pers_name = (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (sub_section) + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_name, sub_section); + ACE_Configuration_ExtId SSExtId (pers_name); + if (IntId.section_hash_map_->bind (SSExtId, ignored, allocator_)) + { + allocator_->free (pers_name); + return -1; + } + return (new_section (section, result)); +} + +int +ACE_Configuration_Heap::new_section (const ACE_TString& section, + ACE_Configuration_Section_Key& result) +{ + ACE_ASSERT (this->allocator_); + // Create a new section and add it to the global list + + // Allocate memory for items to be stored in the table. + size_t section_len = section.length () + 1; + ACE_TCHAR *ptr = (ACE_TCHAR*) this->allocator_->malloc (section_len * sizeof (ACE_TCHAR)); + + int return_value = -1; + + if (ptr == 0) + return -1; + else + { + // Populate memory with data. + ACE_OS::strcpy (ptr, section.fast_rep ()); + + void *value_hash_map = 0; + size_t map_size = sizeof (VALUE_MAP); + value_hash_map = this->allocator_->malloc (map_size); + + // If allocation failed ... + if (value_hash_map == 0) + return -1; + + // Initialize allocated hash map through placement new. + if (value_open_helper (default_map_size_, value_hash_map ) == -1) + { + this->allocator_->free (value_hash_map ); + return -1; + } + + // create the section map + void* section_hash_map = 0; + map_size = sizeof (SUBSECTION_MAP); + section_hash_map = this->allocator_->malloc (map_size); + + // If allocation failed + if (section_hash_map == 0) + return -1; + + // initialize allocated hash map through placement new + if (section_open_helper (default_map_size_, section_hash_map) == -1) + { + this->allocator_->free (value_hash_map ); + this->allocator_->free (section_hash_map); + return -1; + } + + ACE_Configuration_ExtId name (ptr); + ACE_Configuration_Section_IntId entry ((VALUE_MAP*) value_hash_map, + (SUBSECTION_MAP*) section_hash_map); + + // Do a normal bind. This will fail if there's already an + // entry with the same name. + return_value = this->index_->bind (name, entry, this->allocator_); + + if (return_value == 1 /* Entry already existed so bind failed. */ + || return_value == -1 /* Unable to bind for other reasons. */) + { + // Free our dynamically allocated memory. + this->allocator_->free (static_cast (ptr)); + return return_value; + } + + // If bind () succeed, it will automatically sync + // up the map manager entry. However, we must sync up our + // name/value memory. + this->allocator_->sync (ptr, section_len); + } + + // set the result + ACE_Configuration_Section_Key_Heap *temp; + ACE_NEW_RETURN (temp, + ACE_Configuration_Section_Key_Heap (ptr), + -1); + result = ACE_Configuration_Section_Key (temp); + return return_value; +} + +int +ACE_Configuration_Heap::value_open_helper (size_t hash_table_size, + void *buffer) +{ + ACE_ASSERT (this->allocator_); + new (buffer) VALUE_MAP (hash_table_size, this->allocator_); + return 0; +} + +int +ACE_Configuration_Heap::section_open_helper (size_t hash_table_size, + void *buffer) +{ + ACE_ASSERT (this->allocator_); + new (buffer) SUBSECTION_MAP (hash_table_size, this->allocator_); + return 0; +} + +int +ACE_Configuration_Heap::open_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + int create, + ACE_Configuration_Section_Key& result) +{ + ACE_ASSERT (this->allocator_); + if (validate_name (sub_section, 1)) // 1 == allow_path + return -1; + + result = base; + + for (const ACE_TCHAR* separator; + (separator = ACE_OS::strchr (sub_section, ACE_TEXT ('\\'))) != 0; + ) + { + ACE_TString simple_section (sub_section, separator - sub_section); + int ret_val = + open_simple_section (result, simple_section.c_str (), create, result); + if (ret_val) + return ret_val; + sub_section = separator + 1; + } + + return open_simple_section (result, sub_section, create, result); +} + +int +ACE_Configuration_Heap::open_simple_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + int create, + ACE_Configuration_Section_Key& result) +{ + ACE_TString section (0, 0, false); + + if (load_key (base, section)) + { + return -1; + } + + // Only add the \\ if were not at the root + if (section.length ()) + { + section += ACE_TEXT ("\\"); + } + + section += sub_section; + + // resolve the section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + + if (index_->find (ExtId, IntId, allocator_)) + { + if (!create) + { + errno = ENOENT; + return -1; + } + + return add_section (base, sub_section, result); + } + + ACE_Configuration_Section_Key_Heap *temp; + ACE_NEW_RETURN (temp, + ACE_Configuration_Section_Key_Heap (section.fast_rep ()), + -1); + result = ACE_Configuration_Section_Key (temp); + return 0; +} + +int +ACE_Configuration_Heap::remove_section (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* sub_section, + bool recursive) +{ + ACE_ASSERT (this->allocator_); + if (validate_name (sub_section)) + return -1; + + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this key + ACE_Configuration_ExtId ParentExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId ParentIntId; + if (index_->find (ParentExtId, ParentIntId, allocator_)) + return -1;// no parent key + + // Find this subkey + if (section.length ()) + section += ACE_TEXT ("\\"); + + section += sub_section; + ACE_Configuration_ExtId SectionExtId (section.fast_rep ()); + SECTION_HASH::ENTRY* section_entry = 0; + SECTION_HASH* hashmap = index_; + if (hashmap->find (SectionExtId, section_entry)) + return -1; + + if (recursive) + { + ACE_Configuration_Section_Key recursive_section; + if (open_section (key, sub_section, 0, recursive_section)) + return -1; + + int index = 0; + ACE_TString name; + while (!enumerate_sections (recursive_section, index, name)) + { + if (remove_section (recursive_section, name.fast_rep (), true)) + return -1; + + ++index; + } + } + + // Now make sure we dont have any subkeys + if (section_entry->int_id_.section_hash_map_->current_size ()) + { + errno = ENOTEMPTY; + return -1; + } + + // Now remove subkey from parent key + ACE_Configuration_ExtId SubSExtId (sub_section); + SUBSECTION_HASH::ENTRY* subsection_entry = 0; + if (((SUBSECTION_HASH*)ParentIntId.section_hash_map_)-> + find (SubSExtId, subsection_entry)) + return -1; + + if (ParentIntId.section_hash_map_->unbind (SubSExtId, allocator_)) + return -1; + + subsection_entry->ext_id_.free (allocator_); + + // Remember the pointers so we can free them after we unbind + ACE_Configuration_ExtId ExtIdToFree (section_entry->ext_id_); + ACE_Configuration_Section_IntId IntIdToFree (section_entry->int_id_); + + // iterate over all values and free memory + VALUE_HASH* value_hash_map = section_entry->int_id_.value_hash_map_; + VALUE_HASH::ITERATOR value_iter = value_hash_map->begin (); + while (!value_iter.done ()) + { + VALUE_HASH::ENTRY* value_entry = 0; + if (!value_iter.next (value_entry)) + return 1; + + value_entry->ext_id_.free (allocator_); + value_entry->int_id_.free (allocator_); + + value_iter.advance (); + } + + // remove it + if (index_->unbind (SectionExtId, allocator_)) + return -1; + + value_hash_map->close (); + section_entry->int_id_.section_hash_map_->close (allocator_); + + // Free the memory + ExtIdToFree.free (allocator_); + IntIdToFree.free (allocator_); + + return 0; +} + +int +ACE_Configuration_Heap::enumerate_values (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name, + VALUETYPE& type) +{ + ACE_ASSERT (this->allocator_); + ACE_Configuration_Section_Key_Heap* pKey = + dynamic_cast (get_internal_key (key)); + if (!pKey) + return -1; + + name = pKey->path_; + + // resolve the section + ACE_Configuration_ExtId ExtId (pKey->path_); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; + + // Handle iterator resets + if (index == 0) + { + ACE_Hash_Map_Manager_Ex, + ACE_Equal_To, + ACE_Null_Mutex>* hash_map = IntId.value_hash_map_; + delete pKey->value_iter_; + + ACE_NEW_RETURN (pKey->value_iter_, + VALUE_HASH::ITERATOR (hash_map->begin ()), + -1); + } + + // Get the next entry + ACE_Hash_Map_Entry* entry = 0; + + if (!pKey->value_iter_->next (entry)) + return 1; + + // Return the value of the iterator and advance it + name = entry->ext_id_.name_; + type = entry->int_id_.type_; + pKey->value_iter_->advance (); + + return 0; +} + +int +ACE_Configuration_Heap::enumerate_sections (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name) +{ + ACE_ASSERT (this->allocator_); + // cast to a heap section key + ACE_Configuration_Section_Key_Heap* pKey = + dynamic_cast (get_internal_key (key)); + if (!pKey) + return -1; // not a heap key! + + // resolve the section + ACE_Configuration_ExtId ExtId (pKey->path_); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; // unknown section + + // Handle iterator resets + if (index == 0) + { + if (pKey->section_iter_) + delete pKey->section_iter_; + + ACE_NEW_RETURN (pKey->section_iter_, + SUBSECTION_HASH::ITERATOR (IntId.section_hash_map_->begin ()), + -1); + } + + // Get the next entry + ACE_Hash_Map_Entry* entry = 0; + if (!pKey->section_iter_->next (entry)) + return 1; + + // Return the value of the iterator and advance it + pKey->section_iter_->advance (); + name = entry->ext_id_.name_; + + return 0; +} + +int +ACE_Configuration_Heap::set_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const ACE_TString& value) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + ACE_TString section; + if (load_key (key, section)) + return -1; + + ACE_Configuration_ExtId section_ext (section.fast_rep ()); + ACE_Configuration_Section_IntId section_int; + if (index_->find (section_ext, section_int, allocator_)) + return -1; + + // Get the entry for this item (if it exists) + VALUE_HASH::ENTRY* entry = 0; + ACE_Configuration_ExtId item_name (t_name); + if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + { + // found item, replace it + // Free the old value + entry->int_id_.free (allocator_); + // Allocate the new value in this heap + ACE_TCHAR* pers_value = + (ACE_TCHAR *) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_value, value.fast_rep ()); + ACE_Configuration_Value_IntId new_value_int (pers_value); + entry->int_id_ = new_value_int; + } + else + { + // it doesn't exist, bind it + ACE_TCHAR* pers_name = + (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (t_name) + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_name, t_name); + ACE_TCHAR* pers_value = + (ACE_TCHAR *) allocator_->malloc ((value.length () + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_value, value.fast_rep ()); + ACE_Configuration_ExtId new_item_name (pers_name); + ACE_Configuration_Value_IntId item_value (pers_value); + if (section_int.value_hash_map_->bind (new_item_name, item_value, allocator_)) + { + allocator_->free (pers_value); + allocator_->free (pers_name); + return -1; + } + return 0; + } + + return 0; +} + +int +ACE_Configuration_Heap::set_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int value) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId section_ext (section.fast_rep ()); + ACE_Configuration_Section_IntId section_int; + if (index_->find (section_ext, section_int, allocator_)) + return -1; // section does not exist + + // Get the entry for this item (if it exists) + VALUE_HASH::ENTRY* entry = 0; + ACE_Configuration_ExtId item_name (t_name); + if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + { + // found item, replace it + ACE_Configuration_Value_IntId new_value_int (value); + entry->int_id_ = new_value_int; + } + else + { + // it doesn't exist, bind it + ACE_TCHAR* pers_name = + (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (t_name) + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_name, t_name); + ACE_Configuration_ExtId item_name (pers_name); + ACE_Configuration_Value_IntId item_value (value); + if (section_int.value_hash_map_->bind (item_name, item_value, allocator_)) + { + allocator_->free (pers_name); + return -1; + } + return 0; + } + + return 0; +} + +int +ACE_Configuration_Heap::set_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const void* data, + size_t length) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId section_ext (section.fast_rep ()); + ACE_Configuration_Section_IntId section_int; + if (index_->find (section_ext, section_int, allocator_)) + return -1; // section does not exist + + // Get the entry for this item (if it exists) + VALUE_HASH::ENTRY* entry = 0; + ACE_Configuration_ExtId item_name (t_name); + if (section_int.value_hash_map_->VALUE_HASH::find (item_name, entry) == 0) + { + // found item, replace it + // Free the old value + entry->int_id_.free (allocator_); + // Allocate the new value in this heap + ACE_TCHAR* pers_value = (ACE_TCHAR *) allocator_->malloc (length); + ACE_OS::memcpy (pers_value, data, length); + ACE_Configuration_Value_IntId new_value_int (pers_value, length); + entry->int_id_ = new_value_int; + } + else + { + // it doesn't exist, bind it + ACE_TCHAR* pers_name = + (ACE_TCHAR *) allocator_->malloc ((ACE_OS::strlen (t_name) + 1) * sizeof (ACE_TCHAR)); + ACE_OS::strcpy (pers_name, t_name); + ACE_TCHAR* pers_value = (ACE_TCHAR *) allocator_->malloc (length); + ACE_OS::memcpy (pers_value, data, length); + ACE_Configuration_ExtId item_name (pers_name); + ACE_Configuration_Value_IntId item_value (pers_value, length); + if (section_int.value_hash_map_->bind (item_name, item_value, allocator_)) + { + allocator_->free (pers_value); + allocator_->free (pers_name); + return -1; + } + return 0; + } + + return 0; +} + +int +ACE_Configuration_Heap::get_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + ACE_TString& value) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; // section does not exist + + // See if it exists first + ACE_Configuration_ExtId VExtId (t_name); + ACE_Configuration_Value_IntId VIntId; + if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_)) + return -1; // unknown value + + // Check type + if (VIntId.type_ != ACE_Configuration::STRING) + { + errno = ENOENT; + return -1; + } + + // everythings ok, return the data + value = static_cast (VIntId.data_.ptr_); + return 0; +} + +int +ACE_Configuration_Heap::get_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int& value) +{ + ACE_ASSERT (this->allocator_); + + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section (0, 0, false); + + if (this->load_key (key, section) != 0) + { + return -1; + } + + // Find this section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + + if (index_->find (ExtId, IntId, allocator_) != 0) + { + return -1; // section does not exist + } + + + // See if it exists first + ACE_Configuration_ExtId VExtId (t_name); + ACE_Configuration_Value_IntId VIntId; + + if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_) != 0) + { + return -1; // unknown value + } + + // Check type + if (VIntId.type_ != ACE_Configuration::INTEGER) + { + errno = ENOENT; + return -1; + } + + // Everythings ok, return the data + value = VIntId.data_.int_; + return 0; +} + +int +ACE_Configuration_Heap::get_binary_value ( + const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + void*& data, + size_t& length) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; // section does not exist + + ACE_Configuration_ExtId VExtId (t_name); + ACE_Configuration_Value_IntId VIntId; + // See if it exists first + if (IntId.value_hash_map_->find (VExtId, VIntId, allocator_)) + return -1; // unknown value + + // Check type + if (VIntId.type_ != ACE_Configuration::BINARY) + { + errno = ENOENT; + return -1; + } + + // Make a copy +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (data, static_cast (ACE_Allocator::instance()->malloc(sizeof(char) * VIntId.length_)), -1); +#else + ACE_NEW_RETURN (data, char[VIntId.length_], -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + ACE_OS::memcpy (data, VIntId.data_.ptr_, VIntId.length_); + length = VIntId.length_; + return 0; +} + +int +ACE_Configuration_Heap::find_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type_out) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; // section does not exist + + // Find it + ACE_Configuration_ExtId ValueExtId (t_name); + VALUE_HASH::ENTRY* value_entry = 0; + if (((VALUE_HASH *) IntId.value_hash_map_)->find (ValueExtId, value_entry)) + return -1; // value does not exist + + type_out = value_entry->int_id_.type_; + return 0; +} + +int +ACE_Configuration_Heap::remove_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name) +{ + ACE_ASSERT (this->allocator_); + const ACE_TCHAR *t_name = name ? name : &this->NULL_String_; + if (validate_value_name (t_name)) + return -1; + + // Get the section name from the key + ACE_TString section; + if (load_key (key, section)) + return -1; + + // Find this section + ACE_Configuration_ExtId ExtId (section.fast_rep ()); + ACE_Configuration_Section_IntId IntId; + if (index_->find (ExtId, IntId, allocator_)) + return -1; // section does not exist + + // Find it + ACE_Configuration_ExtId ValueExtId (t_name); + VALUE_HASH::ENTRY* value_entry = 0; + if (((VALUE_HASH *) IntId.value_hash_map_)->find (ValueExtId, value_entry)) + return -1; + + // free it + value_entry->ext_id_.free (allocator_); + value_entry->int_id_.free (allocator_); + + // Unbind it + if (IntId.value_hash_map_->unbind (ValueExtId, allocator_)) + return -1; + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Configuration.h b/dep/acelite/ace/Configuration.h new file mode 100644 index 000000000..aa69ea49e --- /dev/null +++ b/dep/acelite/ace/Configuration.h @@ -0,0 +1,901 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Configuration.h + * + * @author Chris Hafey + * + * The ACE configuration API provides a portable abstraction for + * program configuration similar to the Microsoft Windows registry. + * The API supports a tree based hierarchy of configuration sections. Each + * section contains other sections or values. Values may contain string, + * unsigned integer and binary data. + * + * @note These classes are not thread safe, if multiple threads use these + * classes, you are responsible for serializing access. + * + * For examples of using this class, see: + * -# The test code in ACE_wrappers/test + * -# wxConfigViewer, a Windows like Registry Editor for ACE_Configuration + * -# TAO's IFR, it makes extensive use of ACE_Configuration + * + * @todo Templatize this class with an ACE_LOCK to provide thread safety + */ +//============================================================================= + +#ifndef ACE_CONFIGURATION_H +#define ACE_CONFIGURATION_H +#include /**/ "ace/pre.h" + +#include "ace/SStringfwd.h" +#include "ace/Hash_Map_With_Allocator_T.h" +#include "ace/Malloc_T.h" +#include "ace/MMAP_Memory_Pool.h" +#include "ace/Local_Memory_Pool.h" +#include "ace/Synch_Traits.h" + + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// configurable parameters + +#if !defined (ACE_CONFIG_SECTION_INDEX) +# define ACE_CONFIG_SECTION_INDEX "Config_Section_Index" +#endif /* ! ACE_CONFIG_SECTION_INDEX */ + +#if !defined (ACE_DEFAULT_CONFIG_SECTION_SIZE) +#define ACE_DEFAULT_CONFIG_SECTION_SIZE 16 +#endif /* ACE_DEFAULT_CONFIG_SECTION_SIZE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Section_Key_Internal + * + * @internal + * + * @brief A base class for internal handles to section keys for + * configuration implementations + * + * Implementations subclass this base class to represent a + * section key. + */ +class ACE_Export ACE_Section_Key_Internal +{ +public: + /// Virtual destructor, make sure descendants are virtual! + virtual ~ACE_Section_Key_Internal (void); + + /// Increment reference count + virtual int add_ref (void); + + /// Decrement reference count. Will delete this if count gets to 0 + virtual int dec_ref (void); +protected: + ACE_Section_Key_Internal (void); + ACE_Section_Key_Internal (const ACE_Section_Key_Internal& rhs); + ACE_Section_Key_Internal& operator= (ACE_Section_Key_Internal& rhs); + + u_int ref_count_; +}; + +/** + * @class ACE_Configuration_Section_Key + * + * @brief Reference counted wrapper for ACE_Section_Key_Internal. + * + * Reference counted wrapper class for the abstract internal + * section key. A user gets one of these to represent a section + * in the configuration database. + */ +class ACE_Export ACE_Configuration_Section_Key +{ + friend class ACE_Configuration; +public: + /// Default constructor. + ACE_Configuration_Section_Key (void); + + /// Constructor that initializes to a pointer to a concrete internal key. + /** + * @param key The section key to reference. Calls add_ref() with @a key. + */ + explicit ACE_Configuration_Section_Key (ACE_Section_Key_Internal *key); + + /// Copy constructor, increments the reference count on the key. + ACE_Configuration_Section_Key (const ACE_Configuration_Section_Key &rhs); + + /// Destructor, decrements reference count on the referenced key. + ~ACE_Configuration_Section_Key (void); + + /// Assignment operator, increments reference count for this object + /// and decrements it on @a rhs. + ACE_Configuration_Section_Key & + operator= (const ACE_Configuration_Section_Key &rhs); +private: + ACE_Section_Key_Internal *key_; +}; + +/** + * @class ACE_Configuration + * + * @internal + * + * @brief Base class for configuration databases + * + * This class provides an interface for configuration databases. A concrete + * class is required that implements the interface. + * + * @sa ACE_Configuration_Heap + * @sa ACE_Configuration_Win32Registry + */ +class ACE_Export ACE_Configuration +{ +public: + /// Enumeration for the various types of values we can store. + enum VALUETYPE + { + STRING, + INTEGER, + BINARY, + INVALID + }; + + /// Destructor + virtual ~ACE_Configuration (void); + + /// Obtain a reference to the root section of this configuration. + /* + * @return Reference to the configuration's root section. Note that + * it is a const reference. + */ + virtual const ACE_Configuration_Section_Key& root_section (void) const; + + /** + * Opens a named section in an existing section. + * + * @param base Existing section in which to open the named section. + * @param sub_section Name of the section to open. + * @param create If zero, the named section must exist. If non-zero, + * the named section will be created if it does not exist. + * @param result Reference; receives the section key for the new + * section. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int open_section (const ACE_Configuration_Section_Key &base, + const ACE_TCHAR *sub_section, + int create, + ACE_Configuration_Section_Key& result) = 0; + + /// Removes a named section. + /** + * @param key Section key to remove the named section from. + * @param sub_section Name of the section to remove. + * @param recursive If true, any subkeys below @a sub_section are + * removed as well. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int remove_section (const ACE_Configuration_Section_Key &key, + const ACE_TCHAR *sub_section, + bool recursive) = 0; + + /** + * Enumerates through the values in a section. + * + * @param key Section key to iterate through. + * @param index Iteration position. Must be zero on the first call to + * iterate through @a key. Increment @a index by one on each + * successive call to this method. + * @param name Receives the value's name. + * @param type Receives the value's data type. + * + * @note You may not delete or add values while enumerating. If the + * section is modified during enumeration, results are undefined; + * you must restart the enumeration from index 0. + * + * @retval 0 for success, @a name and @a type are valid. + * @retval 1 there are no more values in the section. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int enumerate_values (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name, + VALUETYPE& type) = 0; + + /** + * Enumerates through the subsections in a section. + * + * @param key Section key to iterate through. + * @param index Iteration position. Must be zero on the first call to + * iterate through @a key. Increment @a index by one on each + * successive call to this method. + * @param name Receives the subsection's name. + * + * @note You may not modify the @a key section while enumerating. If the + * section is modified during enumeration, results are undefined; + * you must restart the enumeration from index 0. + * + * @retval 0 for success, @a name has a valid name. + * @retval 1 there are no more subsections in the section. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int enumerate_sections (const ACE_Configuration_Section_Key& key, + int index, ACE_TString& name) = 0; + + /// Sets a string-typed value. + /** + * @param key Configuration section to set the value in. + * @param name Name of the configuration value to set. If a value with + * the specified name exists, it is replaced. + * @param value The string to set the configuration value to. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int set_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const ACE_TString& value) = 0; + + /// Sets a integer-typed value. + /** + * @param key Configuration section to set the value in. + * @param name Name of the configuration value to set. If a value with + * the specified name exists, it is replaced. + * @param value The integer to set the configuration value to. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int set_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int value) = 0; + + /// Sets a binary-typed value. + /** + * @param key Configuration section to set the value in. + * @param name Name of the configuration value to set. If a value with + * the specified name exists, it is replaced. + * @param data Pointer to the binary data for the value. + * @param length Number of bytes for the new value. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int set_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const void* data, + size_t length) = 0; + + /// Gets a string-typed value. + /** + * @param key Configuration section to get the value from. + * @param name Name of the configuration value to get. + * @param value Receives the configuration value if it exists and + * has type STRING. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int get_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + ACE_TString& value) = 0; + + /// Gets an integer-typed value. + /** + * @param key Configuration section to get the value from. + * @param name Name of the configuration value to get. + * @param value Receives the configuration value if it exists and + * has type INTEGER. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int get_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int& value) = 0; + + /// Gets a binary-typed value. + /** + * @param key Configuration section to get the value from. + * @param name Name of the configuration value to get. + * @param data Receives a pointer to memory holding the binary data + * for the value. This method allocates the memory pointed + * to using operator new[]. The caller is responsible for + * freeing the memory using operator delete[]. + * @param length Receives the number of bytes in the value. + * + * @retval 0 for success; caller is responsible for freeing the + * returned memory. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int get_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + void*& data, + size_t& length) = 0; + + /** + * Retrieves the type of a named configuration value. + * + * @param key Configuration section to look up the name in. + * @param name Name of the configuration value to get the type of. + * @param type Receives the data type of the named value, if it exists. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int find_value(const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type) = 0; + + /// Removes a named value. + /** + * @param key Configuration section to remove the named value from. + * @param name Name of the configuration value to remove. + * + * @retval 0 for success. + * @retval -1 for error; ACE_OS::last_error() retrieves error code. + */ + virtual int remove_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name) = 0; + + /** + * Expands @a path_in to @a key_out from @a key. If create is true, + * the subsections are created. Returns 0 on success, non zero on + * error The path consists of sections separated by the backslash + * '\' or forward slash '/'. + * Returns 0 on success, -1 if + virtual ~ACE_Section_Key_Win32 (void); + + // Not used + ACE_Section_Key_Win32 (const ACE_Section_Key_Win32& rhs); + ACE_Section_Key_Win32& operator= (const ACE_Section_Key_Win32& rhs); +}; + +/** + * @class ACE_Configuration_Win32Registry + * + * @brief The win32 registry implementation of a configuration database + * + * The win32 implementation basically makes calls through to the + * registry functions. The API is very similar so very little + * work must be done + */ +class ACE_Export ACE_Configuration_Win32Registry : public ACE_Configuration +{ +public: + + /** + * Constructor for registry configuration database. hKey is the + * base registry key to attach to. This class takes ownership of + * hKey, it will invoke on it upon destruction. + */ + explicit ACE_Configuration_Win32Registry (HKEY hKey); + + /// Destructor + virtual ~ACE_Configuration_Win32Registry (void); + + virtual int open_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + int create, + ACE_Configuration_Section_Key& result); + + virtual int remove_section (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* sub_section, + bool recursive); + + virtual int enumerate_values (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name, + VALUETYPE& type); + + virtual int enumerate_sections (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name); + + virtual int set_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const ACE_TString& value); + + virtual int set_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int value); + + virtual int set_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const void* data, + size_t length); + + virtual int get_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + ACE_TString& value); + + virtual int get_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int& value); + + virtual int get_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + void*& data, + size_t& length); + + virtual int find_value(const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type); + + /// Removes the the value @a name from @a key. returns non zero on error + virtual int remove_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name); + + /** + * This method traverses through . It is useful when + * you want the HKEY for a specific registry key, especially when + * initializing this implementation. Caller is responsible for + * closeing this key when it is no longer used. If create is 1 + * (default) the keys are create if they don't already exist. + * Returns 0 on error + */ + static HKEY resolve_key (HKEY hKey, + const ACE_TCHAR* path, + int create = 1); + virtual bool operator== (const ACE_Configuration_Win32Registry &rhs) const; + virtual bool operator!= (const ACE_Configuration_Win32Registry &rhs) const; + +protected: + + /// Gets the HKEY for a configuration section + int load_key (const ACE_Configuration_Section_Key& key, HKEY& hKey); + + // Not used + ACE_Configuration_Win32Registry (void); + ACE_Configuration_Win32Registry (const ACE_Configuration_Win32Registry& rhs); + ACE_Configuration_Win32Registry& operator= (const ACE_Configuration_Win32Registry& rhs); +}; +#endif /* ACE_WIN32 && !ACE_LACKS_WIN32_REGISTRY */ + +// ACE_Allocator version + +typedef ACE_Allocator_Adapter > + PERSISTENT_ALLOCATOR; +typedef ACE_Allocator_Adapter > + HEAP_ALLOCATOR; + +/** + * @class ACE_Configuration_ExtId + * + * @brief External ID for the section and value hash + * + * Contains a pointer to the section or value name. + */ +class ACE_Export ACE_Configuration_ExtId +{ +public: + /// Defeault ctor + ACE_Configuration_ExtId (void); + + /// Named constructor + explicit ACE_Configuration_ExtId (const ACE_TCHAR* name); + + /// Copy ctor + ACE_Configuration_ExtId (const ACE_Configuration_ExtId& rhs); + + /// destructor + ~ACE_Configuration_ExtId (void); + + /// Assignment operator + ACE_Configuration_ExtId& operator= (const ACE_Configuration_ExtId& rhs); + + /// Equality comparison operator (must match name_). + bool operator== (const ACE_Configuration_ExtId &rhs) const; + + /// Inequality comparison operator. + bool operator!= (const ACE_Configuration_ExtId &rhs) const; + + /// Frees the name of the value. needed since we don't know the + /// allocator name_ was created in + void free (ACE_Allocator *alloc); + + /// hash function is required in order for this class to be usable by + /// ACE_Hash_Map_Manager. + u_long hash (void) const; + + // = Data members. + + const ACE_TCHAR * name_; + + // Accessors + const ACE_TCHAR *name (void); +}; + +typedef ACE_Hash_Map_With_Allocator + SUBSECTION_MAP; +typedef ACE_Hash_Map_Manager_Ex, + ACE_Equal_To, + ACE_Null_Mutex> + SUBSECTION_HASH; + +/** + * @class ACE_Configuration_Value_IntId + * + * @brief The section hash table internal value class + * + * This class is present as the internal portion of a section's + * value hash table It may store string, integer or binary data. + */ +class ACE_Export ACE_Configuration_Value_IntId +{ +public: + /// Default constructor + ACE_Configuration_Value_IntId (void); + + /// String constructor, takes ownership of string + explicit ACE_Configuration_Value_IntId (ACE_TCHAR* string); + + /// Integer constructor + explicit ACE_Configuration_Value_IntId (u_int integer); + + /// Binary constructor, takes ownership of data + ACE_Configuration_Value_IntId (void* data, size_t length); + + /// Copy ctor + ACE_Configuration_Value_IntId (const ACE_Configuration_Value_IntId& rhs); + + /// Destructor + ~ACE_Configuration_Value_IntId (void); + + /// Assignment operator + ACE_Configuration_Value_IntId& operator= ( + const ACE_Configuration_Value_IntId& rhs); + + void free (ACE_Allocator *alloc); + + // = Data members. + + /** + * Points to the string value or binary data or IS the integer + * Length is only used when type_ == BINARY + */ + ACE_Configuration::VALUETYPE type_; + union { + void * ptr_; + u_int int_; + } data_; + size_t length_; +}; + +typedef ACE_Hash_Map_With_Allocator + VALUE_MAP; +typedef ACE_Hash_Map_Manager_Ex, + ACE_Equal_To, + ACE_Null_Mutex> + VALUE_HASH; + +// Deprecated typedef. Use the VALUE_HASH::ENTRY trait instead. +typedef VALUE_HASH::ENTRY VALUE_ENTRY; + +/** + * @class ACE_Configuration_Section_IntId + * + * @brief The internal ID for a section hash table + * + * Contains a hash table containing value name/values + */ +class ACE_Export ACE_Configuration_Section_IntId +{ +public: + /// Default ctor + ACE_Configuration_Section_IntId (void); + + /// Named ctor + ACE_Configuration_Section_IntId (VALUE_MAP* value_hash_map, + SUBSECTION_MAP* section_hash_map); + + /// Copy ctor + ACE_Configuration_Section_IntId (const ACE_Configuration_Section_IntId& rhs); + + /// Destructor + ~ACE_Configuration_Section_IntId (void); + + /// Assignment operator + ACE_Configuration_Section_IntId& operator= ( + const ACE_Configuration_Section_IntId& rhs); + + /// Frees the hash table and all its values + void free (ACE_Allocator *alloc); + + // = Data Members. + VALUE_MAP* value_hash_map_; + + SUBSECTION_MAP* section_hash_map_; +}; + +typedef ACE_Hash_Map_With_Allocator + SECTION_MAP; +typedef ACE_Hash_Map_Manager_Ex, + ACE_Equal_To, + ACE_Null_Mutex> + SECTION_HASH; + +// Deprecated typedef. Use the SECTION_HASH::ENTRY trait instead. +typedef SECTION_HASH::ENTRY SECTION_ENTRY; + +/** + * @class ACE_Configuration_Section_Key_Heap + * + * @brief Internal section key class for heap based configuration + * database. + * + * Contains a value iterator and full path name of section. + */ +class ACE_Export ACE_Configuration_Section_Key_Heap + : public ACE_Section_Key_Internal +{ +public: + /// Constructor based on the full path of the section + ACE_Configuration_Section_Key_Heap (const ACE_TCHAR* path); + + /// The path itself + ACE_TCHAR* path_; + + /// The value iterator + VALUE_HASH::ITERATOR* value_iter_; + + /// The sub section iterator + SUBSECTION_HASH::ITERATOR* section_iter_; + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Destructor - will delete the iterators + virtual ~ACE_Configuration_Section_Key_Heap (void); + + // Not used + ACE_Configuration_Section_Key_Heap (const ACE_Configuration_Section_Key_Heap& rhs); + ACE_Configuration_Section_Key_Heap& operator= (const ACE_Configuration_Section_Key_Heap& rhs); +}; + +/** + * @class ACE_Configuration_Heap + * + * @brief The concrete implementation of a allocator based + * configuration database + * + * This class uses ACE's Allocators to manage a memory + * representation of a configuration database. A persistent heap + * may be used to store configurations persistently + * + * @note Before using this class you must call one of the open methods. + * + * @todo + * - Need to investigate what happens if memory mapped file gets mapped to + * a location different than it was created with. + */ +class ACE_Export ACE_Configuration_Heap : public ACE_Configuration +{ +public: + + /// Default ctor + ACE_Configuration_Heap (void); + + /// Destructor + virtual ~ACE_Configuration_Heap (void); + + /** + * Opens a configuration that allocates its memory from a memory-mapped file. + * This makes it possible to persist a configuration to permanent storage. + * This is not the same as exporting the configuration to a file; the + * memory-mapped file is not likely to be very readable by humans. + * + * @param file_name Name of the file to map into memory. + * + * @param base_address Address to map the base of @a file_name to. + * + * @param default_map_size Starting size for the internal hash tables that + * contain configuration information. + * + * @retval 0 for success. + * @retval -1 for error, with errno set to indicate the cause. If open() + * is called multiple times, errno will be @c EBUSY. + */ + int open (const ACE_TCHAR* file_name, + void* base_address = ACE_DEFAULT_BASE_ADDR, + size_t default_map_size = ACE_DEFAULT_CONFIG_SECTION_SIZE); + + /** + * Opens a configuration that allocates memory from the heap. + * + * @param default_map_size Starting size for the internal hash tables that + * contain configuration information. + * + * @retval 0 for success. + * @retval -1 for error, with errno set to indicate the cause. If open() + * is called multiple times, errno will be @c EBUSY. + */ + int open (size_t default_map_size = ACE_DEFAULT_CONFIG_SECTION_SIZE); + + virtual int open_section (const ACE_Configuration_Section_Key& base, + const ACE_TCHAR* sub_section, + int create, ACE_Configuration_Section_Key& result); + + virtual int remove_section (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* sub_section, + bool recursive); + + virtual int enumerate_values (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name, + VALUETYPE& type); + + virtual int enumerate_sections (const ACE_Configuration_Section_Key& key, + int index, + ACE_TString& name); + + virtual int set_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const ACE_TString& value); + + virtual int set_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int value); + + virtual int set_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + const void* data, + size_t length); + + virtual int get_string_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + ACE_TString& value); + + virtual int get_integer_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + u_int& value); + + virtual int get_binary_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + void* &data, + size_t &length); + + virtual int find_value(const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name, + VALUETYPE& type); + + /// Removes the the value @a name from @a key. returns non zero on error + virtual int remove_value (const ACE_Configuration_Section_Key& key, + const ACE_TCHAR* name); + +private: + /// @a sub_section may not contain path separators + int open_simple_section (const ACE_Configuration_Section_Key &base, + const ACE_TCHAR *sub_section, + int create, ACE_Configuration_Section_Key &result); + /// Adds a new section + int add_section (const ACE_Configuration_Section_Key &base, + const ACE_TCHAR *sub_section, + ACE_Configuration_Section_Key &result); + + /// Helper for the method. + int create_index (void); + + /// Helper for create_index() method: places hash table into an + /// allocated space. + int create_index_helper (void *buffer); + + int value_open_helper (size_t hash_table_size, void *buffer); + + int section_open_helper (size_t hash_table_size, void *buffer); + + int load_key (const ACE_Configuration_Section_Key& key, ACE_TString& name); + + int new_section (const ACE_TString& section, + ACE_Configuration_Section_Key& result); + + ACE_Configuration_Heap (const ACE_Configuration_Heap& rhs); + ACE_Configuration_Heap& operator= (const ACE_Configuration_Heap& rhs); + + ACE_Allocator *allocator_; + SECTION_MAP *index_; + size_t default_map_size_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Configuration.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_CONFIGURATION_H */ diff --git a/dep/acelite/ace/Configuration.inl b/dep/acelite/ace/Configuration.inl new file mode 100644 index 000000000..ebd6d6f9e --- /dev/null +++ b/dep/acelite/ace/Configuration.inl @@ -0,0 +1,10 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE const ACE_TCHAR* +ACE_Configuration_ExtId::name (void) +{ + return name_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Configuration_Import_Export.cpp b/dep/acelite/ace/Configuration_Import_Export.cpp new file mode 100644 index 000000000..c9da29bfb --- /dev/null +++ b/dep/acelite/ace/Configuration_Import_Export.cpp @@ -0,0 +1,749 @@ +#include "ace/Configuration_Import_Export.h" +#include "ace/OS_Errno.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Config_ImpExp_Base::ACE_Config_ImpExp_Base (ACE_Configuration& config) + : config_ (config) +{ +} + +ACE_Config_ImpExp_Base::~ACE_Config_ImpExp_Base (void) +{ +} + +ACE_Registry_ImpExp::ACE_Registry_ImpExp (ACE_Configuration& config) + : ACE_Config_ImpExp_Base (config) +{ +} + +ACE_Registry_ImpExp::~ACE_Registry_ImpExp (void) +{ +} + +// Imports the configuration database from filename. +// No existing data is removed. +int +ACE_Registry_ImpExp::import_config (const ACE_TCHAR* filename) +{ + if (0 == filename) + { + errno = EINVAL; + return -1; + } + FILE* in = ACE_OS::fopen (filename, ACE_TEXT ("r")); + if (!in) + return -1; + + u_int buffer_size = 4096; + u_int read_pos = 0; + ACE_TCHAR *buffer = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_NORETURN (buffer, static_cast (ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR) * buffer_size))); +#else + ACE_NEW_NORETURN (buffer, ACE_TCHAR[buffer_size]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + if (!buffer) + { + ACE_Errno_Guard guard (errno); + (void) ACE_OS::fclose (in); + return -1; + } + ACE_Configuration_Section_Key section; + ACE_TCHAR *end = 0; + + while (ACE_OS::fgets (buffer+read_pos, buffer_size - read_pos, in)) + { + // Check if we got all the line. + end = ACE_OS::strrchr (buffer + read_pos, + ACE_TEXT ('\n')); // look for end of line + if (!end) // we havn't reach the end of the line yet + { + // allocate a new buffer - double size the previous one + ACE_TCHAR *temp_buffer; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_NORETURN (temp_buffer, static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_TCHAR) * buffer_size * 2))); +#else + ACE_NEW_NORETURN (temp_buffer, ACE_TCHAR[buffer_size * 2]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + if (!temp_buffer) + { + ACE_Errno_Guard guard (errno); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + (void) ACE_OS::fclose (in); + return -1; + } + + // copy the beginnning of the line + ACE_OS::memcpy (temp_buffer, buffer, buffer_size); + read_pos = buffer_size - 1; + buffer_size *= 2; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + buffer = temp_buffer; + continue; + } + read_pos = 0; + + // Check for a comment + if (buffer[0] == ACE_TEXT (';') || buffer[0] == ACE_TEXT ('#')) + continue; + + if (buffer[0] == ACE_TEXT ('[')) + { + // We have a new section here, strip out the section name + end = ACE_OS::strrchr (buffer, ACE_TEXT (']')); + if (!end) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -3; + } + *end = 0; + + if (config_.expand_path (config_.root_section (), buffer + 1, section, 1)) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -3; + } + continue; + } // end if firs char is a [ + + if (buffer[0] == ACE_TEXT ('"')) + { + // we have a value + end = ACE_OS::strchr (buffer+1, '"'); + if (!end) // no closing quote, not a value so just skip it + continue; + + // null terminate the name + *end = 0; + ACE_TCHAR* name = buffer + 1; + end+=2; + // determine the type + if (*end == '\"') + { + // string type + // truncate trailing " + ++end; + ACE_TCHAR* trailing = ACE_OS::strrchr (end, '"'); + if (trailing) + *trailing = 0; + if (config_.set_string_value (section, name, end)) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -4; + } + } + else if (ACE_OS::strncmp (end, ACE_TEXT ("dword:"), 6) == 0) + { + // number type + ACE_TCHAR* endptr = 0; + unsigned long value = ACE_OS::strtoul (end + 6, &endptr, 16); + if (config_.set_integer_value (section, name, + static_cast (value))) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -4; + } + } + else if (ACE_OS::strncmp (end, ACE_TEXT ("hex:"), 4) == 0) + { + // binary type + size_t string_length = ACE_OS::strlen (end + 4); + // divide by 3 to get the actual buffer length + size_t length = string_length / 3; + size_t remaining = length; + u_char* data = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (data, + static_cast (ACE_Allocator::instance()->malloc(sizeof(u_char) * length)), + -1); +#else + ACE_NEW_RETURN (data, + u_char[length], + -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + u_char* out = data; + ACE_TCHAR* inb = end + 4; + ACE_TCHAR* endptr = 0; + while (remaining) + { + u_char charin = (u_char) ACE_OS::strtoul (inb, &endptr, 16); + *out = charin; + ++out; + --remaining; + inb += 3; + } + if (config_.set_binary_value (section, name, data, length)) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(data); + ACE_Allocator::instance()->free(buffer); +#else + delete [] data; + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -4; + } + else +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(data); +#else + delete [] data; +#endif /* ACE_HAS_ALLOC_HOOKS */ + } + else + { + // invalid type, ignore + continue; + } + }// end if first char is a " + else + { + // if the first character is not a ", [, ;, or # we may be + // processing a file in the old format. + // Try and process the line as such and if it fails, + // return an error + int rc = process_previous_line_format (buffer, section); + if (rc != 0) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return rc; + } + } // end if maybe old format + } // end while fgets + + if (ferror (in)) + { + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return -1; + } + + ACE_OS::fclose (in); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(buffer); +#else + delete [] buffer; +#endif /* ACE_HAS_ALLOC_HOOKS */ + return 0; +} + +// This method exports the entire configuration database to . +// Once the file is opened this method calls 'export_section' passing +// the root section. +int +ACE_Registry_ImpExp::export_config (const ACE_TCHAR* filename) +{ + if (0 == filename) + { + errno = EINVAL; + return -1; + } + int result = -1; + + FILE* out = ACE_OS::fopen (filename, ACE_TEXT ("w")); + if (out) + { + result = this->export_section (config_.root_section (), + ACE_TEXT (""), + out); + // The data may have been buffered and will be flush on close, + // so we need to check that the close succeeds. + if (ACE_OS::fclose (out) < 0) + result = -7; + } + return result; +} + + +#if !defined ACE_USES_WCHAR && defined ACE_LACKS_FPUTS +# define ACE_WRITE_STRING write_string +namespace +{ + int write_string (const char *string, FILE *stream) + { + const size_t count = ACE_OS::strlen (string); + return (ACE_OS::fwrite (string, 1, count, stream) < count) ? -1 : 0; + } +} +#else +# define ACE_WRITE_STRING ACE_OS::fputs +#endif + +// Method provided by derived classes in order to write one section +// to the file specified. Called by export_config when exporting +// the entire configuration object. + +int +ACE_Registry_ImpExp::export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out) +{ + // don't export the root + if (path.length ()) + { + // Write out the section header + ACE_TString header = ACE_TEXT ("["); + header += path; + header += ACE_TEXT ("]"); + header += ACE_TEXT ("\n"); + if (ACE_WRITE_STRING (header.fast_rep (), out) < 0) + return -1; + // Write out each value + int index = 0; + ACE_TString name; + ACE_Configuration::VALUETYPE type; + ACE_TString line; + ACE_TCHAR int_value[32]; + ACE_TCHAR bin_value[3]; + void* binary_data; + size_t binary_length; + ACE_TString string_value; + while (!config_.enumerate_values (section, index, name, type)) + { + line = ACE_TEXT ("\"") + name + ACE_TEXT ("\"="); + switch (type) + { + case ACE_Configuration::INTEGER: + { + u_int value; + if (config_.get_integer_value (section, name.fast_rep (), value)) + return -2; + ACE_OS::snprintf (int_value, 32, ACE_TEXT ("%08x"), value); + line += ACE_TEXT ("dword:"); + line += int_value; + break; + } + case ACE_Configuration::STRING: + { + if (config_.get_string_value (section, + name.fast_rep (), + string_value)) + return -2; + line += ACE_TEXT ("\""); + line += string_value + ACE_TEXT ("\""); + break; + } +#ifdef ACE_WIN32 + case ACE_Configuration::INVALID: + break; +#endif + case ACE_Configuration::BINARY: + { + // not supported yet - maybe use BASE64 codeing? + if (config_.get_binary_value (section, + name.fast_rep (), + binary_data, + binary_length)) + return -2; + line += ACE_TEXT ("hex:"); + unsigned char* ptr = (unsigned char*)binary_data; + while (binary_length) + { + if (ptr != binary_data) + { + line += ACE_TEXT (","); + } + ACE_OS::snprintf (bin_value, 3, ACE_TEXT ("%02x"), *ptr); + line += bin_value; + --binary_length; + ++ptr; + } +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(binary_data); +#else + delete [] (char*) binary_data; +#endif /* ACE_HAS_ALLOC_HOOKS */ + break; + } + default: + return -3; + } + line += ACE_TEXT ("\n"); + if (ACE_WRITE_STRING (line.fast_rep (), out) < 0) + return -4; + ++index; + } + } + // Export all sub sections + int index = 0; + ACE_TString name; + ACE_Configuration_Section_Key sub_key; + ACE_TString sub_section; + while (!config_.enumerate_sections (section, index, name)) + { + ACE_TString sub_section (path); + if (path.length ()) + sub_section += ACE_TEXT ("\\"); + sub_section += name; + if (config_.open_section (section, name.fast_rep (), 0, sub_key)) + return -5; + if (export_section (sub_key, sub_section.fast_rep (), out)) + return -6; + ++index; + } + return 0; +} + +// +// This method read the line format origionally used in ACE 5.1 +// +int +ACE_Registry_ImpExp::process_previous_line_format (ACE_TCHAR* buffer, + ACE_Configuration_Section_Key& section) +{ + // Chop any cr/lf at the end of the line. + ACE_TCHAR *endp = ACE_OS::strpbrk (buffer, ACE_TEXT ("\r\n")); + if (endp != 0) + *endp = '\0'; + + // assume this is a value, read in the value name + ACE_TCHAR* end = ACE_OS::strchr (buffer, '='); + if (end) // no =, not a value so just skip it + { + // null terminate the name + *end = 0; + ++end; + // determine the type + if (*end == '\"') + { + // string type + if(config_.set_string_value (section, buffer, end + 1)) + return -4; + } + else if (*end == '#') + { + // number type + u_int value = ACE_OS::atoi (end + 1); + if (config_.set_integer_value (section, buffer, value)) + return -4; + } + } + return 0; +} // end read_previous_line_format + + +ACE_Ini_ImpExp::ACE_Ini_ImpExp (ACE_Configuration& config) + : ACE_Config_ImpExp_Base (config) +{ +} + +ACE_Ini_ImpExp::~ACE_Ini_ImpExp (void) +{ +} + +// Method to read file and populate object. +int +ACE_Ini_ImpExp::import_config (const ACE_TCHAR* filename) +{ + if (0 == filename) + { + errno = EINVAL; + return -1; + } + FILE* in = ACE_OS::fopen (filename, ACE_TEXT ("r")); + if (!in) + return -1; + + // @@ Make this a dynamic size! + ACE_TCHAR buffer[4096]; + ACE_Configuration_Section_Key section; + while (ACE_OS::fgets (buffer, sizeof buffer, in)) + { + ACE_TCHAR *line = this->squish (buffer); + // Check for a comment and blank line + if (line[0] == ACE_TEXT (';') || + line[0] == ACE_TEXT ('#') || + line[0] == '\0') + continue; + + if (line[0] == ACE_TEXT ('[')) + { + // We have a new section here, strip out the section name + ACE_TCHAR* end = ACE_OS::strrchr (line, ACE_TEXT (']')); + if (!end) + { + ACE_OS::fclose (in); + return -3; + } + *end = 0; + + if (config_.expand_path (config_.root_section (), + line + 1, + section, + 1)) + { + ACE_OS::fclose (in); + return -3; + } + + continue; + } + + // We have a line; name ends at equal sign. + ACE_TCHAR *end = ACE_OS::strchr (line, ACE_TEXT ('=')); + if (end == 0) // No '=' + { + ACE_OS::fclose (in); + return -3; + } + *end++ = '\0'; + ACE_TCHAR *name = this->squish (line); +#if 0 + if (ACE_OS::strlen (name) == 0) // No name; just an '=' + { + ACE_OS::fclose (in); + return -3; + } +#endif + // Now find the start of the value + ACE_TCHAR *value = this->squish (end); + size_t value_len = ACE_OS::strlen (value); + if (value_len > 0) + { + // ACE 5.2 (and maybe earlier) exported strings may be enclosed + // in quotes. If string is quote-delimited, strip the quotes. + // Newer exported files don't have quote delimiters. + if (value[0] == ACE_TEXT ('"') && + value[value_len - 1] == ACE_TEXT ('"')) + { + // Strip quotes off both ends. + value[value_len - 1] = '\0'; + ++value; + } + } + + if (config_.set_string_value (section, name, value)) + { + ACE_OS::fclose (in); + return -4; + } + } // end while fgets + + if (ferror (in)) + { + ACE_OS::fclose (in); + return -1; + } + + ACE_OS::fclose (in); + return 0; +} + +// This method exports the entire configuration database to . +// Once the file is opened this method calls 'export_section' passing +// the root section. +int +ACE_Ini_ImpExp::export_config (const ACE_TCHAR* filename) +{ + if (0 == filename) + { + errno = EINVAL; + return -1; + } + int result = -1; + + FILE* out = ACE_OS::fopen (filename, ACE_TEXT ("w")); + if (out) + { + result = this->export_section (config_.root_section (), + ACE_TEXT (""), + out); + // The data may have been buffered and will be flush on close, + // so we need to check that the close succeeds. + if (ACE_OS::fclose (out) < 0) + result = -7; + } + return result; +} + +// Method provided by derived classes in order to write one section to the +// file specified. Called by export_config when exporting the entire +// configuration objet + +int +ACE_Ini_ImpExp::export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out) +{ + // don't export the root + if (path.length ()) + { + // Write out the section header + ACE_TString header = ACE_TEXT ("["); + header += path; + header += ACE_TEXT ("]\n"); + if (ACE_WRITE_STRING (header.fast_rep (), out) < 0) + return -1; + // Write out each value + int index = 0; + ACE_TString name; + ACE_Configuration::VALUETYPE type; + ACE_TString line; + ACE_TCHAR int_value[32]; + ACE_TCHAR bin_value[3]; + void* binary_data; + size_t binary_length; + ACE_TString string_value; + while (!config_.enumerate_values (section, index, name, type)) + { + line = name + ACE_TEXT ("="); + switch (type) + { + case ACE_Configuration::INTEGER: + { + u_int value; + if (config_.get_integer_value (section, name.fast_rep (), value)) + return -2; + ACE_OS::snprintf (int_value, 32, ACE_TEXT ("%08x"), value); + line += int_value; + break; + } + case ACE_Configuration::STRING: + { + if (config_.get_string_value (section, + name.fast_rep (), + string_value)) + return -2; + line += string_value; + break; + } +#ifdef _WIN32 + case ACE_Configuration::INVALID: + break; // JDO added break. Otherwise INVALID is processed + // like BINARY. If that's correct, please remove the + // break and these comments +#endif + case ACE_Configuration::BINARY: + { + // not supported yet - maybe use BASE64 codeing? + if (config_.get_binary_value (section, + name.fast_rep (), + binary_data, + binary_length)) + return -2; + line += ACE_TEXT ("\""); + unsigned char* ptr = (unsigned char*)binary_data; + while (binary_length) + { + if (ptr != binary_data) + { + line += ACE_TEXT (","); + } + ACE_OS::snprintf (bin_value, 3, ACE_TEXT ("%02x"), *ptr); + line += bin_value; + --binary_length; + ++ptr; + } + line += ACE_TEXT ("\""); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(binary_data); +#else + delete [] (char *) binary_data; +#endif /* ACE_HAS_ALLOC_HOOKS */ + break; + } + default: + return -3; + + }// end switch on type + + line += ACE_TEXT ("\n"); + if (ACE_WRITE_STRING (line.fast_rep (), out) < 0) + return -4; + ++index; + }// end while enumerating values + } + // Export all sub sections + int index = 0; + ACE_TString name; + ACE_Configuration_Section_Key sub_key; + ACE_TString sub_section; + while (!config_.enumerate_sections (section, index, name)) + { + ACE_TString sub_section (path); + if (path.length ()) + sub_section += ACE_TEXT ("\\"); + sub_section += name; + if (config_.open_section (section, name.fast_rep (), 0, sub_key)) + return -5; + if (export_section (sub_key, sub_section.fast_rep (), out)) + return -6; + ++index; + } + return 0; + +} + +// Method to squish leading and trailing whitespaces from a string. +// Whitespace is defined as: spaces (' '), tabs ('\t') or end-of-line +// (cr/lf). The terminating nul is moved up to expunge trailing +// whitespace and the returned pointer points at the first +// non-whitespace character in the string, which may be the nul +// terminator if the string is all whitespace. + +ACE_TCHAR * +ACE_Ini_ImpExp::squish (ACE_TCHAR *src) +{ + ACE_TCHAR *cp = 0; + + if (src == 0) + return 0; + + // Start at the end and work backwards over all whitespace. + for (cp = src + ACE_OS::strlen (src) - 1; + cp != src; + --cp) + if (!ACE_OS::ace_isspace (*cp)) + break; + cp[1] = '\0'; // Chop trailing whitespace + + // Now start at the beginning and move over all whitespace. + for (cp = src; ACE_OS::ace_isspace (*cp); ++cp) + continue; + + return cp; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Configuration_Import_Export.h b/dep/acelite/ace/Configuration_Import_Export.h new file mode 100644 index 000000000..f40019ecc --- /dev/null +++ b/dep/acelite/ace/Configuration_Import_Export.h @@ -0,0 +1,211 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Configuration_Import_Export.h + * + * @author Jerry D. Odenwelder Jr. + * Chris Hafey + * + * Classes defined in this file provide the ability to import and export + * ACE Configuration objects to/from disk files. The base class + * ACE_Config_ImpExp_Base provides the common functionality and the derived + * classes implement the import/export functionality for the specific format. + * + * @todo + * - Add locking for thread safety. + * - Provide ability to read file in one format and write in another. + * - See todo's in each class + */ +//============================================================================= + +#ifndef ACE_CONFIGURATION_IMPORT_EXPORT_H +#define ACE_CONFIGURATION_IMPORT_EXPORT_H +#include /**/ "ace/pre.h" + +#include "ace/Configuration.h" +#include "ace/SString.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Config_ImpExp_Base + * + * @brief Base class for file import/export configuration. + * + * This class provides base functionality for configuration objects + * that are persisted in files. It takes an ACE_Configuration + * object that it populates with the data read. + */ +class ACE_Export ACE_Config_ImpExp_Base +{ +public: + /// Constructor taking the ACE_Configuration to import/export to + ACE_Config_ImpExp_Base (ACE_Configuration& config); + + /** + * Destructor + */ + virtual ~ACE_Config_ImpExp_Base (void); + + /** + * Imports the configuration database from @a filename. + * No existing data is removed. + */ + virtual int import_config (const ACE_TCHAR* filename) = 0; + + /** + * This method exports the entire configuration database to @a filename. + * Once the file is opened this method calls 'export_section' passing + * the root section. + */ + virtual int export_config (const ACE_TCHAR* filename) = 0; + +protected: + ACE_Configuration &config_; + +private: + ACE_Config_ImpExp_Base (const ACE_Config_ImpExp_Base&); + ACE_Config_ImpExp_Base& operator= (const ACE_Config_ImpExp_Base&); +}; + +/** + * @class ACE_Registry_ImpExp + * + * @brief Configuration object that imports/exports data to a file formatted + * using the Win32 Registry file export format. This format looks like + * [Section] + * "key"="String Data" + * "key"=dword: numeric data in hexadecimal format + * "key"=hex: binary data + * + * @todo + * - Add dynamic buffer when importing. currently it will not allow + * importing of values greater than a fixed amount (4096 bytes) + */ +class ACE_Export ACE_Registry_ImpExp : public ACE_Config_ImpExp_Base +{ +public: + /// Construction + ACE_Registry_ImpExp (ACE_Configuration&); + + /// Destruction. + virtual ~ACE_Registry_ImpExp (void); + + /** + * Imports the configuration database from @a filename. + * No existing data is removed. + */ + virtual int import_config (const ACE_TCHAR* filename); + + /** + * This method exports the entire configuration database to @a filename. + * Once the file is opened this method calls export_section() passing + * the root section. + */ + virtual int export_config (const ACE_TCHAR* filename); + +private: + int export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out); + + int process_previous_line_format (ACE_TCHAR* buffer, + ACE_Configuration_Section_Key& section); + + ACE_Registry_ImpExp ( const ACE_Registry_ImpExp&); + ACE_Registry_ImpExp& operator= ( const ACE_Registry_ImpExp&); +}; + +/** + * @class ACE_Ini_ImpExp + * + * @brief Imports the configuration database from filename as strings. + * Allows non-typed values. (no #, dword: hex:, etc. prefixes) and + * skips whitespace (tabs and spaces) as in standard .ini and .conf + * files. Values (to right of equal sign) can be double quote + * delimited to embed tabs and spaces in the string. + * Caller must convert string to type. + * + * This method allows for lines in the .ini or .conf file like this: + * + * TimeToLive = 100 + * Delay = FALSE + * Flags = FF34 + * Heading = "ACE - Adaptive Communication Environment" + * + * (note leading whitespace (tabs) in examples below) + * + * SeekIndex = 14 + * TraceLevel = 6 # Can comment lines like this + * Justification = left_justified + * + * The caller can then retrieve the string with the regular + * get_string_value() function and convert the string to the + * desired data type. + * + * @todo + * - Strings with embedded newlines cause the import to fail + * - Strings with embedded quotes " cause the import to fail + * - Importing/exporting for values in the root section does not work + * - Add dynamic buffer when importing. currently it will not allow + * importing of values greater than a fixed amount (4096 bytes) +*/ +class ACE_Export ACE_Ini_ImpExp : public ACE_Config_ImpExp_Base +{ +public: + /** + * Construction + */ + ACE_Ini_ImpExp (ACE_Configuration&); + + /** + * Destructor + */ + virtual ~ACE_Ini_ImpExp (void); + + /** + * Imports the configuration database from @a filename. + * No existing data is removed. + */ + virtual int import_config (const ACE_TCHAR* filename); + + /** + * This method exports the entire configuration database to @a filename. + * Once the file is opened this method calls export_section() passing + * the root section. + */ + virtual int export_config (const ACE_TCHAR* filename); + +private: + /** + * Method provided by derived classes in order to write one section + * to the file specified. Called by export_config() when exporting + * the entire configuration object. + */ + int export_section (const ACE_Configuration_Section_Key& section, + const ACE_TString& path, + FILE* out); + + /** + * Method to squish leading and trailing whitespaces in a string. + * Whitespace is defined as: spaces (' '), tabs ('\\t') or cr/lf. + * Returns a pointer to the first non-whitespace character in the + * buffer provided, or a pointer to the terminating null if the string + * is all whitespace. The terminating null is moved forward to the + * first character past the last non-whitespace. + */ + ACE_TCHAR *squish (ACE_TCHAR *src); + + ACE_Ini_ImpExp (const ACE_Ini_ImpExp&); + ACE_Ini_ImpExp& operator= (const ACE_Ini_ImpExp&); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_CONFIGURATION_IMPORT_EXPORT_H */ diff --git a/dep/acelite/ace/Connection_Recycling_Strategy.cpp b/dep/acelite/ace/Connection_Recycling_Strategy.cpp new file mode 100644 index 000000000..b5619a674 --- /dev/null +++ b/dep/acelite/ace/Connection_Recycling_Strategy.cpp @@ -0,0 +1,13 @@ +#include "ace/Connection_Recycling_Strategy.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Connection_Recycling_Strategy::ACE_Connection_Recycling_Strategy (void) +{ +} + +ACE_Connection_Recycling_Strategy::~ACE_Connection_Recycling_Strategy (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Connection_Recycling_Strategy.h b/dep/acelite/ace/Connection_Recycling_Strategy.h new file mode 100644 index 000000000..763c7e548 --- /dev/null +++ b/dep/acelite/ace/Connection_Recycling_Strategy.h @@ -0,0 +1,62 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Connection_Recycling_Strategy.h + * + * @author Doug Schmidt + */ +//============================================================================= +#ifndef ACE_CONNECTION_RECYCLING_STRATEGY_H +#define ACE_CONNECTION_RECYCLING_STRATEGY_H +#include /**/ "ace/pre.h" + +#include "ace/Recyclable.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Connection_Recycling_Strategy + * + * @brief Defines the interface for a connection recycler. + */ +class ACE_Export ACE_Connection_Recycling_Strategy +{ +public: + ACE_Connection_Recycling_Strategy (void); + + /// Virtual Destructor + virtual ~ACE_Connection_Recycling_Strategy (void); + + /// Remove from cache. + virtual int purge (const void *recycling_act) = 0; + + /// Add to cache. + virtual int cache (const void *recycling_act) = 0; + + virtual int recycle_state (const void *recycling_act, + ACE_Recyclable_State new_state) = 0; + + /// Get/Set recycle_state. + virtual ACE_Recyclable_State recycle_state (const void *recycling_act) const = 0; + + /// Mark as closed. + virtual int mark_as_closed (const void *recycling_act) = 0; + + /// Mark as closed.(non-locking version) + virtual int mark_as_closed_i (const void *recycling_act) = 0; + + /// Cleanup hint and reset @a act_holder to zero if @a act_holder != 0. + virtual int cleanup_hint (const void *recycling_act, + void **act_holder = 0) = 0; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /*ACE_CONNECTION_RECYCLING_STRATEGY*/ diff --git a/dep/acelite/ace/Connector.cpp b/dep/acelite/ace/Connector.cpp new file mode 100644 index 000000000..1303ab9ca --- /dev/null +++ b/dep/acelite/ace/Connector.cpp @@ -0,0 +1,1001 @@ +#ifndef ACE_CONNECTOR_CPP +#define ACE_CONNECTOR_CPP + +#include "ace/Connector.h" +#include "ace/ACE.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/os_fcntl.h" /* Has ACE_NONBLOCK */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc (ACE_NonBlocking_Connect_Handler) +ACE_ALLOC_HOOK_DEFINE_Tco (ACE_Connector) +ACE_ALLOC_HOOK_DEFINE_Tco (ACE_Strategy_Connector) + +template +ACE_NonBlocking_Connect_Handler::ACE_NonBlocking_Connect_Handler (ACE_Connector_Base &connector, + SVC_HANDLER *sh, + long id) + : connector_ (connector), + svc_handler_ (sh), + cleanup_svc_handler_ (0), + timer_id_ (id) +{ + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::ACE_NonBlocking_Connect_Handler"); + + this->reference_counting_policy ().value + (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); + + if (this->svc_handler_ != 0 && + this->svc_handler_->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED) + { + // If SVC_HANDLER is reference counted then NBCH holds a reference + // in cleanup_svc_handle_ which is both a pointer to SVC_HANDLER + // and a flag that triggers remove_reference in NBCH destructor. + this->cleanup_svc_handler_ = sh; + this->cleanup_svc_handler_->add_reference (); + } +} + +template +ACE_NonBlocking_Connect_Handler::~ACE_NonBlocking_Connect_Handler (void) +{ + if (this->cleanup_svc_handler_) + this->cleanup_svc_handler_->remove_reference (); +} + +template SVC_HANDLER * +ACE_NonBlocking_Connect_Handler::svc_handler (void) +{ + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::svc_handler"); + return this->svc_handler_; +} + +template long +ACE_NonBlocking_Connect_Handler::timer_id (void) +{ + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::timer_id"); + return this->timer_id_; +} + +template void +ACE_NonBlocking_Connect_Handler::timer_id (long id) +{ + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::timer_id"); + this->timer_id_ = id; +} + +template void +ACE_NonBlocking_Connect_Handler::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("svc_handler_ = %x"), this->svc_handler_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ntimer_id_ = %d"), this->timer_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template bool +ACE_NonBlocking_Connect_Handler::close (SVC_HANDLER *&sh) +{ + // Make sure that we haven't already initialized the Svc_Handler. + if (!this->svc_handler_) + return false; + + { + // Exclusive access to the Reactor. + ACE_GUARD_RETURN (ACE_Lock, + ace_mon, + this->reactor ()->lock (), + 0); + + // Double check. + if (!this->svc_handler_) + return false; + + // Remember the Svc_Handler. + sh = this->svc_handler_; + ACE_HANDLE h = sh->get_handle (); + this->svc_handler_ = 0; + + // Remove this handle from the set of non-blocking handles + // in the Connector. + this->connector_.non_blocking_handles ().remove (h); + + // Cancel timer. + if (this->reactor ()->cancel_timer (this->timer_id (), + 0, + 0) == -1) + return false; + + // Remove from Reactor. + if (-1 == this->reactor ()->remove_handler ( + h, + ACE_Event_Handler::ALL_EVENTS_MASK | ACE_Event_Handler::DONT_CALL)) + return false; + } + + return true; +} + + +template int +ACE_NonBlocking_Connect_Handler::handle_timeout +(const ACE_Time_Value &tv, + const void *arg) +{ + // This method is called if a connection times out before completing. + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::handle_timeout"); + + SVC_HANDLER *svc_handler = 0; + int const retval = this->close (svc_handler) ? 0 : -1; + + // Forward to the SVC_HANDLER the that was passed in as a + // magic cookie during ACE_Connector::connect(). This gives the + // SVC_HANDLER an opportunity to take corrective action (e.g., wait + // a few milliseconds and try to reconnect again. + if (svc_handler != 0 && svc_handler->handle_timeout (tv, arg) == -1) + svc_handler->handle_close (svc_handler->get_handle (), + ACE_Event_Handler::TIMER_MASK); + + return retval; +} + + +template int +ACE_NonBlocking_Connect_Handler::handle_input (ACE_HANDLE) +{ + // Called when a failure occurs during asynchronous connection + // establishment. + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::handle_input"); + + SVC_HANDLER *svc_handler = 0; + int const retval = this->close (svc_handler) ? 0 : -1; + + // Close Svc_Handler. + if (svc_handler != 0) + { + svc_handler->close (NORMAL_CLOSE_OPERATION); + } + + return retval; +} + +template int +ACE_NonBlocking_Connect_Handler::handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask m) +{ + // epoll on Linux will, at least sometimes, return EPOLLERR when a connect + // fails, triggering a total removal from the reactor. This is different from + // select()-based systems which select the fd for read on a connect failure. + // So just call handle_input() to rejoin common handling for a failed + // connect. + if (m == ACE_Event_Handler::ALL_EVENTS_MASK) + return this->handle_input (handle); + return -1; +} + +template int +ACE_NonBlocking_Connect_Handler::handle_output (ACE_HANDLE handle) +{ + // Called when a connection is establishment asynchronous. + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::handle_output"); + + // Grab the connector ref before smashing ourselves in close(). + ACE_Connector_Base &connector = this->connector_; + SVC_HANDLER *svc_handler = 0; + int const retval = this->close (svc_handler) ? 0 : -1; + + if (svc_handler != 0) + { + connector.initialize_svc_handler (handle, svc_handler); + } + + return retval; +} + +template int +ACE_NonBlocking_Connect_Handler::handle_exception (ACE_HANDLE h) +{ + // On Win32, the except mask must also be set for asynchronous + // connects. + ACE_TRACE ("ACE_NonBlocking_Connect_Handler::handle_exception"); + return this->handle_output (h); +} + +template int +ACE_NonBlocking_Connect_Handler::resume_handler (void) +{ + return ACE_Event_Handler::ACE_EVENT_HANDLER_NOT_RESUMED; +} + +template void +ACE_Connector::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Connector::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nflags_ = %d"), this->flags_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template int +ACE_Connector::make_svc_handler (SVC_HANDLER *&sh) +{ + ACE_TRACE ("ACE_Connector::make_svc_handler"); + + if (sh == 0) + ACE_NEW_RETURN (sh, + SVC_HANDLER, + -1); + + // Set the reactor of the newly created to the same + // reactor that this is using. + sh->reactor (this->reactor ()); + return 0; +} + +template int +ACE_Connector::activate_svc_handler (SVC_HANDLER *svc_handler) +{ + ACE_TRACE ("ACE_Connector::activate_svc_handler"); + // No errors initially + int error = 0; + + // See if we should enable non-blocking I/O on the 's + // peer. + if (ACE_BIT_ENABLED (this->flags_, ACE_NONBLOCK) != 0) + { + if (svc_handler->peer ().enable (ACE_NONBLOCK) == -1) + error = 1; + } + // Otherwise, make sure it's disabled by default. + else if (svc_handler->peer ().disable (ACE_NONBLOCK) == -1) + error = 1; + + // We are connected now, so try to open things up. + if (error || svc_handler->open ((void *) this) == -1) + { + // Make sure to close down the to avoid descriptor + // leaks. + // The connection was already made; so this close is a "normal" + // close operation. + svc_handler->close (NORMAL_CLOSE_OPERATION); + return -1; + } + else + return 0; +} + +template PEER_CONNECTOR & +ACE_Connector::connector (void) const +{ + return const_cast (this->connector_); +} + +template int +ACE_Connector::connect_svc_handler +(SVC_HANDLER *&svc_handler, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_Connector::connect_svc_handler"); + + return this->connector_.connect (svc_handler->peer (), + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Connector::connect_svc_handler +(SVC_HANDLER *&svc_handler, + SVC_HANDLER *&sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_Connector::connect_svc_handler"); + + sh_copy = svc_handler; + return this->connector_.connect (svc_handler->peer (), + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Connector::open (ACE_Reactor *r, int flags) +{ + ACE_TRACE ("ACE_Connector::open"); + this->reactor (r); + this->flags_ = flags; + return 0; +} + +template +ACE_Connector::ACE_Connector (ACE_Reactor *r, + int flags) +{ + ACE_TRACE ("ACE_Connector::ACE_Connector"); + (void) this->open (r, flags); +} + +template int +ACE_Connector::connect +(SVC_HANDLER *&sh, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + // Initiate connection to peer. + return this->connect_i (sh, + 0, + remote_addr, + synch_options, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Connector::connect +(SVC_HANDLER *&sh, + SVC_HANDLER *&sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + // Initiate connection to peer. + return this->connect_i (sh, + &sh_copy, + remote_addr, + synch_options, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Connector::connect_i +(SVC_HANDLER *&sh, + SVC_HANDLER **sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_Connector::connect_i"); + + // If the user hasn't supplied us with a we'll use the + // factory method to create one. Otherwise, things will remain as + // they are... + if (this->make_svc_handler (sh) == -1) + return -1; + + ACE_Time_Value *timeout = 0; + int const use_reactor = synch_options[ACE_Synch_Options::USE_REACTOR]; + + if (use_reactor) + timeout = const_cast (&ACE_Time_Value::zero); + else + timeout = const_cast (synch_options.time_value ()); + + int result; + if (sh_copy == 0) + result = this->connect_svc_handler (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); + else + result = this->connect_svc_handler (sh, + *sh_copy, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); + + // Activate immediately if we are connected. + if (result != -1) + return this->activate_svc_handler (sh); + + // Delegate to connection strategy. + if (use_reactor && ACE_OS::last_error () == EWOULDBLOCK) + { + // If the connection hasn't completed and we are using + // non-blocking semantics then register + // ACE_NonBlocking_Connect_Handler with the ACE_Reactor so that + // it will call us back when the connection is complete or we + // timeout, whichever comes first... + if (sh_copy == 0) + result = this->nonblocking_connect (sh, synch_options); + else + result = this->nonblocking_connect (*sh_copy, synch_options); + + // If for some reason the call failed, then + // will be set to the new error. If the call succeeds, however, + // we need to make sure that remains set to + // . + if (result == 0) + errno = EWOULDBLOCK; + } + else + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + // Make sure to close down the service handler to avoid handle + // leaks. + if (sh_copy == 0) + { + if (sh) + sh->close (CLOSE_DURING_NEW_CONNECTION); + } + else if (*sh_copy) + (*sh_copy)->close (CLOSE_DURING_NEW_CONNECTION); + } + + return -1; +} + +template int +ACE_Connector::connect_n +(size_t n, + SVC_HANDLER *sh[], + typename PEER_CONNECTOR::PEER_ADDR remote_addrs[], + ACE_TCHAR *failed_svc_handlers, + const ACE_Synch_Options &synch_options) +{ + int result = 0; + + for (size_t i = 0; i < n; i++) + { + if (this->connect (sh[i], remote_addrs[i], synch_options) == -1 + && !(synch_options[ACE_Synch_Options::USE_REACTOR] + && errno == EWOULDBLOCK)) + { + result = -1; + if (failed_svc_handlers != 0) + // Mark this entry as having failed. + failed_svc_handlers[i] = 1; + } + else if (failed_svc_handlers != 0) + // Mark this entry as having succeeded. + failed_svc_handlers[i] = 0; + } + + return result; +} + +// Cancel a that was started asynchronously. +template int +ACE_Connector::cancel (SVC_HANDLER *sh) +{ + ACE_TRACE ("ACE_Connector::cancel"); + + ACE_Event_Handler *handler = + this->reactor ()->find_handler (sh->get_handle ()); + + if (handler == 0) + return -1; + + // find_handler() increments handler's refcount; ensure we decrement it. + ACE_Event_Handler_var safe_handler (handler); + + NBCH *nbch = + dynamic_cast (handler); + + if (nbch == 0) + return -1; + + SVC_HANDLER *tmp_sh = 0; + + if (nbch->close (tmp_sh) == false) + return -1; + + return 0; +} + +template int +ACE_Connector::nonblocking_connect +(SVC_HANDLER *sh, + const ACE_Synch_Options &synch_options) +{ + ACE_TRACE ("ACE_Connector::nonblocking_connect"); + + // Must have a valid Reactor for non-blocking connects to work. + if (this->reactor () == 0) + return -1; + + // Register the pending SVC_HANDLER so that it can be activated + // later on when the connection completes. + + ACE_HANDLE handle = sh->get_handle (); + long timer_id = -1; + ACE_Time_Value *tv = 0; + NBCH *nbch = 0; + + ACE_NEW_RETURN (nbch, + NBCH (*this, + sh, + -1), + -1); + + ACE_Event_Handler_var safe_nbch (nbch); + + // Exclusive access to the Reactor. + ACE_GUARD_RETURN (ACE_Lock, ace_mon, this->reactor ()->lock (), -1); + + // Register handle with the reactor for connection events. + ACE_Reactor_Mask mask = ACE_Event_Handler::CONNECT_MASK; + if (this->reactor ()->register_handler (handle, + nbch, + mask) == -1) + goto reactor_registration_failure; + + // Add handle to non-blocking handle set. + this->non_blocking_handles ().insert (handle); + + // If we're starting connection under timer control then we need to + // schedule a timeout with the ACE_Reactor. + tv = const_cast (synch_options.time_value ()); + if (tv != 0) + { + timer_id = + this->reactor ()->schedule_timer (nbch, + synch_options.arg (), + *tv); + if (timer_id == -1) + goto timer_registration_failure; + + // Remember timer id. + nbch->timer_id (timer_id); + } + + return 0; + + // Undo previous actions using the ol' "goto label and fallthru" + // trick... + timer_registration_failure: + + // Remove from Reactor. + this->reactor ()->remove_handler (handle, mask); + + // Remove handle from the set of non-blocking handles. + this->non_blocking_handles ().remove (handle); + + /* FALLTHRU */ + + reactor_registration_failure: + // Close the svc_handler + + sh->close (CLOSE_DURING_NEW_CONNECTION); + + return -1; +} + +template +ACE_Connector::~ACE_Connector (void) +{ + ACE_TRACE ("ACE_Connector::~ACE_Connector"); + + this->close (); +} + +template void +ACE_Connector::initialize_svc_handler +(ACE_HANDLE handle, + SVC_HANDLER *svc_handler) +{ + // Try to find out if the reactor uses event associations for the + // handles it waits on. If so we need to reset it. + bool reset_new_handle = + this->reactor ()->uses_event_associations (); + + if (reset_new_handle) + this->connector_.reset_new_handle (handle); + + // Transfer ownership of the ACE_HANDLE to the SVC_HANDLER. + svc_handler->set_handle (handle); + + typename PEER_CONNECTOR::PEER_ADDR raddr; + + // Check to see if we're connected. + if (svc_handler->peer ().get_remote_addr (raddr) != -1) + this->activate_svc_handler (svc_handler); + else // Somethings gone wrong, so close down... + { +#if defined (ACE_WIN32) + // Win32 (at least prior to Windows 2000) has a timing problem. + // If you check to see if the connection has completed too fast, + // it will fail - so wait 35 milliseconds to let it catch up. + ACE_Time_Value tv (0, ACE_NON_BLOCKING_BUG_DELAY); + ACE_OS::sleep (tv); + if (svc_handler->peer ().get_remote_addr (raddr) != -1) + this->activate_svc_handler (svc_handler); + else // do the svc handler close below... +#endif /* ACE_WIN32 */ + svc_handler->close (NORMAL_CLOSE_OPERATION); + } +} + +template void +ACE_Connector::reactor (ACE_Reactor *reactor) +{ + this->reactor_ = reactor; +} + +template ACE_Reactor * +ACE_Connector::reactor (void) const +{ + return this->reactor_; +} + +template ACE_Unbounded_Set & +ACE_Connector::non_blocking_handles (void) +{ + return this->non_blocking_handles_; +} + +template int +ACE_Connector::close (void) +{ + // If there are no non-blocking handle pending, return immediately. + if (this->non_blocking_handles ().size () == 0) + return 0; + + // Exclusive access to the Reactor. + ACE_GUARD_RETURN (ACE_Lock, ace_mon, this->reactor ()->lock (), -1); + + // Go through all the non-blocking handles. It is necessary to + // create a new iterator each time because we remove from the handle + // set when we cancel the Svc_Handler. + ACE_HANDLE *handle = 0; + while (1) + { + ACE_Unbounded_Set_Iterator + iterator (this->non_blocking_handles ()); + if (!iterator.next (handle)) + break; + + ACE_Event_Handler *handler = + this->reactor ()->find_handler (*handle); + if (handler == 0) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%t: Connector::close h %d, no handler\n"), + *handle)); + // Remove handle from the set of non-blocking handles. + this->non_blocking_handles ().remove (*handle); + continue; + } + + // find_handler() incremented handler's refcount; ensure it's decremented + ACE_Event_Handler_var safe_handler (handler); + NBCH *nbch = dynamic_cast (handler); + if (nbch == 0) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%t: Connector::close h %d handler %@ ") + ACE_TEXT ("not a legit handler\n"), + *handle, + handler)); + // Remove handle from the set of non-blocking handles. + this->non_blocking_handles ().remove (*handle); + continue; + } + SVC_HANDLER *svc_handler = nbch->svc_handler (); + + // Cancel the non-blocking connection. + this->cancel (svc_handler); + + // Close the associated Svc_Handler. + svc_handler->close (NORMAL_CLOSE_OPERATION); + } + + return 0; +} + +template int +ACE_Connector::fini (void) +{ + ACE_TRACE ("ACE_Connector::fini"); + + return this->close (); +} + +// Hook called by the explicit dynamic linking facility. + +template int +ACE_Connector::init (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("ACE_Connector::init"); + return -1; +} + +template int +ACE_Connector::suspend (void) +{ + ACE_TRACE ("ACE_Connector::suspend"); + return -1; +} + +template int +ACE_Connector::resume (void) +{ + ACE_TRACE ("ACE_Connector::resume"); + return -1; +} + +template int +ACE_Connector::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TRACE ("ACE_Connector::info"); + ACE_TCHAR buf[BUFSIZ]; + + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%s\t %s"), + ACE_TEXT ("ACE_Connector"), + ACE_TEXT ("# connector factory\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strsncpy (*strp, buf, length); + return static_cast (ACE_OS::strlen (buf)); +} + +template int +ACE_Strategy_Connector::open (ACE_Reactor *r, + int flags) +{ + ACE_TRACE ("ACE_Strategy_Connector::open"); + return this->open (r, 0, 0, 0, flags); +} + +template int +ACE_Strategy_Connector::open +(ACE_Reactor *r, + ACE_Creation_Strategy *cre_s, + ACE_Connect_Strategy *conn_s, + ACE_Concurrency_Strategy *con_s, + int flags) +{ + ACE_TRACE ("ACE_Strategy_Connector::open"); + + this->reactor (r); + + // @@ Not implemented yet. + // this->flags_ = flags; + ACE_UNUSED_ARG (flags); + + // Initialize the creation strategy. + + // First we decide if we need to clean up. + if (this->creation_strategy_ != 0 && + this->delete_creation_strategy_ && + cre_s != 0) + { + delete this->creation_strategy_; + this->creation_strategy_ = 0; + this->delete_creation_strategy_ = false; + } + + if (cre_s != 0) + this->creation_strategy_ = cre_s; + else if (this->creation_strategy_ == 0) + { + ACE_NEW_RETURN (this->creation_strategy_, + CREATION_STRATEGY (0, r), + -1); + this->delete_creation_strategy_ = true; + } + + + // Initialize the accept strategy. + + if (this->connect_strategy_ != 0 && + this->delete_connect_strategy_ && + conn_s != 0) + { + delete this->connect_strategy_; + this->connect_strategy_ = 0; + this->delete_connect_strategy_ = false; + } + + if (conn_s != 0) + this->connect_strategy_ = conn_s; + else if (this->connect_strategy_ == 0) + { + ACE_NEW_RETURN (this->connect_strategy_, + CONNECT_STRATEGY, + -1); + this->delete_connect_strategy_ = true; + } + + // Initialize the concurrency strategy. + + if (this->concurrency_strategy_ != 0 && + this->delete_concurrency_strategy_ && + con_s != 0) + { + delete this->concurrency_strategy_; + this->concurrency_strategy_ = 0; + this->delete_concurrency_strategy_ = false; + } + + if (con_s != 0) + this->concurrency_strategy_ = con_s; + else if (this->concurrency_strategy_ == 0) + { + ACE_NEW_RETURN (this->concurrency_strategy_, + CONCURRENCY_STRATEGY, + -1); + this->delete_concurrency_strategy_ = true; + } + + return 0; +} + +template +ACE_Strategy_Connector::ACE_Strategy_Connector +(ACE_Reactor *reactor, + ACE_Creation_Strategy *cre_s, + ACE_Connect_Strategy *conn_s, + ACE_Concurrency_Strategy *con_s, + int flags) + : base_type (reactor), + creation_strategy_ (0), + delete_creation_strategy_ (false), + connect_strategy_ (0), + delete_connect_strategy_ (false), + concurrency_strategy_ (0), + delete_concurrency_strategy_ (false) +{ + ACE_TRACE ("ACE_Connector::ACE_Strategy_Connector"); + + if (this->open (reactor, cre_s, conn_s, con_s, flags) == -1) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_Strategy_Connector::ACE_Strategy_Connector"))); +} + +template +ACE_Strategy_Connector::~ACE_Strategy_Connector (void) +{ + ACE_TRACE ("ACE_Strategy_Connector::~ACE_Strategy_Connector"); + + // Close down + this->close (); +} + +template int +ACE_Strategy_Connector::close (void) +{ + if (this->delete_creation_strategy_) + delete this->creation_strategy_; + this->delete_creation_strategy_ = false; + this->creation_strategy_ = 0; + + if (this->delete_connect_strategy_) + delete this->connect_strategy_; + this->delete_connect_strategy_ = false; + this->connect_strategy_ = 0; + + if (this->delete_concurrency_strategy_) + delete this->concurrency_strategy_; + this->delete_concurrency_strategy_ = false; + this->concurrency_strategy_ = 0; + + return SUPER::close (); +} + +template int +ACE_Strategy_Connector::make_svc_handler (SVC_HANDLER *&sh) +{ + return this->creation_strategy_->make_svc_handler (sh); +} + +template int +ACE_Strategy_Connector::connect_svc_handler +(SVC_HANDLER *&sh, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + return this->connect_strategy_->connect_svc_handler (sh, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Strategy_Connector::connect_svc_handler +(SVC_HANDLER *&sh, + SVC_HANDLER *&sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms) +{ + return this->connect_strategy_->connect_svc_handler (sh, + sh_copy, + remote_addr, + timeout, + local_addr, + reuse_addr, + flags, + perms); +} + +template int +ACE_Strategy_Connector::activate_svc_handler (SVC_HANDLER *svc_handler) +{ + return this->concurrency_strategy_->activate_svc_handler (svc_handler, this); +} + +template ACE_Creation_Strategy * +ACE_Strategy_Connector::creation_strategy (void) const +{ + return this->creation_strategy_; +} + +template ACE_Connect_Strategy * +ACE_Strategy_Connector::connect_strategy (void) const +{ + return this->connect_strategy_; +} + +template ACE_Concurrency_Strategy * +ACE_Strategy_Connector::concurrency_strategy (void) const +{ + return this->concurrency_strategy_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CONNECTOR_C */ diff --git a/dep/acelite/ace/Connector.h b/dep/acelite/ace/Connector.h new file mode 100644 index 000000000..2217fe97b --- /dev/null +++ b/dep/acelite/ace/Connector.h @@ -0,0 +1,581 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Connector.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_CONNECTOR_H +#define ACE_CONNECTOR_H + +#include /**/ "ace/pre.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Strategies_T.h" +#include "ace/Synch_Options.h" +#include "ace/Unbounded_Set.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Connector_Base + * + * @brief This base interface allows ACE_NonBlocking_Connect_Handler + * to only care about the SVC_HANDLER template parameter of the + * ACE_Connector. Otherwise, ACE_NonBlocking_Connect_Handler would + * have to be configured with all the template parameters that + * ACE_Connector is configured with. + */ +template +class ACE_Connector_Base +{ +public: + + virtual ~ACE_Connector_Base (void) {} + + /// Initialize the Svc_Handler. + virtual void initialize_svc_handler (ACE_HANDLE handle, + SVC_HANDLER *svc_handler) = 0; + + /// Return the handle set representing the non-blocking connects in + /// progress. + virtual ACE_Unbounded_Set &non_blocking_handles (void) = 0; +}; + +/** + * @class ACE_NonBlocking_Connect_Handler + * + * @brief Performs non-blocking connects on behalf of the Connector. + */ +template +class ACE_NonBlocking_Connect_Handler : public ACE_Event_Handler +{ +public: + /// Constructor. + ACE_NonBlocking_Connect_Handler (ACE_Connector_Base &connector, + SVC_HANDLER *, + long timer_id); + + /// Destructor. + ~ACE_NonBlocking_Connect_Handler (void); + + /// Close up and return underlying SVC_HANDLER through @c sh. + /** + * If the return value is true the close was performed successfully, + * implying that this object was removed from the reactor and thereby + * (by means of reference counting decremented to 0) deleted. + * If the return value is false, the close was not successful. + * The @c sh does not have any connection to the return + * value. The argument will return a valid svc_handler object if a + * valid one exists within the object. Returning a valid svc_handler + * pointer also invalidates the svc_handler contained in this + * object. + */ + bool close (SVC_HANDLER *&sh); + + /// Get SVC_HANDLER. + SVC_HANDLER *svc_handler (void); + + /// Get handle. + ACE_HANDLE handle (void); + + /// Set handle. + void handle (ACE_HANDLE); + + /// Get timer id. + long timer_id (void); + + /// Set timer id. + void timer_id (long timer_id); + + /// Called by ACE_Reactor when asynchronous connections fail. + virtual int handle_input (ACE_HANDLE); + + /// Called by ACE_Dev_Poll_Reactor when asynchronous connections fail. + virtual int handle_close (ACE_HANDLE, ACE_Reactor_Mask); + + /// Called by ACE_Reactor when asynchronous connections succeed. + virtual int handle_output (ACE_HANDLE); + + /// Called by ACE_Reactor when asynchronous connections suceeds (on + /// some platforms only). + virtual int handle_exception (ACE_HANDLE fd); + + /// This method is called if a connection times out before + /// completing. + virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg); + + /// Should Reactor resume us if we have been suspended before the upcall? + virtual int resume_handler (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Connector base. + ACE_Connector_Base &connector_; + + /// Associated SVC_HANDLER. + SVC_HANDLER *svc_handler_; + + /// Same as svc_handler_ if svc_handler_ is reference counted. + SVC_HANDLER *cleanup_svc_handler_; + + /// Associated timer id. + long timer_id_; +}; + +/** + * @class ACE_Connector + * + * @brief Generic factory for actively connecting clients and creating + * service handlers (SVC_HANDLERs). + * + * Implements the strategy for actively establishing connections with + * clients. Both blocking and non-blocking connects are supported. + * Moreover, non-blocking connects support timeouts. + * + * An ACE_Connector is parameterized by concrete types that conform to + * the interfaces of SVC_HANDLER and PEER_CONNECTOR described below. + * + * @tparam SVC_HANDLER The name of the concrete type that performs the + * application-specific service. The SVC_HANDLER typically + * inherits from ACE_Svc_Handler. @see Svc_Handler.h. + * + * @tparam PEER_CONNECTOR The name of the class that implements the + * PEER_CONNECTOR endpoint (e.g., ACE_SOCK_Connector) to + * passively establish connections. A PEER_CONNECTOR + * implementation must provide a PEER_STREAM and PEER_ADDR + * trait to identify the type of stream (e.g., + * ACE_SOCK_Stream) and type of address (e.g., ACE_INET_Addr) + * used by the endpoint. + */ +template +class ACE_Connector : public ACE_Connector_Base, public ACE_Service_Object +{ +public: + + // Useful STL-style traits. + typedef typename SVC_HANDLER::addr_type addr_type; + typedef PEER_CONNECTOR connector_type; + typedef SVC_HANDLER handler_type; + typedef typename SVC_HANDLER::stream_type stream_type; + typedef typename PEER_CONNECTOR::PEER_ADDR peer_addr_type; + typedef typename PEER_CONNECTOR::PEER_ADDR PEER_ADDR_TYPEDEF; + + /** + * Initialize a connector. @a flags indicates how SVC_HANDLER's + * should be initialized prior to being activated. Right now, the + * only flag that is processed is ACE_NONBLOCK, which enabled + * non-blocking I/O on the SVC_HANDLER when it is opened. + */ + ACE_Connector (ACE_Reactor *r = ACE_Reactor::instance (), + int flags = 0); + + /** + * Initialize a connector. @a flags indicates how SVC_HANDLER's + * should be initialized prior to being activated. Right now, the + * only flag that is processed is ACE_NONBLOCK, which enabled + * non-blocking I/O on the SVC_HANDLER when it is opened. + */ + virtual int open (ACE_Reactor *r = ACE_Reactor::instance (), + int flags = 0); + + /// Shutdown a connector and release resources. + virtual ~ACE_Connector (void); + + // = Connection establishment methods. + + /** + * Initiate connection of @a svc_handler to peer at @a remote_addr + * using @a synch_options. If the caller wants to designate the + * selected @a local_addr they can (and can also insist that the + * @a local_addr be reused by passing a value @a reuse_addr == + * 1). @a flags and @a perms can be used to pass any flags that are + * needed to perform specific operations such as opening a file + * within connect with certain permissions. If the connection fails + * the hook on the @a svc_handler will be called + * automatically to prevent resource leaks. + */ + virtual int connect (SVC_HANDLER *&svc_handler, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options = ACE_Synch_Options::defaults, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr + = reinterpret_cast(peer_addr_type::sap_any), + int reuse_addr = 0, + int flags = O_RDWR, + int perms = 0); + + /** + * This is a variation on the previous method. On cached + * connectors the @a svc_handler_hint variable can be used as a hint + * for future lookups. Since this variable is modified in the + * context of the internal cache its use is thread-safe. But the + * actual svc_handler for the current connection is returned in the + * second parameter @a svc_handler. If the connection fails the + * hook on the @a svc_handler will be called automatically to + * prevent resource leaks. + */ + virtual int connect (SVC_HANDLER *&svc_handler_hint, + SVC_HANDLER *&svc_handler, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options = ACE_Synch_Options::defaults, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr + = reinterpret_cast(peer_addr_type::sap_any), + int reuse_addr = 0, + int flags = O_RDWR, + int perms = 0); + + /** + * Initiate connection of @a n @a svc_handlers to peers at + * @a remote_addrs using @a synch_options. Returns -1 if failure + * occurs and 0 otherwise. If @a failed_svc_handlers is non-NULL, a + * 1 is placed in the corresponding index of @a failed_svc_handlers + * for each that failed to connect, else a 0 is + * placed in that index. + */ + virtual int connect_n (size_t n, + SVC_HANDLER *svc_handlers[], + typename PEER_CONNECTOR::PEER_ADDR remote_addrs[], + ACE_TCHAR *failed_svc_handlers = 0, + const ACE_Synch_Options &synch_options = + ACE_Synch_Options::defaults); + + /** + * Cancel the @a svc_handler that was started asynchronously. Note that + * this is the only case when the Connector does not actively close + * the @a svc_handler. It is left up to the caller of to + * decide the fate of the @a svc_handler. + */ + virtual int cancel (SVC_HANDLER *svc_handler); + + /// Close down the Connector. All pending non-blocking connects are + /// canceled and the corresponding svc_handler is closed. + virtual int close (void); + + /// Return the underlying PEER_CONNECTOR object. + virtual PEER_CONNECTOR &connector (void) const; + + /// Initialize Svc_Handler. + virtual void initialize_svc_handler (ACE_HANDLE handle, + SVC_HANDLER *svc_handler); + + /// Set Reactor. + virtual void reactor (ACE_Reactor *reactor); + + /// Get Reactor. + virtual ACE_Reactor *reactor (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Helpful typedefs. + typedef ACE_NonBlocking_Connect_Handler NBCH; + + // = The following two methods define the Connector's strategies for + // creating, connecting, and activating SVC_HANDLER's, respectively. + + /** + * Bridge method for creating a SVC_HANDLER. The default is to + * create a new SVC_HANDLER only if @a sh == 0, else @a sh is + * unchanged. However, subclasses can override this policy to + * perform SVC_HANDLER creation in any way that they like (such as + * creating subclass instances of SVC_HANDLER, using a singleton, + * dynamically linking the handler, etc.). Returns -1 if failure, + * else 0. + */ + virtual int make_svc_handler (SVC_HANDLER *&sh); + + /** + * Bridge method for connecting the @a svc_handler to the + * @a remote_addr. The default behavior delegates to the + * . + */ + virtual int connect_svc_handler (SVC_HANDLER *&svc_handler, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms); + virtual int connect_svc_handler (SVC_HANDLER *&svc_handler, + SVC_HANDLER *&sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms); + + /** + * Bridge method for activating a @a svc_handler with the appropriate + * concurrency strategy. The default behavior of this method is to + * activate the SVC_HANDLER by calling its method (which + * allows the SVC_HANDLER to define its own concurrency strategy). + * However, subclasses can override this strategy to do more + * sophisticated concurrency activations (such as creating the + * SVC_HANDLER as an "active object" via multi-threading or + * multi-processing). + */ + virtual int activate_svc_handler (SVC_HANDLER *svc_handler); + + /// Creates and registers ACE_NonBlocking_Connect_Handler. + int nonblocking_connect (SVC_HANDLER *, + const ACE_Synch_Options &); + + /// Implementation of the connect methods. + virtual int connect_i (SVC_HANDLER *&svc_handler, + SVC_HANDLER **sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + const ACE_Synch_Options &synch_options, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms); + + /// Return the handle set representing the non-blocking connects in + /// progress. + ACE_Unbounded_Set &non_blocking_handles (void); + + // = Dynamic linking hooks. + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int init (int argc, ACE_TCHAR *argv[]); + + /// Calls handle_close() to shutdown the Connector gracefully. + virtual int fini (void); + + /// Default version returns address info in @a buf. + virtual int info (ACE_TCHAR **strp, size_t length) const; + + // = Service management hooks. + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int suspend (void); + + /// Default version does no work and returns -1. Must be overloaded + /// by application developer to do anything meaningful. + virtual int resume (void); + +private: + /// This is the peer connector factory. + PEER_CONNECTOR connector_; + + /** + * Flags that indicate how SVC_HANDLER's should be initialized + * prior to being activated. Right now, the only flag that is + * processed is ACE_NONBLOCK, which enabled non-blocking I/O on + * the SVC_HANDLER when it is opened. + */ + int flags_; + + /// Pointer to the Reactor. + ACE_Reactor *reactor_; + + /// Handle set representing the non-blocking connects in progress. + ACE_Unbounded_Set non_blocking_handles_; + +}; + +/** + * @class ACE_Strategy_Connector + * + * @brief Abstract factory for creating a service handler + * (SVC_HANDLER), connecting the SVC_HANDLER, and activating the + * SVC_HANDLER. + * + * Implements a flexible and extensible set of strategies for + * actively establishing connections with clients. There are + * three main strategies: (1) creating a SVC_HANDLER, (2) + * actively initiating a new connection from the client, + * and (3) activating the SVC_HANDLER with a + * particular concurrency mechanism after the connection is established. + */ +template +class ACE_Strategy_Connector + : public ACE_Connector +{ +public: + + // Useful STL-style traits. + typedef ACE_Creation_Strategy + creation_strategy_type; + typedef ACE_Connect_Strategy + connect_strategy_type; + typedef ACE_Concurrency_Strategy + concurrency_strategy_type; + typedef ACE_Connector + base_type; + + // = Define some useful (old style) traits. + typedef ACE_Creation_Strategy + CREATION_STRATEGY; + typedef ACE_Connect_Strategy + CONNECT_STRATEGY; + typedef ACE_Concurrency_Strategy + CONCURRENCY_STRATEGY; + typedef ACE_Connector + SUPER; + + /** + * Initialize a connector. @a flags indicates how SVC_HANDLER's + * should be initialized prior to being activated. Right now, the + * only flag that is processed is ACE_NONBLOCK, which enabled + * non-blocking I/O on the SVC_HANDLER when it is opened. + */ + ACE_Strategy_Connector (ACE_Reactor *r = ACE_Reactor::instance (), + ACE_Creation_Strategy * = 0, + ACE_Connect_Strategy * = 0, + ACE_Concurrency_Strategy * = 0, + int flags = 0); + + /** + * Initialize a connector. @a flags indicates how SVC_HANDLER's + * should be initialized prior to being activated. Right now, the + * only flag that is processed is ACE_NONBLOCK, which enabled + * non-blocking I/O on the SVC_HANDLER when it is opened. + * Default strategies would be created and used. + */ + virtual int open (ACE_Reactor *r, + int flags); + + /** + * Initialize a connector. @a flags indicates how SVC_HANDLER's + * should be initialized prior to being activated. Right now, the + * only flag that is processed is ACE_NONBLOCK, which enabled + * non-blocking I/O on the SVC_HANDLER when it is opened. + */ + virtual int open (ACE_Reactor *r = ACE_Reactor::instance (), + ACE_Creation_Strategy * = 0, + ACE_Connect_Strategy * = 0, + ACE_Concurrency_Strategy * = 0, + int flags = 0); + + /// Shutdown a connector and release resources. + virtual ~ACE_Strategy_Connector (void); + + /// Close down the Connector + virtual int close (void); + + // = Strategies accessors + virtual ACE_Creation_Strategy *creation_strategy (void) const; + virtual ACE_Connect_Strategy *connect_strategy (void) const; + virtual ACE_Concurrency_Strategy *concurrency_strategy (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = The following three methods define the 's strategies + // for creating, connecting, and activating SVC_HANDLER's, + // respectively. + + /** + * Bridge method for creating a SVC_HANDLER. The strategy for + * creating a SVC_HANDLER are configured into the Connector via + * it's . The default is to create a new + * SVC_HANDLER only if @a sh == 0, else @a sh is unchanged. + * However, subclasses can override this policy to perform + * SVC_HANDLER creation in any way that they like (such as + * creating subclass instances of SVC_HANDLER, using a singleton, + * dynamically linking the handler, etc.). Returns -1 if failure, + * else 0. + */ + virtual int make_svc_handler (SVC_HANDLER *&sh); + + /** + * Bridge method for connecting the new connection into the + * SVC_HANDLER. The default behavior delegates to the + * in the . + */ + virtual int connect_svc_handler (SVC_HANDLER *&sh, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms); + + /** + * Bridge method for connecting the new connection into the + * SVC_HANDLER. The default behavior delegates to the + * in the . + * @a sh_copy is used to obtain a copy of the @a sh pointer, but that + * can be kept in the stack; the motivation is a bit too long to + * include here, but basically we want to modify @a sh safely, using + * the internal locks in the Connect_Strategy, while saving a TSS + * copy in @a sh_copy, usually located in the stack. + */ + virtual int connect_svc_handler (SVC_HANDLER *&sh, + SVC_HANDLER *&sh_copy, + const typename PEER_CONNECTOR::PEER_ADDR &remote_addr, + ACE_Time_Value *timeout, + const typename PEER_CONNECTOR::PEER_ADDR &local_addr, + int reuse_addr, + int flags, + int perms); + + /** + * Bridge method for activating a SVC_HANDLER with the appropriate + * concurrency strategy. The default behavior of this method is to + * activate the SVC_HANDLER by calling its method (which + * allows the SVC_HANDLER to define its own concurrency strategy). + * However, subclasses can override this strategy to do more + * sophisticated concurrency activations (such as creating the + * SVC_HANDLER as an "active object" via multi-threading or + * multi-processing). + */ + virtual int activate_svc_handler (SVC_HANDLER *svc_handler); + + // = Strategy objects. + + /// Creation strategy for an Connector. + CREATION_STRATEGY *creation_strategy_; + + /// True if Connector created the creation strategy and thus should + /// delete it, else false. + bool delete_creation_strategy_; + + /// Connect strategy for a Connector. + CONNECT_STRATEGY *connect_strategy_; + + /// True if Connector created the connect strategy and thus should + /// delete it, else false. + bool delete_connect_strategy_; + + /// Concurrency strategy for a Connector. + CONCURRENCY_STRATEGY *concurrency_strategy_; + + /// True if Connector created the concurrency strategy and thus should + /// delete it, else false. + bool delete_concurrency_strategy_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Connector.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Connector.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CONNECTOR_H */ diff --git a/dep/acelite/ace/Containers.cpp b/dep/acelite/ace/Containers.cpp new file mode 100644 index 000000000..3e86f3afb --- /dev/null +++ b/dep/acelite/ace/Containers.cpp @@ -0,0 +1,7 @@ +#include "ace/Containers.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Containers.inl" +#endif /* __ACE_INLINE__ */ + +ACE_ALLOC_HOOK_DEFINE (ACE_DLList_Node) diff --git a/dep/acelite/ace/Containers.h b/dep/acelite/ace/Containers.h new file mode 100644 index 000000000..4d671ca98 --- /dev/null +++ b/dep/acelite/ace/Containers.h @@ -0,0 +1,69 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Containers.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_CONTAINERS_H +#define ACE_CONTAINERS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template class ACE_Double_Linked_List; +template class ACE_Double_Linked_List_Iterator_Base; +template class ACE_Double_Linked_List_Iterator; +template class ACE_Double_Linked_List_Reverse_Iterator; + +/** + * @class ACE_DLList_Node + * + * @brief Base implementation of element in a DL list. Needed for + * ACE_Double_Linked_List. + */ +class ACE_Export ACE_DLList_Node +{ +public: + friend class ACE_Double_Linked_List; + friend class ACE_Double_Linked_List_Iterator_Base; + friend class ACE_Double_Linked_List_Iterator; + friend class ACE_Double_Linked_List_Reverse_Iterator; + + ACE_DLList_Node (void *i, + ACE_DLList_Node *n = 0, + ACE_DLList_Node *p = 0); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + void *item_; + + ACE_DLList_Node *next_; + ACE_DLList_Node *prev_; + +protected: + ACE_DLList_Node (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Containers.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Containers_T.h" + +#include /**/ "ace/post.h" + +#endif /* ACE_CONTAINERS_H */ diff --git a/dep/acelite/ace/Containers.inl b/dep/acelite/ace/Containers.inl new file mode 100644 index 000000000..cd7507d40 --- /dev/null +++ b/dep/acelite/ace/Containers.inl @@ -0,0 +1,22 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_DLList_Node::ACE_DLList_Node (void) + : item_ (0), + next_ (0), + prev_ (0) +{ +} + +ACE_INLINE +ACE_DLList_Node::ACE_DLList_Node (void *i, + ACE_DLList_Node *n, + ACE_DLList_Node *p) + : item_ (i), + next_ (n), + prev_ (p) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Containers_T.cpp b/dep/acelite/ace/Containers_T.cpp new file mode 100644 index 000000000..4fa39569b --- /dev/null +++ b/dep/acelite/ace/Containers_T.cpp @@ -0,0 +1,1898 @@ +#ifndef ACE_CONTAINERS_T_CPP +#define ACE_CONTAINERS_T_CPP + +#include "ace/Log_Category.h" +#include "ace/Malloc_Base.h" +#include "ace/OS_Memory.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Containers.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Containers_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Bounded_Stack) + +template void +ACE_Bounded_Stack::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Bounded_Stack::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Bounded_Stack::ACE_Bounded_Stack (size_t size) + : size_ (size), + top_ (0) +{ + ACE_NEW (this->stack_, + T[size]); + ACE_TRACE ("ACE_Bounded_Stack::ACE_Bounded_Stack"); +} + +template +ACE_Bounded_Stack::ACE_Bounded_Stack (const ACE_Bounded_Stack &s) + : size_ (s.size_), + top_ (s.top_) +{ + ACE_NEW (this->stack_, + T[s.size_]); + + ACE_TRACE ("ACE_Bounded_Stack::ACE_Bounded_Stack"); + + for (size_t i = 0; i < this->top_; i++) + this->stack_[i] = s.stack_[i]; +} + +template void +ACE_Bounded_Stack::operator= (const ACE_Bounded_Stack &s) +{ + ACE_TRACE ("ACE_Bounded_Stack::operator="); + + if (&s != this) + { + if (this->size_ < s.size_) + { + delete [] this->stack_; + ACE_NEW (this->stack_, + T[s.size_]); + this->size_ = s.size_; + } + this->top_ = s.top_; + + for (size_t i = 0; i < this->top_; i++) + this->stack_[i] = s.stack_[i]; + } +} + +template +ACE_Bounded_Stack::~ACE_Bounded_Stack (void) +{ + ACE_TRACE ("ACE_Bounded_Stack::~ACE_Bounded_Stack"); + delete [] this->stack_; +} + +// ---------------------------------------- + +ACE_ALLOC_HOOK_DEFINE_Tcs(ACE_Fixed_Stack) + +template void +ACE_Fixed_Stack::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Fixed_Stack::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Fixed_Stack::ACE_Fixed_Stack (void) + : size_ (ACE_SIZE), + top_ (0) +{ + ACE_TRACE ("ACE_Fixed_Stack::ACE_Fixed_Stack"); +} + +template +ACE_Fixed_Stack::ACE_Fixed_Stack (const ACE_Fixed_Stack &s) + : size_ (s.size_), + top_ (s.top_) +{ + ACE_TRACE ("ACE_Fixed_Stack::ACE_Fixed_Stack"); + for (size_t i = 0; i < this->top_; i++) + this->stack_[i] = s.stack_[i]; +} + +template void +ACE_Fixed_Stack::operator= (const ACE_Fixed_Stack &s) +{ + ACE_TRACE ("ACE_Fixed_Stack::operator="); + + if (&s != this) + { + this->top_ = s.top_; + + for (size_t i = 0; i < this->top_; i++) + this->stack_[i] = s.stack_[i]; + } +} + +template +ACE_Fixed_Stack::~ACE_Fixed_Stack (void) +{ + ACE_TRACE ("ACE_Fixed_Stack::~ACE_Fixed_Stack"); +} + +//---------------------------------------- + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Unbounded_Stack) + +template void +ACE_Unbounded_Stack::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // ACE_TRACE ("ACE_Unbounded_Stack::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Unbounded_Stack::ACE_Unbounded_Stack (ACE_Allocator *alloc) + : head_ (0), + cur_size_ (0), + allocator_ (alloc) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::ACE_Unbounded_Stack"); + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + ACE_NEW_MALLOC (this->head_, + (ACE_Node *) this->allocator_->malloc (sizeof (ACE_Node)), + ACE_Node); + this->head_->next_ = this->head_; +} + +template void +ACE_Unbounded_Stack::delete_all_nodes (void) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::delete_all_nodes"); + + while (this->is_empty () == 0) + { + ACE_Node *temp = this->head_->next_; + this->head_->next_ = temp->next_; + ACE_DES_FREE_TEMPLATE (temp, this->allocator_->free, + ACE_Node, ); + } + + this->cur_size_ = 0; + + ACE_ASSERT (this->head_ == this->head_->next_ + && this->is_empty ()); +} + +template void +ACE_Unbounded_Stack::copy_all_nodes (const ACE_Unbounded_Stack &s) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::copy_all_nodes"); + + ACE_ASSERT (this->head_ == this->head_->next_); + + ACE_Node *temp = this->head_; + + for (ACE_Node *s_temp = s.head_->next_; + s_temp != s.head_; + s_temp = s_temp->next_) + { + ACE_Node *nptr = temp->next_; + ACE_NEW_MALLOC (temp->next_, + (ACE_Node *) this->allocator_->malloc (sizeof (ACE_Node)), + ACE_Node (s_temp->item_, nptr)); + temp = temp->next_; + } + this->cur_size_ = s.cur_size_; +} + +template +ACE_Unbounded_Stack::ACE_Unbounded_Stack (const ACE_Unbounded_Stack &s) + : head_ (0), + cur_size_ (0), + allocator_ (s.allocator_) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + ACE_NEW_MALLOC (this->head_, + (ACE_Node *) this->allocator_->malloc (sizeof (ACE_Node)), + ACE_Node); + this->head_->next_ = this->head_; + + // ACE_TRACE ("ACE_Unbounded_Stack::ACE_Unbounded_Stack"); + this->copy_all_nodes (s); +} + +template void +ACE_Unbounded_Stack::operator= (const ACE_Unbounded_Stack &s) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::operator="); + + if (this != &s) + { + this->delete_all_nodes (); + this->copy_all_nodes (s); + } +} + +template +ACE_Unbounded_Stack::~ACE_Unbounded_Stack (void) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::~ACE_Unbounded_Stack"); + + this->delete_all_nodes (); + ACE_DES_FREE_TEMPLATE (head_, + this->allocator_->free, + ACE_Node, + ); +} + +template int +ACE_Unbounded_Stack::push (const T &new_item) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::push"); + + ACE_Node *temp = 0; + + ACE_NEW_MALLOC_RETURN (temp, + static_cast *> (this->allocator_->malloc (sizeof (ACE_Node))), + ACE_Node (new_item, this->head_->next_), + -1); + this->head_->next_ = temp; + ++this->cur_size_; + return 0; +} + +template int +ACE_Unbounded_Stack::pop (T &item) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::pop"); + + if (this->is_empty ()) + return -1; + else + { + ACE_Node *temp = this->head_->next_; + item = temp->item_; + this->head_->next_ = temp->next_; + + ACE_DES_FREE_TEMPLATE (temp, + this->allocator_->free, + ACE_Node, + ); + --this->cur_size_; + return 0; + } +} + +template int +ACE_Unbounded_Stack::find (const T &item) const +{ + // ACE_TRACE ("ACE_Unbounded_Stack::find"); + // Set into the dummy node. + this->head_->item_ = item; + + ACE_Node *temp = this->head_->next_; + + // Keep looping until we find the item. + while (!(temp->item_ == item)) + temp = temp->next_; + + // If we found the dummy node then it's not really there, otherwise, + // it is there. + return temp == this->head_ ? -1 : 0; +} + +template int +ACE_Unbounded_Stack::insert (const T &item) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::insert"); + + if (this->find (item) == 0) + return 1; + else + return this->push (item); +} + +template int +ACE_Unbounded_Stack::remove (const T &item) +{ + // ACE_TRACE ("ACE_Unbounded_Stack::remove"); + + // Insert the item to be founded into the dummy node. + this->head_->item_ = item; + + ACE_Node *curr = this->head_; + + while (!(curr->next_->item_ == item)) + curr = curr->next_; + + if (curr->next_ == this->head_) + return -1; // Item was not found. + else + { + ACE_Node *temp = curr->next_; + // Skip over the node that we're deleting. + curr->next_ = temp->next_; + --this->cur_size_; + ACE_DES_FREE_TEMPLATE (temp, + this->allocator_->free, + ACE_Node, + ); + return 0; + } +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Double_Linked_List_Iterator_Base) + +template +ACE_Double_Linked_List_Iterator_Base::ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List &dll) + : current_ (0), dllist_ (&dll) +{ + // Do nothing +} + +template +ACE_Double_Linked_List_Iterator_Base::ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List_Iterator_Base &iter) + : current_ (iter.current_), + dllist_ (iter.dllist_) +{ + // Do nothing +} + + +template T * +ACE_Double_Linked_List_Iterator_Base::next (void) const +{ + return this->not_done (); +} + +template int +ACE_Double_Linked_List_Iterator_Base::next (T *&ptr) const +{ + ptr = this->not_done (); + return ptr ? 1 : 0; +} + + +template int +ACE_Double_Linked_List_Iterator_Base::done (void) const +{ + return this->not_done () ? 0 : 1; +} + +template T & +ACE_Double_Linked_List_Iterator_Base::operator* (void) const +{ + return *(this->not_done ()); +} + +// @@ Is this a valid retasking? Make sure to check with Purify and +// whatnot that we're not leaking memory or doing any other screwing things. +template void +ACE_Double_Linked_List_Iterator_Base::reset (ACE_Double_Linked_List &dll) +{ + current_ = 0; + dllist_ = &dll; +} + + template int +ACE_Double_Linked_List_Iterator_Base::go_head (void) +{ + this->current_ = static_cast (dllist_->head_->next_); + return this->current_ ? 1 : 0; +} + +template int +ACE_Double_Linked_List_Iterator_Base::go_tail (void) +{ + this->current_ = static_cast (dllist_->head_->prev_); + return this->current_ ? 1 : 0; +} + +template T * +ACE_Double_Linked_List_Iterator_Base::not_done (void) const +{ + if (this->current_ != this->dllist_->head_) + return this->current_; + else + return 0; +} + +template T * +ACE_Double_Linked_List_Iterator_Base::do_advance (void) +{ + if (this->not_done ()) + { + this->current_ = static_cast (this->current_->next_); + return this->not_done (); + } + else + return 0; +} + +template T * +ACE_Double_Linked_List_Iterator_Base::do_retreat (void) +{ + if (this->not_done ()) + { + this->current_ = static_cast (this->current_->prev_); + return this->not_done (); + } + else + return 0; +} + +template void +ACE_Double_Linked_List_Iterator_Base::dump_i (void) const +{ + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("current_ = %x"), this->current_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Double_Linked_List_Iterator) + +template +ACE_Double_Linked_List_Iterator::ACE_Double_Linked_List_Iterator (const ACE_Double_Linked_List &dll) + : ACE_Double_Linked_List_Iterator_Base (dll) +{ + this->current_ = static_cast (dll.head_->next_); + // Advance current_ out of the null area and onto the first item in + // the list +} + +template void +ACE_Double_Linked_List_Iterator::reset (ACE_Double_Linked_List &dll) +{ + this->ACE_Double_Linked_List_Iterator_Base ::reset (dll); + this->current_ = static_cast (dll.head_->next_); + // Advance current_ out of the null area and onto the first item in + // the list +} + +template int +ACE_Double_Linked_List_Iterator::first (void) +{ + return this->go_head (); +} + +template int +ACE_Double_Linked_List_Iterator::advance (void) +{ + return this->do_advance () ? 1 : 0; +} + +template T* +ACE_Double_Linked_List_Iterator::advance_and_remove (bool dont_remove) +{ + T* item = 0; + if (dont_remove) + this->do_advance (); + else + { + item = this->next (); + this->do_advance (); + // It seems dangerous to remove nodes in an iterator, but so it goes... + ACE_Double_Linked_List *dllist = + const_cast *> (this->dllist_); + dllist->remove (item); + } + return item; +} + +template void +ACE_Double_Linked_List_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->dump_i (); +#endif /* ACE_HAS_DUMP */ +} + +// Prefix advance. + +template +ACE_Double_Linked_List_Iterator & +ACE_Double_Linked_List_Iterator::operator++ (void) +{ + this->do_advance (); + return *this; +} + + +// Postfix advance. + +template +ACE_Double_Linked_List_Iterator +ACE_Double_Linked_List_Iterator::operator++ (int) +{ + ACE_Double_Linked_List_Iterator retv (*this); + this->do_advance (); + return retv; +} + + +// Prefix reverse. + +template +ACE_Double_Linked_List_Iterator & +ACE_Double_Linked_List_Iterator::operator-- (void) +{ + this->do_retreat (); + return *this; +} + + +// Postfix reverse. + +template +ACE_Double_Linked_List_Iterator +ACE_Double_Linked_List_Iterator::operator-- (int) +{ + ACE_Double_Linked_List_Iterator retv (*this); + this->do_retreat (); + return retv; +} + + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Double_Linked_List_Reverse_Iterator) + + template +ACE_Double_Linked_List_Reverse_Iterator::ACE_Double_Linked_List_Reverse_Iterator (ACE_Double_Linked_List &dll) + : ACE_Double_Linked_List_Iterator_Base (dll) +{ + this->current_ = static_cast (dll.head_->prev_); + // Advance current_ out of the null area and onto the last item in + // the list +} + +template void +ACE_Double_Linked_List_Reverse_Iterator::reset (ACE_Double_Linked_List &dll) +{ + this->ACE_Double_Linked_List_Iterator_Base ::reset (dll); + this->current_ = static_cast (dll.head_->prev_); + // Advance current_ out of the null area and onto the last item in + // the list +} + +template int +ACE_Double_Linked_List_Reverse_Iterator::first (void) +{ + return this->go_tail (); +} + +template int +ACE_Double_Linked_List_Reverse_Iterator::advance (void) +{ + return this->do_retreat () ? 1 : 0; +} + +template T* +ACE_Double_Linked_List_Reverse_Iterator::advance_and_remove (bool dont_remove) +{ + T* item = 0; + if (dont_remove) + { + this->do_retreat (); + } + else + { + item = this->next (); + this->do_retreat (); + // It seems dangerous to remove nodes in an iterator, but so it goes... + ACE_Double_Linked_List *dllist = + const_cast *> (this->dllist_); + dllist->remove (item); + } + return item; +} + +template void +ACE_Double_Linked_List_Reverse_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->dump_i (); +#endif /* ACE_HAS_DUMP */ +} + +// Prefix advance. + +template +ACE_Double_Linked_List_Reverse_Iterator & +ACE_Double_Linked_List_Reverse_Iterator::operator++ (void) +{ + this->do_retreat (); + return *this; +} + + +// Postfix advance. + +template +ACE_Double_Linked_List_Reverse_Iterator +ACE_Double_Linked_List_Reverse_Iterator::operator++ (int) +{ + ACE_Double_Linked_List_Reverse_Iterator retv (*this); + this->do_retreat (); + return retv; +} + + +// Prefix reverse. + +template +ACE_Double_Linked_List_Reverse_Iterator & +ACE_Double_Linked_List_Reverse_Iterator::operator-- (void) +{ + this->do_advance (); + return *this; +} + + +// Postfix reverse. + +template +ACE_Double_Linked_List_Reverse_Iterator +ACE_Double_Linked_List_Reverse_Iterator::operator-- (int) +{ + ACE_Double_Linked_List_Reverse_Iterator retv (*this); + this->do_advance (); + return retv; +} + + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Double_Linked_List) + + template +ACE_Double_Linked_List:: ACE_Double_Linked_List (ACE_Allocator *alloc) + : size_ (0), allocator_ (alloc) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + ACE_NEW_MALLOC (this->head_, + (T *) this->allocator_->malloc (sizeof (T)), + T); + this->init_head (); +} + +template +ACE_Double_Linked_List::ACE_Double_Linked_List (const ACE_Double_Linked_List &cx) + : allocator_ (cx.allocator_) +{ + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + ACE_NEW_MALLOC (this->head_, + (T *) this->allocator_->malloc (sizeof (T)), + T); + this->init_head (); + this->copy_nodes (cx); + this->size_ = cx.size_; +} + +template void +ACE_Double_Linked_List::operator= (const ACE_Double_Linked_List &cx) +{ + if (this != &cx) + { + this->delete_nodes (); + this->copy_nodes (cx); + } +} + +template +ACE_Double_Linked_List::~ACE_Double_Linked_List (void) +{ + this->delete_nodes (); + + ACE_DES_FREE (head_, + this->allocator_->free, + T); + + this->head_ = 0; +} + +template int +ACE_Double_Linked_List::is_empty (void) const +{ + return this->size () ? 0 : 1; +} + +template int +ACE_Double_Linked_List::is_full (void) const +{ + return 0; // We have no bound. +} + +template T * +ACE_Double_Linked_List::insert_tail (T *new_item) +{ + // Insert it before , i.e., at tail. + this->insert_element (new_item, 1); + return new_item; +} + +template T * +ACE_Double_Linked_List::insert_head (T *new_item) +{ + this->insert_element (new_item); // Insert it after , i.e., at head. + return new_item; +} + +template T * +ACE_Double_Linked_List::delete_head (void) +{ + if (this->is_empty ()) + return 0; + + T *temp = static_cast (this->head_->next_); + // Detach it from the list. + this->remove_element (temp); + return temp; +} + +template T * +ACE_Double_Linked_List::delete_tail (void) +{ + if (this->is_empty ()) + return 0; + + T *temp = static_cast (this->head_->prev_); + // Detach it from the list. + this->remove_element (temp); + return temp; +} + +template void +ACE_Double_Linked_List::reset (void) +{ + this->delete_nodes (); +} + +template int +ACE_Double_Linked_List::get (T *&item, size_t slot) +{ + ACE_Double_Linked_List_Iterator iter (*this); + + for (size_t i = 0; + i < slot && !iter.done (); + i++) + iter.advance (); + + item = iter.next (); + return item ? 0 : -1; +} + +template size_t +ACE_Double_Linked_List::size (void) const +{ + return this->size_; +} + +template void +ACE_Double_Linked_List::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // Dump the state of an object. +#endif /* ACE_HAS_DUMP */ +} + +template int +ACE_Double_Linked_List::remove (T *n) +{ + return this->remove_element (n); +} + +template void +ACE_Double_Linked_List::delete_nodes (void) +{ + while (! this->is_empty ()) + { + T * temp = static_cast (this->head_->next_); + this->remove_element (temp); + ACE_DES_FREE (temp, + this->allocator_->free, + T); + } +} + +template void +ACE_Double_Linked_List::copy_nodes (const ACE_Double_Linked_List &c) +{ + for (ACE_Double_Linked_List_Iterator iter (c); + !iter.done (); + iter.advance ()) + { + T* temp = 0; + ACE_NEW_MALLOC (temp, + (T *)this->allocator_->malloc (sizeof (T)), + T (*iter.next ())); + this->insert_tail (temp); + } +} + +template void +ACE_Double_Linked_List::init_head (void) +{ + this->head_->next_ = this->head_; + this->head_->prev_ = this->head_; +} + +template int +ACE_Double_Linked_List::insert_element (T *new_item, + int before, + T *old_item) +{ + if (old_item == 0) + old_item = this->head_; + + if (before) + old_item = static_cast (old_item->prev_); + + new_item->next_ = old_item->next_; + new_item->next_->prev_ = new_item; + new_item->prev_ = old_item; + old_item->next_ = new_item; + ++this->size_; + return 0; // Well, what will cause errors here? +} + +template int +ACE_Double_Linked_List::remove_element (T *item) +{ + // Notice that you have to ensure that item is an element of this + // list. We can't do much checking here. + + if (item == this->head_ || item->next_ == 0 + || item->prev_ == 0 || this->size () == 0) // Can't remove head + return -1; + + item->prev_->next_ = item->next_; + item->next_->prev_ = item->prev_; + item->next_ = item->prev_ = 0; // reset pointers to prevent double removal. + --this->size_; + return 0; +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tcs(ACE_Fixed_Set) + +template size_t +ACE_Fixed_Set::size (void) const +{ + ACE_TRACE ("ACE_Fixed_Set::size"); + return this->cur_size_; +} + +template void +ACE_Fixed_Set::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Fixed_Set::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Fixed_Set::~ACE_Fixed_Set (void) +{ + ACE_TRACE ("ACE_Fixed_Set::~ACE_Fixed_Set"); + this->cur_size_ = 0; +} + +template +ACE_Fixed_Set::ACE_Fixed_Set (const ACE_Fixed_Set &fs) + : cur_size_ (fs.cur_size_) +{ + ACE_TRACE ("ACE_Fixed_Set::ACE_Fixed_Set"); + + for (size_t i = 0, j = 0; i < fs.max_size_ && j < this->cur_size_; ++i) + if (fs.search_structure_[i].is_free_ == 0) + this->search_structure_[j++] = fs.search_structure_[i]; +} + +template void +ACE_Fixed_Set::operator= (const ACE_Fixed_Set &fs) +{ + ACE_TRACE ("ACE_Fixed_Set::operator="); + + if (this != &fs) + { + this->cur_size_ = fs.cur_size_; + + for (size_t i = 0, j = 0; i < fs.max_size_ && j < this->cur_size_; ++i) + if (fs.search_structure_[i].is_free_ == 0) + this->search_structure_[j++] = fs.search_structure_[i]; + } +} + +template +ACE_Fixed_Set::ACE_Fixed_Set (void) + : cur_size_ (0), + max_size_ (ACE_SIZE) +{ + ACE_TRACE ("ACE_Fixed_Set::ACE_Fixed_Set"); + for (size_t i = 0; i < this->max_size_; i++) + this->search_structure_[i].is_free_ = 1; +} + +template int +ACE_Fixed_Set::find (const T &item) const +{ + ACE_TRACE ("ACE_Fixed_Set::find"); + + for (size_t i = 0, j = 0; i < this->max_size_ && j < this->cur_size_; ++i) + if (this->search_structure_[i].is_free_ == 0) + { + if (this->search_structure_[i].item_ == item) + return 0; + ++j; + } + + return -1; +} + +template int +ACE_Fixed_Set::insert (const T &item) +{ + ACE_TRACE ("ACE_Fixed_Set::insert"); + ssize_t first_free = -1; // Keep track of first free slot. + size_t i; + + for (i = 0; + i < this->max_size_ && first_free == -1; + ++i) + + // First, make sure we don't allow duplicates. + + if (this->search_structure_[i].is_free_ == 0) + { + if (this->search_structure_[i].item_ == item) + return 1; + } + else + first_free = static_cast (i); + + // If we found a free spot let's reuse it. + + if (first_free > -1) + { + this->search_structure_[first_free].item_ = item; + this->search_structure_[first_free].is_free_ = 0; + this->cur_size_++; + return 0; + } + else /* No more room! */ + { + errno = ENOMEM; + return -1; + } +} + +template int +ACE_Fixed_Set::remove (const T &item) +{ + ACE_TRACE ("ACE_Fixed_Set::remove"); + + for (size_t i = 0, j = 0; + i < this->max_size_ && j < this->cur_size_; + ++i) + if (this->search_structure_[i].is_free_ == 0) + { + if (this->search_structure_[i].item_ == item) + { + // Mark this entry as being free. + this->search_structure_[i].is_free_ = 1; + + --this->cur_size_; + return 0; + } + else + ++j; + } + + return -1; +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tcs(ACE_Fixed_Set_Iterator_Base) + +template void +ACE_Fixed_Set_Iterator_Base::dump_i (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::dump_i"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Fixed_Set_Iterator_Base::ACE_Fixed_Set_Iterator_Base (ACE_Fixed_Set &s) + : s_ (s), + next_ (-1), + iterated_items_ (0) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::ACE_Fixed_Set_Iterator_Base"); + this->advance (); +} + +template int +ACE_Fixed_Set_Iterator_Base::advance (void) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::advance"); + + if (this->iterated_items_ < this->s_.cur_size_) + { + for (++this->next_; + static_cast (this->next_) < this->s_.max_size_; + ++this->next_) + if (this->s_.search_structure_[this->next_].is_free_ == 0) + { + ++this->iterated_items_; + return 1; + } + } + else + ++this->next_; + + return 0; +} + +template int +ACE_Fixed_Set_Iterator_Base::first (void) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::first"); + + next_ = -1; + iterated_items_ = 0; + return this->advance (); +} + +template int +ACE_Fixed_Set_Iterator_Base::done (void) const +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::done"); + + return ! (this->iterated_items_ < this->s_.cur_size_); +} + +template int +ACE_Fixed_Set_Iterator_Base::next_i (T *&item) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator_Base::next_i"); + + if (static_cast (this->next_) < this->s_.max_size_) + do + { + if (this->s_.search_structure_[this->next_].is_free_ == 0) + { + item = &this->s_.search_structure_[this->next_].item_; + this->advance (); + return 1; + } + } + while (this->advance () == 1); + + return 0; +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tcs(ACE_Fixed_Set_Iterator) + +template void +ACE_Fixed_Set_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->dump_i (); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Fixed_Set_Iterator::ACE_Fixed_Set_Iterator (ACE_Fixed_Set &s) + : ACE_Fixed_Set_Iterator_Base (s) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator::ACE_Fixed_Set_Iterator"); +} + +template int +ACE_Fixed_Set_Iterator::next (T *&item) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator::next"); + return this->next_i (item); +} + +template int +ACE_Fixed_Set_Iterator::remove (T *&item) +{ + ACE_TRACE ("ACE_Fixed_Set_Iterator::remove"); + + if (this->s_.search_structure_[this->next_].is_free_ == 0) + { + item = &this->s_.search_structure_[this->next_].item_; + this->s_.remove (*item); + --(this->iterated_items_); + return 1; + } + + return 0; +} + +template T& +ACE_Fixed_Set_Iterator::operator* (void) +{ + T *retv = 0; + + if (this->s_.search_structure_[this->next_].is_free_ == 0) + retv = &this->s_.search_structure_[this->next_].item_; + + ACE_ASSERT (retv != 0); + + return *retv; +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tcs(ACE_Fixed_Set_Const_Iterator) + +template void +ACE_Fixed_Set_Const_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + this->dump_i (); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Fixed_Set_Const_Iterator::ACE_Fixed_Set_Const_Iterator (const ACE_Fixed_Set &s) + : ACE_Fixed_Set_Iterator_Base (s) +{ + ACE_TRACE ("ACE_Fixed_Set_Const_Iterator::ACE_Fixed_Set_Const_Iterator"); +} + +template int +ACE_Fixed_Set_Const_Iterator::next (const T *&item) +{ + ACE_TRACE ("ACE_Fixed_Set_Const_Iterator::next"); + + return this->next_i (item); +} + +template const T& +ACE_Fixed_Set_Const_Iterator::operator* (void) const +{ + const T *retv = 0; + + if (this->s_.search_structure_[this->next_].is_free_ == 0) + retv = &this->s_.search_structure_[this->next_].item_; + + ACE_ASSERT (retv != 0); + + return *retv; +} + +//-------------------------------------------------- +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Bounded_Set) + +template void +ACE_Bounded_Set::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Bounded_Set::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Bounded_Set::~ACE_Bounded_Set (void) +{ + ACE_TRACE ("ACE_Bounded_Set::~ACE_Bounded_Set"); + delete [] this->search_structure_; +} + +template +ACE_Bounded_Set::ACE_Bounded_Set (void) + : cur_size_ (0), + max_size_ (static_cast (ACE_Bounded_Set::DEFAULT_SIZE)) +{ + ACE_TRACE ("ACE_Bounded_Set::ACE_Bounded_Set"); + + ACE_NEW (this->search_structure_, + typename ACE_Bounded_Set::Search_Structure[this->max_size_]); + + for (size_t i = 0; i < this->max_size_; ++i) + this->search_structure_[i].is_free_ = 1; +} + +template size_t +ACE_Bounded_Set::size (void) const +{ + ACE_TRACE ("ACE_Bounded_Set::size"); + return this->cur_size_; +} + +template +ACE_Bounded_Set::ACE_Bounded_Set (const ACE_Bounded_Set &bs) + : cur_size_ (bs.cur_size_), + max_size_ (bs.max_size_) +{ + ACE_TRACE ("ACE_Bounded_Set::ACE_Bounded_Set"); + + ACE_NEW (this->search_structure_, + typename ACE_Bounded_Set::Search_Structure[this->max_size_]); + + for (size_t i = 0; i < this->cur_size_; i++) + this->search_structure_[i] = bs.search_structure_[i]; +} + +template void +ACE_Bounded_Set::operator= (const ACE_Bounded_Set &bs) +{ + ACE_TRACE ("ACE_Bounded_Set::operator="); + + if (this != &bs) + { + if (this->max_size_ < bs.cur_size_) + { + delete [] this->search_structure_; + ACE_NEW (this->search_structure_, + typename ACE_Bounded_Set::Search_Structure[bs.cur_size_]); + this->max_size_ = bs.cur_size_; + } + + this->cur_size_ = bs.cur_size_; + + for (size_t i = 0; i < this->cur_size_; i++) + this->search_structure_[i] = bs.search_structure_[i]; + } +} + +template +ACE_Bounded_Set::ACE_Bounded_Set (size_t size) + : cur_size_ (0), + max_size_ (size) +{ + ACE_TRACE ("ACE_Bounded_Set::ACE_Bounded_Set"); + ACE_NEW (this->search_structure_, + typename ACE_Bounded_Set::Search_Structure[size]); + + for (size_t i = 0; i < this->max_size_; i++) + this->search_structure_[i].is_free_ = 1; +} + +template int +ACE_Bounded_Set::find (const T &item) const +{ + ACE_TRACE ("ACE_Bounded_Set::find"); + + for (size_t i = 0; i < this->cur_size_; i++) + if (this->search_structure_[i].item_ == item + && this->search_structure_[i].is_free_ == 0) + return 0; + + return -1; +} + +template int +ACE_Bounded_Set::insert (const T &item) +{ + ACE_TRACE ("ACE_Bounded_Set::insert"); + int first_free = -1; // Keep track of first free slot. + size_t i; + + for (i = 0; i < this->cur_size_; i++) + // First, make sure we don't allow duplicates. + + if (this->search_structure_[i].item_ == item + && this->search_structure_[i].is_free_ == 0) + return 1; + else if (this->search_structure_[i].is_free_ && first_free == -1) + first_free = static_cast (i); + + if (first_free > -1) // If we found a free spot let's reuse it. + { + this->search_structure_[first_free].item_ = item; + this->search_structure_[first_free].is_free_ = 0; + return 0; + } + else if (i < this->max_size_) // Insert at the end of the active portion. + { + this->search_structure_[i].item_ = item; + this->search_structure_[i].is_free_ = 0; + this->cur_size_++; + return 0; + } + else /* No more room! */ + { + errno = ENOMEM; + return -1; + } +} + +template int +ACE_Bounded_Set::remove (const T &item) +{ + ACE_TRACE ("ACE_Bounded_Set::remove"); + for (size_t i = 0; i < this->cur_size_; i++) + if (this->search_structure_[i].item_ == item) + { + // Mark this entry as being free. + this->search_structure_[i].is_free_ = 1; + + // If we just unbound the highest entry, then we need to + // figure out where the next highest active entry is. + if (i + 1 == this->cur_size_) + { + while (i > 0 && this->search_structure_[--i].is_free_) + continue; + + if (i == 0 && this->search_structure_[i].is_free_) + this->cur_size_ = 0; + else + this->cur_size_ = i + 1; + } + return 0; + } + + return -1; +} + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Bounded_Set_Iterator) + + template void +ACE_Bounded_Set_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Bounded_Set_Iterator::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Bounded_Set_Iterator::ACE_Bounded_Set_Iterator (ACE_Bounded_Set &s) + : s_ (s), + next_ (-1) +{ + ACE_TRACE ("ACE_Bounded_Set_Iterator::ACE_Bounded_Set_Iterator"); + this->advance (); +} + +template int +ACE_Bounded_Set_Iterator::advance (void) +{ + ACE_TRACE ("ACE_Bounded_Set_Iterator::advance"); + + for (++this->next_; + static_cast (this->next_) < this->s_.cur_size_ + && this->s_.search_structure_[this->next_].is_free_; + ++this->next_) + continue; + + return static_cast (this->next_) < this->s_.cur_size_; +} + +template int +ACE_Bounded_Set_Iterator::first (void) +{ + ACE_TRACE ("ACE_Bounded_Set_Iterator::first"); + + next_ = -1; + return this->advance (); +} + +template int +ACE_Bounded_Set_Iterator::done (void) const +{ + ACE_TRACE ("ACE_Bounded_Set_Iterator::done"); + + return static_cast (this->next_) >= + this->s_.cur_size_; +} + +template int +ACE_Bounded_Set_Iterator::next (T *&item) +{ + ACE_TRACE ("ACE_Bounded_Set_Iterator::next"); + if (static_cast (this->next_) < this->s_.cur_size_) + { + item = &this->s_.search_structure_[this->next_].item_; + return 1; + } + else + return 0; +} + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_DNode) + + template +ACE_DNode::ACE_DNode (const T &i, ACE_DNode *n, ACE_DNode *p) + : next_ (n), prev_ (p), item_ (i) +{ +} + +template +ACE_DNode::~ACE_DNode (void) +{ +} + +// **************************************************************** + +template void +ACE_Unbounded_Stack_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // ACE_TRACE ("ACE_Unbounded_Stack_Iterator::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Unbounded_Stack_Iterator::ACE_Unbounded_Stack_Iterator (ACE_Unbounded_Stack &q) + : current_ (q.head_->next_), + stack_ (q) +{ + // ACE_TRACE ("ACE_Unbounded_Stack_Iterator::ACE_Unbounded_Stack_Iterator"); +} + +template int +ACE_Unbounded_Stack_Iterator::advance (void) +{ + // ACE_TRACE ("ACE_Unbounded_Stack_Iterator::advance"); + this->current_ = this->current_->next_; + return this->current_ != this->stack_.head_; +} + +template int +ACE_Unbounded_Stack_Iterator::first (void) +{ + // ACE_TRACE ("ACE_Unbounded_Stack_Iterator::first"); + this->current_ = this->stack_.head_->next_; + return this->current_ != this->stack_.head_; +} + +template int +ACE_Unbounded_Stack_Iterator::done (void) const +{ + ACE_TRACE ("ACE_Unbounded_Stack_Iterator::done"); + + return this->current_ == this->stack_.head_; +} + +template int +ACE_Unbounded_Stack_Iterator::next (T *&item) +{ + // ACE_TRACE ("ACE_Unbounded_Stack_Iterator::next"); + if (this->current_ == this->stack_.head_) + return 0; + else + { + item = &this->current_->item_; + return 1; + } +} + + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Ordered_MultiSet) + + template +ACE_Ordered_MultiSet::ACE_Ordered_MultiSet (ACE_Allocator *alloc) + : head_ (0) + , tail_ (0) + , cur_size_ (0) + , allocator_ (alloc) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::ACE_Ordered_MultiSet"); + + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); +} + +template +ACE_Ordered_MultiSet::ACE_Ordered_MultiSet (const ACE_Ordered_MultiSet &us) + : head_ (0) + , tail_ (0) + , cur_size_ (0) + , allocator_ (us.allocator_) +{ + ACE_TRACE ("ACE_Ordered_MultiSet::ACE_Ordered_MultiSet"); + + if (this->allocator_ == 0) + this->allocator_ = ACE_Allocator::instance (); + + this->copy_nodes (us); +} + +template +ACE_Ordered_MultiSet::~ACE_Ordered_MultiSet (void) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::~ACE_Ordered_MultiSet"); + + this->delete_nodes (); +} + + +template void +ACE_Ordered_MultiSet::operator= (const ACE_Ordered_MultiSet &us) +{ + ACE_TRACE ("ACE_Ordered_MultiSet::operator="); + + if (this != &us) + { + this->delete_nodes (); + this->copy_nodes (us); + } +} + + +template int +ACE_Ordered_MultiSet::insert (const T &item) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::insert"); + + return this->insert_from (item, this->head_, 0); +} + +template int +ACE_Ordered_MultiSet::insert (const T &new_item, + ITERATOR &iter) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::insert using iterator"); + + return this->insert_from (new_item, iter.current_, &iter.current_); +} + +template int +ACE_Ordered_MultiSet::remove (const T &item) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::remove"); + + ACE_DNode *node = 0; + + int result = locate (item, 0, node); + + // if we found the node, remove from list and free it + if (node && (result == 0)) + { + if (node->prev_) + node->prev_->next_ = node->next_; + else + head_ = node->next_; + + if (node->next_) + node->next_->prev_ = node->prev_; + else + tail_ = node->prev_; + + --this->cur_size_; + + ACE_DES_FREE_TEMPLATE (node, + this->allocator_->free, + ACE_DNode, + ); + return 0; + } + + return -1; +} + +template int +ACE_Ordered_MultiSet::find (const T &item, + ITERATOR &iter) const +{ + // search an occurrence of item, using iterator's current position as a hint + ACE_DNode *node = iter.current_; + int const result = locate (item, node, node); + + // if we found the node, update the iterator and indicate success + if (node && (result == 0)) + { + iter.current_ = node; + return 0; + } + + return -1; +} + + + +template void +ACE_Ordered_MultiSet::reset (void) +{ + ACE_TRACE ("reset"); + + this->delete_nodes (); +} + +template void +ACE_Ordered_MultiSet::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + // ACE_TRACE ("ACE_Ordered_MultiSet::dump"); + // + // ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhead_ = %u"), this->head_)); + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhead_->next_ = %u"), this->head_->next_)); + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncur_size_ = %d\n"), this->cur_size_)); + // + // T *item = 0; + // size_t count = 1; + // + // for (ACE_Ordered_MultiSet_Iterator iter (*(ACE_Ordered_MultiSet *) this); + // iter.next (item) != 0; + // iter.advance ()) + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("count = %d\n"), count++)); + // + // ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template int +ACE_Ordered_MultiSet::insert_from (const T &item, ACE_DNode *position, + ACE_DNode **new_position) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet::insert_from"); + + // create a new node + ACE_DNode *temp = 0; + ACE_NEW_MALLOC_RETURN (temp, + static_cast*> (this->allocator_->malloc (sizeof (ACE_DNode))), + ACE_DNode (item), + -1); + // obtain approximate location of the node + int result = locate (item, position, position); + + // if there are nodes in the multiset + if (position) + { + switch (result) + { + // insert after the approximate position + case -1: + + // if there is a following node + if (position->next_) + { + // link up with the following node + position->next_->prev_ = temp; + temp->next_ = position->next_; + } + else + // appending to the end of the set + tail_ = temp; + + // link up with the preceeding node + temp->prev_ = position; + position->next_ = temp; + + break; + + // insert before the position + case 0: + case 1: + + // if there is a preceeding node + if (position->prev_) + { + // link up with the preceeding node + position->prev_->next_ = temp; + temp->prev_ = position->prev_; + } + else + // prepending to the start of the set + head_ = temp; + + // link up with the preceeding node + temp->next_ = position; + position->prev_ = temp; + + break; + + default: + return -1; + } + } + else + { + // point the head and tail to the new node. + this->head_ = temp; + this->tail_ = temp; + } + + ++this->cur_size_; + if (new_position) + *new_position = temp; + + return 0; +} + +template int +ACE_Ordered_MultiSet::locate (const T &item, ACE_DNode *start_position, + ACE_DNode *&new_position) const +{ + if (! start_position) + start_position = this->head_; + + // If starting before the item, move forward until at or just before + // item. + while (start_position && start_position->item_ < item && + start_position->next_) + start_position = start_position->next_; + + // If starting after the item, move back until at or just after item + while (start_position && item < start_position->item_ && + start_position->prev_) + start_position = start_position->prev_; + + // Save the (approximate) location in the passed pointer. + new_position = start_position; + + // Show the location is after (1), before (-1) , or at (0) the item + if (!new_position) + return 1; + else if (item < new_position->item_) + return 1; + else if (new_position->item_ < item) + return -1; + else + return 0; +} + +// Looks for first occurrence of in the ordered set, using the +// passed starting position as a hint: if there is such an instance, +// it updates the new_position pointer to point to one such node and +// returns 0; if there is no such node, then if there is a node before +// where the item would have been, it updates the new_position pointer +// to point to this node and returns -1; if there is no such node, +// then if there is a node after where the item would have been, it +// updates the new_position pointer to point to this node (or 0 if +// there is no such node) and returns 1; + +template void +ACE_Ordered_MultiSet::copy_nodes (const ACE_Ordered_MultiSet &us) +{ + ACE_DNode *insertion_point = this->head_; + + for (ACE_DNode *curr = us.head_; + curr != 0; + curr = curr->next_) + this->insert_from (curr->item_, insertion_point, &insertion_point); +} + +template void +ACE_Ordered_MultiSet::delete_nodes (void) +{ + // iterate through list, deleting nodes + for (ACE_DNode *curr = this->head_; + curr != 0; + ) + { + ACE_DNode *temp = curr; + curr = curr->next_; + ACE_DES_FREE_TEMPLATE (temp, + this->allocator_->free, + ACE_DNode, + ); + } + + this->head_ = 0; + this->tail_ = 0; + this->cur_size_ = 0; +} + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Ordered_MultiSet_Iterator) + +template +ACE_Ordered_MultiSet_Iterator::ACE_Ordered_MultiSet_Iterator (ACE_Ordered_MultiSet &s) + : current_ (s.head_), + set_ (s) +{ + // ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::ACE_Ordered_MultiSet_Iterator"); +} + +template int +ACE_Ordered_MultiSet_Iterator::next (T *&item) const +{ + // ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::next"); + if (this->current_) + { + item = &this->current_->item_; + return 1; + } + + return 0; +} + +template T& +ACE_Ordered_MultiSet_Iterator::operator* (void) +{ + //ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::operator*"); + T *retv = 0; + + int const result = this->next (retv); + ACE_ASSERT (result != 0); + ACE_UNUSED_ARG (result); + + return *retv; +} + +template T * +ACE_DLList::insert_tail (T *new_item) +{ + ACE_DLList_Node *temp1 = 0; + ACE_NEW_MALLOC_RETURN (temp1, + static_cast (this->allocator_->malloc (sizeof (ACE_DLList_Node))), + ACE_DLList_Node (new_item), + 0); + ACE_DLList_Node *temp2 = ACE_DLList_Base::insert_tail (temp1); + return (T *) (temp2 ? temp2->item_ : 0); +} + +template T * +ACE_DLList::insert_head (T *new_item) +{ + ACE_DLList_Node *temp1 = 0; + ACE_NEW_MALLOC_RETURN (temp1, + (ACE_DLList_Node *) this->allocator_->malloc (sizeof (ACE_DLList_Node)), + ACE_DLList_Node (new_item), 0); + ACE_DLList_Node *temp2 = ACE_DLList_Base::insert_head (temp1); + return (T *) (temp2 ? temp2->item_ : 0); +} + +template T * +ACE_DLList::delete_head (void) +{ + ACE_DLList_Node *temp1 = ACE_DLList_Base::delete_head (); + T *temp2 = (T *) (temp1 ? temp1->item_ : 0); + ACE_DES_FREE (temp1, + this->allocator_->free, + ACE_DLList_Node); + + return temp2; +} + +template T * +ACE_DLList::delete_tail (void) +{ + ACE_DLList_Node *temp1 = ACE_DLList_Base::delete_tail (); + T *temp2 = (T *) (temp1 ? temp1->item_ : 0); + ACE_DES_FREE (temp1, + this->allocator_->free, + ACE_DLList_Node); + return temp2; +} + +// **************************************************************** + +// Compare this array with for equality. + +template bool +ACE_Array::operator== (const ACE_Array &s) const +{ + if (this == &s) + return true; + else if (this->size () != s.size ()) + return false; + + const size_t len = s.size (); + for (size_t slot = 0; slot < len; ++slot) + if ((*this)[slot] != s[slot]) + return false; + + return true; +} + +// **************************************************************** + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_CONTAINERS_T_CPP */ diff --git a/dep/acelite/ace/Containers_T.h b/dep/acelite/ace/Containers_T.h new file mode 100644 index 000000000..2220acc3b --- /dev/null +++ b/dep/acelite/ace/Containers_T.h @@ -0,0 +1,2060 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Containers_T.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_CONTAINERS_T_H +#define ACE_CONTAINERS_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// Need by ACE_DLList_Node. +#include "ace/Containers.h" + +// Shared with "ace/Unbounded_Set.h" +#include "ace/Node.h" + +// Backwards compatibility, please include "ace/Array_Base.h" directly. +#include "ace/Array_Base.h" + +// Backwards compatibility, please include "ace/Unbounded_Set.h" directly. +#include "ace/Unbounded_Set.h" + +// Backwards compatibility, please include "ace/Unbounded_Queue.h" directly. +#include "ace/Unbounded_Queue.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Allocator; + + +/** + * @class ACE_Bounded_Stack + * + * @brief Implement a generic LIFO abstract data type. + * + * This implementation of a Stack uses a bounded array + * that is allocated dynamically. The Stack interface + * provides the standard constant time push, pop, and top + * operations. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Dynamic array + * - Duplicates allowed? + * Yes + * - Random access allowed? + * No + * - Search speed + * N/A + * - Insert/replace speed + * N/A + * - Iterator still valid after change to container? + * N/A + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + */ +template +class ACE_Bounded_Stack +{ +public: + // = Initialization, assignment, and termination methods. + + /// Initialize a new empty stack with the provided size.. + /** + * Initialize and allocate space for a new Bounded_Stack with the provided + * size. + */ + ACE_Bounded_Stack (size_t size); + + /// Initialize the stack to be a copy of the stack provided. + /** + * Initialize the stack to be an exact copy of the Bounded_Stack provided + * as a parameter. + */ + ACE_Bounded_Stack (const ACE_Bounded_Stack &s); + + /// Assignment operator + /** + * Perform a deep copy operation using the Bounded_Stack parameter. If the + * capacity of the lhs isn't sufficient for the rhs, then the underlying data + * structure will be reallocated to accomadate the larger number of elements. + */ + void operator= (const ACE_Bounded_Stack &s); + + /// Perform actions needed when stack goes out of scope. + /** + * Deallocate the memory used by the Bounded_Stack. + */ + ~ACE_Bounded_Stack (void); + + // = Classic Stack operations. + + ///Add an element to the top of the stack. + /** + * Place a new item on top of the stack. Returns -1 if the stack + * is already full, 0 if the stack is not already full, and -1 if + * failure occurs. + */ + int push (const T &new_item); + + ///Remove an item from the top of stack. + /** + * Remove and return the top stack item. Returns -1 if the stack is + * already empty, 0 if the stack is not already empty, and -1 if + * failure occurs. + */ + int pop (T &item); + + ///Examine the contents of the top of stack. + /** + * Return top stack item without removing it. Returns -1 if the + * stack is already empty, 0 if the stack is not already empty, and + * -1 if failure occurs. + */ + int top (T &item) const; + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * Performs constant time check to determine if the stack is empty. + */ + int is_empty (void) const; + + /// Returns 1 if the container is full, otherwise returns 0. + /** + * Performs constant time check to determine if the stack is at capacity. + */ + int is_full (void) const; + + /// The number of items in the stack. + /** + * Return the number of items currently in the stack. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Size of the dynamically allocated data. + size_t size_; + + /// Keeps track of the current top of stack. + size_t top_; + + /// Holds the stack's contents. + T *stack_; +}; + +//---------------------------------------- + + +/** + * @class ACE_Fixed_Stack + * + * @brief Implement a generic LIFO abstract data type. + * + * This implementation of a Stack uses a fixed array + * with the size fixed at instantiation time. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Fixed array + * - Duplicates allowed? + * Yes + * - Random access allowed? + * No + * - Search speed + * N/A + * - Insert/replace speed + * N/A + * - Iterator still valid after change to container? + * N/A + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + */ +template +class ACE_Fixed_Stack +{ +public: + // = Initialization, assignment, and termination methods. + /// Initialize a new stack so that it is empty. + /** + * Initialize an empty stack. + */ + ACE_Fixed_Stack (void); + + /// The copy constructor (performs initialization). + /** + * Initialize the stack and copy the provided stack into the current stack. + */ + ACE_Fixed_Stack (const ACE_Fixed_Stack &s); + + /// Assignment operator (performs assignment). + /** + * Perform a deep copy of the provided stack. + */ + void operator= (const ACE_Fixed_Stack &s); + + /// Perform actions needed when stack goes out of scope. + /** + * Destroy the stack. + */ + ~ACE_Fixed_Stack (void); + + // = Classic Stack operations. + + ///Constant time placement of element on top of stack. + /** + * Place a new item on top of the stack. Returns -1 if the stack + * is already full, 0 if the stack is not already full, and -1 if + * failure occurs. + */ + int push (const T &new_item); + + ///Constant time removal of top of stack. + /** + * Remove and return the top stack item. Returns -1 if the stack is + * already empty, 0 if the stack is not already empty, and -1 if + * failure occurs. + */ + int pop (T &item); + + ///Constant time examination of top of stack. + /** + * Return top stack item without removing it. Returns -1 if the + * stack is already empty, 0 if the stack is not already empty, and + * -1 if failure occurs. + */ + int top (T &item) const; + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * Performs constant time check to see if stack is empty. + */ + int is_empty (void) const; + + /// Returns 1 if the container is full, otherwise returns 0. + /** + * Performs constant time check to see if stack is full. + */ + int is_full (void) const; + + /// The number of items in the stack. + /** + * Constant time access to the current size of the stack. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Size of the allocated data. + size_t size_; + + /// Keeps track of the current top of stack. + size_t top_; + + /// Holds the stack's contents. + T stack_[ACE_SIZE]; +}; + +//---------------------------------------- + +template class ACE_Ordered_MultiSet; +template class ACE_Ordered_MultiSet_Iterator; + +/** + * @class ACE_DNode + * + * @brief Implementation element in a bilinked list. + */ +template +class ACE_DNode +{ + friend class ACE_Ordered_MultiSet; + friend class ACE_Ordered_MultiSet_Iterator; + +public: + + /// This isn't necessary, but it keeps some compilers happy. + ~ACE_DNode (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + // = Initialization methods + ACE_DNode (const T &i, ACE_DNode *n = 0, ACE_DNode *p = 0); + + /// Pointer to next element in the list of {ACE_DNode}s. + ACE_DNode *next_; + + /// Pointer to previous element in the list of {ACE_DNode}s. + ACE_DNode *prev_; + + /// Current value of the item in this node. + T item_; +}; + + + +/** + * @class ACE_Unbounded_Stack + * + * @brief Implement a generic LIFO abstract data type. + * + * This implementation of an unbounded Stack uses a linked list. + * If you use the {insert} or {remove} methods you should keep + * in mind that duplicate entries aren't allowed. In general, + * therefore, you should avoid the use of these methods since + * they aren't really part of the ADT stack. The stack is implemented + * as a doubly linked list. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Double linked list + * - Duplicates allowed? + * No + * - Random access allowed? + * No + * - Search speed + * Linear + * - Insert/replace speed + * Linear + * - Iterator still valid after change to container? + * Yes + * - Frees memory for removed elements? + * Yes + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + */ +template +class ACE_Unbounded_Stack +{ +public: + friend class ACE_Unbounded_Stack_Iterator; + + // Trait definition. + typedef ACE_Unbounded_Stack_Iterator ITERATOR; + + // = Initialization, assignment, and termination methods. + /// Initialize a new stack so that it is empty. Use user defined + /// allocation strategy if specified. + /** + * Initialize an empty stack using the user specified allocation strategy + * if provided. + */ + ACE_Unbounded_Stack (ACE_Allocator *the_allocator = 0); + + /// The copy constructor (performs initialization). + /** + * Initialize this stack to be an exact copy of {s}. + */ + ACE_Unbounded_Stack (const ACE_Unbounded_Stack &s); + + /// Assignment operator (performs assignment). + /** + * Perform a deep copy of the rhs into the lhs. + */ + void operator= (const ACE_Unbounded_Stack &s); + + /// Perform actions needed when stack goes out of scope. + /** + * Destroy the underlying list for the stack. + */ + ~ACE_Unbounded_Stack (void); + + // = Classic Stack operations. + + + ///Push an element onto the top of stack. + /** + * Place a new item on top of the stack. Returns -1 if the stack + * is already full, 0 if the stack is not already full, and -1 if + * failure occurs. + */ + int push (const T &new_item); + + ///Pop the top element of the stack. + /** + * Remove and return the top stack item. Returns -1 if the stack is + * already empty, 0 if the stack is not already empty, and -1 if + * failure occurs. + */ + int pop (T &item); + + ///Examine the top of the stack. + /** + * Return top stack item without removing it. Returns -1 if the + * stack is already empty, 0 if the stack is not already empty, and + * -1 if failure occurs. + */ + int top (T &item) const; + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * Constant time check to see if the stack is empty. + */ + int is_empty (void) const; + + /// Returns 1 if the container is full, otherwise returns 0. + /** + * Always resturns 0 since the stack is unbounded. + */ + int is_full (void) const; + + // = Auxiliary methods (not strictly part of the Stack ADT). + + ///Linear Insert of an item. + /** + * Insert {new_item} into the Stack at the head (but doesn't allow + * duplicates). Returns -1 if failures occur, 1 if item is already + * present (i.e., no duplicates are allowed), else 0. + */ + int insert (const T &new_item); + + /// Remove @a item from the Stack. Returns 0 if it removes the item, + /// -1 if it can't find the item, and -1 if a failure occurs. + /** + * Linear remove operation. + */ + int remove (const T &item); + + /// Finds if @a item occurs the set. Returns 0 if finds, else -1. + /** + * Linear find operation. + */ + int find (const T &item) const; + + /// The number of items in the stack. + /** + * Constant time access to the current stack size. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Delete all the nodes in the stack. + void delete_all_nodes (void); + + /// Copy all nodes from {s} to {this}. + void copy_all_nodes (const ACE_Unbounded_Stack &s); + + /// Head of the linked list of Nodes. + ACE_Node *head_; + + /// Current size of the stack. + size_t cur_size_; + + /// Allocation strategy of the stack. + ACE_Allocator *allocator_; +}; + +/** + * @class ACE_Unbounded_Stack_Iterator + * + * @brief Implement an iterator over an unbounded Stack. + */ +template +class ACE_Unbounded_Stack_Iterator +{ +public: + // = Initialization method. + /// Move to the first element in the {stack}. + ACE_Unbounded_Stack_Iterator (ACE_Unbounded_Stack &stack); + + // = Iteration methods. + + /// Pass back the @a next_item that hasn't been seen in the Stack. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item); + + /// Move forward by one element in the Stack. Returns 0 when all the + /// items in the Stack have been seen, else 1. + int advance (void); + + /// Move to the first element in the Stack. Returns 0 if the + /// Stack is empty, else 1. + int first (void); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Pointer to the current node in the iteration. + ACE_Node *current_; + + /// Pointer to the Stack we're iterating over. + ACE_Unbounded_Stack &stack_; +}; + +template +class ACE_Double_Linked_List; + +/** + * @class ACE_Double_Linked_List_Iterator_Base + * + * @brief Implements a common base class for iterators for a double + * linked list ADT + */ +template +class ACE_Double_Linked_List_Iterator_Base +{ +public: + // = Iteration methods. + + /// Passes back the {entry} under the iterator. Returns 0 if the + /// iteration has completed, otherwise 1 + int next (T *&) const; + + /** + * @deprecated Return the address of next (current) unvisited item in + * the list. 0 if there is no more element available. + */ + T *next (void) const; + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// STL-like iterator dereference operator: returns a reference + /// to the node underneath the iterator. + T & operator* (void) const ; + + /** + * Retasks the iterator to iterate over a new + * Double_Linked_List. This allows clients to reuse an iterator + * without incurring the constructor overhead. If you do use this, + * be aware that if there are more than one reference to this + * iterator, the other "clients" may be very bothered when their + * iterator changes. @@ Here be dragons. Comments? + */ + void reset (ACE_Double_Linked_List &); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Initialization methods. + + /// Constructor + ACE_Double_Linked_List_Iterator_Base (const ACE_Double_Linked_List &); + + /// Copy constructor. + ACE_Double_Linked_List_Iterator_Base (const + ACE_Double_Linked_List_Iterator_Base + &iter); + + // = Iteration methods. + /** + * Move to the first element of the list. Returns 0 if the list is + * empty, else 1. + * @note the head of the ACE_DLList is actually a null entry, so the + * first element is actually the 2n'd entry + */ + int go_head (void); + + /// Move to the last element of the list. Returns 0 if the list is + /// empty, else 1. + int go_tail (void); + + /** + * Check if we reach the end of the list. Can also be used to get + * the *current* element in the list. Return the address of the + * current item if there are still elements left , 0 if we run out + * of element. + */ + T *not_done (void) const ; + + /// Advance to the next element in the list. Return the address of the + /// next element if there are more, 0 otherwise. + T *do_advance (void); + + /// Retreat to the previous element in the list. Return the address + /// of the previous element if there are more, 0 otherwise. + T *do_retreat (void); + + /// Dump the state of an object. + void dump_i (void) const; + + /// Remember where we are. + T *current_; + + const ACE_Double_Linked_List *dllist_; +}; + +/** + * @class ACE_Double_Linked_List_Iterator + * + * @brief Implements an iterator for a double linked list ADT + * + * Iterate thru the double-linked list. This class provides + * an interface that let users access the internal element + * addresses directly. Notice {class T} must declare + * ACE_Double_Linked_List<T>, + * ACE_Double_Linked_List_Iterator_Base <T> and + * ACE_Double_Linked_List_Iterator as friend classes and class T + * should also have data members T* next_ and T* prev_. + */ +template +class ACE_Double_Linked_List_Iterator : public ACE_Double_Linked_List_Iterator_Base +{ +public: + // = Initialization method. + ACE_Double_Linked_List_Iterator (const ACE_Double_Linked_List &); + + /** + * Retasks the iterator to iterate over a new + * Double_Linked_List. This allows clients to reuse an iterator + * without incurring the constructor overhead. If you do use this, + * be aware that if there are more than one reference to this + * iterator, the other "clients" may be very bothered when their + * iterator changes. + * @@ Here be dragons. Comments? + */ + void reset (ACE_Double_Linked_List &); + + /// Move to the first element in the list. Returns 0 if the + /// list is empty, else 1. + int first (void); + + /// Move forward by one element in the list. Returns 0 when all the + /// items in the list have been seen, else 1. + int advance (void); + + /** + * Advance the iterator while removing the original item from the + * list. Return a pointer points to the original (removed) item. + * If @a dont_remove equals false, this function behaves like {advance} + * but return 0 (NULL) instead. + */ + T* advance_and_remove (bool dont_remove); + + // = STL-style iteration methods + + /// Prefix advance. + ACE_Double_Linked_List_Iterator & operator++ (void); + + /// Postfix advance. + ACE_Double_Linked_List_Iterator operator++ (int); + + /// Prefix reverse. + ACE_Double_Linked_List_Iterator & operator-- (void); + + /// Postfix reverse. + ACE_Double_Linked_List_Iterator operator-- (int); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +/** + * @class ACE_Double_Linked_List_Reverse_Iterator + * + * @brief Implements a reverse iterator for a double linked list ADT + * + * Iterate backwards over the double-linked list. This class + * provide an interface that let users access the internal + * element addresses directly, which seems to break the + * encapsulation. Notice {class T} must declare + * ACE_Double_Linked_List<T>, + * ACE_Double_Linked_List_Iterator_Base <T> and + * ACE_Double_Linked_List_Iterator as friend classes and class T + * should also have data members T* next_ and T* prev_. + */ +template +class ACE_Double_Linked_List_Reverse_Iterator : public ACE_Double_Linked_List_Iterator_Base +{ +public: + // = Initialization method. + ACE_Double_Linked_List_Reverse_Iterator (ACE_Double_Linked_List &); + + /** + * Retasks the iterator to iterate over a new + * Double_Linked_List. This allows clients to reuse an iterator + * without incurring the constructor overhead. If you do use this, + * be aware that if there are more than one reference to this + * iterator, the other "clients" may be very bothered when their + * iterator changes. + * @@ Here be dragons. Comments? + */ + void reset (ACE_Double_Linked_List &); + + /// Move to the first element in the list. Returns 0 if the + /// list is empty, else 1. + int first (void); + + /// Move forward by one element in the list. Returns 0 when all the + /// items in the list have been seen, else 1. + int advance (void); + + /** + * Advance the iterator while removing the original item from the + * list. Return a pointer points to the original (removed) item. + * If @a dont_remove equals false, this function behaves like {advance} + * but return 0 (NULL) instead. + */ + T* advance_and_remove (bool dont_remove); + + // = STL-style iteration methods + + /// Prefix advance. + ACE_Double_Linked_List_Reverse_Iterator & operator++ (void); + + /// Postfix advance. + ACE_Double_Linked_List_Reverse_Iterator operator++ (int); + + /// Prefix reverse. + ACE_Double_Linked_List_Reverse_Iterator & operator-- (void); + + /// Postfix reverse. + ACE_Double_Linked_List_Reverse_Iterator operator-- (int); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + + +/** + * @class ACE_Double_Linked_List + * + * @brief A double-linked list implementation. + * + * This implementation of an unbounded double-linked list uses a + * circular linked list with a dummy node. It is pretty much + * like the {ACE_Unbounded_Queue} except that it allows removing + * of a specific element from a specific location. + * Notice that this class is an implementation of a very simple + * data structure. This is *NOT* a container class. You can use the + * class to implement other contains classes but it is *NOT* a + * general purpose container class. + * The parameter class *MUST* have members T* prev and T* next + * and users of this class are responsible to follow the general + * rules of using double-linked lists to maintaining the list + * integrity. + * If you need a double linked container class, use the DLList + * class which is a container but delegates to the Double_Linked_List + * class. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Double Linked List + * - Duplicates allowed? + * Yes + * - Random access allowed? + * No + * - Search speed + * N/A + * - Insert/replace speed + * Linear + * - Iterator still valid after change to container? + * Yes + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + */ +template +class ACE_Double_Linked_List +{ +public: + friend class ACE_Double_Linked_List_Iterator_Base; + friend class ACE_Double_Linked_List_Iterator; + friend class ACE_Double_Linked_List_Reverse_Iterator; + + // Trait definition. + typedef ACE_Double_Linked_List_Iterator ITERATOR; + typedef ACE_Double_Linked_List_Reverse_Iterator REVERSE_ITERATOR; + + // = Initialization and termination methods. + /// construction. Use user specified allocation strategy + /// if specified. + /** + * Initialize an empy list using the allocation strategy specified by the user. + * If none is specified, then use default allocation strategy. + */ + ACE_Double_Linked_List (ACE_Allocator *the_allocator = 0); + + /// Copy constructor. + /** + * Create a double linked list that is a copy of the provided + * parameter. + */ + ACE_Double_Linked_List (const ACE_Double_Linked_List &); + + /// Assignment operator. + /** + * Perform a deep copy of the provided list by first deleting the nodes of the + * lhs and then copying the nodes of the rhs. + */ + void operator= (const ACE_Double_Linked_List &); + + /// Destructor. + /** + * Clean up the memory allocated for the nodes of the list. + */ + ~ACE_Double_Linked_List (void); + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, 0 otherwise. + /** + * Performs constant time check to determine if the list is empty. + */ + int is_empty (void) const; + + /// The list is unbounded, so this always returns 0. + /** + * Since the list is unbounded, the method simply returns 0. + */ + int is_full (void) const; + + // = Classic queue operations. + + /// Adds @a new_item to the tail of the list. Returns the new item + /// that was inserted. + /** + * Provides constant time insertion at the end of the list structure. + */ + T *insert_tail (T *new_item); + + /// Adds @a new_item to the head of the list.Returns the new item that + /// was inserted. + /** + * Provides constant time insertion at the head of the list. + */ + T *insert_head (T *new_item); + + /// Removes the head of the list and returns a pointer to that item. + /** + * Removes and returns the first {item} in the list. Returns + * internal node's address on success, 0 if the queue was empty. + * This method will *not* free the internal node. + */ + T* delete_head (void); + + /// Removes the tail of the list and returns a pointer to that item. + /** + * Removes and returns the last {item} in the list. Returns + * internal nodes's address on success, 0 if the queue was + * empty. This method will *not* free the internal node. + */ + T *delete_tail (void); + + // = Additional utility methods. + + ///Empty the list. + /** + * Reset the {ACE_Double_Linked_List} to be empty. + * Notice that since no one is interested in the items within, + * This operation will delete all items. + */ + void reset (void); + + /// Get the {slot}th element in the set. Returns -1 if the element + /// isn't in the range {0..{size} - 1}, else 0. + /** + * Iterates through the list to the desired index and assigns the provides pointer + * with the address of the node occupying that index. + */ + int get (T *&item, size_t slot = 0); + + /// The number of items in the queue. + /** + * Constant time call to return the current size of the list. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Use DNode address directly. + /** + * Constant time removal of an item from the list using it's address. + */ + int remove (T *n); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Delete all the nodes in the list. + /** + * Removes and deallocates memory for all of the list nodes. + */ + void delete_nodes (void); + + /// Copy nodes from {rhs} into this list. + /** + * Copy the elements of the provided list by allocated new nodes and assigning + * them with the proper data. + */ + void copy_nodes (const ACE_Double_Linked_List &rhs); + + /// Setup header pointer. Called after we create the head node in ctor. + /** + * Initialize the head pointer so that the list has a dummy node. + */ + void init_head (void); + + ///Constant time insert a new item into the list structure. + /** + * Insert a @a new_item into the list. It will be added before + * or after @a old_item. Default is to insert the new item *after* + * {head_}. Return 0 if succeed, -1 if error occurred. + */ + int insert_element (T *new_item, + int before = 0, + T *old_item = 0); + + ///Constant time delete an item from the list structure. + /** + * Remove @a item from the list. Return 0 if succeed, -1 otherwise. + * Notice that this function checks if item is {head_} and either its + * {next_} or {prev_} is NULL. The function resets item's {next_} and + * {prev_} to 0 to prevent clobbering the double-linked list if a user + * tries to remove the same node again. + */ + int remove_element (T *item); + + /// Head of the circular double-linked list. + T *head_; + + /// Size of this list. + size_t size_; + + /// Allocation Strategy of the queue. + ACE_Allocator *allocator_; +}; + + +template class ACE_DLList; +template class ACE_DLList_Iterator; +template class ACE_DLList_Reverse_Iterator; + +typedef ACE_Double_Linked_List ACE_DLList_Base; + +//typedef ACE_Double_Linked_List_Iterator +// ACE_DLList_Iterator_Base; +//typedef ACE_Double_Linked_List_Reverse_Iterator +// ACE_DLList_Reverse_Iterator_Base; +//@@ These two typedefs (inherited from James Hu's original design) +// have been removed because Sun CC 4.2 had problems with it. I guess +// having the DLList_Iterators inheriting from a class which is +// actually a typedef leads to problems. #define'ing rather than +// typedef'ing worked, but as per Carlos's reccomendation, I'm just +// replacing all references to the base classes with their actual +// type. Matt Braun (6/15/99) + +/** + * @class ACE_DLList + * + * @brief A double-linked list container class. + * + * ACE_DLList is a simple, unbounded container implemented using a + * double-linked list. It is critical to remember that ACE_DLList inherits + * from ACE_Double_Linked_List, wrapping each T pointer in a ACE_DLList_Node + * object which satisfies the next/prev pointer requirements imposed by + * ACE_Double_Linked_List. + * + * Each item inserted to an ACE_DLList is a pointer to a T object. The + * caller is responsible for lifetime of the T object. ACE_DLList takes no + * action on the T object; it is not copied on insertion and it is not + * deleted on removal from the ACE_DLList. + */ +template +class ACE_DLList : public ACE_DLList_Base +{ + friend class ACE_DLList_Node; + friend class ACE_Double_Linked_List_Iterator; + friend class ACE_DLList_Iterator; + friend class ACE_DLList_Reverse_Iterator; + +public: + + /// Delegates to ACE_Double_Linked_List. + void operator= (const ACE_DLList &l); + + /** + * @name Queue-like insert and delete methods + */ + //@{ + + /** + * Insert pointer for a new item at the tail of the list. + * + * @return Pointer to item inserted; 0 on error. + */ + T *insert_tail (T *new_item); + + /** + * Insert pointer for a new item at the head of the list. + * + * @return Pointer to item inserted; 0 on error. + */ + T *insert_head (T *new_item); + + /** + * Removes the item at the head of the list and returns its pointer. + * + * @return Pointer to previously inserted item; 0 if the list is empty, + * an error occurred, or the original pointer inserted was 0. + */ + T *delete_head (void); + + /** + * Removes the item at the tail of the list and returns its pointer. + * + * @return Pointer to previously inserted item; 0 if the list is empty, + * an error occurred, or the original pointer inserted was 0. + */ + T *delete_tail (void); + //@} + + /** + * Provide random access to any item in the list. + * + * @param item Receives a pointer to the T object pointer held at the + * specified position in the list. + * @param slot Position in the list to access. The first position is 0. + * + * @retval 0 Success; T pointer returned in item. + * @retval -1 Error, most likely slot is outside the range of the list. + */ + int get (T *&item, size_t slot = 0); + + /// Delegates to ACE_Double_Linked_List. + void dump (void) const; + + /// Delegates to ACE_Double_Linked_List. + int remove (ACE_DLList_Node *n); + + /** + * Constructor. + * + * @param the_allocator Allocator to use for allocating ACE_DLList_Node + * objects that wrap T objects for inclusion in the + * list. If 0, ACE_Allocator::instance() is used. + */ + ACE_DLList (ACE_Allocator *the_allocator = 0); + + /// Delegates to ACE_Double_Linked_List. + ACE_DLList (const ACE_DLList &l); + + /** + * Deletes all ACE_DLList_Node objects in the list starting from the head. + * No T objects referred to by the deleted ACE_DLList_Node objects are + * modified or freed. If you desire all of the T objects in the list to + * be deleted as well, code such as this should be used prior to destroying + * the ACE_DLList: + * @code + ACE_DLList list; + ... // insert dynamically allocated Items... + Item *p; + while ((p = list.delete_head()) != 0) + delete *p; + @endcode + */ + ~ACE_DLList (void); +}; + +/** + * @class ACE_DLList_Iterator + * + * @brief A double-linked list container class iterator. + * + * This implementation uses ACE_Double_Linked_List_Iterator to + * perform the logic behind this container class. It delegates + * all of its calls to ACE_Double_Linked_List_Iterator. + */ +template +class ACE_DLList_Iterator : public ACE_Double_Linked_List_Iterator +{ + + friend class ACE_DLList; + friend class ACE_DLList_Node; + +public: + + // = Initialization method. + ACE_DLList_Iterator (ACE_DLList &l); + + /** + * Retasks the iterator to iterate over a new + * Double_Linked_List. This allows clients to reuse an iterator + * without incurring the constructor overhead. If you do use this, + * be aware that if there are more than one reference to this + * iterator, the other "clients" may be very bothered when their + * iterator changes. + * @@ Here be dragons. Comments? + */ + void reset (ACE_DLList &l); + + // = Iteration methods. + /// Move forward by one element in the list. Returns 0 when all the + /// items in the list have been seen, else 1. + int advance (void); + + /// Pass back the {next_item} that hasn't been seen in the list. + /// Returns 0 when all items have been seen, else 1. + int next (T *&); + + /** + * @deprecated Delegates to ACE_Double_Linked_List_Iterator, except that + * whereas the Double_Linked_List version of next returns the node, this next + * returns the contents of the node + */ + T *next (void) const; + + /** + * Removes the current item (i.e., {next}) from the list. + * Note that DLList iterators do not support {advance_and_remove} + * directly (defined in its base class) and you will need to + * release the element returned by it. + */ + int remove (void); + + /// Delegates to ACE_Double_Linked_List_Iterator. + void dump (void) const; + +private: + ACE_DLList *list_; +}; + +/** + * @class ACE_DLList_Reverse_Iterator + * + * @brief A double-linked list container class iterator. + * + * This implementation uses ACE_Double_Linked_List_Iterator to + * perform the logic behind this container class. It delegates + * all of its calls to ACE_Double_Linked_List_Iterator. + */ +template +class ACE_DLList_Reverse_Iterator : public ACE_Double_Linked_List_Reverse_Iterator +{ + + friend class ACE_DLList; + friend class ACE_DLList_Node; + +public: + + // = Initialization method. + ACE_DLList_Reverse_Iterator (ACE_DLList &l); + + /** + * Retasks the iterator to iterate over a new + * Double_Linked_List. This allows clients to reuse an iterator + * without incurring the constructor overhead. If you do use this, + * be aware that if there are more than one reference to this + * iterator, the other "clients" may be very bothered when their + * iterator changes. + * @@ Here be dragons. Comments? + */ + void reset (ACE_DLList &l); + + // = Iteration methods. + /// Move forward by one element in the list. Returns 0 when all the + /// items in the list have been seen, else 1. + int advance (void); + + /// Pass back the {next_item} that hasn't been seen in the list. + /// Returns 0 when all items have been seen, else 1. + int next (T *&); + + /// @deprecated Delegates to ACE_Double_Linked_List_Iterator. + T *next (void) const; + + /// Removes the current item (i.e., {next}) from the list. + /// Note that DLList iterators do not support {advance_and_remove} + /// directly (defined in its base class) and you will need to + /// release the element returned by it. + int remove (void); + + /// Delegates to ACE_Double_Linked_List_Iterator. + void dump (void) const; + +private: + ACE_DLList *list_; +}; + +// Forward declaration. +template +class ACE_Fixed_Set; + +/** + * @class ACE_Fixed_Set_Iterator_Base + * + * @brief Implements a common base class for iterators for a unordered set. + */ +template +class ACE_Fixed_Set_Iterator_Base +{ +public: + // = Iteration methods. + + /// Pass back the {next_item} that hasn't been seen in the Set. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item); + + /// Move forward by one element in the set. Returns 0 when all the + /// items in the set have been seen, else 1. + int advance (void); + + /// Move to the first element in the set. Returns 0 if the + /// set is empty, else 1. + int first (void); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Initialization method. + ACE_Fixed_Set_Iterator_Base (ACE_Fixed_Set &s); + + /// Set we are iterating over. + ACE_Fixed_Set &s_; + + /// How far we've advanced over the set. + ssize_t next_; + + /// The number of non free items that the iterator had pointed at. + size_t iterated_items_; + + /// Dump the state of an object. + void dump_i (void) const; + + /// Pass back the {next_item} that hasn't been seen in the Set. + /// Returns 0 when all items have been seen, else 1. + int next_i (T *&next_item); +}; + +/** + * @class ACE_Fixed_Set_Iterator + * + * @brief Iterates through an unordered set. + * + * This implementation of an unordered set uses a fixed array. + * Allows deletions while iteration is occurring. + */ +template +class ACE_Fixed_Set_Iterator : public ACE_Fixed_Set_Iterator_Base +{ +public: + // = Initialization method. + ACE_Fixed_Set_Iterator (ACE_Fixed_Set &s); + + // = Iteration methods. + + /// Pass back the {next_item} that hasn't been seen in the Set. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item); + + /// Dump the state of an object. + void dump (void) const; + + /// Remove the item where the itearetor is located at. + /// Returns 1 if it removes a item, else 0. + /// Pass back the removed {item}. + int remove (T *&item); + + /// STL-like iterator dereference operator: returns a reference + /// to the node underneath the iterator. + T & operator* (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +/** + * @class ACE_Fixed_Set_Const_Iterator + * + * @brief Iterates through a const unordered set. + * + * This implementation of an unordered set uses a fixed array. + */ +template +class ACE_Fixed_Set_Const_Iterator : public ACE_Fixed_Set_Iterator_Base +{ +public: + // = Initialization method. + ACE_Fixed_Set_Const_Iterator (const ACE_Fixed_Set &s); + + // = Iteration methods. + + /// Pass back the {next_item} that hasn't been seen in the Set. + /// Returns 0 when all items have been seen, else 1. + int next (const T *&next_item); + + /// Dump the state of an object. + void dump (void) const; + + /// STL-like iterator dereference operator: returns a reference + /// to the node underneath the iterator. + const T & operator* (void) const ; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +/** + * @class ACE_Fixed_Set + * + * @brief Implement a simple unordered set of {T} with maximum {ACE_SIZE}. + * + * This implementation of an unordered set uses a fixed array. + * It does not allow duplicate members. The set provides linear insertion/deletion + * operations. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Fixed array + * - Duplicates allowed? + * No + * - Random access allowed? + * No + * - Search speed + * Linear + * - Insert/replace speed + * Linear + * - Iterator still valid after change to container? + * Yes + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + * -# operator== + */ +template +class ACE_Fixed_Set +{ +public: + friend class ACE_Fixed_Set_Iterator_Base; + friend class ACE_Fixed_Set_Iterator; + friend class ACE_Fixed_Set_Const_Iterator; + + // Trait definitions. + typedef ACE_Fixed_Set_Iterator ITERATOR; + typedef ACE_Fixed_Set_Const_Iterator CONST_ITERATOR; + + // = Initialization and termination methods. + /// Default Constructor. + /** + * Creates an empy set + */ + ACE_Fixed_Set (void); + + /// Copy constructor. + /** + * Initializes a set to be a copy of the set parameter. + */ + ACE_Fixed_Set (const ACE_Fixed_Set &); + + /// Assignment operator. + /** + * Deep copy of one set to another. + */ + void operator= (const ACE_Fixed_Set &); + + /// Destructor. + /** + * Destroys a set. + */ + ~ACE_Fixed_Set (void); + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * Performs constant time check to determine if a set is empty. + */ + int is_empty (void) const; + + /// Returns 1 if the container is full, otherwise returns 0. + /** + * Performs a constant time check to see if the set is full. + */ + int is_full (void) const; + + // = Classic unordered set operations. + + ///Linear time insertion of an item unique to the set. + /** + * Insert @a new_item into the set (doesn't allow duplicates). + * Returns -1 if failures occur, 1 if item is already present, else + * 0. + */ + int insert (const T &new_item); + + ///Linear time removal operation of an item. + /** + * Remove first occurrence of {item} from the set. Returns 0 if + * it removes the item, -1 if it can't find the item, and -1 if a + * failure occurs. Removal doesn't reclaim memory for the @a item. + */ + int remove (const T &item); + + /// Finds if @a item occurs in the set. Returns 0 if finds, else -1. + /** + * Performs a linear find operation for the specified @a item. + */ + int find (const T &item) const; + + /// Size of the set. + /** + * Returns the current size of the set. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Holds the contents of the set. + struct + { + /// Item in the set. + T item_; + + /// Keeps track of whether this item is in use or not. + int is_free_; + } search_structure_[ACE_SIZE]; + + /// Current size of the set. + size_t cur_size_; + + /// Maximum size of the set. + size_t max_size_; +}; + +// Forward declaration. +template +class ACE_Bounded_Set; + +/** + * @class ACE_Bounded_Set_Iterator + * + * @brief Iterates through an unordered set. + * + * This implementation of an unordered set uses a Bounded array. + * Allows deletions while iteration is occurring. + */ +template +class ACE_Bounded_Set_Iterator +{ +public: + // = Initialization method. + ACE_Bounded_Set_Iterator (ACE_Bounded_Set &s); + + // = Iteration methods. + + /// Pass back the {next_item} that hasn't been seen in the Set. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item); + + /// Move forward by one element in the set. Returns 0 when all the + /// items in the set have been seen, else 1. + int advance (void); + + /// Move to the first element in the set. Returns 0 if the + /// set is empty, else 1. + int first (void); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Set we are iterating over. + ACE_Bounded_Set &s_; + + /// How far we've advanced over the set. + ssize_t next_; +}; + + +/** + * @class ACE_Bounded_Set + * + * @brief Implement a simple unordered set of {T} with maximum + * set at creation time. + * + * This implementation of an unordered set uses a Bounded array. + * This implementation does not allow duplicates. It provides + * linear insert/remove/find operations. Insertion/removal does not + * invalidate iterators, but caution should be taken to ensure + * expected behavior. Once initialized, the object has a maximum size + * which can only be increased by the assignment of another larger Bounded_Set. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Bounded array which can grow via assignment + * - Duplicates allowed? + * No + * - Random access allowed? + * No + * - Search speed + * Linear + * - Insert/replace speed + * Linear + * - Iterator still valid after change to container? + * Yes + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + * -# operator== + */ +template +class ACE_Bounded_Set +{ +public: + friend class ACE_Bounded_Set_Iterator; + + // Trait definition. + typedef ACE_Bounded_Set_Iterator ITERATOR; + + enum + { + DEFAULT_SIZE = 10 + }; + + // = Initialization and termination methods. + /// Construct a Bounded_Set using the default size. + /** + * The default constructor initializes the Bounded_Set to a maximum size + * specified by the DEFAULT_SIZE. + */ + ACE_Bounded_Set (void); + + /// Construct a Bounded_Set with the provided sizeB. + /** + * Initialize the Bounded_Set to have a maximum size equal to the size + * parameter specified. + */ + ACE_Bounded_Set (size_t size); + + /// Construct a Bounded_Set that is a copy of the provides Bounded_Set. + /** + * Initialize the Bounded_Set to be a copy of the Bounded_Set parameter. + */ + ACE_Bounded_Set (const ACE_Bounded_Set &); + + /// Assignment operator. + /** + * The assignment will make a deep copy of the Bounded_Set provided. If the + * rhs has more elements than the capacity of the lhs, then the lhs will be + * deleted and reallocated to accomadate the larger number of elements. + */ + void operator= (const ACE_Bounded_Set &); + + /// Destructor + /** + * Clean up the underlying dynamically allocated memory that is used by + * the Bounded_Set. + */ + ~ACE_Bounded_Set (void); + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * A constant time check is performed to determine if the Bounded_Set is + * empty. + */ + int is_empty (void) const; + + /// Returns 1 if the container is full, otherwise returns 0. + /** + * Performs a constant time check to determine if the Bounded_Set is at + * capacity. + */ + int is_full (void) const; + + // = Classic unordered set operations. + + ///Inserts a new element unique to the set. + /** + * Insert @a new_item into the set (doesn't allow duplicates) in linear + * time. + * Returns -1 if failures occur, 1 if item is already present, else + * 0. + */ + int insert (const T &new_item); + + ///Finds the specified element and removes it from the set. + /** + * Remove first occurrence of @a item from the set. Returns 0 if it + * removes the item, -1 if it can't find the item, and -1 if a + * failure occurs. The linear remove operation does not reclaim the + * memory associated with the removed item. + */ + int remove (const T &item); + + /// Finds if @a item occurs in the set. Returns 0 if finds, else -1. + /** + * find preforms a linear search for {item} and returns 0 on successful + * find and -1 otherwise. + */ + int find (const T &item) const; + + /// Size of the set. + /** + * Returns a size_t representing the current size of the set. + */ + size_t size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + struct Search_Structure + { + /// Item in the set. + T item_; + + /// Keeps track of whether this item is in use or not. + int is_free_; + }; + + /// Holds the contents of the set. + Search_Structure *search_structure_; + + /// Current size of the set. + size_t cur_size_; + + /// Maximum size of the set. + size_t max_size_; +}; + +/** + * @class ACE_Ordered_MultiSet_Iterator + * + * @brief Implement a bidirectional iterator over an ordered multiset. + * This class template requires that < operator semantics be + * defined for the parameterized type {T}, but does not impose + * any restriction on how that ordering operator is implemented. + */ +template +class ACE_Ordered_MultiSet_Iterator +{ +public: + friend class ACE_Ordered_MultiSet; + + // = Initialization method. + ACE_Ordered_MultiSet_Iterator (ACE_Ordered_MultiSet &s); + + // = Iteration methods. + + /// Pass back the {next_item} that hasn't been seen in the ordered multiset. + /// Returns 0 when all items have been seen, else 1. + int next (T *&next_item) const; + + /// Repositions the iterator at the first item in the ordered multiset + /// Returns 0 if the list is empty else 1. + int first (void); + + /// Repositions the iterator at the last item in the ordered multiset + /// Returns 0 if the list is empty else 1. + int last (void); + + /// Move forward by one element in the set. Returns 0 when all the + /// items in the set have been seen, else 1. + int advance (void); + + /// Move backward by one element in the set. Returns 0 when all the + /// items in the set have been seen, else 1. + int retreat (void); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Returns a reference to the internal element {this} is pointing to. + T& operator* (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// Pointer to the current node in the iteration. + ACE_DNode *current_; + + /// Pointer to the set we're iterating over. + ACE_Ordered_MultiSet &set_; +}; + + +/** + * @class ACE_Ordered_MultiSet + * + * @brief Implement a simple ordered multiset of {T} of unbounded size + * that allows duplicates. This class template requires that < + * operator semantics be defined for the parameterized type {T}, but + * does not impose any restriction on how that ordering operator is + * implemented. The set is implemented as a linked list. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Double linked list + * - Duplicates allowed? + * Yes + * - Random access allowed? + * No + * - Search speed + * Linear + * - Insert/replace speed + * Linear + * - Iterator still valid after change to container? + * Yes + * - Frees memory for removed elements? + * Yes + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + * -# operator== + * -# operator< + */ +template +class ACE_Ordered_MultiSet +{ +public: + friend class ACE_Ordered_MultiSet_Iterator; + + // Trait definition. + typedef ACE_Ordered_MultiSet_Iterator ITERATOR; + + // = Initialization and termination methods. + /// Constructor. Use user specified allocation strategy + /// if specified. + /** + * Initialize the set using the allocation strategy specified. If none, use the + * default strategy. + */ + ACE_Ordered_MultiSet (ACE_Allocator *the_allocator = 0); + + /// Copy constructor. + /** + * Initialize the set to be a copy of the provided set. + */ + ACE_Ordered_MultiSet (const ACE_Ordered_MultiSet &); + + /// Destructor. + /** + * Delete the nodes of the set. + */ + ~ACE_Ordered_MultiSet (void); + + /// Assignment operator. + /** + * Delete the nodes in lhs, and copy the nodes from the rhs. + */ + void operator= (const ACE_Ordered_MultiSet &); + + // = Check boundary conditions. + + /// Returns 1 if the container is empty, otherwise returns 0. + /** + * Constant time check to determine if the set is empty. + */ + int is_empty (void) const; + + /// Size of the set. + /** + * Constant time check to determine the size of the set. + */ + size_t size (void) const; + + // = Classic unordered set operations. + + /// Insert @a new_item into the ordered multiset. + /// Returns -1 if failures occur, else 0. + /** + * Linear time, order preserving insert into the set beginning at the head. + */ + int insert (const T &new_item); + + ///Linear time insert beginning at the point specified by the provided iterator. + /** + * Insert @a new_item into the ordered multiset, starting its search at + * the node pointed to by the iterator, and if insertion was successful, + * updates the iterator to point to the newly inserted node. + * Returns -1 if failures occur, else 0. + */ + int insert (const T &new_item, ITERATOR &iter); + + /// Remove first occurrence of @a item from the set. Returns 0 if + /// it removes the item, -1 if it can't find the item. + /** + * Linear time search operation which removes the item from the set if found . + */ + int remove (const T &item); + + ///Linear find operation. + /** + * Finds first occurrence of @a item in the multiset, using the iterator's + * current position as a hint to improve performance. If find succeeds, + * it positions the iterator at that node and returns 0, or if it cannot + * locate the node, it leaves the iterator alone and just returns -1. + */ + int find (const T &item, ITERATOR &iter) const; + + /// Reset the ACE_Ordered_MultiSet to be empty. + /** + * Delete the nodes inside the set. + */ + void reset (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /** + * Insert @a item, starting its search at the position given, + * and if successful updates the passed pointer to point to + * the newly inserted item's node. + */ + int insert_from (const T &item, ACE_DNode *start_position, + ACE_DNode **new_position); + + /** + * Looks for first occurrence of @a item in the ordered set, using the + * passed starting position as a hint: if there is such an instance, it + * updates the new_position pointer to point to this node and returns 0; + * if there is no such node, then if there is a node before where the + * item would have been, it updates the new_position pointer to point + * to this node and returns -1; if there is no such node, then if there + * is a node after where the item would have been, it updates the + * new_position pointer to point to this node (or 0 if there is no such + * node) and returns 1; + */ + int locate (const T &item, ACE_DNode *start_position, + ACE_DNode *&new_position) const; + + /// Delete all the nodes in the Set. + void delete_nodes (void); + + /// Copy nodes into this set. + void copy_nodes (const ACE_Ordered_MultiSet &); + + /// Head of the bilinked list of Nodes. + ACE_DNode *head_; + + /// Head of the bilinked list of Nodes. + ACE_DNode *tail_; + + /// Current size of the set. + size_t cur_size_; + + /// Allocation strategy of the set. + ACE_Allocator *allocator_; +}; + +// **************************************************************** + +/** + * @class ACE_Array + * + * @brief A dynamic array class. + * + * This class extends ACE_Array_Base, adding comparison operators. + * + * Requirements and Performance Characteristics + * - Internal Structure + * Dynamic array + * - Duplicates allowed? + * Yes + * - Random access allowed? + * Yes + * - Search speed + * N/A + * - Insert/replace speed + * O(1) + * - Iterator still valid after change to container? + * - In general, yes. + * - If array size is changed during iteration, no. + * - Frees memory for removed elements? + * No + * - Items inserted by + * Value + * - Requirements for contained type + * -# Default constructor + * -# Copy constructor + * -# operator= + * -# operator!= + * + * @sa ACE_Array_Base. This class inherits its operations and requirements. + */ +template +class ACE_Array : public ACE_Array_Base +{ +public: + // Define a "trait" + typedef T TYPE; + typedef ACE_Array_Iterator ITERATOR; + + /// Dynamically create an uninitialized array. + /** + * Initialize an empty array of the specified size using the provided + * allocation strategy. + */ + ACE_Array (size_t size = 0, + ACE_Allocator* alloc = 0); + + /// Dynamically initialize the entire array to the {default_value}. + /** + * Initialize an array the given size placing the default_value in each index. + */ + ACE_Array (size_t size, + const T &default_value, + ACE_Allocator* alloc = 0); + + ///Copy constructor. + /** + * The copy constructor performs initialization by making an exact + * copy of the contents of parameter {s}, i.e., *this == s will + * return true. + */ + ACE_Array (const ACE_Array &s); + + ///Assignment operator + /** + * Assignment operator performs an assignment by making an exact + * copy of the contents of parameter {s}, i.e., *this == s will + * return true. Note that if the {max_size_} of {array_} is >= than + * {s.max_size_} we can copy it without reallocating. However, if + * {max_size_} is < {s.max_size_} we must delete the {array_}, + * reallocate a new {array_}, and then copy the contents of {s}. + */ + void operator= (const ACE_Array &s); + + // = Compare operators + + ///Equality comparison operator. + /** + * Compare this array with {s} for equality. Two arrays are equal + * if their {size}'s are equal and all the elements from 0 .. {size} + * are equal. + */ + bool operator== (const ACE_Array &s) const; + + ///Inequality comparison operator. + /** + * Compare this array with {s} for inequality such that {*this} != + * {s} is always the complement of the boolean return value of + * {*this} == {s}. + */ + bool operator!= (const ACE_Array &s) const; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Containers_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Containers_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Containers_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_CONTAINERS_T_H */ diff --git a/dep/acelite/ace/Containers_T.inl b/dep/acelite/ace/Containers_T.inl new file mode 100644 index 000000000..adc0f42cd --- /dev/null +++ b/dep/acelite/ace/Containers_T.inl @@ -0,0 +1,476 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE int +ACE_Bounded_Stack::is_empty (void) const +{ + ACE_TRACE ("ACE_Bounded_Stack::is_empty"); + return this->top_ == 0; +} + +template ACE_INLINE int +ACE_Bounded_Stack::is_full (void) const +{ + ACE_TRACE ("ACE_Bounded_Stack::is_full"); + return this->top_ >= this->size_; +} + +template ACE_INLINE int +ACE_Bounded_Stack::push (const T &new_item) +{ + ACE_TRACE ("ACE_Bounded_Stack::push"); + if (this->is_full () == 0) + { + this->stack_[this->top_++] = new_item; + return 0; + } + else + return -1; +} + +template ACE_INLINE int +ACE_Bounded_Stack::pop (T &item) +{ + ACE_TRACE ("ACE_Bounded_Stack::pop"); + if (this->is_empty () == 0) + { + item = this->stack_[--this->top_]; + return 0; + } + else + return -1; +} + +template ACE_INLINE int +ACE_Bounded_Stack::top (T &item) const +{ + ACE_TRACE ("ACE_Bounded_Stack::top"); + if (this->is_empty () == 0) + { + item = this->stack_[this->top_ - 1]; + return 0; + } + else + return -1; +} + +template ACE_INLINE size_t +ACE_Bounded_Stack::size (void) const +{ + return this->size_; +} + +//---------------------------------------- + +template ACE_INLINE int +ACE_Fixed_Stack::is_empty (void) const +{ + ACE_TRACE ("ACE_Fixed_Stack::is_empty"); + return this->top_ == 0; +} + +template ACE_INLINE int +ACE_Fixed_Stack::is_full (void) const +{ + ACE_TRACE ("ACE_Fixed_Stack::is_full"); + return this->top_ >= this->size_; +} + +template ACE_INLINE int +ACE_Fixed_Stack::push (const T &new_item) +{ + ACE_TRACE ("ACE_Fixed_Stack::push"); + if (this->is_full () == 0) + { + this->stack_[this->top_++] = new_item; + return 0; + } + else + return -1; +} + +template ACE_INLINE int +ACE_Fixed_Stack::pop (T &item) +{ + ACE_TRACE ("ACE_Fixed_Stack::pop"); + if (this->is_empty () == 0) + { + item = this->stack_[--this->top_]; + return 0; + } + else + return -1; +} + +template ACE_INLINE int +ACE_Fixed_Stack::top (T &item) const +{ + ACE_TRACE ("ACE_Fixed_Stack::top"); + if (this->is_empty () == 0) + { + item = this->stack_[this->top_ - 1]; + return 0; + } + else + return -1; +} + +template ACE_INLINE size_t +ACE_Fixed_Stack::size (void) const +{ + return this->size_; +} + +template ACE_INLINE int +ACE_Unbounded_Stack::is_empty (void) const +{ + // ACE_TRACE ("ACE_Unbounded_Stack::is_empty"); + return this->head_ == this->head_->next_; +} + +template ACE_INLINE int +ACE_Unbounded_Stack::top (T &item) const +{ + ACE_TRACE ("ACE_Unbounded_Stack::top"); + if (this->is_empty () == 0) + { + item = this->head_->next_->item_; + return 0; + } + else + return -1; +} + +template ACE_INLINE int +ACE_Unbounded_Stack::is_full (void) const +{ + ACE_TRACE ("ACE_Unbounded_Stack::is_full"); + return 0; // ??? +} + +template ACE_INLINE size_t +ACE_Unbounded_Stack::size (void) const +{ + return this->cur_size_; +} + +// --- + + +// --- + +template ACE_INLINE int +ACE_Fixed_Set::is_empty (void) const +{ + ACE_TRACE ("ACE_Fixed_Set::is_empty"); + return this->cur_size_ == 0; +} + +template ACE_INLINE int +ACE_Fixed_Set::is_full (void) const +{ + ACE_TRACE ("ACE_Fixed_Set::is_full"); + return this->cur_size_ == this->max_size_; +} + +// --- + +template ACE_INLINE int +ACE_Bounded_Set::is_empty (void) const +{ + ACE_TRACE ("ACE_Bounded_Set::is_empty"); + return this->cur_size_ == 0; +} + +template ACE_INLINE int +ACE_Bounded_Set::is_full (void) const +{ + ACE_TRACE ("ACE_Bounded_Set::is_full"); + return this->cur_size_ == this->max_size_; +} + +// -- + +template ACE_INLINE int +ACE_Ordered_MultiSet_Iterator::first (void) +{ + ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::first"); + current_ = set_.head_; + + return (current_ ? 1 : 0); +} + +template ACE_INLINE int +ACE_Ordered_MultiSet_Iterator::last (void) +{ + ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::last"); + current_ = set_.tail_; + + return (current_ ? 1 : 0); +} + +template ACE_INLINE int +ACE_Ordered_MultiSet_Iterator::advance (void) +{ + ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::advance"); + + current_ = current_ ? current_->next_ : 0; + + return (current_ ? 1 : 0); +} + +template ACE_INLINE int +ACE_Ordered_MultiSet_Iterator::retreat (void) +{ + ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::retreat"); + + current_ = current_ ? current_->prev_ : 0; + + return (current_ ? 1 : 0); +} + +template ACE_INLINE int +ACE_Ordered_MultiSet_Iterator::done (void) const +{ + ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::done"); + + return (current_ ? 0 : 1); +} + +template ACE_INLINE void +ACE_Ordered_MultiSet_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Ordered_MultiSet_Iterator::dump"); +#endif /* ACE_HAS_DUMP */ +} + + + +// -- + +template ACE_INLINE int +ACE_Ordered_MultiSet::is_empty (void) const +{ + ACE_TRACE ("ACE_Ordered_MultiSet::is_empty"); + return this->cur_size_ > 0 ? 0 : 1; +} + +template ACE_INLINE size_t +ACE_Ordered_MultiSet::size (void) const +{ +// ACE_TRACE ("ACE_Ordered_MultiSet::size"); + return this->cur_size_; +} + +// **************************************************************** + +template ACE_INLINE +ACE_Array::ACE_Array (size_t size, + ACE_Allocator *alloc) + : ACE_Array_Base (size, alloc) +{ +} + +template ACE_INLINE +ACE_Array::ACE_Array (size_t size, + const T &default_value, + ACE_Allocator *alloc) + : ACE_Array_Base (size, default_value, alloc) +{ +} + +// The copy constructor (performs initialization). + +template ACE_INLINE +ACE_Array::ACE_Array (const ACE_Array &s) + : ACE_Array_Base (s) +{ +} + +// Assignment operator (performs assignment). + +template ACE_INLINE void +ACE_Array::operator= (const ACE_Array &s) +{ + // Check for "self-assignment". + + if (this != &s) + this->ACE_Array_Base::operator= (s); +} + +// Compare this array with for inequality. + +template ACE_INLINE bool +ACE_Array::operator!= (const ACE_Array &s) const +{ + return !(*this == s); +} + +// **************************************************************** + + +// **************************************************************** + +template ACE_INLINE void +ACE_DLList::operator= (const ACE_DLList &l) +{ + *(ACE_DLList_Base *) this = l; +} + +template ACE_INLINE int +ACE_DLList::get (T *&item, size_t index) +{ + ACE_DLList_Node *node; + int result = ACE_DLList_Base::get (node, index); + if (result != -1) + item = (T *) node->item_; + return result; +} + +template ACE_INLINE void +ACE_DLList::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_DLList_Base::dump (); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_INLINE int +ACE_DLList::remove (ACE_DLList_Node *n) +{ + int result = ACE_DLList_Base::remove (n); + ACE_DES_FREE (n, + this->allocator_->free, + ACE_DLList_Node); + return result; +} + +template ACE_INLINE +ACE_DLList::ACE_DLList (ACE_Allocator *alloc) + : ACE_DLList_Base (alloc) +{ +} + +template ACE_INLINE +ACE_DLList::ACE_DLList (const ACE_DLList &l) + : ACE_DLList_Base ((ACE_DLList &) l) +{ +} + +template ACE_INLINE +ACE_DLList::~ACE_DLList (void) +{ + while (this->delete_head ()) ; +} + +template ACE_INLINE int +ACE_DLList_Iterator::remove (void) +{ + ACE_DLList_Node *temp = this->ACE_Double_Linked_List_Iterator ::next (); + this->ACE_Double_Linked_List_Iterator ::advance (); + return list_->remove (temp); +} + +template ACE_INLINE +ACE_DLList_Iterator::ACE_DLList_Iterator (ACE_DLList &l) + : ACE_Double_Linked_List_Iterator ((ACE_DLList_Base &)l), + list_ (&l) +{ +} + +template ACE_INLINE void +ACE_DLList_Iterator::reset (ACE_DLList &l) +{ + list_ = &l; + this->ACE_Double_Linked_List_Iterator ::reset ((ACE_DLList_Base &)l); +} + +template ACE_INLINE int +ACE_DLList_Iterator::next (T *&ptr) +{ + ACE_DLList_Node *temp = + ACE_Double_Linked_List_Iterator ::next (); + if (temp) + ptr = (T *) temp->item_; + return temp ? 1 : 0; +} + +template ACE_INLINE T * +ACE_DLList_Iterator::next (void) const +{ + ACE_DLList_Node *temp = ACE_Double_Linked_List_Iterator ::next (); + return (T *) (temp ? temp->item_ : 0); +} + +template ACE_INLINE int +ACE_DLList_Iterator::advance (void) +{ + return this->ACE_Double_Linked_List_Iterator ::advance (); +} + +template ACE_INLINE void +ACE_DLList_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_Double_Linked_List_Iterator ::dump (); +#endif /* ACE_HAS_DUMP */ +} + + +template ACE_INLINE int +ACE_DLList_Reverse_Iterator::remove (void) +{ + ACE_DLList_Node *temp = ACE_Double_Linked_List_Reverse_Iterator ::next (); + this->ACE_Double_Linked_List_Reverse_Iterator ::advance (); + return list_->remove (temp); +} + +template ACE_INLINE +ACE_DLList_Reverse_Iterator::ACE_DLList_Reverse_Iterator (ACE_DLList &l) + : ACE_Double_Linked_List_Reverse_Iterator ((ACE_DLList_Base &)l), + list_ (&l) +{ +} + +template ACE_INLINE void +ACE_DLList_Reverse_Iterator::reset (ACE_DLList &l) +{ + list_ = &l; + this->ACE_Double_Linked_List_Reverse_Iterator ::reset ((ACE_DLList_Base &)l); +} + +template ACE_INLINE int +ACE_DLList_Reverse_Iterator::advance (void) +{ + return ACE_Double_Linked_List_Reverse_Iterator ::advance (); +} + +template ACE_INLINE int +ACE_DLList_Reverse_Iterator::next (T *&ptr) +{ + ACE_DLList_Node *temp = + ACE_Double_Linked_List_Reverse_Iterator ::next (); + if (temp == 0) + return 0; + ptr = (T *) temp->item_; + return 1; +} + +template ACE_INLINE T * +ACE_DLList_Reverse_Iterator::next (void) const +{ + ACE_DLList_Node *temp = ACE_Double_Linked_List_Reverse_Iterator ::next (); + return (T *) (temp ? temp->item_ : 0); +} + + +template ACE_INLINE void +ACE_DLList_Reverse_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_Double_Linked_List_Reverse_Iterator ::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Copy_Disabled.cpp b/dep/acelite/ace/Copy_Disabled.cpp new file mode 100644 index 000000000..59c6ba7af --- /dev/null +++ b/dep/acelite/ace/Copy_Disabled.cpp @@ -0,0 +1,15 @@ +/** + * @file Copy_Disabled.cpp + * + * @author Carlos O'Ryan + */ + +#include "ace/Copy_Disabled.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Copy_Disabled::ACE_Copy_Disabled (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Copy_Disabled.h b/dep/acelite/ace/Copy_Disabled.h new file mode 100644 index 000000000..374227e8a --- /dev/null +++ b/dep/acelite/ace/Copy_Disabled.h @@ -0,0 +1,62 @@ +// -*- C++ -*- + +//=========================================================================== +/** + * @file Copy_Disabled.h + * + * @author Carlos O'Ryan + */ +//=========================================================================== + +#ifndef ACE_COPY_DISABLED_H +#define ACE_COPY_DISABLED_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Copy_Disabled + * + * @brief Helper class to disable copy construction and assignment + * + * Classes used to control OS and other resources are not "canonical", + * i.e. they have their copy constructor and assignment operators + * disabled. + * This is often done by making the copy constructor and assignment + * operators private, effectively disallowing copying by clients of + * the class (including derived classes). If the copy constructor and + * assingment operators are left unimplemented then the class itself + * cannot make any copies of its instances, because it would result in + * link errors. + * + * To use this class simply use private inheritance: + * + * class Foo : private ACE_Copy_Disabled + * { + * // code here + * }; + */ +class ACE_Export ACE_Copy_Disabled +{ +public: + + /// Default constructor + ACE_Copy_Disabled (void); + +private: + ACE_Copy_Disabled (const ACE_Copy_Disabled &); + ACE_Copy_Disabled &operator= (const ACE_Copy_Disabled &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_COPY_DISABLED_H */ diff --git a/dep/acelite/ace/Countdown_Time.h b/dep/acelite/ace/Countdown_Time.h new file mode 100644 index 000000000..b6966d68f --- /dev/null +++ b/dep/acelite/ace/Countdown_Time.h @@ -0,0 +1,34 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Countdown_Time.h + * + * @author Douglas C. Schmidt + * @author Irfan Pyarali + */ +//============================================================================= + +#ifndef ACE_COUNTDOWN_TIME_H +#define ACE_COUNTDOWN_TIME_H + +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Countdown_Time_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// The following typedef is here for ease of use and backward +// compatibility. +typedef ACE_Countdown_Time_T + ACE_Countdown_Time; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_COUNTDOWN_TIME_H */ diff --git a/dep/acelite/ace/Countdown_Time_T.cpp b/dep/acelite/ace/Countdown_Time_T.cpp new file mode 100644 index 000000000..8a38c4de1 --- /dev/null +++ b/dep/acelite/ace/Countdown_Time_T.cpp @@ -0,0 +1,65 @@ +#ifndef ACE_COUNTDOWN_TIME_T_CPP +#define ACE_COUNTDOWN_TIME_T_CPP + +#include "ace/Countdown_Time_T.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Countdown_Time_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_Countdown_Time_T::ACE_Countdown_Time_T (ACE_Time_Value *max_wait_time, + TIME_POLICY const & time_policy) + : time_policy_ (time_policy), + max_wait_time_ (max_wait_time), + max_wait_value_ (ACE_Time_Value::zero), + stopped_ (false) +{ + this->start (); +} + +template ACE_INLINE +ACE_Countdown_Time_T::~ACE_Countdown_Time_T (void) +{ + this->stop (); +} + +template ACE_INLINE void +ACE_Countdown_Time_T::start (void) +{ + if (this->max_wait_time_ != 0) + { + this->max_wait_value_ = *this->max_wait_time_; + this->start_time_ = this->time_policy_ (); + this->stopped_ = false; + } +} + +template ACE_INLINE void +ACE_Countdown_Time_T::stop (void) +{ + if (this->max_wait_time_ != 0 && !this->stopped_) + { + ACE_Time_Value const elapsed_time = + this->time_policy_ () - this->start_time_; + + if (elapsed_time >= ACE_Time_Value::zero && + this->max_wait_value_ > elapsed_time) + { + *this->max_wait_time_ = this->max_wait_value_ - elapsed_time; + } + else + { + // Used all of timeout. + *this->max_wait_time_ = ACE_Time_Value::zero; + // errno = ETIME; + } + this->stopped_ = true; + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_COUNTDOWN_TIME_T_CPP */ diff --git a/dep/acelite/ace/Countdown_Time_T.h b/dep/acelite/ace/Countdown_Time_T.h new file mode 100644 index 000000000..12aab657b --- /dev/null +++ b/dep/acelite/ace/Countdown_Time_T.h @@ -0,0 +1,101 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Countdown_Time_T.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_COUNTDOWN_TIME_T_H +#define ACE_COUNTDOWN_TIME_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Time_Value.h" +#include "ace/Time_Policy.h" +#include "ace/Copy_Disabled.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Countdown_Time + * + * @brief Keeps track of the amount of elapsed time. + * + * This class has a side-effect on the @c max_wait_time -- every + * time the stop() method is called the @c max_wait_time is + * updated. + */ +template +class ACE_Countdown_Time_T : private ACE_Copy_Disabled +{ +public: + /// Cache the @a max_wait_time and call @c start(). + ACE_Countdown_Time_T (ACE_Time_Value *max_wait_time, + TIME_POLICY const & time_policy = TIME_POLICY()); + + /// Destructor, makes sure the max_wait_time that got passed as pointer + /// to the constructor is updated with the time elapsed. + ~ACE_Countdown_Time_T (void); + + /// Cache the current time and enter a start state. + void start (void); + + /// Subtract the elapsed time from max_wait_time_ and enter a stopped + /// state. + void stop (void); + + /// Calls stop and then start. max_wait_time_ is modified by the + /// call to stop. + void update (void); + + /// Returns true if we've already been stopped, else false. + bool stopped (void) const; + + /// Allows applications to control how the timer queue gets the time + /// of day. + void set_time_policy(TIME_POLICY const & time_policy); + +private: + /// The policy to return the current time of day + TIME_POLICY time_policy_; + + /// Maximum time we are monitoring + ACE_Time_Value *max_wait_time_; + + /// Copy of the maximum time value, used to avoid nested decrements + ACE_Time_Value max_wait_value_; + + /// Beginning of the start time. + ACE_Time_Value start_time_; + + /// Keeps track of whether we've already been stopped. + bool stopped_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#if defined (__ACE_INLINE__) +#include "ace/Countdown_Time_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Countdown_Time_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Countdown_Time_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + + +#endif /* ACE_COUNTDOWN_TIME_T_H */ diff --git a/dep/acelite/ace/Countdown_Time_T.inl b/dep/acelite/ace/Countdown_Time_T.inl new file mode 100644 index 000000000..319729d9c --- /dev/null +++ b/dep/acelite/ace/Countdown_Time_T.inl @@ -0,0 +1,23 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE bool +ACE_Countdown_Time_T::stopped (void) const +{ + return stopped_; +} + +template ACE_INLINE void +ACE_Countdown_Time_T::update (void) +{ + this->stop (); + this->start (); +} + +template ACE_INLINE void +ACE_Countdown_Time_T::set_time_policy(TIME_POLICY const & time_policy) +{ + this->time_policy_ = time_policy; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV.cpp b/dep/acelite/ace/DEV.cpp new file mode 100644 index 000000000..08a7e581f --- /dev/null +++ b/dep/acelite/ace/DEV.cpp @@ -0,0 +1,45 @@ +#include "ace/DEV.h" + +#include "ace/OS_NS_unistd.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/DEV.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_DEV) + +void +ACE_DEV::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_DEV::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// This is the do-nothing constructor. + +ACE_DEV::ACE_DEV (void) +{ + ACE_TRACE ("ACE_DEV::ACE_DEV"); +} + +// Close the device + +int +ACE_DEV::close (void) +{ + ACE_TRACE ("ACE_DEV::close"); + int result = ACE_OS::close (this->get_handle ()); + this->set_handle (ACE_INVALID_HANDLE); + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV.h b/dep/acelite/ace/DEV.h new file mode 100644 index 000000000..c74c23429 --- /dev/null +++ b/dep/acelite/ace/DEV.h @@ -0,0 +1,63 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file DEV.h + * + * @author Gerhard Lenzer + */ +//============================================================================= + + +#ifndef ACE_DEV_H +#define ACE_DEV_H +#include /**/ "ace/pre.h" + +#include "ace/IO_SAP.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/DEV_Addr.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_DEV + * + * @brief Defines the member functions for the base class of the + * ACE_DEV abstraction. + */ +class ACE_Export ACE_DEV : public ACE_IO_SAP +{ +public: + /// Close down the DEVICE + int close (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /** + * Disable signal @a signum + * This is here to prevent Win32 from + * disabling SPIPE using socket calls + */ + int disable (int signum) const ; + +protected: + /// Ensure that this class is an abstract base class + ACE_DEV (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/DEV.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DEV_H */ diff --git a/dep/acelite/ace/DEV.inl b/dep/acelite/ace/DEV.inl new file mode 100644 index 000000000..ee0bb7838 --- /dev/null +++ b/dep/acelite/ace/DEV.inl @@ -0,0 +1,15 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_DEV::disable (int signum) const +{ +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (signum) ; + return 0 ; +#else /* ACE_WIN32 */ + return ACE_IO_SAP::disable (signum) ; +#endif /* ACE_WIN32 */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_Addr.cpp b/dep/acelite/ace/DEV_Addr.cpp new file mode 100644 index 000000000..c5c2cc3bc --- /dev/null +++ b/dep/acelite/ace/DEV_Addr.cpp @@ -0,0 +1,105 @@ +#include "ace/DEV_Addr.h" +#if !defined (__ACE_INLINE__) +#include "ace/DEV_Addr.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/OS_NS_string.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_DEV_Addr) + +// Transform the current address into string format. + +int +ACE_DEV_Addr::addr_to_string (ACE_TCHAR *s, size_t len) const +{ + ACE_TRACE ("ACE_DEV_Addr::addr_to_string"); + + ACE_OS::strsncpy (s, this->devname_, len); + return 0; +} + +// Return a pointer to the address. + +void * +ACE_DEV_Addr::get_addr (void) const +{ + ACE_TRACE ("ACE_DEV_Addr::get_addr"); + + return (void *) &this->devname_; +} + +void +ACE_DEV_Addr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_DEV_Addr::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("devname_ = %s"), this->devname_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Do nothing constructor. + +ACE_DEV_Addr::ACE_DEV_Addr (void) + : ACE_Addr (AF_DEV, sizeof this->devname_) +{ + ACE_TRACE ("ACE_DEV_Addr::ACE_DEV_Addr"); + + (void) ACE_OS::memset ((void *) &this->devname_, + 0, sizeof this->devname_); +} + +int +ACE_DEV_Addr::set (const ACE_DEV_Addr &sa) +{ + this->base_set (sa.get_type (), sa.get_size ()); + + if (sa.get_type () == AF_ANY) + (void) ACE_OS::memset ((void *) &this->devname_, + 0, + sizeof this->devname_); + else + (void) ACE_OS::strsncpy (this->devname_, + sa.devname_, + ACE_DEV_Addr::DEVNAME_LENGTH); + return 0; +} + +// Copy constructor. + +ACE_DEV_Addr::ACE_DEV_Addr (const ACE_DEV_Addr &sa) + : ACE_Addr (AF_DEV, sizeof this->devname_) +{ + ACE_TRACE ("ACE_DEV_Addr::ACE_DEV_Addr"); + + this->set (sa); +} + +ACE_DEV_Addr::ACE_DEV_Addr (const ACE_TCHAR *devname) + : ACE_Addr (AF_DEV, sizeof this->devname_) +{ + ACE_TRACE ("ACE_DEV_Addr::ACE_DEV_Addr"); + + this->set (devname); +} + +ACE_DEV_Addr & +ACE_DEV_Addr::operator= (const ACE_DEV_Addr &sa) +{ + ACE_TRACE ("ACE_DEV_Addr::operator="); + + if (this != &sa) + this->set (sa); + + return *this; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_Addr.h b/dep/acelite/ace/DEV_Addr.h new file mode 100644 index 000000000..3bbbad057 --- /dev/null +++ b/dep/acelite/ace/DEV_Addr.h @@ -0,0 +1,88 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file DEV_Addr.h + * + * @author Gerhard Lenzer and Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_DEV_ADDR_H +#define ACE_DEV_ADDR_H + +#include /**/ "ace/pre.h" + +#include "ace/Addr.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/os_dirent.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_DEV_Addr + * + * @brief Defines device address family address format. + */ +class ACE_Export ACE_DEV_Addr : public ACE_Addr +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_DEV_Addr (void); + + /// Copy constructor. + ACE_DEV_Addr (const ACE_DEV_Addr &sa); + + /// Acts like a copy constructor. + int set (const ACE_DEV_Addr &sa); + + /// Create a ACE_DEV_Addr from a device name. + explicit ACE_DEV_Addr (const ACE_TCHAR *devname); + + /// Create a ACE_Addr from a ACE_DEV pathname. + void set (const ACE_TCHAR *devname); + + /// Assignment operator. + ACE_DEV_Addr &operator= (const ACE_DEV_Addr &); + + /// Return a pointer to the address. + virtual void *get_addr (void) const; + + /// Transform the current address into string format. + virtual int addr_to_string (ACE_TCHAR *addr, size_t) const; + + /// Compare two addresses for equality. + bool operator == (const ACE_DEV_Addr &SAP) const; + + /// Compare two addresses for inequality. + bool operator != (const ACE_DEV_Addr &SAP) const; + + /// Return the path name used for the rendezvous point. + const ACE_TCHAR *get_path_name (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + enum { DEVNAME_LENGTH = MAXPATHLEN + 1 }; + /// Name of the device. + ACE_TCHAR devname_[DEVNAME_LENGTH]; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/DEV_Addr.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_DEV_ADDR_H */ diff --git a/dep/acelite/ace/DEV_Addr.inl b/dep/acelite/ace/DEV_Addr.inl new file mode 100644 index 000000000..3025745f2 --- /dev/null +++ b/dep/acelite/ace/DEV_Addr.inl @@ -0,0 +1,48 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" +#include "ace/Global_Macros.h" +#include "ace/os_include/sys/os_socket.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_DEV_Addr::set (const ACE_TCHAR *devname) +{ + ACE_TRACE ("ACE_DEV_Addr::set"); + + this->ACE_Addr::base_set + (AF_DEV, static_cast (ACE_OS::strlen (devname))); + ACE_OS::strsncpy (this->devname_, devname, ACE_DEV_Addr::DEVNAME_LENGTH); +} + +// Compare two addresses for equality. + +ACE_INLINE bool +ACE_DEV_Addr::operator == (const ACE_DEV_Addr &sap) const +{ + ACE_TRACE ("ACE_DEV_Addr::operator =="); + + return ACE_OS::strcmp (this->devname_, sap.devname_) == 0; +} + +// Compare two addresses for inequality. + +ACE_INLINE bool +ACE_DEV_Addr::operator != (const ACE_DEV_Addr &sap) const +{ + ACE_TRACE ("ACE_DEV_Addr::operator !="); + + return !((*this) == sap); // This is lazy, of course... ;-). +} + +// Return the path name used for the rendezvous point. + +ACE_INLINE const ACE_TCHAR * +ACE_DEV_Addr::get_path_name (void) const +{ + ACE_TRACE ("ACE_DEV_Addr::get_path_name"); + + return this->devname_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_Connector.cpp b/dep/acelite/ace/DEV_Connector.cpp new file mode 100644 index 000000000..159e5ecee --- /dev/null +++ b/dep/acelite/ace/DEV_Connector.cpp @@ -0,0 +1,48 @@ +#include "ace/DEV_Connector.h" + +#include "ace/Handle_Ops.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/DEV_Connector.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_DEV_Connector) + +void +ACE_DEV_Connector::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_DEV_Connector::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_DEV_Connector::ACE_DEV_Connector (void) +{ + ACE_TRACE ("ACE_DEV_Connector::ACE_DEV_Connector"); +} + +int +ACE_DEV_Connector::connect (ACE_DEV_IO &new_io, + const ACE_DEV_Addr &remote_sap, + ACE_Time_Value *timeout, + const ACE_Addr &, + int, + int flags, + int perms) +{ + ACE_TRACE ("ACE_DEV_Connector::connect"); + + ACE_HANDLE handle = ACE::handle_timed_open (timeout, + remote_sap.get_path_name (), + flags, perms); + new_io.set_handle (handle); + new_io.addr_ = remote_sap; // class copy. + return handle == ACE_INVALID_HANDLE ? -1 : 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_Connector.h b/dep/acelite/ace/DEV_Connector.h new file mode 100644 index 000000000..5c889301b --- /dev/null +++ b/dep/acelite/ace/DEV_Connector.h @@ -0,0 +1,108 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file DEV_Connector.h + * + * @author Gerhard Lenzer and Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_DEV_CONNECTOR_H +#define ACE_DEV_CONNECTOR_H +#include /**/ "ace/pre.h" + +#include "ace/DEV_IO.h" +#include "ace/Log_Category.h" +#include "ace/os_include/os_fcntl.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_DEV_Connector + * + * @brief Defines an active connection factory for the ACE_DEV wrappers. + */ +class ACE_Export ACE_DEV_Connector +{ +public: + /// Default constructor. + ACE_DEV_Connector (void); + + /** + * Actively connect and produce a @a new_io if things go well. + * The @a remote_sap is the address that we are trying to connect + * with. The @a timeout is the amount of time to wait to connect. + * If it's 0 then we block indefinitely. If *timeout == {0, 0} then + * the connection is done using non-blocking mode. In this case, if + * the connection can't be made immediately the value of -1 is + * returned with @c errno == EWOULDBLOCK. If *timeout > {0, 0} then + * this is the maximum amount of time to wait before timing out. If the + * time expires before the connection is made @c errno == ETIME. The + * @a local_sap is the value of local address to bind to. If it's + * the default value of ACE_Addr::sap_any then the user is letting + * the OS do the binding. If @a reuse_addr == 1 then the + * is reused, even if it hasn't been cleanedup yet. + * The @a flags and @a perms arguments are passed down to the + * method. + */ + ACE_DEV_Connector (ACE_DEV_IO &new_io, + const ACE_DEV_Addr &remote_sap, + ACE_Time_Value *timeout = 0, + const ACE_Addr &local_sap = ACE_Addr::sap_any, + int reuse_addr = 0, + int flags = O_RDWR, + int perms = 0); + + /** + * Actively connect and produce a @a new_io if things go well. + * The @a remote_sap is the address that we are trying to connect + * with. The @a timeout is the amount of time to wait to connect. + * If it's 0 then we block indefinitely. If *timeout == {0, 0} then + * the connection is done using non-blocking mode. In this case, if + * the connection can't be made immediately the value of -1 is + * returned with @c errno == EWOULDBLOCK. If *timeout > {0, 0} then + * this is the maximum amount of time to wait before timing out. If the + * time expires before the connection is made @c errno == ETIME. The + * @a local_sap is the value of local address to bind to. If it's + * the default value of ACE_Addr::sap_any then the user is letting + * the OS do the binding. If @a reuse_addr == 1 then the + * is reused, even if it hasn't been cleanedup yet. + * The @a flags and @a perms arguments are passed down to the + * method. + */ + int connect (ACE_DEV_IO &new_io, + const ACE_DEV_Addr &remote_sap, + ACE_Time_Value *timeout = 0, + const ACE_Addr &local_sap = ACE_Addr::sap_any, + int reuse_addr = 0, + int flags = O_RDWR, + int perms = 0); + + /// Resets any event associations on this handle + bool reset_new_handle (ACE_HANDLE handle); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Meta-type info + typedef ACE_DEV_Addr PEER_ADDR; + typedef ACE_DEV_IO PEER_STREAM; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/DEV_Connector.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DEV_CONNECTOR_H */ diff --git a/dep/acelite/ace/DEV_Connector.inl b/dep/acelite/ace/DEV_Connector.inl new file mode 100644 index 000000000..b92b4d2a5 --- /dev/null +++ b/dep/acelite/ace/DEV_Connector.inl @@ -0,0 +1,30 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Creates a Local ACE_DEV. + +ACE_INLINE +ACE_DEV_Connector::ACE_DEV_Connector (ACE_DEV_IO &new_io, + const ACE_DEV_Addr &remote_sap, + ACE_Time_Value *timeout, + const ACE_Addr &local_sap, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_DEV_Connector::ACE_DEV_Connector"); + if (this->connect (new_io, remote_sap, timeout, local_sap, + reuse_addr, flags, perms) == ACE_IO_SAP::INVALID_HANDLE + && timeout != 0 && !(errno == EWOULDBLOCK || errno == ETIME)) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("address %s, %p\n"), + remote_sap.get_path_name (), ACE_TEXT ("ACE_DEV_IO"))); +} + +ACE_INLINE bool +ACE_DEV_Connector::reset_new_handle (ACE_HANDLE) +{ + // Nothing to do here since the handle is not a socket + return false; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_IO.cpp b/dep/acelite/ace/DEV_IO.cpp new file mode 100644 index 000000000..f1dcda429 --- /dev/null +++ b/dep/acelite/ace/DEV_IO.cpp @@ -0,0 +1,164 @@ +#include "ace/DEV_IO.h" +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/DEV_IO.inl" +#endif /* __ACE_INLINE__ */ + + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_DEV_IO) + +// Return the local endpoint address. + +int +ACE_DEV_IO::get_local_addr (ACE_DEV_Addr &addr) const +{ + ACE_TRACE ("ACE_DEV_IO::get_local_addr"); + + addr = this->addr_; + return 0; +} + +// Return the address of the remotely connected peer (if there is +// one). + +int +ACE_DEV_IO::get_remote_addr (ACE_DEV_Addr &addr) const +{ + ACE_TRACE ("ACE_DEV_IO::get_remote_addr"); + addr = this->addr_; + return 0; +} + +void +ACE_DEV_IO::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_DEV_IO::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->addr_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Simple-minded do nothing constructor. + +ACE_DEV_IO::ACE_DEV_IO (void) +{ + ACE_TRACE ("ACE_DEV_IO::ACE_DEV_IO"); +} + +// Send N char *ptrs and int lengths. Note that the char *'s precede +// the ints (basically, an varargs version of writev). The count N is +// the *total* number of trailing arguments, *not* a couple of the +// number of tuple pairs! + +ssize_t +ACE_DEV_IO::send (size_t n, ...) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); +#ifdef ACE_LACKS_VA_FUNCTIONS + ACE_UNUSED_ARG (n); + ACE_NOTSUP_RETURN (-1); +#else + va_list argp; + int total_tuples = static_cast (n / 2); + iovec *iovp; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t result = ACE_OS::writev (this->get_handle (), iovp, total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +#endif // ACE_LACKS_VA_FUNCTIONS +} + +// This is basically an interface to ACE_OS::readv, that doesn't use the +// struct iovec explicitly. The ... can be passed as an arbitrary +// number of (char *ptr, int len) tuples. However, the count N is the +// *total* number of trailing arguments, *not* a couple of the number +// of tuple pairs! + +ssize_t +ACE_DEV_IO::recv (size_t n, ...) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); +#ifdef ACE_LACKS_VA_FUNCTIONS + ACE_UNUSED_ARG (n); + ACE_NOTSUP_RETURN (-1); +#else + va_list argp; + int total_tuples = static_cast (n / 2); + iovec *iovp; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t result = ACE_OS::readv (this->get_handle (), iovp, total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +#endif // ACE_LACKS_VA_FUNCTIONS +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DEV_IO.h b/dep/acelite/ace/DEV_IO.h new file mode 100644 index 000000000..9a97c011f --- /dev/null +++ b/dep/acelite/ace/DEV_IO.h @@ -0,0 +1,183 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file DEV_IO.h + * + * @author Gerhard Lenzer + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_DEV_IO_H +#define ACE_DEV_IO_H +#include /**/ "ace/pre.h" + +#include "ace/DEV.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_STREAM_PIPES) +# include "ace/OS_NS_stropts.h" +#endif /* ACE_HAS_STREAM_PIPES */ + +#include "ace/os_include/os_stdio.h" +#include "ace/os_include/sys/os_uio.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @class ACE_DEV_IO + * + * @brief Read/Write operations on Devices. + */ +class ACE_Export ACE_DEV_IO : public ACE_DEV +{ +public: + friend class ACE_DEV_Connector; + + /// Default constructor. + ACE_DEV_IO (void); + + // = Various send operations. + /// send upto @a n bytes in @a buf. + ssize_t send (const void *buf, size_t n) const; + + /// Recv upto @a n bytes in @a buf. + ssize_t recv (void *buf, size_t n) const; + + /// Send n bytes, keep trying until n are sent. + ssize_t send_n (const void *buf, + size_t n) const; + + /** + * @name I/O operations + * + * Notes on common parameters: + * + * @a buf is the buffer to write from or receive into. + * + * @a len is the number of bytes to transfer. + * + * The @a timeout parameter in the following methods indicates how + * long to blocking trying to transfer data. If @a timeout == 0, + * then the call behaves as a normal send/recv call, i.e., for + * blocking sockets, the call will block until action is possible; + * for non-blocking sockets, EWOULDBLOCK will be returned if no + * action is immediately possible. + * + * If @a timeout != 0, the call will wait until the relative time + * specified in *@a timeout elapses. + * + * The "_n()" I/O methods keep looping until all the data has been + * transferred. These methods also work for sockets in non-blocking + * mode i.e., they keep looping on EWOULDBLOCK. @a timeout is used + * to make sure we keep making progress, i.e., the same timeout + * value is used for every I/O operation in the loop and the timeout + * is not counted down. + * + * The return values for the "*_n()" methods match the return values + * from the non "_n()" methods and are specified as follows: + * + * - On complete transfer, the number of bytes transferred is returned. + * - On timeout, -1 is returned, errno == ETIME. + * - On error, -1 is returned, errno is set to appropriate error. + * - On EOF, 0 is returned, errno is irrelevant. + * + * On partial transfers, i.e., if any data is transferred before + * timeout/error/EOF, @a bytes_transferred will contain the number of + * bytes transferred. + */ + ssize_t recv_n (void *buf, + size_t n, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0) const; + +#if defined (ACE_HAS_STREAM_PIPES) + /// Recv bytes via STREAM pipes using "band" mode. + ssize_t recv (ACE_Str_Buf *cntl, + ACE_Str_Buf *data, + int *band, + int *flags) const; + + /// Send bytes via STREAM pipes using "band" mode. + ssize_t send (const ACE_Str_Buf *cntl, + const ACE_Str_Buf *data, + int band, + int flags) const; + + /// Recv @a cntl and @a data via STREAM pipes. + ssize_t recv (ACE_Str_Buf *cntl, + ACE_Str_Buf *data, + int *flags) const; + + /// Send @a cntl and @a data via STREAM pipes. + ssize_t send (const ACE_Str_Buf *cntl, + const ACE_Str_Buf *data, + int flags = 0) const; +#endif /* ACE_HAS_STREAM_PIPES */ + + /// Send iovecs via <::writev>. + ssize_t send (const iovec iov[], size_t n) const; + + /// Recv iovecs via <::readv>. + ssize_t recv (iovec iov[], size_t n) const; + + /** + * Send N char *ptrs and int lengths. Note that the char *'s + * precede the ints (basically, an varargs version of writev). The + * count N is the *total* number of trailing arguments, *not* a + * couple of the number of tuple pairs! + */ + ssize_t send (size_t n, ...) const; + + /** + * This is an interface to ::readv, that doesn't use the struct + * iovec explicitly. The ... can be passed as an arbitrary number + * of (char *ptr, int len) tuples. However, the count N is the + * *total* number of trailing arguments, *not* a couple of the + * number of tuple pairs! + */ + ssize_t recv (size_t n, ...) const; + + /// Send @a n bytes via Win32 WriteFile using overlapped I/O. + ssize_t send (const void *buf, size_t n, ACE_OVERLAPPED *overlapped) const; + + /// Recv @a n bytes via Win32 ReadFile using overlapped I/O. + ssize_t recv (void *buf, size_t n, ACE_OVERLAPPED *overlapped) const; + + /// Dump the state of an object. + void dump (void) const; + + // = The following two methods are no-ops to keep the + // ACE_Connector happy. + /// Return the local endpoint address. + int get_local_addr (ACE_DEV_Addr &) const; + + /// Return the address of the remotely connected peer (if there is + /// one). + int get_remote_addr (ACE_DEV_Addr &) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Meta-type info + typedef ACE_DEV_Addr PEER_ADDR; + +private: + /// Address of device we are connected to. + ACE_DEV_Addr addr_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/DEV_IO.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DEV_IO_H */ diff --git a/dep/acelite/ace/DEV_IO.inl b/dep/acelite/ace/DEV_IO.inl new file mode 100644 index 000000000..45e4a0970 --- /dev/null +++ b/dep/acelite/ace/DEV_IO.inl @@ -0,0 +1,123 @@ +// -*- C++ -*- +#include "ace/OS_NS_sys_uio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_Memory.h" + +#include "ace/ACE.h" + +// Send exactly N bytes from BUF to this device. Keeping trying until +// this many bytes are sent. + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_DEV_IO::send_n (const void *buf, size_t n) const +{ + ACE_TRACE ("ACE_DEV_IO::send_n"); + return ACE::write_n (this->get_handle (), buf, n); +} + +// Receive exactly N bytes from this file into BUF. Keep trying until +// this many bytes are received. + +ACE_INLINE ssize_t +ACE_DEV_IO::recv_n (void *buf, + size_t n, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) const +{ + ACE_TRACE ("ACE_DEV_IO::recv_n"); +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (timeout); + + return ACE::read_n (this->get_handle (), + buf, + n, + bytes_transferred); +#else + return ACE::recv_n (this->get_handle (), + buf, + n, + timeout, + bytes_transferred); +#endif /*ACE_WIN32*/ +} + +ACE_INLINE ssize_t +ACE_DEV_IO::send (const void *buf, size_t n) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); + return ACE_OS::write (this->get_handle (), (const char *) buf, n); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::recv (void *buf, size_t n) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); + return ACE_OS::read (this->get_handle (), (char *) buf, n); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::send (const iovec iov[], size_t n) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); + return ACE_OS::writev (this->get_handle (), iov, static_cast (n)); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::recv (iovec iov[], size_t n) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); + return ACE_OS::readv (this->get_handle (), iov, static_cast (n)); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::send (const void *buf, size_t n, + ACE_OVERLAPPED *overlapped) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); + return ACE_OS::write (this->get_handle (), + (const char *) buf, n, + overlapped); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::recv (void *buf, size_t n, + ACE_OVERLAPPED *overlapped) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); + return ACE_OS::read (this->get_handle (), (char *) buf, n, + overlapped); +} + +#if defined (ACE_HAS_STREAM_PIPES) +ACE_INLINE ssize_t +ACE_DEV_IO::recv (ACE_Str_Buf *cntl, ACE_Str_Buf *data, int *band, int *flags) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); + return ACE_OS::getpmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, band, flags); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::send (const ACE_Str_Buf *cntl, const ACE_Str_Buf *data, int band, int flags) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); + return ACE_OS::putpmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, band, flags); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::recv (ACE_Str_Buf *cntl, ACE_Str_Buf *data, int *flags) const +{ + ACE_TRACE ("ACE_DEV_IO::recv"); + return ACE_OS::getmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, flags); +} + +ACE_INLINE ssize_t +ACE_DEV_IO::send (const ACE_Str_Buf *cntl, const ACE_Str_Buf *data, int flags) const +{ + ACE_TRACE ("ACE_DEV_IO::send"); + return ACE_OS::putmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, flags); +} +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DLL.cpp b/dep/acelite/ace/DLL.cpp new file mode 100644 index 000000000..4fed8ba8d --- /dev/null +++ b/dep/acelite/ace/DLL.cpp @@ -0,0 +1,287 @@ +#include "ace/DLL.h" + +#include "ace/Log_Category.h" +#include "ace/ACE.h" +#include "ace/DLL_Manager.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_dlfcn.h" +#include "ace/OS_NS_Thread.h" + +#include + + + + ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Default constructor. Also, by default, the object will be closed +// before it is destroyed. + +ACE_DLL::ACE_DLL (bool close_handle_on_destruction) + : open_mode_ (0), + dll_name_ (0), + close_handle_on_destruction_ (close_handle_on_destruction), + dll_handle_ (0), + error_ (0) +{ + ACE_TRACE ("ACE_DLL::ACE_DLL (int)"); +} + +ACE_DLL::ACE_DLL (const ACE_DLL &rhs) + : open_mode_ (0), + dll_name_ (0), + close_handle_on_destruction_ (false), + dll_handle_ (0), + error_ (0) +{ + ACE_TRACE ("ACE_DLL::ACE_DLL (const ACE_DLL &)"); + + if (rhs.dll_name_ + // This will automatically up the refcount. + && this->open (rhs.dll_name_, + rhs.open_mode_, + rhs.close_handle_on_destruction_) != 0 + && ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE_DLL::copy_ctor: error: %s\n"), + this->error ())); +} + +// Assignment operator + +ACE_DLL & +ACE_DLL::operator= (const ACE_DLL &rhs) +{ + ACE_TRACE ("ACE_DLL::operator= (const ACE_DLL &)"); + + ACE_DLL tmp (rhs); + + std::swap (this->open_mode_, tmp.open_mode_); + std::swap (this->dll_name_, tmp.dll_name_); + std::swap (this->close_handle_on_destruction_, + tmp.close_handle_on_destruction_); + std::swap (this->dll_handle_, tmp.dll_handle_); + std::swap (this->error_, tmp.error_); + + return *this; +} + + +// If the library name and the opening mode are specified than on +// object creation the library is implicitly opened. + +ACE_DLL::ACE_DLL (const ACE_TCHAR *dll_name, + int open_mode, + bool close_handle_on_destruction) + : open_mode_ (open_mode), + dll_name_ (0), + close_handle_on_destruction_ (close_handle_on_destruction), + dll_handle_ (0), + error_ (0) +{ + ACE_TRACE ("ACE_DLL::ACE_DLL"); + + if (this->open (dll_name, this->open_mode_, close_handle_on_destruction) != 0 + && ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE_DLL::open: error calling open: %s\n"), + this->error ())); +} + +// The library is closed before the class gets destroyed depending on +// the close_handle_on_destruction value specified which is stored in +// close_handle_on_destruction_. + +ACE_DLL::~ACE_DLL (void) +{ + ACE_TRACE ("ACE_DLL::~ACE_DLL"); + + this->close (); + + // Normally delete()d in ACE_DLL::close(). However, that may not + // occur if full ACE_DLL initialization is interrupted due to errors + // (e.g. attempting to open a DSO/DLL that does not exist). Make + // sure this->dll_name_ is deallocated. +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->dll_name_); +#else + delete [] this->dll_name_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +// This method opens the library based on the mode specified using the +// ACE_SHLIB_HANDLE which is obtained on making the ACE_OS::dlopen call. +// The default mode is: +// RTLD_LAZY Only references to data symbols are relocate when the +// object is first loaded. +// The other modes include: +// RTLD_NOW All necessary relocations are performed when the +// object is first loaded. +// RTLD_GLOBAL The object symbols are made available for the +// relocation processing of any other object. + +int +ACE_DLL::open (const ACE_TCHAR *dll_filename, + int open_mode, + bool close_handle_on_destruction) +{ + ACE_TRACE ("ACE_DLL::open"); + + return open_i (dll_filename, open_mode, close_handle_on_destruction); +} + +int +ACE_DLL::open_i (const ACE_TCHAR *dll_filename, + int open_mode, + bool close_handle_on_destruction, + ACE_SHLIB_HANDLE handle) +{ + ACE_TRACE ("ACE_DLL::open_i"); + + this->error_ = 0; + this->errmsg_.clear (true); + + if (!dll_filename) + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE_DLL::open_i: dll_name is %s\n"), + this->dll_name_ == 0 ? ACE_TEXT ("(null)") + : this->dll_name_)); + return -1; + } + + if (this->dll_handle_) + { + // If we have a good handle and its the same name, just return. + if (ACE_OS::strcmp (this->dll_name_, dll_filename) == 0) + return 0; + else + this->close (); + } + + if (!this->dll_name_) + this->dll_name_ = ACE::strnew (dll_filename); + + this->open_mode_ = open_mode; + this->close_handle_on_destruction_ = close_handle_on_destruction; + + ACE_DLL_Handle::ERROR_STACK errors; + this->dll_handle_ = ACE_DLL_Manager::instance()->open_dll (this->dll_name_, + this->open_mode_, + handle, + &errors); + + if (!this->dll_handle_) + { + ACE_TString errtmp; + while (!errors.is_empty ()) + { + errors.pop (errtmp); + if (this->errmsg_.length () > 0) + this->errmsg_ += ACE_TEXT ("\n"); + this->errmsg_ += errtmp; + } + this->error_ = 1; + } + + return this->error_ ? -1 : 0; +} + +// The symbol refernce of the name specified is obtained. + +void * +ACE_DLL::symbol (const ACE_TCHAR *sym_name, int ignore_errors) +{ + ACE_TRACE ("ACE_DLL::symbol"); + + this->error_ = 0; + this->errmsg_.clear (true); + + void *sym = 0; + if (this->dll_handle_) + sym = this->dll_handle_->symbol (sym_name, ignore_errors, this->errmsg_); + + if (!sym) + this->error_ = 1; + + return sym; +} + +// The library is closed using the ACE_SHLIB_HANDLE object, i.e., the +// shared object is now disassociated form the current process. + +int +ACE_DLL::close (void) +{ + ACE_TRACE ("ACE_DLL::close"); + + int retval = 0; + + if (this->dll_handle_ + && this->close_handle_on_destruction_ + && this->dll_name_ + && (retval = ACE_DLL_Manager::instance ()->close_dll (this->dll_name_)) != 0) + this->error_ = 1; + + // Even if close_dll() failed, go ahead and cleanup. + this->dll_handle_ = 0; +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->dll_name_); +#else + delete [] this->dll_name_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + this->dll_name_ = 0; + this->close_handle_on_destruction_ = false; + + return retval; +} + +// This method is used return the last error of a library operation. + +ACE_TCHAR * +ACE_DLL::error (void) const +{ + ACE_TRACE ("ACE_DLL::error"); + if (this->error_) + { + return const_cast (this->errmsg_.c_str ()); + } + + return 0; +} + +// Return the handle to the user either temporarily or forever, thus +// orphaning it. If 0 means the user wants the handle forever and if 1 +// means the user temporarily wants to take the handle. + +ACE_SHLIB_HANDLE +ACE_DLL::get_handle (bool become_owner) const +{ + ACE_TRACE ("ACE_DLL::get_handle"); + + ACE_SHLIB_HANDLE handle = ACE_SHLIB_INVALID_HANDLE; + + if (this->dll_handle_) + handle = this->dll_handle_->get_handle (become_owner); + + return handle; +} + +// Set the handle for the DLL. By default, the object will be closed +// before it is destroyed. + +int +ACE_DLL::set_handle (ACE_SHLIB_HANDLE handle, + bool close_handle_on_destruction) +{ + ACE_TRACE ("ACE_DLL::set_handle"); + + // Create a unique name. Note that this name is only quaranteed + // to be unique for the life of this object. + ACE_TCHAR temp[ACE_UNIQUE_NAME_LEN]; + ACE_OS::unique_name (this, temp, ACE_UNIQUE_NAME_LEN); + + return this->open_i (temp, 1, close_handle_on_destruction, handle); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DLL.h b/dep/acelite/ace/DLL.h new file mode 100644 index 000000000..a5d8dae69 --- /dev/null +++ b/dep/acelite/ace/DLL.h @@ -0,0 +1,210 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file DLL.h + * + * @author Kirthika Parameswaran + */ +//============================================================================= + +#ifndef ACE_DLL_H +#define ACE_DLL_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/os_include/os_dlfcn.h" +#include "ace/SString.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_DLL_Handle; + +/** + * @class ACE_DLL + * + * @brief Provides an abstract interface for handling various DLL + * operations. + * + * This class is a wrapper over the various methods for utilizing + * a dynamically linked library (DLL), which is called a shared + * library on some platforms. Operations @c open(), @c close(), and + * @c symbol() have been implemented to help opening/closing and + * extracting symbol information from a DLL, respectively. + */ +class ACE_Export ACE_DLL +{ +public: + // = Initialization and termination methods. + + /** + * Default constructor. By default, the close() operation on the + * object will be invoked before it is destroyed. + * @param close_handle_on_destruction Indicates whether or not the + * close() method will be called to close an open DLL when this + * object is destroyed. By default, close() will be called. + * Set this parameter to false for situations where the DLL's lifetime + * is controlled in a scope other than that of this ACE_DLL object. + * For example, termination by ACE_DLL_Manager via ACE::fini(). + */ + explicit ACE_DLL (bool close_handle_on_destruction = true); + + /// Allow assignment + ACE_DLL& operator= (const ACE_DLL &rhs); + + + /** + * This constructor performs the actions of open() during construction. + * @param dll_name The name or path of the DLL to load. + * @param open_mode Flags to alter the actions taken when loading the DLL. + * The possible values are: + * @li @c RTLD_LAZY (this the default): loads identifier symbols but + * not the symbols for functions, which are loaded dynamically + * on-demand. + * @li @c RTLD_NOW: performs all necessary relocations when + * @a dll_name is first loaded + * @li RTLD_GLOBAL: makes symbols available for relocation + * processing of any other DLLs. + * @param close_handle_on_destruction Indicates whether or not the + * close() method will be called to close an open DLL when this + * object is destroyed. By default, close() will be called. + * Set this parameter to 0 for situations where the DLL's lifetime + * is controlled in a scope other than that of this ACE_DLL object. + * For example, termination by ACE_DLL_Manager via ACE::fini(). + */ + explicit ACE_DLL (const ACE_TCHAR *dll_name, + int open_mode = ACE_DEFAULT_SHLIB_MODE, + bool close_handle_on_destruction = true); + + /// Copy constructor. + ACE_DLL (const ACE_DLL &); + + /** + * This method opens and dynamically links a specified DLL. + * @param dll_name The filename or path of the DLL to load. ACE will + * attempt to apply the platform's standard library/DLL prefixes + * and suffixes, allowing a simple, unadorned name to be passed + * regardless of platform. The set of name transforms is listed + * below. A @i decorator is a platform's name designator for a debug + * vs release build. For example, on Windows it is usually "d". + * @li Prefix + name + decorator + suffix + * @li Prefix + name + suffix + * @li Name + decorator + suffix + * @li Name + suffix + * @li Name + * Note that the transforms with @i decorator will be avoided if + * ACE is built with the @c ACE_DISABLE_DEBUG_DLL_CHECK config macro. + * + * @Note There is another mode for locating library/DLL files that + * was used in old versions of ACE. The alternate method builds + * more combinations of pathname by combining the names transforms + * above with locations listed in the platform's standard "path" + * locations (e.g., @c LD_LIBRARY_PATH). It can be enabled by building + * ACE with the @c ACE_MUST_HELP_DLOPEN_SEARCH_PATH config macro. + * Use of this option is discouraged since it avoids the standard + * platform search options and security mechanisms. + * + * @param open_mode Flags to alter the actions taken when loading the DLL. + * The possible values are: + * @li @c RTLD_LAZY (this the default): loads identifier symbols but + * not the symbols for functions, which are loaded dynamically + * on demand. + * @li @c RTLD_NOW: performs all necessary relocations when + * @a dll_name is first loaded + * @li @c RTLD_GLOBAL: makes symbols available for relocation + * processing of any other DLLs. + * @param close_handle_on_destruction Indicates whether or not the + * close() method will be called to close an open DLL when this + * object is destroyed. By default, close() will be called. + * Set this parameter to 0 for situations where the DLL's lifetime + * is controlled in a scope other than that of this ACE_DLL object. + * For example, termination by ACE_DLL_Manager via ACE::fini(). + * @retval -1 On failure + * @retval 0 On success. + */ + int open (const ACE_TCHAR *dll_name, + int open_mode = ACE_DEFAULT_SHLIB_MODE, + bool close_handle_on_destruction = true); + + /// Call to close the DLL object. + int close (void); + + /** + * Called when the DLL object is destroyed -- invokes close() if the + * @a close_handle_on_destruction flag was set to non-zero in the + * constructor or open() method. + */ + ~ACE_DLL (void); + + /** + * Look up a named symbol in the DLL. DLL must be successfully opened + * before calling symbol(). + * @param symbol_name The symbol name to look up. + * @param ignore_errors If set to 1, allows you to probe a dll without + * generating error messages in the log. Handy for determining + * the capabilities of a library. + * @return Returns the value of @a symbol_name if it is a valid symbol + * in the DLL. Otherwise, returns 0. + */ + void *symbol (const ACE_TCHAR *symbol_name, int ignore_errors = 0); + + /// Returns a pointer to a string explaining that an error occurred. You + /// will need to consult the error log for the actual error string + /// returned by the OS. + ACE_TCHAR *error (void) const; + + /** + * Return the handle to the caller. If @a become_owner is true then + * caller assumes ownership of the handle and the ACE_DLL object + * won't call close() when it goes out of scope, even if + * @c close_handle_on_destruction is set. + */ + ACE_SHLIB_HANDLE get_handle (bool become_owner = false) const; + + /// Set the handle for the DLL object. By default, the close() + /// operation on / the object will be invoked before it is destroyed. + int set_handle (ACE_SHLIB_HANDLE handle, + bool close_handle_on_destruction = true); + +private: + + int open_i (const ACE_TCHAR *dll_name, + int open_mode = ACE_DEFAULT_SHLIB_MODE, + bool close_handle_on_destruction = true, + ACE_SHLIB_HANDLE handle = 0); + + + //private: +public: + + /// Open mode. + int open_mode_; + + /// Keep track of the name of the loaded dll, so it can be used + /// to remove framework components, singletons that live in the dll, + /// prior to unloading the dll in the close() method. + ACE_TCHAR *dll_name_; + + /// This flag keeps track of whether we should close the handle + /// automatically when the object is destroyed. + bool close_handle_on_destruction_; + + ACE_DLL_Handle *dll_handle_; + + /// Flag to record if the last operation had an error. + bool error_; + + /// Any error messages encountered during last operation. + ACE_TString errmsg_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_DLL_H */ diff --git a/dep/acelite/ace/DLL_Manager.cpp b/dep/acelite/ace/DLL_Manager.cpp new file mode 100644 index 000000000..68dda37c0 --- /dev/null +++ b/dep/acelite/ace/DLL_Manager.cpp @@ -0,0 +1,840 @@ +#include "ace/DLL_Manager.h" + +#include "ace/Auto_Ptr.h" +#include "ace/Log_Category.h" +#include "ace/ACE.h" +#include "ace/Framework_Component.h" + +#include "ace/Lib_Find.h" +#include "ace/Object_Manager.h" +#include "ace/SString.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_dlfcn.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +sig_atomic_t ACE_DLL_Handle::open_called_ = 0; + +ACE_DLL_Handle::ACE_DLL_Handle (void) + : refcount_ (0), + dll_name_ (0), + handle_ (ACE_SHLIB_INVALID_HANDLE) +{ + ACE_TRACE ("ACE_DLL_Handle::ACE_DLL_Handle"); +} + +ACE_DLL_Handle::~ACE_DLL_Handle (void) +{ + ACE_TRACE ("ACE_DLL_Handle::~ACE_DLL_Handle"); + this->close (1); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(this->dll_name_); +#else + delete[] this->dll_name_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_DLL_Handle) + +const ACE_TCHAR * +ACE_DLL_Handle::dll_name (void) const +{ + ACE_TRACE ("ACE_DLL_Handle::dll_name"); + return this->dll_name_; +} + +int +ACE_DLL_Handle::open (const ACE_TCHAR *dll_name, + int open_mode, + ACE_SHLIB_HANDLE handle, + ERROR_STACK *errors) +{ + ACE_TRACE ("ACE_DLL_Handle::open"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + if (this->dll_name_) + { + // Once dll_name_ has been set, it can't be changed.. + if (ACE_OS::strcmp (this->dll_name_, dll_name) != 0) + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open: error, ") + ACE_TEXT ("tried to reopen %s with name %s\n"), + this->dll_name_, + dll_name)); + + return -1; + } + } + else + this->dll_name_ = ACE::strnew (dll_name); + + if (!this->open_called_) + this->open_called_ = 1; + + // If it hasn't been loaded yet, go ahead and do that now. + if (this->handle_ == ACE_SHLIB_INVALID_HANDLE) + { + if (handle) + this->handle_ = handle; + else + { + /* + ** Get the set of names to try loading. We need to do this to + ** properly support the ability for a user to specify a simple, + ** unadorned name (for example, "ACE") that will work across + ** platforms. We apply platform specifics to get a name that will + ** work (e.g. libACE, ACEd.dll, ACE.dll, etc.) We rely on the + ** underlying dlopen() implementation to "Do The Right Thing" in + ** terms of using relative paths, LD_LIBRARY_PATH, system security + ** rules, etc. except when ACE_MUST_HELP_DLOPEN_SEARCH_PATH is set. + ** If it is set, then ACE::ldfind() scans the configured path + ** looking for a match on the name and prefix/suffix applications. + ** NOTE: having ACE scan for a file and then pass a fully-qualified + ** pathname to dlopen() is a potential security hole; therefore, + ** do not use ACE_MUST_HELP_DLOPEN_SEARCH_PATH unless necessary + ** and only after considering the risks. + */ + ACE_Array dll_names; + dll_names.max_size (10); // Decent guess to avoid realloc later + +#if defined (ACE_MUST_HELP_DLOPEN_SEARCH_PATH) + // Find out where the library is + ACE_TCHAR dll_pathname[MAXPATHLEN + 1]; + + // Transform the pathname into the appropriate dynamic link library + // by searching the ACE_LD_SEARCH_PATH. + ACE::ldfind (dll_name, + dll_pathname, + (sizeof dll_pathname / sizeof (ACE_TCHAR))); + ACE_TString dll_str (dll_pathname); + dll_names.size (1); + dll_names.set (dll_str, 0); +#else + this->get_dll_names (dll_name, dll_names); +#endif + + ACE_TString *name = 0; + for (ACE_Array_Iterator name_iter (dll_names); + name_iter.next (name); name_iter.advance ()) + { + if (this->open_i (name->c_str (), open_mode)) + break; + + this->log_error (name->c_str (), errors); + +#if defined (AIX) +# define SHR_O ACE_TEXT("(shr.o)") +# define SHR_O_LEN (sizeof (SHR_O) / sizeof(ACE_TCHAR) - 1) + // AIX often puts the shared library file (most often named + // shr.o) inside an archive library. If this is an archive + // library name, then try appending [shr.o] and retry. + if (ACE_TString::npos != name->strstr (ACE_TEXT (".a"))) + { + ACE_TCHAR aix_pathname[MAXPATHLEN + 1]; + if (name->length () + SHR_O_LEN <= MAXPATHLEN) + { + ACE_OS::strcpy (aix_pathname, name->c_str()); + ACE_OS::strcat (aix_pathname, SHR_O); + } + else + { + if (errors) + { + errors->push ("path is too long"); + } + + if (ACE::debug ()) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open: ") + ACE_TEXT ("('%s(shr.o)') is too long\n"), + name->c_str())); + } + + return -1; + } + open_mode |= RTLD_MEMBER; + + if (this->open_i (aix_pathname, open_mode)) + break; + + this->log_error (aix_pathname, errors); + } +#endif /* AIX */ + } + + if (this->handle_ == ACE_SHLIB_INVALID_HANDLE) + { + if (errors || ACE::debug ()) + { + ACE_TString errtmp; + if (errors) + { + errors->push (this->error (errtmp)); + } + + if (ACE::debug ()) + { + if (!errors) + this->error (errtmp); + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open (\"%s\"): ") + ACE_TEXT ("Invalid handle error: %s\n"), + this->dll_name_, + errtmp.c_str ())); + } + } + + return -1; + } + } + } + + ++this->refcount_; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open - %s (%d), refcount=%d\n"), + this->dll_name_, + this->handle_, + this->refcount_)); + return 0; +} + + +int +ACE_DLL_Handle::close (int unload) +{ + ACE_TRACE ("ACE_DLL_Handle::close"); + + int retval = 0; + ACE_SHLIB_HANDLE h = ACE_SHLIB_INVALID_HANDLE; + + // Only hold the lock until it comes time to dlclose() the DLL. Closing + // the DLL can cause further shutdowns as DLLs and their dependents are + // unloaded. + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + // Since we don't actually unload the dll as soon as the refcount + // reaches zero, we need to make sure we don't decrement it below + // zero. + if (this->refcount_ > 0) + --this->refcount_; + else + this->refcount_ = 0; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ") + ACE_TEXT ("%s (handle=%d, refcount=%d)\n"), + this->dll_name_, + this->handle_, + this->refcount_)); + + if (this->refcount_ == 0 && + this->handle_ != ACE_SHLIB_INVALID_HANDLE && + unload == 1) + { + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::close: ") + ACE_TEXT ("Unloading %s (handle=%d)\n"), + this->dll_name_, + this->handle_)); + + // First remove any associated Framework Components. + ACE_Framework_Repository *frPtr= ACE_Framework_Repository::instance (); + if (frPtr) + { + frPtr->remove_dll_components (this->dll_name_); + } + + h = this->handle_; + this->handle_ = ACE_SHLIB_INVALID_HANDLE; + } + } // Release lock_ here + + if (h != ACE_SHLIB_INVALID_HANDLE) + { + retval = ACE_OS::dlclose (h); + + if (retval != 0 && ACE::debug ()) + { + ACE_TString err; + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::close - ") + ACE_TEXT ("Failed with: \"%s\".\n"), + this->error (err).c_str ())); + } + } + + return retval; +} + +sig_atomic_t +ACE_DLL_Handle::refcount (void) const +{ + return this->refcount_; +} + +void * +ACE_DLL_Handle::symbol (const ACE_TCHAR *sym_name, bool ignore_errors) +{ + ACE_TString error; + return this->symbol (sym_name, ignore_errors, error); +} + +void * +ACE_DLL_Handle::symbol (const ACE_TCHAR *sym_name, bool ignore_errors, ACE_TString &error) +{ + ACE_TRACE ("ACE_DLL_Handle::symbol"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + ACE_Auto_Array_Ptr auto_name (ACE::ldname (sym_name)); + // handle_ can be invalid especially when ACE_DLL_Handle resigned ownership + // BTW. Handle lifecycle management is a little crazy in ACE + if (this->handle_ != ACE_SHLIB_INVALID_HANDLE) + { +#if defined (ACE_OPENVMS) + void *sym = ACE::ldsymbol (this->handle_, auto_name.get ()); +#else + void *sym = ACE_OS::dlsym (this->handle_, auto_name.get ()); +#endif + + // Linux says that the symbol could be null and that it isn't an + // error. So you should check the error message also, but since + // null symbols won't do us much good anyway, let's still report + // an error. + if (!sym && !ignore_errors) + { + this->error (error); + + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::symbol (\"%s\") ") + ACE_TEXT (" failed with \"%s\".\n"), + auto_name.get (), + error.c_str ())); + + return 0; + } + return sym; + } + return 0; +} + +ACE_SHLIB_HANDLE +ACE_DLL_Handle::get_handle (bool become_owner) +{ + ACE_TRACE ("ACE_DLL_Handle::get_handle"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + if (this->refcount_ == 0 && become_owner) + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ") + ACE_TEXT ("cannot become owner, refcount == 0.\n"))); + + return ACE_SHLIB_INVALID_HANDLE; + } + + ACE_SHLIB_HANDLE handle = this->handle_; + + if (become_owner) + { + if (--this->refcount_ == 0) + this->handle_ = ACE_SHLIB_INVALID_HANDLE; + } + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::get_handle: ") + ACE_TEXT ("post call: handle %s, refcount %d\n"), + this->handle_ == ACE_SHLIB_INVALID_HANDLE ? + ACE_TEXT ("invalid") : ACE_TEXT ("valid"), + this->refcount_)); + + return handle; +} + +// This method is used return the last error of a library operation. + +ACE_TString & +ACE_DLL_Handle::error (ACE_TString &err) +{ + ACE_TRACE ("ACE_DLL_Handle::error"); + const ACE_TCHAR *error = ACE_OS::dlerror (); + err = (error ? error : ACE_TEXT ("no error")); + return err; +} + +void +ACE_DLL_Handle::get_dll_names (const ACE_TCHAR *dll_name, + ACE_Array &try_names) +{ + // Build the array of DLL names to try on this platform by applying the + // proper prefixes and/or suffixes to the specified dll_name. + ACE_TString base (dll_name); + ACE_TString base_dir, base_file, base_suffix; + + // 1. Separate the dll_name into the dir part and the file part. We + // only decorate the file part to determine the names to try loading. + ACE_TString::size_type pos = base.rfind (ACE_DIRECTORY_SEPARATOR_CHAR); + if (pos != ACE_TString::npos) + { + base_dir = base.substr (0, pos + 1); + base_file = base.substr (pos + 1); + } + else + base_file = base; + + // 2. Locate the file suffix, if there is one. Move the '.' and the + // suffix to base_suffix. + if ((pos = base_file.rfind (ACE_TEXT ('.'))) != ACE_TString::npos) + { + base_suffix = base_file.substr (pos); + base_file = base_file.substr (0, pos); + } + + // 3. Build the combinations to try for this platform. + // Try these combinations: + // - name with platform's dll prefix (if it has one) and suffix + // - name with platform's dll prefix, decorator, and suffix. + // - name with decorator and platform's suffix appended (if not supplied) + // - name with platform's suffix appended (if not supplied) + // - name as originally given + // We first try to find the file using the decorator so that when a + // filename with and without decorator is used, we get the file with + // the same decorator as the ACE dll has and then as last resort + // the one without. For example with msvc, the debug build has a "d" + // decorator, but the release build has none and we really want to get + // the debug version of the library in a debug application instead + // of the release one. + // So we need room for 5 entries in try_names. + try_names.size (0); + if ((try_names.max_size () - try_names.size ()) < 5) + try_names.max_size (try_names.max_size () + 5); +#if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK) + ACE_TString decorator (ACE_LD_DECORATOR_STR); +#endif + ACE_TString suffix (ACE_DLL_SUFFIX); + ACE_TString prefix (ACE_DLL_PREFIX); + + for (size_t i = 0; i < 5 && try_names.size () < try_names.max_size (); ++i) + { + ACE_TString try_this; + size_t const j = try_names.size (); + switch (i) + { + case 0: // Prefix + name + decorator + suffix + case 1: // Prefix + name + suffix + case 2: // Name + decorator + suffix + case 3: // Name + suffix + if ( + base_suffix.length () > 0 +#if !(defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK)) + || (i == 1 || i == 3) // No decorator desired; skip +#endif + ) + break; + try_this = base_dir; + if (i < 2) + try_this += prefix; + try_this += base_file; + if (base_suffix.length () > 0) + try_this += base_suffix; + else + { +#if defined (ACE_LD_DECORATOR_STR) && !defined (ACE_DISABLE_DEBUG_DLL_CHECK) + try_this += decorator; +#endif + try_this += suffix; + } + break; + case 4: + try_this = dll_name; + break; + } + + if (try_this.length ()) + { + try_names.size (j + 1); + try_names.set (try_this, j); + } + } + return; +} + +bool +ACE_DLL_Handle::open_i (const ACE_TCHAR *dll_name, int open_mode) +{ + // The ACE_SHLIB_HANDLE object is obtained. + this->handle_ = ACE_OS::dlopen (dll_name, open_mode); + + if (ACE::debug ()) + { + ACE_TString err; + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") + ACE_TEXT ("(\"%s\", 0x%x) -> %s: %s\n"), + dll_name, + open_mode, + ((this->handle_ != ACE_SHLIB_INVALID_HANDLE) + ? ACE_TEXT ("succeeded") + : ACE_TEXT ("failed")), + this->error (err).c_str())); + } + + return this->handle_ != ACE_SHLIB_INVALID_HANDLE; +} + +void +ACE_DLL_Handle::log_error (const ACE_TCHAR *dll_name, ERROR_STACK *errors) +{ + // If errno is ENOENT we just skip over this one, anything + // else - like an undefined symbol, for instance + // must be flagged here or the next error will mask it. + // + // @TODO: If we've found our DLL _and_ it's broken, + // should we continue at all? + if (errno != ENOENT && (errors || ACE::debug ())) + { + ACE_TString errtmp; + if (errors) + { + errors->push (this->error (errtmp)); + } + + if (ACE::debug ()) + { + if (!errors) + this->error (errtmp); + + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Handle::open ") + ACE_TEXT ("(\'%s\') failed, errno=") + ACE_TEXT ("%d: <%s>\n"), + dll_name, + ACE_ERRNO_GET, + errtmp.c_str ())); + } + } +} + +/******************************************************************/ + +// Pointer to the Singleton instance. +ACE_DLL_Manager *ACE_DLL_Manager::instance_ = 0; + + +ACE_DLL_Manager * +ACE_DLL_Manager::instance (int size) +{ + ACE_TRACE ("ACE_DLL_Manager::instance"); + + if (ACE_DLL_Manager::instance_ == 0) + { + // Perform Double-Checked Locking Optimization. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + if (ACE_DLL_Manager::instance_ == 0) + { + ACE_NEW_RETURN (ACE_DLL_Manager::instance_, + ACE_DLL_Manager (size), + 0); + } + } + + return ACE_DLL_Manager::instance_; +} + +void +ACE_DLL_Manager::close_singleton (void) +{ + ACE_TRACE ("ACE_DLL_Manager::close_singleton"); + + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance ())); + + delete ACE_DLL_Manager::instance_; + ACE_DLL_Manager::instance_ = 0; +} + +ACE_DLL_Manager::ACE_DLL_Manager (int size) + : handle_vector_ (0), + current_size_ (0), + total_size_ (0), + unload_policy_ (ACE_DLL_UNLOAD_POLICY_PER_DLL) +{ + ACE_TRACE ("ACE_DLL_Manager::ACE_DLL_Manager"); + + if (this->open (size) != 0 && ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Manager ctor failed to allocate ") + ACE_TEXT ("handle_vector_.\n"))); +} + +ACE_DLL_Manager::~ACE_DLL_Manager (void) +{ + ACE_TRACE ("ACE_DLL_Manager::~ACE_DLL_Manager"); + + if (this->close () != 0 && ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Manager dtor failed to close ") + ACE_TEXT ("properly.\n"))); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_DLL_Manager) + +ACE_DLL_Handle * +ACE_DLL_Manager::open_dll (const ACE_TCHAR *dll_name, + int open_mode, + ACE_SHLIB_HANDLE handle, + ACE_DLL_Handle::ERROR_STACK *errors) +{ + ACE_TRACE ("ACE_DLL_Manager::open_dll"); + + ACE_DLL_Handle *temp_handle = 0; + ACE_DLL_Handle *dll_handle = 0; + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + dll_handle = this->find_dll (dll_name); + if (!dll_handle) + { + if (this->current_size_ < this->total_size_) + { + ACE_NEW_RETURN (temp_handle, + ACE_DLL_Handle, + 0); + + dll_handle = temp_handle; + } + } + } + + if (dll_handle) + { + if (dll_handle->open (dll_name, open_mode, handle, errors) != 0) + { + // Error while opening dll. Free temp handle + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Manager::open_dll: Could not ") + ACE_TEXT ("open dll %s.\n"), + dll_name)); + + delete temp_handle; + return 0; + } + + // Add the handle to the vector only if the dll is successfully + // opened. + if (temp_handle != 0) + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + this->handle_vector_[this->current_size_] = dll_handle; + ++this->current_size_; + } + } + + return dll_handle; +} + +int +ACE_DLL_Manager::close_dll (const ACE_TCHAR *dll_name) +{ + ACE_TRACE ("ACE_DLL_Manager::close_dll"); + ACE_DLL_Handle *handle = 0; + + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + handle = this->find_dll (dll_name); + } + + if (handle) + { + return this->unload_dll (handle, 0); + } + + return -1; +} + +u_long +ACE_DLL_Manager::unload_policy (void) const +{ + ACE_TRACE ("ACE_DLL_Manager::unload_policy"); + return this->unload_policy_; +} + +void +ACE_DLL_Manager::unload_policy (u_long unload_policy) +{ + ACE_TRACE ("ACE_DLL_Manager::unload_policy"); + ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_)); + + u_long old_policy = this->unload_policy_; + this->unload_policy_ = unload_policy; + + // If going from LAZY to EAGER or from PER_DLL to PER_PROCESS|EAGER, + // call close(1) on all the ACE_DLL_Handle objects with refcount == 0 + // which will force those that are still loaded to be unloaded. + if (this->handle_vector_) + if (( ACE_BIT_ENABLED (old_policy, ACE_DLL_UNLOAD_POLICY_LAZY) && + ACE_BIT_DISABLED (this->unload_policy_, ACE_DLL_UNLOAD_POLICY_LAZY) ) || + ( ACE_BIT_DISABLED (this->unload_policy_, ACE_DLL_UNLOAD_POLICY_LAZY) && + ACE_BIT_ENABLED (old_policy, ACE_DLL_UNLOAD_POLICY_PER_DLL) && + ACE_BIT_DISABLED (this->unload_policy_, ACE_DLL_UNLOAD_POLICY_PER_DLL) )) + { + for (int i = this->current_size_ - 1; i >= 0; i--) + { + if (this->handle_vector_[i] && + this->handle_vector_[i]->refcount () == 0) + this->handle_vector_[i]->close (1); + } + } +} + +int +ACE_DLL_Manager::open (int size) +{ + ACE_TRACE ("ACE_DLL_Manager::open"); + + ACE_DLL_Handle **temp = 0; + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (temp, + static_cast (ACE_Allocator::instance()->malloc(sizeof (ACE_DLL_Handle*) * size)), + -1); +#else + ACE_NEW_RETURN (temp, + ACE_DLL_Handle *[size], + -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + this->handle_vector_ = temp; + this->total_size_ = size; + return 0; +} + +int +ACE_DLL_Manager::close (void) +{ + ACE_TRACE ("ACE_DLL_Manager::close"); + + int force_close = 1; + + if (this->handle_vector_ != 0) + { + // Delete components in reverse order. + for (int i = this->current_size_ - 1; i >= 0; i--) + { + if (this->handle_vector_[i]) + { + ACE_DLL_Handle *s = + const_cast (this->handle_vector_[i]); + this->handle_vector_[i] = 0; + this->unload_dll (s, force_close); + delete s; + } + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(this->handle_vector_); +#else + delete [] this->handle_vector_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + + this->handle_vector_ = 0; + this->current_size_ = 0; + } + return 0; +} + +ACE_DLL_Handle * +ACE_DLL_Manager::find_dll (const ACE_TCHAR *dll_name) const +{ + ACE_TRACE ("ACE_DLL_Manager::find_dll"); + + for (int i = 0; i < this->current_size_; i++) + if (this->handle_vector_[i] && + ACE_OS::strcmp (this->handle_vector_[i]->dll_name (), dll_name) == 0) + { + return this->handle_vector_[i]; + } + + return 0; +} + +int +ACE_DLL_Manager::unload_dll (ACE_DLL_Handle *dll_handle, int force_unload) +{ + ACE_TRACE ("ACE_DLL_Manager::unload_dll"); + + if (dll_handle) + { + int unload = force_unload; + if (unload == 0) + { + // apply strategy + if (ACE_BIT_DISABLED (this->unload_policy_, + ACE_DLL_UNLOAD_POLICY_PER_DLL)) + { + unload = ACE_BIT_DISABLED (this->unload_policy_, + ACE_DLL_UNLOAD_POLICY_LAZY); + } + else + { + // Declare the type of the symbol: + typedef int (*dll_unload_policy)(void); + + void * const unload_policy_ptr = + dll_handle->symbol (ACE_TEXT ("_get_dll_unload_policy"), 1); +#if defined (ACE_OPENVMS) && (!defined (__INITIAL_POINTER_SIZE) || (__INITIAL_POINTER_SIZE < 64)) + int const temp_p = + reinterpret_cast (unload_policy_ptr); +#else + intptr_t const temp_p = + reinterpret_cast (unload_policy_ptr); +#endif + + dll_unload_policy const the_policy = + reinterpret_cast (temp_p); + + if (the_policy != 0) + unload = ACE_BIT_DISABLED (the_policy (), + ACE_DLL_UNLOAD_POLICY_LAZY); + else + unload = ACE_BIT_DISABLED (this->unload_policy_, + ACE_DLL_UNLOAD_POLICY_LAZY); + } + } + + if (dll_handle->close (unload) != 0) + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Manager::unload error.\n"))); + + return -1; + } + } + else + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) DLL_Manager::unload_dll called with ") + ACE_TEXT ("null pointer.\n"))); + + return -1; + } + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/DLL_Manager.h b/dep/acelite/ace/DLL_Manager.h new file mode 100644 index 000000000..9fea80a30 --- /dev/null +++ b/dep/acelite/ace/DLL_Manager.h @@ -0,0 +1,334 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file DLL_Manager.h + * + * @author Don Hinton + */ +//============================================================================= + +#ifndef ACE_DLL_MANAGER_H +#define ACE_DLL_MANAGER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Containers_T.h" +#include "ace/SString.h" +#include "ace/os_include/os_dlfcn.h" + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +# include "ace/Thread_Mutex.h" +#endif /* ACE_MT_SAFE */ + +#define ACE_DEFAULT_DLL_MANAGER_SIZE 1024 + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_DLL_Handle + * + * @brief Provides an abstract interface for handling various DLL + * operations. + * + * This class is an wrapper over the various methods for utilizing a + * dynamically linked library (DLL), which is called a shared library + * on some platforms. It is refcounted and managed by + * ACE_DLL_Manager, so there will only be a single instance of this + * class for each dll loaded, no matter how many instances of ACE_DLL + * an application has open. Operations open(), close(), and symbol() + * have been implemented to help opening/closing and extracting symbol + * information from a DLL, respectively. + * + * Most of this class came from the original ACE_DLL class. ACE_DLL + * is now just an interface that passed all it's calls either directly + * or via ACE_DLL_Manager to this class for execution. + */ +class ACE_Export ACE_DLL_Handle +{ +public: + + /// Error stack. Fixed size should suffice. Ignores any errors exceeding the size. + typedef ACE_Fixed_Stack < ACE_TString, 10 > ERROR_STACK; + + /// Default construtor. + ACE_DLL_Handle (void); + + /// Destructor. + ~ACE_DLL_Handle (void); + + /// Returns the name of the shared library (without prefixes or suffixes). + const ACE_TCHAR *dll_name () const; + + /** + * This method opens and dynamically links a library/DLL. + * @param dll_name The filename or path of the DLL to load. ACE will + * attempt to apply the platform's standard library/DLL prefixes + * and suffixes, allowing a simple, unadorned name to be passed + * regardless of platform. The set of name transforms is listed + * below. A @i decorator is a platform's name designator for a debug + * vs release build. For example, on Windows it is usually "d". + * @li Prefix + name + decorator + suffix + * @li Prefix + name + suffix + * @li Name + decorator + suffix + * @li Name + suffix + * @li Name + * Note that the transforms with @i decorator will be avoided if + * ACE is built with the @c ACE_DISABLE_DEBUG_DLL_CHECK config macro. + * + * @Note There is another mode for locating library/DLL files that + * was used in old versions of ACE. The alternate method builds + * more combinations of pathname by combining the names transforms + * above with locations listed in the platform's standard "path" + * locations (e.g., @c LD_LIBRARY_PATH). It can be enabled by building + * ACE with the @c ACE_MUST_HELP_DLOPEN_SEARCH_PATH config macro. + * Use of this option is discouraged since it avoids the standard + * platform search options and security mechanisms. + * + * @param open_mode Flags to alter the actions taken when loading the DLL. + * The possible values are: + * @li @c RTLD_LAZY (this the default): loads identifier symbols but + * not the symbols for functions, which are loaded dynamically + * on demand. + * @li @c RTLD_NOW: performs all necessary relocations when + * @a dll_name is first loaded + * @li @c RTLD_GLOBAL: makes symbols available for relocation + * processing of any other DLLs. + * @param handle If a value other than @c ACE_INVALID_HANDLE is supplied, + * this object is assigned the specified handle instead of attempting + * to open the specified @a dll_name. + * @param errors Optional address of an error stack to collect any errors + * encountered. + * @retval -1 On failure + * @retval 0 On success. + */ + int open (const ACE_TCHAR *dll_name, + int open_mode, + ACE_SHLIB_HANDLE handle, + ERROR_STACK *errors = 0); + + /// Call to close the DLL object. If unload = 0, it only decrements + /// the refcount, but if unload = 1, then it will actually unload + /// the library when the refcount == 0; + int close (int unload = 0); + + /// Return the current refcount. + sig_atomic_t refcount (void) const; + + /// If @a symbol_name is in the symbol table of the DLL a pointer to + /// the @a symbol_name is returned. Otherwise, returns 0. Set the + /// ignore_errors flag to supress logging errors if symbol_name isn't + /// found. This is nice if you just want to probe a dll to see what's + /// available, since missing functions in that case aren't really errors. + void *symbol (const ACE_TCHAR *symbol_name, bool ignore_errors = false); + + /// Resolves and returns any error encountered. + void *symbol (const ACE_TCHAR *symbol_name, bool ignore_errors, + ACE_TString &error); + + /** + * Return the handle to the caller. If @a become_owner is true then + * caller assumes ownership of the handle so we decrement the retcount. + */ + ACE_SHLIB_HANDLE get_handle (bool become_owner = false); + + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// Returns a string explaining why or + /// failed in @a err. This is used internal to print out the error to the log, + /// but since this object is shared, we can't store or return the error + /// to the caller. + ACE_TString& error (ACE_TString& err); + + /// Builds array of DLL names to try to dlopen, based on platform + /// and configured DLL prefixes/suffixes. + /// Returns the array of names to try in try_names. + void get_dll_names (const ACE_TCHAR *dll_name, + ACE_Array &try_names); + + /** + * This method opens and dynamically links a library/DLL. + * @param dll_name The filename or path of the DLL to load. + * @param open_mode Flags to alter the actions taken when loading the DLL. + * The possible values are: + * @li @c RTLD_LAZY (this the default): loads identifier symbols but + * not the symbols for functions, which are loaded dynamically + * on demand. + * @li @c RTLD_NOW: performs all necessary relocations when + * @a dll_name is first loaded + * @li @c RTLD_GLOBAL: makes symbols available for relocation + * processing of any other DLLs. + * @retval false On failure + * @retval true On success. + */ + bool open_i (const ACE_TCHAR *dll_name, int open_mode); + + /** + * This method logs error of opening the DLL. + * @param dll_name The filename or path of the DLL to load. + * @param errors Optional address of an error stack to collect any errors + * encountered. + */ + void log_error (const ACE_TCHAR *dll_name, ERROR_STACK *errors); + + /// Disallow copying and assignment since we don't handle them. + ACE_DLL_Handle (const ACE_DLL_Handle &); + void operator= (const ACE_DLL_Handle &); + +private: + + /// Keep track of how many ACE_DLL objects have a reference to this + /// dll. + sig_atomic_t refcount_; + + /// Name of the shared library. + ACE_TCHAR *dll_name_; + + /// Handle to the actual library loaded by the OS. + ACE_SHLIB_HANDLE handle_; + + /// Keeps track of whether or not open() has ever been called. This + /// helps get around problem on Linux, and perhaps other OS's, that + /// seg-fault if dlerror() is called before the ld library has been + /// initialized by a call to dlopen(). + static sig_atomic_t open_called_; + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + /// Synchronization variable for the MT_SAFE Repository + ACE_Thread_Mutex lock_; +#endif /* ACE_MT_SAFE */ +}; + +class ACE_Framework_Repository; + +/** + * @class ACE_DLL_Manager + * + * @brief This class is a singleton and serves as a factory and + * repository for instances of ACE_DLL_Handle. + * + * This class is a singleton whose lifetime is managed by the + * ACE_Framework_Repository. Although it is normally meant to be + * used directly only by ACE_DLL, applications can call the unload_policy() + * methods in order get/set the the dll unload policy. Unload policies include + * per_process/per-dll and eager/lazy. Dlls can export set their own policy + * by using the ACE_DLL_UNLOAD_POLICY macro found in config-all.h. If a dll + * choses to set an unload policy, it will be used when the per-dll policy + * (the default) is in effect. If the per-dll policy is in effect and a dll + * has not chosen to set a policy, the current per-process policy will be + * used. + * + * The following policy macros are provided in config-all.h: + * + * ACE_DLL_UNLOAD_POLICY_PER_PROCESS - Per-process policy that unloads dlls + * eagerly. + * + * ACE_DLL_UNLOAD_POLICY_PER_DLL - Apply policy on a per-dll basis. If the + * dll doesn't use one of the macros below, the current per-process policy + * will be used. + * + * ACE_DLL_UNLOAD_POLICY_LAZY - Don't unload dll when refcount reaches + * zero, i.e., wait for either an explicit unload request or program exit. + * + * ACE_DLL_UNLOAD_POLICY_DEFAULT - Default policy allows dlls to control + * their own destinies, but will unload those that don't make a choice eagerly. + */ +class ACE_Export ACE_DLL_Manager +{ +public: + friend class ACE_Framework_Repository; + friend class ACE_Object_Manager; + + enum + { + DEFAULT_SIZE = ACE_DEFAULT_DLL_MANAGER_SIZE + }; + + /// Return a unique instance + static ACE_DLL_Manager *instance (int size = ACE_DLL_Manager::DEFAULT_SIZE); + + /// Factory for ACE_DLL_Handle objects. If one already exits, + /// its refcount is incremented. + ACE_DLL_Handle *open_dll (const ACE_TCHAR *dll_name, + int openmode, + ACE_SHLIB_HANDLE handle, + ACE_DLL_Handle::ERROR_STACK *errors = 0); + + /// Close the underlying dll. Decrements the refcount. + int close_dll (const ACE_TCHAR *dll_name); + + /// Returns the current per-process UNLOAD_POLICY. + u_long unload_policy (void) const; + + /// Set the per-process UNLOAD_POLICY. If the policy is changed from + /// LAZY to EAGER, then it will also unload any dlls with zero + /// refcounts. + void unload_policy (u_long unload_policy); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// Default constructor. + ACE_DLL_Manager (int size = ACE_DLL_Manager::DEFAULT_SIZE); + + /// Destructor. + ~ACE_DLL_Manager (void); + + /// Allocate handle_vector_. + int open (int size); + + /// Close all open dlls and deallocate memory. + int close (void); + + /// Find dll in handle_vector_. + ACE_DLL_Handle *find_dll (const ACE_TCHAR *dll_name) const; + + /// Applies strategy for unloading dll. + int unload_dll (ACE_DLL_Handle *dll_handle, int force_unload = 0); + +private: + + /// Close the singleton instance. + static void close_singleton (void); + + /// Disallow copying and assignment since we don't handle these. + ACE_DLL_Manager (const ACE_DLL_Manager &); + void operator= (const ACE_DLL_Manager &); + +private: + + /// Vector containing all loaded handle objects. + ACE_DLL_Handle **handle_vector_; + + /// Current number of handles. + int current_size_; + + /// Maximum number of handles. + int total_size_; + + /// Unload strategy. + u_long unload_policy_; + + /// Pointer to a process-wide ACE_DLL_Manager. + static ACE_DLL_Manager *instance_; + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + /// Synchronization variable for the MT_SAFE Repository + ACE_Thread_Mutex lock_; +#endif /* ACE_MT_SAFE */ + +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_DLL_MANAGER_H */ diff --git a/dep/acelite/ace/Date_Time.cpp b/dep/acelite/ace/Date_Time.cpp new file mode 100644 index 000000000..8d84df812 --- /dev/null +++ b/dep/acelite/ace/Date_Time.cpp @@ -0,0 +1,8 @@ +// Date_Time.cpp +#include "ace/Date_Time.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Date_Time.inl" +#endif /* __ACE_INLINE__ */ + + diff --git a/dep/acelite/ace/Date_Time.h b/dep/acelite/ace/Date_Time.h new file mode 100644 index 000000000..aba5d0448 --- /dev/null +++ b/dep/acelite/ace/Date_Time.h @@ -0,0 +1,122 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Date_Time.h + * + * @author Tim Harrison (harrison@cs.wustl.edu) (and he's darn proud of this ;-)) + */ +//========================================================================== + +#ifndef ACE_DATE_TIME_H +#define ACE_DATE_TIME_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @class ACE_Date_Time + * + * @brief System independent representation of date and time. + */ +class ACE_Export ACE_Date_Time +{ +public: + /// Constructor initializes current time/date info. + ACE_Date_Time (void); + + /// Constructor initializes with the given ACE_Time_Value + explicit ACE_Date_Time (const ACE_Time_Value& timevalue); + + /// Constructor with init values, no check for validy + /// Set/get portions of ACE_Date_Time, no check for validity. + ACE_Date_Time (long day, + long month = 0, + long year = 0, + long hour = 0, + long minute = 0, + long second = 0, + long microsec = 0, + long wday = 0); + + /// Update to the current time/date. + void update (void); + + /// Update to the given ACE_Time_Value + void update (const ACE_Time_Value& timevalue); + + /// Get day. + long day (void) const; + + /// Set day. + void day (long day); + + /// Get month. + long month (void) const; + + /// Set month. + void month (long month); + + /// Get year. + long year (void) const; + + /// Set year. + void year (long year); + + /// Get hour. + long hour (void) const; + + /// Set hour. + void hour (long hour); + + /// Get minute. + long minute (void) const; + + /// Set minute. + void minute (long minute); + + /// Get second. + long second (void) const; + + /// Set second. + void second (long second); + + /// Get microsec. + long microsec (void) const; + + /// Set microsec. + void microsec (long microsec); + + /// Get weekday. + long weekday (void) const; + + /// Set weekday. + void weekday (long wday); + +private: + long day_; + long month_; + long year_; + long hour_; + long minute_; + long second_; + long microsec_; + long wday_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Date_Time.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DATE_TIME_H */ diff --git a/dep/acelite/ace/Date_Time.inl b/dep/acelite/ace/Date_Time.inl new file mode 100644 index 000000000..196f572be --- /dev/null +++ b/dep/acelite/ace/Date_Time.inl @@ -0,0 +1,216 @@ +// -*- C++ -*- +#include "ace/Global_Macros.h" +#include "ace/Time_Value.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/OS_NS_time.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void +ACE_Date_Time::update (const ACE_Time_Value& timevalue) +{ +#if defined (ACE_HAS_WINCE) + // CE doesn't do localtime(). + FILETIME file_time = timevalue; + FILETIME local_file_time; + SYSTEMTIME sys_time; + ::FileTimeToLocalFileTime (&file_time, &local_file_time); + ::FileTimeToSystemTime (&local_file_time, &sys_time); + this->day_ = sys_time.wDay; + this->month_ = sys_time.wMonth; + this->year_ = sys_time.wYear; + this->hour_ = sys_time.wHour; + this->minute_ = sys_time.wMinute; + this->second_ = sys_time.wSecond; + this->microsec_ = sys_time.wMilliseconds * 1000; + this->wday_ = sys_time.wDayOfWeek; +#else + time_t time = timevalue.sec (); + struct tm tm_time; + ACE_OS::localtime_r (&time, &tm_time); + this->day_ = tm_time.tm_mday; + this->month_ = tm_time.tm_mon + 1; // localtime's months are 0-11 + this->year_ = tm_time.tm_year + 1900; // localtime reports years since 1900 + this->hour_ = tm_time.tm_hour; + this->minute_ = tm_time.tm_min; + this->second_ = tm_time.tm_sec; + this->microsec_ = timevalue.usec (); + this->wday_ = tm_time.tm_wday; +#endif /* ACE_HAS_WINCE */ +} + +ACE_INLINE void +ACE_Date_Time::update (void) +{ + ACE_TRACE ("ACE_Date_Time::update"); + + update(ACE_OS::gettimeofday ()); +} + +ACE_INLINE +ACE_Date_Time::ACE_Date_Time (void) +{ + ACE_TRACE ("ACE_Date_Time::ACE_Date_Time"); + this->update (); +} + +ACE_INLINE +ACE_Date_Time::ACE_Date_Time (const ACE_Time_Value& timevalue) +{ + ACE_TRACE ("ACE_Date_Time::ACE_Date_Time: timevalue"); + this->update (timevalue); +} + +// Constructor with init values, no check for validy +ACE_INLINE +ACE_Date_Time::ACE_Date_Time (long day, + long month, + long year, + long hour, + long minute, + long second, + long microsec, + long wday) + : day_ (day), + month_ (month), + year_ (year), + hour_ (hour), + minute_ (minute), + second_ (second), + microsec_ (microsec), + wday_ (wday) +{ + ACE_TRACE ("ACE_Date_Time::ACE_Date_Time"); +} + +// set/get portions of ACE_Date_Time, no check for validy + +// get day +ACE_INLINE long +ACE_Date_Time::day (void) const +{ + ACE_TRACE ("ACE_Date_Time::day"); + return day_; +} + +// set day +ACE_INLINE void +ACE_Date_Time::day (long day) +{ + ACE_TRACE ("ACE_Date_Time::day"); + day_ = day; +} + +// get month +ACE_INLINE long +ACE_Date_Time::month (void) const +{ + ACE_TRACE ("ACE_Date_Time::month"); + return month_; +} + +// set month +ACE_INLINE void +ACE_Date_Time::month (long month) +{ + ACE_TRACE ("ACE_Date_Time::month"); + month_ = month; +} + +// get year +ACE_INLINE long +ACE_Date_Time::year (void) const +{ + ACE_TRACE ("ACE_Date_Time::year"); + return year_; +} + +// set year +ACE_INLINE void +ACE_Date_Time::year (long year) +{ + ACE_TRACE ("ACE_Date_Time::year"); + year_ = year; +} + +// get hour +ACE_INLINE long +ACE_Date_Time::hour (void) const +{ + ACE_TRACE ("ACE_Date_Time::hour"); + return hour_; +} + +// set hour +ACE_INLINE void +ACE_Date_Time::hour (long hour) +{ + ACE_TRACE ("ACE_Date_Time::hour"); + hour_ = hour; +} + +// get minute +ACE_INLINE long +ACE_Date_Time::minute (void) const +{ + ACE_TRACE ("ACE_Date_Time::minute"); + return minute_; +} + +// set minute +ACE_INLINE void +ACE_Date_Time::minute (long minute) +{ + ACE_TRACE ("ACE_Date_Time::minute"); + minute_ = minute; +} + +// get second +ACE_INLINE long +ACE_Date_Time::second (void) const +{ + ACE_TRACE ("ACE_Date_Time::second"); + return second_; +} + +// set second +ACE_INLINE void +ACE_Date_Time::second (long second) +{ + ACE_TRACE ("ACE_Date_Time::second"); + second_ = second; +} + +// get microsec +ACE_INLINE long +ACE_Date_Time::microsec (void) const +{ + ACE_TRACE ("ACE_Date_Time::microsec"); + return microsec_; +} + +// set microsec +ACE_INLINE void +ACE_Date_Time::microsec (long microsec) +{ + ACE_TRACE ("ACE_Date_Time::microsec"); + microsec_ = microsec; +} + +// get wday +ACE_INLINE long +ACE_Date_Time::weekday (void) const +{ + ACE_TRACE ("ACE_Date_Time::weekday"); + return wday_; +} + +// set wday +ACE_INLINE void +ACE_Date_Time::weekday (long wday) +{ + ACE_TRACE ("ACE_Date_Time::weekday"); + wday_ = wday; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Default_Constants.h b/dep/acelite/ace/Default_Constants.h new file mode 100644 index 000000000..6a8d4acc8 --- /dev/null +++ b/dep/acelite/ace/Default_Constants.h @@ -0,0 +1,588 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Default_Constants.h + * + * @author Douglas C. Schmidt + * @author Jesper S. M|ller + * @author and a cast of thousands... + * + * This one is split from the famous OS.h + */ +//============================================================================= + +#ifndef ACE_DEFAULT_CONSTANTS_H +#define ACE_DEFAULT_CONSTANTS_H +#include /**/ "ace/pre.h" + +// Included just keep compilers that see #pragma directive first +// happy. +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// For _POSIX_TIMER_MAX +#include "ace/os_include/os_limits.h" + +// Define the default constants for ACE. Many of these are used for +// the ACE tests and applications. You can change these values by +// defining the macros in your config.h file. +# if !defined (ACE_DEFAULT_CLOSE_ALL_HANDLES) +# define ACE_DEFAULT_CLOSE_ALL_HANDLES true +# endif /* ACE_DEFAULT_CLOSE_ALL_HANDLES */ + +// The maximum length for a fully qualified Internet name. +# if !defined(ACE_MAX_FULLY_QUALIFIED_NAME_LEN) +# define ACE_MAX_FULLY_QUALIFIED_NAME_LEN 256 +# endif /* ACE_MAX_FULLY_QUALIFIED_NAME_LEN */ + +#if !defined (ACE_DEFAULT_PAGEFILE_POOL_BASE) +#define ACE_DEFAULT_PAGEFILE_POOL_BASE (void *) 0 +#endif /* ACE_DEFAULT_PAGEFILE_POOL_BASE */ + +#if !defined (ACE_DEFAULT_PAGEFILE_POOL_SIZE) +#define ACE_DEFAULT_PAGEFILE_POOL_SIZE (size_t) 0x01000000 +#endif /* ACE_DEFAULT_PAGEFILE_POOL_SIZE */ + +#if !defined (ACE_DEFAULT_PAGEFILE_POOL_CHUNK) +#define ACE_DEFAULT_PAGEFILE_POOL_CHUNK (size_t) 0x00010000 +#endif /* ACE_DEFAULT_PAGEFILE_POOL_CHUNK */ + +#if !defined (ACE_DEFAULT_PAGEFILE_POOL_NAME) +#define ACE_DEFAULT_PAGEFILE_POOL_NAME ACE_TEXT ("Default_ACE_Pagefile_Memory_Pool") +#endif /* ACE_DEFAULT_PAGEFILE_POOL_NAME */ + +#if !defined (ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY) +#define ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY 0 +#endif /* ACE_DEFAULT_MESSAGE_BLOCK_PRIORITY */ + +#if !defined (ACE_DEFAULT_SERVICE_REPOSITORY_SIZE) +#define ACE_DEFAULT_SERVICE_REPOSITORY_SIZE 1024 +#endif /* ACE_DEFAULT_SERVICE_REPOSITORY_SIZE */ + +#if !defined (ACE_DEFAULT_SERVICE_GESTALT_SIZE) +#define ACE_DEFAULT_SERVICE_GESTALT_SIZE 1024 +#endif /* ACE_DEFAULT_SERVICE_GESTALT_SIZE */ + +#if !defined (ACE_REACTOR_NOTIFICATION_ARRAY_SIZE) +#define ACE_REACTOR_NOTIFICATION_ARRAY_SIZE 1024 +#endif /* ACE_REACTOR_NOTIFICATION_ARRAY_SIZE */ + +# if !defined (ACE_DEFAULT_TIMEOUT) +# define ACE_DEFAULT_TIMEOUT 5 +# endif /* ACE_DEFAULT_TIMEOUT */ + +# if !defined (ACE_DEFAULT_BACKLOG) +# define ACE_DEFAULT_BACKLOG 5 +# endif /* ACE_DEFAULT_BACKLOG */ + +# if !defined (ACE_DEFAULT_ASYNCH_BACKLOG) +# define ACE_DEFAULT_ASYNCH_BACKLOG 5 +# endif /* ACE_DEFAULT_ASYNCH_BACKLOG */ + +# if !defined (ACE_DEFAULT_THREADS) +# define ACE_DEFAULT_THREADS 1 +# endif /* ACE_DEFAULT_THREADS */ + +// The following 3 defines are used in the IP multicast and broadcast tests. +# if !defined (ACE_DEFAULT_BROADCAST_PORT) +# define ACE_DEFAULT_BROADCAST_PORT 20000 +# endif /* ACE_DEFAULT_BROADCAST_PORT */ + +# if !defined (ACE_DEFAULT_MULTICAST_PORT) +# define ACE_DEFAULT_MULTICAST_PORT 20001 +# endif /* ACE_DEFAULT_MULTICAST_PORT */ + +# if !defined (ACE_DEFAULT_MULTICAST_ADDR) +// This address MUST be within the range for host group addresses: +// 224.0.0.0 to 239.255.255.255. +# define ACE_DEFAULT_MULTICAST_ADDR "224.9.9.2" +# endif /* ACE_DEFAULT_MULTICAST_ADDR */ + +# if defined (ACE_HAS_IPV6) +# if !defined (ACE_DEFAULT_MULTICASTV6_ADDR) +// This address should be within the range for site-local addresses: +// ff05::0/16 . +# define ACE_DEFAULT_MULTICASTV6_ADDR "ff05:0::ff01:1" +# endif /* ACE_DEFAULT_MULTICASTV6_ADDR */ +# endif + +// Default port number for HTTP. +# if !defined (ACE_DEFAULT_HTTP_SERVER_PORT) +# define ACE_DEFAULT_HTTP_SERVER_PORT 80 +# endif /* ACE_DEFAULT_HTTP_SERVER_PORT */ + +// Used in many IPC_SAP tests +# if !defined (ACE_DEFAULT_SERVER_PORT) +# define ACE_DEFAULT_SERVER_PORT 20002 +# endif /* ACE_DEFAULT_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_HTTP_PORT) +# define ACE_DEFAULT_HTTP_PORT 80 +# endif /* ACE_DEFAULT_HTTP_PORT */ + +# if !defined (ACE_DEFAULT_MAX_SOCKET_BUFSIZ) +# define ACE_DEFAULT_MAX_SOCKET_BUFSIZ 65536 +# endif /* ACE_DEFAULT_MAX_SOCKET_BUFSIZ */ + +# if !defined (ACE_DEFAULT_SERVER_PORT_STR) +# define ACE_DEFAULT_SERVER_PORT_STR ACE_TEXT("20002") +# endif /* ACE_DEFAULT_SERVER_PORT_STR */ + +// Used for the Service_Directory test +# if !defined (ACE_DEFAULT_SERVICE_PORT) +# define ACE_DEFAULT_SERVICE_PORT 20003 +# endif /* ACE_DEFAULT_SERVICE_PORT */ + +// Used for the ACE_Thread_Spawn test +# if !defined (ACE_DEFAULT_THR_PORT ) +# define ACE_DEFAULT_THR_PORT 20004 +# endif /* ACE_DEFAULT_THR_PORT */ + +// Used for tests +# if !defined (ACE_DEFAULT_LOCAL_PORT) +# define ACE_DEFAULT_LOCAL_PORT 20005 +# endif /* ACE_DEFAULT_LOCAL_PORT */ + +// Used for Connector tests +# if !defined (ACE_DEFAULT_LOCAL_PORT_STR) +# define ACE_DEFAULT_LOCAL_PORT_STR "20005" +# endif /* ACE_DEFAULT_LOCAL_PORT_STR */ + +// Used for the name server. +# if !defined (ACE_DEFAULT_NAME_SERVER_PORT) +# define ACE_DEFAULT_NAME_SERVER_PORT 20006 +# endif /* ACE_DEFAULT_NAME_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_NAME_SERVER_PORT_STR) +# define ACE_DEFAULT_NAME_SERVER_PORT_STR "20006" +# endif /* ACE_DEFAULT_NAME_SERVER_PORT_STR */ + +// Used for the token server. +# if !defined (ACE_DEFAULT_TOKEN_SERVER_PORT) +# define ACE_DEFAULT_TOKEN_SERVER_PORT 20007 +# endif /* ACE_DEFAULT_TOKEN_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_TOKEN_SERVER_PORT_STR) +# define ACE_DEFAULT_TOKEN_SERVER_PORT_STR "20007" +# endif /* ACE_DEFAULT_TOKEN_SERVER_PORT_STR */ + +// Used for the logging server. +# if !defined (ACE_DEFAULT_LOGGING_SERVER_PORT) +# define ACE_DEFAULT_LOGGING_SERVER_PORT 20008 +# endif /* ACE_DEFAULT_LOGGING_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_LOGGING_SERVER_PORT_STR) +# define ACE_DEFAULT_LOGGING_SERVER_PORT_STR "20008" +# endif /* ACE_DEFAULT_LOGGING_SERVER_PORT_STR */ + +// Used for the logging server. +# if !defined (ACE_DEFAULT_THR_LOGGING_SERVER_PORT) +# define ACE_DEFAULT_THR_LOGGING_SERVER_PORT 20008 +# endif /* ACE_DEFAULT_THR_LOGGING_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_THR_LOGGING_SERVER_PORT_STR) +# define ACE_DEFAULT_THR_LOGGING_SERVER_PORT_STR "20008" +# endif /* ACE_DEFAULT_THR_LOGGING_SERVER_PORT_STR */ + +// Used for the time server. +# if !defined (ACE_DEFAULT_TIME_SERVER_PORT) +# define ACE_DEFAULT_TIME_SERVER_PORT 20009 +# endif /* ACE_DEFAULT_TIME_SERVER_PORT */ + +# if !defined (ACE_DEFAULT_TIME_SERVER_PORT_STR) +# define ACE_DEFAULT_TIME_SERVER_PORT_STR "20009" +# endif /* ACE_DEFAULT_TIME_SERVER_PORT_STR */ + +# if !defined (ACE_DEFAULT_TIME_SERVER_STR) +# define ACE_DEFAULT_TIME_SERVER_STR "ACE_TS_TIME" +# endif /* ACE_DEFAULT_TIME_SERVER_STR */ + +// Used by the FIFO tests +# if !defined (ACE_DEFAULT_RENDEZVOUS) +# if defined (ACE_HAS_STREAM_PIPES) +# define ACE_DEFAULT_RENDEZVOUS ACE_TEXT("/tmp/fifo.ace") +# else +# define ACE_DEFAULT_RENDEZVOUS ACE_TEXT("localhost:20010") +# endif /* ACE_HAS_STREAM_PIPES */ +# endif /* ACE_DEFAULT_RENDEZVOUS */ + +// Used for the UNIX syslog logging interface to ACE_Log_Msg. +# ifndef ACE_DEFAULT_SYSLOG_FACILITY +# define ACE_DEFAULT_SYSLOG_FACILITY LOG_USER +# endif /* ACE_DEFAULT_SYSLOG_FACILITY */ + +# if !defined (ACE_HAS_STREAM_LOG_MSG_IPC) +# if defined (ACE_HAS_STREAM_PIPES) +# define ACE_HAS_STREAM_LOG_MSG_IPC 1 +# else +# define ACE_HAS_STREAM_LOG_MSG_IPC 0 +# endif /* ACE_HAS_STREAM_PIPES */ +# endif /* !ACE_HAS_STREAM_LOG_MSG_IPC */ + +# if !defined (ACE_DEFAULT_LOGGER_KEY) +# if (ACE_HAS_STREAM_LOG_MSG_IPC == 1) +# define ACE_DEFAULT_LOGGER_KEY ACE_TEXT ("/tmp/server_daemon") +# else +# define ACE_DEFAULT_LOGGER_KEY ACE_TEXT ("localhost:20012") +# endif /* ACE_HAS_STREAM_LOG_MSG_IPC==1 */ +# endif /* ACE_DEFAULT_LOGGER_KEY */ + +// The way to specify the local host for loopback IP. This is usually +// "localhost" but it may need changing on some platforms. +# if !defined (ACE_LOCALHOST) +# define ACE_LOCALHOST ACE_TEXT ("localhost") +# endif + +// This specification for an IPv6 localhost should work on all platforms +// supporting IPv6 +# if defined (ACE_HAS_IPV6) +# if !defined (ACE_IPV6_LOCALHOST) +# define ACE_IPV6_LOCALHOST ACE_TEXT ("::1") +# endif /* ACE_IPV6_LOCALHOST*/ +#endif /* ACE_HAS_IPV6 */ + +// This specification for an IPv6 ANY address should work on all platforms +// supporting IPv6 +# if defined (ACE_HAS_IPV6) +# if !defined (ACE_IPV6_ANY) +# define ACE_IPV6_ANY ACE_TEXT ("::") +# endif /* ACE_IPV6_ANY*/ +#endif /* ACE_HAS_IPV6 */ + +# if !defined (ACE_DEFAULT_SERVER_HOST) +# if defined (ACE_HAS_IPV6) +# define ACE_DEFAULT_SERVER_HOST ACE_IPV6_LOCALHOST +# else /*ACE_HAS_IPV6*/ +# define ACE_DEFAULT_SERVER_HOST ACE_LOCALHOST +# endif /*ACE_HAS_IPV6*/ +# endif /* ACE_DEFAULT_SERVER_HOST */ + +// Default shared memory key +# if !defined (ACE_DEFAULT_SHM_KEY) +# define ACE_DEFAULT_SHM_KEY 1234 +# endif /* ACE_DEFAULT_SHM_KEY */ + +// Default address for shared memory mapped files and SYSV shared memory +// (defaults to 64 M). +# if !defined (ACE_DEFAULT_BASE_ADDR) +# define ACE_DEFAULT_BASE_ADDR ((char *) (64 * 1024 * 1024)) +# endif /* ACE_DEFAULT_BASE_ADDR */ + +// Default segment size used by SYSV shared memory (128 K) +# if !defined (ACE_DEFAULT_SEGMENT_SIZE) +# define ACE_DEFAULT_SEGMENT_SIZE 1024 * 128 +# endif /* ACE_DEFAULT_SEGMENT_SIZE */ + +// Maximum number of SYSV shared memory segments +// (does anyone know how to figure out the right values?!) +# if !defined (ACE_DEFAULT_MAX_SEGMENTS) +# define ACE_DEFAULT_MAX_SEGMENTS 6 +# endif /* ACE_DEFAULT_MAX_SEGMENTS */ + +// Name of the map that's stored in shared memory. +# if !defined (ACE_NAME_SERVER_MAP) +# define ACE_NAME_SERVER_MAP "Name Server Map" +# endif /* ACE_NAME_SERVER_MAP */ + +// Default file permissions. +# if !defined (ACE_DEFAULT_FILE_PERMS) +# if defined (ACE_VXWORKS) +# define ACE_DEFAULT_FILE_PERMS (S_IRUSR | S_IWUSR| S_IRGRP| S_IROTH) +# else +# define ACE_DEFAULT_FILE_PERMS 0644 +# endif /* ACE_VXWORKS */ +# endif /* ACE_DEFAULT_FILE_PERMS */ + +// Default directory permissions. +# if !defined (ACE_DEFAULT_DIR_PERMS) +# define ACE_DEFAULT_DIR_PERMS 0755 +# endif /* ACE_DEFAULT_DIR_PERMS */ + +# if !defined (ACE_DEFAULT_TIMEPROBE_TABLE_SIZE) +# define ACE_DEFAULT_TIMEPROBE_TABLE_SIZE 8 * 1024 +# endif /* ACE_DEFAULT_TIMEPROBE_TABLE_SIZE */ + +// Default size of the ACE Map_Manager. +# if !defined (ACE_DEFAULT_MAP_SIZE) +# define ACE_DEFAULT_MAP_SIZE 1024 +# endif /* ACE_DEFAULT_MAP_SIZE */ + +# if defined (ACE_DEFAULT_MAP_SIZE) && (ACE_DEFAULT_MAP_SIZE == 0) +# error ACE_DEFAULT_MAP_SIZE should not be zero +# endif /* ACE_DEFAULT_MAP_SIZE */ + +// Defaults for ACE Timer Wheel +# if !defined (ACE_DEFAULT_TIMER_WHEEL_SIZE) +# define ACE_DEFAULT_TIMER_WHEEL_SIZE 1024 +# endif /* ACE_DEFAULT_TIMER_WHEEL_SIZE */ + +# if !defined (ACE_DEFAULT_TIMER_WHEEL_RESOLUTION) +# define ACE_DEFAULT_TIMER_WHEEL_RESOLUTION 100 +# endif /* ACE_DEFAULT_TIMER_WHEEL_RESOLUTION */ + +// Default size for ACE Timer Hash table +# if !defined (ACE_DEFAULT_TIMER_HASH_TABLE_SIZE) +# define ACE_DEFAULT_TIMER_HASH_TABLE_SIZE 1024 +# endif /* ACE_DEFAULT_TIMER_HASH_TABLE_SIZE */ + +// Defaults for the ACE Free List +# if !defined (ACE_DEFAULT_FREE_LIST_PREALLOC) +# define ACE_DEFAULT_FREE_LIST_PREALLOC 0 +# endif /* ACE_DEFAULT_FREE_LIST_PREALLOC */ + +# if !defined (ACE_DEFAULT_FREE_LIST_LWM) +# define ACE_DEFAULT_FREE_LIST_LWM 0 +# endif /* ACE_DEFAULT_FREE_LIST_LWM */ + +# if !defined (ACE_DEFAULT_FREE_LIST_HWM) +# define ACE_DEFAULT_FREE_LIST_HWM 25000 +# endif /* ACE_DEFAULT_FREE_LIST_HWM */ + +# if !defined (ACE_DEFAULT_FREE_LIST_INC) +# define ACE_DEFAULT_FREE_LIST_INC 100 +# endif /* ACE_DEFAULT_FREE_LIST_INC */ + +# if !defined (ACE_UNIQUE_NAME_LEN) +# define ACE_UNIQUE_NAME_LEN 100 +# endif /* ACE_UNIQUE_NAME_LEN */ + +# if !defined (ACE_MAX_DGRAM_SIZE) + // This is just a guess. 8k is the normal limit on + // most machines because that's what NFS expects. +# define ACE_MAX_DGRAM_SIZE 8192 +# endif /* ACE_MAX_DGRAM_SIZE */ + +# if !defined (ACE_DEFAULT_ARGV_BUFSIZ) +# define ACE_DEFAULT_ARGV_BUFSIZ 1024 * 4 +# endif /* ACE_DEFAULT_ARGV_BUFSIZ */ + +// A free list which create more elements when there aren't enough +// elements. +# define ACE_FREE_LIST_WITH_POOL 1 + +// A simple free list which doen't allocate/deallocate elements. +# define ACE_PURE_FREE_LIST 2 + +# if defined (ACE_WIN32) + +// This is necessary to work around bugs with Win32 non-blocking +// connects... +# if !defined (ACE_NON_BLOCKING_BUG_DELAY) +# define ACE_NON_BLOCKING_BUG_DELAY 35000 +# endif /* ACE_NON_BLOCKING_BUG_DELAY */ +# endif /*ACE_WIN32*/ + +// Max size of an ACE Log Record data buffer. This can be reset in +// the config.h file if you'd like to increase or decrease the size. +# if !defined (ACE_MAXLOGMSGLEN) +# define ACE_MAXLOGMSGLEN 4 * 1024 +# endif /* ACE_MAXLOGMSGLEN */ + +// Max size of an ACE Token. +# define ACE_MAXTOKENNAMELEN 40 + +// Max size of an ACE Token client ID. +# define ACE_MAXCLIENTIDLEN MAXHOSTNAMELEN + 20 + +/// Max udp packet size +#if !defined (ACE_MAX_UDP_PACKET_SIZE) +#define ACE_MAX_UDP_PACKET_SIZE 65507 +#endif + +/** + * @name Default values to control CDR classes memory allocation strategies + */ +//@{ + +/// Control the initial size of all CDR buffers, application +/// developers may want to optimize this value to fit their request +/// size +#if !defined (ACE_DEFAULT_CDR_BUFSIZE) +# define ACE_DEFAULT_CDR_BUFSIZE 512 +#endif /* ACE_DEFAULT_CDR_BUFSIZE */ + +#if (ACE_DEFAULT_CDR_BUFSIZE == 0) +# error: ACE_DEFAULT_CDR_BUFSIZE should be bigger then 0 +#endif + +/// Stop exponential growth of CDR buffers to avoid overallocation +#if !defined (ACE_DEFAULT_CDR_EXP_GROWTH_MAX) +# define ACE_DEFAULT_CDR_EXP_GROWTH_MAX 65536 +#endif /* ACE_DEFAULT_CDR_EXP_GROWTH_MAX */ + +/// Control CDR buffer growth after maximum exponential growth is +/// reached +#if !defined (ACE_DEFAULT_CDR_LINEAR_GROWTH_CHUNK) +# define ACE_DEFAULT_CDR_LINEAR_GROWTH_CHUNK 65536 +#endif /* ACE_DEFAULT_CDR_LINEAR_GROWTH_CHUNK */ +//@} + +/// Control the zero-copy optimizations for octet sequences +/** + * Large octet sequences can be sent without any copies by chaining + * them in the list of message blocks that represent a single CDR + * stream. However, if the octet sequence is too small the zero copy + * optimizations actually hurt performance. Octet sequences smaller + * than this value will be copied. + */ +#if !defined (ACE_DEFAULT_CDR_MEMCPY_TRADEOFF) +#define ACE_DEFAULT_CDR_MEMCPY_TRADEOFF 256 +#endif /* ACE_DEFAULT_CDR_MEMCPY_TRADEOFF */ + +#if defined (ACE_WIN32) + // Define the pathname separator characters for Win32 (ugh). +# define ACE_DIRECTORY_SEPARATOR_STR_A "\\" +# define ACE_DIRECTORY_SEPARATOR_CHAR_A '\\' +#else + // Define the pathname separator characters for UNIX. +# define ACE_DIRECTORY_SEPARATOR_STR_A "/" +# define ACE_DIRECTORY_SEPARATOR_CHAR_A '/' +#endif /* ACE_WIN32 */ + +// Define the Wide character and normal versions of some of the string macros +#if defined (ACE_HAS_WCHAR) +# define ACE_DIRECTORY_SEPARATOR_STR_W ACE_TEXT_WIDE(ACE_DIRECTORY_SEPARATOR_STR_A) +# define ACE_DIRECTORY_SEPARATOR_CHAR_W ACE_TEXT_WIDE(ACE_DIRECTORY_SEPARATOR_CHAR_A) +#endif /* ACE_HAS_WCHAR */ + +#define ACE_DIRECTORY_SEPARATOR_STR ACE_TEXT (ACE_DIRECTORY_SEPARATOR_STR_A) +#define ACE_DIRECTORY_SEPARATOR_CHAR ACE_TEXT (ACE_DIRECTORY_SEPARATOR_CHAR_A) + +#if !defined (ACE_DEFAULT_THREAD_PRIORITY) +# define ACE_DEFAULT_THREAD_PRIORITY (-0x7fffffffL - 1L) +#endif /* ACE_DEFAULT_THREAD_PRIORITY */ + +#if !defined (ACE_DEFAULT_THREAD_STACKSIZE) +# define ACE_DEFAULT_THREAD_STACKSIZE 0 +#endif /* ACE_DEFAULT_THREAD_STACKSIZE */ + +#if !defined (ACE_MAX_DEFAULT_PORT) +# define ACE_MAX_DEFAULT_PORT 65535 +#endif /* ACE_MAX_DEFAULT_PORT */ + +// Default number of ACE_Event_Handlers supported by +// ACE_Timer_Heap. +#if !defined (ACE_DEFAULT_TIMERS) && defined (_POSIX_TIMER_MAX) +# define ACE_DEFAULT_TIMERS _POSIX_TIMER_MAX +#endif /* ACE_DEFAULT_TIMERS */ + +#if !defined (ACE_DEFAULT_TIMERS) || (defined (ACE_DEFAULT_TIMERS) && (ACE_DEFAULT_TIMERS == 0)) +#error ACE_DEFAULT_TIMERS should be defined and not be zero +#endif /* ACE_DEFAULT_TIMERS */ + +#if defined (ACE_WIN32) +# define ACE_PLATFORM_A "Win32" +# define ACE_PLATFORM_EXE_SUFFIX_A ".exe" +#elif defined (ACE_VXWORKS) +# define ACE_PLATFORM_A "VxWorks" +# if defined (__RTP__) +# define ACE_PLATFORM_EXE_SUFFIX_A ".vxe" +# else +# define ACE_PLATFORM_EXE_SUFFIX_A ".out" +# endif +#else /* !ACE_WIN32 && !ACE_VXWORKS */ +# define ACE_PLATFORM_A "UNIX" +# define ACE_PLATFORM_EXE_SUFFIX_A "" +#endif /* ACE_WIN32 */ + +// Define the Wide character and normal versions of some of the string macros +#if defined (ACE_HAS_WCHAR) +# define ACE_PLATFORM_W ACE_TEXT_WIDE(ACE_PLATFORM_A) +# define ACE_PLATFORM_EXE_SUFFIX_W ACE_TEXT_WIDE(ACE_PLATFORM_EXE_SUFFIX_A) +#endif /* ACE_HAS_WCHAR */ + +#define ACE_PLATFORM ACE_TEXT (ACE_PLATFORM_A) +#define ACE_PLATFORM_EXE_SUFFIX ACE_TEXT (ACE_PLATFORM_EXE_SUFFIX_A) + +#if defined (ACE_WIN32) +# define ACE_LD_SEARCH_PATH ACE_TEXT ("PATH") +# define ACE_LD_SEARCH_PATH_SEPARATOR_STR ACE_TEXT (";") +# define ACE_DLL_SUFFIX ACE_TEXT (".dll") +# if !defined (ACE_DLL_PREFIX) +# define ACE_DLL_PREFIX ACE_TEXT ("") +# endif /* !ACE_DLL_PREFIX */ +#else /* !ACE_WIN32 */ +# if !defined (ACE_LD_SEARCH_PATH) +# define ACE_LD_SEARCH_PATH ACE_TEXT ("LD_LIBRARY_PATH") +# endif /* ACE_LD_SEARCH_PATH */ +# if !defined (ACE_LD_SEARCH_PATH_SEPARATOR_STR) +# define ACE_LD_SEARCH_PATH_SEPARATOR_STR ACE_TEXT (":") +# endif /* ACE_LD_SEARCH_PATH_SEPARATOR_STR */ +#endif /* ACE_WIN32 */ + +#if !defined (ACE_DLL_SUFFIX) +# define ACE_DLL_SUFFIX ACE_TEXT (".so") +#endif /* ACE_DLL_SUFFIX */ + +#if !defined (ACE_DLL_PREFIX) +# define ACE_DLL_PREFIX ACE_TEXT ("lib") +#endif /* ACE_DLL_PREFIX */ + +#if defined (ACE_WIN32) +// Used for dynamic linking +# if !defined (ACE_DEFAULT_SVC_CONF) +# if (ACE_USES_CLASSIC_SVC_CONF == 1) +# define ACE_DEFAULT_SVC_CONF ACE_TEXT (".\\svc.conf") +# else +# define ACE_DEFAULT_SVC_CONF ACE_TEXT (".\\svc.conf.xml") +# endif /* ACE_USES_CLASSIC_SVC_CONF ==1 */ +# endif /* ACE_DEFAULT_SVC_CONF */ +#endif /* ACE_WIN32 */ + + // Used for dynamic linking. +#if !defined (ACE_DEFAULT_SVC_CONF) +# if (ACE_USES_CLASSIC_SVC_CONF == 1) +# define ACE_DEFAULT_SVC_CONF ACE_TEXT ("./svc.conf") +# else +# define ACE_DEFAULT_SVC_CONF ACE_TEXT ("./svc.conf.xml") +# endif /* ACE_USES_CLASSIC_SVC_CONF ==1 */ +#endif /* ACE_DEFAULT_SVC_CONF */ + +#if !defined (ACE_LOGGER_KEY) +# define ACE_LOGGER_KEY ACE_TEXT ("/tmp/server_daemon") +#endif /* ACE_LOGGER_KEY */ + +// Theses defines are used by the ACE Name Server. +#if !defined (ACE_DEFAULT_LOCALNAME_A) +# define ACE_DEFAULT_LOCALNAME_A "localnames" +#endif /* ACE_DEFAULT_LOCALNAME_A */ +#if !defined (ACE_DEFAULT_GLOBALNAME_A) +# define ACE_DEFAULT_GLOBALNAME_A "globalnames" +#endif /* ACE_DEFAULT_GLOBALNAME_A */ + +#if defined (ACE_HAS_WCHAR) +# define ACE_DEFAULT_LOCALNAME_W ACE_TEXT_WIDE(ACE_DEFAULT_LOCALNAME_A) +# define ACE_DEFAULT_GLOBALNAME_W ACE_TEXT_WIDE(ACE_DEFAULT_GLOBALNAME_A) +#endif /* ACE_HAS_WCHAR */ + +#define ACE_DEFAULT_LOCALNAME ACE_TEXT (ACE_DEFAULT_LOCALNAME_A) +#define ACE_DEFAULT_GLOBALNAME ACE_TEXT (ACE_DEFAULT_GLOBALNAME_A) + +#if !defined (ACE_DEFAULT_OPEN_PERMS) +# define ACE_DEFAULT_OPEN_PERMS ACE_DEFAULT_FILE_PERMS +#endif /* ACE_DEFAULT_OPEN_PERMS */ + +#if !defined (ACE_DEFAULT_RW_PROCESS_MUTEX_PERMS) +# if defined (ACE_WIN32) +# define ACE_DEFAULT_RW_PROCESS_MUTEX_PERMS ACE_DEFAULT_OPEN_PERMS +# else +# define ACE_DEFAULT_RW_PROCESS_MUTEX_PERMS (S_IRUSR | S_IWUSR) +# endif /* ACE_WIN32 */ +#endif /* ACE_DEFAULT_RW_PROCESS_MUTEX_PERMS */ + +# if defined (ACE_WIN32) + // The "null" device on Win32. +# define ACE_DEV_NULL "nul" +# define ACE_SYSCALL_FAILED 0xFFFFFFFF +# else /* !ACE_WIN32 */ + // The "null" device on UNIX. +# define ACE_DEV_NULL "/dev/null" +# define ACE_SYSCALL_FAILED -1 +# endif /* ACE_WIN32 */ + +#include /**/ "ace/post.h" +#endif /*ACE_DEFAULT_CONSTANTS_H*/ diff --git a/dep/acelite/ace/Dev_Poll_Reactor.cpp b/dep/acelite/ace/Dev_Poll_Reactor.cpp new file mode 100644 index 000000000..4d85a7092 --- /dev/null +++ b/dep/acelite/ace/Dev_Poll_Reactor.cpp @@ -0,0 +1,2588 @@ +#include "ace/OS_NS_errno.h" +#include "ace/Dev_Poll_Reactor.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" +#include "ace/Flag_Manip.h" + +#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) + +# include "ace/OS_NS_unistd.h" +# include "ace/OS_NS_fcntl.h" +# include "ace/OS_NS_stropts.h" + +# if defined (ACE_HAS_DEV_POLL) +# if defined (ACE_LINUX) +# include /**/ +# elif defined (HPUX_VERS) && HPUX_VERS < 1123 +# include /**/ +# else +# include /**/ +# endif /* ACE_LINUX */ +# endif /* ACE_HAS_DEV_POLL */ + +#if !defined (__ACE_INLINE__) +# include "ace/Dev_Poll_Reactor.inl" +#endif /* __ACE_INLINE__ */ + + +#include "ace/Handle_Set.h" +#include "ace/Reactor.h" +#include "ace/Timer_Heap.h" +#include "ace/Timer_Queue.h" +#include "ace/ACE.h" +#include "ace/Reverse_Lock_T.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Null_Mutex.h" +#include "ace/os_include/os_poll.h" +#include "ace/OS_NS_sys_mman.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Functor_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Dev_Poll_Reactor) +ACE_ALLOC_HOOK_DEFINE(ACE_Dev_Poll_Reactor::Event_Tuple) +ACE_ALLOC_HOOK_DEFINE(ACE_Dev_Poll_Reactor_Notify) + +ACE_Dev_Poll_Reactor_Notify::ACE_Dev_Poll_Reactor_Notify (void) + : dp_reactor_ (0) + , notification_pipe_ () + , max_notify_iterations_ (-1) +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + , notification_queue_ () +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ +{ +} + +int +ACE_Dev_Poll_Reactor_Notify::open (ACE_Reactor_Impl *r, + ACE_Timer_Queue * /* timer_queue */, + int disable_notify_pipe) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::open"); + + if (disable_notify_pipe == 0) + { + this->dp_reactor_ = dynamic_cast (r); + + if (this->dp_reactor_ == 0) + { + errno = EINVAL; + return -1; + } + + if (this->notification_pipe_.open () == -1) + return -1; + +#if defined (F_SETFD) && !defined (ACE_LACKS_FCNTL) + // close-on-exec + if (ACE_OS::fcntl (this->notification_pipe_.read_handle (), F_SETFD, 1) == -1) + { + return -1; + } + if (ACE_OS::fcntl (this->notification_pipe_.write_handle (), F_SETFD, 1) == -1) + { + return -1; + } +#endif /* F_SETFD */ + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + if (notification_queue_.open () == -1) + { + return -1; + } + + if (ACE::set_flags (this->notification_pipe_.write_handle (), + ACE_NONBLOCK) == -1) + return -1; +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ + + // Set the read handle into non-blocking mode since we need to + // perform a "speculative" read when determining if there are + // notifications to dispatch. + if (ACE::set_flags (this->notification_pipe_.read_handle (), + ACE_NONBLOCK) == -1) + return -1; + } + + return 0; +} + +int +ACE_Dev_Poll_Reactor_Notify::close (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::close"); + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + notification_queue_.reset (); +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ + + return this->notification_pipe_.close (); +} + +int +ACE_Dev_Poll_Reactor_Notify::notify (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask, + ACE_Time_Value *timeout) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::notify"); + + // Just consider this method a "no-op" if there's no + // ACE_Dev_Poll_Reactor configured. + if (this->dp_reactor_ == 0) + return 0; + + ACE_Notification_Buffer buffer (eh, mask); + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + ACE_UNUSED_ARG (timeout); + ACE_Dev_Poll_Handler_Guard eh_guard (eh); + + // When using the queue, always try to write to the notify pipe. If it + // fills up, ignore it safely because the already-written bytes will + // eventually cause the notify handler to be dispatched. + if (-1 == this->notification_queue_.push_new_notification (buffer)) + return -1; // Also decrement eh's reference count + + // The notification has been queued, so it will be delivered at some + // point (and may have been already); release the refcnt guard. + eh_guard.release (); + + // Now pop the pipe to force the callback for dispatching when ready. If + // the send fails due to a full pipe, don't fail - assume the already-sent + // pipe bytes will cause the entire notification queue to be processed. + // Note that we don't need a timeout since the pipe is already in + // nonblocking mode and all we want is one attempt. + ssize_t n = ACE::send (this->notification_pipe_.write_handle (), + (char *) &buffer, + 1); // Only need one byte to pop the pipe + if (n == -1 && (errno != EAGAIN)) + return -1; + + return 0; +#else + + ACE_Dev_Poll_Handler_Guard eh_guard (eh); + + ssize_t n = ACE::send (this->notification_pipe_.write_handle (), + (char *) &buffer, + sizeof buffer, + timeout); + if (n == -1) + return -1; + + eh_guard.release (); + + return 0; +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ +} + +int +ACE_Dev_Poll_Reactor_Notify::dispatch_notifications ( + int & /* number_of_active_handles */, + ACE_Handle_Set & /* rd_mask */) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::dispatch_notifications"); + + // This method is unimplemented in the ACE_Dev_Poll_Reactor. + // Instead, the notification handler is invoked as part of the IO + // event set. Doing so alters the some documented semantics that + // state that the notifications are handled before IO events. + // Enforcing such semantics does not appear to be beneficial, and + // also serves to slow down event dispatching particularly with this + // ACE_Dev_Poll_Reactor. + + ACE_NOTSUP_RETURN (-1); +} + +int +ACE_Dev_Poll_Reactor_Notify::read_notify_pipe (ACE_HANDLE handle, + ACE_Notification_Buffer &buffer) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::read_notify_pipe"); + + // This is a (non-blocking) "speculative" read, i.e., we attempt to + // read even if no event was polled on the read handle. A + // speculative read is necessary since notifications must be + // dispatched before IO events. We can avoid the speculative read + // by "walking" the array of pollfd structures returned from + // `/dev/poll' or `/dev/epoll' but that is potentially much more + // expensive than simply checking for an EWOULDBLOCK. + size_t to_read; + char *read_p; + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + // The idea in the queued case is to be sure we never end up with a notify + // queued but no byte in the pipe. If that happens, the notify won't be + // dispatched. So always try to empty the pipe, read the queue, then put + // a byte in if needed. The notify() method is enqueueing then writing the + // pipe, so be sure to do it in the reverse order here to avoid a race + // between removing the last notification from the queue and the notify + // side writing its byte. + char b[1024]; + read_p = b; + to_read = sizeof(b); + (void)ACE::recv (handle, read_p, to_read); + + bool more_messages_queued = false; + ACE_Notification_Buffer next; + int result = 1; + while (result == 1) + { + result = notification_queue_.pop_next_notification (buffer, + more_messages_queued, + next); + + if (result <= 0) // Nothing dequeued or error + return result; + + // If it's just a wake-up, toss it and see if there's anything else. + if (buffer.eh_ != 0) + break; + } + + // If there are more messages, ensure there's a byte in the pipe + // in case the notification limit stops dequeuing notifies before + // emptying the queue. + if (more_messages_queued) + (void) ACE::send (this->notification_pipe_.write_handle (), + (char *)&next, + 1); /* one byte is enough */ + return 1; +#else + to_read = sizeof buffer; + read_p = (char *)&buffer; + + ssize_t n = ACE::recv (handle, read_p, to_read); + + if (n > 0) + { + // Check to see if we've got a short read. + if (static_cast (n) != to_read) + { + size_t remainder = to_read - n; + + // If so, try to recover by reading the remainder. If this + // doesn't work we're in big trouble since the input stream + // won't be aligned correctly. I'm not sure quite what to + // do at this point. It's probably best just to return -1. + if (ACE::recv (handle, &read_p[n], remainder) <= 0) + return -1; + } + + return 1; + } + + // Return -1 if things have gone seriously wrong. + if (n <= 0 && (errno != EWOULDBLOCK && errno != EAGAIN)) + return -1; + + return 0; +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ +} + + +int +ACE_Dev_Poll_Reactor_Notify::handle_input (ACE_HANDLE /*handle*/) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::handle_input"); + ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT ("SHOULD NOT BE HERE.\n")), -1); +} + +ACE_HANDLE +ACE_Dev_Poll_Reactor_Notify::notify_handle (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::notify_handle"); + + return this->notification_pipe_.read_handle (); +} + +int +ACE_Dev_Poll_Reactor_Notify::is_dispatchable (ACE_Notification_Buffer &) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::is_dispatchable"); + + ACE_NOTSUP_RETURN (-1); +} + +int +ACE_Dev_Poll_Reactor_Notify::dispatch_notify (ACE_Notification_Buffer &buffer) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::dispatch_notify"); + + // If eh == 0 then another thread is unblocking the + // ACE_Dev_Poll_Reactor to update the ACE_Dev_Poll_Reactor's + // internal structures. Otherwise, we need to dispatch the + // appropriate handle_* method on the ACE_Event_Handler + // pointer we've been passed. + if (buffer.eh_ != 0) + { + int result = 0; + + // Guard the handler's refcount. Recall that when the notify + // was queued, the refcount was incremented, so it need not be + // now. The guard insures that it is decremented properly. + ACE_Dev_Poll_Handler_Guard eh_guard (buffer.eh_, false); + + switch (buffer.mask_) + { + case ACE_Event_Handler::READ_MASK: + case ACE_Event_Handler::ACCEPT_MASK: + result = buffer.eh_->handle_input (ACE_INVALID_HANDLE); + break; + case ACE_Event_Handler::WRITE_MASK: + result = buffer.eh_->handle_output (ACE_INVALID_HANDLE); + break; + case ACE_Event_Handler::EXCEPT_MASK: + result = buffer.eh_->handle_exception (ACE_INVALID_HANDLE); + break; + default: + // Should we bail out if we get an invalid mask? + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("dispatch_notify invalid mask = %d\n"), + buffer.mask_)); + } + if (result == -1) + buffer.eh_->handle_close (ACE_INVALID_HANDLE, buffer.mask_); + } + + return 1; +} + +void +ACE_Dev_Poll_Reactor_Notify::max_notify_iterations (int iterations) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::max_notify_iterations"); + + // Must always be > 0 or < 0 to optimize the loop exit condition. + if (iterations == 0) + iterations = 1; + + this->max_notify_iterations_ = iterations; +} + +int +ACE_Dev_Poll_Reactor_Notify::max_notify_iterations (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::max_notify_iterations"); + + return this->max_notify_iterations_; +} + +int +ACE_Dev_Poll_Reactor_Notify::purge_pending_notifications ( + ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::purge_pending_notifications"); + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + + return notification_queue_.purge_pending_notifications (eh, mask); + +#else /* defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) */ + ACE_UNUSED_ARG (eh); + ACE_UNUSED_ARG (mask); + ACE_NOTSUP_RETURN (-1); +#endif /* defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) */ +} + +void +ACE_Dev_Poll_Reactor_Notify::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Dev_Poll_Reactor_Notify::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("dp_reactor_ = %@"), + this->dp_reactor_)); + this->notification_pipe_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Dev_Poll_Reactor_Notify::dequeue_one (ACE_Notification_Buffer &nb) +{ + nb.eh_ = 0; + nb.mask_ = 0; + return this->read_notify_pipe (this->notify_handle (), nb); +} + + +// ----------------------------------------------------------------- + +ACE_Dev_Poll_Reactor::Handler_Repository::Handler_Repository (void) + : size_ (0), + max_size_ (0), + handlers_ (0) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::Handler_Repository"); +} + +bool +ACE_Dev_Poll_Reactor::Handler_Repository::invalid_handle ( + ACE_HANDLE handle) const +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::invalid_handle"); + + if (handle < 0 || handle >= this->max_size_) + { + errno = EINVAL; + return true; + } + else + return false; +} + +bool +ACE_Dev_Poll_Reactor::Handler_Repository::handle_in_range ( + ACE_HANDLE handle) const +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::handle_in_range"); + + if (handle >= 0 && handle < this->max_size_) + return true; + else + { + errno = EINVAL; + return false; + } +} + +int +ACE_Dev_Poll_Reactor::Handler_Repository::open (size_t size) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::open"); + + this->max_size_ = size; + + // Try to allocate the memory. + ACE_NEW_RETURN (this->handlers_, Event_Tuple[size], -1); + + // Try to increase the number of handles if is greater than + // the current limit. + return ACE::set_handle_limit (size); +} + +int +ACE_Dev_Poll_Reactor::Handler_Repository::unbind_all (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::unbind_all"); + + // Unbind all of the event handlers; similar to remove_handler() on all. + for (int handle = 0; + handle < this->max_size_; + ++handle) + { + Event_Tuple *entry = this->find (handle); + if (entry == 0) + continue; + + // Check for ref counting now - handle_close () may delete eh. + bool const requires_reference_counting = + entry->event_handler->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + (void) entry->event_handler->handle_close (handle, entry->mask); + this->unbind (handle, requires_reference_counting); + } + + return 0; +} + +int +ACE_Dev_Poll_Reactor::Handler_Repository::close (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::close"); + + if (this->handlers_ != 0) + { + this->unbind_all (); + + delete [] this->handlers_; + this->handlers_ = 0; + } + + return 0; +} + +ACE_Dev_Poll_Reactor::Event_Tuple * +ACE_Dev_Poll_Reactor::Handler_Repository::find (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::find"); + + Event_Tuple *tuple = 0; + + // Only bother to search for the if it's in range. + if (!this->handle_in_range (handle)) + { + errno = ERANGE; + return 0; + } + + tuple = &(this->handlers_[handle]); + if (tuple->event_handler == 0) + { + errno = ENOENT; + tuple = 0; + } + + return tuple; +} + +int +ACE_Dev_Poll_Reactor::Handler_Repository::bind ( + ACE_HANDLE handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::bind"); + + if (event_handler == 0) + return -1; + + if (handle == ACE_INVALID_HANDLE) + handle = event_handler->get_handle (); + + if (this->invalid_handle (handle)) + return -1; + + this->handlers_[handle].event_handler = event_handler; + this->handlers_[handle].mask = mask; + event_handler->add_reference (); + ++this->size_; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::Handler_Repository::unbind (ACE_HANDLE handle, + bool decr_refcnt) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::unbind"); + + Event_Tuple *entry = this->find (handle); + if (entry == 0) + return -1; + + if (decr_refcnt) + entry->event_handler->remove_reference (); + + entry->event_handler = 0; + entry->mask = ACE_Event_Handler::NULL_MASK; + entry->suspended = false; + entry->controlled = false; + --this->size_; + return 0; +} + +// ----------------------------------------------------------------- + +ACE_Dev_Poll_Reactor::ACE_Dev_Poll_Reactor (ACE_Sig_Handler *sh, + ACE_Timer_Queue *tq, + int disable_notify_pipe, + ACE_Reactor_Notify *notify, + int mask_signals, + int s_queue) + : initialized_ (false) + , poll_fd_ (ACE_INVALID_HANDLE) + // , ready_set_ () +#if defined (ACE_HAS_DEV_POLL) + , dp_fds_ (0) + , start_pfds_ (0) + , end_pfds_ (0) +#endif /* ACE_HAS_DEV_POLL */ + , token_ (*this, s_queue) + , lock_adapter_ (token_) + , deactivated_ (0) + , timer_queue_ (0) + , delete_timer_queue_ (false) + , signal_handler_ (0) + , delete_signal_handler_ (false) + , notify_handler_ (0) + , delete_notify_handler_ (false) + , mask_signals_ (mask_signals) + , restart_ (0) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::ACE_Dev_Poll_Reactor"); + + if (this->open (ACE::max_handles (), + 0, + sh, + tq, + disable_notify_pipe, + notify) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Dev_Poll_Reactor::open ") + ACE_TEXT ("failed inside ") + ACE_TEXT ("ACE_Dev_Poll_Reactor::CTOR"))); +} + +ACE_Dev_Poll_Reactor::ACE_Dev_Poll_Reactor (size_t size, + bool rs, + ACE_Sig_Handler *sh, + ACE_Timer_Queue *tq, + int disable_notify_pipe, + ACE_Reactor_Notify *notify, + int mask_signals, + int s_queue) + : initialized_ (false) + , poll_fd_ (ACE_INVALID_HANDLE) + // , ready_set_ () +#if defined (ACE_HAS_DEV_POLL) + , dp_fds_ (0) + , start_pfds_ (0) + , end_pfds_ (0) +#endif /* ACE_HAS_DEV_POLL */ + , token_ (*this, s_queue) + , lock_adapter_ (token_) + , deactivated_ (0) + , timer_queue_ (0) + , delete_timer_queue_ (false) + , signal_handler_ (0) + , delete_signal_handler_ (false) + , notify_handler_ (0) + , delete_notify_handler_ (false) + , mask_signals_ (mask_signals) + , restart_ (0) +{ + if (this->open (size, + rs, + sh, + tq, + disable_notify_pipe, + notify) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Dev_Poll_Reactor::open ") + ACE_TEXT ("failed inside ACE_Dev_Poll_Reactor::CTOR"))); +} + +ACE_Dev_Poll_Reactor::~ACE_Dev_Poll_Reactor (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::~ACE_Dev_Poll_Reactor"); + + (void) this->close (); +} + +int +ACE_Dev_Poll_Reactor::open (size_t size, + bool restart, + ACE_Sig_Handler *sh, + ACE_Timer_Queue *tq, + int disable_notify_pipe, + ACE_Reactor_Notify *notify) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::open"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, -1)); + + // Can't initialize ourselves more than once. + if (this->initialized_) + return -1; + +#ifdef ACE_HAS_EVENT_POLL + ACE_OS::memset (&this->event_, 0, sizeof (this->event_)); + this->event_.data.fd = ACE_INVALID_HANDLE; +#endif /* ACE_HAS_EVENT_POLL */ + + this->restart_ = restart; + this->signal_handler_ = sh; + this->timer_queue_ = tq; + this->notify_handler_ = notify; + + int result = 0; + + // Allows the signal handler to be overridden. + if (this->signal_handler_ == 0) + { + ACE_NEW_RETURN (this->signal_handler_, + ACE_Sig_Handler, + -1); + + if (this->signal_handler_ == 0) + result = -1; + else + this->delete_signal_handler_ = true; + } + + // Allows the timer queue to be overridden. + if (result != -1 && this->timer_queue_ == 0) + { + ACE_NEW_RETURN (this->timer_queue_, + ACE_Timer_Heap, + -1); + + if (this->timer_queue_ == 0) + result = -1; + else + this->delete_timer_queue_ = true; + } + + // Allows the Notify_Handler to be overridden. + if (result != -1 && this->notify_handler_ == 0) + { + ACE_NEW_RETURN (this->notify_handler_, + ACE_Dev_Poll_Reactor_Notify, + -1); + + if (this->notify_handler_ == 0) + result = -1; + else + this->delete_notify_handler_ = true; + } + +#if defined (ACE_HAS_EVENT_POLL) + + // Initialize epoll: + this->poll_fd_ = ::epoll_create (size); + if (this->poll_fd_ == -1) + result = -1; + +#else + + // Allocate the array before opening the device to avoid a potential + // resource leak if allocation fails. + ACE_NEW_RETURN (this->dp_fds_, + pollfd[size], + -1); + + // Open the `/dev/poll' character device. + this->poll_fd_ = ACE_OS::open ("/dev/poll", O_RDWR); + if (this->poll_fd_ == ACE_INVALID_HANDLE) + result = -1; + +#endif /* ACE_HAS_EVENT_POLL */ + + if (result != -1 && this->handler_rep_.open (size) == -1) + result = -1; + + // Registration of the notification handler must be done after the + // /dev/poll device has been fully initialized. + else if (this->notify_handler_->open (this, + 0, + disable_notify_pipe) == -1 + || (disable_notify_pipe == 0 + && this->register_handler_i ( + this->notify_handler_->notify_handle (), + this->notify_handler_, + ACE_Event_Handler::READ_MASK) == -1)) + result = -1; + + if (result != -1) + // We're all set to go. + this->initialized_ = true; + else + // This will close down all the allocated resources properly. + (void) this->close (); + + return result; +} + +int +ACE_Dev_Poll_Reactor::current_info (ACE_HANDLE, size_t & /* size */) +{ + ACE_NOTSUP_RETURN (-1); +} + + +int +ACE_Dev_Poll_Reactor::set_sig_handler (ACE_Sig_Handler *signal_handler) +{ + if (this->delete_signal_handler_) + delete this->signal_handler_; + + this->signal_handler_ = signal_handler; + this->delete_signal_handler_ = false; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::timer_queue (ACE_Timer_Queue *tq) +{ + if (this->delete_timer_queue_) + delete this->timer_queue_; + else if (this->timer_queue_) + this->timer_queue_->close (); + + this->timer_queue_ = tq; + this->delete_timer_queue_ = false; + + return 0; +} + +ACE_Timer_Queue * +ACE_Dev_Poll_Reactor::timer_queue (void) const +{ + return this->timer_queue_; +} + +int +ACE_Dev_Poll_Reactor::close (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::close"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, -1)); + + int result = 0; + + if (this->poll_fd_ != ACE_INVALID_HANDLE) + { + result = ACE_OS::close (this->poll_fd_); + } + +#if defined (ACE_HAS_EVENT_POLL) + + ACE_OS::memset (&this->event_, 0, sizeof (this->event_)); + this->event_.data.fd = ACE_INVALID_HANDLE; + +#else + + delete [] this->dp_fds_; + this->dp_fds_ = 0; + this->start_pfds_ = 0; + this->end_pfds_ = 0; + +#endif /* ACE_HAS_EVENT_POLL */ + + if (this->delete_signal_handler_) + { + delete this->signal_handler_; + this->signal_handler_ = 0; + this->delete_signal_handler_ = false; + } + + (void) this->handler_rep_.close (); + + if (this->delete_timer_queue_) + { + delete this->timer_queue_; + this->timer_queue_ = 0; + this->delete_timer_queue_ = false; + } + else if (this->timer_queue_) + { + this->timer_queue_->close (); + this->timer_queue_ = 0; + } + + if (this->notify_handler_ != 0) + this->notify_handler_->close (); + + if (this->delete_notify_handler_) + { + delete this->notify_handler_; + this->notify_handler_ = 0; + this->delete_notify_handler_ = false; + } + + this->poll_fd_ = ACE_INVALID_HANDLE; + + this->initialized_ = false; + + return result; +} + +int +ACE_Dev_Poll_Reactor::work_pending (const ACE_Time_Value & max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::work_pending"); + + // Stash the current time + // + // The destructor of this object will automatically compute how much + // time elapsed since this method was called. + ACE_Time_Value mwt (max_wait_time); + ACE_MT (ACE_Countdown_Time countdown (&mwt)); + + Token_Guard guard (this->token_); + int const result = guard.acquire_quietly (&mwt); + + // If the guard is NOT the owner just return the retval + if (!guard.is_owner ()) + return result; + + // Update the countdown to reflect time waiting for the mutex. + ACE_MT (countdown.update ()); + + return this->work_pending_i (&mwt); +} + +int +ACE_Dev_Poll_Reactor::work_pending_i (ACE_Time_Value * max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::work_pending_i"); + + if (this->deactivated_) + return 0; + +#if defined (ACE_HAS_EVENT_POLL) + if (this->event_.data.fd != ACE_INVALID_HANDLE) +#else + if (this->start_pfds_ != this->end_pfds_) +#endif /* ACE_HAS_EVENT_POLL */ + return 1; // We still have work_pending (). Do not poll for + // additional events. + + ACE_Time_Value timer_buf (0); + ACE_Time_Value *this_timeout = + this->timer_queue_->calculate_timeout (max_wait_time, &timer_buf); + + // Check if we have timers to fire. + int const timers_pending = + ((this_timeout != 0 && max_wait_time == 0) + || (this_timeout != 0 && max_wait_time != 0 + && *this_timeout != *max_wait_time) ? 1 : 0); + + long const timeout = + (this_timeout == 0 + ? -1 /* Infinity */ + : static_cast (this_timeout->msec ())); + +#if defined (ACE_HAS_EVENT_POLL) + + // Wait for an event. + int const nfds = ::epoll_wait (this->poll_fd_, + &this->event_, + 1, + static_cast (timeout)); + +#else + + struct dvpoll dvp; + + dvp.dp_fds = this->dp_fds_; + dvp.dp_nfds = this->handler_rep_.size (); + dvp.dp_timeout = timeout; // Milliseconds + + // Poll for events + int const nfds = ACE_OS::ioctl (this->poll_fd_, DP_POLL, &dvp); + + // Retrieve the results from the pollfd array. + this->start_pfds_ = dvp.dp_fds; + + // If nfds == 0 then end_pfds_ == start_pfds_ meaning that there is + // no work pending. If nfds > 0 then there is work pending. + // Otherwise an error occurred. + if (nfds > -1) + this->end_pfds_ = this->start_pfds_ + nfds; +#endif /* ACE_HAS_EVENT_POLL */ + + // If timers are pending, override any timeout from the poll. + return (nfds == 0 && timers_pending != 0 ? 1 : nfds); +} + + +int +ACE_Dev_Poll_Reactor::handle_events (ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events"); + + // Stash the current time + // + // The destructor of this object will automatically compute how much + // time elapsed since this method was called. + ACE_Countdown_Time countdown (max_wait_time); + + Token_Guard guard (this->token_); + int const result = guard.acquire_quietly (max_wait_time); + + // If the guard is NOT the owner just return the retval + if (!guard.is_owner ()) + return result; + + if (this->deactivated_) + { + errno = ESHUTDOWN; + return -1; + } + + // Update the countdown to reflect time waiting for the mutex. + ACE_MT (countdown.update ()); + + return this->handle_events_i (max_wait_time, guard); +} + +int +ACE_Dev_Poll_Reactor::handle_events_i (ACE_Time_Value *max_wait_time, + Token_Guard &guard) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events_i"); + + int result = 0; + + // Poll for events + // + // If the underlying event wait call was interrupted via the interrupt + // signal (i.e. returned -1 with errno == EINTR) then the loop will + // be restarted if so desired. + do + { + result = this->work_pending_i (max_wait_time); + if (result == -1 && (this->restart_ == 0 || errno != EINTR)) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT("%t: %p\n"), ACE_TEXT("work_pending_i"))); + } + while (result == -1 && this->restart_ != 0 && errno == EINTR); + + if (result == 0 || (result == -1 && errno == ETIME)) + return 0; + else if (result == -1) + { + if (errno != EINTR) + return -1; + + // Bail out -- we got here since the poll was interrupted. + // If it was due to a signal registered through our ACE_Sig_Handler, + // then it was dispatched, so we count it in the number of events + // handled rather than cause an error return. + if (ACE_Sig_Handler::sig_pending () != 0) + { + ACE_Sig_Handler::sig_pending (0); + return 1; + } + return -1; + } + + // Dispatch an event. + return this->dispatch (guard); +} + +// Dispatch an event. On entry, the token is held by the caller. If an +// event is found to dispatch, the token is released before dispatching it. +int +ACE_Dev_Poll_Reactor::dispatch (Token_Guard &guard) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::dispatch"); + + // Perform the Template Method for dispatching the first located event. + // We dispatch only one to effectively dispatch events concurrently. + // As soon as an event is located, the token is released, allowing the + // next waiter to begin getting an event while we dispatch one here. + int result = 0; + + // Handle timers early since they may have higher latency + // constraints than I/O handlers. Ideally, the order of + // dispatching should be a strategy... + if ((result = this->dispatch_timer_handler (guard)) != 0) + return result; + + // If no timer dispatched, check for an I/O event. + result = this->dispatch_io_event (guard); + + return result; +} + +int +ACE_Dev_Poll_Reactor::dispatch_timer_handler (Token_Guard &guard) +{ + typedef ACE_Member_Function_Command Guard_Release; + + Guard_Release release(guard, &Token_Guard::release_token); + return this->timer_queue_->expire_single(release); +} + +#if 0 +int +ACE_Dev_Poll_Reactor::dispatch_notification_handlers ( + ACE_Select_Reactor_Handle_Set &dispatch_set, + int &number_of_active_handles, + int &number_of_handlers_dispatched) +{ + // Check to see if the ACE_HANDLE associated with the + // Dev_Poll_Reactor's notify hook is enabled. If so, it means that + // one or more other threads are trying to update the + // ACE_Dev_Poll_Reactor's internal tables or the notify pipe is + // enabled. We'll handle all these threads and notifications, and + // then break out to continue the event loop. + + const int n = + this->notify_handler_->dispatch_notifications (number_of_active_handles, + dispatch_set.rd_mask_); + + if (n == -1) + return -1; + else + number_of_handlers_dispatched += n; + + return /* this->state_changed_ ? -1 : */ 0; +} +#endif /* 0 */ + +int +ACE_Dev_Poll_Reactor::dispatch_io_event (Token_Guard &guard) +{ + + // Dispatch a ready event. + + // Define bits to check for while dispatching. +#if defined (ACE_HAS_EVENT_POLL) + const __uint32_t out_event = EPOLLOUT; + const __uint32_t exc_event = EPOLLPRI; + const __uint32_t in_event = EPOLLIN; + const __uint32_t err_event = EPOLLHUP | EPOLLERR; +#else + const short out_event = POLLOUT; + const short exc_event = POLLPRI; + const short in_event = POLLIN; + const short err_event = 0; // No known bits for this +#endif /* ACE_HAS_EVENT_POLL */ + +#if defined (ACE_HAS_EVENT_POLL) + // epoll_wait() pulls one event which is stored in event_. If the handle + // is invalid, there's no event there. Else process it. In any event, we + // have the event, so clear event_ for the next thread. + const ACE_HANDLE handle = this->event_.data.fd; + __uint32_t revents = this->event_.events; + this->event_.data.fd = ACE_INVALID_HANDLE; + this->event_.events = 0; + if (handle != ACE_INVALID_HANDLE) + +#else + // Since the underlying event demultiplexing mechansim (`/dev/poll' + // or '/dev/epoll') is stateful, and since only one result buffer is + // used, all pending events (i.e. those retrieved from a previous + // poll) must be dispatched before any additional event can be + // polled. As such, the Dev_Poll_Reactor keeps track of the + // progress of events that have been dispatched. + + // Select the first available handle with event (s) pending. Check for + // event type in defined order of dispatch: output, exception, input. + // When an event is located, clear its bit in the dispatch set. If there + // are no more events for the handle, also increment the pfds pointer + // to move to the next handle ready. + // + // Notice that pfds only contains file descriptors that have + // received events. + struct pollfd *& pfds = this->start_pfds_; + const ACE_HANDLE handle = pfds->fd; + short &revents = pfds->revents; + if (pfds < this->end_pfds_) +#endif /* ACE_HAS_EVENT_POLL */ + + { + /* When using sys_epoll, we can attach arbitrary user + data to the descriptor, so it can be delivered when + activity is detected. Perhaps we should store event + handler together with descriptor, instead of looking + it up in a repository ? Could it boost performance ? + */ + + // Going to access handler repo, so lock it. If the lock is + // unobtainable, something is very wrong so bail out. + Event_Tuple *info = 0; + ACE_Reactor_Mask disp_mask = 0; + ACE_Event_Handler *eh = 0; + int (ACE_Event_Handler::*callback)(ACE_HANDLE) = 0; + bool reactor_resumes_eh = false; + { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1); + info = this->handler_rep_.find (handle); + if (info == 0) // No registered handler any longer + return 0; + + // It is possible another thread has changed (and possibly re-armed) + // this handle mask before current thread obtained the repo lock. + // If that did happen and this handler is still suspended, don't + // dispatch on top of another callback. See Bugzilla 4129. + if (info->suspended) + return 0; + + // Figure out what to do first in order to make it easier to manage + // the bit twiddling and possible pfds increment before releasing + // the token for dispatch. + // Note that if there's an error (such as the handle was closed + // without being removed from the event set) the EPOLLHUP and/or + // EPOLLERR bits will be set in revents. + eh = info->event_handler; + if (ACE_BIT_ENABLED (revents, out_event)) + { + disp_mask = ACE_Event_Handler::WRITE_MASK; + callback = &ACE_Event_Handler::handle_output; + ACE_CLR_BITS (revents, out_event); + } + else if (ACE_BIT_ENABLED (revents, exc_event)) + { + disp_mask = ACE_Event_Handler::EXCEPT_MASK; + callback = &ACE_Event_Handler::handle_exception; + ACE_CLR_BITS (revents, exc_event); + } + else if (ACE_BIT_ENABLED (revents, in_event)) + { + disp_mask = ACE_Event_Handler::READ_MASK; + callback = &ACE_Event_Handler::handle_input; + ACE_CLR_BITS (revents, in_event); + } + else if (ACE_BIT_ENABLED (revents, err_event)) + { + this->remove_handler_i (handle, + ACE_Event_Handler::ALL_EVENTS_MASK, + grd, + info->event_handler); +#ifdef ACE_HAS_DEV_POLL + ++pfds; +#endif /* ACE_HAS_DEV_POLL */ + return 1; + } + else + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%t) dispatch_io h %d unknown events 0x%x\n"), + handle, revents)); + } + +#ifdef ACE_HAS_DEV_POLL + // Increment the pointer to the next element before we + // release the token. Otherwise event handlers end up being + // dispatched multiple times for the same poll. + if (revents == 0) + ++pfds; +#else + // With epoll, events are registered with oneshot, so the handle is + // effectively suspended; future calls to epoll_wait() will select + // the next event, so they're not managed here. + // The hitch to this is that the notify handler is always registered + // WITHOUT oneshot and is never suspended/resumed. This avoids endless + // notify loops caused by the notify handler requiring a resumption + // which requires the token, which requires a notify, etc. described + // in Bugzilla 3714. So, never suspend the notify handler. + if (eh != this->notify_handler_) + { + info->suspended = true; + + reactor_resumes_eh = + eh->resume_handler () == + ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER; + } +#endif /* ACE_HAS_DEV_POLL */ + + } // End scope for ACE_GUARD holding repo lock + + int status = 0; // gets callback status, below. + + // Dispatch notifies directly. The notify dispatcher locates a + // notification then releases the token prior to dispatching it. + // NOTE: If notify_handler_->dispatch_one() returns a fail condition + // it has not releases the guard. Else, it has. + if (eh == this->notify_handler_) + { + ACE_Notification_Buffer b; + status = + dynamic_cast(notify_handler_)->dequeue_one (b); + if (status == -1) + return status; + guard.release_token (); + return notify_handler_->dispatch_notify (b); + } + + { + // Modify the reference count in an exception-safe way. + // Note that eh could be the notify handler. It's not strictly + // necessary to manage its refcount, but since we don't enable + // the counting policy, it won't do much. Management of the + // notified handlers themselves is done in the notify handler. + ACE_Dev_Poll_Handler_Guard eh_guard (eh); + + // Release the reactor token before upcall. + guard.release_token (); + + // Dispatch the detected event; will do the repeated upcalls + // if callback returns > 0, unless it's the notify handler (which + // returns the number of notfies dispatched, not an indication of + // re-callback requested). If anything other than the notify, come + // back with either 0 or < 0. + status = this->upcall (eh, callback, handle); + + // If the callback returned 0, epoll-based needs to resume the + // suspended handler but dev/poll doesn't. + // In both epoll and dev/poll cases, if the callback returns <0, + // the token needs to be acquired and the handler checked and + // removed if it hasn't already been. + if (status == 0) + { +#ifdef ACE_HAS_EVENT_POLL + // epoll-based effectively suspends handlers around the upcall. + // If the handler must be resumed, check to be sure it's the + // same handle/handler combination still. + if (reactor_resumes_eh) + { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1); + info = this->handler_rep_.find (handle); + if (info != 0 && info->event_handler == eh) + this->resume_handler_i (handle); + } +#endif /* ACE_HAS_EVENT_POLL */ + return 1; + } + + // All state in the handler repository may have changed during the + // upcall. Thus, reacquire the repo lock and evaluate what's needed. + // If the upcalled handler is still the handler of record for handle, + // continue with checking whether or not to remove or resume the + // handler. + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, 1); + info = this->handler_rep_.find (handle); + if (info != 0 && info->event_handler == eh) + { + if (status < 0) + { + this->remove_handler_i (handle, disp_mask, grd); +#ifdef ACE_HAS_EVENT_POLL + // epoll-based effectively suspends handlers around the upcall. + // If the handler must be resumed, check to be sure it's the + // same handle/handler combination still. + if (reactor_resumes_eh) + { + info = this->handler_rep_.find (handle); + if (info != 0 && info->event_handler == eh) + { + this->resume_handler_i (handle); + } + } +#endif /* ACE_HAS_EVENT_POLL */ + } + } + } + // Scope close handles eh ref count decrement, if needed. + + return 1; + } + + return 0; +} + +int +ACE_Dev_Poll_Reactor::alertable_handle_events (ACE_Time_Value *max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::alertable_handle_events"); + + return this->handle_events (max_wait_time); +} + +int +ACE_Dev_Poll_Reactor::handle_events (ACE_Time_Value &max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handle_events"); + + return this->handle_events (&max_wait_time); +} + +int +ACE_Dev_Poll_Reactor::alertable_handle_events (ACE_Time_Value &max_wait_time) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::alertable_handle_events"); + + return this->handle_events (max_wait_time); +} + +int +ACE_Dev_Poll_Reactor::deactivated (void) +{ + return this->deactivated_; +} + +void +ACE_Dev_Poll_Reactor::deactivate (int do_stop) +{ + this->deactivated_ = do_stop; + this->wakeup_all_threads (); +} + +int +ACE_Dev_Poll_Reactor::register_handler (ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->register_handler_i (handler->get_handle (), + handler, + mask); +} + +int +ACE_Dev_Poll_Reactor::register_handler (ACE_HANDLE handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->register_handler_i (handle, + event_handler, + mask); +} + +int +ACE_Dev_Poll_Reactor::register_handler_i (ACE_HANDLE handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler_i"); + + if (handle == ACE_INVALID_HANDLE + || mask == ACE_Event_Handler::NULL_MASK) + { + errno = EINVAL; + return -1; + } + + if (this->handler_rep_.find (handle) == 0) + { + // Handler not present in the repository. Bind it. + if (this->handler_rep_.bind (handle, event_handler, mask) != 0) + return -1; + +#if defined (ACE_HAS_EVENT_POLL) + + Event_Tuple *info = this->handler_rep_.find (handle); + + struct epoll_event epev; + ACE_OS::memset (&epev, 0, sizeof (epev)); + static const int op = EPOLL_CTL_ADD; + + epev.data.fd = handle; + epev.events = this->reactor_mask_to_poll_event (mask); + // All but the notify handler get registered with oneshot to facilitate + // auto suspend before the upcall. See dispatch_io_event for more + // information. + if (event_handler != this->notify_handler_) + epev.events |= EPOLLONESHOT; + + if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1) + { + ACELIB_ERROR ((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("epoll_ctl"))); + (void) this->handler_rep_.unbind (handle); + return -1; + } + info->controlled = true; + +#endif /* ACE_HAS_EVENT_POLL */ + } + else + { + // Handler is already present in the repository, so register it + // again, possibly for different event. Add new mask to the + // current one. + if (this->mask_ops_i (handle, mask, ACE_Reactor::ADD_MASK) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, ACE_TEXT("%p\n"), ACE_TEXT("mask_ops_i")), + -1); + } + +#ifdef ACE_HAS_DEV_POLL + + struct pollfd pfd; + + pfd.fd = handle; + pfd.events = this->reactor_mask_to_poll_event (mask); + pfd.revents = 0; + + // Add file descriptor to the "interest set." + if (ACE_OS::write (this->poll_fd_, &pfd, sizeof (pfd)) != sizeof (pfd)) + { + (void) this->handler_rep_.unbind (handle); + return -1; + } +#endif /*ACE_HAS_DEV_POLL*/ + + // Note the fact that we've changed the state of the wait_set_, + // which is used by the dispatching loop to determine whether it can + // keep going or if it needs to reconsult select (). + // this->state_changed_ = 1; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::register_handler ( + ACE_HANDLE /* event_handle */, + ACE_HANDLE /* io_handle */, + ACE_Event_Handler * /* event_handler */, + ACE_Reactor_Mask /* mask */) +{ + ACE_NOTSUP_RETURN (-1); +} + +int +ACE_Dev_Poll_Reactor::register_handler (const ACE_Handle_Set &handle_set, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler"); + + ACE_Handle_Set_Iterator handle_iter (handle_set); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + // @@ It might be more efficient to construct a pollfd array and + // pass it to the write () call in register_handler_i () only once, + // instead of calling write () (a system call) once for each file + // descriptor. + + for (ACE_HANDLE h = handle_iter (); + h != ACE_INVALID_HANDLE; + h = handle_iter ()) + if (this->register_handler_i (h, event_handler, mask) == -1) + return -1; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler"); + + return this->signal_handler_->register_handler (signum, + new_sh, + new_disp, + old_sh, + old_disp); +} + +int +ACE_Dev_Poll_Reactor::register_handler (const ACE_Sig_Set &sigset, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::register_handler"); + + int result = 0; + +#if (ACE_NSIG > 0) + + for (int s = 1; s < ACE_NSIG; ++s) + if ((sigset.is_member (s) == 1) + && this->signal_handler_->register_handler (s, + new_sh, + new_disp) == -1) + result = -1; + +#else /* ACE_NSIG <= 0 */ + + ACE_UNUSED_ARG (sigset); + ACE_UNUSED_ARG (new_sh); + ACE_UNUSED_ARG (new_disp); + +#endif /* ACE_NSIG <= 0 */ + + return result; +} + +int +ACE_Dev_Poll_Reactor::remove_handler (ACE_Event_Handler *handler, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler"); + + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1); + return this->remove_handler_i (handler->get_handle (), mask, grd); +} + +int +ACE_Dev_Poll_Reactor::remove_handler (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler"); + + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1); + + return this->remove_handler_i (handle, mask, grd); +} + +// FUZZ: disable check_for_ACE_Guard +int +ACE_Dev_Poll_Reactor::remove_handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Guard &repo_guard, + ACE_Event_Handler *eh) +// FUZZ: enable check_for_ACE_Guard +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler_i"); + + // If registered event handler not the same as eh, don't mess with + // the mask, but do the proper callback and refcount when needed. + bool handle_reg_changed = true; + Event_Tuple *info = this->handler_rep_.find (handle); + if (info == 0 && eh == 0) // Nothing to work with + return -1; + if (info != 0 && (eh == 0 || info->event_handler == eh)) + { + if (this->mask_ops_i (handle, mask, ACE_Reactor::CLR_MASK) == -1) + return -1; + handle_reg_changed = false; + eh = info->event_handler; + } + + // Check for ref counting now - handle_close () may delete eh. + bool const requires_reference_counting = + eh->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + if (ACE_BIT_DISABLED (mask, ACE_Event_Handler::DONT_CALL)) + { + // It would be great if ACE_Reverse_Lock worked with the Guard. + repo_guard.release (); + eh->handle_close (handle, mask); + repo_guard.acquire (); + } + + // If there are no longer any outstanding events on the given handle + // then remove it from the handler repository. + if (!handle_reg_changed && info->mask == ACE_Event_Handler::NULL_MASK) + this->handler_rep_.unbind (handle, requires_reference_counting); + + return 0; +} + +int +ACE_Dev_Poll_Reactor::remove_handler (const ACE_Handle_Set &handle_set, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler"); + + ACE_Handle_Set_Iterator handle_iter (handle_set); + for (ACE_HANDLE h = handle_iter (); + h != ACE_INVALID_HANDLE; + h = handle_iter ()) + { + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1); + if (this->remove_handler_i (h, mask, grd) == -1) + return -1; + } + return 0; +} + +int +ACE_Dev_Poll_Reactor::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int sigkey) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler"); + + return this->signal_handler_->remove_handler (signum, + new_disp, + old_disp, + sigkey); +} + +int +ACE_Dev_Poll_Reactor::remove_handler (const ACE_Sig_Set &sigset) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::remove_handler"); + + int result = 0; + +#if (ACE_NSIG > 0) + + for (int s = 1; s < ACE_NSIG; ++s) + if ((sigset.is_member (s) == 1) + && this->signal_handler_->remove_handler (s) == -1) + result = -1; + +#else /* ACE_NSIG <= 0 */ + + ACE_UNUSED_ARG (sigset); + +#endif /* ACE_NSIG <= 0 */ + + return result; +} + +int +ACE_Dev_Poll_Reactor::suspend_handler (ACE_Event_Handler *event_handler) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::suspend_handler"); + + if (event_handler == 0) + { + errno = EINVAL; + return -1; + } + + ACE_HANDLE handle = event_handler->get_handle (); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->suspend_handler_i (handle); +} + +int +ACE_Dev_Poll_Reactor::suspend_handler (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::suspend_handler"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->suspend_handler_i (handle); +} + +int +ACE_Dev_Poll_Reactor::suspend_handler (const ACE_Handle_Set &handles) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::suspend_handler"); + + ACE_Handle_Set_Iterator handle_iter (handles); + ACE_HANDLE h; + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + while ((h = handle_iter ()) != ACE_INVALID_HANDLE) + if (this->suspend_handler_i (h) == -1) + return -1; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::suspend_handlers (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::suspend_handlers"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + size_t const len = this->handler_rep_.max_size (); + + for (size_t i = 0; i < len; ++i) + { + Event_Tuple *info = this->handler_rep_.find (i); + if (info != 0 && !info->suspended && this->suspend_handler_i (i) != 0) + return -1; + } + return 0; +} + +int +ACE_Dev_Poll_Reactor::suspend_handler_i (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::suspend_handler_i"); + + Event_Tuple *info = this->handler_rep_.find (handle); + if (info == 0) + return -1; + + if (info->suspended) + return 0; // Already suspended. @@ Should this be an error? + + // Remove the handle from the "interest set." + // + // Note that the associated event handler is still in the handler + // repository, but no events will be polled on the given handle thus + // no event will be dispatched to the event handler. + +#if defined (ACE_HAS_EVENT_POLL) + + struct epoll_event epev; + ACE_OS::memset (&epev, 0, sizeof (epev)); + static const int op = EPOLL_CTL_DEL; + + epev.events = 0; + epev.data.fd = handle; + + if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1) + return -1; + info->controlled = false; +#else + + struct pollfd pfd[1]; + + pfd[0].fd = handle; + pfd[0].events = POLLREMOVE; + pfd[0].revents = 0; + + if (ACE_OS::write (this->poll_fd_, pfd, sizeof (pfd)) != sizeof (pfd)) + return -1; + +#endif /* ACE_HAS_EVENT_POLL */ + + info->suspended = true; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::resume_handler (ACE_Event_Handler *event_handler) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::resume_handler"); + + if (event_handler == 0) + { + errno = EINVAL; + return -1; + } + + ACE_HANDLE handle = event_handler->get_handle (); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->resume_handler_i (handle); +} + +int +ACE_Dev_Poll_Reactor::resume_handler (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::resume_handler"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->resume_handler_i (handle); +} + +int +ACE_Dev_Poll_Reactor::resume_handler (const ACE_Handle_Set &handles) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::resume_handler"); + + ACE_Handle_Set_Iterator handle_iter (handles); + ACE_HANDLE h; + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + while ((h = handle_iter ()) != ACE_INVALID_HANDLE) + if (this->resume_handler_i (h) == -1) + return -1; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::resume_handlers (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::resume_handlers"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + size_t const len = this->handler_rep_.max_size (); + + for (size_t i = 0; i < len; ++i) + { + Event_Tuple *info = this->handler_rep_.find (i); + if (info != 0 && info->suspended && this->resume_handler_i (i) != 0) + return -1; + } + + return 0; +} + +int +ACE_Dev_Poll_Reactor::resume_handler_i (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::resume_handler_i"); + + Event_Tuple *info = this->handler_rep_.find (handle); + if (info == 0) + return -1; + + if (!info->suspended) + return 0; + + ACE_Reactor_Mask mask = info->mask; + if (mask == ACE_Event_Handler::NULL_MASK) + { + info->suspended = false; + return 0; + } + + // Place the handle back in to the "interest set." + // + // Events for the given handle will once again be polled. + +#if defined (ACE_HAS_EVENT_POLL) + + struct epoll_event epev; + ACE_OS::memset (&epev, 0, sizeof (epev)); + int op = EPOLL_CTL_ADD; + if (info->controlled) + op = EPOLL_CTL_MOD; + epev.events = this->reactor_mask_to_poll_event (mask) | EPOLLONESHOT; + epev.data.fd = handle; + + if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1) + return -1; + info->controlled = true; + +#else + + struct pollfd pfd[1]; + + pfd[0].fd = handle; + pfd[0].events = this->reactor_mask_to_poll_event (mask); + pfd[0].revents = 0; + + if (ACE_OS::write (this->poll_fd_, pfd, sizeof (pfd)) != sizeof (pfd)) + return -1; + +#endif /* ACE_HAS_EVENT_POLL */ + + info->suspended = false; + + return 0; +} + +int +ACE_Dev_Poll_Reactor::resumable_handler (void) +{ + // @@ Is this correct? + + return 1; +} + +bool +ACE_Dev_Poll_Reactor::uses_event_associations (void) +{ + // Since the Dev_Poll_Reactor does not do any event associations, + // this method always return false. + return false; +} + +long +ACE_Dev_Poll_Reactor::schedule_timer (ACE_Event_Handler *event_handler, + const void *arg, + const ACE_Time_Value &delay, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::schedule_timer"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, -1)); + + if (0 != this->timer_queue_) + return this->timer_queue_->schedule + (event_handler, + arg, + this->timer_queue_->gettimeofday () + delay, + interval); + + errno = ESHUTDOWN; + return -1; +} + +int +ACE_Dev_Poll_Reactor::reset_timer_interval (long timer_id, + const ACE_Time_Value &interval) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::reset_timer_interval"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, -1)); + + if (0 != this->timer_queue_) + return this->timer_queue_->reset_interval (timer_id, interval); + + errno = ESHUTDOWN; + return -1; +} + +int +ACE_Dev_Poll_Reactor::cancel_timer (ACE_Event_Handler *handler, + int dont_call_handle_close) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::cancel_timer"); + + // Don't bother waking the poll - the worse that will happen is it will + // wake up for a timer that doesn't exist then go back to waiting. + if ((this->timer_queue_ != 0) && (handler != 0)) + return this->timer_queue_->cancel (handler, dont_call_handle_close); + else + return 0; +} + +int +ACE_Dev_Poll_Reactor::cancel_timer (long timer_id, + const void **arg, + int dont_call_handle_close) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::cancel_timer"); + + // Don't bother waking the poll - the worse that will happen is it will + // wake up for a timer that doesn't exist then go back to waiting. + return (this->timer_queue_ == 0 + ? 0 + : this->timer_queue_->cancel (timer_id, + arg, + dont_call_handle_close)); +} + +int +ACE_Dev_Poll_Reactor::schedule_wakeup (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::schedule_wakeup"); + + return this->mask_ops (eh->get_handle (), mask, ACE_Reactor::ADD_MASK); +} + +int +ACE_Dev_Poll_Reactor::schedule_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::schedule_wakeup"); + + return this->mask_ops (handle, mask, ACE_Reactor::ADD_MASK); +} + +int +ACE_Dev_Poll_Reactor::cancel_wakeup (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::cancel_wakeup"); + + return this->mask_ops (eh->get_handle (), mask, ACE_Reactor::CLR_MASK); +} + +int +ACE_Dev_Poll_Reactor::cancel_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::cancel_wakeup"); + + return this->mask_ops (handle, mask, ACE_Reactor::CLR_MASK); +} + +int +ACE_Dev_Poll_Reactor::notify (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask, + ACE_Time_Value *timeout) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::notify"); + + ssize_t n = 0; + + // Pass over both the Event_Handler *and* the mask to allow the + // caller to dictate which Event_Handler method the receiver + // invokes. Note that this call can timeout. + + n = this->notify_handler_->notify (eh, mask, timeout); + + return n == -1 ? -1 : 0; +} + +void +ACE_Dev_Poll_Reactor::max_notify_iterations (int iterations) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::max_notify_iterations"); + + ACE_MT (ACE_GUARD (ACE_Dev_Poll_Reactor_Token, mon, this->token_)); + + this->notify_handler_->max_notify_iterations (iterations); +} + +int +ACE_Dev_Poll_Reactor::max_notify_iterations (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::max_notify_iterations"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, -1)); + + return this->notify_handler_->max_notify_iterations (); +} + +int +ACE_Dev_Poll_Reactor::purge_pending_notifications (ACE_Event_Handler * eh, + ACE_Reactor_Mask mask) +{ + if (this->notify_handler_ == 0) + return 0; + + return this->notify_handler_->purge_pending_notifications (eh, mask); +} + +ACE_Event_Handler * +ACE_Dev_Poll_Reactor::find_handler (ACE_HANDLE handle) +{ + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, 0)); + + Event_Tuple *info = this->handler_rep_.find (handle); + if (info) + { + info->event_handler->add_reference (); + return info->event_handler; + } + else + { + return 0; + } +} + +int +ACE_Dev_Poll_Reactor::handler (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Event_Handler **event_handler) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handler"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + Event_Tuple *info = this->handler_rep_.find (handle); + + if (info != 0 + && ACE_BIT_CMP_MASK (info->mask, + mask, // Compare all bits in the mask + mask)) + { + if (event_handler != 0) + *event_handler = info->event_handler; + + return 0; + } + + return -1; +} + +int +ACE_Dev_Poll_Reactor::handler (int signum, + ACE_Event_Handler **eh) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::handler"); + + ACE_Event_Handler *handler = this->signal_handler_->handler (signum); + + if (handler == 0) + return -1; + else if (eh != 0) + *eh = handler; + + return 0; +} + +bool +ACE_Dev_Poll_Reactor::initialized (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::initialized"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, false)); + + return this->initialized_; +} + +size_t +ACE_Dev_Poll_Reactor::size (void) const +{ + return this->handler_rep_.size (); +} + +ACE_Lock & +ACE_Dev_Poll_Reactor::lock (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::lock"); + + return this->lock_adapter_; +} + +void +ACE_Dev_Poll_Reactor::wakeup_all_threads (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::wakeup_all_threads"); + + // Send a notification, but don't block if there's no one to receive + // it. + this->notify (0, + ACE_Event_Handler::NULL_MASK, + (ACE_Time_Value *) &ACE_Time_Value::zero); +} + +int +ACE_Dev_Poll_Reactor::owner (ACE_thread_t /* new_owner */, + ACE_thread_t * /* old_owner */) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::owner"); + + // There is no need to set the owner of the event loop. Multiple + // threads may invoke the event loop simulataneously. + + return 0; +} + +int +ACE_Dev_Poll_Reactor::owner (ACE_thread_t * /* owner */) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::owner"); + + // There is no need to set the owner of the event loop. Multiple + // threads may invoke the event loop simulataneously. + + return 0; +} + +bool +ACE_Dev_Poll_Reactor::restart (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::restart"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, false)); + + return this->restart_; +} + +bool +ACE_Dev_Poll_Reactor::restart (bool r) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::restart"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Dev_Poll_Reactor_Token, mon, this->token_, false)); + + bool current_value = this->restart_; + this->restart_ = r; + return current_value; +} + +void +ACE_Dev_Poll_Reactor::requeue_position (int) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::requeue_position"); +} + +int +ACE_Dev_Poll_Reactor::requeue_position (void) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::requeue_position"); + + ACE_NOTSUP_RETURN (-1); +} + +int +ACE_Dev_Poll_Reactor::mask_ops (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask, + int ops) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::mask_ops"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->mask_ops_i (event_handler->get_handle (), mask, ops); +} + +int +ACE_Dev_Poll_Reactor::mask_ops (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + int ops) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::mask_ops"); + + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, grd, this->repo_lock_, -1)); + + return this->mask_ops_i (handle, mask, ops); +} + +int +ACE_Dev_Poll_Reactor::mask_ops_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + int ops) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::mask_ops_i"); + + Event_Tuple *info = this->handler_rep_.find (handle); + if (info == 0) + return -1; + + // Block out all signals until method returns. + ACE_Sig_Guard sb; + + ACE_Reactor_Mask const old_mask = info->mask; + ACE_Reactor_Mask new_mask = old_mask; + + // Perform GET, CLR, SET, and ADD operations on the interest/wait + // set and the suspend set (if necessary). + // + // GET = 1, Retrieve current value + // SET = 2, Set value of bits to new mask (changes the entire mask) + // ADD = 3, Bitwise "or" the value into the mask (only changes + // enabled bits) + // CLR = 4 Bitwise "and" the negation of the value out of the mask + // (only changes enabled bits) + // + // Returns the original mask. + + switch (ops) + { + case ACE_Reactor::GET_MASK: + // The work for this operation is done in all cases at the + // beginning of the function. + return old_mask; + + case ACE_Reactor::CLR_MASK: + ACE_CLR_BITS (new_mask, mask); + break; + + case ACE_Reactor::SET_MASK: + new_mask = mask; + break; + + case ACE_Reactor::ADD_MASK: + ACE_SET_BITS (new_mask, mask); + break; + + default: + return -1; + } + + /// Reset the mask for the given handle. + info->mask = new_mask; + + // Only attempt to alter events for the handle from the + // "interest set" if it hasn't been suspended. If it has been + // suspended, the revised mask will take affect when the + // handle is resumed. The exception is if all the mask bits are + // cleared, we can un-control the fd now. + if (!info->suspended || (info->controlled && new_mask == 0)) + { + + short const events = this->reactor_mask_to_poll_event (new_mask); + +#if defined (sun) + // Apparently events cannot be updated on-the-fly on Solaris so + // remove the existing events, and then add the new ones. + struct pollfd pfd[2]; + + pfd[0].fd = handle; + pfd[0].events = POLLREMOVE; + pfd[0].revents = 0; + pfd[1].fd = (events == POLLREMOVE ? ACE_INVALID_HANDLE : handle); + pfd[1].events = events; + pfd[1].revents = 0; + + // Change the events associated with the given file descriptor. + if (ACE_OS::write (this->poll_fd_, + pfd, + sizeof (pfd)) != sizeof (pfd)) + return -1; +#elif defined (ACE_HAS_EVENT_POLL) + + struct epoll_event epev; + ACE_OS::memset (&epev, 0, sizeof (epev)); + int op; + + // ACE_Event_Handler::NULL_MASK ??? + if (new_mask == 0) + { + op = EPOLL_CTL_DEL; + epev.events = 0; + } + else + { + op = EPOLL_CTL_MOD; + epev.events = events | EPOLLONESHOT; + } + + epev.data.fd = handle; + + if (::epoll_ctl (this->poll_fd_, op, handle, &epev) == -1) + { + // If a handle is closed, epoll removes it from the poll set + // automatically - we may not know about it yet. If that's the + // case, a mod operation will fail with ENOENT. Retry it as + // an add. If it's any other failure, just fail outright. + if (op != EPOLL_CTL_MOD || errno != ENOENT || + ::epoll_ctl (this->poll_fd_, EPOLL_CTL_ADD, handle, &epev) == -1) + return -1; + } + info->controlled = (op != EPOLL_CTL_DEL); +#else + pollfd pfd[1]; + + pfd[0].fd = handle; + pfd[0].events = events; + pfd[0].revents = 0; + + // Change the events associated with the given file descriptor. + if (ACE_OS::write (this->poll_fd_, + pfd, + sizeof (pfd)) != sizeof (pfd)) + return -1; +#endif /*ACE_HAS_EVENT_POLL */ + } + + return old_mask; +} + +int +ACE_Dev_Poll_Reactor::ready_ops (ACE_Event_Handler * /* event_handler */, + ACE_Reactor_Mask /* mask */, + int /* ops */) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::ready_ops"); + + // Since the Dev_Poll_Reactor uses the poll result buffer, the + // ready_set cannot be directly manipulated outside of the event + // loop. + ACE_NOTSUP_RETURN (-1); +} + +int +ACE_Dev_Poll_Reactor::ready_ops (ACE_HANDLE /* handle */, + ACE_Reactor_Mask /* mask */, + int /* ops */) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::ready_ops"); + + // Since the Dev_Poll_Reactor uses the poll result buffer, the + // ready_set cannot be directly manipulated outside of the event + // loop. + ACE_NOTSUP_RETURN (-1); +} + +void +ACE_Dev_Poll_Reactor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Dev_Poll_Reactor::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("restart_ = %d\n"), this->restart_)); + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("initialized_ = %d"), + this->initialized_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("poll_fd_ = %d"), this->poll_fd_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("size_ = %u"), this->handler_rep_.size ())); + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("deactivated_ = %d"), + this->deactivated_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +short +ACE_Dev_Poll_Reactor::reactor_mask_to_poll_event (ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::reactor_mask_to_poll_event"); + + if (mask == ACE_Event_Handler::NULL_MASK) + // No event. Remove from interest set. +#if defined (ACE_HAS_EVENT_POLL) + return EPOLL_CTL_DEL; +#else + return POLLREMOVE; +#endif /* ACE_HAS_EVENT_POLL */ + + short events = 0; + + // READ, ACCEPT, and CONNECT flag will place the handle in the + // read set. + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::READ_MASK) + || ACE_BIT_ENABLED (mask, ACE_Event_Handler::ACCEPT_MASK) + || ACE_BIT_ENABLED (mask, ACE_Event_Handler::CONNECT_MASK)) + { +#if defined (ACE_HAS_EVENT_POLL) + ACE_SET_BITS (events, EPOLLIN); +#else + ACE_SET_BITS (events, POLLIN); +#endif /*ACE_HAS_EVENT_POLL*/ + } + + // WRITE and CONNECT flag will place the handle in the write set. + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::WRITE_MASK) + || ACE_BIT_ENABLED (mask, ACE_Event_Handler::CONNECT_MASK)) + { +#if defined (ACE_HAS_EVENT_POLL) + ACE_SET_BITS (events, EPOLLOUT); +#else + ACE_SET_BITS (events, POLLOUT); +#endif /*ACE_HAS_EVENT_POLL*/ + } + + // EXCEPT flag will place the handle in the except set. + if (ACE_BIT_ENABLED (mask, ACE_Event_Handler::EXCEPT_MASK)) + { +#if defined (ACE_HAS_EVENT_POLL) + ACE_SET_BITS (events, EPOLLPRI); +#else + ACE_SET_BITS (events, POLLPRI); +#endif /*ACE_HAS_EVENT_POLL*/ + } + + return events; +} + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +namespace { + void polite_sleep_hook (void *) { } +} +#endif + +int +ACE_Dev_Poll_Reactor::Token_Guard::acquire_quietly (ACE_Time_Value *max_wait) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Token_Guard::acquire_quietly"); + + // Acquire the token but don't ping any waiters; just queue up politely. + int result = 0; + if (max_wait) + { + ACE_Time_Value tv = ACE_OS::gettimeofday (); + tv += *max_wait; + + ACE_MT (result = this->token_.acquire_read (&polite_sleep_hook, + 0, + &tv)); + } + else + { + ACE_MT (result = this->token_.acquire_read (&polite_sleep_hook)); + } + + // Check for timeouts and errors. + if (result == -1) + { + if (errno == ETIME) + return 0; + else + { + ACELIB_ERROR ((LM_ERROR, ACE_TEXT("%t: %p\n"), ACE_TEXT("token acquire_read"))); + return -1; + } + } + + // We got the token and so let us mark ourselves as owner + this->owner_ = 1; + + return result; +} + +int +ACE_Dev_Poll_Reactor::Token_Guard::acquire (ACE_Time_Value *max_wait) +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Token_Guard::acquire"); + + // Try to grab the token. If someone if already there, don't wake + // them up, just queue up in the thread pool. + int result = 0; + if (max_wait) + { + ACE_Time_Value tv = ACE_OS::gettimeofday (); + tv += *max_wait; + + ACE_MT (result = this->token_.acquire (0, 0, &tv)); + } + else + { + ACE_MT (result = this->token_.acquire ()); + } + + // Check for timeouts and errors. + if (result == -1) + { + if (errno == ETIME) + return 0; + else + return -1; + } + + // We got the token and so let us mark ourseleves as owner + this->owner_ = 1; + + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_EVENT_POLL || ACE_HAS_DEV_POLL */ diff --git a/dep/acelite/ace/Dev_Poll_Reactor.h b/dep/acelite/ace/Dev_Poll_Reactor.h new file mode 100644 index 000000000..37798db97 --- /dev/null +++ b/dep/acelite/ace/Dev_Poll_Reactor.h @@ -0,0 +1,1211 @@ +// -*- C++ -*- + +// ========================================================================= +/** + * @file Dev_Poll_Reactor.h + * + * @c /dev/poll (or Linux @c sys_epoll) based Reactor implementation. + * + * @author Ossama Othman + */ +// ========================================================================= + + +#ifndef ACE_DEV_POLL_REACTOR_H +#define ACE_DEV_POLL_REACTOR_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_EVENT_POLL) && defined (ACE_HAS_DEV_POLL) +# error ACE_HAS_EVENT_POLL and ACE_HAS_DEV_POLL are mutually exclusive. +#endif /* ACE_HAS_EVENT_POLL && defined ACE_HAS_DEV_POLL */ + +#if defined (ACE_HAS_EVENT_POLL) || defined (ACE_HAS_DEV_POLL) + +#include "ace/Pipe.h" +#include "ace/Lock_Adapter_T.h" +#include "ace/Reactor_Impl.h" +#include "ace/Reactor_Token_T.h" +#include "ace/Token.h" + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) +# include "ace/Notification_Queue.h" +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ + +#if defined (ACE_HAS_DEV_POLL) +struct pollfd; +#elif defined (ACE_HAS_EVENT_POLL) +# include "ace/Array_Map.h" +# include /**/ +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations +class ACE_Sig_Handler; +class ACE_Dev_Poll_Reactor; + + +// --------------------------------------------------------------------- + +/** + * @class ACE_Dev_Poll_Reactor_Notify + * + * @brief Event handler used for unblocking the ACE_Dev_Poll_Reactor + * from its event loop. + * + * This event handler is used internally by the ACE_Dev_Poll_Reactor + * as a means to allow a thread other then the one running the event + * loop to unblock the event loop. + */ +class ACE_Dev_Poll_Reactor_Notify : public ACE_Reactor_Notify +{ +public: + + /// Constructor + ACE_Dev_Poll_Reactor_Notify (void); + + /** + * @name Initialization and Termination Methods + * + * Methods called when initializing and terminating this event + * handler. + */ + virtual int open (ACE_Reactor_Impl *, + ACE_Timer_Queue *timer_queue = 0, + int disable_notify = 0); + virtual int close (void); + + /** + * Called by a thread when it wants to unblock the Reactor_Impl. + * This wakes up the Reactor_Impl if currently blocked. Pass over + * both the Event_Handler and the mask to allow the caller to + * dictate which Event_Handler method the Reactor_Impl will + * invoke. The ACE_Time_Value indicates how long to block + * trying to notify the Reactor_Impl. If timeout == 0, the + * caller will block until action is possible, else will wait until + * the relative time specified in *timeout elapses). + */ + virtual int notify (ACE_Event_Handler *eh = 0, + ACE_Reactor_Mask mask = ACE_Event_Handler::EXCEPT_MASK, + ACE_Time_Value *timeout = 0); + + /// Unimplemented method required by pure virtual method in abstract + /// base class. + /** + * This method's interface is not very compatibile with this + * Reactor's design. It's not clear why this method is pure virtual + * either. + */ + virtual int dispatch_notifications (int &number_of_active_handles, + ACE_Handle_Set &rd_mask); + + /// Returns the ACE_HANDLE of the notify pipe on which the reactor + /// is listening for notifications so that other threads can unblock + /// the Reactor_Impl. + virtual ACE_HANDLE notify_handle (void); + + /// Verify whether the buffer has dispatchable info or not. + virtual int is_dispatchable (ACE_Notification_Buffer &buffer); + + /// Handle one notify call represented in @a buffer. This could be + /// because of a thread trying to unblock the Reactor_Impl. + virtual int dispatch_notify (ACE_Notification_Buffer &buffer); + + /// Read one notify call on the handle into @a buffer. + /// This could be because of a thread trying to unblock the Reactor_Impl. + virtual int read_notify_pipe (ACE_HANDLE handle, + ACE_Notification_Buffer &buffer); + + /// Called back by the ACE_Dev_Poll_Reactor when a thread wants to + /// unblock us. + virtual int handle_input (ACE_HANDLE handle); + + /** + * Set the maximum number of times that the handle_input method + * will iterate and dispatch the ACE_Event_Handlers that are + * passed in via the notify queue before breaking out of the event + * loop. By default, this is set to -1, which means "iterate until + * the queue is empty." Setting this to a value like "1 or 2" will + * increase "fairness" (and thus prevent starvation) at the expense + * of slightly higher dispatching overhead. + */ + virtual void max_notify_iterations (int); + + /** + * Get the maximum number of times that the handle_input method + * will iterate and dispatch the ACE_Event_Handlers that are + * passed in via the notify queue before breaking out of its event + * loop. + */ + virtual int max_notify_iterations (void); + + /** + * Purge any notifications pending in this reactor for the specified + * ACE_Event_Handler object. Returns the number of notifications + * purged. Returns -1 on error. + */ + virtual int purge_pending_notifications ( + ACE_Event_Handler * = 0, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /// Dump the state of an object. + virtual void dump (void) const; + + /// Method called by ACE_Dev_Poll_Reactor to obtain one notification. + /// THIS METHOD MUST BE CALLED WITH THE REACTOR TOKEN HELD! + /// + /// @return -1 on error, else 0 and @arg nb has the notify to + /// dispatch. Note that the contained event handler may be + /// 0 if there were only wake-ups (no handlers to dispatch). + int dequeue_one (ACE_Notification_Buffer &nb); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /** + * Keep a back pointer to the ACE_Dev_Poll_Reactor. If this value + * if NULL then the ACE_Dev_Poll_Reactor has been initialized with + * disable_notify_pipe. + */ + ACE_Dev_Poll_Reactor *dp_reactor_; + + /** + * Contains the ACE_HANDLE the ACE_Dev_Poll_Reactor is listening + * on, as well as the ACE_HANDLE that threads wanting the attention + * of the ACE_Dev_Poll_Reactor will write to. + */ + ACE_Pipe notification_pipe_; + + /** + * Keeps track of the maximum number of times that the + * ACE_Dev_Poll_Reactor_Notify::handle_input method will iterate and + * dispatch the ACE_Event_Handlers that are passed in via the + * notify pipe before breaking out of its recv loop. By default, + * this is set to -1, which means "iterate until the pipe is empty." + */ + int max_notify_iterations_; + +#if defined (ACE_HAS_REACTOR_NOTIFICATION_QUEUE) + /** + * @brief A user-space queue to store the notifications. + * + * The notification pipe has OS-specific size restrictions. That + * is, no more than a certain number of bytes may be stored in the + * pipe without blocking. This limit may be too small for certain + * applications. In this case, ACE can be configured to store all + * the events in user-space. The pipe is still needed to wake up + * the reactor thread, but only one event is sent through the pipe + * at a time. + */ + ACE_Notification_Queue notification_queue_; +#endif /* ACE_HAS_REACTOR_NOTIFICATION_QUEUE */ +}; + +// --------------------------------------------------------------------- + +/** + * @class ACE_Dev_Poll_Reactor + * + * @brief A `/dev/poll' or `/dev/epoll' based Reactor implemenatation. + * + * @attention The Linux epoll implementation works quite well and is + * fully supported; however, the /dev/poll implementation is @em experimental. + * + * The ACE_Dev_Poll_Reactor uses the `/dev/poll' or '/dev/epoll' + * character devices to demultiplex events on a given set of file + * descriptors. Unlike @c select(), `/dev/poll' and `/dev/epoll' have + * no hard-coded limit on the number of file descriptors that may be + * handled at any given time. As such, the ACE_Dev_Poll_Reactor can + * generally handle a much larger number of file descriptors than + * @c select() -based reactors. Furthermore, since `/dev/poll' and + * `/dev/epoll' both return a set of file descriptors that are active, + * there is no need to "walk" the set of file descriptors to determine + * which ones are active, such as what is done with the @c select() and + * @c poll() system calls. All returned file descriptors are active. + * This makes event dispatching very efficient. + * + * @note In general, this reactor may only be used to demultiplex + * events on sockets. Demultiplexing events on pipes, for + * example may not work. This is due to a limitation in the + * underlying `/dev/poll' device driver. + * + * @note It is only possible to achieve millisecond timeout + * resolutions with the @c ACE_Dev_Poll_Reactor. However, the + * timeout resolution for timers is independent of the reactors + * timeout resolution. As such, it may be possible to achieve + * sub-millisecond timeout resolutions for timers but that is + * entirely platform dependent. + */ + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +typedef ACE_Token ACE_DEV_POLL_TOKEN; +#else +typedef ACE_Noop_Token ACE_DEV_POLL_TOKEN; +#endif /* ACE_MT_SAFE && ACE_MT_SAFE != 0 */ +typedef ACE_Reactor_Token_T ACE_Dev_Poll_Reactor_Token; + +class ACE_Export ACE_Dev_Poll_Reactor : public ACE_Reactor_Impl +{ + + /** + * @struct Event_Tuple + * + * @brief Struct that collects event registration information for a handle. + * + * @internal Internal use only + * + * This struct merely provides a means to associate an event mask + * with an event handler. Such an association is needed since it is + * not possible to retrieve the event mask from the "interest set" + * stored in the `/dev/poll' or `/dev/epoll' driver. Without this + * external association, it would not be possible keep track of the + * event mask for a given event handler when suspending it or resuming + * it. + * + * @note An ACE_Handle_Set is not used since the number of handles may + * exceed its capacity (ACE_DEFAULT_SELECT_REACTOR_SIZE). + */ + struct Event_Tuple + { + /// Constructor to set up defaults. + Event_Tuple (ACE_Event_Handler *eh = 0, + ACE_Reactor_Mask m = ACE_Event_Handler::NULL_MASK, + bool is_suspended = false, + bool is_controlled = false); + + /// The event handler. + ACE_Event_Handler *event_handler; + + /// The event mask for the above event handler. + ACE_Reactor_Mask mask; + + /// Flag that states whether or not the event handler is suspended. + bool suspended; + + /// Flag to say whether or not this handle is registered with epoll. + bool controlled; + + ACE_ALLOC_HOOK_DECLARE; + }; + + + // --------------------------------------------------------------------- + + /** + * @class Handler_Repository + * + * @internal + * + * @brief Used to map ACE_HANDLEs onto the appropriate Event_Tuple. + * + * This class is simply a container that maps a handle to its + * corresponding event tuple. It is not meant for use outside of + * the Dev_Poll_Reactor. + * + * @note Calls to any method in this class, and any modification to a + * Event_Tuple returned from this class's methods, must be made + * while holding the repository lock. + */ + class Handler_Repository + { + public: + + /// Constructor. + Handler_Repository (void); + + /// Initialize a repository that can map handles up to the value @a size. + /// Since the event tuples are accessed directly using the handle as + /// an index, @a size sets the maximum handle value, minus 1. + int open (size_t size); + + /// Close down the repository. + int close (void); + + /** + * @name Repository Manipulation Operations + * + * Methods used to search and modify the handler repository. + */ + //@{ + + /// Return a pointer to the Event_Tuple associated with @a handle. + /// If there is none associated, returns 0 and sets errno. + Event_Tuple *find (ACE_HANDLE handle); + + + /// Bind the ACE_Event_Handler to the @c ACE_HANDLE with the + /// appropriate ACE_Reactor_Mask settings. + int bind (ACE_HANDLE handle, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask); + + /// Remove the binding for @a handle; optionally decrement the associated + /// handler's reference count. + int unbind (ACE_HANDLE handle, bool decr_refcnt = true); + + /// Remove all the registered tuples. + int unbind_all (void); + + //@} + + /** + * @name Sanity Checking + * + * Methods used to prevent "out-of-range" errors when indexing the + * underlying handler array. + */ + //@{ + + // Check the @a handle to make sure it's a valid @c ACE_HANDLE that + // within the range of legal handles (i.e., greater than or equal to + // zero and less than @c max_size_). + bool invalid_handle (ACE_HANDLE handle) const; + + // Check the handle to make sure it's a valid @c ACE_HANDLE that is + // within the range of currently registered handles (i.e., greater + // than or equal to zero and less than @c max_handlep1_). + bool handle_in_range (ACE_HANDLE handle) const; + + //@} + + /// Returns the current table size. + size_t size (void) const; + + /// Returns the current table size. + size_t max_size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + private: + + /// Current number of handles. + int size_; + + /// Maximum number of handles. + int max_size_; + + /// The underlying array of event handlers. + /** + * The array of event handlers is directly indexed directly using + * an @c ACE_HANDLE value. This is Unix-specific. + */ + Event_Tuple *handlers_; + + }; + +public: + + /// Initialize @c ACE_Dev_Poll_Reactor with the default size. + /** + * The default size for the @c ACE_Dev_Poll_Reactor is the maximum + * number of open file descriptors for the process. + */ + ACE_Dev_Poll_Reactor (ACE_Sig_Handler * = 0, + ACE_Timer_Queue * = 0, + int disable_notify_pipe = 0, + ACE_Reactor_Notify *notify = 0, + int mask_signals = 1, + int s_queue = ACE_DEV_POLL_TOKEN::FIFO); + + /// Initialize ACE_Dev_Poll_Reactor with size @a size. + /** + * @note On Unix platforms, the @a size parameter should be as large + * as the maximum number of file descriptors allowed for a + * given process. This is necessary since a file descriptor + * is used to directly index the array of event handlers + * maintained by the Reactor's handler repository. Direct + * indexing is used for efficiency reasons. If the size + * parameter is less than the process maximum, the process + * maximum will be decreased in order to prevent potential + * access violations. + */ + ACE_Dev_Poll_Reactor (size_t size, + bool restart = false, + ACE_Sig_Handler * = 0, + ACE_Timer_Queue * = 0, + int disable_notify_pipe = 0, + ACE_Reactor_Notify *notify = 0, + int mask_signals = 1, + int s_queue = ACE_DEV_POLL_TOKEN::FIFO); + + /// Close down and release all resources. + virtual ~ACE_Dev_Poll_Reactor (void); + + /// Initialization. + virtual int open (size_t size, + bool restart = false, + ACE_Sig_Handler * = 0, + ACE_Timer_Queue * = 0, + int disable_notify_pipe = 0, + ACE_Reactor_Notify * = 0); + + /** + * @param handle allows the reactor to check if the caller is + * valid. + * + * @return 0 if the size of the current message has been put in + * size. -1 if not. + */ + virtual int current_info (ACE_HANDLE handle, size_t & /* size */); + + /// Use a user specified signal handler instead. + virtual int set_sig_handler (ACE_Sig_Handler *signal_handler); + + /// Set a user-specified timer queue. + virtual int timer_queue (ACE_Timer_Queue *tq); + + /// Get the timer queue + /// @return The current @c ACE_Timer_Queue. + virtual ACE_Timer_Queue *timer_queue (void) const; + + /// Close down and release all resources. + virtual int close (void); + + // = Event loop drivers. + /** + * Returns non-zero if there are I/O events "ready" for dispatching, + * but does not actually dispatch the event handlers. By default, + * don't block while checking this, i.e., "poll". + * + * @note It is only possible to achieve millisecond timeout + * resolutions with the @c ACE_Dev_Poll_Reactor. + */ + virtual int work_pending ( + const ACE_Time_Value &max_wait_time = ACE_Time_Value::zero); + + /** + * This event loop driver blocks for up to @a max_wait_time before + * returning. It will return earlier if events occur. Note that + * @a max_wait_time can be 0, in which case this method blocks + * indefinitely until events occur. + * @par + * @a max_wait_time is decremented to reflect how much time this + * call took. For instance, if a time value of 3 seconds is passed + * to @c handle_events() and an event occurs after 2 seconds, + * @a max_wait_time will equal 1 second. This can be used if an + * application wishes to handle events for some fixed amount of + * time. + * @par + * The only difference between @c alertable_handle_events() and + * handle_events() is that in the alertable case, the event loop + * will return when the system queues an I/O completion routine or + * an Asynchronous Procedure Call. + * + * @return The total number of @c ACE_Event_Handlers that were + * dispatched, 0 if the @a max_wait_time elapsed without + * dispatching any handlers, or -1 if an error occurs. + + * @note It is only possible to achieve millisecond timeout + * resolutions with the @c ACE_Dev_Poll_Reactor. + */ + virtual int handle_events (ACE_Time_Value *max_wait_time = 0); + virtual int alertable_handle_events (ACE_Time_Value *max_wait_time = 0); + + /** + * This method is just like the one above, except the + * @a max_wait_time value is a reference and can therefore never be + * @c NULL. + * + * @note It is only possible to achieve millisecond timeout + * resolutions with the @c ACE_Dev_Poll_Reactor. + */ + virtual int handle_events (ACE_Time_Value &max_wait_time); + virtual int alertable_handle_events (ACE_Time_Value &max_wait_time); + + // = Event handling control. + + /** + * @return The status of Reactor. If this function returns 0, the + * reactor is actively handling events. If it returns + * non-zero, @c handle_events() and + * @c handle_alertable_events() return -1 immediately. + */ + virtual int deactivated (void); + + /** + * Control whether the Reactor will handle any more incoming events + * or not. If @a do_stop == 1, the Reactor will be disabled. By + * default, a reactor is in active state and can be + * deactivated/reactived as desired. + */ + virtual void deactivate (int do_stop); + + // = Register and remove Handlers. + + /// Register @a event_handler with @a mask. The I/O handle will + /// always come from get_handle on the event_handler. + virtual int register_handler (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask); + + /// Register @a event_handler with @a mask. The I/O handle is + /// provided through the @a io_handle parameter. + virtual int register_handler (ACE_HANDLE io_handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask); + + /** + * Register an @a event_handler that will be notified when + * @a event_handle is signaled. @a mask specifies the network + * events that the @a event_handler is interested in. + */ + virtual int register_handler (ACE_HANDLE event_handle, + ACE_HANDLE io_handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask); + + /// Register @a event_handler with all the @a handles in the @c + /// Handle_Set. + virtual int register_handler (const ACE_Handle_Set &handles, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask); + + /** + * Register @a new_sh to handle the signal @a signum using the + * @a new_disp. Returns the @a old_sh that was previously + * registered (if any), along with the @a old_disp of the signal + * handler. + */ + virtual int register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp = 0, + ACE_Event_Handler **old_sh = 0, + ACE_Sig_Action *old_disp = 0); + + /// Registers @a new_sh to handle a set of signals @a sigset using the + /// @a new_disp. + virtual int register_handler (const ACE_Sig_Set &sigset, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp = 0); + + /// Removes @a event_handler. + /** + * @note The I/O handle will be obtained using @c get_handle() + * method of @a event_handler . If @a mask == + * @c ACE_Event_Handler::DONT_CALL then the @c handle_close() + * method of the @a event_handler is not invoked. + */ + virtual int remove_handler (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask); + + /** + * Removes @a handle. If @a mask == ACE_Event_Handler::DONT_CALL + * then the method of the associated + * is not invoked. + */ + virtual int remove_handler (ACE_HANDLE handle, + ACE_Reactor_Mask mask); + + /** + * Removes all handles in @a handle_set. If @a mask == + * ACE_Event_Handler::DONT_CALL then the method of + * the associated s is not invoked. + */ + virtual int remove_handler (const ACE_Handle_Set &handle_set, + ACE_Reactor_Mask mask); + + /** + * Remove the ACE_Event_Handler currently associated with @a signum. + * Install the new disposition (if given) and return the previous + * disposition (if desired by the caller). Returns 0 on success and + * -1 if @a signum is invalid. + */ + virtual int remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp = 0, + int sigkey = -1); + + /// Calls for every signal in @a sigset. + virtual int remove_handler (const ACE_Sig_Set &sigset); + + // = Suspend and resume Handlers. + + /// Suspend event_handler temporarily. Use + /// ACE_Event_Handler::get_handle() to get the handle. + virtual int suspend_handler (ACE_Event_Handler *event_handler); + + /// Suspend handle temporarily. + virtual int suspend_handler (ACE_HANDLE handle); + + /// Suspend all handles in handle set temporarily. + virtual int suspend_handler (const ACE_Handle_Set &handles); + + /// Suspend all handles temporarily. + virtual int suspend_handlers (void); + + /// Resume event_handler. Use ACE_Event_Handler::get_handle() to + /// get the handle. + virtual int resume_handler (ACE_Event_Handler *event_handler); + + /// Resume handle. + virtual int resume_handler (ACE_HANDLE handle); + + /// Resume all handles in handle set. + virtual int resume_handler (const ACE_Handle_Set &handles); + + /// Resume all handles. + virtual int resume_handlers (void); + + /// Does the reactor allow the application to resume the handle on + /// its own, i.e., can it pass on the control of handle resumption to + /// the application. + virtual int resumable_handler (void); + + /// Return true if we any event associations were made by the reactor + /// for the handles that it waits on, false otherwise. + virtual bool uses_event_associations (void); + + // = Timer management. + + /** + * Schedule an ACE_Event_Handler that will expire after an amount + * of time. The return value of this method, a timer_id value, + * uniquely identifies the event_handler in the ACE_Reactor's + * internal list of timers. + * This timer_id value can be used to cancel the timer + * with the cancel_timer() call. + * + * @see cancel_timer() + * @see reset_timer_interval() + * + * @param event_handler event handler to schedule on reactor + * @param arg argument passed to the handle_timeout() method of + * event_handler. + * @param delay time interval after which the timer will expire. + * @param interval time interval for which the timer will be + * automatically rescheduled. + * @return -1 on failure, a timer_id value on success + */ + virtual long schedule_timer (ACE_Event_Handler *event_handler, + const void *arg, + const ACE_Time_Value &delay, + const ACE_Time_Value &interval = ACE_Time_Value::zero); + + /** + * Resets the interval of the timer represented by @a timer_id to + * @a interval, which is specified in relative time to the current + * . If @a interval is equal to + * ACE_Time_Value::zero, the timer will become a non-rescheduling + * timer. Returns 0 if successful, -1 if not. + */ + virtual int reset_timer_interval (long timer_id, + const ACE_Time_Value &interval); + + /// Cancel all Event_Handlers that match the address of + /// @a event_handler. Returns number of handlers cancelled. + virtual int cancel_timer (ACE_Event_Handler *event_handler, + int dont_call_handle_close = 1); + + /** + * Cancel the single event handler that matches the @a timer_id value + * (which was returned from the schedule method). If @a arg is + * non-NULL then it will be set to point to the ``magic cookie'' + * argument passed in when the event handler was registered. This + * makes it possible to free up the memory and avoid memory leaks. + * Returns 1 if cancellation succeeded and 0 if the @a timer_id + * wasn't found. + */ + virtual int cancel_timer (long timer_id, + const void **arg = 0, + int dont_call_handle_close = 1); + + // = High-level event handler scheduling operations + + /// Add @a masks_to_be_added to the @a event_handler's entry. + /// @a event_handler must already have been registered. + virtual int schedule_wakeup (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask masks_to_be_added); + + /// Add @a masks_to_be_added to the @a handle's entry. + /// associated with @a handle must already have been registered. + virtual int schedule_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask masks_to_be_added); + + /// Clear @a masks_to_be_cleared from the @a event_handler's entry. + virtual int cancel_wakeup (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask masks_to_be_cleared); + + /// Clear @a masks_to_be_cleared from the @a handle's entry. + virtual int cancel_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask masks_to_be_cleared); + + // = Notification methods. + + /** + * Notify @a event_handler of @a mask event. The ACE_Time_Value + * indicates how long to blocking trying to notify. If @a timeout == + * 0, the caller will block until action is possible, else will wait + * until the relative time specified in @a timeout elapses). + */ + virtual int notify (ACE_Event_Handler *event_handler = 0, + ACE_Reactor_Mask mask = ACE_Event_Handler::EXCEPT_MASK, + ACE_Time_Value * = 0); + + /** + * Set the maximum number of times that ACE_Reactor_Impl will + * iterate and dispatch the ACE_Event_Handlers that are passed in + * via the notify queue before breaking out of its + * ACE_Message_Queue::dequeue() loop. By default, this is set to + * -1, which means "iterate until the queue is empty." Setting this + * to a value like "1 or 2" will increase "fairness" (and thus + * prevent starvation) at the expense of slightly higher dispatching + * overhead. + */ + virtual void max_notify_iterations (int); + + /** + * Get the maximum number of times that the ACE_Reactor_Impl will + * iterate and dispatch the ACE_Event_Handlers that are passed in + * via the notify queue before breaking out of its + * ACE_Message_Queue::dequeue() loop. + */ + virtual int max_notify_iterations (void); + + /** + * Purge any notifications pending in this reactor for the specified + * ACE_Event_Handler object. Returns the number of notifications + * purged. Returns -1 on error. + */ + virtual int purge_pending_notifications (ACE_Event_Handler * = 0, + ACE_Reactor_Mask = ACE_Event_Handler::ALL_EVENTS_MASK); + + /** + * Return the Event_Handler associated with @a handle. Return 0 if + * @a handle is not registered. + */ + virtual ACE_Event_Handler *find_handler (ACE_HANDLE handle); + + /** + * Check to see if @a handle is associated with a valid Event_Handler + * bound to @a mask. Return the @a event_handler associated with this + * @c handler if @a event_handler != 0. + */ + virtual int handler (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Event_Handler **event_handler = 0); + + /** + * Check to see if @a signum is associated with a valid Event_Handler + * bound to a signal. Return the @a event_handler associated with + * this @c handler if @a event_handler != 0. + */ + virtual int handler (int signum, + ACE_Event_Handler ** = 0); + + /// Returns true if Reactor has been successfully initialized, else + /// false. + virtual bool initialized (void); + + /// Returns the current size of the Reactor's internal descriptor + /// table. + virtual size_t size (void) const; + + /// Returns a reference to the Reactor's internal repository lock. + virtual ACE_Lock &lock (void); + + /// Wake up all threads waiting in the event loop. + virtual void wakeup_all_threads (void); + + /// Transfers ownership of Reactor_Impl to the @a new_owner. + /** + * @note There is no need to set the owner of the event loop for the + * ACE_Dev_Poll_Reactor. Multiple threads may invoke the + * event loop simulataneously. As such, this method is a + * no-op. + */ + virtual int owner (ACE_thread_t new_owner, ACE_thread_t *old_owner = 0); + + /// Return the ID of the "owner" thread. + /** + * @note There is no need to set the owner of the event loop for the + * ACE_Dev_Poll_Reactor. Multiple threads may invoke the + * event loop simultaneously. As such, this method is a + * no-op. + */ + virtual int owner (ACE_thread_t *owner); + + /// Get the existing restart value. + virtual bool restart (void); + + /// Set a new value for restart and return the original value. + /** + * @param r If zero, then the event loop will not be automatically + * restarted if the underlying poll is interrupted via the + * INTR (interrupt) signal. + * + * @return Returns the previous "restart" value. + */ + virtual bool restart (bool r); + + /// Set position of the owner thread. + /** + * @note This is currently a no-op. + */ + virtual void requeue_position (int); + + /// Get position of the owner thread. + /** + * @note This is currently a no-op. + */ + virtual int requeue_position (void); + + /** + * @name Low-level wait_set mask manipulation methods + * + * Low-level methods to manipulate the event/reactor mask associated + * with a handle and event handler when polling for events. + * @par + * The "interest set," i.e. the wait set, can be directly + * manipulated with these methods. + */ + //@{ + + /// GET/SET/ADD/CLR the dispatch mask "bit" bound with the + /// event_handler and mask. + /** + * @return Old mask on success, -1 on error. + */ + virtual int mask_ops (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask, + int ops); + + /// GET/SET/ADD/CLR the dispatch MASK "bit" bound with the handle + /// and mask. + /** + * @return Old mask on success, -1 on error. + */ + virtual int mask_ops (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + int ops); + + //@} + + /** + * @name Low-level ready_set mask manipulation methods + * + * These methods are unimplemented. + */ + //@{ + + /// GET/SET/ADD/CLR the ready "bit" bound with the event_handler + /// and mask. + virtual int ready_ops (ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask, + int ops); + + /// GET/SET/ADD/CLR the ready "bit" bound with the handle and mask. + virtual int ready_ops (ACE_HANDLE handle, + ACE_Reactor_Mask, + int ops); + + //@} + + /// Dump the state of an object. + virtual void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + class Token_Guard; + + /// Non-locking version of wait_pending(). + /** + * Returns non-zero if there are I/O events "ready" for dispatching, + * but does not actually dispatch the event handlers. By default, + * don't block while checking this, i.e., "poll". + * + * @note It is only possible to achieve millisecond timeout + * resolutions with the ACE_Dev_Poll_Reactor. + */ + int work_pending_i (ACE_Time_Value *max_wait_time); + + /// Poll for events and return the number of event handlers that + /// were dispatched. + /** + * This is a helper method called by all handle_events() methods. + */ + int handle_events_i (ACE_Time_Value *max_wait_time, Token_Guard &guard); + + /// Perform the upcall with the given event handler method. + int upcall (ACE_Event_Handler *event_handler, + int (ACE_Event_Handler::*callback)(ACE_HANDLE), + ACE_HANDLE handle); + + /** + * Dispatch ACE_Event_Handlers for time events, I/O events, and + * signal events. Returns the total number of ACE_Event_Handlers + * that were dispatched or -1 if something goes wrong. + */ + int dispatch (Token_Guard &guard); + + /// Dispatch a single timer, if ready. + /// Returns: 0 if no timers ready (token still held), + /// 1 if a timer was expired (token released), + /// -1 on error (token still held). + int dispatch_timer_handler (Token_Guard &guard); + + /// Dispatch an IO event to the corresponding event handler. Returns + /// Returns: 0 if no events ready (token still held), + /// 1 if an event was expired (token released), + /// -1 on error (token still held). + int dispatch_io_event (Token_Guard &guard); + + /// Register the given event handler with the reactor. + int register_handler_i (ACE_HANDLE handle, + ACE_Event_Handler *eh, + ACE_Reactor_Mask mask); + + /// Remove the event handler associated with the given handle and + /// event mask from the "interest set." If @a eh is supplied, only do the + /// remove if @eh matches the event handler that's registered for @a handle. + /// The caller is expected to be holding the repo token on entry and have + /// @repo_guard referencing that token. It will be temporarily released + /// during a handle_close() callback if needed; if it is released for the + //// callback it will be reacquired before return. + // FUZZ: disable check_for_ACE_Guard + int remove_handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Guard &repo_guard, + ACE_Event_Handler *eh = 0); + // FUZZ: enable check_for_ACE_Guard + + /// Temporarily remove the given handle from the "interest set." + int suspend_handler_i (ACE_HANDLE handle); + + /// Place the given handle that was temporarily removed from the + /// "interest set," i.e that was suspended, back in to the interest + /// set. The given handle will once again be polled for events. + int resume_handler_i (ACE_HANDLE handle); + + /// GET/SET/ADD/CLR the dispatch MASK "bit" bound with the handle + /// and mask. This internal helper method acquires no lock. + /** + * @return Old mask on success, -1 on error. + */ + int mask_ops_i (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + int ops); + + /// Convert a reactor mask to its corresponding poll() event mask. + short reactor_mask_to_poll_event (ACE_Reactor_Mask mask); + +protected: + + /// Has the reactor been initialized. + bool initialized_; + + /// The file descriptor associated with the open `/dev/poll' or + /// `/dev/epoll' device. + /** + * All interactions with the `/dev/poll' or `/dev/epoll' device are + * done through this file descriptor. + */ + ACE_HANDLE poll_fd_; + +#if defined (ACE_HAS_EVENT_POLL) + /// Event structure to be filled by epoll_wait. epoll_wait() only gets + /// one event at a time and we rely on it's internals for fairness. + /// If this struct's fd is ACE_INVALID_HANDLE, the rest is indeterminate. + /// If the fd is good, the event is one that's been retrieved by + /// epoll_wait() but not yet processed. + struct epoll_event event_; + +#else + /// The pollfd array that `/dev/poll' will feed its results to. + struct pollfd *dp_fds_; + + + /// Pointer to the next pollfd array element that contains the next + /// event to be dispatched. + struct pollfd *start_pfds_; + + /// The last element in the pollfd array plus one. + /** + * The loop that dispatches IO events stops when this->start_pfds == + * this->end_pfds_. + */ + struct pollfd *end_pfds_; +#endif /* ACE_HAS_EVENT_POLL */ + + /// Token serializing event waiter threads. + ACE_Dev_Poll_Reactor_Token token_; + + /// Adapter used to return internal lock to outside world. + ACE_Lock_Adapter lock_adapter_; + + /// This flag is used to keep track of whether we are actively handling + /// events or not. + sig_atomic_t deactivated_; + + /// Token used to protect manipulation of the handler repository. + /// No need to hold the waiter token to change the repo. + // ACE_DEV_POLL_TOKEN repo_token_; + ACE_SYNCH_MUTEX repo_lock_; + + /// The repository that contains all registered event handlers. + Handler_Repository handler_rep_; + + /// Defined as a pointer to allow overriding by derived classes... + ACE_Timer_Queue *timer_queue_; + + /// Keeps track of whether we should delete the timer queue (if we + /// didn't create it, then we don't delete it). + bool delete_timer_queue_; + + /// Handle signals without requiring global/static variables. + ACE_Sig_Handler *signal_handler_; + + /// Keeps track of whether we should delete the signal handler (if we + /// didn't create it, then we don't delete it). + bool delete_signal_handler_; + + /// Callback object that unblocks the if it's + /// sleeping. + ACE_Reactor_Notify *notify_handler_; + + /// Keeps track of whether we need to delete the notify handler (if + /// we didn't create it, then we don't delete it). + bool delete_notify_handler_; + + /// Flag that determines if signals are masked during event + /// dispatching. + /** + * If 0 then the Reactor will not mask the signals during the event + * dispatching. This is useful for applications that do not + * register any signal handlers and want to reduce the overhead + * introduce by the kernel level locks required to change the mask. + */ + int mask_signals_; + + /// Restart the handle_events event loop method automatically when + /// polling function in use (ioctl() in this case) is interrupted + /// via an EINTR signal. + bool restart_; + +protected: + + /** + * @class Token_Guard + * + * @brief A helper class that helps grabbing, releasing and waiting + * on tokens for a thread that needs access to the reactor's token. + */ + class ACE_Export Token_Guard + { + public: + + /// Constructor that will grab the token for us + Token_Guard (ACE_Dev_Poll_Reactor_Token &token); + + /// Destructor. This will release the token if it hasn't been + /// released till this point + ~Token_Guard (void); + + /// Release the token .. + void release_token (void); + + /// Returns whether the thread that created this object owns the + /// token or not. + int is_owner (void); + + /// A helper method that acquires the token 1) at a low priority, and + /// 2) wait quietly for the token, not waking another thread. This + /// is appropriate for cases where a thread wants to wait for and + /// dispatch an event, not causing an existing waiter to relinquish the + /// token. + int acquire_quietly (ACE_Time_Value *max_wait = 0); + + /// A helper method that acquires the token at a high priority, and + /// does wake the current token holder. + int acquire (ACE_Time_Value *max_wait = 0); + + private: + + Token_Guard (void); + + private: + + /// The Reactor token. + ACE_Dev_Poll_Reactor_Token &token_; + + /// Flag that indicate whether the thread that created this object + /// owns the token or not. A value of 0 indicates that this class + /// hasn't got the token (and hence the thread) and a value of 1 + /// vice-versa. + int owner_; + + }; +}; + + +/** + * @class ACE_Dev_Poll_Handler_Guard + * + * @brief Class used to make event handler reference count + * manipulation exception-safe. + * + * This class makes the reference count manipulation that occurs + * during an upcall exception-safe. Prior to dispatching the event + * handler, the reference count is increased. Once the upcall for the + * given event handler is complete, its reference count will be decreased. + */ +class ACE_Dev_Poll_Handler_Guard +{ +public: + + /// Constructor + /** + * The constructor checks to see if @a eh is a reference-counted handler and + * remember that for later. If @a eh is reference counted, its reference + * count is incremented unless @a do_incr is false. + * @a do_incr should be false if the reference count was incremented + * independently of this guard, for example, on a notify handler since + * the reference count is incremented when the notify is queued. + */ + ACE_Dev_Poll_Handler_Guard (ACE_Event_Handler *eh, bool do_incr = true); + + /// Destructor + /** + * The destructor decrements the reference count on the event + * handler corresponding to the given handle. + */ + ~ACE_Dev_Poll_Handler_Guard (void); + + /// Release the event handler from this guard; when the destructor is + /// called, the handler's reference count will not be decremented. + void release (void); + +private: + + /// The event handler being managed. + ACE_Event_Handler *eh_; + + /// true if eh_ is a reference-counted handler. + bool refcounted_; + +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +# include "ace/Dev_Poll_Reactor.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_HAS_EVENT_POLL || ACE_HAS_DEV_POLL */ + +#include /**/ "ace/post.h" + +#endif /* ACE_DEV_POLL_REACTOR_H */ diff --git a/dep/acelite/ace/Dev_Poll_Reactor.inl b/dep/acelite/ace/Dev_Poll_Reactor.inl new file mode 100644 index 000000000..aedd57057 --- /dev/null +++ b/dep/acelite/ace/Dev_Poll_Reactor.inl @@ -0,0 +1,132 @@ +// -*- C++ -*- +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Dev_Poll_Reactor::Event_Tuple::Event_Tuple (ACE_Event_Handler *eh, + ACE_Reactor_Mask m, + bool is_suspended, + bool is_controlled) + : event_handler (eh), + mask (m), + suspended (is_suspended), + controlled (is_controlled) +{ +} + +// --------------------------------------------------------------------- + +ACE_INLINE size_t +ACE_Dev_Poll_Reactor::Handler_Repository::size (void) const +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::size"); + + return this->size_; +} + +ACE_INLINE size_t +ACE_Dev_Poll_Reactor::Handler_Repository::max_size (void) const +{ + ACE_TRACE ("ACE_Dev_Poll_Reactor::Handler_Repository::max_size"); + + return this->max_size_; +} + +// ----------------------------------------------------------------- + +ACE_INLINE +ACE_Dev_Poll_Handler_Guard::ACE_Dev_Poll_Handler_Guard + (ACE_Event_Handler *eh, + bool do_incr) + : eh_ (eh), + refcounted_ (false) +{ + if (eh == 0) + return; + + this->refcounted_ = + eh->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + if (do_incr && this->refcounted_) + eh->add_reference (); +} + +ACE_INLINE +ACE_Dev_Poll_Handler_Guard::~ACE_Dev_Poll_Handler_Guard (void) +{ + if (this->refcounted_ && this->eh_ != 0) + this->eh_->remove_reference (); +} + +ACE_INLINE void +ACE_Dev_Poll_Handler_Guard::release (void) +{ + this->eh_ = 0; +} + +// --------------------------------------------------------------------- + +ACE_INLINE int +ACE_Dev_Poll_Reactor::upcall (ACE_Event_Handler *event_handler, + int (ACE_Event_Handler::*callback)(ACE_HANDLE), + ACE_HANDLE handle) +{ + // If the handler returns positive value (requesting a reactor + // callback) just call back as many times as the handler requests + // it. The handler is suspended internally and other threads are off + // handling other things. + int status = 0; + + do + { + status = (event_handler->*callback) (handle); + } + while (status > 0 && event_handler != this->notify_handler_); + + return status; +} + + +/************************************************************************/ +// Methods for ACE_Dev_Poll_Reactor::Token_Guard +/************************************************************************/ + +ACE_INLINE +ACE_Dev_Poll_Reactor::Token_Guard::Token_Guard (ACE_Dev_Poll_Reactor_Token &token) + + : token_ (token), + owner_ (0) +{ +} + +ACE_INLINE +ACE_Dev_Poll_Reactor::Token_Guard::~Token_Guard (void) +{ + if (this->owner_ == 1) + { + ACE_MT (this->token_.release ()); + this->owner_ = 0; + } +} + +ACE_INLINE void +ACE_Dev_Poll_Reactor::Token_Guard::release_token (void) +{ + if (this->owner_) + { + ACE_MT (this->token_.release ()); + + // We are not the owner anymore.. + this->owner_ = 0; + } +} + +ACE_INLINE int +ACE_Dev_Poll_Reactor::Token_Guard::is_owner (void) +{ + return this->owner_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dirent.cpp b/dep/acelite/ace/Dirent.cpp new file mode 100644 index 000000000..5f8bd074d --- /dev/null +++ b/dep/acelite/ace/Dirent.cpp @@ -0,0 +1,5 @@ +#include "ace/Dirent.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Dirent.inl" +#endif /* __ACE_INLINE__ */ diff --git a/dep/acelite/ace/Dirent.h b/dep/acelite/ace/Dirent.h new file mode 100644 index 000000000..af982db8f --- /dev/null +++ b/dep/acelite/ace/Dirent.h @@ -0,0 +1,120 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Dirent.h + * + * Define a portable C++ interface to ACE_OS_Dirent directory-entry + * manipulation. + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_DIRENT_H +#define ACE_DIRENT_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_dirent.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dirent + * + * @brief Define a portable C++ directory-entry iterator based on the POSIX API. + */ +class ACE_Export ACE_Dirent +{ +public: + // = Initialization and termination methods. + /// Default constructor. + ACE_Dirent (void); + + /// Constructor calls @c opendir() + explicit ACE_Dirent (const ACE_TCHAR *dirname); + + /// Opens the directory named by filename and associates a directory + /// stream with it. + int open (const ACE_TCHAR *filename); + + /// Destructor calls @c closedir(). + ~ACE_Dirent (void); + + /// Closes the directory stream and frees the ACE_DIR structure. + void close (void); + + // = Iterator methods. + /** + * Returns a pointer to a structure representing the directory entry + * at the current position in the directory stream to which dirp + * refers, and positions the directory stream at the next entry, + * except on read-only filesystems. It returns a NULL pointer upon + * reaching the end of the directory stream, or upon detecting an + * invalid location in the directory. @c read() shall not return + * directory entries containing empty names. It is unspecified + * whether entries are returned for dot or dot-dot. The pointer + * returned by @c read() points to data that may be overwritten by + * another call to @c read() on the same directory stream. This + * data shall not be overwritten by another call to @c read() on a + * different directory stream. @c read() may buffer several + * directory entries per actual read operation; @c read() marks for + * update the st_atime field of the directory each time the + * directory is actually read. + */ + ACE_DIRENT *read (void); + + /** + * Has the equivalent functionality as @c read() except that an + * @a entry and @a result buffer must be supplied by the caller to + * store the result. + */ + int read (struct ACE_DIRENT *entry, + struct ACE_DIRENT **result); + + // = Manipulators. + /// Returns the current location associated with the directory + /// stream. + long tell (void); + + /** + * Sets the position of the next @c read() operation on the + * directory stream. The new position reverts to the position + * associated with the directory stream at the time the @c tell() + * operation that provides loc was performed. Values returned by + * @c tell() are good only for the lifetime of the ACE_DIR pointer from + * which they are derived. If the directory is closed and then + * reopened, the @c telldir() value may be invalidated due to + * undetected directory compaction. It is safe to use a previous + * @c telldir() value immediately after a call to @c opendir() and before + * any calls to readdir. + */ + void seek (long loc); + + /** + * Resets the position of the directory stream to the beginning of + * the directory. It also causes the directory stream to refer to + * the current state of the corresponding directory, as a call to + * @c opendir() would. + */ + void rewind (void); + +private: + /// Pointer to the directory stream. + ACE_DIR *dirp_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Dirent.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DIRENT_H */ diff --git a/dep/acelite/ace/Dirent.inl b/dep/acelite/ace/Dirent.inl new file mode 100644 index 000000000..3e420f1cc --- /dev/null +++ b/dep/acelite/ace/Dirent.inl @@ -0,0 +1,96 @@ +// -*- C++ -*- +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_Dirent::open (const ACE_TCHAR *dirname) +{ + // If the directory stream is already open, close it to prevent + // possible resource leaks. + + if (this->dirp_ != 0) + { + ACE_OS::closedir (this->dirp_); + this->dirp_ = 0; + } + + this->dirp_ = ACE_OS::opendir (dirname); + + if (this->dirp_ == 0) + return -1; + else + return 0; +} + +ACE_INLINE +ACE_Dirent::ACE_Dirent (void) + : dirp_ (0) +{ +} + +ACE_INLINE +ACE_Dirent::ACE_Dirent (const ACE_TCHAR *dirname) + : dirp_ (0) +{ + if (this->open (dirname) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Dirent::ACE_Dirent"))); +} + +ACE_INLINE +ACE_Dirent::~ACE_Dirent (void) +{ + if (this->dirp_ != 0) + ACE_OS::closedir (this->dirp_); +} + +ACE_INLINE ACE_DIRENT * +ACE_Dirent::read (void) +{ + return this->dirp_ ? ACE_OS::readdir (this->dirp_) : 0; +} + +ACE_INLINE int +ACE_Dirent::read (struct ACE_DIRENT *entry, + struct ACE_DIRENT **result) +{ + return this->dirp_ + ? ACE_OS::readdir_r (this->dirp_, entry, result) + : 0; +} + +ACE_INLINE void +ACE_Dirent::close (void) +{ + if (this->dirp_ != 0) + { + ACE_OS::closedir (this->dirp_); + + // Prevent double closure + this->dirp_ = 0; + } +} + +ACE_INLINE void +ACE_Dirent::rewind (void) +{ + if (this->dirp_) + ACE_OS::rewinddir (this->dirp_); +} + +ACE_INLINE void +ACE_Dirent::seek (long loc) +{ + if (this->dirp_) + ACE_OS::seekdir (this->dirp_, loc); +} + +ACE_INLINE long +ACE_Dirent::tell (void) +{ + return this->dirp_ ? ACE_OS::telldir (this->dirp_) : 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dirent_Selector.cpp b/dep/acelite/ace/Dirent_Selector.cpp new file mode 100644 index 000000000..f16d1da68 --- /dev/null +++ b/dep/acelite/ace/Dirent_Selector.cpp @@ -0,0 +1,69 @@ +#include "ace/Dirent_Selector.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Dirent_Selector.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_dirent.h" +#include "ace/OS_NS_stdlib.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Construction/Destruction + +ACE_Dirent_Selector::ACE_Dirent_Selector (void) + : namelist_ (0), + n_ (0) +{ +} + +ACE_Dirent_Selector::~ACE_Dirent_Selector (void) +{ + // Free up any allocated resources. + this->close(); +} + +int +ACE_Dirent_Selector::open (const ACE_TCHAR *dir, + ACE_SCANDIR_SELECTOR sel, + ACE_SCANDIR_COMPARATOR cmp) +{ + n_ = ACE_OS::scandir (dir, &this->namelist_, sel, cmp); + return n_; +} + +int +ACE_Dirent_Selector::close (void) +{ + for (--n_; n_ >= 0; --n_) + { +#if defined (ACE_LACKS_STRUCT_DIR) + // Only the lacking-struct-dir emulation allocates this. Native + // scandir includes d_name in the dirent struct itself. +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->namelist_[n_]->d_name); +#else + ACE_OS::free (this->namelist_[n_]->d_name); +#endif /* ACE_HAS_ALLOC_HOOKS */ +#endif +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->namelist_[n_]); +#else + ACE_OS::free (this->namelist_[n_]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (this->namelist_); +#else + ACE_OS::free (this->namelist_); +#endif /* ACE_HAS_ALLOC_HOOKS */ + this->namelist_ = 0; + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dirent_Selector.h b/dep/acelite/ace/Dirent_Selector.h new file mode 100644 index 000000000..0de9dc085 --- /dev/null +++ b/dep/acelite/ace/Dirent_Selector.h @@ -0,0 +1,73 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Dirent_Selector.h + * + * Define a portable C++ interface to the method. + * + * @author Rich Newman + */ +//============================================================================= + +#ifndef ACE_DIRENT_SELECTOR_H +#define ACE_DIRENT_SELECTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_dirent.h" /* Need ACE_SCANDIR_SELECTOR, COMPARATOR */ +#include "ace/os_include/os_dirent.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dirent_Selector + * + * @brief Define a portable C++ directory-entry iterator based on the + * POSIX scandir API. + */ +class ACE_Export ACE_Dirent_Selector +{ +public: + /// Constructor + ACE_Dirent_Selector (void); + + /// Destructor. + virtual ~ACE_Dirent_Selector (void); + + /// Return the length of the list of matching directory entries. + int length (void) const; + + /// Return the entry at @a index. + ACE_DIRENT *operator[] (const int index) const; + + /// Free up resources. + int close (void); + + /// Open the directory @a dir and populate the current list of names with + /// directory entries that match the @a selector and @a comparator. + int open (const ACE_TCHAR *dir, + ACE_SCANDIR_SELECTOR selector = 0, + ACE_SCANDIR_COMPARATOR comparator = 0); + +protected: + /// Ptr to the namelist array. + ACE_DIRENT **namelist_; + + /// Number of entries in the array. + int n_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Dirent_Selector.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DIRENT_SELECTOR_H */ diff --git a/dep/acelite/ace/Dirent_Selector.inl b/dep/acelite/ace/Dirent_Selector.inl new file mode 100644 index 000000000..27651569b --- /dev/null +++ b/dep/acelite/ace/Dirent_Selector.inl @@ -0,0 +1,16 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_Dirent_Selector::length (void) const +{ + return n_; +} + +ACE_INLINE ACE_DIRENT * +ACE_Dirent_Selector::operator[] (const int n) const +{ + return this->namelist_[n]; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dump.cpp b/dep/acelite/ace/Dump.cpp new file mode 100644 index 000000000..576417e81 --- /dev/null +++ b/dep/acelite/ace/Dump.cpp @@ -0,0 +1,143 @@ +#include "ace/Dump.h" +#include "ace/Guard_T.h" +#include "ace/Thread_Mutex.h" +#include "ace/Object_Manager.h" +#include "ace/Log_Category.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Implementations (very simple for now...) + +ACE_Dumpable::~ACE_Dumpable (void) +{ + ACE_TRACE ("ACE_Dumpable::~ACE_Dumpable"); +} + +ACE_Dumpable::ACE_Dumpable (const void *this_ptr) + : this_ (this_ptr) +{ + ACE_TRACE ("ACE_Dumpable::ACE_Dumpable"); +} + +ACE_Dumpable_Ptr::ACE_Dumpable_Ptr (const ACE_Dumpable *dumper) + : dumper_ (dumper) +{ + ACE_TRACE ("ACE_Dumpable_Ptr::ACE_Dumpable_Ptr"); +} + +const ACE_Dumpable * +ACE_Dumpable_Ptr::operator->() const +{ + ACE_TRACE ("ACE_Dumpable_Ptr::operator->"); + return this->dumper_; +} + +void +ACE_Dumpable_Ptr::operator= (const ACE_Dumpable *dumper) const +{ + ACE_TRACE ("ACE_Dumpable_Ptr::operator="); + if (this->dumper_ != dumper) + { + delete const_cast (this->dumper_); + (const_cast (this))->dumper_ = dumper; + } +} + +ACE_ODB::ACE_ODB (void) + // Let the Tuple default constructor initialize object_table_ + : current_size_ (0) +{ + ACE_TRACE ("ACE_ODB::ACE_ODB"); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_ODB) + +ACE_ODB * +ACE_ODB::instance (void) +{ + ACE_TRACE ("ACE_ODB::instance"); + + if (ACE_ODB::instance_ == 0) + { + ACE_MT (ACE_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_DUMP_LOCK); + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, *lock, 0)); + + if (ACE_ODB::instance_ == 0) + ACE_NEW_RETURN (ACE_ODB::instance_, + ACE_ODB, + 0); + } + + return ACE_ODB::instance_; +} + +void +ACE_ODB::dump_objects (void) +{ + ACE_TRACE ("ACE_ODB::dump_objects"); + for (int i = 0; i < this->current_size_; i++) + { + if (this->object_table_[i].this_ != 0) + // Dump the state of the object. + this->object_table_[i].dumper_->dump (); + } +} + +// This method registers a new . It detects +// duplicates and simply overwrites them. + +void +ACE_ODB::register_object (const ACE_Dumpable *dumper) +{ + ACE_TRACE ("ACE_ODB::register_object"); + int i; + int slot = 0; + + for (i = 0; i < this->current_size_; i++) + { + if (this->object_table_[i].this_ == 0) + slot = i; + else if (this->object_table_[i].this_ == dumper->this_) + { + slot = i; + break; + } + } + + if (i == this->current_size_) + { + slot = this->current_size_++; + ACE_ASSERT (this->current_size_ < ACE_ODB::MAX_TABLE_SIZE); + } + this->object_table_[slot].this_ = dumper->this_; + this->object_table_[slot].dumper_ = dumper; +} + +void +ACE_ODB::remove_object (const void *this_ptr) +{ + ACE_TRACE ("ACE_ODB::remove_object"); + int i; + + for (i = 0; i < this->current_size_; i++) + { + if (this->object_table_[i].this_ == this_ptr) + break; + } + + if (i < this->current_size_) + { + this->object_table_[i].this_ = 0; + this->object_table_[i].dumper_ = 0; + } +} + +ACE_ODB *ACE_ODB::instance_ = 0; + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dump.h b/dep/acelite/ace/Dump.h new file mode 100644 index 000000000..09eafd1a6 --- /dev/null +++ b/dep/acelite/ace/Dump.h @@ -0,0 +1,170 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Dump.h + * + * A prototype mechanism that allow all ACE objects to be registered + * with a central in-memory "database" that can dump the state of all + * live ACE objects (e.g., from within a debugger). + * + * The macros which allow easy registration and removal of objects to be + * dumped (ACE_REGISTER_OBJECT and ACE_REMOVE_OBJECT) are turned into + * no-ops by compiling with the ACE_NDEBUG macro defined. This allows + * usage to be removed in "release mode" builds without changing code. + * + * There are several interesting aspects to this design: + * + * 1. It uses the External Polymorphism pattern to avoid having to + * derive all ACE classes from a common base class that has virtual + * methods (this is crucial to avoid unnecessary overhead). In + * addition, there is no additional space added to ACE objects + * (this is crucial to maintain binary layout compatibility). + * + * 2. This mechanism can be conditionally compiled in order to + * completely disable this feature entirely. Moreover, by + * using macros there are relatively few changes to ACE code. + * + * 3. This mechanism copes with single-inheritance hierarchies of + * dumpable classes. In such cases we typically want only one + * dump, corresponding to the most derived instance. Thanks to + * Christian Millour (chris@etca.fr) for illustrating how to do + * this. Note, however, that this scheme doesn't generalize to + * work with multiple-inheritance or virtual base classes. + * + * Future work includes: + * + * 1. Using a dynamic object table rather than a static table + * + * 2. Adding support to allow particular classes of objects to + * be selectively dumped. + * + * @author Doug Schmidt + */ +//============================================================================= + + +#ifndef ACE_DUMP_H +#define ACE_DUMP_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dumpable + * + * @brief Base class that defines a uniform interface for all object + * dumping. + */ +class ACE_Export ACE_Dumpable +{ +public: + friend class ACE_ODB; + friend class ACE_Dumpable_Ptr; + + /// Constructor. + ACE_Dumpable (const void *); + + /// This pure virtual method must be filled in by a subclass. + virtual void dump (void) const = 0; + +protected: + virtual ~ACE_Dumpable (void); + +private: + /// Pointer to the object that is being stored. + const void *this_; +}; + +/** + * @class ACE_Dumpable_Ptr + * + * @brief A smart pointer stored in the in-memory object database + * ACE_ODB. The pointee (if any) is deleted when reassigned. + */ +class ACE_Export ACE_Dumpable_Ptr +{ +public: + ACE_Dumpable_Ptr (const ACE_Dumpable *dumper = 0); + const ACE_Dumpable *operator->() const; + void operator= (const ACE_Dumpable *dumper) const; + +private: + /// "Real" pointer to the underlying abstract base class + /// pointer that does the real work. + const ACE_Dumpable *dumper_; +}; + +/** + * @class ACE_ODB + * + * @brief This is the object database (ODB) that keeps track of all + * live ACE objects. + */ +class ACE_Export ACE_ODB +{ +public: + /// @todo This is clearly inadequate and should be dynamic... + enum {MAX_TABLE_SIZE = 100000}; + + /// Iterates through the entire set of registered objects and + /// dumps their state. + void dump_objects (void); + + /// Add the tuple to the list of registered ACE objects. + void register_object (const ACE_Dumpable *dumper); + + /// Use to locate and remove the associated from the + /// list of registered ACE objects. + void remove_object (const void *this_); + + /// Interface to the Singleton instance of the object database. + static ACE_ODB *instance (void); + + ACE_ALLOC_HOOK_DECLARE; + +private: + ACE_ODB (void); // Ensure we have a Singleton... + + struct Tuple + { + /// Pointer to the object that is registered. + const void *this_; + + /// Smart pointer to the ACE_Dumpable object associated with this_. + /// This uses an ACE_Dumpable_Ptr, instead of a bare pointer, to + /// cope with hierarchies of dumpable classes. In such cases we + /// typically want only one dump, corresponding to the most derived + /// instance. To achieve this, the handle registered for the + /// subobject corresponding to the base class is destroyed (hence + /// on destruction of the subobject its handle won't exist anymore + /// and we'll have to check for that). + const ACE_Dumpable_Ptr dumper_; + + Tuple (void) : this_ (0), dumper_(0) {} + }; + + /// Singleton instance of this class. + static ACE_ODB *instance_; + + /// The current implementation is very simple-minded and will be + /// changed to be dynamic. + Tuple object_table_[ACE_ODB::MAX_TABLE_SIZE]; + + /// Current size of . + int current_size_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Include the templates classes at this point. +#include "ace/Dump_T.h" + +#include /**/ "ace/post.h" +#endif /* ACE_DUMP_H */ diff --git a/dep/acelite/ace/Dump_T.cpp b/dep/acelite/ace/Dump_T.cpp new file mode 100644 index 000000000..fc0833a9e --- /dev/null +++ b/dep/acelite/ace/Dump_T.cpp @@ -0,0 +1,45 @@ +// Dump_T.cpp +#ifndef ACE_DUMP_T_CPP +#define ACE_DUMP_T_CPP + +#include "ace/Dump_T.h" +#include "ace/Global_Macros.h" +#include "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Dumpable_Adapter::~ACE_Dumpable_Adapter (void) +{ + ACE_TRACE ("ACE_Dumpable_Adapter::~ACE_Dumpable_Adapter"); +} + +template +ACE_Dumpable_Adapter::ACE_Dumpable_Adapter (const Concrete *t) + : ACE_Dumpable ((const void *) t), this_ (t) +{ + ACE_TRACE ("ACE_Dumpable_Adapter::ACE_Dumpable_Adapter"); +} + +template Concrete * +ACE_Dumpable_Adapter::operator->() const +{ + return (Concrete *) this->this_; +} + +template void +ACE_Dumpable_Adapter::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Dumpable_Adapter::dump"); + this->this_->dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_DUMP_T_CPP */ diff --git a/dep/acelite/ace/Dump_T.h b/dep/acelite/ace/Dump_T.h new file mode 100644 index 000000000..b8859d113 --- /dev/null +++ b/dep/acelite/ace/Dump_T.h @@ -0,0 +1,81 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Dump_T.h + * + * @author Doug Schmidt + */ +//============================================================================= + + +#ifndef ACE_DUMP_T_H +#define ACE_DUMP_T_H +#include /**/ "ace/pre.h" + +#include "ace/Dump.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dumpable_Adapter + * + * @brief + * This class inherits the interface of the abstract ACE_Dumpable + * class and is instantiated with the implementation of the + * concrete component class . + * + * This design is similar to the Adapter and Decorator patterns + * from the ``Gang of Four'' book. Note that + * need not inherit from a common class since ACE_Dumpable + * provides the uniform virtual interface! + */ +template +class ACE_Dumpable_Adapter : public ACE_Dumpable +{ +public: + // = Initialization and termination methods. + ACE_Dumpable_Adapter (const Concrete *t); + ~ACE_Dumpable_Adapter (void); + + /// Concrete dump method (simply delegates to the dump() method of + /// ). + virtual void dump (void) const; + + /// Delegate to methods in the Concrete class. + Concrete *operator->() const; + +private: + /// Pointer to @c this of . + const Concrete *this_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +// Some useful macros for conditionally compiling this feature... +#if defined (ACE_NDEBUG) +#define ACE_REGISTER_OBJECT(CLASS) +#define ACE_REMOVE_OBJECT +#else +#define ACE_REGISTER_OBJECT(CLASS) \ + ACE_ODB::instance ()->register_object \ + (new ACE_Dumpable_Adapter (this)); +#define ACE_REMOVE_OBJECT \ + ACE_ODB::instance ()->remove_object \ + ((void *) this); +#endif /* ACE_NDEBUG */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Dump_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Dump_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_DUMP_T_H */ diff --git a/dep/acelite/ace/Dynamic.cpp b/dep/acelite/ace/Dynamic.cpp new file mode 100644 index 000000000..469d67e40 --- /dev/null +++ b/dep/acelite/ace/Dynamic.cpp @@ -0,0 +1,32 @@ +#include "ace/Dynamic.h" +#include "ace/Singleton.h" +#include "ace/TSS_T.h" +#include "ace/Synch_Traits.h" +#include "ace/Null_Mutex.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Dynamic.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Dynamic::ACE_Dynamic (void) + : is_dynamic_ (false) +{ + ACE_TRACE ("ACE_Dynamic::ACE_Dynamic"); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Dynamic) + +/* static */ ACE_Dynamic * +ACE_Dynamic::instance (void) +{ + return ACE_TSS_Singleton::instance (); +} + +ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_TSS_Singleton, ACE_Dynamic, ACE_Null_Mutex); + + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic.h b/dep/acelite/ace/Dynamic.h new file mode 100644 index 000000000..041e3cdef --- /dev/null +++ b/dep/acelite/ace/Dynamic.h @@ -0,0 +1,75 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Dynamic.h + * + * @author Doug Schmidt + * @author Irfan Pyarali. + */ +//========================================================================== + +#ifndef ACE_DYNAMIC_H +#define ACE_DYNAMIC_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dynamic + * + * @brief Checks to see if an object was dynamically allocated. + * + * This class holds the pointer in a thread-safe manner between + * the call to operator new and the call to the constructor. + */ +class ACE_Export ACE_Dynamic +{ +public: + // = Initialization and termination method. + /// Constructor. + ACE_Dynamic (void); + + /// Destructor. + ~ACE_Dynamic (void); + + /** + * Sets a flag that indicates that the object was dynamically + * created. This method is usually called in operator new and then + * checked and reset in the constructor. + */ + void set (void); + + /// @c true if we were allocated dynamically, else @c false. + bool is_dynamic (void); + + /// Resets state flag. + void reset (void); + + static ACE_Dynamic *instance (void); + + ACE_ALLOC_HOOK_DECLARE; + +private: + /** + * Flag that indicates that the object was dynamically created. This + * method is usually called in operator new and then checked and + * reset in the constructor. + */ + bool is_dynamic_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Dynamic.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_DYNAMIC_H */ diff --git a/dep/acelite/ace/Dynamic.inl b/dep/acelite/ace/Dynamic.inl new file mode 100644 index 000000000..795f33d2e --- /dev/null +++ b/dep/acelite/ace/Dynamic.inl @@ -0,0 +1,31 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Dynamic::~ACE_Dynamic (void) +{ + // ACE_TRACE ("ACE_Dynamic::~ACE_Dynamic"); +} + +ACE_INLINE void +ACE_Dynamic::set (void) +{ + // ACE_TRACE ("ACE_Dynamic::set"); + this->is_dynamic_ = true; +} + +ACE_INLINE bool +ACE_Dynamic::is_dynamic (void) +{ + // ACE_TRACE ("ACE_Dynamic::is_dynamic"); + return this->is_dynamic_; +} + +ACE_INLINE void +ACE_Dynamic::reset (void) +{ + // ACE_TRACE ("ACE_Dynamic::reset"); + this->is_dynamic_ = false; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Message_Strategy.cpp b/dep/acelite/ace/Dynamic_Message_Strategy.cpp new file mode 100644 index 000000000..35802fdbf --- /dev/null +++ b/dep/acelite/ace/Dynamic_Message_Strategy.cpp @@ -0,0 +1,201 @@ +#include "ace/Dynamic_Message_Strategy.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Dynamic_Message_Strategy.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Guard_T.h" +#include "ace/Log_Category.h" +#include "ace/Malloc_Base.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// ctor + +ACE_Dynamic_Message_Strategy::ACE_Dynamic_Message_Strategy (unsigned long static_bit_field_mask, + unsigned long static_bit_field_shift, + unsigned long dynamic_priority_max, + unsigned long dynamic_priority_offset) + : static_bit_field_mask_ (static_bit_field_mask), + static_bit_field_shift_ (static_bit_field_shift), + dynamic_priority_max_ (dynamic_priority_max), + dynamic_priority_offset_ (dynamic_priority_offset), + max_late_ (0, dynamic_priority_offset - 1), + min_pending_ (0, dynamic_priority_offset), + pending_shift_ (0, dynamic_priority_max) +{ +} + +// dtor + +ACE_Dynamic_Message_Strategy::~ACE_Dynamic_Message_Strategy (void) +{ +} + +ACE_Dynamic_Message_Strategy::Priority_Status +ACE_Dynamic_Message_Strategy::priority_status (ACE_Message_Block & mb, + const ACE_Time_Value & tv) +{ + // default the message to have pending priority status + Priority_Status status = ACE_Dynamic_Message_Strategy::PENDING; + + // start with the passed absolute time as the message's priority, then + // call the polymorphic hook method to (at least partially) convert + // the absolute time and message attributes into the message's priority + ACE_Time_Value priority (tv); + convert_priority (priority, mb); + + // if the priority is negative, the message is pending + if (priority < ACE_Time_Value::zero) + { + // priority for pending messages must be shifted + // upward above the late priority range + priority += pending_shift_; + if (priority < min_pending_) + priority = min_pending_; + } + // otherwise, if the priority is greater than the maximum late + // priority value that can be represented, it is beyond late + else if (priority > max_late_) + { + // all messages that are beyond late are assigned lowest priority (zero) + mb.msg_priority (0); + return ACE_Dynamic_Message_Strategy::BEYOND_LATE; + } + // otherwise, the message is late, but its priority is correct + else + status = ACE_Dynamic_Message_Strategy::LATE; + + // use (fast) bitwise operators to isolate and replace + // the dynamic portion of the message's priority + mb.msg_priority((mb.msg_priority() & static_bit_field_mask_) | + ((priority.usec () + + ACE_ONE_SECOND_IN_USECS * (suseconds_t)(priority.sec())) << + static_bit_field_shift_)); + + // returns the priority status of the message + return status; +} + + +// Dump the state of the strategy. + +void +ACE_Dynamic_Message_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Dynamic_Message_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("static_bit_field_mask_ = %u\n") + ACE_TEXT ("static_bit_field_shift_ = %u\n") + ACE_TEXT ("dynamic_priority_max_ = %u\n") + ACE_TEXT ("dynamic_priority_offset_ = %u\n") + ACE_TEXT ("max_late_ = [%d sec, %d usec]\n") + ACE_TEXT ("min_pending_ = [%d sec, %d usec]\n") + ACE_TEXT ("pending_shift_ = [%d sec, %d usec]\n"), + this->static_bit_field_mask_, + this->static_bit_field_shift_, + this->dynamic_priority_max_, + this->dynamic_priority_offset_, + this->max_late_.sec (), + this->max_late_.usec (), + this->min_pending_.sec (), + this->min_pending_.usec (), + this->pending_shift_.sec (), + this->pending_shift_.usec ())); + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Deadline_Message_Strategy::ACE_Deadline_Message_Strategy (unsigned long static_bit_field_mask, + unsigned long static_bit_field_shift, + unsigned long dynamic_priority_max, + unsigned long dynamic_priority_offset) + : ACE_Dynamic_Message_Strategy (static_bit_field_mask, + static_bit_field_shift, + dynamic_priority_max, + dynamic_priority_offset) +{ +} + +ACE_Deadline_Message_Strategy::~ACE_Deadline_Message_Strategy (void) +{ +} + +void +ACE_Deadline_Message_Strategy::convert_priority (ACE_Time_Value & priority, + const ACE_Message_Block & mb) +{ + // Convert absolute time passed in tv to negative time + // to deadline of mb with respect to that absolute time. + priority -= mb.msg_deadline_time (); +} + // dynamic priority conversion function based on time to deadline + +void +ACE_Deadline_Message_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Deadline_Message_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE_Dynamic_Message_Strategy base class:\n"))); + this->ACE_Dynamic_Message_Strategy::dump (); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nderived class: ACE_Deadline_Message_Strategy\n"))); + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Laxity_Message_Strategy::ACE_Laxity_Message_Strategy (unsigned long static_bit_field_mask, + unsigned long static_bit_field_shift, + unsigned long dynamic_priority_max, + unsigned long dynamic_priority_offset) + : ACE_Dynamic_Message_Strategy (static_bit_field_mask, + static_bit_field_shift, + dynamic_priority_max, + dynamic_priority_offset) +{ +} + +ACE_Laxity_Message_Strategy::~ACE_Laxity_Message_Strategy (void) +{ +} + +void +ACE_Laxity_Message_Strategy::convert_priority (ACE_Time_Value & priority, + const ACE_Message_Block & mb) +{ + // Convert absolute time passed in tv to negative + // laxity of mb with respect to that absolute time. + priority += mb.msg_execution_time (); + priority -= mb.msg_deadline_time (); +} + // dynamic priority conversion function based on laxity + +void +ACE_Laxity_Message_Strategy::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Laxity_Message_Strategy::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE_Dynamic_Message_Strategy base class:\n"))); + this->ACE_Dynamic_Message_Strategy::dump (); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nderived class: ACE_Laxity_Message_Strategy\n"))); + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + // Dump the state of the strategy. + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Message_Strategy.h b/dep/acelite/ace/Dynamic_Message_Strategy.h new file mode 100644 index 000000000..f6d003c7a --- /dev/null +++ b/dep/acelite/ace/Dynamic_Message_Strategy.h @@ -0,0 +1,213 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Dynamic_Message_Strategy.h + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_DYNAMIC_MESSAGE_STRATEGY_H +#define ACE_DYNAMIC_MESSAGE_STRATEGY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-lite.h" +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Message_Block.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dynamic_Message_Strategy + * + * @brief An abstract base class which provides dynamic priority + * evaluation methods for use by the ACE_Dynamic_Message_Queue + * class or any other class which needs to manage the priorities + * of a collection of ACE_Message_Blocks dynamically. + * + * Methods for deadline and laxity based priority evaluation are + * provided. These methods assume a specific partitioning of + * the message priority number into a higher order dynamic bit + * field and a lower order static priority bit field. The + * default partitioning assumes an unsigned dynamic message + * priority field of 22 bits and an unsigned static message + * priority field of 10 bits. This corresponds to the initial + * values of the static class members. To provide a different + * partitioning, assign a different set of values to the static + * class members before using the static member functions. + */ +class ACE_Export ACE_Dynamic_Message_Strategy +{ +public: + + /// Message priority status + /// Values are defined as bit flags so that status combinations may + /// be specified easily. + enum Priority_Status + { + /// Message can still make its deadline + PENDING = 0x01, + /// Message cannot make its deadline + LATE = 0x02, + /// Message is so late its priority is undefined + BEYOND_LATE = 0x04, + /// Mask to match any priority status + ANY_STATUS = 0x07 + }; + + /// Constructor. + ACE_Dynamic_Message_Strategy (unsigned long static_bit_field_mask, + unsigned long static_bit_field_shift, + unsigned long dynamic_priority_max, + unsigned long dynamic_priority_offset); + + /// Virtual destructor. + virtual ~ACE_Dynamic_Message_Strategy (void); + + /// Updates the message's priority and returns its priority status. + Priority_Status priority_status (ACE_Message_Block &mb, + const ACE_Time_Value &tv); + + /// Get static bit field mask. + unsigned long static_bit_field_mask (void) const; + + /// Set static bit field mask. + void static_bit_field_mask (unsigned long); + + /// Get left shift value to make room for static bit field. + unsigned long static_bit_field_shift (void) const; + + /// Set left shift value to make room for static bit field. + void static_bit_field_shift (unsigned long); + + /// Get maximum supported priority value. + unsigned long dynamic_priority_max (void) const; + + /// Set maximum supported priority value. + void dynamic_priority_max (unsigned long); + + /// Get offset to boundary between signed range and unsigned range. + unsigned long dynamic_priority_offset (void) const; + + /// Set offset to boundary between signed range and unsigned range. + void dynamic_priority_offset (unsigned long); + + /// Dump the state of the strategy. + virtual void dump (void) const; + +protected: + /// Hook method for dynamic priority conversion. + virtual void convert_priority (ACE_Time_Value &priority, + const ACE_Message_Block &mb) = 0; + + /// This is a bit mask with all ones in the static bit field. + unsigned long static_bit_field_mask_; + + /** + * This is a left shift value to make room for static bit field: + * this value should be the logarithm base 2 of + * (static_bit_field_mask_ + 1). + */ + unsigned long static_bit_field_shift_; + + /// Maximum supported priority value. + unsigned long dynamic_priority_max_; + + /// Offset to boundary between signed range and unsigned range. + unsigned long dynamic_priority_offset_; + + /// Maximum late time value that can be represented. + ACE_Time_Value max_late_; + + /// Minimum pending time value that can be represented. + ACE_Time_Value min_pending_; + + /// Time value by which to shift pending priority. + ACE_Time_Value pending_shift_; +}; + +/** + * @class ACE_Deadline_Message_Strategy + * + * @brief Deadline based message priority strategy. + * + * Assigns dynamic message priority according to time to deadline. The + * message priority is divided into high and low order bit fields. The + * high order bit field is used for dynamic message priority, which is + * updated whenever the convert_priority() method is called. The + * low order bit field is used for static message priority and is left + * unchanged. The partitioning of the priority value into high and low + * order bit fields is done according to the arguments passed to the + * strategy object's constructor. + */ +class ACE_Export ACE_Deadline_Message_Strategy : public ACE_Dynamic_Message_Strategy +{ +public: + /// Constructor with all arguments defaulted. + ACE_Deadline_Message_Strategy (unsigned long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 + unsigned long static_bit_field_shift = 10, // 10 low order bits + unsigned long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 + unsigned long dynamic_priority_offset = 0x200000UL); // 2^(22-1) + + /// Virtual destructor. + virtual ~ACE_Deadline_Message_Strategy (void); + + /// Dynamic priority conversion function based on time to deadline. + virtual void convert_priority (ACE_Time_Value &priority, + const ACE_Message_Block &mb); + + /// Dump the state of the strategy. + virtual void dump (void) const; +}; + +/** + * @class ACE_Laxity_Message_Strategy + * + * @brief Laxity based message priority strategy. + * + * Assigns dynamic message priority according to laxity (time to + * deadline minus worst case execution time). The message priority is + * divided into high and low order bit fields. The high order + * bit field is used for dynamic message priority, which is + * updated whenever the convert_priority() method is called. The + * low order bit field is used for static message priority and is left + * unchanged. The partitioning of the priority value into high and low + * order bit fields is done according to the arguments passed to the + * strategy object's constructor. + */ +class ACE_Export ACE_Laxity_Message_Strategy : public ACE_Dynamic_Message_Strategy +{ +public: + /// Ctor, with all arguments defaulted. + ACE_Laxity_Message_Strategy (unsigned long static_bit_field_mask = 0x3FFUL, // 2^(10) - 1 + unsigned long static_bit_field_shift = 10, // 10 low order bits + unsigned long dynamic_priority_max = 0x3FFFFFUL, // 2^(22)-1 + unsigned long dynamic_priority_offset = 0x200000UL); // 2^(22-1) + + /// virtual dtor. + virtual ~ACE_Laxity_Message_Strategy (void); + + /// Dynamic priority conversion function based on laxity. + virtual void convert_priority (ACE_Time_Value &priority, + const ACE_Message_Block &mb); + + /// Dump the state of the strategy. + virtual void dump (void) const; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Dynamic_Message_Strategy.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_DYNAMIC_MESSAGE_STRATEGY_H */ diff --git a/dep/acelite/ace/Dynamic_Message_Strategy.inl b/dep/acelite/ace/Dynamic_Message_Strategy.inl new file mode 100644 index 000000000..675e0f1e4 --- /dev/null +++ b/dep/acelite/ace/Dynamic_Message_Strategy.inl @@ -0,0 +1,72 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE unsigned long +ACE_Dynamic_Message_Strategy::static_bit_field_mask (void) const +{ + return static_bit_field_mask_; +} + // get static bit field mask + +ACE_INLINE void +ACE_Dynamic_Message_Strategy::static_bit_field_mask (unsigned long ul) +{ + static_bit_field_mask_ = ul; +} + // set static bit field mask + +ACE_INLINE unsigned long +ACE_Dynamic_Message_Strategy::static_bit_field_shift (void) const +{ + return static_bit_field_shift_; +} + // get left shift value to make room for static bit field + +ACE_INLINE void +ACE_Dynamic_Message_Strategy::static_bit_field_shift (unsigned long ul) +{ + static_bit_field_shift_ = ul; +} + // set left shift value to make room for static bit field + +ACE_INLINE unsigned long +ACE_Dynamic_Message_Strategy::dynamic_priority_max (void) const +{ + return dynamic_priority_max_; +} + // get maximum supported priority value + +ACE_INLINE void +ACE_Dynamic_Message_Strategy::dynamic_priority_max (unsigned long ul) +{ + // pending_shift_ depends on dynamic_priority_max_: for performance + // reasons, the value in pending_shift_ is (re)calculated only when + // dynamic_priority_max_ is initialized or changes, and is stored + // as a class member rather than being a derived value. + dynamic_priority_max_ = ul; + pending_shift_ = ACE_Time_Value (0, ul); +} + // set maximum supported priority value + +ACE_INLINE unsigned long +ACE_Dynamic_Message_Strategy::dynamic_priority_offset (void) const +{ + return dynamic_priority_offset_; +} + // get offset for boundary between signed range and unsigned range + +ACE_INLINE void +ACE_Dynamic_Message_Strategy::dynamic_priority_offset (unsigned long ul) +{ + // max_late_ and min_pending_ depend on dynamic_priority_offset_: + // for performance reasons, the values in max_late_ and min_pending_ + // are (re)calculated only when dynamic_priority_offset_ is + // initialized or changes, and are stored as a class member rather + // than being derived each time one of their values is needed. + dynamic_priority_offset_ = ul; + max_late_ = ACE_Time_Value (0, ul - 1); + min_pending_ = ACE_Time_Value (0, ul); +} + // set offset for boundary between signed range and unsigned range + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Service.cpp b/dep/acelite/ace/Dynamic_Service.cpp new file mode 100644 index 000000000..8bf6871d1 --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service.cpp @@ -0,0 +1,61 @@ +#ifndef ACE_DYNAMIC_SERVICE_CPP +#define ACE_DYNAMIC_SERVICE_CPP + +#include "ace/Dynamic_Service.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Object.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Dynamic_Service.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + + +template TYPE * +ACE_Dynamic_Service::instance (const ACE_TCHAR *name) +{ + ACE_Service_Object * svc_obj = + static_cast + (ACE_Dynamic_Service_Base::instance (name,false)); + return dynamic_cast (svc_obj); +} + +template TYPE * +ACE_Dynamic_Service::instance (const ACE_TCHAR *name, + bool no_global) +{ + ACE_Service_Object * svc_obj = + static_cast + (ACE_Dynamic_Service_Base::instance (name, no_global)); + return dynamic_cast (svc_obj); +} + +template TYPE * +ACE_Dynamic_Service::instance (const ACE_Service_Gestalt* conf, + const ACE_TCHAR *name) +{ + ACE_Service_Object * svc_obj = + static_cast + (ACE_Dynamic_Service_Base::instance (conf, name, false)); + return dynamic_cast (svc_obj); +} + +template TYPE * +ACE_Dynamic_Service::instance (const ACE_Service_Gestalt* conf, + const ACE_TCHAR *name, + bool no_global) +{ + ACE_Service_Object * svc_obj = + static_cast + (ACE_Dynamic_Service_Base::instance (conf, name, no_global)); + return dynamic_cast (svc_obj); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_DYNAMIC_SERVICE_CPP */ diff --git a/dep/acelite/ace/Dynamic_Service.h b/dep/acelite/ace/Dynamic_Service.h new file mode 100644 index 000000000..84b45b0bd --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service.h @@ -0,0 +1,87 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Dynamic_Service.h + * + * @author Prashant Jain + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_DYNAMIC_SERVICE_H +#define ACE_DYNAMIC_SERVICE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Global_Macros.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Dynamic_Service_Base.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Service_Object; + +/** + * @class ACE_Dynamic_Service + * + * @brief Provides a general interface to retrieve arbitrary objects + * from the ACE service repository. + * + * Uses "name" for lookup in the ACE service repository. Obtains + * the object and returns it as the appropriate type. + */ +template +class ACE_Dynamic_Service : public ACE_Dynamic_Service_Base +{ +public: + /// Return instance using @a name to search the Service_Repository. + static TYPE* instance (const ACE_TCHAR *name); + static TYPE* instance (const ACE_TCHAR *name, bool no_global); + + static TYPE* instance (const ACE_Service_Gestalt* repo, + const ACE_TCHAR *name); + static TYPE* instance (const ACE_Service_Gestalt* repo, + const ACE_TCHAR *name, bool no_global); + +#if defined (ACE_USES_WCHAR) + + /// Return instance using @a name to search the Service_Repository. + static TYPE* instance (const ACE_ANTI_TCHAR *name); + + static TYPE* instance (const ACE_ANTI_TCHAR *name, bool no_global); + + static TYPE* instance (const ACE_Service_Gestalt* repo, + const ACE_ANTI_TCHAR *name); + static TYPE* instance (const ACE_Service_Gestalt* repo, + const ACE_ANTI_TCHAR *name, bool no_global); +#endif // ACE_USES_WCHAR + +private: + ACE_UNIMPLEMENTED_FUNC (ACE_Dynamic_Service ()) + ACE_UNIMPLEMENTED_FUNC (ACE_Dynamic_Service (const ACE_Dynamic_Service&)) + ACE_UNIMPLEMENTED_FUNC (ACE_Dynamic_Service& operator= (const ACE_Dynamic_Service&)) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Dynamic_Service.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +# include "ace/Dynamic_Service.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +# pragma implementation ("Dynamic_Service.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" + +#endif /* ACE_DYNAMIC_SERVICE_H */ diff --git a/dep/acelite/ace/Dynamic_Service.inl b/dep/acelite/ace/Dynamic_Service.inl new file mode 100644 index 000000000..5ae958d8f --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service.inl @@ -0,0 +1,36 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_USES_WCHAR) + +template ACE_INLINE TYPE * +ACE_Dynamic_Service::instance (const ACE_ANTI_TCHAR *name) +{ + return instance (ACE_TEXT_CHAR_TO_TCHAR (name),false); +} + +template ACE_INLINE TYPE * +ACE_Dynamic_Service::instance (const ACE_ANTI_TCHAR *name, + bool no_global) +{ + return instance (ACE_TEXT_CHAR_TO_TCHAR (name),no_global); +} + +template ACE_INLINE TYPE * +ACE_Dynamic_Service::instance (const ACE_Service_Gestalt* repo, + const ACE_ANTI_TCHAR *name) +{ + return instance (repo, ACE_TEXT_CHAR_TO_TCHAR (name),false); +} + +template ACE_INLINE TYPE * +ACE_Dynamic_Service::instance (const ACE_Service_Gestalt* repo, + const ACE_ANTI_TCHAR *name, + bool no_global) +{ + return instance (repo, ACE_TEXT_CHAR_TO_TCHAR (name),no_global); +} + +#endif // ACE_USES_WCHAR + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Service_Base.cpp b/dep/acelite/ace/Dynamic_Service_Base.cpp new file mode 100644 index 000000000..d38f1a5cd --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service_Base.cpp @@ -0,0 +1,102 @@ +#include "ace/Dynamic_Service_Base.h" +#include "ace/ACE.h" +#include "ace/Service_Config.h" +#include "ace/Service_Repository.h" +#include "ace/Service_Types.h" +#include "ace/Log_Category.h" + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + + +void +ACE_Dynamic_Service_Base::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Dynamic_Service_Base::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Get the instance using for the current global +// service configuration repository. + +void * +ACE_Dynamic_Service_Base::instance (const ACE_TCHAR *name, bool no_global) +{ + ACE_TRACE ("ACE_Dynamic_Service_Base::instance"); + return instance (ACE_Service_Config::current (), name, no_global); +} + +// Find a service registration + +const ACE_Service_Type * +ACE_Dynamic_Service_Base::find_i (const ACE_Service_Gestalt* &repo, + const ACE_TCHAR *name, + bool no_global) +{ + ACE_TRACE ("ACE_Dynamic_Service_Base::find_i"); + const ACE_Service_Type *svc_rec = 0; + + ACE_Service_Gestalt* global = ACE_Service_Config::global (); + + for ( ; (repo->find (name, &svc_rec) == -1) && !no_global; repo = global) + { + // Check the static repo, too if different + if (repo == global) + break; + } + + return svc_rec; +} + + +// Get the instance using for specific configuration repository. +void * +ACE_Dynamic_Service_Base::instance (const ACE_Service_Gestalt* repo, + const ACE_TCHAR *name, + bool no_global) +{ + ACE_TRACE ("ACE_Dynamic_Service_Base::instance"); + + void *obj = 0; + const ACE_Service_Type_Impl *type = 0; + + const ACE_Service_Gestalt* repo_found = repo; + const ACE_Service_Type *svc_rec = find_i (repo_found, name, no_global); + if (svc_rec != 0) + { + type = svc_rec->type (); + if (type != 0) + obj = type->object (); + } + + if (ACE::debug ()) + { + ACE_GUARD_RETURN (ACE_Log_Msg, log_guard, *ACE_Log_Msg::instance (), 0); + + if (repo->repo_ != repo_found->repo_) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DSB::instance, repo=%@, name=%s") + ACE_TEXT (" type=%@ => %@") + ACE_TEXT (" [in repo=%@]\n"), + repo->repo_, name, type, obj, + repo_found->repo_)); + } + else + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) DSB::instance, repo=%@, name=%s") + ACE_TEXT (" type=%@ => %@\n"), + repo->repo_, name, type, obj)); + } + } + + return obj; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Service_Base.h b/dep/acelite/ace/Dynamic_Service_Base.h new file mode 100644 index 000000000..3d4649203 --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service_Base.h @@ -0,0 +1,71 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Dynamic_Service_Base.h + * + * @author Prashant Jain + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_DYNAMIC_SERVICE_BASE_H +#define ACE_DYNAMIC_SERVICE_BASE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Service_Gestalt; +class ACE_Service_Type; + +/** + * @class ACE_Dynamic_Service_Base + * + * @brief Base class for all ACE_Dynamic_Service instantiations. + * + * Factors out common code shared by all ACE_Dynamic_Service + * instantiations, this avoid code bloat. + */ +class ACE_Export ACE_Dynamic_Service_Base +{ +public: + /// Dump the current static of the object + void dump (void) const; + +protected: + /// Perform the default repo search, but optionally skip searching the global + /// repo. + static void* instance (const ACE_TCHAR *name, bool no_global = false); + + static void* instance (const ACE_Service_Gestalt* repo, + const ACE_TCHAR *name, + bool no_global = false); + + /// No need to create, or assign instances of this class + ACE_Dynamic_Service_Base (void); + ~ACE_Dynamic_Service_Base (void); + const ACE_Dynamic_Service_Base& operator= (const ACE_Dynamic_Service_Base&); + +private: + /// Implement the service search policy, i.e. "look for the service first + /// locally and then globally" + static const ACE_Service_Type *find_i (const ACE_Service_Gestalt* &repo, + const ACE_TCHAR *name, + bool no_global); + + /// The dependency declaration class needs access to the service search + /// policy, implemented by find_i() + friend class ACE_Dynamic_Service_Dependency; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_DYNAMIC_SERVICE_BASE_H */ diff --git a/dep/acelite/ace/Dynamic_Service_Dependency.cpp b/dep/acelite/ace/Dynamic_Service_Dependency.cpp new file mode 100644 index 000000000..0a7e9e03d --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service_Dependency.cpp @@ -0,0 +1,45 @@ +#include "ace/ACE.h" +#include "ace/DLL_Manager.h" +#include "ace/Dynamic_Service_Dependency.h" +#include "ace/Service_Config.h" +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Dynamic_Service_Dependency::ACE_Dynamic_Service_Dependency (const ACE_TCHAR *principal) +{ + this->init (ACE_Service_Config::current (), principal); +} + +ACE_Dynamic_Service_Dependency::ACE_Dynamic_Service_Dependency (const ACE_Service_Gestalt *cfg, + const ACE_TCHAR *principal) +{ + this->init (cfg, principal); +} + + +ACE_Dynamic_Service_Dependency::~ACE_Dynamic_Service_Dependency (void) +{ + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) DSD, this=%@ - destroying\n"), + this)); +} + +void +ACE_Dynamic_Service_Dependency::init (const ACE_Service_Gestalt *cfg, + const ACE_TCHAR *principal) +{ + const ACE_Service_Type* st = + ACE_Dynamic_Service_Base::find_i (cfg, principal,false); + if (ACE::debug ()) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) DSD, this=%@ - creating dependency on "), this)); + st->dump (); + } + this->tracker_ = st->dll (); +} + + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Dynamic_Service_Dependency.h b/dep/acelite/ace/Dynamic_Service_Dependency.h new file mode 100644 index 000000000..bb5294f40 --- /dev/null +++ b/dep/acelite/ace/Dynamic_Service_Dependency.h @@ -0,0 +1,68 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Dynamic_Service_Dependency.h + * + * @author Iliyan Jeliazkov + */ +//============================================================================= + +#ifndef ACE_DYNAMIC_SERVICE_DEPENDENCY_H +#define ACE_DYNAMIC_SERVICE_DEPENDENCY_H + +#include /**/ "ace/pre.h" + + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Dynamic_Service_Base.h" +#include "ace/Service_Object.h" +#include "ace/DLL.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Dynamic_Service_Dependency + * + * @brief Provides a way to declare dependency on specific service, + * thus helping to avoid order of initialization issues with instances + * of an objects whose implementation code resides in dynamically loaded + * services. + * + * It is disastrous to have dynamically loadable services create and give away + * ownership of objects and then ending up being unloaded before all those + * instances have been deleted. Normally the code for such objects classes + * resides within the TEXT segment of the DLL, which implements the service. + * If a service gets removed, its DLL may be unmapped from memory and then + * any attempt to invoke a method on the said objects will cause SEGV. + * + * Such instances must contain a member of ACE_Dynamic_Service_Dependency + * initialized with the service they depend on. + * ACE_Dynamic_Service_Dependency's constructor and destructor are + * "magical" - they work by maintaining the underlying dynamic service's + * DLL reference count. + */ +class ACE_Export ACE_Dynamic_Service_Dependency +{ +public: + ACE_Dynamic_Service_Dependency (const ACE_Service_Gestalt *cfg, + const ACE_TCHAR *principal); + ACE_Dynamic_Service_Dependency (const ACE_TCHAR *principal); + ~ACE_Dynamic_Service_Dependency (void); + +private: + void init (const ACE_Service_Gestalt *cfg, const ACE_TCHAR *principal); + +private: + ACE_DLL tracker_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + + +#include /**/ "ace/post.h" + +#endif /* ACE_DYNAMIC_SERVICE_DEPENDENCY_H */ diff --git a/dep/acelite/ace/Encoding_Converter.cpp b/dep/acelite/ace/Encoding_Converter.cpp new file mode 100644 index 000000000..29a3a1d18 --- /dev/null +++ b/dep/acelite/ace/Encoding_Converter.cpp @@ -0,0 +1,11 @@ +#include "ace/Encoding_Converter.h" + +#if defined (ACE_USES_WCHAR) +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Encoding_Converter::~ACE_Encoding_Converter (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* ACE_USES_WCHAR */ diff --git a/dep/acelite/ace/Encoding_Converter.h b/dep/acelite/ace/Encoding_Converter.h new file mode 100644 index 000000000..c430e8f93 --- /dev/null +++ b/dep/acelite/ace/Encoding_Converter.h @@ -0,0 +1,68 @@ +// -*- C++ -*- + +//========================================================================= +/** + * @file Encoding_Converter.h + * + * This class is the base class for all encoding converters that convert + * to and from UTF-8. + * + * @author Chad Elliott + */ +//========================================================================= + +#ifndef ACE_ENCODING_CONVERTER_H +#define ACE_ENCODING_CONVERTER_H + +#include /**/ "ace/pre.h" + +#include "ace/Basic_Types.h" + +#if defined (ACE_USES_WCHAR) +#include /**/ "ace/ACE_export.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** The base class for all ACE UTF Encoding Converters. + * This class provides a generic interface that is used to implement + * various UTF encoding conversion classes. + */ +class ACE_Export ACE_Encoding_Converter +{ +public: + /// This enum describes the various states that can be returned + /// from the to_utf8() and from_utf8() methods which depends on + /// both the source buffer and the size of the target buffer. + enum Result {CONVERSION_OK, + SOURCE_EXHAUSTED, + TARGET_EXHAUSTED, + SOURCE_ILLEGAL + }; + + /// This destructor is here (and virtual) because we have virtual + /// functions. + virtual ~ACE_Encoding_Converter (void); + + /// Convert the source (which can be in any encoding) to UTF-8 and + /// store it in the provided target buffer. + virtual Result to_utf8 (const void* source, + size_t source_size, + ACE_Byte* target, + size_t target_size, + bool strict = true) = 0; + + /// Convert the UTF-8 source into an alternate encoding and store it + /// in the provided target buffer. + virtual Result from_utf8 (const ACE_Byte* source, + size_t source_size, + void* target, + size_t target_size, + bool strict = true) = 0; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* ACE_USES_WCHAR */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ENCODING_CONVERTER_H */ diff --git a/dep/acelite/ace/Encoding_Converter_Factory.cpp b/dep/acelite/ace/Encoding_Converter_Factory.cpp new file mode 100644 index 000000000..85f139fc1 --- /dev/null +++ b/dep/acelite/ace/Encoding_Converter_Factory.cpp @@ -0,0 +1,73 @@ +#include "ace/Encoding_Converter_Factory.h" + +#if defined (ACE_USES_WCHAR) +#include "ace/UTF32_Encoding_Converter.h" +#include "ace/UTF16_Encoding_Converter.h" +#include "ace/UTF8_Encoding_Converter.h" +#include "ace/OS_Memory.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Encoding_Converter* +ACE_Encoding_Converter_Factory::create ( + const ACE_Byte* source, + size_t source_size, + ACE_Encoding_Converter_Factory::Encoding_Hint hint) +{ +#if defined (ACE_BIG_ENDIAN) + bool const convert_for_bigendian = true; +#else + bool const convert_for_bigendian = false; +#endif /* ACE_BIG_ENDIAN */ + ACE_Encoding_Converter* converter = 0; + + switch (hint) + { + case ACE_UTF_32BE: + ACE_NEW_RETURN (converter, + ACE_UTF32_Encoding_Converter (!convert_for_bigendian), + 0); + break; + case ACE_UTF_32LE: + ACE_NEW_RETURN (converter, + ACE_UTF32_Encoding_Converter (convert_for_bigendian), + 0); + break; + case ACE_UTF_16BE: + ACE_NEW_RETURN (converter, + ACE_UTF16_Encoding_Converter (!convert_for_bigendian), + 0); + break; + case ACE_UTF_16LE: + ACE_NEW_RETURN (converter, + ACE_UTF16_Encoding_Converter (convert_for_bigendian), + 0); + break; + case ACE_UTF_8: + ACE_NEW_RETURN (converter, + ACE_UTF8_Encoding_Converter, + 0); + break; + default: + // First check for ASCII since much of ASCII text will appear to + // convert from UTF-16 to UTF-8. + converter = ACE_UTF8_Encoding_Converter::encoded (source, source_size); + if (converter != 0) + return converter; + + // Check for UTF-32 + converter = ACE_UTF32_Encoding_Converter::encoded (source, source_size); + if (converter != 0) + return converter; + + // Check for UTF-16 + converter = ACE_UTF16_Encoding_Converter::encoded (source, source_size); + if (converter != 0) + return converter; + } + + return converter; +} + +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* ACE_USES_WCHAR */ diff --git a/dep/acelite/ace/Encoding_Converter_Factory.h b/dep/acelite/ace/Encoding_Converter_Factory.h new file mode 100644 index 000000000..1a871a4cc --- /dev/null +++ b/dep/acelite/ace/Encoding_Converter_Factory.h @@ -0,0 +1,52 @@ +// -*- C++ -*- + +//========================================================================= +/** + * @file Encoding_Converter_Factory.h + * + * This class can be used to create encoding converters of various types. + * + * @author Chad Elliott + */ +//========================================================================= + +#ifndef ACE_ENCODING_CONVERTER_FACTORY_H +#define ACE_ENCODING_CONVERTER_FACTORY_H + +#include /**/ "ace/pre.h" + +#include "ace/Basic_Types.h" + +#if defined (ACE_USES_WCHAR) +#include /**/ "ace/ACE_export.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Encoding_Converter; + +/** Create an encoding converter based on the source or hint. + * This class allows users to avoid knowing any concrete converter types. + */ +class ACE_Export ACE_Encoding_Converter_Factory +{ +public: + /// This enum is used to tell what type of converter to create. + enum Encoding_Hint { ACE_UTF_32BE, ACE_UTF_32LE, + ACE_UTF_16BE, ACE_UTF_16LE, + ACE_UTF_8, ACE_NONE + }; + + /// Create an encoding converter based on the source. If a hint is + /// given, it just creates the specified type of converter without looking + /// at the source. + static ACE_Encoding_Converter* create (const ACE_Byte* source, + size_t source_size, + Encoding_Hint hint = ACE_NONE); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* ACE_USES_WCHAR */ + +#include /**/ "ace/post.h" + +#endif /* ACE_ENCODING_CONVERTER_FACTORY_H */ diff --git a/dep/acelite/ace/Env_Value_T.cpp b/dep/acelite/ace/Env_Value_T.cpp new file mode 100644 index 000000000..a63e76844 --- /dev/null +++ b/dep/acelite/ace/Env_Value_T.cpp @@ -0,0 +1,10 @@ +#ifndef ACE_ENV_VALUE_T_CPP +#define ACE_ENV_VALUE_T_CPP + +#include "ace/Env_Value_T.h" + +#if ! defined (__ACE_INLINE__) +#include "ace/Env_Value_T.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* ACE_ENV_VALUE_T_CPP */ diff --git a/dep/acelite/ace/Env_Value_T.h b/dep/acelite/ace/Env_Value_T.h new file mode 100644 index 000000000..4e268d3f9 --- /dev/null +++ b/dep/acelite/ace/Env_Value_T.h @@ -0,0 +1,159 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Env_Value_T.h + * + * Template to encapsulate getting a value from an environment variable + * and using a supplied default value if not in the environment. + * + * @author Chris Cleeland (derived from work by Carlos O'Ryan) + */ +//============================================================================= + +#ifndef ACE_ENV_VALUE_T_H +#define ACE_ENV_VALUE_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Global_Macros.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/Copy_Disabled.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Env_Value + * + * @brief Environment Variable Value + * + * Reads a variable from the user environment, providing a default + * value. + */ +template +class ACE_Env_Value : private ACE_Copy_Disabled +{ +public: + /** + * Default constructor which isn't bound to a specific environment + * variable name or a default value. Before being useful it must + * open()'d. + */ + ACE_Env_Value (void); + + /// Constructor that calls open(). + ACE_Env_Value (const ACE_TCHAR *varname, const T &vardefault); + + /// Destroy the value. + ~ACE_Env_Value (void); + + /// Returns the value as type T. + operator T (void); + + /// The constructor, read @a varname from the environment, using + /// @a defval as its value if it is not defined. + void open (const ACE_TCHAR *varname, const T &defval); + + /// Returns the name of the variable being tracked. + const ACE_TCHAR *varname (void) const; + +private: + void fetch_value (void); + + const ACE_TCHAR *varname_; + T value_; +}; + +/// Function to convert a string @a s into type @c T. +template void ACE_Convert (const ACE_TCHAR *s, T &t); + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Env_Value_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Env_Value_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, ACE_TCHAR *&v) +{ + v = (ACE_TCHAR *) s; +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, const ACE_TCHAR *&v) +{ + v = (const ACE_TCHAR *) s; +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, short &si) +{ + si = static_cast (ACE_OS::strtol (s, 0, 10)); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, u_short &us) +{ + us = static_cast (ACE_OS::strtol (s, 0, 10)); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, u_int &i) +{ + i = static_cast (ACE_OS::strtol (s, 0, 10)); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, long &l) +{ + l = ACE_OS::strtol (s, 0, 10); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, int &i) +{ + i = static_cast (ACE_OS::strtol (s, 0, 10)); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, u_long &ul) +{ + ul = ACE_OS::strtoul (s, 0, 10); +} + +template <> inline void +ACE_Convert (const ACE_TCHAR *s, double &d) +{ + d = ACE_OS::strtod (s, 0); +} + +// Default calls a CTOR on type T of the form 'T::T(const char*)', but +// users can feel free to create their own specialized conversion +// functions if necessary, as shown above. Note that for 'char*' the +// default is used because a simple cast will be performed and no +// conversion will be necessary. +template inline void +ACE_Convert (const ACE_TCHAR *s, T &t) +{ + t = T (s); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Env_Value_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_ENV_VALUE_T_H */ diff --git a/dep/acelite/ace/Env_Value_T.inl b/dep/acelite/ace/Env_Value_T.inl new file mode 100644 index 000000000..1fc1b863f --- /dev/null +++ b/dep/acelite/ace/Env_Value_T.inl @@ -0,0 +1,58 @@ +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_Env_Value::operator T (void) +{ + return value_; +} + +template ACE_INLINE +ACE_Env_Value::ACE_Env_Value (void) + : varname_ (0) +{ +} + +template ACE_INLINE +ACE_Env_Value::ACE_Env_Value (const ACE_TCHAR *varname, + const T &defval) + : varname_ (varname), + value_(defval) +{ + this->fetch_value (); +} + +template ACE_INLINE void +ACE_Env_Value::open (const ACE_TCHAR *varname, + const T &defval) +{ + this->varname_ = varname; + this->value_ = defval; + this->fetch_value (); +} + +template ACE_INLINE void +ACE_Env_Value::fetch_value (void) +{ +#if defined (ACE_WIN32) + const ACE_TCHAR *env = ACE_OS::getenv (this->varname_); + if (env != 0) + ACE_Convert (env, value_); +#else + char *nenv = ACE_OS::getenv (ACE_TEXT_ALWAYS_CHAR (this->varname_)); + if (nenv != 0) + ACE_Convert (ACE_TEXT_CHAR_TO_TCHAR (nenv), this->value_); +#endif +} + +template ACE_INLINE const ACE_TCHAR* +ACE_Env_Value::varname (void) const +{ + return this->varname_; +} + +template ACE_INLINE +ACE_Env_Value::~ACE_Env_Value (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event.cpp b/dep/acelite/ace/Event.cpp new file mode 100644 index 000000000..20fe07306 --- /dev/null +++ b/dep/acelite/ace/Event.cpp @@ -0,0 +1,45 @@ +#include "ace/Event.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Event.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/Condition_Attributes.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Event_T) + +template +ACE_Event_T::ACE_Event_T (int manual_reset, + int initial_state, + int type, + const ACE_TCHAR *name, + void *arg, + LPSECURITY_ATTRIBUTES sa) + : ACE_Event_Base () +{ + ACE_Condition_Attributes_T cond_attr (type); + if (ACE_OS::event_init (&this->handle_, + type, + &const_cast (cond_attr.attributes ()), + manual_reset, + initial_state, + name, + arg, + sa) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Event_T::ACE_Event_T"))); +} + +template +ACE_Event_T::~ACE_Event_T (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event.h b/dep/acelite/ace/Event.h new file mode 100644 index 000000000..e8c9db91f --- /dev/null +++ b/dep/acelite/ace/Event.h @@ -0,0 +1,93 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Event.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_EVENT_H +#define ACE_EVENT_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event_Base.h" +#include "ace/Time_Policy.h" +#include "ace/Time_Value_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Event_T + * + * @brief A wrapper around the Win32 event locking mechanism. + * + * Portable implementation of an Event mechanism, which is native to + * Win32, but must be emulated on UNIX. All platforms support + * process-scope locking support. However, only Win32 platforms + * support global naming and system-scope locking support. + */ +template +class ACE_Event_T : public ACE_Event_Base +{ +public: + /// Constructor that creates event. + ACE_Event_T (int manual_reset = 0, + int initial_state = 0, + int type = USYNC_THREAD, + const ACE_TCHAR *name = 0, + void *arg = 0, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Implicitly destroy the event variable. + virtual ~ACE_Event_T (void); + + /// Get the current time of day according to the queue's TIME_POLICY. + /// Allows users to initialize timeout values using correct time policy. + ACE_Time_Value_T gettimeofday (void) const; + + /// Allows applications to control how the event gets the time + /// of day. + void set_time_policy (TIME_POLICY const & time_policy); + + /// Declare the dynamic allocation hooks + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// The policy to return the current time of day + TIME_POLICY time_policy_; + +private: + // = Prevent copying. + ACE_Event_T (const ACE_Event_T& event); + const ACE_Event_T &operator= (const ACE_Event_T &rhs); +}; + +typedef ACE_Event_T ACE_Event; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Event.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Event.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Event.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_EVENT_H */ diff --git a/dep/acelite/ace/Event.inl b/dep/acelite/ace/Event.inl new file mode 100644 index 000000000..b8a688be7 --- /dev/null +++ b/dep/acelite/ace/Event.inl @@ -0,0 +1,18 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Time_Value_T +ACE_Event_T::gettimeofday (void) const +{ + return this->time_policy_ (); +} + +template +void +ACE_Event_T::set_time_policy (TIME_POLICY const & rhs) +{ + this->time_policy_ = rhs; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Base.cpp b/dep/acelite/ace/Event_Base.cpp new file mode 100644 index 000000000..3ec4ea02b --- /dev/null +++ b/dep/acelite/ace/Event_Base.cpp @@ -0,0 +1,79 @@ +#include "ace/Event_Base.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Event_Base.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Event_Base) + +ACE_Event_Base::ACE_Event_Base () + : removed_ (false) +{ +} + +ACE_Event_Base::~ACE_Event_Base (void) +{ + this->remove (); +} + +int +ACE_Event_Base::remove (void) +{ + int result = 0; + if (!this->removed_) + { + this->removed_ = true; + result = ACE_OS::event_destroy (&this->handle_); + } + return result; +} + +int +ACE_Event_Base::wait (void) +{ + return ACE_OS::event_wait (&this->handle_); +} + +int +ACE_Event_Base::wait (const ACE_Time_Value *abstime, int use_absolute_time) +{ + return ACE_OS::event_timedwait (&this->handle_, + const_cast (abstime), + use_absolute_time); +} + +int +ACE_Event_Base::signal (void) +{ + return ACE_OS::event_signal (&this->handle_); +} + +int +ACE_Event_Base::pulse (void) +{ + return ACE_OS::event_pulse (&this->handle_); +} + +int +ACE_Event_Base::reset (void) +{ + return ACE_OS::event_reset (&this->handle_); +} + +void +ACE_Event_Base::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Base.h b/dep/acelite/ace/Event_Base.h new file mode 100644 index 000000000..a158c5e67 --- /dev/null +++ b/dep/acelite/ace/Event_Base.h @@ -0,0 +1,139 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Event_Base.h + * + * Moved from Synch.h. + * + * @author Martin Corino + */ +//========================================================================== + +#ifndef ACE_EVENT_BASE_H +#define ACE_EVENT_BASE_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_Thread.h" +#include "ace/Time_Value.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Event_Base + * + * @brief A base class for wrappers around the Win32 event locking + * mechanism. + * + * Portable implementation of an Event mechanism, which is native to + * Win32, but must be emulated on UNIX. All platforms support + * process-scope locking support. However, only Win32 platforms + * support global naming and system-scope locking support. + */ +class ACE_Export ACE_Event_Base +{ +public: + /// Implicitly destroy the event variable. + virtual ~ACE_Event_Base (void); + + /** + * Explicitly destroy the event variable. Note that only one thread + * should call this method since it doesn't protect against race + * conditions. + */ + int remove (void); + + /// Underlying handle to event. + ACE_event_t handle (void) const; + + /** + * Set the underlying handle to event. Note that this method assumes + * ownership of the and will close it down in . If + * you want the to stay open when is called make + * sure to call on the before closing it. You are + * responsible for the closing the existing before + * overwriting it. + */ + void handle (ACE_event_t new_handle); + + /** + * if MANUAL reset + * sleep till the event becomes signaled + * event remains signaled after wait() completes. + * else AUTO reset + * sleep till the event becomes signaled + * event resets wait() completes. + */ + int wait (void); + + /// Same as wait() above, but this one can be timed + /// @a abstime is absolute time-of-day if if @a use_absolute_time + /// is non-0, else it is relative time. + int wait (const ACE_Time_Value *abstime, + int use_absolute_time = 1); + + /** + * if MANUAL reset + * wake up all waiting threads + * set to signaled state + * else AUTO reset + * if no thread is waiting, set to signaled state + * if thread(s) are waiting, wake up one waiting thread and + * reset event + */ + int signal (void); + + /** + * if MANUAL reset + * wakeup all waiting threads and + * reset event + * else AUTO reset + * wakeup one waiting thread (if present) and + * reset event + */ + int pulse (void); + + /// Set to nonsignaled state. + int reset (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Only derived classes allowed to construct event. + ACE_Event_Base (); + + + /// The underlying handle. + ACE_event_t handle_; + + /// Keeps track of whether has been called yet to avoid + /// multiple calls, e.g., explicitly and implicitly in the + /// destructor. This flag isn't protected by a lock, so make sure + /// that you don't have multiple threads simultaneously calling + /// on the same object, which is a bad idea anyway... + bool removed_; + +private: + // = Prevent copying. + ACE_Event_Base (const ACE_Event_Base& event); + const ACE_Event_Base &operator= (const ACE_Event_Base &rhs); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Event_Base.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_EVENT_BASE_H */ diff --git a/dep/acelite/ace/Event_Base.inl b/dep/acelite/ace/Event_Base.inl new file mode 100644 index 000000000..fa8cf909e --- /dev/null +++ b/dep/acelite/ace/Event_Base.inl @@ -0,0 +1,16 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ACE_event_t +ACE_Event_Base::handle (void) const +{ + return this->handle_; +} + +ACE_INLINE void +ACE_Event_Base::handle (ACE_event_t new_handle) +{ + this->handle_ = new_handle; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Handler.cpp b/dep/acelite/ace/Event_Handler.cpp new file mode 100644 index 000000000..82e6879be --- /dev/null +++ b/dep/acelite/ace/Event_Handler.cpp @@ -0,0 +1,410 @@ +// Event_Handler.cpp +#include "ace/Event_Handler.h" +#include "ace/OS_Errno.h" +#include "ace/Reactor.h" +#include "ace/Thread_Manager.h" +/* Need to see if ACE_HAS_BUILTIN_ATOMIC_OP defined */ +#include "ace/Atomic_Op.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Event_Handler.inl" +#endif /* __ACE_INLINE__ */ + +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Implement conceptually abstract virtual functions in the base class +// so derived classes don't have to implement unused ones. + +ACE_Event_Handler::ACE_Event_Handler (ACE_Reactor *r, + int p) + : reference_count_ (1), + priority_ (p), + reactor_ (r), + reference_counting_policy_ (Reference_Counting_Policy::DISABLED) +{ + // ACE_TRACE ("ACE_Event_Handler::ACE_Event_Handler"); +} + +ACE_Event_Handler::~ACE_Event_Handler (void) +{ + // ACE_TRACE ("ACE_Event_Handler::~ACE_Event_Handler"); +} + +// Gets the file descriptor associated with this I/O device. + +ACE_HANDLE +ACE_Event_Handler::get_handle (void) const +{ + ACE_TRACE ("ACE_Event_Handler::get_handle"); + return ACE_INVALID_HANDLE; +} + +// Sets the file descriptor associated with this I/O device. + +void +ACE_Event_Handler::set_handle (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::set_handle"); +} + +// Gets the priority of this handler. + +int +ACE_Event_Handler::priority (void) const +{ + ACE_TRACE ("ACE_Event_Handler::priority"); + return this->priority_; +} + +// Sets the priority + +void +ACE_Event_Handler::priority (int priority) +{ + ACE_TRACE ("ACE_Event_Handler::priority"); + this->priority_ = priority; +} + +// Called when the object is about to be removed from the Dispatcher +// tables. + +int +ACE_Event_Handler::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_TRACE ("ACE_Event_Handler::handle_close"); + return -1; +} + +// Called when input becomes available on fd. + +int +ACE_Event_Handler::handle_input (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::handle_input"); + return -1; +} + +// Called when output is possible on fd. + +int +ACE_Event_Handler::handle_output (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::handle_output"); + return -1; +} + +// Called when urgent data is available on fd. + +int +ACE_Event_Handler::handle_exception (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::handle_exception"); + return -1; +} + +// Called when timer expires, TV stores the current time. + +int +ACE_Event_Handler::handle_timeout (const ACE_Time_Value &, const void *) +{ + ACE_TRACE ("ACE_Event_Handler::handle_timeout"); + return -1; +} + +// Called when a monitored Process exits + +int +ACE_Event_Handler::handle_exit (ACE_Process *) +{ + ACE_TRACE ("ACE_Event_Handler::handle_exit"); + return -1; +} + +// Called when a registered signal occurs. + +int +ACE_Event_Handler::handle_signal (int, siginfo_t *, ucontext_t *) +{ + ACE_TRACE ("ACE_Event_Handler::handle_signal"); + return -1; +} + +int +ACE_Event_Handler::resume_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler::resume_handler"); + + // Return a default value and allow the reactor to take care of + // resuming the handler + return ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER; +} + + +int +ACE_Event_Handler::handle_qos (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::handle_qos"); + return -1; +} + +int +ACE_Event_Handler::handle_group_qos (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Event_Handler::handle_group_qos"); + return -1; +} + +void +ACE_Event_Handler::reactor (ACE_Reactor *reactor) +{ + ACE_TRACE ("ACE_Event_Handler::reactor"); + this->reactor_ = reactor; +} + +ACE_Reactor * +ACE_Event_Handler::reactor (void) const +{ + ACE_TRACE ("ACE_Event_Handler::reactor"); + return this->reactor_; +} + +ACE_Reactor_Timer_Interface * +ACE_Event_Handler::reactor_timer_interface (void) const +{ + ACE_TRACE ("ACE_Event_Handler::reactor_timer_interface"); + return this->reactor_; +} + +ACE_Event_Handler::Reference_Count +ACE_Event_Handler::add_reference (void) +{ + bool const reference_counting_required = + this->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + if (reference_counting_required) + return ++this->reference_count_; + else + return 1; +} + +ACE_Event_Handler::Reference_Count +ACE_Event_Handler::remove_reference (void) +{ + bool const reference_counting_required = + this->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + if (reference_counting_required) + { + Reference_Count result = + --this->reference_count_; + + if (result == 0) + delete this; + + return result; + } + else + { + return 1; + } +} + +ACE_Event_Handler::Policy::~Policy (void) +{ +} + +ACE_Event_Handler::Reference_Counting_Policy::Reference_Counting_Policy (Reference_Counting_Policy::Value value) + : value_ (value) +{ +} + +ACE_Event_Handler::Reference_Counting_Policy::Value +ACE_Event_Handler::Reference_Counting_Policy::value (void) const +{ + return this->value_; +} + +void +ACE_Event_Handler::Reference_Counting_Policy::value (ACE_Event_Handler::Reference_Counting_Policy::Value value) +{ + this->value_ = value; +} + +ACE_Event_Handler::Reference_Counting_Policy & +ACE_Event_Handler::reference_counting_policy (void) +{ + return this->reference_counting_policy_; +} + +ACE_THR_FUNC_RETURN +ACE_Event_Handler::read_adapter (void *args) +{ + ACE_Event_Handler *this_ptr = static_cast (args); + ACE_Reactor *r = this_ptr->reactor (); + + while (this_ptr->handle_input (ACE_STDIN) != -1) + continue; + + this_ptr->handle_close (ACE_STDIN, ACE_Event_Handler::READ_MASK); + // It's possible for handle_close() to "delete this" so we need to + // cache the reactor pointer and use it here. + r->notify (); + + return 0; +} + +int +ACE_Event_Handler::register_stdin_handler (ACE_Event_Handler *eh, + ACE_Reactor *reactor, + ACE_Thread_Manager *thr_mgr, + int flags) +{ +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (reactor); + + eh->reactor (reactor); + return thr_mgr->spawn (&read_adapter, static_cast (eh), flags); +#else + // Keep compilers happy. + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (thr_mgr); + return reactor->register_handler (ACE_STDIN, + eh, + ACE_Event_Handler::READ_MASK); +#endif /* ACE_WIN32 */ +} + +int +ACE_Event_Handler::remove_stdin_handler (ACE_Reactor *reactor, + ACE_Thread_Manager * /* thr_mgr */) +{ +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (reactor); + + // What should we do here? + ACE_NOTSUP_RETURN (-1); +#else + return reactor->remove_handler (ACE_STDIN, + ACE_Event_Handler::READ_MASK); +#endif /* ACE_WIN32 */ +} + +// --------------------------------------------------------------------- + +ACE_Event_Handler_var::ACE_Event_Handler_var (void) + : ptr_ (0) +{ +} + +ACE_Event_Handler_var::ACE_Event_Handler_var (ACE_Event_Handler *p) + : ptr_ (p) +{ +} + +ACE_Event_Handler_var::ACE_Event_Handler_var (const ACE_Event_Handler_var &b) + : ptr_ (b.ptr_) +{ + if (this->ptr_ != 0) + { + this->ptr_->add_reference (); + } +} + +ACE_Event_Handler_var::~ACE_Event_Handler_var (void) +{ + if (this->ptr_ != 0) + { + ACE_Errno_Guard eguard (errno); + this->ptr_->remove_reference (); + } +} + +ACE_Event_Handler_var & +ACE_Event_Handler_var::operator= (ACE_Event_Handler *p) +{ + if (this->ptr_ != p) + { + ACE_Event_Handler_var tmp (p); + std::swap (this->ptr_, tmp.ptr_); + } + + return *this; +} + +ACE_Event_Handler_var & +ACE_Event_Handler_var::operator= (const ACE_Event_Handler_var &b) +{ + ACE_Event_Handler_var tmp (b); + std::swap (this->ptr_, tmp.ptr_); + + return *this; +} + +ACE_Event_Handler * +ACE_Event_Handler_var::operator->() const +{ + return this->ptr_; +} + +ACE_Event_Handler * +ACE_Event_Handler_var::handler (void) const +{ + return this->ptr_; +} + +ACE_Event_Handler * +ACE_Event_Handler_var::release (void) +{ + ACE_Event_Handler * const old = this->ptr_; + this->ptr_ = 0; + return old; +} + +void +ACE_Event_Handler_var::reset (ACE_Event_Handler *p) +{ + *this = p; +} + +#if defined (ACE_HAS_CPP11) +ACE_Event_Handler_var::operator bool() const +{ + return this->ptr_ == nullptr ? false : true; +} + +bool +ACE_Event_Handler_var::operator ==(std::nullptr_t) const +{ + return this->ptr_ == nullptr ? true : false; +} + +bool +ACE_Event_Handler_var::operator !=(std::nullptr_t) const +{ + return this->ptr_ == nullptr ? false : true; + +} +#endif /* ACE_HAS_CPP11 */ + +// --------------------------------------------------------------------- + +ACE_Notification_Buffer::ACE_Notification_Buffer (void) + : eh_ (0), + mask_ (ACE_Event_Handler::NULL_MASK) +{ + ACE_TRACE ("ACE_Notification_Buffer::ACE_Notification_Buffer"); +} + +ACE_Notification_Buffer::ACE_Notification_Buffer (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) + : eh_ (eh), + mask_ (mask) +{ + ACE_TRACE ("ACE_Notification_Buffer::ACE_Notification_Buffer"); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Handler.h b/dep/acelite/ace/Event_Handler.h new file mode 100644 index 000000000..caf5068a0 --- /dev/null +++ b/dep/acelite/ace/Event_Handler.h @@ -0,0 +1,426 @@ +/* -*- C++ -*- */ + +//========================================================================== +/** + * @file Event_Handler.h + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_EVENT_HANDLER_H +#define ACE_EVENT_HANDLER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/os_signal.h" +#include "ace/Atomic_Op.h" +#include "ace/OS_NS_Thread.h" +#include "ace/Synch_Traits.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declaration. +class ACE_Message_Block; +class ACE_Reactor; +class ACE_Reactor_Timer_Interface; +class ACE_Thread_Manager; +class ACE_Process; + +typedef unsigned long ACE_Reactor_Mask; + +/** + * @class ACE_Event_Handler + * + * @brief + * Provides an abstract interface for handling various types of + * I/O, timer, and signal events. + * + * Subclasses read/write input/output on an I/O descriptor, + * handle an exception raised on an I/O descriptor, handle a + * timer's expiration, or handle a signal. + */ +class ACE_Export ACE_Event_Handler +{ +public: + enum + { + LO_PRIORITY = 0, + HI_PRIORITY = 10, + NULL_MASK = 0, +#if defined (ACE_USE_POLL) + READ_MASK = POLLIN, + WRITE_MASK = POLLOUT, + EXCEPT_MASK = POLLPRI, +#else /* USE SELECT */ + READ_MASK = (1 << 0), + WRITE_MASK = (1 << 1), + EXCEPT_MASK = (1 << 2), +#endif /* ACE_USE_POLL */ + ACCEPT_MASK = (1 << 3), + CONNECT_MASK = (1 << 4), + TIMER_MASK = (1 << 5), + QOS_MASK = (1 << 6), + GROUP_QOS_MASK = (1 << 7), + SIGNAL_MASK = (1 << 8), + ALL_EVENTS_MASK = READ_MASK | + WRITE_MASK | + EXCEPT_MASK | + ACCEPT_MASK | + CONNECT_MASK | + TIMER_MASK | + QOS_MASK | + GROUP_QOS_MASK | + SIGNAL_MASK, + RWE_MASK = READ_MASK | + WRITE_MASK | + EXCEPT_MASK, + DONT_CALL = (1 << 9) + }; + + /// Destructor is virtual to enable proper cleanup. + virtual ~ACE_Event_Handler (void); + + /// Get the I/O handle. + virtual ACE_HANDLE get_handle (void) const; + + /// Set the I/O handle. + virtual void set_handle (ACE_HANDLE); + + // = Get/set priority + + /// Get the priority of the Event_Handler. + /// @note Priorities run from MIN_PRIORITY (which is the "lowest priority") + /// to MAX_PRIORITY (which is the "highest priority"). + virtual int priority (void) const; + + /// Set the priority of the Event_Handler. + virtual void priority (int priority); + + /// Called when input events occur (e.g., connection or data). + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + /// Called when output events are possible (e.g., when flow control + /// abates or non-blocking connection completes). + virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + /// Called when an exceptional events occur (e.g., SIGURG). + virtual int handle_exception (ACE_HANDLE fd = ACE_INVALID_HANDLE); + + /** + * Called when timer expires. @a current_time represents the current + * time that the Event_Handler was selected for timeout + * dispatching and @a act is the asynchronous completion token that + * was passed in when was invoked. + */ + virtual int handle_timeout (const ACE_Time_Value ¤t_time, + const void *act = 0); + + /// Called when a process exits. + virtual int handle_exit (ACE_Process *); + + /// Called when a handle_*() method returns -1 or when the + /// remove_handler() method is called on an ACE_Reactor. The + /// @a close_mask indicates which event has triggered the + /// handle_close() method callback on a particular @a handle. + virtual int handle_close (ACE_HANDLE handle, + ACE_Reactor_Mask close_mask); + + /// Called when object is signaled by OS (either via UNIX signals or + /// when a Win32 object becomes signaled). + virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + + enum + { + /// The handler is not resumed at all. Could lead to deadlock.. + ACE_EVENT_HANDLER_NOT_RESUMED = -1, + /// The reactor takes responsibility of resuming the handler and + /// is the default + ACE_REACTOR_RESUMES_HANDLER = 0, + /// The application takes responsibility of resuming the handler + ACE_APPLICATION_RESUMES_HANDLER + }; + + /** + * Called to figure out whether the handler needs to resumed by the + * reactor or the application can take care of it. The default + * value of 0 would be returned which would allow the reactor to + * take care of resumption of the handler. The application can + * return a value more than zero and decide to resume the handler + * themselves. + * + * @note This method has an affect only when used with the + * ACE_Dev_Poll_Reactor (and then, only on Linux) or the ACE_TP_Reactor. + */ + virtual int resume_handler (void); + + virtual int handle_qos (ACE_HANDLE = ACE_INVALID_HANDLE); + virtual int handle_group_qos (ACE_HANDLE = ACE_INVALID_HANDLE); + + // = Accessors to set/get the various event demultiplexors. + /// Set the event demultiplexors. + virtual void reactor (ACE_Reactor *reactor); + + /// Get the event demultiplexors. + virtual ACE_Reactor *reactor (void) const; + + /// Get only the reactor's timer related interface. + virtual ACE_Reactor_Timer_Interface *reactor_timer_interface (void) const; + + /** + * Used to read from non-socket ACE_HANDLEs in our own thread to + * work around Win32 limitations that don't allow us to 'able on + * Win32. + */ + static int register_stdin_handler (ACE_Event_Handler *eh, + ACE_Reactor *reactor, + ACE_Thread_Manager *thr_mgr, + int flags = THR_DETACHED); + + /// Performs the inverse of the register_stdin_handler() method. + static int remove_stdin_handler (ACE_Reactor *reactor, + ACE_Thread_Manager *thr_mgr); + + /// Reference count type. + typedef long Reference_Count; + + /// Increment reference count on the handler. + /** + * This method is called when the handler is registered with the + * Reactor and when the Reactor makes an upcall on the handler. + * Reference count is 1 when the handler is created. + * + * @return Current reference count. + */ + virtual Reference_Count add_reference (void); + + /// Decrement reference count on the handler. + /** + * This method is called when the handler is removed from the + * Reactor and when an upcall made on the handler by the Reactor + * completes. Handler is deleted when the reference count reaches + * 0. + * + * @return Current reference count. + */ + virtual Reference_Count remove_reference (void); + + /** + * @class Policy + * + * @brief Base class for all handler policies. + */ + class ACE_Export Policy + { + + public: + + /// Virtual destructor. + virtual ~Policy (void); + }; + + /** + * @class Reference_Counting_Policy + * + * @brief + * This policy dictates the reference counting requirements + * for the handler. + * + * This policy allows applications to configure whether it wants the + * Reactor to call add_reference() and remove_reference() during + * registrations, removals, and upcalls. + * + * Default: DISABLED. + */ + class ACE_Export Reference_Counting_Policy : public Policy + { + /// This policy can only be created by the handler. + friend class ACE_Event_Handler; + + public: + + enum Value + { + /// Perform reference counting. + ENABLED, + /// Don't perform reference counting. + DISABLED + }; + + /// Current Reference_Counting_Policy. + Value value (void) const; + + /// Update Reference_Counting_Policy. + void value (Value value); + + private: + + /// Private constructor. + Reference_Counting_Policy (Value value); + + /// The value of the policy. + Value value_; + }; + + /// Current Reference_Counting_Policy. + Reference_Counting_Policy &reference_counting_policy (void); + +protected: + /// Force ACE_Event_Handler to be an abstract base class. + ACE_Event_Handler (ACE_Reactor * = 0, + int priority = ACE_Event_Handler::LO_PRIORITY); + + /// Typedef for implementation of reference counting. + typedef ACE_Atomic_Op Atomic_Reference_Count; + + /// Reference count. + Atomic_Reference_Count reference_count_; + +private: + + /// Priority of this Event_Handler. + int priority_; + + /// Pointer to the various event demultiplexors. + ACE_Reactor *reactor_; + + /// Reference counting requirements. + Reference_Counting_Policy reference_counting_policy_; +}; + +/** + * @class ACE_Event_Handler_var + * + * @brief Auto pointer like class for Event Handlers. + * + * Used to manage lifecycle of handlers. This class calls + * ACE_Event_Handler::remove_reference() in its destructor. + */ +class ACE_Export ACE_Event_Handler_var +{ +public: + /// Default constructor. + ACE_Event_Handler_var (void); + + /// Construct with a handler. + ACE_Event_Handler_var (ACE_Event_Handler *p); + + /// Copy constructor. + ACE_Event_Handler_var (const ACE_Event_Handler_var &b); + + /// Destructor. + ~ACE_Event_Handler_var (void); + + /// Assignment to a handler. + ACE_Event_Handler_var &operator= (ACE_Event_Handler *p); + + /// Assignment to a ACE_Event_Handler_var. + ACE_Event_Handler_var &operator= (const ACE_Event_Handler_var &b); + + /// Overloaded "->". + ACE_Event_Handler *operator-> () const; + + /// Access the handler. + ACE_Event_Handler *handler (void) const; + + /// Release the handler. + ACE_Event_Handler *release (void); + + /// Reset the handler. + void reset (ACE_Event_Handler *p = 0); + +#if defined (ACE_HAS_CPP11) + /// Bool operator to check if the ACE_Event_Handler_var has a value + explicit operator bool() const; + /// Equality operator to compare with nullptr_t + bool operator ==(std::nullptr_t) const; + /// Not equal operator to compare with nullptr_t + bool operator !=(std::nullptr_t) const; +#endif + +private: + + /// Handler. + ACE_Event_Handler *ptr_; +}; + +#if defined ACE_HAS_CPP11 + +/// Define that we can use in user code to check if this +/// helper factory method is there +#define ACE_HAS_ACE_MAKE_EVENT_HANDLER + +namespace ACE +{ + /// With C++11 it is common to not use C++ new and delete, but + /// use std::make_shared and std::make_unique. This will not + /// work for ACE event handlers so we introduce a new + /// ACE::make_event_handler which can be used in user code to + /// allocate a new ACE event handler instance and directly assign + /// it to a ACE_Event_Handler_var + /// As user this now makes it for example possible to implement + /// the following when Simple_Handler is derived from ACE_Event_Handler + /// ACE_Event_Handler_var v = + /// ACE::make_event_handler (reactor.get()); + template::value>::type, + typename ...Args> inline + ACE_Event_Handler_var make_event_handler (Args&& ...args) + { + return ACE_Event_Handler_var (new T (std::forward (args)...)); + } +} + +#endif + +/** + * @class ACE_Notification_Buffer + * + * @brief Simple wrapper for passing ACE_Event_Handler *s and + * ACE_Reactor_Masks between threads. + */ +class ACE_Export ACE_Notification_Buffer +{ +public: + ACE_Notification_Buffer (void); + + ACE_Notification_Buffer (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask); + + /// Default destructor. + ~ACE_Notification_Buffer (void); + + /// Pointer to the Event_Handler that will be dispatched + /// by the main event loop. + ACE_Event_Handler *eh_; + + /// Mask that indicates which method to call. + ACE_Reactor_Mask mask_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Event_Handler.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_EVENT_HANDLER_H */ diff --git a/dep/acelite/ace/Event_Handler.inl b/dep/acelite/ace/Event_Handler.inl new file mode 100644 index 000000000..4ad5d2d26 --- /dev/null +++ b/dep/acelite/ace/Event_Handler.inl @@ -0,0 +1,9 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Notification_Buffer::~ACE_Notification_Buffer (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.cpp b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.cpp new file mode 100644 index 000000000..f361e5aae --- /dev/null +++ b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.cpp @@ -0,0 +1,99 @@ +#include "ace/Event_Handler_Handle_Timeout_Upcall.h" +#include "ace/Reactor_Timer_Interface.h" +#include "ace/Abstract_Timer_Queue.h" + +#if !defined(__ACE_INLINE__) +# include "ace/Event_Handler_Handle_Timeout_Upcall.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Event_Handler_Handle_Timeout_Upcall) + +ACE_Event_Handler_Handle_Timeout_Upcall:: +ACE_Event_Handler_Handle_Timeout_Upcall (void) : + requires_reference_counting_ (0) +{ +} + +ACE_Event_Handler_Handle_Timeout_Upcall:: +~ACE_Event_Handler_Handle_Timeout_Upcall (void) +{ +} + +int +ACE_Event_Handler_Handle_Timeout_Upcall:: +timeout (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *event_handler, + const void *act, + int recurring_timer, + const ACE_Time_Value &cur_time) +{ + int requires_reference_counting = 0; + + if (!recurring_timer) + { + requires_reference_counting = + event_handler->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + } + + // Upcall to the s handle_timeout method. + if (event_handler->handle_timeout (cur_time, act) == -1) + { + if (event_handler->reactor_timer_interface ()) + event_handler->reactor_timer_interface ()->cancel_timer (event_handler, 0); + else + timer_queue.cancel (event_handler, 0); // 0 means "call handle_close()". + } + + if (!recurring_timer && + requires_reference_counting) + { + event_handler->remove_reference (); + } + + return 0; +} + +int +ACE_Event_Handler_Handle_Timeout_Upcall:: +cancel_type (ACE_Timer_Queue &, + ACE_Event_Handler *event_handler, + int dont_call, + int &requires_reference_counting) +{ + requires_reference_counting = + event_handler->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + // Upcall to the s handle_close method + if (dont_call == 0) + event_handler->handle_close (ACE_INVALID_HANDLE, + ACE_Event_Handler::TIMER_MASK); + + return 0; +} + +int +ACE_Event_Handler_Handle_Timeout_Upcall:: +deletion (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *event_handler, + const void *) +{ + int requires_reference_counting = 0; + + this->cancel_type (timer_queue, + event_handler, + 0, + requires_reference_counting); + + this->cancel_timer (timer_queue, + event_handler, + 0, + requires_reference_counting); + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.h b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.h new file mode 100644 index 000000000..bb94a918d --- /dev/null +++ b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.h @@ -0,0 +1,104 @@ +#ifndef ACE_EVENT_HANDLER_HANDLE_TIMEOUT_UPCALL_H +#define ACE_EVENT_HANDLER_HANDLE_TIMEOUT_UPCALL_H + +#include /**/ "ace/pre.h" + +/** + * @file Event_Handler_Handle_Timeout_Upcall.h + * + * @author Carlos O'Ryan + * + * Based on classes and files developed by Doug Schmidt, Darrell + * Brunsch, Irfan Pyarali and a cast of thousands. + */ + +#include "ace/Timer_Queuefwd.h" +#include "ace/Copy_Disabled.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @class ACE_Event_Handler_Handle_Timeout_Upcall + * + * @brief Functor for Timer_Queues. + * + * This class implements the functor required by the Timer + * Queue to call on ACE_Event_Handlers. + */ +class ACE_Export ACE_Event_Handler_Handle_Timeout_Upcall + : private ACE_Copy_Disabled +{ +public: + // = Initialization and termination methods. + /// Constructor. + ACE_Event_Handler_Handle_Timeout_Upcall (void); + + /// Destructor. + ~ACE_Event_Handler_Handle_Timeout_Upcall (void); + + /// This method is called when a timer is registered. + int registration (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + const void *arg); + + /// This method is called before the timer expires. + int preinvoke (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time, + const void *&upcall_act); + + /// This method is called when the timer expires. + int timeout (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time); + + /// This method is called after the timer expires. + int postinvoke (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + const void *arg, + int recurring_timer, + const ACE_Time_Value &cur_time, + const void *upcall_act); + + /// This method is called when a handler is cancelled + int cancel_type (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + int dont_call, + int &requires_reference_counting); + + /// This method is called when a timer is cancelled + int cancel_timer (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + int dont_call, + int requires_reference_counting); + + /// This method is called when the timer queue is destroyed and + /// the timer is still contained in it + int deletion (ACE_Timer_Queue &timer_queue, + ACE_Event_Handler *handler, + const void *arg); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// Flag indicating that reference counting is required for this + /// event handler upcall. + int requires_reference_counting_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined(__ACE_INLINE__) +# include "ace/Event_Handler_Handle_Timeout_Upcall.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_EVENT_HANDLER_HANDLE_TIMEOUT_UPCALL_H */ diff --git a/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.inl b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.inl new file mode 100644 index 000000000..8c0b41bb0 --- /dev/null +++ b/dep/acelite/ace/Event_Handler_Handle_Timeout_Upcall.inl @@ -0,0 +1,69 @@ +#include "ace/Event_Handler.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_Event_Handler_Handle_Timeout_Upcall:: +registration (ACE_Timer_Queue &, + ACE_Event_Handler *event_handler, + const void *) +{ + event_handler->add_reference (); + return 0; +} + +ACE_INLINE int +ACE_Event_Handler_Handle_Timeout_Upcall:: +preinvoke (ACE_Timer_Queue &, + ACE_Event_Handler *event_handler, + const void *, + int, + const ACE_Time_Value &, + const void * & upcall_act) +{ + bool const requires_reference_counting = + event_handler->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED; + + if (requires_reference_counting) + { + event_handler->add_reference (); + + upcall_act = &this->requires_reference_counting_; + } + + return 0; +} + +ACE_INLINE int +ACE_Event_Handler_Handle_Timeout_Upcall:: +postinvoke (ACE_Timer_Queue & /* timer_queue */, + ACE_Event_Handler *event_handler, + const void * /* timer_act */, + int /* recurring_timer */, + const ACE_Time_Value & /* cur_time */, + const void *upcall_act) +{ + if (upcall_act == &this->requires_reference_counting_) + { + event_handler->remove_reference (); + } + + return 0; +} + +ACE_INLINE int +ACE_Event_Handler_Handle_Timeout_Upcall:: +cancel_timer (ACE_Timer_Queue &, + ACE_Event_Handler *event_handler, + int, + int requires_reference_counting) +{ + if (requires_reference_counting) + event_handler->remove_reference (); + + return 0; +} + + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Event_Handler_T.cpp b/dep/acelite/ace/Event_Handler_T.cpp new file mode 100644 index 000000000..51efca891 --- /dev/null +++ b/dep/acelite/ace/Event_Handler_T.cpp @@ -0,0 +1,118 @@ +// Event_Handler_T.cpp +#ifndef ACE_EVENT_HANDLER_T_CPP +#define ACE_EVENT_HANDLER_T_CPP + +#include "ace/Event_Handler_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Event_Handler_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Event_Handler_T) + +template void +ACE_Event_Handler_T::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Event_Handler_T::dump"); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Event_Handler_T::~ACE_Event_Handler_T (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::~ACE_Event_Handler_T"); + if (this->delete_handler_) + delete this->op_handler_; +} + +template +ACE_Event_Handler_T::ACE_Event_Handler_T (T *op_handler, int delete_handler, + GET_HANDLE get_handle, + IO_HANDLER input_h, + CL_HANDLER close_h, + SIG_HANDLER sig_h, + TO_HANDLER timeout_h, + IO_HANDLER output_h, + SET_HANDLE set_handle, + IO_HANDLER except_h) + : op_handler_ (op_handler), + input_handler_ (input_h), + output_handler_ (output_h), + except_handler_ (except_h), + to_handler_ (timeout_h), + cl_handler_ (close_h), + sig_handler_ (sig_h), + delete_handler_ (delete_handler), + set_handle_ (set_handle), + get_handle_ (get_handle) +{ + ACE_TRACE ("ACE_Event_Handler_T::ACE_Event_Handler_T"); +} + +template ACE_HANDLE +ACE_Event_Handler_T::get_handle (void) const +{ + ACE_TRACE ("ACE_Event_Handler_T::get_handle"); + return this->get_handle_ == 0 ? ACE_INVALID_HANDLE : (this->op_handler_->*get_handle_) (); +} + +template void +ACE_Event_Handler_T::set_handle (ACE_HANDLE h) +{ + ACE_TRACE ("ACE_Event_Handler_T::set_handle"); + if (this->set_handle_ != 0) + (this->op_handler_->*set_handle_) (h); +} + +template int +ACE_Event_Handler_T::handle_input (ACE_HANDLE fd) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_input"); + return this->input_handler_ == 0 ? 0 : (this->op_handler_->*input_handler_) (fd); +} + +template int +ACE_Event_Handler_T::handle_output (ACE_HANDLE fd) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_output"); + return this->output_handler_ == 0 ? 0 : (this->op_handler_->*output_handler_) (fd); +} + +template int +ACE_Event_Handler_T::handle_exception (ACE_HANDLE fd) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_exception"); + return this->except_handler_ == 0 ? 0 : (this->op_handler_->*except_handler_) (fd); +} + +template int +ACE_Event_Handler_T::handle_timeout (const ACE_Time_Value &tv, const void *arg) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_timeout"); + return this->to_handler_ == 0 ? 0 : (this->op_handler_->*to_handler_) (tv, arg); +} + +template int +ACE_Event_Handler_T::handle_close (ACE_HANDLE fd, ACE_Reactor_Mask close_mask) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_close"); + return this->cl_handler_ == 0 ? 0 : (this->op_handler_->*cl_handler_) (fd, close_mask); +} + +template int +ACE_Event_Handler_T::handle_signal (int signum, siginfo_t *s, ucontext_t *u) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_signal"); + return this->sig_handler_ == 0 ? 0 : (this->op_handler_->*sig_handler_) (signum, s, u); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_EVENT_HANDLER_T_CPP */ diff --git a/dep/acelite/ace/Event_Handler_T.h b/dep/acelite/ace/Event_Handler_T.h new file mode 100644 index 000000000..ce9dc663d --- /dev/null +++ b/dep/acelite/ace/Event_Handler_T.h @@ -0,0 +1,186 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Event_Handler_T.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_EVENT_HANDLER_T_H +#define ACE_EVENT_HANDLER_T_H +#include /**/ "ace/pre.h" + +#include "ace/Event_Handler.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Event_Handler_T + * + * @brief Enable a class that doesn't inherit from the + * ACE_Event_Handler to be incorporated into the ACE_Reactor + * framework. Thanks to Greg Lavender (g.lavender@isode.com) + * for sharing this idea. + * + * It is sometimes the case that an application has a hierarchy + * of operation dispatcher classes that have their own + * inheritance hierarchy but also would like to integrate with + * the ACE_Reactor. Rather than adopt a "mixin" approach, it is + * often cleaner to define a template as a subclass of + * ACE_Event_Handler and parameterize it with an operation + * dispatcher type. + * When constructing an instantiation of the ACE_Event_Handler_T + * object, a set of pointers to member functions must be + * provided so that when one of the handle_* methods is called + * by the ACE_Reactor, the appropriate method is called on the + * underlying operations object. This is done since in some + * cases it is useful to map any event that happens to the same + * method on an object. + * The ACE_Event_Handler_T template is instantiated by an + * operations object and registered with the ACE_Reactor, and it + * then calls the appropriate op_handler. So, it's basically + * just another level of indirection in event dispatching. The + * coupling betweent the ultimate handler of the event and the + * ACE_Event_Handler class is relaxed a bit by have this + * intermediate object of type around. The + * client object can then dynamically change the bindings for + * the various handlers so that during the life of one of the + * operation objects, it can change how it wants events to be + * handled. It just instantiates a new instance of the template + * with different bindings and reregisters this new object with + * the ACE_Reactor. + */ +template +class ACE_Event_Handler_T : public ACE_Event_Handler +{ +public: + // = Typedefs to simplify pointer-to-member-function registration. + + // Get/set the underlying handle. + typedef ACE_HANDLE (T::*GET_HANDLE) (void) const; + typedef void (T::*SET_HANDLE) (ACE_HANDLE); + + /// Handle I/O events. + typedef int (T::*IO_HANDLER) (ACE_HANDLE); + + /// Handle timeout events. + typedef int (T::*TO_HANDLER) (const ACE_Time_Value &, const void *); + + /// Handle close events. + typedef int (T::*CL_HANDLER) (ACE_HANDLE, ACE_Reactor_Mask); + + /// = Initialization and termination methods. + typedef int (T::*SIG_HANDLER) (int, siginfo_t*, ucontext_t*); + + /// Initialize the op_handler. + ACE_Event_Handler_T (T *op_handler, + int delete_handler, + GET_HANDLE get_handle = 0, + IO_HANDLER input = 0, + CL_HANDLER close = 0, + SIG_HANDLER sig = 0, + TO_HANDLER timeout = 0, + IO_HANDLER output = 0, + SET_HANDLE set_handle = 0, + IO_HANDLER except = 0); + + /// Close down and delete the + ~ACE_Event_Handler_T (void); + + // = Override all the ACE_Event_Handler methods. + + // These methods all delegate down to the operations handler. + virtual ACE_HANDLE get_handle (void) const; + virtual void set_handle (ACE_HANDLE); + virtual int handle_input (ACE_HANDLE fd = ACE_INVALID_HANDLE); + virtual int handle_output (ACE_HANDLE fd = ACE_INVALID_HANDLE); + virtual int handle_exception (ACE_HANDLE fd = ACE_INVALID_HANDLE); + virtual int handle_timeout (const ACE_Time_Value &tv, const void *arg = 0); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask close_mask); + virtual int handle_signal (int signum, siginfo_t * = 0, ucontext_t * = 0); + + // = Get/set the operations handler. + T *op_handler (void); + void op_handler (T *); + + // = Get/set the target pointer-to-method used for dispatching. + + GET_HANDLE handle_get (void); + void handle_get (GET_HANDLE); + + SET_HANDLE handle_set (void); + void handle_set (SET_HANDLE); + + IO_HANDLER input_handler (void); + void input_handler (IO_HANDLER); + + IO_HANDLER output_handler (void); + void output_handler (IO_HANDLER); + + IO_HANDLER except_handler (void); + void except_handler (IO_HANDLER); + + TO_HANDLER to_handler (void); + void to_handler (TO_HANDLER); + + CL_HANDLER cl_handler (void); + void cl_handler (CL_HANDLER); + + SIG_HANDLER sig_handler (void); + void sig_handler (SIG_HANDLER); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Pointer to the object that handles all the delegated operations. + T *op_handler_; + + // = Handle input, output, and exception events. + IO_HANDLER input_handler_; + IO_HANDLER output_handler_; + IO_HANDLER except_handler_; + + /// Handle timeout events. + TO_HANDLER to_handler_; + + /// Handle close events. + CL_HANDLER cl_handler_; + + /// Handle signal events. + SIG_HANDLER sig_handler_; + + /// Keeps track of whether we need to delete the handler in the + /// destructor. + int delete_handler_; + + // = Get/set underlying handle. + SET_HANDLE set_handle_; + GET_HANDLE get_handle_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Event_Handler_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Event_Handler_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Event_Handler_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_EVENT_HANDLER_H */ diff --git a/dep/acelite/ace/Event_Handler_T.inl b/dep/acelite/ace/Event_Handler_T.inl new file mode 100644 index 000000000..64df02a1d --- /dev/null +++ b/dep/acelite/ace/Event_Handler_T.inl @@ -0,0 +1,132 @@ +// -*- C++ -*- +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE void +ACE_Event_Handler_T::op_handler (T *op) +{ + ACE_TRACE ("ACE_Event_Handler_T::op_handler"); + this->op_handler_ = op; +} + +template ACE_INLINE T * +ACE_Event_Handler_T::op_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::op_handler"); + return this->op_handler_; +} + +template ACE_INLINE typename ACE_Event_Handler_T::GET_HANDLE +ACE_Event_Handler_T::handle_get (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_get"); + return this->get_handle_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::handle_get (typename ACE_Event_Handler_T::GET_HANDLE h) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_get"); + this->get_handle_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::SET_HANDLE +ACE_Event_Handler_T::handle_set (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_set"); + return this->set_handle_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::handle_set (typename ACE_Event_Handler_T::SET_HANDLE h) +{ + ACE_TRACE ("ACE_Event_Handler_T::handle_set"); + this->set_handle_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::IO_HANDLER +ACE_Event_Handler_T::input_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::input_handler"); + return this->input_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::input_handler (typename ACE_Event_Handler_T::IO_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::input_handler"); + this->input_handler_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::IO_HANDLER +ACE_Event_Handler_T::output_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::output_handler"); + return this->output_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::output_handler (typename ACE_Event_Handler_T::IO_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::output_handler"); + this->output_handler_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::IO_HANDLER +ACE_Event_Handler_T::except_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::except_handler"); + return this->except_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::except_handler (typename ACE_Event_Handler_T::IO_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::except_handler"); + this->except_handler_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::TO_HANDLER +ACE_Event_Handler_T::to_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::to_handler"); + return this->to_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::to_handler (typename ACE_Event_Handler_T::TO_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::to_handler"); + this->to_handler_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::CL_HANDLER +ACE_Event_Handler_T::cl_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::cl_handler"); + return this->cl_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::cl_handler (typename ACE_Event_Handler_T::CL_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::cl_handler"); + this->cl_handler_ = h; +} + +template ACE_INLINE typename ACE_Event_Handler_T::SIG_HANDLER +ACE_Event_Handler_T::sig_handler (void) +{ + ACE_TRACE ("ACE_Event_Handler_T::sig_handler"); + return this->sig_handler_; +} + +template ACE_INLINE void +ACE_Event_Handler_T::sig_handler (typename ACE_Event_Handler_T::SIG_HANDLER h) +{ + ACE_TRACE ("ACE_Event_Handler_T::sig_handler"); + this->sig_handler_ = h; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO.cpp b/dep/acelite/ace/FIFO.cpp new file mode 100644 index 000000000..e598bb636 --- /dev/null +++ b/dep/acelite/ace/FIFO.cpp @@ -0,0 +1,77 @@ +#include "ace/FIFO.h" + +#if !defined (__ACE_INLINE__) +#include "ace/FIFO.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_NS_fcntl.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FIFO) + +void +ACE_FIFO::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("rendezvous_ = %s"), this->rendezvous_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_FIFO::open (const ACE_TCHAR *r, int flags, mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO::open"); + ACE_OS::strsncpy (this->rendezvous_, r, MAXPATHLEN); + + if ((flags & O_CREAT) != 0 + && ACE_OS::mkfifo (this->rendezvous_, perms) == -1 + && !(errno == EEXIST)) + return -1; + + this->set_handle (ACE_OS::open (this->rendezvous_, flags, 0, sa)); + return this->get_handle () == ACE_INVALID_HANDLE ? -1 : 0; +} + +ACE_FIFO::ACE_FIFO (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO::ACE_FIFO"); + if (this->open (fifo_name, flags, perms, sa) == -1) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_FIFO"))); +} + +ACE_FIFO::ACE_FIFO (void) +{ +// ACE_TRACE ("ACE_FIFO::ACE_FIFO"); +} + +int +ACE_FIFO::close (void) +{ + ACE_TRACE ("ACE_FIFO::close"); + int result = 0; + + if (this->get_handle () != ACE_INVALID_HANDLE) + { + result = ACE_OS::close (this->get_handle ()); + this->set_handle (ACE_INVALID_HANDLE); + } + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO.h b/dep/acelite/ace/FIFO.h new file mode 100644 index 000000000..2c66ab10f --- /dev/null +++ b/dep/acelite/ace/FIFO.h @@ -0,0 +1,97 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file FIFO.h + * + * @author Doug Schmidt + */ +//========================================================================== + + +#ifndef ACE_FIFO_H +#define ACE_FIFO_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/IPC_SAP.h" +#include "ace/os_include/os_limits.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FIFO + * + * @brief Abstract base class for UNIX FIFOs + * + * UNIX FIFOs are also known Named Pipes, which are totally + * unrelated to Windows Named Pipes. If you want to use a local + * IPC mechanism that will be portable to both UNIX and Windows, + * take a look at the ACE_Pipe or ACE_SPIPE_Stream classes. + */ +class ACE_Export ACE_FIFO : public ACE_IPC_SAP +{ +public: + /** + * Open up the named pipe (FIFO) on the @a rendezvous point in accordance + * with the @a flags. + * + * If @a flags contains @c O_CREAT open() will attempt to call mkfifo() + * to create the FIFO before opening it. In this case, this method + * will not fail simply because the fifo already exists. + * + * @retval 0 for success + * @retval -1 for error; errno contains the error code. + */ + int open (const ACE_TCHAR *rendezvous, int flags, mode_t perms, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Close down the ACE_FIFO without removing the rendezvous point. + int close (void); + + /// Close down the ACE_FIFO and remove the rendezvous point from the + /// file system. + int remove (void); + + /// Return the local address of this endpoint. + int get_local_addr (const ACE_TCHAR *&rendezvous) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /** + * Protected constructors ensure this class cannot be used directly. + * User code must use ACE_FIFO_Send and/or ACE_FIFO_Recv. + */ + //@{ + /// Default constructor. + ACE_FIFO (void); + + /// Open up the named pipe on the @a rendezvous in accordance with the + /// flags. + ACE_FIFO (const ACE_TCHAR *rendezvous, int flags, mode_t perms, + LPSECURITY_ATTRIBUTES sa = 0); + //@} + +private: + /// Rendezvous point in the file system. + ACE_TCHAR rendezvous_[MAXPATHLEN + 1]; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FIFO.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FIFO_H */ diff --git a/dep/acelite/ace/FIFO.inl b/dep/acelite/ace/FIFO.inl new file mode 100644 index 000000000..9fe5c733e --- /dev/null +++ b/dep/acelite/ace/FIFO.inl @@ -0,0 +1,22 @@ +// -*- C++ -*- +#include "ace/OS_NS_unistd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_FIFO::get_local_addr (const ACE_TCHAR *&r) const +{ + ACE_TRACE ("ACE_FIFO::get_local_addr"); + r = this->rendezvous_; + return 0; +} + +ACE_INLINE int +ACE_FIFO::remove (void) +{ + ACE_TRACE ("ACE_FIFO::remove"); + int const result = this->close (); + return ACE_OS::unlink (this->rendezvous_) == -1 || result == -1 ? -1 : 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Recv.cpp b/dep/acelite/ace/FIFO_Recv.cpp new file mode 100644 index 000000000..bb5568d56 --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv.cpp @@ -0,0 +1,89 @@ +#include "ace/FIFO_Recv.h" +#include "ace/Log_Category.h" +#include "ace/OS_NS_fcntl.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FIFO_Recv.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FIFO_Recv) + +void +ACE_FIFO_Recv::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO_Recv::dump"); + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACE_FIFO::dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("aux_handle_ = %d"), this->aux_handle_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_FIFO_Recv::close (void) +{ + ACE_TRACE ("ACE_FIFO_Recv::close"); + int result = ACE_FIFO::close (); + + if (this->aux_handle_ != ACE_INVALID_HANDLE) + return ACE_OS::close (this->aux_handle_); + else + return result; +} + +// Note that persistent means "open fifo for writing, as well as +// reading." This ensures that the fifo never gets EOF, even if there +// aren't any writers at the moment! + +int +ACE_FIFO_Recv::open (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + int persistent, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Recv::open"); + + if (ACE_FIFO::open (fifo_name, ACE_NONBLOCK | flags, perms, sa) == -1) + return -1; + else if (this->disable (ACE_NONBLOCK) == -1) + return -1; + else if (persistent + && (this->aux_handle_ = ACE_OS::open (fifo_name, O_WRONLY, 0, sa)) == ACE_INVALID_HANDLE) + return -1; + else + return this->get_handle () == ACE_INVALID_HANDLE ? -1 : 0; +} + +ACE_FIFO_Recv::ACE_FIFO_Recv (void) + : aux_handle_ (ACE_INVALID_HANDLE) +{ + ACE_TRACE ("ACE_FIFO_Recv::ACE_FIFO_Recv"); +} + +ACE_FIFO_Recv::ACE_FIFO_Recv (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + int persistent, + LPSECURITY_ATTRIBUTES sa) + : aux_handle_ (ACE_INVALID_HANDLE) +{ + ACE_TRACE ("ACE_FIFO_Recv::ACE_FIFO_Recv"); + + if (this->ACE_FIFO_Recv::open (fifo_name, + flags, + perms, + persistent, + sa) == -1) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_FIFO_Recv"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Recv.h b/dep/acelite/ace/FIFO_Recv.h new file mode 100644 index 000000000..bf3c9a8d2 --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv.h @@ -0,0 +1,94 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file FIFO_Recv.h + * + * @author Doug Schmidt + */ +//========================================================================== + + +#ifndef ACE_FIFO_RECV_H +#define ACE_FIFO_RECV_H + +#include /**/ "ace/pre.h" + +#include "ace/FIFO.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/os_fcntl.h" +#include "ace/Default_Constants.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FIFO_Recv + * + * @brief Receiver side of the bytestream C++ wrapper for UNIX + * FIFOs. + */ +class ACE_Export ACE_FIFO_Recv : public ACE_FIFO +{ +public: + /// @name Initialization methods. + /// + /// Note that @c ACE_NONBLOCK will be added to any @a flags value passed. + /// This causes the open to succeed even if no writer has yet opened the + /// fifo. There is no way to disable this behavior. + /// + /// @arg persistent Means "open fifo for writing, as well as + /// reading." This ensures that the fifo never gets EOF, even if there + /// aren't any writers at the moment! + //@{ + + /// Default constructor. + ACE_FIFO_Recv (void); + + /// Open up a bytestream named pipe for reading. + ACE_FIFO_Recv (const ACE_TCHAR *rendezvous, + int flags = O_CREAT | O_RDONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + int persistent = 1, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Open up a bytestream named pipe for reading. + int open (const ACE_TCHAR *rendezvous, + int flags = O_CREAT | O_RDONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + int persistent = 1, + LPSECURITY_ATTRIBUTES sa = 0); + //@} + + /// Close down the fifo. + int close (void); + + /// Recv @a buf of up to @a len bytes. + ssize_t recv (void *buf, size_t len); + + /// Recv @a buf of exactly @a len bytes (block until done). + ssize_t recv_n (void *buf, size_t len); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Auxiliary handle that is used to implement persistent FIFOs. + ACE_HANDLE aux_handle_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FIFO_Recv.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_FIFO_RECV_H */ diff --git a/dep/acelite/ace/FIFO_Recv.inl b/dep/acelite/ace/FIFO_Recv.inl new file mode 100644 index 000000000..aa95234c5 --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv.inl @@ -0,0 +1,21 @@ +// -*- C++ -*- +#include "ace/ACE.h" +#include "ace/OS_NS_unistd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_FIFO_Recv::recv (void *buf, size_t len) +{ + ACE_TRACE ("ACE_FIFO_Recv::recv"); + return ACE_OS::read (this->get_handle (), (char *) buf, len); +} + +ACE_INLINE ssize_t +ACE_FIFO_Recv::recv_n (void *buf, size_t n) +{ + ACE_TRACE ("ACE_FIFO_Recv::recv_n"); + return ACE::recv_n (this->get_handle (), buf, n); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Recv_Msg.cpp b/dep/acelite/ace/FIFO_Recv_Msg.cpp new file mode 100644 index 000000000..494f098ac --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv_Msg.cpp @@ -0,0 +1,66 @@ +#include "ace/FIFO_Recv_Msg.h" + +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FIFO_Recv_Msg.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FIFO_Recv_Msg) + +void +ACE_FIFO_Recv_Msg::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO_Recv_Msg::dump"); + ACE_FIFO_Recv::dump (); +#endif /* ACE_HAS_DUMP */ +} + +// Note that persistent means "open FIFO for writing, as well as +// reading." This ensures that the FIFO never gets EOF, even if there +// aren't any writers at the moment! + +int +ACE_FIFO_Recv_Msg::open (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + int persistent, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::open"); + + return ACE_FIFO_Recv::open (fifo_name, + flags, + perms, + persistent, + sa); +} + +ACE_FIFO_Recv_Msg::ACE_FIFO_Recv_Msg (void) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::ACE_FIFO_Recv_Msg"); +} + +ACE_FIFO_Recv_Msg::ACE_FIFO_Recv_Msg (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + int persistent, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::ACE_FIFO_Recv_Msg"); + + if (this->ACE_FIFO_Recv_Msg::open (fifo_name, + flags, + perms, + persistent, + sa) == -1) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_FIFO_Recv_Msg"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Recv_Msg.h b/dep/acelite/ace/FIFO_Recv_Msg.h new file mode 100644 index 000000000..566f26fdf --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv_Msg.h @@ -0,0 +1,136 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FIFO_Recv_Msg.h + * + * @author Doug Schmidt + */ +//============================================================================= + + +#ifndef ACE_FIFO_RECV_MSG_H +#define ACE_FIFO_RECV_MSG_H +#include /**/ "ace/pre.h" + +#include "ace/FIFO_Recv.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decls +class ACE_Str_Buf; + +/** + * @class ACE_FIFO_Recv_Msg + * + * @brief Receiver side for the record oriented C++ wrapper for UNIX FIFOs. + * + * This method works slightly differently on platforms with the + * @c ACE_HAS_STREAM_PIPES configuration setting than those without. + * With ACE_HAS_STREAM_PIPES, the @c getmsg() system function is used + * and it preserves message boundaries internally. Without + * @c ACE_HAS_STREAM_PIPES, the message boundaries are emulated by + * this class and ACE_FIFO_Send_Msg cooperating. The sending class + * first writes an integer number of bytes in the message, then the + * message. ACE_FIFO_Recv_Msg reads the count, then the data. + * The operational differences occur primarily when a message is larger + * than what a caller of this class requests. See recv() for details. + */ +class ACE_Export ACE_FIFO_Recv_Msg : public ACE_FIFO_Recv +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_FIFO_Recv_Msg (void); + + /// Open up a record-oriented named pipe for reading. + ACE_FIFO_Recv_Msg (const ACE_TCHAR *rendezvous, + int flags = O_CREAT | O_RDONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + int persistent = 1, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Open up a record-oriented named pipe for reading. + int open (const ACE_TCHAR *rendezvous, + int flags = O_CREAT | O_RDONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + int persistent = 1, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Receive a message based on attributes in an ACE_Str_Buf. + /** + * @param msg Reference to an ACE_Str_Buf whose @c buf member points + * to the memory to receive the data and @c maxlen member + * contains the maximum number of bytes to receive. + * On return after successfully reading data, the + * @c len member contains the number of bytes received and + * placed in the buffer pointed to by @c msg.buf. + * + * @retval -1 Error; consult @c errno for specific error number. + * @return If the @c ACE_HAS_STREAM_PIPES configuration setting is + * defined, the return value is the number of bytes received + * in the message and will be the same as @c buf.len. + * The return value from the @c getmsg() system function + * is discarded. + * If @c ACE_HAS_STREAM_PIPES is not defined, the number + * of bytes in the message read from the FIFO is returned. + * If the message is larger than the maximum length + * requested in @c msg.maxlen, the return value reflects + * the entire message length, and the @c msg.len member + * reflects how many bytes were actually placed in the + * caller's buffer. Any part of the message longer than + * @c msg.maxlen is discarded. + */ + ssize_t recv (ACE_Str_Buf &msg); + + /// Receive a message based on buffer pointer and maximum size. + /** + * @param buf Pointer to the memory to receive the data. + * @param len The maximum number of bytes to receive. + * + * @retval -1 Error; consult @c errno for specific error number. + * @return The number of bytes received in the message. For messages + * that are larger than the requested maximum size, the + * behavior is different depending on the @c ACE_HAS_STREAM_PIPES + * configuration setting. With @c ACE_HAS_STREAM_PIPES, + * the return value will be the same as @arg len (this is + * also possible if the message is exactly the same length + * as @arg len, and the two cases are indistinguishable). + * Without @c ACE_HAS_STREAM_PIPES, the return value is + * the total length of the message, including bytes in + * excess of @arg len. The excess bytes are discarded. + */ + ssize_t recv (void *buf, size_t len); + +#if defined (ACE_HAS_STREAM_PIPES) + /// Recv @a data and @a cntl message via Stream pipes. + ssize_t recv (ACE_Str_Buf *data, + ACE_Str_Buf *cntl, + int *flags); + + /// Recv @a data and @a cntl message via Stream pipes in "band" mode. + ssize_t recv (int *band, + ACE_Str_Buf *data, + ACE_Str_Buf *cntl, + int *flags); +#endif /* ACE_HAS_STREAM_PIPES */ + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FIFO_Recv_Msg.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FIFO_RECV_MSG_H */ diff --git a/dep/acelite/ace/FIFO_Recv_Msg.inl b/dep/acelite/ace/FIFO_Recv_Msg.inl new file mode 100644 index 000000000..917aee9df --- /dev/null +++ b/dep/acelite/ace/FIFO_Recv_Msg.inl @@ -0,0 +1,134 @@ +// -*- C++ -*- +#include "ace/Min_Max.h" +#include "ace/OS_NS_stropts.h" +#include "ace/Truncate.h" + +#if !defined (ACE_HAS_STREAM_PIPES) +#include "ace/OS_NS_unistd.h" +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_FIFO_Recv_Msg::recv (ACE_Str_Buf &recv_msg) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::recv"); +#if defined (ACE_HAS_STREAM_PIPES) + int i = 0; + if (ACE_OS::getmsg (this->get_handle (), + (strbuf *) 0, + (strbuf *) &recv_msg, + &i) == -1) + { + return -1; + } + else + { + return recv_msg.len; + } +#else /* Do the ol' 2-read trick... */ + if (ACE_OS::read (this->get_handle (), + (char *) &recv_msg.len, + sizeof recv_msg.len) != (ssize_t) sizeof recv_msg.len) + { + return -1; + } + else + { + size_t remaining = static_cast (recv_msg.len); + size_t requested = static_cast (recv_msg.maxlen); + ssize_t recv_len = ACE_OS::read (this->get_handle (), + (char *) recv_msg.buf, + ACE_MIN (remaining, requested)); + + if (recv_len == -1) + { + return -1; + } + + // Tell caller what's really in the buffer. + recv_msg.len = static_cast (recv_len); + + // If there are more bytes remaining in the message, read them and + // throw them away. Leaving them in the FIFO would make it difficult + // to find the start of the next message in the fifo. + // Since the ACE_HAS_STREAM_PIPES version of this method doesn't + // return getmsg()'s indication of "data remaining", don't worry about + // saving the indication here either to read the remainder later. + size_t total_msg_size = remaining; + remaining -= recv_len; + + while (remaining > 0) + { + const size_t throw_away = 1024; + char dev_null[throw_away]; + recv_len = ACE_OS::read (this->get_handle (), + dev_null, + ACE_MIN (remaining, throw_away)); + + if (recv_len == -1) + { + break; + } + + remaining -= recv_len; + } + + return ACE_Utils::truncate_cast (total_msg_size); + } +#endif /* ACE_HAS_STREAM_PIPES */ +} + +ACE_INLINE ssize_t +ACE_FIFO_Recv_Msg::recv (void *buf, size_t max_len) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::recv"); + ACE_Str_Buf recv_msg ((char *) buf, 0, static_cast (max_len)); + + return this->recv (recv_msg); +} + +#if defined (ACE_HAS_STREAM_PIPES) +ACE_INLINE ssize_t +ACE_FIFO_Recv_Msg::recv (ACE_Str_Buf *data, + ACE_Str_Buf *cntl, + int *flags) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::recv"); + if (ACE_OS::getmsg (this->get_handle (), + (strbuf *) cntl, + (strbuf *) data, + flags) == -1) + { + return -1; + } + else + { + return (cntl == 0 ? 0 : cntl->len) + (data == 0 ? 0 : data->len); + } +} + +ACE_INLINE ssize_t +ACE_FIFO_Recv_Msg::recv (int *band, + ACE_Str_Buf *data, + ACE_Str_Buf *cntl, + int *flags) +{ + ACE_TRACE ("ACE_FIFO_Recv_Msg::recv"); + + if (ACE_OS::getpmsg (this->get_handle (), + (strbuf *) cntl, + (strbuf *) data, + band, + flags) == -1) + { + return -1; + } + else + { + return (cntl == 0 ? 0 : cntl->len) + (data == 0 ? 0 : data->len); + } +} +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Send.cpp b/dep/acelite/ace/FIFO_Send.cpp new file mode 100644 index 000000000..0c37b917e --- /dev/null +++ b/dep/acelite/ace/FIFO_Send.cpp @@ -0,0 +1,59 @@ +#include "ace/FIFO_Send.h" +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FIFO_Send.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FIFO_Send) + +void +ACE_FIFO_Send::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO_Send::dump"); + ACE_FIFO::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_FIFO_Send::ACE_FIFO_Send (void) +{ +// ACE_TRACE ("ACE_FIFO_Send::ACE_FIFO_Send"); +} + +int +ACE_FIFO_Send::open (const ACE_TCHAR *rendezvous_name, + int flags, + mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Send::open"); + return ACE_FIFO::open (rendezvous_name, + flags | O_WRONLY, + perms, + sa); +} + +ACE_FIFO_Send::ACE_FIFO_Send (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Send::ACE_FIFO_Send"); + if (this->ACE_FIFO_Send::open (fifo_name, + flags, + perms, + sa) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_FIFO_Send::ACE_FIFO_Send"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Send.h b/dep/acelite/ace/FIFO_Send.h new file mode 100644 index 000000000..37580662b --- /dev/null +++ b/dep/acelite/ace/FIFO_Send.h @@ -0,0 +1,79 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file FIFO_Send.h + * + * @author Doug Schmidt + */ +//========================================================================== + + +#ifndef ACE_FIFO_SEND_H +#define ACE_FIFO_SEND_H + +#include /**/ "ace/pre.h" + +#include "ace/FIFO.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/os_fcntl.h" +#include "ace/Default_Constants.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FIFO_Send + * + * @brief Sender side for the bytestream C++ wrapper for UNIX FIFOs + */ +class ACE_Export ACE_FIFO_Send : public ACE_FIFO +{ +public: + /// @name Initialization methods. + /// + /// Note that @c O_WRONLY will be added to any @a flags value passed. + /// Default behavior is to block until a receiver also opens the fifo. + /// To use non-blocking behavior include ACE_NONBLOCK in @a flags. + //@{ + /// Default constructor. + ACE_FIFO_Send (void); + + /// Open up a bytestream named pipe for writing. + ACE_FIFO_Send (const ACE_TCHAR *rendezvous, + int flags = O_WRONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Open up a bytestream named pipe for writing. + int open (const ACE_TCHAR *rendezvous, + int flags = O_WRONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + LPSECURITY_ATTRIBUTES sa = 0); + //@} + + /// Send @a buf of up to @a len bytes. + ssize_t send (const void *buf, size_t len); + + /// Send @a buf of exactly @a len bytes (block until done). + ssize_t send_n (const void *buf, size_t len); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FIFO_Send.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_FIFO_SEND_H */ diff --git a/dep/acelite/ace/FIFO_Send.inl b/dep/acelite/ace/FIFO_Send.inl new file mode 100644 index 000000000..ee0d8d0b5 --- /dev/null +++ b/dep/acelite/ace/FIFO_Send.inl @@ -0,0 +1,21 @@ +// -*- C++ -*- +#include "ace/ACE.h" +#include "ace/OS_NS_unistd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_FIFO_Send::send (const void *buf, size_t len) +{ + ACE_TRACE ("ACE_FIFO_Send::send"); + return ACE_OS::write (this->get_handle (), (const char *) buf, len); +} + +ACE_INLINE ssize_t +ACE_FIFO_Send::send_n (const void *buf, size_t n) +{ + ACE_TRACE ("ACE_FIFO_Send::send_n"); + return ACE::send_n (this->get_handle (), buf, n); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Send_Msg.cpp b/dep/acelite/ace/FIFO_Send_Msg.cpp new file mode 100644 index 000000000..756a570f2 --- /dev/null +++ b/dep/acelite/ace/FIFO_Send_Msg.cpp @@ -0,0 +1,81 @@ +#include "ace/FIFO_Send_Msg.h" + +#include "ace/Log_Category.h" +#include "ace/OS_NS_sys_uio.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FIFO_Send_Msg.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FIFO_Send_Msg) + +void +ACE_FIFO_Send_Msg::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FIFO_Send_Msg::dump"); + ACE_FIFO_Send::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ssize_t +ACE_FIFO_Send_Msg::send (const ACE_Str_Buf &send_msg) +{ + // ACE_TRACE ("ACE_FIFO_Send_Msg::send"); +#if defined (ACE_HAS_STREAM_PIPES) + if (ACE_OS::putmsg (this->get_handle (), + (strbuf *) 0, + (strbuf *) &send_msg, + 0) == -1) + return -1; + else + return send_msg.len; +#else + iovec iov[2]; + + iov[0].iov_base = (char *) &send_msg.len; + iov[0].iov_len = sizeof send_msg.len; + + iov[1].iov_base = (char *) send_msg.buf; + iov[1].iov_len = static_cast (send_msg.len); + + ssize_t sent = ACE_OS::writev (this->get_handle (), iov, 2); + if (sent > 0) + sent -= iov[0].iov_len; // Don't count the length we added. + return sent; +#endif /* ACE_HAS_STREAM_PIPES */ +} + +ACE_FIFO_Send_Msg::ACE_FIFO_Send_Msg (void) +{ +// ACE_TRACE ("ACE_FIFO_Send_Msg::ACE_FIFO_Send_Msg"); +} + +int +ACE_FIFO_Send_Msg::open (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Send_Msg::open"); + return ACE_FIFO_Send::open (fifo_name, flags | O_WRONLY, perms, sa); +} + +ACE_FIFO_Send_Msg::ACE_FIFO_Send_Msg (const ACE_TCHAR *fifo_name, + int flags, + mode_t perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE_FIFO_Send_Msg::ACE_FIFO_Send_Msg"); + if (this->ACE_FIFO_Send_Msg::open (fifo_name, flags, perms, sa) == -1) + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p\n"), ACE_TEXT ("ACE_FIFO_Send_Msg"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FIFO_Send_Msg.h b/dep/acelite/ace/FIFO_Send_Msg.h new file mode 100644 index 000000000..226f53da0 --- /dev/null +++ b/dep/acelite/ace/FIFO_Send_Msg.h @@ -0,0 +1,89 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file FIFO_Send_Msg.h + * + * @author Doug Schmidt + */ +//============================================================================= + + +#ifndef ACE_FIFO_SEND_MSG_H +#define ACE_FIFO_SEND_MSG_H +#include /**/ "ace/pre.h" + +#include "ace/FIFO_Send.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_STREAM_PIPES) +# include "ace/OS_NS_stropts.h" +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward Decls +class ACE_Str_Buf; + +/** + * @class ACE_FIFO_Send_Msg + * + * @brief Sender side for the Record oriented C++ wrapper for UNIX + * FIFOs. + */ +class ACE_Export ACE_FIFO_Send_Msg : public ACE_FIFO_Send +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_FIFO_Send_Msg (void); + + /// Open up a record-oriented named pipe for writing. + ACE_FIFO_Send_Msg (const ACE_TCHAR *rendezvous, + int flags = O_WRONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Open up a record-oriented named pipe for writing. + int open (const ACE_TCHAR *rendezvous, + int flags = O_WRONLY, + mode_t perms = ACE_DEFAULT_FILE_PERMS, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Send @a buf of up to @a len bytes. + ssize_t send (const ACE_Str_Buf &msg); + + /// Send @a buf of exactly @a len bytes (block until done). + ssize_t send (const void *buf, size_t len); + +#if defined (ACE_HAS_STREAM_PIPES) + /// Send @a data and @a cntl message via Stream pipes. + ssize_t send (const ACE_Str_Buf *data, + const ACE_Str_Buf *cntl = 0, + int flags = 0); + + /// Send @a data and @a cntl message via Stream pipes in "band" mode. + ssize_t send (int band, + const ACE_Str_Buf *data, + const ACE_Str_Buf *cntl = 0, + int flags = MSG_BAND); +#endif /* ACE_HAS_STREAM_PIPES */ + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FIFO_Send_Msg.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FIFO_SEND_MSG_H */ diff --git a/dep/acelite/ace/FIFO_Send_Msg.inl b/dep/acelite/ace/FIFO_Send_Msg.inl new file mode 100644 index 000000000..74aaa1971 --- /dev/null +++ b/dep/acelite/ace/FIFO_Send_Msg.inl @@ -0,0 +1,50 @@ +// -*- C++ -*- +#include "ace/OS_NS_stropts.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_FIFO_Send_Msg::send (const void *buf, size_t len) +{ + ACE_TRACE ("ACE_FIFO_Send_Msg::send"); + ACE_Str_Buf send_msg ((char *) buf, static_cast (len)); + + return this->send (send_msg); +} + +#if defined (ACE_HAS_STREAM_PIPES) +ACE_INLINE ssize_t +ACE_FIFO_Send_Msg::send (const ACE_Str_Buf *data, + const ACE_Str_Buf *cntl, + int flags) +{ + ACE_TRACE ("ACE_FIFO_Send_Msg::send"); + if (ACE_OS::putmsg (this->get_handle (), + (strbuf *) cntl, + (strbuf *) data, + flags) == -1) + return-1; + else + return (cntl == 0 ? 0 : cntl->len) + (data == 0 ? 0 : data->len); +} + +ACE_INLINE ssize_t +ACE_FIFO_Send_Msg::send (int band, + const ACE_Str_Buf *data, + const ACE_Str_Buf *cntl, + int flags) +{ + ACE_TRACE ("ACE_FIFO_Send_Msg::send"); + + if (ACE_OS::putpmsg (this->get_handle (), + (strbuf *) cntl, + (strbuf *) data, + band, + flags) == -1) + return -1; + else + return (cntl == 0 ? 0 : cntl->len) + (data == 0 ? 0 : data->len); +} +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE.cpp b/dep/acelite/ace/FILE.cpp new file mode 100644 index 000000000..f7be0af71 --- /dev/null +++ b/dep/acelite/ace/FILE.cpp @@ -0,0 +1,149 @@ +/* Defines the member functions for the base class of the ACE_IO_SAP + ACE_FILE abstraction. */ + +#include "ace/FILE.h" + +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_stat.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FILE.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FILE) + +void +ACE_FILE::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FILE::dump"); + ACE_IO_SAP::dump (); +#endif /* ACE_HAS_DUMP */ +} + +// This is the do-nothing constructor. + +ACE_FILE::ACE_FILE (void) +{ + ACE_TRACE ("ACE_FILE::ACE_FILE"); +} + +// Close the file + +int +ACE_FILE::close (void) +{ + ACE_TRACE ("ACE_FILE::close"); + int result = 0; + + if (this->get_handle () != ACE_INVALID_HANDLE) + { + result = ACE_OS::close (this->get_handle ()); + this->set_handle (ACE_INVALID_HANDLE); + } + return result; +} + +int +ACE_FILE::get_info (ACE_FILE_Info *finfo) +{ + ACE_TRACE ("ACE_FILE::get_info"); + ACE_stat filestatus; + + int const result = ACE_OS::fstat (this->get_handle (), &filestatus); + + if (result == 0) + { + finfo->mode_ = filestatus.st_mode; + finfo->nlink_ = filestatus.st_nlink; + finfo->size_ = filestatus.st_size; + } + + return result; +} + +int +ACE_FILE::get_info (ACE_FILE_Info &finfo) +{ + ACE_TRACE ("ACE_FILE::get_info"); + + return this->get_info (&finfo); +} + +int +ACE_FILE::truncate (ACE_OFF_T length) +{ + ACE_TRACE ("ACE_FILE::truncate"); + return ACE_OS::ftruncate (this->get_handle (), length); +} + +ACE_OFF_T +ACE_FILE::seek (ACE_OFF_T offset, int startpos) +{ + return ACE_OS::lseek (this->get_handle (), offset, startpos); +} + +ACE_OFF_T +ACE_FILE::tell (void) +{ + ACE_TRACE ("ACE_FILE::tell"); + return ACE_OS::lseek (this->get_handle (), 0, SEEK_CUR); +} + +// Return the local endpoint address. + +int +ACE_FILE::get_local_addr (ACE_Addr &addr) const +{ + ACE_TRACE ("ACE_FILE::get_local_addr"); + + // Perform the downcast since had better be an + // . + ACE_FILE_Addr *file_addr = + dynamic_cast (&addr); + + if (file_addr == 0) + return -1; + else + { + *file_addr = this->addr_; + return 0; + } +} + +// Return the same result as . + +int +ACE_FILE::get_remote_addr (ACE_Addr &addr) const +{ + ACE_TRACE ("ACE_FILE::get_remote_addr"); + + return this->get_local_addr (addr); +} + +int +ACE_FILE::remove (void) +{ + ACE_TRACE ("ACE_FILE::remove"); + + this->close (); + return ACE_OS::unlink (this->addr_.get_path_name ()); +} + +int +ACE_FILE::unlink (void) +{ + ACE_TRACE ("ACE_FILE::unlink"); + + return ACE_OS::unlink (this->addr_.get_path_name ()); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE.h b/dep/acelite/ace/FILE.h new file mode 100644 index 000000000..e128eda3a --- /dev/null +++ b/dep/acelite/ace/FILE.h @@ -0,0 +1,124 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file FILE.h + * + * @author Gerhard Lenzer + */ +//============================================================================= + +#ifndef ACE_FILE_H +#define ACE_FILE_H +#include /**/ "ace/pre.h" + +#include "ace/IO_SAP.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/FILE_Addr.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FILE_Info + * + * @brief Abstracts basic OS FILE information. + */ +class ACE_Export ACE_FILE_Info +{ +public: + /// Mode of file + mode_t mode_; + + /// No of links + nlink_t nlink_; + + /// Size of file + ACE_OFF_T size_; +}; + +/** + * @class ACE_FILE + * + * @brief Defines the core methods of the ACE_FILE abstraction. + */ +class ACE_Export ACE_FILE : public ACE_IO_SAP +{ +public: + /// Close the ACE_FILE handle without removing the ACE_FILE from + /// the file system. + int close (void); + + /// Close and remove the ACE_FILE from the file system. + int remove (void); + + /// Remove the ACE_FILE from the file system without closing the + /// ACE_FILE handle. + int unlink (void); + + /// Get information on this ACE_FILE. + int get_info (ACE_FILE_Info *finfo); + + /// Get information on this ACE_FILE. + int get_info (ACE_FILE_Info &finfo); + + /// Set filesize to length byte. + int truncate (ACE_OFF_T length); + + /** + * Sets the file pointer as follows: + * o If @ whence is @c SEEK_SET, the pointer is set to @a offset + * bytes. + * + * o If @a whence> is @c SEEK_CUR, the pointer is set to its + * current location plus @a offset. + * + * o If @a whence is @c SEEK_END, the pointer is set to the size + * of the file plus offset. + */ + ACE_OFF_T seek (ACE_OFF_T offset, + int whence = SEEK_CUR); + + /// Return an offset for the file handle. + ACE_OFF_T tell (void); + + /** + * Disable signal @a signum + * This is here to prevent Win32 from + * disabling SPIPE using socket calls + */ + int disable (int signum) const ; + + /// Return the local endpoint address in the referenced ACE_Addr. + /// Returns 0 if successful, else -1. + int get_local_addr (ACE_Addr &) const; + + /// Return the same thing as get_local_addr(). + int get_remote_addr (ACE_Addr &) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Ensure that this class is only created by the + /// ACE_FILE_Connector. + ACE_FILE (void); + + /// File we are "connected" with... + ACE_FILE_Addr addr_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FILE.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FILE_H */ diff --git a/dep/acelite/ace/FILE.inl b/dep/acelite/ace/FILE.inl new file mode 100644 index 000000000..69c3e0cd2 --- /dev/null +++ b/dep/acelite/ace/FILE.inl @@ -0,0 +1,15 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_FILE::disable (int signum) const +{ +#if defined (ACE_WIN32) + ACE_UNUSED_ARG (signum) ; + return 0 ; +#else /* ACE_WIN32 */ + return ACE_IO_SAP::disable (signum) ; +#endif /* ACE_WIN32 */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_Addr.cpp b/dep/acelite/ace/FILE_Addr.cpp new file mode 100644 index 000000000..9d043f5fc --- /dev/null +++ b/dep/acelite/ace/FILE_Addr.cpp @@ -0,0 +1,129 @@ +#include "ace/FILE_Addr.h" +#include "ace/Lib_Find.h" +#include "ace/Log_Category.h" +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/os_include/sys/os_socket.h" + +#if !defined (__ACE_INLINE__) +#include "ace/FILE_Addr.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FILE_Addr) + +ACE_FILE_Addr::ACE_FILE_Addr (void) + : ACE_Addr (AF_FILE, sizeof this->filename_ / sizeof (ACE_TCHAR)) +{ + this->filename_[0] = '\0'; +} + +int +ACE_FILE_Addr::set (const ACE_FILE_Addr &sa) +{ + if (sa.get_type () == AF_ANY) + { +#if defined (ACE_DISABLE_MKTEMP) + // Built without mktemp support; punt back to caller. + errno = ENOTSUP; + return -1; +#else + +# if defined (ACE_DEFAULT_TEMP_FILE) + // Create a temporary file. + ACE_OS::strcpy (this->filename_, + ACE_DEFAULT_TEMP_FILE); +# else /* ACE_DEFAULT_TEMP_FILE */ + if (ACE::get_temp_dir (this->filename_, MAXPATHLEN - 15) == -1) + // -15 for ace-file-XXXXXX + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("Temporary path too long, ") + ACE_TEXT ("defaulting to current directory\n"))); + this->filename_[0] = 0; + } + + // Add the filename to the end + ACE_OS::strcat (this->filename_, ACE_TEXT ("ace-fileXXXXXX")); + +# endif /* ACE_DEFAULT_TEMP_FILE */ + + if (ACE_OS::mktemp (this->filename_) == 0) + return -1; + this->base_set (AF_FILE, + static_cast (ACE_OS::strlen (this->filename_) + 1)); +#endif /* ACE_DISABLE_MKTEMP */ + } + else + { + (void)ACE_OS::strsncpy (this->filename_, sa.filename_, sa.get_size ()); + + this->base_set (sa.get_type (), sa.get_size ()); + } + return 0; +} + +// Copy constructor. + +ACE_FILE_Addr::ACE_FILE_Addr (const ACE_FILE_Addr &sa) + : ACE_Addr (AF_FILE, sizeof this->filename_) +{ + this->set (sa); +} + +int +ACE_FILE_Addr::set (const ACE_TCHAR *filename) +{ + this->ACE_Addr::base_set (AF_FILE, + static_cast (ACE_OS::strlen (filename) + 1)); + (void) ACE_OS::strsncpy (this->filename_, + filename, + sizeof this->filename_ / sizeof (ACE_TCHAR)); + return 0; +} + +ACE_FILE_Addr & +ACE_FILE_Addr::operator= (const ACE_FILE_Addr &sa) +{ + if (this != &sa) + this->set (sa); + return *this; +} + +// Create a ACE_Addr from a ACE_FILE pathname. + +ACE_FILE_Addr::ACE_FILE_Addr (const ACE_TCHAR *filename) +{ + this->set (filename); +} + +int +ACE_FILE_Addr::addr_to_string (ACE_TCHAR *s, size_t len) const +{ + ACE_OS::strsncpy (s, this->filename_, len); + return 0; +} + +// Return the address. + +void * +ACE_FILE_Addr::get_addr (void) const +{ + return (void *)&this->filename_; +} + +void +ACE_FILE_Addr::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FILE_Addr::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("filename_ = %s"), this->filename_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_Addr.h b/dep/acelite/ace/FILE_Addr.h new file mode 100644 index 000000000..d35537301 --- /dev/null +++ b/dep/acelite/ace/FILE_Addr.h @@ -0,0 +1,87 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file FILE_Addr.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_FILE_ADDR_H +#define ACE_FILE_ADDR_H +#include /**/ "ace/pre.h" + +#include "ace/Addr.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Flag_Manip.h" +#include "ace/os_include/os_dirent.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FILE_Addr + * + * @brief Defines the FILE address family address format. + */ +class ACE_Export ACE_FILE_Addr : public ACE_Addr +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_FILE_Addr (void); + + /// Copy constructor. + ACE_FILE_Addr (const ACE_FILE_Addr &sa); + + /// Acts like a copy constructor. If @a sa == ACE_Addr::sap_any then + /// create a temporary filename using ACE_OS::mktemp. + int set (const ACE_FILE_Addr &sa); + + /// Create a ACE_FILE_Addr from a pathname. + explicit ACE_FILE_Addr (const ACE_TCHAR *filename); + + /// Create a ACE_FILE_Addr from a pathname. + int set (const ACE_TCHAR *filename); + + /// Assignment operator. + ACE_FILE_Addr &operator= (const ACE_FILE_Addr &); + + /// Return a pointer to the address. + virtual void *get_addr (void) const; + + /// Transform the current address into string format. + virtual int addr_to_string (ACE_TCHAR *addr, size_t) const; + + /// Compare two addresses for equality. + bool operator == (const ACE_FILE_Addr &SAP) const; + + /// Compare two addresses for inequality. + bool operator != (const ACE_FILE_Addr &SAP) const; + + /// Return the path name used for the rendezvous point. + const ACE_TCHAR *get_path_name (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Name of the file. + ACE_TCHAR filename_[MAXPATHLEN + 1]; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FILE_Addr.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FILE_ADDR_H */ diff --git a/dep/acelite/ace/FILE_Addr.inl b/dep/acelite/ace/FILE_Addr.inl new file mode 100644 index 000000000..c873ba8b0 --- /dev/null +++ b/dep/acelite/ace/FILE_Addr.inl @@ -0,0 +1,31 @@ +// -*- C++ -*- + +#include "ace/SString.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Compare two addresses for equality. + +ACE_INLINE bool +ACE_FILE_Addr::operator == (const ACE_FILE_Addr &sap) const +{ + return ACE_OS::strcmp (this->filename_, sap.filename_) == 0; +} + +// Compare two addresses for inequality. + +ACE_INLINE bool +ACE_FILE_Addr::operator != (const ACE_FILE_Addr &sap) const +{ + return !((*this) == sap); // This is lazy, of course... ;-) +} + +// Return the path name used for the rendezvous point. + +ACE_INLINE const ACE_TCHAR * +ACE_FILE_Addr::get_path_name (void) const +{ + return this->filename_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_Connector.cpp b/dep/acelite/ace/FILE_Connector.cpp new file mode 100644 index 000000000..5ff46dec5 --- /dev/null +++ b/dep/acelite/ace/FILE_Connector.cpp @@ -0,0 +1,85 @@ +#include "ace/FILE_Connector.h" +#include "ace/Handle_Ops.h" +#include "ace/OS_NS_stdlib.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FILE_Connector.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FILE_Connector) + +void +ACE_FILE_Connector::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FILE_Connector::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_FILE_Connector::ACE_FILE_Connector (void) +{ + ACE_TRACE ("ACE_FILE_Connector::ACE_FILE_Connector"); +} + +int +ACE_FILE_Connector::connect (ACE_FILE_IO &new_io, + const ACE_FILE_Addr &remote_sap, + ACE_Time_Value *timeout, + const ACE_Addr &, + int, + int flags, + int perms) +{ + ACE_TRACE ("ACE_FILE_Connector::connect"); + ACE_ASSERT (new_io.get_handle () == ACE_INVALID_HANDLE); + + ACE_HANDLE handle = ACE_INVALID_HANDLE; + + // Check to see if caller has requested that we create the filename. + if (reinterpret_cast ( + const_cast (remote_sap)) == ACE_Addr::sap_any) + { + // Create a new temporary file. + // Use ACE_OS::mkstemp() if it is available since it avoids a + // race condition, and subsequently a security hole due to that + // race condition (specifically, a denial-of-service attack). + // + // However, using mkstemp() prevents us from doing a timed open + // since it opens the file for us. Better to avoid the race + // condition. + char filename[] = "ace-file-XXXXXX"; + + handle = ACE_OS::mkstemp (filename); // mkstemp() replaces "XXXXXX" + + if (handle == ACE_INVALID_HANDLE + || new_io.addr_.set (ACE_TEXT_CHAR_TO_TCHAR (filename)) != 0) + return -1; + + new_io.set_handle (handle); + + return 0; + } + else + new_io.addr_ = remote_sap; // class copy. + + handle = ACE::handle_timed_open (timeout, + new_io.addr_.get_path_name (), + flags, + perms); + + new_io.set_handle (handle); + return handle == ACE_INVALID_HANDLE ? -1 : 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_Connector.h b/dep/acelite/ace/FILE_Connector.h new file mode 100644 index 000000000..b554a1e81 --- /dev/null +++ b/dep/acelite/ace/FILE_Connector.h @@ -0,0 +1,111 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file FILE_Connector.h + * + * @author Doug Schmidt + */ +//============================================================================= + +#ifndef ACE_FILE_CONNECTOR_H +#define ACE_FILE_CONNECTOR_H +#include /**/ "ace/pre.h" + +#include "ace/FILE_IO.h" +#include "ace/Log_Category.h" +#include "ace/os_include/os_fcntl.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_FILE_Connector + * + * @brief Defines an active connection factory for the ACE_FILE wrappers. + * + * Note that the O_APPEND flag is only partly supported on Win32. If + * you specify O_APPEND, then the file pointer will be positioned at + * the end of the file initially during open, but it is not + * re-positioned at the end prior to each write, as specified by + * POSIX. This is generally good enough for typical situations, but + * it is ``not quite right'' in its semantics. + */ +class ACE_Export ACE_FILE_Connector +{ +public: + // = Initialization methods. + /// Default constructor. + ACE_FILE_Connector (void); + + /** + * Actively ``connect'' and produce a @a new_io ACE_FILE_IO object + * if things go well. The @a remote_sap is the file that we are + * trying to create/open. If it's the default value of + * ACE_Addr::sap_any then the user is letting the OS create the + * filename (via ). The @a timeout is the amount of + * time to wait to create/open the file. If it's 0 then we block + * indefinitely. If *timeout == {0, 0} then the file is created + * using non-blocking mode. If *timeout > {0, 0} then this is the + * maximum amount of time to wait before timing out. The + * @a local_sap and @a reuse_addr parameters are ignored. The @a flags + * and @a perms arguments are passed down to the + * method. + */ + ACE_FILE_Connector (ACE_FILE_IO &new_io, + const ACE_FILE_Addr &remote_sap, + ACE_Time_Value *timeout = 0, + const ACE_Addr &local_sap = ACE_Addr::sap_any, + int reuse_addr = 0, + int flags = O_RDWR | O_CREAT, + int perms = ACE_DEFAULT_FILE_PERMS); + + /** + * Actively ``connect'' and produce a @a new_io object + * if things go well. The @a remote_sap is the file that we are + * trying to create/open. If it's the default value of + * ACE_Addr::sap_any then the user is letting the OS create the + * filename (via ). The @a timeout is the amount of + * time to wait to create/open the file. If it's 0 then we block + * indefinitely. If *timeout == {0, 0} then the file is created + * using non-blocking mode. In this case, if the create/open can't + * be done immediately the value of -1 is returned with . If *timeout > {0, 0} then this is the maximum amount of + * time to wait before timing out. If the time expires before the + * connection is made @c errno == ETIME. The @a local_sap and + * @a reuse_addr parameters are ignored. The @a flags and @a perms + * arguments are passed down to the method. + */ + int connect (ACE_FILE_IO &new_io, + const ACE_FILE_Addr &remote_sap, + ACE_Time_Value *timeout = 0, + const ACE_Addr &local_sap = ACE_Addr::sap_any, + int reuse_addr = 0, + int flags = O_RDWR | O_CREAT, + int perms = ACE_DEFAULT_FILE_PERMS); + + /// Resets any event associations on this handle + bool reset_new_handle (ACE_HANDLE handle); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Meta-type "trait" information. + typedef ACE_FILE_Addr PEER_ADDR; + typedef ACE_FILE_IO PEER_STREAM; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FILE_Connector.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FILE_CONNECTOR_H */ diff --git a/dep/acelite/ace/FILE_Connector.inl b/dep/acelite/ace/FILE_Connector.inl new file mode 100644 index 000000000..a12a6573b --- /dev/null +++ b/dep/acelite/ace/FILE_Connector.inl @@ -0,0 +1,32 @@ +// -*- C++ -*- +// Creates a Local ACE_FILE. + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_FILE_Connector::ACE_FILE_Connector (ACE_FILE_IO &new_io, + const ACE_FILE_Addr &remote_sap, + ACE_Time_Value *timeout, + const ACE_Addr &local_sap, + int reuse_addr, + int flags, + int perms) +{ + ACE_TRACE ("ACE_FILE_Connector::ACE_FILE_Connector"); + if (this->connect (new_io, remote_sap, timeout, local_sap, + reuse_addr, flags, perms) == ACE_IO_SAP::INVALID_HANDLE + && timeout != 0 && !(errno == EWOULDBLOCK || errno == ETIME)) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("address %s, %p\n"), + remote_sap.get_path_name (), + ACE_TEXT ("ACE_FILE_IO"))); +} + +ACE_INLINE bool +ACE_FILE_Connector::reset_new_handle (ACE_HANDLE) +{ + // Nothing to do here since the handle is not a socket + return false; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_IO.cpp b/dep/acelite/ace/FILE_IO.cpp new file mode 100644 index 000000000..1a999c83e --- /dev/null +++ b/dep/acelite/ace/FILE_IO.cpp @@ -0,0 +1,185 @@ +#include "ace/FILE_IO.h" + +#include "ace/Log_Category.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_Memory.h" +#include "ace/Truncate.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/FILE_IO.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_FILE_IO) + +void +ACE_FILE_IO::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_FILE_IO::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->addr_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Simple-minded do nothing constructor. + +ACE_FILE_IO::ACE_FILE_IO (void) +{ + ACE_TRACE ("ACE_FILE_IO::ACE_FILE_IO"); +} + +// Send N char *ptrs and int lengths. Note that the char *'s precede +// the ints (basically, an varargs version of writev). The count N is +// the *total* number of trailing arguments, *not* a couple of the +// number of tuple pairs! + +ssize_t +ACE_FILE_IO::send (size_t n, ...) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); +#ifdef ACE_LACKS_VA_FUNCTIONS + ACE_UNUSED_ARG (n); + ACE_NOTSUP_RETURN (-1); +#else + va_list argp; + int total_tuples = ACE_Utils::truncate_cast (n / 2); + iovec *iovp = 0; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t result = ACE_OS::writev (this->get_handle (), + iovp, + total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +#endif // ACE_LACKS_VA_FUNCTIONS +} + +// This is basically an interface to ACE_OS::readv, that doesn't use +// the struct iovec explicitly. The ... can be passed as an arbitrary +// number of (char *ptr, int len) tuples. However, the count N is the +// *total* number of trailing arguments, *not* a couple of the number +// of tuple pairs! + +ssize_t +ACE_FILE_IO::recv (size_t n, ...) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); +#ifdef ACE_LACKS_VA_FUNCTIONS + ACE_UNUSED_ARG (n); + ACE_NOTSUP_RETURN (-1); +#else + va_list argp; + int total_tuples = ACE_Utils::truncate_cast (n / 2); + iovec *iovp = 0; +#if defined (ACE_HAS_ALLOCA) + iovp = (iovec *) alloca (total_tuples * sizeof (iovec)); +#else +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_ALLOCATOR_RETURN (iovp, (iovec *) + ACE_Allocator::instance ()->malloc (total_tuples * + sizeof (iovec)), + -1); +# else + ACE_NEW_RETURN (iovp, + iovec[total_tuples], + -1); +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + + va_start (argp, n); + + for (int i = 0; i < total_tuples; i++) + { + iovp[i].iov_base = va_arg (argp, char *); + iovp[i].iov_len = va_arg (argp, int); + } + + ssize_t const result = ACE_OS::readv (this->get_handle (), + iovp, + total_tuples); +#if !defined (ACE_HAS_ALLOCA) +# ifdef ACE_HAS_ALLOC_HOOKS + ACE_Allocator::instance ()->free (iovp); +# else + delete [] iovp; +# endif /* ACE_HAS_ALLOC_HOOKS */ +#endif /* !defined (ACE_HAS_ALLOCA) */ + va_end (argp); + return result; +#endif // ACE_LACKS_VA_FUNCTIONS +} + +// Allows a client to read from a file without having to provide a +// buffer to read. This method determines how much data is in the +// file, allocates a buffer of this size, reads in the data, and +// returns the number of bytes read. + +ssize_t +ACE_FILE_IO::recvv (iovec *io_vec) +{ + ACE_TRACE ("ACE_FILE_IO::recvv"); + + io_vec->iov_base = 0; + ACE_OFF_T const length = ACE_OS::filesize (this->get_handle ()); + + if (length > 0) + { + // Restrict to max size we can record in iov_len. + size_t len = ACE_Utils::truncate_cast (length); +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (io_vec->iov_base, + static_cast(ACE_Allocator::instance()->malloc(sizeof(char) * len)), + -1); +#else + ACE_NEW_RETURN (io_vec->iov_base, + char[len], + -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + io_vec->iov_len = static_cast (this->recv_n (io_vec->iov_base, + len)); + return io_vec->iov_len; + } + else + { + return ACE_Utils::truncate_cast (length); + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/FILE_IO.h b/dep/acelite/ace/FILE_IO.h new file mode 100644 index 000000000..2ef049020 --- /dev/null +++ b/dep/acelite/ace/FILE_IO.h @@ -0,0 +1,168 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file FILE_IO.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_FILE_IO_H +#define ACE_FILE_IO_H +#include /**/ "ace/pre.h" + +#include "ace/FILE.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/FILE_Addr.h" + +// Used in the FILE_IO.h file... +#include "ace/os_include/os_stdio.h" +#include "ace/os_include/sys/os_uio.h" + +#if defined (ACE_HAS_STREAM_PIPES) +# include "ace/OS_NS_stropts.h" +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decl. +class ACE_Message_Block; +class ACE_Time_Value; + +/** + * @class ACE_FILE_IO + * + * @brief Read/Write operations on Files + */ +class ACE_Export ACE_FILE_IO : public ACE_FILE +{ +public: + friend class ACE_FILE_Connector; + + // = Initialization method. + /// Default constructor. + ACE_FILE_IO (void); + + /// send upto @a n bytes in @a buf. + ssize_t send (const void *buf, size_t n) const; + + /// Recv upto @a n bytes in @a buf. + ssize_t recv (void *buf, size_t n) const; + + /// Send n bytes, keep trying until n are sent. + ssize_t send_n (const void *buf, size_t n) const; + + /// Send all the @a message_blocks chained through their next and + /// cont pointers. This call uses the underlying OS gather-write + /// operation to reduce the domain-crossing penalty. + ssize_t send_n (const ACE_Message_Block *message_block, + const ACE_Time_Value *timeout = 0, + size_t *bytes_transferred = 0); + + /// Recv n bytes, keep trying until n are received. + ssize_t recv_n (void *buf, size_t n) const; + +#if defined (ACE_HAS_STREAM_PIPES) + /// Send bytes via STREAM pipes. + ssize_t send (const ACE_Str_Buf *cntl, + const ACE_Str_Buf *data, + int flags = 0) const; + + /// Recv bytes via STREAM pipes. + ssize_t recv (ACE_Str_Buf *cntl, + ACE_Str_Buf *data, + int *flags) const; + + /// Send bytes via STREAM pipes using "band" mode. + ssize_t send (const ACE_Str_Buf *cntl, + const ACE_Str_Buf *data, + int band, + int flags) const; + + /// Recv bytes via STREAM pipes using "band" mode. + ssize_t recv (ACE_Str_Buf *cntl, + ACE_Str_Buf *data, + int *band, + int *flags) const; + +#endif /* ACE_HAS_STREAM_PIPES */ + + /// Send iovecs via <::writev>. + ssize_t send (const iovec iov[], int n) const; + + /// Recv iovecs via <::readv>. + ssize_t recv (iovec iov[], int n) const; + + /** + * Send N char *ptrs and int lengths. Note that the char *'s + * precede the ints (basically, an varargs version of writev). The + * count N is the *total* number of trailing arguments, *not* a + * couple of the number of tuple pairs! + */ + ssize_t send (size_t n, ...) const; + + /** + * This is an interface to ::readv, that doesn't use the struct + * iovec explicitly. The ... can be passed as an arbitrary number + * of (char *ptr, int len) tuples. However, the count N is the + * *total* number of trailing arguments, *not* a couple of the + * number of tuple pairs! + */ + ssize_t recv (size_t n, ...) const; + + /// Send @a n bytes via Win32 WriteFile using overlapped I/O. + ssize_t send (const void *buf, + size_t n, + ACE_OVERLAPPED *overlapped) const; + + /// Recv @a n bytes via Win32 ReadFile using overlapped I/O. + ssize_t recv (void *buf, + size_t n, + ACE_OVERLAPPED *overlapped) const; + + /// Send an @c iovec of size @a n to the file. + ssize_t sendv (const iovec iov[], + int n) const; + + /** + * Allows a client to read from a file without having to provide a + * buffer to read. This method determines how much data is in the + * file, allocates a buffer of this size, reads in the data, and + * returns the number of bytes read. The caller is responsible for + * deleting the member in the field of using + * delete [] io_vec->iov_base. + */ + ssize_t recvv (iovec *io_vec); + + /// Send an of size @a n to the file. Will block until all + /// bytes are sent or an error occurs. + ssize_t sendv_n (const iovec iov[], + int n) const; + + /// Receive an of size @a n to the file. + ssize_t recvv_n (iovec iov[], + int n) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Meta-type info + typedef ACE_FILE_Addr PEER_ADDR; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/FILE_IO.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FILE_IO_H */ diff --git a/dep/acelite/ace/FILE_IO.inl b/dep/acelite/ace/FILE_IO.inl new file mode 100644 index 000000000..57c300490 --- /dev/null +++ b/dep/acelite/ace/FILE_IO.inl @@ -0,0 +1,149 @@ +// -*- C++ -*- +#include "ace/ACE.h" +#include "ace/OS_NS_sys_uio.h" +#include "ace/OS_NS_unistd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ssize_t +ACE_FILE_IO::sendv_n (const iovec iov[], int n) const +{ + ACE_TRACE ("ACE_FILE_IO::sendv_n"); + return ACE::writev_n (this->get_handle (), + iov, + n); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send_n (const ACE_Message_Block *message_block, + const ACE_Time_Value *timeout, + size_t *bytes_transferred) +{ + ACE_TRACE ("ACE_FILE_IO::send_n"); + ACE_UNUSED_ARG (timeout); + return ACE::write_n (this->get_handle (), + message_block, + bytes_transferred); +} + +// Recv an n byte message from the file. + +ACE_INLINE ssize_t +ACE_FILE_IO::recvv_n (iovec iov[], int n) const +{ + ACE_TRACE ("ACE_FILE_IO::recvv_n"); + // @@ Carlos, can you please update this to call the + // new ACE::recvv_n() method that you write? + return ACE_OS::readv (this->get_handle (), + iov, + n); +} + +// Send an of size to the file. + +ACE_INLINE ssize_t +ACE_FILE_IO::sendv (const iovec iov[], int n) const +{ + ACE_TRACE ("ACE_FILE_IO::sendv"); + return ACE_OS::writev (this->get_handle (), iov, n); +} + +// Send exactly N bytes from BUF to this file. Keeping trying until +// this many bytes are sent. + +ACE_INLINE ssize_t +ACE_FILE_IO::send_n (const void *buf, size_t n) const +{ + ACE_TRACE ("ACE_FILE_IO::send_n"); + return ACE::write_n (this->get_handle (), buf, n); +} + +// Receive exactly N bytes from this file into BUF. Keep trying until +// this many bytes are received. + +ACE_INLINE ssize_t +ACE_FILE_IO::recv_n (void *buf, size_t n) const +{ + ACE_TRACE ("ACE_FILE_IO::recv_n"); + return ACE::read_n (this->get_handle (), buf, n); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send (const void *buf, size_t n) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); + return ACE_OS::write (this->get_handle (), buf, n); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::recv (void *buf, size_t n) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); + return ACE_OS::read (this->get_handle (), buf, n); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send (const iovec iov[], int n) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); + return ACE_OS::writev (this->get_handle (), iov, n); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::recv (iovec iov[], int n) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); + return ACE_OS::readv (this->get_handle (), iov, n); +} + +#if defined (ACE_HAS_STREAM_PIPES) +ACE_INLINE ssize_t +ACE_FILE_IO::recv (ACE_Str_Buf *cntl, ACE_Str_Buf *data, int *band, int *flags) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); + return ACE_OS::getpmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, band, flags); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send (const ACE_Str_Buf *cntl, const ACE_Str_Buf *data, int band, int flags) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); + return ACE_OS::putpmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, band, flags); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::recv (ACE_Str_Buf *cntl, ACE_Str_Buf *data, int *flags) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); + return ACE_OS::getmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, flags); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send (const ACE_Str_Buf *cntl, const ACE_Str_Buf *data, int flags) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); + return ACE_OS::putmsg (this->get_handle (), (strbuf *) cntl, (strbuf *) data, flags); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::send (const void *buf, size_t n, + ACE_OVERLAPPED *overlapped) const +{ + ACE_TRACE ("ACE_FILE_IO::send"); + return ACE_OS::write (this->get_handle (), + buf, n, + overlapped); +} + +ACE_INLINE ssize_t +ACE_FILE_IO::recv (void *buf, size_t n, + ACE_OVERLAPPED *overlapped) const +{ + ACE_TRACE ("ACE_FILE_IO::recv"); + return ACE_OS::read (this->get_handle (), buf, n, + overlapped); +} + +#endif /* ACE_HAS_STREAM_PIPES */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/File_Lock.cpp b/dep/acelite/ace/File_Lock.cpp new file mode 100644 index 000000000..f5e421acb --- /dev/null +++ b/dep/acelite/ace/File_Lock.cpp @@ -0,0 +1,73 @@ +#include "ace/File_Lock.h" +#include "ace/Log_Category.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/File_Lock.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_File_Lock) + +void +ACE_File_Lock::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_File_Lock::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->lock_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_File_Lock::ACE_File_Lock (ACE_HANDLE h, + bool unlink_in_destructor) + : removed_ (false), + unlink_in_destructor_ (unlink_in_destructor) +{ +// ACE_TRACE ("ACE_File_Lock::ACE_File_Lock"); + if (ACE_OS::flock_init (&this->lock_) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_File_Lock::ACE_File_Lock"))); + this->set_handle (h); +} + +ACE_File_Lock::ACE_File_Lock (const ACE_TCHAR *name, + int flags, + mode_t perms, + bool unlink_in_destructor) + : unlink_in_destructor_ (unlink_in_destructor) +{ +// ACE_TRACE ("ACE_File_Lock::ACE_File_Lock"); + + if (this->open (name, flags, perms) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p %s\n"), + ACE_TEXT ("ACE_File_Lock::ACE_File_Lock"), + name)); +} + +int +ACE_File_Lock::open (const ACE_TCHAR *name, + int flags, + mode_t perms) +{ +// ACE_TRACE ("ACE_File_Lock::open"); + this->removed_ = false; + return ACE_OS::flock_init (&this->lock_, flags, name, perms); +} + +ACE_File_Lock::~ACE_File_Lock (void) +{ +// ACE_TRACE ("ACE_File_Lock::~ACE_File_Lock"); + this->remove (this->unlink_in_destructor_); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/File_Lock.h b/dep/acelite/ace/File_Lock.h new file mode 100644 index 000000000..d71e42c00 --- /dev/null +++ b/dep/acelite/ace/File_Lock.h @@ -0,0 +1,168 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file File_Lock.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_FILE_LOCK_H +#define ACE_FILE_LOCK_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_stdio.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_File_Lock + * + * @brief A wrapper around the UNIX file locking mechanism. + * + * Allows us to "adapt" the UNIX file locking mechanisms to work + * with all of our Guard stuff... + */ +class ACE_Export ACE_File_Lock +{ +public: + /** + * Set the of the File_Lock to @a handle. Note that this + * constructor assumes ownership of the @a handle and will close it + * down in . If you want the @a handle to stay open when + * is called make sure to call on the @a handle. + * If you don't want the file unlinked in the destructor pass a + * zero value for . + */ + ACE_File_Lock (ACE_HANDLE handle = ACE_INVALID_HANDLE, + bool unlink_in_destructor = true); + + /// Open the @a filename with @a flags and @a mode and set the result + /// to . If you don't want the file unlinked in the + /// destructor pass a false value for @a unlink_in_destructor. + ACE_File_Lock (const ACE_TCHAR *filename, + int flags, + mode_t mode = 0, + bool unlink_in_destructor = true); + + /// Open the @a filename with @a flags and @a mode and set the result to + /// . + int open (const ACE_TCHAR *filename, + int flags, + mode_t mode = 0); + + /// Remove a File lock by releasing it and closing down the . + ~ACE_File_Lock (void); + + /// Remove a File lock by releasing it and closing down the + /// . If @a unlink_file is true then we unlink the file. + int remove (bool unlink_file = true); + + /** + * Note, for interface uniformity with other synchronization + * wrappers we include the acquire() method. This is implemented as + * a write-lock to be on the safe-side... + */ + int acquire (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /** + * Note, for interface uniformity with other synchronization + * wrappers we include the method. This is implemented + * as a write-lock to be on the safe-side... Returns -1 on failure. + * If we "failed" because someone else already had the lock, @c errno + * is set to @c EBUSY. + */ + int tryacquire (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /// Unlock a readers/writer lock. + int release (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /// Acquire a write lock, but block if any readers or a + /// writer hold the lock. + int acquire_write (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /** + * Conditionally acquire a write lock (i.e., won't block). Returns + * -1 on failure. If we "failed" because someone else already had + * the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_write (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /** + * Conditionally upgrade to a write lock (i.e., won't block). Returns + * -1 on failure. If we "failed" because someone else already had + * the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_write_upgrade (short whence = 0, + ACE_OFF_T start = 0, + ACE_OFF_T len = 1); + + /** + * Acquire a read lock, but block if a writer hold the lock. + * Returns -1 on failure. If we "failed" because someone else + * already had the lock, @c errno is set to @c EBUSY. + */ + int acquire_read (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /** + * Conditionally acquire a read lock (i.e., won't block). Returns + * -1 on failure. If we "failed" because someone else already had + * the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_read (short whence = 0, ACE_OFF_T start = 0, ACE_OFF_T len = 1); + + /// Get underlying ACE_HANDLE for the file. + ACE_HANDLE get_handle (void) const; + + /** + * Set underlying ACE_HANDLE. Note that this method assumes + * ownership of the @a handle and will close it down in . If + * you want the @a handle to stay open when is called make + * sure to call on the @a handle before closing it. You are + * responsible for the closing the existing @a handle before + * overwriting it. + */ + void set_handle (ACE_HANDLE); + + /// Dump state of the object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Locking structure for OS record locks. + ACE_OS::ace_flock_t lock_; + + /// Keeps track of whether has been called yet to avoid + /// multiple calls, e.g., explicitly and implicitly in the + /// destructor. This flag isn't protected by a lock, so make sure + /// that you don't have multiple threads simultaneously calling + /// on the same object, which is a bad idea anyway... + bool removed_; + + /// Keeps track of whether to unlink the underlying file in the + /// destructor. + bool const unlink_in_destructor_; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_File_Lock &); + ACE_File_Lock (const ACE_File_Lock &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/File_Lock.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FILE_LOCK_H */ diff --git a/dep/acelite/ace/File_Lock.inl b/dep/acelite/ace/File_Lock.inl new file mode 100644 index 000000000..fb9ae6e0c --- /dev/null +++ b/dep/acelite/ace/File_Lock.inl @@ -0,0 +1,93 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_File_Lock::acquire_read (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::acquire_read"); + return ACE_OS::flock_rdlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::tryacquire_read (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::tryacquire_read"); + return ACE_OS::flock_tryrdlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::tryacquire_write (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::tryacquire_write"); + return ACE_OS::flock_trywrlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::tryacquire_write_upgrade (short whence, + ACE_OFF_T start, + ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::tryacquire_write_upgrade"); + return ACE_OS::flock_trywrlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::tryacquire (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::tryacquire"); + return this->tryacquire_write (whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::acquire_write (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::acquire_write"); + return ACE_OS::flock_wrlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::acquire (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::acquire"); + return this->acquire_write (whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::release (short whence, ACE_OFF_T start, ACE_OFF_T len) +{ +// ACE_TRACE ("ACE_File_Lock::release"); + return ACE_OS::flock_unlock (&this->lock_, whence, start, len); +} + +ACE_INLINE int +ACE_File_Lock::remove (bool unlink_file) +{ +// ACE_TRACE ("ACE_File_Lock::remove"); + + int result = 0; + + if (!this->removed_) + { + this->removed_ = true; + result = ACE_OS::flock_destroy (&this->lock_, + unlink_file); + } + return result; +} + +ACE_INLINE ACE_HANDLE +ACE_File_Lock::get_handle (void) const +{ +// ACE_TRACE ("ACE_File_Lock::get_handle"); + return this->lock_.handle_; +} + +ACE_INLINE void +ACE_File_Lock::set_handle (ACE_HANDLE h) +{ +// ACE_TRACE ("ACE_File_Lock::set_handle"); + this->lock_.handle_ = h; + this->removed_ = false; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Filecache.cpp b/dep/acelite/ace/Filecache.cpp new file mode 100644 index 000000000..6916367bc --- /dev/null +++ b/dep/acelite/ace/Filecache.cpp @@ -0,0 +1,749 @@ +#include "ace/Filecache.h" +#include "ace/Object_Manager.h" +#include "ace/Log_Category.h" +#include "ace/ACE.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/Truncate.h" + +#if defined (ACE_WIN32) +// Specifies no sharing flags. +#define R_MASK ACE_DEFAULT_OPEN_PERMS +#define W_MASK 0 +#else +#define R_MASK S_IRUSR|S_IRGRP|S_IROTH +#define W_MASK S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH +#endif /* ACE_WIN32 */ + +#if defined (ACE_WIN32) +// See if you can get rid of some of these. +#define READ_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \ + FILE_FLAG_OVERLAPPED | \ + O_RDONLY) +// static const int RCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN | +// O_RDONLY); +#define WRITE_FLAGS (FILE_FLAG_SEQUENTIAL_SCAN | \ + FILE_FLAG_OVERLAPPED | \ + O_RDWR | O_CREAT | O_TRUNC) +// static const int WCOPY_FLAGS = (FILE_FLAG_SEQUENTIAL_SCAN | +// O_RDWR | O_CREAT | O_TRUNC); +#else +#define READ_FLAGS O_RDONLY +// static const int RCOPY_FLAGS = O_RDONLY; +#define WRITE_FLAGS (O_RDWR | O_CREAT | O_TRUNC) +// static const int WCOPY_FLAGS = O_RDWR | O_CREAT | O_TRUNC; +#endif /* ACE_WIN32 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// static data members +ACE_Filecache *ACE_Filecache::cvf_ = 0; + +void +ACE_Filecache_Handle::init (void) +{ + this->file_ = 0; + this->handle_ = ACE_INVALID_HANDLE; +} + +ACE_Filecache_Handle::ACE_Filecache_Handle (void) + : file_ (0), handle_ (0) +{ + this->init (); +} + +ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename, + ACE_Filecache_Flag mapit) + : file_ (0), handle_ (0) +{ + this->init (); + // Fetch the file from the Virtual_Filesystem let the + // Virtual_Filesystem do the work of cache coherency. + + // Filecache will also do the acquire, since it holds the lock at + // that time. + this->file_ = ACE_Filecache::instance ()->fetch (filename, mapit); +} + +ACE_Filecache_Handle::ACE_Filecache_Handle (const ACE_TCHAR *filename, + int size, + ACE_Filecache_Flag ) + : file_ (0), handle_ (0) +{ + this->init (); + + if (size == 0) + ACE_Filecache::instance ()->remove (filename); + else + { + // Since this is being opened for a write, simply create a new + // ACE_Filecache_Object now, and let the destructor add it into CVF + // later + + // Filecache will also do the acquire, since it holds the lock at + // that time. + this->file_ = ACE_Filecache::instance ()->create (filename, size); + } +} + +ACE_Filecache_Handle::~ACE_Filecache_Handle (void) +{ + if (this->handle_ != ACE_INVALID_HANDLE) + // this was dup ()'d + ACE_OS::close (this->handle_); + + ACE_Filecache::instance ()->finish (this->file_); +} + +void * +ACE_Filecache_Handle::address (void) const +{ + return this->file_ == 0 ? 0 : this->file_->address (); +} + +ACE_HANDLE +ACE_Filecache_Handle::handle (void) const +{ + if (this->handle_ == ACE_INVALID_HANDLE && this->file_ != 0) + { + ACE_Filecache_Handle *mutable_this = + const_cast (this); + mutable_this->handle_ = ACE_OS::dup (this->file_->handle ()); + } + return this->handle_; +} + +int +ACE_Filecache_Handle::error (void) const +{ + if (this->file_ == 0) + return -1; + else + return this->file_->error (); +} + +ACE_OFF_T +ACE_Filecache_Handle::size (void) const +{ + if (this->file_ == 0) + return -1; + else + return this->file_->size (); +} + +// ------------------ +// ACE_Filecache_Hash +// ------------------ + +#define ACE_Filecache_Hash \ + ACE_Hash_Map_Manager_Ex, ACE_Equal_To, ACE_Null_Mutex> +#define ACE_Filecache_Hash_Entry \ + ACE_Hash_Map_Entry + +template <> +ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry ( + const ACE_TCHAR *const &ext_id, + ACE_Filecache_Object *const &int_id, + ACE_Filecache_Hash_Entry *next, + ACE_Filecache_Hash_Entry *prev) + : ext_id_ (ext_id + ? ACE_OS::strdup (ext_id) + : ACE_OS::strdup (ACE_TEXT (""))), + int_id_ (int_id), + next_ (next), + prev_ (prev) +{ +} + +template <> +ACE_Filecache_Hash_Entry::ACE_Hash_Map_Entry (ACE_Filecache_Hash_Entry *next, + ACE_Filecache_Hash_Entry *prev) + : ext_id_ (0), + int_id_ (0), + next_ (next), + prev_ (prev) +{ +} + +template <> +ACE_Filecache_Hash_Entry::~ACE_Hash_Map_Entry (void) +{ +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free ((void *) ext_id_); +#else + ACE_OS::free ((void *) ext_id_); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +// We need these template specializations since KEY is defined as a +// ACE_TCHAR*, which doesn't have a hash() or equal() method defined on it. + +template <> +unsigned long +ACE_Filecache_Hash::hash (const ACE_TCHAR *const &ext_id) +{ + return ACE::hash_pjw (ext_id); +} + +template <> +int +ACE_Filecache_Hash::equal (const ACE_TCHAR *const &id1, + const ACE_TCHAR *const &id2) +{ + return ACE_OS::strcmp (id1, id2) == 0; +} + +#undef ACE_Filecache_Hash +#undef ACE_Filecache_Hash_Entry + + +// ------------- +// ACE_Filecache +// ------------- + +ACE_Filecache * +ACE_Filecache::instance (void) +{ + // Double check locking pattern. + if (ACE_Filecache::cvf_ == 0) + { + ACE_SYNCH_RW_MUTEX &lock = + *ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_FILECACHE_LOCK); + ACE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, ace_mon, lock, 0); + + // @@ James, please check each of the ACE_NEW_RETURN calls to + // make sure that it is safe to return if allocation fails. + if (ACE_Filecache::cvf_ == 0) + ACE_NEW_RETURN (ACE_Filecache::cvf_, + ACE_Filecache, + 0); + } + + return ACE_Filecache::cvf_; +} + +ACE_Filecache::ACE_Filecache (void) + : size_ (ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE), + hash_ (size_) +{ +} + +ACE_Filecache::~ACE_Filecache (void) +{ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Filecache) + +ACE_Filecache_Object * +ACE_Filecache::insert_i (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &filelock, + int mapit) +{ + ACE_Filecache_Object *handle = 0; + + if (this->hash_.find (filename, handle) == -1) + { + ACE_NEW_RETURN (handle, + ACE_Filecache_Object (filename, filelock, 0, mapit), + 0); + + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: creating %s\n"), filename)); + + if (this->hash_.bind (filename, handle) == -1) + { + delete handle; + handle = 0; + } + } + else + handle = 0; + + return handle; +} + +ACE_Filecache_Object * +ACE_Filecache::remove_i (const ACE_TCHAR *filename) +{ + ACE_Filecache_Object *handle = 0; + + // Disassociate file from the cache. + if (this->hash_.unbind (filename, handle) == 0) + { + handle->stale_ = 1; + + // Try a lock. If it succeeds, we can delete it now. + // Otherwise, it will clean itself up later. + if (handle->lock_.tryacquire_write () == 0) + { + delete handle; + handle = 0; + } + } + else + handle = 0; + + return handle; +} + +ACE_Filecache_Object * +ACE_Filecache::update_i (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &filelock, + int mapit) +{ + ACE_Filecache_Object *handle = 0; + + handle = this->remove_i (filename); + handle = this->insert_i (filename, filelock, mapit); + + return handle; +} + +int +ACE_Filecache::find (const ACE_TCHAR *filename) +{ + return this->hash_.find (filename); +} + + +ACE_Filecache_Object * +ACE_Filecache::remove (const ACE_TCHAR *filename) +{ + ACE_Filecache_Object *handle = 0; + + ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_; + ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc]; + // ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc]; + + if (this->hash_.find (filename, handle) != -1) + { + ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, + ace_mon, + hashlock, + 0); + + return this->remove_i (filename); + } + + return 0; +} + + +ACE_Filecache_Object * +ACE_Filecache::fetch (const ACE_TCHAR *filename, int mapit) +{ + ACE_Filecache_Object *handle = 0; + + ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_; + ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc]; + ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc]; + + filelock.acquire_read (); + + if (this->hash_.find (filename, handle) == -1) + { + ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, + ace_mon, + hashlock, + 0); + + // Second check in the method call + handle = this->insert_i (filename, filelock, mapit); + + if (handle == 0) + filelock.release (); + } + else + { + if (handle->update ()) + { + { + // Double check locking pattern + ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, + ace_mon, + hashlock, + 0); + + // Second check in the method call + handle = this->update_i (filename, filelock, mapit); + + if (handle == 0) + filelock.release (); + } + } + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (%t) CVF: found %s\n"), filename)); + } + + return handle; +} + +ACE_Filecache_Object * +ACE_Filecache::create (const ACE_TCHAR *filename, int size) +{ + ACE_Filecache_Object *handle = 0; + + ACE_OFF_T loc = ACE::hash_pjw (filename) % this->size_; + ACE_SYNCH_RW_MUTEX &filelock = this->file_lock_[loc]; + + ACE_NEW_RETURN (handle, + ACE_Filecache_Object (filename, size, filelock), + 0); + handle->acquire (); + + return handle; +} + +ACE_Filecache_Object * +ACE_Filecache::finish (ACE_Filecache_Object *&file) +{ + if (file == 0) + return file; + + ACE_OFF_T loc = ACE::hash_pjw (file->filename_) % this->size_; + ACE_SYNCH_RW_MUTEX &hashlock = this->hash_lock_[loc]; + + if (file != 0) + switch (file->action_) + { + case ACE_Filecache_Object::ACE_WRITING: + { + ACE_WRITE_GUARD_RETURN (ACE_SYNCH_RW_MUTEX, + ace_mon, + hashlock, + 0); + + file->release (); + + this->remove_i (file->filename_); +#if 0 + int result = this->hash_.bind (file->filename (), file); + + if (result == 0) + file->acquire (); +#else + // Last one using a stale file is resposible for deleting it. + if (file->stale_) + { + // Try a lock. If it succeds, we can delete it now. + // Otherwise, it will clean itself up later. + if (file->lock_.tryacquire_write () == 0) + { + delete file; + file = 0; + } + } +#endif + } + + break; + default: + file->release (); + + // Last one using a stale file is resposible for deleting it. + if (file->stale_) + { + // Try a lock. If it succeds, we can delete it now. + // Otherwise, it will clean itself up later. + if (file->lock_.tryacquire_write () == 0) + { + delete file; + file = 0; + } + } + + break; + } + + return file; +} + +void +ACE_Filecache_Object::init (void) +{ + this->filename_[0] = '\0'; + this->handle_ = ACE_INVALID_HANDLE; + this->error_ = ACE_SUCCESS; + this->tempname_ = 0; + this->size_ = 0; + + ACE_OS::memset (&(this->stat_), 0, sizeof (this->stat_)); +} + +ACE_Filecache_Object::ACE_Filecache_Object (void) + : tempname_ (0), + mmap_ (), + handle_ (0), + // stat_ (), + size_ (0), + action_ (0), + error_ (0), + stale_ (0), + // sa_ (), + junklock_ (), + lock_ (junklock_) +{ + this->init (); +} + +ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &lock, + LPSECURITY_ATTRIBUTES sa, + int mapit) + : tempname_ (0), + mmap_ (), + handle_ (0), + // stat_ (), + size_ (0), + action_ (0), + error_ (0), + stale_ (0), + sa_ (sa), + junklock_ (), + lock_ (lock) +{ + this->init (); + + // ASSERT strlen(filename) < sizeof (this->filename_) + ACE_OS::strcpy (this->filename_, filename); + this->action_ = ACE_Filecache_Object::ACE_READING; + // place ourselves into the READING state + + // Can we access the file? + if (ACE_OS::access (this->filename_, R_OK) == -1) + { + this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED); + return; + } + + // Can we stat the file? + if (ACE_OS::stat (this->filename_, &this->stat_) == -1) + { + this->error_i (ACE_Filecache_Object::ACE_STAT_FAILED); + return; + } + + this->size_ = ACE_Utils::truncate_cast (this->stat_.st_size); + this->tempname_ = this->filename_; + + // Can we open the file? + this->handle_ = ACE_OS::open (this->tempname_, + READ_FLAGS, R_MASK, this->sa_); + if (this->handle_ == ACE_INVALID_HANDLE) + { + this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED, + ACE_TEXT ("ACE_Filecache_Object::ctor: open")); + return; + } + + if (mapit) + { + // Can we map the file? + if (this->mmap_.map (this->handle_, static_cast (-1), + PROT_READ, ACE_MAP_PRIVATE, 0, 0, this->sa_) != 0) + { + this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED, + ACE_TEXT ("ACE_Filecache_Object::ctor: map")); + ACE_OS::close (this->handle_); + this->handle_ = ACE_INVALID_HANDLE; + return; + } + } + + // Ok, finished! + this->action_ = ACE_Filecache_Object::ACE_READING; +} + +ACE_Filecache_Object::ACE_Filecache_Object (const ACE_TCHAR *filename, + ACE_OFF_T size, + ACE_SYNCH_RW_MUTEX &lock, + LPSECURITY_ATTRIBUTES sa) + : stale_ (0), + sa_ (sa), + lock_ (lock) +{ + this->init (); + + this->size_ = size; + ACE_OS::strcpy (this->filename_, filename); + this->action_ = ACE_Filecache_Object::ACE_WRITING; + + // Can we access the file? + if (ACE_OS::access (this->filename_, R_OK|W_OK) == -1 + // Does it exist? + && ACE_OS::access (this->filename_, F_OK) != -1) + { + // File exists, but we cannot access it. + this->error_i (ACE_Filecache_Object::ACE_ACCESS_FAILED); + return; + } + + this->tempname_ = this->filename_; + + // Can we open the file? + this->handle_ = ACE_OS::open (this->tempname_, WRITE_FLAGS, W_MASK, this->sa_); + if (this->handle_ == ACE_INVALID_HANDLE) + { + this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED, + ACE_TEXT ("ACE_Filecache_Object::acquire: open")); + return; + } + + // Can we write? + if (ACE_OS::pwrite (this->handle_, "", 1, this->size_ - 1) != 1) + { + this->error_i (ACE_Filecache_Object::ACE_WRITE_FAILED, + ACE_TEXT ("ACE_Filecache_Object::acquire: write")); + ACE_OS::close (this->handle_); + return; + } + + // Can we map? + if (this->mmap_.map (this->handle_, this->size_, PROT_RDWR, MAP_SHARED, + 0, 0, this->sa_) != 0) + { + this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED, + ACE_TEXT ("ACE_Filecache_Object::acquire: map")); + ACE_OS::close (this->handle_); + } + + // Ok, done! +} + +ACE_Filecache_Object::~ACE_Filecache_Object (void) +{ + if (this->error_ == ACE_SUCCESS) + { + this->mmap_.unmap (); + ACE_OS::close (this->handle_); + this->handle_ = ACE_INVALID_HANDLE; + } + + this->lock_.release (); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Filecache_Object) + +int +ACE_Filecache_Object::acquire (void) +{ + return this->lock_.tryacquire_read (); +} + +int +ACE_Filecache_Object::release (void) +{ + if (this->action_ == ACE_WRITING) + { + // We are safe since only one thread has a writable Filecache_Object + +#if 0 + ACE_HANDLE original = ACE_OS::open (this->filename_, WRITE_FLAGS, W_MASK, + this->sa_); + if (original == ACE_INVALID_HANDLE) + this->error_ = ACE_Filecache_Object::ACE_OPEN_FAILED; + else if (ACE_OS::write (original, this->mmap_.addr (), + this->size_) == -1) + { + this->error_ = ACE_Filecache_Object::ACE_WRITE_FAILED; + ACE_OS::close (original); + ACE_OS::unlink (this->filename_); + } + else if (ACE_OS::stat (this->filename_, &this->stat_) == -1) + this->error_ = ACE_Filecache_Object::ACE_STAT_FAILED; +#endif + + this->mmap_.unmap (); + ACE_OS::close (this->handle_); + this->handle_ = ACE_INVALID_HANDLE; + +#if 0 + // Leave the file in an acquirable state. + this->handle_ = ACE_OS::open (this->tempname_, READ_FLAGS, R_MASK); + if (this->handle_ == ACE_INVALID_HANDLE) + { + this->error_i (ACE_Filecache_Object::ACE_OPEN_FAILED, + "ACE_Filecache_Object::acquire: open"); + } + else if (this->mmap_.map (this->handle_, -1, + PROT_READ, + ACE_MAP_PRIVATE, + 0, + 0, + this->sa_) != 0) + { + this->error_i (ACE_Filecache_Object::ACE_MEMMAP_FAILED, + "ACE_Filecache_Object::acquire: map"); + ACE_OS::close (this->handle_); + this->handle_ = ACE_INVALID_HANDLE; + } + + this->action_ = ACE_Filecache_Object::ACE_READING; +#endif + } + + return this->lock_.release (); +} + +int +ACE_Filecache_Object::error (void) const +{ + // The existence of the object means a read lock is being held. + return this->error_; +} + +int +ACE_Filecache_Object::error_i (int error_value, const ACE_TCHAR *s) +{ + ACE_UNUSED_ARG (s); + ACELIB_ERROR ((LM_ERROR, ACE_TEXT ("%p.\n"), s)); + this->error_ = error_value; + return error_value; +} + +const ACE_TCHAR * +ACE_Filecache_Object::filename (void) const +{ + // The existence of the object means a read lock is being held. + return this->filename_; +} + +ACE_OFF_T +ACE_Filecache_Object::size (void) const +{ + // The existence of the object means a read lock is being held. + return this->size_; +} + +ACE_HANDLE +ACE_Filecache_Object::handle (void) const +{ + // The existence of the object means a read lock is being held. + return this->handle_; +} + +void * +ACE_Filecache_Object::address (void) const +{ + // The existence of the object means a read lock is being held. + return this->mmap_.addr (); +} + +int +ACE_Filecache_Object::update (void) const +{ + // The existence of the object means a read lock is being held. + int result; + ACE_stat statbuf; + + if (ACE_OS::stat (this->filename_, &statbuf) == -1) + result = 1; + else + result = ACE_OS::difftime (this->stat_.st_mtime, statbuf.st_mtime) < 0; + + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Filecache.h b/dep/acelite/ace/Filecache.h new file mode 100644 index 000000000..fb66ea3ab --- /dev/null +++ b/dep/acelite/ace/Filecache.h @@ -0,0 +1,356 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Filecache.h + * + * @author James Hu + */ +//============================================================================= + + +#ifndef ACE_FILECACHE_H +#define ACE_FILECACHE_H + +#include /**/ "ace/pre.h" + +#include "ace/Mem_Map.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Null_Mutex.h" +#include "ace/Synch_Traits.h" +#include "ace/RW_Thread_Mutex.h" +#include "ace/OS_NS_sys_stat.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +enum ACE_Filecache_Flag +{ + ACE_NOMAP = 0, + ACE_MAPIT = 1 +}; + +class ACE_Filecache_Object; + +/** + * @class ACE_Filecache_Handle + * + * @brief + * Abstraction over a real file. This is meant to be the entry + * point into the Cached Virtual Filesystem. + * + * This is a cached filesystem implementation based loosely on the + * implementation of JAWS_File. The interfaces will be nearly the + * same. The under-the-hood implementation should hopefully be a + * much faster thing. + * These will be given their own implementations later. For now, we + * borrow the implementation provided by JAWS. + * On creation, the cache is checked, and reference count is + * incremented. On destruction, reference count is decremented. If + * the reference count is 0, the file is removed from the cache. + * E.g. 1, + * { + * ACE_Filecache_Handle foo("foo.html"); + * this->peer ().send (foo.address (), foo.size ()); + * } + * E.g. 2, + * { + * ACE_Filecache_Handle foo("foo.html"); + * io->transmitfile (foo.handle (), this->peer ().handle ()); + * } + * E.g. 3, + * { + * ACE_Filecache_Handle foo("foo.html", content_length); + * this->peer ().recv (foo.address (), content_length); + * } + * TODO: + */ +class ACE_Export ACE_Filecache_Handle +{ + // (1) Get rid of the useless copying of files when reading. + // Although it does make sure the file you send isn't being changed, + // it doesn't make sure the file is in a sensible state before + // sending it. + // + // Alternative: if the file get's trashed while it is being shipped, + // let the client request the file again. The cache should have an + // updated copy by that point. + // + // (2) Use hashing for locating files. This means I need a hastable + // implementation with buckets. + // + // (3) Only lock when absolutely necessary. JAWS_Virtual_Filesystem was + // rather conservative, but for some reason it still ran into problems. + // Since this design should be simpler, problems should be easier to spot. + // +public: + + /// Query cache for file, and acquire it. Assumes the file is being + /// opened for reading. + ACE_Filecache_Handle (const ACE_TCHAR *filename, + ACE_Filecache_Flag mapit = ACE_MAPIT); + + /** + * Create new entry, and acquire it. Presence of SIZE assumes the + * file is being opened for writing. If SIZE is zero, assumes the + * file is to be removed from the cache. + */ + ACE_Filecache_Handle (const ACE_TCHAR *filename, + int size, + ACE_Filecache_Flag mapit = ACE_MAPIT); + + /// Closes any open handles, release acquired file. + ~ACE_Filecache_Handle (void); + + /// Base address of memory mapped file. + void *address (void) const; + + /// A handle (e.g., UNIX file descriptor, or NT file handle). + ACE_HANDLE handle (void) const; + + /// Any associated error in handle creation and acquisition. + int error (void) const; + + /// The size of the file. + ACE_OFF_T size (void) const; + +protected: + /// Default do nothing constructor. Prevent it from being called. + ACE_Filecache_Handle (void); + + /// Common initializations for constructors. + void init (void); + +public: + /// These come from ACE_Filecache_Object, which is an internal class. + enum + { + ACE_SUCCESS = 0, + ACE_ACCESS_FAILED, + ACE_OPEN_FAILED, + ACE_COPY_FAILED, + ACE_STAT_FAILED, + ACE_MEMMAP_FAILED, + ACE_WRITE_FAILED + }; + +private: + /// A reference to the low level instance. + ACE_Filecache_Object *file_; + + /// A dup'd version of the one from file_. + ACE_HANDLE handle_; +}; + +typedef ACE_Hash_Map_Manager_Ex, ACE_Equal_To, ACE_Null_Mutex> + ACE_Filecache_Hash; + +typedef ACE_Hash_Map_Entry ACE_Filecache_Hash_Entry; + +/** + * @class ACE_Filecache + * + * @brief + * A hash table holding the information about entry point into + * the Cached Virtual Filesystem. On insertion, the reference + * count is incremented. On destruction, reference count is + * decremented. + */ +class ACE_Export ACE_Filecache +{ +public: + /// Singleton pattern. + static ACE_Filecache *instance (void); + + ~ACE_Filecache (void); + + /// Returns 0 if the file associated with ``filename'' is in the cache, + /// or -1 if not. + int find (const ACE_TCHAR *filename); + + /// Return the file associated with ``filename'' if it is in the cache, + /// or create if not. + ACE_Filecache_Object *fetch (const ACE_TCHAR *filename, int mapit = 1); + + /// Remove the file associated with ``filename'' from the cache. + ACE_Filecache_Object *remove (const ACE_TCHAR *filename); + + /// Create a new Filecache_Object, returns it. + ACE_Filecache_Object *create (const ACE_TCHAR *filename, int size); + + /// Release an acquired Filecache_Object, returns it again or NULL if it + /// was deleted. + ACE_Filecache_Object *finish (ACE_Filecache_Object *&new_file); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + ACE_Filecache_Object *insert_i (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &filelock, + int mapit); + ACE_Filecache_Object *remove_i (const ACE_TCHAR *filename); + ACE_Filecache_Object *update_i (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &filelock, + int mapit); + +public: + + enum + { + /// For this stupid implementation, use an array. Someday, use a + /// balanced search tree, or real hash table. + ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE = 512, + + /// This determines the highwater mark in megabytes for the cache. + /// This will be ignored for now. + ACE_DEFAULT_VIRTUAL_FILESYSTEM_CACHE_SIZE = 20 + }; + +protected: + /// Prevent it from being called. + ACE_Filecache (void); + +private: + ACE_OFF_T size_; + + /// The hash table + ACE_Filecache_Hash hash_; + + /// The reference to the instance + static ACE_Filecache *cvf_; + + // = Synchronization variables. + ACE_SYNCH_RW_MUTEX hash_lock_[ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE]; + ACE_SYNCH_RW_MUTEX file_lock_[ACE_DEFAULT_VIRTUAL_FILESYSTEM_TABLE_SIZE]; +}; + +/** + * @class ACE_Filecache_Object + * + * @brief + * Abstraction over a real file. This is what the Virtual + * Filesystem contains. This class is not intended for general + * consumption. Please consult a physician before attempting to + * use this class. + */ +class ACE_Export ACE_Filecache_Object +{ +public: + friend class ACE_Filecache; + + /// Creates a file for reading. + ACE_Filecache_Object (const ACE_TCHAR *filename, + ACE_SYNCH_RW_MUTEX &lock, + LPSECURITY_ATTRIBUTES sa = 0, + int mapit = 1); + + /// Creates a file for writing. + ACE_Filecache_Object (const ACE_TCHAR *filename, + ACE_OFF_T size, + ACE_SYNCH_RW_MUTEX &lock, + LPSECURITY_ATTRIBUTES sa = 0); + + /// Only if reference count is zero should this be called. + ~ACE_Filecache_Object (void); + + /// Increment the reference_count_. + int acquire (void); + + /// Decrement the reference_count_. + int release (void); + + // = error_ accessors + int error (void) const; + int error (int error_value, + const ACE_TCHAR *s = ACE_TEXT ("ACE_Filecache_Object")); + + /// filename_ accessor + const ACE_TCHAR *filename (void) const; + + /// handle_ accessor. + ACE_HANDLE handle (void) const; + + /// Base memory address for memory mapped file. + void *address (void) const; + + /// size_ accessor. + ACE_OFF_T size (void) const; + + /// True if file on disk is newer than cached file. + int update (void) const; + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Prevent from being called. + ACE_Filecache_Object (void); + + /// Common initialization code, + void init (void); + +private: + /// Internal error logging method, no locking. + int error_i (int error_value, + const ACE_TCHAR *s = ACE_TEXT ("ACE_Filecache_Object")); + +public: + + enum Creation_States + { + ACE_READING = 1, + ACE_WRITING = 2 + }; + + enum Error_Conditions + { + ACE_SUCCESS = 0, + ACE_ACCESS_FAILED, + ACE_OPEN_FAILED, + ACE_COPY_FAILED, + ACE_STAT_FAILED, + ACE_MEMMAP_FAILED, + ACE_WRITE_FAILED + }; + +private: + /// The temporary file name and the real file name. The real file is + /// copied into the temporary file for safety reasons. + ACE_TCHAR *tempname_; + ACE_TCHAR filename_[MAXPATHLEN + 1]; + + /// Holds the memory mapped version of the temporary file. + ACE_Mem_Map mmap_; + + /// The descriptor to the temporary file. + ACE_HANDLE handle_; + + /// Used to compare against the real file to test if an update is needed. + ACE_stat stat_; + ACE_OFF_T size_; + + /// Status indicators. + int action_; + int error_; + + /// If set to 1, means the object is flagged for removal. + int stale_; + + /// Security attribute object. + LPSECURITY_ATTRIBUTES sa_; + + /// The default initializer + ACE_SYNCH_RW_MUTEX junklock_; + + /// Provides a bookkeeping mechanism for users of this object. + ACE_SYNCH_RW_MUTEX &lock_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_FILECACHE_H */ diff --git a/dep/acelite/ace/Flag_Manip.cpp b/dep/acelite/ace/Flag_Manip.cpp new file mode 100644 index 000000000..0b5ec2d0e --- /dev/null +++ b/dep/acelite/ace/Flag_Manip.cpp @@ -0,0 +1,104 @@ +#include "ace/Flag_Manip.h" + +#if defined (ACE_LACKS_FCNTL) +# include "ace/OS_NS_stropts.h" +# include "ace/OS_NS_errno.h" +#endif /* ACE_LACKS_FCNTL */ + +#if defined (ACE_LACKS_IOCTL) +# include "ace/OS_NS_devctl.h" +#endif + +#if !defined (__ACE_INLINE__) +#include "ace/Flag_Manip.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (CYGWIN32) +# include "ace/os_include/os_termios.h" +#endif /* CYGWIN32 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Flags are file status flags to turn on. + +int +ACE::set_flags (ACE_HANDLE handle, int flags) +{ + ACE_TRACE ("ACE::set_flags"); +#if defined (ACE_LACKS_FCNTL) + switch (flags) + { + case ACE_NONBLOCK: + // nonblocking argument (1) + // blocking: (0) + { + int nonblock = 1; +# if defined (ACE_LACKS_IOCTL) + int dev_info; + return ACE_OS::posix_devctl (handle, FIONBIO, &nonblock, + sizeof nonblock, &dev_info); +# else + return ACE_OS::ioctl (handle, FIONBIO, &nonblock); +# endif + } + default: + ACE_NOTSUP_RETURN (-1); + } +#else + int val = ACE_OS::fcntl (handle, F_GETFL, 0); + + if (val == -1) + return -1; + + // Turn on flags. + ACE_SET_BITS (val, flags); + + if (ACE_OS::fcntl (handle, F_SETFL, val) == -1) + return -1; + else + return 0; +#endif /* ACE_LACKS_FCNTL */ +} + +// Flags are the file status flags to turn off. + +int +ACE::clr_flags (ACE_HANDLE handle, int flags) +{ + ACE_TRACE ("ACE::clr_flags"); +#if defined (ACE_LACKS_FCNTL) + switch (flags) + { + case ACE_NONBLOCK: + // nonblocking argument (1) + // blocking: (0) + { + int nonblock = 0; +# if defined (ACE_LACKS_IOCTL) + int dev_info; + return ACE_OS::posix_devctl (handle, FIONBIO, &nonblock, + sizeof nonblock, &dev_info); +# else + return ACE_OS::ioctl (handle, FIONBIO, &nonblock); +# endif + } + default: + ACE_NOTSUP_RETURN (-1); + } +#else + int val = ACE_OS::fcntl (handle, F_GETFL, 0); + + if (val == -1) + return -1; + + // Turn flags off. + ACE_CLR_BITS (val, flags); + + if (ACE_OS::fcntl (handle, F_SETFL, val) == -1) + return -1; + else + return 0; +#endif /* ACE_LACKS_FCNTL */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Flag_Manip.h b/dep/acelite/ace/Flag_Manip.h new file mode 100644 index 000000000..f9324dd34 --- /dev/null +++ b/dep/acelite/ace/Flag_Manip.h @@ -0,0 +1,56 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Flag_Manip.h + * + * This class includes the functions used for the Flag Manipulation. + * + * @author Priyanka Gontla + */ +//============================================================================= + +#ifndef ACE_FLAG_MANIP_H +#define ACE_FLAG_MANIP_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/os_include/os_fcntl.h" /* For values passed to these methods */ + +#if defined (ACE_EXPORT_MACRO) +# undef ACE_EXPORT_MACRO +#endif +#define ACE_EXPORT_MACRO ACE_Export + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +namespace ACE +{ + // = Set/get/clear various flags related to I/O HANDLE. + /// Set flags associated with @a handle. + extern ACE_Export int set_flags (ACE_HANDLE handle, + int flags); + + /// Clear flags associated with @a handle. + extern ACE_Export int clr_flags (ACE_HANDLE handle, + int flags); + + /// Return the current setting of flags associated with @a handle. + ACE_NAMESPACE_INLINE_FUNCTION int get_flags (ACE_HANDLE handle); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Flag_Manip.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FLAG_MANIP_H */ diff --git a/dep/acelite/ace/Flag_Manip.inl b/dep/acelite/ace/Flag_Manip.inl new file mode 100644 index 000000000..f6def7748 --- /dev/null +++ b/dep/acelite/ace/Flag_Manip.inl @@ -0,0 +1,23 @@ +// -*- C++ -*- +#include "ace/OS_NS_fcntl.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Return flags currently associated with handle. +ACE_INLINE int +ACE::get_flags (ACE_HANDLE handle) +{ + ACE_TRACE ("ACE::get_flags"); + +#if defined (ACE_LACKS_FCNTL) + // ACE_OS::fcntl is not supported. It + // would be better to store ACE's notion of the flags + // associated with the handle, but this works for now. + ACE_UNUSED_ARG (handle); + return 0; +#else + return ACE_OS::fcntl (handle, F_GETFL, 0); +#endif /* ACE_LACKS_FCNTL */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Framework_Component.cpp b/dep/acelite/ace/Framework_Component.cpp new file mode 100644 index 000000000..513d378b9 --- /dev/null +++ b/dep/acelite/ace/Framework_Component.cpp @@ -0,0 +1,284 @@ +#include "ace/Framework_Component.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Framework_Component.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Object_Manager.h" +#include "ace/Log_Category.h" +#include "ace/DLL_Manager.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Framework_Component::~ACE_Framework_Component (void) +{ + ACE_TRACE ("ACE_Framework_Component::~ACE_Framework_Component"); + + ACE::strdelete (const_cast (this->dll_name_)); + ACE::strdelete (const_cast (this->name_)); +} + +/***************************************************************/ + +ACE_ALLOC_HOOK_DEFINE(ACE_Framework_Repository) + +sig_atomic_t ACE_Framework_Repository::shutting_down_ = 0; + +// Pointer to the Singleton instance. +ACE_Framework_Repository *ACE_Framework_Repository::repository_ = 0; + +ACE_Framework_Repository::~ACE_Framework_Repository (void) +{ + ACE_TRACE ("ACE_Framework_Repository::~ACE_Framework_Repository"); + this->close (); +} + +int +ACE_Framework_Repository::open (int size) +{ + ACE_TRACE ("ACE_Framework_Repository::open"); + + ACE_Framework_Component **temp = 0; + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_RETURN (temp, + static_cast (ACE_Allocator::instance()->malloc(sizeof(ACE_Framework_Component*) * size)), + -1); +#else + ACE_NEW_RETURN (temp, + ACE_Framework_Component *[size], + -1); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + this->component_vector_ = temp; + this->total_size_ = size; + return 0; +} + +int +ACE_Framework_Repository::close (void) +{ + ACE_TRACE ("ACE_Framework_Repository::close"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1); + + this->shutting_down_ = 1; + + if (this->component_vector_ != 0) + { + // Delete components in reverse order. + for (int i = this->current_size_ - 1; i >= 0; i--) + if (this->component_vector_[i]) + { + ACE_Framework_Component *s = + const_cast ( + this->component_vector_[i]); + + this->component_vector_[i] = 0; + delete s; + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(this->component_vector_); +#else + delete [] this->component_vector_; +#endif /* ACE_HAS_ALLOC_HOOKS */ + this->component_vector_ = 0; + this->current_size_ = 0; + } + + ACE_DLL_Manager::close_singleton (); + return 0; +} + +ACE_Framework_Repository * +ACE_Framework_Repository::instance (int size) +{ + ACE_TRACE ("ACE_Framework_Repository::instance"); + + if (ACE_Framework_Repository::repository_ == 0) + { + // Perform Double-Checked Locking Optimization. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + if (ACE_Framework_Repository::repository_ == 0) + { + if (ACE_Object_Manager::starting_up () || + !ACE_Object_Manager::shutting_down ()) + { + ACE_NEW_RETURN (ACE_Framework_Repository::repository_, + ACE_Framework_Repository (size), + 0); + } + } + } + + return ACE_Framework_Repository::repository_; +} + +void +ACE_Framework_Repository::close_singleton (void) +{ + ACE_TRACE ("ACE_Framework_Repository::close_singleton"); + + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance ())); + + delete ACE_Framework_Repository::repository_; + ACE_Framework_Repository::repository_ = 0; +} + +int +ACE_Framework_Repository::register_component (ACE_Framework_Component *fc) +{ + ACE_TRACE ("ACE_Framework_Repository::register_component"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1); + int i; + + // Check to see if it's already registered + for (i = 0; i < this->current_size_; i++) + if (this->component_vector_[i] && + fc->this_ == this->component_vector_[i]->this_) + { + ACELIB_ERROR_RETURN ((LM_ERROR, + "AFR::register_component: error, compenent already registered\n"), + -1); + } + + if (i < this->total_size_) + { + this->component_vector_[i] = fc; + ++this->current_size_; + return 0; + } + + return -1; +} + +int +ACE_Framework_Repository::remove_component (const ACE_TCHAR *name) +{ + ACE_TRACE ("ACE_Framework_Repository::remove_component"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1); + int i; + + for (i = 0; i < this->current_size_; i++) + if (this->component_vector_[i] && + ACE_OS::strcmp (this->component_vector_[i]->name_, name) == 0) + { + delete this->component_vector_[i]; + this->component_vector_[i] = 0; + this->compact (); + return 0; + } + + return -1; +} + +int +ACE_Framework_Repository::remove_dll_components (const ACE_TCHAR *dll_name) +{ + ACE_TRACE ("ACE_Framework_Repository::remove_dll_components"); + + if (this->shutting_down_) + return this->remove_dll_components_i (dll_name); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1); + + return this->remove_dll_components_i (dll_name); +} + +int +ACE_Framework_Repository::remove_dll_components_i (const ACE_TCHAR *dll_name) +{ + ACE_TRACE ("ACE_Framework_Repository::remove_dll_components_i"); + + int i; + int retval = -1; + + for (i = 0; i < this->current_size_; i++) + if (this->component_vector_[i] && + ACE_OS::strcmp (this->component_vector_[i]->dll_name_, dll_name) == 0) + { + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("AFR::remove_dll_components_i (%s) ") + ACE_TEXT ("component \"%s\"\n"), + dll_name, this->component_vector_[i]->name_)); + delete this->component_vector_[i]; + this->component_vector_[i] = 0; + ++retval; + } + + this->compact (); + + return retval == -1 ? -1 : 0; +} + +void +ACE_Framework_Repository::compact (void) +{ + ACE_TRACE ("ACE_Framework_Repository::compact"); + + int i; + int start_hole; + int end_hole; + + do + { + start_hole = this->current_size_; + end_hole = this->current_size_; + + // Find hole + for (i = 0; i < this->current_size_; ++i) + { + if (this->component_vector_[i] == 0) + { + if (start_hole == this->current_size_) + { + start_hole = i; + end_hole = i; + } + else + end_hole = i; + } + else if (end_hole != this->current_size_) + break; + } + + if (start_hole != this->current_size_) + { + // move the contents and reset current_size_ + while (end_hole + 1 < this->current_size_) + { + this->component_vector_[start_hole++] = + this->component_vector_[++end_hole]; + } + // Since start_hole is now one past the last + // active slot. + this->current_size_ = start_hole; + } + + } while (start_hole != this->current_size_); +} + +void +ACE_Framework_Repository::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Framework_Repository::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Framework_Repository::ACE_Framework_Repository (int size) + : current_size_ (0) +{ + ACE_TRACE ("ACE_Framework_Repository::ACE_Framework_Repository"); + + if (this->open (size) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Framework_Repository"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Framework_Component.h b/dep/acelite/ace/Framework_Component.h new file mode 100644 index 000000000..9cf7c4d57 --- /dev/null +++ b/dep/acelite/ace/Framework_Component.h @@ -0,0 +1,198 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Framework_Component.h + * + * A prototype mechanism that allows framework components, singletons + * such as ACE_Reactor, ACE_Proactor, etc, to be registered with a + * central repository managed by the ACE_Object_Manager or + * ACE_Service_Config that will handle destruction. + * + * This technique obviates changing ACE_Object_Manager and + * ACE_Service_Config everytime a new framework is added. Which also + * means that unused framework components don't need to linked into + * the final application which is important for applications with + * stringent footprint requirements. + * + * Framework components need only provide a static method, + * close_singleton() and add the ACE_REGISTER_FRAMEWORK_COMPONENT macro + * call to their instance() methods in order to participate. Components + * that don't have a close_singleton() method can also participate via + * template specialization of ACE_Framework_Component_T. + * + * This design uses the External Polymorphism pattern to avoid having + * to derive all framework components from a common base class that + * has virtual methods (this is crucial to avoid unnecessary overhead), + * and is based on the dump debugging implementation found in + * . + * + * @author Don Hinton . + */ +//============================================================================= + +#ifndef ACE_FRAMEWORK_COMPONENT_H +#define ACE_FRAMEWORK_COMPONENT_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/os_signal.h" +#include "ace/Thread_Mutex.h" +#include "ace/Copy_Disabled.h" +#include "ace/Synch_Traits.h" + +#define ACE_DEFAULT_FRAMEWORK_REPOSITORY_SIZE 1024 + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Framework_Component + * + * @brief Base class that defines a uniform interface for all managed + * framework components. + */ +class ACE_Export ACE_Framework_Component : private ACE_Copy_Disabled +{ +public: + friend class ACE_Framework_Repository; + + /// Constructor. + ACE_Framework_Component (void *_this, + const ACE_TCHAR *dll_name = 0, + const ACE_TCHAR *name = 0); + + /// Close the contained singleton. + virtual void close_singleton (void) = 0; + +protected: + /// Destructor. + virtual ~ACE_Framework_Component (void); + +private: + /// Pointer to the actual component. + const void *this_; + + /// Library associated with this component + const ACE_TCHAR *dll_name_; + + /// Component name + const ACE_TCHAR *name_; +}; + +/** + * @class ACE_Framework_Repository + * + * @brief Contains all framework components used by an application. + * + * This class contains a vector of ACE_Framework_Component *'s. On + * destruction, framework components are destroyed in the reverse order + * that they were added originally. + */ +class ACE_Export ACE_Framework_Repository : private ACE_Copy_Disabled +{ +public: + // This is just to silence a compiler warning about no public ctors + friend class ACE_Framework_Component; + + enum + { + DEFAULT_SIZE = ACE_DEFAULT_FRAMEWORK_REPOSITORY_SIZE + }; + + /// Close down the repository and free up dynamically allocated + /// resources. + ~ACE_Framework_Repository (void); + + /// Initialize the repository. + int open (int size = DEFAULT_SIZE); + + /// Close down the repository and free up dynamically allocated + /// resources, also called by dtor. + int close (void); + + /// Get pointer to a process-wide ACE_Framework_Repository. + static ACE_Framework_Repository *instance + (int size = ACE_Framework_Repository::DEFAULT_SIZE); + + /// Delete the dynamically allocated Singleton. + static void close_singleton (void); + + // = Search structure operations (all acquire locks as necessary). + + /// Insert a new component. Returns -1 when the repository is full + /// and 0 on success. + int register_component (ACE_Framework_Component *fc); + + /// Remove a component. Returns -1 on error or if component not found + /// and 0 on success. + int remove_component (const ACE_TCHAR *name); + + /// Remove all components associated with a particular dll. + int remove_dll_components (const ACE_TCHAR *dll_name); + + /// Return the current size of the repository. + int current_size (void) const; + + /// Return the total size of the repository. + int total_size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + /// Initialize the repository. + ACE_Framework_Repository (int size = ACE_Framework_Repository::DEFAULT_SIZE); + +private: + + /// Actually removes the dll components, must be called with locks held. + int remove_dll_components_i (const ACE_TCHAR *dll_name); + + /// Compact component_vector_ after components have been removed__maintains + /// order. + void compact (void); + +private: + + /// Contains all the framework components. + ACE_Framework_Component **component_vector_; + + /// Current number of components. + int current_size_; + + /// Maximum number of components. + int total_size_; + + /// Pointer to a process-wide ACE_Framework_Repository. + static ACE_Framework_Repository *repository_; + + /// Flag set when repository is the process of shutting down. This + /// is necessary to keep from self-deadlocking since some of + /// the components might make calls back to the repository to + /// unload their components, e.g., ACE_DLL_Manager. + static sig_atomic_t shutting_down_; + + /// Synchronization variable for the repository + ACE_SYNCH_MUTEX lock_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Framework_Component.inl" +#endif /* __ACE_INLINE__ */ + +// Include the templates classes at this point. +#include "ace/Framework_Component_T.h" + +#include /**/ "ace/post.h" +#endif /* ACE_FRAMEWORK_COMPONENT_H */ diff --git a/dep/acelite/ace/Framework_Component.inl b/dep/acelite/ace/Framework_Component.inl new file mode 100644 index 000000000..e5d25bb2f --- /dev/null +++ b/dep/acelite/ace/Framework_Component.inl @@ -0,0 +1,36 @@ +// -*- C++ -*- +#include "ace/ACE.h" +#include "ace/Guard_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Framework_Component::ACE_Framework_Component (void *_this, + const ACE_TCHAR *dll_name, + const ACE_TCHAR *name) + : this_ (_this), + dll_name_ (ACE::strnew (dll_name ? dll_name : ACE_TEXT (""))), + name_ (ACE::strnew (name ? name : ACE_TEXT (""))) +{ + ACE_TRACE ("ACE_Framework_Component::ctor"); +} + +/***************************************************************/ + +ACE_INLINE int +ACE_Framework_Repository::current_size (void) const +{ + ACE_TRACE ("ACE_Framework_Repository::current_size"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, const_cast (this->lock_), -1); + return this->current_size_; +} + +ACE_INLINE int +ACE_Framework_Repository::total_size (void) const +{ + ACE_TRACE ("ACE_Framework_Repository::total_size"); + ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, const_cast (this->lock_), -1); + return this->total_size_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Framework_Component_T.cpp b/dep/acelite/ace/Framework_Component_T.cpp new file mode 100644 index 000000000..abefe8325 --- /dev/null +++ b/dep/acelite/ace/Framework_Component_T.cpp @@ -0,0 +1,37 @@ +#ifndef ACE_FRAMEWORK_COMPONENT_T_CPP +#define ACE_FRAMEWORK_COMPONENT_T_CPP + +#include "ace/Framework_Component_T.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Framework_Component_T::ACE_Framework_Component_T (Concrete *concrete) + : ACE_Framework_Component ((void *) concrete, concrete->dll_name (), concrete->name ()) +{ + ACE_TRACE ("ACE_Framework_Component_T::ctor"); +} + +template +ACE_Framework_Component_T::~ACE_Framework_Component_T (void) +{ + ACE_TRACE ("ACE_Framework_Component_T::~ACE_Framework_Component_T"); + Concrete::close_singleton (); +} + +ACE_ALLOC_HOOK_DEFINE_Tt(ACE_Framework_Component_T) + +template void +ACE_Framework_Component_T::close_singleton (void) +{ + ACE_TRACE ("ACE_Framework_Component_T::close_singleton"); + Concrete::close_singleton (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_FRAMEWORK_COMPONENT_T_CPP */ diff --git a/dep/acelite/ace/Framework_Component_T.h b/dep/acelite/ace/Framework_Component_T.h new file mode 100644 index 000000000..6df8dbeac --- /dev/null +++ b/dep/acelite/ace/Framework_Component_T.h @@ -0,0 +1,71 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Framework_Component_T.h + * + * @author Don Hinton + */ +//============================================================================= + +#ifndef ACE_FRAMEWORK_COMPONENT_T_H +#define ACE_FRAMEWORK_COMPONENT_T_H +#include /**/ "ace/pre.h" +#include "ace/Framework_Component.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Framework_Component_T + * + * @brief This class inherits the interface of the abstract + * ACE_Framework_Component class and is instantiated with the + * implementation of the concrete component class @c class Concrete. + * + * This design is similar to the Adapter and Decorator patterns + * from the ``Gang of Four'' book. Note that @c class Concrete + * need not inherit from a common class since ACE_Framework_Component + * provides the uniform virtual interface! (implementation based on + * ACE_Dumpable_Adapter in . + */ +template +class ACE_Framework_Component_T : public ACE_Framework_Component +{ +public: + // = Initialization and termination methods. + + /// Constructor. + ACE_Framework_Component_T (Concrete *concrete); + + /// Destructor. + ~ACE_Framework_Component_T (void); + + /// Close the contained singleton. + void close_singleton (void); + + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +/// This macro should be called in the instance() method +/// of the Concrete class that will be managed. Along +/// with the appropriate template instantiation. +#define ACE_REGISTER_FRAMEWORK_COMPONENT(CLASS, INSTANCE) \ + ACE_Framework_Repository::instance ()->register_component \ + (new ACE_Framework_Component_T (INSTANCE)); + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Framework_Component_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Framework_Component_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_FRAMEWORK_COMPONENT_T_H */ diff --git a/dep/acelite/ace/Free_List.cpp b/dep/acelite/ace/Free_List.cpp new file mode 100644 index 000000000..36eed6d47 --- /dev/null +++ b/dep/acelite/ace/Free_List.cpp @@ -0,0 +1,167 @@ +#ifndef ACE_FREE_LIST_CPP +#define ACE_FREE_LIST_CPP + +#include "ace/Free_List.h" +#include "ace/Guard_T.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Free_List::~ACE_Free_List (void) +{ +} + +// Default constructor that takes in a preallocation number +// (), a low and high water mark ( and ) and an +// increment value () + +template +ACE_Locked_Free_List::ACE_Locked_Free_List (int mode, + size_t prealloc, + size_t lwm, + size_t hwm, + size_t inc) + : mode_ (mode), + free_list_ (0), + lwm_ (lwm), + hwm_ (hwm), + inc_ (inc), + size_ (0) +{ + this->alloc (prealloc); +} + +// Destructor - removes all the elements from the free_list + +template +ACE_Locked_Free_List::~ACE_Locked_Free_List (void) +{ + if (this->mode_ != ACE_PURE_FREE_LIST) + while (this->free_list_ != 0) + { + T *temp = this->free_list_; + this->free_list_ = this->free_list_->get_next (); + delete temp; + } +} + +// Inserts an element onto the free list (if we are allowed to manage +// elements withing and it pasts the high water mark, delete the +// element) + +template void +ACE_Locked_Free_List::add (T *element) +{ + ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_)); + + // Check to see that we not at the high water mark. + if (this->mode_ == ACE_PURE_FREE_LIST + || this->size_ < this->hwm_) + { + element->set_next (this->free_list_); + this->free_list_ = element; + this->size_++; + } + else + delete element; +} + +// Takes a element off the freelist and returns it. It creates +// new elements if we are allowed to do it and the size is at the low +// water mark. + +template T * +ACE_Locked_Free_List::remove (void) +{ + ACE_MT (ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->mutex_, 0)); + + // If we are at the low water mark, add some nodes + if (this->mode_ != ACE_PURE_FREE_LIST && this->size_ <= this->lwm_) + this->alloc (this->inc_); + + // Remove a node + T *temp = this->free_list_; + + if (temp != 0) + { + this->free_list_ = this->free_list_->get_next (); + this->size_--; + } + + return temp; +} + + +// Returns the current size of the free list + +template size_t +ACE_Locked_Free_List::size (void) +{ + return this->size_; +} + +// Resizes the free list to + +template void +ACE_Locked_Free_List::resize (size_t newsize) +{ + ACE_MT (ACE_GUARD (ACE_LOCK, ace_mon, this->mutex_)); + + // Check if we are allowed to resize + if (this->mode_ != ACE_PURE_FREE_LIST) + { + // Check to see if we grow or shrink + if (newsize < this->size_) + { + this->dealloc (this->size_ - newsize); + } + else + { + this->alloc (newsize - this->size_); + } + } +} + +// Allocates extra nodes for the freelist + +template void +ACE_Locked_Free_List::alloc (size_t n) +{ + for (; n > 0; n--) + { + T *temp = 0; + ACE_NEW (temp, T); + temp->set_next (this->free_list_); + this->free_list_ = temp; + this->size_++; + } +} + +// Removes and frees nodes from the freelist. + +template void +ACE_Locked_Free_List::dealloc (size_t n) +{ + for (; this->free_list_ != 0 && n > 0; + n--) + { + T *temp = this->free_list_; + this->free_list_ = this->free_list_->get_next (); + delete temp; + this->size_--; + } +} + +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Locked_Free_List) + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_FREE_LIST_CPP */ diff --git a/dep/acelite/ace/Free_List.h b/dep/acelite/ace/Free_List.h new file mode 100644 index 000000000..ae5ac9f64 --- /dev/null +++ b/dep/acelite/ace/Free_List.h @@ -0,0 +1,150 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Free_List.h + * + * @author Darrell Brunsch (brunsch@cs.wustl.edu) + */ +//============================================================================= + +#ifndef ACE_FREE_LIST_H +#define ACE_FREE_LIST_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/Default_Constants.h" +#include "ace/os_include/os_stddef.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Free_List + * + * @brief Implements a free list. + * + * This class maintains a free list of nodes of type T. + */ +template +class ACE_Free_List +{ +public: + /// Destructor - removes all the elements from the free_list. + virtual ~ACE_Free_List (void); + + /// Inserts an element onto the free list (if it isn't past the high + /// water mark). + virtual void add (T *element) = 0; + + /// Takes a element off the freelist and returns it. It creates + /// new elements if the size is at or below the low water mark. + virtual T *remove (void) = 0; + + /// Returns the current size of the free list. + virtual size_t size (void) = 0; + + /// Resizes the free list to @a newsize. + virtual void resize (size_t newsize) = 0; +}; + +/** + * @class ACE_Locked_Free_List + * + * @brief Implements a free list. + * + * This class maintains a free list of nodes of type T. It + * depends on the type T having a get_next() and set_next() + * method. It maintains a mutex so the freelist can be used in + * a multithreaded program . + */ +template +class ACE_Locked_Free_List : public ACE_Free_List +{ +public: + // = Initialization and termination. + /** + * Constructor takes a @a mode (i.e., ACE_FREE_LIST_WITH_POOL or + * ACE_PURE_FREE_LIST), a count of the number of nodes to + * @a prealloc, a low and high water mark (@a lwm and @a hwm) that + * indicate when to allocate more nodes, an increment value (@a inc) + * that indicates how many nodes to allocate when the list must + * grow. + */ + ACE_Locked_Free_List (int mode = ACE_FREE_LIST_WITH_POOL, + size_t prealloc = ACE_DEFAULT_FREE_LIST_PREALLOC, + size_t lwm = ACE_DEFAULT_FREE_LIST_LWM, + size_t hwm = ACE_DEFAULT_FREE_LIST_HWM, + size_t inc = ACE_DEFAULT_FREE_LIST_INC); + + /// Destructor - removes all the elements from the free_list. + virtual ~ACE_Locked_Free_List (void); + + /// Inserts an element onto the free list (if it isn't past the high + /// water mark). + virtual void add (T *element); + + /// Takes a element off the freelist and returns it. It creates + /// new elements if the size is at or below the low water mark. + virtual T *remove (void); + + /// Returns the current size of the free list. + virtual size_t size (void); + + /// Resizes the free list to @a newsize. + virtual void resize (size_t newsize); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Allocates @a n extra nodes for the freelist. + virtual void alloc (size_t n); + + /// Removes and frees @a n nodes from the freelist. + virtual void dealloc (size_t n); + + /// Free list operation mode, either ACE_FREE_LIST_WITH_POOL or + /// ACE_PURE_FREE_LIST. + int mode_; + + /// Pointer to the first node in the freelist. + T *free_list_; + + /// Low water mark. + size_t lwm_; + + /// High water mark. + size_t hwm_; + + /// Increment value. + size_t inc_; + + /// Keeps track of the size of the list. + size_t size_; + + /// Synchronization variable for ACE_Timer_Queue. + ACE_LOCK mutex_; + +private: + // = Don't allow these operations for now. + ACE_UNIMPLEMENTED_FUNC (ACE_Locked_Free_List (const ACE_Locked_Free_List &)) + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Locked_Free_List &)) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Free_List.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Free_List.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_FREE_LIST_H */ diff --git a/dep/acelite/ace/Functor.cpp b/dep/acelite/ace/Functor.cpp new file mode 100644 index 000000000..b5b13c921 --- /dev/null +++ b/dep/acelite/ace/Functor.cpp @@ -0,0 +1,50 @@ + +//============================================================================= +/** + * @file Functor.cpp + * + * Non-inlinable method definitions for non-templatized classes + * and template specializations implementing the GOF Command Pattern, + * and STL-style functors. + * + * @author Chris Gill + * + * Based on Command Pattern implementations originally done by + * + * Carlos O'Ryan + * Douglas C. Schmidt + * Sergio Flores-Gaitan + * + * and on STL-style functor implementations originally done by + * + * Irfan Pyarali + */ +//============================================================================= + + +#include "ace/Functor_T.h" +#include "ace/Functor.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Functor.inl" +#endif /* __ACE_INLINE__ */ + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Command_Base::~ACE_Command_Base (void) +{ +} + +ACE_Noop_Command::ACE_Noop_Command() +{ +} + +int +ACE_Noop_Command::execute(void*) +{ + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Functor.h b/dep/acelite/ace/Functor.h new file mode 100644 index 000000000..736dcd5a2 --- /dev/null +++ b/dep/acelite/ace/Functor.h @@ -0,0 +1,473 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Functor.h + * + * Non-templatized classes and class template specializations for + * implementing function objects that are used in various places + * in ACE. There are currently two major categories of function + * objects in ACE: GoF Command Pattern objects, and STL-style + * functors for comparison of container elements. The command objects + * are invoked via an execute () method, while the STL-style functors are + * invoked via an operator() () method. + * Non-templatized classes for implementing the GoF Command Pattern, + * also known as functors or function objects. + * + * @author Chris Gill + * @author Based on Command Pattern implementations originally done by + * @author Carlos O'Ryan + * @author Douglas C. Schmidt + * @author Sergio Flores-Gaitan + * @author and on STL-style functor implementations originally done by + * @author Irfan Pyarali + */ +//========================================================================== + + +#ifndef ACE_FUNCTOR_H +#define ACE_FUNCTOR_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/ACE_export.h" +#include "ace/Basic_Types.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +////////////////////////////////////////////////////////////// +// GOF Command Pattern Classes and Template Specializations // +////////////////////////////////////////////////////////////// + +/** + * @class ACE_Command_Base + * + * @brief Defines an abstract class that allows us to invoke commands + * without knowing anything about the implementation. + * + * This class declares an interface to execute a command + * independent of the effect of the command, or the objects used + * to implement it. + */ +class ACE_Export ACE_Command_Base +{ +public: + // = Initialization and termination methods. + /// Default constructor. + ACE_Command_Base (void); + + /// Virtual destructor. + virtual ~ACE_Command_Base (void); + + /** + * Invokes the method encapsulated by the command, passing along the + * passed argument (if any). Users of classes derived from this + * class must ensure that the resulting invocation can tolerate a + * null void pointer being passed, or otherwise ensure that this + * will never occur. + */ + virtual int execute (void *arg = 0) = 0; +}; + +/** + * @class ACE_Noop_Command + * + * Implements a ACE_Command_Base with an empty execute() body. + */ + +class ACE_Export ACE_Noop_Command + : public ACE_Command_Base +{ +public: + /// Constructor + ACE_Noop_Command(); + + /// Implement the empty execute() member function + virtual int execute(void*); +}; + +//////////////////////////////////////////////////////////// +// STL-style Functor Classes and Template Specializations // +//////////////////////////////////////////////////////////// + +// Forward declaration since we are going to specialize that template +// here. The template itself requires this file so every user of the +// template should also see the specialization. +template class ACE_Hash; +template class ACE_Equal_To; +template class ACE_Less_Than; + +/** + * @brief Function object for hashing a char + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (char t) const; +}; + +/** + * @brief Function object for hashing a signed char + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (signed char t) const; +}; + +/** + * @brief Function object for hashing an unsigned char + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (unsigned char t) const; +}; + +/** + * @brief Function object for hashing a short number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (short t) const; +}; + +/** + * @brief Function object for hashing an unsigned short number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (unsigned short t) const; +}; + +/** + * @brief Function object for hashing an int number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (int t) const; +}; + +/** + * @brief Function object for hashing an unsigned int number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (unsigned int t) const; +}; + +/** + * @brief Function object for hashing a long number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (long t) const; +}; + +/** + * @brief Function object for hashing an unsigned long number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (unsigned long t) const; +}; + +#if (ACE_SIZEOF_LONG < 8) +/** + * @brief Function object for hashing a signed 64-bit number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (ACE_INT64 t) const; +}; +#endif /* ACE_SIZEOF_LONG < 8 */ + +#if (ACE_SIZEOF_LONG < 8) +/** + * @brief Function object for hashing an unsigned 64-bit number + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (const ACE_UINT64 &t) const; +}; +#endif /* ACE_SIZEOF_LONG < 8 */ + +/** + * @brief Function object for hashing a const string + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const char *t) const; +}; + +/** + * @brief Function object for hashing a string + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const char *t) const; +}; + +/** + * @brief Function object for hashing a void */ +template<> +class ACE_Export ACE_Hash +{ +public: + unsigned long operator () (const void *) const; +}; + +/** + * @brief Function object for determining whether two const strings are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const char *lhs, + const char *rhs) const; +}; + +/** + * @brief Function object for determining whether two non-const + * strings are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const char *lhs, + const char *rhs) const; +}; + +/** + * @brief Function object for determining whether two unsigned + * 16 bit ints are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls built-in operators + int operator () (const ACE_UINT16 lhs, + const ACE_UINT16 rhs) const; +}; + +/** + * @brief Function object for determining whether two + * 16 bit ints are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls built-in operators + int operator () (const ACE_INT16 lhs, + const ACE_INT16 rhs) const; +}; + +/** + * @brief Function object for determining whether two unsigned + * 32 bit ints are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls built-in operators + int operator () (const ACE_UINT32 lhs, + const ACE_UINT32 rhs) const; +}; + +/** + * @brief Function object for determining whether two + * 32 bit ints are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls built-in operators + int operator () (const ACE_INT32 lhs, + const ACE_INT32 rhs) const; +}; + +/** + * @brief Function object for determining whether two unsigned + * 64 bit ints are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls built-in operators + int operator () (const ACE_UINT64 lhs, + const ACE_UINT64 rhs) const; +}; + +/** + * @brief Function object for determining whether the first const string + * is less than the second const string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const char *lhs, + const char *rhs) const; +}; + +/** + * @brief Function object for determining whether the first string + * is less than the second string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const char *lhs, + const char *rhs) const; +}; + +#if defined (ACE_HAS_WCHAR) + +# if ! defined (ACE_LACKS_NATIVE_WCHAR_T) +/** + * @brief Function object for hashing a wchar_t + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Simply returns t + unsigned long operator () (wchar_t t) const; +}; +# endif /* ACE_LACKS_NATIVE_WCHAR_T */ +/** + * @brief Function object for hashing a const string + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const wchar_t *t) const; +}; + +/** + * @brief Function object for hashing a string + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const wchar_t *t) const; +}; + +/** + * @brief Function object for determining whether two const strings are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const wchar_t *lhs, + const wchar_t *rhs) const; +}; + +/** + * @brief Function object for determining whether two non-const + * strings are equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const wchar_t *lhs, + const wchar_t *rhs) const; +}; + +/** + * @brief Function object for determining whether the first const string + * is less than the second const string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const wchar_t *lhs, + const wchar_t *rhs) const; +}; + +/** + * @brief Function object for determining whether the first string + * is less than the second string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const wchar_t *lhs, + const wchar_t *rhs) const; +}; + +#endif // ACE_HAS_WCHAR + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Functor.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_FUNCTOR_H */ diff --git a/dep/acelite/ace/Functor.inl b/dep/acelite/ace/Functor.inl new file mode 100644 index 000000000..f6a87f85f --- /dev/null +++ b/dep/acelite/ace/Functor.inl @@ -0,0 +1,245 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Functor.inl + * + * Inlinable method definitions for non-templatized classes + * and template specializations implementing the GOF Command Pattern, + * and STL-style functors. + * + * @author Chris Gill + * + * Based on Command Pattern implementations originally done by + * + * Carlos O'Ryan + * Douglas C. Schmidt + * Sergio Flores-Gaitan + * + * and on STL-style functor implementations originally done by + * Irfan Pyarali + */ +//============================================================================= + + +#include "ace/ACE.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +////////////////////////////////////////////////////////////// +// GOF Command Pattern Classes and Template Specializations // +////////////////////////////////////////////////////////////// + +// Default constructor. + +ACE_INLINE +ACE_Command_Base::ACE_Command_Base (void) +{ +} + +//////////////////////////////////////////////////////////// +// STL-style Functor Classes and Template Specializations // +//////////////////////////////////////////////////////////// + +ACE_INLINE unsigned long +ACE_Hash::operator () (char t) const +{ + return t; +} + +#if defined (ACE_HAS_WCHAR) && ! defined (ACE_LACKS_NATIVE_WCHAR_T) +ACE_INLINE unsigned long +ACE_Hash::operator () (wchar_t t) const +{ + return t; +} +#endif /* ACE_HAS_WCHAR && ! ACE_LACKS_NATIVE_WCHAR_T */ + +ACE_INLINE unsigned long +ACE_Hash::operator () (signed char t) const +{ + return t; +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (unsigned char t) const +{ + return t; +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (short t) const +{ + return static_cast (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (unsigned short t) const +{ + return static_cast (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (int t) const +{ + return static_cast (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (unsigned int t) const +{ + return static_cast (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (long t) const +{ + return static_cast (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (unsigned long t) const +{ + return t; +} + +// This #if needs to match the one in Functor.h +#if (ACE_SIZEOF_LONG < 8) +ACE_INLINE unsigned long +ACE_Hash::operator () (ACE_INT64 t) const +{ + return static_cast (t); +} +#endif /* ACE_SIZEOF_LONG < 8 */ + +#if (ACE_SIZEOF_LONG < 8) +ACE_INLINE unsigned long +ACE_Hash::operator () (const ACE_UINT64 &t) const +{ +#if (ACE_SIZEOF_LONG == 4) + return ACE_U64_TO_U32 (t); +#else + return static_cast (t); +#endif /* ACE_SIZEOF_LONG */ +} +#endif /* ACE_SIZEOF_LONG < 8 */ + +ACE_INLINE unsigned long +ACE_Hash::operator () (const char *t) const +{ + return ACE::hash_pjw (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (const char *t) const +{ + return ACE::hash_pjw (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (const void *t) const +{ + return static_cast (reinterpret_cast (t)); +} + +/***********************************************************************/ +ACE_INLINE int +ACE_Equal_To::operator () (const char *lhs, const char *rhs) const +{ + return !ACE_OS::strcmp (lhs, rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const char *lhs, const char *rhs) const +{ + return !ACE_OS::strcmp (lhs, rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_UINT16 lhs, const ACE_UINT16 rhs) const +{ + return (lhs == rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_INT16 lhs, const ACE_INT16 rhs) const +{ + return (lhs == rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_UINT32 lhs, const ACE_UINT32 rhs) const +{ + return (lhs == rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_INT32 lhs, const ACE_INT32 rhs) const +{ + return (lhs == rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_UINT64 lhs, const ACE_UINT64 rhs) const +{ + return (lhs == rhs); +} + +/****************************************************************************/ +ACE_INLINE int +ACE_Less_Than::operator () (const char *lhs, const char *rhs) const +{ + return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0; +} + +ACE_INLINE int +ACE_Less_Than::operator () (const char *lhs, const char *rhs) const +{ + return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0; +} + + +#if defined (ACE_HAS_WCHAR) + +ACE_INLINE unsigned long +ACE_Hash::operator () (const wchar_t *t) const +{ + return ACE::hash_pjw (t); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (const wchar_t *t) const +{ + return ACE::hash_pjw (t); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const wchar_t *lhs, + const wchar_t *rhs) const +{ + return !ACE_OS::strcmp (lhs, rhs); +} + +ACE_INLINE int +ACE_Equal_To::operator () (const wchar_t *lhs, + const wchar_t *rhs) const +{ + return !ACE_OS::strcmp (lhs, rhs); +} + +ACE_INLINE int +ACE_Less_Than::operator () (const wchar_t *lhs, const wchar_t *rhs) const +{ + return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0; +} + +ACE_INLINE int +ACE_Less_Than::operator () (const wchar_t *lhs, const wchar_t *rhs) const +{ + return (ACE_OS::strcmp (lhs, rhs) < 0) ? 1 : 0; +} + +#endif // ACE_HAS_WCHAR + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Functor_String.cpp b/dep/acelite/ace/Functor_String.cpp new file mode 100644 index 000000000..e12934fca --- /dev/null +++ b/dep/acelite/ace/Functor_String.cpp @@ -0,0 +1,7 @@ +#include "ace/Functor_String.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Functor_String.inl" +#endif /* __ACE_INLINE__ */ + + diff --git a/dep/acelite/ace/Functor_String.h b/dep/acelite/ace/Functor_String.h new file mode 100644 index 000000000..c04cc01c5 --- /dev/null +++ b/dep/acelite/ace/Functor_String.h @@ -0,0 +1,166 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Functor_String.h + * + * Class template specializations for ACE_*String types implementing + * function objects that are used in various places in ATC. They + * could be placed in Functor.h. But we don't want to couple string + * types to the rest of ACE+TAO. Hence they are placed in a separate + * file. + */ +//========================================================================== +#ifndef ACE_FUNCTOR_STRING_H +#define ACE_FUNCTOR_STRING_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/ACE_export.h" +#include "ace/SStringfwd.h" +#include + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +//////////////////////////////////////////////////////////// +// STL-style Functor Classes and Template Specializations // +//////////////////////////////////////////////////////////// + +// Forward declaration since we are going to specialize that template +// here. The template itself requires this file so every user of the +// template should also see the specialization. +template class ACE_Hash; +template class ACE_Equal_To; +template class ACE_Less_Than; + +/** + * @brief Function object for determining whether two ACE_CStrings are + * equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + int operator () (const ACE_CString &lhs, + const ACE_CString &rhs) const; +}; + + +/** + * @brief Function object for hashing a ACE_CString + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const ACE_CString &lhs) const; +}; + + +/** + * @brief Function object for determining whether the first const string + * is less than the second const string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const ACE_CString &lhs, + const ACE_CString &rhs) const; +}; + +/** + * @brief Function object for determining whether two std::strings are + * equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + int operator () (const std::string &lhs, + const std::string &rhs) const; +}; + + +/** + * @brief Function object for hashing a std::string + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const std::string &lhs) const; +}; + + +/** + * @brief Function object for determining whether the first const string + * is less than the second const string. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls std::string::compare + int operator () (const std::string &lhs, + const std::string &rhs) const; +}; + + +#if defined (ACE_USES_WCHAR) + +/** + * @brief Function object for determining whether two ACE_WStrings are + * equal. + */ +template<> +class ACE_Export ACE_Equal_To +{ +public: + int operator () (const ACE_WString &lhs, + const ACE_WString &rhs) const; +}; + + +/** + * @brief Function object for hashing a ACE_WString + */ +template<> +class ACE_Export ACE_Hash +{ +public: + /// Calls ACE::hash_pjw + unsigned long operator () (const ACE_WString &lhs) const; +}; + +/** + * @brief Function object for determining whether the first const wstring + * is less than the second const wstring. + */ +template<> +class ACE_Export ACE_Less_Than +{ +public: + /// Simply calls ACE_OS::strcmp + int operator () (const ACE_WString &lhs, + const ACE_WString &rhs) const; +}; + +#endif /*ACE_USES_WCHAR*/ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Functor_String.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /*ACE_FUNCTOR_STRING_H*/ diff --git a/dep/acelite/ace/Functor_String.inl b/dep/acelite/ace/Functor_String.inl new file mode 100644 index 000000000..d6f427f4a --- /dev/null +++ b/dep/acelite/ace/Functor_String.inl @@ -0,0 +1,73 @@ +// -*- C++ -*- +#include "ace/ACE.h" +#include "ace/String_Base.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE unsigned long +ACE_Hash::operator () (const ACE_CString &t) const +{ + return t.hash (); +} + + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_CString &lhs, + const ACE_CString &rhs) const +{ + return lhs == rhs; +} + +ACE_INLINE int +ACE_Less_Than::operator () (const ACE_CString &lhs, + const ACE_CString &rhs) const +{ + return (lhs < rhs); +} + +ACE_INLINE unsigned long +ACE_Hash::operator () (const std::string &t) const +{ + return ACE::hash_pjw (t.c_str (), t.length ()); +} + + +ACE_INLINE int +ACE_Equal_To::operator () (const std::string &lhs, + const std::string &rhs) const +{ + return lhs == rhs; +} + +ACE_INLINE int +ACE_Less_Than::operator () (const std::string &lhs, + const std::string &rhs) const +{ + return (lhs < rhs); +} + +#if defined (ACE_USES_WCHAR) +ACE_INLINE unsigned long +ACE_Hash::operator () (const ACE_WString &t) const +{ + return t.hash (); +} + + +ACE_INLINE int +ACE_Equal_To::operator () (const ACE_WString &lhs, + const ACE_WString &rhs) const +{ + return lhs == rhs; +} + +ACE_INLINE int +ACE_Less_Than::operator () (const ACE_WString &lhs, + const ACE_WString &rhs) const +{ + return (lhs < rhs); +} + +#endif /*ACE_USES_WCHAR*/ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Functor_T.cpp b/dep/acelite/ace/Functor_T.cpp new file mode 100644 index 000000000..9b99c5029 --- /dev/null +++ b/dep/acelite/ace/Functor_T.cpp @@ -0,0 +1,51 @@ +#ifndef ACE_FUNCTOR_T_CPP +#define ACE_FUNCTOR_T_CPP + +#include "ace/Functor_T.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Functor_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Command_Callback) + +/////////////////////////////////// +// GOF Command Pattern Templates // +/////////////////////////////////// + +// Constructor. + +template +ACE_Command_Callback::ACE_Command_Callback (RECEIVER &recvr, + ACTION action) + : receiver_ (recvr), + action_ (action) +{ +} + +template +ACE_Command_Callback::~ACE_Command_Callback (void) +{ +} + +// Invokes an operation. + +template int +ACE_Command_Callback::execute (void *arg) +{ + return (receiver_.*action_) (arg); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_FUNCTOR_T_CPP */ diff --git a/dep/acelite/ace/Functor_T.h b/dep/acelite/ace/Functor_T.h new file mode 100644 index 000000000..33b955ae9 --- /dev/null +++ b/dep/acelite/ace/Functor_T.h @@ -0,0 +1,193 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Functor_T.h + * + * Templatized classes for implementing function objects that are + * used in various places in ACE. There are currently two major + * categories of function objects in ACE: GOF Command Pattern + * objects, and STL-style functors for comparison of container + * elements. The command objects are invoked via an + * method, while the STL-style functors are invoked via an + * method. + * + * @author Chris Gill + * @author Based on Command Pattern implementations originally done by + * @author Carlos O'Ryan + * @author Douglas C. Schmidt + * @author Sergio Flores-Gaitan + * @author and on STL-style functor implementations originally done by + * @author Irfan Pyarali + */ +//============================================================================= + + +#ifndef ACE_FUNCTOR_T_H +#define ACE_FUNCTOR_T_H +#include /**/ "ace/pre.h" + +#include "ace/Functor.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Functor_String.h" +#include "ace/Truncate.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/////////////////////////////////// +// GOF Command Pattern Templates // +/////////////////////////////////// + +/** + * @class ACE_Command_Callback + * + * @brief + * Defines a class template that allows us to invoke a GOF + * command style callback to an object without knowing anything + * about the object except its type. + * + * This class declares an interface to execute operations, + * binding a RECEIVER object with an ACTION. The RECEIVER knows + * how to implement the operation. A class can invoke operations + * without knowing anything about it, or how it was implemented. + */ +template +class ACE_Command_Callback : public ACE_Command_Base +{ +public: + /// Constructor: sets the @c receiver_ of the Command to @a recvr, and the + /// @c action_ of the Command to @a action. + ACE_Command_Callback (RECEIVER &recvr, ACTION action); + + /// Virtual destructor. + virtual ~ACE_Command_Callback (void); + + /// Invokes the method @c action_ from the object @c receiver_. + virtual int execute (void *arg = 0); + + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Object where the method resides. + RECEIVER &receiver_; + + /// Method that is going to be invoked. + ACTION action_; +}; + +/** + * @class ACE_Member_Function_Command + * + * @brief Defines a class template that allows us to invoke a member + * function using the GoF command style callback. + */ +template +class ACE_Member_Function_Command : public ACE_Command_Base +{ +public: + typedef void (RECEIVER::*PTMF)(void); + + /// Con Constructor: sets the of the Command to recvr, and the + /// of the Command to . + ACE_Member_Function_Command (RECEIVER &recvr, PTMF ptmf); + + /// Virtual destructor. + virtual ~ACE_Member_Function_Command (void); + + /// Invokes the method from the object . The + /// parameter is ignored + virtual int execute (void *); + +private: + /// Object where the method resides. + RECEIVER &receiver_; + + /// Method that is going to be invoked. + PTMF ptmf_; +}; + +///////////////////////////////// +// STL-style Functor Templates // +///////////////////////////////// + +/** + * @class ACE_Hash + * + * @brief Function object for hashing + */ +template +class ACE_Hash +{ +public: + /// Simply calls t.hash () + unsigned long operator () (const TYPE &t) const; +}; + +/** + * @class ACE_Pointer_Hash + * + * @brief + * Function object for hashing pointers + */ +template +class ACE_Pointer_Hash +{ +public: + /// Simply returns t. + unsigned long operator () (TYPE t) const; +}; + +/** + * @class ACE_Equal_To + * + * @brief + * Function object for comparing two objects of + * the given type for equality. + */ +template +class ACE_Equal_To +{ +public: + /// Simply calls operator== + bool operator () (const TYPE &lhs, + const TYPE &rhs) const; +}; + +/** + * @class ACE_Less_Than + * + * @brief + * Function object for determining whether the first object of + * the given type is less than the second object of the same + * type. + */ +template +class ACE_Less_Than +{ +public: + /// Simply calls operator< + bool operator () (const TYPE &lhs, + const TYPE &rhs) const; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Functor_T.inl" +#endif /* __ACE_INLINE__ */ + + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Functor_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Functor_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_FUNCTOR_T_H */ diff --git a/dep/acelite/ace/Functor_T.inl b/dep/acelite/ace/Functor_T.inl new file mode 100644 index 000000000..415a0090b --- /dev/null +++ b/dep/acelite/ace/Functor_T.inl @@ -0,0 +1,60 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE +ACE_Member_Function_Command:: +ACE_Member_Function_Command (RECEIVER &recvr, PTMF ptmf) + : receiver_(recvr) + , ptmf_(ptmf) +{ +} + +template ACE_INLINE +ACE_Member_Function_Command:: +~ACE_Member_Function_Command (void) +{ +} + +template ACE_INLINE int +ACE_Member_Function_Command::execute (void *) +{ + (this->receiver_.*ptmf_)(); + return 0; +} + +template ACE_INLINE unsigned long +ACE_Hash::operator () (const TYPE &t) const +{ + return t.hash (); +} + +template ACE_INLINE unsigned long +ACE_Pointer_Hash::operator () (TYPE t) const +{ +#if defined (ACE_WIN64) + // The cast below is legit... we only want a hash, and need not convert + // the hash back to a pointer. +# pragma warning(push) +# pragma warning(disable : 4311) /* Truncate pointer to unsigned long */ +#endif /* ACE_WIN64 */ + return ACE_Utils::truncate_cast ((intptr_t)t); +#if defined (ACE_WIN64) +# pragma warning(pop) +#endif /* ACE_WIN64 */ +} + +template ACE_INLINE bool +ACE_Equal_To::operator () (const TYPE &lhs, + const TYPE &rhs) const +{ + return lhs == rhs; +} + +template ACE_INLINE bool +ACE_Less_Than::operator () (const TYPE &lhs, + const TYPE &rhs) const +{ + return lhs < rhs; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Future.cpp b/dep/acelite/ace/Future.cpp new file mode 100644 index 000000000..c2ec6adfc --- /dev/null +++ b/dep/acelite/ace/Future.cpp @@ -0,0 +1,438 @@ +#ifndef ACE_FUTURE_CPP +#define ACE_FUTURE_CPP + +#include "ace/Future.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +# include "ace/Guard_T.h" +# include "ace/Recursive_Thread_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Holder) +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Observer) +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Rep) +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future) + +template +ACE_Future_Holder::ACE_Future_Holder (void) +{ +} + +template +ACE_Future_Holder::ACE_Future_Holder (const ACE_Future &item) + : item_ (item) +{ +} + +template +ACE_Future_Holder::~ACE_Future_Holder (void) +{ +} + +template +ACE_Future_Observer::ACE_Future_Observer (void) +{ +} + +template +ACE_Future_Observer::~ACE_Future_Observer (void) +{ +} + +// Dump the state of an object. + +template void +ACE_Future_Rep::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, + "ref_count_ = %d\n", + (int) this->ref_count_)); + ACELIB_DEBUG ((LM_INFO,"value_:\n")); + if (this->value_) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NON-NULL)\n"))); + else + //FUZZ: disable check_for_NULL + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" (NULL)\n"))); + //FUZZ: enable check_for_NULL + + ACELIB_DEBUG ((LM_INFO,"value_ready_:\n")); + this->value_ready_.dump (); + ACELIB_DEBUG ((LM_INFO,"value_ready_mutex_:\n")); + this->value_ready_mutex_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_Future_Rep * +ACE_Future_Rep::internal_create (void) +{ + ACE_Future_Rep *temp = 0; + ACE_NEW_RETURN (temp, + ACE_Future_Rep (), + 0); + return temp; +} + +template ACE_Future_Rep * +ACE_Future_Rep::create (void) +{ + // Yes set ref count to zero. + ACE_Future_Rep *temp = internal_create (); +#if defined (ACE_NEW_THROWS_EXCEPTIONS) + if (temp == 0) + ACE_throw_bad_alloc; +#else + ACE_ASSERT (temp != 0); +#endif /* ACE_NEW_THROWS_EXCEPTIONS */ + return temp; + } + + +template ACE_Future_Rep * +ACE_Future_Rep::attach (ACE_Future_Rep*& rep) +{ + ACE_ASSERT (rep != 0); + // Use value_ready_mutex_ for both condition and ref count management + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_, 0); + ++rep->ref_count_; + return rep; +} + +template void +ACE_Future_Rep::detach (ACE_Future_Rep*& rep) +{ + ACE_ASSERT (rep != 0); + // Use value_ready_mutex_ for both condition and ref count management + ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_); + + if (rep->ref_count_-- == 0) + { + ACE_MT (r_mon.release ()); + // We do not need the lock when deleting the representation. + // There should be no side effects from deleting rep and we don + // not want to release a deleted mutex. + delete rep; + } +} + +template void +ACE_Future_Rep::assign (ACE_Future_Rep*& rep, ACE_Future_Rep* new_rep) +{ + ACE_ASSERT (rep != 0); + ACE_ASSERT (new_rep != 0); + // Use value_ready_mutex_ for both condition and ref count management + ACE_GUARD (ACE_SYNCH_RECURSIVE_MUTEX, r_mon, rep->value_ready_mutex_); + + ACE_Future_Rep* old = rep; + rep = new_rep; + + // detached old last for exception safety + if (old->ref_count_-- == 0) + { + ACE_MT (r_mon.release ()); + // We do not need the lock when deleting the representation. + // There should be no side effects from deleting rep and we don + // not want to release a deleted mutex. + delete old; + } +} + +template +ACE_Future_Rep::ACE_Future_Rep (void) + : value_ (0), + ref_count_ (0), + value_ready_ (value_ready_mutex_) +{ +} + +template +ACE_Future_Rep::~ACE_Future_Rep (void) +{ + delete this->value_; +} + +template int +ACE_Future_Rep::ready (void) const +{ + return this->value_ != 0; +} + +template int +ACE_Future_Rep::set (const T &r, + ACE_Future &caller) +{ + // If the value is already produced, ignore it... + if (this->value_ == 0) + { + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, + this->value_ready_mutex_, + -1); + // Otherwise, create a new result value. Note the use of the + // Double-checked locking pattern to avoid multiple allocations. + + if (this->value_ == 0) // Still no value, so proceed + { + ACE_NEW_RETURN (this->value_, + T (r), + -1); + + // Remove and notify all subscribed observers. + typename OBSERVER_COLLECTION::iterator iterator = + this->observer_collection_.begin (); + + typename OBSERVER_COLLECTION::iterator end = + this->observer_collection_.end (); + + while (iterator != end) + { + OBSERVER *observer = *iterator++; + if (observer) + { + observer->update (caller); + } + } + + // Signal all the waiting threads. + return this->value_ready_.broadcast (); + } + // Destructor releases the lock. + } + return 0; +} + +template int +ACE_Future_Rep::get (T &value, + ACE_Time_Value *tv) const +{ + // If the value is already produced, return it. + if (this->value_ == 0) + { + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, + this->value_ready_mutex_, + -1); + // If the value is not yet defined we must block until the + // producer writes to it. + + while (this->value_ == 0) + // Perform a timed wait. + if (this->value_ready_.wait (tv) == -1) + return -1; + + // Destructor releases the lock. + } + + value = *this->value_; + return 0; +} + +template int +ACE_Future_Rep::attach (ACE_Future_Observer *observer, + ACE_Future &caller) +{ + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1); + + // Otherwise, create a new result value. Note the use of the + // Double-checked locking pattern to avoid corrupting the list. + + int result = 1; + + // If the value is already produced, then notify observer + if (this->value_ == 0) + result = this->observer_collection_.insert (observer); + else + observer->update (caller); + + return result; +} + +template int +ACE_Future_Rep::detach (ACE_Future_Observer *observer) +{ + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, -1); + + // Remove all occurrences of the specified observer from this + // objects hash map. + return this->observer_collection_.remove (observer); +} + +template +ACE_Future_Rep::operator T () +{ + // If the value is already produced, return it. + if (this->value_ == 0) + { + // Constructor of ace_mon acquires the mutex. + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->value_ready_mutex_, 0); + + // If the value is not yet defined we must block until the + // producer writes to it. + + // Wait ``forever.'' + + while (this->value_ == 0) + if (this->value_ready_.wait () == -1) + // What to do in this case since we've got to indicate + // failure somehow? Exceptions would be nice, but they're + // not portable... + return 0; + + // Destructor releases the mutex + } + + return *this->value_; +} + +template +ACE_Future::ACE_Future (void) + : future_rep_ (FUTURE_REP::create ()) +{ +} + +template +ACE_Future::ACE_Future (const ACE_Future &r) + : future_rep_ (FUTURE_REP::attach (((ACE_Future &) r).future_rep_)) +{ +} + +template +ACE_Future::ACE_Future (const T &r) + : future_rep_ (FUTURE_REP::create ()) +{ + this->future_rep_->set (r, *this); +} + +template +ACE_Future::~ACE_Future (void) +{ + FUTURE_REP::detach (future_rep_); +} + +template bool +ACE_Future::operator== (const ACE_Future &r) const +{ + return r.future_rep_ == this->future_rep_; +} + +template bool +ACE_Future::operator!= (const ACE_Future &r) const +{ + return r.future_rep_ != this->future_rep_; +} + +template int +ACE_Future::cancel (const T &r) +{ + this->cancel (); + return this->future_rep_->set (r, *this); +} + +template int +ACE_Future::cancel (void) +{ + // If this ACE_Future is already attached to a ACE_Future_Rep, + // detach it (maybe delete the ACE_Future_Rep). + FUTURE_REP::assign (this->future_rep_, + FUTURE_REP::create ()); + return 0; +} + +template int +ACE_Future::set (const T &r) +{ + // Give the pointer to the result to the ACE_Future_Rep. + return this->future_rep_->set (r, *this); +} + +template int +ACE_Future::ready (void) const +{ + // We're ready if the ACE_Future_rep is ready... + return this->future_rep_->ready (); +} + +template int +ACE_Future::get (T &value, + ACE_Time_Value *tv) const +{ + // We return the ACE_Future_rep. + return this->future_rep_->get (value, tv); +} + +template int +ACE_Future::attach (ACE_Future_Observer *observer) +{ + return this->future_rep_->attach (observer, *this); +} + +template int +ACE_Future::detach (ACE_Future_Observer *observer) +{ + return this->future_rep_->detach (observer); +} + +template +ACE_Future::operator T () +{ + // note that this will fail (and COREDUMP!) + // if future_rep_ == 0 ! + // + // but... + // this is impossible unless somebody is so stupid to + // try something like this: + // + // Future futT; + // T t; + // t = futT; + + // perform type conversion on Future_Rep. + return *future_rep_; +} + +template void +ACE_Future::operator = (const ACE_Future &rhs) +{ + // assignment: + // + // bind to the same as . + + // This will work if &r == this, by first increasing the ref count + ACE_Future &r = (ACE_Future &) rhs; + FUTURE_REP::assign (this->future_rep_, + FUTURE_REP::attach (r.future_rep_)); +} + +template void +ACE_Future::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, + ACE_BEGIN_DUMP, this)); + + if (this->future_rep_) + this->future_rep_->dump (); + + ACELIB_DEBUG ((LM_DEBUG, + ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template ACE_Future_Rep * +ACE_Future::get_rep () +{ + return this->future_rep_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ + +#endif /* ACE_FUTURE_CPP */ diff --git a/dep/acelite/ace/Future.h b/dep/acelite/ace/Future.h new file mode 100644 index 000000000..81fcb820c --- /dev/null +++ b/dep/acelite/ace/Future.h @@ -0,0 +1,385 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Future.h + * + * @author Andres Kruse + * @author Douglas C. Schmidt + * @author Per Andersson and + * @author John Tucker + */ +//============================================================================= + +#ifndef ACE_FUTURE_H +#define ACE_FUTURE_H + +#include /**/ "ace/pre.h" + +#include "ace/Unbounded_Set.h" +#include "ace/Strategies_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +#include "ace/Synch_Traits.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Condition_Recursive_Thread_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decl. +template class ACE_Future_Holder; +template class ACE_Future_Observer; +template class ACE_Future_Rep; +template class ACE_Future; + +/** + * @class ACE_Future_Holder + * + * @brief Implementation of object that holds an ACE_Future. + */ +template +class ACE_Future_Holder +{ +public: + ACE_Future_Holder (const ACE_Future &future); + ~ACE_Future_Holder (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + ACE_Future item_; + +protected: + ACE_Future_Holder (void); +}; + +/** + * @class ACE_Future_Observer + * + * @brief ACE_Future_Observer + * + * An ACE_Future_Observer object implements an object that is + * subscribed with an ACE_Future object so that it may be notified + * when the value of the ACE_Future object is written to by a writer + * thread. It uses the Observer pattern. + */ +template +class ACE_Future_Observer +{ +public: + /// Destructor + virtual ~ACE_Future_Observer (void); + + /// Called by the ACE_Future in which we are subscribed to when + /// its value is written to. + virtual void update (const ACE_Future &future) = 0; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +protected: + + /// Constructor + ACE_Future_Observer (void); +}; + +/** + * @class ACE_Future_Rep + * + * @internal + * + * @brief ACE_Future_Rep + * + * An ACE_Future_Rep object encapsulates a pointer to an object + * of class T which is the result of an asynchronous method + * invocation. It is pointed to by ACE_Future object[s] and + * only accessible through them. + */ +template +class ACE_Future_Rep +{ +private: + friend class ACE_Future; + + /** + * Set the result value. The specified @a caller represents the + * future that invoked this method, which is used to notify + * the list of future observers. Returns 0 for success, -1 on error. + * This function only has an effect the first time it is called for + * the object. Subsequent calls return 0 (success) but have no effect. + */ + int set (const T &r, + ACE_Future &caller); + + /// Wait up to @a tv time to get the @a value. Note that @a tv must be + /// specified in absolute time rather than relative time. + int get (T &value, + ACE_Time_Value *tv) const; + + /** + * Attaches the specified observer to a subject (i.e., the ACE_Future_Rep). + * The update method of the specified subject will be invoked with a copy of + * the written-to ACE_Future as input when the result gets set. + * + * Returns 0 if the observer is successfully attached, 1 if the + * observer is already attached, and -1 if failures occur. + */ + int attach (ACE_Future_Observer *observer, + ACE_Future &caller); + + /** + * Detaches the specified observer from a subject (i.e., the ACE_Future_Rep). + * The update method of the specified subject will not be invoked when the + * ACE_Future_Reps result gets set. Returns 1 if the specified observer was + * actually attached to the subject prior to this call and 0 if was not. + * + * Returns 0 if the observer was successfully detached, and -1 if the + * observer was not attached in the first place. + */ + int detach (ACE_Future_Observer *observer); + + /** + * Type conversion. will block forever until the result is + * available. Note that this method is going away in a subsequent + * release since it doesn't distinguish between failure results and + * success results (exceptions should be used, but they aren't + * portable...). The method should be used instead since it + * separates the error value from the result, and also permits + * timeouts. + */ + operator T (); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + // = Encapsulate reference count and object lifetime of instances. + + // These methods must go after the others to work around a bug with + // Borland's C++ Builder... + + /// Allocate a new ACE_Future_Rep instance, returning NULL if it + /// cannot be created. + static ACE_Future_Rep *internal_create (void); + + /// Create a ACE_Future_Rep and initialize the reference count. + static ACE_Future_Rep *create (void); + + /** + * Increase the reference count and return argument. Uses the + * attribute "value_ready_mutex_" to synchronize reference count + * updating. + * + * Precondition (rep != 0). + */ + static ACE_Future_Rep *attach (ACE_Future_Rep *&rep); + + /** + * Decreases the reference count and deletes rep if there are no + * more references to rep. + * + * Precondition (rep != 0) + */ + static void detach (ACE_Future_Rep *&rep); + + /** + * Decreases the rep's reference count and deletes rep if there + * are no more references to rep. Then assigns new_rep to rep. + * + * Precondition (rep != 0 && new_rep != 0) + */ + static void assign (ACE_Future_Rep *&rep, ACE_Future_Rep *new_rep); + + /// Is result available? + int ready (void) const; + + /// Pointer to the result. + T *value_; + + /// Reference count. + int ref_count_; + + typedef ACE_Future_Observer OBSERVER; + + typedef ACE_Unbounded_Set OBSERVER_COLLECTION; + + /// Keep a list of ACE_Future_Observers unread by client's reader thread. + OBSERVER_COLLECTION observer_collection_; + + // = Condition variable and mutex that protect the . + mutable ACE_SYNCH_RECURSIVE_MUTEX value_ready_mutex_; + mutable ACE_SYNCH_RECURSIVE_CONDITION value_ready_; + +private: + + ACE_Future_Rep (void); + +protected: + + ~ACE_Future_Rep (void); + +}; + +/** + * @class ACE_Future + * + * @brief This class implements a ``single write, multiple read'' + * pattern that can be used to return results from asynchronous + * method invocations. + */ +template +class ACE_Future +{ +public: + // = Initialization and termination methods. + /// Constructor. + ACE_Future (void); + + /// Copy constructor binds @a this and @a r to the same + /// ACE_Future_Rep. An ACE_Future_Rep is created if necessary. + ACE_Future (const ACE_Future &r); + + /// Constructor that initialises an ACE_Future to point to the + /// result @a r immediately. + ACE_Future (const T &r); + + /// Destructor. + ~ACE_Future (void); + + /// Assignment operator that binds @a this and @a r to the same + /// ACE_Future_Rep. An ACE_Future_Rep is created if necessary. + void operator = (const ACE_Future &r); + + /// Cancel an ACE_Future and assign the value @a r. It is used if a + /// client does not want to wait for the value to be produced. + int cancel (const T &r); + + /** + * Cancel an ACE_Future. Put the future into its initial + * state. Returns 0 on succes and -1 on failure. It is now possible + * to reuse the ACE_Future. But remember, the ACE_Future + * is now bound to a new ACE_Future_Rep. + */ + int cancel (void); + + /** + * Equality operator that returns @c true if both ACE_Future objects + * point to the same ACE_Future_Rep object. + * + * @note It also returns @c true if both objects have just been + * instantiated and not used yet. + */ + bool operator == (const ACE_Future &r) const; + + /// Inequality operator, which is the opposite of equality. + bool operator != (const ACE_Future &r) const; + + /** + * Make the result available. Is used by the server thread to give + * the result to all waiting clients. Returns 0 for success, -1 on failure. + * This function only has an effect the first time it is called for + * the object (actually, the first time the underlying ACE_Future_Rep has a + * value assigned to it). Subsequent calls return 0 (success) but have no + * effect. + */ + int set (const T &r); + + /** + * Wait to get the object's value. + * + * @param value Receives the value of this ACE_Future when it is set. + * @param tv Pointer to an ACE_Time_Value containing the absolute + * time to wait until for the value to be set. If @a tv + * is 0, the call waits indefinitely for the value to be + * set, unless an error occurs. + * + * @retval 0 Success; @a value contains the value of the ACE_Future. + * @retval -1 Error; check ACE_OS::last_error() for an error code. + */ + int get (T &value, ACE_Time_Value *tv = 0) const; + + /** + * @deprecated Note that this method is going away in a subsequent + * release since it doesn't distinguish between failure + * results and success results (exceptions should be + * used, but they aren't portable...). + * Type conversion, which obtains the result of the asynchronous + * method invocation. Will block forever. The get() method should be + * used instead since it separates the error value from the result, + * and also permits timeouts. + */ + operator T (); + + /// Check if the result is available. + int ready (void) const; + + /** + * Attaches the specified observer to a subject (this ACE_Future). + * The update method of the specified subject will be invoked with a copy of + * the associated ACE_Future as input when the result gets set. If the + * result is already set when this method gets invoked, then the update + * method of the specified subject will be invoked immediately. + * + * @param observer The observer to attach to the subject. + * + * @retval 0 Success. + * @retval 1 The observer was already attached. + * @retval -1 Error; check ACE_OS::last_error() for an error code. + */ + int attach (ACE_Future_Observer *observer); + + /** + * Detaches the specified observer from a subject (this ACE_Future). + * The update method of the specified subject will not be invoked when the + * ACE_Future_Rep result gets set. + * + * @param observer The observer to attach to the subject. + * + * @retval 0 The observer was successfully detached. + * @retval -1 Error, including the observer not attached prior + * to calling this method. + */ + int detach (ACE_Future_Observer *observer); + + /// Dump the state of an object. + void dump (void) const; + + /** + * Get the underlying ACE_Future_Rep pointer. Note that this method should + * rarely, if ever, be used and that modifying the underlying + * ACE_Future_Rep should be done with extreme caution. + */ + ACE_Future_Rep *get_rep (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + /// The ACE_Future_Rep + /// Protect operations on the . + typedef ACE_Future_Rep FUTURE_REP; + FUTURE_REP *future_rep_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Future.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Future.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" + +#endif /* ACE_FUTURE_H */ diff --git a/dep/acelite/ace/Future_Set.cpp b/dep/acelite/ace/Future_Set.cpp new file mode 100644 index 000000000..413539b2a --- /dev/null +++ b/dep/acelite/ace/Future_Set.cpp @@ -0,0 +1,136 @@ +#ifndef ACE_FUTURE_SET_CPP +#define ACE_FUTURE_SET_CPP + +#include "ace/Future_Set.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_Future_Set) + +template +ACE_Future_Set::ACE_Future_Set (ACE_Message_Queue *new_queue) + : delete_queue_ (false) +{ + if (new_queue) + this->future_notification_queue_ = new_queue; + else + { + ACE_NEW (this->future_notification_queue_, + ACE_Message_Queue); + this->delete_queue_ = true; + } +} + +template +ACE_Future_Set::~ACE_Future_Set (void) +{ + // Detach ourselves from all remaining futures, if any, in our map. + typename FUTURE_HASH_MAP::iterator iterator = + this->future_map_.begin (); + + typename FUTURE_HASH_MAP::iterator end = + this->future_map_.end (); + + for (; + iterator != end; + ++iterator) + { + FUTURE_HOLDER *future_holder = (*iterator).int_id_; + future_holder->item_.detach (this); + delete future_holder; + } + + if (this->delete_queue_) + delete this->future_notification_queue_; +} + +template int +ACE_Future_Set::is_empty () const +{ + return (((ACE_Future_Set*)this)->future_map_.current_size () == 0 ); +} + +template int +ACE_Future_Set::insert (ACE_Future &future) +{ + FUTURE_HOLDER *future_holder; + ACE_NEW_RETURN (future_holder, + FUTURE_HOLDER (future), + -1); + + FUTURE_REP *future_rep = future.get_rep (); + int result = this->future_map_.bind (future_rep, + future_holder); + + // If a new map entry was created, then attach to the future, + // otherwise we were already attached to the future or some error + // occurred so just delete the future holder. + if (result == 0) + // Attach ourself to the ACE_Futures list of observer + future.attach (this); + else + delete future_holder; + + return result; +} + +template void +ACE_Future_Set::update (const ACE_Future &future) +{ + ACE_Message_Block *mb = 0; + FUTURE &local_future = const_cast &> (future); + + ACE_NEW (mb, + ACE_Message_Block ((char *) local_future.get_rep (), 0)); + + // Enqueue in priority order. + this->future_notification_queue_->enqueue (mb, 0); +} + +template int +ACE_Future_Set::next_readable (ACE_Future &future, + ACE_Time_Value *tv) +{ + if (this->is_empty ()) + return 0; + + ACE_Message_Block *mb = 0; + FUTURE_REP *future_rep = 0; + + // Wait for a "readable future" signal from the message queue. + if (this->future_notification_queue_->dequeue_head (mb, + tv) != -1) + { + // Extract future rep from the message block. + future_rep = reinterpret_cast (mb->base ()); + + // Delete the message block. + mb->release (); + } + else + return 0; + + // Remove the hash map entry with the specified future rep from our map. + FUTURE_HOLDER *future_holder = 0; + if (this->future_map_.find (future_rep, + future_holder) != -1) + { + future = future_holder->item_; + this->future_map_.unbind (future_rep); + delete future_holder; + return 1; + } + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ +#endif /* ACE_FUTURE_SET_CPP */ diff --git a/dep/acelite/ace/Future_Set.h b/dep/acelite/ace/Future_Set.h new file mode 100644 index 000000000..937416496 --- /dev/null +++ b/dep/acelite/ace/Future_Set.h @@ -0,0 +1,141 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Future_Set.h + * + * @author John Tucker + */ +//============================================================================= + +#ifndef ACE_FUTURE_SET_H +#define ACE_FUTURE_SET_H +#include /**/ "ace/pre.h" + +#include "ace/Thread.h" +#include "ace/Message_Queue.h" +#include "ace/Future.h" +#include "ace/Hash_Map_Manager_T.h" +#include "ace/Null_Mutex.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +#pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Future_Set + * + * @brief This class implements a mechanism that allows the values of + * a collection of ACE_Future objects to be accessed by reader threads + * as they become available. The caller(s) provide the ACE_Future_Set + * (i.e. the observer...) with the collection of ACE_Future objects + * (i.e. the subjects...) that are to be observed using the the + * ACE_Future_Set::insert() method. The caller(s) may then iterate + * over the collection in the order in which they become readable + * using the ACE_Future_Set::next_readable() method. + */ +template +class ACE_Future_Set : public ACE_Future_Observer, + private ACE_Copy_Disabled +{ +public: + // = Initialization and termination methods. + + /// Constructor. + ACE_Future_Set (ACE_Message_Queue *future_notification_queue_ = 0); + + /// Destructor. + ~ACE_Future_Set (void); + + /** + * Return 1 if their are no ACE_Future objects left on its queue and + * 0 otherwise. + * + * When an ACE_Future_Set has no ACE_Future>subjects to observe it is + * empty. The ACE_Future_Set is in the empty state when either the caller(s) + * have retrieved every readable ACE_Future subject assigned the + * ACE_Future_Set via the ACE_Future_Set::next_readable() method, + * or when the ACE_Future_Set has not been assigned any subjects. + */ + int is_empty (void) const; + + /** + * Enqueus the given ACE_Future into this objects queue when it is + * readable. + * + * Returns 0 if the future is successfully inserted, 1 if the + * future is already inserted, and -1 if failures occur. + */ + int insert (ACE_Future &future); + + /** + * Wait up to @a tv time to get the @a value. Note that @a tv must be + * specified in absolute time rather than relative time.); get the + * next ACE_Future that is readable. If @a tv = 0, the will block + * forever. + * + * If a readable future becomes available, then the input + * ACE_Future object param will be assigned with it and 1 will + * be returned. If the ACE_Future_Set is empty (i.e. see definition + * of ACE_Future_Set::is_empty()), then 0 is returned. + * + * When a readable ACE_Future object is retrieved via the + * ACE_Future_Set::next_readable() method, the ACE_Future_Set will + * remove that ACE_Future object from its list of subjects. + */ + int next_readable (ACE_Future &result, + ACE_Time_Value *tv = 0); + + /// Called by the ACE_Future subject in which we are subscribed to + /// when its value is written to. + virtual void update (const ACE_Future &future); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + typedef ACE_Future FUTURE; + + typedef ACE_Future_Rep FUTURE_REP; + + typedef ACE_Future_Holder FUTURE_HOLDER; + + typedef ACE_Pointer_Hash FUTURE_REP_HASH; + + typedef ACE_Equal_To FUTURE_REP_COMPARE; + + typedef ACE_Hash_Map_Manager_Ex FUTURE_HASH_MAP; + + /// Map of , subjects, which have not been written to by + /// client's writer thread. + FUTURE_HASH_MAP future_map_; + + /// Message queue for notifying the reader thread of which + /// have been written to by client's writer thread. + ACE_Message_Queue *future_notification_queue_; + + /// Keeps track of whether we need to delete the message queue. + bool delete_queue_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Future_Set.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Future_Set.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#endif /* ACE_HAS_THREADS */ +#include /**/ "ace/post.h" +#endif /* ACE_FUTURE_SET_H */ diff --git a/dep/acelite/ace/Get_Opt.cpp b/dep/acelite/ace/Get_Opt.cpp new file mode 100644 index 000000000..9e8d7c1fb --- /dev/null +++ b/dep/acelite/ace/Get_Opt.cpp @@ -0,0 +1,734 @@ +#include "ace/Get_Opt.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Get_Opt.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/ACE.h" +#include "ace/Log_Category.h" +#include "ace/SString.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_ctype.h" +#include "ace/OS_NS_stdlib.h" + +/* + * Copyright (c) 1987, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS OR CONTRIBUTORS 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. + */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``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 THE FOUNDATION OR CONTRIBUTORS + * 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. + */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt) + +#ifdef ACE_USES_WCHAR +void ACE_Get_Opt::ACE_Get_Opt_Init (const ACE_TCHAR *optstring) +#else +ACE_Get_Opt::ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const ACE_TCHAR *optstring, + int skip, + int report_errors, + int ordering, + int long_only) + : argc_ (argc), + argv_ (argv), + optind (skip), + opterr (report_errors), + optarg (0), + optstring_ (0), + long_only_ (long_only), + has_colon_ (0), + last_option_ (0), + nextchar_ (0), + optopt_ (0), + ordering_ (ordering), + nonopt_start_ (optind), + nonopt_end_ (optind), + long_option_ (0) +#endif +{ + ACE_TRACE ("ACE_Get_Opt::ACE_Get_Opt"); + + ACE_NEW (this->optstring_, ACE_TString (optstring)); + ACE_NEW (this->last_option_, ACE_TString (ACE_TEXT (""))); + + // First check to see if POSIXLY_CORRECT was set. + // Win32 is the only platform capable of wide-char env var. +#if defined (ACE_WIN32) + const ACE_TCHAR *env_check = ACE_TEXT ("POSIXLY_CORRECT"); +#else + const char *env_check = "POSIXLY_CORRECT"; +#endif + if (ACE_OS::getenv (env_check) != 0) + this->ordering_ = REQUIRE_ORDER; + + // Now, check to see if any or the following were passed at + // the beginning of optstring: '+' same as POSIXLY_CORRECT; + // '-' turns off POSIXLY_CORRECT; or ':' which signifies we + // should return ':' if a parameter is missing for an option. + // We use a loop here, since a combination of "{+|-}:" in any + // order should be legal. + int done = 0; + int offset = 0; + while (!done) + { + switch (optstring[offset++]) + { + case '+': + this->ordering_ = REQUIRE_ORDER; + break; + case '-': + this->ordering_ = RETURN_IN_ORDER; + break; + case ':': + this->has_colon_ = 1; + break; + default: + // Quit as soon as we see something else... + done = 1; + break; + } + } +} + +ACE_Get_Opt::~ACE_Get_Opt (void) +{ + ACE_TRACE ("ACE_Get_Opt::~ACE_Get_Opt"); + + size_t i = 0; + size_t size = this->long_opts_.size (); + ACE_Get_Opt_Long_Option *option = 0; + for (i = 0; i < size; ++i) + { + int retval = this->long_opts_.get (option, i); + if (retval != 0) + { + // Should never happen. + retval = 0; + continue; + } + if (option) + { + delete option; + option = 0; + } + } + delete this->optstring_; + delete this->last_option_; +} + +int +ACE_Get_Opt::nextchar_i (void) +{ + ACE_TRACE ("ACE_Get_Opt::nextchar_i"); + + if (this->ordering_ == PERMUTE_ARGS) + if (this->permute () == EOF) + return EOF; + + // Update scanning pointer. + if (this->optind >= this->argc_) + { + // We're done... + this->nextchar_ = 0; + return EOF; + } + else if (*(this->nextchar_ = this->argv_[this->optind]) != '-' + || this->nextchar_[1] == '\0') + { + // We didn't get an option. + + if (this->ordering_ == REQUIRE_ORDER + || this->ordering_ == PERMUTE_ARGS) + // If we permuted or require the options to be in order, we're done. + return EOF; + + // It must be RETURN_IN_ORDER... + this->optarg = this->argv_[this->optind++]; + this->nextchar_ = 0; + return 1; + } + else if (this->nextchar_[1] != 0 + && *++this->nextchar_ == '-' + && this->nextchar_[1] == 0) + { + // Found "--" so we're done... + ++this->optind; + this->nextchar_ = 0; + return EOF; + } + + // If it's a long option, and we allow long options advance nextchar_. + if (*this->nextchar_ == '-' && this->long_opts_.size () != 0) + this->nextchar_++; + + return 0; +} + +int +ACE_Get_Opt::long_option_i (void) +{ + ACE_TRACE ("ACE_Get_Opt::long_option_i"); + + ACE_Get_Opt_Long_Option *p; + ACE_TCHAR *s = this->nextchar_; + int hits = 0; + int exact = 0; + ACE_Get_Opt_Long_Option *pfound = 0; + int indfound = 0; + + // Advance to the end of the long option name so we can use + // it to get the length for a string compare. + while (*s && *s != '=') + s++; + + size_t len = s - this->nextchar_; + // set last_option_ to nextchar_, up to the '='. + this->last_option (ACE_TString (this->nextchar_, len)); + + size_t size = this->long_opts_.size (); + u_int option_index = 0; + for (option_index = 0; option_index < size ; option_index++) + { + p = this->long_opts_[option_index]; + ACE_ASSERT (p); + + if (!ACE_OS::strncmp (p->name_, this->nextchar_, len)) + { + // Got at least a partial match. + pfound = p; + indfound = option_index; + hits += 1; + if (len == ACE_OS::strlen(p->name_)) + { + // And in fact, it's an exact match, so let's use it. + exact = 1; + break; + } + } + } + + if ((hits > 1) && !exact) + { + // Great, we found a match, but unfortunately we found more than + // one and it wasn't exact. + if (this->opterr) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%s: option `%s' is ambiguous\n"), + this->argv_[0], this->argv_[this->optind])); + this->nextchar_ = 0; + this->optind++; + return '?'; + } + + if (pfound != 0) + { + // Okay, we found a good one (either a single hit or an exact match). + option_index = indfound; + this->optind++; + if (*s) + { + // s must point to '=' which means there's an argument (well + // close enough). + if (pfound->has_arg_ != NO_ARG) + // Good, we want an argument and here it is. + this->optarg = ++s; + else + { + // Whoops, we've got what looks like an argument, but we + // don't want one. + if (this->opterr) + ACELIB_ERROR + ((LM_ERROR, + ACE_TEXT ("%s: long option `--%s' doesn't allow ") + ACE_TEXT ("an argument\n"), + this->argv_[0], pfound->name_)); + // The spec doesn't cover this, so we keep going and the program + // doesn't know we ignored an argument if opt_err is off!!! + } + } + else if (pfound->has_arg_ == ARG_REQUIRED) + { + // s didn't help us, but we need an argument. Note that + // optional arguments for long options must use the "=" syntax, + // so we won't get here in that case. + if (this->optind < this->argc_) + // We still have some elements left, so use the next one. + this->optarg = this->argv_[this->optind++]; + else + { + // All out of elements, so we have to punt... + if (this->opterr) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%s: long option '--%s' requires ") + ACE_TEXT ("an argument\n"), + this->argv_[0], pfound->name_)); + this->nextchar_ = 0; + this->optopt_ = pfound->val_; // Remember matching short equiv + return this->has_colon_ ? ':' : '?'; + } + } + this->nextchar_ = 0; + this->long_option_ = pfound; + // Since val_ has to be either a valid short option or 0, this works + // great. If the user really wants to know if a long option was passed. + this->optopt_ = pfound->val_; + return pfound->val_; + } + if (!this->long_only_ || this->argv_[this->optind][1] == '-' + || this->optstring_->find (*this->nextchar_) == ACE_TString::npos) + { + // Okay, we couldn't find a long option. If it isn't long_only (which + // means try the long first, and if not found try the short) or a long + // signature was passed, e.g. "--", or it's not a short (not sure when + // this could happen) it's an error. + if (this->opterr) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%s: illegal long option '--%s'\n"), + this->argv_[0], this->nextchar_)); + this->nextchar_ = 0; + this->optind++; + return '?'; + } + return this->short_option_i (); +} + +int +ACE_Get_Opt::short_option_i (void) +{ + ACE_TRACE ("ACE_Get_Opt::short_option_i"); + + /* Look at and handle the next option-character. */ + ACE_TCHAR opt = *this->nextchar_++; + // Set last_option_ to opt + this->last_option (opt); + + ACE_TCHAR *oli = 0; + oli = + const_cast (ACE_OS::strchr (this->optstring_->c_str (), opt)); + + /* Increment `optind' when we start to process its last character. */ + if (*this->nextchar_ == '\0') + ++this->optind; + + if (oli == 0 || opt == ':') + { + if (this->opterr) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%s: illegal short option -- %c\n"), + this->argv_[0], opt)); + return '?'; + } + if (opt == 'W' && oli[1] == ';') + { + if (this->nextchar_[0] == 0) + this->nextchar_ = this->argv_[this->optind]; + return long_option_i (); + } + this->optopt_ = oli[0]; // Remember the option that matched + if (oli[1] == ':') + { + if (oli[2] == ':') + { + // Takes an optional argument, and since short option args must + // must follow directly in the same argument, a NULL nextchar_ + // means we didn't get one. + if (*this->nextchar_ != '\0') + { + this->optarg = this->nextchar_; + this->optind++; + } + else + this->optarg = 0; + this->nextchar_ = 0; + } + else + { + // Takes a required argument. + if (*this->nextchar_ != '\0') + { + // Found argument in same argv-element. + this->optarg = this->nextchar_; + this->optind++; + } + else if (this->optind == this->argc_) + { + // Ran out of arguments before finding required argument. + if (this->opterr) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%s: short option requires ") + ACE_TEXT ("an argument -- %c\n"), + this->argv_[0], opt)); + opt = this->has_colon_ ? ':' : '?'; + } + else + // Use the next argv-element as the argument. + this->optarg = this->argv_[this->optind++]; + this->nextchar_ = 0; + } + } + return opt; +} + +int +ACE_Get_Opt::operator () (void) +{ + ACE_TRACE ("ACE_Get_Opt_Long::operator"); + + // First of all, make sure we reinitialize any pointers.. + this->optarg = 0; + this->long_option_ = 0; + + if (this->argv_ == 0) + { + // It can happen, e.g., on VxWorks. + this->optind = 0; + return -1; + } + + // We check this because we can string short options together if the + // preceding one doesn't take an argument. + if (this->nextchar_ == 0 || *this->nextchar_ == '\0') + { + int retval = this->nextchar_i (); + if (retval != 0) + return retval; + } + + if (((this->argv_[this->optind][0] == '-') + && (this->argv_[this->optind][1] == '-')) || this->long_only_) + return this->long_option_i (); + + return this->short_option_i (); +} + +int +ACE_Get_Opt::long_option (const ACE_TCHAR *name, + OPTION_ARG_MODE has_arg) +{ + ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, OPTION_ARG_MODE has_arg)"); + return this->long_option (name, 0, has_arg); +} + +int +ACE_Get_Opt::long_option (const ACE_TCHAR *name, + int short_option, + OPTION_ARG_MODE has_arg) +{ + ACE_TRACE ("ACE_Get_Opt::long_option (const ACE_TCHAR *name, int short_option, OPTION_ARG_MODE has_arg)"); + + // We only allow valid alpha-numeric characters as short options. + // If short_options is not a valid alpha-numeric, we can still return it + // when the long option is found, but won't allow the caller to pass it on + // the command line (how could they?). The special case is 0, but since + // we always return it, we let the caller worry about that. + if (ACE_OS::ace_isalnum (short_option) != 0) + { + // If the short_option already exists, make sure it matches, otherwise + // add it. + ACE_TCHAR *s = 0; + if ((s = const_cast ( + ACE_OS::strchr (this->optstring_->c_str (), + short_option))) != 0) + { + // Short option exists, so verify the argument options + if (s[1] == ':') + { + if (s[2] == ':') + { + if (has_arg != ARG_OPTIONAL) + { + if (this->opterr) + ACELIB_ERROR + ((LM_ERROR, + ACE_TEXT ("Existing short option '%c' takes ") + ACE_TEXT ("optional argument; adding %s ") + ACE_TEXT ("requires ARG_OPTIONAL\n"), + short_option, name)); + return -1; + } + } + else + if (has_arg != ARG_REQUIRED) + { + if (this->opterr) + ACELIB_ERROR + ((LM_ERROR, + ACE_TEXT ("Existing short option '%c' requires ") + ACE_TEXT ("an argument; adding %s ") + ACE_TEXT ("requires ARG_REQUIRED\n"), + short_option, name)); + return -1; + } + } + else if (has_arg != NO_ARG) + { + if (this->opterr) + ACELIB_ERROR + ((LM_ERROR, + ACE_TEXT ("Existing short option '%c' does not ") + ACE_TEXT ("accept an argument; adding %s ") + ACE_TEXT ("requires NO_ARG\n"), + short_option, name)); + return -1; + } + } + else + { + // Didn't find short option, so add it... + *this->optstring_ += (ACE_TCHAR) short_option; + if (has_arg == ARG_REQUIRED) + *this->optstring_ += ACE_TEXT (":"); + else if (has_arg == ARG_OPTIONAL) + *this->optstring_ += ACE_TEXT ("::"); + } + } + + ACE_Get_Opt_Long_Option *option = + new ACE_Get_Opt_Long_Option (name, has_arg, short_option); + + if (!option) + return -1; + + // Add to array + size_t size = this->long_opts_.size (); + if (this->long_opts_.size (size + 1) != 0 + || this->long_opts_.set (option, size) != 0) + { + delete option; + ACELIB_ERROR_RETURN + ((LM_ERROR, ACE_TEXT ("Could not add long option to array.\n")), + -1); + } + return 0; +} + +const ACE_TCHAR* +ACE_Get_Opt::long_option (void) const +{ + ACE_TRACE ("ACE_Get_Opt::long_option (void)"); + if (this->long_option_) + return this->long_option_->name_; + return 0; +} + +const ACE_TCHAR* +ACE_Get_Opt::last_option (void) const +{ + return this->last_option_->c_str (); +} + +void +ACE_Get_Opt::last_option (const ACE_TString &last_option) +{ + *this->last_option_ = last_option; +} + +void +ACE_Get_Opt::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Get_Opt::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n") + ACE_TEXT ("opstring_ = %s\n") + ACE_TEXT ("long_only_ = %d\n") + ACE_TEXT ("has_colon_ = %d\n") + ACE_TEXT ("last_option_ = %s\n") + ACE_TEXT ("nextchar_ = %s\n") + ACE_TEXT ("optopt_ = %c\n") + ACE_TEXT ("ordering_ = %d\n"), + this->optstring_->c_str (), + this->long_only_, + this->has_colon_, + this->last_option_->c_str (), + this->nextchar_, + this->optopt_, + this->ordering_)); + + // now loop through the + size_t size = this->long_opts_.size (); + for (u_int i = 0; i < size ; ++i) + { + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n") + ACE_TEXT ("long_option name_ = %s\n") + ACE_TEXT ("has_arg_ = %d\n") + ACE_TEXT ("val_ = %d\n"), + this->long_opts_[i]->name_, + this->long_opts_[i]->has_arg_, + this->long_opts_[i]->val_)); + } + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +void +ACE_Get_Opt::permute_args (void) +{ + ACE_TRACE ("ACE_Get_Opt::permute_args"); + + u_long cyclelen, i, j, ncycle, nnonopts, nopts; + u_long opt_end = this->optind; + int cstart, pos = 0; + ACE_TCHAR *swap = 0; + + nnonopts = this->nonopt_end_ - this->nonopt_start_; + nopts = opt_end - this->nonopt_end_; + ncycle = ACE::gcd (nnonopts, nopts); + cyclelen = (opt_end - this->nonopt_start_) / ncycle; + + this->optind = this->optind - nnonopts; + + for (i = 0; i < ncycle; i++) + { + cstart = this->nonopt_end_ + i; + pos = cstart; + for (j = 0; j < cyclelen; j++) + { + if (pos >= this->nonopt_end_) + pos -= nnonopts; + else + pos += nopts; + swap = this->argv_[pos]; + + ((ACE_TCHAR **)this->argv_)[pos] = argv_[cstart]; + + ((ACE_TCHAR **)this->argv_)[cstart] = swap; + } + } +} + +int +ACE_Get_Opt::permute (void) +{ + ACE_TRACE ("ACE_Get_Opt::permute"); + + if (this->nonopt_start_ != this->nonopt_end_ + && this->nonopt_start_ != this->optind) + this->permute_args (); + + this->nonopt_start_ = this->optind; + + // Skip over args untill we find the next option. + while (this->optind < this->argc_ + && (this->argv_[this->optind][0] != '-' + || this->argv_[this->optind][1] == '\0')) + this->optind++; + + // Got an option, so mark this as the end of the non options. + this->nonopt_end_ = this->optind; + + if (this->optind != this->argc_ + && ACE_OS::strcmp (this->argv_[this->optind], + ACE_TEXT ("--")) == 0) + { + // We found the marker for the end of the options. + ++this->optind; + + if (this->nonopt_start_ != this->nonopt_end_ + && this->nonopt_end_ != this->optind) + this->permute_args (); + } + + if (this->optind == this->argc_) + { + if (this->nonopt_start_ != this->nonopt_end_) + this->optind = this->nonopt_start_; + return EOF; + } + return 0; +} + +const ACE_TCHAR * +ACE_Get_Opt::optstring (void) const +{ + return this->optstring_->c_str (); +} + +ACE_Get_Opt::ACE_Get_Opt_Long_Option::ACE_Get_Opt_Long_Option ( + const ACE_TCHAR *name, + int has_arg, + int val) + : name_ (ACE::strnew (name)), + has_arg_ (has_arg), + val_ (val) +{} + +ACE_Get_Opt::ACE_Get_Opt_Long_Option::~ACE_Get_Opt_Long_Option (void) +{ +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(const_cast(this->name_)); +#else + delete [] this->name_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Get_Opt::ACE_Get_Opt_Long_Option); + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Get_Opt.h b/dep/acelite/ace/Get_Opt.h new file mode 100644 index 000000000..47aa82720 --- /dev/null +++ b/dep/acelite/ace/Get_Opt.h @@ -0,0 +1,494 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Get_Opt.h + * + * @author Douglas C. Schmidt + * @author Don Hinton (added long option support) + */ +//========================================================================== + +#ifndef ACE_GET_OPT_H +#define ACE_GET_OPT_H +#include /**/ "ace/pre.h" + +#include "ace/SStringfwd.h" +#include "ace/Containers.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#undef optind +#undef optarg +#undef opterr + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/* + * These definitions are for backward compatibility with previous versions. + * of ACE_Get_Opt. + */ + +/** + * @class ACE_Get_Opt + * + * @brief Iterator for parsing command-line arguments. + * + * This is a C++ wrapper for getopt(3c) and getopt_long(3c). + */ + +class ACE_Export ACE_Get_Opt +{ +public: + /// Mutually exclusive ordering values. + enum + { + /** + * REQUIRE_ORDER means that processing stops and @c EOF is + * returned as soon as a non-option argument is found. @c opt_ind() + * will return the index of the next @a argv element so the program + * can continue processing the rest of the @a argv elements. + */ + REQUIRE_ORDER = 1, + + /** + * PERMUTE_ARGS means the @a argv elements are reordered dynamically + * (permuted) so that all options appear first. When the elements are + * permuted, the order of the options and the following arguments are + * maintained. When the last option has been processed, @c EOF is + * returned and @c opt_ind() returns the index into the next non-option + * element. + */ + PERMUTE_ARGS = 2, + + /** + * RETURN_IN_ORDER means each @a argv element is processed in the + * order is it seen. If the element is not recognized as an option, '1' + * is returned and @c opt_arg() refers to the @a argv element found. + */ + RETURN_IN_ORDER = 3 + }; + + /// Mutually exclusive option argument mode used by long options. + enum OPTION_ARG_MODE + { + /// Doesn't take an argument. + NO_ARG = 0, + + /// Requires an argument, same as passing ":" after a short option + /// character in @a optstring. + ARG_REQUIRED = 1, + + /// Argument is optional, same as passing "::" after a short + /// option character in @a optstring. + ARG_OPTIONAL = 2 + }; + + /** + * Constructor initializes the command line to be parsed. All information + * for parsing must be supplied to this constructor. + * + * @param argc The number of @a argv elements to parse. + * @param argv Command line tokens, such as would be passed + * to @c main(). + * @param optstring Nul-terminated string containing the legitimate + * short option characters. A single colon ":" + * following an option character means the option + * requires an argument. A double colon "::" following + * an option character means the argument is optional. + * The argument is taken from the rest of the current + * @a argv element, or from the following @a argv + * element (only valid for required arguments; + * optional arguments must always reside in the same + * @a argv element). The argument value, if any is + * returned by the @c opt_arg() method. + * @a optstring can be extended by adding long options + * with corresponding short options via the + * @c long_option() method. If the short option + * already appears in @a optstring, the argument + * characteristics must match, otherwise it is added. + * See @c long_option() for more information. + * If 'W', followed by a semi-colon ';' appears in + * @a optstring, then any time a 'W' appears on the + * command line, the following argument is treated as + * a long option. For example, if the command line + * contains "program -W foo", "foo" is treated as a + * long option, that is, as if "program --foo" had + * been passed. + * The following characters can appear in @a optstring + * before any option characters, with the described + * effect: + * - '+' changes the @a ordering to @a REQUIRE_ORDER. + * - '-' changes the @a ordering to @a RETURN_IN_ORDER. + * - ':' changes the return value from @c operator() + * and get_opt() from '?' to ':' when an option + * requires an argument but none is specified. + * + * @param skip_args Optional (default 1). The specified number of + * initial elements in @a argv are skipped before + * parsing begins. Thus, the default prevents + * @a argv[0] (usually the command name) from being + * parsed. @a argc includes all @a argv elements, + * including any skipped elements. + * @param report_errors Optional, if non-zero then parsing errors cause + * an error message to be displayed from the + * @c operator() method before it returns. The + * error message is suppressed if this argument is 0. + * This setting also controls whether or not an error + * message is displayed in @c long_option() encounters + * an error. + * @param ordering Optional (default is @c PERMUTE_ARGS); determines + * how the @a argv elements are processed. This argument + * is overridden by two factors: + * -# The @c POSIXLY_CORRECT environment variable. If + * this environment variable is set, the ordering + * is changed to @c REQUIRE_ORDER. + * -# Leading characters in @a optstring (see above). + * Any leading ordering characters override both + * the @a ordering argument and any effect of the + * @c POSIXLY_CORRECT environment variable. + * @param long_only Optional. If non-zero, then long options can be + * specified using a single '-' on the command line. + * If the token is not a long option, it is processed + * as usual, that is, as a short option or set of + * short options. + * + * Multiple short options can be combined as long as only the last + * one can takes an argument. For example, if @a optstring is defined as + * @c "abc:" or @c "abc::" then the command line @e "program -abcxxx" short + * options @e a, @e b, and @e c are found with @e "xxx" as the argument for + * @e c. + * However, if the command line is specified as @e "program -acb" only + * options @e a and @e c are found with @e "b" as the argument for @e c. + * Also, for options with optional arguments, that is, those followed by + * "::", the argument must be in the same @a argv element, so "program -abc + * xxx" will only find "xxx" as the argument for @e c if @a optstring is + * specified as @c "abc:" not @c "abc::". + */ +#ifndef ACE_USES_WCHAR + ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const ACE_TCHAR *optstring = ACE_TEXT (""), + int skip_args = 1, + int report_errors = 0, + int ordering = PERMUTE_ARGS, + int long_only = 0); + +#else +private: + void ACE_Get_Opt_Init (const ACE_TCHAR *optstring); +public: + ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const ACE_TCHAR *optstring = ACE_TEXT (""), + int skip_args = 1, + int report_errors = 0, + int ordering = PERMUTE_ARGS, + int long_only = 0); + ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const char *optstring, + int skip_args = 1, + int report_errors = 0, + int ordering = PERMUTE_ARGS, + int long_only = 0); +#endif + /// Default dtor. + ~ACE_Get_Opt (void); + + /** + * Scan elements of @a argv (whose length is @a argc) for short option + * characters given in @a optstring or long options (with no short + * option equivalents). + * + * If an element of @a argv starts with '-', and is not exactly "-" + * or "--", then it is a short option element. The characters of this + * element (aside from the initial '-') are option characters. If + * it starts with "--" followed by other characters it is treated as + * a long option. If @c operator() is called repeatedly, it returns + * each of the option characters from each of the option elements. + * + * @return The parsed option character. The following characters have + * special significance. + * @retval 0 A long option was found + * @retval '\?' Either an unknown option character was found, or the + * option is known but requires an argument, none was + * specified, and @a optstring did not contain a leading + * colon. + * @retval ':' A known option character was found but it requires an + * argument and none was supplied, and the first character + * of @a optstring was a colon. @c opt_opt() indicates + * which option was specified. + * @retval '1' @c RETURN_IN_ORDER was specified and a non-option argument + * was found. + * @retval EOF No more option characters were found. @c opt_ind() will + * return the index in @a argv of the first @a argv element + * that is not an option. If @c PERMUTE_ARGS was + * specified, the @a argv elements have been permuted so that + * those that are not options now come last. + * + * @note The standards are unclear with respect to the conditions under + * which '?' and ':' are returned, so we scan the initial characters of + * @a optstring up unto the first short option character for '+', '-', + * and ':' in order to determine ordering and missing argument behavior. + */ + int operator () (void); + + /** + * For communication from @c operator() to the caller. When + * @c operator() finds an option that takes an argument, the argument + * value is returned from this method, otherwise it returns 0. + */ + ACE_TCHAR *opt_arg (void) const; + + /** + * Returns the most recently matched option character. Especially + * useful when operator() returns ':' for an unspecified argument + * that's required, since this allows the caller to learn what option + * was specified without its required argument. + */ + int opt_opt (void); + + /** + * Index in @a argv of the next element to be scanned. This is used + * for communication to and from the caller and for communication + * between successive calls to @c operator(). On entry to + * @c operator(), zero means this is the first call; initialize. + * + * When @c operator() returns @c EOF, this is the index of the first of + * the non-option elements that the caller should itself scan. + * + * Otherwise, @c opt_ind() communicates from one call to the next how + * much of @a argv has been scanned so far. + */ + int &opt_ind (void); + + /// Adds a long option with no corresponding short option. + /** + * If the @a name option is seen, @c operator() returns 0. + * + * @param name The long option to add. + * @param has_arg Defines the argument requirements for + * the new option. + * + * @retval 0 Success + * @retval -1 The long option can not be added. + */ + int long_option (const ACE_TCHAR *name, + OPTION_ARG_MODE has_arg = NO_ARG); + + /// Adds a long option with a corresponding short option. + /** + * @param name The long option to add. + * @param short_option A character, the short option that corresponds + * to @a name. + * @param has_arg Defines the argument requirements for + * the new option. If the short option has already + * been supplied in the @a optstring, @a has_arg + * must match or an error is returned; otherwise, the + * new short option is added to the @a optstring. + * + * @retval 0 Success + * @retval -1 The long option can not be added. + */ + int long_option (const ACE_TCHAR *name, + int short_option, + OPTION_ARG_MODE has_arg = NO_ARG); + + /// Returns the name of the long option found on the last call to + /// @c operator() or 0 if none was found. + const ACE_TCHAR *long_option (void) const; + + /// The number of arguments in the internal @c argv_. + int argc (void) const; + + /// Accessor for the internal @c argv_ pointer. + ACE_TCHAR **argv (void) const; + + /// Accessor for the @c last_option that was processed. This allows + /// applications to know if the found option was a short or long + /// option, and is especially useful in cases where it was invalid + /// and the caller wants to print out the invalid value. + const ACE_TCHAR *last_option (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Return the @a optstring. This is handy to verify that calls to + /// long_option added short options as expected. + const ACE_TCHAR *optstring (void) const; + +public: + /* + * The following five data members should be private, but that + * would break backwards compatibility. However, we recommend not + * writing code that uses these fields directly. + */ + + /// Holds the @a argc count. + /** + * @deprecated This is public for backwards compatibility only. + * It will be made private in a release of ACE past 5.3. Do not + * write code that relies on this member being public; use the + * @c argc() accessor method instead. + */ + int argc_; + + /// Holds the @a argv pointer. + /** + * @deprecated This is public for backwards compatibility only. + * It will be made private in a release of ACE past 5.3. Do not + * write code that relies on this member being public; use the + * @c argv() accessor method instead. + */ + ACE_TCHAR **argv_; + + /// Index in @c argv_ of the next element to be scanned. + /** + * @deprecated This is public for backwards compatibility only. + * It will be made private in a release of ACE past 5.3. Do not + * write code that relies on this member being public; use the + * @c opt_ind() accessor method instead. + */ + int optind; + + /// Callers store zero here to inhibit the error message for + /// unrecognized options. + /** + * @deprecated This is public for backwards compatibility only. + * It will be made private in a release of ACE past 5.3. Do not + * write code that relies on this member being public; use the + * @a report_errors argument to this class's constructor instead. + */ + int opterr; + + /// Points to the option argument when one is found on last call to + /// @c operator(). + /** + * @deprecated This is public for backwards compatibility only. + * It will be made private in a release of ACE past 5.3. Do not + * write code that relies on this member being public; use the + * @c opt_arg() accessor method instead. + */ + ACE_TCHAR *optarg; + +private: + /** + * @class ACE_Get_Opt_Long_Option This class is for internal use + * in the ACE_Get_Opt class, and is inaccessible to users. + */ + class ACE_Get_Opt_Long_Option + { + public: + /// ctor + ACE_Get_Opt_Long_Option (const ACE_TCHAR *name, + int has_arg, + int val = 0); + + /// Dtor. + ~ACE_Get_Opt_Long_Option (void); + + bool operator < (const ACE_Get_Opt_Long_Option &rhs); + + /// Long option name. + const ACE_TCHAR *name_; + + /// Contains value for . + int has_arg_; + + /// Contains a valid short option character or zero if it doesn't + /// have a corresponding short option. It can also contain a + /// non-printable value that cannot be passed to but + /// will be returned by . This is handy for + /// simplifying long option handling, see tests/Get_Opt_Test.cpp + /// for an example of this technique. + int val_; + + ACE_ALLOC_HOOK_DECLARE; + }; + + /// Updates nextchar_. + int nextchar_i (void); + + /// Handles long options. + int long_option_i (void); + + /// Handles short options. + int short_option_i (void); + + /// If permuting args, this functions manages the nonopt_start_ and + /// nonopt_end_ indexes and makes calls to permute to actually + /// reorder the -elements. + void permute_args (void); + + /// Handles reordering -elements. + int permute (void); + + /// Set last_option. + void last_option (const ACE_TString &s); + + // Disallow copying and assignment. + ACE_Get_Opt (const ACE_Get_Opt &); + ACE_Get_Opt &operator= (const ACE_Get_Opt &); + +private: + + /// Holds the option string. + ACE_TString *optstring_; + + /// Treat all options as long options. + int long_only_; + + /// Keeps track of whether or not a colon was passed in . + /// This is used to determine the return value when required + /// arguments are missing. + int has_colon_; + + /// This is the last option, short or long, that was processed. This + /// is handy to have in cases where the option passed was invalid. + ACE_TString *last_option_; + + /** + * The next char to be scanned in the option-element in which the + * last option character we returned was found. This allows us to + * pick up the scan where we left off * + * If this is zero, or a null string, it means resume the scan + * by advancing to the next -element. + */ + ACE_TCHAR *nextchar_; + + /// Most recently matched short option character. + int optopt_; + + /// Keeps track of ordering mode (default ). + int ordering_; + + /// Index of the first non-option -element found (only valid + /// when permuting). + int nonopt_start_; + + /// Index of the -element following the last non-option element + /// (only valid when permuting). + int nonopt_end_; + + /// Points to the long_option found on last call to . + ACE_Get_Opt_Long_Option *long_option_; + + /// Array of long options. + ACE_Array long_opts_; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Get_Opt.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_GET_OPT_H */ diff --git a/dep/acelite/ace/Get_Opt.inl b/dep/acelite/ace/Get_Opt.inl new file mode 100644 index 000000000..32de1d85c --- /dev/null +++ b/dep/acelite/ace/Get_Opt.inl @@ -0,0 +1,94 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE bool +ACE_Get_Opt::ACE_Get_Opt_Long_Option::operator < (const ACE_Get_Opt_Long_Option &rhs) +{ + return this->name_ < rhs.name_; +} + +ACE_INLINE int +ACE_Get_Opt::argc (void) const +{ + return this->argc_; +} + +ACE_INLINE ACE_TCHAR ** +ACE_Get_Opt::argv (void) const +{ + return this->argv_; +} + +ACE_INLINE ACE_TCHAR* +ACE_Get_Opt::opt_arg (void) const +{ + return this->optarg; +} + +ACE_INLINE int +ACE_Get_Opt::opt_opt (void) +{ + return this->optopt_; +} + +ACE_INLINE int & +ACE_Get_Opt::opt_ind (void) +{ + return this->optind; +} + +#ifdef ACE_USES_WCHAR +ACE_INLINE ACE_Get_Opt::ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const ACE_TCHAR *optstring, + int skip_args, + int report_errors, + int ordering, + int long_only) + : argc_ (argc), + argv_ (argv), + optind (skip_args), + opterr (report_errors), + optarg (0), + optstring_ (0), + long_only_ (long_only), + has_colon_ (0), + last_option_ (0), + nextchar_ (0), + optopt_ (0), + ordering_ (ordering), + nonopt_start_ (optind), + nonopt_end_ (optind), + long_option_ (0) +{ + ACE_Get_Opt_Init (optstring); +} + +ACE_INLINE ACE_Get_Opt::ACE_Get_Opt (int argc, + ACE_TCHAR **argv, + const char *optstring, + int skip_args, + int report_errors, + int ordering, + int long_only) + : argc_ (argc), + argv_ (argv), + optind (skip_args), + opterr (report_errors), + optarg (0), + optstring_ (), + long_only_ (long_only), + has_colon_ (0), + last_option_ (0), + nextchar_ (0), + optopt_ (0), + ordering_ (ordering), + nonopt_start_ (optind), + nonopt_end_ (optind), + long_option_ (0) +{ + ACE_Get_Opt_Init (ACE_TEXT_CHAR_TO_TCHAR (optstring)); +} +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Global_Macros.h b/dep/acelite/ace/Global_Macros.h new file mode 100644 index 000000000..23d81ef88 --- /dev/null +++ b/dep/acelite/ace/Global_Macros.h @@ -0,0 +1,1014 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Global_Macros.h + * + * @author Douglas C. Schmidt + * @author Jesper S. M|ller + * @author and a cast of thousands... + * + * This one is split from the famous OS.h + */ +//============================================================================= + +#ifndef ACE_GLOBAL_MACROS_H +#define ACE_GLOBAL_MACROS_H + +#include /**/ "ace/pre.h" + +// Included just keep compilers that see #pragma dierctive first +// happy. +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/config-lite.h" +#include "ace/Assert.h" // For ACE_ASSERT + +// Start Global Macros +# define ACE_BEGIN_DUMP ACE_TEXT ("\n====\n(%P|%t|%x)\n") +# define ACE_END_DUMP ACE_TEXT ("====\n") + +# if defined (ACE_NDEBUG) +# define ACE_DB(X) +# else +# define ACE_DB(X) X +# endif /* ACE_NDEBUG */ + +// Turn a number into a string. +# define ACE_ITOA(X) #X + +// Create a string of a server address with a "host:port" format. +# define ACE_SERVER_ADDRESS(H,P) H ACE_TEXT(":") P + +// A couple useful inline functions for checking whether bits are +// enabled or disabled. + +// Efficiently returns the least power of two >= X... +# define ACE_POW(X) (((X) == 0)?1:(X-=1,X|=X>>1,X|=X>>2,X|=X>>4,X|=X>>8,X|=X>>16,(++X))) +# define ACE_EVEN(NUM) (((NUM) & 1) == 0) +# define ACE_ODD(NUM) (((NUM) & 1) == 1) +# define ACE_BIT_ENABLED(WORD, BIT) (((WORD) & (BIT)) != 0) +# define ACE_BIT_DISABLED(WORD, BIT) (((WORD) & (BIT)) == 0) +# define ACE_BIT_CMP_MASK(WORD, BIT, MASK) (((WORD) & (BIT)) == MASK) +# define ACE_SET_BITS(WORD, BITS) (WORD |= (BITS)) +# define ACE_CLR_BITS(WORD, BITS) (WORD &= ~(BITS)) + +# if !defined (ACE_ENDLESS_LOOP) +# define ACE_ENDLESS_LOOP +# endif /* ! ACE_ENDLESS_LOOP */ + +# if defined (ACE_NEEDS_FUNC_DEFINITIONS) && !defined (ACE_HAS_CPP11) + // It just evaporated ;-) Not pleasant. +# define ACE_UNIMPLEMENTED_FUNC(f) +# else +# if defined (ACE_HAS_CPP11) +# define ACE_UNIMPLEMENTED_FUNC(f) f = delete; +# else +# define ACE_UNIMPLEMENTED_FUNC(f) f; +# endif +# endif /* ACE_NEEDS_FUNC_DEFINITIONS */ + +// noexcept(false) specification to specify that the operation can +// throw an exception +#if defined (ACE_HAS_CPP11) +#define ACE_NOEXCEPT_FALSE noexcept(false) +#else +#define ACE_NOEXCEPT_FALSE +#endif + +// ---------------------------------------------------------------- + +// FUZZ: disable check_for_ACE_Guard + +/* Convenient macro for testing for deadlock, as well as for detecting + * when mutexes fail. + * + * The parameters to the ACE_GUARD_XXX macros are used as follows: + * + * MUTEX - This is the type used as the template parameter for ACE_Guard + * + * OBJ - Name for the guard object. This name should not be declared + * outside the macro. + * + * LOCK - The actual lock (mutex) variable. This should be a variable + * of type MUTEX, see above. + * + * ACTION - Code segment to be run, if and only if the lock is + * acquired. + * + * REACTION - Code segment to be run, if and only if the lock is not + * acquired. + * + * RETURN - A value to be returned from the calling function, if and + * only if the lock is not acquired. + * + * @warning + * Use of ACE_GUARD() is rarely correct. ACE_GUARD() causes the + * current function to return if the lock is not acquired. Since + * merely returning (no value) almost certainly fails to handle the + * acquisition failure and almost certainly fails to communicate the + * failure to the caller for the caller to handle, ACE_GUARD() is + * almost always the wrong thing to do. The same goes for + * ACE_WRITE_GUARD() and ACE_READ_GUARD() . ACE_GUARD_REACTION() is + * better because it lets you specify error handling code. + */ +#if !defined (ACE_GUARD_ACTION) +#define ACE_GUARD_ACTION(MUTEX, OBJ, LOCK, ACTION, REACTION) \ + ACE_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () != 0) { ACTION; } \ + else { REACTION; } +#endif /* !ACE_GUARD_ACTION */ +#if !defined (ACE_GUARD_REACTION) +#define ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, REACTION) \ + ACE_GUARD_ACTION(MUTEX, OBJ, LOCK, ;, REACTION) +#endif /* !ACE_GUARD_REACTION */ +#if !defined (ACE_GUARD) +#define ACE_GUARD(MUTEX, OBJ, LOCK) \ + ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, return) +#endif /* !ACE_GUARD */ +#if !defined (ACE_GUARD_RETURN) +#define ACE_GUARD_RETURN(MUTEX, OBJ, LOCK, RETURN) \ + ACE_GUARD_REACTION(MUTEX, OBJ, LOCK, return RETURN) +#endif /* !ACE_GUARD_RETURN */ +#if !defined (ACE_WRITE_GUARD) +# define ACE_WRITE_GUARD(MUTEX,OBJ,LOCK) \ + ACE_Write_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) return; +#endif /* !ACE_WRITE_GUARD */ +#if !defined (ACE_WRITE_GUARD_RETURN) +# define ACE_WRITE_GUARD_RETURN(MUTEX,OBJ,LOCK,RETURN) \ + ACE_Write_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) return RETURN; +#endif /* ACE_WRITE_GUARD_RETURN */ +#if !defined (ACE_READ_GUARD) +# define ACE_READ_GUARD(MUTEX,OBJ,LOCK) \ + ACE_Read_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) return; +#endif /* !ACE_READ_GUARD */ +#if !defined (ACE_READ_GUARD_RETURN) +# define ACE_READ_GUARD_RETURN(MUTEX,OBJ,LOCK,RETURN) \ + ACE_Read_Guard< MUTEX > OBJ (LOCK); \ + if (OBJ.locked () == 0) return RETURN; +#endif /* !ACE_READ_GUARD_RETURN */ +// FUZZ: enable check_for_ACE_Guard + +// ---------------------------------------------------------------- + +#if defined(ACE_UNEXPECTED_RETURNS) + +/* Using ACE_UNEXPECTED_RETURNS is ill-advised because, in many cases, + * it fails to inform callers of the error condition. + * It exists mainly to provide back-compatibility with old, dangegrous, + * incorrect behavior. + * Code that previously used ACE_GUARD() or ACE_GUARD_RETURN() to return + * upon failure to acquire a lock can now use: + * ACE_GUARD_REACTION(..., ACE_UNEXPECTED(...)) + * The behavior of this depends on whether or not ACE_UNEXPECTED_RETURNS + * is defined. If so, it just returns upon failure (as in the original), + * which is usually dangerous because it usually fails to handle the + * error. If not, it calls std::unexpected(), which does whatever the + * std::unexpected handler does (which is to abort, by default). + */ +# define ACE_UNEXPECTED(RETVAL) \ + do { \ + return RETVAL; \ + } while (0) + +#else + +# define ACE_UNEXPECTED(RETVAL) \ + do { \ + std::unexpected(); \ + } while (0) + +#endif + +// ---------------------------------------------------------------- + +# define ACE_DES_NOFREE(POINTER,CLASS) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~CLASS (); \ + } \ + } \ + while (0) + +# define ACE_DES_ARRAY_NOFREE(POINTER,SIZE,CLASS) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (&(POINTER)[i])->~CLASS (); \ + } \ + } \ + } \ + while (0) + +# define ACE_DES_FREE(POINTER,DEALLOCATOR,CLASS) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) + +# define ACE_DES_FREE_THIS(DEALLOCATOR,CLASS) \ + do { \ + this->~CLASS (); \ + DEALLOCATOR (this); \ + } \ + while (0) + +# define ACE_DES_ARRAY_FREE(POINTER,SIZE,DEALLOCATOR,CLASS) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (&(POINTER)[i])->~CLASS (); \ + } \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) + +# if defined (ACE_HAS_WORKING_EXPLICIT_TEMPLATE_DESTRUCTOR) +# define ACE_DES_NOFREE_TEMPLATE(POINTER,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + } \ + } \ + while (0) +# define ACE_DES_ARRAY_NOFREE_TEMPLATE(POINTER,SIZE,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (&(POINTER)[i])->~T_CLASS (); \ + } \ + } \ + } \ + while (0) + +#if defined (ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) +# define ACE_DES_FREE_TEMPLATE(POINTER,DEALLOCATOR,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS T_PARAMETER (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#else +# define ACE_DES_FREE_TEMPLATE(POINTER,DEALLOCATOR,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#endif /* defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) */ +# define ACE_DES_ARRAY_FREE_TEMPLATE(POINTER,SIZE,DEALLOCATOR,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (&(POINTER)[i])->~T_CLASS (); \ + } \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#if defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) +# define ACE_DES_FREE_TEMPLATE2(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#else +# define ACE_DES_FREE_TEMPLATE2(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#endif /* defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) */ +#if defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) +# define ACE_DES_FREE_TEMPLATE3(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#else +# define ACE_DES_FREE_TEMPLATE3(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#endif /* defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) */ +#if defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) +# define ACE_DES_FREE_TEMPLATE4(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3, T_PARAM4) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#else +# define ACE_DES_FREE_TEMPLATE4(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3, T_PARAM4) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +#endif /* defined(ACE_EXPLICIT_TEMPLATE_DESTRUCTOR_TAKES_ARGS) */ +# define ACE_DES_ARRAY_FREE_TEMPLATE2(POINTER,SIZE,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (&(POINTER)[i])->~T_CLASS (); \ + } \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# else /* ! ACE_HAS_WORKING_EXPLICIT_TEMPLATE_DESTRUCTOR */ +# define ACE_DES_NOFREE_TEMPLATE(POINTER,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + (POINTER)->T_CLASS T_PARAMETER::~T_CLASS (); \ + } \ + } \ + while (0) +# define ACE_DES_ARRAY_NOFREE_TEMPLATE(POINTER,SIZE,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + (POINTER)[i].T_CLASS T_PARAMETER::~T_CLASS (); \ + } \ + } \ + } \ + while (0) +# define ACE_DES_FREE_TEMPLATE(POINTER,DEALLOCATOR,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + POINTER->T_CLASS T_PARAMETER::~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# define ACE_DES_ARRAY_FREE_TEMPLATE(POINTER,SIZE,DEALLOCATOR,T_CLASS,T_PARAMETER) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + POINTER[i].T_CLASS T_PARAMETER::~T_CLASS (); \ + } \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# define ACE_DES_FREE_TEMPLATE2(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2) \ + do { \ + if (POINTER) \ + { \ + POINTER->T_CLASS ::~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# define ACE_DES_FREE_TEMPLATE3(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3) \ + do { \ + if (POINTER) \ + { \ + POINTER->T_CLASS ::~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# define ACE_DES_FREE_TEMPLATE4(POINTER,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2,T_PARAM3,T_PARAM4) \ + do { \ + if (POINTER) \ + { \ + POINTER->T_CLASS ::~T_CLASS (); \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# define ACE_DES_ARRAY_FREE_TEMPLATE2(POINTER,SIZE,DEALLOCATOR,T_CLASS,T_PARAM1,T_PARAM2) \ + do { \ + if (POINTER) \ + { \ + for (size_t i = 0; \ + i < SIZE; \ + ++i) \ + { \ + POINTER[i].T_CLASS ::~T_CLASS (); \ + } \ + DEALLOCATOR (POINTER); \ + } \ + } \ + while (0) +# endif /* defined ! ACE_HAS_WORKING_EXPLICIT_TEMPLATE_DESTRUCTOR */ + + +/*******************************************************************/ + +/// Service Objects, i.e., objects dynamically loaded via the service +/// configurator, must provide a destructor function with the +/// following prototype to perform object cleanup. +typedef void (*ACE_Service_Object_Exterminator)(void *); + +/** @name Service Configurator macros + * + * The following macros are used to define helper objects used in + * ACE's Service Configurator framework, which is described in + * Chapter 5 of C++NPv2 . This + * framework implements the Component Configurator pattern, which is + * described in Chapter 2 of POSA2 . + * The intent of this pattern is to allow developers to dynamically + * load and configure services into a system. With a little help from + * this macros statically linked services can also be dynamically + * configured. + * + * More details about this component are available in the documentation + * of the ACE_Service_Configurator class and also + * ACE_Dynamic_Service. + * + * Notice that in all the macros the SERVICE_CLASS parameter must be + * the name of a class derived from ACE_Service_Object. + */ +//@{ +/// Declare a the data structure required to register a statically +/// linked service into the service configurator. +/** + * The macro should be used in the header file where the service is + * declared, its only argument is usually the name of the class that + * implements the service. + * + * @param SERVICE_CLASS The name of the class implementing the + * service. + */ +# define ACE_STATIC_SVC_DECLARE(SERVICE_CLASS) \ +extern ACE_Static_Svc_Descriptor ace_svc_desc_##SERVICE_CLASS ; + +/// As ACE_STATIC_SVC_DECLARE, but using an export macro for NT +/// compilers. +/** + * NT compilers require the use of explicit directives to export and + * import symbols from a DLL. If you need to define a service in a + * dynamic library you should use this version instead. + * Normally ACE uses a macro to inject the correct export/import + * directives on NT. Naturally it also the macro expands to a blank + * on platforms that do not require such directives. + * The first argument (EXPORT_NAME) is the prefix for this export + * macro, the full name is formed by appending _Export. + * ACE provides tools to generate header files that define the macro + * correctly on all platforms, please see + * $ACE_ROOT/bin/generate_export_file.pl + * + * @param EXPORT_NAME The export macro name prefix. + * @param SERVICE_CLASS The name of the class implementing the service. + */ +#define ACE_STATIC_SVC_DECLARE_EXPORT(EXPORT_NAME,SERVICE_CLASS) \ +extern EXPORT_NAME##_Export ACE_Static_Svc_Descriptor ace_svc_desc_##SERVICE_CLASS; + +/// Define the data structure used to register a statically linked +/// service into the Service Configurator. +/** + * The service configurator requires several arguments to build and + * control an statically linked service, including its name, the + * factory function used to construct the service, and some flags. + * All those parameters are configured in a single structure, an + * instance of this structure is statically initialized using the + * following macro. + * + * @param SERVICE_CLASS The name of the class that implements the + * service, must be derived (directly or indirectly) from + * ACE_Service_Object. + * @param NAME The name for this service, this name is used by the + * service configurator to match configuration options provided in + * the svc.conf file. + * @param TYPE The type of object. Objects can be streams or service + * objects. Please read the ACE_Service_Configurator and ASX + * documentation for more details. + * @param FN The name of the factory function, usually the + * ACE_SVC_NAME macro can be used to generate the name. The + * factory function is often defined using ACE_FACTORY_DECLARE and + * ACE_FACTORY_DEFINE. + * @param FLAGS Flags to control the ownership and lifecycle of the + * object. Please read the ACE_Service_Configurator documentation + * for more details. + * @param ACTIVE If not zero then a thread will be dedicate to the + * service. Please read the ACE_Service_Configurator documentation + * for more details. + */ +# define ACE_STATIC_SVC_DEFINE(SERVICE_CLASS, NAME, TYPE, FN, FLAGS, ACTIVE) \ +ACE_Static_Svc_Descriptor ace_svc_desc_##SERVICE_CLASS = { NAME, TYPE, FN, FLAGS, ACTIVE }; + +/// Automatically register a service with the service configurator +/** + * In some applications the services must be automatically registered + * with the service configurator, before main() starts. + * The ACE_STATIC_SVC_REQUIRE macro defines a class whose constructor + * register the service, it also defines a static instance of that + * class to ensure that the service is registered before main. + * + * On platforms that lack adequate support for static C++ objects the + * macro ACE_STATIC_SVC_REGISTER can be used to explicitly register + * the service. + * + * @todo One class per-Service_Object seems wasteful. It should be + * possible to define a single class and re-use it for all the + * service objects, just by passing the Service_Descriptor as an + * argument to the constructor. + */ +#if defined(ACE_LACKS_STATIC_CONSTRUCTORS) +# define ACE_STATIC_SVC_REQUIRE(SERVICE_CLASS)\ +class ACE_Static_Svc_##SERVICE_CLASS {\ +public:\ + ACE_Static_Svc_##SERVICE_CLASS() { \ + ACE_Service_Config::insert (\ + &ace_svc_desc_##SERVICE_CLASS); \ + } \ +}; +#define ACE_STATIC_SVC_REGISTER(SERVICE_CLASS)\ +ACE_Static_Svc_##SERVICE_CLASS ace_static_svc_##SERVICE_CLASS + +#else /* !ACE_LACKS_STATIC_CONSTRUCTORS */ + +# define ACE_STATIC_SVC_REQUIRE(SERVICE_CLASS)\ +class ACE_Static_Svc_##SERVICE_CLASS {\ +public:\ + ACE_Static_Svc_##SERVICE_CLASS() { \ + ACE_Service_Config::insert (\ + &ace_svc_desc_##SERVICE_CLASS); \ + } \ +};\ +static ACE_Static_Svc_##SERVICE_CLASS ace_static_svc_##SERVICE_CLASS; +#define ACE_STATIC_SVC_REGISTER(SERVICE_CLASS) do {} while (0) + +#endif /* !ACE_LACKS_STATIC_CONSTRUCTORS */ + +// Preprocessor symbols will not be expanded if they are +// concatenated. Force the preprocessor to expand them during the +// argument prescan by calling a macro that itself calls another that +// performs the actual concatenation. +#define ACE_PREPROC_CONCATENATE_IMPL(A,B) A ## B +#define ACE_PREPROC_CONCATENATE(A,B) ACE_PREPROC_CONCATENATE_IMPL(A,B) + +#if defined (ACE_HAS_VERSIONED_NAMESPACE) && ACE_HAS_VERSIONED_NAMESPACE == 1 +// Preprocessor symbols will not be expanded if they are +// concatenated. Force the preprocessor to expand them during the +// argument prescan by calling a macro that itself calls another that +// performs the actual concatenation. +# define ACE_MAKE_SVC_CONFIG_FUNCTION_NAME(PREFIX,VERSIONED_NAMESPACE,SERVICE_CLASS) PREFIX ## _ ## VERSIONED_NAMESPACE ## _ ## SERVICE_CLASS +#else +# define ACE_MAKE_SVC_CONFIG_FUNCTION_NAME(PREFIX,VERSIONED_NAMESPACE,SERVICE_CLASS) PREFIX ## _ ## SERVICE_CLASS +#endif /* ACE_HAS_VERSIONED_NAMESPACE == 1 */ + +#define ACE_MAKE_SVC_CONFIG_FACTORY_NAME(VERSIONED_NAMESPACE,SERVICE_CLASS) ACE_MAKE_SVC_CONFIG_FUNCTION_NAME(_make,VERSIONED_NAMESPACE,SERVICE_CLASS) +#define ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(VERSIONED_NAMESPACE,SERVICE_CLASS) ACE_MAKE_SVC_CONFIG_FUNCTION_NAME(_gobble,VERSIONED_NAMESPACE,SERVICE_CLASS) + + +/// Declare the factory method used to create dynamically loadable +/// services. +/** + * Once the service implementation is dynamically loaded the Service + * Configurator uses a factory method to create the object. + * This macro declares such a factory function with the proper + * interface and export macros. + * Normally used in the header file that declares the service + * implementation. + * + * @param CLS must match the prefix of the export macro used for this + * service. + * @param SERVICE_CLASS must match the name of the class that + * implements the service. + */ +# define ACE_FACTORY_DECLARE(CLS,SERVICE_CLASS) \ +extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * \ +ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *); + +/// Define the factory method (and destructor) for a dynamically +/// loadable service. +/** + * Use with arguments matching ACE_FACTORY_DECLARE. + * Normally used in the .cpp file that defines the service + * implementation. + * + * This macro defines both the factory method and the function used to + * cleanup the service object. + * + * If this macro is used to define a factory function that need not be + * exported (for example, in a static service situation), CLS can be + * specified as ACE_Local_Service. + */ +# define ACE_Local_Service_Export + +#if defined (ACE_OPENVMS) +# define ACE_PREPROC_STRINGIFY(A) #A +# define ACE_MAKE_SVC_REGISTRAR_ARG(A) ACE_PREPROC_STRINGIFY(A), (void*)&A +# define ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS) \ +void ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (void *p) { \ + ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * _p = \ + static_cast< ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *> (p); \ + ACE_ASSERT (_p != 0); \ + delete _p; } \ +extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *\ +ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *gobbler) \ +{ \ + ACE_TRACE (#SERVICE_CLASS); \ + if (gobbler != 0) \ + *gobbler = (ACE_Service_Object_Exterminator) ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS); \ + return new SERVICE_CLASS; \ +} \ +ACE_Dynamic_Svc_Registrar ace_svc_reg_##SERVICE_CLASS \ + (ACE_MAKE_SVC_REGISTRAR_ARG(ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS))); +#else +# define ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS) \ +void ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (void *p) { \ + ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * _p = \ + static_cast< ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *> (p); \ + ACE_ASSERT (_p != 0); \ + delete _p; } \ +extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *\ +ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *gobbler) \ +{ \ + ACE_TRACE (#SERVICE_CLASS); \ + if (gobbler != 0) \ + *gobbler = (ACE_Service_Object_Exterminator) ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS); \ + return new SERVICE_CLASS; \ +} +#endif + +/** + * For service classes scoped within namespaces, use this macro in + * place of ACE_FACTORY_DEFINE. The third argument in this case is + * the fully scoped name of the class as it is to be + * instantiated. For example, given: + * namespace ACE + * { + * namespace Foo + * { + * class Bar : public ACE_Service_Object + * {}; + * }; + * }; + * + * ACE_FACTORY_DECLARE(ACE,ACE_Foo_Bar) + * + * you would then use: + * + * ACE_FACTORY_NAMESPACE_DEFINE(ACE,ACE_Foo_Bar,ACE::Foo::Bar) + * + * Note that in this example, the ACE_FACTORY_DECLARE is done outside + * the namespace scope. Then, the SERVICE_CLASS name is the same as + * the fully scoped class name, but with '::' replaced with '_'. Doing + * this will ensure unique generated signatures for the various C + * style functions. + */ +#if defined (ACE_OPENVMS) +# define ACE_PREPROC_STRINGIFY(A) #A +# define ACE_MAKE_SVC_REGISTRAR_ARG(A) ACE_PREPROC_STRINGIFY(A), (void*)&A +# define ACE_FACTORY_NAMESPACE_DEFINE(CLS,SERVICE_CLASS,NAMESPACE_CLASS) \ +void ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (void *p) { \ + ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * _p = \ + static_cast< ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *> (p); \ + ACE_ASSERT (_p != 0); \ + delete _p; } \ +extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *\ +ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *gobbler) \ +{ \ + ACE_TRACE (#SERVICE_CLASS); \ + if (gobbler != 0) \ + *gobbler = (ACE_Service_Object_Exterminator) ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS); \ + return new NAMESPACE_CLASS; \ +} \ +ACE_Dynamic_Svc_Registrar ace_svc_reg_##SERVICE_CLASS \ + (ACE_MAKE_SVC_REGISTRAR_ARG(ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS))); +#else +# define ACE_FACTORY_NAMESPACE_DEFINE(CLS,SERVICE_CLASS,NAMESPACE_CLASS) \ +void ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (void *p) { \ + ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * _p = \ + static_cast< ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *> (p); \ + ACE_ASSERT (_p != 0); \ + delete _p; } \ +extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *\ +ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *gobbler) \ +{ \ + ACE_TRACE (#SERVICE_CLASS); \ + if (gobbler != 0) \ + *gobbler = (ACE_Service_Object_Exterminator) ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS); \ + return new NAMESPACE_CLASS; \ +} +#endif + +/// The canonical name for a service factory method +# define ACE_SVC_NAME(SERVICE_CLASS) ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) + +/// The canonical way to invoke (i.e. construct) a service factory +/// method. +#define ACE_SVC_INVOKE(SERVICE_CLASS) ACE_SVC_NAME(SERVICE_CLASS) (0) + +//@} + +/** @name Helper macros for services defined in the netsvcs library. + * + * The ACE services defined in netsvcs use this helper macros for + * simplicity. + */ +//@{ +# define ACE_SVC_FACTORY_DECLARE(X) ACE_FACTORY_DECLARE (ACE_Svc, X) +# define ACE_SVC_FACTORY_DEFINE(X) ACE_FACTORY_DEFINE (ACE_Svc, X) +//@} + +#if defined (ACE_WIN32) +// These are used in SPIPE_Acceptor/Connector, but are ignored at runtime. +# if defined (ACE_HAS_WINCE) +# if !defined (PIPE_TYPE_MESSAGE) +# define PIPE_TYPE_MESSAGE 0 +# endif +# if !defined (PIPE_READMODE_MESSAGE) +# define PIPE_READMODE_MESSAGE 0 +# endif +# if !defined (PIPE_WAIT) +# define PIPE_WAIT 0 +# endif +# endif /* ACE_HAS_WINCE */ +#else /* !ACE_WIN32 */ +// Add some typedefs and macros to enhance Win32 conformance... +# if !defined (LPSECURITY_ATTRIBUTES) +# define LPSECURITY_ATTRIBUTES int +# endif /* !defined LPSECURITY_ATTRIBUTES */ +# if !defined (GENERIC_READ) +# define GENERIC_READ 0 +# endif /* !defined GENERIC_READ */ +# if !defined (FILE_SHARE_READ) +# define FILE_SHARE_READ 0 +# endif /* !defined FILE_SHARE_READ */ +# if !defined (OPEN_EXISTING) +# define OPEN_EXISTING 0 +# endif /* !defined OPEN_EXISTING */ +# if !defined (FILE_ATTRIBUTE_NORMAL) +# define FILE_ATTRIBUTE_NORMAL 0 +# endif /* !defined FILE_ATTRIBUTE_NORMAL */ +# if !defined (MAXIMUM_WAIT_OBJECTS) +# define MAXIMUM_WAIT_OBJECTS 0 +# endif /* !defined MAXIMUM_WAIT_OBJECTS */ +# if !defined (FILE_FLAG_OVERLAPPED) +# define FILE_FLAG_OVERLAPPED 0 +# endif /* !defined FILE_FLAG_OVERLAPPED */ +# if !defined (FILE_FLAG_SEQUENTIAL_SCAN) +# define FILE_FLAG_SEQUENTIAL_SCAN 0 +# endif /* FILE_FLAG_SEQUENTIAL_SCAN */ +# if !defined(FILE_FLAG_WRITE_THROUGH) +# define FILE_FLAG_WRITE_THROUGH 0 +# endif /* !defined FILE_FLAG_WRITE_THROUGH */ +# if !defined(PIPE_WAIT) +# define PIPE_WAIT 0 +# endif /* !defined PIPE_WAIT */ +# if !defined(PIPE_NOWAIT) +# define PIPE_NOWAIT 0 +# endif /* !defined PIPE_WAIT */ +# if !defined(PIPE_READMODE_BYTE) +# define PIPE_READMODE_BYTE 0 +# endif /* !defined PIPE_READMODE_BYTE */ +# if !defined(PIPE_READMODE_MESSAGE) +# define PIPE_READMODE_MESSAGE 0 +# endif /* !defined PIPE_READMODE_MESSAGE */ +# if !defined(PIPE_TYPE_BYTE) +# define PIPE_TYPE_BYTE 0 +# endif /* !defined PIPE_TYPE_BYTE */ +# if !defined(PIPE_TYPE_MESSAGE) +# define PIPE_TYPE_MESSAGE 0 +# endif /* !defined PIPE_TYPE_MESSAGE */ +#endif /* ACE_WIN32 */ + + +// Some useful abstractions for expressions involving +// ACE_Allocator.malloc (). The difference between ACE_NEW_MALLOC* +// with ACE_ALLOCATOR* is that they call constructors also. + +#include "ace/OS_Errno.h" /* Need errno and ENOMEM */ + +# define ACE_ALLOCATOR_RETURN(POINTER,ALLOCATOR,RET_VAL) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \ + } while (0) +# define ACE_ALLOCATOR(POINTER,ALLOCATOR) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return; } \ + } while (0) +# define ACE_ALLOCATOR_NORETURN(POINTER,ALLOCATOR) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; } \ + } while (0) + +# define ACE_NEW_MALLOC_RETURN(POINTER,ALLOCATOR,CONSTRUCTOR,RET_VAL) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return RET_VAL;} \ + else { (void) new (POINTER) CONSTRUCTOR; } \ + } while (0) +# define ACE_NEW_MALLOC(POINTER,ALLOCATOR,CONSTRUCTOR) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return;} \ + else { (void) new (POINTER) CONSTRUCTOR; } \ + } while (0) +# define ACE_NEW_MALLOC_NORETURN(POINTER,ALLOCATOR,CONSTRUCTOR) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM;} \ + else { (void) new (POINTER) CONSTRUCTOR; } \ + } while (0) + +/* ACE_Metrics */ +#if defined ACE_LACKS_ARRAY_PLACEMENT_NEW +# define ACE_NEW_MALLOC_ARRAY_RETURN(POINTER,ALLOCATOR,CONSTRUCTOR,COUNT,RET_VAL) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return RET_VAL;} \ + else { for (u_int i = 0; i < COUNT; ++i) \ + {(void) new (POINTER) CONSTRUCTOR; ++POINTER;} \ + POINTER -= COUNT;} \ + } while (0) +# define ACE_NEW_MALLOC_ARRAY(POINTER,ALLOCATOR,CONSTRUCTOR,COUNT) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return;} \ + else { for (u_int i = 0; i < COUNT; ++i) \ + {(void) new (POINTER) CONSTRUCTOR; ++POINTER;} \ + POINTER -= COUNT;} \ + } while (0) +#else /* ! defined ACE_LACKS_ARRAY_PLACEMENT_NEW */ +# define ACE_NEW_MALLOC_ARRAY_RETURN(POINTER,ALLOCATOR,CONSTRUCTOR,COUNT,RET_VAL) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return RET_VAL;} \ + else { (void) new (POINTER) CONSTRUCTOR [COUNT]; } \ + } while (0) +# define ACE_NEW_MALLOC_ARRAY(POINTER,ALLOCATOR,CONSTRUCTOR,COUNT) \ + do { POINTER = ALLOCATOR; \ + if (POINTER == 0) { errno = ENOMEM; return;} \ + else { (void) new (POINTER) CONSTRUCTOR [COUNT]; } \ + } while (0) +#endif /* defined ACE_LACKS_ARRAY_PLACEMENT_NEW */ + +// This is being placed here temporarily to help stabilize the builds, but will +// be moved out along with the above macros as part of the subsetting. dhinton +#if !defined (ACE_LACKS_NEW_H) +# if defined (ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB) +# include /**/ +# else +# include /**/ +# endif /* ACE_USES_STD_NAMESPACE_FOR_STDCPP_LIB */ +#endif /* ! ACE_LACKS_NEW_H */ + +# define ACE_NOOP(x) + +#if defined (ACE_WIN32) && defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) +# define ACE_SEH_TRY __try +# define ACE_SEH_EXCEPT(X) __except(X) +# define ACE_SEH_FINALLY __finally +#else /* !ACE_WIN32 */ +# define ACE_SEH_TRY if (1) +# define ACE_SEH_EXCEPT(X) while (0) +# define ACE_SEH_FINALLY if (1) +#endif /* ACE_WIN32 */ + +// Handle ACE_Message_Queue. +# define ACE_SYNCH_DECL typename _ACE_SYNCH +# define ACE_SYNCH_USE _ACE_SYNCH +# define ACE_SYNCH_MUTEX_T typename _ACE_SYNCH::MUTEX +# define ACE_SYNCH_CONDITION_T typename _ACE_SYNCH::CONDITION +# define ACE_SYNCH_SEMAPHORE_T typename _ACE_SYNCH::SEMAPHORE + +// Handle ACE_Malloc* +# define ACE_MEM_POOL_1 typename _ACE_MEM_POOL +# define ACE_MEM_POOL_2 _ACE_MEM_POOL +# define ACE_MEM_POOL _ACE_MEM_POOL +# define ACE_MEM_POOL_OPTIONS typename _ACE_MEM_POOL::OPTIONS + +// @deprecated These macros are not longer used in ACE_Svc_Handler. +// Handle ACE_Svc_Handler +# define ACE_PEER_STREAM_1 typename _ACE_PEER_STREAM +# define ACE_PEER_STREAM_2 _ACE_PEER_STREAM +# define ACE_PEER_STREAM _ACE_PEER_STREAM +# define ACE_PEER_STREAM_ADDR typename _ACE_PEER_STREAM::PEER_ADDR + +// @deprecated These macros are not longer used in ACE_Acceptor. +// Handle ACE_Acceptor +# define ACE_PEER_ACCEPTOR_1 typename _ACE_PEER_ACCEPTOR +# define ACE_PEER_ACCEPTOR_2 _ACE_PEER_ACCEPTOR +# define ACE_PEER_ACCEPTOR _ACE_PEER_ACCEPTOR +# define ACE_PEER_ACCEPTOR_ADDR typename _ACE_PEER_ACCEPTOR::PEER_ADDR + +// @deprecated These macros are not longer used in ACE_Connector. +// Handle ACE_Connector +# define ACE_PEER_CONNECTOR_1 typename _ACE_PEER_CONNECTOR +# define ACE_PEER_CONNECTOR_2 _ACE_PEER_CONNECTOR +# define ACE_PEER_CONNECTOR _ACE_PEER_CONNECTOR +# define ACE_PEER_CONNECTOR_ADDR typename ACE_PEER_CONNECTOR::PEER_ADDR +# define ACE_PEER_CONNECTOR_ADDR_ANY ACE_PEER_ADDR_TYPEDEF::sap_any + +// Handle ACE_SOCK_* +# define ACE_SOCK_ACCEPTOR ACE_SOCK_Acceptor +# define ACE_SOCK_CONNECTOR ACE_SOCK_Connector +# define ACE_SOCK_STREAM ACE_SOCK_Stream +# define ACE_SOCK_DGRAM ACE_SOCK_Dgram +# define ACE_SOCK_DGRAM_BCAST ACE_SOCK_Dgram_Bcast +# define ACE_SOCK_DGRAM_MCAST ACE_SOCK_Dgram_Mcast + +// Handle ACE_SOCK_SEQPACK_* +# define ACE_SOCK_SEQPACK_ACCEPTOR ACE_SOCK_SEQPACK_Acceptor +# define ACE_SOCK_SEQPACK_CONNECTOR ACE_SOCK_SEQPACK_Connector +# define ACE_SOCK_SEQPACK_ASSOCIATION ACE_SOCK_SEQPACK_Association + +// Handle ACE_MEM_* +# define ACE_MEM_ACCEPTOR ACE_MEM_Acceptor +# define ACE_MEM_CONNECTOR ACE_MEM_Connector +# define ACE_MEM_STREAM ACE_MEM_Stream + +// Handle ACE_LSOCK_* +# define ACE_LSOCK_ACCEPTOR ACE_LSOCK_Acceptor +# define ACE_LSOCK_CONNECTOR ACE_LSOCK_Connector +# define ACE_LSOCK_STREAM ACE_LSOCK_Stream + +// Handle ACE_TLI_* +# define ACE_TLI_ACCEPTOR ACE_TLI_Acceptor +# define ACE_TLI_CONNECTOR ACE_TLI_Connector +# define ACE_TLI_STREAM ACE_TLI_Stream + +// Handle ACE_SPIPE_* +# define ACE_SPIPE_ACCEPTOR ACE_SPIPE_Acceptor +# define ACE_SPIPE_CONNECTOR ACE_SPIPE_Connector +# define ACE_SPIPE_STREAM ACE_SPIPE_Stream + +// Handle ACE_UPIPE_* +# define ACE_UPIPE_ACCEPTOR ACE_UPIPE_Acceptor +# define ACE_UPIPE_CONNECTOR ACE_UPIPE_Connector +# define ACE_UPIPE_STREAM ACE_UPIPE_Stream + +// Handle ACE_*_Memory_Pool. +# define ACE_MMAP_MEMORY_POOL ACE_MMAP_Memory_Pool +# define ACE_LITE_MMAP_MEMORY_POOL ACE_Lite_MMAP_Memory_Pool +# define ACE_SBRK_MEMORY_POOL ACE_Sbrk_Memory_Pool +# define ACE_SHARED_MEMORY_POOL ACE_Shared_Memory_Pool +# define ACE_LOCAL_MEMORY_POOL ACE_Local_Memory_Pool +# define ACE_PAGEFILE_MEMORY_POOL ACE_Pagefile_Memory_Pool + +#include /**/ "ace/post.h" + +#endif /*ACE_GLOBAL_MACROS_H*/ diff --git a/dep/acelite/ace/Guard_T.cpp b/dep/acelite/ace/Guard_T.cpp new file mode 100644 index 000000000..dd4f9a2b9 --- /dev/null +++ b/dep/acelite/ace/Guard_T.cpp @@ -0,0 +1,60 @@ +#ifndef ACE_GUARD_T_CPP +#define ACE_GUARD_T_CPP + +// FUZZ: disable check_for_ACE_Guard +#include "ace/Guard_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Guard_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_DUMP) +# include "ace/Log_Category.h" +#endif /* ACE_HAS_DUMP */ + +// **************************************************************** + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// ACE_ALLOC_HOOK_DEFINE(ACE_Guard) + +template void +ACE_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Guard::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("mutex_ = %x\n"), this->lock_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("owner_ = %d\n"), this->owner_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// ACE_ALLOC_HOOK_DEFINE(ACE_Write_Guard) + +template void +ACE_Write_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Write_Guard::dump"); + ACE_Guard::dump (); +#endif /* ACE_HAS_DUMP */ +} + +// ACE_ALLOC_HOOK_DEFINE(ACE_Read_Guard) + +template void +ACE_Read_Guard::dump (void) const +{ +// ACE_TRACE ("ACE_Read_Guard::dump"); + ACE_Guard::dump (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_GUARD_T_CPP */ diff --git a/dep/acelite/ace/Guard_T.h b/dep/acelite/ace/Guard_T.h new file mode 100644 index 000000000..ec415b794 --- /dev/null +++ b/dep/acelite/ace/Guard_T.h @@ -0,0 +1,405 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Guard_T.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_GUARD_T_H +#define ACE_GUARD_T_H +#include /**/ "ace/pre.h" + +#include "ace/Lock.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" +#include "ace/OS_NS_Thread.h" + +// FUZZ: disable check_for_ACE_Guard + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Guard + * + * @brief This data structure is meant to be used within a method or + * function... It performs automatic acquisition and release of + * a parameterized synchronization object ACE_LOCK. + * + * The ACE_LOCK class given as an actual parameter must provide, at + * the very least the acquire(), tryacquire(), release(), and + * remove() methods. + * + * @warning A successfully constructed ACE_Guard does NOT mean that the + * lock was acquired! It is the caller's responsibility, after + * constructing an ACE_Guard, to check whether the lock was successfully + * acquired. Code like this is dangerous: + * { + * ACE_Guard g(lock); + * ... perform critical operation requiring lock to be held ... + * } + * Instead, one must do something like this: + * { + * ACE_Guard g(lock); + * if (! g.locked()) + * { + * ... handle error ... + * } + * else + * { + * ... perform critical operation requiring lock to be held ... + * } + * } + * The ACE_GUARD_RETURN() and ACE_GUARD_REACTION() macros are designed to + * to help with this. + */ +template +class ACE_Guard +{ +public: + + // = Initialization and termination methods. + ACE_Guard (ACE_LOCK &l); + + /// Implicitly and automatically acquire (or try to acquire) the + /// lock. If @a block is non-0 then acquire() the ACE_LOCK, else + /// tryacquire() it. + ACE_Guard (ACE_LOCK &l, bool block); + + /// Initialize the guard without implicitly acquiring the lock. The + /// @a become_owner parameter indicates whether the guard should release + /// the lock implicitly on destruction. The @a block parameter is + /// ignored and is used here to disambiguate with the preceding + /// constructor. + ACE_Guard (ACE_LOCK &l, bool block, int become_owner); + + /// Implicitly release the lock. + ~ACE_Guard (void); + + // = Lock accessors. + + /// Explicitly acquire the lock. + int acquire (void); + + /// Conditionally acquire the lock (i.e., won't block). + int tryacquire (void); + + /// Explicitly release the lock, but only if it is held! + int release (void); + + /// Relinquish ownership of the lock so that it is not released + /// implicitly in the destructor. + void disown (void); + + // = Utility methods. + /// true if locked, false if couldn't acquire the lock + /// (errno will contain the reason for this). + bool locked (void) const; + + /// Explicitly remove the lock. + int remove (void); + + /// Dump the state of an object. + void dump (void) const; + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. + +protected: + + /// Helper, meant for subclass only. + ACE_Guard (ACE_LOCK *lock): lock_ (lock), owner_ (0) {} + + /// Pointer to the ACE_LOCK we're guarding. + ACE_LOCK *lock_; + + /// Keeps track of whether we acquired the lock or failed. + int owner_; + +private: + // = Prevent assignment and initialization. + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Guard &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Guard (const ACE_Guard &)) +}; + +/** + * @class ACE_Write_Guard + * + * @brief This class is similar to class ACE_Guard, though it + * acquires/releases a write lock automatically (naturally, the + * it is instantiated with must support the appropriate + * API). + * + * @warning See important "WARNING" in comments at top of ACE_Guard. + */ +template +class ACE_Write_Guard : public ACE_Guard +{ +public: + // = Initialization method. + + /// Implicitly and automatically acquire a write lock. + ACE_Write_Guard (ACE_LOCK &m); + + /// Implicitly and automatically acquire (or try to acquire) a write + /// lock. + ACE_Write_Guard (ACE_LOCK &m, bool block); + + // = Lock accessors. + + /// Explicitly acquire the write lock. + int acquire_write (void); + + /// Explicitly acquire the write lock. + int acquire (void); + + /// Conditionally acquire the write lock (i.e., won't block). + int tryacquire_write (void); + + /// Conditionally acquire the write lock (i.e., won't block). + int tryacquire (void); + + // = Utility methods. + + /// Dump the state of an object. + void dump (void) const; + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. +}; + +/** + * @class ACE_Read_Guard + * + * @brief This class is similar to class ACE_Guard, though it + * acquires/releases a read lock automatically (naturally, the + * it is instantiated with must support the appropriate + * API). + * + * @warning See important "WARNING" in comments at top of ACE_Guard. + */ +template +class ACE_Read_Guard : public ACE_Guard +{ +public: + // = Initialization methods. + + /// Implicitly and automatically acquire a read lock. + ACE_Read_Guard (ACE_LOCK& m); + + /// Implicitly and automatically acquire (or try to acquire) a read + /// lock. + ACE_Read_Guard (ACE_LOCK &m, bool block); + + // = Lock accessors. + + /// Explicitly acquire the read lock. + int acquire_read (void); + + /// Explicitly acquire the read lock. + int acquire (void); + + /// Conditionally acquire the read lock (i.e., won't block). + int tryacquire_read (void); + + /// Conditionally acquire the read lock (i.e., won't block). + int tryacquire (void); + + // = Utility methods. + + /// Dump the state of an object. + void dump (void) const; + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. +}; + +#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) + +#define ACE_TSS_Guard ACE_Guard +#define ACE_TSS_Write_GUARD ACE_Write_Guard +#define ACE_TSS_Read_GUARD ACE_Read_Guard + +#else + /* ACE platform supports some form of threading and + thread-specific storage. */ + +/** + * @class ACE_TSS_Guard + * + * @brief This data structure is meant to be used within a method or + * function... It performs automatic aquisition and release of + * a synchronization object. Moreover, it ensures that the lock + * is released even if a thread exits via ! + */ +template +class ACE_TSS_Guard +{ +public: + // = Initialization and termination methods. + + /// Implicitly and automatically acquire the thread-specific lock. + ACE_TSS_Guard (ACE_LOCK &lock, bool block = true); + + /// Implicitly release the thread-specific lock. + ~ACE_TSS_Guard (void); + + // = Lock accessors. + + /// Explicitly acquire the thread-specific lock. + int acquire (void); + + /// Conditionally acquire the thread-specific lock (i.e., won't + /// block). + int tryacquire (void); + + /// Explicitly release the thread-specific lock. + int release (void); + + // = Utility methods. + /// Explicitly release the thread-specific lock. + int remove (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Helper, meant for subclass only. + ACE_TSS_Guard (void); + + /// Initialize the key. + void init_key (void); + + /// Called when thread exits to clean up the lock. + static void cleanup (void *ptr); + + /// Thread-specific key... + ACE_thread_key_t key_; + +private: + // FUZZ: disable check_for_ACE_Guard + typedef ACE_Guard Guard_Type; + // FUZZ: enable check_for_ACE_Guard + + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS_Guard &)) + ACE_UNIMPLEMENTED_FUNC (ACE_TSS_Guard (const ACE_TSS_Guard &)) +}; + +/** + * @class ACE_TSS_Write_Guard + * + * @brief This class is similar to class ACE_TSS_Guard, though it + * acquires/releases a write-lock automatically (naturally, the + * ACE_LOCK it is instantiated with must support the appropriate + * API). + */ +template +class ACE_TSS_Write_Guard : public ACE_TSS_Guard +{ +public: + // = Initialization method. + + /// Implicitly and automatically acquire the thread-specific write lock. + ACE_TSS_Write_Guard (ACE_LOCK &lock, bool block = true); + + // = Lock accessors. + + /// Explicitly acquire the thread-specific write lock. + int acquire_write (void); + + /// Explicitly acquire the thread-specific write lock. + int acquire (void); + + /// Conditionally acquire the thread-specific write lock (i.e., won't block). + int tryacquire_write (void); + + /// Conditionally acquire the thread-specific write lock (i.e., won't block). + int tryacquire (void); + + // = Utility methods. + + /// Dump the state of an object. + void dump (void) const; + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. +private: + // FUZZ: disable check_for_ACE_Guard + typedef ACE_Guard Guard_Type; + typedef ACE_Write_Guard Write_Guard_Type; + // FUZZ: enable check_for_ACE_Guard +}; + +/** + * @class ACE_TSS_Read_Guard + * + * @brief This class is similar to class , though it + * acquires/releases a read lock automatically (naturally, the + * it is instantiated with must support the + * appropriate API). + */ +template +class ACE_TSS_Read_Guard : public ACE_TSS_Guard +{ +public: + // = Initialization method. + /// Implicitly and automatically acquire the thread-specific read lock. + ACE_TSS_Read_Guard (ACE_LOCK &lock, bool block = true); + + // = Lock accessors. + /// Explicitly acquire the thread-specific read lock. + int acquire_read (void); + + /// Explicitly acquire the thread-specific read lock. + int acquire (void); + + /// Conditionally acquire the thread-specific read lock (i.e., won't + /// block). + int tryacquire_read (void); + + /// Conditionally acquire the thread-specific read lock (i.e., won't + /// block). + int tryacquire (void); + + // = Utility methods. + /// Dump the state of an object. + void dump (void) const; + + // ACE_ALLOC_HOOK_DECLARE; + // Declare the dynamic allocation hooks. +private: + // FUZZ: disable check_for_ACE_Guard + typedef ACE_Guard Guard_Type; + typedef ACE_Read_Guard Read_Guard_Type; + // FUZZ: enable check_for_ACE_Guard +}; + +#endif /* !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Guard_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Guard_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Guard_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_GUARD_T_H */ diff --git a/dep/acelite/ace/Guard_T.inl b/dep/acelite/ace/Guard_T.inl new file mode 100644 index 000000000..02d6989cd --- /dev/null +++ b/dep/acelite/ace/Guard_T.inl @@ -0,0 +1,169 @@ +// -*- C++ -*- +// FUZZ: disable check_for_ACE_Guard + +#include "ace/RW_Thread_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE int +ACE_Guard::acquire (void) +{ + return this->owner_ = this->lock_->acquire (); +} + +template ACE_INLINE int +ACE_Guard::tryacquire (void) +{ + return this->owner_ = this->lock_->tryacquire (); +} + +template ACE_INLINE int +ACE_Guard::release (void) +{ + if (this->owner_ == -1) + return -1; + else + { + this->owner_ = -1; + return this->lock_->release (); + } +} + +template ACE_INLINE +ACE_Guard::ACE_Guard (ACE_LOCK &l) + : lock_ (&l), + owner_ (0) +{ + this->acquire (); +} + +template ACE_INLINE +ACE_Guard::ACE_Guard (ACE_LOCK &l, bool block) + : lock_ (&l), + owner_ (0) +{ + if (block) + this->acquire (); + else + this->tryacquire (); +} + +template ACE_INLINE +ACE_Guard::ACE_Guard (ACE_LOCK &l, bool /* block */, int become_owner) + : lock_ (&l), + owner_ (become_owner == 0 ? -1 : 0) +{ +} + +// Implicitly and automatically acquire (or try to acquire) the +// lock. + +template ACE_INLINE +ACE_Guard::~ACE_Guard (void) +{ + this->release (); +} + +template ACE_INLINE bool +ACE_Guard::locked (void) const +{ + return this->owner_ != -1; +} + +template ACE_INLINE int +ACE_Guard::remove (void) +{ + return this->lock_->remove (); +} + +template ACE_INLINE void +ACE_Guard::disown (void) +{ + this->owner_ = -1; +} + +template ACE_INLINE +ACE_Write_Guard::ACE_Write_Guard (ACE_LOCK &m) + : ACE_Guard (&m) +{ + this->acquire_write (); +} + +template ACE_INLINE int +ACE_Write_Guard::acquire_write (void) +{ + return this->owner_ = this->lock_->acquire_write (); +} + +template ACE_INLINE int +ACE_Write_Guard::acquire (void) +{ + return this->owner_ = this->lock_->acquire_write (); +} + +template ACE_INLINE int +ACE_Write_Guard::tryacquire_write (void) +{ + return this->owner_ = this->lock_->tryacquire_write (); +} + +template ACE_INLINE int +ACE_Write_Guard::tryacquire (void) +{ + return this->owner_ = this->lock_->tryacquire_write (); +} + +template ACE_INLINE +ACE_Write_Guard::ACE_Write_Guard (ACE_LOCK &m, + bool block) + : ACE_Guard (&m) +{ + if (block) + this->acquire_write (); + else + this->tryacquire_write (); +} + +template ACE_INLINE int +ACE_Read_Guard::acquire_read (void) +{ + return this->owner_ = this->lock_->acquire_read (); +} + +template ACE_INLINE int +ACE_Read_Guard::acquire (void) +{ + return this->owner_ = this->lock_->acquire_read (); +} + +template ACE_INLINE int +ACE_Read_Guard::tryacquire_read (void) +{ + return this->owner_ = this->lock_->tryacquire_read (); +} + +template ACE_INLINE int +ACE_Read_Guard::tryacquire (void) +{ + return this->owner_ = this->lock_->tryacquire_read (); +} + +template ACE_INLINE +ACE_Read_Guard::ACE_Read_Guard (ACE_LOCK &m) + : ACE_Guard (&m) +{ + this->acquire_read (); +} + +template ACE_INLINE +ACE_Read_Guard::ACE_Read_Guard (ACE_LOCK &m, + bool block) + : ACE_Guard (&m) +{ + if (block) + this->acquire_read (); + else + this->tryacquire_read (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Handle_Gobbler.h b/dep/acelite/ace/Handle_Gobbler.h new file mode 100644 index 000000000..2d52e1f87 --- /dev/null +++ b/dep/acelite/ace/Handle_Gobbler.h @@ -0,0 +1,66 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Handle_Gobbler.h + * + * @author Kirthika Parameswaran + * @author Irfan Pyarali + */ +//============================================================================= + + +#ifndef ACE_HANDLE_GOBBLER_H +#define ACE_HANDLE_GOBBLER_H +#include /**/ "ace/pre.h" + +#include "ace/Handle_Set.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Handle_Gobbler + * + * @brief This class gobbles up handles. + * + * This is useful when we need to control the number of handles + * available for a process. This class is mostly used for + * testing purposes. + */ +class ACE_Handle_Gobbler +{ +public: + + /// Destructor. Cleans up any remaining handles. + inline ~ACE_Handle_Gobbler (void); + + /** + * Handles are opened continously until the process runs out of + * them, and then handles are closed + * (freed) thereby making them usable in the future. + */ + inline int consume_handles (size_t n_handles_to_keep_available); + + /// Free up @a n_handles. + inline int free_handles (size_t n_handles); + + /// All remaining handles are closed. + inline void close_remaining_handles (void); + +private: + typedef ACE_Handle_Set HANDLE_SET; + + /// The container which holds the open descriptors. + HANDLE_SET handle_set_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include "ace/Handle_Gobbler.inl" + +#include /**/ "ace/post.h" +#endif /* ACE_HANDLE_GOBBLER_H */ diff --git a/dep/acelite/ace/Handle_Gobbler.inl b/dep/acelite/ace/Handle_Gobbler.inl new file mode 100644 index 000000000..8bacb005d --- /dev/null +++ b/dep/acelite/ace/Handle_Gobbler.inl @@ -0,0 +1,76 @@ +// -*- C++ -*- +// Since this is only included in Handle_Gobbler.h, these should be +// inline, not ACE_INLINE. +// FUZZ: disable check_for_inline + +#include "ace/ACE.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_fcntl.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +inline void +ACE_Handle_Gobbler::close_remaining_handles (void) +{ + ACE_Handle_Set_Iterator iter (this->handle_set_); + for (ACE_HANDLE h = iter (); h != ACE_INVALID_HANDLE; h = iter ()) + ACE_OS::close (h); +} + +inline +ACE_Handle_Gobbler::~ACE_Handle_Gobbler (void) +{ + this->close_remaining_handles (); +} + +inline int +ACE_Handle_Gobbler::free_handles (size_t n_handles) +{ + ACE_Handle_Set_Iterator iter (this->handle_set_); + for (ACE_HANDLE h = iter (); + h != ACE_INVALID_HANDLE && n_handles > 0; + --n_handles, h = iter ()) + ACE_OS::close (h); + + return 0; +} + +inline int +ACE_Handle_Gobbler::consume_handles (size_t n_handles_to_keep_available) +{ + int result = 0; + +#if defined(ACE_WIN32) + // On Win32, this style of gobbling doesn't seem to work. + ACE_UNUSED_ARG(n_handles_to_keep_available); + +#else + + while (1) + { + ACE_HANDLE handle = ACE_OS::open (ACE_DEV_NULL, O_WRONLY); + + if (handle == ACE_INVALID_HANDLE) + { + if (ACE::out_of_handles (errno)) + { + result = this->free_handles (n_handles_to_keep_available); + break; + } + else + { + result = -1; + break; + } + } + if (handle >= static_cast(FD_SETSIZE)) + break; + this->handle_set_.set_bit (handle); + } + +#endif /* ACE_WIN32 */ + + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Handle_Ops.cpp b/dep/acelite/ace/Handle_Ops.cpp new file mode 100644 index 000000000..6d83f91b8 --- /dev/null +++ b/dep/acelite/ace/Handle_Ops.cpp @@ -0,0 +1,42 @@ +#include "ace/Handle_Ops.h" + +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_fcntl.h" +#include "ace/Time_Value.h" + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_HANDLE +ACE::handle_timed_open (ACE_Time_Value *timeout, + const ACE_TCHAR *name, + int flags, + int perms, + LPSECURITY_ATTRIBUTES sa) +{ + ACE_TRACE ("ACE::handle_timed_open"); + + if (timeout != 0) + { +#if !defined (ACE_WIN32) + // On Win32, ACE_NONBLOCK gets recognized as O_WRONLY so we + // don't use it there + flags |= ACE_NONBLOCK; +#endif /* ACE_WIN32 */ + + // Open the named pipe or file using non-blocking mode... + ACE_HANDLE const handle = ACE_OS::open (name, flags, perms, sa); + + if (handle == ACE_INVALID_HANDLE + && (errno == EWOULDBLOCK + && (timeout->sec () > 0 || timeout->usec () > 0))) + // This expression checks if we were polling. + errno = ETIMEDOUT; + + return handle; + } + else + return ACE_OS::open (name, flags, perms, sa); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Handle_Ops.h b/dep/acelite/ace/Handle_Ops.h new file mode 100644 index 000000000..bc95fd30c --- /dev/null +++ b/dep/acelite/ace/Handle_Ops.h @@ -0,0 +1,48 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Handle_Ops.h + * + * Handle operations. + */ +//============================================================================= + +#ifndef ACE_HANDLE_OPS_H +#define ACE_HANDLE_OPS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +// = Operations on HANDLEs. +namespace ACE +{ + /** + * Wait up to @a timeout amount of time to actively open a device. + * This method doesn't perform the @c connect, it just does the + * timed wait. + */ + extern ACE_Export ACE_HANDLE handle_timed_open ( + ACE_Time_Value *timeout, + const ACE_TCHAR *name, + int flags, + int perms, + LPSECURITY_ATTRIBUTES sa = 0); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_HANDLE_OPS_H */ diff --git a/dep/acelite/ace/Handle_Set.cpp b/dep/acelite/ace/Handle_Set.cpp new file mode 100644 index 000000000..0643de5dc --- /dev/null +++ b/dep/acelite/ace/Handle_Set.cpp @@ -0,0 +1,523 @@ +// Handle_Set.cpp +#include "ace/Handle_Set.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Handle_Set.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Handle_Set) + + // ACE_MSB_MASK is only used here. + // This needs to go here to avoid overflow problems on some compilers. +#if defined (ACE_WIN32) + // Does ACE_WIN32 have an fd_mask? +# define ACE_MSB_MASK (~(1 << (NFDBITS - 1))) +#else /* ! ACE_WIN32 */ +# define ACE_MSB_MASK (~((fd_mask) 1 << (NFDBITS - 1))) +#endif /* ! ACE_WIN32 */ + +#if defined (ACE_LINUX) && __GLIBC__ > 1 && __GLIBC_MINOR__ >= 1 && !defined (_XOPEN_SOURCE) + // XPG4.2 requires the fds_bits member name, so it is not enabled by + // default on Linux/glibc-2.1.x systems. Instead use "__fds_bits." + // Ugly, but "what are you going to do?" 8-) +#define fds_bits __fds_bits +#elif defined ACE_FDS_BITS +#define fds_bits ACE_FDS_BITS +#endif /* ACE_LINUX && __GLIBC__ > 1 && __GLIBC_MINOR__ >= 1 && !_XOPEN_SOURCE */ + +void +ACE_Handle_Set::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Handle_Set::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nsize_ = %d"), this->size_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmax_handle_ = %d"), this->max_handle_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n[ "))); + +#if defined (ACE_WIN32) + for (size_t i = 0; i < (size_t) this->mask_.fd_count + 1; i++) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" %x "), this->mask_.fd_array[i])); +#else /* !ACE_WIN32 */ + for (ACE_HANDLE i = 0; i < this->max_handle_ + 1; i++) + if (this->is_set (i)) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" %d "), i)); +#endif /* ACE_WIN32 */ + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT (" ]\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// Table that maps bytes to counts of the enabled bits in each value +// from 0 to 255, +// +// nbits_[0] == 0 +// +// because there are no bits enabled for the value 0. +// +// nbits_[5] == 2 +// +// because there are 2 bits enabled in the value 5, i.e., it's +// 101 in binary. + +const char ACE_Handle_Set::nbits_[256] = +{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}; + +// Constructor, initializes the bitmask to all 0s. + +ACE_Handle_Set::ACE_Handle_Set (void) +{ + ACE_TRACE ("ACE_Handle_Set::ACE_Handle_Set"); + this->reset (); +} + +ACE_Handle_Set::ACE_Handle_Set (const fd_set &fd_mask) +{ + ACE_TRACE ("ACE_Handle_Set::ACE_Handle_Set"); + this->reset (); + ACE_OS::memcpy ((void *) &this->mask_, + (void *) &fd_mask, + sizeof this->mask_); +#if !defined (ACE_WIN32) + this->sync (ACE_Handle_Set::MAXSIZE); +#if defined (ACE_HAS_BIG_FD_SET) + this->min_handle_ = 0; +#endif /* ACE_HAS_BIG_FD_SET */ +#endif /* !ACE_WIN32 */ +} + +// Counts the number of bits enabled in N. Uses a table lookup to +// speed up the count. + +int +ACE_Handle_Set::count_bits (u_long n) +{ + + ACE_TRACE ("ACE_Handle_Set::count_bits"); +#if defined (ACE_HAS_HANDLE_SET_OPTIMIZED_FOR_SELECT) + int rval = 0; + + // Count the number of enabled bits in . This algorithm is very + // fast, i.e., O(enabled bits in n). + + for (u_long m = n; + m != 0; + m &= m - 1) + rval++; + + return rval; +#else + return (ACE_Handle_Set::nbits_[n & 0xff] + + ACE_Handle_Set::nbits_[(n >> 8) & 0xff] + + ACE_Handle_Set::nbits_[(n >> 16) & 0xff] + + ACE_Handle_Set::nbits_[(n >> 24) & 0xff]); +#endif /* ACE_HAS_HANDLE_SET_OPTIMIZED_FOR_SELECT */ +} + +#if defined (ACE_HAS_BIG_FD_SET) +// Find the bit position counting from right to left worst case +// (1<<31) is 8. + +int +ACE_Handle_Set::bitpos (u_long bit) +{ + int l = 0; + u_long n = bit - 1; + + // This is a fast count method when have the most significative bit. + + while (n >> 8) + { + n >>= 8; + l += 8; + } + + // Is greater than 15? + if (n & 16) + { + n >>= 4; + l += 4; + } + + // Count number remaining bits. + while (n != 0) + { + n &= n - 1; + l++; + } + return l; +} +#endif /* ACE_HAS_BIG_FD_SET */ + +// Synchronize the underlying FD_SET with the MAX_FD and the SIZE. + +#if defined (ACE_USE_SHIFT_FOR_EFFICIENCY) +// These don't work because shifting right 3 bits is not the same as +// dividing by 3, e.g., dividing by 8 requires shifting right 3 bits. +// In order to do the shift, we need to calculate the number of bits +// at some point. +#define ACE_DIV_BY_WORDSIZE(x) ((x) >> ((int) ACE_Handle_Set::WORDSIZE)) +#define ACE_MULT_BY_WORDSIZE(x) ((x) << ((int) ACE_Handle_Set::WORDSIZE)) +#else +#define ACE_DIV_BY_WORDSIZE(x) ((x) / ((int) ACE_Handle_Set::WORDSIZE)) +#define ACE_MULT_BY_WORDSIZE(x) ((x) * ((int) ACE_Handle_Set::WORDSIZE)) +#endif /* ACE_USE_SHIFT_FOR_EFFICIENCY */ + +void +ACE_Handle_Set::sync (ACE_HANDLE max) +{ + ACE_TRACE ("ACE_Handle_Set::sync"); +#if !defined (ACE_WIN32) + fd_mask *maskp = (fd_mask *)(this->mask_.fds_bits); + this->size_ = 0; + + for (int i = ACE_DIV_BY_WORDSIZE (max - 1); + i >= 0; + i--) + this->size_ += ACE_Handle_Set::count_bits (maskp[i]); + + this->set_max (max); +#else + ACE_UNUSED_ARG (max); +#endif /* !ACE_WIN32 */ +} + +// Resets the MAX_FD after a clear of the original MAX_FD. + +void +ACE_Handle_Set::set_max (ACE_HANDLE current_max) +{ + ACE_TRACE ("ACE_Handle_Set::set_max"); +#if !defined(ACE_WIN32) + fd_mask * maskp = (fd_mask *)(this->mask_.fds_bits); + + if (this->size_ == 0) + this->max_handle_ = ACE_INVALID_HANDLE; + else + { + int i; + + for (i = ACE_DIV_BY_WORDSIZE (current_max - 1); + maskp[i] == 0; + i--) + continue; + this->max_handle_ = ACE_MULT_BY_WORDSIZE (i); + for (fd_mask val = maskp[i]; + (val & ~1) != 0; // This obscure code is needed since "bit 0" is in location 1... + val = (val >> 1) & ACE_MSB_MASK) + ++this->max_handle_; + } + + // Do some sanity checking... + if (this->max_handle_ >= ACE_Handle_Set::MAXSIZE) + this->max_handle_ = ACE_Handle_Set::MAXSIZE - 1; +#else + ACE_UNUSED_ARG (current_max); +#endif /* !ACE_WIN32 */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Handle_Set_Iterator) + +void +ACE_Handle_Set_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Handle_Set_Iterator::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); +#if defined(ACE_WIN32) || !defined(ACE_HAS_BIG_FD_SET) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nhandle_index_ = %d"), this->handle_index_)); +#elif defined(ACE_HAS_BIG_FD_SET) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nword_max_ = %d"), this->word_max_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nword_val_ = %d"), this->word_val_)); +#endif + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nword_num_ = %d"), this->word_num_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_HANDLE +ACE_Handle_Set_Iterator::operator () (void) +{ + ACE_TRACE ("ACE_Handle_Set_Iterator::operator"); +#if defined (ACE_WIN32) + if (this->handle_index_ < this->handles_.mask_.fd_count) + // Return the handle and advance the iterator. + return (ACE_HANDLE) this->handles_.mask_.fd_array[this->handle_index_++]; + else + return ACE_INVALID_HANDLE; + +#elif !defined (ACE_HAS_BIG_FD_SET) /* !ACE_WIN32 */ + // No sense searching further than the max_handle_ + 1; + ACE_HANDLE maxhandlep1 = this->handles_.max_handle_ + 1; + + // HP-UX 11 plays some games with the fd_mask type - fd_mask is + // defined as an int_32t, but the fds_bits is an array of longs. + // This makes plainly indexing through the array by hand tricky, + // since the FD_* macros treat the array as int32_t. So the bits + // are in the right place for int32_t, even though the array is + // long. This, they say, is to preserve the same in-memory layout + // for 32-bit and 64-bit processes. So, we play the same game as + // the FD_* macros to get the bits right. On all other systems, + // this amounts to practically a NOP, since this is what would have + // been done anyway, without all this type jazz. + fd_mask * maskp = (fd_mask *)(this->handles_.mask_.fds_bits); + + if (this->handle_index_ >= maxhandlep1) + // We've seen all the handles we're interested in seeing for this + // iterator. + return ACE_INVALID_HANDLE; + else + { + ACE_HANDLE result = this->handle_index_; + + // Increment the iterator and advance to the next bit in this + // word. + this->handle_index_++; + this->word_val_ = (this->word_val_ >> 1) & ACE_MSB_MASK; + + // If we've examined all the bits in this word, we'll go onto + // the next word. + + if (this->word_val_ == 0) + { + // Start the handle_index_ at the beginning of the next word + // and then loop until we've found the first non-zero bit or + // we run past the of the bitset. + + for (this->handle_index_ = ACE_MULT_BY_WORDSIZE(++this->word_num_); + this->handle_index_ < maxhandlep1 + && maskp[this->word_num_] == 0; + this->word_num_++) + this->handle_index_ += ACE_Handle_Set::WORDSIZE; + + // If the bit index becomes >= the maxhandlep1 that means + // there weren't any more bits set that we want to consider. + // Therefore, we'll just store the maxhandlep1, which will + // cause to return + // immediately next time it's called. + if (this->handle_index_ >= maxhandlep1) + { + this->handle_index_ = maxhandlep1; + return result; + } + else + // Load the bits of the next word. + this->word_val_ = maskp[this->word_num_]; + } + + // Loop until we get to have its least significant + // bit enabled, keeping track of which this + // represents (this information is used by subsequent calls to + // ). + for (; + ACE_BIT_DISABLED (this->word_val_, 1); + this->handle_index_++) + this->word_val_ = (this->word_val_ >> 1) & ACE_MSB_MASK; + + return result; + } +#else /* !ACE_HAS_BIG_FD_SET */ + // Find the first word in fds_bits with bit on + u_long lsb = this->word_val_; + + if (lsb == 0) + { + do + { + // We have exceeded the word count in Handle_Set? + if (++this->word_num_ >= this->word_max_) + return ACE_INVALID_HANDLE; + + lsb = this->handles_.mask_.fds_bits[this->word_num_]; + } + while (lsb == 0); + + // Set index to word boundary. + this->handle_index_ = ACE_MULT_BY_WORDSIZE (this->word_num_); + + // Put new word_val. + this->word_val_ = lsb; + + // Find the least significative bit. + lsb &= ~(lsb - 1); + + // Remove least significative bit. + this->word_val_ ^= lsb; + + // Save to calculate bit distance. + this->oldlsb_ = lsb; + + // Move index to least significative bit. + while (lsb >>= 1) + this->handle_index_++; + } + else + { + // Find the least significative bit. + lsb &= ~(lsb - 1); + + // Remove least significative bit. + this->word_val_ ^= lsb; + + u_long n = lsb - this->oldlsb_; + + // Move index to bit distance between new lsb and old lsb. + do + { + this->handle_index_++; + n &= n >> 1; + } + while (n != 0); + + this->oldlsb_ = lsb; + } + + return this->handle_index_; +#endif /* ACE_WIN32 */ +} + +ACE_Handle_Set_Iterator::ACE_Handle_Set_Iterator (const ACE_Handle_Set &hs) + : handles_ (hs), +#if !defined (ACE_HAS_BIG_FD_SET) || defined (ACE_WIN32) + handle_index_ (0), + word_num_ (-1) +#elif defined (ACE_HAS_BIG_FD_SET) + handle_index_ (0), + oldlsb_ (0), + word_max_ (hs.max_handle_ == ACE_INVALID_HANDLE + ? 0 + : ((ACE_DIV_BY_WORDSIZE (hs.max_handle_)) + 1)) +#endif /* ACE_HAS_BIG_FD_SET */ +{ + ACE_TRACE ("ACE_Handle_Set_Iterator::ACE_Handle_Set_Iterator"); +#if !defined (ACE_WIN32) && !defined (ACE_HAS_BIG_FD_SET) + // No sense searching further than the max_handle_ + 1; + ACE_HANDLE maxhandlep1 = + this->handles_.max_handle_ + 1; + + fd_mask *maskp = + (fd_mask *)(this->handles_.mask_.fds_bits); + + // Loop until we've found the first non-zero bit or we run past the + // of the bitset. + while (this->handle_index_ < maxhandlep1 + && maskp[++this->word_num_] == 0) + this->handle_index_ += ACE_Handle_Set::WORDSIZE; + + // If the bit index becomes >= the maxhandlep1 that means there + // weren't any bits set. Therefore, we'll just store the + // maxhandlep1, which will cause to return + // immediately. + if (this->handle_index_ >= maxhandlep1) + this->handle_index_ = maxhandlep1; + else + // Loop until we get to have its least significant bit + // enabled, keeping track of which this represents + // (this information is used by ). + for (this->word_val_ = maskp[this->word_num_]; + ACE_BIT_DISABLED (this->word_val_, 1) + && this->handle_index_ < maxhandlep1; + this->handle_index_++) + this->word_val_ = (this->word_val_ >> 1) & ACE_MSB_MASK; +#elif !defined (ACE_WIN32) && defined (ACE_HAS_BIG_FD_SET) + if (this->word_max_==0) + { + this->word_num_ = -1; + this->word_val_ = 0; + } + else + { + this->word_num_ = + ACE_DIV_BY_WORDSIZE (this->handles_.min_handle_) - 1; + this->word_val_ = 0; + } +#endif /* !ACE_WIN32 && !ACE_HAS_BIG_FD_SET */ +} + +void +ACE_Handle_Set_Iterator::reset_state (void) +{ + ACE_TRACE ("ACE_Handle_Set_Iterator::reset_state"); + +#if !defined (ACE_HAS_BIG_FD_SET) || defined (ACE_WIN32) + this->handle_index_ = 0; + this->word_num_ = -1; +#elif defined (ACE_HAS_BIG_FD_SET) + this->oldlsb_ = 0; + this->word_max_ = + this->handles_.max_handle_ == ACE_INVALID_HANDLE ? 0 + : ((ACE_DIV_BY_WORDSIZE (this->handles_.max_handle_)) + 1); +#endif /* ACE_HAS_BIG_FD_SET */ + +#if !defined (ACE_WIN32) && !defined (ACE_HAS_BIG_FD_SET) + // No sense searching further than the max_handle_ + 1; + ACE_HANDLE maxhandlep1 = + this->handles_.max_handle_ + 1; + + fd_mask *maskp = + (fd_mask *)(this->handles_.mask_.fds_bits); + + // Loop until we've found the first non-zero bit or we run past the + // of the bitset. + while (this->handle_index_ < maxhandlep1 + && maskp[++this->word_num_] == 0) + this->handle_index_ += ACE_Handle_Set::WORDSIZE; + + // If the bit index becomes >= the maxhandlep1 that means there + // weren't any bits set. Therefore, we'll just store the + // maxhandlep1, which will cause to return + // immediately. + if (this->handle_index_ >= maxhandlep1) + this->handle_index_ = maxhandlep1; + else + // Loop until we get to have its least significant bit + // enabled, keeping track of which this represents + // (this information is used by ). + for (this->word_val_ = maskp[this->word_num_]; + ACE_BIT_DISABLED (this->word_val_, 1) + && this->handle_index_ < maxhandlep1; + this->handle_index_++) + this->word_val_ = (this->word_val_ >> 1) & ACE_MSB_MASK; +#elif !defined (ACE_WIN32) && defined (ACE_HAS_BIG_FD_SET) + if (this->word_max_==0) + { + this->word_num_ = -1; + this->word_val_ = 0; + } + else + { + this->word_num_ = + ACE_DIV_BY_WORDSIZE (this->handles_.min_handle_) - 1; + this->word_val_ = 0; + } +#endif /* !ACE_WIN32 && !ACE_HAS_BIG_FD_SET */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Handle_Set.h b/dep/acelite/ace/Handle_Set.h new file mode 100644 index 000000000..21b239e42 --- /dev/null +++ b/dep/acelite/ace/Handle_Set.h @@ -0,0 +1,237 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Handle_Set.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_HANDLE_SET_H +#define ACE_HANDLE_SET_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/sys/os_select.h" +#include "ace/os_include/os_limits.h" + +// Default size of the ACE Reactor. +#if defined (FD_SETSIZE) + int const ACE_FD_SETSIZE = FD_SETSIZE; +#else /* !FD_SETSIZE */ +# define ACE_FD_SETSIZE FD_SETSIZE +#endif /* ACE_FD_SETSIZE */ + +#if defined(FD_SETSIZE) && defined(__FD_SETSIZE) && (FD_SETSIZE > __FD_SETSIZE) +#error FD_SETSIZE definition is too large, please correct! +#endif + +#if !defined (ACE_DEFAULT_SELECT_REACTOR_SIZE) +# define ACE_DEFAULT_SELECT_REACTOR_SIZE ACE_FD_SETSIZE +#endif /* ACE_DEFAULT_SELECT_REACTOR_SIZE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Handle_Set + * + * @brief C++ wrapper facade for the socket @c fd_set abstraction. + * + * This abstraction is a very efficient wrapper facade over + * @c fd_set. In particular, no range checking is performed, so + * it's important not to set or clear bits that are outside the + * @c ACE_DEFAULT_SELECT_REACTOR_SIZE. + */ +class ACE_Export ACE_Handle_Set +{ +public: + friend class ACE_Handle_Set_Iterator; + + // = Initialization and termination. + + enum + { + MAXSIZE = ACE_DEFAULT_SELECT_REACTOR_SIZE + }; + + /// Constructor, initializes the bitmask to all 0s. + ACE_Handle_Set (void); + + /** + * Constructor, initializes the handle set from a given mask. + */ + ACE_Handle_Set (const fd_set &mask); + + // = Methods for manipulating bitsets. + /// Initialize the bitmask to all 0s and reset the associated fields. + void reset (void); + + /** + * Checks whether @a handle is enabled. No range checking is + * performed so @a handle must be less than + * @c ACE_DEFAULT_SELECT_REACTOR_SIZE. + */ + int is_set (ACE_HANDLE handle) const; + + /// Enables the @a handle. No range checking is performed so @a handle + /// must be less than @c ACE_DEFAULT_SELECT_REACTOR_SIZE. + void set_bit (ACE_HANDLE handle); + + /// Disables the @a handle. No range checking is performed so + /// @a handle must be less than @c ACE_DEFAULT_SELECT_REACTOR_SIZE. + void clr_bit (ACE_HANDLE handle); + + /// Returns a count of the number of enabled bits. + int num_set (void) const; + + /// Returns the number of the large bit. + ACE_HANDLE max_set (void) const; + + /** + * Rescan the underlying @c fd_set up to handle @a max to find the new + * (highest bit set) and (how many bits set) values. + * This is useful for evaluating the changes after the handle set has + * been manipulated in some way other than member functions; for example, + * after + ACE_Select_Reactor_Handle_Set dispatch_set_; + + /// Tracks handles that are waited for by . + ACE_Select_Reactor_Handle_Set ready_set_; + + /// Defined as a pointer to allow overriding by derived classes... + ACE_Timer_Queue *timer_queue_; + + /// Handle signals without requiring global/static variables. + ACE_Sig_Handler *signal_handler_; + + /// Callback object that unblocks the ACE_Select_Reactor if it's + /// sleeping. + ACE_Reactor_Notify *notify_handler_; + + /// Keeps track of whether we should delete the timer queue (if we + /// didn't create it, then we don't delete it). + bool delete_timer_queue_; + + /// Keeps track of whether we should delete the signal handler (if we + /// didn't create it, then we don't delete it). + bool delete_signal_handler_; + + /// Keeps track of whether we need to delete the notify handler (if + /// we didn't create it, then we don't delete it). + bool delete_notify_handler_; + + /// True if we've been initialized yet... + bool initialized_; + + /// Restart the event-loop method automatically when + /// . + + if (number_of_active_handles == 0) + { + do + { + if (this->timer_queue_ == 0) + return 0; + + this_timeout = + this->timer_queue_->calculate_timeout (max_wait_time, + &timer_buf); +#ifdef ACE_WIN32 + // This arg is ignored on Windows and causes pointer + // truncation warnings on 64-bit compiles. + int const width = 0; +#else + int const width = this->handler_rep_.max_handlep1 (); +#endif /* ACE_WIN32 */ + + dispatch_set.rd_mask_ = this->wait_set_.rd_mask_; + dispatch_set.wr_mask_ = this->wait_set_.wr_mask_; + dispatch_set.ex_mask_ = this->wait_set_.ex_mask_; + number_of_active_handles = ACE_OS::select (width, + dispatch_set.rd_mask_, + dispatch_set.wr_mask_, + dispatch_set.ex_mask_, + this_timeout); + } + while (number_of_active_handles == -1 && this->handle_error () > 0); + + if (number_of_active_handles > 0) + { +#if !defined (ACE_WIN32) + // Resynchronize the fd_sets so their "max" is set properly. + dispatch_set.rd_mask_.sync (this->handler_rep_.max_handlep1 ()); + dispatch_set.wr_mask_.sync (this->handler_rep_.max_handlep1 ()); + dispatch_set.ex_mask_.sync (this->handler_rep_.max_handlep1 ()); +#endif /* ACE_WIN32 */ + } + else if (number_of_active_handles == -1) + { + // Normally, select() will reset the bits in dispatch_set + // so that only those filed descriptors that are ready will + // have bits set. However, when an error occurs, the bit + // set remains as it was when the select call was first made. + // Thus, we now have a dispatch_set that has every file + // descriptor that was originally waited for, which is not + // correct. We must clear all the bit sets because we + // have no idea if any of the file descriptors is ready. + // + // NOTE: We dont have a test case to reproduce this + // problem. But pleae dont ignore this and remove it off. + dispatch_set.rd_mask_.reset (); + dispatch_set.wr_mask_.reset (); + dispatch_set.ex_mask_.reset (); + } + } + + // Return the number of events to dispatch. + return number_of_active_handles; +} + +template int +ACE_Select_Reactor_T::dispatch_timer_handlers + (int &number_of_handlers_dispatched) +{ + number_of_handlers_dispatched += this->timer_queue_->expire (); + + return 0; +} + +template int +ACE_Select_Reactor_T::dispatch_notification_handlers + (ACE_Select_Reactor_Handle_Set &dispatch_set, + int &number_of_active_handles, + int &number_of_handlers_dispatched) +{ + // Check to see if the ACE_HANDLE associated with the + // Select_Reactor's notify hook is enabled. If so, it means that + // one or more other threads are trying to update the + // ACE_Select_Reactor_T's internal tables or the notify pipe is + // enabled. We'll handle all these threads and notifications, and + // then break out to continue the event loop. + int const n = + this->notify_handler_->dispatch_notifications (number_of_active_handles, + dispatch_set.rd_mask_); + + if (n == -1) + return -1; + else + { + number_of_handlers_dispatched += n; + number_of_active_handles -= n; + } + + // Same as dispatch_timer_handlers + // No need to do anything with the state changed. That is because + // unbind already handles the case where someone unregister some + // kind of handle and unbind it. (::unbind calls the function + // state_changed () to reflect ant change with that) + // return this->state_changed_ ? -1 : 0; + return 0; +} + +template int +ACE_Select_Reactor_T::dispatch_io_set + (int number_of_active_handles, + int &number_of_handlers_dispatched, + int mask, + ACE_Handle_Set &dispatch_mask, + ACE_Handle_Set &ready_mask, + ACE_EH_PTMF callback) +{ + ACE_TRACE ("ACE_Select_Reactor_T::dispatch_io_set"); + ACE_HANDLE handle; + + ACE_Handle_Set_Iterator handle_iter (dispatch_mask); + + while ((handle = handle_iter ()) != ACE_INVALID_HANDLE && + number_of_handlers_dispatched < number_of_active_handles) + { + ++number_of_handlers_dispatched; + + this->notify_handle (handle, + mask, + ready_mask, + this->handler_rep_.find (handle), + callback); + + // clear the bit from that dispatch mask, + // so when we need to restart the iteration (rebuilding the iterator...) + // we will not dispatch the already dispatched handlers + this->clear_dispatch_mask (handle, mask); + + if (this->state_changed_) + { + + handle_iter.reset_state (); + this->state_changed_ = false; + } + } + + return 0; +} + +template int +ACE_Select_Reactor_T::dispatch_io_handlers + (ACE_Select_Reactor_Handle_Set &dispatch_set, + int &number_of_active_handles, + int &number_of_handlers_dispatched) +{ + ACE_TRACE ("ACE_Select_Reactor_T::dispatch_io_handlers"); + + // Handle output events (this code needs to come first to handle the + // obscure case of piggy-backed data coming along with the final + // handshake message of a nonblocking connection). + + if (this->dispatch_io_set (number_of_active_handles, + number_of_handlers_dispatched, + ACE_Event_Handler::WRITE_MASK, + dispatch_set.wr_mask_, + this->ready_set_.wr_mask_, + &ACE_Event_Handler::handle_output) == -1) + { + number_of_active_handles -= number_of_handlers_dispatched; + return -1; + } + + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE_Select_Reactor_T::dispatch - EXCEPT\n"))); + if (this->dispatch_io_set (number_of_active_handles, + number_of_handlers_dispatched, + ACE_Event_Handler::EXCEPT_MASK, + dispatch_set.ex_mask_, + this->ready_set_.ex_mask_, + &ACE_Event_Handler::handle_exception) == -1) + { + number_of_active_handles -= number_of_handlers_dispatched; + return -1; + } + + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("ACE_Select_Reactor_T::dispatch - READ\n"))); + if (this->dispatch_io_set (number_of_active_handles, + number_of_handlers_dispatched, + ACE_Event_Handler::READ_MASK, + dispatch_set.rd_mask_, + this->ready_set_.rd_mask_, + &ACE_Event_Handler::handle_input) == -1) + { + number_of_active_handles -= number_of_handlers_dispatched; + return -1; + } + + number_of_active_handles -= number_of_handlers_dispatched; + return 0; +} + +template int +ACE_Select_Reactor_T::dispatch + (int active_handle_count, + ACE_Select_Reactor_Handle_Set &dispatch_set) +{ + ACE_TRACE ("ACE_Select_Reactor_T::dispatch"); + + int io_handlers_dispatched = 0; + int other_handlers_dispatched = 0; + int signal_occurred = 0; + // The following do/while loop keeps dispatching as long as there + // are still active handles. Note that the only way we should ever + // iterate more than once through this loop is if signals occur + // while we're dispatching other handlers. + + do + { + // We expect that the loop will decrease the number of active + // handles in each iteration. If it does not, then something is + // inconsistent in the state of the Reactor and we should avoid + // the loop. Please read the comments on bug 2540 for more + // details. + int initial_handle_count = active_handle_count; + + // Note that we keep track of changes to our state. If any of + // the dispatch_*() methods below return -1 it means that the + // state has changed as the result of an + // being dispatched. This means that we + // need to bail out and rerun the select() loop since our + // existing notion of handles in may no longer be + // correct. + // + // In the beginning, our state starts out unchanged. After + // every iteration (i.e., due to signals), our state starts out + // unchanged again. + + this->state_changed_ = false; + + // Perform the Template Method for dispatching all the handlers. + + // First check for interrupts. + if (active_handle_count == -1) + { + // Bail out -- we got here since /. Pass over both the Event_Handler *and* the + * @a mask to allow the caller to dictate which + * method the will invoke. The ACE_Time_Value + * indicates how long to blocking trying to notify the + * . If @a timeout == 0, the caller will block until + * action is possible, else will wait until the relative time + * specified in *@a timeout elapses). + */ + virtual int notify (ACE_Event_Handler * = 0, + ACE_Reactor_Mask = ACE_Event_Handler::EXCEPT_MASK, + ACE_Time_Value * = 0); + + /** + * Set the maximum number of times that the + * ACE_Select_Reactor_Notify::handle_input() method will iterate and + * dispatch the ACE_Event_Handlers that are passed in via the + * notify pipe before breaking out of its recv loop. By default, + * this is set to -1, which means "iterate until the pipe is empty." + * Setting this to a value like "1 or 2" will increase "fairness" + * (and thus prevent starvation) at the expense of slightly higher + * dispatching overhead. + */ + virtual void max_notify_iterations (int); + + /** + * Get the maximum number of times that the + * ACE_Select_Reactor_Notify::handle_input() method will iterate and + * dispatch the ACE_Event_Handlers that are passed in via the + * notify pipe before breaking out of its recv loop. + */ + virtual int max_notify_iterations (void); + + /// Get the existing restart value. + virtual bool restart (void); + + /// Set a new value for restart and return the original value. + virtual bool restart (bool r); + + /// Set position that the main ACE_Select_Reactor thread is requeued in the + /// list of waiters during a callback. + virtual void requeue_position (int); + + /// Get position that the main ACE_Select_Reactor thread is requeued in the + /// list of waiters during a callback. + virtual int requeue_position (void); + + // = Low-level wait_set mask manipulation methods. + /// GET/SET/ADD/CLR the dispatch mask "bit" bound with the @a eh and + /// @a mask. + virtual int mask_ops (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask, + int ops); + + /// GET/SET/ADD/CLR the dispatch MASK "bit" bound with the @a handle + /// and @a mask. + virtual int mask_ops (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + int ops); + + // = Low-level ready_set mask manipulation methods. + /// GET/SET/ADD/CLR the ready "bit" bound with the @a eh and @a mask. + virtual int ready_ops (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask, + int ops); + + /// GET/SET/ADD/CLR the ready "bit" bound with the @a handle and @a mask. + virtual int ready_ops (ACE_HANDLE handle, + ACE_Reactor_Mask, + int ops); + + /// Wake up all threads in waiting in the event loop + virtual void wakeup_all_threads (void); + + // = Only the owner thread can perform a . + + /// Set the new owner of the thread and return the old owner. + virtual int owner (ACE_thread_t n_id, ACE_thread_t *o_id = 0); + + /// Return the current owner of the thread. + virtual int owner (ACE_thread_t *); + + // = Miscellaneous Handler operations. + + /** + * Return the Event_Handler associated with @a handle. Return 0 if + * @a handle is not registered. + */ + virtual ACE_Event_Handler *find_handler (ACE_HANDLE handle); + + /** + * Check to see if @a handle is associated with a valid Event_Handler + * bound to @a mask. Return the @a eh associated with this @a handler + * if @a eh != 0. + */ + virtual int handler (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Event_Handler **eh = 0); + + /** + * Check to see if @a signum is associated with a valid Event_Handler + * bound to a signal. Return the @a eh associated with this + * handler if @a eh != 0. + */ + virtual int handler (int signum, + ACE_Event_Handler ** = 0); + + /// Returns true if we've been successfully initialized, else false. + virtual bool initialized (void); + + /// Returns the current size of the Reactor's internal descriptor + /// table. + virtual size_t size (void) const; + + /** + * Returns a reference to the ACE_Reactor_Token that is + * used to serialize the internal processing logic. + * This can be useful for situations where you need to avoid + * deadlock efficiently when ACE_Event_Handlers are used in + * multiple threads. + */ + virtual ACE_Lock &lock (void); + + /// Dump the state of an object. + virtual void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Internal methods that do the actual work. + + // All of these methods assume that the token + // lock is held by the public methods that call down to them. + + /// Do the work of actually binding the @a handle and @a eh with the + /// @a mask. + virtual int register_handler_i (ACE_HANDLE handle, + ACE_Event_Handler *eh, + ACE_Reactor_Mask mask); + + /// Register a set of @a handles. + virtual int register_handler_i (const ACE_Handle_Set &handles, + ACE_Event_Handler *handler, + ACE_Reactor_Mask mask); + + /// Do the work of actually unbinding the @a handle and @a eh with the + /// @a mask. + virtual int remove_handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask); + + /// Remove a set of @a handles. + virtual int remove_handler_i (const ACE_Handle_Set &handles, + ACE_Reactor_Mask); + + /// Suspend the associated with @a handle + virtual int suspend_i (ACE_HANDLE handle); + + /// Check to see if the associated with @a handle is + /// suspended. Returns 0 if not, 1 if so. + virtual int is_suspended_i (ACE_HANDLE handle); + + /// Resume the associated with @a handle + virtual int resume_i (ACE_HANDLE handle); + + /// Implement the public handler method. + virtual ACE_Event_Handler *find_handler_i (ACE_HANDLE handle); + + /// Implement the public handler method. + virtual int handler_i (ACE_HANDLE handle, + ACE_Reactor_Mask, + ACE_Event_Handler ** = 0); + + /// Implement the public handler method. + virtual int handler_i (int signum, ACE_Event_Handler ** = 0); + + /** + * Check if there are any HANDLEs enabled in the , and + * if so, update the @a handle_set and return the number ready. If + * there aren't any HANDLEs enabled return 0. + */ + virtual int any_ready (ACE_Select_Reactor_Handle_Set &handle_set); + + /// Implement the method, assuming that the Sig_Guard is + /// being held + virtual int any_ready_i (ACE_Select_Reactor_Handle_Set &handle_set); + + /// Take corrective action when errors occur. + virtual int handle_error (void); + + /// Make sure the handles are all valid. + virtual int check_handles (void); + + /// Wait for events to occur. + virtual int wait_for_multiple_events (ACE_Select_Reactor_Handle_Set &, + ACE_Time_Value *); + + // = Dispatching methods. + + /** + * Template Method that dispatches ACE_Event_Handlers for time + * events, I/O events, and signal events. Returns the total number + * of ACE_Event_Handlers that were dispatched or -1 if something + * goes wrong. + */ + virtual int dispatch (int nfound, + ACE_Select_Reactor_Handle_Set &); + + /** + * Dispatch all timer handlers that have expired. Returns -1 if the + * state of the has changed, else 0. + * is set to the number of timer handlers + * dispatched. + */ + virtual int dispatch_timer_handlers (int &number_dispatched); + + /** + * Dispatch any notification handlers. Returns -1 if the state of + * the has changed, else returns number of handlers + * notified. + */ + virtual int dispatch_notification_handlers (ACE_Select_Reactor_Handle_Set &dispatch_set, + int &number_of_active_handles, + int &number_of_handlers_dispatched); + + /** + * Dispatch all the input/output/except handlers that are enabled in + * the @a dispatch_set. Updates @a number_of_active_handles and + * @a number_of_handlers_dispatched according to the behavior of the + * number Returns -1 if the state of the has changed, + * else 0. + */ + virtual int dispatch_io_handlers (ACE_Select_Reactor_Handle_Set &dispatch_set, + int &number_of_active_handles, + int &number_of_handlers_dispatched); + + /** + * Factors the dispatching of an io handle set (each WRITE, EXCEPT + * or READ set of handles). It updates the + * @a number_of_handlers_dispatched and invokes this->notify_handle + * for all the handles in using the @a mask, + * and @a callback parameters. Must return -1 if + * this->state_changed otherwise it must return 0. + */ + virtual int dispatch_io_set (int number_of_active_handles, + int &number_of_handlers_dispatched, + int mask, + ACE_Handle_Set& dispatch_mask, + ACE_Handle_Set& ready_mask, + ACE_EH_PTMF callback); + + /// Notify the appropriate @a callback in the context of the @a eh + /// associated with @a handle that a particular event has occurred. + virtual void notify_handle (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Handle_Set &, + ACE_Event_Handler *eh, + ACE_EH_PTMF callback); + + /// Enqueue ourselves into the list of waiting threads at the + /// appropriate point specified by . + virtual void renew (void); + + /// Synchronization token for the MT_SAFE ACE_Select_Reactor. + ACE_SELECT_REACTOR_TOKEN token_; + + /// Adapter used to return internal lock to outside world. + ACE_Lock_Adapter lock_adapter_; + + /// Release the token lock when a Win32 structured exception occurs. + int release_token (void); + + /// Stops the VC++ compiler from bitching about exceptions and destructors + int handle_events_i (ACE_Time_Value *max_wait_time = 0); + + /// This flag is used to keep track of whether we are actively handling + /// events or not. + sig_atomic_t deactivated_; + +private: + /// Deny access since member-wise won't work... + ACE_UNIMPLEMENTED_FUNC (ACE_Select_Reactor_T (const ACE_Select_Reactor_T &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Select_Reactor_T &operator= (const ACE_Select_Reactor_T &) ) +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Select_Reactor_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Select_Reactor_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Select_Reactor_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_SELECT_REACTOR_T_H */ diff --git a/dep/acelite/ace/Select_Reactor_T.inl b/dep/acelite/ace/Select_Reactor_T.inl new file mode 100644 index 000000000..7200933a4 --- /dev/null +++ b/dep/acelite/ace/Select_Reactor_T.inl @@ -0,0 +1,231 @@ +// -*- C++ -*- +#include "ace/Reactor.h" +#include "ace/Signal.h" +#include "ace/Sig_Handler.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_INLINE int +ACE_Select_Reactor_T::resume_handler (ACE_Event_Handler *h) +{ + ACE_TRACE ("ACE_Select_Reactor_T::resume_handler"); + return this->resume_handler (h->get_handle ()); +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::resume_handler (const ACE_Handle_Set &handles) +{ + ACE_TRACE ("ACE_Select_Reactor_T::resume_handler"); + ACE_Handle_Set_Iterator handle_iter (handles); + ACE_HANDLE h; + + ACE_MT (ACE_GUARD_RETURN (ACE_SELECT_REACTOR_TOKEN, ace_mon, this->token_, -1)); + + while ((h = handle_iter ()) != ACE_INVALID_HANDLE) + if (this->resume_i (h) == -1) + return -1; + + return 0; +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::suspend_handler (ACE_Event_Handler *h) +{ + ACE_TRACE ("ACE_Select_Reactor_T::suspend_handler"); + return this->suspend_handler (h->get_handle ()); +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::suspend_handler (const ACE_Handle_Set &handles) +{ + ACE_TRACE ("ACE_Select_Reactor_T::suspend_handler"); + ACE_Handle_Set_Iterator handle_iter (handles); + ACE_HANDLE h; + + ACE_MT (ACE_GUARD_RETURN (ACE_SELECT_REACTOR_TOKEN, ace_mon, this->token_, -1)); + + while ((h = handle_iter ()) != ACE_INVALID_HANDLE) + if (this->suspend_i (h) == -1) + return -1; + + return 0; +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Select_Reactor_T::register_handler"); + return this->signal_handler_->register_handler (signum, + new_sh, new_disp, + old_sh, old_disp); +} + +#if defined (ACE_WIN32) +template +ACE_INLINE int +ACE_Select_Reactor_T::register_handler (ACE_Event_Handler *, + ACE_HANDLE ) +{ + // Don't have an implementation for this yet... + ACE_NOTSUP_RETURN (-1); +} +#endif /* ACE_WIN32 */ + +template +ACE_INLINE int +ACE_Select_Reactor_T::register_handler (ACE_HANDLE , + ACE_HANDLE , + ACE_Event_Handler *, + ACE_Reactor_Mask ) +{ + // Don't have an implementation for this yet... + ACE_NOTSUP_RETURN (-1); +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::handler (int signum, ACE_Event_Handler **handler) +{ + ACE_TRACE ("ACE_Select_Reactor_T::handler"); + return this->handler_i (signum, handler); +} + +template +ACE_INLINE int +ACE_Select_Reactor_T::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int sigkey) +{ + ACE_TRACE ("ACE_Select_Reactor_T::remove_handler"); + return this->signal_handler_->remove_handler (signum, new_disp, old_disp, sigkey); +} + +template +ACE_INLINE bool +ACE_Select_Reactor_T::uses_event_associations (void) +{ + // Since the Select_Reactor does not do any event associations, this + // function always return false. + return false; +} + +// = The remaining methods in this file must be called with locks +// held. + +// Performs operations on the "ready" bits. + +template ACE_INLINE int +ACE_Select_Reactor_T::ready_ops (ACE_Event_Handler *handler, + ACE_Reactor_Mask mask, + int ops) +{ + ACE_TRACE ("ACE_Select_Reactor_T::ready_ops"); + return this->ready_ops (handler->get_handle (), mask, ops); +} + +// Performs operations on the "dispatch" masks. + +template ACE_INLINE int +ACE_Select_Reactor_T::mask_ops (ACE_Event_Handler *handler, + ACE_Reactor_Mask mask, + int ops) +{ + ACE_TRACE ("ACE_Select_Reactor_T::mask_ops"); + return this->mask_ops (handler->get_handle (), mask, ops); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::schedule_wakeup (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Select_Reactor_T::schedule_wakeup"); + return this->mask_ops (eh->get_handle (), mask, ACE_Reactor::ADD_MASK); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::cancel_wakeup (ACE_Event_Handler *eh, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Select_Reactor_T::cancel_wakeup"); + return this->mask_ops (eh->get_handle (), mask, ACE_Reactor::CLR_MASK); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::schedule_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Select_Reactor_T::schedule_wakeup"); + return this->mask_ops (handle, mask, ACE_Reactor::ADD_MASK); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::cancel_wakeup (ACE_HANDLE handle, + ACE_Reactor_Mask mask) +{ + ACE_TRACE ("ACE_Select_Reactor_T::cancel_wakeup"); + return this->mask_ops (handle, mask, ACE_Reactor::CLR_MASK); +} + +template ACE_INLINE ACE_Lock & +ACE_Select_Reactor_T::lock (void) +{ + ACE_TRACE ("ACE_Select_Reactor_T::lock"); + return this->lock_adapter_; +} + +template ACE_INLINE void +ACE_Select_Reactor_T::wakeup_all_threads (void) +{ + // Send a notification, but don't block if there's no one to receive + // it. + this->notify (0, ACE_Event_Handler::NULL_MASK, (ACE_Time_Value *) &ACE_Time_Value::zero); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::alertable_handle_events (ACE_Time_Value *max_wait_time) +{ + return this->handle_events (max_wait_time); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::alertable_handle_events (ACE_Time_Value &max_wait_time) +{ + return this->handle_events (max_wait_time); +} + +template ACE_INLINE int +ACE_Select_Reactor_T::deactivated (void) +{ + return this->deactivated_; +} + +template ACE_INLINE void +ACE_Select_Reactor_T::deactivate (int do_stop) +{ + { + ACE_MT (ACE_GUARD (ACE_SELECT_REACTOR_TOKEN, + ace_mon, + this->token_)); + this->deactivated_ = static_cast (do_stop); + } + + this->wakeup_all_threads (); +} + +template ACE_INLINE size_t +ACE_Select_Reactor_T::size (void) const +{ + return this->handler_rep_.size (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Semaphore.cpp b/dep/acelite/ace/Semaphore.cpp new file mode 100644 index 000000000..dcbac24fc --- /dev/null +++ b/dep/acelite/ace/Semaphore.cpp @@ -0,0 +1,61 @@ +#include "ace/Semaphore.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Semaphore.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/ACE.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Semaphore) + +void +ACE_Semaphore::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Semaphore::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Semaphore::ACE_Semaphore (unsigned int count, + int type, + const ACE_TCHAR *name, + void *arg, + int max) + : removed_ (false) +{ +// ACE_TRACE ("ACE_Semaphore::ACE_Semaphore"); +#if defined(ACE_LACKS_UNNAMED_SEMAPHORE) +// if the user does not provide a name, we generate a unique name here + ACE_TCHAR iname[ACE_UNIQUE_NAME_LEN]; + if (name == 0) + ACE::unique_name (this, iname, ACE_UNIQUE_NAME_LEN); + if (ACE_OS::sema_init (&this->semaphore_, count, type, + name ? name : iname, + arg, max) != 0) +#else + if (ACE_OS::sema_init (&this->semaphore_, count, type, + name, arg, max) != 0) +#endif + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Semaphore::ACE_Semaphore"))); +} + +ACE_Semaphore::~ACE_Semaphore (void) +{ +// ACE_TRACE ("ACE_Semaphore::~ACE_Semaphore"); + + this->remove (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Semaphore.h b/dep/acelite/ace/Semaphore.h new file mode 100644 index 000000000..a94afc3fc --- /dev/null +++ b/dep/acelite/ace/Semaphore.h @@ -0,0 +1,181 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Semaphore.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_SEMAPHORE_H +#define ACE_SEMAPHORE_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_Thread.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Time_Value; + +/** + * @class ACE_Semaphore + * + * @brief Wrapper for Dijkstra style general semaphores. + */ +class ACE_Export ACE_Semaphore +{ +public: + // = Initialization and termination. + /// Initialize the semaphore, with initial value of "count". + ACE_Semaphore (unsigned int count = 1, // By default make this unlocked. + int type = USYNC_THREAD, + const ACE_TCHAR *name = 0, + void * = 0, + int max = 0x7fffffff); + + /// Implicitly destroy the semaphore. + ~ACE_Semaphore (void); + + /** + * Explicitly destroy the semaphore. Note that only one thread + * should call this method since it doesn't protect against race + * conditions. + */ + int remove (void); + + /// Block the thread until the semaphore count becomes + /// greater than 0, then decrement it. + int acquire (void); + + /** + * Block the thread until the semaphore count becomes greater than 0 + * (at which point it is decremented) or until @a tv times out (in + * which case -1 is returned and @c errno == @c ETIME). Note that @a tv + * is assumed to be in "absolute" rather than "relative" time. The + * value of @a tv is updated upon return to show the actual + * (absolute) acquisition time. + * + * @note Solaris threads do not support timed semaphores. + * Therefore, if you're running on Solaris you might want to + * consider using the ACE POSIX pthreads implementation instead, + * which can be enabled by compiling ACE with + * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or + * -DACE_HAS_POSIX_SEM. + */ + int acquire (ACE_Time_Value &tv); + + /** + * If @a tv == 0 then call directly. Otherwise, Block + * the thread until the semaphore count becomes greater than 0 + * (at which point it is decremented) or until @a tv times out (in + * which case -1 is returned and @c errno == @c ETIME). Note that + * <*tv> is assumed to be in "absolute" rather than "relative" time. + * The value of <*tv> is updated upon return to show the actual + * (absolute) acquisition time. + * + * @note Solaris threads do not support timed semaphores. + * Therefore, if you're running on Solaris you might want to + * consider using the ACE POSIX pthreads implementation instead, + * which can be enabled by compiling ACE with + * -DACE_HAS_PTHREADS, rather than -DACE_HAS_STHREADS or + * -DACE_HAS_POSIX_SEM. */ + int acquire (ACE_Time_Value *tv); + + /** + * Conditionally decrement the semaphore if count is greater than 0 + * (i.e., won't block). Returns -1 on failure. If we "failed" + * because someone else already had the lock, @c errno is set to + * @c EBUSY. + */ + int tryacquire (void); + + /// Increment the semaphore by 1, potentially unblocking a waiting + /// thread. + int release (void); + + /// Increment the semaphore by @a release_count, potentially + /// unblocking waiting threads. + int release (unsigned int release_count); + + /** + * Acquire semaphore ownership. This calls and is only + * here to make the ACE_Semaphore interface consistent with the + * other synchronization APIs. + */ + int acquire_read (void); + + /** + * Acquire semaphore ownership. This calls and is only + * here to make the ACE_Semaphore interface consistent with the + * other synchronization APIs. + */ + int acquire_write (void); + + /** + * Conditionally acquire semaphore (i.e., won't block). This calls + * and is only here to make the ACE_Semaphore + * interface consistent with the other synchronization APIs. + * Returns -1 on failure. If we "failed" because someone else + * already had the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_read (void); + + /** + * Conditionally acquire semaphore (i.e., won't block). This calls + * and is only here to make the ACE_Semaphore + * interface consistent with the other synchronization APIs. + * Returns -1 on failure. If we "failed" because someone else + * already had the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_write (void); + + /** + * This is only here to make the ACE_Semaphore + * interface consistent with the other synchronization APIs. + * Assumes the caller has already acquired the semaphore using one of + * the above calls, and returns 0 (success) always. + */ + int tryacquire_write_upgrade (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Return the underlying lock. + const ACE_sema_t &lock (void) const; + +protected: + ACE_sema_t semaphore_; + + /// Keeps track of whether remove() has been called yet to avoid + /// multiple remove() calls, e.g., explicitly and implicitly in the + /// destructor. This flag isn't protected by a lock, so make sure + /// that you don't have multiple threads simultaneously calling + /// remove () on the same object, which is a bad idea anyway... + bool removed_; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Semaphore &); + ACE_Semaphore (const ACE_Semaphore &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Semaphore.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SEMAPHORE_H */ diff --git a/dep/acelite/ace/Semaphore.inl b/dep/acelite/ace/Semaphore.inl new file mode 100644 index 000000000..8de0beef3 --- /dev/null +++ b/dep/acelite/ace/Semaphore.inl @@ -0,0 +1,116 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE const ACE_sema_t & +ACE_Semaphore::lock (void) const +{ +// ACE_TRACE ("ACE_Semaphore::lock"); + return this->semaphore_; +} + +ACE_INLINE int +ACE_Semaphore::remove (void) +{ +// ACE_TRACE ("ACE_Semaphore::remove"); + int result = 0; + if (!this->removed_) + { + this->removed_ = true; + result = ACE_OS::sema_destroy (&this->semaphore_); + } + return result; +} + +ACE_INLINE int +ACE_Semaphore::acquire (void) +{ +// ACE_TRACE ("ACE_Semaphore::acquire"); + return ACE_OS::sema_wait (&this->semaphore_); +} + +ACE_INLINE int +ACE_Semaphore::acquire (ACE_Time_Value &tv) +{ +// ACE_TRACE ("ACE_Semaphore::acquire"); + return ACE_OS::sema_wait (&this->semaphore_, tv); +} + +ACE_INLINE int +ACE_Semaphore::acquire (ACE_Time_Value *tv) +{ +// ACE_TRACE ("ACE_Semaphore::acquire"); + return ACE_OS::sema_wait (&this->semaphore_, tv); +} + +ACE_INLINE int +ACE_Semaphore::tryacquire (void) +{ +// ACE_TRACE ("ACE_Semaphore::tryacquire"); + return ACE_OS::sema_trywait (&this->semaphore_); +} + +ACE_INLINE int +ACE_Semaphore::release (void) +{ +// ACE_TRACE ("ACE_Semaphore::release"); + return ACE_OS::sema_post (&this->semaphore_); +} + +ACE_INLINE int +ACE_Semaphore::release (unsigned int release_count) +{ +// ACE_TRACE ("ACE_Semaphore::release"); + return ACE_OS::sema_post (&this->semaphore_, release_count); +} + +// Acquire semaphore ownership. This calls and is only +// here to make the interface consistent with the +// other synchronization APIs. + +ACE_INLINE int +ACE_Semaphore::acquire_read (void) +{ + return this->acquire (); +} + +// Acquire semaphore ownership. This calls and is only +// here to make the interface consistent with the +// other synchronization APIs. + +ACE_INLINE int +ACE_Semaphore::acquire_write (void) +{ + return this->acquire (); +} + +// Conditionally acquire semaphore (i.e., won't block). This calls +// and is only here to make the +// interface consistent with the other synchronization APIs. + +ACE_INLINE int +ACE_Semaphore::tryacquire_read (void) +{ + return this->tryacquire (); +} + +// Conditionally acquire semaphore (i.e., won't block). This calls +// and is only here to make the +// interface consistent with the other synchronization APIs. + +ACE_INLINE int +ACE_Semaphore::tryacquire_write (void) +{ + return this->tryacquire (); +} + +// This is only here to make the interface consistent +// with the other synchronization APIs. Assumes the caller has +// already acquired the semaphore using one of the above calls, and +// returns 0 (success) always. +ACE_INLINE int +ACE_Semaphore::tryacquire_write_upgrade (void) +{ + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Config.cpp b/dep/acelite/ace/Service_Config.cpp new file mode 100644 index 000000000..193e54ab8 --- /dev/null +++ b/dep/acelite/ace/Service_Config.cpp @@ -0,0 +1,615 @@ +#include "ace/Service_Config.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Service_Config.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Service_Types.h" +#include "ace/Reactor.h" +#include "ace/Singleton.h" +#include "ace/Service_Repository.h" + +#ifndef ACE_LACKS_UNIX_SIGNALS +# include "ace/Sig_Adapter.h" +#endif /* !ACE_LACKS_UNIX_SIGNALS */ + +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_unistd.h" +#include "ace/Thread.h" +#include "ace/Get_Opt.h" +#include "ace/ARGV.h" +#include "ace/Log_Category.h" +#include "ace/ACE.h" + +#ifdef ACE_HAS_TSS_EMULATION +#include "ace/Object_Manager.h" +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Threading_Helper::~ACE_Threading_Helper (void) +{ + ACE_OS::thr_key_detach (this->key_); + ACE_OS::thr_keyfree (this->key_); +} + +ACE_Threading_Helper::ACE_Threading_Helper (void) + : key_ (ACE_OS::NULL_key) +{ +# if defined (ACE_HAS_TSS_EMULATION) + ACE_Object_Manager::init_tss (); +# endif + + if (ACE_Thread::keycreate (&key_, 0) == -1) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Failed to create thread key: %p\n"), + ACE_TEXT (""))); + } +} + +void +ACE_Threading_Helper::set (void* p) +{ + if (ACE_Thread::setspecific (key_, p) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) Service Config failed to set thread key value: %p\n"), + ACE_TEXT(""))); +} + +void* +ACE_Threading_Helper::get (void) +{ + void* temp = 0; + if (ACE_Thread::getspecific (key_, &temp) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) Service Config failed to get thread key value: %p\n"), + ACE_TEXT("")), + 0); + return temp; +} + +ACE_Threading_Helper::~ACE_Threading_Helper () +{ +} + +ACE_Threading_Helper::ACE_Threading_Helper () +{ +} + +void +ACE_Threading_Helper::set (void*) +{ +} + +void* +ACE_Threading_Helper::get (void) +{ + return ACE_Service_Config::singleton()->instance_.get (); +} + +/** + * @c ACE_Service_Config is supposed to be a Singleton. This is the + * only Configuration Gestalt available for access from static + * initializers at proces start-up time. Using Unmanaged Singleton + * is safer because (a) the Object Manager may not yet be fully initialized + * in the context of a static initializer that uses SC, and (b) because we + * know that upon process exit the SC will still be automaticaly and explicitly + * closed by @c ACE_Object_Manager::fini(). + */ +typedef ACE_Unmanaged_Singleton ACE_SERVICE_CONFIG_SINGLETON; + + +/// ctor +ACE_Service_Config_Guard::ACE_Service_Config_Guard (ACE_Service_Gestalt * psg) + : saved_ (ACE_Service_Config::current ()) +{ + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) - SCG:") + ACE_TEXT (" - config=%@ repo=%@ superseded by repo=%@\n"), + this, + this->saved_.get (), + this->saved_->repo_, + psg->repo_)); + + // Modify the TSS if the repo has changed + ACE_Service_Config::current (psg); +} + +ACE_Service_Config_Guard::~ACE_Service_Config_Guard (void) +{ + ACE_Service_Gestalt* s = this->saved_.get (); + ACE_ASSERT (s != 0); + + ACE_Service_Config::current (s); + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SCG:") + ACE_TEXT (" - new repo=%@\n"), + this, + this->saved_->repo_)); +} + + +ACE_ALLOC_HOOK_DEFINE (ACE_Service_Config) + +// Set the signal handler to point to the handle_signal() function. +ACE_Sig_Adapter *ACE_Service_Config::signal_handler_ = 0; + +// Trigger a reconfiguration. +sig_atomic_t ACE_Service_Config::reconfig_occurred_ = 0; + +// = Set by command-line options. + +/// Pathname of file to write process id. +ACE_TCHAR *ACE_Service_Config::pid_file_name_ = 0; + +/// Shall we become a daemon process? +bool ACE_Service_Config::be_a_daemon_ = false; + +/// Number of the signal used to trigger reconfiguration. +int ACE_Service_Config::signum_ = SIGHUP; + +void +ACE_Service_Config::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Config::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Service_Config::parse_args_i (int argc, ACE_TCHAR *argv[]) +{ + ACE_TRACE ("ACE_Service_Config::parse_args_i"); + + // Using PERMUTE_ARGS (default) in order to have all + // unrecognized options and their value arguments moved + // to the end of the argument vector. We'll pick them up + // after processing our options and pass them on to the + // base class for further parsing. + //FUZZ: disable check_for_lack_ACE_OS + ACE_Get_Opt getopt (argc, + argv, + ACE_TEXT ("bs:p:"), + 1 , // Start at argv[1]. + 0, // Do not report errors + ACE_Get_Opt::RETURN_IN_ORDER); + //FUZZ: enable check_for_lack_ACE_OS + + //FUZZ: disable check_for_lack_ACE_OS + for (int c; (c = getopt ()) != -1; ) + //FUZZ: enable check_for_lack_ACE_OS + switch (c) + { + case 'p': + ACE_Service_Config::pid_file_name_ = getopt.opt_arg (); + break; + case 'b': + ACE_Service_Config::be_a_daemon_ = true; + break; + case 's': + { + // There's no point in dealing with this on NT since it + // doesn't really support signals very well... +#if !defined (ACE_LACKS_UNIX_SIGNALS) + ACE_Service_Config::signum_ = + ACE_OS::atoi (getopt.opt_arg ()); + + if (ACE_Reactor::instance ()->register_handler + (ACE_Service_Config::signum_, + ACE_Service_Config::signal_handler_) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("cannot obtain signal handler\n")), + -1); +#endif /* ACE_LACKS_UNIX_SIGNALS */ + break; + } + default:; // unknown arguments are benign + + } + + return 0; +} /* parse_args_i () */ + + +int +ACE_Service_Config::open_i (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key, + bool , + bool , + bool ) +{ + ACE_TRACE ("ACE_Service_Config::open_i"); + ACE_MT (ACE_GUARD_RETURN (ACE_SYNCH_MUTEX, ace_mon, this->lock_, -1)); + + ACE_Log_Msg *log_msg = ACE_LOG_MSG; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SC::open_i - this=%@, opened=%d\n"), + this, this->is_opened_)); + + // Guard against reentrant processing. + if (this->is_opened_) + return 0; + + this->is_opened_ = true; + + // Check for things we need to do on a per-process basis and which + // may not be safe, or wise to do an a per instance basis + + // Become a daemon before doing anything else. + if (ACE_Service_Config::be_a_daemon_) + { + // If we have to become a daemn and that fails + // return -1 here + if (ACE::daemonize () == -1) + return -1; + } + + // Write process id to file. + if (this->pid_file_name_ != 0) + { + FILE* pidf = ACE_OS::fopen (this->pid_file_name_, + ACE_TEXT("w")); + + if (pidf != 0) + { + ACE_OS::fprintf (pidf, + "%ld\n", + static_cast (ACE_OS::getpid())); + ACE_OS::fclose (pidf); + } + } + + u_long flags = log_msg->flags (); + + // Only use STDERR if the caller hasn't already set the flags. + if (flags == 0) + flags = (u_long) ACE_Log_Msg::STDERR; + + const ACE_TCHAR *key = logger_key; + + if (key == 0 || ACE_OS::strcmp (key, ACE_DEFAULT_LOGGER_KEY) == 0) + { + // Only use the static if the caller doesn't + // override it in the parameter list or if the key supplied is + // equal to the default static logger key. + key = ACE_Service_Config::current()->logger_key_; + } + else + { + ACE_SET_BITS (flags, ACE_Log_Msg::LOGGER); + } + + if (log_msg->open (program_name, + flags, + key) == -1) + return -1; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_STARTUP, + ACE_TEXT ("starting up daemon %n\n"))); + + // Initialize the Service Repository (this will still work if + // user forgets to define an object of type ACE_Service_Config). + ACE_Service_Repository::instance (ACE_Service_Gestalt::MAX_SERVICES); + + // Initialize the ACE_Reactor (the ACE_Reactor should be the + // same size as the ACE_Service_Repository). + ACE_Reactor::instance (); + + // There's no point in dealing with this on NT since it doesn't + // really support signals very well... +#if !defined (ACE_LACKS_UNIX_SIGNALS) + // Only attempt to register a signal handler for positive + // signal numbers. + if (ACE_Service_Config::signum_ > 0) + { + ACE_Sig_Set ss; + ss.sig_add (ACE_Service_Config::signum_); + if ((ACE_Reactor::instance () != 0) && + (ACE_Reactor::instance ()->register_handler + (ss, ACE_Service_Config::signal_handler_) == -1)) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("can't register signal handler\n"))); + } +#endif /* ACE_LACKS_UNIX_SIGNALS */ + + return 0; +} + +/// Return the global configuration instance. Always returns the same +/// instance +ACE_Service_Config * +ACE_Service_Config::singleton (void) +{ + return ACE_SERVICE_CONFIG_SINGLETON::instance (); +} + +int +ACE_Service_Config::insert (ACE_Static_Svc_Descriptor* stsd) +{ + return ACE_Service_Config::instance ()->insert (stsd); +} + + +// Totally remove from the daemon by removing it from the +// ACE_Reactor, and unlinking it if necessary. +int +ACE_Service_Config::remove (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Config::remove"); + return ACE_Service_Repository::instance ()->remove (svc_name); +} + +// Suspend . Note that this will not unlink the service +// from the daemon if it was dynamically linked, it will mark it as +// being suspended in the Service Repository and call the +// member function on the appropriate . A service +// can be resumed later on by calling the method... + +int +ACE_Service_Config::suspend (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Config::suspend"); + return ACE_Service_Repository::instance ()->suspend (svc_name); +} + +// Resume a SVC_NAME that was previously suspended or has not yet +// been resumed (e.g., a static service). + +int +ACE_Service_Config::resume (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Config::resume"); + return ACE_Service_Repository::instance ()->resume (svc_name); +} + + +ACE_Service_Config::ACE_Service_Config (bool ignore_static_svcs, + size_t size, + int signum) +{ + ACE_TRACE ("ACE_Service_Config::ACE_Service_Config"); + + // TODO: Need to find a more customizable way of instantiating the + // gestalt but perhaps we should leave this out untill such + // customizations are identified. + ACE_Service_Gestalt* tmp = 0; + ACE_NEW_NORETURN (tmp, + ACE_Service_Gestalt (size, false, ignore_static_svcs)); + + this->is_opened_ = false; + this->instance_ = tmp; + this->threadkey_.set (tmp); + + ACE_Service_Config::signum_ = signum; +} + +ACE_Service_Config::ACE_Service_Config (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key) +{ + ACE_TRACE ("ACE_Service_Config::ACE_Service_Config"); + + // TODO: Need to find a more customizable way of instantiating the + // gestalt but perhaps we should leave this out untill such + // customizations are identified. + ACE_Service_Gestalt* tmp = 0; + ACE_NEW_NORETURN (tmp, + ACE_Service_Gestalt (ACE_Service_Repository::DEFAULT_SIZE, false)); + + this->is_opened_ = false; + this->instance_ = tmp; + this->threadkey_.set (tmp); + + if (this->open (program_name, + logger_key) == -1 && errno != ENOENT) + { + // Only print out an error if it wasn't the svc.conf file that was + // missing. + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) SC failed to open: %p\n"), + program_name)); + } +} + +/// Return the "global" configuration instance, for the current +/// thread. This may be the same as instance(), but on some occasions, +/// it may be a different one. For example, ACE_Service_Config_Guard +/// provides a way of temporarily replacing the "current" +/// configuration instance in the context of a thread. +ACE_Service_Gestalt* +ACE_Service_Config::current (void) +{ + void* temp = ACE_Service_Config::singleton()->threadkey_.get (); + if (temp == 0) { + + // The most likely reason is that the current thread was spawned + // by some native primitive, like pthreads or Windows API - not + // from ACE. This is perfectly legal for callers who are not, or + // do not need to be ACE-aware. Such callers must have no + // expectation that the pluggable, multi-context configuration + // support will work - they would always get the global context, + // because at this point there is no information what the "parent" + // thread's configuration context was. + + temp = global(); + singleton()->threadkey_.set (temp); + } + + return static_cast (temp); +} + +/// A mutator to set the "current" (TSS) gestalt instance. +void +ACE_Service_Config::current (ACE_Service_Gestalt* newcurrent) +{ + ACE_Service_Config::singleton()->threadkey_.set (newcurrent); +} + + + +#if (ACE_USES_CLASSIC_SVC_CONF == 0) +ACE_Service_Type * +ACE_Service_Config::create_service_type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *o, + ACE_DLL &dll, + int active) +{ + ACE_Service_Type *sp = 0; + ACE_NEW_RETURN (sp, + ACE_Service_Type (n, o, dll, active), + 0); + return sp; +} +#endif /* ACE_USES_CLASSIC_SVC_CONF == 0 */ + +ACE_Service_Type_Impl * +ACE_Service_Config::create_service_type_impl (const ACE_TCHAR *name, + int type, + void *symbol, + u_int flags, + ACE_Service_Object_Exterminator gobbler) +{ + ACE_Service_Type_Impl *stp = 0; + + // Note, the only place we need to put a case statement. This is + // also the place where we'd put the RTTI tests, if the compiler + // actually supported them! + + switch (type) + { + case ACE_Service_Type::SERVICE_OBJECT: + ACE_NEW_RETURN (stp, + ACE_Service_Object_Type ((ACE_Service_Object *) symbol, + name, flags, + gobbler), + 0); + break; + case ACE_Service_Type::MODULE: + ACE_NEW_RETURN (stp, + ACE_Module_Type (symbol, name, flags), + 0); + break; + case ACE_Service_Type::STREAM: + ACE_NEW_RETURN (stp, + ACE_Stream_Type (symbol, name, flags), + 0); + break; + default: + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("unknown case\n"))); + break; + } + return stp; + +} + + +// Signal handling API to trigger dynamic reconfiguration. +void +ACE_Service_Config::handle_signal (int sig, + siginfo_t *, + ucontext_t *) +{ +#if defined (ACE_NDEBUG) + ACE_UNUSED_ARG (sig); +#else /* ! ACE_NDEBUG */ + ACE_ASSERT (ACE_Service_Config::signum_ == sig); +#endif /* ! ACE_NDEBUG */ + + ACE_Service_Config::reconfig_occurred_ = 1; +} + +// Trigger reconfiguration to re-read configuration files. +void +ACE_Service_Config::reconfigure (void) +{ + ACE_TRACE ("ACE_Service_Config::reconfigure"); + + ACE_Service_Config::reconfig_occurred_ = 0; + + if (ACE::debug ()) + { +#if !defined (ACE_NLOGGING) + time_t t = ACE_OS::time (0); + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("beginning reconfiguration at %s"), + ACE_OS::ctime (&t))); +#endif /* ! ACE_NLOGGING */ + } + if (ACE_Service_Config::process_directives () == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("process_directives"))); +} + +// Tidy up and perform last rites on a terminating ACE_Service_Config. +int +ACE_Service_Config::close (void) +{ + ACE_Service_Config::singleton ()->instance_->close (); + + // Delete the service repository. All the objects inside the + // service repository should already have been finalized. + ACE_Service_Repository::close_singleton (); + + // Do away with the singleton ACE_Service_Config (calls dtor) + ACE_SERVICE_CONFIG_SINGLETON::close (); + + return 0; +} + + +int +ACE_Service_Config::fini_svcs (void) +{ + ACE_TRACE ("ACE_Service_Config::fini_svcs"); + + // Clear the LM_DEBUG bit from log messages if appropriate + if (ACE::debug ()) + ACE_Log_Msg::disable_debug_messages (); + + int result = 0; + if (ACE_Service_Repository::instance () != 0) + result = ACE_Service_Repository::instance ()->fini (); + + if (ACE::debug ()) + ACE_Log_Msg::enable_debug_messages (); + + return result; +} + +/// Perform user-specified close activities and remove dynamic memory. +ACE_Service_Config::~ACE_Service_Config (void) +{ + ACE_TRACE ("ACE_Service_Config::~ACE_Service_Config"); +} + +// ************************************************************ + +/* static */ +int +ACE_Service_Config::reconfig_occurred (void) +{ + ACE_TRACE ("ACE_Service_Config::reconfig_occurred"); + return ACE_Service_Config::reconfig_occurred_ != 0; +} + +void +ACE_Service_Config::reconfig_occurred (int config_occurred) +{ + ACE_TRACE ("ACE_Service_Config::reconfig_occurred"); + ACE_Service_Config::reconfig_occurred_ = + static_cast (config_occurred); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Config.h b/dep/acelite/ace/Service_Config.h new file mode 100644 index 000000000..3076a3bb5 --- /dev/null +++ b/dep/acelite/ace/Service_Config.h @@ -0,0 +1,748 @@ +// -*- C++ -*- + +//==================================================================== +/** + * @file Service_Config.h + * + * @author Douglas C. Schmidt + */ +//==================================================================== + +#ifndef ACE_SERVICE_CONFIG_H +#define ACE_SERVICE_CONFIG_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Default_Constants.h" +#include "ace/Intrusive_Auto_Ptr.h" +#include "ace/Service_Gestalt.h" +#include "ace/Synch_Traits.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_signal.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decl. +class ACE_Service_Object; +class ACE_Service_Type; +class ACE_Service_Type_Impl; +class ACE_Service_Repository; +class ACE_Sig_Adapter; +class ACE_Allocator; +class ACE_Reactor; +class ACE_Thread_Manager; +class ACE_DLL; + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) +#define ACE_STATIC_SERVICE_DIRECTIVE(ident, parameters) \ + ACE_TEXT ("static ") \ + ACE_TEXT (ident) \ + ACE_TEXT (" \"") \ + ACE_TEXT (parameters) \ + ACE_TEXT ("\"") +#define ACE_DYNAMIC_SERVICE_DIRECTIVE(ident, libpathname, objectclass, parameters) \ + ACE_TEXT ("dynamic ") \ + ACE_TEXT (ident) \ + ACE_TEXT (" Service_Object * ") \ + ACE_TEXT (libpathname) \ + ACE_TEXT (":") \ + ACE_TEXT (objectclass) \ + ACE_TEXT ("() \"") \ + ACE_TEXT (parameters) \ + ACE_TEXT ("\"") +#if defined (ACE_VERSIONED_SO) && (ACE_VERSIONED_SO == 2) +#define ACE_DYNAMIC_VERSIONED_SERVICE_DIRECTIVE(ident, libpathname, version, objectclass, parameters) \ + ACE_TEXT ("dynamic ") \ + ACE_TEXT (ident) \ + ACE_TEXT (" Service_Object * ") \ + ACE_DLL_PREFIX \ + ACE_TEXT (libpathname) \ + ACE_TEXT ("-") \ + ACE_TEXT (version) \ + ACE_DLL_SUFFIX \ + ACE_TEXT (":") \ + ACE_TEXT (objectclass) \ + ACE_TEXT ("() \"") \ + ACE_TEXT (parameters) \ + ACE_TEXT ("\"") +#else +#define ACE_DYNAMIC_VERSIONED_SERVICE_DIRECTIVE(ident, libpathname, version, objectclass, parameters) \ + ACE_TEXT ("dynamic ") \ + ACE_TEXT (ident) \ + ACE_TEXT (" Service_Object * ") \ + ACE_TEXT (libpathname) \ + ACE_TEXT (":") \ + ACE_TEXT (objectclass) \ + ACE_TEXT ("() \"") \ + ACE_TEXT (parameters) \ + ACE_TEXT ("\"") +#endif /* ACE_VERSIONED_SO */ +#define ACE_REMOVE_SERVICE_DIRECTIVE(ident) \ + ACE_TEXT ("remove ") \ + ACE_TEXT (ident) +class ACE_Svc_Conf_Param; +#else +#define ACE_STATIC_SERVICE_DIRECTIVE(ident, parameters) \ + ACE_TEXT ("") +#define ACE_DYNAMIC_SERVICE_DIRECTIVE(ident, libpathname, objectclass, parameters) \ + ACE_TEXT ("") \ + ACE_TEXT ("") +#if defined (ACE_VERSIONED_SO) && (ACE_VERSIONED_SO == 2) +#define ACE_DYNAMIC_VERSIONED_SERVICE_DIRECTIVE(ident, libpathname, version, objectclass, parameters) \ + ACE_TEXT ("") \ + ACE_TEXT ("") +#else +#define ACE_DYNAMIC_VERSIONED_SERVICE_DIRECTIVE(ident, libpathname, version, objectclass, parameters) \ + ACE_TEXT ("") \ + ACE_TEXT ("") +#endif +#define ACE_REMOVE_SERVICE_DIRECTIVE(ident) \ + ACE_TEXT ("") +class ACE_XML_Svc_Conf; +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +extern "C" +{ + typedef ACE_Service_Object *(*ACE_SERVICE_ALLOCATOR) (ACE_Service_Object_Exterminator *); +} + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Static_Svc_Descriptor + * + * @brief Holds the information necessary to describe a statically linked + * Svc. + */ +class ACE_Static_Svc_Descriptor +{ +public: + /// Name of the service. + const ACE_TCHAR *name_; + + /// Type of service. + int type_; + + /// Factory function that allocates the service. + ACE_SERVICE_ALLOCATOR alloc_; + + /// Bitmask flags indicating how the framework should delete memory. + u_int flags_; + + /// Flag indicating whether the service starts out active. + int active_; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +public: + /// Compare two service descriptors for equality. + bool operator== (ACE_Static_Svc_Descriptor &) const; + + /// Compare two service descriptors for inequality. + bool operator!= (ACE_Static_Svc_Descriptor &) const; +}; + + +/** + * @class ACE_Threading_Helper + * + * @brief Encapsulates responsibility for allocating, destroying and + * manipulating the value, associated with a thread-specific + * key. Relates to the ability of the created thread to inherit the + * parent thread's gestalt. Designed to be used as an instance member + * of @c ACE_Service_Config. + * + * Partial specialization over ACE_SYNCH_MUTEX is used to implement + * specific behavior in both multi- and single-threaded builds. + */ +template +class ACE_Threading_Helper +{ +}; + +/* + * Specialization for a multi threaded program + */ +template<> +class ACE_Export ACE_Threading_Helper +{ +public: + ACE_Threading_Helper (void); + ~ACE_Threading_Helper (void); + + void set (void*); + void* get (void); + +private: + /// Key for the thread-specific data, which is a simple pointer to + /// the thread's (currently-) global configuration context. + ACE_thread_key_t key_; +}; + +/* + * Specialization for a single threaded program + */ +template<> +class ACE_Export ACE_Threading_Helper +{ +public: + ACE_Threading_Helper (void); + ~ACE_Threading_Helper (void); + + void set (void*); + void* get (void); +}; + +#define ACE_Component_Config ACE_Service_Config + +/** + * @class ACE_Service_Config + * + * @brief Supplies common server operations for dynamic and static + * configuration of service. + * + * The ACE_Service_Config uses the Monostate pattern. Therefore, + * you can only have one of these instantiated per-process. It + * represents the process-wide collection of services, which is + * typically shared among all other configurable entities. The only + * ACE_Service_Config instance is registered with and owned by the + * ACE_Object_Manager. + * + * By contrast, the ACE_Service_Gestalt represents the collection + * of services, pertaining to a configurable entity. Typically, a + * "configurable entity" is an instance, which owns an instance of + * ACE_Service_Gestalt in order to ensure full control over the + * services it needs. + * + * Another facet of ACE_Service_Config is that for a given thread, + * it provides access to its current, process-global + * ACE_Service_Gestalt instance through its current() method. + * + * @note The signal_handler_ static member is allocated by the + * ACE_Object_Manager. The ACE_Service_Config constructor + * uses signal_handler_. Therefore, if the program has any + * static ACE_Service_Config objects, there might be + * initialization order problems. They can be minimized, but + * not eliminated, by _not_ #defining + * ACE_HAS_NONSTATIC_OBJECT_MANAGER. + */ +class ACE_Export ACE_Service_Config +{ + + /// The Instance, or the global (default) configuration context. + /// The monostate would forward the calls to that instance. The TSS + /// will point here + ACE_Intrusive_Auto_Ptr instance_; + + /// A helper instance to manage thread-specific key creation. + /// Dependent on the syncronization mutex ACE uses, the corresponding + /// partial template instantiation will perform the right services + /// that have to do with managing thread-specific storage. Note that, + /// for single-threaded builds they would do (next to) nothing. + ACE_Threading_Helper threadkey_; + +public: + + // = Initialization and termination methods. + + /** + * Initialize the Service Repository. Note that initialising @a + * signum to a negative number will prevent a signal handler being + * registered when the repository is opened. + */ + ACE_Service_Config (bool ignore_static_svcs = true, + size_t size = ACE_DEFAULT_SERVICE_REPOSITORY_SIZE, + int signum = SIGHUP); + + /** + * Performs an open without parsing command-line arguments. The + * @a logger_key indicates where to write the logging output, which + * is typically either a STREAM pipe or a socket address. + */ + ACE_Service_Config (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY); + + /// Perform user-specified close activities and remove dynamic + /// memory. + virtual ~ACE_Service_Config (void); + +private: + + /** + * Performs an open without parsing command-line arguments. + * Implements whats different in the opening sequence + * for this class, as opposed to the base class. + * + * The @a logger_key indicates where to write the logging output, which + * is typically either a STREAM pipe or a socket address. If + * @a ignore_default_svc_conf_file is non-0 then the "svc.conf" file + * will be ignored. If @a ignore_debug_flag is non-0 then the + * application is responsible for setting the + * @c ACE_Log_Msg::priority_mask() appropriately. Returns number of + * errors that occurred on failure and 0 otherwise. + */ + virtual int open_i (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf_file, + bool ignore_debug_flag); + + /** + * Implements whats different in the command line parameter processing + * for this class, as opposed to the base class. + */ + virtual int parse_args_i (int argc, ACE_TCHAR *argv[]); + + /// = Static interfaces + + public: + /** + * Returns the process-wide global singleton instance. It would + * have been created and will be managed by the Object Manager. + */ + static ACE_Service_Config* singleton (void); + + /** + * Mutator for the currently active configuration context instance + * (gestalt). Intended for use by helper classes like @see + * ACE_Service_Config_Guard. Stack-based instances can be used to + * temporarily change which gestalt is seen as global by static + * initializers (especially those in DLLs loaded at run-time). + */ + static void current (ACE_Service_Gestalt*); + + /** + * Accessor for the "current" service gestalt + */ + static ACE_Service_Gestalt* current (void); + + /** + * This is what the static service initializators are hard-wired to + * use, so in order to avoid interface changes this method merely + * forwards to @c ACE_Service_Config::current. This enables us to + * enforce which Service Gestalt is used for services registering + * through static initializers. Especially important for DLL-based + * dynamic services, which can contain their own static services and + * static initializers. + * + * @deprecated Use current() instead. + */ + static ACE_Service_Gestalt* instance (void); + + /** + * Returns a process-wide global singleton instance in contrast with + * current (), which may return a different instance at different + * times, dependent on the context. Modifying this method's return + * value is strongly discouraged as it will circumvent the mechanism + * for dynamically loading services. If you must, use with extreme + * caution! + */ + static ACE_Service_Gestalt* global (void); + + /** + * Performs an open without parsing command-line arguments. The + * @a logger_key indicates where to write the logging output, which + * is typically either a STREAM pipe or a socket address. If + * @a ignore_static_svcs is true then static services are not loaded, + * otherwise, they are loaded. If @a ignore_default_svc_conf_file is + * non-0 then the configuration file will be ignored. + * Returns zero upon success, -1 if the file is not found or cannot + * be opened (errno is set accordingly), otherwise returns the + * number of errors encountered loading the services in the + * specified svc.conf configuration file. If @a ignore_debug_flag is + * non-0 then the application is responsible for setting the + * @c ACE_Log_Msg::priority_mask appropriately. + */ + static int open (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY, + bool ignore_static_svcs = true, + bool ignore_default_svc_conf_file = false, + bool ignore_debug_flag = false); + + /** + * This is the primary entry point into the ACE_Service_Config (the + * constructor just handles simple initializations). It parses + * arguments passed in from @a argc and @a argv parameters. The + * arguments that are valid in a call to this method include: + * + * - '-b' Option to indicate that we should be a daemon. Note that when + * this option is used, the process will be daemonized before the + * service configuration file(s) are read. During daemonization, + * (on POSIX systems) the current directory will be changed to "/" + * so the caller should either fully specify the file names, or + * execute a @c chroot() to the appropriate directory. + * @sa ACE::daemonize(). + * - '-d' Turn on debugging mode + * - '-f' Specifies a configuration file name other than the default + * svc.conf. Can be specified multiple times to use multiple files. + * If any configuration file is provided with this option then + * the default svc.conf will be ignored. + * - '-k' Specifies the rendezvous point to use for the ACE distributed + * logger. + * - '-y' Explicitly enables the use of static services. This flag + * overrides the @a ignore_static_svcs parameter value. + * - '-n' Explicitly disables the use of static services. This flag + * overrides the @a ignore_static_svcs parameter value. + * - '-p' Specifies a pathname which is used to store the process id. + * - '-s' Specifies a signal number other than SIGHUP to trigger reprocessing + * of the configuration file(s). Ignored for platforms that do not + * have POSIX signals, such as Windows. + * - '-S' Specifies a service directive string. Enclose the string in quotes + * and escape any embedded quotes with a backslash. This option + * specifies service directives without the need for a configuration + * file. Can be specified multiple times. + * + * Note: Options '-f' and '-S' complement each other. Directives from files + * and from '-S' option are processed together in the following order. First, + * all files are processed in the order they are specified in @a argv + * parameter. Second, all directive strings are executed in the order the + * directives appear in @a argv parameter. + * + * @param argc The number of commandline arguments. + * @param argv The array with commandline arguments + * @param logger_key Indicates where to write the logging output, + * which is typically either a STREAM pipe or a + * socket address. + * @param ignore_static_svcs If true then static services are not loaded, + * otherwise, they are loaded. + * @param ignore_default_svc_conf_file If non-0 then the @c svc.conf + * configuration file will be ignored. + * @param ignore_debug_flag If true then the application is responsible + * for setting the @c ACE_Log_Msg::priority_mask + * appropriately. + * + * @retval -1 The configuration file is not found or cannot + * be opened (errno is set accordingly). + * @retval 0 Success. + * @retval >0 The number of errors encountered while processing + * the service configuration file(s). + */ + static int open (int argc, + ACE_TCHAR *argv[], + const ACE_TCHAR *logger_key = ACE_DEFAULT_LOGGER_KEY, + bool ignore_static_svcs = true, + bool ignore_default_svc_conf_file = false, + bool ignore_debug_flag = false); + + /// Tidy up and perform last rites when ACE_Service_Config is shut + /// down. This method calls close_svcs(). Returns 0. + static int close (void); + + /// Perform user-specified close hooks and possibly delete all of the + /// configured services in the . + static int fini_svcs (void); + + /// True if reconfiguration occurred. + static int reconfig_occurred (void); + + /// Indicate that reconfiguration occurred. + static void reconfig_occurred (int); + + /// Perform the reconfiguration process. + static void reconfigure (void); + + // = The following methods are static in order to enforce Singleton + // semantics for the Reactor, Service_Repository, Thread_Manager, + // and Acceptor/Connector Strategy factory. Other portions of the + // system may need to access them at some point or another... + + // = This is not strictly needed, anymore since the service configurator + // has been refactored to allow multiple service configuration + // instances (called gestalts). The interfaces, however were retained in for + // the sake of maintaining source-code compatibility. + + + // = Accessors and mutators for process-wide Singletons. + + /// Returns a pointer to the list of statically linked services. + /// + /// @deprecated - Same as instance(), but still useful in legacy code, + /// (notably, one that can not be easily modified) which uses the following + /// idiom for registering static services: + /// + /// ACE_Service_Config::static_svcs ()->insert (...); + static ACE_Service_Gestalt* static_svcs (void); + + /// Insert a static service descriptor for processing on open_i(). The + /// corresponding ACE_STATIC_SVC_* macros were chaged to use this method + /// instead of obtaining a ptr to a container. See the note on static_svcs(). + /// Added to prevent exposing the internal storage representation of the + /// services repository and provide a better way of debugging service + /// loading and registration problems. + static int insert (ACE_Static_Svc_Descriptor *svc); + + // = Utility methods. + /// Dynamically link the shared object file and retrieve a pointer to + /// the designated shared object in this file. + static int initialize (const ACE_Service_Type *, + const ACE_TCHAR *parameters); + + /// Initialize and activate a statically @a svc_name service. + static int initialize (const ACE_TCHAR *svc_name, + const ACE_TCHAR *parameters); + + /// Resume a @a svc_name that was previously suspended or has not yet + /// been resumed (e.g., a static service). + static int resume (const ACE_TCHAR svc_name[]); + + /** + * Suspend @a svc_name. Note that this will not unlink the service + * from the daemon if it was dynamically linked, it will mark it as + * being suspended in the Service Repository and call the + * member function on the appropriate ACE_Service_Object. A + * service can be resumed later on by calling the member + * function... + */ + static int suspend (const ACE_TCHAR svc_name[]); + + /// Totally remove @a svc_name from the daemon by removing it + /// from the ACE_Reactor, and unlinking it if necessary. + static int remove (const ACE_TCHAR svc_name[]); + +#if defined (ACE_HAS_WINCE) && defined (ACE_USES_WCHAR) + // We must provide these function to bridge the Svc_Conf parser + // with ACE. + static int initialize (const ACE_Service_Type *, ACE_ANTI_TCHAR []); + static int initialize (const char svc_name[], ACE_ANTI_TCHAR parameters[]); + static int resume (const ACE_ANTI_TCHAR svc_name[]); + static int suspend (const ACE_ANTI_TCHAR svc_name[]); + static int remove (const ACE_ANTI_TCHAR svc_name[]); +#endif /* ACE_HAS_WINCE */ + + /// Dump the state of an object. + void dump (void) const; + + /// Set the signal_handler;for internal use by ACE_Object_Manager only. + static ACE_INLINE void signal_handler (ACE_Sig_Adapter *); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Process a file containing a list of service configuration + /// directives. + static int process_file (const ACE_TCHAR file[]); + + /// Process one service configuration @a directive, which is passed as + /// a string. Returns the number of errors that occurred. + static int process_directive (const ACE_TCHAR directive[]); + + /** + * Process one static service definition. Load a new static service + * into the ACE_Service_Repository. + * + * @param ssd Service descriptor, see the document of + * ACE_Static_Svc_Descriptor for more details. + * + * @param force_replace If set the new service descriptor replaces + * any previous instance in the ACE_Service_Repository. + * + * @return Returns -1 if the service cannot be 'loaded'. + */ + static int process_directive (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace = false); + + /** + * Process (or re-process) service configuration requests that are + * provided in the svc.conf file(s). Returns the number of errors + * that occurred. + */ + static int process_directives (void); + + /// Handles signals to trigger reconfigurations. + static void handle_signal (int sig, siginfo_t *, ucontext_t *); + + /** + * Handle the command-line options intended for the + * ACE_Service_Config. Note that @c argv[0] is assumed to be the + * program name. + * The arguments that are valid in a call to this method are + * - '-b' Option to indicate that we should be a daemon + * - '-d' Turn on debugging mode + * - '-f' Option to read in the list of svc.conf file names + * - '-k' Option to read a wide string where in the logger output can + * be written + * - '-y' Turn on the flag for a repository of statically + * linked services + * - '-n' Need not have a repository of statically linked services + * - '-S' Option to read in the list of services on the command-line + * Please observe the difference between options '-f' that looks + * for a list of files and here a list of services. + */ + static int parse_args (int, ACE_TCHAR *argv[]); + +#if (ACE_USES_CLASSIC_SVC_CONF == 0) + static ACE_Service_Type *create_service_type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *o, + ACE_DLL &dll, + int active); +#endif /* ACE_USES_CLASSIC_SVC_CONF == 0 */ + + static ACE_Service_Type_Impl * + create_service_type_impl (const ACE_TCHAR *name, + int type, + void *symbol, + u_int flags, + ACE_Service_Object_Exterminator gobbler); + + /// @deprecated + /// Process service configuration requests that were provided on the + /// command-line. Returns the number of errors that occurred. + static int process_commandline_directives (void); + + /// Become a daemon. + static int start_daemon (void); + + // @deprecated + // Add the default statically-linked services to the + // ACE_Service_Repository. + static int load_static_svcs (void); + +protected: + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + /// @deprecated + /// This is the implementation function that process_directives() + /// and process_directive() both call. Returns the number of errors + /// that occurred. + static int process_directives_i (ACE_Svc_Conf_Param *param); +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + + + // = Process-wide state. + +private: + + /// Have we called ACE_Service_Config::open() yet? + bool is_opened_; + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + /// Synchronization variable for open, etc. + mutable ACE_SYNCH_MUTEX lock_; +#endif /* ACE_MT_SAFE */ + + /// True if reconfiguration occurred. + static sig_atomic_t reconfig_occurred_; + + // = Set by command-line options. + /// Shall we become a daemon process? + static bool be_a_daemon_; + + /// Pathname of file to write process id. + static ACE_TCHAR *pid_file_name_; + + /// Number of the signal used to trigger reconfiguration. + static int signum_; + + /// Handles the reconfiguration signals. + static ACE_Sig_Adapter *signal_handler_; + + /// Pointer to the Singleton (ACE_Cleanup) Gestalt instance. + /// There is thread-specific global instance pointer, which is used to + /// temporarily change which Gestalt instance is used for static service + /// registrations. + /// + /// A specific use case is a thread, which loads a _dynamic_ service from + /// a DLL. If the said DLL also contains additional _static_ services, + /// those *must* be registered with the same configuration repository as + /// the dynamic service. Otherwise, the DLL's static services would be + /// registered with the global Gestalt and may outlive the DLL that + /// contains their code and perhaps the memory in which they are in. + /// This is a problem because if the DLL gets unloaded (as it will, if + /// it was loaded in an instance of Gestalt), the DLL's memory will be + /// deallocated, but the global service repository will still "think" + /// it must finalize the (DLL's) static services - with disastrous + /// consequences, occurring in the post-main code (at_exit()). + + /// This class needs the intimate access to be able to swap the + /// current TSS pointer for the global Gestalt. + friend class ACE_Service_Config_Guard; + + /// The helper needs intimate access (when building with no threads) + friend class ACE_Threading_Helper ; + friend class ACE_Threading_Helper ; +}; + +/** + * @class ACE_Service_Config_Guard + * + * @brief A guard class, designed to be instantiated on the stack. + * + * Instantiating it with a specific configuration ensures any references to + * ACE_Service_Config::instance(), even when occurring in static constructors, + * will allways access the designated configuration instance. + * This comes very handy when a dynamic service also registers any static + * services of its own and their static factories. + */ +class ACE_Export ACE_Service_Config_Guard +{ +public: + ACE_Service_Config_Guard (ACE_Service_Gestalt* psg); + ~ACE_Service_Config_Guard (void); + +private: + // Private AND not implemented to disable copying + ACE_Service_Config_Guard(const ACE_Service_Config_Guard&); + ACE_Service_Config_Guard& operator= (const ACE_Service_Config_Guard&); + +private: + ACE_Intrusive_Auto_Ptr saved_; +}; + + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Service_Config.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_SERVICE_CONFIG_H */ diff --git a/dep/acelite/ace/Service_Config.inl b/dep/acelite/ace/Service_Config.inl new file mode 100644 index 000000000..5cffe4344 --- /dev/null +++ b/dep/acelite/ace/Service_Config.inl @@ -0,0 +1,205 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// This is the primary entry point into the ACE_Service_Config (the +// constructor just handles simple initializations). +ACE_INLINE int +ACE_Service_Config::open (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf, + bool ignore_debug_flag) +{ + ACE_TRACE ("ACE_Service_Config::open"); + if (singleton()->open_i (program_name, + logger_key, + ignore_static_svcs, + ignore_default_svc_conf, + ignore_debug_flag) == -1) + return -1; + + return current()->open (program_name, + logger_key, + ignore_static_svcs, + ignore_default_svc_conf, + ignore_debug_flag); +} + + +ACE_INLINE int +ACE_Service_Config::open (int argc, + ACE_TCHAR *argv[], + const ACE_TCHAR *logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf, + bool ignore_debug_flag) +{ + ACE_TRACE ("ACE_Service_Config::open"); + + if (singleton()->parse_args_i(argc, argv) == -1) + return -1; + + if (singleton()->open_i (argv[0], + logger_key, + ignore_static_svcs, + ignore_default_svc_conf, + ignore_debug_flag) == -1) + return -1; + + return current()->open (argc, + argv, + logger_key, + ignore_static_svcs, + ignore_default_svc_conf, + ignore_debug_flag); +} + +// Handle the command-line options intended for the +// ACE_Service_Config. +ACE_INLINE int +ACE_Service_Config::parse_args (int argc, ACE_TCHAR *argv[]) +{ + return ACE_Service_Config::current ()->parse_args (argc, argv); +} + +/// Return the global configuration instance. Allways returns the same +/// instance +ACE_INLINE ACE_Service_Gestalt * +ACE_Service_Config::global (void) +{ + return ACE_Service_Config::singleton()->instance_.get (); +} + +/// Return the configuration instance, considered "global" in the +/// current thread. This may be the same as instance(), but on some +/// occasions, it may be a different one. For example, +/// ACE_Service_Config_Guard provides a way of temporarily replacing +/// the "current" configuration instance in the context of a thread. +ACE_INLINE ACE_Service_Gestalt * +ACE_Service_Config::instance (void) +{ + return ACE_Service_Config::current (); +} + +// This method has changed to return the gestalt instead of the +// container, underlying the service repository and defined +// ACE_Service_Gestalt::insert (ACE_Static_Svc_Descriptor*). This way +// the existing source code can keep using +// ACE_Service_Config::static_svcs(), however now it is not necessary +// to expose the repository storage *and* it is much easier to debug +// service registration problems. + +ACE_INLINE ACE_Service_Gestalt* +ACE_Service_Config::static_svcs (void) +{ + return ACE_Service_Config::current (); +} + +/// Compare two service descriptors for equality. +ACE_INLINE bool +ACE_Static_Svc_Descriptor::operator== (ACE_Static_Svc_Descriptor &d) const +{ + return ACE_OS::strcmp (name_, d.name_) == 0; +} + +/// Compare two service descriptors for inequality. +ACE_INLINE bool +ACE_Static_Svc_Descriptor::operator!= (ACE_Static_Svc_Descriptor &d) const +{ + return !(*this == d); +} + +ACE_INLINE void +ACE_Service_Config::signal_handler (ACE_Sig_Adapter *signal_handler) +{ + signal_handler_ = signal_handler; +} + +/// Initialize and activate a statically linked service. +ACE_INLINE int +ACE_Service_Config::initialize (const ACE_TCHAR *svc_name, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Config::initialize"); + return ACE_Service_Config::current ()->initialize (svc_name, + parameters); +} + +/// Dynamically link the shared object file and retrieve a pointer to +/// the designated shared object in this file. +ACE_INLINE int +ACE_Service_Config::initialize (const ACE_Service_Type *sr, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Config::initialize"); + return ACE_Service_Config::current ()->initialize (sr, parameters); +} + +/// Process a file containing a list of service configuration +/// directives. +ACE_INLINE int ACE_Service_Config::process_file (const ACE_TCHAR file[]) +{ + return ACE_Service_Config::current ()->process_file (file); +} + +/// +ACE_INLINE int +ACE_Service_Config::process_directive (const ACE_TCHAR directive[]) +{ + return ACE_Service_Config::current ()->process_directive (directive); +} + +/// Process service configuration requests as indicated in the queue of +/// svc.conf files. +ACE_INLINE int +ACE_Service_Config::process_directives (void) +{ + return ACE_Service_Config::current ()->process_directives (false); +} + +ACE_INLINE int +ACE_Service_Config::process_directive (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace) +{ + return ACE_Service_Config::current ()->process_directive (ssd, force_replace); +} + + +#if defined (ACE_HAS_WINCE) && defined (ACE_USES_WCHAR) +// We must provide these function to bridge Svc_Conf parser with ACE. + +ACE_INLINE int +ACE_Service_Config::initialize (const ACE_Service_Type *sp, ACE_ANTI_TCHAR parameters[]) +{ + return ACE_Service_Config::initialize (sp, ACE_TEXT_ANTI_TO_TCHAR (parameters)); +} + +ACE_INLINE int +ACE_Service_Config::initialize (const ACE_ANTI_TCHAR svc_name[], ACE_ANTI_TCHAR parameters[]) +{ + return ACE_Service_Config::initialize (ACE_TEXT_ANTI_TO_TCHAR (svc_name), + ACE_TEXT_ANTI_TO_TCHAR (parameters)); +} + +ACE_INLINE int +ACE_Service_Config::resume (const ACE_ANTI_TCHAR svc_name[]) +{ + return ACE_Service_Config::resume (ACE_TEXT_ANTI_TO_TCHAR (svc_name)); +} + +ACE_INLINE int +ACE_Service_Config::suspend (const ACE_ANTI_TCHAR svc_name[]) +{ + return ACE_Service_Config::suspend (ACE_TEXT_ANTI_TO_TCHAR (svc_name)); +} + +ACE_INLINE int +ACE_Service_Config::remove (const ACE_ANTI_TCHAR svc_name[]) +{ + return ACE_Service_Config::remove (ACE_TEXT_ANTI_TO_TCHAR (svc_name)); +} +#endif /* ACE_HAS_WINCE && !ACE_USES_WCHAR */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Gestalt.cpp b/dep/acelite/ace/Service_Gestalt.cpp new file mode 100644 index 000000000..6bc653bf2 --- /dev/null +++ b/dep/acelite/ace/Service_Gestalt.cpp @@ -0,0 +1,1335 @@ +#include "ace/Svc_Conf.h" +#include "ace/Get_Opt.h" +#include "ace/ARGV.h" +#include "ace/Malloc.h" +#include "ace/Service_Manager.h" +#include "ace/Service_Types.h" +#include "ace/Containers.h" +#include "ace/Auto_Ptr.h" +#include "ace/Reactor.h" +#include "ace/Thread_Manager.h" +#include "ace/DLL.h" +#include "ace/XML_Svc_Conf.h" +#include "ace/SString.h" + +#ifndef ACE_LACKS_UNIX_SIGNALS +# include "ace/Signal.h" +#endif /* !ACE_LACKS_UNIX_SIGNALS */ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_time.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_sys_stat.h" + +#include "ace/TSS_T.h" +#include "ace/Service_Gestalt.h" + +#include "ace/Svc_Conf_Param.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Service_Type_Dynamic_Guard::ACE_Service_Type_Dynamic_Guard + (ACE_Service_Repository &r, const ACE_TCHAR *name) + : repo_ (r) + // Relocation starts where the next service will be inserted (if any) + , repo_begin_ (r.current_size ()) + , name_ (name) +# if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + // On this thread (for the duration of the initialize() method), + // we're about to do two things that require locking: (1) fiddle + // with the repository and (2) load a DLL and hence lock the + // DLL_Manager. + // + // Now if we don't lock the repo here, it is possible that two + // threads may deadlock on initialization because they can acquire + // locks (1) and (2) in different order, for instance: + // + // T1: loads a DLL (2) and registers a service (1); + // + // T2: may be relocating a service (1), which could lead to a + // (re)opening or uping the ref count on a DLL (2); + // + // To prevent this, we lock the repo here, using the repo_monitor_ + // member guard. + , repo_monitor_ (r.lock_) +#endif +{ + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) STDG::, repo=%@") + ACE_TEXT(", name=%s - beginning at [%d]\n"), + &this->repo_, + this->name_, + this->repo_begin_)); + + ACE_ASSERT (this->name_ != 0); // No name? +} + + +/// Destructor +ACE_Service_Type_Dynamic_Guard::~ACE_Service_Type_Dynamic_Guard (void) +{ + const ACE_Service_Type *tmp = 0; + + // Lookup without ignoring suspended services. Making sure + // not to ignore any inactive services, since those may be forward + // declarations + size_t slot = 0; + int const ret = this->repo_.find_i (this->name_, slot, &tmp, false); + + // We inserted it (as inactive), so we expect to find it, right? + if ((ret < 0 && ret != -2) || tmp == 0) + { + if (ACE::debug ()) + ACELIB_ERROR ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) STDG:: - Failed (%d) to find %s -> %@\n"), + ret, this->name_, tmp)); + return; + } + + if (tmp->type () != 0) + { + // Something has registered a proper (non-forward-decl) service with + // the same name as our dummy. + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) STDG::, repo=%@ [%d], ") + ACE_TEXT ("name=%s - updating dependents [%d - %d)\n"), + &this->repo_, + slot, + this->name_, + this->repo_begin_, + this->repo_.current_size ())); + + // Relocate any services inserted since we were created. + // Any (static, i.e. DLL = 0) services registered in + // the context of this guard aren't really static because + // their code belongs in the DLL's code segment + this->repo_.relocate_i (this->repo_begin_, this->repo_.current_size (), tmp->dll()); + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) STDG::, repo=%@ [%d], ") + ACE_TEXT ("name=%s - loaded (type=%@, impl=%@, object=%@, active=%d)\n"), + &this->repo_, + slot, + this->name_, + tmp, + tmp->type (), + tmp->type ()->object (), + tmp->active ())); + } +} + + + +// ---------------------------------------- + +ACE_Service_Gestalt::Processed_Static_Svc:: +Processed_Static_Svc (const ACE_Static_Svc_Descriptor *assd) + :name_(0), + assd_(assd) +{ +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_ALLOCATOR_NORETURN (name_, static_cast(ACE_Allocator::instance()->malloc (sizeof(ACE_TCHAR) * (ACE_OS::strlen(assd->name_)+1)))); +#else + ACE_NEW_NORETURN (name_, ACE_TCHAR[ACE_OS::strlen(assd->name_)+1]); +#endif /* ACE_HAS_ALLOC_HOOKS */ + ACE_OS::strcpy(name_,assd->name_); +} + +ACE_Service_Gestalt::Processed_Static_Svc::~Processed_Static_Svc (void) +{ +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(name_); +#else + delete [] name_; +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Gestalt::Processed_Static_Svc) + +void +ACE_Service_Gestalt::intrusive_add_ref (ACE_Service_Gestalt* g) +{ + if (g != 0) + { + ++g->refcnt_; + ACE_ASSERT (g->refcnt_ > 0); + } +} + +void +ACE_Service_Gestalt::intrusive_remove_ref (ACE_Service_Gestalt* g) +{ + if (g != 0) + { + long tmp = --g->refcnt_; + if (tmp <= 0) delete g; + ACE_ASSERT (tmp >= 0); + } +} + + +ACE_Service_Gestalt::~ACE_Service_Gestalt (void) +{ + + if (this->svc_repo_is_owned_) + delete this->repo_; + + this->repo_ =0; + + delete this->static_svcs_; + this->static_svcs_ = 0; + + // Delete the dynamically allocated static_svcs instance. +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::~SG - this=%@, pss = %@\n"), + this, this->processed_static_svcs_)); +#endif + + if (this->processed_static_svcs_ && + !this->processed_static_svcs_->is_empty()) + { + Processed_Static_Svc **pss = 0; + for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_); + iter.next (pss) != 0; + iter.advance ()) + { + delete *pss; + } + } + + delete this->processed_static_svcs_; + this->processed_static_svcs_ = 0; + + delete this->svc_conf_file_queue_; + this->svc_conf_file_queue_ = 0; + + delete this->svc_queue_; + this->svc_queue_ = 0; +} + +ACE_Service_Gestalt::ACE_Service_Gestalt (size_t size, + bool svc_repo_is_owned, + bool no_static_svcs) + : svc_repo_is_owned_ (svc_repo_is_owned) + , svc_repo_size_ (size) + , is_opened_ (0) + , logger_key_ (ACE_DEFAULT_LOGGER_KEY) + , no_static_svcs_ (no_static_svcs) + , svc_queue_ (0) + , svc_conf_file_queue_ (0) + , repo_ (0) + , static_svcs_ (0) + , processed_static_svcs_ (0) + , refcnt_ (0) +{ + (void)this->init_i (); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::ctor - this = %@, pss = %@\n"), + this, this->processed_static_svcs_)); +#endif +} + +/// Performs the common initialization tasks for a new or previously +/// closed instance. Must not be virtual, as it is also called from +/// the constructor. +int +ACE_Service_Gestalt::init_i (void) +{ + // Only initialize the repo_ if (a) we are being constructed, or; + // (b) we're being open()-ed, perhaps after previously having been + // close()-ed. In both cases: repo_ == 0 and we need a repository. + if (this->repo_ == 0) + { + if (this->svc_repo_is_owned_) + { + ACE_NEW_RETURN (this->repo_, + ACE_Service_Repository (this->svc_repo_size_), + -1); + } + else + { + this->repo_ = + ACE_Service_Repository::instance (this->svc_repo_size_); + } + } + + if (init_svc_conf_file_queue () == -1) + return -1; + + return 0; +} + + +/// Add the default statically-linked services to the Service +/// Repository. +int +ACE_Service_Gestalt::load_static_svcs (void) +{ + ACE_TRACE ("ACE_Service_Gestalt::load_static_svcs"); + + if (this->static_svcs_ == 0) + return 0; // Nothing to do + + ACE_Static_Svc_Descriptor **ssdp = 0; + for (ACE_STATIC_SVCS_ITERATOR iter (*this->static_svcs_); + iter.next (ssdp) != 0; + iter.advance ()) + { + ACE_Static_Svc_Descriptor *ssd = *ssdp; + + if (this->process_directive (*ssd, 1) == -1) + return -1; + } + return 0; + +} /* load_static_svcs () */ + + + +/// Find a static service descriptor by name +int +ACE_Service_Gestalt::find_static_svc_descriptor (const ACE_TCHAR* name, + ACE_Static_Svc_Descriptor **ssd) const +{ + ACE_TRACE ("ACE_Service_Gestalt::find_static_svc_descriptor"); + + if (this->static_svcs_ == 0) + return -1; + + ACE_Static_Svc_Descriptor **ssdp = 0; + for (ACE_STATIC_SVCS_ITERATOR iter ( *this->static_svcs_); + iter.next (ssdp) != 0; + iter.advance ()) + { + if (ACE_OS::strcmp ((*ssdp)->name_, name) == 0) + { + if (ssd != 0) + *ssd = *ssdp; + + return 0; + } + } + + return -1; +} + +/// @brief +const ACE_Static_Svc_Descriptor* +ACE_Service_Gestalt::find_processed_static_svc (const ACE_TCHAR* name) +{ + if (this->processed_static_svcs_ == 0 || name == 0) + return 0; + + Processed_Static_Svc **pss = 0; + for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_); + iter.next (pss) != 0; + iter.advance ()) + { + if (ACE_OS::strcmp ((*pss)->name_, name) == 0) + return (*pss)->assd_; + } + return 0; +} + + + +/// @brief Captures a list of the direcives processed (explicitely) for this +/// Gestalt so that services can be replicated in other repositories +/// upon their first initialization. +/// +/// This is part of the mechanism ensuring distinct local instances +/// for static service objects, loaded in another repository. +void +ACE_Service_Gestalt::add_processed_static_svc + (const ACE_Static_Svc_Descriptor *assd) +{ + + /// When process_directive(Static_Svc_Descriptor&) is called, it + /// associates a service object with the Gestalt and makes the + /// resource (a Service Object) local to the repository. This is but + /// the first step in using such SO. The next is the + /// "initialization" step. It is typically done through a "static" + /// service configuration directive. + /// + /// In contrast a "dynamic" directive, when processed through the + /// overloaded process_directives(string) both creates the SO + /// locally and initializes it, where the statics directive must + /// first locate the SO and then calls the init() method. This means + /// that durig the "static" initialization there's no specific + /// information about the hosting repository and the gestalt must + /// employ some lookup strategy to find it elsewhere. + + if (this->processed_static_svcs_ == 0) + ACE_NEW (this->processed_static_svcs_, + ACE_PROCESSED_STATIC_SVCS); + + Processed_Static_Svc **pss = 0; + for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_); + iter.next (pss) != 0; + iter.advance ()) + { + if (ACE_OS::strcmp ((*pss)->name_, assd->name_) == 0) + { + (*pss)->assd_ = assd; + return; + } + } + Processed_Static_Svc *tmp = 0; + ACE_NEW (tmp,Processed_Static_Svc(assd)); + this->processed_static_svcs_->insert(tmp); + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::add_processed_static_svc, ") + ACE_TEXT ("repo=%@ - %s\n"), + this->repo_, + assd->name_)); +} + + +/// Queues a static service object descriptor which, during open() +/// will be given to process_directive() to create the Service +/// Object. Normally, only called from static initializers, prior to +/// calling open() but loading a service from a DLL can cause it too. + +int +ACE_Service_Gestalt::insert (ACE_Static_Svc_Descriptor *stsd) +{ + if (this->static_svcs_ == 0) + ACE_NEW_RETURN (this->static_svcs_, + ACE_STATIC_SVCS, + -1); + + return this->static_svcs_->insert (stsd); +} + + +ACE_ALLOC_HOOK_DEFINE (ACE_Service_Gestalt) + + +void +ACE_Service_Gestalt::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Gestalt::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Service_Gestalt::initialize (const ACE_TCHAR *svc_name, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Gestalt_Base::initialize (repo)"); + ACE_ARGV args (parameters); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::initialize - () repo=%@, ") + ACE_TEXT ("looking up static ") + ACE_TEXT ("service \'%s\' to initialize\n"), + this->repo_, + svc_name)); + } +#endif + + const ACE_Service_Type *srp = 0; + for (int i = 0; this->find (svc_name, &srp) == -1 && i < 2; i++) + // if (this->repo_->find (svc_name, &srp) == -1) + { + const ACE_Static_Svc_Descriptor *assd = + ACE_Service_Config::global()->find_processed_static_svc(svc_name); + if (assd != 0) + { + this->process_directive_i(*assd, 0); + } + else + { + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'") + ACE_TEXT (" was not located.\n"), + svc_name), + -1); + } + } + if (srp == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - service \'%s\'") + ACE_TEXT (" was not located.\n"), + svc_name), + -1); + + /// If initialization fails ... + if (srp->type ()->init (args.argc (), + args.argv ()) == -1) + { + // ... report and remove this entry. + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) ERROR: SG::initialize - static init of \'%s\'") + ACE_TEXT (" failed (%p)\n"), + svc_name, ACE_TEXT ("error"))); + this->repo_->remove (svc_name); + return -1; + } + + // If everything is ok, activate it + const_cast(srp)->active (1); + return 0; +} + + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) +int +ACE_Service_Gestalt::initialize (const ACE_Service_Type_Factory *stf, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Gestalt::initialize"); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s") + ACE_TEXT (" - looking up in the repo\n"), + this->repo_, + stf->name ())); +#endif + + ACE_Service_Type *srp = 0; + int const retv = this->repo_->find (stf->name (), + (const ACE_Service_Type **) &srp); + + // If there is an active service already, remove it first + // before it can be re-installed. + if (retv >= 0) + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,") + ACE_TEXT (" name=%s - removing a pre-existing namesake.\n"), + this->repo_, + stf->name ())); +#endif + this->repo_->remove (stf->name ()); + } + + // If there is an inactive service by that name it may have been + // either inactivated, or just a forward declaration for a service, + // that is in the process of being initialized. If it is the latter, + // then we have detected an attempt to initialize the same dynamic + // service while still processing previous attempt. This can lock up + // the process, because the ACE_DLL_Manager::open () is not + // re-entrant - it uses a Singleton lock to serialize concurent + // invocations. This use case must be handled here, because if the + // DLL_Manager was re-entrant we would have entered an infinite + // recursion here. + if (retv == -2 && srp->type () == 0) + ACELIB_ERROR_RETURN ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@,") + ACE_TEXT (" name=%s - forward-declared; ") + ACE_TEXT (" recursive initialization requests are") + ACE_TEXT (" ignored.\n"), + this->repo_, + stf->name ()), + -1); + + // Reserve a spot for the dynamic service by inserting an incomplete + // service declaration, i.e. one that can not produce a service + // object if asked (a forward declaration). This declaration + // ensures maintaining the proper partial ordering of the services + // with respect to their finalization. For example, dependent static + // services must be registered *after* the dynamic service that + // loads them, so that their finalization is complete *before* + // finalizing the dynamic service. + ACE_Service_Type_Dynamic_Guard dummy (*this->repo_, + stf->name ()); + + // make_service_type() is doing the dynamic loading and also runs + // any static initializers + ACE_Auto_Ptr tmp (stf->make_service_type (this)); + + if (tmp.get () != 0 && + this->initialize_i (tmp.get (), parameters) == 0) + { + // All good. Tthe ACE_Service_Type instance is now owned by the + // repository and we should make sure it is not destroyed upon + // exit from this method. + tmp.release (); + return 0; + } + + return -1; +} +#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */ + + +/// Dynamically link the shared object file and retrieve a pointer to +/// the designated shared object in this file. +/// @note This is obsolete (and error-prone) in the presense of dynamic +/// services with their own static services. This method will allow those +/// static services to register *before* the dynamic service that owns them. +/// Upon finalization of the static services the process may crash, because +/// the dynamic service's DLL may have been already released, together with +/// the memory in which the static services reside. +/// It may not crash, for instance, when the first static service to register +/// is the same as the dynamic service being loaded. You should be so lucky! .. +int +ACE_Service_Gestalt::initialize (const ACE_Service_Type *sr, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Gestalt::initialize"); + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s") + ACE_TEXT (" - looking up in the repo\n"), + this->repo_, + sr->name ())); + + ACE_Service_Type *srp = 0; + if (this->repo_->find (sr->name (), + (const ACE_Service_Type **) &srp) >= 0) + { +#ifndef ACE_NLOGGING + ACELIB_DEBUG ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) SG::initialize - repo=%@, name=%s") + ACE_TEXT (" - removing a pre-existing namesake.\n"), + this->repo_, + sr->name ())); +#endif + this->repo_->remove (sr->name ()); + } + + return this->initialize_i (sr, parameters); + +} + +/// Dynamically link the shared object file and retrieve a pointer to +/// the designated shared object in this file. +int +ACE_Service_Gestalt::initialize_i (const ACE_Service_Type *sr, + const ACE_TCHAR *parameters) +{ + ACE_TRACE ("ACE_Service_Gestalt::initialize_i"); + ACE_ARGV args (parameters); + if (sr->type ()->init (args.argc (), + args.argv ()) == -1) + { + // We just get ps to avoid having remove() delete it. + ACE_Service_Type *ps = 0; + this->repo_->remove (sr->name (), &ps); + +#ifndef ACE_NLOGGING + // Not using LM_ERROR here to avoid confusing the test harness + if (ACE::debug ()) + ACELIB_ERROR_RETURN ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) SG::initialize_i -") + ACE_TEXT (" repo=%@, name=%s - remove failed: %m\n"), + this->repo_, + sr->name ()), + -1); +#endif + return -1; + } + + if (this->repo_->insert (sr) == -1) + { +#ifndef ACE_NLOGGING + // Not using LM_ERROR here to avoid confusing the test harness + if (ACE::debug ()) + ACELIB_ERROR_RETURN ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) SG::initialize_i -") + ACE_TEXT (" repo=%@, name=%s - insert failed: %m\n"), + this->repo_, + sr->name ()), + -1); +#endif + return -1; + } + + return 0; +} + +// Totally remove from the daemon by removing it from the +// ACE_Reactor, and unlinking it if necessary. + +int +ACE_Service_Gestalt::remove (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::remove"); + if (this->repo_ == 0) + return -1; + + return this->repo_->remove (svc_name); +} + +/// Suspend @a svc_name. Note that this will not unlink the service +/// from the daemon if it was dynamically linked, it will mark it as +/// being suspended in the Service Repository and call the +/// member function on the appropriate . A service +/// can be resumed later on by calling the method... +int +ACE_Service_Gestalt::suspend (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::suspend"); + if (this->repo_ == 0) + return -1; + + return this->repo_->suspend (svc_name); +} + +// Resume a SVC_NAME that was previously suspended or has not yet +// been resumed (e.g., a static service). + +int +ACE_Service_Gestalt::resume (const ACE_TCHAR svc_name[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::resume"); + if (this->repo_ == 0) + return -1; + + return this->repo_->resume (svc_name); +} + + +int +ACE_Service_Gestalt::process_directive (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace) +{ + int const result = process_directive_i (ssd, force_replace); + if (result == 0) + { + this->add_processed_static_svc(&ssd); + } + return result; +} + +int +ACE_Service_Gestalt::process_directive_i (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace) +{ + if (this->repo_ == 0) + return -1; + + if (!force_replace) + { + if (this->repo_->find (ssd.name_, 0, 0) >= 0) + { + // The service is already there, just return + return 0; + } + } + + + ACE_Service_Object_Exterminator gobbler; + void *sym = (ssd.alloc_)(&gobbler); + + ACE_Service_Type_Impl *stp = + ACE_Service_Config::create_service_type_impl (ssd.name_, + ssd.type_, + sym, + ssd.flags_, + gobbler); + if (stp == 0) + return 0; + + ACE_Service_Type *service_type = 0; + + // This is just a temporary to force the compiler to use the right + // constructor in ACE_Service_Type. Note that, in cases where we are + // called from a static initializer which is part of a DLL, there is + // not enough information about the actuall DLL in this context. + ACE_DLL tmp_dll; + + ACE_NEW_RETURN (service_type, + ACE_Service_Type (ssd.name_, + stp, + tmp_dll, + ssd.active_), + -1); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::process_directive_i, ") + ACE_TEXT ("repo=%@ - %s, dll=%s, force=%d\n"), + this->repo_, + ssd.name_, + (tmp_dll.dll_name_ == 0) ? ACE_TEXT ("") : tmp_dll.dll_name_, + force_replace)); +#endif + + return this->repo_->insert (service_type); +} + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + +int +ACE_Service_Gestalt::process_directives_i (ACE_Svc_Conf_Param *param) +{ +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::process_directives_i, ") + ACE_TEXT ("repo=%@ - %s\n"), + this->repo_, + (param->type == ACE_Svc_Conf_Param::SVC_CONF_FILE) + ? ACE_TEXT ("") + : param->source.directive)); +#endif + + // Were we called in the context of the current instance? + ACE_ASSERT (this == param->config); + + // Temporarily (for the duration of this call) make sure that *any* + // static service registrations will happen with this instance. Such + // registrations are possible as a side-effect of dynamically + // loading a DLL, which has other static services registered. Thus + // this instance will own both the DLL and those static services, + // which implies that their finalization will be performed in the + // correct order, i.e. prior to finalizing the DLL + ACE_Service_Config_Guard guard (this); + + ::ace_yyparse (param); + + // This is a hack, better errors should be provided... + if (param->yyerrno > 0) + { + // Always set the last error if ace_yyparse() fails. + // Other code may use errno to determine the type + // of problem that occurred from processing directives. + ACE_OS::last_error (EINVAL); + return param->yyerrno; + } + else + return 0; +} + +#else + +ACE_XML_Svc_Conf * +ACE_Service_Gestalt::get_xml_svc_conf (ACE_DLL &xmldll) +{ + if (xmldll.open (ACE_TEXT ("ACEXML_XML_Svc_Conf_Parser")) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) Failure to open ACEXML_XML_Svc_Conf_Parser: %p\n"), + ACE_TEXT("ACE_Service_Config::get_xml_svc_conf")), + 0); + + void * foo = + xmldll.symbol (ACE_TEXT ("_ACEXML_create_XML_Svc_Conf_Object")); + +#if defined (ACE_OPENVMS) && (!defined (__INITIAL_POINTER_SIZE) || (__INITIAL_POINTER_SIZE < 64)) + int const temp_p = reinterpret_cast (foo); +#else + intptr_t const temp_p = reinterpret_cast (foo); +#endif + + ACE_XML_Svc_Conf::Factory factory = reinterpret_cast (temp_p); + + if (factory == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) Unable to resolve factory: %p\n"), + xmldll.error ()), + 0); + + return factory (); +} +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + +int +ACE_Service_Gestalt::process_file (const ACE_TCHAR file[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::process_file"); + + // To avoid recursive processing of the same file and the same repository + // we maintain an implicit stack of dummy "services" named after the file + // being processed. Anytime we have to open a new file, we then can check + // to see if it is not already being processed by searching for a dummy + // service with a matching name. + if (this->repo_->find (file, 0, 0) >=0) + { + ACELIB_DEBUG ((LM_WARNING, + ACE_TEXT ("ACE (%P|%t) Configuration file %s is currently") + ACE_TEXT (" being processed. Ignoring recursive process_file().\n"), + file)); + return 0; + } + + // Register a dummy service as a forward decl, using the file name as name. + // The entry will be automaticaly removed once the thread exits this block. + ACE_Service_Type_Dynamic_Guard recursion_guard (*this->repo_, + file); + + /* + * @TODO: Test with ACE_USES_CLASSIC_SVC_CONF turned off! + */ +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + int result = 0; + + FILE *fp = ACE_OS::fopen (file, + ACE_TEXT ("r")); + + if (fp == 0) + { + // Invalid svc.conf file. We'll report it here and break out of + // the method. + if (ACE::debug ()) + ACELIB_DEBUG ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t): %p\n"), + file)); + + // Use stat to find out if the file exists. I didn't use access() + // because stat is better supported on most non-unix platforms. + ACE_stat exists; + if (ACE_OS::stat (file, &exists) == 0) + // If it exists, but we couldn't open it for reading then we + // must not have permission to read it. + errno = EPERM; + else + errno = ENOENT; + result = -1; + } + else + { + ACE_Svc_Conf_Param f (this, fp); + + // Keep track of the number of errors. + result = this->process_directives_i (&f); + + (void) ACE_OS::fclose (fp); + } + return result; +#else + ACE_DLL dll; + + auto_ptr xml_svc_conf (this->get_xml_svc_conf (dll)); + + if (xml_svc_conf.get () == 0) + return -1; + + return xml_svc_conf->parse_file (file); +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ +} + +int +ACE_Service_Gestalt::process_directive (const ACE_TCHAR directive[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::process_directive"); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::process_directive, repo=%@ - %s\n"), + this->repo_, + directive)); +#endif + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + ACE_UNUSED_ARG (directive); + + ACE_Svc_Conf_Param d (this, directive); + + return this->process_directives_i (&d); +#else + ACE_DLL dll; + + auto_ptr + xml_svc_conf (this->get_xml_svc_conf (dll)); + + if (xml_svc_conf.get () == 0) + return -1; + + // Temporarily (for the duration of this call) make sure that *any* static + // service registrations will happen with this instance. Such registrations + // are possible as a side-effect of dynamically loading a DLL, which has + // other static services registered. Thus this instance will own both the + // DLL and those static services, which implies that their finalization + // will be performed in the correct order, i.e. prior to finalizing the DLL + ACE_Service_Config_Guard guard (this); + + return xml_svc_conf->parse_string (directive); +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + +} /* process_directive () */ + + +int +ACE_Service_Gestalt::init_svc_conf_file_queue (void) +{ + if (this->svc_conf_file_queue_ == 0) + { + ACE_SVC_QUEUE *tmp = 0; + ACE_NEW_RETURN (tmp, + ACE_SVC_QUEUE, + -1); + this->svc_conf_file_queue_ = tmp; + } + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::init_svc_conf_file_queue ") + ACE_TEXT ("- this=%@, repo=%@\n"), + this, this->repo_)); +#endif + + return 0; + +} /* init_svc_conf_file_queue () */ + + +int +ACE_Service_Gestalt::open_i (const ACE_TCHAR program_name[], + const ACE_TCHAR* logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf_file, + bool ignore_debug_flag) +{ + ACE_TRACE ("ACE_Service_Gestalt::open_i"); + int result = 0; + ACE_Log_Msg *log_msg = ACE_LOG_MSG; + + this->no_static_svcs_ = ignore_static_svcs; + + // Record the current log setting upon entering this thread. + u_long old_process_mask = log_msg->priority_mask + (ACE_Log_Msg::PROCESS); + + u_long old_thread_mask = log_msg->priority_mask + (ACE_Log_Msg::THREAD); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::open_i - this=%@, ") + ACE_TEXT ("opened=%d, loadstatics=%d\n"), + this, this->is_opened_, this->no_static_svcs_)); +#endif + + // Guard against reentrant processing. For example, + // if the singleton gestalt (ubergestalt) was already open, + // do not open it again... + if (this->is_opened_++ != 0) + return 0; + + if (this->init_i () != 0) + return -1; + + u_long flags = log_msg->flags (); + + // Only use STDERR if the caller hasn't already set the flags. + if (flags == 0) + flags = (u_long) ACE_Log_Msg::STDERR; + + const ACE_TCHAR *key = logger_key; + + if (key == 0 || ACE_OS::strcmp (key, ACE_DEFAULT_LOGGER_KEY) == 0) + { + // Only use the static if the caller doesn't + // override it in the parameter list or if the key supplied is + // equal to the default static logger key. + key = this->logger_key_; + } + else + { + ACE_SET_BITS (flags, ACE_Log_Msg::LOGGER); + } + + if (log_msg->open (program_name, + flags, + key) == -1) + return -1; + + if (!ignore_debug_flag) + { + // If -d was included as a startup parameter, the user wants debug + // information printed during service initialization. + if (ACE::debug ()) + ACE_Log_Msg::enable_debug_messages (); + else + // The user has requested no debugging info. + ACE_Log_Msg::disable_debug_messages (); + } + + if (!ignore_default_svc_conf_file) + { + bool add_default = true; + bool has_files = this->svc_conf_file_queue_ && + !this->svc_conf_file_queue_->is_empty (); + bool has_cmdline = this->svc_queue_ && !this->svc_queue_->is_empty (); + if (has_files || has_cmdline) + { + // check if default file is already listed + ACE_TString *sptr = 0; + ACE_TString default_svc_conf (ACE_DEFAULT_SVC_CONF); + + for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_conf_file_queue_); + iter.next (sptr) != 0 && add_default; + iter.advance ()) + { + add_default = (*sptr != default_svc_conf); + } + + if (add_default) + { + FILE *fp = ACE_OS::fopen (ACE_DEFAULT_SVC_CONF, ACE_TEXT ("r")); + if (fp != 0) + ACE_OS::fclose(fp); + else + add_default = false; + + } + } + + // Load the default "svc.conf" entry. here if there weren't + // overriding -f arguments in . + if (add_default && svc_conf_file_queue_->enqueue_head + (ACE_TString (ACE_DEFAULT_SVC_CONF)) == -1) + { + errno = ENOENT; + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("enqueuing ") + ACE_DEFAULT_SVC_CONF + ACE_TEXT(" file")), + -1); + } + } + + // See if we need to load the static services. + if (this->no_static_svcs_ == 0 + && this->load_static_svcs () == -1) + result = -1; + else + { + result = this->process_directives (); + if (result != -1) + { + int temp = this->process_commandline_directives (); + if (temp == -1) + result = -1; + else result += temp; + } + } + + // Reset debugging back to the way it was when we came into + // into . + { + // Make sure to save/restore errno properly. + ACE_Errno_Guard error (errno); + + if (!ignore_debug_flag) + { + log_msg->priority_mask (old_process_mask, ACE_Log_Msg::PROCESS); + log_msg->priority_mask (old_thread_mask, ACE_Log_Msg::THREAD); + } + } + + return result; +} /* open_i () */ + + +int +ACE_Service_Gestalt::is_opened (void) +{ + return this->is_opened_; +} + +int +ACE_Service_Gestalt::process_commandline_directives (void) +{ + int result = 0; + if (this->svc_queue_ != 0) + { + ACE_TString *sptr = 0; + for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_queue_); + iter.next (sptr) != 0; + iter.advance ()) + { + // Process just a single directive. + if (this->process_directive ((sptr->fast_rep ())) != 0) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE (%P|%t) %p\n"), + ACE_TEXT ("process_directive"))); + result = -1; + } + } + + delete this->svc_queue_; + this->svc_queue_ = 0; + } + + return result; + +} /* process_commandline_directives () */ + + +int +ACE_Service_Gestalt::parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_TRACE ("ACE_Service_Gestalt::parse_args"); + bool unused_ignore_default_svc_conf = true; + return parse_args_i (argc, argv, unused_ignore_default_svc_conf); +} + +int +ACE_Service_Gestalt::parse_args_i (int argc, + ACE_TCHAR *argv[], + bool &ignore_default_svc_conf_file) +{ + ACE_TRACE ("ACE_Service_Gestalt::parse_args_i"); + ACE_Get_Opt get_opt (argc, + argv, + ACE_TEXT ("df:k:nyS:"), + 1); // Start at argv[1]. + + if (this->init_svc_conf_file_queue () == -1) + return -1; + + for (int c; (argc != 0) && ((c = get_opt ()) != -1); ) + switch (c) + { + case 'd': + ACE::debug (1); + break; + case 'f': + if (this->svc_conf_file_queue_->enqueue_tail (ACE_TString (get_opt.opt_arg ())) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("enqueue_tail")), + -1); + ignore_default_svc_conf_file = true; + break; + case 'k': + /* + * @TODO: Is this always a static storage? Shouldn't we copy + * & gain ownership of the value? + */ + this->logger_key_ = get_opt.opt_arg (); + break; + case 'n': + this->no_static_svcs_ = 1; + break; + case 'y': + this->no_static_svcs_ = 0; + break; + case 'S': + if (this->svc_queue_ == 0) + { + ACE_NEW_RETURN (this->svc_queue_, + ACE_SVC_QUEUE, + -1); + } + + if (this->svc_queue_->enqueue_tail (ACE_TString (get_opt.opt_arg ())) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("enqueue_tail")), + -1); + break; + default: + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) %c is not a ACE_Service_Config option\n"), + c)); + } + + return 0; +} /* parse_args_i () */ + + + +// Process service configuration directives from the files queued for +// processing +int +ACE_Service_Gestalt::process_directives (bool ) +{ + ACE_TRACE ("ACE_Service_Gestalt::process_directives"); + if (this->svc_conf_file_queue_ == 0 + || this->svc_conf_file_queue_->is_empty ()) + { + return 0; + } + + ACE_TString *sptr = 0; + int failed = 0; + + // Iterate through all the svc.conf files. + for (ACE_SVC_QUEUE_ITERATOR iter (*this->svc_conf_file_queue_); + iter.next (sptr) != 0; + iter.advance ()) + { + int result = this->process_file (sptr->fast_rep ()); + if (result < 0) + return result; + failed += result; + } + + return failed; + +} /* process_directives () */ + +// Tidy up and perform last rites on a terminating ACE_Service_Gestalt. +int +ACE_Service_Gestalt::close (void) +{ + ACE_TRACE ("ACE_Service_Gestalt::close"); + + if (!this->is_opened_ || --this->is_opened_ != 0) + return 0; + + // Delete the list fo svc.conf files + delete this->svc_conf_file_queue_; + this->svc_conf_file_queue_ = 0; + + if (this->processed_static_svcs_ && + !this->processed_static_svcs_->is_empty()) + { + Processed_Static_Svc **pss = 0; + for (ACE_PROCESSED_STATIC_SVCS_ITERATOR iter (*this->processed_static_svcs_); + iter.next (pss) != 0; + iter.advance ()) + { + delete *pss; + } + } + delete this->processed_static_svcs_; + this->processed_static_svcs_ = 0; + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SG::close - complete this=%@, repo=%@, owned=%d\n"), + this, this->repo_, this->svc_repo_is_owned_)); +#endif + + if (this->svc_repo_is_owned_) + delete this->repo_; + + this->repo_ = 0; + + return 0; +} /* close () */ + + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if !defined (__ACE_INLINE__) +#include "ace/Service_Gestalt.inl" +#endif /* __ACE_INLINE__ */ + +// Allocate a Service Manager. +ACE_FACTORY_DEFINE (ACE, ACE_Service_Manager) diff --git a/dep/acelite/ace/Service_Gestalt.h b/dep/acelite/ace/Service_Gestalt.h new file mode 100644 index 000000000..aae3b3981 --- /dev/null +++ b/dep/acelite/ace/Service_Gestalt.h @@ -0,0 +1,522 @@ +// -*- C++ -*- + +//==================================================================== +/** + * @file Service_Gestalt.h + * + * @author Iliyan Jeliazkov + */ +//==================================================================== + +#ifndef ACE_SERVICE_GESTALT_H +#define ACE_SERVICE_GESTALT_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/Default_Constants.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SString.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Unbounded_Set.h" +#include "ace/Service_Repository.h" +#include "ace/Singleton.h" +#include "ace/OS_NS_signal.h" +#include "ace/Synch_Traits.h" +#include "ace/Atomic_Op.h" +#include "ace/Guard_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) +class ACE_Service_Type_Factory; +class ACE_Location_Node; +#else +class ACE_XML_Svc_Conf; +class ACE_DLL; +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + +class ACE_Static_Svc_Descriptor; +class ACE_Svc_Conf_Param; + +/** + * @class ACE_Service_Gestalt + * + * @brief Supplies common server operations for dynamic and static + * configuration of services. + * + * The Gestalt embodies the concept of configuration context. On one + * hand, it is a flat namespace, where names correspond to a Service + * Object instance. A Gestalt owns the Service Repository instance, + * which in turn owns the Service Object instances. + * + * Another aspect of a Gestalt is its responsibility for + * record-keeping and accounting for the meta-data, necessary for + * locating, removing or instantiating a service. + * + * A repository underlies an instance of a gestalt and its lifetime + * may or may not be bounded by the lifetime of the gestalt, that owns + * it. This feature is important for the derived classes and the + * Service Config in particular. + */ +class ACE_Export ACE_Service_Gestalt : private ACE_Copy_Disabled +{ +public: + enum + { + MAX_SERVICES = ACE_DEFAULT_SERVICE_REPOSITORY_SIZE + }; + + enum + { + DEFAULT_SIZE = ACE_DEFAULT_SERVICE_GESTALT_SIZE + }; + + /// Constructor either associates the instance with the process-wide + /// singleton instance of ACE_Service_Repository, or creates and + /// manages its own instance of the specified size. + ACE_Service_Gestalt (size_t size = DEFAULT_SIZE, + bool svc_repo_is_owned = true, + bool no_static_svcs = true); + + /// Perform user-specified close activities and remove dynamic + /// memory. + ~ACE_Service_Gestalt (void); + + /// Dump the state of an object. + void dump (void) const; + + /** + * Performs an open without parsing command-line arguments. The + * @a logger_key indicates where to write the logging output, which + * is typically either a STREAM pipe or a socket address. If + * @a ignore_static_svcs is true then static services are not loaded, + * otherwise, they are loaded. If @a ignore_default_svc_conf_file is + * true then the @c svc.conf configuration file will be ignored. + * Returns zero upon success, -1 if the file is not found or cannot + * be opened (errno is set accordingly), otherwise returns the + * number of errors encountered loading the services in the + * specified svc.conf configuration file. If @a ignore_debug_flag is + * true then the application is responsible for setting the + * ACE_Log_Msg::priority_mask appropriately. + */ + int open (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key = 0, + bool ignore_static_svcs = true, + bool ignore_default_svc_conf_file = false, + bool ignore_debug_flag = false); + + /** + * This is the primary entry point into the ACE_Service_Config (the + * constructor just handles simple initializations). It parses + * arguments passed in from @a argc and @a argv parameters. The + * arguments that are valid in a call to this method include: + * + * - '-b' Option to indicate that we should be a daemon. Note that when + * this option is used, the process will be daemonized before the + * service configuration file(s) are read. During daemonization, + * (on POSIX systems) the current directory will be changed to "/" + * so the caller should either fully specify the file names, or + * execute a @c chroot() to the appropriate directory. + * @sa ACE::daemonize(). + * - '-d' Turn on debugging mode + * - '-f' Specifies a configuration file name other than the default + * svc.conf. Can be specified multiple times to use multiple files. + * If any configuration file is provided with this option then + * the default svc.conf will be ignored. + * - '-k' Specifies the rendezvous point to use for the ACE distributed + * logger. + * - '-y' Explicitly enables the use of static services. This flag + * overrides the @a ignore_static_svcs parameter value. + * - '-n' Explicitly disables the use of static services. This flag + * overrides the @a ignore_static_svcs parameter value. + * - '-p' Specifies a pathname which is used to store the process id. + * - '-s' Specifies a signal number other than SIGHUP to trigger reprocessing + * of the configuration file(s). Ignored for platforms that do not + * have POSIX signals, such as Windows. + * - '-S' Specifies a service directive string. Enclose the string in quotes + * and escape any embedded quotes with a backslash. This option + * specifies service directives without the need for a configuration + * file. Can be specified multiple times. + * + * Note: Options '-f' and '-S' complement each other. Directives + * from files and from '-S' option are processed together in the + * following order. First, the default file "./svc.conf" is + * evaluated if not ignored, then all files are processed in the + * order they are specified in '-f' @a argv parameter. Finally, all + * '-S' directive strings are executed in the order the directives + * appear in @a argv parameter. + * + * If no files or directives are added via the '-f' and '-S' + * arguments, and the default file is not ignored, it will be + * evaluated whether it exists or not, possibly causing a failure + * return. If any other directives are added then the default file + * will be evaluated only if it exists. + * + * @param argc The number of commandline arguments. + * @param argv The array with commandline arguments + * @param logger_key Indicates where to write the logging output, + * which is typically either a STREAM pipe or a + * socket address. + * @param ignore_static_svcs If true then static services are not loaded, + * otherwise, they are loaded. + * @param ignore_default_svc_conf_file If false then the @c ./svc.conf + * configuration file will be ignored. + * @param ignore_debug_flag If false then the application is responsible + * for setting the @c ACE_Log_Msg::priority_mask + * appropriately. + * + * @retval -1 A configuration file is not found or cannot + * be opened (errno is set accordingly). + * @retval 0 Success. + * @retval >0 The number of directive errors encountered while processing + * the service configuration file(s). + */ + int open (int argc, + ACE_TCHAR *argv[], + const ACE_TCHAR *logger_key = 0, + bool ignore_static_svcs = true, + bool ignore_default_svc_conf_file = false, + bool ignore_debug_flag = false); + + /// Has it been opened? Returns the difference between the times + /// open and close have been called on this instance + int is_opened (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + + /// Process one service configuration @a directive, which is passed as + /// a string. Returns the number of errors that occurred. + int process_directive (const ACE_TCHAR directive[]); + + /// Process one static service definition. + /** + * Load a new static service. + * + * @param ssd Service descriptor, see the document of + * ACE_Static_Svc_Descriptor for more details. + * + * @param force_replace If set the new service descriptor replaces + * any previous instance in the repository. + * + * @return Returns -1 if the service cannot be 'loaded'. + */ + int process_directive (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace = false); + + /// Process a file containing a list of service configuration + /// directives. + int process_file (const ACE_TCHAR file[]); + + /** + * Locate an entry with @a name in the table. If @a ignore_suspended + * is set then only consider services marked as resumed. If the + * caller wants the located entry, pass back a pointer to the + * located entry via @a srp. If @a name is not found, -1 is returned. + * If @a name is found, but it is suspended and the caller wants to + * ignore suspended services a -2 is returned. + */ + int find (const ACE_TCHAR name[], + const ACE_Service_Type **srp = 0, + bool ignore_suspended = true) const; + + /** + * Handle the command-line options intended for the + * ACE_Service_Gestalt. Note that @c argv[0] is assumed to be the + * program name. + * + * The arguments that are valid in a call to this method are + * - '-d' Turn on debugging mode + * - '-f' Option to read in the list of svc.conf file names + * - '-k' Option to read a wide string where in the logger output can + * be written + * - '-y' Turn on the flag for a repository of statically + * linked services + * - '-n' Need not have a repository of statically linked services + * - '-S' Option to read in the list of services on the command-line + * Please observe the difference between options '-f' that looks + * for a list of files and here a list of services. + */ + int parse_args (int argc, ACE_TCHAR *argv[]); + + /** + * Process (or re-process) service configuration requests that are + * provided in the svc.conf file(s). Returns the number of errors + * that occurred. + */ + int process_directives (bool defunct_option = false); + + /// Tidy up and perform last rites when ACE_Service_Config is shut + /// down. This method calls @c close_svcs. Returns 0. + int close (void); + + /// Registers a service descriptor for a static service object + int insert (ACE_Static_Svc_Descriptor *stsd); + + // = Utility methods. + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + /// Dynamically link the shared object file and retrieve a pointer to + /// the designated shared object in this file. Also account for the + /// possiblity to have static services registered when loading the DLL, by + /// ensuring that the dynamic sevice is registered before any of its + /// subordibnate static services. Thus avoiding any finalization order + /// problems. + int initialize (const ACE_Service_Type_Factory *, + const ACE_TCHAR *parameters); +#endif /* (ACE_USES_CLASSIC_SVC_CONF == 1) */ + + /// Dynamically link the shared object file and retrieve a pointer to + /// the designated shared object in this file. + /// @deprecated + /// @note This is error-prone in the presense of dynamic services, + /// which in turn initialize their own static services. This method + /// will allow those static services to register *before* the dynamic + /// service that owns them. Upon finalization of the static services + /// the process will typically crash, because the dynamic service's + /// DLL may have been already released, together with the memory in + /// which the static services reside. It may not crash, for + /// instance, when the first static service to register is the same + /// as the dynamic service being loaded. You should be so lucky! + int initialize (const ACE_Service_Type *, + const ACE_TCHAR *parameters); + + /// Initialize and activate a statically @a svc_name service. + int initialize (const ACE_TCHAR *svc_name, + const ACE_TCHAR *parameters); + + /// Resume a @a svc_name that was previously suspended or has not yet + /// been resumed (e.g., a static service). + int resume (const ACE_TCHAR svc_name[]); + + /** + * Suspend @a svc_name. Note that this will not unlink the service + * from the daemon if it was dynamically linked, it will mark it as + * being suspended in the Service Repository and call the @c suspend() + * member function on the appropriate ACE_Service_Object. A + * service can be resumed later on by calling the @c resume() member + * function... + */ + int suspend (const ACE_TCHAR svc_name[]); + + /// Totally remove @a svc_name from the daemon by removing it + /// from the ACE_Reactor, and unlinking it if necessary. + int remove (const ACE_TCHAR svc_name[]); + + /** + * Using the supplied name, finds and (if needed) returns a pointer to a + * static service descriptor. Returns 0 for success and -1 for failure + */ + int find_static_svc_descriptor (const ACE_TCHAR* name, + ACE_Static_Svc_Descriptor **ssd = 0) const; + + struct Processed_Static_Svc + { + Processed_Static_Svc (const ACE_Static_Svc_Descriptor *); + ~Processed_Static_Svc (void); + ACE_TCHAR * name_; + const ACE_Static_Svc_Descriptor *assd_; + ACE_ALLOC_HOOK_DECLARE; + }; + + /// Get the current ACE_Service_Repository held by this object. + ACE_Service_Repository* current_service_repository (void); + +protected: + + int parse_args_i (int, ACE_TCHAR *argv[], + bool& ignore_default_svc_conf_file); + + /** + * Performs an open without parsing command-line arguments. The @a + * logger_key indicates where to write the logging output, which is + * typically either a STREAM pipe or a socket address. If @a + * ignore_default_svc_conf_file is non-0 then the "svc.conf" file + * will not be added by default. If @a ignore_debug_flag is non-0 + * then the application is responsible for setting the @c + * ACE_Log_Msg::priority_mask() appropriately. Returns number of + * errors that occurred on failure and 0 otherwise. + */ + int open_i (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key = 0, + bool ignore_static_svcs = true, + bool ignore_default_svc_conf_file = false, + bool ignore_debug_flag = false); + + /// Initialize the @c svc_conf_file_queue_ if necessary. + int init_svc_conf_file_queue (void); + + /// Add the default statically-linked services to the + /// ACE_Service_Repository. + int load_static_svcs (void); + + /// Process service configuration requests that were provided on the + /// command-line. Returns the number of errors that occurred. + int process_commandline_directives (void); + + /// Process a static directive without also inserting its descriptor + /// the global table. This avoids multiple additions when processing + /// directives in non-global gestalts. + int process_directive_i (const ACE_Static_Svc_Descriptor &ssd, + bool force_replace = false); + +#if (ACE_USES_CLASSIC_SVC_CONF == 1) + /// This is the implementation function that process_directives() + /// and process_directive() both call. Returns the number of errors + /// that occurred. + int process_directives_i (ACE_Svc_Conf_Param *param); +#else + /// Helper function to dynamically link in the XML Service Configurator + /// parser. + ACE_XML_Svc_Conf* get_xml_svc_conf (ACE_DLL &d); +#endif /* ACE_USES_CLASSIC_SVC_CONF == 1 */ + + /// Dynamically link the shared object file and retrieve a pointer to + /// the designated shared object in this file. + int initialize_i (const ACE_Service_Type *sr, const ACE_TCHAR *parameters); + + const ACE_Static_Svc_Descriptor* find_processed_static_svc (const ACE_TCHAR*); + void add_processed_static_svc (const ACE_Static_Svc_Descriptor *); + + /// Performs the common initialization tasks for a new or previously + /// closed instance. Must not be virtual, as it is called from the + /// constructor. + int init_i (void); + +protected: + + /// Maintain a queue of services to be configured from the + /// command-line. + typedef ACE_Unbounded_Queue ACE_SVC_QUEUE; + typedef ACE_Unbounded_Queue_Iterator ACE_SVC_QUEUE_ITERATOR; + + /// Maintain a set of the statically linked service descriptors. + typedef ACE_Unbounded_Set + ACE_STATIC_SVCS; + + typedef ACE_Unbounded_Set_Iterator + ACE_STATIC_SVCS_ITERATOR; + + typedef ACE_Unbounded_Set + ACE_PROCESSED_STATIC_SVCS; + + typedef ACE_Unbounded_Set_Iterator + ACE_PROCESSED_STATIC_SVCS_ITERATOR; + + friend class ACE_Dynamic_Service_Base; + friend class ACE_Service_Object; + friend class ACE_Service_Config; + friend class ACE_Service_Config_Guard; + +protected: + + /// Do we own the service repository instance, or have only been + /// given a ptr to the singleton? + bool svc_repo_is_owned_; + + /// Repository size is necessary, so that we can close (which may + /// destroy the repository instance), and then re-open again. + size_t svc_repo_size_; + + /// Keep track of the number of times the instance has been + /// initialized (opened). "If so, we can't allow to be called since + /// it's not reentrant" is the original motivation, but that does not seem + /// to be the case anymore. This variable is incremented by the + /// method and decremented by the + /// method. + int is_opened_; + + /// Indicates where to write the logging output. This is typically + /// either a STREAM pipe or a socket + const ACE_TCHAR *logger_key_; + + /// Should we avoid loading the static services? + bool no_static_svcs_; + + /// Queue of services specified on the command-line. + ACE_SVC_QUEUE* svc_queue_; + + /** + * Queue of svc.conf files specified on the command-line. + * @@ This should probably be made to handle unicode filenames... + */ + ACE_SVC_QUEUE* svc_conf_file_queue_; + + /// The service repository to hold the services. + ACE_Service_Repository* repo_; + + /// Repository of statically linked services. + ACE_STATIC_SVCS* static_svcs_; + + /// Repository of statically linked services for which process + /// directive was called, but the service is not already a member of + /// the static_svcs_ list. + ACE_PROCESSED_STATIC_SVCS* processed_static_svcs_; + + /// Support for intrusive reference counting + ACE_Atomic_Op refcnt_; + + public: + static void intrusive_add_ref (ACE_Service_Gestalt*); + static void intrusive_remove_ref (ACE_Service_Gestalt*); + +}; /* class ACE_Service_Gestalt */ + + +/** + * @class ACE_Service_Type_Dynamic_Guard + * + * @brief A forward service declaration guard. + * + * Helps to resolve an issue with hybrid services, i.e. dynamic + * services, accompanied by static services in the same DLL. Only + * automatic instances of this class are supposed to exist. Those are + * created during (dynamic) service initialization and serve to: + * + * (a) Ensure the service we are loading is ordered last in the + * repository, following any other services it may cause to register, + * as part of its own registration. This is a common case when + * loading dynamic services from DLLs - there are often static + * initializers, which register static services. + * + * (b) The SDG instance destructor detects if the dynamic service + * initialized successfully and "fixes-up" all the newly registered + * static services to hold a reference to the DLL, from which they + * have originated. + */ +class ACE_Export ACE_Service_Type_Dynamic_Guard +{ +public: + ACE_Service_Type_Dynamic_Guard (ACE_Service_Repository &r, + ACE_TCHAR const *name); + + ~ACE_Service_Type_Dynamic_Guard (void); + +private: + ACE_Service_Repository & repo_; + size_t repo_begin_; + ACE_TCHAR const * const name_; + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +// FUZZ: disable check_for_ACE_Guard + ACE_Guard< ACE_Recursive_Thread_Mutex > repo_monitor_; +// FUZZ: enable check_for_ACE_Guard +#endif +}; + + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Service_Gestalt.inl" +#endif /* __ACE_INLINE__ */ + + +#include /**/ "ace/post.h" + +#endif /* ACE_SERVICE_GESTALT_H */ diff --git a/dep/acelite/ace/Service_Gestalt.inl b/dep/acelite/ace/Service_Gestalt.inl new file mode 100644 index 000000000..ec46b2706 --- /dev/null +++ b/dep/acelite/ace/Service_Gestalt.inl @@ -0,0 +1,75 @@ +// -*- C++ -*- + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + + +// This is the primary entry point into the ACE_Service_Config (the +// constructor just handles simple initializations). + +ACE_INLINE int +ACE_Service_Gestalt::open (const ACE_TCHAR program_name[], + const ACE_TCHAR *logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf, + bool ignore_debug_flag) +{ + ACE_TRACE ("ACE_Service_Gestalt::open"); + this->no_static_svcs_ = ignore_static_svcs; + + return this->open_i (program_name, + logger_key, + ignore_static_svcs, + ignore_default_svc_conf, + ignore_debug_flag); +} + +ACE_INLINE int +ACE_Service_Gestalt::open (int argc, + ACE_TCHAR *argv[], + const ACE_TCHAR *logger_key, + bool ignore_static_svcs, + bool ignore_default_svc_conf, + bool ignore_debug_flag) +{ + ACE_TRACE ("ACE_Service_Gestalt::open"); + + // Parsing argv may change no_static_svcs_ so set the default here, then + // parse, then pass the final value to open_i(). + this->no_static_svcs_ = ignore_static_svcs; + + if (this->parse_args_i (argc, + argv, + ignore_default_svc_conf) == -1) + return -1; + + return this->open_i (argv == 0 ? 0 : argv[0], + logger_key, + this->no_static_svcs_, + ignore_default_svc_conf, + ignore_debug_flag); +} + +/// Searches for a service object declaration in the local repo, only + +ACE_INLINE int +ACE_Service_Gestalt::find (const ACE_TCHAR name[], + const ACE_Service_Type **srp, + bool ignore_suspended) const +{ + // Closing the gestalt will have disassociated it from the + // repository. If the repository used to be owned by the gestalt, it + // will also have been destroyed - so just check for repo_ before + // doing anything with it. + if (this->repo_ != 0) + return this->repo_->find (name, srp, ignore_suspended); + + return 0; +} + +ACE_INLINE ACE_Service_Repository* +ACE_Service_Gestalt::current_service_repository (void) +{ + return this->repo_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Manager.cpp b/dep/acelite/ace/Service_Manager.cpp new file mode 100644 index 000000000..547648ea5 --- /dev/null +++ b/dep/acelite/ace/Service_Manager.cpp @@ -0,0 +1,431 @@ +#include "ace/Service_Manager.h" + +#include "ace/Get_Opt.h" +#include "ace/Log_Category.h" +#include "ace/Service_Repository.h" +#include "ace/Service_Config.h" +#include "ace/Service_Types.h" +#include "ace/Reactor.h" +#include "ace/WFMO_Reactor.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE (ACE_Service_Manager) + +void +ACE_Service_Manager::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Manager::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// Static variables. + +u_short ACE_Service_Manager::DEFAULT_PORT_ = 10000; + +ACE_Service_Manager::ACE_Service_Manager (void) + : debug_ (false), + signum_ (SIGHUP) +{ + ACE_TRACE ("ACE_Service_Manager::ACE_Service_Manager"); +} + +ACE_Service_Manager::~ACE_Service_Manager (void) +{ + ACE_TRACE ("ACE_Service_Manager::~ACE_Service_Manager"); +} + +int +ACE_Service_Manager::suspend (void) +{ + ACE_TRACE ("ACE_Service_Manager::suspend"); + return ACE_Reactor::instance ()->suspend_handler (this); +} + +int +ACE_Service_Manager::resume (void) +{ + ACE_TRACE ("ACE_Service_Manager::resume"); + return ACE_Reactor::instance ()->resume_handler (this); +} + +int +ACE_Service_Manager::open (const ACE_INET_Addr &sia) +{ + ACE_TRACE ("ACE_Service_Manager::open"); + + // Reuse the listening address, even if it's already in use! + if (this->acceptor_.open (sia, 1) == -1) + { + return -1; + } + + return 0; +} + +int +ACE_Service_Manager::info (ACE_TCHAR **strp, size_t length) const +{ + ACE_TRACE ("ACE_Service_Manager::info"); + ACE_INET_Addr sa; + ACE_TCHAR buf[BUFSIZ]; + + if (this->acceptor_.get_local_addr (sa) == -1) + { + return -1; + } + + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%d/%s %s"), + sa.get_port_number (), + ACE_TEXT ("tcp"), + ACE_TEXT ("# lists all services in the daemon\n")); + + if (*strp == 0 && (*strp = ACE_OS::strdup (buf)) == 0) + { + return -1; + } + else + { + ACE_OS::strsncpy (*strp, buf, length); + } + + return static_cast (ACE_OS::strlen (buf)); +} + +int +ACE_Service_Manager::init (int argc, ACE_TCHAR *argv[]) +{ + ACE_TRACE ("ACE_Service_Manager::init"); + ACE_INET_Addr local_addr (ACE_Service_Manager::DEFAULT_PORT_); + + //FUZZ: disable check_for_lack_ACE_OS + ACE_Get_Opt getopt (argc, argv, ACE_TEXT ("dp:s:"), 0); // Start at argv[0] + + for (int c; (c = getopt ()) != -1; ) + //FUZZ: enable check_for_lack_ACE_OS + switch (c) + { + case 'd': + this->debug_ = true; + break; + case 'p': + local_addr.set ((u_short) ACE_OS::atoi (getopt.opt_arg ())); + break; + case 's': + this->signum_ = ACE_OS::atoi (getopt.opt_arg ()); + break; + default: + break; + } + + if (this->get_handle () == ACE_INVALID_HANDLE && + this->open (local_addr) == -1) + { + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("open")), -1); + } + else if (ACE_Reactor::instance ()->register_handler + (this, + ACE_Event_Handler::ACCEPT_MASK) == -1) + { + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("registering service with ACE_Reactor\n")), + -1); + } + + return 0; +} + +int +ACE_Service_Manager::handle_close (ACE_HANDLE, ACE_Reactor_Mask) +{ + ACE_TRACE ("ACE_Service_Manager::handle_close"); + return this->acceptor_.close (); +} + +int +ACE_Service_Manager::fini (void) +{ + ACE_TRACE ("ACE_Service_Manager::fini"); + + int retv = 0; + + if (this->get_handle () != ACE_INVALID_HANDLE) + { + retv = + ACE_Reactor::instance ()->remove_handler ( + this, + ACE_Event_Handler::ACCEPT_MASK | ACE_Event_Handler::DONT_CALL); + + this->handle_close (ACE_INVALID_HANDLE, + ACE_Event_Handler::NULL_MASK); + } + + return retv; +} + +ACE_HANDLE +ACE_Service_Manager::get_handle (void) const +{ + ACE_TRACE ("ACE_Service_Manager::get_handle"); + return this->acceptor_.get_handle (); +} + +int +ACE_Service_Manager::handle_signal (int, siginfo_t *, ucontext_t *) +{ + return 0; +} + +// Determine all the services offered by this daemon and return the +// information back to the client. + +int +ACE_Service_Manager::list_services (void) +{ + ACE_TRACE ("ACE_Service_Manager::list_services"); + ACE_Service_Repository_Iterator sri (*ACE_Service_Repository::instance (), 0); + + for (const ACE_Service_Type *sr; + sri.next (sr) != 0; + sri.advance ()) + { + ssize_t len = static_cast (ACE_OS::strlen (sr->name ())) + 11; + ACE_TCHAR buf[BUFSIZ]; + ACE_TCHAR *p = buf + len; + + ACE_OS::strcpy (buf, sr->name ()); + ACE_OS::strcat (buf, (sr->active ()) ? + ACE_TEXT (" (active) ") : + ACE_TEXT (" (paused) ")); + + p[-1] = ' '; + p[0] = '\0'; + + len += sr->type ()->info (&p, sizeof buf - len); + + if (this->debug_) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("len = %d, info = %s%s"), + len, + buf, + buf[len - 1] == '\n' ? ACE_TEXT ("") : ACE_TEXT ("\n"))); + } + + if (len > 0) + { + ssize_t n = this->client_stream_.send_n (buf, len); + + if (n <= 0 && errno != EPIPE) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("send_n"))); + } + } + } + + return 0; +} + +// Trigger a reconfiguration of the Service Configurator via its +// svc.conf file. + +int +ACE_Service_Manager::reconfigure_services (void) +{ + ACE_TRACE ("ACE_Service_Manager::reconfigure_services"); + +#if 0 +// Send ourselves a signal! ACE_OS::kill (ACE_OS::getpid (), +// this->signum_); +#endif /* 0 */ + + // Flag the main event loop that a reconfiguration should occur. + // The next trip through the should + // pick this up and cause a reconfiguration. Note that we can't + // trigger the reconfiguration automatically since that might "pull + // the rug" out from underneath the existing services in a + // problematic way. + ACE_Service_Config::reconfig_occurred ((sig_atomic_t) 1); + return static_cast (this->client_stream_.send_n ("done\n", + sizeof ("done\n"))); +} + +// isolate the request-processing code +void +ACE_Service_Manager::process_request (ACE_TCHAR *request) +{ + ACE_TRACE("ACE_Service_Manager::process_request"); + ACE_TCHAR *p; + + // Kill trailing newlines. + for (p = request; + (*p != '\0') && (*p != '\r') && (*p != '\n'); + p++) + { + continue; + } + + *p = '\0'; + + if (ACE_OS::strcmp (request, ACE_TEXT ("help")) == 0) + { + // Return a list of the configured services. + this->list_services (); + } + else if (ACE_OS::strcmp (request, ACE_TEXT ("reconfigure") )== 0) + { + // Trigger a reconfiguration by re-reading the local file. + this->reconfigure_services (); + } + else + { + // Just process a single request passed in via the socket + // remotely. + ACE_Service_Config_Guard guard (ACE_Service_Config::global ()); + ACE_Service_Config::process_directive (request); + } + + // Additional management services may be handled here... +} + +// Accept new connection from client and carry out the service they +// request. + +int +ACE_Service_Manager::handle_input (ACE_HANDLE) +{ + ACE_TRACE ("ACE_Service_Manager::handle_input"); + + // Try to find out if the implementation of the reactor that we are + // using requires us to reset the event association for the newly + // created handle. This is because the newly created handle will + // inherit the properties of the listen handle, including its event + // associations. + bool reset_new_handle = + ACE_Reactor::instance ()->uses_event_associations (); + + if (this->acceptor_.accept (this->client_stream_, // stream + 0, // remote address + 0, // timeout + 1, // restart + reset_new_handle // reset new handler + ) == -1) + { + return -1; + } + + if (this->debug_) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("client_stream fd = %d\n"), + this->client_stream_.get_handle ())); + ACE_INET_Addr sa; + + if (this->client_stream_.get_remote_addr (sa) == -1) + { + return -1; + } + + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("accepted from host %C at port %d\n"), + sa.get_host_name (), + sa.get_port_number ())); + } + + ACE_TCHAR request[BUFSIZ]; + ACE_TCHAR* offset = request; + ssize_t remaining = sizeof (request); + + // Read service request from client. + + ssize_t result; + + // Keep looping until we actually get the request. Note that Win32 + // sets the socket into non-blocking mode, so we may need to loop if + // the system is heavily loaded. Read bytes into the buffer until a + // '\n' or '\r' is found in the buffer, otherwise the buffer + // contains an incomplete string. + + int error; + + do + { + result = client_stream_.recv (offset, remaining); + error = errno; + + if (result == 0 && error != EWOULDBLOCK) + { + remaining = 0; + } + + if (result >= 0) + { + if ((remaining -= result) <= 0) + { + ACELIB_DEBUG ((LM_ERROR, + ACE_TEXT ("Request buffer overflow.\n"))); + result = 0; + break; + } + + offset += result; + *offset = 0; + + if (ACE_OS::strchr (request, '\r') != 0 + || ACE_OS::strchr (request, '\n') != 0) + { + remaining = 0; + } + } + } + while ((result == -1 && error == EWOULDBLOCK) || remaining > 0); + + switch (result) + { + case -1: + if (this->debug_) + { + ACELIB_DEBUG ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("recv"))); + } + + break; + case 0: + return 0; + /* NOTREACHED */ + default: + { + ACE_Event_Handler *old_signal_handler = 0; + ACE_Reactor::instance ()->register_handler (SIGPIPE, + this, + 0, + &old_signal_handler); + + this->process_request (request); + + // Restore existing SIGPIPE handler + ACE_Reactor::instance ()->register_handler (SIGPIPE, + old_signal_handler); + } + } + + if (this->client_stream_.close () == -1 && this->debug_) + { + ACELIB_DEBUG ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("close"))); + } + + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Manager.h b/dep/acelite/ace/Service_Manager.h new file mode 100644 index 000000000..132853855 --- /dev/null +++ b/dep/acelite/ace/Service_Manager.h @@ -0,0 +1,118 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Service_Manager.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SERVICE_MANAGER_H +#define ACE_SERVICE_MANAGER_H +#include /**/ "ace/pre.h" + +#include "ace/SOCK_Stream.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SOCK_Acceptor.h" +#include "ace/INET_Addr.h" +#include "ace/Service_Object.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Service_Manager + * + * @brief Provide a standard ACE service for managing all the services + * configured in an ACE_Service_Repository. + * + * This implementation is simple and just handles each client + * request one at a time. There are currently 3 types of requests: + * - List services: If the string "help" is sent, return a list of all + * the services supported by the Service Configurator. + * - Reconfigure: If the string "reconfigure" is sent trigger a + * reconfiguration, which will re-read the local file. + * - Process directive: If neither "help" nor "reconfigure" is sent, + * simply treat the incoming string as a process directive and pass + * it along to . This allows + * remote configuration via command-line instructions like + * % echo suspend My_Remote_Service | telnet hostname 3911 + * + * Each request is associated with a new connection, which is closed + * when the request is processed. In addition, you must be using the + * singleton in order to trigger + * reconfigurations. + */ +class ACE_Export ACE_Service_Manager : public ACE_Service_Object +{ +public: + // = Initialization and termination hooks. + /// Constructor. + ACE_Service_Manager (void); + + /// Destructor. + virtual ~ACE_Service_Manager (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Perform the various meta-services. + + /// Trigger a reconfiguration of the Service Configurator by + /// re-reading its local file. + virtual int reconfigure_services (void); + + /// Determine all the services offered by this daemon and return the + /// information back to the client. + virtual int list_services (void); + + // = Dynamic linking hooks. + virtual int init (int argc, ACE_TCHAR *argv[]); + virtual int info (ACE_TCHAR **info_string, size_t length) const; + virtual int fini (void); + + // = Scheduling hooks. + virtual int suspend (void); + virtual int resume (void); + + /// Dump the state of an object. + void dump (void) const; + +protected: + int open (const ACE_INET_Addr &sia); + + // = Demultiplexing hooks. + virtual ACE_HANDLE get_handle (void) const; + virtual int handle_input (ACE_HANDLE fd); + virtual int handle_close (ACE_HANDLE fd, ACE_Reactor_Mask); + virtual int handle_signal (int signum, siginfo_t *, ucontext_t *); + + /// Handle one request. + virtual void process_request (ACE_TCHAR *request); + + /// Connection to the client (we only support one client connection + /// at a time). + ACE_SOCK_Stream client_stream_; + + /// Acceptor instance. + ACE_SOCK_Acceptor acceptor_; + + /// Keep track whether we debug or not. + bool debug_; + + /// The signal used to trigger reconfiguration. + int signum_; + + /// Default port for the Acceptor to listen on. + static u_short DEFAULT_PORT_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* _SERVICE_MANAGER_H */ diff --git a/dep/acelite/ace/Service_Object.cpp b/dep/acelite/ace/Service_Object.cpp new file mode 100644 index 000000000..a16b9af04 --- /dev/null +++ b/dep/acelite/ace/Service_Object.cpp @@ -0,0 +1,189 @@ +#include "ace/config-all.h" + +#include "ace/Service_Object.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Service_Object.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_stdio.h" +#include "ace/Service_Types.h" +#include "ace/DLL.h" +#include "ace/ACE.h" +#include "ace/Log_Category.h" +#if defined (ACE_OPENVMS) +# include "ace/Lib_Find.h" +#endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Object) +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Type) + +void +ACE_Service_Type::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Type::dump"); +#endif /* ACE_HAS_DUMP */ + + // Using printf, since the log facility may not have been + // initialized yet. Using a "//" prefix, in case the executable + // happens to be a code generator and the output gets embedded in + // the generated C++ code. +#ifndef ACE_LACKS_STDERR + ACE_OS::fprintf(stderr, + "// [ST] dump, this=%p, name=%s, type=%p, so=%p, active=%d\n", + static_cast (this), + ACE_TEXT_ALWAYS_CHAR (this->name_), + static_cast (this->type_), + (this->type_ != 0) ? this->type_->object () : 0, + this->active_); +#endif +} + +ACE_Service_Type::ACE_Service_Type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *t, + const ACE_DLL &dll, + bool active) + : name_ (0), + type_ (t), + dll_ (dll), + active_ (active), + fini_already_called_ (false) +{ + ACE_TRACE ("ACE_Service_Type::ACE_Service_Type"); + this->name (n); +} + +ACE_Service_Type::ACE_Service_Type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *t, + ACE_SHLIB_HANDLE handle, + bool active) + : name_ (0), + type_ (t), + active_ (active), + fini_already_called_ (false) +{ + ACE_TRACE ("ACE_Service_Type::ACE_Service_Type"); + this->dll_.set_handle (handle); + this->name (n); +} + +ACE_Service_Type::~ACE_Service_Type (void) +{ + ACE_TRACE ("ACE_Service_Type::~ACE_Service_Type"); + this->fini (); + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(const_cast (this->name_)); +#else + delete [] const_cast (this->name_); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +int +ACE_Service_Type::fini (void) +{ + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) ST::fini - destroying name=%s, dll=%s\n"), + this->name_, + this->dll_.dll_name_)); + + if (this->fini_already_called_) + return 0; + + this->fini_already_called_ = true; + + if (this->type_ == 0) + { + // Returning 1 currently only makes sense for dummy instances, used + // to "reserve" a spot (kind of like forward-declarations) for a + // dynamic service. This is necessary to help enforce the correct + // finalization order, when such service also has any (dependent) + // static services + + return 1; // No implementation was found. + } + + int ret = this->type_->fini (); + + // Ensure type is 0 to prevent invalid access after call to fini. + this->type_ = 0; + + // Ensure that closing the DLL is done after type_->fini() as it may + // require access to the code for the service object destructor, + // which resides in the DLL + + return (ret | this->dll_.close ()); +} + +int +ACE_Service_Type::suspend (void) const +{ + ACE_TRACE ("ACE_Service_Type::suspend"); + (const_cast (this))->active_ = false; + return this->type_->suspend (); +} + +int +ACE_Service_Type::resume (void) const +{ + ACE_TRACE ("ACE_Service_Type::resume"); + (const_cast (this))->active_ = true; + return this->type_->resume (); +} + +ACE_Service_Object::ACE_Service_Object (ACE_Reactor *r) + : ACE_Event_Handler (r) +{ + ACE_TRACE ("ACE_Service_Object::ACE_Service_Object"); +} + +ACE_Service_Object::~ACE_Service_Object (void) +{ + ACE_TRACE ("ACE_Service_Object::~ACE_Service_Object"); +} + +int +ACE_Service_Object::suspend (void) +{ + ACE_TRACE ("ACE_Service_Object::suspend"); + return 0; +} + +int +ACE_Service_Object::resume (void) +{ + ACE_TRACE ("ACE_Service_Object::resume"); + return 0; +} + +void +ACE_Service_Type::name (const ACE_TCHAR *n) +{ + ACE_TRACE ("ACE_Service_Type::name"); + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(const_cast (this->name_)); +#else + delete [] const_cast (this->name_); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + this->name_ = ACE::strnew (n); +} + +#if defined (ACE_OPENVMS) +ACE_Dynamic_Svc_Registrar::ACE_Dynamic_Svc_Registrar (const ACE_TCHAR* alloc_name, + void* svc_allocator) +{ + // register service allocator function by full name in ACE singleton registry + ACE::ldregister (alloc_name, svc_allocator); +} +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Object.h b/dep/acelite/ace/Service_Object.h new file mode 100644 index 000000000..37803f5f5 --- /dev/null +++ b/dep/acelite/ace/Service_Object.h @@ -0,0 +1,207 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Service_Object.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SERVICE_OBJECT_H +#define ACE_SERVICE_OBJECT_H +#include /**/ "ace/pre.h" + +#include "ace/Shared_Object.h" +#include "ace/Svc_Conf_Tokens.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event_Handler.h" +#include "ace/DLL.h" + +#include "ace/Service_Gestalt.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#define ACE_Component ACE_Service_Object + +/** + * @class ACE_Service_Object + * + * @brief Provide the abstract base class common to all service + * implementations. + * + * Classes that inherit from ACE_Service_Objects are capable + * of being registered with the ACE_Reactor (due to the + * ACE_Event_Handler, as well as being dynamically linked by + * the ACE_Service_Config (due to the ACE_Shared_Object). + */ +class ACE_Export ACE_Service_Object + : public ACE_Event_Handler, + public ACE_Shared_Object +{ +public: + // = Initialization and termination methods. + /// Constructor. + ACE_Service_Object (ACE_Reactor * = 0); + + /// Destructor. + virtual ~ACE_Service_Object (void); + + /// Temporarily disable a service without removing it completely. + virtual int suspend (void); + + /// Re-enable a previously suspended service. + virtual int resume (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +// Forward decl. +class ACE_Service_Type_Impl; + +/** + * @class ACE_Service_Type + * + * @brief Keeps track of information related to the various + * ACE_Service_Type_Impl subclasses. + * + * This class acts as the interface of the "Bridge" pattern. + */ +class ACE_Export ACE_Service_Type +{ +public: + enum + { + /// Delete the payload object. + DELETE_OBJ = 1, + + /// Delete the enclosing object. + DELETE_THIS = 2 + }; + + enum + { + SERVICE_OBJECT = ACE_SVC_OBJ_T, + MODULE = ACE_MODULE_T, + STREAM = ACE_STREAM_T, + INVALID_TYPE = -1 + }; + + // = Initialization and termination methods. + ACE_Service_Type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *o, + const ACE_DLL &dll, + bool active); + ACE_Service_Type (const ACE_TCHAR *n, + ACE_Service_Type_Impl *o, + ACE_SHLIB_HANDLE handle, + bool active); + ~ACE_Service_Type (void); + + const ACE_TCHAR *name (void) const; + void name (const ACE_TCHAR *); + + const ACE_Service_Type_Impl *type (void) const; + void type (const ACE_Service_Type_Impl *, bool active = true); + + /// Is this just a stub for the real thing? + bool is_forward_declaration (void) const; + + int suspend (void) const; + int resume (void) const; + bool active (void) const; + void active (bool turnon); + + /// Calls @c fini on @c type_ + int fini (void); + + /// Check if the service has been fini'ed. + bool fini_called (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Get to the DLL's implentation + const ACE_DLL & dll (void) const; + + /// Sets the DLL + void dll (const ACE_DLL&); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Humanly readible name of svc. + const ACE_TCHAR *name_; + + /// Pointer to C++ object that implements the svc. + const ACE_Service_Type_Impl *type_; + + /// ACE_DLL representing the shared object file (non-zero if + /// dynamically linked). + mutable ACE_DLL dll_; + + /// true if svc is currently active, otherwise false. + bool active_; + + /// true if @c fini on @c type_ has already been called, otherwise false. + bool fini_already_called_; +}; + +/** + * @class ACE_Service_Object_Ptr + * + * @brief This is a smart pointer that holds onto the associated + * ACE_Service_Object * until the current scope is left, at + * which point the object's fini() hook is called and the + * service_object_ gets deleted. + * + * This class is similar to the Standard C++ Library class + * auto_ptr. It is used in conjunction with statically linked + * ACE_Service_Objects, as shown in the ./netsvcs/server/main.cpp example. + */ +class ACE_Export ACE_Service_Object_Ptr +{ +public: + // = Initialization and termination methods. + /// Acquire ownership of the @a so. + ACE_Service_Object_Ptr (ACE_Service_Object *so); + + /// Release the held ACE_Service_Object by calling its fini() hook. + ~ACE_Service_Object_Ptr (void); + + /// Smart pointer to access the underlying ACE_Service_Object. + ACE_Service_Object *operator-> (); + +private: + /// Holds the service object until we're done. + ACE_Service_Object *service_object_; +}; + +#if defined (ACE_OPENVMS) +/** + * @class ACE_Dynamic_Svc_Registrar + * + * @brief Used to register Service allocator function by its full name. + */ +class ACE_Dynamic_Svc_Registrar +{ +public: + ACE_Dynamic_Svc_Registrar (const ACE_TCHAR* alloc_name, + void* svc_allocator); +}; +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Service_Object.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SERVICE_OBJECT_H */ diff --git a/dep/acelite/ace/Service_Object.inl b/dep/acelite/ace/Service_Object.inl new file mode 100644 index 000000000..e5c5099f0 --- /dev/null +++ b/dep/acelite/ace/Service_Object.inl @@ -0,0 +1,77 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ACE_Service_Object_Ptr::ACE_Service_Object_Ptr (ACE_Service_Object *so) + : service_object_ (so) +{ +} + +ACE_INLINE ACE_Service_Object_Ptr::~ACE_Service_Object_Ptr (void) +{ + this->service_object_->fini (); + delete this->service_object_; +} + +ACE_INLINE ACE_Service_Object * +ACE_Service_Object_Ptr::operator-> () +{ + return this->service_object_; +} + +ACE_INLINE const ACE_TCHAR * +ACE_Service_Type::name (void) const +{ + ACE_TRACE ("ACE_Service_Type::name"); + return this->name_; +} + +ACE_INLINE const ACE_Service_Type_Impl * +ACE_Service_Type::type (void) const +{ + ACE_TRACE ("ACE_Service_Type::type"); + return this->type_; +} + +ACE_INLINE void +ACE_Service_Type::type (const ACE_Service_Type_Impl *o, bool enabled) +{ + ACE_TRACE ("ACE_Service_Type::type"); + this->type_ = o; + ((ACE_Service_Type *) this)->active_ = enabled; +} + +ACE_INLINE bool +ACE_Service_Type::active (void) const +{ + ACE_TRACE ("ACE_Service_Type::active"); + return this->active_; +} + +ACE_INLINE void +ACE_Service_Type::active (bool turnon) +{ + ACE_TRACE ("ACE_Service_Type::active"); + this->active_ = turnon; +} + +ACE_INLINE bool +ACE_Service_Type::fini_called (void) const +{ + ACE_TRACE ("ACE_Service_Type::fini_called"); + return this->fini_already_called_; +} + +ACE_INLINE const ACE_DLL & ACE_Service_Type::dll () const +{ + ACE_TRACE ("ACE_Service_Type::dll"); + return this->dll_; +} + +ACE_INLINE void ACE_Service_Type::dll (const ACE_DLL &adll) +{ + ACE_TRACE ("ACE_Service_Type::dll"); + this->dll_ = adll; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + diff --git a/dep/acelite/ace/Service_Repository.cpp b/dep/acelite/ace/Service_Repository.cpp new file mode 100644 index 000000000..6c5fb03df --- /dev/null +++ b/dep/acelite/ace/Service_Repository.cpp @@ -0,0 +1,622 @@ +#include "ace/Service_Repository.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Service_Repository.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Service_Types.h" +#include "ace/Object_Manager.h" +#include "ace/Log_Category.h" +#include "ace/ACE.h" +#include "ace/OS_NS_unistd.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository) + +/// Process-wide Service Repository. +ACE_Service_Repository *ACE_Service_Repository::svc_rep_ = 0; + +/// Controls whether the Service_Repository is deleted when we shut +/// down (we can only delete it safely if we created it)! +bool ACE_Service_Repository::delete_svc_rep_ = false; + +void +ACE_Service_Repository::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Repository::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Service_Repository * +ACE_Service_Repository::instance (size_t size) +{ + ACE_TRACE ("ACE_Service_Repository::instance"); + + if (ACE_Service_Repository::svc_rep_ == 0) + { + // Perform Double-Checked Locking Optimization. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + if (ACE_Service_Repository::svc_rep_ == 0) + { + if (ACE_Object_Manager::starting_up () || + !ACE_Object_Manager::shutting_down ()) + { + ACE_NEW_RETURN (ACE_Service_Repository::svc_rep_, + ACE_Service_Repository (size), + 0); + ACE_Service_Repository::delete_svc_rep_ = true; + } + } + } + + return ACE_Service_Repository::svc_rep_; +} + +ACE_Service_Repository * +ACE_Service_Repository::instance (ACE_Service_Repository *s) +{ + ACE_TRACE ("ACE_Service_Repository::instance"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + + ACE_Service_Repository *t = ACE_Service_Repository::svc_rep_; + // We can't safely delete it since we don't know who created it! + ACE_Service_Repository::delete_svc_rep_ = false; + + ACE_Service_Repository::svc_rep_ = s; + return t; +} + +void +ACE_Service_Repository::close_singleton (void) +{ + ACE_TRACE ("ACE_Service_Repository::close_singleton"); + + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance ())); + + if (ACE_Service_Repository::delete_svc_rep_) + { + delete ACE_Service_Repository::svc_rep_; + ACE_Service_Repository::svc_rep_ = 0; + ACE_Service_Repository::delete_svc_rep_ = false; + } +} + +/// Initialize the Repository to a clean slate. +int +ACE_Service_Repository::open (size_t size) +{ + ACE_TRACE ("ACE_Service_Repository::open"); + + // Create a new array and swap it with the local array + array_type local_array (size); + this->service_array_.swap (local_array); + + return 0; +} + +ACE_Service_Repository::ACE_Service_Repository (size_t size) + : service_array_ (size) +{ + ACE_TRACE ("ACE_Service_Repository::ACE_Service_Repository"); +} + + +/// Finalize (call fini() and possibly delete) all the services. + +int +ACE_Service_Repository::fini (void) +{ + ACE_TRACE ("ACE_Service_Repository::fini"); + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + + int retval = 0; + // Do not be tempted to use the prefix decrement operator. Use + // postfix decrement operator since the index is unsigned and may + // wrap around the 0 + // + // debug output for empty service entries +#ifndef ACE_NLOGGING + if (ACE::debug ()) + { + for (size_t i = this->service_array_.size (); i-- != 0;) + { + ACE_Service_Type *s = + const_cast (this->service_array_[i]); + if (s == 0) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d] -> 0\n"), + this, + i)); + } + } +#endif + // + // Remove all the Service_Object and Stream instances + // + for (size_t i = this->service_array_.size (); i-- != 0;) + { + // the services in reverse order. + ACE_Service_Type *s = + const_cast (this->service_array_[i]); + + if (s != 0 && + s->type () != 0 && + (s->type ()->service_type () != ACE_Service_Type::MODULE)) + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d], ") + ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"), + this, + i, + s->name (), + s->type (), + (s->type () != 0) ? s->type ()->object () : 0, + s->active ())); + } +#endif + + // Collect any errors. + retval += s->fini (); + } + } + // + // Remove all the Module instances + // + for (size_t i = this->service_array_.size (); i-- != 0;) + { + // the services in reverse order. + ACE_Service_Type *s = + const_cast (this->service_array_[i]); + + if (s != 0 && + s->type () != 0 && + (s->type ()->service_type () == ACE_Service_Type::MODULE)) + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::fini, repo=%@ [%d], ") + ACE_TEXT ("name=%s, type=%@, object=%@, active=%d\n"), + this, + i, + s->name (), + s->type (), + (s->type () != 0) ? s->type ()->object () : 0, + s->active ())); + } +#endif + // Collect any errors. + retval += s->fini (); + } + } + return (retval == 0) ? 0 : -1; +} + + +/// Close down all the services. +int +ACE_Service_Repository::close (void) +{ + ACE_TRACE ("ACE_Service_Repository::close"); + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + +#ifndef ACE_NLOGGING + if(ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@, size=%d\n"), + this, + this->service_array_.size())); +#endif + + // Do not use the prefix decrement operator since the index is + // unsigned and may wrap around the 0. + for (size_t i = this->service_array_.size(); i-- != 0; ) + { + // Delete services in reverse order. + ACE_Service_Type *s = + const_cast (this->service_array_[i]); + +#ifndef ACE_NLOGGING + if(ACE::debug ()) + { + if (s == 0) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d] -> 0\n"), + this, + i)); + else + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::close - repo=%@ [%d], name=%s, object=%@\n"), + this, + i, + s->name (), + s)); + } +#endif + delete s; + } + + this->service_array_.clear (); + + return 0; +} + +ACE_Service_Repository::~ACE_Service_Repository (void) +{ + ACE_TRACE ("ACE_Service_Repository::~ACE_Service_Repository"); +#ifndef ACE_NLOGGING + if(ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, "ACE (%P|%t) SR::, this=%@\n", this)); +#endif + this->close (); +} + +/// Locate an entry with @a name in the table. If @a ignore_suspended is +/// set then only consider services marked as resumed. If the caller +/// wants the located entry, pass back a pointer to the located entry +/// via @a srp. If @a name is not found -1 is returned. If @a name is +/// found, but it is suspended and the caller wants to ignore suspended +/// services a -2 is returned. Must be called with locks held. +int +ACE_Service_Repository::find_i (const ACE_TCHAR name[], + size_t &slot, + const ACE_Service_Type **srp, + bool ignore_suspended) const +{ + ACE_TRACE ("ACE_Service_Repository::find_i"); + size_t i = 0; + array_type::const_iterator element = this->service_array_.end (); + + for (i = 0; i < this->service_array_.size(); i++) + { + array_type::const_iterator iter = this->service_array_.find (i); + if (iter != this->service_array_.end () + && (*iter).second != 0 // skip any empty slots + && ACE_OS::strcmp (name, (*iter).second->name ()) == 0) + { + element = iter; + break; + } + } + + if (element != this->service_array_.end ()) + { + slot = i; + if ((*element).second->fini_called ()) + { + if (srp != 0) + *srp = 0; + return -1; + } + + if (srp != 0) + *srp = (*element).second; + + if (ignore_suspended + && (*element).second->active () == 0) + return -2; + + return 0; + } + + return -1; +} + + +/// @brief Relocate (a static) service to another DLL. +/// +/// Works by having the service type keep a reference to a specific +/// DLL. No locking, caller makes sure calling it is safe. You can +/// forcefully relocate any DLLs in the given range, not only the +/// static ones - but that will cause Very Bad Things (tm) to happen. +int +ACE_Service_Repository::relocate_i (size_t begin, + size_t end, + const ACE_DLL& adll) +{ + ACE_SHLIB_HANDLE new_handle = adll.get_handle (0); + + for (size_t i = begin; i < end; i++) + { + ACE_Service_Type *type = + const_cast (this->service_array_[i]); + + ACE_SHLIB_HANDLE old_handle = (type == 0) ? ACE_SHLIB_INVALID_HANDLE + : type->dll ().get_handle (0); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + { + if (type == 0) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]") + ACE_TEXT (": skipping empty slot\n"), + this, + i)); + else + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]") + ACE_TEXT (": trying name=%s, handle: %d -> %d\n"), + this, + i, + type->name (), + old_handle, + new_handle)); + } +#endif + + if (type != 0 // skip any gaps + && old_handle == ACE_SHLIB_INVALID_HANDLE + && new_handle != old_handle) + { +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::relocate_i - repo=%@ [%d]") + ACE_TEXT (": relocating name=%s, handle: %d -> %d\n"), + this, + i, + type->name (), + old_handle, + new_handle)); +#endif + type->dll (adll); // ups the refcount on adll + } + } + + return 0; +} + +int +ACE_Service_Repository::find (const ACE_TCHAR name[], + const ACE_Service_Type **srp, + bool ignore_suspended) const +{ + ACE_TRACE ("ACE_Service_Repository::find"); + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + size_t ignore_location = 0; + return this->find_i (name, ignore_location, srp, ignore_suspended); +} + +/// Insert the ACE_Service_Type SR into the repository. Note that +/// services may be inserted either resumed or suspended. Using same +/// name as in an existing service causes the delete () to be called +/// for the old one, i.e. make sure @code sr is allocated on the heap! +int +ACE_Service_Repository::insert (const ACE_Service_Type *sr) +{ + ACE_TRACE ("ACE_Service_Repository::insert"); + + size_t i = 0; + int return_value = -1; + ACE_Service_Type const *s = 0; + + // Establish scope for locking while manipulating the service + // storage + { + // @TODO: Do we need a recursive mutex here? + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, + ace_mon, this->lock_, -1); + + return_value = find_i (sr->name (), i, &s, false); + + // Adding an entry. + if (s != 0) + { + this->service_array_[i] = sr; + } + else + { + // New services are always added where current_size_ points, + // because if any DLL relocation needs to happen, it will be + // performed on services with indexes between some old + // current_size_ and the new current_size_ value. See + // ACE_Service_Type_Dynamic_Guard ctor and dtor for details. + + if (i < this->service_array_.size ()) + i = this->service_array_.size (); + + this->service_array_[i] = sr; + return_value = 0; + } + } +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::insert - repo=%@ [%d],") + ACE_TEXT (" name=%s (%C) (type=%@, object=%@, active=%d)\n"), + this, + i, + sr->name(), + (return_value == 0 ? ((s==0) ? "new" : "replacing") : "failed"), + sr->type (), + (sr->type () != 0) ? sr->type ()->object () : 0, + sr->active ())); +#endif + + // If necessary, delete but outside the lock. (s may be 0, but + // that's okay, too) + delete s; + + if (return_value == -1) + ACE_OS::last_error (ENOSPC); + + return return_value; +} + +/// Resume a service that was previously suspended. +int +ACE_Service_Repository::resume (const ACE_TCHAR name[], + const ACE_Service_Type **srp) +{ + ACE_TRACE ("ACE_Service_Repository::resume"); + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + + size_t i = 0; + if (-1 == this->find_i (name, i, srp, 0)) + return -1; + + return this->service_array_[i]->resume (); +} + +/// Suspend a service so that it will not be considered active under +/// most circumstances by other portions of the ACE_Service_Repository. +int +ACE_Service_Repository::suspend (const ACE_TCHAR name[], + const ACE_Service_Type **srp) +{ + ACE_TRACE ("ACE_Service_Repository::suspend"); + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + size_t i = 0; + if (-1 == this->find_i (name, i, srp, 0)) + return -1; + + return this->service_array_[i]->suspend (); +} + +/** + * @brief Completely remove a @a name entry from the Repository and + * dynamically unlink it if it was originally dynamically linked. + */ +int +ACE_Service_Repository::remove (const ACE_TCHAR name[], ACE_Service_Type **ps) +{ + ACE_TRACE ("ACE_Service_Repository::remove"); + ACE_Service_Type *s = 0; + { + ACE_GUARD_RETURN (ACE_SYNCH_RECURSIVE_MUTEX, ace_mon, this->lock_, -1); + + // Not found!? + if (this->remove_i (name, &s) == -1) + return -1; + } + + if (ps != 0) + *ps = s; + else + delete s; + return 0; +} + +/** + * @brief Completely remove a @a name entry from the Repository and + * dynamically unlink it if it was originally dynamically linked. + * + * Return a ptr to the entry in @code ps. There is no locking so make + * sure you hold the repo lock when calling. + * + * Since the order of services in the Respository matters, we can't + * simply overwrite the entry being deleted with the last and + * decrement the @c current_size by 1. A good example of why the order + * matters is a dynamic service, in whose DLL there is at least one + * static service. In order to prevent SEGV during finalization, those + * static services must be finalized _before_the dynamic service that + * owns them. Otherwice the TEXT segment, containing the code for the + * static service's desructor may be unloaded with the DLL. + * + * Neither can we "pack" the array because this may happen inside the + * scope of a Service_Dynamic_Guard, which caches an index where + * loading of a DLL started in order to relocate dependent services. + */ +int +ACE_Service_Repository::remove_i (const ACE_TCHAR name[], ACE_Service_Type **ps) +{ + size_t i = 0; + if (-1 == this->find_i (name, i, 0, false)) + return -1; // Not found + + // We may need the old ptr - to be delete outside the lock! + *ps = const_cast (this->service_array_[i]); + +#ifndef ACE_NLOGGING + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("ACE (%P|%t) SR::remove_i - repo=%@ [%d],") + ACE_TEXT (" name=%s (removed) (type=%@, active=%d)\n"), + this, + i, + name, + *ps, + (*ps)->active ())); +#endif + + this->service_array_[i] = 0; // simply leave a gap + return 0; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Repository_Iterator) + +void +ACE_Service_Repository_Iterator::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Repository_Iterator::dump"); +#endif /* ACE_HAS_DUMP */ +} + +/// Initializes the iterator and skips over any suspended entries at +/// the beginning of the table, if necessary. Note, you must not +/// perform destructive operations on elements during this iteration... +ACE_Service_Repository_Iterator::ACE_Service_Repository_Iterator + (ACE_Service_Repository &sr, bool ignored_suspended) + : svc_rep_ (sr), + next_ (0), + ignore_suspended_ (ignored_suspended) +{ + while (!(done() || valid())) + this->next_++; +} + +/// Obtains a pointer to the next valid service in the table. If there +/// are no more entries, returns 0, else 1. +int +ACE_Service_Repository_Iterator::next (const ACE_Service_Type *&sr) +{ + ACE_TRACE ("ACE_Service_Repository_Iterator::next"); + + if (done ()) + return 0; + + sr = this->svc_rep_.service_array_[this->next_]; + return 1; +} + +/// Advance the iterator by the proper amount. If we are ignoring +/// suspended entries and the current entry is suspended, then we must +/// skip over this entry. Otherwise, we must advance the NEXT index to +/// reference the next valid service entry. +int +ACE_Service_Repository_Iterator::advance (void) +{ + ACE_TRACE ("ACE_Service_Repository_Iterator::advance"); + + if (done()) return 0; + + do this->next_++; while (!(done () || valid ())); + + return !done(); +} + +bool +ACE_Service_Repository_Iterator::valid (void) const +{ + ACE_TRACE ("ACE_Service_Repository_Iterator::valid"); + if (!this->ignore_suspended_) + return (this->svc_rep_.service_array_[this->next_] != 0); // skip over gaps + + return (this->svc_rep_.service_array_[this->next_] != 0 + && this->svc_rep_.service_array_[this->next_]->active ()); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Repository.h b/dep/acelite/ace/Service_Repository.h new file mode 100644 index 000000000..8b3af28c1 --- /dev/null +++ b/dep/acelite/ace/Service_Repository.h @@ -0,0 +1,276 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Service_Repository.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SERVICE_REPOSITORY_H +#define ACE_SERVICE_REPOSITORY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Default_Constants.h" +#include "ace/Synch_Traits.h" +#include "ace/Array_Map.h" +#include "ace/Malloc_Base.h" +#include "ace/Recursive_Thread_Mutex.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Service_Type; +class ACE_DLL; + +#define ACE_Component_Repository ACE_Service_Repository +/** + * @class ACE_Service_Repository + * + * @brief Contains all the services offered by a Service + * Configurator-based application. + * + * This class contains a vector of ACE_Service_Types *'s and + * allows an administrative entity to centrally manage and + * control the behavior of application services. Note that if + * services are removed from the middle of the repository the + * order won't necessarily be maintained since the @a remove + * method performs compaction. However, the common case is not + * to remove services, so typically they are deleted in the + * reverse order that they were added originally. + */ +class ACE_Export ACE_Service_Repository +{ +public: + friend class ACE_Service_Repository_Iterator; + + enum + { + DEFAULT_SIZE = ACE_DEFAULT_SERVICE_REPOSITORY_SIZE + }; + + // = Initialization and termination methods. + /// Initialize the repository. + ACE_Service_Repository (size_t size = DEFAULT_SIZE); + + /// Initialize the repository. + int open (size_t size = DEFAULT_SIZE); + + /// Close down the repository and free up dynamically allocated + /// resources. + ~ACE_Service_Repository (void); + + /// Close down the repository and free up dynamically allocated + /// resources. + int close (void); + + /// Finalize all the services by calling fini() and deleting + /// dynamically allocated services. + int fini (void); + + /// Get pointer to a process-wide ACE_Service_Repository. + static ACE_Service_Repository * instance + (size_t size = ACE_Service_Repository::DEFAULT_SIZE); + + /// Set pointer to a process-wide ACE_Service_Repository and return + /// existing pointer. + static ACE_Service_Repository *instance (ACE_Service_Repository *); + + /// Delete the dynamically allocated Singleton. + static void close_singleton (void); + + // = Search structure operations (all acquire locks as necessary). + + /// Insert a new service record. Returns -1 when the service repository + /// is full and 0 on success. + int insert (const ACE_Service_Type *sr); + + /** + * Locate a named entry in the service table, optionally ignoring + * suspended entries. + * + * @param name The name of the service to search for. + * @param srp Optional; if not 0, it is a pointer to a location + * to receive the ACE_Service_Type pointer for the + * located service. Meaningless if this method + * returns -1. + * @param ignore_suspended If true, the search ignores suspended services. + * + * @retval 0 Named service was located. + * @retval -1 Named service was not found. + * @retval -2 Named service was found, but is suspended and + * @a ignore_suspended is true. + */ + int find (const ACE_TCHAR name[], + const ACE_Service_Type **srp = 0, + bool ignore_suspended = true) const; + + /// Remove an existing service record. If @a sr == 0, the service record + /// is deleted before control is returned to the caller. If @a sr != 0, + /// the service's record is removed from the repository, but not deleted; + /// *sr receives the service record pointer and the caller is responsible + /// for properly disposing of it. + int remove (const ACE_TCHAR name[], ACE_Service_Type **sr = 0); + + // = Liveness control + /// Resume a service record. + int resume (const ACE_TCHAR name[], const ACE_Service_Type **srp = 0); + + /// Suspend a service record. + int suspend (const ACE_TCHAR name[], const ACE_Service_Type **srp = 0); + + /// Return the current size of the repository. + size_t current_size (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Returns a reference to the lock used by the ACE_Service_Repository + ACE_SYNCH_RECURSIVE_MUTEX &lock (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + + friend class ACE_Service_Type_Dynamic_Guard; + + /// Remove an existing service record. It requires @a sr != 0, which + /// receives the service record pointer and the caller is + /// responsible for properly disposing of it. + int remove_i (const ACE_TCHAR[], ACE_Service_Type **sr); + + /** + * Locate a named entry in the service table, optionally ignoring + * suspended entries. + * + * @param service_name The name of the service to search for. + * @param slot Receives the position index of the service if it + * is found. Contents are meaningless if this method + * returns -1. + * @param srp Optional; if not 0, it is a pointer to a location + * to receive the ACE_Service_Type pointer for the + * located service. Meaningless if this method + * returns -1. + * @param ignore_suspended If true, the search ignores suspended services. + * + * @retval 0 Named service was located; index in the table is set in + * @a slot. + * @retval -1 Named service was not found. + * @retval -2 Named service was found, but is suspended and + * @a ignore_suspended is true. + */ + int find_i (const ACE_TCHAR service_name[], + size_t &slot, + const ACE_Service_Type **srp = 0, + bool ignore_suspended = true) const; + + /// @brief Relocate (static) services to another DLL. + /// + /// If any have been registered in the context of a "forward + /// declaration" guard, those really aren't static services. Their + /// code is in the DLL's code segment, or in one of the dependent + /// DLLs. Therefore, such services need to be associated with the + /// proper DLL in order to prevent failures upon finalization. The + /// method locks the repo. + /// + /// Works by having the service type keep a reference to a specific + /// DLL. No locking, caller makes sure calling it is safe. You can + /// forcefully relocate any DLLs in the given range, not only the + /// static ones - but that will cause Very Bad Things (tm) to happen. + int relocate_i (size_t begin, + size_t end, + const ACE_DLL &adll); + + /// The typedef of the array used to store the services. +#if defined (ACE_HAS_ALLOC_HOOKS) + typedef ACE_Array_Map, ACE_Allocator_Std_Adapter > > array_type; +#else + typedef ACE_Array_Map array_type; +#endif /* ACE_HAS_ALLOC_HOOKS */ + + /// Contains all the configured services. + array_type service_array_; + + /// Pointer to a process-wide ACE_Service_Repository. + static ACE_Service_Repository *svc_rep_; + + /// Must delete the @c svc_rep_ if true. + static bool delete_svc_rep_; + + /// Synchronization variable for the ACE_Service_Repository. + mutable ACE_SYNCH_RECURSIVE_MUTEX lock_; +}; + +/** + * @class ACE_Service_Repository_Iterator + * + * @brief Iterate through the ACE_Service_Repository. + * + * Make sure not to delete entries as the iteration is going on + * since this class is not designed as a robust iterator. + */ +class ACE_Export ACE_Service_Repository_Iterator +{ +public: + // = Initialization and termination methods. + /// Constructor initializes the iterator. + ACE_Service_Repository_Iterator (ACE_Service_Repository &sr, + bool ignored_suspended = true); + + /// Destructor. + ~ACE_Service_Repository_Iterator (void); + + +public: + // = Iteration methods. + + /// Pass back the @a next_item that hasn't been seen in the repository. + /// Returns 0 when all items have been seen, else 1. + int next (const ACE_Service_Type *&next_item); + + /// Returns 1 when all items have been seen, else 0. + int done (void) const; + + /// Move forward by one element in the repository. Returns 0 when all the + /// items in the set have been seen, else 1. + int advance (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + bool valid (void) const; + +private: + ACE_Service_Repository_Iterator (const ACE_Service_Repository_Iterator&); + + /// Reference to the Service Repository we are iterating over. + ACE_Service_Repository &svc_rep_; + + /// Next index location that we haven't yet seen. + size_t next_; + + /// Are we ignoring suspended services? + bool const ignore_suspended_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Service_Repository.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* _SERVICE_REPOSITORY_H */ diff --git a/dep/acelite/ace/Service_Repository.inl b/dep/acelite/ace/Service_Repository.inl new file mode 100644 index 000000000..9cbd38821 --- /dev/null +++ b/dep/acelite/ace/Service_Repository.inl @@ -0,0 +1,41 @@ +// -*- C++ -*- +// Returns a count of the number of currently valid entries (counting +// both resumed and suspended entries). + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) +#include "ace/Guard_T.h" +#include "ace/Thread_Mutex.h" +#endif /* ACE_MT_SAFE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE size_t +ACE_Service_Repository::current_size (void) const +{ + ACE_TRACE ("ACE_Service_Repository::current_size"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, + ace_mon, + (ACE_Recursive_Thread_Mutex &) this->lock_, 0)); + return this->service_array_.size (); +} + +ACE_INLINE ACE_SYNCH_RECURSIVE_MUTEX& +ACE_Service_Repository::lock (void) const +{ + return this->lock_; +} + +ACE_INLINE int +ACE_Service_Repository_Iterator::done (void) const +{ + ACE_TRACE ("ACE_Service_Repository_Iterator::done"); + + return this->next_ >= this->svc_rep_.current_size (); +} + +ACE_INLINE +ACE_Service_Repository_Iterator::~ACE_Service_Repository_Iterator (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Types.cpp b/dep/acelite/ace/Service_Types.cpp new file mode 100644 index 000000000..1d835685e --- /dev/null +++ b/dep/acelite/ace/Service_Types.cpp @@ -0,0 +1,463 @@ +#include "ace/Service_Types.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Service_Types.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Stream_Modules.h" +#include "ace/Stream.h" +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +typedef ACE_Stream MT_Stream; +typedef ACE_Module MT_Module; +typedef ACE_Task MT_Task; + +ACE_ALLOC_HOOK_DEFINE(ACE_Service_Type_Impl) + +void +ACE_Service_Type_Impl::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Service_Type_Impl::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Service_Type_Impl::ACE_Service_Type_Impl (void *so, + const ACE_TCHAR *s_name, + u_int f, + ACE_Service_Object_Exterminator gobbler, + int stype) + : name_ (0), + obj_ (so), + gobbler_ (gobbler), + flags_ (f), + service_type_ (stype) +{ + ACE_TRACE ("ACE_Service_Type_Impl::ACE_Service_Type_Impl"); + this->name (s_name); +} + +ACE_Service_Type_Impl::~ACE_Service_Type_Impl (void) +{ + ACE_TRACE ("ACE_Service_Type_Impl::~ACE_Service_Type_Impl"); + + // It's ok to call this, even though we may have already deleted it + // in the fini() method since it would then be NULL. +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(const_cast (this->name_)); +#else + delete [] const_cast (this->name_); +#endif /* ACE_HAS_ALLOC_HOOKS */ +} + +int +ACE_Service_Type_Impl::fini (void) const +{ + ACE_TRACE ("ACE_Service_Type_Impl::fini"); + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free(const_cast (this->name_)); +#else + delete [] const_cast (this->name_); +#endif /* ACE_HAS_ALLOC_HOOKS */ + (const_cast (this))->name_ = 0; + + if (ACE_BIT_ENABLED (this->flags_, + ACE_Service_Type::DELETE_OBJ)) + { + if (gobbler_ != 0) + gobbler_ (this->object ()); + else + // Cast to remove const-ness. + operator delete ((void *) this->object ()); + } + + if (ACE_BIT_ENABLED (this->flags_, + ACE_Service_Type::DELETE_THIS)) + delete const_cast (this); + + return 0; +} + +ACE_Service_Object_Type::ACE_Service_Object_Type (void *so, + const ACE_TCHAR *s_name, + u_int f, + ACE_Service_Object_Exterminator gobbler, + int stype) + : ACE_Service_Type_Impl (so, s_name, f, gobbler, stype) + , initialized_ (-1) +{ + ACE_TRACE ("ACE_Service_Object_Type::ACE_Service_Object_Type"); +} + +int +ACE_Service_Object_Type::init (int argc, ACE_TCHAR *argv[]) const +{ + ACE_TRACE ("ACE_Service_Object_Type::init"); + + void * const obj = this->object (); + + ACE_Service_Object * const so = + static_cast (obj); + + if (so == 0) + return -1; + + this->initialized_ = so->init (argc, argv); + + return this->initialized_; +} + +int +ACE_Service_Object_Type::fini (void) const +{ + ACE_TRACE ("ACE_Service_Object_Type::fini"); + + void * const obj = this->object (); + + ACE_Service_Object * const so = + static_cast (obj); + + // Call fini() if an only if, the object was successfuly + // initialized, i.e. init() returned 0. This is necessary to + // maintain the ctor/dtor-like semantics for init/fini. + if (so != 0 && this->initialized_ == 0) + so->fini (); + + return ACE_Service_Type_Impl::fini (); +} + +ACE_Service_Object_Type::~ACE_Service_Object_Type (void) +{ + ACE_TRACE ("ACE_Service_Object_Type::~ACE_Service_Object_Type"); +} + +int +ACE_Service_Object_Type::suspend (void) const +{ + ACE_TRACE ("ACE_Service_Object_Type::suspend"); + return static_cast (this->object ())->suspend (); +} + +int +ACE_Service_Object_Type::resume (void) const +{ + ACE_TRACE ("ACE_Service_Object_Type::resume"); + return static_cast (this->object ())->resume (); +} + +int +ACE_Service_Object_Type::info (ACE_TCHAR **str, size_t len) const +{ + ACE_TRACE ("ACE_Service_Object_Type::info"); + return static_cast (this->object ())->info (str, len); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Module_Type) + +void +ACE_Module_Type::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Module_Type::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Module_Type::ACE_Module_Type (void *m, + const ACE_TCHAR *m_name, + u_int f, + int stype) + : ACE_Service_Type_Impl (m, m_name, f, 0, stype) + , link_ (0) +{ + ACE_TRACE ("ACE_Module_Type::ACE_Module_Type"); +} + +ACE_Module_Type::~ACE_Module_Type (void) +{ + ACE_TRACE ("ACE_Module_Type::~ACE_Module_Type"); +} + +int +ACE_Module_Type::init (int argc, ACE_TCHAR *argv[]) const +{ + ACE_TRACE ("ACE_Module_Type::init"); + void *obj = this->object (); + MT_Module *mod = (MT_Module *) obj; + // + // Change the Module's name to what's in the svc.conf file. We must + // do this so the names match up so everything shuts down properly + // during the call to ACE_Stream_Type::fini which calls + // MT_Stream::remove([name]) for all the modules. If the calls to + // remove fail, we end up with a double delete during + // shutdown. Bugzilla #3847 + // + mod->name (this->name_); + MT_Task *reader = mod->reader (); + MT_Task *writer = mod->writer (); + + if (reader->init (argc, argv) == -1 + || writer->init (argc, argv) == -1) + return -1; + else + return 0; +} + +int +ACE_Module_Type::suspend (void) const +{ + ACE_TRACE ("ACE_Module_Type::suspend"); + void *obj = this->object (); + MT_Module *mod = (MT_Module *) obj; + MT_Task *reader = mod->reader (); + MT_Task *writer = mod->writer (); + + if (reader->suspend () == -1 + || writer->suspend () == -1) + return -1; + else + return 0; +} + +int +ACE_Module_Type::resume (void) const +{ + ACE_TRACE ("ACE_Module_Type::resume"); + void *obj = this->object (); + MT_Module *mod = (MT_Module *) obj; + MT_Task *reader = mod->reader (); + MT_Task *writer = mod->writer (); + + if (reader->resume () == -1 + || writer->resume () == -1) + return -1; + else + return 0; +} + +// Note, these operations are somewhat too familiar with the +// implementation of ACE_Module and ACE_Module::close... + +int +ACE_Module_Type::fini (void) const +{ + ACE_TRACE ("ACE_Module_Type::fini"); + void *obj = this->object (); + MT_Module *mod = (MT_Module *) obj; + MT_Task *reader = mod->reader (); + MT_Task *writer = mod->writer (); + + if (reader != 0) + reader->fini (); + + if (writer != 0) + writer->fini (); + + // Close the module and delete the memory. + mod->close (MT_Module::M_DELETE); + return ACE_Service_Type_Impl::fini (); +} + +int +ACE_Module_Type::info (ACE_TCHAR **str, size_t len) const +{ + ACE_TRACE ("ACE_Module_Type::info"); + ACE_TCHAR buf[BUFSIZ]; + + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%s\t %s"), + this->name (), + ACE_TEXT ("# ACE_Module\n")); + + if (*str == 0 && (*str = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strsncpy (*str, buf, len); + return static_cast (ACE_OS::strlen (buf)); +} + +void +ACE_Module_Type::link (ACE_Module_Type *n) +{ + ACE_TRACE ("ACE_Module_Type::link"); + this->link_ = n; +} + +ACE_Module_Type * +ACE_Module_Type::link (void) const +{ + ACE_TRACE ("ACE_Module_Type::link"); + return this->link_; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Stream_Type) + +void +ACE_Stream_Type::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Stream_Type::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Stream_Type::init (int, ACE_TCHAR *[]) const +{ + ACE_TRACE ("ACE_Stream_Type::init"); + return 0; +} + +int +ACE_Stream_Type::suspend (void) const +{ + ACE_TRACE ("ACE_Stream_Type::suspend"); + + for (ACE_Module_Type *m = this->head_; + m != 0; + m = m->link ()) + m->suspend (); + + return 0; +} + +int +ACE_Stream_Type::resume (void) const +{ + ACE_TRACE ("ACE_Stream_Type::resume"); + + for (ACE_Module_Type *m = this->head_; + m != 0; + m = m->link ()) + m->resume (); + + return 0; +} + +ACE_Stream_Type::ACE_Stream_Type (void *s, + const ACE_TCHAR *s_name, + u_int f, + int stype) + : ACE_Service_Type_Impl (s, s_name, f, 0, stype), + head_ (0) +{ + ACE_TRACE ("ACE_Stream_Type::ACE_Stream_Type"); +} + +ACE_Stream_Type::~ACE_Stream_Type (void) +{ + ACE_TRACE ("ACE_Stream_Type::~ACE_Stream_Type"); +} + +int +ACE_Stream_Type::info (ACE_TCHAR **str, size_t len) const +{ + ACE_TRACE ("ACE_Stream_Type::info"); + ACE_TCHAR buf[BUFSIZ]; + + ACE_OS::snprintf (buf, BUFSIZ, + ACE_TEXT ("%s\t %s"), + this->name (), + ACE_TEXT ("# STREAM\n")); + + if (*str == 0 && (*str = ACE_OS::strdup (buf)) == 0) + return -1; + else + ACE_OS::strsncpy (*str, buf, len); + return static_cast (ACE_OS::strlen (buf)); +} + +int +ACE_Stream_Type::fini (void) const +{ + ACE_TRACE ("ACE_Stream_Type::fini"); + void *obj = this->object (); + MT_Stream *str = (MT_Stream *) obj; + + for (ACE_Module_Type *m = this->head_; m != 0;) + { + ACE_Module_Type *t = m->link (); + + // Final arg is an indication to *not* delete the Module. + str->remove (m->name (), + MT_Module::M_DELETE_NONE); + m = t; + } + str->close (); + + return ACE_Service_Type_Impl::fini (); +} + +// Locate and remove from the ACE_Stream. + +int +ACE_Stream_Type::remove (ACE_Module_Type *mod) +{ + ACE_TRACE ("ACE_Stream_Type::remove"); + + ACE_Module_Type *prev = 0; + void *obj = this->object (); + MT_Stream *str = (MT_Stream *) obj; + int result = 0; + + for (ACE_Module_Type *m = this->head_; m != 0; ) + { + // We need to do this first so we don't bomb out if we delete m! + ACE_Module_Type *link = m->link (); + + if (m == mod) + { + if (prev == 0) + this->head_ = link; + else + prev->link (link); + + // Final arg is an indication to *not* delete the Module. + if (str->remove (m->name (), + MT_Module::M_DELETE_NONE) == -1) + result = -1; + + // Do not call m->fini (); as this will result in a double delete + // of the ACE_Module_type when ACE_Service_Repository::fini is called + } + else + prev = m; + + m = link; + } + + return result; +} + +int +ACE_Stream_Type::push (ACE_Module_Type *new_module) +{ + ACE_TRACE ("ACE_Stream_Type::push"); + void *obj = this->object (); + MT_Stream *str = (MT_Stream *) obj; + + new_module->link (this->head_); + this->head_ = new_module; + obj = new_module->object (); + return str->push ((MT_Module *) obj); +} + +ACE_Module_Type * +ACE_Stream_Type::find (const ACE_TCHAR *module_name) const +{ + ACE_TRACE ("ACE_Stream_Type::find"); + + for (ACE_Module_Type *m = this->head_; + m != 0; + m = m->link ()) + if (ACE_OS::strcmp (m->name (), module_name) == 0) + return m; + + return 0; +} + +// @@@ Eliminated ommented out explicit template instantiation code + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Service_Types.h b/dep/acelite/ace/Service_Types.h new file mode 100644 index 000000000..922abee6a --- /dev/null +++ b/dep/acelite/ace/Service_Types.h @@ -0,0 +1,219 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Service_Types.h + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_SERVICE_TYPE_H +#define ACE_SERVICE_TYPE_H + +#include /**/ "ace/pre.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Service_Type_Impl + * + * @brief The abstract base class of the hierarchy that defines the + * contents of the ACE_Service_Repository. The subclasses of + * this class allow the configuration of ACE_Service_Objects, + * ACE_Modules, and ACE_Streams. + * + * This class provides the root of the implementation hierarchy + * of the "Bridge" pattern. It maintains a pointer to the + * appropriate type of service implementation, i.e., + * ACE_Service_Object, ACE_Module, or ACE_Stream. + */ +class ACE_Export ACE_Service_Type_Impl +{ +public: + // = Initialization and termination methods. + ACE_Service_Type_Impl (void *object, + const ACE_TCHAR *s_name, + u_int flags = 0, + ACE_Service_Object_Exterminator gobbler = 0, + int stype = ACE_Service_Type::INVALID_TYPE); + virtual ~ACE_Service_Type_Impl (void); + + // = Pure virtual interface (must be defined by the subclass). + virtual int suspend (void) const = 0; + virtual int resume (void) const = 0; + virtual int init (int argc, ACE_TCHAR *argv[]) const = 0; + virtual int fini (void) const; + virtual int info (ACE_TCHAR **str, size_t len) const = 0; + + /// The pointer to the service. + void *object (void) const; + + /// Get the name of the service. + const ACE_TCHAR *name (void) const; + + /// Set the name of the service. + void name (const ACE_TCHAR *); + + /// Dump the state of an object. + void dump (void) const; + + /// get the service_type of this service + int service_type (void) const; + + /// set the service_type of this service + void service_type (int stype); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Name of the service. + const ACE_TCHAR *name_; + + /// Pointer to object that implements the service. This actually + /// points to an ACE_Service_Object, ACE_Module, or ACE_Stream. + void *obj_; + + /// Destroy function to deallocate obj_. + ACE_Service_Object_Exterminator gobbler_; + + /// Flags that control serivce behavior (particularly deletion). + u_int flags_; + + /// type of this service + /// Used to properly manage the lifecycle of ACE_Modules and ACE_Streams + /// during shutdown + int service_type_; +}; + +/** + * @class ACE_Service_Object_Type + * + * @brief Define the methods for handling the configuration of + * ACE_Service_Objects. + */ +class ACE_Export ACE_Service_Object_Type : public ACE_Service_Type_Impl +{ +public: + // = Initialization method. + ACE_Service_Object_Type (void *so, + const ACE_TCHAR *name, + u_int flags = 0, + ACE_Service_Object_Exterminator gobbler = 0, + int stype = ACE_Service_Type::SERVICE_OBJECT); + + ~ACE_Service_Object_Type (void); + + // = Implement the hooks for . + virtual int suspend (void) const; + virtual int resume (void) const; + virtual int init (int argc, ACE_TCHAR *argv[]) const; + virtual int fini (void) const; + virtual int info (ACE_TCHAR **str, size_t len) const; + +private: + /// Holds the initialization status (result of object->init()) + mutable int initialized_; +}; + +/** + * @class ACE_Module_Type + * + * @brief Define the methods for handling the configuration of + * ACE_Modules. + */ +class ACE_Export ACE_Module_Type : public ACE_Service_Type_Impl +{ +public: + // = Initialization method. + ACE_Module_Type (void *m, // Really an ACE_Module *. + const ACE_TCHAR *identifier, + u_int flags = 0, + int stype = ACE_Service_Type::MODULE); + + ~ACE_Module_Type (void); + + // = Implement the hooks for . + virtual int suspend (void) const; + virtual int resume (void) const; + virtual int init (int argc, ACE_TCHAR *argv[]) const; + virtual int fini (void) const; + virtual int info (ACE_TCHAR **str, size_t len) const; + + /// Get the link pointer. + ACE_Module_Type *link (void) const; + + /// Set the link pointer. + void link (ACE_Module_Type *); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Pointer to the next ACE_Module_Type in an ACE_Stream_Type. + ACE_Module_Type *link_; +}; + +/** + * @class ACE_Stream_Type + * + * @brief Define the methods for handling the configuration of + * ACE_Streams. + */ +class ACE_Export ACE_Stream_Type : public ACE_Service_Type_Impl +{ +public: + // = Initialization method. + ACE_Stream_Type (void *s, // Really an ACE_Stream *. + const ACE_TCHAR *identifier, + u_int flags = 0, + int stype = ACE_Service_Type::STREAM); + + ~ACE_Stream_Type (void); + + // = Implement the hooks for . + virtual int suspend (void) const; + virtual int resume (void) const; + virtual int init (int argc, ACE_TCHAR *argv[]) const; + virtual int fini (void) const; + virtual int info (ACE_TCHAR **str, size_t len) const; + + /// Add a new ACE_Module to the top of the ACE_Stream. + int push (ACE_Module_Type *new_module); + + /// Search for @a module and remove it from the ACE_Stream. + int remove (ACE_Module_Type *module); + + /// Locate the ACE_Module with @a mod_name. + ACE_Module_Type *find (const ACE_TCHAR *module_name) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Pointer to the head of the ACE_Module list. + ACE_Module_Type *head_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Service_Types.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* _SERVICE_TYPE_H */ diff --git a/dep/acelite/ace/Service_Types.inl b/dep/acelite/ace/Service_Types.inl new file mode 100644 index 000000000..cb13c1c4e --- /dev/null +++ b/dep/acelite/ace/Service_Types.inl @@ -0,0 +1,40 @@ +// -*- C++ -*- +#include "ace/ACE.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE void * +ACE_Service_Type_Impl::object (void) const +{ + ACE_TRACE ("ACE_Service_Type_Impl::object"); + return this->obj_; +} + +ACE_INLINE const ACE_TCHAR * +ACE_Service_Type_Impl::name (void) const +{ + ACE_TRACE ("ACE_Service_Type_Impl::name"); + return this->name_; +} + +ACE_INLINE void +ACE_Service_Type_Impl::name (const ACE_TCHAR *n) +{ + ACE_TRACE ("ACE_Service_Type_Impl::name"); + + ACE::strdelete (const_cast (this->name_)); + this->name_ = ACE::strnew (n); +} + +ACE_INLINE int +ACE_Service_Type_Impl::service_type (void) const +{ + return service_type_; +} + +ACE_INLINE void +ACE_Service_Type_Impl::service_type (int stype) +{ + service_type_ = stype; +} +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Memory.cpp b/dep/acelite/ace/Shared_Memory.cpp new file mode 100644 index 000000000..7b2cba500 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory.cpp @@ -0,0 +1,11 @@ +#include "ace/Shared_Memory.h" + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Shared_Memory::~ACE_Shared_Memory (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Memory.h b/dep/acelite/ace/Shared_Memory.h new file mode 100644 index 000000000..be6970e31 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory.h @@ -0,0 +1,56 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Shared_Memory.h + * + * @author Doug Schmidt + */ +//========================================================================== + + +#ifndef ACE_SHARED_MEMORY_H +#define ACE_SHARED_MEMORY_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#include "ace/os_include/os_stddef.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Shared_Memory + * + * @brief This base class adapts both System V shared memory and "BSD" + * mmap to a common API. + * + * This is a very simple-minded wrapper, i.e., it really is only + * useful for allocating large contiguous chunks of shared + * memory. For a much more sophisticated version, please check + * out the class. + */ +class ACE_Export ACE_Shared_Memory +{ +public: + virtual ~ACE_Shared_Memory (void); + + // = Note that all the following methods are pure virtual. + virtual int close (void) = 0; + virtual int remove (void) = 0; + virtual void *malloc (size_t = 0) = 0; + virtual int free (void *p) = 0; + virtual size_t get_segment_size (void) const = 0; + virtual ACE_HANDLE get_id (void) const = 0; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_SHARED_MEMORY_H */ diff --git a/dep/acelite/ace/Shared_Memory_MM.cpp b/dep/acelite/ace/Shared_Memory_MM.cpp new file mode 100644 index 000000000..c465fe0b1 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_MM.cpp @@ -0,0 +1,108 @@ +#include "ace/Shared_Memory_MM.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Shared_Memory_MM.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_MM) + +void +ACE_Shared_Memory_MM::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Shared_Memory_MM::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// Creates a shared memory segment of SIZE bytes. + +ACE_Shared_Memory_MM::ACE_Shared_Memory_MM (ACE_HANDLE handle, + size_t length, + int prot, + int share, + char *addr, + ACE_OFF_T pos) + : shared_memory_ (handle, length, prot, share, addr, pos) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::ACE_Shared_Memory_MM"); +} + +ACE_Shared_Memory_MM::ACE_Shared_Memory_MM (const ACE_TCHAR *file_name, + size_t len, + int flags, + int mode, + int prot, + int share, + char *addr, + ACE_OFF_T pos) + : shared_memory_ (file_name, len, flags, mode, + prot, share, addr, pos) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::ACE_Shared_Memory_MM"); +} + +// The "do-nothing" constructor. + +ACE_Shared_Memory_MM::ACE_Shared_Memory_MM (void) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::ACE_Shared_Memory_MM"); +} + +// The overall size of the segment. + +size_t +ACE_Shared_Memory_MM::get_segment_size (void) const +{ + ACE_TRACE ("ACE_Shared_Memory_MM::get_segment_size"); + // This cast is legit since the original length in open() is an int. + return this->shared_memory_.size (); +} + +// Unmaps the shared memory segment. + +int +ACE_Shared_Memory_MM::remove (void) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::remove"); + return shared_memory_.remove (); +} + +// Closes (unmaps) the shared memory segment. + +int +ACE_Shared_Memory_MM::close (void) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::close"); + return shared_memory_.unmap (); +} + +void * +ACE_Shared_Memory_MM::malloc (size_t) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::malloc"); + void *addr = 0; + + return this->shared_memory_ (addr) == -1 ? 0 : addr; +} + +ACE_HANDLE +ACE_Shared_Memory_MM::get_id (void) const +{ + ACE_TRACE ("ACE_Shared_Memory_MM::get_id"); + return this->shared_memory_.handle (); +} + +int +ACE_Shared_Memory_MM::free (void *p) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::free"); + return p != 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Memory_MM.h b/dep/acelite/ace/Shared_Memory_MM.h new file mode 100644 index 000000000..d3e54464b --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_MM.h @@ -0,0 +1,118 @@ +/* -*- C++ -*- */ + +//============================================================================= +/** + * @file Shared_Memory_MM.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + + +#ifndef ACE_SHARED_MALLOC_MM_H +#define ACE_SHARED_MALLOC_MM_H +#include /**/ "ace/pre.h" + +#include "ace/Shared_Memory.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Mem_Map.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Shared_Memory_MM + * + * @brief Shared memory wrapper based on MMAP. + * + * This class provides a very simple-minded shared memory manager. We + * strongly recommend that you do NOT use this class. Instead, please + * use @c ACE_Malloc, which has much more powerful capabilities. + */ +class ACE_Export ACE_Shared_Memory_MM : public ACE_Shared_Memory +{ +public: + // = Initialization and termination methods. + /// Default constructor. + ACE_Shared_Memory_MM (void); + + /// Constructor. + ACE_Shared_Memory_MM (ACE_HANDLE handle, + size_t length = static_cast (-1), + int prot = PROT_RDWR, + int share = ACE_MAP_PRIVATE, + char *addr = 0, + ACE_OFF_T pos = 0); + + /// Constructor. + ACE_Shared_Memory_MM (const ACE_TCHAR *file_name, + size_t length = static_cast (-1), + int flags = O_RDWR | O_CREAT, + int mode = ACE_DEFAULT_FILE_PERMS, + int prot = PROT_RDWR, + int share = ACE_MAP_SHARED, + char *addr = 0, ACE_OFF_T pos = 0); + + /// Open method. + int open (ACE_HANDLE handle, + size_t length = static_cast (-1), + int prot = PROT_RDWR, + int share = ACE_MAP_PRIVATE, + char *addr = 0, + ACE_OFF_T pos = 0); + + /// Open method. + int open (const ACE_TCHAR *file_name, + size_t length = static_cast (-1), + int flags = O_RDWR | O_CREAT, + int mode = ACE_DEFAULT_FILE_PERMS, + int prot = PROT_RDWR, + int share = ACE_MAP_SHARED, + char *addr = 0, + ACE_OFF_T pos = 0); + + /// Return the name of file that is mapped (if any). + const ACE_TCHAR *filename (void) const; + + /// Close down the shared memory segment. + virtual int close (void); + + /// Remove the shared memory segment and the underlying file. + virtual int remove (void); + + // = Allocation and deallocation methods. + /// Create a new chuck of memory containing @a size bytes. + virtual void *malloc (size_t size = 0); + + /// Free a chuck of memory allocated by + /// . + virtual int free (void *p); + + /// Return the size of the shared memory segment. + virtual size_t get_segment_size (void) const; + + /// Return the ID of the shared memory segment (i.e., an ACE_HANDLE). + virtual ACE_HANDLE get_id (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// This version is implemented with memory-mapped files. + ACE_Mem_Map shared_memory_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Shared_Memory_MM.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SHARED_MALLOC_MM_H */ diff --git a/dep/acelite/ace/Shared_Memory_MM.inl b/dep/acelite/ace/Shared_Memory_MM.inl new file mode 100644 index 000000000..75762c199 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_MM.inl @@ -0,0 +1,39 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Return the name of file that is mapped (if any). + +ACE_INLINE const ACE_TCHAR * +ACE_Shared_Memory_MM::filename (void) const +{ + return this->shared_memory_.filename (); +} + +ACE_INLINE int +ACE_Shared_Memory_MM::open (ACE_HANDLE handle, + size_t length, + int prot, + int share, + char *addr, + ACE_OFF_T pos) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::open"); + return shared_memory_.map (handle, length, prot, share, addr, pos); +} + +ACE_INLINE int +ACE_Shared_Memory_MM::open (const ACE_TCHAR *file_name, + size_t len, + int flags, + int mode, + int prot, + int share, + char *addr, + ACE_OFF_T pos) +{ + ACE_TRACE ("ACE_Shared_Memory_MM::open"); + return shared_memory_.map (file_name, len, flags, mode, + prot, share, addr, pos); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Memory_Pool.cpp b/dep/acelite/ace/Shared_Memory_Pool.cpp new file mode 100644 index 000000000..845f595ad --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_Pool.cpp @@ -0,0 +1,467 @@ +// Shared_Memory_Pool.cpp +#include "ace/Shared_Memory_Pool.h" +#include "ace/OS_NS_sys_shm.h" +#include "ace/Log_Category.h" + + + +#if !defined (ACE_LACKS_SYSV_SHMEM) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_Pool) + +ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options ( + const char *base_addr, + size_t max_segments, + size_t file_perms, + ACE_OFF_T minimum_bytes, + size_t segment_size) + : base_addr_ (base_addr), + max_segments_ (max_segments), + minimum_bytes_ (minimum_bytes), + file_perms_ (file_perms), + segment_size_ (segment_size) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool_Options::ACE_Shared_Memory_Pool_Options"); +} + +void +ACE_Shared_Memory_Pool::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Shared_Memory_Pool::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Shared_Memory_Pool::in_use (ACE_OFF_T &offset, + size_t &counter) +{ +#ifndef ACE_HAS_SYSV_IPC + ACE_UNUSED_ARG (offset); + ACE_UNUSED_ARG (counter); + ACE_NOTSUP_RETURN (-1); +#else + offset = 0; + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + shmid_ds buf; + + for (counter = 0; + counter < this->max_segments_ && st[counter].used_ == 1; + counter++) + { + if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("shmctl")), + -1); + offset += buf.shm_segsz; + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset)); + } + return 0; +#endif +} + +int +ACE_Shared_Memory_Pool::find_seg (const void* const searchPtr, + ACE_OFF_T &offset, + size_t &counter) +{ +#ifndef ACE_HAS_SYSV_IPC + ACE_UNUSED_ARG (searchPtr); + ACE_UNUSED_ARG (offset); + ACE_UNUSED_ARG (counter); + ACE_NOTSUP_RETURN (-1); +#else + offset = 0; + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + shmid_ds buf; + + for (counter = 0; + counter < this->max_segments_ + && st[counter].used_ == 1; + counter++) + { + if (ACE_OS::shmctl (st[counter].shmid_, IPC_STAT, &buf) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("shmctl")), + -1); + offset += buf.shm_segsz; + + // If segment 'counter' starts at a location greater than the + // place we are searching for. We then decrement the offset to + // the start of counter-1. (flabar@vais.net) + if (((ptrdiff_t) offset + (ptrdiff_t) (this->base_addr_)) > (ptrdiff_t) searchPtr) + { + --counter; + offset -= buf.shm_segsz; + return 0; + } + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) segment size = %d, offset = %d\n"), buf.shm_segsz, offset)); + } + + return 0; +#endif +} + +int +ACE_Shared_Memory_Pool::commit_backing_store_name (size_t rounded_bytes, + ACE_OFF_T &offset) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::commit_backing_store_name"); + + size_t counter; + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + + if (this->in_use (offset, counter) == -1) + return -1; + + if (counter == this->max_segments_) + ACELIB_ERROR_RETURN ((LM_ERROR, + "exceeded max number of segments = %d, base = %u, offset = %u\n", + counter, + this->base_addr_, + static_cast(offset)), + -1); + else + { + int shmid = ACE_OS::shmget (st[counter].key_, + rounded_bytes, + this->file_perms_ | IPC_CREAT | IPC_EXCL); + if (shmid == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("shmget")), + -1); + st[counter].shmid_ = shmid; + st[counter].used_ = 1; + + void *address = (void *) (((char *) this->base_addr_) + offset); + void *shmem = ACE_OS::shmat (st[counter].shmid_, + (char *) address, + 0); + + if (shmem != address) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) %p, shmem = %u, address = %u\n"), + ACE_TEXT("shmat"), + shmem, + address), + -1); + } + return 0; +} + +/// Handle SIGSEGV and SIGBUS signals to remap shared memory properly. +int +ACE_Shared_Memory_Pool::handle_signal (int, siginfo_t *siginfo, ucontext_t *) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::handle_signal"); + + // While FreeBSD 5.X has a siginfo_t struct with a si_addr field, + // it does not define SEGV_MAPERR. +#if defined (ACE_HAS_SIGINFO_T) && !defined (ACE_LACKS_SI_ADDR) && \ + (defined (SEGV_MAPERR) || defined (SEGV_MEMERR)) + if (siginfo == 0) + return -1; + + ACE_OFF_T offset; + + // Make sure that the pointer causing the problem is within the + // range of the backing store. + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) si_signo = %d, si_code = %d, addr = %u\n"), siginfo->si_signo, siginfo->si_code, siginfo->si_addr)); + size_t counter = 0; + if (this->in_use (offset, counter) == -1) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("in_use"))); + } + else if (!(siginfo->si_code == SEGV_MAPERR + && siginfo->si_addr < (((char *) this->base_addr_) + offset) + && siginfo->si_addr >= ((char *) this->base_addr_))) + { + ACELIB_ERROR_RETURN ((LM_ERROR, + "(%P|%t) address %u out of range\n", + siginfo->si_addr), + -1); + } + + // The above if case will check to see that the address is in the + // proper range. Therefore there is a segment out there that the + // pointer wants to point into. Find the segment that someone else + // has used and attach to it (flabar@vais.net) + + counter = 0; // ret value to get shmid from the st table. + if (this->find_seg (siginfo->si_addr, offset, counter) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("in_use")), + -1); + + void *address = (void *) (((char *) this->base_addr_) + offset); + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + + void *shmem = ACE_OS::shmat (st[counter].shmid_, (char *) address, 0); + + if (shmem != address) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) %p, shmem = %u, address = %u\n"), + ACE_TEXT("shmat"), + shmem, + address), + -1); + + // NOTE: this won't work if we dont have SIGINFO_T or SI_ADDR +#else + ACE_UNUSED_ARG (siginfo); +#endif /* ACE_HAS_SIGINFO_T && !defined (ACE_LACKS_SI_ADDR) */ + + return 0; +} + +ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool ( + const ACE_TCHAR *backing_store_name, + const OPTIONS *options) + : base_addr_ (0), + file_perms_ (ACE_DEFAULT_FILE_PERMS), + max_segments_ (ACE_DEFAULT_MAX_SEGMENTS), + minimum_bytes_ (0), + segment_size_ (ACE_DEFAULT_SEGMENT_SIZE) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::ACE_Shared_Memory_Pool"); + + // Only change the defaults if != 0. + if (options) + { + this->base_addr_ = + reinterpret_cast (const_cast (options->base_addr_)); + this->max_segments_ = options->max_segments_; + this->file_perms_ = options->file_perms_; + this->minimum_bytes_ = options->minimum_bytes_; + this->segment_size_ = options->segment_size_; + } + +#ifndef ACE_HAS_SYSV_IPC + ACE_UNUSED_ARG (backing_store_name); +#else + if (backing_store_name) + { + // Convert the string into a number that is used as the segment + // key. + + int segment_key = 0; +#if !defined (ACE_LACKS_SSCANF) + int result = ::sscanf (ACE_TEXT_ALWAYS_CHAR (backing_store_name), + "%d", + &segment_key); +#else + int result = 0; +#endif /* ACE_LACKS_SSCANF */ + if (result == 0 || result == EOF) + // The conversion to a number failed so hash with crc32 + // ACE::crc32 is also used in . + this->base_shm_key_ = + (key_t) ACE::crc32 (ACE_TEXT_ALWAYS_CHAR (backing_store_name)); + else + this->base_shm_key_ = segment_key; + + if (this->base_shm_key_ == IPC_PRIVATE) + // Make sure that the segment can be shared between unrelated + // processes. + this->base_shm_key_ = ACE_DEFAULT_SHM_KEY; + } + else + this->base_shm_key_ = ACE_DEFAULT_SHM_KEY; +#endif // ACE_HAS_SYSV_IPC + + if (this->signal_handler_.register_handler (SIGSEGV, this) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Sig_Handler::register_handler"))); +} + +ACE_Shared_Memory_Pool::~ACE_Shared_Memory_Pool (void) +{ +} + +// Ask system for more shared memory. + +void * +ACE_Shared_Memory_Pool::acquire (size_t nbytes, + size_t &rounded_bytes) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::acquire"); + + rounded_bytes = this->round_up (nbytes); + + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) acquiring more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes)); + + ACE_OFF_T offset; + + if (this->commit_backing_store_name (rounded_bytes, offset) == -1) + return 0; + + // ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("(%P|%t) acquired more chunks, nbytes = %d, rounded_bytes = %d\n"), nbytes, rounded_bytes)); + return ((char *) this->base_addr_) + offset; +} + +// Ask system for initial chunk of shared memory. + +void * +ACE_Shared_Memory_Pool::init_acquire (size_t nbytes, + size_t &rounded_bytes, + int &first_time) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::init_acquire"); + + ACE_OFF_T shm_table_offset = ACE::round_to_pagesize (sizeof (SHM_TABLE)); + rounded_bytes = this->round_up (nbytes > (size_t) this->minimum_bytes_ + ? nbytes + : (size_t) this->minimum_bytes_); + + // Acquire the semaphore to serialize initialization and prevent + // race conditions. + + int shmid = ACE_OS::shmget (this->base_shm_key_, + rounded_bytes + shm_table_offset, + this->file_perms_ | IPC_CREAT | IPC_EXCL); + if (shmid == -1) + { + if (errno != EEXIST) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("shmget")), + 0); + first_time = 0; + + shmid = ACE_OS::shmget (this->base_shm_key_, 0, 0); + + if (shmid == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("(%P|%t) %p\n"), + ACE_TEXT ("shmget")), + 0); + + // This implementation doesn't care if we don't get the key we + // want... + this->base_addr_ = + ACE_OS::shmat (shmid, + reinterpret_cast (this->base_addr_), + 0); + if (this->base_addr_ == reinterpret_cast (-1)) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) %p, base_addr = %u\n"), + ACE_TEXT("shmat"), + this->base_addr_), + 0); + } + else + { + first_time = 1; + + // This implementation doesn't care if we don't get the key we + // want... + this->base_addr_ = + ACE_OS::shmat (shmid, + reinterpret_cast (this->base_addr_), + 0); + if (this->base_addr_ == reinterpret_cast (-1)) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("(%P|%t) %p, base_addr = %u\n"), + ACE_TEXT("shmat"), + this->base_addr_), 0); + + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + st[0].key_ = this->base_shm_key_; + st[0].shmid_ = shmid; + + st[0].used_ = 1; + + for (size_t counter = 1; // Skip over the first entry... + counter < this->max_segments_; + counter++) + { +#ifdef ACE_HAS_SYSV_IPC + st[counter].key_ = this->base_shm_key_ + counter; +#endif + st[counter].shmid_ = 0; + st[counter].used_ = 0; + } + } + + return (void *) (((char *) this->base_addr_) + shm_table_offset); +} + +// Instruct the memory pool to release all of its resources. + +int +ACE_Shared_Memory_Pool::release (int) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::release"); + + int result = 0; + SHM_TABLE *st = reinterpret_cast (this->base_addr_); + + for (size_t counter = 0; + counter < this->max_segments_ && st[counter].used_ == 1; + counter++) + if (ACE_OS::shmctl (st[counter].shmid_, IPC_RMID, 0) == -1) + result = -1; + + return result; +} + +int +ACE_Shared_Memory_Pool::sync (ssize_t, int) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::sync"); + return 0; +} + +int +ACE_Shared_Memory_Pool::sync (void *, size_t, int) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::sync"); + return 0; +} + +int +ACE_Shared_Memory_Pool::protect (ssize_t, int) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::protect"); + return 0; +} + +int +ACE_Shared_Memory_Pool::protect (void *, size_t, int) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::protect"); + return 0; +} + +void * +ACE_Shared_Memory_Pool::base_addr (void) const +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::base_addr"); + return this->base_addr_; +} + +// Implement the algorithm for rounding up the request to an +// appropriate chunksize. + +size_t +ACE_Shared_Memory_Pool::round_up (size_t nbytes) +{ + ACE_TRACE ("ACE_Shared_Memory_Pool::round_up"); + if (nbytes < this->segment_size_) + nbytes = this->segment_size_; + + return ACE::round_to_pagesize (nbytes); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* !ACE_LACKS_SYSV_SHMEM */ diff --git a/dep/acelite/ace/Shared_Memory_Pool.h b/dep/acelite/ace/Shared_Memory_Pool.h new file mode 100644 index 000000000..d8872f18b --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_Pool.h @@ -0,0 +1,208 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Shared_Memory_Pool.h + * + * @author Dougls C. Schmidt + * @author Prashant Jain + */ +//============================================================================= + +#ifndef ACE_SHARED_MEMORY_POOL_H +#define ACE_SHARED_MEMORY_POOL_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_LACKS_SYSV_SHMEM) + +#include "ace/ACE.h" +#include "ace/Event_Handler.h" +#include "ace/Sig_Handler.h" +#include "ace/os_include/sys/os_mman.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Shared_Memory_Pool_Options + * + * @brief Helper class for Shared Memory Pool constructor options. + * + * This should be a nested class, but that breaks too many + * compilers. + */ +class ACE_Export ACE_Shared_Memory_Pool_Options +{ +public: + /// Initialization method. + ACE_Shared_Memory_Pool_Options ( + const char *base_addr = ACE_DEFAULT_BASE_ADDR, + size_t max_segments = ACE_DEFAULT_MAX_SEGMENTS, + size_t file_perms = ACE_DEFAULT_FILE_PERMS, + ACE_OFF_T minimum_bytes = 0, + size_t segment_size = ACE_DEFAULT_SEGMENT_SIZE); + + /// Base address of the memory-mapped backing store. + const char *base_addr_; + + /// Number of shared memory segments to allocate. + size_t max_segments_; + + /// What the minimum bytes of the initial segment should be. + ACE_OFF_T minimum_bytes_; + + /// File permissions to use when creating/opening a segment. + size_t file_perms_; + + /// Shared memory segment size. + size_t segment_size_; +}; + +/** + * @class ACE_Shared_Memory_Pool + * + * @brief Make a memory pool that is based on System V shared memory + * (shmget(2) etc.). This implementation allows memory to be + * shared between processes. If your platform doesn't support + * System V shared memory (e.g., Win32 and many RTOS platforms + * do not) then you should use ACE_MMAP_Memory_Pool instead of this + * class. In fact, you should probably use ACE_MMAP_Memory_Pool on + * platforms that *do* support System V shared memory since it + * provides more powerful features, such as persistent backing store + * and greatly scalability. + */ +class ACE_Export ACE_Shared_Memory_Pool : public ACE_Event_Handler +{ +public: + typedef ACE_Shared_Memory_Pool_Options OPTIONS; + + /// Initialize the pool. + ACE_Shared_Memory_Pool (const ACE_TCHAR *backing_store_name = 0, + const OPTIONS *options = 0); + + virtual ~ACE_Shared_Memory_Pool (void); + + /// Ask system for initial chunk of local memory. + virtual void *init_acquire (size_t nbytes, + size_t &rounded_bytes, + int &first_time); + + /** + * Acquire at least @a nbytes from the memory pool. @a rounded_byes is + * the actual number of bytes allocated. Also acquires an internal + * semaphore that ensures proper serialization of Memory_Pool + * initialization across processes. + */ + virtual void *acquire (size_t nbytes, + size_t &rounded_bytes); + + /// Instruct the memory pool to release all of its resources. + virtual int release (int destroy = 1); + + /// Sync the memory region to the backing store starting at + /// @c this->base_addr_. + virtual int sync (ssize_t len = -1, int flags = MS_SYNC); + + /// Sync the memory region to the backing store starting at @a addr. + virtual int sync (void *addr, size_t len, int flags = MS_SYNC); + + /** + * Change the protection of the pages of the mapped region to @a prot + * starting at @c this->base_addr_ up to @a len bytes. If @a len == -1 + * then change protection of all pages in the mapped region. + */ + virtual int protect (ssize_t len = -1, int prot = PROT_RDWR); + + /// Change the protection of the pages of the mapped region to @a prot + /// starting at @a addr up to @a len bytes. + virtual int protect (void *addr, size_t len, int prot = PROT_RDWR); + + /// Return the base address of this memory pool, 0 if base_addr + /// never changes. + virtual void *base_addr (void) const; + + /// Dump the state of an object. + virtual void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Implement the algorithm for rounding up the request to an + /// appropriate chunksize. + virtual size_t round_up (size_t nbytes); + + /** + * Commits a new shared memory segment if necessary after an + * acquire() or a signal. @a offset is set to the new offset into + * the backing store. + */ + virtual int commit_backing_store_name (size_t rounded_bytes, + ACE_OFF_T &offset); + + /// Keeps track of all the segments being used. + struct SHM_TABLE + { + /// Shared memory segment key. + key_t key_; + + /// Shared memory segment internal id. + int shmid_; + + /// Is the segment currently used.; + int used_; + }; + + /** + * Base address of the shared memory segment. If this has the value + * of 0 then the OS is free to select any address, otherwise this + * value is what the OS must try to use to map the shared memory + * segment. + */ + void *base_addr_; + + /// File permissions to use when creating/opening a segment. + size_t file_perms_; + + /// Number of shared memory segments in the table. + size_t max_segments_; + + /// What the minimim bytes of the initial segment should be. + ACE_OFF_T minimum_bytes_; + + /// Shared memory segment size. + size_t segment_size_; + + /// Base shared memory key for the segment. + key_t base_shm_key_; + + /// Find the segment that contains the @a searchPtr + virtual int find_seg (const void *const searchPtr, + ACE_OFF_T &offset, + size_t &counter); + + /// Determine how much memory is currently in use. + virtual int in_use (ACE_OFF_T &offset, + size_t &counter); + + /// Handles SIGSEGV. + ACE_Sig_Handler signal_handler_; + + /// Handle SIGSEGV and SIGBUS signals to remap shared memory + /// properly. + virtual int handle_signal (int, siginfo_t *siginfo, ucontext_t *); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* !ACE_LACKS_SYSV_SHMEM */ + +#include /**/ "ace/post.h" + +#endif /* ACE_SHARED_MEMORY_POOL_H */ diff --git a/dep/acelite/ace/Shared_Memory_SV.cpp b/dep/acelite/ace/Shared_Memory_SV.cpp new file mode 100644 index 000000000..1a7e10b40 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_SV.cpp @@ -0,0 +1,84 @@ +#include "ace/Shared_Memory_SV.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Shared_Memory_SV.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Shared_Memory_SV) + +void +ACE_Shared_Memory_SV::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Shared_Memory_SV::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Shared_Memory_SV::ACE_Shared_Memory_SV (key_t id, + size_t length, + int create, + int perms, + void *addr, + int flags) + : shared_memory_ (id, length, create, perms, addr, flags) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::ACE_Shared_Memory_SV"); +} + +// The overall size of the segment. + +size_t +ACE_Shared_Memory_SV::get_segment_size (void) const +{ + ACE_TRACE ("ACE_Shared_Memory_SV::get_segment_size"); + // This cast is ok since the 'open' method for this class allows only + // an 'int' size. Therefore, this case should not lose information. + return this->shared_memory_.get_segment_size (); +} + +// Removes the shared memory segment. + +int +ACE_Shared_Memory_SV::remove (void) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::remove"); + return shared_memory_.remove (); +} + +// Closes (detaches) the shared memory segment. + +int +ACE_Shared_Memory_SV::close (void) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::close"); + return shared_memory_.detach (); +} + +void * +ACE_Shared_Memory_SV::malloc (size_t) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::malloc"); + return this->shared_memory_.get_segment_ptr (); +} + +ACE_HANDLE +ACE_Shared_Memory_SV::get_id (void) const +{ + ACE_TRACE ("ACE_Shared_Memory_SV::get_id"); + return this->shared_memory_.get_id (); +} + +int +ACE_Shared_Memory_SV::free (void *p) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::free"); + return p != 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Memory_SV.h b/dep/acelite/ace/Shared_Memory_SV.h new file mode 100644 index 000000000..f6109d507 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_SV.h @@ -0,0 +1,99 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Shared_Memory_SV.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + + +#ifndef ACE_SHARED_MALLOC_SV_H +#define ACE_SHARED_MALLOC_SV_H +#include /**/ "ace/pre.h" + +#include "ace/Shared_Memory.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/SV_Shared_Memory.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Shared_Memory_SV + * + * @brief Shared memory wrapper based on System V shared memory. + * + * This class provides a very simple-minded shared memory manager. We + * strongly recommend that you do NOT use this class. Instead, please + * use @c ACE_Malloc, which has much more powerful capabilities. + */ +class ACE_Export ACE_Shared_Memory_SV : public ACE_Shared_Memory +{ +public: + enum + { + ACE_CREATE = IPC_CREAT, + ACE_OPEN = 0 + }; + + // = Initialization and termination methods. + ACE_Shared_Memory_SV (void); + ACE_Shared_Memory_SV (key_t id, + size_t length, + int create = ACE_Shared_Memory_SV::ACE_OPEN, + int perms = ACE_DEFAULT_FILE_PERMS, + void *addr = 0, + int flags = 0); + + int open (key_t id, + size_t length, + int create = ACE_Shared_Memory_SV::ACE_OPEN, + int perms = ACE_DEFAULT_FILE_PERMS, + void *addr = 0, + int flags = 0); + + /// Close down the shared memory segment. + virtual int close (void); + + /// Remove the underlying shared memory segment. + virtual int remove (void); + + // = Allocation and deallocation methods. + /// Create a new chuck of memory containing @a size bytes. + virtual void *malloc (size_t = 0); + + /// Free a chuck of memory allocated by . + virtual int free (void *p); + + /// Return the size of the shared memory segment. + virtual size_t get_segment_size (void) const; + + /// Return the ID of the shared memory segment (i.e., a System V + /// shared memory internal id). + virtual ACE_HANDLE get_id (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// This version is implemented with System V shared memory + /// segments. + ACE_SV_Shared_Memory shared_memory_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Shared_Memory_SV.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SHARED_MALLOC_SV_H */ diff --git a/dep/acelite/ace/Shared_Memory_SV.inl b/dep/acelite/ace/Shared_Memory_SV.inl new file mode 100644 index 000000000..ae7fbc6e2 --- /dev/null +++ b/dep/acelite/ace/Shared_Memory_SV.inl @@ -0,0 +1,27 @@ +// -*- C++ -*- +#include "ace/Global_Macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE int +ACE_Shared_Memory_SV::open (key_t id, + size_t length, + int create, + int perms, + void *addr, + int flags) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::open"); + return shared_memory_.open_and_attach (id, length, create, + perms, addr, flags); +} + +// The "do-nothing" constructor. + +ACE_INLINE +ACE_Shared_Memory_SV::ACE_Shared_Memory_SV (void) +{ + ACE_TRACE ("ACE_Shared_Memory_SV::ACE_Shared_Memory_SV"); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Object.cpp b/dep/acelite/ace/Shared_Object.cpp new file mode 100644 index 000000000..117b32d47 --- /dev/null +++ b/dep/acelite/ace/Shared_Object.cpp @@ -0,0 +1,48 @@ +#include "ace/Shared_Object.h" +#include "ace/Global_Macros.h" +#include "ace/config-all.h" + +/* Provide the abstract base class used to access dynamic linking + facilities */ + +#if !defined (__ACE_INLINE__) +#include "ace/Shared_Object.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Initializes object when dynamic linking occurs. + +int +ACE_Shared_Object::init (int, ACE_TCHAR *[]) +{ + ACE_TRACE ("ACE_Shared_Object::init"); + return 0; +} + +// Terminates object when dynamic unlinking occurs. + +int +ACE_Shared_Object::fini (void) +{ + ACE_TRACE ("ACE_Shared_Object::fini"); + return 0; +} + +// Returns information on active object. + +int +ACE_Shared_Object::info (ACE_TCHAR **, size_t) const +{ + ACE_TRACE ("ACE_Shared_Object::info"); + return 0; +} + +// Need to give a default implementation. + +ACE_Shared_Object::~ACE_Shared_Object (void) +{ + ACE_TRACE ("ACE_Shared_Object::~ACE_Shared_Object"); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Shared_Object.h b/dep/acelite/ace/Shared_Object.h new file mode 100644 index 000000000..6497f292e --- /dev/null +++ b/dep/acelite/ace/Shared_Object.h @@ -0,0 +1,59 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Shared_Object.h + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_SHARED_OBJECT_H +#define ACE_SHARED_OBJECT_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/os_include/sys/os_types.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Shared_Object + * + * @brief Provide the abstract base class used to access dynamic + * linking facilities. + */ +class ACE_Export ACE_Shared_Object +{ +public: + /// Constructor + ACE_Shared_Object (void); + + /// Destructor + virtual ~ACE_Shared_Object (void); + + /// Initializes object when dynamic linking occurs. + virtual int init (int argc, ACE_TCHAR *argv[]); + + /// Terminates object when dynamic unlinking occurs. + virtual int fini (void); + + /// Returns information on a service object. + virtual int info (ACE_TCHAR **info_string, size_t length = 0) const; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Shared_Object.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_SHARED_OBJECT_H */ diff --git a/dep/acelite/ace/Shared_Object.inl b/dep/acelite/ace/Shared_Object.inl new file mode 100644 index 000000000..358a3fb7a --- /dev/null +++ b/dep/acelite/ace/Shared_Object.inl @@ -0,0 +1,9 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Shared_Object::ACE_Shared_Object (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Sig_Adapter.cpp b/dep/acelite/ace/Sig_Adapter.cpp new file mode 100644 index 000000000..18a5cc9b9 --- /dev/null +++ b/dep/acelite/ace/Sig_Adapter.cpp @@ -0,0 +1,81 @@ +#include "ace/Sig_Adapter.h" + +ACE_Sig_Adapter::ACE_Sig_Adapter (ACE_Sig_Action &sa, int sigkey) + : sigkey_ (sigkey), + type_ (SIG_ACTION), + sa_ (sa), + eh_ (0), + sig_func_ (0) +{ + // ACE_TRACE ("ACE_Sig_Adapter::ACE_Sig_Adapter"); +} + +ACE_Sig_Adapter::ACE_Sig_Adapter (ACE_Event_Handler *eh, + int sigkey) + : sigkey_ (sigkey), + type_ (ACE_HANDLER), + eh_ (eh), + sig_func_ (0) +{ + // ACE_TRACE ("ACE_Sig_Adapter::ACE_Sig_Adapter"); +} + +ACE_Sig_Adapter::ACE_Sig_Adapter (ACE_Sig_Handler_Ex sig_func, + int sigkey) + : sigkey_ (sigkey), + type_ (C_FUNCTION), + eh_ (0), + sig_func_ (sig_func) +{ + // ACE_TRACE ("ACE_Sig_Adapter::ACE_Sig_Adapter"); +} + +ACE_Sig_Adapter::~ACE_Sig_Adapter () +{ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Adapter) + +int +ACE_Sig_Adapter::sigkey (void) +{ + ACE_TRACE ("ACE_Sig_Adapter::sigkey"); + return this->sigkey_; +} + +int +ACE_Sig_Adapter::handle_signal (int signum, + siginfo_t *siginfo, + ucontext_t *ucontext) +{ + ACE_TRACE ("ACE_Sig_Adapter::handle_signal"); + + switch (this->type_) + { + case SIG_ACTION: + { + // We have to dispatch a handler that was registered by a + // third-party library. + + ACE_Sig_Action old_disp; + + // Make sure this handler executes in the context it was + // expecting... + this->sa_.register_action (signum, &old_disp); + + ACE_Sig_Handler_Ex sig_func = ACE_Sig_Handler_Ex (this->sa_.handler ()); + + (*sig_func) (signum, siginfo, ucontext); + // Restore the original disposition. + old_disp.register_action (signum); + break; + } + case ACE_HANDLER: + this->eh_->handle_signal (signum, siginfo, ucontext); + break; + case C_FUNCTION: + (*this->sig_func_) (signum, siginfo, ucontext); + break; + } + return 0; +} diff --git a/dep/acelite/ace/Sig_Adapter.h b/dep/acelite/ace/Sig_Adapter.h new file mode 100644 index 000000000..bb0f791a0 --- /dev/null +++ b/dep/acelite/ace/Sig_Adapter.h @@ -0,0 +1,81 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Sig_Adapter.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SIG_ADAPTER_H +#define ACE_SIG_ADAPTER_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event_Handler.h" +#include "ace/Signal.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Sig_Adapter + * + * @brief Provide an adapter that transforms various types of signal + * handlers into the scheme used by the ACE_Reactor. + */ +class ACE_Export ACE_Sig_Adapter : public ACE_Event_Handler +{ +public: + ACE_Sig_Adapter (ACE_Sig_Action &, int sigkey); + ACE_Sig_Adapter (ACE_Event_Handler *, int sigkey); + ACE_Sig_Adapter (ACE_Sig_Handler_Ex, int sigkey = 0); + ~ACE_Sig_Adapter (void); + + /// Returns this signal key that's used to remove this from the + /// ACE_Reactor's internal table. + int sigkey (void); + + /// Called by the to dispatch the signal handler. + virtual int handle_signal (int, siginfo_t *, ucontext_t *); + + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Key for this signal handler (used to remove it). + int sigkey_; + + /// Is this an external handler or an ACE handler? + enum + { + /// We're just wrapping an ACE_Event_Handler. + ACE_HANDLER, + /// An ACE_Sig_Action. + SIG_ACTION, + /// A normal C function. + C_FUNCTION + } type_; + + // = This should be a union, but C++ won't allow that because the + // has a constructor. + /// This is an external handler (ugh). + ACE_Sig_Action sa_; + + /// This is an ACE hander. + ACE_Event_Handler *eh_; + + /// This is a normal C function. + ACE_Sig_Handler_Ex sig_func_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_SIG_ADAPTER_H */ diff --git a/dep/acelite/ace/Sig_Handler.cpp b/dep/acelite/ace/Sig_Handler.cpp new file mode 100644 index 000000000..577a1e430 --- /dev/null +++ b/dep/acelite/ace/Sig_Handler.cpp @@ -0,0 +1,622 @@ +#include "ace/Sig_Handler.h" +#include "ace/Sig_Adapter.h" +#include "ace/Signal.h" +#include "ace/Recursive_Thread_Mutex.h" +#include "ace/Managed_Object.h" +#include "ace/Containers.h" +#include "ace/Guard_T.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Sig_Handler.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_SIG_C_FUNC) + +extern "C" void +ace_sig_handler_dispatch (int signum, siginfo_t *info, ucontext_t *context) +{ + ACE_TRACE ("ace_sig_handler_dispatch"); + ACE_Sig_Handler::dispatch (signum, info, context); +} + +#define ace_signal_handler_dispatcher ACE_SignalHandler(ace_sig_handler_dispatch) + +extern "C" void +ace_sig_handlers_dispatch (int signum, siginfo_t *info, ucontext_t *context) +{ + ACE_TRACE ("ace_sig_handlers_dispatch"); + ACE_Sig_Handlers::dispatch (signum, info, context); +} + +#define ace_signal_handlers_dispatcher ACE_SignalHandler(ace_sig_handlers_dispatch) + +#else +#define ace_signal_handler_dispatcher ACE_SignalHandler(ACE_Sig_Handler::dispatch) + +#define ace_signal_handlers_dispatcher ACE_SignalHandler(ACE_Sig_Handlers::dispatch) +#endif /* ACE_HAS_SIG_C_FUNC */ + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Array of Event_Handlers that will handle the signals. +ACE_Event_Handler *ACE_Sig_Handler::signal_handlers_[ACE_NSIG]; + +// Remembers if a signal has occurred. +sig_atomic_t ACE_Sig_Handler::sig_pending_ = 0; + + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Handler) + +ACE_Sig_Handler::~ACE_Sig_Handler (void) +{ + for (int s = 1; s < ACE_NSIG; ++s) + if (ACE_Sig_Handler::signal_handlers_[s]) + ACE_Sig_Handler::remove_handler_i (s); +} + +void +ACE_Sig_Handler::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Handler::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Sig_Handler::sig_pending (void) +{ + ACE_TRACE ("ACE_Sig_Handler::sig_pending"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); + return ACE_Sig_Handler::sig_pending_ != 0; +} + +void +ACE_Sig_Handler::sig_pending (int pending) +{ + ACE_TRACE ("ACE_Sig_Handler::sig_pending"); + + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD (ACE_Recursive_Thread_Mutex, m, *lock)); + ACE_Sig_Handler::sig_pending_ = pending; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler (int signum) +{ + ACE_TRACE ("ACE_Sig_Handler::handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); + + if (ACE_Sig_Handler::in_range (signum)) + return ACE_Sig_Handler::signal_handlers_[signum]; + else + return 0; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler_i (int signum, + ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handler::handler_i"); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Event_Handler *sh = ACE_Sig_Handler::signal_handlers_[signum]; + + ACE_Sig_Handler::signal_handlers_[signum] = new_sh; + return sh; + } + else + return 0; +} + +ACE_Event_Handler * +ACE_Sig_Handler::handler (int signum, + ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handler::handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, 0)); + + return ACE_Sig_Handler::handler_i (signum, new_sh); +} + +// Register an ACE_Event_Handler along with the corresponding SIGNUM. +// This method does NOT acquire any locks, so it can be called from a +// signal handler. + +int +ACE_Sig_Handler::register_handler_i (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handler::register_handler_i"); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Sig_Action sa; // Define a "null" action. + ACE_Event_Handler *sh = ACE_Sig_Handler::handler_i (signum, new_sh); + + // Return a pointer to the old if the user + // asks for this. + if (old_sh != 0) + *old_sh = sh; + + // Make sure that points to a valid location if the + // user doesn't care... + if (new_disp == 0) + new_disp = &sa; + + new_disp->handler (ace_signal_handler_dispatcher); +#if !defined (ACE_HAS_LYNXOS4_SIGNALS) + new_disp->flags (new_disp->flags () | SA_SIGINFO); +#endif /* ACE_HAS_LYNXOS4_SIGNALS */ + return new_disp->register_action (signum, old_disp); + } + else + return -1; +} + +// Register an ACE_Event_Handler along with the corresponding SIGNUM. +// This method acquires a lock, so it can't be called from a signal +// handler, e.g., . + +int +ACE_Sig_Handler::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **old_sh, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handler::register_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); + + return ACE_Sig_Handler::register_handler_i (signum, + new_sh, + new_disp, + old_sh, + old_disp); +} + +int +ACE_Sig_Handler::remove_handler_i (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int) +{ + ACE_TRACE ("ACE_Sig_Handler::remove_handler_i"); + + ACE_Sig_Action sa (SIG_DFL, (sigset_t *) 0); // Reset to default disposition. + + if (new_disp == 0) + new_disp = &sa; + + ACE_Event_Handler *eh = ACE_Sig_Handler::signal_handlers_[signum]; + ACE_Sig_Handler::signal_handlers_[signum] = 0; + + // Allow the event handler to close down if necessary. + if (eh) + { + eh->handle_close (ACE_INVALID_HANDLE, + ACE_Event_Handler::SIGNAL_MASK); + } + + // Register either the new disposition or restore the default. + return new_disp->register_action (signum, old_disp); +} + +// Remove an ACE_Event_Handler. + +int +ACE_Sig_Handler::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int) +{ + ACE_TRACE ("ACE_Sig_Handler::remove_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); + + if (ACE_Sig_Handler::in_range (signum)) + return ACE_Sig_Handler::remove_handler_i (signum, new_disp, old_disp); + + return -1; +} + +// Master dispatcher function that gets called by a signal handler and +// dispatches one handler... + +void +ACE_Sig_Handler::dispatch (int signum, + siginfo_t *siginfo, + ucontext_t *ucontext) +{ + ACE_TRACE ("ACE_Sig_Handler::dispatch"); + + // Save/restore errno. + ACE_Errno_Guard error (errno); + + // We can't use the call here because that acquires + // the lock, which is non-portable... + ACE_Sig_Handler::sig_pending_ = 1; + + // Darn well better be in range since the OS dispatched this... + ACE_ASSERT (ACE_Sig_Handler::in_range (signum)); + + ACE_Event_Handler *eh = ACE_Sig_Handler::signal_handlers_[signum]; + + if (eh != 0) + { + if (eh->handle_signal (signum, siginfo, ucontext) == -1) + ACE_Sig_Handler::remove_handler_i (signum); +#if defined (ACE_WIN32) + else + // Win32 is weird in the sense that it resets the signal + // disposition to SIG_DFL after a signal handler is + // dispatched. Therefore, to workaround this "feature" we + // must re-register the with + // explicitly. + ACE_Sig_Handler::register_handler_i (signum, eh); +#endif /* ACE_WIN32*/ + } +} + +// ---------------------------------------- +// The following classes are local to this file. + +// There are bugs with HP/UX's C++ compiler that prevents this stuff +// from compiling... +#define ACE_MAX_SIGNAL_HANDLERS ((size_t) 20) + +// Keeps track of the id that uniquely identifies each registered +// signal handler. This id can be used to cancel a timer via the +// method. +int ACE_Sig_Handlers::sigkey_ = 0; + +// If this is true then a 3rd party library has registered a +// handler... +bool ACE_Sig_Handlers::third_party_sig_handler_ = false; + +// Make life easier by defining typedefs... +typedef ACE_Fixed_Set ACE_SIG_HANDLERS_SET; +typedef ACE_Fixed_Set_Iterator ACE_SIG_HANDLERS_ITERATOR; + +class ACE_Sig_Handlers_Set +{ +public: + static ACE_SIG_HANDLERS_SET *instance (int signum); + +private: + static ACE_SIG_HANDLERS_SET *sig_handlers_[ACE_NSIG]; +}; + +/* static */ +ACE_SIG_HANDLERS_SET *ACE_Sig_Handlers_Set::sig_handlers_[ACE_NSIG]; + +/* static */ +ACE_SIG_HANDLERS_SET * +ACE_Sig_Handlers_Set::instance (int signum) +{ + if (signum <= 0 || signum >= ACE_NSIG) + return 0; // This will cause problems... + else if (ACE_Sig_Handlers_Set::sig_handlers_[signum] == 0) + ACE_NEW_RETURN (ACE_Sig_Handlers_Set::sig_handlers_[signum], + ACE_SIG_HANDLERS_SET, + 0); + return ACE_Sig_Handlers_Set::sig_handlers_[signum]; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Handlers) + +ACE_Sig_Handlers::ACE_Sig_Handlers (void) +{ +} + +void +ACE_Sig_Handlers::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Handlers::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// This is the method that does all the dirty work... The basic +// structure of this method was devised by Detlef Becker. + +int +ACE_Sig_Handlers::register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp, + ACE_Event_Handler **, + ACE_Sig_Action *old_disp) +{ + ACE_TRACE ("ACE_Sig_Handlers::register_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_Sig_Adapter *ace_sig_adapter = 0; // Our signal handler. + ACE_Sig_Adapter *extern_sh = 0; // An external signal handler. + ACE_Sig_Action sa; + + // Get current signal disposition. + sa.retrieve_action (signum); + + // Check whether we are already in control of the signal + // handling disposition... + + if (!(sa.handler () == ace_signal_handlers_dispatcher + || sa.handler () == ACE_SignalHandler (SIG_IGN) + || sa.handler () == ACE_SignalHandler (SIG_DFL))) + { + // Drat, a 3rd party library has already installed a signal ;-( + + // Upto here we never disabled RESTART_MODE. Thus, + // RESTART_MODE can only be changed by 3rd party libraries. + + if (ACE_BIT_DISABLED (sa.flags (), SA_RESTART) + && ACE_Sig_Handlers::third_party_sig_handler_) + // Toggling is disallowed since we might break 3rd party + // code. + return -1; + + // Note that we've seen a 3rd party handler... + ACE_Sig_Handlers::third_party_sig_handler_ = true; + + // Create a new 3rd party disposition, remembering its + // preferred signal blocking etc...; + ACE_NEW_RETURN (extern_sh, + ACE_Sig_Adapter (sa, + ++ACE_Sig_Handlers::sigkey_), + -1); + // Add the external signal handler to the set of handlers + // for this signal. + if (ACE_Sig_Handlers_Set::instance (signum)->insert (extern_sh) == -1) + { + delete extern_sh; + return -1; + } + } + // Add our new handler at this point. + ACE_NEW_RETURN (ace_sig_adapter, + ACE_Sig_Adapter (new_sh, + ++ACE_Sig_Handlers::sigkey_), + -1); + // Add the ACE signal handler to the set of handlers for this + // signal (make sure it goes before the external one if there is + // one of these). + + int result = ACE_Sig_Handlers_Set::instance (signum)->insert (ace_sig_adapter); + + if (result == -1) + { + // We couldn't reinstall our handler, so let's pretend like + // none of this happened... + if (extern_sh) + { + ACE_Sig_Handlers_Set::instance (signum)->remove (extern_sh); + delete extern_sh; + } + delete ace_sig_adapter; + return -1; + } + // If ACE_Sig_Handlers::dispatch() was set we're done. + else if (sa.handler () == ace_signal_handlers_dispatcher) + return ace_sig_adapter->sigkey (); + + // Otherwise, we need to register our handler function so that + // all signals will be dispatched through ACE. + else + { + // Make sure that new_disp points to a valid location if the + // user doesn't care... + if (new_disp == 0) + new_disp = &sa; + + new_disp->handler (ace_signal_handlers_dispatcher); + + // Default is to restart signal handlers. + new_disp->flags (new_disp->flags () | SA_RESTART); +#if !defined (ACE_HAS_LYNXOS4_SIGNALS) + new_disp->flags (new_disp->flags () | SA_SIGINFO); +#endif /* ACE_HAS_LYNXOS4_SIGNALS */ + + // Finally install (possibly reinstall) the ACE signal + // handler disposition with the SA_RESTART mode enabled. + if (new_disp->register_action (signum, old_disp) == -1) + { + // Yikes, lots of roll back at this point... + ACE_Sig_Handlers_Set::instance (signum)->remove (ace_sig_adapter); + delete ace_sig_adapter; + + if (extern_sh) + { + ACE_Sig_Handlers_Set::instance (signum)->remove (extern_sh); + delete extern_sh; + } + return -1; + } + else // Return the signal key so that programs can cancel this + // handler if they want! + return ace_sig_adapter->sigkey (); + } + } + + return -1; +} + +// Remove the ACE_Event_Handler currently associated with . +// Install the new disposition (if given) and return the previous +// disposition (if desired by the caller). Returns 0 on success and +// -1 if is invalid. + +int +ACE_Sig_Handlers::remove_handler (int signum, + ACE_Sig_Action *new_disp, + ACE_Sig_Action *old_disp, + int sigkey) +{ + ACE_TRACE ("ACE_Sig_Handlers::remove_handler"); + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, m, *lock, -1)); + + if (ACE_Sig_Handler::in_range (signum)) + { + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + + // Iterate through the set of handlers for this signal. + + for (ACE_Event_Handler **eh; + handler_iterator.next (eh) != 0; + ) + { + // Type-safe downcast would be nice here... + ACE_Sig_Adapter *sh = (ACE_Sig_Adapter *) *eh; + + // Remove the handler if (1) its key matches the key we've + // been told to remove or (2) if we've been told to remove + // *all* handlers (i.e., == -1). + + if (sh->sigkey () == sigkey || sigkey == -1) + { + handler_set->remove (*eh); + delete *eh; + } + } + + if (handler_set->size () == 0) + { + // If there are no more handlers left for a signal then + // register the new disposition or restore the default + // disposition. + + ACE_Sig_Action sa (SIG_DFL, (sigset_t *) 0); + + if (new_disp == 0) + new_disp = &sa; + + return new_disp->register_action (signum, old_disp); + } + return 0; + } + else + return -1; +} + +// Master dispatcher function that gets called by a signal handler and +// dispatches *all* the handlers... + +void +ACE_Sig_Handlers::dispatch (int signum, + siginfo_t *siginfo, + ucontext_t *ucontext) +{ + ACE_TRACE ("ACE_Sig_Handlers::dispatch"); + // The following is #ifdef'd out because it's entirely non-portable + // to acquire a mutex in a signal handler... +#if 0 + ACE_MT (ACE_Recursive_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_SIG_HANDLER_LOCK); + ACE_TSS_Guard m (*lock)); +#endif /* 0 */ + + // Save/restore errno. + ACE_Errno_Guard error (errno); + + ACE_Sig_Handler::sig_pending_ = 1; + + // Darn well better be in range since the OS dispatched this... + ACE_ASSERT (ACE_Sig_Handler::in_range (signum)); + + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + + for (ACE_Event_Handler **eh = 0; + handler_iterator.next (eh) != 0; + ) + if ((*eh)->handle_signal (signum, siginfo, ucontext) == -1) + { + handler_set->remove (*eh); + delete *eh; + } +} + +// Return the first item in the list of handlers. Note that this will +// trivially provide the same behavior as the ACE_Sig_Handler +// version if there is only 1 handler registered! + +ACE_Event_Handler * +ACE_Sig_Handlers::handler (int signum) +{ + ACE_TRACE ("ACE_Sig_Handlers::handler"); + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + ACE_Event_Handler **eh = 0; + handler_iterator.next (eh); + return *eh; +} + +// The following is a strange bit of logic that tries to give the same +// semantics as what happens in ACE_Sig_Handler when we replace the +// current signal handler with a new one. Note that if there is only +// one signal handler the behavior will be identical. If there is +// more than one handler then things get weird... + +ACE_Event_Handler * +ACE_Sig_Handlers::handler (int signum, ACE_Event_Handler *new_sh) +{ + ACE_TRACE ("ACE_Sig_Handlers::handler"); + ACE_SIG_HANDLERS_SET *handler_set = + ACE_Sig_Handlers_Set::instance (signum); + ACE_SIG_HANDLERS_ITERATOR handler_iterator (*handler_set); + ACE_Event_Handler **eh = 0; + + // Find the first handler... + handler_iterator.next (eh); + + // ... then remove it from the set ... + handler_set->remove (*eh); + + // ... and then insert the new signal handler into the beginning of + // the set (note, this is a bit too tied up in the implementation of + // ACE_Unbounded_Set...). + ACE_Sig_Adapter *temp = 0; + + ACE_NEW_RETURN (temp, + ACE_Sig_Adapter (new_sh, + ++ACE_Sig_Handlers::sigkey_), + 0); + handler_set->insert (temp); + return *eh; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Sig_Handler.h b/dep/acelite/ace/Sig_Handler.h new file mode 100644 index 000000000..e71b153fb --- /dev/null +++ b/dep/acelite/ace/Sig_Handler.h @@ -0,0 +1,243 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Sig_Handler.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SIGNAL_HANDLER_H +#define ACE_SIGNAL_HANDLER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Event_Handler.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Sig_Action; + +/** + * @class ACE_Sig_Handler + * + * @brief This is the main dispatcher of signals for ACE. It improves + * the existing UNIX signal handling mechanism by allowing C++ + * objects to handle signals in a way that avoids the use of + * global/static variables and functions. + * + * Using this class a program can register an ACE_Event_Handler + * with the ACE_Sig_Handler in order to handle a designated + * @a signum. When a signal occurs that corresponds to this + * @a signum, the @c handle_signal method of the registered + * ACE_Event_Handler is invoked automatically. + */ +class ACE_Export ACE_Sig_Handler +{ +public: + /// Default constructor. + ACE_Sig_Handler (void); + + /// Destructor + virtual ~ACE_Sig_Handler (void); + + // = Registration and removal methods. + /** + * Add a new ACE_Event_Handler and a new sigaction associated with + * @a signum. Passes back the existing ACE_Event_Handler and its + * sigaction if pointers are non-zero. Returns -1 on failure and >= + * 0 on success. + */ + virtual int register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp = 0, + ACE_Event_Handler **old_sh = 0, + ACE_Sig_Action *old_disp = 0); + + /** + * Remove the ACE_Event_Handler currently associated with + * @a signum. @a sigkey is ignored in this implementation since there + * is only one instance of a signal handler. Install the new + * disposition (if given) and return the previous disposition (if + * desired by the caller). Returns 0 on success and -1 if @a signum + * is invalid. + */ + virtual int remove_handler (int signum, + ACE_Sig_Action *new_disp = 0, + ACE_Sig_Action *old_disp = 0, + int sigkey = -1); + + // Set/get signal status. + /// True if there is a pending signal. + static int sig_pending (void); + + /// Reset the value of so that no signal is pending. + static void sig_pending (int); + + // = Set/get the handler associated with a particular signal. + + /// Return the ACE_Sig_Handler associated with @a signum. + virtual ACE_Event_Handler *handler (int signum); + + /// Set a new ACE_Event_Handler that is associated with @a signum. + /// Return the existing handler. + virtual ACE_Event_Handler *handler (int signum, ACE_Event_Handler *); + + /** + * Callback routine registered with sigaction(2) that dispatches the + * method of the appropriate pre-registered + * ACE_Event_Handler. + */ + static void dispatch (int, siginfo_t *, + ucontext_t *); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = These methods and data members are shared by derived classes. + + /** + * Set a new ACE_Event_Handler that is associated with @a signum. + * Return the existing handler. Does not acquire any locks so that + * it can be called from a signal handler, such as . + */ + static ACE_Event_Handler *handler_i (int signum, + ACE_Event_Handler *); + + /** + * This implementation method is called by and + * @c dispatch. It doesn't do any locking so that it can be called + * within a signal handler, such as @c dispatch. It adds a new + * ACE_Event_Handler and a new sigaction associated with @a signum. + * Passes back the existing ACE_Event_Handler and its sigaction if + * pointers are non-zero. Returns -1 on failure and >= 0 on + * success. + */ + static int register_handler_i (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp = 0, + ACE_Event_Handler **old_sh = 0, + ACE_Sig_Action *old_disp = 0); + + static int remove_handler_i (int signum, + ACE_Sig_Action *new_disp = 0, + ACE_Sig_Action *old_disp = 0, + int sigkey = -1); + + /// Check whether the SIGNUM is within the legal range of signals. + static int in_range (int signum); + + /// Keeps track of whether a signal is pending. + static sig_atomic_t sig_pending_; + +private: + /// Array used to store one user-defined Event_Handler for every + /// signal. + static ACE_Event_Handler *signal_handlers_[ACE_NSIG]; +}; + +/** + * @class ACE_Sig_Handlers + * + * @brief This is an alternative signal handling dispatcher for ACE. It + * allows a list of signal handlers to be registered for each + * signal. It also makes SA_RESTART the default mode. + * + * Using this class a program can register one or more + * ACE_Event_Handler with the ACE_Sig_Handler in order to + * handle a designated @a signum. When a signal occurs that + * corresponds to this @a signum, the methods of + * all the registered ACE_Event_Handlers are invoked + * automatically. + */ +class ACE_Export ACE_Sig_Handlers : public ACE_Sig_Handler +{ +public: + /// Default constructor + ACE_Sig_Handlers (void); + + // = Registration and removal methods. + /** + * Add a new ACE_Event_Handler and a new sigaction associated with + * @a signum. Passes back the existing ACE_Event_Handler and its + * sigaction if pointers are non-zero. Returns -1 on failure and + * a that is >= 0 on success. + */ + virtual int register_handler (int signum, + ACE_Event_Handler *new_sh, + ACE_Sig_Action *new_disp = 0, + ACE_Event_Handler **old_sh = 0, + ACE_Sig_Action *old_disp = 0); + + /** + * Remove an ACE_Event_Handler currently associated with @a signum. + * We remove the handler if (1) its sigkey> matches the @a sigkey + * passed as a parameter or (2) if we've been told to remove all the + * handlers, i.e., @a sigkey == -1. If a new disposition is given it + * is installed and the previous disposition is returned (if desired + * by the caller). Returns 0 on success and -1 if @a signum is + * invalid. + */ + virtual int remove_handler (int signum, + ACE_Sig_Action *new_disp = 0, + ACE_Sig_Action *old_disp = 0, + int sigkey = -1); + + // = Set/get the handler associated with a particular signal. + + /// Return the head of the list of s associated with + /// SIGNUM. + virtual ACE_Event_Handler *handler (int signum); + + /** + * Set a new ACE_Event_Handler that is associated with SIGNUM at + * the head of the list of signals. Return the existing handler + * that was at the head. + */ + virtual ACE_Event_Handler *handler (int signum, + ACE_Event_Handler *); + + /** + * Callback routine registered with sigaction(2) that dispatches the + * method of all the pre-registered + * ACE_Event_Handlers for @a signum + */ + static void dispatch (int signum, siginfo_t *, ucontext_t *); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /** + * Keeps track of the id that uniquely identifies each registered + * signal handler. This id can be used to cancel a timer via the + * method. + */ + static int sigkey_; + + /// If this is true then a 3rd party library has registered a + /// handler... + static bool third_party_sig_handler_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Sig_Handler.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SIG_HANDLER_H */ diff --git a/dep/acelite/ace/Sig_Handler.inl b/dep/acelite/ace/Sig_Handler.inl new file mode 100644 index 000000000..a2ad69de7 --- /dev/null +++ b/dep/acelite/ace/Sig_Handler.inl @@ -0,0 +1,12 @@ +// -*- C++ -*- +ACE_INLINE +ACE_Sig_Handler::ACE_Sig_Handler (void) +{ +} + +ACE_INLINE int +ACE_Sig_Handler::in_range (int signum) +{ + ACE_TRACE ("ACE_Sig_Handler::in_range"); + return signum > 0 && signum < ACE_NSIG; +} diff --git a/dep/acelite/ace/Signal.cpp b/dep/acelite/ace/Signal.cpp new file mode 100644 index 000000000..b04b80042 --- /dev/null +++ b/dep/acelite/ace/Signal.cpp @@ -0,0 +1,223 @@ +#include "ace/Signal.h" +// #include "ace/Log_Category.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Signal.inl" +#endif /* __ACE_INLINE__ */ + + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Action) + +void +ACE_Sig_Action::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Action::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Set) + +ACE_Sig_Set::~ACE_Sig_Set (void) +{ + ACE_TRACE ("ACE_Sig_Set::~ACE_Sig_Set"); + ACE_OS::sigemptyset (&this->sigset_); +} + +ACE_Sig_Action::~ACE_Sig_Action (void) +{ + ACE_TRACE ("ACE_Sig_Action::~ACE_Sig_Action"); +} + +// Restore the signal mask. + +ACE_Sig_Guard::~ACE_Sig_Guard (void) +{ + //ACE_TRACE ("ACE_Sig_Guard::~ACE_Sig_Guard"); + if (!this->condition_) + return; + +#if !defined (ACE_LACKS_UNIX_SIGNALS) +#if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK) + ACE_OS::sigprocmask (SIG_SETMASK, + (sigset_t *) this->omask_, + 0); +#else + ACE_OS::thr_sigsetmask (SIG_SETMASK, + (sigset_t *) this->omask_, + 0); +#endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */ +#endif /* !ACE_LACKS_UNIX_SIGNALS */ +} + +void +ACE_Sig_Set::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Set::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Sig_Guard) + +void +ACE_Sig_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Sig_Guard::dump"); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Sig_Action::ACE_Sig_Action (void) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = 0; + + // Since Service_Config::signal_handler_ is static and has an + // ACE_Sig_Action instance, Win32 will get errno set unless this is + // commented out. +#if !defined (ACE_WIN32) + ACE_OS::sigemptyset (&this->sa_.sa_mask); +#endif /* ACE_WIN32 */ + this->sa_.sa_handler = 0; +} + +ACE_Sig_Action::ACE_Sig_Action (ACE_SignalHandler sig_handler, + sigset_t *sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + if (sig_mask == 0) + ACE_OS::sigemptyset (&this->sa_.sa_mask); + else + this->sa_.sa_mask = *sig_mask; // Structure assignment... + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ +} + +ACE_Sig_Action::ACE_Sig_Action (ACE_SignalHandler sig_handler, + const ACE_Sig_Set &sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + // Structure assignment... + this->sa_.sa_mask = sig_mask.sigset (); + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ +} + +ACE_Sig_Action::ACE_Sig_Action (ACE_SignalHandler sig_handler, + int signum, + sigset_t *sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + if (sig_mask == 0) + ACE_OS::sigemptyset (&this->sa_.sa_mask); + else + this->sa_.sa_mask = *sig_mask; // Structure assignment... + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ + ACE_OS::sigaction (signum, &this->sa_, 0); +} + +ACE_Sig_Action::ACE_Sig_Action (ACE_SignalHandler sig_handler, + int signum, + const ACE_Sig_Set &sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + // Structure assignment... + this->sa_.sa_mask = sig_mask.sigset (); + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ + ACE_OS::sigaction (signum, &this->sa_, 0); +} + +ACE_Sig_Action::ACE_Sig_Action (const ACE_Sig_Set &signals, + ACE_SignalHandler sig_handler, + const ACE_Sig_Set &sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + // Structure assignment... + this->sa_.sa_mask = sig_mask.sigset (); + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ + +#if (ACE_NSIG > 0) + for (int s = 1; s < ACE_NSIG; s++) + if ((signals.is_member (s)) == 1) + ACE_OS::sigaction (s, &this->sa_, 0); +#else /* ACE_NSIG <= 0 */ + ACE_UNUSED_ARG (signals); +#endif /* ACE_NSIG <= 0 */ +} + +ACE_Sig_Action::ACE_Sig_Action (const ACE_Sig_Set &signals, + ACE_SignalHandler sig_handler, + sigset_t *sig_mask, + int sig_flags) +{ + // ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + this->sa_.sa_flags = sig_flags; + + if (sig_mask == 0) + ACE_OS::sigemptyset (&this->sa_.sa_mask); + else + this->sa_.sa_mask = *sig_mask; // Structure assignment... + +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (sig_handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (sig_handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ + +#if (ACE_NSIG > 0) + for (int s = 1; s < ACE_NSIG; s++) + if ((signals.is_member (s)) == 1) + ACE_OS::sigaction (s, &this->sa_, 0); +#else /* ACE_NSIG <= 0 */ + ACE_UNUSED_ARG (signals); +#endif /* ACE_NSIG <= 0 */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Signal.h b/dep/acelite/ace/Signal.h new file mode 100644 index 000000000..3c39e92f7 --- /dev/null +++ b/dep/acelite/ace/Signal.h @@ -0,0 +1,252 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Signal.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_SIGNAL_H +#define ACE_SIGNAL_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-lite.h" + +#if defined (ACE_DONT_INCLUDE_ACE_SIGNAL_H) +# error ace/Signal.h was #included instead of signal.h by ace/OS_NS_signal.h: fix!!!! +#endif /* ACE_DONT_INCLUDE_ACE_SIGNAL_H */ + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_signal.h" + +/// Type of the extended signal handler. +typedef void (*ACE_Sig_Handler_Ex) (int, siginfo_t *siginfo, ucontext_t *ucontext); + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Sig_Set + * + * @brief Provide a C++ wrapper for the C sigset_t interface. + * + * Handle signals via a more elegant C++ interface (e.g., + * doesn't require the use of global variables or global + * functions in an application). + */ +class ACE_Export ACE_Sig_Set +{ +public: + /// Initialize with @a sigset. If @a sigset == 0 then fill + /// the set. + ACE_Sig_Set (sigset_t *sigset); + + /// Initialize with @a sigset. If @a sigset == 0 then fill + /// the set. + ACE_Sig_Set (ACE_Sig_Set *sigset); + + /// If @a fill == 0 then initialize the to be empty, else + /// full. + ACE_Sig_Set (int fill = 0); + + ~ACE_Sig_Set (void); + + /// Create a set that excludes all signals defined by the system. + int empty_set (void); + + /// Create a set that includes all signals defined by the system. + int fill_set (void); + + /// Adds the individual signal specified by @a signo to the set. + int sig_add (int signo); + + /// Deletes the individual signal specified by @a signo from the set. + int sig_del (int signo); + + /// Checks whether the signal specified by @a signo is in the set. + int is_member (int signo) const; + + /// Returns a pointer to the underlying @c sigset_t. + operator sigset_t *(); + + /// Returns a copy of the underlying @c sigset_t. + sigset_t sigset (void) const; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Set of signals. + sigset_t sigset_; +}; + +/** + * @class ACE_Sig_Action + * + * @brief C++ wrapper facade for the @c sigaction struct. + */ +class ACE_Export ACE_Sig_Action +{ +public: + // = Initialization methods. + /// Default constructor. Initializes everything to 0. + ACE_Sig_Action (void); + + /// Assigns the various fields of a @c sigaction struct but doesn't + /// register for signal handling via the @c sigaction function. + ACE_Sig_Action (ACE_SignalHandler handler, + sigset_t *sigmask = 0, + int flags = 0); + + /// Assigns the various fields of a @c sigaction struct but doesn't + /// register for signal handling via the @c sigaction function. + ACE_Sig_Action (ACE_SignalHandler handler, + const ACE_Sig_Set &sigmask, + int flags = 0); + + /** + * Assigns the various fields of a @c sigaction struct and registers + * the @a handler to process signal @a signum via the @c sigaction + * function. + */ + ACE_Sig_Action (ACE_SignalHandler handler, + int signum, + sigset_t *sigmask = 0, + int flags = 0); + + /** + * Assigns the various fields of a @c sigaction struct and registers + * the @a handler to process signal @a signum via the @c sigaction + * function. + */ + ACE_Sig_Action (ACE_SignalHandler handler, + int signum, + const ACE_Sig_Set &sigmask, + int flags = 0); + + /** + * Assigns the various fields of a @c sigaction struct and registers + * the @a handler to process all @a signalss via the @c sigaction + * function. + */ + ACE_Sig_Action (const ACE_Sig_Set &signalss, + ACE_SignalHandler handler, + const ACE_Sig_Set &sigmask, + int flags = 0); + + /** + * Assigns the various fields of a @c sigaction struct and registers + * the @a handler to process all @a signalss via the @c sigaction + * function. + */ + ACE_Sig_Action (const ACE_Sig_Set &signalss, + ACE_SignalHandler handler, + sigset_t *sigmask = 0, + int flags = 0); + + /// Copy constructor. + ACE_Sig_Action (const ACE_Sig_Action &s); + + /// Default dtor. + ~ACE_Sig_Action (void); + + // = Signal action management. + /// Register @c this as the current disposition and store old + /// disposition into @a oaction if it is non-NULL. + int register_action (int signum, + ACE_Sig_Action *oaction = 0); + + /// Assign the value of @a oaction to @c this and make it become the + /// new signal disposition. + int restore_action (int signum, + ACE_Sig_Action &oaction); + + /// Retrieve the current disposition into @c this. + int retrieve_action (int signum); + + /// Set current signal action. + void set (struct sigaction *); + + /// Get current signal action. + struct sigaction *get (void); + operator struct sigaction *(); + + /// Set current signal flags. + void flags (int); + + /// Get current signal flags. + int flags (void); + + /// Set current signal mask. + void mask (sigset_t *); + void mask (ACE_Sig_Set &); + + /// Get current signal mask. + sigset_t *mask (void); + + /// Set current signal handler (pointer to function). + void handler (ACE_SignalHandler); + + /// Get current signal handler (pointer to function). + ACE_SignalHandler handler (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Controls signal behavior. + struct sigaction sa_; +}; + +/** + * @class ACE_Sig_Guard + * + * @brief Hold signals in MASK for duration of a C++ statement block. + * Note that a "0" for mask causes all signals to be held. + */ +class ACE_Export ACE_Sig_Guard +{ +public: + // = Initialization and termination methods. + /// This is kind of conditional Guard, needed when guard should be + /// activated only when a specific condition met. When condition == + /// true (default), Guard is activated + ACE_Sig_Guard (ACE_Sig_Set *mask = 0, bool condition = true); + + /// Restore blocked signals. + ~ACE_Sig_Guard (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Original signal mask. + ACE_Sig_Set omask_; + + /// Guard Condition + bool condition_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Signal.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_SIGNAL_HANDLER_H */ diff --git a/dep/acelite/ace/Signal.inl b/dep/acelite/ace/Signal.inl new file mode 100644 index 000000000..ff2f52403 --- /dev/null +++ b/dep/acelite/ace/Signal.inl @@ -0,0 +1,246 @@ +// -*- C++ -*- +#include "ace/OS_NS_signal.h" +#include "ace/config-all.h" +#include "ace/Trace.h" +#include "ace/Object_Manager_Base.h" +#include "ace/OS_NS_Thread.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Sig_Set::ACE_Sig_Set (sigset_t *ss) + // : sigset_ () +{ + ACE_TRACE ("ACE_Sig_Set::ACE_Sig_Set"); + + if (ss == 0) + ACE_OS::sigfillset (&this->sigset_); + else + // Structure assignment. + this->sigset_ = *ss; +} + +ACE_INLINE +ACE_Sig_Set::ACE_Sig_Set (int fill) + // : sigset_ () +{ + ACE_TRACE ("ACE_Sig_Set::ACE_Sig_Set"); + + if (fill) + ACE_OS::sigfillset (&this->sigset_); + else + ACE_OS::sigemptyset (&this->sigset_); +} + +ACE_INLINE +ACE_Sig_Set::ACE_Sig_Set (ACE_Sig_Set *ss) + // : sigset_ () +{ + ACE_TRACE ("ACE_Sig_Set::ACE_Sig_Set"); + + if (ss == 0) + ACE_OS::sigfillset (&this->sigset_); + else + this->sigset_ = ss->sigset_; +} + +ACE_INLINE int +ACE_Sig_Set::empty_set (void) +{ + ACE_TRACE ("ACE_Sig_Set::empty_set"); + return ACE_OS::sigemptyset (&this->sigset_); +} + +ACE_INLINE int +ACE_Sig_Set::fill_set (void) +{ + ACE_TRACE ("ACE_Sig_Set::fill_set"); + return ACE_OS::sigfillset (&this->sigset_); +} + +ACE_INLINE int +ACE_Sig_Set::sig_add (int signo) +{ + ACE_TRACE ("ACE_Sig_Set::sig_add"); + return ACE_OS::sigaddset (&this->sigset_, signo); +} + +ACE_INLINE int +ACE_Sig_Set::sig_del (int signo) +{ + ACE_TRACE ("ACE_Sig_Set::sig_del"); + return ACE_OS::sigdelset (&this->sigset_, signo); +} + +ACE_INLINE int +ACE_Sig_Set::is_member (int signo) const +{ + ACE_TRACE ("ACE_Sig_Set::is_member"); + return ACE_OS::sigismember (const_cast (&this->sigset_), signo); +} + +ACE_INLINE +ACE_Sig_Set::operator sigset_t *(void) +{ + ACE_TRACE ("ACE_Sig_Set::operator sigset_t *"); + return &this->sigset_; +} + +ACE_INLINE sigset_t +ACE_Sig_Set::sigset (void) const +{ + ACE_TRACE ("ACE_Sig_Set::sigset"); + return this->sigset_; +} + +ACE_INLINE int +ACE_Sig_Action::flags (void) +{ + ACE_TRACE ("ACE_Sig_Action::flags"); + return this->sa_.sa_flags; +} + +ACE_INLINE void +ACE_Sig_Action::flags (int flags) +{ + ACE_TRACE ("ACE_Sig_Action::flags"); + this->sa_.sa_flags = flags; +} + +ACE_INLINE sigset_t * +ACE_Sig_Action::mask (void) +{ + ACE_TRACE ("ACE_Sig_Action::mask"); + return &this->sa_.sa_mask; +} + +ACE_INLINE void +ACE_Sig_Action::mask (sigset_t *ss) +{ + ACE_TRACE ("ACE_Sig_Action::mask"); + if (ss != 0) + this->sa_.sa_mask = *ss; // Structure assignment +} + +ACE_INLINE void +ACE_Sig_Action::mask (ACE_Sig_Set &ss) +{ + ACE_TRACE ("ACE_Sig_Action::mask"); + this->sa_.sa_mask = ss.sigset (); // Structure assignment +} + +ACE_INLINE ACE_SignalHandler +ACE_Sig_Action::handler (void) +{ + ACE_TRACE ("ACE_Sig_Action::handler"); + return ACE_SignalHandler (this->sa_.sa_handler); +} + +ACE_INLINE void +ACE_Sig_Action::handler (ACE_SignalHandler handler) +{ + ACE_TRACE ("ACE_Sig_Action::handler"); +#if !defined(ACE_HAS_TANDEM_SIGNALS) + this->sa_.sa_handler = ACE_SignalHandlerV (handler); +#else + this->sa_.sa_handler = (void (*)()) ACE_SignalHandlerV (handler); +#endif /* !ACE_HAS_TANDEM_SIGNALS */ +} + +ACE_INLINE void +ACE_Sig_Action::set (struct sigaction *sa) +{ + ACE_TRACE ("ACE_Sig_Action::set"); + this->sa_ = *sa; // Structure assignment. +} + +ACE_INLINE struct sigaction * +ACE_Sig_Action::get (void) +{ + ACE_TRACE ("ACE_Sig_Action::get"); + return &this->sa_; +} + +ACE_INLINE +ACE_Sig_Action::operator struct sigaction * () +{ + ACE_TRACE ("ACE_Sig_Action::operator struct sigaction *"); + return &this->sa_; +} + +ACE_INLINE +ACE_Sig_Action::ACE_Sig_Action (const ACE_Sig_Action &s) + // : sa_ () +{ + ACE_TRACE ("ACE_Sig_Action::ACE_Sig_Action"); + *this = s; // structure copy. +} + +ACE_INLINE int +ACE_Sig_Action::register_action (int signum, ACE_Sig_Action *oaction) +{ + ACE_TRACE ("ACE_Sig_Action::register_action"); + struct sigaction *sa = oaction == 0 ? 0 : oaction->get (); + + return ACE_OS::sigaction (signum, &this->sa_, sa); +} + +ACE_INLINE int +ACE_Sig_Action::retrieve_action (int signum) +{ + ACE_TRACE ("ACE_Sig_Action::retrieve_action"); + return ACE_OS::sigaction (signum, 0, &this->sa_); +} + +ACE_INLINE int +ACE_Sig_Action::restore_action (int signum, ACE_Sig_Action &oaction) +{ + ACE_TRACE ("ACE_Sig_Action::restore_action"); + this->sa_ = *oaction.get (); // Structure assignment + return ACE_OS::sigaction (signum, &this->sa_, 0); +} + +// Block out the signal MASK until the destructor is called. + +ACE_INLINE +ACE_Sig_Guard::ACE_Sig_Guard (ACE_Sig_Set *mask, + bool condition) + : omask_ () + , condition_ (condition) +{ + //ACE_TRACE ("ACE_Sig_Guard::ACE_Sig_Guard"); + if (!this->condition_) + return; + +#if defined (ACE_LACKS_UNIX_SIGNALS) + ACE_UNUSED_ARG (mask); +#else + // If MASK is 0 then block all signals! + if (mask == 0) + { +# if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK) + ACE_OS::sigprocmask (SIG_BLOCK, + ACE_OS_Object_Manager::default_mask (), + (sigset_t *) this->omask_); +# else + ACE_OS::thr_sigsetmask (SIG_BLOCK, + ACE_OS_Object_Manager::default_mask (), + (sigset_t *) this->omask_); +# endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */ + } + else +# if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK) + ACE_OS::sigprocmask (SIG_BLOCK, + (sigset_t *) *mask, + (sigset_t *) + this->omask_); +# else + ACE_OS::thr_sigsetmask (SIG_BLOCK, + (sigset_t *) *mask, + (sigset_t *) + this->omask_); +# endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */ +#endif /* ACE_LACKS_UNIX_SIGNALS */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Singleton.cpp b/dep/acelite/ace/Singleton.cpp new file mode 100644 index 000000000..52ca2b53d --- /dev/null +++ b/dep/acelite/ace/Singleton.cpp @@ -0,0 +1,587 @@ +#ifndef ACE_SINGLETON_CPP +#define ACE_SINGLETON_CPP + +#include "ace/Singleton.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Singleton.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Object_Manager.h" +#include "ace/Log_Category.h" +#include "ace/Framework_Component.h" +#include "ace/Guard_T.h" +#include "ace/os_include/os_typeinfo.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Singleton) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Unmanaged_Singleton) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_TSS_Singleton) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_Unmanaged_TSS_Singleton) +ACE_ALLOC_HOOK_DEFINE_Tcc(ACE_DLL_Singleton_T) +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_DLL_Singleton_Adapter_T) + +template void +ACE_Singleton::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Singleton::dump"); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("instance_ = %x"), + ACE_Singleton::instance_i ())); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +#endif /* ACE_HAS_DUMP */ +} + +template ACE_Singleton *& +ACE_Singleton::instance_i (void) +{ +#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + // Pointer to the Singleton instance. This works around a bug with + // G++ and it's (mis-)handling of templates and statics... + static ACE_Singleton *singleton_ = 0; + + return singleton_; +#else + return ACE_Singleton::singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +} + +template TYPE * +ACE_Singleton::instance (void) +{ + ACE_TRACE ("ACE_Singleton::instance"); + + ACE_Singleton *&singleton = + ACE_Singleton::instance_i (); + + // Perform the Double-Check pattern... + if (singleton == 0) + { + if (ACE_Object_Manager::starting_up () || + ACE_Object_Manager::shutting_down ()) + { + // The program is still starting up, and therefore assumed + // to be single threaded. There's no need to double-check. + // Or, the ACE_Object_Manager instance has been destroyed, + // so the preallocated lock is not available. Either way, + // don't register for destruction with the + // ACE_Object_Manager: we'll have to leak this instance. + + ACE_NEW_RETURN (singleton, (ACE_Singleton), 0); + } + else + { +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + // Obtain a lock from the ACE_Object_Manager. The pointer + // is static, so we only obtain one per ACE_Singleton + // instantiation. +#if defined(ACE_FACE_SAFETY_BASE) + static ACE_LOCK the_lock; + static ACE_LOCK *lock = &the_lock; +#else /* ACE_FACE_SAFETY_BASE */ + static ACE_LOCK *lock = 0; +#endif /* ACE_FACE_SAFETY_BASE */ + if (ACE_Object_Manager::get_singleton_lock (lock) != 0) + // Failed to acquire the lock! + return 0; + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0); + + if (singleton == 0) + { +#endif /* ACE_MT_SAFE */ + ACE_NEW_RETURN (singleton, (ACE_Singleton), 0); + + // Register for destruction with ACE_Object_Manager. +#if !defined (ACE_MT_SAFE) || (ACE_MT_SAFE == 0) + ACE_Object_Manager::at_exit (singleton, 0, typeid (TYPE).name ()); +#else + ACE_Object_Manager::at_exit (singleton, &lock, + typeid (TYPE).name ()); + } +#endif /* ACE_MT_SAFE */ + } + } + + return &singleton->instance_; +} + +template void +ACE_Singleton::cleanup (void *param) +{ + ACE_Object_Manager::remove_at_exit (this); + delete this; + ACE_Singleton::instance_i () = 0; + +#if !defined ACE_MT_SAFE || ACE_MT_SAFE == 0 || defined ACE_FACE_SAFETY_BASE + ACE_UNUSED_ARG (param); +#else + if (param) + { + ACE_LOCK **lock = static_cast (param); + *lock = 0; + } +#endif +} + +template void +ACE_Singleton::close (void) +{ + ACE_Singleton *&singleton = + ACE_Singleton::instance_i (); + + if (singleton) + { + singleton->cleanup (); + ACE_Singleton::instance_i () = 0; + } +} + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) +// Pointer to the Singleton instance. +template ACE_Singleton * +ACE_Singleton::singleton_ = 0; + +template ACE_Unmanaged_Singleton * +ACE_Unmanaged_Singleton::singleton_ = 0; +#endif /* !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) */ + +template void +ACE_Unmanaged_Singleton::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Unmanaged_Singleton::dump"); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("instance_ = %x"), + ACE_Unmanaged_Singleton::instance_i ())); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Unmanaged_Singleton *& +ACE_Unmanaged_Singleton::instance_i (void) +{ +#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + // Pointer to the Singleton instance. This works around a bug with + // G++ and it's (mis-)handling of templates and statics... + static ACE_Unmanaged_Singleton *singleton_ = 0; + + return singleton_; +#else + return ACE_Unmanaged_Singleton::singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +} + +template TYPE * +ACE_Unmanaged_Singleton::instance (void) +{ + ACE_TRACE ("ACE_Unmanaged_Singleton::instance"); + + ACE_Unmanaged_Singleton *&singleton = + ACE_Unmanaged_Singleton::instance_i (); + + // Perform the Double-Check pattern... + if (singleton == 0) + { + if (ACE_Object_Manager::starting_up () || + ACE_Object_Manager::shutting_down ()) + { + // The program is still starting up, and therefore assumed + // to be single threaded. There's no need to double-check. + // Or, the ACE_Object_Manager instance has been destroyed, + // so the preallocated lock is not available. Either way, + // don't register for destruction with the + // ACE_Object_Manager: we'll have to leak this instance. + + ACE_NEW_RETURN (singleton, (ACE_Unmanaged_Singleton), + 0); + } + else + { +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + // Obtain a lock from the ACE_Object_Manager. The pointer + // is static, so we only obtain one per + // ACE_Unmanaged_Singleton instantiation. +#if defined(ACE_FACE_SAFETY_BASE) + static ACE_LOCK the_lock; + static ACE_LOCK *lock = &the_lock; +#else /* ACE_FACE_SAFETY_BASE */ + static ACE_LOCK *lock = 0; +#endif /* ACE_FACE_SAFETY_BASE */ + if (ACE_Object_Manager::get_singleton_lock (lock) != 0) + // Failed to acquire the lock! + return 0; + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0); +#endif /* ACE_MT_SAFE */ + + if (singleton == 0) + ACE_NEW_RETURN (singleton, + (ACE_Unmanaged_Singleton), + 0); + } + } + + return &singleton->instance_; +} + +template void +ACE_Unmanaged_Singleton::close (void) +{ + ACE_Unmanaged_Singleton *&singleton = + ACE_Unmanaged_Singleton::instance_i (); + + if (singleton) + { + singleton->cleanup (); + ACE_Unmanaged_Singleton::instance_i () = 0; + } +} + +template void +ACE_TSS_Singleton::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_TSS_Singleton::dump"); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("instance_ = %x"), + ACE_TSS_Singleton::instance_i ())); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +#endif /* ACE_HAS_DUMP */ +} + +template ACE_TSS_Singleton *& +ACE_TSS_Singleton::instance_i (void) +{ +#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + // Pointer to the Singleton instance. This works around a bug with + // G++ and it's (mis-)handling of templates and statics... + static ACE_TSS_Singleton *singleton_ = 0; + + return singleton_; +#else + return ACE_TSS_Singleton::singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +} + +template TYPE * +ACE_TSS_Singleton::instance (void) +{ + ACE_TRACE ("ACE_TSS_Singleton::instance"); + + ACE_TSS_Singleton *&singleton = + ACE_TSS_Singleton::instance_i (); + + // Perform the Double-Check pattern... + if (singleton == 0) + { + if (ACE_Object_Manager::starting_up () || + ACE_Object_Manager::shutting_down ()) + { + // The program is still starting up, and therefore assumed + // to be single threaded. There's no need to double-check. + // Or, the ACE_Object_Manager instance has been destroyed, + // so the preallocated lock is not available. Either way, + // don't register for destruction with the + // ACE_Object_Manager: we'll have to leak this instance. + + ACE_NEW_RETURN (singleton, (ACE_TSS_Singleton), 0); + } + else + { +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + + // Obtain a lock from the ACE_Object_Manager. The pointer + // is static, so we only obtain one per ACE_Singleton instantiation. +#if defined(ACE_FACE_SAFETY_BASE) + static ACE_LOCK the_lock; + static ACE_LOCK *lock = &the_lock; +#else /* ACE_FACE_SAFETY_BASE */ + static ACE_LOCK *lock = 0; +#endif /* ACE_FACE_SAFETY_BASE */ + if (ACE_Object_Manager::get_singleton_lock (lock) != 0) + // Failed to acquire the lock! + return 0; + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0); + + if (singleton == 0) + { +#endif /* ACE_MT_SAFE */ + ACE_NEW_RETURN (singleton, (ACE_TSS_Singleton), + 0); + + // Register for destruction with ACE_Object_Manager. + ACE_Object_Manager::at_exit (singleton, 0, typeid (TYPE).name ()); +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + } +#endif /* ACE_MT_SAFE */ + } + } + + return ACE_TSS_GET (&singleton->instance_, TYPE); +} + +template void +ACE_TSS_Singleton::cleanup (void *) +{ + delete this; + ACE_TSS_Singleton::instance_i () = 0; +} + +template void +ACE_Unmanaged_TSS_Singleton::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Unmanaged_TSS_Singleton::dump"); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("instance_ = %x"), + ACE_Unmanaged_TSS_Singleton::instance_i ())); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_Unmanaged_TSS_Singleton *& +ACE_Unmanaged_TSS_Singleton::instance_i (void) +{ +#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + // Pointer to the Singleton instance. This works around a bug with + // G++ and it's (mis-)handling of templates and statics... + static ACE_Unmanaged_TSS_Singleton *singleton_ = 0; + + return singleton_; +#else + return ACE_Unmanaged_TSS_Singleton::singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +} + +template TYPE * +ACE_Unmanaged_TSS_Singleton::instance (void) +{ + ACE_TRACE ("ACE_Unmanaged_TSS_Singleton::instance"); + + ACE_Unmanaged_TSS_Singleton *&singleton = + ACE_Unmanaged_TSS_Singleton::instance_i (); + + // Perform the Double-Check pattern... + if (singleton == 0) + { + if (ACE_Object_Manager::starting_up () || + ACE_Object_Manager::shutting_down ()) + { + // The program is still starting up, and therefore assumed + // to be single threaded. There's no need to double-check. + // Or, the ACE_Object_Manager instance has been destroyed, + // so the preallocated lock is not available. Either way, + // don't register for destruction with the + // ACE_Object_Manager: we'll have to leak this instance. + + ACE_NEW_RETURN (singleton, + (ACE_Unmanaged_TSS_Singleton), + 0); + } + else + { +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + // Obtain a lock from the ACE_Object_Manager. The pointer + // is static, so we only obtain one per + // ACE_Unmanaged_Singleton instantiation. +#if defined(ACE_FACE_SAFETY_BASE) + static ACE_LOCK the_lock; + static ACE_LOCK *lock = &the_lock; +#else /* ACE_FACE_SAFETY_BASE */ + static ACE_LOCK *lock = 0; +#endif /* ACE_FACE_SAFETY_BASE */ + if (ACE_Object_Manager::get_singleton_lock (lock) != 0) + // Failed to acquire the lock! + return 0; + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0); +#endif /* ACE_MT_SAFE */ + + if (singleton == 0) + ACE_NEW_RETURN (singleton, + (ACE_Unmanaged_TSS_Singleton), + 0); + } + } + + return ACE_TSS_GET (&singleton->instance_, TYPE); +} + +template void +ACE_Unmanaged_TSS_Singleton::close (void) +{ + ACE_Unmanaged_TSS_Singleton *&singleton = + ACE_Unmanaged_TSS_Singleton::instance_i (); + + if (singleton) + singleton->cleanup (); +} + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) +// Pointer to the Singleton instance. +template ACE_TSS_Singleton * +ACE_TSS_Singleton::singleton_ = 0; + +template +ACE_Unmanaged_TSS_Singleton * +ACE_Unmanaged_TSS_Singleton::singleton_ = 0; +#endif /* !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) */ + +/*************************************************************************/ + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) +// Pointer to the Singleton instance. +template ACE_DLL_Singleton_T * +ACE_DLL_Singleton_T::singleton_ = 0; +#endif /* !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) */ + +template void +ACE_DLL_Singleton_T::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_DLL_Singleton_T::dump"); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("instance_ = %x"), + ACE_DLL_Singleton_T::instance_i ())); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_DLL_Singleton_T *& +ACE_DLL_Singleton_T::instance_i (void) +{ + ACE_TRACE ("ACE_DLL_Singleton_T::instance_i"); + +#if defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + // Pointer to the Singleton instance. This works around a bug with + // G++ and it's (mis-)handling of templates and statics... + static ACE_DLL_Singleton_T *singleton_ = 0; + + return singleton_; +#else + return ACE_DLL_Singleton_T::singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ +} + +template TYPE * +ACE_DLL_Singleton_T::instance (void) +{ + ACE_TRACE ("ACE_DLL_Singleton_T::instance"); + + ACE_DLL_Singleton_T *&singleton = + ACE_DLL_Singleton_T::instance_i (); + + // Perform the Double-Check pattern... + if (singleton == 0) + { + if (ACE_Object_Manager::starting_up () || + ACE_Object_Manager::shutting_down ()) + { + // The program is still starting up, and therefore assumed + // to be single threaded. There's no need to double-check. + // Or, the ACE_Object_Manager instance has been destroyed, + // so the preallocated lock is not available. Either way, + // don't register for destruction with the + // ACE_Object_Manager: we'll have to leak this instance. + + ACE_NEW_RETURN (singleton, (ACE_DLL_Singleton_T), + 0); + } + else + { +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + // Obtain a lock from the ACE_Object_Manager. The pointer + // is static, so we only obtain one per + // ACE_Unmanaged_Singleton instantiation. +#if defined(ACE_FACE_SAFETY_BASE) + static ACE_LOCK the_lock; + static ACE_LOCK *lock = &the_lock; +#else /* ACE_FACE_SAFETY_BASE */ + static ACE_LOCK *lock = 0; +#endif /* ACE_FACE_SAFETY_BASE */ + if (ACE_Object_Manager::get_singleton_lock (lock) != 0) + // Failed to acquire the lock! + return 0; + + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, *lock, 0); +#endif /* ACE_MT_SAFE */ + + if (singleton == 0) + ACE_NEW_RETURN (singleton, + (ACE_DLL_Singleton_T), + 0); + } + //ACE_REGISTER_FRAMEWORK_COMPONENT(ACE_DLL_Singleton, singleton); + ACE_Framework_Repository::instance ()->register_component + (new ACE_Framework_Component_T > (singleton)); + } + + return &singleton->instance_; +} + +template void +ACE_DLL_Singleton_T::close (void) +{ + ACE_TRACE ("ACE_DLL_Singleton_T::close"); + + ACE_DLL_Singleton_T *&singleton = + ACE_DLL_Singleton_T::instance_i (); + + delete singleton; + singleton = 0; +} + +template void +ACE_DLL_Singleton_T::close_singleton (void) +{ + ACE_TRACE ("ACE_DLL_Singleton_T::close_singleton"); + ACE_DLL_Singleton_T::close (); +} + +template const ACE_TCHAR * +ACE_DLL_Singleton_T::dll_name (void) +{ + return this->instance ()->dll_name (); +} + +template const ACE_TCHAR * +ACE_DLL_Singleton_T::name (void) +{ + return this->instance ()->name (); +} + + +/**********************************************************************/ + +template const ACE_TCHAR* +ACE_DLL_Singleton_Adapter_T::dll_name (void) +{ + // @todo make this a constant somewhere (or it there already is one + // then use it. + return ACE_TEXT("ACE"); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_SINGLETON_CPP */ diff --git a/dep/acelite/ace/Singleton.h b/dep/acelite/ace/Singleton.h new file mode 100644 index 000000000..d0cd95f4a --- /dev/null +++ b/dep/acelite/ace/Singleton.h @@ -0,0 +1,346 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Singleton.h + * + * @brief + * + * @author Tim Harrison + * @author Douglas C. Schmidt + * @author Chris Lahey + * @author Rich Christy + * @author David Levine + */ +//============================================================================= + +#ifndef ACE_SINGLETON_H +#define ACE_SINGLETON_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" +#include "ace/TSS_T.h" +#include "ace/Cleanup.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Singleton + * + * @brief A Singleton Adapter uses the Adapter pattern to turn ordinary + * classes into Singletons optimized with the Double-Checked + * Locking optimization pattern. + * + * This implementation is a slight variation on the GoF + * Singleton pattern. In particular, a single + * > instance is allocated here, + * not a instance. The reason for this is to allow + * registration with the ACE_Object_Manager, so that the + * Singleton can be cleaned up when the process exits. For this + * scheme to work, a (static) cleanup() function must be + * provided. ACE_Singleton provides one so that TYPE doesn't + * need to. + * If you want to make sure that only the singleton instance of + * is created, and that users cannot create their own + * instances of , do the following to class : + * (a) Make the constructor of private (or protected) + * (b) Make Singleton a friend of + * Here is an example: + * @verbatim + * class foo + * { + * friend class ACE_Singleton; + * private: + * foo () { cout << "foo constructed" << endl; } + * ~foo () { cout << "foo destroyed" << endl; } + * }; + * typedef ACE_Singleton FOO; + * @endverbatim + * + * @note The best types to use for ACE_LOCK are + * ACE_Recursive_Thread_Mutex and ACE_Null_Mutex. + * ACE_Recursive_Thread_Mutex should be used in multi-threaded + * programs in which it is possible for more than one thread to + * access the > instance. + * ACE_Null_Mutex can be used otherwise. The reason that these + * types of locks are best has to do with their allocation by + * the ACE_Object_Manager. Single ACE_Recursive_Thread_Mutex + * and ACE_Null_Mutex instances are used for all ACE_Singleton + * instantiations. However, other types of locks are allocated + * per ACE_Singleton instantiation. + */ +template +class ACE_Singleton : public ACE_Cleanup +{ +public: + /// Global access point to the Singleton. + static TYPE *instance (void); + + /// Cleanup method, used by @c ace_cleanup_destroyer to destroy the + /// ACE_Singleton. + virtual void cleanup (void *param = 0); + + /// Explicitly delete the Singleton instance. + static void close (void); + + /// Dump the state of the object. + static void dump (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Default constructor. + ACE_Singleton (void); + + /// Contained instance. + TYPE instance_; + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + /// Pointer to the Singleton (ACE_Cleanup) instance. + static ACE_Singleton *singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ + + /// Get pointer to the Singleton instance. + static ACE_Singleton *&instance_i (void); +}; + +/** + * @class ACE_Unmanaged_Singleton + * + * @brief Same as ACE_Singleton, except does _not_ register with + * ACE_Object_Manager for destruction. + * + * This version of ACE_Singleton can be used if, for example, + * its DLL will be unloaded before the ACE_Object_Manager + * destroys the instance. Unlike with ACE_Singleton, the + * application is responsible for explicitly destroying the + * instance after it is no longer needed (if it wants to avoid + * memory leaks, at least). The close() static member function + * must be used to explicitly destroy the Singleton. + * Usage is the same as for ACE_Singleton, but note that if you + * you declare a friend, the friend class must still be an + * *ACE_Singleton*, not an ACE_Unmanaged_Singleton. + */ +template +class ACE_Unmanaged_Singleton : public ACE_Singleton +{ +public: + /// Global access point to the Singleton. + static TYPE *instance (void); + + /// Explicitly delete the Singleton instance. + static void close (void); + + /// Dump the state of the object. + static void dump (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Default constructor. + ACE_Unmanaged_Singleton (void); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + /// Pointer to the Singleton (ACE_Cleanup) instance. + static ACE_Unmanaged_Singleton *singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ + + /// Get pointer to the Singleton instance. + static ACE_Unmanaged_Singleton *&instance_i (void); +}; + +/** + * @class ACE_TSS_Singleton + * + * @brief This class uses the Adapter pattern to turn ordinary classes + * into Thread-specific Singletons optimized with the + * Double-Checked Locking optimization pattern. + * + * This implementation is another variation on the GoF Singleton + * pattern. In this case, a single > instance is allocated here, not a instance. + * Each call to the static method returns a Singleton + * whose pointer resides in thread-specific storage. As with + * ACE_Singleton, we use the ACE_Object_Manager so that the + * Singleton can be cleaned up when the process exits. For this + * scheme to work, a (static) cleanup() function must be + * provided. ACE_Singleton provides one so that TYPE doesn't + * need to. + */ +template +class ACE_TSS_Singleton : public ACE_Cleanup +{ +public: + /// Global access point to the singleton. + static TYPE *instance (void); + + /// Cleanup method, used by to destroy the + /// singleton. + virtual void cleanup (void *param = 0); + + /// Dump the state of the object. + static void dump (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Default constructor. + ACE_TSS_Singleton (void); + + /// Contained instance. + ACE_TSS_TYPE (TYPE) instance_; + + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_TSS_Singleton &)) + ACE_UNIMPLEMENTED_FUNC (ACE_TSS_Singleton (const ACE_TSS_Singleton &)) + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + /// Pointer to the Singleton (ACE_Cleanup) instance. + static ACE_TSS_Singleton *singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ + + /// Get pointer to the TSS Singleton instance. + static ACE_TSS_Singleton *&instance_i (void); +}; + +/** + * @class ACE_Unmanaged_TSS_Singleton + * + * @brief Same as ACE_TSS_Singleton, except does _not_ register with + * ACE_Object_Manager for destruction. + * + * This version of ACE_TSS_Singleton can be used if, for example, its DLL will + * be unloaded before the ACE_Object_Manager destroys the instance. Unlike with + * ACE_Singleton, the application is responsible for explicitly destroying the + * instance after it is no longer needed (if it wants to avoid memory leaks, + * at least). The close() static member function must be used to explicitly + * destroy the Singleton. + */ +template +class ACE_Unmanaged_TSS_Singleton : public ACE_TSS_Singleton +{ +public: + /// Global access point to the singleton. + static TYPE *instance (void); + + /// Explicitly delete the singleton instance. + static void close (void); + + /// Dump the state of the object. + static void dump (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Default constructor. + ACE_Unmanaged_TSS_Singleton (void); + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + /// Pointer to the Singleton (ACE_Cleanup) instance. + static ACE_Unmanaged_TSS_Singleton *singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ + + /// Get pointer to the Singleton instance. + static ACE_Unmanaged_TSS_Singleton *&instance_i (void); +}; + +/** + * @class ACE_DLL_Singleton_T + * + * @brief Same as ACE_Singleton, except that it registers for + * destruction with the ACE_Framework_Repository instead of + * with the ACE_Object_Manager directly. + * + * This version of ACE_Singleton should be used for singletons + * that live in a dll loaded either directly by ACE_DLL or indirectly + * by the ACE Service Configuration framework. Whenever ACE_DLL is ready + * to actually unload the dll, ACE_DLL_Singleton based dlls associated + * with that dll will be destroyed first. In fact, any singleton can + * safely use ACE_DLL_Singleton, even those that don't live in dlls. In + * that case, the singleton will be destroyed at normal program shutdown. + * + * The only additional requirement is that the contained class + * export name() and dll_name() methods. See ACE_DLL_Singleton_Adapter_T + * below for a convenient example of how to satisfy this + * requirement for the dll_name(). + * + * Usage is the same as for ACE_Singleton, but note that if you + * you declare a friend, the friend class must still be an + * *ACE_Singleton*, not an ACE_Unmanaged_Singleton. + */ +template +class ACE_DLL_Singleton_T +{ +public: + //void cleanup (void *param = 0); + + /// Global access point to the Singleton. + static TYPE *instance (void); + + /// Explicitly delete the Singleton instance. + static void close (void); + + static void close_singleton (void); + + /// Dump the state of the object. + static void dump (void); + + const ACE_TCHAR *dll_name (void); + + const ACE_TCHAR *name (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Default constructor. + ACE_DLL_Singleton_T (void); + + /// Destructor. + ~ACE_DLL_Singleton_T (void); + + /// Contained instance. + TYPE instance_; + +#if !defined (ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES) + /// Pointer to the Singleton instance. + static ACE_DLL_Singleton_T *singleton_; +#endif /* ACE_LACKS_STATIC_DATA_MEMBER_TEMPLATES */ + + /// Get pointer to the singleton instance. + static ACE_DLL_Singleton_T *&instance_i (void); +}; + +template +class ACE_DLL_Singleton_Adapter_T : public TYPE +{ +public: + const ACE_TCHAR *dll_name (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Singleton.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Singleton.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Singleton.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_SINGLETON_H */ diff --git a/dep/acelite/ace/Singleton.inl b/dep/acelite/ace/Singleton.inl new file mode 100644 index 000000000..912271ba2 --- /dev/null +++ b/dep/acelite/ace/Singleton.inl @@ -0,0 +1,39 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Default constructors. +// +// Note: don't explicitly initialize "instance_", because TYPE may not +// have a default constructor. Let the compiler figure it out . . . + +template ACE_INLINE +ACE_Singleton::ACE_Singleton (void) +{ +} + +template ACE_INLINE +ACE_Unmanaged_Singleton::ACE_Unmanaged_Singleton (void) +{ +} + +template ACE_INLINE +ACE_TSS_Singleton::ACE_TSS_Singleton (void) +{ +} + +template ACE_INLINE +ACE_Unmanaged_TSS_Singleton::ACE_Unmanaged_TSS_Singleton (void) +{ +} + +template ACE_INLINE +ACE_DLL_Singleton_T::ACE_DLL_Singleton_T (void) +{ +} + +template +ACE_DLL_Singleton_T::~ACE_DLL_Singleton_T (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Sock_Connect.cpp b/dep/acelite/ace/Sock_Connect.cpp new file mode 100644 index 000000000..43606fa2f --- /dev/null +++ b/dep/acelite/ace/Sock_Connect.cpp @@ -0,0 +1,1536 @@ +#include "ace/Sock_Connect.h" +#include "ace/INET_Addr.h" +#include "ace/Log_Category.h" +#include "ace/Handle_Set.h" +#include "ace/Auto_Ptr.h" +#include "ace/SString.h" +#include "ace/OS_Memory.h" +#include "ace/OS_NS_stdio.h" +#include "ace/ACE.h" + +#if defined (sparc) +# include "ace/OS_NS_fcntl.h" +#endif // sparc + +#include "ace/OS_NS_stdlib.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_sys_socket.h" +#include "ace/OS_NS_netdb.h" +#include "ace/OS_NS_unistd.h" +#include "ace/os_include/net/os_if.h" + +#if defined (ACE_HAS_IPV6) +# include "ace/Guard_T.h" +# include "ace/Recursive_Thread_Mutex.h" +# if defined (_AIX) +# include /**/ +# endif /* _AIX */ +#endif /* ACE_HAS_IPV6 */ + +#if defined (ACE_HAS_GETIFADDRS) +# include "ace/os_include/os_ifaddrs.h" +#endif /* ACE_HAS_GETIFADDRS */ + +#if defined (ACE_VXWORKS) && (ACE_VXWORKS <= 0x670) && defined (__RTP__) && defined (ACE_HAS_IPV6) +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT; +const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; +const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; +#endif /* ACE_VXWORKS <= 0x670 && __RTP__ && ACE_HAS_IPV6 */ + +#if defined (ACE_HAS_WINCE) +#include /**/ +# if defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) && (_WIN32_WCE < 0x600) && defined (ACE_HAS_IPV6) +# include /**/ +const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; +const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; +# endif +#endif // ACE_HAS_WINCE + +#if defined (ACE_WIN32) && defined (ACE_HAS_PHARLAP) +# include "ace/OS_NS_stdio.h" +#endif + +#if defined (ACE_HAS_IPV6) + +// These defines support a generic usage based on +// the various SIGCF*IF ioctl implementations + +# if defined (SIOCGLIFCONF) +# define SIOCGIFCONF_CMD SIOCGLIFCONF +# if defined (__hpux) +# define IFREQ if_laddrreq +# define IFCONF if_laddrconf +# define IFC_REQ iflc_req +# define IFC_LEN iflc_len +# define IFC_BUF iflc_buf +# define IFR_ADDR iflr_addr +# define IFR_NAME iflr_name +# define IFR_FLAGS iflr_flags +# undef SETFAMILY +# define SA_FAMILY sa_family +# else +# define IFREQ lifreq +# define IFCONF lifconf +# define IFC_REQ lifc_req +# define IFC_LEN lifc_len +# define IFC_BUF lifc_buf +# define IFR_ADDR lifr_addr +# define IFR_NAME lifr_name +# define IFR_FLAGS lifr_flags +# define SETFAMILY +# define IFC_FAMILY lifc_family +# define IFC_FLAGS lifc_flags +# define SA_FAMILY ss_family +# endif +# else +# define SIOCGIFCONF_CMD SIOCGIFCONF +# define IFREQ ifreq +# define IFCONF ifconf +# define IFC_REQ ifc_req +# define IFC_LEN ifc_len +# define IFC_BUF ifc_buf +# define IFR_ADDR ifr_addr +# define IFR_NAME ifr_name +# define IFR_FLAGS ifr_flags +# undef SETFAMILY +# define SA_FAMILY sa_family +# endif /* SIOCGLIFCONF */ + +# if defined (ACE_HAS_THREADS) +# include "ace/Object_Manager.h" +# endif /* ACE_HAS_THREADS */ + +namespace +{ + // private: + // Used internally so not exported. + + // Does this box have ipv4 turned on? + int ace_ipv4_enabled = -1; + + // Does this box have ipv6 turned on? + int ace_ipv6_enabled = -1; + +} +#else /* ACE_HAS_IPV6 */ +# define SIOCGIFCONF_CMD SIOCGIFCONF +# define IFREQ ifreq +# define IFCONF ifconf +# define IFC_REQ ifc_req +# define IFC_LEN ifc_len +# define IFC_BUF ifc_buf +# define IFR_ADDR ifr_addr +# define IFR_NAME ifr_name +# define IFR_FLAGS ifr_flags +# undef SETFAMILY +# define SA_FAMILY sa_family +#endif /* ACE_HAS_IPV6 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Bind socket to an unused port. + +int +ACE::bind_port (ACE_HANDLE handle, ACE_UINT32 ip_addr, int address_family) +{ + ACE_TRACE ("ACE::bind_port"); + + ACE_INET_Addr addr; + +#if defined (ACE_HAS_IPV6) + if (address_family != PF_INET6) + // What do we do if it is PF_"INET6? Since it's 4 bytes, it must be an + // IPV4 address. Is there a difference? Why is this test done? dhinton +#else /* ACE_HAS_IPV6 */ + ACE_UNUSED_ARG (address_family); +#endif /* !ACE_HAS_IPV6 */ + addr = ACE_INET_Addr ((u_short)0, ip_addr); +#if defined (ACE_HAS_IPV6) + else if (ip_addr != INADDR_ANY) + // address_family == PF_INET6 and a non default IP address means to bind + // to the IPv4-mapped IPv6 address + addr.set ((u_short)0, ip_addr, 1, 1); +#endif /* ACE_HAS_IPV6 */ + + // The OS kernel should select a free port for us. + return ACE_OS::bind (handle, + (sockaddr*)addr.get_addr(), + addr.get_size()); +} + +int +ACE::get_bcast_addr (ACE_UINT32 &bcast_addr, + const ACE_TCHAR *host_name, + ACE_UINT32 host_addr, + ACE_HANDLE handle) +{ + ACE_TRACE ("ACE::get_bcast_addr"); + +#if defined (ACE_LACKS_GET_BCAST_ADDR) + ACE_UNUSED_ARG (bcast_addr); + ACE_UNUSED_ARG (host_name); + ACE_UNUSED_ARG (host_addr); + ACE_UNUSED_ARG (handle); + ACE_NOTSUP_RETURN (-1); +#elif !defined(ACE_WIN32) && !defined(__INTERIX) + ACE_HANDLE s = handle; + + if (s == ACE_INVALID_HANDLE) + s = ACE_OS::socket (AF_INET, SOCK_STREAM, 0); + + if (s == ACE_INVALID_HANDLE) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_OS::socket")), + -1); + + struct ifconf ifc; + char buf[BUFSIZ]; + + ifc.ifc_len = sizeof buf; + ifc.ifc_buf = buf; + + // Get interface structure and initialize the addresses using UNIX + // techniques + if (ACE_OS::ioctl (s, SIOCGIFCONF_CMD, (char *) &ifc) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT ("ioctl (get interface configuration)")), + -1); + + struct ifreq *ifr = ifc.ifc_req; + + struct sockaddr_in ip_addr; + + // Get host ip address if necessary. + if (host_name) + { + hostent *hp = ACE_OS::gethostbyname (ACE_TEXT_ALWAYS_CHAR (host_name)); + + if (hp == 0) + return -1; + else + ACE_OS::memcpy ((char *) &ip_addr.sin_addr.s_addr, +# ifdef ACE_HOSTENT_H_ADDR + (char *) hp->ACE_HOSTENT_H_ADDR, +# else + (char *) hp->h_addr, +# endif + hp->h_length); + } + else + { + ACE_OS::memset ((void *) &ip_addr, 0, sizeof ip_addr); + ACE_OS::memcpy ((void *) &ip_addr.sin_addr, + (void*) &host_addr, + sizeof ip_addr.sin_addr); + } + +#if !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) + for (int n = ifc.ifc_len / sizeof (struct ifreq) ; n > 0; + n--, ifr++) +#else + // see mk_broadcast@SOCK_Dgram_Bcast.cpp + for (int nbytes = ifc.ifc_len; nbytes >= (int) sizeof (struct ifreq) && + ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ? + (nbytes >= (int) sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len) : 1); + ((ifr->ifr_addr.sa_len > sizeof (struct sockaddr)) ? + (nbytes -= sizeof (ifr->ifr_name) + ifr->ifr_addr.sa_len, + ifr = (struct ifreq *) + ((caddr_t) &ifr->ifr_addr + ifr->ifr_addr.sa_len)) : + (nbytes -= sizeof (struct ifreq), ifr++))) +#endif /* !defined(AIX) && !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (__Lynx__) */ + { + struct sockaddr_in if_addr; + + // Compare host ip address with interface ip address. + ACE_OS::memcpy (&if_addr, + &ifr->ifr_addr, + sizeof if_addr); + + if (ip_addr.sin_addr.s_addr != if_addr.sin_addr.s_addr) + continue; + + if (ifr->ifr_addr.sa_family != AF_INET) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT ("Not AF_INET"))); + continue; + } + + struct ifreq flags = *ifr; + struct ifreq if_req = *ifr; + + if (ACE_OS::ioctl (s, SIOCGIFFLAGS, (char *) &flags) == -1) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT (" ioctl (get interface flags)"))); + continue; + } + + if (ACE_BIT_DISABLED (flags.ifr_flags, IFF_UP)) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT ("Network interface is not up"))); + continue; + } + + if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_LOOPBACK)) + continue; + + if (ACE_BIT_ENABLED (flags.ifr_flags, IFF_BROADCAST)) + { + if (ACE_OS::ioctl (s, + SIOCGIFBRDADDR, + (char *) &if_req) == -1) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT ("ioctl (get broadaddr)"))); + else + { + ACE_OS::memcpy (&ip_addr, + &if_req.ifr_broadaddr, + sizeof if_req.ifr_broadaddr); + + ACE_OS::memcpy ((void *) &host_addr, + (void *) &ip_addr.sin_addr, + sizeof host_addr); + + if (handle == ACE_INVALID_HANDLE) + ACE_OS::close (s); + + bcast_addr = host_addr; + return 0; + } + } + else + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_bcast_addr:") + ACE_TEXT ("Broadcast is not enabled for this interface."))); + + if (handle == ACE_INVALID_HANDLE) + ACE_OS::close (s); + + bcast_addr = host_addr; + return 0; + } + + return 0; +#else + ACE_UNUSED_ARG (handle); + ACE_UNUSED_ARG (host_addr); + ACE_UNUSED_ARG (host_name); + bcast_addr = (ACE_UINT32 (INADDR_BROADCAST)); + return 0; +#endif /* !ACE_WIN32 && !__INTERIX */ +} + +int +ACE::get_fqdn (ACE_INET_Addr const & addr, + char hostname[], + size_t len) +{ +#ifndef ACE_LACKS_GETNAMEINFO + + const socklen_t addr_size = +# ifdef ACE_HAS_IPV6 + (addr.get_type () == PF_INET6) ? sizeof (sockaddr_in6) : +# endif + sizeof (sockaddr_in); + + if (ACE_OS::getnameinfo ((const sockaddr *) addr.get_addr (), + addr_size, hostname, + static_cast (len), + 0, 0, NI_NAMEREQD) != 0) + return -1; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ") + ACE_TEXT ("canonical host name is %C\n"), + hostname)); + + return 0; +#else // below, ACE_LACKS_GETNAMEINFO + int h_error; // Not the same as errno! + hostent hentry; + ACE_HOSTENT_DATA buf; + + char * ip_addr = 0; + int ip_addr_size = 0; + if (addr.get_type () == AF_INET) + { + sockaddr_in * const sock_addr = + reinterpret_cast (addr.get_addr ()); + ip_addr_size = sizeof sock_addr->sin_addr; + ip_addr = (char*) &sock_addr->sin_addr; + } +# ifdef ACE_HAS_IPV6 + else + { + sockaddr_in6 * sock_addr = + reinterpret_cast (addr.get_addr ()); + + ip_addr_size = sizeof sock_addr->sin6_addr; + ip_addr = (char*) &sock_addr->sin6_addr; + } +# endif /* ACE_HAS_IPV6 */ + + // get the host entry for the address in question + hostent * const hp = ACE_OS::gethostbyaddr_r (ip_addr, + ip_addr_size, + addr.get_type (), + &hentry, + buf, + &h_error); + + // if it's not found in the host file or the DNS datase, there is nothing + // much we can do. embed the IP address + if (hp == 0 || hp->h_name == 0) + return -1; + + if (ACE::debug()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ") + ACE_TEXT ("canonical host name is %C\n"), + hp->h_name)); + + // check if the canonical name is the FQDN + if (!ACE_OS::strchr(hp->h_name, '.')) + { + // list of address + char** p; + // list of aliases + char** q; + + // for every address and for every alias within the address, check and + // see if we can locate a FQDN + for (p = hp->h_addr_list; *p != 0; ++p) + { + for (q = hp->h_aliases; *q != 0; ++q) + { + if (ACE_OS::strchr(*q, '.')) + { + // we got an FQDN from an alias. use this + if (ACE_OS::strlen (*q) >= len) + // the hostname is too huge to fit into a + // buffer of size MAXHOSTNAMELEN + // should we check other aliases as well + // before bailing out prematurely? + // for right now, let's do it. this (short name) + // is atleast better than embedding the IP + // address in the profile + continue; + + if (ACE::debug ()) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("(%P|%t) - ACE::get_fqdn, ") + ACE_TEXT ("found fqdn within alias as %C\n"), + *q)); + ACE_OS::strcpy (hostname, *q); + + return 0; + } + } + } + } + + // The canonical name may be an FQDN when we reach here. + // Alternatively, the canonical name (a non FQDN) may be the best + // we can do. + if (ACE_OS::strlen (hp->h_name) >= len) + { + // The hostname is too large to fit into a buffer of size + // MAXHOSTNAMELEN. + return -2; + } + else + { + ACE_OS::strcpy (hostname, hp->h_name); + } + + return 0; +#endif /* ACE_LACKS_GETNAMEINFO */ +} + +#if defined (ACE_WIN32) + +static int +get_ip_interfaces_win32 (size_t &count, + ACE_INET_Addr *&addrs) +{ +# if defined (ACE_HAS_WINCE) && defined (ACE_HAS_WINSOCK2) && (ACE_HAS_WINSOCK2 != 0) + // moved the ACE_HAS_WINCE impl ahaid of ACE_HAS_WINSOCK2 because + // WINCE in fact has winsock2, but doesn't properly support the + // WSAIoctl for obtaining IPv6 address info. + PIP_ADAPTER_ADDRESSES AdapterAddresses = 0; + ULONG OutBufferLength = 0; + ULONG RetVal = 0; + unsigned char *octet_buffer = 0; + + RetVal = + GetAdaptersAddresses(AF_UNSPEC, + 0, + 0, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != ERROR_BUFFER_OVERFLOW) + { + return -1; + } + + ACE_NEW_RETURN (octet_buffer, unsigned char[OutBufferLength],-1); + AdapterAddresses = (IP_ADAPTER_ADDRESSES *)octet_buffer; + + RetVal = + GetAdaptersAddresses(AF_UNSPEC, + 0, + 0, + AdapterAddresses, + &OutBufferLength); + + if (RetVal != NO_ERROR) + { + delete [] octet_buffer; + return -1; + } + + // If successful, output some information from the data we received + PIP_ADAPTER_ADDRESSES AdapterList = AdapterAddresses; + while (AdapterList) + { + if (AdapterList->OperStatus == IfOperStatusUp) + { + if (AdapterList->IfIndex != 0) + ++count; + if (AdapterList->Ipv6IfIndex != 0) + ++count; + } + AdapterList = AdapterList->Next; + } + + AdapterList = AdapterAddresses; + + ACE_NEW_RETURN (addrs, ACE_INET_Addr[count],-1); + count = 0; + for (AdapterList = AdapterAddresses; + AdapterList != 0; + AdapterList = AdapterList->Next) + { + if (AdapterList->OperStatus != IfOperStatusUp) + continue; + + IP_ADAPTER_UNICAST_ADDRESS *uni = 0; + if (AdapterList->IfIndex != 0) + for (uni = AdapterList->FirstUnicastAddress; + uni != 0; + uni = uni->Next) + { + SOCKET_ADDRESS *sa_addr = &uni->Address; + if (sa_addr->lpSockaddr->sa_family == AF_INET) + { + sockaddr_in *sin = (sockaddr_in*)sa_addr->lpSockaddr; + addrs[count].set(sin,sa_addr->iSockaddrLength); + ++count; + break; + } + } + if (AdapterList->Ipv6IfIndex != 0) + { + for (uni = AdapterList->FirstUnicastAddress; + uni != 0; + uni = uni->Next) + { + SOCKET_ADDRESS *sa_addr = &uni->Address; + if (sa_addr->lpSockaddr->sa_family == AF_INET6) + { + sockaddr_in *sin = (sockaddr_in*)sa_addr->lpSockaddr; + addrs[count].set(sin,sa_addr->iSockaddrLength); + ++count; + break; + } + } + } + } + + delete [] octet_buffer; + return 0; + +# elif defined (ACE_HAS_PHARLAP) + // PharLap ETS has its own kernel routines to rummage through the device + // configs and extract the interface info, but only for Pharlap RT. +# if !defined (ACE_HAS_PHARLAP_RT) + ACE_NOTSUP_RETURN (-1); +# endif /* ACE_HAS_PHARLAP_RT */ + + // Locate all of the IP devices in the system, saving a DEVHANDLE + // for each. Then allocate the ACE_INET_Addrs needed and fetch all + // the IP addresses. To locate the devices, try the available + // device name roots and increment the device number until the + // kernel says there are no more of that type. + const size_t ACE_MAX_ETS_DEVICES = 64; // Arbitrary, but should be enough. + DEVHANDLE ip_dev[ACE_MAX_ETS_DEVICES]; + EK_TCPIPCFG *devp = 0; + size_t i, j; + ACE_TCHAR dev_name[16]; + + count = 0; + for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) + { + // Ethernet. + ACE_OS::sprintf (dev_name, + "ether%d", + i); + ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); + if (ip_dev[count] == 0) + break; + } + for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) + { + // SLIP. + ACE_OS::sprintf (dev_name, + "sl%d", + i); + ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); + if (ip_dev[count] == 0) + break; + } + for (i = 0; count < ACE_MAX_ETS_DEVICES; i++, ++count) + { + // PPP. + ACE_OS::sprintf (dev_name, + "ppp%d", + i); + ip_dev[count] = EtsTCPGetDeviceHandle (dev_name); + if (ip_dev[count] == 0) + break; + } + + if (count > 0) + ACE_NEW_RETURN (addrs, + ACE_INET_Addr[count], + -1); + else + addrs = 0; + + for (i = 0, j = 0; i < count; i++) + { + devp = EtsTCPGetDeviceCfg (ip_dev[i]); + if (devp != 0) + { + addrs[j].set (0, + devp->nwIPAddress, + 0); // Already in net order. + ++j; + } + // There's no call to close the DEVHANDLE. + } + + count = j; + if (count == 0 && addrs != 0) + { + delete [] addrs; + addrs = 0; + } + + return 0; + + +# else + // All non-CE, non-Pharlap Windows. Must support Winsock2. + + int i, n_interfaces, status; + + INTERFACE_INFO info[64]; + SOCKET sock; + + // Get an (overlapped) DGRAM socket to test with + sock = socket (AF_INET, SOCK_DGRAM, 0); + if (sock == INVALID_SOCKET) + return -1; + + DWORD bytes; + status = WSAIoctl(sock, + SIO_GET_INTERFACE_LIST, + 0, + 0, + info, + sizeof(info), + &bytes, + 0, + 0); + closesocket (sock); + if (status == SOCKET_ERROR) + return -1; + + n_interfaces = bytes / sizeof(INTERFACE_INFO); + + // SIO_GET_INTERFACE_LIST does not work for IPv6 + // Instead recent versions of Winsock2 add the new opcode + // SIO_ADDRESS_LIST_QUERY. + // If this is not available forget about IPv6 local interfaces:-/ + int n_v6_interfaces = 0; + +# if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY) + + LPSOCKET_ADDRESS_LIST v6info; + char *buffer; + DWORD buflen = sizeof (SOCKET_ADDRESS_LIST) + (63 * sizeof (SOCKET_ADDRESS)); + ACE_NEW_RETURN (buffer, + char[buflen], + -1); + v6info = reinterpret_cast (buffer); + + // Get an (overlapped) DGRAM socket to test with. + // If it fails only return IPv4 interfaces. + sock = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (sock != INVALID_SOCKET) + { + status = WSAIoctl(sock, + SIO_ADDRESS_LIST_QUERY, + 0, + 0, + v6info, + buflen, + &bytes, + 0, + 0); + closesocket (sock); + if (status != SOCKET_ERROR) + n_v6_interfaces = v6info->iAddressCount; + } +# endif /* ACE_HAS_IPV6 */ + + ACE_NEW_RETURN (addrs, + ACE_INET_Addr[n_interfaces + n_v6_interfaces], + -1); + + // Now go through the list and transfer the good ones to the list of + // because they're down or don't have an IP address. + for (count = 0, i = 0; i < n_interfaces; ++i) + { + LPINTERFACE_INFO lpii; + struct sockaddr_in *addrp = 0; + + lpii = &info[i]; + if (!(lpii->iiFlags & IFF_UP)) + continue; + + // We assume IPv4 addresses here + addrp = reinterpret_cast (&lpii->iiAddress.AddressIn); + if (addrp->sin_addr.s_addr == INADDR_ANY) + continue; + + // Set the address for the caller. + addrs[count].set(addrp, sizeof(sockaddr_in)); + ++count; + } + +# if defined (ACE_HAS_IPV6) && defined (SIO_ADDRESS_LIST_QUERY) + // Now go through the list and transfer the good ones to the list of + // because they're down or don't have an IP address. + for (i = 0; i < n_v6_interfaces; i++) + { + struct sockaddr_in6 *addr6p; + + if (v6info->Address[i].lpSockaddr->sa_family != AF_INET6) + continue; + + addr6p = reinterpret_cast (v6info->Address[i].lpSockaddr); + if (IN6_IS_ADDR_UNSPECIFIED(&addr6p->sin6_addr)) // IN6ADDR_ANY? + continue; + + // Set the address for the caller. + addrs[count].set(reinterpret_cast (addr6p), sizeof(sockaddr_in6)); + ++count; + } + + delete [] buffer; // Clean up +# endif /* ACE_HAS_IPV6 */ + + if (count == 0) + { + delete [] addrs; + addrs = 0; + } + + return 0; + +# endif /* ACE_HAS_WINCE */ +} + +#elif defined (ACE_HAS_GETIFADDRS) +static int +get_ip_interfaces_getifaddrs (size_t &count, + ACE_INET_Addr *&addrs) +{ + // Take advantage of the BSD getifaddrs function that simplifies + // access to connected interfaces. + struct ifaddrs *ifap = 0; + struct ifaddrs *p_if = 0; + + if (::getifaddrs (&ifap) != 0) + return -1; + + // Count number of interfaces. + size_t num_ifs = 0; + for (p_if = ifap; p_if != 0; p_if = p_if->ifa_next) + ++num_ifs; + + // Now create and initialize output array. + ACE_NEW_RETURN (addrs, + ACE_INET_Addr[num_ifs], + -1); // caller must free + + // Pull the address out of each INET interface. Not every interface + // is for IP, so be careful to count properly. When setting the + // INET_Addr, note that the 3rd arg (0) says to leave the byte order + // (already in net byte order from the interface structure) as is. + count = 0; + + for (p_if = ifap; + p_if != 0; + p_if = p_if->ifa_next) + { + if (p_if->ifa_addr == 0) + continue; + + // Check to see if it's up. + if ((p_if->ifa_flags & IFF_UP) != IFF_UP) + continue; + + if (p_if->ifa_addr->sa_family == AF_INET) + { + struct sockaddr_in *addr = + reinterpret_cast (p_if->ifa_addr); + + // Sometimes the kernel returns 0.0.0.0 as the interface + // address, skip those... + if (addr->sin_addr.s_addr != INADDR_ANY) + { + addrs[count].set ((u_short) 0, + addr->sin_addr.s_addr, + 0); + ++count; + } + } +# if defined (ACE_HAS_IPV6) + else if (p_if->ifa_addr->sa_family == AF_INET6) + { + struct sockaddr_in6 *addr = + reinterpret_cast (p_if->ifa_addr); + + // Skip the ANY address + if (!IN6_IS_ADDR_UNSPECIFIED(&addr->sin6_addr)) + { + addrs[count].set(reinterpret_cast (addr), + sizeof(sockaddr_in6)); + ++count; + } + } +# endif /* ACE_HAS_IPV6 */ + } + + ::freeifaddrs (ifap); + + return 0; +} +#elif defined (__hpux) +static int +get_ip_interfaces_hpux (size_t &count, + ACE_INET_Addr *&addrs) +{ + size_t num_ifs = 0; + size_t num_ifs_found = 0; + + // Call specific routine as necessary. + ACE_HANDLE handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0); + ACE_HANDLE handle_ipv6 = ACE_INVALID_HANDLE; + + if (handle == ACE_INVALID_HANDLE) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces:open")), + -1); + + int result = 0; + int tmp_how_many = 0; + + result = ACE_OS::ioctl (handle, + SIOCGIFNUM, + (caddr_t) &tmp_how_many); + if (result != -1) + num_ifs = (size_t)tmp_how_many; + +# if defined (ACE_HAS_IPV6) + tmp_how_many = 0; + handle_ipv6 = ACE_OS::socket (PF_INET6, SOCK_DGRAM, 0); + result = ACE_OS::ioctl (handle_ipv6, + SIOCGLIFNUM, + (caddr_t) &tmp_how_many); + if (result != -1) + num_ifs += (size_t)tmp_how_many; +# endif + + if (num_ifs == 0) + { + ACE_OS::close (handle); + ACE_OS::close (handle_ipv6); + return -1; + } + + // ioctl likes to have an extra IFREQ structure to mark the end of + // what it returned, so increase the num_ifs by one. + ++num_ifs; + + //HPUX requires two passes, First for IPv4, then for IPv6 + + struct ifreq *ifs = 0; + ACE_NEW_RETURN (ifs, + struct ifreq[num_ifs], + -1); + ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct ifreq)); + + ACE_Auto_Array_Ptr p_ifs (ifs); + + if (p_ifs.get() == 0) + { + ACE_OS::close (handle); + ACE_OS::close (handle_ipv6); + errno = ENOMEM; + return -1; + } + + struct ifconf ifcfg; + ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf)); + + ifcfg.ifc_req = p_ifs.get (); + ifcfg.ifc_len = num_ifs * sizeof (struct ifreq); + + if (ACE_OS::ioctl (handle, + SIOCGIFCONF, + (char *) &ifcfg) == -1) + { + ACE_OS::close (handle); + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces:") + ACE_TEXT ("ioctl - SIOCGIFCONF failed")), + -1); + } + + ACE_OS::close (handle); + + // Now create and initialize output array. + + ACE_NEW_RETURN (addrs, + ACE_INET_Addr[num_ifs], + -1); // caller must free + + struct ifreq *pcur = p_ifs.get (); + num_ifs_found = ifcfg.ifc_len / sizeof (struct ifreq); // get the number of returned ifs + + for (size_t i = 0; + i < num_ifs_found; + i++) + { + struct sockaddr_in *addr = + reinterpret_cast (&pcur->ifr_addr); + if (addr->sin_addr.s_addr != 0) + { + addrs[count].set ((u_short) 0, + addr->sin_addr.s_addr, + 0); + ++count; + } + ++pcur; + } + +# if defined (ACE_HAS_IPV6) + + if (handle_ipv6 != ACE_INVALID_HANDLE) + { + struct if_laddrreq *lifs = 0; + ACE_NEW_RETURN (lifs, + struct if_laddrreq[num_ifs], + -1); + ACE_OS::memset (lifs, 0, num_ifs * sizeof (struct if_laddrreq)); + + ACE_Auto_Array_Ptr p_lifs (lifs); + + if (p_lifs.get() == 0) + { + ACE_OS::close (handle); + ACE_OS::close (handle_ipv6); + errno = ENOMEM; + return -1; + } + + struct if_laddrconf lifcfg; + ACE_OS::memset (&lifcfg, 0, sizeof (struct if_laddrconf)); + + lifcfg.iflc_req = p_lifs.get (); + lifcfg.iflc_len = num_ifs * sizeof (struct if_laddrreq); + + if (ACE_OS::ioctl (handle_ipv6, + SIOCGLIFCONF, + (char *) &lifcfg) == -1) + { + ACE_OS::close (handle); + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces:") + ACE_TEXT ("ioctl - SIOCGLIFCONF failed")), + -1); + } + + ACE_OS::close (handle_ipv6); + + struct if_laddrreq *plcur = p_lifs.get (); + num_ifs_found = lifcfg.iflc_len / sizeof (struct if_laddrreq); + + for (size_t i = 0; + i < num_ifs_found; + i++) + { + struct sockaddr_in *addr = + reinterpret_cast (&plcur->iflr_addr); + if (!IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(addr)->sin6_addr)) + { + addrs[count].set(addr, sizeof(struct sockaddr_in6)); + ++count; + } + ++plcur; + } + } +# endif /* ACE_HAS_IPV6 */ + return 0; +} +#elif defined (_AIX) +static int +get_ip_interfaces_aix (size_t &count, + ACE_INET_Addr *&addrs) +{ + ACE_HANDLE handle = ACE::get_handle(); + size_t num_ifs = 0; + struct ifconf ifc; + + if (handle == ACE_INVALID_HANDLE) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces_aix:")), + -1); + + if (ACE_OS::ioctl (handle, + SIOCGSIZIFCONF, + (caddr_t)&ifc.ifc_len) == -1) + { + ACE_OS::close (handle); + ACELIB_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get ifconf size")), + -1); + } + + ACE_NEW_RETURN (ifc.ifc_buf,char [ifc.ifc_len], -1); + + ACE_Auto_Array_Ptr safe_buf (ifc.ifc_buf); + ACE_OS::memset (safe_buf.get(), 0, ifc.ifc_len); + + if (ACE_OS::ioctl(handle, SIOCGIFCONF, (caddr_t)&ifc) == -1) + { + ACE_OS::close (handle); + ACELIB_ERROR_RETURN((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("get ifconf")), + -1); + } + + ACE_OS::close (handle); + + char *buf_start = safe_buf.get(); + char *buf_end = buf_start + ifc.ifc_len; + + num_ifs = 0; + for (char *ptr = buf_start; ptr < buf_end; ) + { + struct ifreq *req = reinterpret_cast(ptr); + ptr += IFNAMSIZ; + ptr += req->ifr_addr.sa_len; + if (req->ifr_addr.sa_family == AF_INET +# if defined (ACE_HAS_IPV6) + || req->ifr_addr.sa_family == AF_INET6 +# endif + ) + ++num_ifs; + } + ACE_NEW_RETURN (addrs,ACE_INET_Addr[num_ifs], -1); + + for (char * ptr = buf_start; ptr < buf_end; ) + { + struct ifreq *req = reinterpret_cast(ptr); + // skip the interface name + ptr += IFNAMSIZ; + if (req->ifr_addr.sa_family == AF_INET +# if defined (ACE_HAS_IPV6) + || req->ifr_addr.sa_family == AF_INET6 +# endif + ) + { + sockaddr_in *addr = (sockaddr_in*)&req->ifr_addr; + addrs[count++].set(addr, addr->sin_len); + } + ptr += req->ifr_addr.sa_len; + } + + return 0; +} + +#endif // ACE_WIN32 || ACE_HAS_GETIFADDRS || __hpux || _AIX + + +// return an array of all configured IP interfaces on this host, count +// rc = 0 on success (count == number of interfaces else -1 caller is +// responsible for calling delete [] on parray + +int +ACE::get_ip_interfaces (size_t &count, ACE_INET_Addr *&addrs) +{ + ACE_TRACE ("ACE::get_ip_interfaces"); + + count = 0; + addrs = 0; + +#if defined (ACE_WIN32) + return get_ip_interfaces_win32 (count, addrs); +#elif defined (ACE_HAS_GETIFADDRS) + return get_ip_interfaces_getifaddrs (count, addrs); +#elif defined (__hpux) + return get_ip_interfaces_hpux (count, addrs); +#elif defined (_AIX) + return get_ip_interfaces_aix (count, addrs); +#elif (defined (__unix) || defined (__unix__) || defined (ACE_OPENVMS) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS)) || defined (ACE_HAS_RTEMS)) && !defined (ACE_LACKS_NETWORKING) + // COMMON (SVR4 and BSD) UNIX CODE + + // Call specific routine as necessary. + ACE_HANDLE handle = ACE::get_handle(); + + if (handle == ACE_INVALID_HANDLE) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces:open")), + -1); + + size_t num_ifs = 0; + + if (ACE::count_interfaces (handle, num_ifs)) + { + ACE_OS::close (handle); + return -1; + } + + // ioctl likes to have an extra ifreq structure to mark the end of + // what it returned, so increase the num_ifs by one. + ++num_ifs; + + struct IFREQ *ifs = 0; + ACE_NEW_RETURN (ifs, + struct IFREQ[num_ifs], + -1); + ACE_OS::memset (ifs, 0, num_ifs * sizeof (struct IFREQ)); + + ACE_Auto_Array_Ptr p_ifs (ifs); + + if (p_ifs.get() == 0) + { + ACE_OS::close (handle); + errno = ENOMEM; + return -1; + } + + struct IFCONF ifcfg; + ACE_OS::memset (&ifcfg, 0, sizeof (struct IFCONF)); + +# ifdef SETFAMILY + ifcfg.IFC_FAMILY = AF_UNSPEC; // request all families be returned + ifcfg.IFC_FLAGS = 0; +# endif + + ifcfg.IFC_REQ = p_ifs.get (); + ifcfg.IFC_LEN = num_ifs * sizeof (struct IFREQ); + + if (ACE_OS::ioctl (handle, + SIOCGIFCONF_CMD, + (caddr_t) &ifcfg) == -1) + { + ACE_OS::close (handle); + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::get_ip_interfaces:") + ACE_TEXT ("ioctl - SIOCGIFCONF failed")), + -1); + } + + ACE_OS::close (handle); + + // Now create and initialize output array. + + ACE_NEW_RETURN (addrs, + ACE_INET_Addr[num_ifs], + -1); // caller must free + + struct IFREQ *pcur = p_ifs.get (); + size_t num_ifs_found = ifcfg.IFC_LEN / sizeof (struct IFREQ); // get the number of returned ifs + + // Pull the address out of each INET interface. Not every interface + // is for IP, so be careful to count properly. When setting the + // INET_Addr, note that the 3rd arg (0) says to leave the byte order + // (already in net byte order from the interface structure) as is. + count = 0; + + for (size_t i = 0; + i < num_ifs_found; + i++) + { + if (pcur->IFR_ADDR.SA_FAMILY == AF_INET +# if defined (ACE_HAS_IPV6) + || pcur->IFR_ADDR.SA_FAMILY == AF_INET6 +# endif + ) + + { + struct sockaddr_in *addr = + reinterpret_cast (&pcur->IFR_ADDR); + + // Sometimes the kernel returns 0.0.0.0 as an IPv4 interface + // address; skip those... + if (addr->sin_addr.s_addr != 0 +# if defined (ACE_HAS_IPV6) + || (addr->sin_family == AF_INET6 && + !IN6_IS_ADDR_UNSPECIFIED(&reinterpret_cast(addr)->sin6_addr)) +# endif + ) + { + int addrlen = static_cast (sizeof (struct sockaddr_in)); +# if defined (ACE_HAS_IPV6) + if (addr->sin_family == AF_INET6) + addrlen = static_cast (sizeof (struct sockaddr_in6)); +# endif + addrs[count].set (addr, addrlen); + ++count; + } + } + +#if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) && !defined (__Lynx__) + ++pcur; +#else + if (pcur->ifr_addr.sa_len <= sizeof (struct sockaddr)) + { + ++pcur; + } + else + { + pcur = (struct ifreq *) + (pcur->ifr_addr.sa_len + (caddr_t) &pcur->ifr_addr); + } +#endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) && !defined (__Lynx__) */ + } + +# if defined (ACE_HAS_IPV6) && !defined (ACE_LACKS_FSCANF) + // Retrieve IPv6 local interfaces by scanning /proc/net/if_inet6 if + // it exists. If we cannot open it then ignore possible IPv6 + // interfaces, we did our best;-) + FILE* fp = 0; + char addr_p[8][5]; + char s_ipaddr[64]; + int scopeid; + struct addrinfo hints, *res0; + int error; + + ACE_OS::memset (&hints, 0, sizeof (hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET6; + + if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0) + { + while (fscanf (fp, + "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*8s\n", + addr_p[0], addr_p[1], addr_p[2], addr_p[3], + addr_p[4], addr_p[5], addr_p[6], addr_p[7], &scopeid) != EOF) + { + // Format the address intoa proper IPv6 decimal address specification and + // resolve the resulting text using getaddrinfo(). + + const char* ip_fmt = "%s:%s:%s:%s:%s:%s:%s:%s%%%d"; + ACE_OS::snprintf (s_ipaddr, 64, ip_fmt, + addr_p[0], addr_p[1], addr_p[2], addr_p[3], + addr_p[4], addr_p[5], addr_p[6], addr_p[7], + scopeid); + + error = ACE_OS::getaddrinfo (s_ipaddr, 0, &hints, &res0); + if (error) + continue; + + if (res0->ai_family == AF_INET6 && + !IN6_IS_ADDR_UNSPECIFIED (&reinterpret_cast (res0->ai_addr)->sin6_addr)) + { + addrs[count].set(reinterpret_cast (res0->ai_addr), res0->ai_addrlen); + ++count; + } + ACE_OS::freeaddrinfo (res0); + + } + ACE_OS::fclose (fp); + } +# endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */ + + return 0; +#else + ACE_UNUSED_ARG (count); + ACE_UNUSED_ARG (addrs); + ACE_NOTSUP_RETURN (-1); // no implementation +#endif /* ACE_WIN32 */ +} + +// Helper routine for get_ip_interfaces, differs by UNIX platform so +// put into own subroutine. perform some ioctls to retrieve ifconf +// list of ifreq structs. + +int +ACE::count_interfaces (ACE_HANDLE handle, size_t &how_many) +{ +#if defined (SIOCGIFNUM) +# if defined (SIOCGLIFNUM) && !defined (ACE_LACKS_STRUCT_LIFNUM) + int cmd = SIOCGLIFNUM; + struct lifnum if_num = {AF_UNSPEC,0,0}; +# else + int cmd = SIOCGIFNUM; + int if_num = 0; +# endif /* SIOCGLIFNUM */ + if (ACE_OS::ioctl (handle, cmd, (caddr_t)&if_num) == -1) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::count_interfaces:") + ACE_TEXT ("ioctl - SIOCGLIFNUM failed")), + -1); +# if defined (SIOCGLIFNUM) && !defined (ACE_LACKS_STRUCT_LIFNUM) + how_many = if_num.lifn_count; +# else + how_many = if_num; +# endif /* SIOCGLIFNUM */ +return 0; + +#elif (defined (__unix) || defined (__unix__) || defined (ACE_OPENVMS) || defined (ACE_HAS_RTEMS) || (defined (ACE_VXWORKS) && !defined (ACE_HAS_GETIFADDRS))) && !defined (ACE_LACKS_NETWORKING) + // Note: DEC CXX doesn't define "unix". BSD compatible OS: HP UX, + // AIX, SunOS 4.x perform some ioctls to retrieve ifconf list of + // ifreq structs no SIOCGIFNUM on SunOS 4.x, so use guess and scan + // algorithm + + // Probably hard to put this many ifs in a unix box.. + int const MAX_INTERFACES = 50; + + // HACK - set to an unreasonable number + int const num_ifs = MAX_INTERFACES; + + struct ifconf ifcfg; + size_t ifreq_size = num_ifs * sizeof (struct ifreq); + struct ifreq *p_ifs; + +#if defined (ACE_HAS_ALLOC_HOOKS) + p_ifs = (struct IFREQ *)ACE_Allocator::instance()->malloc (ifreq_size); +#else + p_ifs = (struct ifreq *) ACE_OS::malloc (ifreq_size); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + if (!p_ifs) + { + errno = ENOMEM; + return -1; + } + + ACE_OS::memset (p_ifs, 0, ifreq_size); + ACE_OS::memset (&ifcfg, 0, sizeof (struct ifconf)); + + ifcfg.ifc_req = p_ifs; + ifcfg.ifc_len = ifreq_size; + + if (ACE_OS::ioctl (handle, + SIOCGIFCONF_CMD, + (caddr_t) &ifcfg) == -1) + { +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (ifcfg.ifc_req); +#else + ACE_OS::free (ifcfg.ifc_req); +#endif /* ACE_HAS_ALLOC_HOOKS */ + + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE::count_interfaces:") + ACE_TEXT ("ioctl - SIOCGIFCONF failed")), + -1); + } + + int if_count = 0; + int i = 0; + + // get if address out of ifreq buffers. ioctl puts a blank-named + // interface to mark the end of the returned interfaces. + for (i = 0; + i < num_ifs; + i++) + { + /* In OpenBSD, the length of the list is returned. */ + ifcfg.ifc_len -= sizeof (struct ifreq); + if (ifcfg.ifc_len < 0) + break; + + ++if_count; +# if !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) && !defined (__Lynx__) + ++p_ifs; +# else + if (p_ifs->ifr_addr.sa_len <= sizeof (struct sockaddr)) + { + ++p_ifs; + } + else + { + p_ifs = (struct ifreq *) + (p_ifs->ifr_addr.sa_len + (caddr_t) &p_ifs->ifr_addr); + } +# endif /* !defined (__QNX__) && !defined (__FreeBSD__) && !defined(__NetBSD__) && !defined (ACE_HAS_RTEMS) && !defined (__Lynx__) */ + } + +#if defined (ACE_HAS_ALLOC_HOOKS) + ACE_Allocator::instance()->free (ifcfg.ifc_req); +#else + ACE_OS::free (ifcfg.ifc_req); +#endif /* ACE_HAS_ALLOC_HOOKS */ + +# if defined (ACE_HAS_IPV6) + FILE* fp = 0; + + if ((fp = ACE_OS::fopen (ACE_TEXT ("/proc/net/if_inet6"), ACE_TEXT ("r"))) != 0) + { + // Scan the lines according to the expected format but don't really read any input + while (fscanf (fp, "%*32s %*02x %*02x %*02x %*02x %*8s\n") != EOF) + { + ++if_count; + } + ACE_OS::fclose (fp); + } +# endif /* ACE_HAS_IPV6 && !ACE_LACKS_FSCANF */ + + how_many = if_count; + return 0; +#else + ACE_UNUSED_ARG (handle); + ACE_UNUSED_ARG (how_many); + ACE_NOTSUP_RETURN (-1); // no implementation +#endif /* sparc && SIOCGIFNUM */ +} + +// Routine to return a handle from which ioctl() requests can be made. + +ACE_HANDLE +ACE::get_handle (void) +{ + // Solaris 2.x + ACE_HANDLE handle = ACE_INVALID_HANDLE; +#if defined (sparc) + handle = ACE_OS::open ("/dev/udp", O_RDONLY); +#elif defined (__unix) || defined (__unix__) || defined (_AIX) || defined (__hpux) || (defined (ACE_VXWORKS) && (ACE_VXWORKS >= 0x600)) || defined (ACE_OPENVMS) || defined (ACE_HAS_RTEMS) + // Note: DEC CXX doesn't define "unix" BSD compatible OS: HP UX, + // AIX, SunOS 4.x + + handle = ACE_OS::socket (PF_INET, SOCK_DGRAM, 0); +#endif /* sparc */ + return handle; +} + + +#if defined (ACE_HAS_IPV6) +static int +ip_check (int &ipvn_enabled, int pf) +{ + // We only get to this point if ipvn_enabled was -1 in the caller. + // Perform Double-Checked Locking Optimization. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + + if (ipvn_enabled == -1) + { + +#if defined (ACE_WIN32) + // as of the release of Windows 2008, even hosts that have IPv6 interfaces disabled + // will still permit the creation of a PF_INET6 socket, thus rendering the socket + // creation test inconsistent. The recommended solution is to get the list of + // endpoint addresses and see if any match the desired family. + ACE_INET_Addr *if_addrs = 0; + size_t if_cnt = 0; + + ipvn_enabled = 1; // assume enabled to avoid recursion during interface lookup. + ACE::get_ip_interfaces (if_cnt, if_addrs); + ipvn_enabled = 0; + for (size_t i = 0; ipvn_enabled == 0 && i < if_cnt; i++) + { + ipvn_enabled = (if_addrs[i].get_type () == pf); + } + delete [] if_addrs; +#else + // Determine if the kernel has IPv6 support by attempting to + // create a PF_INET6 socket and see if it fails. + ACE_HANDLE const s = ACE_OS::socket (pf, SOCK_DGRAM, 0); + if (s == ACE_INVALID_HANDLE) + { + ipvn_enabled = 0; + } + else + { + ipvn_enabled = 1; + ACE_OS::closesocket (s); + } +#endif + } + return ipvn_enabled; +} +#endif /* ACE_HAS_IPV6 */ + +bool +ACE::ipv4_enabled (void) +{ +#if defined (ACE_HAS_IPV6) + return static_cast (ace_ipv4_enabled == -1 ? + ::ip_check (ace_ipv4_enabled, PF_INET) : + ace_ipv4_enabled); +#else + // Assume it's always enabled since ACE requires some version of + // TCP/IP to exist. + return true; +#endif /* ACE_HAS_IPV6*/ +} + +int +ACE::ipv6_enabled (void) +{ +#if defined (ACE_HAS_IPV6) + return ace_ipv6_enabled == -1 ? + ::ip_check (ace_ipv6_enabled, PF_INET6) : + ace_ipv6_enabled; +#else /* ACE_HAS_IPV6 */ + return 0; +#endif /* !ACE_HAS_IPV6 */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Sock_Connect.h b/dep/acelite/ace/Sock_Connect.h new file mode 100644 index 000000000..540111474 --- /dev/null +++ b/dep/acelite/ace/Sock_Connect.h @@ -0,0 +1,105 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Sock_Connect.h + * + * @author Priyanka Gontla + * @author Based on code that existed formerly in ACE.h. + */ +//========================================================================== + +#ifndef ACE_SOCK_CONNECT_H +#define ACE_SOCK_CONNECT_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Types.h" +#include "ace/os_include/netinet/os_in.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward Declarations +class ACE_INET_Addr; + +namespace ACE +{ + // = Socket connection establishment calls. + + /// Bind a new unused port to @a handle. + extern ACE_Export int bind_port (ACE_HANDLE handle, + ACE_UINT32 ip_addr = INADDR_ANY, + int address_family = AF_UNSPEC); + + /** + * Get our broadcast address based on our @a host_addr. If + * @a hostname is non-0 we'll use it to determine our IP address. If + * @a handle is not ACE_INVALID_HANDLE then we'll use this to + * determine our broadcast address, otherwise we'll have to create a + * socket internally (and free it). Returns -1 on failure and 0 on + * success. + */ + extern ACE_Export int get_bcast_addr ( + ACE_UINT32 &bcast_addr, + const ACE_TCHAR *hostname = 0, + ACE_UINT32 host_addr = 0, + ACE_HANDLE handle = ACE_INVALID_HANDLE); + + /// Get fully qualified host/domain name. + extern ACE_Export int get_fqdn (ACE_INET_Addr const & addr, + char hostname[], + size_t len); + + /** + * Return count and array of all configured IP interfaces on this + * host, rc = 0 on success (count == number of interfaces else -1). + * Caller is responsible for calling delete [] on @a addr_array. + */ + extern ACE_Export int get_ip_interfaces (size_t &count, + ACE_INET_Addr *&addr_array); + + /** + * Helper routine for get_ip_interfaces, differs by UNIX platform so + * put into own subroutine. perform some ioctls to retrieve ifconf + * list of ifreq structs. + */ + extern ACE_Export int count_interfaces (ACE_HANDLE handle, + size_t &how_many); + + /// Routine to return a handle from which @c ioctl requests can be + /// made. Caller must close the handle. + extern ACE_Export ACE_HANDLE get_handle (void); + + /// Returns @c true if IPv4 is enabled on the current host; @c false + /// if not. + /** + * This is an execution-time check. If ACE has not been compiled + * with @c ACE_HAS_IPV6, it always returns @c true. This function + * tries to create a @c PF_INET socket, returning @c true if it + * succeeds, and @c false if it fails. Caches the result so it only + gets checked once. + */ + extern ACE_Export bool ipv4_enabled (void); + + /** + * Returns 1 if IPv6 is enabled on the current host; 0 if not. + * This is an execution-time check. If ACE has not been compiled + * with ACE_HAS_IPV6, it always returns 0. If ACE_HAS_IPV6 is + * enabled, this function tries to create a PF_INET6 socket, + * returning 1 if it succeeds, and 0 if it fails. Caches the result + * so it only gets checked once. + */ + extern ACE_Export int ipv6_enabled (void); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ACE_SOCK_CONNECT_H */ diff --git a/dep/acelite/ace/Stack_Trace.cpp b/dep/acelite/ace/Stack_Trace.cpp new file mode 100644 index 000000000..cd6f154ad --- /dev/null +++ b/dep/acelite/ace/Stack_Trace.cpp @@ -0,0 +1,738 @@ +//============================================================================= +/** + * @file Stack_Trace.cpp + * + * @brief Encapsulate string representation of stack trace. + * + * Some platform-specific areas of this code have been adapted from + * examples found elsewhere. Specifically, + * - the GLIBC stack generation uses the documented "backtrace" API + * and is adapted from examples shown in relevant documentation + * and repeated elsewhere, e.g., + * http://www.linuxselfhelp.com/gnu/glibc/html_chapter/libc_33.html + * - the Solaris stack generation is adapted from a 1995 post on + * comp.unix.solaris by Bart Smaalders, + * http://groups.google.com/group/comp.unix.solaris/browse_thread/thread/8b9f3de8be288f1c/31550f93a48231d5?lnk=gst&q=how+to+get+stack+trace+on+solaris+group:comp.unix.solaris#31550f93a48231d5 + * - VxWorks kernel-mode stack tracing is adapted from a code example + * in the VxWorks FAQ at http://www.xs4all.nl/~borkhuis/vxworks/vxw_pt5.html + * although the undocumented functions it uses are also mentioned in + * various documents available on the WindRiver support website. + * + * If you add support for a new platform, please add a bullet to the + * above list with durable references to the origins of your code. + */ +//============================================================================= + +#include "ace/Stack_Trace.h" +#include "ace/Min_Max.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_stdio.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/* + This is ugly, simply because it's very platform-specific. +*/ + +const char ACE_Stack_Trace::UNSUPPORTED[] = ""; +const char ACE_Stack_Trace::UNABLE_TO_GET_TRACE[] = ""; + +ACE_Stack_Trace::ACE_Stack_Trace (ssize_t starting_frame_offset, size_t num_frames) + : buflen_(0) +{ + // cannot initialize arrays, so we must assign. + this->buf_[0] = '\0'; + this->generate_trace (starting_frame_offset, num_frames); +} + +const char* +ACE_Stack_Trace::c_str () const +{ + return &this->buf_[0]; +} + +static inline size_t +determine_starting_frame (ssize_t initial_frame, ssize_t offset) +{ + return ACE_MAX( initial_frame + offset, static_cast(0)); +} + +#if defined(ACE_FACE_SAFETY_BASE) && !defined(ACE_FACE_DEV) +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, size_t num_frames) +{ + ACE_UNUSED_ARG (starting_frame_offset); + ACE_UNUSED_ARG (num_frames); + ACE_OS::strcpy (&this->buf_[0], UNABLE_TO_GET_TRACE); +} + +#elif (defined(__GLIBC__) || defined(ACE_HAS_EXECINFO_H)) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) +// This is the code for glibc +# include + +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, size_t num_frames) +{ + const size_t MAX_FRAMES = 128; + const ssize_t INITIAL_FRAME = 3; + + void* stack[MAX_FRAMES]; + size_t stack_size = 0; + char** stack_syms; + + if (num_frames == 0) + num_frames = MAX_FRAMES; + + size_t starting_frame = + determine_starting_frame (INITIAL_FRAME, starting_frame_offset); + + stack_size = ::backtrace (&stack[0], sizeof(stack)/sizeof(stack[0])); + if (stack_size != 0) + { + stack_syms = ::backtrace_symbols (stack, stack_size); + + for (size_t i = starting_frame; + i < stack_size && num_frames > 0; + i++, num_frames--) + { + // this could be more efficient by remembering where we left off in buf_ + char *symp = &stack_syms[i][0]; + while (this->buflen_ < SYMBUFSIZ - 2 && *symp != '\0') + { + this->buf_[this->buflen_++] = *symp++; + } + this->buf_[this->buflen_++] = '\n'; // put a newline at the end + } + this->buf_[this->buflen_] = '\0'; // zero terminate the string + + ::free (stack_syms); + } + else + { + ACE_OS::strcpy (&this->buf_[0], UNABLE_TO_GET_TRACE); + } +} +#elif defined(VXWORKS) && !defined(__RTP__) +# include +# include // hopefully this is enough to get all the necessary #defines. + +struct ACE_Stack_Trace_stackstate +{ + ACE_Stack_Trace_stackstate (char* b, size_t& bl, size_t nf, size_t sf) + : buf(b), buflen(bl), num_frames(nf), starting_frame(sf) + { } + + char* buf; + size_t& buflen; + size_t num_frames; + size_t starting_frame; +}; + +//@TODO: Replace with a TSS-based pointer to avoid problems in multithreaded environs, +// or use a mutex to serialize access to this. +static ACE_Stack_Trace_stackstate* ACE_Stack_Trace_stateptr = 0; + +static void +ACE_Stack_Trace_Add_Frame_To_Buf (INSTR *caller, + INSTR *func, + int nargs, + ACE_VX_USR_ARG_T *args) +{ + if (ACE_Stack_Trace_stateptr == 0) + return; + + ACE_Stack_Trace_stackstate *stackstate = ACE_Stack_Trace_stateptr; + + // Decrement the num_frames and starting_frame elements, + // then see if we're ready to start or ready to finish. + --stackstate->num_frames; + --stackstate->starting_frame; + + if (stackstate->num_frames == 0 || stackstate->starting_frame > 0) + return; + + // These are references so that the structure gets updated + // in the code below. + char*& buf = stackstate->buf; + size_t& len = stackstate->buflen; + + // At some point try using symFindByValue() to lookup func (and caller?) + // to print out symbols rather than simply addresses. + + // VxWorks can pass -1 for "nargs" if there was an error + if (nargs == -1) + nargs = 0; + + len += ACE_OS::sprintf (&buf[len], "%p: %p (", caller, func); + for (int i = 0; i < nargs; ++i) + { + if (i != 0) + len += ACE_OS::sprintf (&buf[len], ", "); + len += ACE_OS::sprintf(&buf[len], "0x" ACE_VX_ARG_FORMAT, args[i]); + } + + len += ACE_OS::sprintf(&buf[len], ")\n"); +} + +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, + size_t num_frames) +{ + const size_t MAX_FRAMES = 128; + const ssize_t INITIAL_FRAME = 3; + + if (num_frames == 0) + num_frames = MAX_FRAMES; + + size_t starting_frame = + determine_starting_frame (INITIAL_FRAME, starting_frame_offset); + + ACE_Stack_Trace_stackstate state (&this->buf_[0], this->buflen_, + num_frames, starting_frame); + + REG_SET regs; + + taskRegsGet (taskIdSelf(), ®s); + // Maybe we should take a lock here to guard stateptr? + ACE_Stack_Trace_stateptr = &state; + trcStack (®s, (FUNCPTR)ACE_Stack_Trace_Add_Frame_To_Buf, taskIdSelf ()); +} + + +#elif defined(VXWORKS) && defined(__RTP__) +# include +# include +# include + +// See memEdrLib.c in VxWorks RTP sources for an example of stack tracing. + +static STATUS ace_vx_rtp_pc_validate (INSTR *pc, TRC_OS_CTX *) +{ + return ALIGNED (pc, sizeof (INSTR)) ? OK : ERROR; +} + +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, + size_t num_frames) +{ + const size_t MAX_FRAMES = 128; + const ssize_t INITIAL_FRAME = 2; + + if (num_frames == 0) num_frames = MAX_FRAMES; + size_t starting_frame = + determine_starting_frame (INITIAL_FRAME, starting_frame_offset); + + jmp_buf regs; + setjmp (regs); + + TASK_DESC desc; + if (taskInfoGet (taskIdSelf (), &desc) == ERROR) return; + + TRC_OS_CTX osCtx; + osCtx.stackBase = desc.td_pStackBase; + osCtx.stackEnd = desc.td_pStackEnd; +#if (ACE_VXWORKS < 0x690) + osCtx.pcValidateRtn = reinterpret_cast (ace_vx_rtp_pc_validate); +#else + // reinterpret_cast causes an error + osCtx.pcValidateRtn = ace_vx_rtp_pc_validate; +#endif + + char *fp = _WRS_FRAMEP_FROM_JMP_BUF (regs); + INSTR *pc = _WRS_RET_PC_FROM_JMP_BUF (regs); + + for (size_t depth = 0; depth < num_frames + starting_frame; ++depth) + { + char *prevFp; + INSTR *prevPc; + INSTR *prevFn; + + if (trcLibFuncs.lvlInfoGet (fp, pc, &osCtx, &prevFp, &prevPc, &prevFn) + == ERROR) + { + ACE_OS::strcpy (this->buf_, UNABLE_TO_GET_TRACE); + return; + } + + if(prevPc == 0 || prevFp == 0) break; + + if (depth >= starting_frame) + { + //Hopefully a future version of VxWorks will have a system call + //for an RTP to query its own symbols, but this is not possible now. + //An enhancement request has been filed under WIND00123307. + const char *fnName = "(no symbols)"; + + static const int N_ARGS = 12; + ACE_VX_USR_ARG_T buf[N_ARGS]; + ACE_VX_USR_ARG_T *pArgs = 0; + int numArgs = + trcLibFuncs.lvlArgsGet (prevPc, prevFn, prevFp, + buf, N_ARGS, &pArgs); + + // VxWorks can return -1 for "numArgs" if there was an error + if (numArgs == -1) numArgs = 0; + + size_t len = ACE_OS::strlen (this->buf_); + size_t space = SYMBUFSIZ - len - 1; + char *cursor = this->buf_ + len; + size_t written = ACE_OS::snprintf (cursor, space, "%p %s", + prevFn, fnName); + cursor += written; + space -= written; + + if (space < 1) return; //no point in logging when we're out of buffer + for (int arg = 0; numArgs != -1 && pArgs && arg < numArgs; ++arg) + { + if (arg == 0) *cursor++ = '(', --space; + written = ACE_OS::snprintf (cursor, space, + (arg < numArgs - 1) ? + ACE_VX_ARG_FORMAT ", " : + ACE_VX_ARG_FORMAT, + pArgs[arg]); + cursor += written; + space -= written; + if (space && arg == numArgs - 1) *cursor++ = ')', --space; + } + if (space) *cursor++ = '\n', --space; + *cursor++ = 0; //we saved space for the null terminator + } + + fp = prevFp; + pc = prevPc; + } +} + +#elif defined(sun) +/* + * walks up call stack, printing library:routine+offset for each routine + */ + +# include +# include +# include +# include +# include +# define ACE_STACK_TRACE_BIAS 0 + +# if defined(sparc) || defined(__sparc) +# define ACE_STACK_TRACE_FLUSHWIN() asm("ta 3"); +# define ACE_STACK_TRACE_FRAME_PTR_INDEX 1 +# define ACE_STACK_TRACE_SKIP_FRAMES 0 +# if defined(__sparcv9) +# undef ACE_STACK_TRACE_BIAS +# define ACE_STACK_TRACE_BIAS 2047 +# endif +# endif + +# if defined(i386) || defined(__i386) +# define ACE_STACK_TRACE_FLUSHWIN() +# define ACE_STACK_TRACE_FRAME_PTR_INDEX 3 +# define ACE_STACK_TRACE_SKIP_FRAMES 0 +# endif + +# if defined(__amd64) || defined(__x86_64) +# define ACE_STACK_TRACE_FLUSHWIN() +# define ACE_STACK_TRACE_FRAME_PTR_INDEX 5 +# define ACE_STACK_TRACE_SKIP_FRAMES 0 +# endif + +# if defined(ppc) || defined(__ppc) +# define ACE_STACK_TRACE_FLUSHWIN() +# define ACE_STACK_TRACE_FRAME_PTR_INDEX 0 +# define ACE_STACK_TRACE_SKIP_FRAMES 2 +# endif + +static frame* +cs_frame_adjust(frame* sp) +{ + unsigned char* sp_byte = (unsigned char*)sp; + sp_byte += ACE_STACK_TRACE_BIAS; + return (frame*) sp_byte; +} + +/* + this function walks up call stack, calling user-supplied + function once for each stack frame, passing the pc and the user-supplied + usrarg as the argument. + */ + +static int +cs_operate(int (*func)(void *, void *), void * usrarg, + size_t starting_frame, size_t num_frames_arg) +{ + ACE_STACK_TRACE_FLUSHWIN(); + + jmp_buf env; + setjmp(env); + frame* sp = cs_frame_adjust((frame*) env[ACE_STACK_TRACE_FRAME_PTR_INDEX]); + + // make a copy of num_frames_arg to eliminate the following warning on some + // solaris platforms: + // Stack_Trace.cpp:318: warning: argument `size_t num_frames' might be clobbered by `longjmp' or `vfork' + size_t num_frames = num_frames_arg; + + // I would like to use ACE_MAX below rather than ?:, but + // I get linker relocation errors such as the following when + // I use it: + // ld: fatal: relocation error: file: .shobj/Stack_Trace.o section: + // .rela.debug_line symbol: : relocation against a discarded symbol, + // symbol is part of discarded section: + // .text%const __type_0&ace_max(const __type_0&,const __type_0&) + // + const size_t starting_skip = starting_frame - 1; +#if ACE_STACK_TRACE_SKIP_FRAMES == 0 + size_t skip_frames = starting_skip; +#else + size_t skip_frames = + ACE_STACK_TRACE_SKIP_FRAMES > starting_skip ? + ACE_STACK_TRACE_SKIP_FRAMES : starting_skip; +#endif /* ACE_STACK_TRACE_SKIP_FRAMES == 0 */ + size_t i; + for (i = 0; i < skip_frames && sp; ++i) + { + sp = cs_frame_adjust((frame*) sp->fr_savfp); + } + + i = 0; + + while ( sp + && sp->fr_savpc + && ++i + && --num_frames + && (*func)((void*)sp->fr_savpc, usrarg)) + { + sp = cs_frame_adjust((frame*) sp->fr_savfp); + } + + return(i); +} + +static int +add_frame_to_buf (void* pc, void* usrarg) +{ + char* buf = (char*)usrarg; + Dl_info info; + const char* func = "??"; + const char* lib = "??"; + + if(dladdr(pc, & info) != 0) + { + lib = (const char *) info.dli_fname; + func = (const char *) info.dli_sname; + } + + (void) ACE_OS::snprintf(buf, + ACE_Stack_Trace::SYMBUFSIZ, + "%s%s:%s+0x%x\n", + buf, + lib, + func, + //@@ Should the arithmetic on the following + //line be done with two void* ptrs? The result + //would be ptrdiff_t, and what is the correct + //sprintf() conversion character for that? + (size_t)pc - (size_t)info.dli_saddr); + + return(1); +} + +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, + size_t num_frames) +{ + const size_t MAX_FRAMES = 128; + const ssize_t INITIAL_FRAME = 3; + + if (num_frames == 0) + num_frames = MAX_FRAMES; + + size_t starting_frame = + determine_starting_frame (INITIAL_FRAME, starting_frame_offset); + + cs_operate (&add_frame_to_buf, &this->buf_[0], starting_frame, num_frames); +} + +#elif defined(ACE_WIN64) && (_WIN32_WINNT <= _WIN32_WINNT_WIN2K) +# if defined(_MSC_VER) +# define STRING2(X) #X +# define STRING(X) STRING2(X) +# pragma message (__FILE__ "(" STRING(__LINE__) ") : warning: stack traces"\ + " can't be generated on 64-bit Windows when _WIN32_WINNT is less than "\ + "0x501.") +# undef STRING +# undef STRING2 +# endif /*_MSC_VER*/ +void +ACE_Stack_Trace::generate_trace (ssize_t, size_t) +{ + ACE_OS::strcpy (&this->buf_[0], ""); +} + +#elif defined(ACE_WIN32) && !defined(ACE_HAS_WINCE) && !defined (__MINGW32__) \ + && !defined(__BORLANDC__) +# include +# include + +# define MAXTEXT 5000 +# define SYMSIZE 100 + +//@TODO: Test with WCHAR +//@TODO: Need a common CriticalSection since dbghelp is not thread-safe + +typedef struct _dbghelp_functions +{ + HMODULE hMod; //our handle to dbghelp.dll + + //these already have typedefs in DbgHelp.h + DWORD64 (WINAPI *SymGetModuleBase64) (HANDLE hProc, DWORD64 dwAddr); + PVOID (WINAPI *SymFunctionTableAccess64) (HANDLE hProc, DWORD64 AddrBase); + + typedef BOOL (WINAPI *SymFromAddr_t) + (HANDLE hProc, DWORD64 Addr, PDWORD64 Disp, PSYMBOL_INFO Symbol); + SymFromAddr_t SymFromAddr; + + typedef BOOL (WINAPI *SymGetLineFromAddr64_t) (HANDLE hProc, DWORD64 dwAddr, + PDWORD pdwDisplacement, + PIMAGEHLP_LINE64 Line); + SymGetLineFromAddr64_t SymGetLineFromAddr64; + + typedef DWORD (WINAPI *SymSetOptions_t) (DWORD SymOptions); + SymSetOptions_t SymSetOptions; + + typedef DWORD (WINAPI *SymGetOptions_t) (); + SymGetOptions_t SymGetOptions; + + typedef BOOL (WINAPI *SymInitialize_t) (HANDLE hProc, PCTSTR UserSearchPath, + BOOL invasive); + SymInitialize_t SymInitialize; + + typedef BOOL + (WINAPI *StackWalk64_t) (DWORD MachineType, HANDLE hPRoc, HANDLE hThr, + LPSTACKFRAME64 StackFrame, PVOID ContextRecord, + PREAD_PROCESS_MEMORY_ROUTINE64 RMRoutine, + PFUNCTION_TABLE_ACCESS_ROUTINE64 FTARoutine, + PGET_MODULE_BASE_ROUTINE64 GMBRoutine, + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + StackWalk64_t StackWalk64; + + typedef BOOL (WINAPI *SymCleanup_t) (HANDLE hProc); + SymCleanup_t SymCleanup; +} dbghelp_functions; + + +# pragma warning (push) +# pragma warning (disable:4706) +static bool load_dbghelp_library_if_needed (dbghelp_functions *pDbg) +{ + //@TODO: See codeproject's StackWalker.cpp for the list of locations to + //search so we get the "enhanced" dbghelp if the user has it but it is not + //first on the path. + if (!(pDbg->hMod = ACE_TEXT_LoadLibrary (ACE_TEXT ("Dbghelp")))) + return false; + + //@TODO: Cache this so we don't have to re-link every time. When to unload? + +# define LINK(TYPE, NAME) (pDbg->NAME = \ + (TYPE) GetProcAddress (pDbg->hMod, #NAME)) +# define LINK_T(NAME) LINK (dbghelp_functions::NAME##_t, NAME) + return LINK (PGET_MODULE_BASE_ROUTINE64, SymGetModuleBase64) + && LINK (PFUNCTION_TABLE_ACCESS_ROUTINE64, SymFunctionTableAccess64) + && LINK_T (SymFromAddr) && LINK_T (SymGetLineFromAddr64) + && LINK_T (SymSetOptions)&& LINK_T (SymGetOptions) + && LINK_T (SymInitialize) && LINK_T (StackWalk64) && LINK_T (SymCleanup); +# undef LINK +# undef LINK_T +} +# pragma warning (pop) + + +struct frame_state { + STACKFRAME64 sf; + PSYMBOL_INFO pSym; + dbghelp_functions *pDbg; +}; + +static int +add_frame_to_buf (struct frame_state const *fs, void *usrarg) +{ + if (fs == 0 || usrarg == 0) + return -1; + + char *buf = static_cast (usrarg); + + DWORD64 disp; + DWORD64 dwModBase = fs->pDbg->SymGetModuleBase64 (GetCurrentProcess (), + fs->sf.AddrPC.Offset); + if (fs->pDbg->SymFromAddr (GetCurrentProcess (), + fs->sf.AddrPC.Offset, &disp, fs->pSym)) + { + IMAGEHLP_LINE64 line = {sizeof (IMAGEHLP_LINE64)}; + DWORD lineDisp; + if (fs->pDbg->SymGetLineFromAddr64 (GetCurrentProcess (), + fs->sf.AddrPC.Offset, + &lineDisp, &line)) + { + (void) ACE_OS::snprintf (buf, ACE_Stack_Trace::SYMBUFSIZ, + "%s%s() %s: %d + 0x%x\n", + buf, fs->pSym->Name, line.FileName, + line.LineNumber, lineDisp); + } + else + { + (void) ACE_OS::snprintf (buf, ACE_Stack_Trace::SYMBUFSIZ, + "%s%s()+0x%x [0x%x]\n", + buf, fs->pSym->Name, disp, + fs->sf.AddrPC.Offset - dwModBase); + } + } + else + { + (void) ACE_OS::snprintf (buf, ACE_Stack_Trace::SYMBUFSIZ, + "%s[0x%x]\n", + buf, fs->sf.AddrPC.Offset - dwModBase); + } + return 0; +} + +static void emptyStack () { } + +#if defined (_MSC_VER) +# pragma warning(push) +// Suppress warning 4748 "/GS can not protect parameters and local +// variables from local buffer overrun because optimizations are +// disabled in function" +# pragma warning(disable: 4748) +#endif /* _MSC_VER */ + +static int +cs_operate(int (*func)(struct frame_state const *, void *), void *usrarg, + size_t starting_frame, size_t num_frames) +{ + dbghelp_functions dbg; + if (!load_dbghelp_library_if_needed (&dbg)) + { + ACE_OS::strcpy (static_cast (usrarg), + ""); + if (dbg.hMod) FreeLibrary (dbg.hMod); + return 1; + } + + frame_state fs; + ZeroMemory (&fs.sf, sizeof (fs.sf)); + fs.pDbg = &dbg; + emptyStack (); //Not sure what this should do, Chad? + + CONTEXT c; + ZeroMemory (&c, sizeof (CONTEXT)); + c.ContextFlags = CONTEXT_FULL; + +# if defined (_M_IX86) + DWORD machine = IMAGE_FILE_MACHINE_I386; + __asm { + call x + x: pop eax + mov c.Eip, eax + mov c.Ebp, ebp + mov c.Esp, esp + } + fs.sf.AddrPC.Offset = c.Eip; + fs.sf.AddrStack.Offset = c.Esp; + fs.sf.AddrFrame.Offset = c.Ebp; + fs.sf.AddrPC.Mode = AddrModeFlat; + fs.sf.AddrStack.Mode = AddrModeFlat; + fs.sf.AddrFrame.Mode = AddrModeFlat; +# elif defined (_M_X64) + DWORD machine = IMAGE_FILE_MACHINE_AMD64; + RtlCaptureContext (&c); + fs.sf.AddrPC.Offset = c.Rip; + fs.sf.AddrFrame.Offset = c.Rsp; //should be Rbp or Rdi instead? + fs.sf.AddrStack.Offset = c.Rsp; + fs.sf.AddrPC.Mode = AddrModeFlat; + fs.sf.AddrFrame.Mode = AddrModeFlat; + fs.sf.AddrStack.Mode = AddrModeFlat; +# elif defined (_M_IA64) + DWORD machine = IMAGE_FILE_MACHINE_IA64; + RtlCaptureContext (&c); + fs.sf.AddrPC.Offset = c.StIIP; + fs.sf.AddrFrame.Offset = c.RsBSP; + fs.sf.AddrBStore.Offset = c.RsBSP; + fs.sf.AddrStack.Offset = c.IntSp; + fs.sf.AddrPC.Mode = AddrModeFlat; + fs.sf.AddrFrame.Mode = AddrModeFlat; + fs.sf.AddrBStore.Mode = AddrModeFlat; + fs.sf.AddrStack.Mode = AddrModeFlat; +# endif + + fs.pSym = (PSYMBOL_INFO) GlobalAlloc (GMEM_FIXED, + sizeof (SYMBOL_INFO) + + sizeof (ACE_TCHAR) * (SYMSIZE - 1)); + fs.pSym->SizeOfStruct = sizeof (SYMBOL_INFO); + fs.pSym->MaxNameLen = SYMSIZE * sizeof (ACE_TCHAR); + dbg.SymSetOptions (SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES + | SYMOPT_FAIL_CRITICAL_ERRORS | dbg.SymGetOptions ()); + dbg.SymInitialize (GetCurrentProcess (), 0, true); + //What does the "true" parameter mean when tracing the current process? + + for (size_t current_frame = 0; current_frame < num_frames + starting_frame; + ++current_frame) + { + BOOL ok = dbg.StackWalk64 (machine, + GetCurrentProcess (), + GetCurrentThread (), + &fs.sf, &c, 0, + dbg.SymFunctionTableAccess64, + dbg.SymGetModuleBase64, 0); + if (!ok || fs.sf.AddrFrame.Offset == 0) + break; + + if (current_frame < starting_frame) + continue; + + func (&fs, usrarg); + } + + dbg.SymCleanup (GetCurrentProcess ()); + GlobalFree (fs.pSym); + FreeLibrary (dbg.hMod); + + return 0; +} + +#if defined (_MSC_VER) +// Restore the warning state to what it was before entry. +# pragma warning(pop) +#endif /* _MSC_VER */ + +void +ACE_Stack_Trace::generate_trace (ssize_t starting_frame_offset, + size_t num_frames) +{ + const size_t MAX_FRAMES = 128; + const ssize_t INITIAL_FRAME = 3; + + if (num_frames == 0) + num_frames = MAX_FRAMES; + + size_t starting_frame = + determine_starting_frame (INITIAL_FRAME, starting_frame_offset); + + cs_operate (&add_frame_to_buf, &this->buf_[0], starting_frame, num_frames); +} + +#else // Unsupported platform +void +ACE_Stack_Trace::generate_trace (ssize_t, size_t) +{ +// Call determine_starting_frame() on HP aCC build to resolve declared +// method never referenced warning. +#if defined (__HP_aCC) + size_t starting_frame = determine_starting_frame (0, 0); +#endif + + ACE_OS::strcpy (&this->buf_[0], UNSUPPORTED); +} +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Stack_Trace.h b/dep/acelite/ace/Stack_Trace.h new file mode 100644 index 000000000..14cdcc012 --- /dev/null +++ b/dep/acelite/ace/Stack_Trace.h @@ -0,0 +1,109 @@ +// -*- C++ -*- +//============================================================================= +/** + * @file Stack_Trace.h + * + * @author Chris Cleeland (cleeland.ociweb.com) + */ +//============================================================================= + +#ifndef ACE_STACK_TRACE_H +#define ACE_STACK_TRACE_H + +#include /**/ "ace/pre.h" + +#include "ace/ACE_export.h" +#include "ace/Basic_Types.h" + +# if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +# endif /* ACE_LACKS_PRAGMA_ONCE */ + +# ifndef ACE_STACK_TRACE_SYMBUFSIZ +# define ACE_STACK_TRACE_SYMBUFSIZ 4096 +# endif + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Stack_Trace + * + * @brief Encapsulate a string representation of a stack trace on supported platforms. + * Stack traces for code built with optimize=1 (or "Release" configs on Visual + * Studio) may be misleading (missng frames) due to inlining performed by the + * compiler, which is indepenent of the inline=0 / inline=1 build option and + * the __ACE_INLINE__ / ACE_NO_INLINE macros. + * + * A new conversion character, the question mark, was added to ACE_Log_Msg for stack + * trace logging. The %? conversion character was added as a convenience so that users + * need not instantiate an ACE_Stack_Trace instance solely for the purpose of printing + * it in an ACE logging message. The following are functionally equivalent: + * + * \code + * ACELIB_DEBUG((LM_DEBUG, "%?")); + * + * ACE_Stack_Trace st; + * ACELIB_DEBUG ((LM_DEBUG, "%C", st.c_str() )); + * \endcode + * + * These usage examples were shown in $ACE_ROOT/tests/Stack_Trace_Test.cpp. + * + * @note The stack trace functionality was currently supported on platforms: + * - Any platform using glibc as its runtime library, or where ACE_HAS_EXECINFO_H is defined + * (this covers Linux and Mac) and gcc version >= 3.3. + * - VxWorks, both kernel and RTP + * - Solaris + * - Windows 32 and 64 bit (Visual C++, excluding WinCE/mobile) + * + * @note Since stack trace buffer size has limitation(@c ACE_STACK_TRACE_SYMBUFSIZ), you will not + * get a complete stack trace if @c ACE_STACK_TRACE_SYMBUFSIZ value is less than actual stack + * trace data length. To get a complete stack trace, you need set @c ACE_STACK_TRACE_SYMBUFSIZ + * with a larger value that is enough for the stack trace data in your @c config.h file + * and rebuild ACE. + * + * @note Using ACE logging mechanism (%?) to log the stack trace also has ACE_MAXLOGMSGLEN size limitation. + * To get a complete stack trace, you could use different output method. Following is an example. + * + * \code + * ACE_Stack_Trace st; + * ACE_OS::printf("at [%s]\n", st.c_str()); + * \endcode + */ +class ACE_Export ACE_Stack_Trace +{ +public: + /** + * @brief Grab a snapshot of the current stack trace and hold it for later use. + * + * @param starting_frame_offset offset into the array of frames to start printing; 0 is the + * platform-specific offset for the first frame, positive numbers give less frames, negative give + * more frames + * @param num_frames the number of stack frames to include (0 indicates platform-specific maximum) + * + */ + explicit ACE_Stack_Trace (ssize_t starting_frame_offset = 0, size_t num_frames = 0); + + /** + * @brief Return buffer as a C-style string. + * @return C-style string with string representation of stack trace. + * @note Lifecycle of string follows lifecycle of ACE_Stack_Trace instance. + */ + const char* c_str() const; + + static const size_t SYMBUFSIZ = ACE_STACK_TRACE_SYMBUFSIZ; + +private: + char buf_[SYMBUFSIZ]; + size_t buflen_; + + static const char UNSUPPORTED[]; + static const char UNABLE_TO_GET_TRACE[]; + + void generate_trace (ssize_t starting_frame_offset, size_t num_frames); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_STACK_TRACE_H */ + diff --git a/dep/acelite/ace/Static_Object_Lock.h b/dep/acelite/ace/Static_Object_Lock.h new file mode 100644 index 000000000..fc167062f --- /dev/null +++ b/dep/acelite/ace/Static_Object_Lock.h @@ -0,0 +1,55 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Static_Object_Lock.h + * + * @author David L. Levine + * @author Matthias Kerkhoff + * @author Per Andersson + */ +//============================================================================= + +#ifndef ACE_STATIC_OBJECT_LOCK_H +#define ACE_STATIC_OBJECT_LOCK_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if defined (ACE_HAS_THREADS) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Recursive_Thread_Mutex; + +/** + * @class ACE_Static_Object_Lock + * + * @brief Provide an interface to access a global lock. + * + * This class is used to serialize the creation of static + * singleton objects. It really isn't needed any more, because + * anyone can access ACE_STATIC_OBJECT_LOCK directly. But, it + * is retained for backward compatibility. + */ +class ACE_Export ACE_Static_Object_Lock +{ +public: + /// Static lock access point. + static ACE_Recursive_Thread_Mutex *instance (void); + + /// For use only by ACE_Object_Manager to clean up lock if it + /// what dynamically allocated. + static void cleanup_lock (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_STATIC_OBJECT_LOCK_H */ diff --git a/dep/acelite/ace/Stats.cpp b/dep/acelite/ace/Stats.cpp new file mode 100644 index 000000000..b47c4857f --- /dev/null +++ b/dep/acelite/ace/Stats.cpp @@ -0,0 +1,413 @@ +#include "ace/Stats.h" + +#if !defined (__ACE_INLINE__) +# include "ace/Stats.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_UINT32 +ACE_Stats_Value::fractional_field (void) const +{ + if (precision () == 0) + { + return 1; + } + else + { + ACE_UINT32 field = 10; + for (u_int i = 0; i < precision () - 1; ++i) + { + field *= 10; + } + + return field; + } +} + +int +ACE_Stats::sample (const ACE_INT32 value) +{ + if (samples_.enqueue_tail (value) == 0) + { + ++number_of_samples_; + if (number_of_samples_ == 0) + { + // That's a lot of samples :-) + overflow_ = EFAULT; + return -1; + } + + if (value < min_) + min_ = value; + + if (value > max_) + max_ = value; + + return 0; + } + else + { + // Probably failed due to running out of memory when trying to + // enqueue the new value. + overflow_ = errno; + return -1; + } +} + +void +ACE_Stats::mean (ACE_Stats_Value &m, + const ACE_UINT32 scale_factor) +{ + if (number_of_samples_ > 0) + { + const ACE_UINT64 ACE_STATS_INTERNAL_OFFSET = + ACE_UINT64_LITERAL (0x100000000); + + ACE_UINT64 sum = ACE_STATS_INTERNAL_OFFSET; + ACE_Unbounded_Queue_Iterator i (samples_); + while (! i.done ()) + { + ACE_INT32 *sample; + if (i.next (sample)) + { + sum += *sample; + i.advance (); + } + } + + // sum_ was initialized with ACE_STATS_INTERNAL_OFFSET, so + // subtract that off here. + quotient (sum - ACE_STATS_INTERNAL_OFFSET, + number_of_samples_ * scale_factor, + m); + } + else + { + m.whole (0); + m.fractional (0); + } +} + +int +ACE_Stats::std_dev (ACE_Stats_Value &std_dev, + const ACE_UINT32 scale_factor) +{ + if (number_of_samples_ <= 1) + { + std_dev.whole (0); + std_dev.fractional (0); + } + else + { + const ACE_UINT32 field = std_dev.fractional_field (); + + // The sample standard deviation is: + // + // sqrt (sum (sample_i - mean)^2 / (number_of_samples_ - 1)) + + ACE_UINT64 mean_scaled; + // Calculate the mean, scaled, so that we don't lose its + // precision. + ACE_Stats_Value avg (std_dev.precision ()); + mean (avg, 1u); + avg.scaled_value (mean_scaled); + + // Calculate the summation term, of squared differences from the + // mean. + ACE_UINT64 sum_of_squares = 0; + ACE_Unbounded_Queue_Iterator i (samples_); + while (! i.done ()) + { + ACE_INT32 *sample; + if (i.next (sample)) + { + const ACE_UINT64 original_sum_of_squares = sum_of_squares; + + // Scale up by field width so that we don't lose the + // precision of the mean. Carefully . . . + const ACE_UINT64 product (*sample * field); + + ACE_UINT64 difference; + // NOTE: please do not reformat this code! It // + // works with the Diab compiler the way it is! // + if (product >= mean_scaled) // + { // + difference = product - mean_scaled; // + } // + else // + { // + difference = mean_scaled - product; // + } // + // NOTE: please do not reformat this code! It // + // works with the Diab compiler the way it is! // + + // Square using 64-bit arithmetic. + sum_of_squares += difference * ACE_U64_TO_U32 (difference); + i.advance (); + + if (sum_of_squares < original_sum_of_squares) + { + overflow_ = ENOSPC; + return -1; + } + } + } + + // Divide the summation by (number_of_samples_ - 1), to get the + // variance. In addition, scale the variance down to undo the + // mean scaling above. Otherwise, it can get too big. + ACE_Stats_Value variance (std_dev.precision ()); + quotient (sum_of_squares, + (number_of_samples_ - 1) * field * field, + variance); + + // Take the square root of the variance to get the standard + // deviation. First, scale up . . . + ACE_UINT64 scaled_variance; + variance.scaled_value (scaled_variance); + + // And scale up, once more, because we'll be taking the square + // root. + scaled_variance *= field; + ACE_Stats_Value unscaled_standard_deviation (std_dev.precision ()); + square_root (scaled_variance, + unscaled_standard_deviation); + + // Unscale. + quotient (unscaled_standard_deviation, + scale_factor * field, + std_dev); + } + + return 0; +} + + +void +ACE_Stats::reset (void) +{ + overflow_ = 0u; + number_of_samples_ = 0u; + min_ = 0x7FFFFFFF; + max_ = -0x8000 * 0x10000; + samples_.reset (); +} + +int +ACE_Stats::print_summary (const u_int precision, + const ACE_UINT32 scale_factor, + FILE *file) const +{ + ACE_TCHAR mean_string [128]; + ACE_TCHAR std_dev_string [128]; + ACE_TCHAR min_string [128]; + ACE_TCHAR max_string [128]; + int success = 0; + + for (int tmp_precision = precision; + ! overflow_ && ! success && tmp_precision >= 0; + --tmp_precision) + { + // Build a format string, in case the C library doesn't support %*u. + ACE_TCHAR format[32]; + if (tmp_precision == 0) + ACE_OS::snprintf (format, 32, ACE_TEXT ("%%%d"), tmp_precision); + else + ACE_OS::snprintf (format, 32, ACE_TEXT ("%%d.%%0%du"), tmp_precision); + + ACE_Stats_Value u (tmp_precision); + ((ACE_Stats *) this)->mean (u, scale_factor); + ACE_OS::snprintf (mean_string, 128, format, u.whole (), u.fractional ()); + + ACE_Stats_Value sd (tmp_precision); + if (((ACE_Stats *) this)->std_dev (sd, scale_factor)) + { + success = 0; + continue; + } + else + { + success = 1; + } + ACE_OS::snprintf (std_dev_string, 128, format, sd.whole (), + sd.fractional ()); + + ACE_Stats_Value minimum (tmp_precision), maximum (tmp_precision); + if (min_ != 0) + { + const ACE_UINT64 m (min_); + quotient (m, scale_factor, minimum); + } + if (max_ != 0) + { + const ACE_UINT64 m (max_); + quotient (m, scale_factor, maximum); + } + ACE_OS::snprintf (min_string, 128, format, + minimum.whole (), minimum.fractional ()); + ACE_OS::snprintf (max_string, 128, format, + maximum.whole (), maximum.fractional ()); + } + + if (success == 1) + { + ACE_OS::fprintf (file, ACE_TEXT ("samples: %u (%s - %s); mean: ") + ACE_TEXT ("%s; std dev: %s\n"), + samples (), min_string, max_string, + mean_string, std_dev_string); + return 0; + } + else + { + ACE_OS::fprintf (file, + ACE_TEXT ("ACE_Stats::print_summary: OVERFLOW: %s\n"), + ACE_OS::strerror (overflow_)); + + return -1; + } +} + +void +ACE_Stats::quotient (const ACE_UINT64 dividend, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient) +{ + // The whole part of the division comes from simple integer division. + quotient.whole (static_cast (divisor == 0 + ? 0 : dividend / divisor)); + + if (quotient.precision () > 0 || divisor == 0) + { + const ACE_UINT32 field = quotient.fractional_field (); + + // Fractional = (dividend % divisor) * 10^precision / divisor + + // It would be nice to add round-up term: + // Fractional = (dividend % divisor) * 10^precision / divisor + + // 10^precision/2 / 10^precision + // = ((dividend % divisor) * 10^precision + divisor) / + // divisor + quotient.fractional (static_cast ( + dividend % divisor * field / divisor)); + } + else + { + // No fractional portion is requested, so don't bother + // calculating it. + quotient.fractional (0); + } +} + +void +ACE_Stats::quotient (const ACE_Stats_Value ÷nd, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient) +{ + // The whole part of the division comes from simple integer division. + quotient.whole (divisor == 0 ? 0 : dividend.whole () / divisor); + + if (quotient.precision () > 0 || divisor == 0) + { + const ACE_UINT32 field = quotient.fractional_field (); + + // Fractional = (dividend % divisor) * 10^precision / divisor. + quotient.fractional (dividend.whole () % divisor * field / divisor + + dividend.fractional () / divisor); + } + else + { + // No fractional portion is requested, so don't bother + // calculating it. + quotient.fractional (0); + } +} + +void +ACE_Stats::square_root (const ACE_UINT64 n, + ACE_Stats_Value &square_root) +{ + ACE_UINT32 floor = 0; + ACE_UINT32 ceiling = 0xFFFFFFFFu; + ACE_UINT32 mid = 0; + u_int i; + + // The maximum number of iterations is log_2 (2^64) == 64. + for (i = 0; i < 64; ++i) + { + mid = (ceiling - floor) / 2 + floor; + if (floor == mid) + // Can't divide the interval any further. + break; + else + { + // Multiply carefully to avoid overflow. + ACE_UINT64 mid_squared = mid; mid_squared *= mid; + if (mid_squared == n) + break; + else if (mid_squared < n) + floor = mid; + else + ceiling = mid; + } + } + + square_root.whole (mid); + ACE_UINT64 mid_squared = mid; mid_squared *= mid; + + if (square_root.precision () && mid_squared < n) + { + // (mid * 10^precision + fractional)^2 == + // n^2 * 10^(precision * 2) + + const ACE_UINT32 field = square_root.fractional_field (); + + floor = 0; + ceiling = field; + mid = 0; + + // Do the 64-bit arithmetic carefully to avoid overflow. + ACE_UINT64 target = n; + target *= field; + target *= field; + + ACE_UINT64 difference = 0; + + for (i = 0; i < square_root.precision (); ++i) + { + mid = (ceiling - floor) / 2 + floor; + + ACE_UINT64 current = square_root.whole () * field + mid; + current *= square_root.whole () * field + mid; + + if (floor == mid) + { + difference = target - current; + break; + } + else if (current <= target) + floor = mid; + else + ceiling = mid; + } + + // Check to see if the fractional part should be one greater. + ACE_UINT64 next = square_root.whole () * field + mid + 1; + next *= square_root.whole () * field + mid + 1; + + square_root.fractional (next - target < difference ? mid + 1 : mid); + } + else + { + // No fractional portion is requested, so don't bother + // calculating it. + square_root.fractional (0); + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Stats.h b/dep/acelite/ace/Stats.h new file mode 100644 index 000000000..e3f16fdd5 --- /dev/null +++ b/dep/acelite/ace/Stats.h @@ -0,0 +1,226 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Stats.h + * + * @author David L. Levine + */ +//========================================================================== + + +#ifndef ACE_STATS_H +#define ACE_STATS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Unbounded_Queue.h" +#include "ace/Log_Category.h" +#include "ace/Basic_Stats.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Stats_Value + * + * @brief Helper class for ACE_Stats. + * + * Container struct for 64-bit signed quantity and its + * precision. It would be nicer to use a fixed-point class, but + * this is sufficient. Users typically don't need to use this + * class directly; see ACE_Stats below. + */ +class ACE_Export ACE_Stats_Value +{ +public: + /** + * Constructor, which requires precision in terms of number of + * decimal digits. The more variation in the data, and the greater + * the data values, the smaller the precision must be to avoid + * overflow in the standard deviation calculation. 3 might be a + * good value, or maybe 4. 5 will probably be too large for + * non-trivial data sets. + */ + ACE_Stats_Value (const u_int precision); + + /// Accessor for precision. + u_int precision (void) const; + + /// Set the whole_ field. + void whole (const ACE_UINT32); + + /// Accessor for the whole_ field. + ACE_UINT32 whole (void) const; + + /// Set the fractional_ field. + void fractional (const ACE_UINT32); + + /// Accessor for the fractional_ field. + ACE_UINT32 fractional (void) const; + + /// Calculates the maximum value of the fractional portion, given its + /// precision. + ACE_UINT32 fractional_field (void) const; + + /** + * Access the value as an _unsigned_ 64 bit quantity. It scales the + * value up by {precision} decimal digits, so that no precision will + * be lost. It assumes that {whole_} is >= 0. + */ + void scaled_value (ACE_UINT64 &) const; + + /// Print to stdout. + void dump (void) const; + +private: + + ACE_Stats_Value (void) {} + +private: + /// The integer portion of the value. + ACE_UINT32 whole_; + + /// The fractional portion of the value. + ACE_UINT32 fractional_; + + /** + * The number of decimal digits of precision represented by + * {fractional_}. Not declared const, so the only way to change it + * is via the assignment operator. + */ + u_int precision_; + +}; + +/** + * @class ACE_Stats + * + * @brief Provides simple statistical analysis. + * + * Simple statistical analysis package. Prominent features are: + * -# It does not use any floating point arithmetic. + * -# It handles positive and/or negative sample values. The + * sample value type is ACE_INT32. + * -# It uses 64 bit unsigned, but not 64 bit signed, quantities + * internally. + * -# It checks for overflow of internal state. + * -# It has no static variables of other than built-in types. + * + * Example usage: + * + * @verbatim + * ACE_Stats stats; + * for (u_int i = 0; i < n; ++i) + * { + * const ACE_UINT32 sample = ...; + * stats.sample (sample); + * } + * stats.print_summary (3); + * @endverbatim + */ +class ACE_Export ACE_Stats +{ +public: + /// Default constructor. + ACE_Stats (void); + + /// Provide a new sample. Returns 0 on success, -1 if it fails due + /// to running out of memory, or to rolling over of the sample count. + int sample (const ACE_INT32 value); + + /// Access the number of samples provided so far. + ACE_UINT32 samples (void) const; + + /// Value of the minimum sample provided so far. + ACE_INT32 min_value (void) const; + + /// Value of the maximum sample provided so far. + ACE_INT32 max_value (void) const; + + /** + * Access the mean of all samples provided so far. The fractional + * part is to the specified number of digits. E.g., 3 fractional + * digits specifies that the fractional part is in thousandths. + */ + void mean (ACE_Stats_Value &mean, + const ACE_UINT32 scale_factor = 1); + + /// Access the standard deviation, whole and fractional parts. See + /// description of {mean} method for argument descriptions. + int std_dev (ACE_Stats_Value &std_dev, + const ACE_UINT32 scale_factor = 1); + + /** + * Print summary statistics. If scale_factor is not 1, then the + * results are divided by it, i.e., each of the samples is scaled + * down by it. If internal overflow is reached with the specified + * scale factor, it successively tries to reduce it. Returns -1 if + * there is overflow even with a 0 scale factor. + */ + int print_summary (const u_int precision, + const ACE_UINT32 scale_factor = 1, + FILE * +#ifdef ACE_LACKS_STDOUT + = 0 +#else + = stdout +#endif + ) const; + + /// Initialize internal state. + void reset (void); + + /// Utility division function, for ACE_UINT64 dividend. + static void quotient (const ACE_UINT64 dividend, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient); + + /// Utility division function, for ACE_Stats_Value dividend. + static void quotient (const ACE_Stats_Value ÷nd, + const ACE_UINT32 divisor, + ACE_Stats_Value "ient); + + /** + * Sqrt function, which uses an oversimplified version of Newton's + * method. It's not fast, but it doesn't require floating point + * support. + */ + static void square_root (const ACE_UINT64 n, + ACE_Stats_Value &square_root); + + /// Print summary statistics to stdout. + void dump (void) const; + +protected: + /// Internal indication of whether there has been overflow. Contains + /// the errno corresponding to the cause of overflow. + u_int overflow_; + + /// Number of samples. + ACE_UINT32 number_of_samples_; + + /// Minimum sample value. + ACE_INT32 min_; + + /// Maximum sample value. + ACE_INT32 max_; + + /// The samples. + ACE_Unbounded_Queue samples_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +# include "ace/Stats.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ! ACE_STATS_H */ diff --git a/dep/acelite/ace/Stats.inl b/dep/acelite/ace/Stats.inl new file mode 100644 index 000000000..2e54c1228 --- /dev/null +++ b/dep/acelite/ace/Stats.inl @@ -0,0 +1,101 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Stats_Value::ACE_Stats_Value (const u_int precision) + : whole_ (0), + fractional_ (0), + precision_ (precision) +{ +} + +ACE_INLINE +u_int +ACE_Stats_Value::precision (void) const +{ + return precision_; +} + +ACE_INLINE +void +ACE_Stats_Value::whole (const ACE_UINT32 value) +{ + whole_ = value; +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats_Value::whole (void) const +{ + return whole_; +} + +ACE_INLINE +void +ACE_Stats_Value::fractional (const ACE_UINT32 value) +{ + fractional_ = value; +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats_Value::fractional (void) const +{ + return fractional_; +} + +ACE_INLINE +void +ACE_Stats_Value::scaled_value (ACE_UINT64 &sv) const +{ + sv = whole () * fractional_field () + fractional (); +} + +ACE_INLINE +void +ACE_Stats_Value::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("precision: %u digits; whole: %u, fractional: %u\n"), + precision_, whole_, fractional_)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_INLINE +ACE_Stats::ACE_Stats (void) +{ + reset (); +} + +ACE_INLINE +ACE_UINT32 +ACE_Stats::samples (void) const +{ + return number_of_samples_; +} + +ACE_INLINE +ACE_INT32 +ACE_Stats::min_value (void) const +{ + return min_; +} + +ACE_INLINE +ACE_INT32 +ACE_Stats::max_value (void) const +{ + return max_; +} + +ACE_INLINE +void +ACE_Stats::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + print_summary (3u); +#endif /* ACE_HAS_DUMP */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Strategies_T.cpp b/dep/acelite/ace/Strategies_T.cpp new file mode 100644 index 000000000..761ca762d --- /dev/null +++ b/dep/acelite/ace/Strategies_T.cpp @@ -0,0 +1,1504 @@ +#ifndef ACE_STRATEGIES_T_CPP +#define ACE_STRATEGIES_T_CPP + +#include "ace/Strategies_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Service_Repository.h" +#include "ace/Service_Types.h" +#include "ace/Thread_Manager.h" +#include "ace/WFMO_Reactor.h" +#include "ace/ACE.h" +#include "ace/OS_NS_dlfcn.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_Errno.h" +#include "ace/Svc_Handler.h" +#if defined (ACE_OPENVMS) +# include "ace/Lib_Find.h" +#endif + +#if !defined (__ACE_INLINE__) +#include "ace/Strategies_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Recycling_Strategy::~ACE_Recycling_Strategy (void) +{ +} + +template int +ACE_Recycling_Strategy::assign_recycler (SVC_HANDLER *svc_handler, + ACE_Connection_Recycling_Strategy *recycler, + const void *recycling_act) +{ + svc_handler->recycler (recycler, recycling_act); + return 0; +} + +template int +ACE_Recycling_Strategy::prepare_for_recycling (SVC_HANDLER *svc_handler) +{ + return svc_handler->recycle (); +} + +template +ACE_Singleton_Strategy::~ACE_Singleton_Strategy (void) +{ + ACE_TRACE ("ACE_Singleton_Strategy::~ACE_Singleton_Strategy"); + if (this->delete_svc_handler_) + delete this->svc_handler_; +} + +// Create a Singleton SVC_HANDLER by always returning the same +// SVC_HANDLER. + +template int +ACE_Singleton_Strategy::make_svc_handler (SVC_HANDLER *&sh) +{ + ACE_TRACE ("ACE_Singleton_Strategy::make_svc_handler"); + sh = this->svc_handler_; + return 0; +} + +template int +ACE_Singleton_Strategy::open (SVC_HANDLER *sh, + ACE_Thread_Manager *) +{ + ACE_TRACE ("ACE_Singleton_Strategy::open"); + + if (this->delete_svc_handler_) + delete this->svc_handler_; + + // If is NULL then create a new . + if (sh == 0) + { + ACE_NEW_RETURN (this->svc_handler_, + SVC_HANDLER, + -1); + this->delete_svc_handler_ = true; + } + else + { + this->svc_handler_ = sh; + this->delete_svc_handler_ = false; + } + + return 0; +} + +template int +ACE_DLL_Strategy::open (const ACE_TCHAR dll_name[], + const ACE_TCHAR factory_function[], + const ACE_TCHAR svc_name[], + ACE_Service_Repository *svc_rep, + ACE_Thread_Manager *thr_mgr) +{ + ACE_TRACE ("ACE_DLL_Strategy::open"); + this->inherited::open (thr_mgr); + ACE_OS::strcpy (this->dll_name_, dll_name); + ACE_OS::strcpy (this->factory_function_, factory_function); + ACE_OS::strcpy (this->svc_name_, svc_name); + this->svc_rep_ = svc_rep; + return 0; +} + +// Create a SVC_HANDLER by dynamically linking it from a DLL. + +template int +ACE_DLL_Strategy::make_svc_handler (SVC_HANDLER *&sh) +{ + ACE_TRACE ("ACE_DLL_Strategy::make_svc_handler"); + + // Open the shared library. + ACE_SHLIB_HANDLE handle = ACE_OS::dlopen (this->dll_name_); + + // Extract the factory function. +#if defined (ACE_OPENVMS) + SVC_HANDLER *(*factory)(void) = + (SVC_HANDLER *(*)(void)) ACE::ldsymbol (handle, + this->factory_function_); +#else + SVC_HANDLER *(*factory)(void) = + (SVC_HANDLER *(*)(void)) ACE_OS::dlsym (handle, + this->factory_function_); +#endif + + // Call the factory function to obtain the new SVC_Handler (should + // use RTTI here when it becomes available...) + SVC_HANDLER *svc_handler = 0; + + ACE_ALLOCATOR_RETURN (svc_handler, (*factory)(), -1); + + if (svc_handler != 0) + { + // Create an ACE_Service_Type containing the SVC_Handler and + // insert into this->svc_rep_; + + ACE_Service_Type_Impl *stp = 0; + ACE_NEW_RETURN (stp, + ACE_Service_Object_Type (svc_handler, + this->svc_name_), + -1); + + ACE_Service_Type *srp = 0; + + ACE_NEW_RETURN (srp, + ACE_Service_Type (this->svc_name_, + stp, + handle, + 1), + -1); + if (srp == 0) + { + delete stp; + errno = ENOMEM; + return -1; + } + + if (this->svc_rep_->insert (srp) == -1) + return -1; + // @@ Somehow, we need to deal with this->thr_mgr_... + } + + sh = svc_handler; + return 0; +} + +// Default behavior is to activate the SVC_HANDLER by calling it's +// open() method, which allows the SVC_HANDLER to determine its own +// concurrency strategy. + +template int +ACE_Concurrency_Strategy::activate_svc_handler (SVC_HANDLER *svc_handler, + void *arg) +{ + ACE_TRACE ("ACE_Concurrency_Strategy::activate_svc_handler"); + + int result = 0; + + // See if we should enable non-blocking I/O on the 's + // peer. + if (ACE_BIT_ENABLED (this->flags_, ACE_NONBLOCK) != 0) + { + if (svc_handler->peer ().enable (ACE_NONBLOCK) == -1) + result = -1; + } + // Otherwise, make sure it's disabled by default. + else if (svc_handler->peer ().disable (ACE_NONBLOCK) == -1) + result = -1; + + if (result == 0 && svc_handler->open (arg) == -1) + result = -1; + + if (result == -1) + // The connection was already made; so this close is a "normal" close + // operation. + svc_handler->close (NORMAL_CLOSE_OPERATION); + + return result; +} + +template int +ACE_Reactive_Strategy::open (ACE_Reactor *reactor, + ACE_Reactor_Mask mask, + int flags) +{ + ACE_TRACE ("ACE_Reactive_Strategy::open"); + this->reactor_ = reactor; + this->mask_ = mask; + this->flags_ = flags; + + // Must have a + if (this->reactor_ == 0) + return -1; + else + return 0; +} + +template int +ACE_Reactive_Strategy::activate_svc_handler (SVC_HANDLER *svc_handler, + void *arg) +{ + ACE_TRACE ("ACE_Reactive_Strategy::activate_svc_handler"); + + int result = 0; + + if (this->reactor_ == 0) + result = -1; + + // Register with the Reactor with the appropriate . + else if (this->reactor_->register_handler (svc_handler, this->mask_) == -1) + result = -1; + + // If the implementation of the reactor uses event associations + else if (this->reactor_->uses_event_associations ()) + { + // If we don't have non-block on, it won't work with + // WFMO_Reactor + // This maybe too harsh + // if (!ACE_BIT_ENABLED (this->flags_, ACE_NONBLOCK)) + // goto failure; + if (svc_handler->open (arg) != -1) + return 0; + else + result = -1; + } + else + // Call up to our parent to do the SVC_HANDLER initialization. + return this->inherited::activate_svc_handler (svc_handler, arg); + + if (result == -1) + // The connection was already made; so this close is a "normal" close + // operation. + svc_handler->close (NORMAL_CLOSE_OPERATION); + + return result; +} + +template int +ACE_Thread_Strategy::open (ACE_Thread_Manager *thr_mgr, + long thr_flags, + int n_threads, + int flags) +{ + ACE_TRACE ("ACE_Thread_Strategy::open"); + this->thr_mgr_ = thr_mgr; + this->n_threads_ = n_threads; + this->thr_flags_ = thr_flags; + this->flags_ = flags; + + // Must have a thread manager! + if (this->thr_mgr_ == 0) + ACELIB_ERROR_RETURN ((LM_ERROR, + ACE_TEXT ("error: must have a non-NULL thread manager\n")), + -1); + else + return 0; +} + +template int +ACE_Thread_Strategy::activate_svc_handler (SVC_HANDLER *svc_handler, + void *arg) +{ + ACE_TRACE ("ACE_Thread_Strategy::activate_svc_handler"); + // Call up to our parent to do the SVC_HANDLER initialization. + if (this->inherited::activate_svc_handler (svc_handler, + arg) == -1) + return -1; + else + // Turn the into an active object (if it isn't + // already one as a result of the first activation...) + return svc_handler->activate (this->thr_flags_, + this->n_threads_); +} + +template int +ACE_Accept_Strategy::open + (const ACE_PEER_ACCEPTOR_ADDR &local_addr, bool reuse_addr) +{ + this->reuse_addr_ = reuse_addr; + this->peer_acceptor_addr_ = local_addr; + if (this->peer_acceptor_.open (local_addr, reuse_addr) == -1) + return -1; + + // Set the peer acceptor's handle into non-blocking mode. This is a + // safe-guard against the race condition that can otherwise occur + // between the time when was interrupted. + if (ACE_Sig_Handler::sig_pending () != 0) + { + ACE_Sig_Handler::sig_pending (0); + + // This piece of code comes from the old TP_Reactor. We did not + // handle signals at all then. If we happen to handle signals + // in the TP_Reactor, we should then start worryiung about this + // - Bala 21-Aug- 01 +if 0 + // Not sure if this should be done in the TP_Reactor + // case... leave it out for now. -Steve Huston 22-Aug-00 + + // If any HANDLES in the are activated as a + // result of signals they should be dispatched since + // they may be time critical... + active_handle_count = this->any_ready (dispatch_set); +else + // active_handle_count = 0; +endif + + // Record the fact that the Reactor has dispatched a + // handle_signal() method. We need this to return the + // appropriate count. + return 1; + } + + return -1; +} +#endif // #if 0 + + +int +ACE_TP_Reactor::handle_timer_events (int & /*event_count*/, + ACE_TP_Token_Guard &guard) +{ + typedef ACE_Member_Function_Command Guard_Release; + + Guard_Release release(guard, &ACE_TP_Token_Guard::release_token); + return this->timer_queue_->expire_single(release); +} + +int +ACE_TP_Reactor::handle_notify_events (int & /*event_count*/, + ACE_TP_Token_Guard &guard) +{ + // Get the handle on which notify calls could have occurred + ACE_HANDLE notify_handle = this->get_notify_handle (); + + int result = 0; + + // The notify was not in the list returned by + // wait_for_multiple_events (). + if (notify_handle == ACE_INVALID_HANDLE) + return result; + + // Now just do a read on the pipe.. + ACE_Notification_Buffer buffer; + + // Clear the handle of the read_mask of our + this->ready_set_.rd_mask_.clr_bit (notify_handle); + + // Keep reading notifies till we empty it or till we have a + // dispatchable buffer + while (this->notify_handler_->read_notify_pipe (notify_handle, buffer) > 0) + { + // Just figure out whether we can read any buffer that has + // dispatchable info. If not we have just been unblocked by + // another thread trying to update the reactor. If we get any + // buffer that needs dispatching we will dispatch that after + // releasing the lock + if (this->notify_handler_->is_dispatchable (buffer) > 0) + { + // Release the token before dispatching notifies... + guard.release_token (); + + // Dispatch the upcall for the notify + this->notify_handler_->dispatch_notify (buffer); + + // We had a successful dispatch. + result = 1; + + // break out of the while loop + break; + } + } + + // If we did some work, then we just return 1 which will allow us + // to get out of here. If we return 0, then we will be asked to do + // some work ie. dispacth socket events + return result; +} + +int +ACE_TP_Reactor::handle_socket_events (int &event_count, + ACE_TP_Token_Guard &guard) +{ + + // We got the lock, lets handle some I/O events. + ACE_EH_Dispatch_Info dispatch_info; + + this->get_socket_event_info (dispatch_info); + + // If there is any event handler that is ready to be dispatched, the + // dispatch information is recorded in dispatch_info. + if (!dispatch_info.dispatch ()) + { + // Check for removed handlers. + if (dispatch_info.event_handler_ == 0) + { + this->handler_rep_.unbind(dispatch_info.handle_, + dispatch_info.mask_); + } + + + return 0; + } + + // Suspend the handler so that other threads don't start dispatching + // it, if we can't suspend then return directly + // + // NOTE: This check was performed in older versions of the + // TP_Reactor. Looks like it is a waste.. + if (dispatch_info.event_handler_ != this->notify_handler_) + if (this->suspend_i (dispatch_info.handle_) == -1) + return 0; + + // Call add_reference() if needed. + if (dispatch_info.reference_counting_required_) + dispatch_info.event_handler_->add_reference (); + + // Release the lock. Others threads can start waiting. + guard.release_token (); + + int result = 0; + + // If there was an event handler ready, dispatch it. + // Decrement the event left + --event_count; + + // Dispatched an event + if (this->dispatch_socket_event (dispatch_info) == 0) + ++result; + + return result; +} + +int +ACE_TP_Reactor::get_event_for_dispatching (ACE_Time_Value *max_wait_time) +{ + // If the reactor handler state has changed, clear any remembered + // ready bits and re-scan from the master wait_set. + if (this->state_changed_) + { + this->ready_set_.rd_mask_.reset (); + this->ready_set_.wr_mask_.reset (); + this->ready_set_.ex_mask_.reset (); + + this->state_changed_ = false; + } + else + { + // This is a hack... somewhere, under certain conditions (which + // I don't understand...) the mask will have all of its bits clear, + // yet have a size_ > 0. This is an attempt to remedy the affect, + // without knowing why it happens. + + this->ready_set_.rd_mask_.sync (this->ready_set_.rd_mask_.max_set ()); + this->ready_set_.wr_mask_.sync (this->ready_set_.wr_mask_.max_set ()); + this->ready_set_.ex_mask_.sync (this->ready_set_.ex_mask_.max_set ()); + } + + return this->wait_for_multiple_events (this->ready_set_, max_wait_time); +} + +int +ACE_TP_Reactor::get_socket_event_info (ACE_EH_Dispatch_Info &event) +{ + // Check for dispatch in write, except, read. Only catch one, but if + // one is caught, be sure to clear the handle from each mask in case + // there is more than one mask set for it. This would cause problems + // if the handler is suspended for dispatching, but its set bit in + // another part of ready_set_ kept it from being dispatched. + int found_io = 0; + ACE_HANDLE handle; + + // @@todo: We can do quite a bit of code reduction here. Let me get + // it to work before I do this. + { + ACE_Handle_Set_Iterator handle_iter (this->ready_set_.wr_mask_); + + while (!found_io && (handle = handle_iter ()) != ACE_INVALID_HANDLE) + { + if (this->is_suspended_i (handle)) + continue; + + // Remember this info + event.set (handle, + this->handler_rep_.find (handle), + ACE_Event_Handler::WRITE_MASK, + &ACE_Event_Handler::handle_output); + + this->clear_handle_read_set (handle); + found_io = 1; + } + } + + if (!found_io) + { + ACE_Handle_Set_Iterator handle_iter (this->ready_set_.ex_mask_); + + while (!found_io && (handle = handle_iter ()) != ACE_INVALID_HANDLE) + { + if (this->is_suspended_i (handle)) + continue; + + // Remember this info + event.set (handle, + this->handler_rep_.find (handle), + ACE_Event_Handler::EXCEPT_MASK, + &ACE_Event_Handler::handle_exception); + + this->clear_handle_read_set (handle); + + found_io = 1; + } + } + + if (!found_io) + { + ACE_Handle_Set_Iterator handle_iter (this->ready_set_.rd_mask_); + + while (!found_io && (handle = handle_iter ()) != ACE_INVALID_HANDLE) + { + if (this->is_suspended_i (handle)) + continue; + + // Remember this info + event.set (handle, + this->handler_rep_.find (handle), + ACE_Event_Handler::READ_MASK, + &ACE_Event_Handler::handle_input); + + this->clear_handle_read_set (handle); + found_io = 1; + } + } + + return found_io; +} + +// Dispatches a single event handler +int +ACE_TP_Reactor::dispatch_socket_event (ACE_EH_Dispatch_Info &dispatch_info) +{ + ACE_TRACE ("ACE_TP_Reactor::dispatch_socket_event"); + + ACE_Event_Handler * const event_handler = dispatch_info.event_handler_; + ACE_EH_PTMF const callback = dispatch_info.callback_; + + // Check for removed handlers. + if (event_handler == 0) + return -1; + + // Upcall. If the handler returns positive value (requesting a + // reactor callback) don't set the ready-bit because it will be + // ignored if the reactor state has changed. Just call back + // as many times as the handler requests it. Other threads are off + // handling other things. + int status = 1; + while (status > 0) + status = (event_handler->*callback) (dispatch_info.handle_); + + // Post process socket event + return this->post_process_socket_event (dispatch_info, status); +} + +int +ACE_TP_Reactor::post_process_socket_event (ACE_EH_Dispatch_Info &dispatch_info, + int status) +{ + int result = 0; + + // First check if we really have to post process something, if not, then + // we don't acquire the token which saves us a lot of time. + if (status < 0 || + (dispatch_info.event_handler_ != this->notify_handler_ && + dispatch_info.resume_flag_ == + ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER)) + { + // Get the reactor token and with this token acquired remove first the + // handler and resume it at the same time. This must be atomic, see also + // bugzilla 2395. When this is not atomic it can be that we resume the + // handle after it is reused by the OS. + ACE_TP_Token_Guard guard (this->token_); + + result = guard.acquire_token (); + + // If the guard is NOT the owner just return the retval + if (!guard.is_owner ()) + return result; + + // A different event handler may have been registered during the + // upcall if the handle was closed and then reopened, for + // example. Make sure we're removing and/or resuming the event + // handler used during the upcall. + ACE_Event_Handler const * const eh = + this->handler_rep_.find (dispatch_info.handle_); + + // Only remove or resume the event handler used during the + // upcall. + if (eh == dispatch_info.event_handler_) + { + if (status < 0) + { + result = + this->remove_handler_i (dispatch_info.handle_, + dispatch_info.mask_); + } + + // Resume handler if required. + if (dispatch_info.event_handler_ != this->notify_handler_ && + dispatch_info.resume_flag_ == + ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER) + this->resume_i (dispatch_info.handle_); + } + } + + // Call remove_reference() if needed. + if (dispatch_info.reference_counting_required_) + dispatch_info.event_handler_->remove_reference (); + + return result; +} + +int +ACE_TP_Reactor::resumable_handler (void) +{ + return 1; +} + +int +ACE_TP_Reactor::handle_events (ACE_Time_Value &max_wait_time) +{ + return this->handle_events (&max_wait_time); +} + +void +ACE_TP_Reactor::notify_handle (ACE_HANDLE, + ACE_Reactor_Mask, + ACE_Handle_Set &, + ACE_Event_Handler *eh, + ACE_EH_PTMF) +{ + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("ACE_TP_Reactor::notify_handle: ") + ACE_TEXT ("Wrong version of notify_handle() got called\n"))); + + ACE_ASSERT (eh == 0); + ACE_UNUSED_ARG (eh); +} + +ACE_HANDLE +ACE_TP_Reactor::get_notify_handle (void) +{ + // Call the notify handler to get a handle on which we would have a + // notify waiting + ACE_HANDLE const read_handle = + this->notify_handler_->notify_handle (); + + // Check whether the rd_mask has been set on that handle. If so + // return the handle. + if (read_handle != ACE_INVALID_HANDLE && + this->ready_set_.rd_mask_.is_set (read_handle)) + { + return read_handle; + } + + // None found.. + return ACE_INVALID_HANDLE; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/TP_Reactor.h b/dep/acelite/ace/TP_Reactor.h new file mode 100644 index 000000000..15384c0eb --- /dev/null +++ b/dep/acelite/ace/TP_Reactor.h @@ -0,0 +1,318 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file TP_Reactor.h + * + * The ACE_TP_Reactor (aka, Thread Pool Reactor) uses the + * Leader/Followers pattern to demultiplex events among a pool of + * threads. When using a thread pool reactor, an application + * pre-spawns a fixed number of threads. When these threads + * invoke the ACE_TP_Reactor's handle_events() method, one thread + * will become the leader and wait for an event. The other + * follower threads will queue up waiting for their turn to become + * the leader. When an event occurs, the leader will pick a + * follower to become the leader and go on to handle the event. + * The consequence of using ACE_TP_Reactor is the amortization of + * the costs used to create threads. The context switching cost + * will also reduce. Moreover, the total resources used by + * threads are bounded because there are a fixed number of threads. + * + * @author Irfan Pyarali + * @author Nanbor Wang + */ +//============================================================================= + + +#ifndef ACE_TP_REACTOR_H +#define ACE_TP_REACTOR_H + +#include /**/ "ace/pre.h" + +#include "ace/Select_Reactor.h" +#include "ace/Timer_Queue.h" /* Simple forward decl won't work... */ + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_EH_Dispatch_Info + * + * @brief This structure contains information of the activated event + * handler. + */ +class ACE_EH_Dispatch_Info +{ +public: + ACE_EH_Dispatch_Info (void); + + void set (ACE_HANDLE handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask, + ACE_EH_PTMF callback); + + bool dispatch (void) const; + + ACE_HANDLE handle_; + ACE_Event_Handler *event_handler_; + ACE_Reactor_Mask mask_; + ACE_EH_PTMF callback_; + int resume_flag_; + bool reference_counting_required_; + +private: + bool dispatch_; + + // Disallow copying and assignment. + ACE_EH_Dispatch_Info (const ACE_EH_Dispatch_Info &); + ACE_EH_Dispatch_Info &operator= (const ACE_EH_Dispatch_Info &); +}; + + +/** + * @class ACE_TP_Token_Guard + * + * @brief A helper class that helps grabbing, releasing and waiting + * on tokens for a thread that tries calling handle_events (). + * + * In short, this class will be owned by one thread by creating on the + * stack. This class gives the status of the ownership of the token + * and manages the ownership + */ + +class ACE_TP_Token_Guard +{ +public: + + /// Constructor that will grab the token for us + ACE_TP_Token_Guard (ACE_Select_Reactor_Token &token); + + /// Destructor. This will release the token if it hasnt been + /// released till this point + ~ACE_TP_Token_Guard (void); + + /// Release the token .. + void release_token (void); + + /// Returns whether the thread that created this object ownes the + /// token or not. + bool is_owner (void); + + /// A helper method that grabs the token for us, after which the + /// thread that owns that can do some actual work. + int acquire_read_token (ACE_Time_Value *max_wait_time = 0); + + /** + * A helper method that grabs the token for us, after which the + * thread that owns that can do some actual work. This differs from + * acquire_read_token() as it uses acquire () to get the token instead of + * acquire_read () + */ + int acquire_token (ACE_Time_Value *max_wait_time = 0); + +private: + + // Disallow default construction. + ACE_TP_Token_Guard (void); + + // Disallow copying and assignment. + ACE_TP_Token_Guard (const ACE_TP_Token_Guard &); + ACE_TP_Token_Guard &operator= (const ACE_TP_Token_Guard &); + +private: + + /// The Select Reactor token. + ACE_Select_Reactor_Token &token_; + + /// Flag that indicate whether the thread that created this object + /// owns the token or not. A value of false indicates that this class + /// hasn't got the token (and hence the thread) and a value of true + /// vice-versa. + bool owner_; + +}; + +/** + * @class ACE_TP_Reactor + * + * @brief Specialization of ACE_Select_Reactor to support thread-pool + * based event dispatching. + * + * One of the shortcomings of the ACE_Select_Reactor is that it + * does not support a thread pool-based event dispatching model, + * similar to the one in ACE_WFMO_Reactor. In ACE_Select_Reactor, only + * thread can call handle_events() at any given time. ACE_TP_Reactor + * removes this short-coming. + * + * ACE_TP_Reactor is a specialization of ACE_Select_Reactor to support + * thread pool-based event dispatching. This reactor takes advantage + * of the fact that events reported by @c select() are persistent if not + * acted upon immediately. It works by remembering the event handler + * which was just activated, suspending it for further I/O activities, + * releasing the internal lock (so that another thread can start waiting + * in the event loop) and then dispatching the event's handler outside the + * scope of the reactor lock. After the event handler has been dispatched + * the event handler is resumed for further I/O activity. + * + * This reactor implementation is best suited for situations when the + * callbacks to event handlers can take arbitrarily long and/or a number + * of threads are available to run the event loop. Note that I/O-processing + * callback code in event handlers (e.g. handle_input()) does not have to + * be modified or made thread-safe for this reactor. This is because + * before an I/O event is dispatched to an event handler, the handler is + * suspended; it is resumed by the reactor after the upcall completes. + * Therefore, multiple I/O events will not be made to one event handler + * multiple threads simultaneously. This suspend/resume protection does not + * apply to either timers scheduled with the reactor or to notifications + * requested via the reactor. When using timers and/or notifications you + * must provide proper protection for your class in the context of multiple + * threads. + */ +class ACE_Export ACE_TP_Reactor : public ACE_Select_Reactor +{ +public: + + /// Initialize ACE_TP_Reactor with the default size. + ACE_TP_Reactor (ACE_Sig_Handler * = 0, + ACE_Timer_Queue * = 0, + bool mask_signals = true, + int s_queue = ACE_Select_Reactor_Token::FIFO); + + /** + * Initialize the ACE_TP_Reactor to manage + * @a max_number_of_handles. If @a restart is non-0 then the + * ACE_Reactor's @c handle_events() method will be restarted + * automatically when @c EINTR occurs. If @a sh or + * @a tq are non-0 they are used as the signal handler and + * timer queue, respectively. + */ + ACE_TP_Reactor (size_t max_number_of_handles, + bool restart = false, + ACE_Sig_Handler *sh = 0, + ACE_Timer_Queue *tq = 0, + bool mask_signals = true, + int s_queue = ACE_Select_Reactor_Token::FIFO); + + /** + * This event loop driver that blocks for @a max_wait_time before + * returning. It will return earlier if timer events, I/O events, + * or signal events occur. Note that @a max_wait_time can be 0, in + * which case this method blocks indefinitely until events occur. + * + * @a max_wait_time is decremented to reflect how much time this call + * took. For instance, if a time value of 3 seconds is passed to + * handle_events and an event occurs after 2 seconds, + * @a max_wait_time will equal 1 second. This can be used if an + * application wishes to handle events for some fixed amount of + * time. + * + * @return The total number of events that were dispatched; 0 if the + * @a max_wait_time elapsed without dispatching any handlers, or -1 + * if an error occurs (check @c errno for more information). + */ + virtual int handle_events (ACE_Time_Value *max_wait_time = 0); + + virtual int handle_events (ACE_Time_Value &max_wait_time); + + /// Does the reactor allow the application to resume the handle on + /// its own ie. can it pass on the control of handle resumption to + /// the application. The TP reactor has can allow applications to + /// resume handles. So return a positive value. + virtual int resumable_handler (void); + + /// Called from handle events + static void no_op_sleep_hook (void *); + + /// The ACE_TP_Reactor implementation does not have a single owner thread. + /// Attempts to set the owner explicitly are ignored. The reported owner + /// thread is the current Leader in the pattern. + virtual int owner (ACE_thread_t n_id, ACE_thread_t *o_id = 0); + + /// Return the thread ID of the current Leader. + virtual int owner (ACE_thread_t *t_id); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Internal methods that do the actual work. + + /// Template method from the base class. + virtual void clear_dispatch_mask (ACE_HANDLE handle, + ACE_Reactor_Mask mask); + + /// Dispatch just 1 signal, timer, notification handlers + int dispatch_i (ACE_Time_Value *max_wait_time, + ACE_TP_Token_Guard &guard); + + /// Get the event that needs dispatching. It could be either a + /// signal, timer, notification handlers or return possibly 1 I/O + /// handler for dispatching. In the most common use case, this would + /// return 1 I/O handler for dispatching + int get_event_for_dispatching (ACE_Time_Value *max_wait_time); + +#if 0 + // @Ciju + // signal handling isn't in a production state yet. + // Commenting it out for now. + + /// Method to handle signals + /// @note It is just busted at this point in time. + int handle_signals (int &event_count, + ACE_TP_Token_Guard &g); +#endif // #if 0 + + /// Handle timer events + int handle_timer_events (int &event_count, + ACE_TP_Token_Guard &g); + + /// Handle notify events + int handle_notify_events (int &event_count, + ACE_TP_Token_Guard &g); + + /// handle socket events + int handle_socket_events (int &event_count, + ACE_TP_Token_Guard &g); + + /// This method shouldn't get called. + virtual void notify_handle (ACE_HANDLE handle, + ACE_Reactor_Mask mask, + ACE_Handle_Set &, + ACE_Event_Handler *eh, + ACE_EH_PTMF callback); +private: + + /// Get the handle of the notify pipe from the ready set if there is + /// an event in the notify pipe. + ACE_HANDLE get_notify_handle (void); + + /// Get socket event dispatch information. + int get_socket_event_info (ACE_EH_Dispatch_Info &info); + + /// Notify the appropriate in the context of the + /// associated with that a particular event has occurred. + int dispatch_socket_event (ACE_EH_Dispatch_Info &dispatch_info); + + /// Clear the @a handle from the read_set + void clear_handle_read_set (ACE_HANDLE handle); + + int post_process_socket_event (ACE_EH_Dispatch_Info &dispatch_info,int status); + +private: + /// Deny access since member-wise won't work... + ACE_TP_Reactor (const ACE_TP_Reactor &); + ACE_TP_Reactor &operator = (const ACE_TP_Reactor &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/TP_Reactor.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_TP_REACTOR_H */ diff --git a/dep/acelite/ace/TP_Reactor.inl b/dep/acelite/ace/TP_Reactor.inl new file mode 100644 index 000000000..f793fd23c --- /dev/null +++ b/dep/acelite/ace/TP_Reactor.inl @@ -0,0 +1,116 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/************************************************************************/ +// Methods for ACE_EH_Dispatch_Info +/************************************************************************/ + +ACE_INLINE +ACE_EH_Dispatch_Info::ACE_EH_Dispatch_Info (void) : + handle_ (ACE_INVALID_HANDLE), + event_handler_ (0), + mask_ (ACE_Event_Handler::NULL_MASK), + callback_ (0), + resume_flag_ (ACE_Event_Handler::ACE_REACTOR_RESUMES_HANDLER), + reference_counting_required_ (false), + dispatch_ (false) +{ +} + +ACE_INLINE void +ACE_EH_Dispatch_Info::set (ACE_HANDLE handle, + ACE_Event_Handler *event_handler, + ACE_Reactor_Mask mask, + ACE_EH_PTMF callback) +{ + this->dispatch_ = true; + + this->handle_ = handle; + this->event_handler_ = event_handler; + this->mask_ = mask; + this->callback_ = callback; + if (event_handler_) + { + this->resume_flag_ = event_handler->resume_handler (); + this->reference_counting_required_ = + (event_handler_->reference_counting_policy ().value () == + ACE_Event_Handler::Reference_Counting_Policy::ENABLED); + } + else + this->dispatch_ = false; +} + +ACE_INLINE bool +ACE_EH_Dispatch_Info::dispatch (void) const +{ + return this->dispatch_; +} + +/************************************************************************/ +// Methods for ACE_TP_Token_Guard +/************************************************************************/ + +ACE_INLINE +ACE_TP_Token_Guard::ACE_TP_Token_Guard (ACE_Select_Reactor_Token &token) + + : token_ (token), + owner_ (false) +{ +} + +ACE_INLINE +ACE_TP_Token_Guard::~ACE_TP_Token_Guard (void) +{ + if (this->owner_) + { + ACE_MT (this->token_.release ()); + this->owner_ = false; + } +} + +ACE_INLINE void +ACE_TP_Token_Guard::release_token (void) +{ + if (this->owner_) + { + ACE_MT (this->token_.release ()); + + // We are not the owner anymore.. + this->owner_ = false; + } +} + +ACE_INLINE bool +ACE_TP_Token_Guard::is_owner (void) +{ + return this->owner_; +} + + +/************************************************************************/ +// Methods for ACE_TP_Reactor +/************************************************************************/ + +ACE_INLINE void +ACE_TP_Reactor::no_op_sleep_hook (void *) +{ +} + +ACE_INLINE void +ACE_TP_Reactor::clear_handle_read_set (ACE_HANDLE handle) +{ + this->ready_set_.wr_mask_.clr_bit (handle); + this->ready_set_.ex_mask_.clr_bit (handle); + this->ready_set_.rd_mask_.clr_bit (handle); +} + +ACE_INLINE void +ACE_TP_Reactor::clear_dispatch_mask (ACE_HANDLE , + ACE_Reactor_Mask ) +{ + this->ready_set_.rd_mask_.reset (); + this->ready_set_.wr_mask_.reset (); + this->ready_set_.ex_mask_.reset (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/TSS_Adapter.cpp b/dep/acelite/ace/TSS_Adapter.cpp new file mode 100644 index 000000000..ee1f55fdc --- /dev/null +++ b/dep/acelite/ace/TSS_Adapter.cpp @@ -0,0 +1,44 @@ +/** + * @file TSS_Adapter.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/TSS_Adapter.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_TSS_Adapter::ACE_TSS_Adapter (void *object, ACE_THR_DEST f) + : ts_obj_ (object), + func_ (f) +{ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_TSS_Adapter); + +void +ACE_TSS_Adapter::cleanup (void) +{ + (*this->func_)(this->ts_obj_); // call cleanup routine for ts_obj_ +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +extern "C" ACE_Export void +ACE_TSS_C_cleanup (void *object) +{ + if (object != 0) + { + ACE_TSS_Adapter * const tss_adapter = (ACE_TSS_Adapter *) object; + // Perform cleanup on the real TS object. + tss_adapter->cleanup (); + // Delete the adapter object. + delete tss_adapter; + } +} diff --git a/dep/acelite/ace/TSS_Adapter.h b/dep/acelite/ace/TSS_Adapter.h new file mode 100644 index 000000000..376f51792 --- /dev/null +++ b/dep/acelite/ace/TSS_Adapter.h @@ -0,0 +1,60 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file TSS_Adapter.h + * + * Originally in Synch.h + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_TSS_ADAPTER_H +#define ACE_TSS_ADAPTER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_TSS_Adapter + * + * @brief This class encapsulates a TSS object and its associated + * C++ destructor function. It is used by the ACE_TSS... + * methods (in Synch_T.cpp) in order to allow an extern + * "C" cleanup routine to be used. + * + * Objects of this class are stored in thread specific + * storage. ts_obj_ points to the "real" object and + * func_ is a pointer to the C++ cleanup function for ts_obj_. + */ +class ACE_Export ACE_TSS_Adapter +{ +public: + /// Initialize the adapter. + ACE_TSS_Adapter (void *object, ACE_THR_DEST f); + + /// Perform the cleanup operation. + void cleanup (void); + + ACE_ALLOC_HOOK_DECLARE; + +//private: + + /// The real TS object. + void * const ts_obj_; + + /// The real cleanup routine for ts_obj; + ACE_THR_DEST func_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_TSS_ADAPTER_H */ diff --git a/dep/acelite/ace/TSS_T.cpp b/dep/acelite/ace/TSS_T.cpp new file mode 100644 index 000000000..bee8257b0 --- /dev/null +++ b/dep/acelite/ace/TSS_T.cpp @@ -0,0 +1,669 @@ +#ifndef ACE_TSS_T_CPP +#define ACE_TSS_T_CPP + +#include "ace/TSS_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/TSS_T.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Thread.h" +#include "ace/Log_Category.h" +#include "ace/Guard_T.h" +#include "ace/OS_NS_stdio.h" +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if defined (ACE_HAS_THR_C_DEST) +# include "ace/TSS_Adapter.h" +#endif /* ACE_HAS_THR_C_DEST */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_TSS) + +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) +# if defined (ACE_HAS_THR_C_DEST) +extern "C" ACE_Export void ACE_TSS_C_cleanup (void *); +# endif /* ACE_HAS_THR_C_DEST */ +#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */ + +template +ACE_TSS::~ACE_TSS (void) +{ +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) + if (this->once_) + { +# if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = this->ts_value (); + this->ts_value (0); + ACE_TSS_C_cleanup (tss_adapter); +# else + TYPE *ts_obj = this->ts_value (); + this->ts_value (0); +# if !defined ACE_HAS_LYNXOS_178 || defined ACE_HAS_TSS_EMULATION + // A bug in LynxOS-178 causes pthread_setspecific (called from ts_value(0) + // above) to call the cleanup function, so we need to avoid calling it here. + ACE_TSS::cleanup (ts_obj); +# else + ACE_UNUSED_ARG (ts_obj); +# endif +# endif /* ACE_HAS_THR_C_DEST */ + + ACE_OS::thr_key_detach (this->key_); + ACE_OS::thr_keyfree (this->key_); + } +#else // defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) + // We own it, we need to delete it. + delete type_; +#endif // defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) +} + +template TYPE * +ACE_TSS::operator-> () const +{ + return this->ts_get (); +} + +template +ACE_TSS::operator TYPE *(void) const +{ + return this->ts_get (); +} + +template TYPE * +ACE_TSS::make_TSS_TYPE (void) const +{ + TYPE *temp = 0; + ACE_NEW_RETURN (temp, + TYPE, + 0); + return temp; +} + +template void +ACE_TSS::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + this->keylock_.dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("key_ = %d\n"), this->key_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nonce_ = %d\n"), this->once_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */ +#endif /* ACE_HAS_DUMP */ +} + +#if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) + +template void +ACE_TSS::cleanup (void *ptr) +{ + // Cast this to the concrete TYPE * so the destructor gets called. + delete (TYPE *) ptr; +} + +template int +ACE_TSS::ts_init (void) +{ + // Ensure that we are serialized! + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->keylock_, 0); + + // Use the Double-Check pattern to make sure we only create the key + // once! + if (!this->once_) + { + if (ACE_Thread::keycreate (&this->key_, +#if defined (ACE_HAS_THR_C_DEST) + &ACE_TSS_C_cleanup +#else + &ACE_TSS::cleanup +#endif /* ACE_HAS_THR_C_DEST */ + ) != 0) + return -1; // Major problems, this should *never* happen! + else + { + // This *must* come last to avoid race conditions! + this->once_ = true; + return 0; + } + } + + return 0; +} + +template +ACE_TSS::ACE_TSS (TYPE *ts_obj) + : once_ (false), + key_ (ACE_OS::NULL_key) +{ + // If caller has passed us a non-NULL TYPE *, then we'll just use + // this to initialize the thread-specific value. Thus, subsequent + // calls to operator->() will return this value. This is useful + // since it enables us to assign objects to thread-specific data + // that have arbitrarily complex constructors! + + if (ts_obj != 0) + { + if (this->ts_init () == -1) + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + // What should we do if this call fails?! +#if defined (ACE_HAS_WINCE) + ::MessageBox (0, + ACE_TEXT ("ACE_Thread::keycreate() failed!"), + ACE_TEXT ("ACE_TSS::ACE_TSS"), + MB_OK); +#elif !defined (ACE_LACKS_VA_FUNCTIONS) + ACE_OS::fprintf (stderr, + "ACE_Thread::keycreate() failed!"); +#endif /* ACE_HAS_WINCE */ + return; + } + +#if defined (ACE_HAS_THR_C_DEST) + // Encapsulate a ts_obj and it's destructor in an + // ACE_TSS_Adapter. + ACE_TSS_Adapter *tss_adapter = 0; + ACE_NEW (tss_adapter, + ACE_TSS_Adapter ((void *) ts_obj, + ACE_TSS::cleanup)); + + // Put the adapter in thread specific storage + if (this->ts_value (tss_adapter) == -1) + { + delete tss_adapter; + } +#else + this->ts_value (ts_obj); +#endif /* ACE_HAS_THR_C_DEST */ + } +} + +template TYPE * +ACE_TSS::ts_get (void) const +{ + if (!this->once_) + { + // Create and initialize thread-specific ts_obj. + if (const_cast< ACE_TSS < TYPE > * >(this)->ts_init () == -1) + // Seriously wrong.. + return 0; + } + + TYPE *ts_obj = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = this->ts_value (); + ACE_TSS_Adapter *fake_tss_adapter = 0; + + // If tss_adapter is not 0 but its ts_obj_ is 0 then we still need to create + // a proper ts_obj. That's the intent of this member function. + if (tss_adapter != 0 && tss_adapter->ts_obj_ == 0) + { + fake_tss_adapter = tss_adapter; + tss_adapter = 0; + } + + // Check to see if this is the first time in for this thread. + if (tss_adapter == 0) +#else + ts_obj = this->ts_value (); + + // Check to see if this is the first time in for this thread. + if (ts_obj == 0) +#endif /* ACE_HAS_THR_C_DEST */ + { + // Allocate memory off the heap and store it in a pointer in + // thread-specific storage (on the stack...). + + ts_obj = this->make_TSS_TYPE (); + + if (ts_obj == 0) + return 0; + +#if defined (ACE_HAS_THR_C_DEST) + // Encapsulate a ts_obj and it's destructor in an + // ACE_TSS_Adapter. + ACE_NEW_RETURN (tss_adapter, + ACE_TSS_Adapter (ts_obj, + ACE_TSS::cleanup), 0); + + // Put the adapter in thread specific storage + if (this->ts_value (tss_adapter) == -1) + { + delete tss_adapter; + delete ts_obj; + return 0; // Major problems, this should *never* happen! + } +#else + // Store the dynamically allocated pointer in thread-specific + // storage. + if (this->ts_value (ts_obj) == -1) + { + delete ts_obj; + return 0; // Major problems, this should *never* happen! + } +#endif /* ACE_HAS_THR_C_DEST */ + } + +#if defined (ACE_HAS_THR_C_DEST) + // Delete the adapter that didn't actually have a real ts_obj. + delete fake_tss_adapter; + // Return the underlying ts object. + return static_cast (tss_adapter->ts_obj_); +#else + return ts_obj; +#endif /* ACE_HAS_THR_C_DEST */ +} + +// Get the thread-specific object for the key associated with this +// object. Returns 0 if the ts_obj has never been initialized, +// otherwise returns a pointer to the ts_obj. + +template TYPE * +ACE_TSS::ts_object (void) const +{ + if (!this->once_) // Return 0 if we've never been initialized. + return 0; + + TYPE *ts_obj = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = this->ts_value (); + + if (tss_adapter != 0) + { + // Extract the real TS object. + ts_obj = static_cast (tss_adapter->ts_obj_); + } +#else + ts_obj = this->ts_value (); +#endif /* ACE_HAS_THR_C_DEST */ + + return ts_obj; +} + +template TYPE * +ACE_TSS::ts_object (TYPE *new_ts_obj) +{ + // Note, we shouldn't hold the keylock at this point because + // does it for us and we'll end up with deadlock + // otherwise... + if (!this->once_) + { + // Create and initialize thread-specific ts_obj. + if (this->ts_init () == -1) + return 0; + } + + TYPE *ts_obj = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = this->ts_value (); + + if (tss_adapter != 0) + { + ts_obj = static_cast (tss_adapter->ts_obj_); + // Don't delete tss_adapter yet. It can be double-deleted + // in case setspecific below fails. + } + + ACE_TSS_Adapter *new_tss_adapter = 0; + ACE_NEW_RETURN (new_tss_adapter, + ACE_TSS_Adapter ((void *) new_ts_obj, + ACE_TSS::cleanup), + 0); + + if (this->ts_value (new_tss_adapter) == -1) + { + delete new_tss_adapter; + } + else + { + // Now it's fine to delete the old tss_adapter. + delete tss_adapter; + } +#else + ts_obj = this->ts_value (); + this->ts_value (new_ts_obj); +#endif /* ACE_HAS_THR_C_DEST */ + + return ts_obj; +} + +ACE_ALLOC_HOOK_DEFINE_Tc(ACE_TSS_Guard) + +template void +ACE_TSS_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("key_ = %d\n"), this->key_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +template void +ACE_TSS_Guard::init_key (void) +{ + this->key_ = ACE_OS::NULL_key; + ACE_Thread::keycreate (&this->key_, +#if defined (ACE_HAS_THR_C_DEST) + &ACE_TSS_C_cleanup +#else + &ACE_TSS_Guard::cleanup +#endif /* ACE_HAS_THR_C_DEST */ + ); +} + +template +ACE_TSS_Guard::ACE_TSS_Guard (void) +{ + this->init_key (); +} + +template int +ACE_TSS_Guard::release (void) +{ + Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->release (); +} + +template int +ACE_TSS_Guard::remove (void) +{ + Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->remove (); +} + +template +ACE_TSS_Guard::~ACE_TSS_Guard (void) +{ + Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + // Make sure that this pointer is NULL when we shut down... + ACE_Thread::setspecific (this->key_, 0); + ACE_Thread::keyfree (this->key_); + // Destructor releases lock. + delete guard; +} + +template void +ACE_TSS_Guard::cleanup (void *ptr) +{ + // Destructor releases lock. + delete (Guard_Type *) ptr; +} + +template +ACE_TSS_Guard::ACE_TSS_Guard (ACE_LOCK &lock, bool block) +{ + this->init_key (); + Guard_Type *guard = 0; + ACE_NEW (guard, + Guard_Type (lock, block)); + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + ACE_NEW (tss_adapter, + ACE_TSS_Adapter ((void *) guard, + ACE_TSS_Guard::cleanup)); + ACE_Thread::setspecific (this->key_, + (void *) tss_adapter); +#else + ACE_Thread::setspecific (this->key_, + (void *) guard); +#endif /* ACE_HAS_THR_C_DEST */ +} + +template int +ACE_TSS_Guard::acquire (void) +{ + Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->acquire (); +} + +template int +ACE_TSS_Guard::tryacquire (void) +{ + Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->tryacquire (); +} + +template +ACE_TSS_Write_Guard::ACE_TSS_Write_Guard (ACE_LOCK &lock, + bool block) +{ + this->init_key (); + Guard_Type *guard = 0; + ACE_NEW (guard, + Write_Guard_Type (lock, block)); + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + ACE_NEW (tss_adapter, + ACE_TSS_Adapter ((void *) guard, + ACE_TSS_Guard::cleanup)); + ACE_Thread::setspecific (this->key_, (void *) tss_adapter); +#else + ACE_Thread::setspecific (this->key_, (void *) guard); +#endif /* ACE_HAS_THR_C_DEST */ +} + +template int +ACE_TSS_Write_Guard::acquire (void) +{ + Write_Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->acquire_write (); +} + +template int +ACE_TSS_Write_Guard::tryacquire (void) +{ + Write_Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->tryacquire_write (); +} + +template int +ACE_TSS_Write_Guard::acquire_write (void) +{ + return this->acquire (); +} + +template int +ACE_TSS_Write_Guard::tryacquire_write (void) +{ + return this->tryacquire (); +} + +template void +ACE_TSS_Write_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TSS_Guard::dump (); +#endif /* ACE_HAS_DUMP */ +} + +template +ACE_TSS_Read_Guard::ACE_TSS_Read_Guard (ACE_LOCK &lock, bool block) +{ + this->init_key (); + Guard_Type *guard = 0; + ACE_NEW (guard, + Read_Guard_Type (lock, block)); +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter; + ACE_NEW (tss_adapter, + ACE_TSS_Adapter ((void *)guard, + ACE_TSS_Guard::cleanup)); + ACE_Thread::setspecific (this->key_, + (void *) tss_adapter); +#else + ACE_Thread::setspecific (this->key_, + (void *) guard); +#endif /* ACE_HAS_THR_C_DEST */ +} + +template int +ACE_TSS_Read_Guard::acquire (void) +{ + Read_Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->acquire_read (); +} + +template int +ACE_TSS_Read_Guard::tryacquire (void) +{ + Read_Guard_Type *guard = 0; + +#if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *tss_adapter = 0; + void *temp = tss_adapter; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + tss_adapter = static_cast (temp); + guard = static_cast (tss_adapter->ts_obj_); +#else + void *temp = guard; // Need this temp to keep G++ from complaining. + ACE_Thread::getspecific (this->key_, &temp); + guard = static_cast (temp); +#endif /* ACE_HAS_THR_C_DEST */ + + return guard->tryacquire_read (); +} + +template int +ACE_TSS_Read_Guard::acquire_read (void) +{ + return this->acquire (); +} + +template int +ACE_TSS_Read_Guard::tryacquire_read (void) +{ + return this->tryacquire (); +} + +template void +ACE_TSS_Read_Guard::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TSS_Guard::dump (); +#endif /* ACE_HAS_DUMP */ +} + +#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TSS_T_CPP */ diff --git a/dep/acelite/ace/TSS_T.h b/dep/acelite/ace/TSS_T.h new file mode 100644 index 000000000..d3097d544 --- /dev/null +++ b/dep/acelite/ace/TSS_T.h @@ -0,0 +1,266 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file TSS_T.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_TSS_T_H +#define ACE_TSS_T_H +#include /**/ "ace/pre.h" + +#include "ace/Lock.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +// This should probably go somewhere else, but it's only used here and +// in Thread_Manager. +// Note there is no ACE_TSS_SET because one would typically do +// 'ACE_TSS_GET()->xyz_ = value', so the macro would have been too +// complicated. +# if defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) +# define ACE_TSS_TYPE(T) ACE_TSS< T > +# define ACE_TSS_GET(I, T) ((I)->operator T * ()) +# else +# define ACE_TSS_TYPE(T) T +# define ACE_TSS_GET(I, T) (I) +# endif /* ACE_HAS_THREADS && (ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION) */ + +#include "ace/Thread_Mutex.h" +#include "ace/Copy_Disabled.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_THR_C_DEST) +class ACE_TSS_Adapter; +#endif + +/** + * @class ACE_TSS + * + * @brief Allows objects that are "physically" in thread specific + * storage (i.e., private to a thread) to be accessed as though + * they were "logically" global to a program. + * + * This class helps to maintain a separate copy of an object for each thread + * that needs access to it. All threads access a single instance of ACE_TSS + * to obtain a pointer to a thread-specific copy of a TYPE object. Using + * a pointer to TYPE in TSS instead of TYPE itself is useful because, + * in addition to avoiding copies on what may be a complex class, it allows + * assignment of objects to thread-specific data that have arbitrarily + * complex constructors. + * + * When the ACE_TSS object is destroyed, all threads's instances of the + * data are deleted. + * + * Modern compilers have no problem using a built-in type for @c TYPE. + * However, if you must use an older compiler that won't work with a built-in + * type, the ACE_TSS_Type_Adapter class template, below, can be used for + * adapting built-in types to work with ACE_TSS. + * + * @note Beware when creating static instances of this type + * (as with any other, btw). The unpredictable order of initialization + * across different platforms may cause a situation where one uses + * the instance before it is fully initialized. That's why typically + * instances of this type are dynamicaly allocated. On the stack it is + * typically allocated inside the ACE_Thread::svc() method which + * limits its lifetime appropriately. + */ +template +class ACE_TSS : private ACE_Copy_Disabled +{ +public: + /** + * Default constructor. Can also initialize this ACE_TSS instance, + * readying it for use by the calling thread as well as all other + * threads in the process. If the constructor does not initialize this + * object, the first access to it will perform the initialization, which + * could possibly (under odd error conditions) fail. + * + * @param ts_obj If non-zero, this object is initialized for use by + * all threads and @a ts_obj is used to set the + * thread-specific value for the calling thread. Other + * threads use the ts_object (TYPE *) method to set + * a specific value. + */ + ACE_TSS (TYPE *ts_obj = 0); + + /// Deregister this object from thread-specific storage administration. + /// Will cause all threads' copies of TYPE to be destroyed. + virtual ~ACE_TSS (void); + + /** + * Set the thread-specific object for the calling thread. + * If this object has not been initialized yet, this method performs the + * initialization. + * + * @param new_ts_obj The new value for the calling thread's copy of + * this object. + * + * @return The previous value of the calling thread's copy of this + * object; 0 if there was no previous value. This method also + * returns 0 on errors. To tell the difference between an error + * and a returned 0 pointer, it's recommended that one set errno + * to 0 prior to calling ts_object() and check for a new errno + * value if ts_object() returns 0. + */ + TYPE *ts_object (TYPE *new_ts_obj); + + /** @name Accessors + * + * All accessors return a pointer to the calling thread's copy of the + * TYPE data. The pointer may be 0 on error conditions or if the calling + * thread's copy of the data has not yet been set. See specific method + * descriptions for complete details. + */ + //@{ + /** + * Get the thread-specific object for this object. + * + * @return 0 if the object has never been initialized, otherwise returns + * the calling thread's copy of the data. The returned pointer + * may be 0 under odd error conditions; check errno for further + * information. + */ + TYPE *ts_object (void) const; + + /** + * Use a "smart pointer" to get the thread-specific data associated + * with this object. + * If this ACE_TSS object hasn't been initialized, this method + * will initialize it as a side-affect. If the calling thread has not + * set a value, a default-constructed instance of TYPE is allocated and it + * becomes the thread's instance. + * + * @return The calling thread's copy of the data. The returned pointer + * may be 0 under odd error conditions; check errno for further + * information. + */ + TYPE *operator-> () const; + + /** + * Obtain a pointer to the calling thread's TYPE object. + * If this ACE_TSS object hasn't been initialized, this method + * will initialize it as a side-affect. If the calling thread has not + * set a value, a default-constructed instance of TYPE is allocated and it + * becomes the thread's instance. + * + * @return The calling thread's copy of the data. The returned pointer + * may be 0 under odd error conditions; check errno for further + * information. + */ + operator TYPE *(void) const; + + //@} + + /// Hook for construction parameters. + virtual TYPE *make_TSS_TYPE (void) const; + + // = Utility methods. + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Actually implements the code that retrieves the object from + /// thread-specific storage. + TYPE *ts_get (void) const; + + /// Factors out common code for initializing TSS. This must NOT be + /// called with the lock held... + int ts_init (void); + +#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) + /// This implementation only works for non-threading systems... + TYPE *type_; +#else + /// Avoid race conditions during initialization. + ACE_Thread_Mutex keylock_; + + /// "First time in" flag. + volatile bool once_; + + /// Key for the thread-specific error data. + ACE_thread_key_t key_; + + /// "Destructor" that deletes internal TYPE * when thread exits. + static void cleanup (void *ptr); + + /// Obtains a plain value stored in the thread-specific storage. +# if defined (ACE_HAS_THR_C_DEST) + ACE_TSS_Adapter *ts_value (void) const; +# else + TYPE *ts_value (void) const; +# endif /* ACE_HAS_THR_C_DEST */ + + /// Stores a new plain value in the thread-specific storage. +# if defined (ACE_HAS_THR_C_DEST) + int ts_value (ACE_TSS_Adapter *new_tss_adapter) const; +# else + int ts_value (TYPE *new_ts_obj) const; +# endif /* ACE_HAS_THR_C_DEST */ +#endif /* defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION)) */ +}; + +/** + * @class ACE_TSS_Type_Adapter + * + * @brief Adapter that allows built-in types to be used with ACE_TSS. + * + * Wraps a value of a built-in type, providing conversions to + * and from the type. Example use with ACE_TSS: + * ACE_TSS > i; + * *i = 37; + * ACE_OS::fprintf (stderr, "%d\n", *i); + * Unfortunately, though, some compilers have trouble with the + * implicit type conversions. This seems to work better: + * ACE_TSS > i; + * i->operator int & () = 37; + * ACE_OS::fprintf (stderr, "%d\n", i->operator int ()); + */ +template +class ACE_TSS_Type_Adapter +{ +public: + /// Constructor. Inlined here so that it should _always_ be inlined. + ACE_TSS_Type_Adapter (const TYPE value = 0): value_ (value) {} + + /// TYPE conversion. Inlined here so that it should _always_ be + /// inlined. + operator TYPE () const { return value_; }; + + /// TYPE & conversion. Inlined here so that it should _always_ be + /// inlined. + operator TYPE &() { return value_; }; + +private: + /// The wrapped value. + TYPE value_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/TSS_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/TSS_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("TSS_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_TSS_T_H */ diff --git a/dep/acelite/ace/TSS_T.inl b/dep/acelite/ace/TSS_T.inl new file mode 100644 index 000000000..7e68976c8 --- /dev/null +++ b/dep/acelite/ace/TSS_T.inl @@ -0,0 +1,100 @@ +// -*- C++ -*- +#include "ace/Thread.h" +#include "ace/Log_Category.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +#if !(defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) + +template ACE_INLINE +ACE_TSS::ACE_TSS (TYPE *type) + : type_ (type) +{ +} + +template ACE_INLINE int +ACE_TSS::ts_init (void) +{ + return 0; +} + +template ACE_INLINE TYPE * +ACE_TSS::ts_object (void) const +{ + return this->type_; +} + +template ACE_INLINE TYPE * +ACE_TSS::ts_object (TYPE *type) +{ + this->type_ = type; + return this->type_; +} + +template ACE_INLINE TYPE * +ACE_TSS::ts_get (void) const +{ + return this->type_; +} + +#else + +# if defined (ACE_HAS_THR_C_DEST) +template ACE_INLINE ACE_TSS_Adapter * +ACE_TSS::ts_value (void) const +{ + // Get the tss adapter from thread-specific storage + void *temp = 0; + if (ACE_Thread::getspecific (this->key_, &temp) == -1) + { + return 0; // This should not happen! + } + return static_cast (temp); +} +# else +template ACE_INLINE TYPE * +ACE_TSS::ts_value (void) const +{ + void *temp = 0; + if (ACE_Thread::getspecific (this->key_, &temp) == -1) + { + return 0; // This should not happen! + } + return static_cast (temp); +} +# endif /* ACE_HAS_THR_C_DEST */ + +# if defined (ACE_HAS_THR_C_DEST) +template ACE_INLINE int +ACE_TSS::ts_value (ACE_TSS_Adapter *new_tss_adapter) const +{ + if (ACE_Thread::setspecific (this->key_, + (void *) new_tss_adapter) != 0) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Error: ACE_Thread::setspecific() failed!"))); + return -1; + } + + return 0; +} +# else +template ACE_INLINE int +ACE_TSS::ts_value (TYPE *new_ts_obj) const +{ + if (ACE_Thread::setspecific (this->key_, (void *) new_ts_obj) != 0) + { + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("Error: ACE_Thread::setspecific() failed!"))); + return -1; + } + + return 0; +} +# endif /* ACE_HAS_THR_C_DEST */ + +#endif /* ! (defined (ACE_HAS_THREADS) && (defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION))) */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/TTY_IO.cpp b/dep/acelite/ace/TTY_IO.cpp new file mode 100644 index 000000000..53c56badd --- /dev/null +++ b/dep/acelite/ace/TTY_IO.cpp @@ -0,0 +1,710 @@ +#include "ace/TTY_IO.h" +#include "ace/OS_NS_errno.h" +#include "ace/OS_NS_string.h" +#include "ace/OS_NS_strings.h" + +#if defined (ACE_HAS_TERMIOS) +# include "ace/os_include/os_termios.h" +#elif defined (ACE_HAS_TERMIO) +# include +#endif + +namespace +{ + const char ACE_TTY_IO_NONE[] = "none"; +#if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO) || defined (ACE_WIN32) + const char ACE_TTY_IO_ODD[] = "odd"; + const char ACE_TTY_IO_EVEN[] = "even"; +#endif +#if defined (ACE_WIN32) + const char ACE_TTY_IO_MARK[] = "mark"; + const char ACE_TTY_IO_SPACE[] = "space"; +#endif /* ACE_WIN32 */ +} + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_TTY_IO::ACE_TTY_IO (void) +{ +} + +ACE_TTY_IO::Serial_Params::Serial_Params (void) +{ + baudrate = 9600; + xonlim = 0; + xofflim = 0; + readmincharacters = 0; + readtimeoutmsec = 10000; + paritymode = ACE_TTY_IO_NONE; + ctsenb = false; + rtsenb = 0; + xinenb = false; + xoutenb = false; + modem = false; + rcvenb = true; + dsrenb = false; + dtrdisable = false; + databits = 8; + stopbits = 1; +} + +// Interface for reading/writing serial device parameters + +int ACE_TTY_IO::control (Control_Mode cmd, Serial_Params *arg) const +{ +#if defined (ACE_HAS_TERMIOS) || defined (ACE_HAS_TERMIO) + +#if defined (ACE_HAS_TERMIOS) + struct termios devpar; + speed_t newbaudrate = 0; + if (tcgetattr (get_handle () , &devpar) == -1) +#elif defined (TCGETS) + struct termios devpar; + unsigned int newbaudrate = 0; + if (this->ACE_IO_SAP::control (TCGETS, static_cast(&devpar)) == -1) +#elif defined (TCGETA) + struct termio devpar; + unsigned int newbaudrate = 0; + if (this->ACE_IO_SAP::control (TCGETA, static_cast(&devpar)) == -1) +#else + errno = ENOSYS; +#endif /* ACE_HAS_TERMIOS */ + return -1; + + switch (cmd) + { + case SETPARAMS: + switch (arg->baudrate) + { +#if defined (B0) + case 0: newbaudrate = B0; break; +#endif /* B0 */ +#if defined (B50) + case 50: newbaudrate = B50; break; +#endif /* B50 */ +#if defined (B75) + case 75: newbaudrate = B75; break; +#endif /* B75 */ +#if defined (B110) + case 110: newbaudrate = B110; break; +#endif /* B110 */ +#if defined (B134) + case 134: newbaudrate = B134; break; +#endif /* B134 */ +#if defined (B150) + case 150: newbaudrate = B150; break; +#endif /* B150 */ +#if defined (B200) + case 200: newbaudrate = B200; break; +#endif /* B200 */ +#if defined (B300) + case 300: newbaudrate = B300; break; +#endif /* B300 */ +#if defined (B600) + case 600: newbaudrate = B600; break; +#endif /* B600 */ +#if defined (B1200) + case 1200: newbaudrate = B1200; break; +#endif /* B1200 */ +#if defined (B1800) + case 1800: newbaudrate = B1800; break; +#endif /* B1800 */ +#if defined (B2400) + case 2400: newbaudrate = B2400; break; +#endif /* B2400 */ +#if defined (B4800) + case 4800: newbaudrate = B4800; break; +#endif /* B4800 */ +#if defined (B9600) + case 9600: newbaudrate = B9600; break; +#endif /* B9600 */ +#if defined (B19200) + case 19200: newbaudrate = B19200; break; +#endif /* B19200 */ +#if defined (B38400) + case 38400: newbaudrate = B38400; break; +#endif /* B38400 */ +#if defined (B56000) + case 56000: newbaudrate = B56000; break; +#endif /* B56000 */ +#if defined (B57600) + case 57600: newbaudrate = B57600; break; +#endif /* B57600 */ +#if defined (B76800) + case 76800: newbaudrate = B76800; break; +#endif /* B76800 */ +#if defined (B115200) + case 115200: newbaudrate = B115200; break; +#endif /* B115200 */ +#if defined (B128000) + case 128000: newbaudrate = B128000; break; +#endif /* B128000 */ +#if defined (B153600) + case 153600: newbaudrate = B153600; break; +#endif /* B153600 */ +#if defined (B230400) + case 230400: newbaudrate = B230400; break; +#endif /* B230400 */ +#if defined (B307200) + case 307200: newbaudrate = B307200; break; +#endif /* B307200 */ +#if defined (B256000) + case 256000: newbaudrate = B256000; break; +#endif /* B256000 */ +#if defined (B460800) + case 460800: newbaudrate = B460800; break; +#endif /* B460800 */ +#if defined (B500000) + case 500000: newbaudrate = B500000; break; +#endif /* B500000 */ +#if defined (B576000) + case 576000: newbaudrate = B576000; break; +#endif /* B576000 */ +#if defined (B921600) + case 921600: newbaudrate = B921600; break; +#endif /* B921600 */ +#if defined (B1000000) + case 1000000: newbaudrate = B1000000; break; +#endif /* B1000000 */ +#if defined (B1152000) + case 1152000: newbaudrate = B1152000; break; +#endif /* B1152000 */ +#if defined (B1500000) + case 1500000: newbaudrate = B1500000; break; +#endif /* B1500000 */ +#if defined (B2000000) + case 2000000: newbaudrate = B2000000; break; +#endif /* B2000000 */ +#if defined (B2500000) + case 2500000: newbaudrate = B2500000; break; +#endif /* B2500000 */ +#if defined (B3000000) + case 3000000: newbaudrate = B3000000; break; +#endif /* B3000000 */ +#if defined (B3500000) + case 3500000: newbaudrate = B3500000; break; +#endif /* B3500000 */ +#if defined (B4000000) + case 4000000: newbaudrate = B4000000; break; +#endif /* B4000000 */ + default: + return -1; + } + +#if defined (ACE_HAS_TERMIOS) + // Can you really have different input and output baud rates?! + if (cfsetospeed (&devpar, newbaudrate) == -1) + return -1; + if (cfsetispeed (&devpar, newbaudrate) == -1) + return -1; +#else + devpar.c_cflag &= ~CBAUD; +# if defined (CBAUDEX) + devpar.c_cflag &= ~CBAUDEX; +# endif /* CBAUDEX */ + devpar.c_cflag |= newbaudrate; +#endif /* ACE_HAS_TERMIOS */ + + devpar.c_cflag &= ~CSIZE; + switch (arg->databits) + { + case 5: + devpar.c_cflag |= CS5; + break; + case 6: + devpar.c_cflag |= CS6; + break; + case 7: + devpar.c_cflag |= CS7; + break; + case 8: + devpar.c_cflag |= CS8; + break; + default: + return -1; + } + + switch (arg->stopbits) + { + case 1: + devpar.c_cflag &= ~CSTOPB; + break; + case 2: + devpar.c_cflag |= CSTOPB; + break; + default: + return -1; + } + + if (arg->paritymode) + { + if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0) + { + devpar.c_cflag |= PARENB; + devpar.c_cflag |= PARODD; + devpar.c_iflag &= ~IGNPAR; + devpar.c_iflag |= INPCK | PARMRK; + } + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0) + { + devpar.c_cflag |= PARENB; + devpar.c_cflag &= ~PARODD; + devpar.c_iflag &= ~IGNPAR; + devpar.c_iflag |= INPCK | PARMRK; + } + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0) + { + devpar.c_cflag &= ~PARENB; + } + else + { + return -1; + } + } + else + { + devpar.c_cflag &= ~PARENB; + } + +#if defined (CNEW_RTSCTS) + if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol + devpar.c_cflag |= CNEW_RTSCTS; + else + devpar.c_cflag &= ~CNEW_RTSCTS; +#elif defined (CRTSCTS) + if ((arg->ctsenb) || (arg->rtsenb)) // Enable RTS/CTS protocol + devpar.c_cflag |= CRTSCTS; + else + devpar.c_cflag &= ~CRTSCTS; +#endif /* NEW_RTSCTS || CRTSCTS */ + +#if defined (CREAD) + // Enable/disable receiver + if (arg->rcvenb) + devpar.c_cflag |= CREAD; + else + devpar.c_cflag &= ~CREAD; +#endif /* CREAD */ + +#if defined (HUPCL) + // Cause DTR to drop after port close. + devpar.c_cflag |= HUPCL; +#endif /* HUPCL */ + +#if defined (CLOCAL) + // If device is not a modem set to local device. + if (arg->modem) + devpar.c_cflag &= ~CLOCAL; + else + devpar.c_cflag |= CLOCAL; +#endif /* CLOCAL */ + + if (arg->databits < 8) + devpar.c_iflag |= ISTRIP; + +#if defined (IGNBRK) + // If device is not a modem set to ignore break points + if(arg->modem) + devpar.c_iflag &= ~IGNBRK; + else + devpar.c_iflag |= IGNBRK; +#endif /* IGNBRK */ + +#if defined (IXOFF) + // Enable/disable software flow control on input + if (arg->xinenb) + devpar.c_iflag |= IXOFF; + else + devpar.c_iflag &= ~IXOFF; +#endif /* IXOFF */ + +#if defined (IXON) + // Enable/disable software flow control on output + if (arg->xoutenb) + devpar.c_iflag |= IXON; + else + devpar.c_iflag &= ~IXON; +#endif /* IXON */ + +#if defined (ICANON) + // Enable noncanonical input processing mode + devpar.c_lflag &= ~ICANON; +#endif /* ICANON */ + +#if defined (ECHO) + // Disable echoing of input characters + devpar.c_lflag &= ~ECHO; +#endif /* ECHO */ + +#if defined (ECHOE) + // Disable echoing erase chareacter as BS-SP-BS + devpar.c_lflag &= ~ECHOE; +#endif /* ECHOE */ + +#if defined (ISIG) + // Disable SIGINTR, SIGSUSP, SIGDSUSP and SIGQUIT signals + devpar.c_lflag &= ~ISIG; +#endif /* ISIG */ + +#if defined (OPOST) + // Disable post-processing of output data + devpar.c_oflag &= ~OPOST; +#endif /* OPOST */ + + if (arg->readtimeoutmsec < 0) + { + // Settings for infinite timeout. + devpar.c_cc[VTIME] = 0; + // In case of infinite timeout [VMIN] must be at least 1. + if (arg->readmincharacters > UCHAR_MAX) + devpar.c_cc[VMIN] = UCHAR_MAX; + else if (arg->readmincharacters < 1) + devpar.c_cc[VMIN] = 1; + else + devpar.c_cc[VMIN] = static_cast(arg->readmincharacters); + } + else + { + devpar.c_cc[VTIME] = static_cast(arg->readtimeoutmsec / 100); + + if (arg->readmincharacters > UCHAR_MAX) + devpar.c_cc[VMIN] = UCHAR_MAX; + else if (arg->readmincharacters < 1) + devpar.c_cc[VMIN] = 0; + else + devpar.c_cc[VMIN] = static_cast(arg->readmincharacters); + } + +#if defined (TIOCMGET) + int status; + this->ACE_IO_SAP::control (TIOCMGET, &status); + + if (arg->dtrdisable) + status &= ~TIOCM_DTR; + else + status |= TIOCM_DTR; + + this->ACE_IO_SAP::control (TIOCMSET, &status); +#endif /* definded (TIOCMGET) */ + +#if defined (ACE_HAS_TERMIOS) + return tcsetattr (get_handle (), TCSANOW, &devpar); +#elif defined (TCSETS) + return this->ACE_IO_SAP::control (TCSETS, static_cast(&devpar)); +#elif defined (TCSETA) + return this->ACE_IO_SAP::control (TCSETA, static_cast(&devpar)); +#else + errno = ENOSYS; + return -1; +#endif /* ACE_HAS_TERMIOS */ + + case GETPARAMS: + return -1; // Not yet implemented. + default: + return -1; // Wrong cmd. + } +#elif defined (ACE_WIN32) + DCB dcb; + dcb.DCBlength = sizeof dcb; + if (!::GetCommState (this->get_handle (), &dcb)) + { + ACE_OS::set_errno_to_last_error (); + return -1; + } + + COMMTIMEOUTS timeouts; + if (!::GetCommTimeouts (this->get_handle(), &timeouts)) + { + ACE_OS::set_errno_to_last_error (); + return -1; + } + + switch (cmd) + { + case SETPARAMS: + dcb.BaudRate = arg->baudrate; + + switch (arg->databits) + { + case 4: + case 5: + case 6: + case 7: + case 8: + dcb.ByteSize = arg->databits; + break; + default: + return -1; + } + + switch (arg->stopbits) + { + case 1: + dcb.StopBits = ONESTOPBIT; + break; + case 2: + dcb.StopBits = TWOSTOPBITS; + break; + default: + return -1; + } + + if (arg->paritymode) + { + dcb.fParity = TRUE; + if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_ODD) == 0) + dcb.Parity = ODDPARITY; + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_EVEN) == 0) + dcb.Parity = EVENPARITY; + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_NONE) == 0) + dcb.Parity = NOPARITY; + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_MARK) == 0) + dcb.Parity = MARKPARITY; + else if (ACE_OS::strcasecmp (arg->paritymode, ACE_TTY_IO_SPACE) == 0) + dcb.Parity = SPACEPARITY; + else + return -1; + } + else + { + dcb.fParity = FALSE; + dcb.Parity = NOPARITY; + } + + // Enable/disable RTS protocol. + switch (arg->rtsenb) + { + case 1: + dcb.fRtsControl = RTS_CONTROL_ENABLE; + break; + case 2: + dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; + break; + case 3: + dcb.fRtsControl = RTS_CONTROL_TOGGLE; + break; + default: + dcb.fRtsControl = RTS_CONTROL_DISABLE; + } + + // Enable/disable CTS protocol. + if (arg->ctsenb) + dcb.fOutxCtsFlow = TRUE; + else + dcb.fOutxCtsFlow = FALSE; + + // Enable/disable DSR protocol. + if (arg->dsrenb) + dcb.fOutxDsrFlow = TRUE; + else + dcb.fOutxDsrFlow = FALSE; + + // Disable/enable DTR protocol + if (arg->dtrdisable) + dcb.fDtrControl = DTR_CONTROL_DISABLE; + else + dcb.fDtrControl = DTR_CONTROL_ENABLE; + + // Enable/disable software flow control on input + if (arg->xinenb) + dcb.fInX = TRUE; + else + dcb.fInX = FALSE; + + // Enable/disable software flow control on output + if (arg->xoutenb) + dcb.fOutX = TRUE; + else + dcb.fOutX = FALSE; + + // Always set limits unless set to negative to use default. + if (arg->xonlim >= 0) + dcb.XonLim = static_cast(arg->xonlim); + if (arg->xofflim >= 0) + dcb.XoffLim = static_cast(arg->xofflim); + + dcb.fAbortOnError = FALSE; + dcb.fErrorChar = FALSE; + dcb.fNull = FALSE; + dcb.fBinary = TRUE; + + if (!::SetCommState (this->get_handle (), &dcb)) + { + ACE_OS::set_errno_to_last_error (); + return -1; + } + + if (arg->readtimeoutmsec < 0) + { + // Settings for infinite timeout. + timeouts.ReadIntervalTimeout = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + } + else if (arg->readtimeoutmsec == 0) + { + // Return immediately if no data in the input buffer. + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + } + else + { + // Wait for specified timeout for char to arrive before returning. + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; + timeouts.ReadTotalTimeoutConstant = arg->readtimeoutmsec; + } + + if (!::SetCommTimeouts (this->get_handle (), &timeouts)) + { + ACE_OS::set_errno_to_last_error (); + return -1; + } + + return 0; + + case GETPARAMS: + arg->baudrate = dcb.BaudRate; + + switch (dcb.ByteSize) + { + case 4: + case 5: + case 6: + case 7: + case 8: + arg->databits = dcb.ByteSize; + break; + default: + return -1; + } + + switch (dcb.StopBits) + { + case ONESTOPBIT: + arg->stopbits = 1; + break; + case TWOSTOPBITS: + arg->stopbits = 2; + break; + default: + return -1; + } + + if (!dcb.fParity) + { + arg->paritymode = ACE_TTY_IO_NONE; + } + else + { + switch (dcb.Parity) + { + case ODDPARITY: + arg->paritymode = ACE_TTY_IO_ODD; + break; + case EVENPARITY: + arg->paritymode = ACE_TTY_IO_EVEN; + break; + case NOPARITY: + arg->paritymode = ACE_TTY_IO_NONE; + break; + case MARKPARITY: + arg->paritymode = ACE_TTY_IO_MARK; + break; + case SPACEPARITY: + arg->paritymode = ACE_TTY_IO_SPACE; + break; + default: + return -1; + } + } + + // Enable/disable RTS protocol. + switch (dcb.fRtsControl) + { + case RTS_CONTROL_ENABLE: + arg->rtsenb = 1; + break; + case RTS_CONTROL_HANDSHAKE: + arg->rtsenb = 2; + break; + case RTS_CONTROL_TOGGLE: + arg->rtsenb = 3; + break; + case RTS_CONTROL_DISABLE: + arg->rtsenb = 0; + break; + default: + return -1; + } + + // Enable/disable CTS protocol. + if (dcb.fOutxCtsFlow) + arg->ctsenb = true; + else + arg->ctsenb = false; + + // Enable/disable DSR protocol. + if (dcb.fOutxDsrFlow) + arg->dsrenb = true; + else + arg->dsrenb = false; + + // Disable/enable DTR protocol + // Attention: DTR_CONTROL_HANDSHAKE is not supported. + switch (dcb.fDtrControl) + { + case DTR_CONTROL_DISABLE: + arg->dtrdisable = true; + break; + case DTR_CONTROL_ENABLE: + arg->dtrdisable = false; + break; + default: + return -1; + } + + // Enable/disable software flow control on input + if (dcb.fInX) + arg->xinenb = true; + else + arg->xinenb = false; + + // Enable/disable software flow control on output + if (dcb.fOutX) + arg->xoutenb = true; + else + arg->xoutenb = false; + + arg->xonlim = static_cast(dcb.XonLim); + arg->xofflim = static_cast(dcb.XoffLim); + + if (timeouts.ReadIntervalTimeout == 0 && + timeouts.ReadTotalTimeoutMultiplier == 0 && + timeouts.ReadTotalTimeoutConstant == 0) + arg->readtimeoutmsec = -1; + else + arg->readtimeoutmsec = timeouts.ReadTotalTimeoutConstant; + + return 0; + + default: + return -1; // Wrong cmd. + + } // arg switch +#else + ACE_UNUSED_ARG (cmd); + ACE_UNUSED_ARG (arg); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_TERMIOS || ACE_HAS_TERMIO */ +} + +#if defined (ACE_NEEDS_DEV_IO_CONVERSION) +ACE_TTY_IO::operator ACE_DEV_IO &() +{ + return static_cast(*this); +} +#endif /* ACE_NEEDS_DEV_IO_CONVERSION */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/TTY_IO.h b/dep/acelite/ace/TTY_IO.h new file mode 100644 index 000000000..860184d7d --- /dev/null +++ b/dep/acelite/ace/TTY_IO.h @@ -0,0 +1,113 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file TTY_IO.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_TTY_IO_H +#define ACE_TTY_IO_H + +#include "ace/DEV_IO.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_TTY_IO + * + * @brief Class definitions for platform specific TTY features. + * + * This class represents an example interface for a specific + * device (a serial line). It extends the capability of the + * underlying DEV_IO class by adding a control method that takes + * a special structure (Serial_Params) as argument to allow a + * comfortable user interface (away from that annoying termios + * structure, which is very specific to UNIX). + */ +class ACE_Export ACE_TTY_IO : public ACE_DEV_IO +{ +public: + ACE_TTY_IO (void); + + enum Control_Mode + { + SETPARAMS, ///< Set control parameters. + GETPARAMS ///< Get control parameters. + }; + + struct ACE_Export Serial_Params + { + Serial_Params (void); + + /** Specifies the baudrate at which the communication port operates. */ + int baudrate; + /** Specifies the minimum number of bytes in input buffer before XON char + is sent. Negative value indicates that default value should + be used (Win32). */ + int xonlim; + /** Specifies the maximum number of bytes in input buffer before XOFF char + is sent. Negative value indicates that default value should + be used (Win32). */ + int xofflim; + /** Specifies the minimum number of characters for non-canonical + read (POSIX). */ + unsigned int readmincharacters; + /** Specifies the time to wait before returning from read. Negative value + means infinite timeout. */ + int readtimeoutmsec; + /** Specifies the parity mode. POSIX supports "none", "even" and + "odd" parity. Additionally Win32 supports "mark" and "space" + parity modes. */ + const char *paritymode; + /** Enable & set CTS mode. Note that RTS & CTS are enabled/disabled + together on some systems (RTS/CTS is enabled if either + ctsenb or rtsenb is set). */ + bool ctsenb; + /** Enable & set RTS mode. Note that RTS & CTS are enabled/disabled + together on some systems (RTS/CTS is enabled if either + ctsenb or rtsenb is set). + - 0 = Disable RTS. + - 1 = Enable RTS. + - 2 = Enable RTS flow-control handshaking (Win32). + - 3 = Specifies that RTS line will be high if bytes are available + for transmission. After transmission RTS will be low (Win32). */ + unsigned char rtsenb; + /** Enable/disable software flow control on input. */ + bool xinenb; + /** Enable/disable software flow control on output. */ + bool xoutenb; + /** Specifies if device is a modem (POSIX). If not set modem status + lines are ignored. */ + bool modem; + /** Enable/disable receiver (POSIX). */ + bool rcvenb; + /** Controls whether DSR is disabled or enabled (Win32). */ + bool dsrenb; + /** Controls whether DTR is disabled or enabled. */ + bool dtrdisable; + /** Data bits. Valid values 5, 6, 7 and 8 data bits. + Additionally Win32 supports 4 data bits. */ + unsigned char databits; + /** Stop bits. Valid values are 1 and 2. */ + unsigned char stopbits; + }; + + /** Interface for reading/writing serial device parameters. */ + int control (Control_Mode cmd, Serial_Params *arg) const; + +#if defined (ACE_NEEDS_DEV_IO_CONVERSION) + /** This is necessary to pass ACE_TTY_IO as parameter to DEV_Connector. */ + operator ACE_DEV_IO &(); +#endif /* ACE_NEEDS_DEV_IO_CONVERSION */ +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TTY_IO_H */ diff --git a/dep/acelite/ace/Task.cpp b/dep/acelite/ace/Task.cpp new file mode 100644 index 000000000..17acc652f --- /dev/null +++ b/dep/acelite/ace/Task.cpp @@ -0,0 +1,293 @@ +#include "ace/Task.h" +#include "ace/Module.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Task.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Task_Base::ACE_Task_Base (ACE_Thread_Manager *thr_man) + : thr_count_ (0), + thr_mgr_ (thr_man), + flags_ (0), + grp_id_ (-1) +#if !(defined (ACE_TANDEM_T1248_PTHREADS) || defined (ACE_THREAD_T_IS_A_STRUCT)) + ,last_thread_id_ (0) +#endif /* ! ACE_TANDEM_T1248_PTHREADS || ACE_THREAD_T_IS_A_STRUCT */ +{ +#if defined (ACE_TANDEM_T1248_PTHREADS) || defined (ACE_THREAD_T_IS_A_STRUCT) + ACE_OS::memset( &this->last_thread_id_, '\0', sizeof( this->last_thread_id_ )); +#endif /* ACE_TANDEM_T1248_PTHREADS || ACE_THREAD_T_IS_A_STRUCT */ +} + +ACE_Task_Base::~ACE_Task_Base (void) +{ +} + +/// Default ACE_Task service routine +int +ACE_Task_Base::svc (void) +{ + ACE_TRACE ("ACE_Task_Base::svc"); + return 0; +} + +/// Default ACE_Task open routine +int +ACE_Task_Base::open (void *) +{ + ACE_TRACE ("ACE_Task_Base::open"); + return 0; +} + +/// Default ACE_Task close routine +int +ACE_Task_Base::close (u_long) +{ + ACE_TRACE ("ACE_Task_Base::close"); + return 0; +} + +/// Forward the call to close() so that existing applications don't +/// break. +int +ACE_Task_Base::module_closed (void) +{ + return this->close (1); +} + +/// Default ACE_Task put routine. +int +ACE_Task_Base::put (ACE_Message_Block *, ACE_Time_Value *) +{ + ACE_TRACE ("ACE_Task_Base::put"); + return 0; +} + +/// Wait for all threads running in a task to exit. +int +ACE_Task_Base::wait (void) +{ + ACE_TRACE ("ACE_Task_Base::wait"); + + // If we don't have a thread manager, we probably were never + // activated. + if (this->thr_mgr () != 0) + return this->thr_mgr ()->wait_task (this); + else + return 0; +} + +/// Suspend a task. +int +ACE_Task_Base::suspend (void) +{ + ACE_TRACE ("ACE_Task_Base::suspend"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + if (this->thr_count_ > 0) + return this->thr_mgr_->suspend_task (this); + + return 0; +} + +/// Resume a suspended task. +int +ACE_Task_Base::resume (void) +{ + ACE_TRACE ("ACE_Task_Base::resume"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + if (this->thr_count_ > 0) + return this->thr_mgr_->resume_task (this); + + return 0; +} + +int +ACE_Task_Base::activate (long flags, + int n_threads, + int force_active, + long priority, + int grp_id, + ACE_Task_Base *task, + ACE_hthread_t thread_handles[], + void *stack[], + size_t stack_size[], + ACE_thread_t thread_ids[], + const char* thr_name[]) +{ + ACE_TRACE ("ACE_Task_Base::activate"); + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1); + + // If the task passed in is zero, we will use + if (task == 0) + task = this; + + if (this->thr_count_ > 0 && force_active == 0) + return 1; // Already active. + else + { + if ((this->thr_count_ > 0 || grp_id == -1) && + this->grp_id_ != -1) + // If we're joining an existing group of threads then make + // sure to (re)use its group id. + grp_id = this->grp_id_; + else if (grp_id != -1) + // make sure to reset the cached grp_id + this->grp_id_ = -1; + this->thr_count_ += n_threads; + } + + // Use the ACE_Thread_Manager singleton if we're running as an + // active object and the caller didn't supply us with a + // Thread_Manager. + if (this->thr_mgr_ == 0) +# if defined (ACE_THREAD_MANAGER_LACKS_STATICS) + this->thr_mgr_ = ACE_THREAD_MANAGER_SINGLETON::instance (); +# else /* ! ACE_THREAD_MANAGER_LACKS_STATICS */ + this->thr_mgr_ = ACE_Thread_Manager::instance (); +# endif /* ACE_THREAD_MANAGER_LACKS_STATICS */ + + int grp_spawned = -1; + if (thread_ids == 0) + // Thread Ids were not specified + grp_spawned = + this->thr_mgr_->spawn_n (n_threads, + &ACE_Task_Base::svc_run, + (void *) this, + flags, + priority, + grp_id, + task, + thread_handles, + stack, + stack_size, + thr_name); + else + // thread names were specified + grp_spawned = + this->thr_mgr_->spawn_n (thread_ids, + n_threads, + &ACE_Task_Base::svc_run, + (void *) this, + flags, + priority, + grp_id, + stack, + stack_size, + thread_handles, + task, + thr_name); + if (grp_spawned == -1) + { + // If spawn_n fails, restore original thread count. + this->thr_count_ -= n_threads; + return -1; + } + + if (this->grp_id_ == -1) + this->grp_id_ = grp_spawned; + +#if defined(ACE_TANDEM_T1248_PTHREADS) || defined (ACE_THREAD_T_IS_A_STRUCT) + ACE_OS::memcpy( &this->last_thread_id_, '\0', sizeof(this->last_thread_id_)); +#else + this->last_thread_id_ = 0; // Reset to prevent inadvertant match on ID +#endif /* ACE_TANDEM_T1248_PTHREADS || ACE_THREAD_T_IS_A_STRUCT */ + + return 0; + +#else + { + // Keep the compiler from complaining. + ACE_UNUSED_ARG (flags); + ACE_UNUSED_ARG (n_threads); + ACE_UNUSED_ARG (force_active); + ACE_UNUSED_ARG (priority); + ACE_UNUSED_ARG (grp_id); + ACE_UNUSED_ARG (task); + ACE_UNUSED_ARG (thread_handles); + ACE_UNUSED_ARG (stack); + ACE_UNUSED_ARG (stack_size); + ACE_UNUSED_ARG (thread_ids); + ACE_UNUSED_ARG (thr_name); + ACE_NOTSUP_RETURN (-1); + } +#endif /* ACE_MT_SAFE */ +} + +void +ACE_Task_Base::cleanup (void *object, void *) +{ + ACE_Task_Base *t = (ACE_Task_Base *) object; + + // The thread count must be decremented first in case the + // hook does something crazy like "delete this". + { + ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, t->lock_)); + t->thr_count_--; + if (0 == t->thr_count_) + t->last_thread_id_ = ACE_Thread::self (); + } + + // @@ Is it possible to pass in the exit status somehow? + t->close (); + // t is undefined here. close() could have deleted it. +} + + +#if defined (ACE_HAS_SIG_C_FUNC) +extern "C" void +ACE_Task_Base_cleanup (void *object, void *) +{ + ACE_Task_Base::cleanup (object, 0); +} +#endif /* ACE_HAS_SIG_C_FUNC */ + +ACE_THR_FUNC_RETURN +ACE_Task_Base::svc_run (void *args) +{ + ACE_TRACE ("ACE_Task_Base::svc_run"); + + ACE_Task_Base *t = (ACE_Task_Base *) args; + + // Register ourself with our 's thread exit hook + // mechanism so that our close() hook will be sure to get invoked + // when this thread exits. + +#if defined ACE_HAS_SIG_C_FUNC + t->thr_mgr ()->at_exit (t, ACE_Task_Base_cleanup, 0); +#else + t->thr_mgr ()->at_exit (t, ACE_Task_Base::cleanup, 0); +#endif /* ACE_HAS_SIG_C_FUNC */ + + ACE_THR_FUNC_RETURN status; + // Call the Task's svc() hook method. + int const svc_status = t->svc (); + +#if defined (ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN) + // Reinterpret case between integral types is not mentioned in the C++ spec + status = static_cast (svc_status); +#else + status = reinterpret_cast (svc_status); +#endif /* ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN */ + +// If we changed this zero change the other if in OS.cpp Thread_Adapter::invoke +#if 1 + // Call the close> hook. + ACE_Thread_Manager *thr_mgr_ptr = t->thr_mgr (); + + // This calls the Task->close () hook. + t->cleanup (t, 0); + + // This prevents a second invocation of the cleanup code + // (called later by . + thr_mgr_ptr->at_exit (t, 0, 0); +#endif + return status; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Task.h b/dep/acelite/ace/Task.h new file mode 100644 index 000000000..87e658b8f --- /dev/null +++ b/dep/acelite/ace/Task.h @@ -0,0 +1,304 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Task.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_TASK_H +#define ACE_TASK_H +#include /**/ "ace/pre.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Thread_Manager.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Task_Flags + * + * @brief These flags are used within the ACE_Task. + * + * These flags should be hidden within ACE_Task. Unfortunately, the + * HP/UX C++ compiler can't grok this... Fortunately, there's no + * code defined here, so we don't have to worry about multiple + * definitions. + */ +namespace ACE_Task_Flags +{ + enum + { + /// Identifies a Task as being the "reader" in a Module. + ACE_READER = 01, + /// Just flush data messages in the queue. + ACE_FLUSHDATA = 02, + /// Flush all messages in the Queue. + ACE_FLUSHALL = 04, + /// Flush read queue + ACE_FLUSHR = 010, + /// Flush write queue + ACE_FLUSHW = 020, + /// Flush both queues + ACE_FLUSHRW = 030 + }; +} + +/** + * @class ACE_Task_Base + * + * @brief Direct base class for the ACE_Task template. + * + * This class factors out the non-template code in order to + * reduce template bloat, as well as to make it possible for the + * ACE_Thread_Manager to store ACE_Task_Base *'s + * polymorphically. + */ +class ACE_Export ACE_Task_Base : public ACE_Service_Object +{ +public: + // = Initialization and termination methods. + /// Constructor. + ACE_Task_Base (ACE_Thread_Manager * = 0); + + /// Destructor. + virtual ~ACE_Task_Base (void); + + // = Initialization and termination hooks. + + // These methods should be overridden by subclasses if you'd like to + // provide -specific initialization and termination behavior. + + /// Hook called to initialize a task and prepare it for execution. + /// @a args can be used to pass arbitrary information into . + virtual int open (void *args = 0); + + /** + * Hook called from ACE_Thread_Exit when during thread exit and from + * the default implementation of @c module_closed(). In general, this + * method shouldn't be called directly by an application, + * particularly if the Task is running as an Active Object. + * Instead, a special message should be passed into the Task via + * the put() method defined below, and the svc() method should + * interpret this as a flag to shut down the Task. + */ + virtual int close (u_long flags = 0); + + /** + * Hook called during ACE_Module::close(). The default + * implementation calls forwards the call to close(1). Please + * notice the changed value of the default argument of close(). + * This allows tasks to differ between the call has been originated + * from ACE_Thread_Exit or from module_closed(). Be aware that + * close(0) will be also called when a thread associated with the + * ACE_Task instance exits. + */ + virtual int module_closed (void); + + // = Immediate and deferred processing methods, respectively. + + // These methods should be overridden by subclasses if you'd like to + // provide -specific message processing behavior. + + /// A hook method that can be used to pass a message to a + /// task, where it can be processed immediately or queued for subsequent + /// processing in the svc() hook method. + virtual int put (ACE_Message_Block *, ACE_Time_Value * = 0); + + /// Run by a daemon thread to handle deferred processing. + virtual int svc (void); + + // = Active object activation method. + /** + * Turn the task into an active object, i.e., having @a n_threads of + * control, all running at the @a priority level (see below) with the + * same @a grp_id, all of which invoke . Returns -1 if + * failure occurs, returns 1 if Task is already an active object and + * @a force_active is false (i.e., do *not* create a new thread in + * this case), and returns 0 if Task was not already an active + * object and a thread is created successfully or thread is an + * active object and @a force_active is true. Note that if + * @a force_active is true and there are already threads spawned in + * this , the @a grp_id parameter is ignored and the @a grp_id + * of any newly activated thread(s) will inherit the existing + * @a grp_id of the existing thread(s) in the . + * + * The <{flags}> are a bitwise-OR of the following: + * = BEGIN + * THR_CANCEL_DISABLE, THR_CANCEL_ENABLE, THR_CANCEL_DEFERRED, + * THR_CANCEL_ASYNCHRONOUS, THR_BOUND, THR_NEW_LWP, THR_DETACHED, + * THR_SUSPENDED, THR_DAEMON, THR_JOINABLE, THR_SCHED_FIFO, + * THR_SCHED_RR, THR_SCHED_DEFAULT, THR_EXPLICIT_SCHED, + * THR_SCOPE_SYSTEM, THR_SCOPE_PROCESS + * = END + * If THR_SCHED_INHERIT is not desirable, applications should + * specifically pass in THR_EXPLICIT_SCHED. + * + * + * By default, or if <{priority}> is set to + * ACE_DEFAULT_THREAD_PRIORITY, an "appropriate" priority value for + * the given scheduling policy (specified in <{flags}>, e.g., + * ) is used. This value is calculated + * dynamically, and is the median value between the minimum and + * maximum priority values for the given policy. If an explicit + * value is given, it is used. Note that actual priority values are + * EXTREMEMLY implementation-dependent, and are probably best + * avoided. + * + * If @a thread_handles != 0 it is assumed to be an array of @a n + * thread_handles that will be assigned the values of the thread + * handles being spawned. Returns -1 on failure (@c errno will + * explain...), otherwise returns the group id of the threads. + * + * Assigning @a task allows you to associate the newly spawned + * threads with an instance of ACE_Task_Base. If @a task == 0, then + * the new threads are associated automatically with @c this + * ACE_Task_Base. Setting the @a task argument to value other than + * @c this makes the thread manipulating methods, such as wait(), + * suspend(), resume(), useless. Threads spawned with user + * specified @a task value must therefore be manipulated thru + * ACE_Thread_Manager directly. + * + * If @a stack != 0 it is assumed to be an array of @a n pointers to + * the base of the stacks to use for the threads being spawned. + * Likewise, if @a stack_size != 0 it is assumed to be an array of + * @a n values indicating how big each of the corresponding @a stacks + * are. + * + * + */ + virtual int activate (long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, + int n_threads = 1, + int force_active = 0, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + int grp_id = -1, + ACE_Task_Base *task = 0, + ACE_hthread_t thread_handles[] = 0, + void *stack[] = 0, + size_t stack_size[] = 0, + ACE_thread_t thread_ids[] = 0, + const char* thr_name[] = 0); + + /** + * Block until there are no more threads running in this task. + * This method will not wait for either detached or daemon threads; + * the threads must have been spawned with the @c THR_JOINABLE flag. + * Upon successful completion, the threads have been joined, so further + * attempts to join with any of the waited-for threads will fail. + * + * @retval 0 Success. + * @retval -1 Failure (consult errno for further information). + */ + virtual int wait (void); + + // = Suspend/resume a Task. + + // Note that these methods are not portable and should be avoided + // since they are inherently error-prone to use. They are only here + // for (the rare) applications that know how to use them correctly. + /// Suspend a task. + virtual int suspend (void); + /// Resume a suspended task. + virtual int resume (void); + + /// Get the current group id. + int grp_id (void) const; + + /// Set the current group id. + void grp_id (int); + + /// Get the thread manager associated with this Task. + ACE_Thread_Manager *thr_mgr (void) const; + + /// Set the thread manager associated with this Task. + void thr_mgr (ACE_Thread_Manager *); + + /// True if queue is a reader, else false. + int is_reader (void) const; + + /// True if queue is a writer, else false. + int is_writer (void) const; + + /** + * Returns the number of threads currently running within a task. + * If we're a passive object this value is 0, else it's greater than + * 0. + */ + size_t thr_count (void) const; + + /** + * Returns the thread ID of the thread whose exit caused this object's + * thread count to be decremented to 0. + * + * When a thread spawned in the context of this object (using activate()) + * returns from its svc() method ACE calls the close() hook. Before it does + * so, it decrements the number of active threads. If the number of threads + * is decremented to 0, the thread ID of the current thread is stored for + * access by this method. If the returned thread ID matches the calling + * thread's ID, the calling thread knows that there are no other threads + * still active in the ACE_Task. + * + * @retval ACE_thread_t of the last thread to close. 0 if the last thread + * is not yet known; for example, if no threads are active, or if + * multiple threads are active. + */ + ACE_thread_t last_thread (void) const; + + /// Routine that runs the service routine as a daemon thread. + static ACE_THR_FUNC_RETURN svc_run (void *); + + /// Cleanup hook that is called when a thread exits to gracefully + /// shutdown an ACE_Task. + static void cleanup (void *object, void *params); + +protected: + /** + * Count of the number of threads running within the task. If this + * value is greater than 0 then we're an active object and the value + * of is the number of active threads at this instant. + * If the value == 0, then we're a passive object. + */ + size_t thr_count_; + + /// Multi-threading manager. + ACE_Thread_Manager *thr_mgr_; + + /// ACE_Task flags. + u_long flags_; + + /// This maintains the group id of the Task. + int grp_id_; + +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + /// Protect the state of a Task during concurrent operations, but + /// only if we're configured as MT safe... + mutable ACE_Thread_Mutex lock_; +#endif /* ACE_MT_SAFE */ + + /// Holds the thread ID of the last thread to exit svc() in this object. + ACE_thread_t last_thread_id_; +private: + + // = Disallow these operations. + ACE_Task_Base &operator= (const ACE_Task_Base &); + ACE_Task_Base (const ACE_Task_Base &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Task.inl" +#endif /* __ACE_INLINE__ */ + +// Include the ACE_Task templates classes at this point. +#include "ace/Task_T.h" + +#include /**/ "ace/post.h" +#endif /* ACE_TASK_H */ diff --git a/dep/acelite/ace/Task.inl b/dep/acelite/ace/Task.inl new file mode 100644 index 000000000..2d585d13b --- /dev/null +++ b/dep/acelite/ace/Task.inl @@ -0,0 +1,73 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Get the current group id. +ACE_INLINE int +ACE_Task_Base::grp_id (void) const +{ + ACE_TRACE ("ACE_Task_Base::grp_id"); + return this->grp_id_; +} + +// Set the current group id. + +ACE_INLINE void +ACE_Task_Base::grp_id (int identifier) +{ + ACE_TRACE ("ACE_Task_Base::grp_id"); + ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, this->lock_)); + + // Cache the group id in the task and then set it in the + // Thread_Manager, if there is one. + this->grp_id_ = identifier; + if (this->thr_mgr ()) + this->thr_mgr ()->set_grp (this, identifier); +} + +ACE_INLINE ACE_Thread_Manager * +ACE_Task_Base::thr_mgr (void) const +{ + ACE_TRACE ("ACE_Task_Base::thr_mgr"); + return this->thr_mgr_; +} + +ACE_INLINE void +ACE_Task_Base::thr_mgr (ACE_Thread_Manager *thr_mgr) +{ + ACE_TRACE ("ACE_Task_Base::thr_mgr"); + this->thr_mgr_ = thr_mgr; +} + +ACE_INLINE int +ACE_Task_Base::is_reader (void) const +{ + ACE_TRACE ("ACE_Task_Base::is_reader"); + return (ACE_BIT_ENABLED (this->flags_, ACE_Task_Flags::ACE_READER)); +} + +ACE_INLINE int +ACE_Task_Base::is_writer (void) const +{ + ACE_TRACE ("ACE_Task_Base::is_writer"); + return (ACE_BIT_DISABLED (this->flags_, ACE_Task_Flags::ACE_READER)); +} + +// Return the count of the current number of threads. +ACE_INLINE size_t +ACE_Task_Base::thr_count (void) const +{ + ACE_TRACE ("ACE_Task_Base::thr_count"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + return this->thr_count_; +} + +// Return the thread ID of the last thread to exit svc(). +ACE_INLINE ACE_thread_t +ACE_Task_Base::last_thread (void) const +{ + ACE_TRACE ("ACE_Task_Base::last_thread"); + return this->last_thread_id_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Task_Ex_T.cpp b/dep/acelite/ace/Task_Ex_T.cpp new file mode 100644 index 000000000..801c433ab --- /dev/null +++ b/dep/acelite/ace/Task_Ex_T.cpp @@ -0,0 +1,117 @@ +#ifndef ACE_TASK_EX_T_CPP +#define ACE_TASK_EX_T_CPP + +#include "ace/Task_Ex_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Module.h" +#include "ace/Null_Condition.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Task_Ex_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tycc (ACE_Task_Ex) + +template void +ACE_Task_Ex::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Task_Ex::dump"); + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_mgr_ = %x"), this->thr_mgr_)); + this->msg_queue_->dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("delete_msg_queue_ = %d\n"), this->delete_msg_queue_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nflags = %x"), this->flags_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmod_ = %x"), this->mod_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nnext_ = %x"), this->next_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_count_ = %d"), this->thr_count_)); +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + this->lock_.dump (); +#endif /* ACE_MT_SAFE */ + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// If the user doesn't supply a ACE_Message_Queue_Ex pointer then we'll +// allocate one dynamically. Otherwise, we'll use the one they give. + +template +ACE_Task_Ex::ACE_Task_Ex (ACE_Thread_Manager *thr_man, + ACE_Message_Queue_Ex *mq) + : ACE_Task_Base (thr_man), + msg_queue_ (0), + delete_msg_queue_ (false), + mod_ (0), + next_ (0) +{ + ACE_TRACE ("ACE_Task_Ex::ACE_Task_Ex"); + + if (mq == 0) + { + ACE_NEW (mq, + (ACE_Message_Queue_Ex)); + this->delete_msg_queue_ = true; + } + + this->msg_queue_ = mq; +} + +template +ACE_Task_Ex::~ACE_Task_Ex (void) +{ + ACE_TRACE ("ACE_Task_Ex::~ACE_Task_Ex"); + if (this->delete_msg_queue_) + delete this->msg_queue_; + + // These assignments aren't strickly necessary but they help guard + // against odd race conditions... + this->delete_msg_queue_ = false; +} + +template ACE_Task * +ACE_Task_Ex::sibling (void) +{ + ACE_TRACE ("ACE_Task_Ex::sibling"); + /// @todo FIXME Need to impl ACE_Moudle to support ACE_Task as well. + /// Now always return 0 for sibling + return 0; +/* + if (this->mod_ == 0) + return 0; + else + return this->mod_->sibling (this); +*/ +} + +template const ACE_TCHAR * +ACE_Task_Ex::name (void) const +{ + ACE_TRACE ("ACE_Task_Ex::name"); + if (this->mod_ == 0) + return 0; + else + return this->mod_->name (); +} + +template ACE_Module * +ACE_Task_Ex::module (void) const +{ + ACE_TRACE ("ACE_Task_Ex::module"); + return this->mod_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TASK_EX_T_CPP */ diff --git a/dep/acelite/ace/Task_Ex_T.h b/dep/acelite/ace/Task_Ex_T.h new file mode 100644 index 000000000..1f883dce7 --- /dev/null +++ b/dep/acelite/ace/Task_Ex_T.h @@ -0,0 +1,192 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Task_Ex_T.h + * + * @author Kobi Cohen-Arazi + */ +//============================================================================= + +#ifndef ACE_TASK_EX_T_H +#define ACE_TASK_EX_T_H +#include /**/ "ace/pre.h" + +#include "ace/Service_Object.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Synch_Traits.h" +#include "ace/Task.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decls... +template class ACE_Module; + +/** + * @class ACE_Task_Ex + * + * @brief Primary interface for application message processing, as well + * as input and output message queueing. + * + * Unlike ACE_Task, these class doesn't have the ability to be a part of + * a Stream chain. I.e. You cannot (yet) chain modules based on ACE_Task_Ex. + * + * @todo: We can merge ACE_Task and ACE_Task_Ex to be one class. + * something like that: + * template + * class ACE_Task : public ACE_Task_Base + * { + * // use here the code from ACE_Task_Ex using ACE_Message_Queue_Ex + * }; + * + * Now specialized version of ACE_Task with ACE_Message_Block as its + * ACE_MESSAGE_TYPE... + * + * template + * class ACE_Task : public ACE_Task_Base + * { + * // put here the good old ACE_Task code + * }; + * + * When User (and legacy code) write ACE_Task, specialized ACE_Task + * code is in action. + */ +template +class ACE_Task_Ex : public ACE_Task_Base, + private ACE_Copy_Disabled +{ +public: + friend class ACE_Module; + friend class ACE_Module_Type; + typedef ACE_Message_Queue_Ex MESSAGE_QUEUE_EX; + + // = Initialization/termination methods. + /** + * Initialize a Task, supplying a thread manager and a message + * queue. If the user doesn't supply a ACE_Message_Queue pointer + * then we'll allocate one dynamically. Otherwise, we'll use the + * one passed as a parameter. + */ + ACE_Task_Ex (ACE_Thread_Manager *thr_mgr = 0, + MESSAGE_QUEUE_EX *mq = 0); + + /// Destructor. + virtual ~ACE_Task_Ex (void); + + /// Gets the message queue associated with this task. + MESSAGE_QUEUE_EX *msg_queue (void); + + /// Sets the message queue associated with this task. + void msg_queue (MESSAGE_QUEUE_EX *); + +public: // Should be protected: + // = Message queue manipulation methods. + + // = Enqueue and dequeue methods. + + // For the following five method if @a timeout == 0, the caller will + // block until action is possible, else will wait until the + // <{absolute}> time specified in *@a timeout elapses). These calls + // will return, however, when queue is closed, deactivated, when a + // signal occurs, or if the time specified in timeout elapses, (in + // which case errno = EWOULDBLOCK). + + /// Insert message into the message queue. Note that @a timeout uses + /// <{absolute}> time rather than <{relative}> time. + int putq (ACE_MESSAGE_TYPE *, ACE_Time_Value *timeout = 0); + + /** + * Extract the first message from the queue (blocking). Note that + * @a timeout uses <{absolute}> time rather than <{relative}> time. + * Returns number of items in queue if the call succeeds or -1 otherwise. + */ + int getq (ACE_MESSAGE_TYPE *&mb, ACE_Time_Value *timeout = 0); + + /// Return a message to the queue. Note that @a timeout uses + /// <{absolute}> time rather than <{relative}> time. + int ungetq (ACE_MESSAGE_TYPE *, ACE_Time_Value *timeout = 0); + + /** + * Turn the message around and send it back down the Stream. Note + * that @a timeout uses <{absolute}> time rather than <{relative}> + * time. + */ + int reply (ACE_MESSAGE_TYPE *, ACE_Time_Value *timeout = 0); + + /** + * Transfer message to the adjacent ACE_Task_Ex in a ACE_Stream. Note + * that @a timeout uses <{absolute}> time rather than <{relative}> + * time. + */ + int put_next (ACE_MESSAGE_TYPE *msg, ACE_Time_Value *timeout = 0); + + // = ACE_Task utility routines to identify names et al. + /// Return the name of the enclosing Module if there's one associated + /// with the Task, else returns 0. + const ACE_TCHAR *name (void) const; + + // = Pointers to next ACE_Task_Base (if ACE is part of an ACE_Stream). + /// Get next Task pointer. + ACE_Task *next (void); + + /// Set next Task pointer. + void next (ACE_Task *); + + /// Alwasy return 0. @todo FIXME + ACE_Task *sibling (void); + + /// Return the Task's Module if there is one, else returns 0. + ACE_Module *module (void) const; + + /** + * Flush the task's queue, i.e., free all of the enqueued + * message blocks and releases any threads blocked on the queue. + * Note that if this conflicts with the C++ iostream + * function, just rewrite the iostream function as ::. + */ + int flush (u_long flag = ACE_Task_Flags::ACE_FLUSHALL); + + // = Special routines corresponding to certain message types. + + /// Manipulate watermarks. + void water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds, size_t); + + /// Queue of messages on the ACE_Task.. + MESSAGE_QUEUE_EX *msg_queue_; + + /// true if should delete Message_Queue, false otherwise. + bool delete_msg_queue_; + + /// Back-pointer to the enclosing module. + ACE_Module *mod_; + + /// Pointer to adjacent ACE_Task. + ACE_Task *next_; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Task_Ex_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Task_Ex_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Task_Ex_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_TASK_EX_H */ diff --git a/dep/acelite/ace/Task_Ex_T.inl b/dep/acelite/ace/Task_Ex_T.inl new file mode 100644 index 000000000..a51323056 --- /dev/null +++ b/dep/acelite/ace/Task_Ex_T.inl @@ -0,0 +1,99 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE void +ACE_Task_Ex::water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd, + size_t wm_size) +{ + ACE_TRACE ("ACE_Task_Ex::water_marks"); + if (cmd == ACE_IO_Cntl_Msg::SET_LWM) + this->msg_queue_->low_water_mark (wm_size); + else /* cmd == ACE_IO_Cntl_Msg::SET_HWM */ + this->msg_queue_->high_water_mark (wm_size); +} + +template ACE_INLINE int +ACE_Task_Ex::getq (ACE_MESSAGE_TYPE *&mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task_Ex::getq"); + return this->msg_queue_->dequeue_head (mb, tv); +} + +template ACE_INLINE int +ACE_Task_Ex::putq (ACE_MESSAGE_TYPE *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task_Ex::putq"); + return this->msg_queue_->enqueue_tail (mb, tv); +} + +template ACE_INLINE int +ACE_Task_Ex::ungetq (ACE_MESSAGE_TYPE *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task_Ex::ungetq"); + return this->msg_queue_->enqueue_head (mb, tv); +} + +template ACE_INLINE int +ACE_Task_Ex::flush (u_long flag) +{ + ACE_TRACE ("ACE_Task_Ex::flush"); + if (ACE_BIT_ENABLED (flag, ACE_Task_Flags::ACE_FLUSHALL)) + return this->msg_queue_ != 0 && this->msg_queue_->close (); + else + return -1; // Note, need to be more careful about what we free... +} + +template ACE_INLINE void +ACE_Task_Ex::msg_queue (ACE_Message_Queue_Ex *mq) +{ + ACE_TRACE ("ACE_Task_Ex::msg_queue"); + if (this->delete_msg_queue_) + { + delete this->msg_queue_; + this->delete_msg_queue_ = false; + } + this->msg_queue_ = mq; +} + +template ACE_Message_Queue_Ex * +ACE_Task_Ex::msg_queue (void) +{ + ACE_TRACE ("ACE_Task_Ex::msg_queue"); + return this->msg_queue_; +} + +template ACE_INLINE int +ACE_Task_Ex::reply (ACE_MESSAGE_TYPE *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task_Ex::reply"); + ACE_UNUSED_ARG (mb); + ACE_UNUSED_ARG (tv); + return -1 ; // this->sibling ()->put_next (mb, tv); +} + +template ACE_INLINE ACE_Task * +ACE_Task_Ex::next (void) +{ + ACE_TRACE ("ACE_Task_Ex::next"); + return this->next_; +} + +template ACE_INLINE void +ACE_Task_Ex::next (ACE_Task *q) +{ + ACE_TRACE ("ACE_Task_Ex::next"); + this->next_ = q; +} + +// Transfer msg to the next ACE_Task_Ex. + +template ACE_INLINE int +ACE_Task_Ex::put_next ( + ACE_MESSAGE_TYPE * /* msg */, + ACE_Time_Value * /* tv */) +{ + ACE_TRACE ("ACE_Task_Ex::put_next"); + return -1; // this->next_ == 0 ? -1 : this->next_->put (msg, tv); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Task_T.cpp b/dep/acelite/ace/Task_T.cpp new file mode 100644 index 000000000..b28dd2cce --- /dev/null +++ b/dep/acelite/ace/Task_T.cpp @@ -0,0 +1,109 @@ +#ifndef ACE_TASK_T_CPP +#define ACE_TASK_T_CPP + +#include "ace/Task_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Module.h" +#include "ace/Null_Condition.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Task_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE_Tyc(ACE_Task) + +template void +ACE_Task::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Task::dump"); + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_mgr_ = %x"), this->thr_mgr_)); + this->msg_queue_->dump (); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("delete_msg_queue_ = %d\n"), this->delete_msg_queue_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nflags = %x"), this->flags_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nmod_ = %x"), this->mod_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nnext_ = %x"), this->next_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_count_ = %d"), this->thr_count_)); +#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0) + this->lock_.dump (); +#endif /* ACE_MT_SAFE */ + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +// If the user doesn't supply a ACE_Message_Queue pointer then we'll +// allocate one dynamically. Otherwise, we'll use the one they give. + +template +ACE_Task::ACE_Task (ACE_Thread_Manager *thr_man, + ACE_Message_Queue *mq) + : ACE_Task_Base (thr_man), + msg_queue_ (0), + delete_msg_queue_ (false), + mod_ (0), + next_ (0) +{ + ACE_TRACE ("ACE_Task::ACE_Task"); + + if (mq == 0) + { + typedef ACE_Message_Queue QUEUE_TYPE; + ACE_NEW (mq, + QUEUE_TYPE); + this->delete_msg_queue_ = true; + } + + this->msg_queue_ = mq; +} + +template +ACE_Task::~ACE_Task (void) +{ + ACE_TRACE ("ACE_Task::~ACE_Task"); + if (this->delete_msg_queue_) + delete this->msg_queue_; + + // These assignments aren't strickly necessary but they help guard + // against odd race conditions... + this->delete_msg_queue_ = false; +} + +template ACE_Task * +ACE_Task::sibling (void) +{ + ACE_TRACE ("ACE_Task::sibling"); + if (this->mod_ == 0) + return 0; + else + return this->mod_->sibling (this); +} + +template const ACE_TCHAR * +ACE_Task::name (void) const +{ + ACE_TRACE ("ACE_Task::name"); + if (this->mod_ == 0) + return 0; + else + return this->mod_->name (); +} + +template ACE_Module * +ACE_Task::module (void) const +{ + ACE_TRACE ("ACE_Task::module"); + return this->mod_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TASK_T_CPP */ diff --git a/dep/acelite/ace/Task_T.h b/dep/acelite/ace/Task_T.h new file mode 100644 index 000000000..696117558 --- /dev/null +++ b/dep/acelite/ace/Task_T.h @@ -0,0 +1,197 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Task_T.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_TASK_T_H +#define ACE_TASK_T_H +#include /**/ "ace/pre.h" + +#include "ace/Message_Queue.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Synch_Traits.h" +#include "ace/Task.h" +#include "ace/IO_Cntl_Msg.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decls... +template class ACE_Module; + +/** + * @class ACE_Task + * + * @brief Primary interface for application message processing, as well + * as input and output message queueing. + * + * This class serves as the basis for passive and active objects + * in ACE. + */ +template +class ACE_Task : public ACE_Task_Base +{ +public: + friend class ACE_Module; + friend class ACE_Module_Type; + + // = Initialization/termination methods. + /** + * Initialize a Task, supplying a thread manager and a message + * queue. If the user doesn't supply a ACE_Message_Queue pointer + * then we'll allocate one dynamically. Otherwise, we'll use the + * one passed as a parameter. + */ + ACE_Task (ACE_Thread_Manager *thr_mgr = 0, + ACE_Message_Queue *mq = 0); + + /// Destructor. + virtual ~ACE_Task (void); + + /// Gets the message queue associated with this task. + ACE_Message_Queue *msg_queue (void); + + /// Sets the message queue associated with this task. + void msg_queue (ACE_Message_Queue *); + + /// Get the current time of day according to the queue's TIME_POLICY. + /// Allows users to initialize timeout values using correct time policy. + ACE_Time_Value_T gettimeofday (void) const; + + /// Allows applications to control how the timer queue gets the time + /// of day. + void set_time_policy (TIME_POLICY const & time_policy); + +public: // Should be protected: + // = Message queue manipulation methods. + + // = Enqueue and dequeue methods. + + // For the following five method if @a timeout == 0, the caller will + // block until action is possible, else will wait until the + // <{absolute}> time specified in *@a timeout elapses). These calls + // will return, however, when queue is closed, deactivated, when a + // signal occurs, or if the time specified in timeout elapses, (in + // which case errno = EWOULDBLOCK). + + /// Insert message into the message queue. Note that @a timeout uses + /// <{absolute}> time rather than <{relative}> time. + int putq (ACE_Message_Block *, ACE_Time_Value *timeout = 0); + + /** + * Extract the first message from the queue (blocking). Note that + * @a timeout uses <{absolute}> time rather than <{relative}> time. + * Returns number of items in queue if the call succeeds or -1 otherwise. + */ + int getq (ACE_Message_Block *&mb, ACE_Time_Value *timeout = 0); + + /// Return a message to the queue. Note that @a timeout uses + /// <{absolute}> time rather than <{relative}> time. + int ungetq (ACE_Message_Block *, ACE_Time_Value *timeout = 0); + + /** + * Turn the message around, sending it in the opposite direction in + * the stream. To do this, the message is put onto the task next in + * the stream after this task's sibling. + * + * @param mb Pointer to the block that is used in the reply. + * @param tv The absolute time at which the put operation used to + * send the message block to the next module in the stream + * will time out. If 0, this call blocks until it can be + * completed. + */ + int reply (ACE_Message_Block *mb, ACE_Time_Value *tv = 0); + + /** + * Transfer message to the adjacent ACE_Task in a ACE_Stream. Note + * that @a timeout uses <{absolute}> time rather than <{relative}> + * time. + */ + int put_next (ACE_Message_Block *msg, ACE_Time_Value *timeout = 0); + + // = ACE_Task utility routines to identify names et al. + /// Return the name of the enclosing Module if there's one associated + /// with the Task, else returns 0. + const ACE_TCHAR *name (void) const; + + // = Pointers to next ACE_Task_Base (if ACE is part of an ACE_Stream). + /// Get next Task pointer. + ACE_Task *next (void); + + /// Set next Task pointer. + void next (ACE_Task *); + + /// Return the Task's sibling if there's one associated with the + /// Task's Module, else returns 0. + ACE_Task *sibling (void); + + /// Return the Task's Module if there is one, else returns 0. + ACE_Module *module (void) const; + + /** + * Flush the task's queue, i.e., free all of the enqueued + * message blocks and unblocks any threads waiting on the queue. + * Note that if this conflicts with the C++ iostream + * function, just rewrite the iostream function as ::. + */ + int flush (u_long flag = ACE_Task_Flags::ACE_FLUSHALL); + + // = Special routines corresponding to certain message types. + + /// Manipulate watermarks. + void water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds, size_t); + + /// Queue of messages on the ACE_Task.. + ACE_Message_Queue *msg_queue_; + + /// true if should delete Message_Queue, false otherwise. + bool delete_msg_queue_; + + /// Back-pointer to the enclosing module. + ACE_Module *mod_; + + /// Pointer to adjacent ACE_Task. + ACE_Task *next_; + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + + // = Disallow these operations. + ACE_UNIMPLEMENTED_FUNC (void operator= (const ACE_Task &)) + ACE_UNIMPLEMENTED_FUNC (ACE_Task (const ACE_Task &)) +}; + +#if defined ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION_EXPORT +template class ACE_Export ACE_Task; +template class ACE_Export ACE_Task; +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION_EXPORT */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Task_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Task_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Task_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_TASK_T_H */ diff --git a/dep/acelite/ace/Task_T.inl b/dep/acelite/ace/Task_T.inl new file mode 100644 index 000000000..99de01add --- /dev/null +++ b/dep/acelite/ace/Task_T.inl @@ -0,0 +1,113 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template ACE_INLINE void +ACE_Task::water_marks (ACE_IO_Cntl_Msg::ACE_IO_Cntl_Cmds cmd, + size_t wm_size) +{ + ACE_TRACE ("ACE_Task::water_marks"); + if (cmd == ACE_IO_Cntl_Msg::SET_LWM) + this->msg_queue_->low_water_mark (wm_size); + else /* cmd == ACE_IO_Cntl_Msg::SET_HWM */ + this->msg_queue_->high_water_mark (wm_size); +} + +template ACE_INLINE int +ACE_Task::getq (ACE_Message_Block *&mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task::getq"); + return this->msg_queue_->dequeue_head (mb, tv); +} + +template ACE_INLINE int +ACE_Task::putq (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task::putq"); + return this->msg_queue_->enqueue_tail (mb, tv); +} + +template ACE_INLINE int +ACE_Task::ungetq (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task::ungetq"); + return this->msg_queue_->enqueue_head (mb, tv); +} + +template ACE_INLINE int +ACE_Task::flush (u_long f) +{ + ACE_TRACE ("ACE_Task::flush"); + if (ACE_BIT_ENABLED (f, ACE_Task_Flags::ACE_FLUSHALL)) + return this->msg_queue_ != 0 && this->msg_queue_->close (); + else + return -1; // Note, need to be more careful about what we free... +} + +template ACE_INLINE void +ACE_Task::msg_queue (ACE_Message_Queue *mq) +{ + ACE_TRACE ("ACE_Task::msg_queue"); + if (this->delete_msg_queue_) + { + delete this->msg_queue_; + this->delete_msg_queue_ = false; + } + this->msg_queue_ = mq; +} + +template ACE_Message_Queue * +ACE_Task::msg_queue (void) +{ + ACE_TRACE ("ACE_Task::msg_queue"); + return this->msg_queue_; +} + +template +ACE_Time_Value_T +ACE_Task::gettimeofday (void) const +{ + if (this->msg_queue_ != 0) + return this->msg_queue_->gettimeofday (); + + return ACE_Time_Value_T (ACE_Time_Value::zero); +} + +template +void +ACE_Task::set_time_policy (TIME_POLICY const & rhs) +{ + if (this->msg_queue_ != 0) + this->msg_queue_->set_time_policy (rhs); +} + +template ACE_INLINE int +ACE_Task::reply (ACE_Message_Block *mb, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task::reply"); + return this->sibling ()->put_next (mb, tv); +} + +template ACE_INLINE ACE_Task * +ACE_Task::next (void) +{ + ACE_TRACE ("ACE_Task::next"); + return this->next_; +} + +template ACE_INLINE void +ACE_Task::next (ACE_Task *q) +{ + ACE_TRACE ("ACE_Task::next"); + this->next_ = q; +} + +// Transfer msg to the next ACE_Task. + +template ACE_INLINE int +ACE_Task::put_next (ACE_Message_Block *msg, ACE_Time_Value *tv) +{ + ACE_TRACE ("ACE_Task::put_next"); + return this->next_ == 0 ? -1 : this->next_->put (msg, tv); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Test_and_Set.cpp b/dep/acelite/ace/Test_and_Set.cpp new file mode 100644 index 000000000..4ba0dd61d --- /dev/null +++ b/dep/acelite/ace/Test_and_Set.cpp @@ -0,0 +1,49 @@ +#ifndef ACE_TEST_AND_SET_CPP +#define ACE_TEST_AND_SET_CPP + +#include "ace/Test_and_Set.h" +#include "ace/Guard_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Test_and_Set::ACE_Test_and_Set (TYPE initial_value) + : is_set_ (initial_value) +{ +} + +// Returns true if we are done, else false. +template TYPE +ACE_Test_and_Set::is_set (void) const +{ + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, (ACE_LOCK &) this->lock_, this->is_set_); + return this->is_set_; +} + +// Sets the status. +template TYPE +ACE_Test_and_Set::set (TYPE status) +{ + ACE_GUARD_RETURN (ACE_LOCK, ace_mon, this->lock_, this->is_set_); + TYPE o_status = this->is_set_; + this->is_set_ = status; + return o_status; +} + +template int +ACE_Test_and_Set::handle_signal (int, siginfo_t *, ucontext_t *) +{ + // By setting this to 1, we are "signaling" to anyone calling + // or or that the "test and set" object is in the + // "signaled" state, i.e., it's "available" to be set back to 0. + this->set (1); + return 0; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TEST_AND_SET_CPP */ diff --git a/dep/acelite/ace/Test_and_Set.h b/dep/acelite/ace/Test_and_Set.h new file mode 100644 index 000000000..6ec541a69 --- /dev/null +++ b/dep/acelite/ace/Test_and_Set.h @@ -0,0 +1,71 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Test_and_Set.h + */ +//============================================================================= + + +#ifndef ACE_TEST_AND_SET_H +#define ACE_TEST_AND_SET_H + +#include /**/ "ace/pre.h" +#include "ace/Event_Handler.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Test_and_Set + * + * @brief Implements the classic ``test and set'' operation. + * + * This class keeps track of the status of , which can be + * set based on various events (such as receipt of a signal). + * This class is derived from ACE_Event_Handler so that it can be + * "signaled" by a Reactor when a signal occurs. We assume that + * is a data type that can be assigned the value 0 or 1. + */ +template +class ACE_Test_and_Set : public ACE_Event_Handler +{ +public: + ACE_Test_and_Set (TYPE initial_value = 0); + + /// Returns true if we are set, else false. + TYPE is_set (void) const; + + /// Sets the status, returning the original value of + /// . + TYPE set (TYPE); + + /// Called when object is signaled by OS (either via UNIX signals or + /// when a Win32 object becomes signaled). + virtual int handle_signal (int signum, + siginfo_t * = 0, + ucontext_t * = 0); + +private: + /// Keeps track of our state. + TYPE is_set_; + + /// Protect the state from race conditions. + ACE_LOCK lock_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Test_and_Set.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Test_and_Set.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + +#include /**/ "ace/post.h" +#endif /* ACE_TEST_AND_SET_H */ diff --git a/dep/acelite/ace/Thread.cpp b/dep/acelite/ace/Thread.cpp new file mode 100644 index 000000000..c8ff2e3bf --- /dev/null +++ b/dep/acelite/ace/Thread.cpp @@ -0,0 +1,95 @@ +#include "ace/Thread.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Thread.inl" +#endif /* !defined (__ACE_INLINE__) */ + +#if defined (ACE_HAS_THREADS) + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +size_t +ACE_Thread::spawn_n (size_t n, + ACE_THR_FUNC func, + void *arg, + long flags, + long priority, + void *stack[], + size_t stack_size[], + ACE_Thread_Adapter *thread_adapter, + const char* thr_name[]) +{ + ACE_TRACE ("ACE_Thread::spawn_n"); + size_t i; + + for (i = 0; i < n; i++) + { + ACE_thread_t t_id; + // Bail out if error occurs. + if (ACE_OS::thr_create (func, + arg, + flags, + &t_id, + 0, + priority, + stack == 0 ? 0 : stack[i], + stack_size == 0 ? ACE_DEFAULT_THREAD_STACKSIZE : stack_size[i], + thread_adapter, + thr_name == 0 ? 0 : &thr_name[i]) != 0) + break; + } + + return i; +} + +size_t +ACE_Thread::spawn_n (ACE_thread_t thread_ids[], + size_t n, + ACE_THR_FUNC func, + void *arg, + long flags, + long priority, + void *stack[], + size_t stack_size[], + ACE_hthread_t thread_handles[], + ACE_Thread_Adapter *thread_adapter, + const char* thr_name[]) +{ + ACE_TRACE ("ACE_Thread::spawn_n"); + size_t i = 0; + + for (i = 0; i < n; i++) + { + ACE_thread_t t_id; + ACE_hthread_t t_handle; + + int const result = + ACE_OS::thr_create (func, + arg, + flags, + &t_id, + &t_handle, + priority, + stack == 0 ? 0 : stack[i], + stack_size == 0 ? ACE_DEFAULT_THREAD_STACKSIZE : stack_size[i], + thread_adapter, + thr_name == 0 ? 0 : &thr_name[i]); + + if (result == 0) + { + if (thread_ids != 0) + thread_ids[i] = t_id; + if (thread_handles != 0) + thread_handles[i] = t_handle; + } + else + // Bail out if error occurs. + break; + } + + return i; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Thread.h b/dep/acelite/ace/Thread.h new file mode 100644 index 000000000..6290de52e --- /dev/null +++ b/dep/acelite/ace/Thread.h @@ -0,0 +1,280 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Thread.h + * + * @author Douglas Schmidt + */ +//========================================================================== + +#ifndef ACE_THREAD_H +#define ACE_THREAD_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/OS_NS_Thread.h" +#include "ace/Thread_Adapter.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +struct cancel_state +{ + /// e.g., PTHREAD_CANCEL_ENABLE, PTHREAD_CANCEL_DISABLE, + /// PTHREAD_CANCELED. + int cancelstate; + + /// e.g., PTHREAD_CANCEL_DEFERRED and PTHREAD_CANCEL_ASYNCHRONOUS. + int canceltype; +}; + +/** + * @class ACE_Thread + * + * @brief Provides a wrapper for threads. + * + * This class provides a common interface that is mapped onto + * POSIX Pthreads, Solaris threads, Win32 threads, VxWorks + * threads, or pSoS threads. Note, however, that it is + * generally a better idea to use the ACE_Thread_Manager + * programming API rather than the API since the + * thread manager is more powerful. + */ +class ACE_Export ACE_Thread +{ +public: + /** + * Creates a new thread having @a flags attributes and running @a func + * with @a args (if @a thread_adapter is non-0 then @a func and @a args + * are ignored and are obtained from @a thread_adapter>. @a thr_id + * and @a t_handle are set to the thread's ID and handle (?), + * respectively. The thread runs at @a priority priority (see + * below). + * + * The @a flags are a bitwise-OR of the following: + * = BEGIN + * THR_CANCEL_DISABLE, THR_CANCEL_ENABLE, THR_CANCEL_DEFERRED, + * THR_CANCEL_ASYNCHRONOUS, THR_BOUND, THR_NEW_LWP, THR_DETACHED, + * THR_SUSPENDED, THR_DAEMON, THR_JOINABLE, THR_SCHED_FIFO, + * THR_SCHED_RR, THR_SCHED_DEFAULT, THR_EXPLICIT_SCHED, + * THR_SCOPE_SYSTEM, THR_SCOPE_PROCESS + * = END + * + * By default, or if @a priority is set to + * ACE_DEFAULT_THREAD_PRIORITY, an "appropriate" priority value for + * the given scheduling policy (specified in @a flags, e.g., + * @c THR_SCHED_DEFAULT is used. This value is calculated + * dynamically, and is the median value between the minimum and + * maximum priority values for the given policy. If an explicit + * value is given, it is used. Note that actual priority values are + * EXTREMELY implementation-dependent, and are probably best + * avoided. + * + * Note that @a thread_adapter is always deleted when @a spawn + * is called, so it must be allocated with global operator new. + */ + static int spawn (ACE_THR_FUNC func, + void *arg = 0, + long flags = THR_NEW_LWP | THR_JOINABLE, + ACE_thread_t *t_id = 0, + ACE_hthread_t *t_handle = 0, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + void *stack = 0, + size_t stack_size = ACE_DEFAULT_THREAD_STACKSIZE, + ACE_Thread_Adapter *thread_adapter = 0, + const char** thr_name = 0); + + /** + * Spawn N new threads, which execute @a func with argument @a arg (if + * @a thread_adapter is non-0 then @a func and @a args are ignored and + * are obtained from @a thread_adapter). If @a stack != 0 it is + * assumed to be an array of @a n pointers to the base of the stacks + * to use for the threads being spawned. Likewise, if @a stack_size + * != 0 it is assumed to be an array of @a n values indicating how + * big each of the corresponding @a stacks are. Returns the number + * of threads actually spawned (if this doesn't equal the number + * requested then something has gone wrong and @c errno will + * explain...). + * + * @see spawn() + */ + static size_t spawn_n (size_t n, + ACE_THR_FUNC func, + void *arg = 0, + long flags = THR_NEW_LWP | THR_JOINABLE, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + void *stack[] = 0, + size_t stack_size[] = 0, + ACE_Thread_Adapter *thread_adapter = 0, + const char* thr_name[] = 0); + + /** + * Spawn @a n new threads, which execute @a func with argument @a arg + * (if @a thread_adapter is non-0 then @a func and @a args are ignored + * and are obtained from @a thread_adapter). The thread_ids of + * successfully spawned threads will be placed into the @a thread_ids + * buffer (which must be the same size as @a n). If @a stack != 0 it + * is assumed to be an array of @a n pointers to the base of the + * stacks to use for the threads being spawned. If @a stack_size != + * 0 it is assumed to be an array of @a n values indicating how big + * each of the corresponding @a stacks are. If @a thread_handles != 0 + * it is assumed to be an array of @a n thread_handles that will be + * assigned the values of the thread handles being spawned. Returns + * the number of threads actually spawned (if this doesn't equal the + * number requested then something has gone wrong and @c errno will + * explain...). + * + * @see spawn() + */ + static size_t spawn_n (ACE_thread_t thread_ids[], + size_t n, + ACE_THR_FUNC func, + void *arg, + long flags, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + void *stack[] = 0, + size_t stack_size[] = 0, + ACE_hthread_t thread_handles[] = 0, + ACE_Thread_Adapter *thread_adapter = 0, + const char* thr_name[] = 0); + + /** + * Wait for one or more threads to exit and reap their exit status. + * thr_join() returns successfully when the target thread terminates. + * + * @param thread_id is the ACE_thread_t ID of the thread to wait for. + * If @a thread_id is 0, join() waits for any + * undetached thread in the process to terminate + * on platforms that support this capability + * (for example, Solaris). + * @param departed points to a location that is set to the ID of the + * terminated thread if join() returns successfully. + * If @a departed is 0, it is ignored. + * @param status Points to the location that receives the joined + * thread's exit value. If @a status is 0, it is ignored. + * + * @retval 0 for success + * @retval -1 (with errno set) for failure. + */ + static int join (ACE_thread_t thread_id, + ACE_thread_t *departed, + ACE_THR_FUNC_RETURN *status); + + /// Wait for one thread to exit and reap its exit status. + static int join (ACE_hthread_t, + ACE_THR_FUNC_RETURN * = 0); + + /// Continue the execution of a previously suspended thread. + static int resume (ACE_hthread_t); + + /// Suspend the execution of a particular thread. + static int suspend (ACE_hthread_t); + + /// Get the priority of a particular thread. + static int getprio (ACE_hthread_t ht_id, int &priority); + + /// Get the priority and policy of a particular thread. + static int getprio (ACE_hthread_t ht_id, int &priority, int &policy); + + /// Set the priority of a particular thread. + static int setprio (ACE_hthread_t ht_id, int priority, int policy = -1); + + /// Send a signal to the thread. + static int kill (ACE_thread_t, int signum); + + /// Yield the thread to another. + static void yield (void); + + /** + * Return the unique kernel handle of the thread. Note that on + * Win32 this is actually a pseudohandle, which cannot be shared + * with other processes or waited on by threads. To locate the real + * handle, please use the ACE_Thread_Manager::thr_self() method. + */ + static void self (ACE_hthread_t &t_handle); + + /// Return the unique ID of the thread. + static ACE_thread_t self (void); + + /// Exit the current thread and return "status". + /// Should _not_ be called by main thread. + static void exit (ACE_THR_FUNC_RETURN status = 0); + + /// Get the LWP concurrency level of the process. + static int getconcurrency (void); + + /// Set the LWP concurrency level of the process. + static int setconcurrency (int new_level); + + /// Change and/or examine calling thread's signal mask. + static int sigsetmask (int how, + const sigset_t *sigset, + sigset_t *osigset = 0); + + /** + * Allocates a @a keyp that is used to identify data that is specific + * to each thread in the process. The key is global to all threads + * in the process. + */ + static int keycreate (ACE_thread_key_t *keyp, +#if defined (ACE_HAS_THR_C_DEST) + ACE_THR_C_DEST destructor +#else + ACE_THR_DEST destructor +#endif /* ACE_HAS_THR_C_DEST */ + ); + + /// Free up the key so that other threads can reuse it. + static int keyfree (ACE_thread_key_t key); + + /// Bind value to the thread-specific data key, @a key, for the calling + /// thread. + static int setspecific (ACE_thread_key_t key, + void *value); + + /// Stores the current value bound to @a key for the calling thread + /// into the location pointed to by @a valuep. + static int getspecific (ACE_thread_key_t key, + void **valuep); + + /// Disable thread cancellation. + static int disablecancel (struct cancel_state *old_state); + + /// Enable thread cancellation. + static int enablecancel (struct cancel_state *old_state, + int flag); + + /// Set the cancellation state. + static int setcancelstate (struct cancel_state &new_state, + struct cancel_state *old_state); + + /** + * Cancel a thread. + * @note This method is only portable on platforms, such as POSIX pthreads, + * that support thread cancellation. + */ + static int cancel (ACE_thread_t t_id); + + /// Test the cancel. + static void testcancel (void); + +private: + /// Ensure that we don't get instantiated. + ACE_Thread (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Thread.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_THREAD_H */ diff --git a/dep/acelite/ace/Thread.inl b/dep/acelite/ace/Thread.inl new file mode 100644 index 000000000..33f7fcf0b --- /dev/null +++ b/dep/acelite/ace/Thread.inl @@ -0,0 +1,283 @@ +// -*- C++ -*- +#include "ace/OS_NS_string.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Allocates a that is used to identify data that is specific +// to each thread in the process. The key is global to all threads in +// the process. + +ACE_INLINE int +ACE_Thread::keycreate (ACE_thread_key_t *keyp, +#if defined (ACE_HAS_THR_C_DEST) + ACE_THR_C_DEST destructor +#else + ACE_THR_DEST destructor +#endif /* ACE_HAS_THR_C_DEST */ + ) +{ + // ACE_TRACE ("ACE_Thread::keycreate"); + return ACE_OS::thr_keycreate (keyp, destructor); +} + +// Free up the key so that other threads can reuse it. + +ACE_INLINE int +ACE_Thread::keyfree (ACE_thread_key_t key) +{ + ACE_TRACE ("ACE_Thread::keyfree"); + return ACE_OS::thr_keyfree (key); +} + +// Bind value to the thread-specific data key, , for the calling +// thread. + +ACE_INLINE int +ACE_Thread::setspecific (ACE_thread_key_t key, void *value) +{ + // ACE_TRACE ("ACE_Thread::setspecific"); + return ACE_OS::thr_setspecific (key, value); +} + +// Stores the current value bound to for the calling thread +// into the location pointed to by . + +ACE_INLINE int +ACE_Thread::getspecific (ACE_thread_key_t key, void **valuep) +{ + // ACE_TRACE ("ACE_Thread::getspecific"); + return ACE_OS::thr_getspecific (key, valuep); +} + +ACE_INLINE ACE_thread_t +ACE_Thread::self (void) +{ +// ACE_TRACE ("ACE_Thread::self"); + return ACE_OS::thr_self (); +} + +ACE_INLINE void +ACE_Thread::exit (ACE_THR_FUNC_RETURN status) +{ + ACE_TRACE ("ACE_Thread::exit"); + ACE_OS::thr_exit (status); +} + +ACE_INLINE void +ACE_Thread::yield (void) +{ + ACE_TRACE ("ACE_Thread::yield"); + ACE_OS::thr_yield (); +} + +ACE_INLINE int +ACE_Thread::spawn (ACE_THR_FUNC func, + void *arg, + long flags, + ACE_thread_t *t_id, + ACE_hthread_t *t_handle, + long priority, + void *thr_stack, + size_t thr_stack_size, + ACE_Thread_Adapter *thread_adapter, + const char** thr_name) +{ + ACE_TRACE ("ACE_Thread::spawn"); + + return ACE_OS::thr_create (func, + arg, + flags, + t_id, + t_handle, + priority, + thr_stack, + thr_stack_size, + thread_adapter, + thr_name); +} + +ACE_INLINE int +ACE_Thread::resume (ACE_hthread_t t_id) +{ + ACE_TRACE ("ACE_Thread::resume"); + return ACE_OS::thr_continue (t_id); +} + +ACE_INLINE int +ACE_Thread::suspend (ACE_hthread_t t_id) +{ + ACE_TRACE ("ACE_Thread::suspend"); + return ACE_OS::thr_suspend (t_id); +} + +ACE_INLINE int +ACE_Thread::kill (ACE_thread_t t_id, int signum) +{ + ACE_TRACE ("ACE_Thread::kill"); + return ACE_OS::thr_kill (t_id, signum); +} + +ACE_INLINE int +ACE_Thread::join (ACE_thread_t wait_for, + ACE_thread_t *departed, + ACE_THR_FUNC_RETURN *status) +{ + ACE_TRACE ("ACE_Thread::join"); + return ACE_OS::thr_join (wait_for, departed, status); +} + +ACE_INLINE int +ACE_Thread::join (ACE_hthread_t wait_for, + ACE_THR_FUNC_RETURN *status) +{ + ACE_TRACE ("ACE_Thread::join"); + return ACE_OS::thr_join (wait_for, status); +} + +ACE_INLINE int +ACE_Thread::getconcurrency (void) +{ + ACE_TRACE ("ACE_Thread::getconcurrency"); + return ACE_OS::thr_getconcurrency (); +} + +ACE_INLINE int +ACE_Thread::setconcurrency (int new_level) +{ + ACE_TRACE ("ACE_Thread::setconcurrency"); + return ACE_OS::thr_setconcurrency (new_level); +} + +ACE_INLINE int +ACE_Thread::sigsetmask (int how, + const sigset_t *sigset, + sigset_t *osigset) +{ + ACE_TRACE ("ACE_Thread::sigsetmask"); + return ACE_OS::thr_sigsetmask (how, sigset, osigset); +} + +ACE_INLINE int +ACE_Thread::disablecancel (struct cancel_state *old_state) +{ + ACE_TRACE ("ACE_Thread::disablecancel"); + int old_cstate = 0; + int result = ACE_OS::thr_setcancelstate (THR_CANCEL_DISABLE, + &old_cstate); + if (result == 0 && old_state != 0) + { + ACE_OS::memset (old_state, + 0, + sizeof (*old_state)); + old_state->cancelstate = old_cstate; + } + + return result; +} + +ACE_INLINE int +ACE_Thread::enablecancel (struct cancel_state *old_state, + int flag) +{ + ACE_TRACE ("ACE_Thread::enablecancel"); + int old_cstate = 0; + int old_ctype = 0; + int result; + + result = ACE_OS::thr_setcancelstate (THR_CANCEL_ENABLE, + &old_cstate); + if (result != 0) + return result; + + result = ACE_OS::thr_setcanceltype (flag, + &old_ctype); + if (result != 0) + return result; + + if (old_state != 0) + { + old_state->cancelstate = old_cstate; + old_state->canceltype = old_ctype; + } + + return 0; +} + +ACE_INLINE int +ACE_Thread::setcancelstate (struct cancel_state &new_state, + struct cancel_state *old_state) +{ + ACE_TRACE ("ACE_Thread::setcancelstate"); + int old_cstate = 0; + int old_ctype = 0; + + if (new_state.cancelstate != 0 + && ACE_OS::thr_setcancelstate (new_state.cancelstate, + &old_cstate) != 0) + return -1; + + if (new_state.canceltype != 0 + && ACE_OS::thr_setcanceltype (new_state.canceltype, + &old_ctype) != 0) + { + int o_cstate; + + ACE_OS::thr_setcancelstate (old_cstate, + &o_cstate); + return -1; + } + + if (old_state != 0) + { + old_state->cancelstate = old_cstate; + old_state->canceltype = old_ctype; + } + + return 0; +} + +ACE_INLINE int +ACE_Thread::cancel (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread::cancel"); + + return ACE_OS::thr_cancel (t_id); +} + +ACE_INLINE void +ACE_Thread::testcancel (void) +{ + ACE_TRACE ("ACE_Thread::testcancel"); + + ACE_OS::thr_testcancel (); +} + +ACE_INLINE void +ACE_Thread::self (ACE_hthread_t &t_id) +{ +// ACE_TRACE ("ACE_Thread::self"); + ACE_OS::thr_self (t_id); +} + +ACE_INLINE int +ACE_Thread::getprio (ACE_hthread_t ht_id, int &priority) +{ + ACE_TRACE ("ACE_Thread::getprio"); + return ACE_OS::thr_getprio (ht_id, priority); +} + +ACE_INLINE int +ACE_Thread::getprio (ACE_hthread_t ht_id, int &priority, int &policy) +{ + ACE_TRACE ("ACE_Thread::getprio"); + return ACE_OS::thr_getprio (ht_id, priority, policy); +} + +ACE_INLINE int +ACE_Thread::setprio (ACE_hthread_t ht_id, int priority, int policy) +{ + ACE_TRACE ("ACE_Thread::setprio"); + return ACE_OS::thr_setprio (ht_id, priority, policy); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Adapter.cpp b/dep/acelite/ace/Thread_Adapter.cpp new file mode 100644 index 000000000..905eefddc --- /dev/null +++ b/dep/acelite/ace/Thread_Adapter.cpp @@ -0,0 +1,240 @@ +#include "ace/Thread_Adapter.h" +#include "ace/Thread_Manager.h" +#include "ace/Thread_Exit.h" +#include "ace/Thread_Hook.h" +#include "ace/Object_Manager_Base.h" +#include "ace/Service_Config.h" + +#if !defined (ACE_HAS_INLINED_OSCALLS) +# include "ace/Thread_Adapter.inl" +#endif /* ACE_HAS_INLINED_OSCALLS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Thread_Adapter::ACE_Thread_Adapter (ACE_THR_FUNC user_func, + void *arg, + ACE_THR_C_FUNC entry_point, + ACE_Thread_Manager *tm, + ACE_Thread_Descriptor *td +#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , ACE_SEH_EXCEPT_HANDLER selector, + ACE_SEH_EXCEPT_HANDLER handler +#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + , long cancel_flags + ) + : ACE_Base_Thread_Adapter ( + user_func + , arg + , entry_point + , td +#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , selector + , handler +#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + , cancel_flags + ) + , thr_mgr_ (tm) +{ + ACE_OS_TRACE ("ACE_Thread_Adapter::ACE_Thread_Adapter"); +} + +ACE_Thread_Adapter::~ACE_Thread_Adapter (void) +{ +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Adapter); + +ACE_THR_FUNC_RETURN +ACE_Thread_Adapter::invoke (void) +{ + // Inherit the logging features if the parent thread has an + // ACE_Log_Msg instance in thread-specific storage. + this->inherit_log_msg (); + + ACE_Service_Config::current (ACE_Service_Config::global()); + +#if !defined(ACE_USE_THREAD_MANAGER_ADAPTER) + // NOTE: this preprocessor directive should match the one in above + // ACE_Thread_Exit::instance (). With the Xavier Pthreads package, + // the exit_hook in TSS causes a seg fault. So, this works around + // that by creating exit_hook on the stack. +# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION) + // Obtain our thread-specific exit hook and make sure that it knows + // how to clean us up! Note that we never use this pointer directly + // (it's stored in thread-specific storage), so it's ok to + // dereference it here and only store it as a reference. + + // Except if it is null, then the thr_mgr() method crashes. + // -jxh + + ACE_Thread_Exit *exit_hook_instance = ACE_Thread_Exit::instance (); + ACE_Thread_Exit_Maybe exit_hook_maybe (exit_hook_instance == 0); + ACE_Thread_Exit *exit_hook_ptr = exit_hook_instance + ? exit_hook_instance + : exit_hook_maybe.instance (); + ACE_Thread_Exit &exit_hook = *exit_hook_ptr; + + if (this->thr_mgr () != 0) + { + // Keep track of the that's associated with this + // . + exit_hook.thr_mgr (this->thr_mgr ()); + } +# else + // Without TSS, create an instance. When this + // function returns, its destructor will be called because the + // object goes out of scope. The drawback with this appraoch is + // that the destructor _won't_ get called if is called. + // So, threads shouldn't exit that way. Instead, they should return + // from . + ACE_Thread_Exit exit_hook; + exit_hook.thr_mgr (this->thr_mgr ()); +# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ + +#endif /* ! ACE_USE_THREAD_MANAGER_ADAPTER */ + + return this->invoke_i (); +} + +ACE_THR_FUNC_RETURN +ACE_Thread_Adapter::invoke_i (void) +{ + // Extract the arguments. + ACE_THR_FUNC func = reinterpret_cast (this->user_func_); + void *arg = this->arg_; + +#if defined (ACE_WIN32) && defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) + ACE_OS_Thread_Descriptor *thr_desc = this->thr_desc_; +#endif /* ACE_WIN32 && ACE_HAS_MFC && (ACE_HAS_MFC != 0) */ + + // Pick up the cancel-related flags before deleting this. + long cancel_flags = this->flags_; + + // Delete ourselves since we don't need anymore. Make sure + // not to access anywhere below this point. + delete this; + +#if defined (ACE_NEEDS_LWP_PRIO_SET) + // On SunOS, the LWP priority needs to be set in order to get + // preemption when running in the RT class. This is the ACE way to + // do that . . . + ACE_hthread_t thr_handle; + ACE_OS::thr_self (thr_handle); + int prio; + + // thr_getprio () on the current thread should never fail. + ACE_OS::thr_getprio (thr_handle, prio); + + // ACE_OS::thr_setprio () has the special logic to set the LWP priority, + // if running in the RT class. + ACE_OS::thr_setprio (prio); + +#endif /* ACE_NEEDS_LWP_PRIO_SET */ + if (cancel_flags != 0) + { + // If both flags are set, ignore this. + int old = 0; + int val = cancel_flags & (THR_CANCEL_ENABLE | THR_CANCEL_DISABLE); + if (val == THR_CANCEL_ENABLE || val == THR_CANCEL_DISABLE) + ACE_OS::thr_setcancelstate (val, &old); + val = cancel_flags & (THR_CANCEL_DEFERRED | THR_CANCEL_ASYNCHRONOUS); + if (val == THR_CANCEL_DEFERRED || val == THR_CANCEL_ASYNCHRONOUS) + ACE_OS::thr_setcanceltype (val, &old); + } + + ACE_THR_FUNC_RETURN status = 0; + + ACE_SEH_TRY + { + ACE_SEH_TRY + { + ACE_Thread_Hook *hook = + ACE_OS_Object_Manager::thread_hook (); + + if (hook) + // Invoke the start hook to give the user a chance to + // perform some initialization processing before the + // is invoked. + status = hook->start (func, arg); + else + // Call thread entry point. + status = (*func) (arg); + } + +#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + ACE_SEH_EXCEPT (ACE_OS_Object_Manager::seh_except_selector ()( + (void *) GetExceptionInformation ())) + { + ACE_OS_Object_Manager::seh_except_handler ()(0); + } +#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + } + + ACE_SEH_FINALLY + { + // If we changed this to 1, change the respective if in + // Task::svc_run to 0. +#if 0 + // Call the close> hook. + if (func == reinterpret_cast ( + ACE_Task_Base::svc_run)) + { + ACE_Task_Base *task_ptr = (ACE_Task_Base *) arg; + ACE_Thread_Manager *thr_mgr_ptr = task_ptr->thr_mgr (); + + // This calls the Task->close () hook. + task_ptr->cleanup (task_ptr, 0); + + // This prevents a second invocation of the cleanup code + // (called later by . + thr_mgr_ptr->at_exit (task_ptr, 0, 0); + } +#endif /* 0 */ + +#if defined (ACE_WIN32) || defined (ACE_HAS_TSS_EMULATION) +# if defined (ACE_WIN32) && defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) + int using_afx = -1; + if (thr_desc) + using_afx = ACE_BIT_ENABLED (thr_desc->flags (), THR_USE_AFX); +# endif /* ACE_WIN32 && ACE_HAS_MFC && (ACE_HAS_MFC != 0) */ + // Call TSS destructors. + ACE_OS::cleanup_tss (0 /* not main thread */); + +# if defined (ACE_WIN32) + // Exit the thread. Allow CWinThread-destructor to be invoked + // from AfxEndThread. _endthreadex will be called from + // AfxEndThread so don't exit the thread now if we are running + // an MFC thread. +# if defined (ACE_HAS_MFC) && (ACE_HAS_MFC != 0) + if (using_afx != -1) + { + if (using_afx) + ::AfxEndThread ((DWORD) status); + else + ACE_ENDTHREADEX (status); + } + else + { + // Not spawned by ACE_Thread_Manager, use the old buggy + // version. You should seriously consider using + // ACE_Thread_Manager to spawn threads. The following code + // is know to cause some problem. + CWinThread *pThread = ::AfxGetThread (); + + if (!pThread || pThread->m_nThreadID != ACE_OS::thr_self ()) + ACE_ENDTHREADEX (status); + else + ::AfxEndThread ((DWORD)status); + } +# else + + ACE_ENDTHREADEX (status); +# endif /* ACE_HAS_MFC && ACE_HAS_MFS != 0*/ +# endif /* ACE_WIN32 */ +#endif /* ACE_WIN32 || ACE_HAS_TSS_EMULATION */ + } + + return status; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Adapter.h b/dep/acelite/ace/Thread_Adapter.h new file mode 100644 index 000000000..660f120e6 --- /dev/null +++ b/dep/acelite/ace/Thread_Adapter.h @@ -0,0 +1,97 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Thread_Adapter.h + * + * @author Carlos O'Ryan + */ +//============================================================================= + +#ifndef ACE_THREAD_ADAPTER_H +#define ACE_THREAD_ADAPTER_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Base_Thread_Adapter.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward decl. +class ACE_Thread_Manager; +class ACE_Thread_Descriptor; + +/** + * @class ACE_Thread_Adapter + * + * @brief Converts a C++ function into a function that + * can be called from a thread creation routine + * (e.g., pthread_create() or _beginthreadex()) that expects an + * extern "C" entry point. This class also makes it possible to + * transparently provide hooks to register a thread with an + * ACE_Thread_Manager. + * + * This class is used in ACE_OS::thr_create(). In general, the + * thread that creates an object of this class is different from + * the thread that calls @c invoke() on this object. Therefore, + * the @c invoke() method is responsible for deleting itself. + */ +class ACE_Export ACE_Thread_Adapter : public ACE_Base_Thread_Adapter +{ +public: + /// Constructor. + ACE_Thread_Adapter (ACE_THR_FUNC user_func, + void *arg, + ACE_THR_C_FUNC entry_point = (ACE_THR_C_FUNC) ACE_THREAD_ADAPTER_NAME, + ACE_Thread_Manager *thr_mgr = 0, + ACE_Thread_Descriptor *td = 0 +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + , ACE_SEH_EXCEPT_HANDLER selector = 0, + ACE_SEH_EXCEPT_HANDLER handler = 0 +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ + , long cancel_flags = 0 + ); + + /** + * Execute the with the . This function deletes + * @c this, thereby rendering the object useless after the call + * returns. + */ + virtual ACE_THR_FUNC_RETURN invoke (void); + + /// Accessor for the optional ACE_Thread_Manager. + ACE_Thread_Manager *thr_mgr (void); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Ensure that this object must be allocated on the heap. + ~ACE_Thread_Adapter (void); + +private: + /// Called by invoke, mainly here to separate the SEH stuff because + /// SEH on Win32 doesn't compile with local vars with destructors. + virtual ACE_THR_FUNC_RETURN invoke_i (void); + +private: + /// Optional thread manager. + ACE_Thread_Manager *thr_mgr_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +# if defined (ACE_HAS_INLINED_OSCALLS) +# if defined (ACE_INLINE) +# undef ACE_INLINE +# endif /* ACE_INLINE */ +# define ACE_INLINE inline +# include "ace/Thread_Adapter.inl" +# endif /* ACE_HAS_INLINED_OSCALLS */ + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_ADAPTER_H */ diff --git a/dep/acelite/ace/Thread_Adapter.inl b/dep/acelite/ace/Thread_Adapter.inl new file mode 100644 index 000000000..06751eecd --- /dev/null +++ b/dep/acelite/ace/Thread_Adapter.inl @@ -0,0 +1,10 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ACE_Thread_Manager * +ACE_Thread_Adapter::thr_mgr (void) +{ + return this->thr_mgr_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Control.cpp b/dep/acelite/ace/Thread_Control.cpp new file mode 100644 index 000000000..c00234e5f --- /dev/null +++ b/dep/acelite/ace/Thread_Control.cpp @@ -0,0 +1,80 @@ +#include "ace/Thread_Control.h" +#include "ace/Thread_Manager.h" + +#if !defined (ACE_HAS_INLINED_OSCALLS) +# include "ace/Thread_Control.inl" +#endif /* ACE_HAS_INLINED_OSCALLS */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +void +ACE_Thread_Control::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_OS_TRACE ("ACE_Thread_Control::dump"); +#endif /* ACE_HAS_DUMP */ +} + +int +ACE_Thread_Control::insert (ACE_Thread_Manager *tm, bool insert) +{ + ACE_OS_TRACE ("ACE_Thread_Control::insert"); + + ACE_hthread_t t_id; + ACE_OS::thr_self (t_id); + this->tm_ = tm; + + if (insert) + return this->tm_->insert_thr (ACE_OS::thr_self (), t_id); + else + return 0; +} + +// Initialize the thread controller. +ACE_Thread_Control::ACE_Thread_Control (ACE_Thread_Manager *t, + int insert) + : tm_ (t), + status_ (0) +{ + ACE_OS_TRACE ("ACE_Thread_Control::ACE_Thread_Control"); + + if (this->tm_ != 0 && insert) + { + ACE_hthread_t t_id; + ACE_OS::thr_self (t_id); + this->tm_->insert_thr (ACE_OS::thr_self (), t_id); + } +} + +// Automatically kill thread on exit. +ACE_Thread_Control::~ACE_Thread_Control (void) +{ + ACE_OS_TRACE ("ACE_Thread_Control::~ACE_Thread_Control"); + +#if defined (ACE_HAS_RECURSIVE_THR_EXIT_SEMANTICS) || defined (ACE_HAS_TSS_EMULATION) || defined (ACE_WIN32) + this->exit (this->status_, 0); +#else + this->exit (this->status_, 1); +#endif /* ACE_HAS_RECURSIVE_THR_EXIT_SEMANTICS */ +} + +// Exit from thread (but clean up first). +ACE_THR_FUNC_RETURN +ACE_Thread_Control::exit (ACE_THR_FUNC_RETURN exit_status, int do_thr_exit) +{ + ACE_OS_TRACE ("ACE_Thread_Control::exit"); + + if (this->tm_ != 0) + return this->tm_->exit (exit_status, do_thr_exit); + else + { +#if !defined (ACE_HAS_TSS_EMULATION) + // With ACE_HAS_TSS_EMULATION, we let ACE_Thread_Adapter::invoke () + // exit the thread after cleaning up TSS. + ACE_OS::thr_exit (exit_status); +#endif /* ! ACE_HAS_TSS_EMULATION */ + return 0; + } +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Control.h b/dep/acelite/ace/Thread_Control.h new file mode 100644 index 000000000..a392d83a5 --- /dev/null +++ b/dep/acelite/ace/Thread_Control.h @@ -0,0 +1,99 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Thread_Control.h + * + * @author Carlos O'Ryan + */ +//============================================================================= + +#ifndef ACE_THREAD_CONTROL_H +#define ACE_THREAD_CONTROL_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +class ACE_Thread_Manager; + +/** + * @class ACE_Thread_Control + * + * @brief Used to keep track of a thread's activities within its entry + * point function. + * + * A ACE_Thread_Manager uses this class to ensure that threads + * it spawns automatically register and unregister themselves + * with it. + * This class can be stored in thread-specific storage using the + * ACE_TSS wrapper. When a thread exits the + * function deletes this object, thereby + * ensuring that it gets removed from its associated + * ACE_Thread_Manager. + */ +class ACE_Export ACE_Thread_Control +{ +public: + /// Initialize the thread control object. If @a insert != 0, then + /// register the thread with the Thread_Manager. + ACE_Thread_Control (ACE_Thread_Manager *tm = 0, + int insert = 0); + + /// Remove the thread from its associated Thread_Manager and exit + /// the thread if is enabled. + ~ACE_Thread_Control (void); + + /// Remove this thread from its associated ACE_Thread_Manager and exit + /// the thread if @a do_thr_exit is enabled. + ACE_THR_FUNC_RETURN exit (ACE_THR_FUNC_RETURN status, + int do_thr_exit); + + /// Store the Thread_Manager and use it to register ourselves for + /// correct shutdown. + int insert (ACE_Thread_Manager *tm, bool insert = false); + + /// Returns the current Thread_Manager. + ACE_Thread_Manager *thr_mgr (void); + + /// Atomically set a new Thread_Manager and return the old + /// Thread_Manager. + ACE_Thread_Manager *thr_mgr (ACE_Thread_Manager *); + + /// Set the exit status (and return existing status). + ACE_THR_FUNC_RETURN status (ACE_THR_FUNC_RETURN status); + + /// Get the current exit status. + ACE_THR_FUNC_RETURN status (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Pointer to the thread manager for this block of code. + ACE_Thread_Manager *tm_; + + /// Keeps track of the exit status for the thread. + ACE_THR_FUNC_RETURN status_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +# if defined (ACE_HAS_INLINED_OSCALLS) +# if defined (ACE_INLINE) +# undef ACE_INLINE +# endif /* ACE_INLINE */ +# define ACE_INLINE inline +# include "ace/Thread_Control.inl" +# endif /* ACE_HAS_INLINED_OSCALLS */ + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_CONTROL_H */ diff --git a/dep/acelite/ace/Thread_Control.inl b/dep/acelite/ace/Thread_Control.inl new file mode 100644 index 000000000..20d03fe78 --- /dev/null +++ b/dep/acelite/ace/Thread_Control.inl @@ -0,0 +1,45 @@ +// -*- C++ -*- +#include "ace/OS_NS_macros.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Set the exit status. + +ACE_INLINE ACE_THR_FUNC_RETURN +ACE_Thread_Control::status (ACE_THR_FUNC_RETURN s) +{ + ACE_OS_TRACE ("ACE_Thread_Control::status"); + return this->status_ = s; +} + +// Get the exit status. + +ACE_INLINE ACE_THR_FUNC_RETURN +ACE_Thread_Control::status (void) +{ + ACE_OS_TRACE ("ACE_Thread_Control::status"); + return this->status_; +} + +// Returns the current . + +ACE_INLINE ACE_Thread_Manager * +ACE_Thread_Control::thr_mgr (void) +{ + ACE_OS_TRACE ("ACE_Thread_Control::thr_mgr"); + return this->tm_; +} + +// Atomically set a new and return the old +// . + +ACE_INLINE ACE_Thread_Manager * +ACE_Thread_Control::thr_mgr (ACE_Thread_Manager *tm) +{ + ACE_OS_TRACE ("ACE_Thread_Control::thr_mgr"); + ACE_Thread_Manager *o_tm = this->tm_; + this->tm_ = tm; + return o_tm; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Exit.cpp b/dep/acelite/ace/Thread_Exit.cpp new file mode 100644 index 000000000..0d35cdba2 --- /dev/null +++ b/dep/acelite/ace/Thread_Exit.cpp @@ -0,0 +1,121 @@ +#include "ace/Thread_Exit.h" +#include "ace/Managed_Object.h" +#include "ace/Thread_Manager.h" +#include "ace/Guard_T.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +bool ACE_Thread_Exit::is_constructed_ = false; + +void +ACE_Thread_Exit::cleanup (void *instance) +{ + ACE_OS_TRACE ("ACE_Thread_Exit::cleanup"); + + delete (ACE_TSS_TYPE (ACE_Thread_Exit) *) instance; + + // Set the thr_exit_ static to null to keep things from crashing if + // ACE::fini() is enabled here. + ACE_Thread_Manager::thr_exit_ = 0; + + ACE_Thread_Exit::is_constructed_ = false; + // All TSS objects have been destroyed. Reset this flag so + // ACE_Thread_Exit singleton can be created again. +} + +// NOTE: this preprocessor directive should match the one in +// ACE_Task_Base::svc_run () below. This prevents the two statics +// from being defined. + +ACE_Thread_Exit * +ACE_Thread_Exit::instance (void) +{ +#if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION) + ACE_OS_TRACE ("ACE_Thread_Exit::instance"); + + // Determines if we were dynamically allocated. + static ACE_TSS_TYPE (ACE_Thread_Exit) * volatile instance_; + + // Implement the Double Check pattern. + + if (!ACE_Thread_Exit::is_constructed_) + { + ACE_MT (ACE_Thread_Mutex *lock = + ACE_Managed_Object::get_preallocated_object + (ACE_Object_Manager::ACE_THREAD_EXIT_LOCK); + ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, *lock, 0)); + + if (!ACE_Thread_Exit::is_constructed_) + { + ACE_NEW_RETURN (instance_, + ACE_TSS_TYPE (ACE_Thread_Exit), + 0); + + ACE_Thread_Exit::is_constructed_ = true; + + ACE_Thread_Manager::set_thr_exit (instance_); + } + } + + return ACE_TSS_GET (instance_, ACE_Thread_Exit); +#else + return 0; +#endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ +} + +// Grab hold of the Task * so that we can close() it in the +// destructor. + +ACE_Thread_Exit::ACE_Thread_Exit (void) +{ + ACE_OS_TRACE ("ACE_Thread_Exit::ACE_Thread_Exit"); +} + +// Set the this pointer... + +void +ACE_Thread_Exit::thr_mgr (ACE_Thread_Manager *tm) +{ + ACE_OS_TRACE ("ACE_Thread_Exit::thr_mgr"); + + if (tm != 0) + this->thread_control_.insert (tm, 0); +} + +// When this object is destroyed the Task is automatically closed +// down! + +ACE_Thread_Exit::~ACE_Thread_Exit (void) +{ + ACE_OS_TRACE ("ACE_Thread_Exit::~ACE_Thread_Exit"); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Exit) + +ACE_Thread_Exit_Maybe::ACE_Thread_Exit_Maybe (int flag) + : instance_ (0) +{ + if (flag) + { + ACE_NEW (instance_, ACE_Thread_Exit); + } +} + +ACE_Thread_Exit_Maybe::~ACE_Thread_Exit_Maybe (void) +{ + delete this->instance_; +} + +ACE_Thread_Exit * +ACE_Thread_Exit_Maybe::operator -> (void) const +{ + return this->instance_; +} + +ACE_Thread_Exit * +ACE_Thread_Exit_Maybe::instance (void) const +{ + return this->instance_; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Exit.h b/dep/acelite/ace/Thread_Exit.h new file mode 100644 index 000000000..a6ac6516c --- /dev/null +++ b/dep/acelite/ace/Thread_Exit.h @@ -0,0 +1,111 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Thread_Exit.h + * + * @author Carlos O'Ryan + */ +//============================================================================= + + +#ifndef ACE_THREAD_EXIT_H +#define ACE_THREAD_EXIT_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Thread_Control.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Thread_Exit + * + * @brief Keep exit information for a Thread in thread specific storage. + * so that the thread-specific exit hooks will get called no + * matter how the thread exits (e.g., via , C++ + * or Win32 exception, "falling off the end" of the thread entry + * point function, etc.). + * + * This clever little helper class is stored in thread-specific + * storage using the wrapper. When a thread exits the + * function deletes this object, thereby + * closing it down gracefully. + */ +class ACE_Export ACE_Thread_Exit +{ +public: + /// Capture the Thread that will be cleaned up automatically. + ACE_Thread_Exit (void); + + /// Set the ACE_Thread_Manager. + void thr_mgr (ACE_Thread_Manager *tm); + + /// Destructor calls the thread-specific exit hooks when a thread + /// exits. + ~ACE_Thread_Exit (void); + + /// Singleton access point. + static ACE_Thread_Exit *instance (void); + + /// Cleanup method, used by the ACE_Object_Manager to destroy the + /// singleton. + static void cleanup (void *instance); + + ACE_ALLOC_HOOK_DECLARE; + +private: + /// Automatically add/remove the thread from the + /// ACE_Thread_Manager. + ACE_Thread_Control thread_control_; + + /** + * Used to detect whether we should create a new instance (or not) + * within the instance method -- we don't trust the instance_ ptr + * because the destructor may have run (if ACE::fini() was called). + * See bug #526. + * We don't follow the singleton pattern due to dependency issues. + */ + static bool is_constructed_; +}; + +/** + * @class ACE_Thread_Exit_Maybe + * + * @brief A version of ACE_Thread_Exit that is created dynamically + * under the hood if the flag is set to TRUE. + * + * Allows the appearance of a "smart pointer", but is not + * always created. + */ +class ACE_Export ACE_Thread_Exit_Maybe +{ +public: + /// Don't create an ACE_Thread_Exit instance by default. + ACE_Thread_Exit_Maybe (int flag = 0); + + /// Destroys the underlying ACE_Thread_Exit instance if it exists. + ~ACE_Thread_Exit_Maybe (void); + + /// Delegates to underlying instance. + ACE_Thread_Exit * operator -> (void) const; + + /// Returns the underlying instance. + ACE_Thread_Exit * instance (void) const; + +private: + + /// Holds the underlying instance. + ACE_Thread_Exit *instance_; + +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_EXIT_H */ diff --git a/dep/acelite/ace/Thread_Hook.cpp b/dep/acelite/ace/Thread_Hook.cpp new file mode 100644 index 000000000..f1b07e392 --- /dev/null +++ b/dep/acelite/ace/Thread_Hook.cpp @@ -0,0 +1,32 @@ +#include "ace/Thread_Hook.h" +#include "ace/Object_Manager_Base.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Thread_Hook::ACE_Thread_Hook() +{ +} + +ACE_Thread_Hook::~ACE_Thread_Hook () +{ +} + +ACE_THR_FUNC_RETURN +ACE_Thread_Hook::start (ACE_THR_FUNC func, void *arg) +{ + return (func) (arg); +} + +ACE_Thread_Hook * +ACE_Thread_Hook::thread_hook (ACE_Thread_Hook *hook) +{ + return ACE_OS_Object_Manager::thread_hook (hook); +} + +ACE_Thread_Hook * +ACE_Thread_Hook::thread_hook (void) +{ + return ACE_OS_Object_Manager::thread_hook (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Hook.h b/dep/acelite/ace/Thread_Hook.h new file mode 100644 index 000000000..dcb6d396e --- /dev/null +++ b/dep/acelite/ace/Thread_Hook.h @@ -0,0 +1,63 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Thread_Hook.h + * + * @author Carlos O'Ryan + */ +//============================================================================= + +#ifndef ACE_THREAD_HOOK_H +#define ACE_THREAD_HOOK_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include /**/ "ace/ACE_export.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Thread_Hook + * + * @brief This class makes it possible to provide user-defined "start" + * hooks that are called before the thread entry point function + * is invoked. + */ +class ACE_Export ACE_Thread_Hook +{ +public: + /// Default constructor + ACE_Thread_Hook (void); + + /// Destructor. + virtual ~ACE_Thread_Hook (void); + + /** + * This method can be overridden in a subclass to customize this + * pre-function call "hook" invocation that can perform + * initialization processing before the thread entry point @a func + * method is called back. The @a func and @a arg passed into the + * start hook are the same as those passed by the application that + * spawned the thread. + */ + virtual ACE_THR_FUNC_RETURN start (ACE_THR_FUNC func, + void *arg); + + /// Sets the system wide thread hook, returns the previous thread + /// hook or 0 if none is set. + static ACE_Thread_Hook *thread_hook (ACE_Thread_Hook *hook); + + /// Returns the current system thread hook. + static ACE_Thread_Hook *thread_hook (void); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_HOOK_H */ diff --git a/dep/acelite/ace/Thread_Manager.cpp b/dep/acelite/ace/Thread_Manager.cpp new file mode 100644 index 000000000..172e4a43a --- /dev/null +++ b/dep/acelite/ace/Thread_Manager.cpp @@ -0,0 +1,2379 @@ +#include "ace/TSS_T.h" +#include "ace/Thread_Manager.h" +#include "ace/Dynamic.h" +#include "ace/Object_Manager.h" +#include "ace/Singleton.h" +#include "ace/Auto_Ptr.h" +#include "ace/Guard_T.h" +#include "ace/Time_Value.h" +#include "ace/OS_NS_sys_time.h" +#include "ace/Truncate.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Thread_Manager.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_At_Thread_Exit::~ACE_At_Thread_Exit (void) +{ + this->do_apply (); +} + +ACE_At_Thread_Exit_Func::~ACE_At_Thread_Exit_Func (void) +{ + this->do_apply (); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_At_Thread_Exit_Func) + +void +ACE_At_Thread_Exit_Func::apply (void) +{ + this->func_ (this->object_, this->param_); +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Control) +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Manager) + +#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) +// Process-wide Thread Manager. +ACE_Thread_Manager *ACE_Thread_Manager::thr_mgr_ = 0; + +// Controls whether the Thread_Manager is deleted when we shut down +// (we can only delete it safely if we created it!) +bool ACE_Thread_Manager::delete_thr_mgr_ = false; +#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ + +ACE_TSS_TYPE (ACE_Thread_Exit) *ACE_Thread_Manager::thr_exit_ = 0; + +int +ACE_Thread_Manager::set_thr_exit (ACE_TSS_TYPE (ACE_Thread_Exit) *ptr) +{ + if (ACE_Thread_Manager::thr_exit_ == 0) + ACE_Thread_Manager::thr_exit_ = ptr; + else + return -1; + return 0; +} + +void +ACE_Thread_Manager::dump (void) +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Thread_Manager::dump"); + // Cast away const-ness of this in order to use its non-const lock_. + ACE_MT (ACE_GUARD (ACE_Thread_Mutex, ace_mon, + ((ACE_Thread_Manager *) this)->lock_)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ncurrent_count_ = %d"), this->thr_list_.size ())); + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + iter.next ()->dump (); + } + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Thread_Descriptor::~ACE_Thread_Descriptor (void) +{ + delete this->sync_; +} + +void +ACE_Thread_Descriptor::at_pop (int apply) +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_pop"); + // Get first at from at_exit_list + ACE_At_Thread_Exit* at = this->at_exit_list_; + // Remove at from at_exit list + this->at_exit_list_ = at->next_; + // Apply if required + if (apply) + { + at->apply (); + // Do the apply method + at->was_applied (true); + // Mark at has been applied to avoid double apply from + // at destructor + } + // If at is not owner delete at. + if (!at->is_owner ()) + delete at; +} + +void +ACE_Thread_Descriptor::at_push (ACE_At_Thread_Exit* cleanup, bool is_owner) +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_push"); + cleanup->is_owner (is_owner); + cleanup->td_ = this; + cleanup->next_ = at_exit_list_; + at_exit_list_ = cleanup; +} + +int +ACE_Thread_Descriptor::at_exit (ACE_At_Thread_Exit& cleanup) +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); + at_push (&cleanup, 1); + return 0; +} + +int +ACE_Thread_Descriptor::at_exit (ACE_At_Thread_Exit* cleanup) +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); + if (cleanup==0) + return -1; + else + { + this->at_push (cleanup); + return 0; + } +} + +void +ACE_Thread_Descriptor::do_at_exit () +{ + ACE_TRACE ("ACE_Thread_Descriptor::do_at_exit"); + while (at_exit_list_!=0) + this->at_pop (); +} + +void +ACE_Thread_Descriptor::terminate () +{ + ACE_TRACE ("ACE_Thread_Descriptor::terminate"); + + if (!terminated_) + { + ACE_Log_Msg* log_msg = this->log_msg_; + terminated_ = true; + // Run at_exit hooks + this->do_at_exit (); + // We must remove Thread_Descriptor from Thread_Manager list + if (this->tm_ != 0) + { + int close_handle = 0; + +#if !defined (ACE_HAS_VXTHREADS) + // Threads created with THR_DAEMON shouldn't exist here, but + // just to be safe, let's put it here. + + if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_JOINING)) + { + if (ACE_BIT_DISABLED (this->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (this->flags_, THR_JOINABLE)) + { + // Mark thread as terminated. + ACE_SET_BITS (this->thr_state_, ACE_Thread_Manager::ACE_THR_TERMINATED); + tm_->register_as_terminated (this); + // Must copy the information here because td will be + // "freed" below. + } +#if defined (ACE_WIN32) + else + { + close_handle = 1; + } +#endif /* ACE_WIN32 */ + } +#endif /* !ACE_HAS_VXTHREADS */ + + // Remove thread descriptor from the table. 'this' is invalid + // upon return. + if (this->tm_ != 0) + { + // remove_thr makes use of 'this' invalid on return. + // Code below will free log_msg, so clear our pointer + // now - it's already been saved in log_msg. + this->log_msg_ = 0; + tm_->remove_thr (this, close_handle); + } + } + + // Check if we need delete ACE_Log_Msg instance + // If ACE_TSS_cleanup was not executed first log_msg == 0 + if (log_msg == 0) + { + // Only inform to ACE_TSS_cleanup that it must delete the log instance + // setting ACE_LOG_MSG thr_desc to 0. + ACE_LOG_MSG->thr_desc (0); + } + else + { + delete log_msg; + } + } +} + +int +ACE_Thread_Descriptor::at_exit (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param) +{ + ACE_TRACE ("ACE_Thread_Descriptor::at_exit"); + // To keep compatibility, when cleanup_hook is null really is a at_pop + // without apply. + if (cleanup_hook == 0) + { + if (this->at_exit_list_!= 0) + this->at_pop(0); + } + else + { + ACE_At_Thread_Exit* cleanup = 0; + ACE_NEW_RETURN (cleanup, + ACE_At_Thread_Exit_Func (object, + cleanup_hook, + param), + -1); + this->at_push (cleanup); + } + return 0; +} + +void +ACE_Thread_Descriptor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_Thread_Descriptor::dump"); + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_id_ = %d"), this->thr_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_handle_ = %d"), this->thr_handle_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\ngrp_id_ = %d"), this->grp_id_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nthr_state_ = %d"), this->thr_state_)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\nflags_ = %x\n"), this->flags_)); + + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Thread_Descriptor::ACE_Thread_Descriptor (void) + : log_msg_ (0), + at_exit_list_ (0), + tm_ (0), + terminated_ (false) +{ + ACE_TRACE ("ACE_Thread_Descriptor::ACE_Thread_Descriptor"); + ACE_NEW (this->sync_, + ACE_DEFAULT_THREAD_MANAGER_LOCK); +} + +void +ACE_Thread_Descriptor::acquire_release (void) +{ + // Just try to acquire the lock then release it. +#if defined (ACE_THREAD_MANAGER_USES_SAFE_SPAWN) + if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED)) +#endif /* ACE_THREAD_MANAGER_USES_SAFE_SPAWN */ + { + this->sync_->acquire (); + // Acquire the lock before removing from the thread table. If + // this thread is in the table already, it should simply acquire the + // lock easily. + + // Once we get the lock, we must have registered. + ACE_ASSERT (ACE_BIT_ENABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED)); + + this->sync_->release (); + // Release the lock before putting it back to freelist. + } +} + +void +ACE_Thread_Descriptor::acquire (void) +{ + // Just try to acquire the lock then release it. +#if defined (ACE_THREAD_MANAGER_USES_SAFE_SPAWN) + if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED)) +#endif /* ACE_THREAD_MANAGER_USES_SAFE_SPAWN */ + { + this->sync_->acquire (); + } +} + +void +ACE_Thread_Descriptor::release (void) +{ + // Just try to acquire the lock then release it. +#if defined (ACE_THREAD_MANAGER_USES_SAFE_SPAWN) + if (ACE_BIT_DISABLED (this->thr_state_, ACE_Thread_Manager::ACE_THR_SPAWNED)) +#endif /* ACE_THREAD_MANAGER_USES_SAFE_SPAWN */ + { + this->sync_->release (); + // Release the lock before putting it back to freelist. + } +} + +// The following macro simplifies subsequence code. +#define ACE_FIND(OP,INDEX) \ + ACE_Thread_Descriptor *INDEX = OP; \ + +ACE_Thread_Descriptor * +ACE_Thread_Manager::thread_descriptor (ACE_thread_t thr_id) +{ + ACE_TRACE ("ACE_Thread_Manager::thread_descriptor"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + ACE_FIND (this->find_thread (thr_id), ptr); + return ptr; +} + +ACE_Thread_Descriptor * +ACE_Thread_Manager::hthread_descriptor (ACE_hthread_t thr_handle) +{ + ACE_TRACE ("ACE_Thread_Manager::hthread_descriptor"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + ACE_FIND (this->find_hthread (thr_handle), ptr); + return ptr; +} + +// Return the thread descriptor (indexed by ACE_hthread_t). + +int +ACE_Thread_Manager::thr_self (ACE_hthread_t &self) +{ + ACE_TRACE ("ACE_Thread_Manager::thr_self"); + + ACE_Thread_Descriptor *desc = + this->thread_desc_self (); + + if (desc == 0) + return -1; + else + desc->self (self); + + return 0; +} + +// Initialize the synchronization variables. + +ACE_Thread_Manager::ACE_Thread_Manager (size_t prealloc, + size_t lwm, + size_t inc, + size_t hwm) + : grp_id_ (1), + automatic_wait_ (1) +#if defined (ACE_HAS_THREADS) + , zero_cond_ (lock_) +#endif /* ACE_HAS_THREADS */ + , thread_desc_freelist_ (ACE_FREE_LIST_WITH_POOL, + prealloc, lwm, hwm, inc) +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + , join_cond_ (this->lock_) +#endif +{ + ACE_TRACE ("ACE_Thread_Manager::ACE_Thread_Manager"); +} + +ACE_Thread_Manager::ACE_Thread_Manager (const ACE_Condition_Attributes &attributes, + size_t prealloc, + size_t lwm, + size_t inc, + size_t hwm) + : grp_id_ (1), + automatic_wait_ (1) +#if defined (ACE_HAS_THREADS) + , zero_cond_ (lock_, attributes) +#endif /* ACE_HAS_THREADS */ + , thread_desc_freelist_ (ACE_FREE_LIST_WITH_POOL, + prealloc, lwm, hwm, inc) +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + , join_cond_ (this->lock_) +#endif +{ +#if !defined (ACE_HAS_THREADS) + ACE_UNUSED_ARG (attributes); +#endif /* ACE_HAS_THREADS */ + ACE_TRACE ("ACE_Thread_Manager::ACE_Thread_Manager"); +} + +#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) +ACE_Thread_Manager * +ACE_Thread_Manager::instance (void) +{ + ACE_TRACE ("ACE_Thread_Manager::instance"); + + if (ACE_Thread_Manager::thr_mgr_ == 0) + { + // Perform Double-Checked Locking Optimization. + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + + if (ACE_Thread_Manager::thr_mgr_ == 0) + { + ACE_NEW_RETURN (ACE_Thread_Manager::thr_mgr_, + ACE_Thread_Manager, + 0); + ACE_Thread_Manager::delete_thr_mgr_ = true; + } + } + + return ACE_Thread_Manager::thr_mgr_; +} + +ACE_Thread_Manager * +ACE_Thread_Manager::instance (ACE_Thread_Manager *tm) +{ + ACE_TRACE ("ACE_Thread_Manager::instance"); + ACE_MT (ACE_GUARD_RETURN (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance (), 0)); + + ACE_Thread_Manager *t = ACE_Thread_Manager::thr_mgr_; + // We can't safely delete it since we don't know who created it! + ACE_Thread_Manager::delete_thr_mgr_ = false; + + ACE_Thread_Manager::thr_mgr_ = tm; + return t; +} + +void +ACE_Thread_Manager::close_singleton (void) +{ + ACE_TRACE ("ACE_Thread_Manager::close_singleton"); + + ACE_MT (ACE_GUARD (ACE_Recursive_Thread_Mutex, ace_mon, + *ACE_Static_Object_Lock::instance ())); + + if (ACE_Thread_Manager::delete_thr_mgr_) + { + // First, we clean up the thread descriptor list. + ACE_Thread_Manager::thr_mgr_->close (); + delete ACE_Thread_Manager::thr_mgr_; + ACE_Thread_Manager::thr_mgr_ = 0; + ACE_Thread_Manager::delete_thr_mgr_ = false; + } + + ACE_Thread_Exit::cleanup (ACE_Thread_Manager::thr_exit_); +} +#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ + +// Close up and release all resources. + +int +ACE_Thread_Manager::close () +{ + ACE_TRACE ("ACE_Thread_Manager::close"); + + // Clean up the thread descriptor list. + if (this->automatic_wait_) + this->wait (0, 1); + else + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + this->remove_thr_all (); + } + + return 0; +} + +ACE_Thread_Manager::~ACE_Thread_Manager (void) +{ + ACE_TRACE ("ACE_Thread_Manager::~ACE_Thread_Manager"); + this->close (); +} + + +// Run the entry point for thread spawned under the control of the +// . This must be an extern "C" to make certain +// compilers happy... +// +// The interaction with and +// works like this, with +// ACE_HAS_THREAD_SPECIFIC_STORAGE or ACE_HAS_TSS_EMULATION: +// +// o Every thread in the is run with +// . +// +// o retrieves the singleton +// instance from . +// The singleton gets created in thread-specific storage +// in the first call to that function. The key point is that the +// instance is in thread-specific storage. +// +// o A thread can exit by various means, such as , C++ +// or Win32 exception, "falling off the end" of the thread entry +// point function, etc. +// +// o If you follow this so far, now it gets really fun . . . +// When the thread-specific storage (for the thread that +// is being destroyed) is cleaned up, the OS threads package (or +// the ACE emulation of thread-specific storage) will destroy any +// objects that are in thread-specific storage. It has a list of +// them, and just walks down the list and destroys each one. +// +// o That's where the ACE_Thread_Exit destructor gets called. + +#if defined(ACE_USE_THREAD_MANAGER_ADAPTER) +extern "C" void * +ace_thread_manager_adapter (void *args) +{ +#if defined (ACE_HAS_TSS_EMULATION) + // As early as we can in the execution of the new thread, allocate + // its local TS storage. Allocate it on the stack, to save dynamic + // allocation/dealloction. + void *ts_storage[ACE_TSS_Emulation::ACE_TSS_THREAD_KEYS_MAX]; + ACE_TSS_Emulation::tss_open (ts_storage); +#endif /* ACE_HAS_TSS_EMULATION */ + + ACE_Thread_Adapter *thread_args = reinterpret_cast (args); + + // NOTE: this preprocessor directive should match the one in above + // ACE_Thread_Exit::instance (). With the Xavier Pthreads package, + // the exit_hook in TSS causes a seg fault. So, this works around + // that by creating exit_hook on the stack. +#if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || defined (ACE_HAS_TSS_EMULATION) + // Obtain our thread-specific exit hook and make sure that it knows + // how to clean us up! Note that we never use this pointer directly + // (it's stored in thread-specific storage), so it's ok to + // dereference it here and only store it as a reference. + ACE_Thread_Exit &exit_hook = *ACE_Thread_Exit::instance (); +#else + // Without TSS, create an instance. When this + // function returns, its destructor will be called because the + // object goes out of scope. The drawback with this appraoch is + // that the destructor _won't_ get called if is called. + // So, threads shouldn't exit that way. Instead, they should return + // from . + ACE_Thread_Exit exit_hook; +#endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */ + + // Keep track of the that's associated with this + // . + exit_hook.thr_mgr (thread_args->thr_mgr ()); + + // Invoke the user-supplied function with the args. + ACE_THR_FUNC_RETURN status = thread_args->invoke (); + + delete static_cast (thread_args); + + return reinterpret_cast (status); +} +#endif + +// Call the appropriate OS routine to spawn a thread. Should *not* be +// called with the lock_ held... + +int +ACE_Thread_Manager::spawn_i (ACE_THR_FUNC func, + void *args, + long flags, + ACE_thread_t *t_id, + ACE_hthread_t *t_handle, + long priority, + int grp_id, + void *stack, + size_t stack_size, + ACE_Task_Base *task, + const char** thr_name) +{ + // First, threads created by Thread Manager should not be daemon threads. + // Using assertion is probably a bit too strong. However, it helps + // finding this kind of error as early as possible. Perhaps we can replace + // assertion by returning error. + ACE_ASSERT (ACE_BIT_DISABLED (flags, THR_DAEMON)); + + // Create a new thread running . *Must* be called with the + // held... + // Get a "new" Thread Descriptor from the freelist. +#if defined (ACE_HAS_CPP11) + std::unique_ptr new_thr_desc (this->thread_desc_freelist_.remove ()); +#else + auto_ptr new_thr_desc (this->thread_desc_freelist_.remove ()); +#endif /* ACE_HAS_CPP11 */ + + // Reset thread descriptor status + new_thr_desc->reset (this); + + ACE_Thread_Adapter *thread_args = 0; +# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) + ACE_NEW_RETURN (thread_args, + ACE_Thread_Adapter (func, + args, + (ACE_THR_C_FUNC) ACE_THREAD_ADAPTER_NAME, + this, + new_thr_desc.get (), + ACE_OS_Object_Manager::seh_except_selector(), + ACE_OS_Object_Manager::seh_except_handler(), + flags), + -1); +# else + ACE_NEW_RETURN (thread_args, + ACE_Thread_Adapter (func, + args, + (ACE_THR_C_FUNC) ACE_THREAD_ADAPTER_NAME, + this, + new_thr_desc.get (), + flags), + -1); +# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */ +#if defined ACE_HAS_CPP11 + std::unique_ptr auto_thread_args (static_cast (thread_args)); +#else + auto_ptr auto_thread_args (static_cast (thread_args)); +#endif + + ACE_TRACE ("ACE_Thread_Manager::spawn_i"); + ACE_hthread_t thr_handle; + + ACE_thread_t thr_id; + if (t_id == 0) + t_id = &thr_id; + + // Acquire the lock to block the spawned thread from + // removing this Thread Descriptor before it gets put into our + // thread table. + new_thr_desc->sync_->acquire (); + + int const result = ACE_Thread::spawn (func, + args, + flags, + t_id, + &thr_handle, + priority, + stack, + stack_size, + thread_args, + thr_name); + + if (result != 0) + { + // _Don't_ clobber errno here! result is either 0 or -1, and + // ACE_OS::thr_create () already set errno! D. Levine 28 Mar 1997 + // errno = result; + ACE_Errno_Guard guard (errno); // Lock release may smash errno + new_thr_desc->sync_->release (); + return -1; + } + auto_thread_args.release (); + +#if defined (ACE_HAS_WTHREADS) + // Have to duplicate handle if client asks for it. + // @@ How are thread handles implemented on AIX? Do they + // also need to be duplicated? + if (t_handle != 0) +# if defined (ACE_LACKS_DUPLICATEHANDLE) + *t_handle = thr_handle; +# else /* ! ACE_LACKS_DUP */ + (void) ::DuplicateHandle (::GetCurrentProcess (), + thr_handle, + ::GetCurrentProcess (), + t_handle, + 0, + TRUE, + DUPLICATE_SAME_ACCESS); +# endif /* ! ACE_LACKS_DUP */ +#else /* ! ACE_HAS_WTHREADS */ + if (t_handle != 0) + *t_handle = thr_handle; +#endif /* ! ACE_HAS_WTHREADS */ + + // append_thr also put the into Thread_Manager's + // double-linked list. Only after this point, can we manipulate + // double-linked list from a spawned thread's context. + return this->append_thr (*t_id, + thr_handle, + ACE_THR_SPAWNED, + grp_id, + task, + flags, + new_thr_desc.release ()); +} + +int +ACE_Thread_Manager::spawn (ACE_THR_FUNC func, + void *args, + long flags, + ACE_thread_t *t_id, + ACE_hthread_t *t_handle, + long priority, + int grp_id, + void *stack, + size_t stack_size, + const char** thr_name) +{ + ACE_TRACE ("ACE_Thread_Manager::spawn"); + + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + if (grp_id == -1) + grp_id = this->grp_id_++; // Increment the group id. + + if (priority != ACE_DEFAULT_THREAD_PRIORITY) + ACE_CLR_BITS (flags, THR_INHERIT_SCHED); + + if (this->spawn_i (func, + args, + flags, + t_id, + t_handle, + priority, + grp_id, + stack, + stack_size, + 0, + thr_name) == -1) + return -1; + + return grp_id; +} + +// Create N new threads running FUNC. + +int +ACE_Thread_Manager::spawn_n (size_t n, + ACE_THR_FUNC func, + void *args, + long flags, + long priority, + int grp_id, + ACE_Task_Base *task, + ACE_hthread_t thread_handles[], + void *stack[], + size_t stack_size[], + const char* thr_name[]) +{ + ACE_TRACE ("ACE_Thread_Manager::spawn_n"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + if (grp_id == -1) + grp_id = this->grp_id_++; // Increment the group id. + + for (size_t i = 0; i < n; i++) + { + // @@ What should happen if this fails?! e.g., should we try to + // cancel the other threads that we've already spawned or what? + if (this->spawn_i (func, + args, + flags, + 0, + thread_handles == 0 ? 0 : &thread_handles[i], + priority, + grp_id, + stack == 0 ? 0 : stack[i], + stack_size == 0 ? ACE_DEFAULT_THREAD_STACKSIZE : stack_size[i], + task, + thr_name == 0 ? 0 : &thr_name [i]) == -1) + return -1; + } + + return grp_id; +} + +// Create N new threads running FUNC. + +int +ACE_Thread_Manager::spawn_n (ACE_thread_t thread_ids[], + size_t n, + ACE_THR_FUNC func, + void *args, + long flags, + long priority, + int grp_id, + void *stack[], + size_t stack_size[], + ACE_hthread_t thread_handles[], + ACE_Task_Base *task, + const char* thr_name[]) +{ + ACE_TRACE ("ACE_Thread_Manager::spawn_n"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + if (grp_id == -1) + grp_id = this->grp_id_++; // Increment the group id. + + for (size_t i = 0; i < n; i++) + { + // @@ What should happen if this fails?! e.g., should we try to + // cancel the other threads that we've already spawned or what? + if (this->spawn_i (func, + args, + flags, + thread_ids == 0 ? 0 : &thread_ids[i], + thread_handles == 0 ? 0 : &thread_handles[i], + priority, + grp_id, + stack == 0 ? 0 : stack[i], + stack_size == 0 ? ACE_DEFAULT_THREAD_STACKSIZE : stack_size[i], + task, + thr_name == 0 ? 0 : &thr_name [i]) == -1) + return -1; + } + + return grp_id; +} + +// Append a thread into the pool (does not check for duplicates). +// Must be called with locks held. + +int +ACE_Thread_Manager::append_thr (ACE_thread_t t_id, + ACE_hthread_t t_handle, + ACE_UINT32 thr_state, + int grp_id, + ACE_Task_Base *task, + long flags, + ACE_Thread_Descriptor *td) +{ + ACE_TRACE ("ACE_Thread_Manager::append_thr"); + ACE_Thread_Descriptor *thr_desc = 0; + + if (td == 0) + { + ACE_NEW_RETURN (thr_desc, + ACE_Thread_Descriptor, + -1); + thr_desc->tm_ = this; + // Setup the Thread_Manager. + } + else + thr_desc = td; + + thr_desc->thr_id_ = t_id; + thr_desc->thr_handle_ = t_handle; + thr_desc->grp_id_ = grp_id; + thr_desc->task_ = task; + thr_desc->flags_ = flags; + + this->thr_list_.insert_head (thr_desc); + ACE_SET_BITS (thr_desc->thr_state_, thr_state); + thr_desc->sync_->release (); + + return 0; +} + +// Return the thread descriptor (indexed by ACE_hthread_t). + +ACE_Thread_Descriptor * +ACE_Thread_Manager::find_hthread (ACE_hthread_t h_id) +{ + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (ACE_OS::thr_cmp (iter.next ()->thr_handle_, h_id)) + { + return iter.next (); + } + } + + return 0; +} + +// Locate the index in the table associated with . Must be +// called with the lock held. + +ACE_Thread_Descriptor * +ACE_Thread_Manager::find_thread (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::find_thread"); + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (ACE_OS::thr_equal (iter.next ()->thr_id_, t_id)) + { + return iter.next (); + } + } + return 0; +} + +// Insert a thread into the pool (checks for duplicates and doesn't +// allow them to be inserted twice). + +int +ACE_Thread_Manager::insert_thr (ACE_thread_t t_id, + ACE_hthread_t t_handle, + int grp_id, + long flags) +{ + ACE_TRACE ("ACE_Thread_Manager::insert_thr"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + // Check for duplicates and bail out if we're already registered... + if (this->find_thread (t_id) != 0 ) + return -1; + + if (grp_id == -1) + grp_id = this->grp_id_++; + + if (this->append_thr (t_id, + t_handle, + ACE_THR_SPAWNED, + grp_id, + 0, + flags) == -1) + return -1; + + return grp_id; +} + +// Run the registered hooks when the thread exits. + +void +ACE_Thread_Manager::run_thread_exit_hooks (int i) +{ +#if 0 // currently unused! + ACE_TRACE ("ACE_Thread_Manager::run_thread_exit_hooks"); + + // @@ Currently, we have just one hook. This should clearly be + // generalized to support an arbitrary number of hooks. + + ACE_Thread_Descriptor *td = this->thread_desc_self (); + for (ACE_Cleanup_Info_Node *iter = td->cleanup_info_->pop_front (); + iter != 0; + iter = cleanup_info_->pop_front ()) + { + if (iter->cleanup_hook () != 0) + { + (*iter->cleanup_hook ()) (iter->object (), iter->param ()); + } + delete iter; + } + + ACE_UNUSED_ARG (i); +#else + ACE_UNUSED_ARG (i); +#endif /* 0 */ +} + +// Remove a thread from the pool. Must be called with locks held. + +void +ACE_Thread_Manager::remove_thr (ACE_Thread_Descriptor *td, + int close_handler) +{ + ACE_TRACE ("ACE_Thread_Manager::remove_thr"); + + td->tm_ = 0; + this->thr_list_.remove (td); + +#if defined (ACE_WIN32) + if (close_handler != 0) + ::CloseHandle (td->thr_handle_); +#else + ACE_UNUSED_ARG (close_handler); +#endif /* ACE_WIN32 */ + + this->thread_desc_freelist_.add (td); + +#if defined (ACE_HAS_THREADS) + // Tell all waiters when there are no more threads left in the pool. + if (this->thr_list_.size () == 0) + this->zero_cond_.broadcast (); +#endif /* ACE_HAS_THREADS */ +} + +// Repeatedly call remove_thr on all table entries until there +// is no thread left. Must be called with lock held. +void +ACE_Thread_Manager::remove_thr_all (void) +{ + ACE_Thread_Descriptor *td = 0; + + while ((td = this->thr_list_.delete_head ()) != 0) + { + this->remove_thr (td, 1); + } +} + +// ------------------------------------------------------------------ +// Factor out some common behavior to simplify the following methods. +#define ACE_THR_OP(OP,STATE) \ + int result = OP (td->thr_handle_); \ + if (result == -1) { \ + if (errno != ENOTSUP) \ + this->thr_to_be_removed_.enqueue_tail (td); \ + return -1; \ + } \ + else { \ + ACE_SET_BITS (td->thr_state_, STATE); \ + return 0; \ + } + +int +ACE_Thread_Manager::join_thr (ACE_Thread_Descriptor *td, int) +{ + ACE_TRACE ("ACE_Thread_Manager::join_thr"); + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + if (ACE_BIT_DISABLED (td->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (td->flags_, THR_JOINABLE)) + { + if (td->terminated_) + return 0; + ACE_SET_BITS (td->thr_state_, ACE_THR_JOINING); + } + else + { + errno = EINVAL; + return -1; + } + + const ACE_thread_t waiting_id = td->thr_id_; + + while (true) + { + if (this->join_cond_.wait () == -1) + return -1; + + bool found = false; + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done () && !found; iter.advance ()) + if (ACE_OS::thr_equal (iter.next ()->thr_id_, waiting_id)) + found = true; + if (!found) + break; + } + +#else + int const result = ACE_Thread::join (td->thr_handle_); + if (result != 0) + { + // Since the thread are being joined, we should + // let it remove itself from the list. + + // this->remove_thr (td); + errno = result; + return -1; + } +#endif // ACE_HAS_THREADS && ACE_LACKS_PTHREAD_JOIN + + return 0; +} + +int +ACE_Thread_Manager::suspend_thr (ACE_Thread_Descriptor *td, int) +{ + ACE_TRACE ("ACE_Thread_Manager::suspend_thr"); + + int const result = ACE_Thread::suspend (td->thr_handle_); + if (result == -1) { + if (errno != ENOTSUP) + this->thr_to_be_removed_.enqueue_tail (td); + return -1; + } + else { + ACE_SET_BITS (td->thr_state_, ACE_THR_SUSPENDED); + return 0; + } +} + +int +ACE_Thread_Manager::resume_thr (ACE_Thread_Descriptor *td, int) +{ + ACE_TRACE ("ACE_Thread_Manager::resume_thr"); + + int const result = ACE_Thread::resume (td->thr_handle_); + if (result == -1) { + if (errno != ENOTSUP) + this->thr_to_be_removed_.enqueue_tail (td); + return -1; + } + else { + ACE_CLR_BITS (td->thr_state_, ACE_THR_SUSPENDED); + return 0; + } +} + +int +ACE_Thread_Manager::cancel_thr (ACE_Thread_Descriptor *td, int async_cancel) +{ + ACE_TRACE ("ACE_Thread_Manager::cancel_thr"); + // Must set the state first and then try to cancel the thread. + ACE_SET_BITS (td->thr_state_, ACE_THR_CANCELLED); + + if (async_cancel != 0) + // Note that this call only does something relevant if the OS + // platform supports asynchronous thread cancellation. Otherwise, + // it's a no-op. + return ACE_Thread::cancel (td->thr_id_); + + return 0; +} + +int +ACE_Thread_Manager::kill_thr (ACE_Thread_Descriptor *td, int signum) +{ + ACE_TRACE ("ACE_Thread_Manager::kill_thr"); + + ACE_thread_t tid = td->thr_id_; + + int const result = ACE_Thread::kill (tid, signum); + + if (result != 0) + { + // Only remove a thread from us when there is a "real" error. + if (errno != ENOTSUP) + this->thr_to_be_removed_.enqueue_tail (td); + + return -1; + } + + return 0; +} + +// ------------------------------------------------------------------ +// Factor out some common behavior to simplify the following methods. +#define ACE_EXECUTE_OP(OP, ARG) \ + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); \ + ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); \ + ACE_FIND (this->find_thread (t_id), ptr); \ + if (ptr == 0) \ + { \ + errno = ENOENT; \ + return -1; \ + } \ + int const result = OP (ptr, ARG); \ + ACE_Errno_Guard error (errno); \ + while (! this->thr_to_be_removed_.is_empty ()) { \ + ACE_Thread_Descriptor * td = 0; \ + this->thr_to_be_removed_.dequeue_head (td); \ + this->remove_thr (td, 1); \ + } \ + return result + +// Suspend a single thread. + +int +ACE_Thread_Manager::suspend (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::suspend"); + ACE_EXECUTE_OP (this->suspend_thr, 0); +} + +// Resume a single thread. + +int +ACE_Thread_Manager::resume (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::resume"); + ACE_EXECUTE_OP (this->resume_thr, 0); +} + +// Cancel a single thread. + +int +ACE_Thread_Manager::cancel (ACE_thread_t t_id, int async_cancel) +{ + ACE_TRACE ("ACE_Thread_Manager::cancel"); + ACE_EXECUTE_OP (this->cancel_thr, async_cancel); +} + +// Send a signal to a single thread. + +int +ACE_Thread_Manager::kill (ACE_thread_t t_id, int signum) +{ + ACE_TRACE ("ACE_Thread_Manager::kill"); + ACE_EXECUTE_OP (this->kill_thr, signum); +} + +int +ACE_Thread_Manager::check_state (ACE_UINT32 state, + ACE_thread_t id, + int enable) +{ + ACE_TRACE ("ACE_Thread_Manager::check_state"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + ACE_UINT32 thr_state; + + int self_check = ACE_OS::thr_equal (id, ACE_OS::thr_self ()); + + // If we're checking the state of our thread, try to get the cached + // value out of TSS to avoid lookup. + if (self_check) + { + ACE_Thread_Descriptor *desc = ACE_LOG_MSG->thr_desc (); + if (desc == 0) + return 0; // Always return false. + thr_state = desc->thr_state_; + } + else + { + // Not calling from self, have to look it up from the list. + ACE_FIND (this->find_thread (id), ptr); + if (ptr == 0) + return 0; + thr_state = ptr->thr_state_; + } + if (enable) + return ACE_BIT_ENABLED (thr_state, state); + + return ACE_BIT_DISABLED (thr_state, state); +} + +// Test if a single thread has terminated. + +int +ACE_Thread_Manager::testterminate (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::testterminate"); + return this->check_state (ACE_THR_TERMINATED, t_id); +} + +// Test if a single thread is suspended. + +int +ACE_Thread_Manager::testsuspend (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::testsuspend"); + return this->check_state (ACE_THR_SUSPENDED, t_id); +} + +// Test if a single thread is active (i.e., resumed). + +int +ACE_Thread_Manager::testresume (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::testresume"); + return this->check_state (ACE_THR_SUSPENDED, t_id, 0); +} + +// Test if a single thread is cancelled. + +int +ACE_Thread_Manager::testcancel (ACE_thread_t t_id) +{ + ACE_TRACE ("ACE_Thread_Manager::testcancel"); + return this->check_state (ACE_THR_CANCELLED, t_id); +} + +// Thread information query functions. + +int +ACE_Thread_Manager::hthread_within (ACE_hthread_t handle) +{ + ACE_TRACE ("ACE_Thread_Manager::hthread_within"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1)); + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (ACE_OS::thr_cmp(iter.next ()->thr_handle_, handle)) + { + return 1; + } + } + + return 0; +} + +int +ACE_Thread_Manager::thread_within (ACE_thread_t tid) +{ + ACE_TRACE ("ACE_Thread_Manager::thread_within"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1)); + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (ACE_OS::thr_equal (iter.next ()->thr_id_, tid)) + { + return 1; + } + } + + return 0; +} + +// Get group ids for a particular thread id. + +int +ACE_Thread_Manager::get_grp (ACE_thread_t t_id, int &grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::get_grp"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + ACE_FIND (this->find_thread (t_id), ptr); + + if (ptr) + grp_id = ptr->grp_id_; + else + return -1; + return 0; +} + +// Set group ids for a particular thread id. + +int +ACE_Thread_Manager::set_grp (ACE_thread_t t_id, int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::set_grp"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + ACE_FIND (this->find_thread (t_id), ptr); + if (ptr) + ptr->grp_id_ = grp_id; + else + return -1; + return 0; +} + +// Suspend a group of threads. + +int +ACE_Thread_Manager::apply_grp (int grp_id, + ACE_THR_MEMBER_FUNC func, + int arg) +{ + ACE_TRACE ("ACE_Thread_Manager::apply_grp"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_monx, this->lock_, -1)); + ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); + + int result = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (iter.next ()->grp_id_ == grp_id) + { + if ((this->*func) (iter.next (), arg) == -1) + { + result = -1; + } + } + } + + // Must remove threads after we have traversed the thr_list_ to + // prevent clobber thr_list_'s integrity. + + if (! this->thr_to_be_removed_.is_empty ()) + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + + for (ACE_Thread_Descriptor *td; + this->thr_to_be_removed_.dequeue_head (td) != -1; + ) + this->remove_thr (td, 1); + } + + return result; +} + +int +ACE_Thread_Manager::suspend_grp (int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::suspend_grp"); + return this->apply_grp (grp_id, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr)); +} + +// Resume a group of threads. + +int +ACE_Thread_Manager::resume_grp (int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::resume_grp"); + return this->apply_grp (grp_id, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr)); +} + +// Kill a group of threads. + +int +ACE_Thread_Manager::kill_grp (int grp_id, int signum) +{ + ACE_TRACE ("ACE_Thread_Manager::kill_grp"); + return this->apply_grp (grp_id, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::kill_thr), signum); +} + +// Cancel a group of threads. + +int +ACE_Thread_Manager::cancel_grp (int grp_id, int async_cancel) +{ + ACE_TRACE ("ACE_Thread_Manager::cancel_grp"); + return this->apply_grp (grp_id, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr), + async_cancel); +} + +int +ACE_Thread_Manager::apply_all (ACE_THR_MEMBER_FUNC func, int arg) +{ + ACE_TRACE ("ACE_Thread_Manager::apply_all"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); + + int result = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if ((this->*func)(iter.next (), arg) == -1) + { + result = -1; + } + } + + // Must remove threads after we have traversed the thr_list_ to + // prevent clobber thr_list_'s integrity. + + if (! this->thr_to_be_removed_.is_empty ()) + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + + for (ACE_Thread_Descriptor *td; + this->thr_to_be_removed_.dequeue_head (td) != -1; + ) + this->remove_thr (td, 1); + } + + return result; +} + +// Resume all threads that are suspended. + +int +ACE_Thread_Manager::resume_all (void) +{ + ACE_TRACE ("ACE_Thread_Manager::resume_all"); + return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr)); +} + +int +ACE_Thread_Manager::suspend_all (void) +{ + ACE_TRACE ("ACE_Thread_Manager::suspend_all"); + return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr)); +} + +int +ACE_Thread_Manager::kill_all (int sig) +{ + ACE_TRACE ("ACE_Thread_Manager::kill_all"); + return this->apply_all (&ACE_Thread_Manager::kill_thr, sig); +} + +int +ACE_Thread_Manager::cancel_all (int async_cancel) +{ + ACE_TRACE ("ACE_Thread_Manager::cancel_all"); + return this->apply_all (ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr), + async_cancel); +} + +int +ACE_Thread_Manager::join (ACE_thread_t tid, ACE_THR_FUNC_RETURN *status) +{ + ACE_TRACE ("ACE_Thread_Manager::join"); + + bool found = false; + ACE_Thread_Descriptor_Base tdb; + + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + +#if !defined (ACE_HAS_VXTHREADS) + for (ACE_Double_Linked_List_Iterator biter (this->terminated_thr_list_); + !biter.done (); + biter.advance ()) + { + if (ACE_OS::thr_equal (biter.next ()->thr_id_, tid)) + { + ACE_Thread_Descriptor_Base *tdbl = biter.advance_and_remove (false); +#ifndef ACE_LACKS_PTHREAD_JOIN + if (ACE_Thread::join (tdbl->thr_handle_, status) == -1) + { + return -1; + } +#endif + delete tdbl; + + // return immediately if we've found the thread we want to join. + return 0; + } + } +#endif /* !ACE_HAS_VXTHREADS */ + + typedef ACE_Double_Linked_List_Iterator iter_t; + for (iter_t iter (this->thr_list_); !iter.done (); iter.advance ()) + { + // If threads are created as THR_DETACHED or THR_DAEMON, we + // can't help much. + if (ACE_OS::thr_equal (iter.next ()->thr_id_,tid) && + (ACE_BIT_DISABLED (iter.next ()->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE))) + { + tdb = *iter.next (); + ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING); + found = true; + break; + } + } + + if (!found) + return -1; + // Didn't find the thread we want or the thread is not joinable. + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + ACE_UNUSED_ARG (status); // not currently supported without pthread_join + + while (found) + { + if (this->join_cond_.wait () == -1) + return -1; + + found = false; + for (iter_t iter (this->thr_list_); !iter.done () && !found; iter.advance ()) + if (ACE_OS::thr_equal (iter.next ()->thr_id_, tid) && + (ACE_BIT_DISABLED (iter.next ()->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE))) + found = true; + } + +#endif // ACE_HAS_THREADS && ACE_LACKS_PTHREAD_JOIN + + } + +#ifndef ACE_LACKS_PTHREAD_JOIN + if (ACE_Thread::join (tdb.thr_handle_, status) == -1) + return -1; +#endif + + return 0; +} + +// Wait for group of threads + +int +ACE_Thread_Manager::wait_grp (int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::wait_grp"); + + int copy_count = 0; + ACE_Thread_Descriptor_Base *copy_table = 0; + + // We have to make sure that while we wait for these threads to + // exit, we do not have the lock. Therefore we make a copy of all + // interesting entries and let go of the lock. + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + +#if !defined (ACE_HAS_VXTHREADS) + ACE_NEW_RETURN (copy_table, + ACE_Thread_Descriptor_Base [this->thr_list_.size () + + this->terminated_thr_list_.size ()], + -1); +#else + ACE_NEW_RETURN (copy_table, + ACE_Thread_Descriptor_Base [this->thr_list_.size ()], + -1); +#endif /* !ACE_HAS_VXTHREADS */ + + typedef ACE_Double_Linked_List_Iterator iter_t; + for (iter_t iter (this->thr_list_); !iter.done (); iter.advance ()) + { + // If threads are created as THR_DETACHED or THR_DAEMON, we + // can't help much. + if (iter.next ()->grp_id_ == grp_id && + (ACE_BIT_DISABLED (iter.next ()->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE))) + { + ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING); + copy_table[copy_count++] = *iter.next (); + } + } + +#if !defined (ACE_HAS_VXTHREADS) + for (ACE_Double_Linked_List_Iterator biter (this->terminated_thr_list_); + !biter.done (); + biter.advance ()) + { + // If threads are created as THR_DETACHED or THR_DAEMON, we + // can't help much. + if (biter.next ()->grp_id_ == grp_id) + { + ACE_Thread_Descriptor_Base *tdb = biter.advance_and_remove (false); + copy_table[copy_count++] = *tdb; + delete tdb; + } + } +#endif /* !ACE_HAS_VXTHREADS */ + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + + while (copy_count) + { + if (this->join_cond_.wait () == -1) + { + delete[] copy_table; + return -1; + } + + copy_count = 0; + for (iter_t iter (this->thr_list_); !iter.done () && !copy_count; iter.advance ()) + if (iter.next ()->grp_id_ == grp_id && + ACE_BIT_ENABLED (iter.next ()->thr_state_, ACE_THR_JOINING) && + (ACE_BIT_DISABLED (iter.next ()->flags_, + THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE))) + ++copy_count; + } + +#endif // ACE_HAS_THREADS && ACE_LACKS_PTHREAD_JOIN + } + + // Now actually join() with all the threads in this group. + int result = 0; + + for (int i = 0; + i < copy_count && result != -1; + i++) + { + if (ACE_Thread::join (copy_table[i].thr_handle_) == -1) + result = -1; + } + + delete [] copy_table; + + return result; +} + +// Must be called when thread goes out of scope to clean up its table +// slot. + +ACE_THR_FUNC_RETURN +ACE_Thread_Manager::exit (ACE_THR_FUNC_RETURN status, bool do_thread_exit) +{ + ACE_TRACE ("ACE_Thread_Manager::exit"); +#if defined (ACE_WIN32) + // Remove detached thread handle. + + if (do_thread_exit) + { +#if 0 + // @@ This callback is now taken care of by TSS_Cleanup. Do we + // need it anymore? + + // On Win32, if we really wants to exit from a thread, we must + // first clean up the thread specific storage. By doing so, + // ACE_Thread_Manager::exit will be called again with + // do_thr_exit = 0 and cleaning up the ACE_Cleanup_Info (but not + // exiting the thread.) After the following call returns, we + // are safe to exit this thread. + delete ACE_Thread_Exit::instance (); +#endif /* 0 */ + ACE_Thread::exit (status); + } +#endif /* ACE_WIN32 */ + + // Just hold onto the guard while finding this thread's id and + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, 0)); + + // Find the thread id, but don't use the cache. It might have been + // deleted already. + ACE_thread_t const id = ACE_OS::thr_self (); + ACE_Thread_Descriptor* td = this->find_thread (id); + if (td != 0) + { + // @@ We call Thread_Descriptor terminate this realize the cleanup + // process itself. + td->terminate(); + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + this->join_cond_.broadcast (); +#endif + } + } + + if (do_thread_exit) + { + ACE_Thread::exit (status); + // On reasonable systems should not return. + // However, due to horrible semantics with Win32 thread-specific + // storage this call can return (don't ask...). + } + + return 0; +} + +// Wait for all the threads to exit. + +int +ACE_Thread_Manager::wait (const ACE_Time_Value *timeout, + bool abandon_detached_threads, + bool use_absolute_time) +{ + ACE_TRACE ("ACE_Thread_Manager::wait"); + + ACE_Auto_Ptr local_timeout; + // Check to see if we're using absolute time or not. + if (use_absolute_time == false && timeout != 0) + { + // create time value duplicate (preserves time policy) + local_timeout.reset (timeout->duplicate ()); + // convert time value to absolute time + (*local_timeout) = local_timeout->to_absolute_time (); + // replace original time by abs time duplicate + timeout = local_timeout.get (); + } + +#if !defined (ACE_HAS_VXTHREADS) + ACE_Double_Linked_List term_thr_list_copy; +#endif /* ACE_HAS_VXTHREADS */ + +#if defined (ACE_HAS_THREADS) + { + // Just hold onto the guard while waiting. + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + if (ACE_Object_Manager::shutting_down () != 1) + { + // Program is not shutting down. Perform a normal wait on threads. + if (abandon_detached_threads != 0) + { + ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); + for (ACE_Double_Linked_List_Iterator + iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (ACE_BIT_ENABLED (iter.next ()->flags_, + THR_DETACHED | THR_DAEMON) + && ACE_BIT_DISABLED (iter.next ()->flags_, THR_JOINABLE)) + { + this->thr_to_be_removed_.enqueue_tail (iter.next ()); + ACE_SET_BITS (iter.next ()->thr_state_, ACE_THR_JOINING); + } + } + + if (! this->thr_to_be_removed_.is_empty ()) + { + ACE_Thread_Descriptor *td = 0; + while (this->thr_to_be_removed_.dequeue_head (td) != -1) + this->remove_thr (td, 1); + } + } + + while (this->thr_list_.size () > 0) + if (this->zero_cond_.wait (timeout) == -1) + return -1; + } + else + // Program is shutting down, no chance to wait on threads. + // Therefore, we'll just remove threads from the list. + this->remove_thr_all (); + +#if !defined (ACE_HAS_VXTHREADS) + ACE_Thread_Descriptor_Base* item = 0; + while ((item = this->terminated_thr_list_.delete_head ()) != 0) + { + term_thr_list_copy.insert_tail (item); + } +#endif /* ACE_HAS_VXTHREADS */ + // Release the guard, giving other threads a chance to run. + } + +#if !defined (ACE_HAS_VXTHREADS) + // @@ VxWorks doesn't support thr_join (yet.) We are working + // on our implementation. Chorus'es thr_join seems broken. + ACE_Thread_Descriptor_Base *item = 0; + + while ((item = term_thr_list_copy.delete_head ()) != 0) + { +#ifndef ACE_LACKS_PTHREAD_JOIN + if (ACE_BIT_DISABLED (item->flags_, THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (item->flags_, THR_JOINABLE)) + // Detached handles shouldn't reached here. + (void) ACE_Thread::join (item->thr_handle_); +#endif + delete item; + } + +#endif /* !ACE_HAS_VXTHREADS */ +#else + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (abandon_detached_threads); +#endif /* ACE_HAS_THREADS */ + + return 0; +} + +int +ACE_Thread_Manager::apply_task (ACE_Task_Base *task, + ACE_THR_MEMBER_FUNC func, + int arg) +{ + ACE_TRACE ("ACE_Thread_Manager::apply_task"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + ACE_ASSERT (this->thr_to_be_removed_.is_empty ()); + + int result = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + if (iter.next ()->task_ == task + && (this->*func) (iter.next (), arg) == -1) + result = -1; + + // Must remove threads after we have traversed the thr_list_ to + // prevent clobber thr_list_'s integrity. + + if (! this->thr_to_be_removed_.is_empty ()) + { + // Save/restore errno. + ACE_Errno_Guard error (errno); + + for (ACE_Thread_Descriptor *td = 0; + this->thr_to_be_removed_.dequeue_head (td) != -1; + ) + this->remove_thr (td, 1); + } + + return result; +} + +// Wait for all threads to exit a task. + +int +ACE_Thread_Manager::wait_task (ACE_Task_Base *task) +{ + int copy_count = 0; + ACE_Thread_Descriptor_Base *copy_table = 0; + + // We have to make sure that while we wait for these threads to + // exit, we do not have the lock. Therefore we make a copy of all + // interesting entries and let go of the lock. + { + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + +#if !defined (ACE_HAS_VXTHREADS) + ACE_NEW_RETURN (copy_table, + ACE_Thread_Descriptor_Base [this->thr_list_.size () + + this->terminated_thr_list_.size ()], + -1); +#else + ACE_NEW_RETURN (copy_table, + ACE_Thread_Descriptor_Base [this->thr_list_.size ()], + -1); +#endif /* !ACE_HAS_VXTHREADS */ + + typedef ACE_Double_Linked_List_Iterator iter_t; + for (iter_t iter (this->thr_list_); !iter.done (); iter.advance ()) + { + // If threads are created as THR_DETACHED or THR_DAEMON, we + // can't wait on them here. + if (iter.next ()->task_ == task && + (ACE_BIT_DISABLED (iter.next ()->flags_, + THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, + THR_JOINABLE))) + { +# ifdef ACE_LACKS_PTHREAD_JOIN + if (ACE_OS::thr_equal (iter.next ()->thr_id_, ACE_OS::thr_self ())) + { + errno = EDEADLK; + delete[] copy_table; + return -1; + } +# endif + ACE_SET_BITS (iter.next ()->thr_state_, + ACE_THR_JOINING); + copy_table[copy_count++] = *iter.next (); + } + } + +#if !defined (ACE_HAS_VXTHREADS) + for (ACE_Double_Linked_List_Iterator titer (this->terminated_thr_list_); + !titer.done (); + titer.advance ()) + { + // If threads are created as THR_DETACHED or THR_DAEMON, we can't help much here. + if (titer.next ()->task_ == task) + { + ACE_Thread_Descriptor_Base *tdb = titer.advance_and_remove (false); +# ifndef ACE_LACKS_PTHREAD_JOIN + copy_table[copy_count++] = *tdb; +# endif + delete tdb; + } + } +#endif /* !ACE_HAS_VXTHREADS */ + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + + while (copy_count) + { + if (this->join_cond_.wait () == -1) + { + delete[] copy_table; + return -1; + } + + copy_count = 0; + for (iter_t iter (this->thr_list_); !iter.done () && !copy_count; iter.advance ()) + if (iter.next ()->task_ == task && + ACE_BIT_ENABLED (iter.next ()->thr_state_, ACE_THR_JOINING) && + (ACE_BIT_DISABLED (iter.next ()->flags_, + THR_DETACHED | THR_DAEMON) + || ACE_BIT_ENABLED (iter.next ()->flags_, THR_JOINABLE))) + ++copy_count; + } + +#endif // ACE_HAS_THREADS && ACE_LACKS_PTHREAD_JOIN + } + + // Now to do the actual work + int result = 0; + + for (int i = 0; + i < copy_count && result != -1; + i++) + { + if (ACE_Thread::join (copy_table[i].thr_handle_) == -1) + result = -1; + } + + delete [] copy_table; + + return result; +} + +// Suspend a task + +int +ACE_Thread_Manager::suspend_task (ACE_Task_Base *task) +{ + ACE_TRACE ("ACE_Thread_Manager::suspend_task"); + return this->apply_task (task, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::suspend_thr)); +} + +// Resume a task. +int +ACE_Thread_Manager::resume_task (ACE_Task_Base *task) +{ + ACE_TRACE ("ACE_Thread_Manager::resume_task"); + return this->apply_task (task, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::resume_thr)); +} + +// Kill a task. + +int +ACE_Thread_Manager::kill_task (ACE_Task_Base *task, int /* signum */) +{ + ACE_TRACE ("ACE_Thread_Manager::kill_task"); + return this->apply_task (task, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::kill_thr)); +} + +// Cancel a task. +int +ACE_Thread_Manager::cancel_task (ACE_Task_Base *task, + int async_cancel) +{ + ACE_TRACE ("ACE_Thread_Manager::cancel_task"); + return this->apply_task (task, + ACE_THR_MEMBER_FUNC (&ACE_Thread_Manager::cancel_thr), + async_cancel); +} + +// Locate the index in the table associated with from the +// beginning of the table up to an index. Must be called with the +// lock held. + +ACE_Thread_Descriptor * +ACE_Thread_Manager::find_task (ACE_Task_Base *task, size_t slot) +{ + ACE_TRACE ("ACE_Thread_Manager::find_task"); + + size_t i = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (i >= slot) + break; + + if (task == iter.next ()->task_) + return iter.next (); + + ++i; + } + + return 0; +} + +// Returns the number of ACE_Task in a group. + +int +ACE_Thread_Manager::num_tasks_in_group (int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::num_tasks_in_group"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + int tasks_count = 0; + size_t i = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (iter.next ()->grp_id_ == grp_id + && this->find_task (iter.next ()->task_, i) == 0 + && iter.next ()->task_ != 0) + { + ++tasks_count; + } + + ++i; + } + return tasks_count; +} + +// Returns the number of threads in an ACE_Task. + +int +ACE_Thread_Manager::num_threads_in_task (ACE_Task_Base *task) +{ + ACE_TRACE ("ACE_Thread_Manager::num_threads_in_task"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + int threads_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (iter.next ()->task_ == task) + { + ++threads_count; + } + } + + return threads_count; +} + +// Returns in task_list a list of ACE_Tasks registered with ACE_Thread_Manager. + +ssize_t +ACE_Thread_Manager::task_all_list (ACE_Task_Base *task_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::task_all_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t task_list_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (task_list_count >= n) + { + break; + } + + ACE_Task_Base *task_p = iter.next ()->task_; + + if (0 != task_p) + { + // This thread has a task pointer; see if it's already in the + // list. Don't add duplicates. + size_t i = 0; + + for (; i < task_list_count; ++i) + { + if (task_list[i] == task_p) + { + break; + } + } + + if (i == task_list_count) // No match - add this one + { + task_list[task_list_count++] = task_p; + } + } + } + + return ACE_Utils::truncate_cast (task_list_count); +} + +// Returns in thread_list a list of all thread ids + +ssize_t +ACE_Thread_Manager::thread_all_list (ACE_thread_t thread_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::thread_all_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t thread_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (thread_count >= n) + { + break; + } + + thread_list[thread_count] = iter.next ()->thr_id_; + ++thread_count; + } + + return ACE_Utils::truncate_cast (thread_count); +} + + +int +ACE_Thread_Manager::thr_state (ACE_thread_t id, + ACE_UINT32& state) +{ + ACE_TRACE ("ACE_Thread_Manager::thr_state"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + int const self_check = ACE_OS::thr_equal (id, ACE_OS::thr_self ()); + + // If we're checking the state of our thread, try to get the cached + // value out of TSS to avoid lookup. + if (self_check) + { + ACE_Thread_Descriptor *desc = ACE_LOG_MSG->thr_desc (); + + if (desc == 0) + { + return 0; // Always return false. + } + + state = desc->thr_state_; + } + else + { + // Not calling from self, have to look it up from the list. + ACE_FIND (this->find_thread (id), ptr); + + if (ptr == 0) + { + return 0; + } + + state = ptr->thr_state_; + } + + return 1; +} + +// Returns in task_list a list of ACE_Tasks in a group. + +ssize_t +ACE_Thread_Manager::task_list (int grp_id, + ACE_Task_Base *task_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::task_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + ACE_Task_Base **task_list_iterator = task_list; + size_t task_list_count = 0; + size_t i = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (task_list_count >= n) + { + break; + } + + if (iter.next ()->grp_id_ == grp_id + && this->find_task (iter.next ()->task_, i) == 0) + { + task_list_iterator[task_list_count] = iter.next ()->task_; + ++task_list_count; + } + + ++i; + } + + return ACE_Utils::truncate_cast (task_list_count); +} + +// Returns in thread_list a list of thread ids in an ACE_Task. + +ssize_t +ACE_Thread_Manager::thread_list (ACE_Task_Base *task, + ACE_thread_t thread_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::thread_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t thread_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (thread_count >= n) + { + break; + } + + if (iter.next ()->task_ == task) + { + thread_list[thread_count] = iter.next ()->thr_id_; + ++thread_count; + } + } + + return ACE_Utils::truncate_cast (thread_count); +} + +// Returns in thread_list a list of thread handles in an ACE_Task. + +ssize_t +ACE_Thread_Manager::hthread_list (ACE_Task_Base *task, + ACE_hthread_t hthread_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::hthread_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t hthread_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (hthread_count >= n) + { + break; + } + + if (iter.next ()->task_ == task) + { + hthread_list[hthread_count] = iter.next ()->thr_handle_; + ++hthread_count; + } + } + + return ACE_Utils::truncate_cast (hthread_count); +} + +ssize_t +ACE_Thread_Manager::thread_grp_list (int grp_id, + ACE_thread_t thread_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::thread_grp_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t thread_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (thread_count >= n) + { + break; + } + + if (iter.next ()->grp_id_ == grp_id) + { + thread_list[thread_count] = iter.next ()->thr_id_; + thread_count++; + } + } + + return ACE_Utils::truncate_cast (thread_count); +} + +// Returns in thread_list a list of thread handles in an ACE_Task. + +ssize_t +ACE_Thread_Manager::hthread_grp_list (int grp_id, + ACE_hthread_t hthread_list[], + size_t n) +{ + ACE_TRACE ("ACE_Thread_Manager::hthread_grp_list"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + size_t hthread_count = 0; + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (hthread_count >= n) + { + break; + } + + if (iter.next ()->grp_id_ == grp_id) + { + hthread_list[hthread_count] = iter.next ()->thr_handle_; + hthread_count++; + } + } + + return ACE_Utils::truncate_cast (hthread_count); +} + +int +ACE_Thread_Manager::set_grp (ACE_Task_Base *task, int grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::set_grp"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + for (ACE_Double_Linked_List_Iterator iter (this->thr_list_); + !iter.done (); + iter.advance ()) + { + if (iter.next ()->task_ == task) + { + iter.next ()->grp_id_ = grp_id; + } + } + + return 0; +} + +int +ACE_Thread_Manager::get_grp (ACE_Task_Base *task, int &grp_id) +{ + ACE_TRACE ("ACE_Thread_Manager::get_grp"); + ACE_MT (ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1)); + + ACE_FIND (this->find_task (task), ptr); + grp_id = ptr->grp_id_; + return 0; +} + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Descriptor_Base); + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Manager.h b/dep/acelite/ace/Thread_Manager.h new file mode 100644 index 000000000..4945ef547 --- /dev/null +++ b/dep/acelite/ace/Thread_Manager.h @@ -0,0 +1,1280 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Thread_Manager.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_THREAD_MANAGER_H +#define ACE_THREAD_MANAGER_H +#include /**/ "ace/pre.h" + +#include "ace/Thread.h" +#include "ace/Thread_Adapter.h" +#include "ace/Thread_Exit.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Condition_Thread_Mutex.h" +#include "ace/Unbounded_Queue.h" +#include "ace/Containers.h" +#include "ace/Free_List.h" +#include "ace/Singleton.h" +#include "ace/Log_Category.h" +#include "ace/Synch_Traits.h" +#include "ace/Basic_Types.h" + +// The following macros control how a Thread Manager manages a pool of +// Thread_Descriptor. Currently, the default behavior is not to +// preallocate any thread descriptor and never (well, almost never) +// free up any thread descriptor until the Thread Manager gets +// destructed. Which means, once your system is stable, you rarely +// need to pay the price of memory allocation. On a deterministic +// system, which means, the number of threads spawned can be +// determined before hand, you can either redefine the memory pool +// size macros to suit your need or constructed the Thread_Manager +// accordingly. That way, you don't pay the price of memory +// allocation when the system is really doing its job. OTOH, on +// system with resources constraint, you may want to lower the size of +// ACE_DEFAULT_THREAD_MANAGER_HWM to avoid unused memory hanging +// around. + +#if !defined (ACE_DEFAULT_THREAD_MANAGER_PREALLOC) +# define ACE_DEFAULT_THREAD_MANAGER_PREALLOC 0 +#endif /* ACE_DEFAULT_THREAD_MANAGER_PREALLOC */ + +#if !defined (ACE_DEFAULT_THREAD_MANAGER_LWM) +# define ACE_DEFAULT_THREAD_MANAGER_LWM 1 +#endif /* ACE_DEFAULT_THREAD_MANAGER_LWM */ + +#if !defined (ACE_DEFAULT_THREAD_MANAGER_INC) +# define ACE_DEFAULT_THREAD_MANAGER_INC 1 +#endif /* ACE_DEFAULT_THREAD_MANAGER_INC */ + +#if !defined (ACE_DEFAULT_THREAD_MANAGER_HWM) +# define ACE_DEFAULT_THREAD_MANAGER_HWM ACE_DEFAULT_FREE_LIST_HWM +// this is a big number +#endif /* ACE_DEFAULT_THREAD_MANAGER_HWM */ + +// This is the synchronization mechanism used to prevent a thread +// descriptor gets removed from the Thread_Manager before it gets +// stash into it. If you want to disable this feature (and risk of +// corrupting the freelist,) you define the lock as ACE_Null_Mutex. +// Usually, if you can be sure that your threads will run for an +// extended period of time, you can safely disable the lock. + +#if !defined (ACE_DEFAULT_THREAD_MANAGER_LOCK) +# define ACE_DEFAULT_THREAD_MANAGER_LOCK ACE_SYNCH_MUTEX +#endif /* ACE_DEFAULT_THREAD_MANAGER_LOCK */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +// Forward declarations. +class ACE_Task_Base; +class ACE_Thread_Manager; +class ACE_Thread_Descriptor; + +/** + * @class ACE_At_Thread_Exit + * + * @brief Contains a method to be applied when a thread is terminated. + */ +class ACE_Export ACE_At_Thread_Exit +{ + friend class ACE_Thread_Descriptor; + friend class ACE_Thread_Manager; +public: + /// Default constructor + ACE_At_Thread_Exit (void); + + /// The destructor + virtual ~ACE_At_Thread_Exit (void); + + /// At_Thread_Exit has the ownership? + bool is_owner (void) const; + + /// Set the ownership of the At_Thread_Exit. + bool is_owner (bool owner); + + /// This At_Thread_Exit was applied? + bool was_applied (void) const; + + /// Set applied state of At_Thread_Exit. + bool was_applied (bool applied); + +protected: + /// The next At_Thread_Exit hook in the list. + ACE_At_Thread_Exit *next_; + + /// Do the apply if necessary + void do_apply (void); + + /// The apply method. + virtual void apply (void) = 0; + + /// The Thread_Descriptor where this at is registered. + ACE_Thread_Descriptor* td_; + + /// The at was applied? + bool was_applied_; + + /// The at has the ownership of this? + bool is_owner_; +}; + +class ACE_Export ACE_At_Thread_Exit_Func : public ACE_At_Thread_Exit +{ +public: + /// Constructor + ACE_At_Thread_Exit_Func (void *object, + ACE_CLEANUP_FUNC func, + void *param = 0); + + virtual ~ACE_At_Thread_Exit_Func (void); + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// The object to be cleanup + void *object_; + + /// The cleanup func + ACE_CLEANUP_FUNC func_; + + /// A param if required + void *param_; + + /// The apply method + void apply (void); +}; + +/** + * @class ACE_Thread_Descriptor_Base + * + * @brief Basic information for thread descriptors. These information + * gets extracted out because we need it after a thread is + * terminated. + * + * @internal + */ +class ACE_Export ACE_Thread_Descriptor_Base : public ACE_OS_Thread_Descriptor +{ + + friend class ACE_Thread_Manager; + friend class ACE_Double_Linked_List; + friend class ACE_Double_Linked_List_Iterator_Base; + friend class ACE_Double_Linked_List_Iterator; + friend class ACE_Double_Linked_List; + friend class ACE_Double_Linked_List_Iterator_Base; + friend class ACE_Double_Linked_List_Iterator; +public: + ACE_Thread_Descriptor_Base (void); + virtual ~ACE_Thread_Descriptor_Base (void); + + // = We need the following operators to make Borland happy. + + /// Equality operator. + bool operator== (const ACE_Thread_Descriptor_Base &rhs) const; + + /// Inequality operator. + bool operator!= (const ACE_Thread_Descriptor_Base &rhs) const; + + /// Group ID. + int grp_id (void) const; + + /// Current state of the thread. + ACE_UINT32 state (void) const; + + /// Return the pointer to an ACE_Task_Base or NULL if there's no + /// ACE_Task_Base associated with this thread.; + ACE_Task_Base *task (void) const; + + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Reset this base thread descriptor. + void reset (void); + + /// Unique thread ID. + ACE_thread_t thr_id_; + + /// Unique handle to thread (used by Win32 and AIX). + ACE_hthread_t thr_handle_; + + /// Group ID. + int grp_id_; + + /// Current state of the thread. + ACE_UINT32 thr_state_; + + /// Pointer to an ACE_Task_Base or NULL if there's no + /// ACE_Task_Base. + ACE_Task_Base *task_; + + /// We need these pointers to maintain the double-linked list in a + /// thread managers. + ACE_Thread_Descriptor_Base *next_; + ACE_Thread_Descriptor_Base *prev_; +}; + +/** + * @class ACE_Thread_Descriptor + * + * @brief Information for controlling threads that run under the control + * of the Thread_Manager. + */ +class ACE_Export ACE_Thread_Descriptor : public ACE_Thread_Descriptor_Base +{ + friend class ACE_At_Thread_Exit; + friend class ACE_Thread_Manager; + friend class ACE_Double_Linked_List; + friend class ACE_Double_Linked_List_Iterator; +public: + // = Initialization method. + ACE_Thread_Descriptor (void); + + // = Accessor methods. + /// Unique thread id. + ACE_thread_t self (void) const; + + /// Unique handle to thread (used by Win32 and AIX). + void self (ACE_hthread_t &); + + /// Dump the state of an object. + void dump (void) const; + + /** + * This cleanup function must be called only for ACE_TSS_cleanup. + * The ACE_TSS_cleanup delegate Log_Msg instance destruction when + * Log_Msg cleanup is called before terminate. + */ + void log_msg_cleanup(ACE_Log_Msg* log_msg); + + /** + * Register an At_Thread_Exit hook and the ownership is acquire by + * Thread_Descriptor, this is the usual case when the AT is dynamically + * allocated. + */ + int at_exit (ACE_At_Thread_Exit* cleanup); + + /// Register an At_Thread_Exit hook and the ownership is retained for the + /// caller. Normally used when the at_exit hook is created in stack. + int at_exit (ACE_At_Thread_Exit& cleanup); + + /** + * Register an object (or array) for cleanup at thread termination. + * "cleanup_hook" points to a (global, or static member) function + * that is called for the object or array when it to be destroyed. + * It may perform any necessary cleanup specific for that object or + * its class. "param" is passed as the second parameter to the + * "cleanup_hook" function; the first parameter is the object (or + * array) to be destroyed. Returns 0 on success, non-zero on + * failure: -1 if virtual memory is exhausted or 1 if the object (or + * array) had already been registered. + */ + int at_exit (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param); + + /// Do nothing destructor to keep some compilers happy + ~ACE_Thread_Descriptor (void); + + /** + * Do nothing but to acquire the thread descriptor's lock and + * release. This will first check if the thread is registered or + * not. If it is already registered, there's no need to reacquire + * the lock again. This is used mainly to get newly spawned thread + * in synch with thread manager and prevent it from accessing its + * thread descriptor before it gets fully built. This function is + * only called from ACE_Log_Msg::thr_desc. + */ + void acquire_release (void); + void acquire (void); + void release (void); + + /** + * Set/get the @c next_ pointer. These are required by the + * ACE_Free_List. + */ + void set_next (ACE_Thread_Descriptor *td); + ACE_Thread_Descriptor *get_next (void) const; + +protected: + /// Run the AT_Thread_Exit hooks. + void do_at_exit (void); + + /// Terminate realize the cleanup process to thread termination + void terminate (void); + +private: + /// Reset this thread descriptor. + void reset (ACE_Thread_Manager *tm); + + /// Pop an At_Thread_Exit from at thread termination list, apply the at + /// if apply is true. + void at_pop (int apply = 1); + + /// Push an At_Thread_Exit to at thread termination list and set the + /// ownership of at. + void at_push (ACE_At_Thread_Exit* cleanup, + bool is_owner = false); + +private: + /// Thread_Descriptor is the ownership of ACE_Log_Msg if log_msg_!=0 + /// This can occur because ACE_TSS_cleanup was executed before terminate. + ACE_Log_Msg *log_msg_; + + /// The AT_Thread_Exit list + ACE_At_Thread_Exit *at_exit_list_; + +#if 0 +/// Currently not used + /** + * Stores the cleanup info for a thread. + * @note This should be generalized to be a stack of ACE_Cleanup_Info's. + */ + ACE_Cleanup_Info_Node_List cleanup_info_; +#endif + + /// Pointer to an ACE_Thread_Manager or NULL if there's no + /// ACE_Thread_Manager + ACE_Thread_Manager* tm_; + + /// Registration lock to prevent premature removal of thread descriptor. + ACE_DEFAULT_THREAD_MANAGER_LOCK *sync_; + + /// Keep track of termination status. + bool terminated_; +}; + +// Forward declaration. +class ACE_Thread_Control; + +// This typedef should be (and used to be) inside the +// ACE_Thread_Manager declaration. But, it caused compilation +// problems on g++/VxWorks/i960 with -g. Note that +// ACE_Thread_Manager::THR_FUNC is only used internally in +// ACE_Thread_Manager, so it's not useful for anyone else. +// It also caused problems on IRIX5 with g++. +#if defined (__GNUG__) +typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int); +#endif /* __GNUG__ */ + +/** + * @class ACE_Thread_Manager + * + * @brief Manages a pool of threads. + * + * This class allows operations on groups of threads atomically. + * The default behavior of thread manager is to wait on + * all threads under it's management when it gets destructed. + * Therefore, remember to remove a thread from thread manager if + * you don't want it to wait for the thread. There are also + * functions to disable this default wait-on-exit behavior. + * However, if your program depends on turning this off to run + * correctly, you are probably doing something wrong. Rule of + * thumb, use ACE_Thread to manage your daemon threads. + * Notice that if there're threads which live beyond the scope of + * main(), you are sure to have resource leaks in your program. + * Remember to wait on threads before exiting your main program if that + * could happen in your programs. + */ +class ACE_Export ACE_Thread_Manager +{ +public: + friend class ACE_Thread_Control; + + // Allow ACE_Thread_Exit to register the global TSS instance object. + friend class ACE_Thread_Exit; + friend class ACE_Thread_Descriptor; + +#if !defined (__GNUG__) + typedef int (ACE_Thread_Manager::*ACE_THR_MEMBER_FUNC)(ACE_Thread_Descriptor *, int); +#endif /* !__GNUG__ */ + + /// These are the various states a thread managed by the + /// ACE_Thread_Manager can be in. + enum + { + /// Uninitialized. + ACE_THR_IDLE = 0x00000000, + + /// Created but not yet running. + ACE_THR_SPAWNED = 0x00000001, + + /// Thread is active (naturally, we don't know if it's actually + /// *running* because we aren't the scheduler...). + ACE_THR_RUNNING = 0x00000002, + + /// Thread is suspended. + ACE_THR_SUSPENDED = 0x00000004, + + /// Thread has been cancelled (which is an indiction that it needs to + /// terminate...). + ACE_THR_CANCELLED = 0x00000008, + + /// Thread has shutdown, but the slot in the thread manager hasn't + /// been reclaimed yet. + ACE_THR_TERMINATED = 0x00000010, + + /// Join operation has been invoked on the thread by thread manager. + ACE_THR_JOINING = 0x10000000 + }; + + /** + * @brief Initialization and termination methods. + * + * Internally, ACE_Thread_Manager keeps a freelist for caching + * resources it uses to keep track of managed threads (not the + * threads themselves.) @a prealloc, @a lwm, @a inc, @hwm + * determine the initial size, the low water mark, increment step, + * and high water mark of the freelist. + * + * @sa ACE_Free_List + */ + ACE_Thread_Manager (size_t preaolloc = ACE_DEFAULT_THREAD_MANAGER_PREALLOC, + size_t lwm = ACE_DEFAULT_THREAD_MANAGER_LWM, + size_t inc = ACE_DEFAULT_THREAD_MANAGER_INC, + size_t hwm = ACE_DEFAULT_THREAD_MANAGER_HWM); + ACE_Thread_Manager (const ACE_Condition_Attributes &attributes, + size_t preaolloc = ACE_DEFAULT_THREAD_MANAGER_PREALLOC, + size_t lwm = ACE_DEFAULT_THREAD_MANAGER_LWM, + size_t inc = ACE_DEFAULT_THREAD_MANAGER_INC, + size_t hwm = ACE_DEFAULT_THREAD_MANAGER_HWM); + ~ACE_Thread_Manager (void); + +#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) + /// Get pointer to a process-wide ACE_Thread_Manager. + static ACE_Thread_Manager *instance (void); + + /// Set pointer to a process-wide ACE_Thread_Manager and return + /// existing pointer. + static ACE_Thread_Manager *instance (ACE_Thread_Manager *); + + /// Delete the dynamically allocated Singleton + static void close_singleton (void); +#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ + + /// No-op. Currently unused. + int open (size_t size = 0); + + /** + * Release all resources. + * By default, this method will wait until all threads exit. + * However, when called from close_singleton(), most global resources + * are destroyed and thus, close() does not try to wait; it simply cleans + * up internal thread records (the thread descriptor list). + */ + int close (void); + + /** + * Create a new thread, which executes @a func with argument @a arg. + * + * @param func The function that is called in the spawned thread. + * + * @param arg The value passed to each spawned thread's @a func. + * + * @param flags Flags to control attributes of the spawned threads. + * @sa ACE_OS::thr_create() for descriptions of the + * possible flags values and their interactions. + * + * @param t_id Pointer to a location to receive the spawned thread's + * ID. If 0, the ID is not returned. + * + * @param t_handle Pointer to a location to receive the spawned thread's + * thread handle. If 0, the handle is not returned. + * + * @param priority The priority at which the thread is spawned. + * + * @param grp_id The thread group that the spawned thread is + * added to. If -1 is specified, a new thread group is + * created for the spawned thread. + * + * @param stack Pointers to the base of a pre-allocated stack space + * for the thread's stack. If 0, the platform allocates + * stack space for the thread. If a stack is specified, + * it is recommended that @a stack_size also be supplied + * to specify the size of the stack. + * Not all platforms support pre-allocated stacks. If + * @a stack is specified for a platform which does not + * allow pre-allocated stack space this parameter is + * ignored. + * + * @param stack_size Indicate how large the thread's stack should be, in + * bytes. If a pre-allocated stack pointer is passed in + * @a stack, @a stack_size indicates the size of that + * stack area. If no pre-allocated stack is passed, + * the stack size specified is passed to the + * operating system to request that it allocate a stack + * of the specified size. + * + * @param thr_name Pointer to a name to assign to the spawned thread. + * This is only meaningful for platforms that have a + * capacity to name threads (e.g., VxWorks and some + * varieties of Pthreads). This argument is ignored if + * specified as 0 and on platforms that do not have the + * capability to name threads. + * + * @retval -1 on failure; @c errno contains an error value. + * @retval The group id of the spawned thread. + */ + int spawn (ACE_THR_FUNC func, + void *arg = 0, + long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, + ACE_thread_t *t_id = 0, + ACE_hthread_t *t_handle = 0, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + int grp_id = -1, + void *stack = 0, + size_t stack_size = ACE_DEFAULT_THREAD_STACKSIZE, + const char** thr_name = 0); + + /** + * Spawn a specified number of threads, all of which execute @a func + * with argument @a arg. + * + * @param n The number of threads to spawn. + * + * @param func The function that is called in the spawned thread. + * + * @param arg The value passed to each spawned thread's @a func. + * + * @param flags Flags to control attributes of the spawned threads. + * @sa ACE_OS::thr_create() for descriptions of the + * possible flags values and their interactions. + * + * @param priority The priority at which the threads are spawned. + * + * @param grp_id The thread group that the spawned threads are + * added to. If -1 is specified, a new thread group is + * created for the spawned threads. + * + * @param task The ACE_Task that the spawned threads are associated + * with. If 0, the threads are not associated with an + * ACE_Task. This argument is usually assigned by the + * ACE_Task_Base::activate() method to associate the + * spawned threads with the spawning ACE_Task object. + * + * @param thread_handles An array of @a n entries which will receive + * the thread handles of the spawned threads. + * + * @param stack An array of @a n pointers to pre-allocated stack space + * for each thread's stack. If specified as 0, the + * platform allocates stack space for each thread. If + * a stack is specified, it is recommended that a + * @a stack_size element also be supplied that specifies + * the size of the stack. + * Not all platforms support pre-allocated stacks. If + * @a stack is specified for a platform which does not + * allow pre-allocated stack space this parameter is + * ignored. + * + * @param stack_size An array of @a n values which indicate how large + * each thread's stack should be, in bytes. + * If pre-allocated stacks are passed in @a stacks, these + * sizes are for those stacks. If no pre-allocated stacks + * are passed, the stack sizes are specified to the + * operating system to request that it allocate stacks + * of the specified sizes. If an array entry is 0, the + * platform defaults are used for the corresponding thread. + * If a 0 array pointer is specified, platform defaults + * are used for all thread stack sizes. + * + * @param thr_name An array of names to assign to the spawned threads. + * This is only meaningful for platforms that have a + * capacity to name threads (e.g., VxWorks and some + * varieties of Pthreads). This argument is ignored if + * specified as 0 and on platforms that do not have the + * capability to name threads. + * + * ACE_Thread_Manager can manipulate threads in groups based on + * @a grp_id or @a task using functions such as kill_grp() or + * cancel_task(). + * + * @retval -1 on failure; @c errno contains an error value. + * @retval The group id of the threads. + */ + int spawn_n (size_t n, + ACE_THR_FUNC func, + void *arg = 0, + long flags = THR_NEW_LWP | THR_JOINABLE | THR_INHERIT_SCHED, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + int grp_id = -1, + ACE_Task_Base *task = 0, + ACE_hthread_t thread_handles[] = 0, + void *stack[] = 0, + size_t stack_size[] = 0, + const char* thr_name[] = 0); + + /** + * Spawn a specified number of threads, all of which execute @a func + * with argument @a arg. + * + * @param thread_ids An array to receive the thread IDs of successfully + * spawned buffer. If 0, the thread IDs are not returned. + * If specified, the array must be at least @a n entries. + * + * @param n The number of threads to spawn. + * + * @param func The function that is called in the spawned thread. + * + * @param arg The value passed to each spawned thread's @a func. + * + * @param flags Flags to control attributes of the spawned threads. + * @sa ACE_OS::thr_create() for descriptions of the + * possible flags values and their interactions. + * + * @param priority The priority at which the threads are spawned. + * + * @param grp_id The thread group that the spawned threads are + * added to. If -1 is specified, a new thread group is + * created for the spawned threads. + * + * @param stack An array of @a n pointers to pre-allocated stack space + * for each thread's stack. If specified as 0, the + * platform allocates stack space for each thread. If + * a stack is specified, it is recommended that a + * @a stack_size element also be supplied that specifies + * the size of the stack. + * Not all platforms support pre-allocated stacks. If + * @a stack is specified for a platform which does not + * allow pre-allocated stack space this parameter is + * ignored. + * + * @param stack_size An array of @a n values which indicate how large + * each thread's stack should be, in bytes. + * If pre-allocated stacks are passed in @a stacks, these + * sizes are for those stacks. If no pre-allocated stacks + * are passed, the stack sizes are specified to the + * operating system to request that it allocate stacks + * of the specified sizes. If an array entry is 0, the + * platform defaults are used for the corresponding thread. + * If a 0 array pointer is specified, platform defaults + * are used for all thread stack sizes. + * + * @param thread_handles An array of @a n entries which will receive + * the thread handles of the spawned threads. + * + * @param task The ACE_Task that the spawned threads are associated + * with. If 0, the threads are not associated with an + * ACE_Task. This argument is usually assigned by the + * ACE_Task_Base::activate() method to associate the + * spawned threads with the spawning ACE_Task object. + * + * @param thr_name An array of names to assign to the spawned threads. + * This is only meaningful for platforms that have a + * capacity to name threads (e.g., VxWorks and some + * varieties of Pthreads). This argument is ignored if + * specified as 0 and on platforms that do not have the + * capability to name threads. + * + * ACE_Thread_Manager can manipulate threads in groups based on + * @a grp_id or @a task using functions such as kill_grp() or + * cancel_task(). + * + * @retval -1 on failure; @c errno contains an error value. + * @retval The group id of the threads. + + */ + int spawn_n (ACE_thread_t thread_ids[], + size_t n, + ACE_THR_FUNC func, + void *arg, + long flags, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + int grp_id = -1, + void *stack[] = 0, + size_t stack_size[] = 0, + ACE_hthread_t thread_handles[] = 0, + ACE_Task_Base *task = 0, + const char* thr_name[] = 0); + + /** + * Called to clean up when a thread exits. + * + * @param do_thread_exit If non-0 then ACE_Thread::exit is called to + * exit the thread + * @param status If ACE_Thread_Exit is called, this is passed as + * the exit value of the thread. + * Should _not_ be called by main thread. + */ + ACE_THR_FUNC_RETURN exit (ACE_THR_FUNC_RETURN status = 0, + bool do_thread_exit = true); + + /** + * Block until there are no more threads running in this thread + * manager or @c timeout expires. + * + * @param timeout is treated as "absolute" time by default, but this + * can be changed to "relative" time by setting the @c + * use_absolute_time to false. + * @param abandon_detached_threads If true, @c wait() will first + * check thru its thread list for + * threads with THR_DETACHED or + * THR_DAEMON flags set and remove + * these threads. Notice that + * unlike other @c wait_*() methods, + * by default, @c wait() does wait on + * all thread spawned by this + * thread manager no matter the detached + * flags are set or not unless it is + * called with @c + * abandon_detached_threads flag set. + * @param use_absolute_time If true then treat @c timeout as + * absolute time, else relative time. + * @return 0 on success * and -1 on failure. + * + * @note If this function is called while the @c + * ACE_Object_Manager is shutting down (as a result of program + * rundown via @c ACE::fini()), it will not wait for any threads to + * complete. If you must wait for threads spawned by this thread + * manager to complete and you are in a ACE rundown situation (such + * as your object is being destroyed by the @c ACE_Object_Manager) + * you can use @c wait_grp() instead. + */ + int wait (const ACE_Time_Value *timeout = 0, + bool abandon_detached_threads = false, + bool use_absolute_time = true); + + /// Join a thread specified by @a tid. Do not wait on a detached thread. + int join (ACE_thread_t tid, ACE_THR_FUNC_RETURN *status = 0); + + /** + * Block until there are no more threads running in a group. + * Returns 0 on success and -1 on failure. Notice that wait_grp + * will not wait on detached threads. + */ + int wait_grp (int grp_id); + + /** + * Return the "real" handle to the calling thread, caching it if + * necessary in TSS to speed up subsequent lookups. This is + * necessary since on some platforms (e.g., Windows) we can't get this + * handle via direct method calls. Notice that you should *not* + * close the handle passed back from this method. It is used + * internally by Thread Manager. On the other hand, you *have to* + * use this internal thread handle when working on Thread_Manager. + * Return -1 if fail. + */ + int thr_self (ACE_hthread_t &); + + /** + * Return the unique ID of the calling thread. + * Same as calling ACE_Thread::self(). + */ + ACE_thread_t thr_self (void); + + /** + * Returns a pointer to the current ACE_Task_Base we're executing + * in if this thread is indeed running in an ACE_Task_Base, else + * return 0. + */ + ACE_Task_Base *task (void); + + /** + * @name Suspend and resume methods + * + * Suspend/resume is not supported on all platforms. For example, Pthreads + * does not support these functions. + */ + //@{ + + /// Suspend all threads + int suspend_all (void); + + /// Suspend a single thread. + int suspend (ACE_thread_t); + + /// Suspend a group of threads. + int suspend_grp (int grp_id); + + /** + * True if @a t_id is inactive (i.e., suspended), else false. Always + * return false if @a t_id is not managed by the Thread_Manager. + */ + int testsuspend (ACE_thread_t t_id); + + /// Resume all stopped threads + int resume_all (void); + + /// Resume a single thread. + int resume (ACE_thread_t); + + /// Resume a group of threads. + int resume_grp (int grp_id); + + /** + * True if @a t_id is active (i.e., resumed), else false. Always + * return false if @a t_id is not managed by the Thread_Manager. + */ + int testresume (ACE_thread_t t_id); + + //@} + + // = Send signals to one or more threads without blocking. + /** + * Send @a signum to all stopped threads. Not supported on platforms + * that do not have advanced signal support, such as Win32. + */ + int kill_all (int signum); + /** + * Send the @a signum to a single thread. Not supported on platforms + * that do not have advanced signal support, such as Win32. + */ + int kill (ACE_thread_t, int signum); + /** + * Send @a signum to a group of threads, not supported on platforms + * that do not have advanced signal support, such as Win32. + */ + int kill_grp (int grp_id, int signum); + + // = Cancel methods, which provides a cooperative thread-termination mechanism (will not block). + /** + * Cancel's all the threads. + */ + int cancel_all (int async_cancel = 0); + + /** + * Cancel a single thread. + */ + int cancel (ACE_thread_t, int async_cancel = 0); + + /** + * Cancel a group of threads. + */ + int cancel_grp (int grp_id, int async_cancel = 0); + + /** + * True if @a t_id is cancelled, else false. Always return false if + * @a t_id is not managed by the Thread_Manager. + */ + int testcancel (ACE_thread_t t_id); + + /** + * True if @a t_id has terminated (i.e., is no longer running), + * but the slot in the thread manager hasn't been reclaimed yet, + * else false. Always return false if @a t_id is not managed by the + * Thread_Manager. + */ + int testterminate (ACE_thread_t t_id); + + /// Set group ids for a particular thread id. + int set_grp (ACE_thread_t, + int grp_id); + + /// Get group ids for a particular thread id. + int get_grp (ACE_thread_t, + int &grp_id); + + /** + * @name Task-related operations + */ + //@{ + /** + * Block until there are no more threads running in a specified task. + * This method will not wait for either detached or daemon threads; + * the threads must have been spawned with the @c THR_JOINABLE flag. + * Upon successful completion, the threads have been joined, so further + * attempts to join with any of the waited-for threads will fail. + * + * @param task The ACE_Task_Base object whose threads are to waited for. + * + * @retval 0 Success. + * @retval -1 Failure (consult errno for further information). + */ + int wait_task (ACE_Task_Base *task); + + /** + * Suspend all threads in an ACE_Task. + */ + int suspend_task (ACE_Task_Base *task); + + /** + * Resume all threads in an ACE_Task. + */ + int resume_task (ACE_Task_Base *task); + + /** + * Send a signal @a signum to all threads in an ACE_Task. + */ + int kill_task (ACE_Task_Base *task, int signum); + + /** + * Cancel all threads in an ACE_Task. If @a async_cancel is non-0, + * then asynchronously cancel these threads if the OS platform + * supports cancellation. Otherwise, perform a "cooperative" + * cancellation. + */ + int cancel_task (ACE_Task_Base *task, int async_cancel = 0); + + //@} + + // = Collect thread handles in the thread manager. Notice that + // the collected information is just a snapshot. + /// Check if the thread is managed by the thread manager. Return true if + /// the thread is found, false otherwise. + int hthread_within (ACE_hthread_t handle); + int thread_within (ACE_thread_t tid); + + /// Returns the number of ACE_Task_Base in a group. + int num_tasks_in_group (int grp_id); + + /// Returns the number of threads in an ACE_Task_Base. + int num_threads_in_task (ACE_Task_Base *task); + + /** + * Returns a list of ACE_Task_Base pointers corresponding to the tasks + * that have active threads in a specified thread group. + * + * @param grp_id The thread group ID to obtain task pointers for. + * + * @param task_list is a pointer to an array to receive the list of pointers. + * The caller is responsible for supplying an array with at + * least @arg n entries. + * + * @param n The maximum number of ACE_Task_Base pointers to write + * in @arg task_list. + * + * @retval If successful, the number of pointers returned, which will be + * no greater than @arg n. Returns -1 on error. + * + * @note This method has no way to indicate if there are more than + * @arg n ACE_Task_Base pointers available. Therefore, it may be + * wise to guess a larger value of @arg n than one thinks in cases + * where the exact number of tasks is not known. + * + * @sa num_tasks_in_group(), task_all_list() + */ + ssize_t task_list (int grp_id, + ACE_Task_Base *task_list[], + size_t n); + + /** + * Returns in @a thread_list a list of up to @a n thread ids in an + * ACE_Task_Base. The caller must allocate the memory for + * @a thread_list. In case of an error, -1 is returned. If no + * requested values are found, 0 is returned, otherwise correct + * number of retrieved values are returned. + */ + ssize_t thread_list (ACE_Task_Base *task, + ACE_thread_t thread_list[], + size_t n); + + /** + * Returns in @a hthread_list a list of up to @a n thread handles in + * an ACE_Task_Base. The caller must allocate memory for + * @a hthread_list. In case of an error, -1 is returned. If no + * requested values are found, 0 is returned, otherwise correct + * number of retrieved values are returned. + */ + ssize_t hthread_list (ACE_Task_Base *task, + ACE_hthread_t hthread_list[], + size_t n); + + /** + * Returns in @a thread_list a list of up to @a n thread ids in a + * group @a grp_id. The caller must allocate the memory for + * @a thread_list. In case of an error, -1 is returned. If no + * requested values are found, 0 is returned, otherwise correct + * number of retrieved values are returned. + */ + ssize_t thread_grp_list (int grp_id, + ACE_thread_t thread_list[], + size_t n); + + /** + * Returns in @a hthread_list a list of up to @a n thread handles in + * a group @a grp_id. The caller must allocate memory for + * @a hthread_list. + */ + ssize_t hthread_grp_list (int grp_id, + ACE_hthread_t hthread_list[], + size_t n); + + /** + * Returns a list of ACE_Task_Base pointers corresponding to the tasks + * that have active threads managed by this instance. + * + * @param task_list is a pointer to an array to receive the list of pointers. + * The caller is responsible for supplying an array with at + * least @arg n entries. + * + * @param n The maximum number of ACE_Task_Base pointers to write + * in @arg task_list. + * + * @retval If successful, the number of pointers returned, which will be + * no greater than @arg n. Returns -1 on error. + * + * @note This method has no way to indicate if there are more than + * @arg n ACE_Task_Base pointers available. Therefore, it may be + * wise to guess a larger value of @arg n than one thinks in cases + * where the exact number of tasks is not known. + * + * @sa count_threads() + */ + ssize_t task_all_list (ACE_Task_Base *task_list[], + size_t n); + + /** + * Returns in @a thread_list a list of up to @a n thread ids. The + * caller must allocate the memory for @a thread_list. In case of an + * error, -1 is returned. If no requested values are found, 0 is + * returned, otherwise correct number of retrieved values are + * returned. + */ + ssize_t thread_all_list (ACE_thread_t thread_list[], + size_t n); + + /// Set group ids for a particular task. + int set_grp (ACE_Task_Base *task, int grp_id); + + /// Get group ids for a particular task. + int get_grp (ACE_Task_Base *task, int &grp_id); + + /// Return a count of the current number of threads active in the + /// Thread_Manager. + size_t count_threads (void) const; + + /// Get the state of the thread. Returns false if the thread is not + /// managed by this thread manager. + int thr_state (ACE_thread_t id, ACE_UINT32& state); + + /** + * Register an At_Thread_Exit hook and the ownership is acquire by + * Thread_Descriptor, this is the usual case when the AT is dynamically + * allocated. + */ + int at_exit (ACE_At_Thread_Exit* cleanup); + + /// Register an At_Thread_Exit hook and the ownership is retained for the + /// caller. Normally used when the at_exit hook is created in stack. + int at_exit (ACE_At_Thread_Exit& cleanup); + + /** + * + ***** + * @deprecated This function is deprecated. Please use the previous two + * at_exit method. Notice that you should avoid mixing this method + * with the previous two at_exit methods. + ***** + * + * Register an object (or array) for cleanup at + * thread termination. "cleanup_hook" points to a (global, or + * static member) function that is called for the object or array + * when it to be destroyed. It may perform any necessary cleanup + * specific for that object or its class. "param" is passed as the + * second parameter to the "cleanup_hook" function; the first + * parameter is the object (or array) to be destroyed. + * "cleanup_hook", for example, may delete the object (or array). + * If @a cleanup_hook == 0, the @a object will _NOT_ get cleanup at + * thread exit. You can use this to cancel the previously added + * at_exit. + */ + int at_exit (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param); + + /// Access function to determine whether the Thread_Manager will + /// wait for its thread to exit or not when being closing down. + void wait_on_exit (int dowait); + int wait_on_exit (void); + + /// Dump the state of an object. + void dump (void); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + // = Accessors for ACE_Thread_Descriptors. + /** + * Get a pointer to the calling thread's own thread_descriptor. + * This must be called from a spawn thread. This function will + * fetch the info from TSS. + */ + ACE_Thread_Descriptor *thread_desc_self (void); + + /// Return a pointer to the thread's Thread_Descriptor, + /// 0 if fail. + ACE_Thread_Descriptor *thread_descriptor (ACE_thread_t); + + /// Return a pointer to the thread's Thread_Descriptor, + /// 0 if fail. + ACE_Thread_Descriptor *hthread_descriptor (ACE_hthread_t); + + /// Create a new thread (must be called with locks held). + int spawn_i (ACE_THR_FUNC func, + void *arg, + long flags, + ACE_thread_t * = 0, + ACE_hthread_t *t_handle = 0, + long priority = ACE_DEFAULT_THREAD_PRIORITY, + int grp_id = -1, + void *stack = 0, + size_t stack_size = 0, + ACE_Task_Base *task = 0, + const char** thr_name = 0); + + /// Run the registered hooks when the thread exits. + void run_thread_exit_hooks (int i); + + /// Locate the index of the table slot occupied by @a t_id. Returns + /// -1 if @a t_id is not in the table doesn't contain @a t_id. + ACE_Thread_Descriptor *find_thread (ACE_thread_t t_id); + + /// Locate the index of the table slot occupied by @a h_id. Returns + /// -1 if @a h_id is not in the table doesn't contain @a h_id. + ACE_Thread_Descriptor *find_hthread (ACE_hthread_t h_id); + + /** + * Locate the thread descriptor address of the list occupied by + * @a task. Returns 0 if @a task is not in the table doesn't contain + * @a task. + */ + ACE_Thread_Descriptor *find_task (ACE_Task_Base *task, + size_t slot = 0); + + /// Insert a thread in the table (checks for duplicates). + int insert_thr (ACE_thread_t t_id, + ACE_hthread_t, + int grp_id = -1, + long flags = 0); + + /// Append a thread in the table (adds at the end, growing the table + /// if necessary). + int append_thr (ACE_thread_t t_id, ACE_hthread_t, + ACE_UINT32, + int grp_id, + ACE_Task_Base *task = 0, + long flags = 0, + ACE_Thread_Descriptor *td = 0); + + /// Remove thread from the table. + void remove_thr (ACE_Thread_Descriptor *td, + int close_handler); + + /// Remove all threads from the table. + void remove_thr_all (void); + + // = The following four methods implement a simple scheme for + // operating on a collection of threads atomically. + + /** + * Efficiently check whether @a thread is in a particular @a state. + * This call updates the TSS cache if possible to speed up + * subsequent searches. + */ + int check_state (ACE_UINT32 state, + ACE_thread_t thread, + int enable = 1); + + /// Apply @a func to all members of the table that match the @a task + int apply_task (ACE_Task_Base *task, + ACE_THR_MEMBER_FUNC func, + int = 0); + + /// Apply @a func to all members of the table that match the @a grp_id. + int apply_grp (int grp_id, + ACE_THR_MEMBER_FUNC func, + int arg = 0); + + /// Apply @a func to all members of the table. + int apply_all (ACE_THR_MEMBER_FUNC, + int = 0); + + /// Join the thread described in @a td. + int join_thr (ACE_Thread_Descriptor *td, + int = 0); + + /// Resume the thread described in @a td. + int resume_thr (ACE_Thread_Descriptor *td, + int = 0); + + /// Suspend the thread described in @a td. + int suspend_thr (ACE_Thread_Descriptor *td, + int = 0); + + /// Send signal @a signum to the thread described in @a td. + int kill_thr (ACE_Thread_Descriptor *td, + int signum); + + /// Set the cancellation flag for the thread described in @a td. + int cancel_thr (ACE_Thread_Descriptor *td, + int async_cancel = 0); + + /// Register a thread as terminated and put it into the terminated_thr_list_. + int register_as_terminated (ACE_Thread_Descriptor *td); + + /// Setting the static ACE_TSS_TYPE (ACE_Thread_Exit) *thr_exit_ pointer. + static int set_thr_exit (ACE_TSS_TYPE (ACE_Thread_Exit) *ptr); + + /** + * Keeping a list of thread descriptors within the thread manager. + * Double-linked list enables us to cache the entries in TSS + * and adding/removing thread descriptor entries without + * affecting other thread's descriptor entries. + */ + ACE_Double_Linked_List thr_list_; + +#if !defined (ACE_HAS_VXTHREADS) + /// Collect terminated but not yet joined thread entries. + ACE_Double_Linked_List terminated_thr_list_; +#endif /* !ACE_HAS_VXTHREADS */ + + /// Collect pointers to thread descriptors of threads to be removed later. + ACE_Unbounded_Queue thr_to_be_removed_; + + /// Keeps track of the next group id to assign. + int grp_id_; + + /// Set if we want the Thread_Manager to wait on all threads before + /// being closed, reset otherwise. + int automatic_wait_; + + // = ACE_Thread_Mutex and condition variable for synchronizing termination. +#if defined (ACE_HAS_THREADS) + /// Serialize access to the zero_cond_. + ACE_Thread_Mutex lock_; + + /// Keep track of when there are no more threads. + ACE_Condition_Thread_Mutex zero_cond_; +#endif /* ACE_HAS_THREADS */ + + ACE_Locked_Free_List thread_desc_freelist_; + +#if defined (ACE_HAS_THREADS) && defined (ACE_LACKS_PTHREAD_JOIN) + ACE_Condition_Thread_Mutex join_cond_; +#endif + +private: +#if ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) + /// Pointer to a process-wide ACE_Thread_Manager. + static ACE_Thread_Manager *thr_mgr_; + + /// Must delete the thr_mgr_ if true. + static bool delete_thr_mgr_; + + /// Global ACE_TSS (ACE_Thread_Exit) object ptr. + static ACE_TSS_TYPE (ACE_Thread_Exit) *thr_exit_; +#endif /* ! defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ +}; + +#if defined (ACE_THREAD_MANAGER_LACKS_STATICS) +#define ACE_THREAD_MANAGER_SINGLETON_DEFINE \ + ACE_Singleton; +typedef ACE_Singleton ACE_THREAD_MANAGER_SINGLETON; +#endif /* defined (ACE_THREAD_MANAGER_LACKS_STATICS) */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Thread_Manager.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_MANAGER_H */ diff --git a/dep/acelite/ace/Thread_Manager.inl b/dep/acelite/ace/Thread_Manager.inl new file mode 100644 index 000000000..e3ddda3a8 --- /dev/null +++ b/dep/acelite/ace/Thread_Manager.inl @@ -0,0 +1,302 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_At_Thread_Exit::ACE_At_Thread_Exit (void) + : next_ (0), + td_ (0), + was_applied_ (false), + is_owner_ (true) +{ +} + +ACE_INLINE bool +ACE_At_Thread_Exit::was_applied() const +{ + return was_applied_; +} + +ACE_INLINE bool +ACE_At_Thread_Exit::was_applied (bool applied) +{ + was_applied_ = applied; + if (was_applied_) + td_ = 0; + return was_applied_; +} + +ACE_INLINE bool +ACE_At_Thread_Exit::is_owner() const +{ + return is_owner_; +} + +ACE_INLINE bool +ACE_At_Thread_Exit::is_owner (bool owner) +{ + is_owner_ = owner; + return is_owner_; +} + +ACE_INLINE void +ACE_At_Thread_Exit::do_apply (void) +{ + if (!this->was_applied_ && this->is_owner_) + td_->at_pop(); +} + +ACE_INLINE +ACE_At_Thread_Exit_Func::ACE_At_Thread_Exit_Func (void *object, + ACE_CLEANUP_FUNC func, + void *param) + : object_(object), + func_(func), + param_(param) +{ +} + +ACE_INLINE +ACE_Thread_Descriptor_Base::ACE_Thread_Descriptor_Base (void) + : ACE_OS_Thread_Descriptor (), + thr_id_ (ACE_OS::NULL_thread), + thr_handle_ (ACE_OS::NULL_hthread), + grp_id_ (0), + thr_state_ (ACE_Thread_Manager::ACE_THR_IDLE), + task_ (0), + next_ (0), + prev_ (0) +{ +} + +ACE_INLINE +ACE_Thread_Descriptor_Base::~ACE_Thread_Descriptor_Base (void) +{ +} + +ACE_INLINE bool +ACE_Thread_Descriptor_Base::operator== ( + const ACE_Thread_Descriptor_Base &rhs) const +{ + return + ACE_OS::thr_cmp (this->thr_handle_, rhs.thr_handle_) + && ACE_OS::thr_equal (this->thr_id_, rhs.thr_id_); +} + +ACE_INLINE bool +ACE_Thread_Descriptor_Base::operator!=(const ACE_Thread_Descriptor_Base &rhs) const +{ + return !(*this == rhs); +} + +ACE_INLINE ACE_Task_Base * +ACE_Thread_Descriptor_Base::task (void) const +{ + ACE_TRACE ("ACE_Thread_Descriptor_Base::task"); + return this->task_; +} + +// Group ID. + +ACE_INLINE int +ACE_Thread_Descriptor_Base::grp_id (void) const +{ + ACE_TRACE ("ACE_Thread_Descriptor_Base::grp_id"); + return grp_id_; +} + +// Current state of the thread. +ACE_INLINE ACE_UINT32 +ACE_Thread_Descriptor_Base::state (void) const +{ + ACE_TRACE ("ACE_Thread_Descriptor_Base::state"); + return thr_state_; +} + +// Reset this base descriptor. +ACE_INLINE void +ACE_Thread_Descriptor_Base::reset (void) +{ + ACE_TRACE ("ACE_Thread_Descriptor_Base::reset"); + this->thr_id_ = ACE_OS::NULL_thread; + this->thr_handle_ = ACE_OS::NULL_hthread; + this->grp_id_ = 0; + this->thr_state_ = ACE_Thread_Manager::ACE_THR_IDLE; + this->task_ = 0; + this->flags_ = 0; +} + +// Unique thread id. +ACE_INLINE ACE_thread_t +ACE_Thread_Descriptor::self (void) const +{ + ACE_TRACE ("ACE_Thread_Descriptor::self"); + return this->thr_id_; +} + +// Unique kernel-level thread handle. + +ACE_INLINE void +ACE_Thread_Descriptor::self (ACE_hthread_t &handle) +{ + ACE_TRACE ("ACE_Thread_Descriptor::self"); + handle = this->thr_handle_; +} + +ACE_INLINE void +ACE_Thread_Descriptor::log_msg_cleanup (ACE_Log_Msg* log_msg) + +{ + log_msg_ = log_msg; +} + +// Set the pointer +ACE_INLINE void +ACE_Thread_Descriptor::set_next (ACE_Thread_Descriptor *td) +{ + ACE_TRACE ("ACE_Thread_Descriptor::set_next"); + this->next_ = td; +} + +// Get the pointer +ACE_INLINE ACE_Thread_Descriptor * +ACE_Thread_Descriptor::get_next (void) const +{ + ACE_TRACE ("ACE_Thread_Descriptor::get_next"); + return static_cast (this->next_); +} + +// Reset this thread descriptor +ACE_INLINE void +ACE_Thread_Descriptor::reset (ACE_Thread_Manager *tm) +{ + ACE_TRACE ("ACE_Thread_Descriptor::reset"); + this->ACE_Thread_Descriptor_Base::reset (); + this->at_exit_list_ = 0; + // Start the at_exit hook list. + this->tm_ = tm; + // Setup the Thread_Manager. + this->log_msg_ = 0; + this->terminated_ = false; +} + +ACE_INLINE ACE_Thread_Descriptor * +ACE_Thread_Manager::thread_desc_self (void) +{ + // This method must be called with lock held. + + // Try to get it from cache. + ACE_Thread_Descriptor *desc = ACE_LOG_MSG->thr_desc (); + +#if 1 + // ACE_ASSERT (desc != 0); + // Thread descriptor should always get cached. +#else + if (desc == 0) + { + ACE_thread_t id = ACE_OS::thr_self (); + + desc = this->find_thread (id); + + // Thread descriptor adapter might not have been put into the + // list yet. + if (desc != 0) + // Update the TSS cache. + ACE_LOG_MSG->thr_desc (desc); + } +#endif + return desc; +} + +// Return the unique ID of the thread. + +ACE_INLINE ACE_thread_t +ACE_Thread_Manager::thr_self (void) +{ + ACE_TRACE ("ACE_Thread_Manager::thr_self"); + return ACE_Thread::self (); +} + +ACE_INLINE ACE_Task_Base * +ACE_Thread_Manager::task (void) +{ + ACE_TRACE ("ACE_Thread_Manager::task"); + + ACE_Thread_Descriptor *td = this->thread_desc_self () ; + + if (td == 0) + return 0; + else + return td->task (); +} + +ACE_INLINE int +ACE_Thread_Manager::open (size_t) +{ + // Currently no-op. + return 0; +} + +ACE_INLINE int +ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit* at) +{ + ACE_Thread_Descriptor *td = this->thread_desc_self (); + if (td == 0) + return -1; + else + return td->at_exit (at); +} + +ACE_INLINE int +ACE_Thread_Manager::at_exit (ACE_At_Thread_Exit& at) +{ + ACE_Thread_Descriptor *td = this->thread_desc_self (); + if (td == 0) + return -1; + else + return td->at_exit (at); +} + +ACE_INLINE int +ACE_Thread_Manager::at_exit (void *object, + ACE_CLEANUP_FUNC cleanup_hook, + void *param) +{ + ACE_Thread_Descriptor *td = this->thread_desc_self (); + if (td == 0) + return -1; + else + return td->at_exit (object, cleanup_hook, param); +} + +ACE_INLINE void +ACE_Thread_Manager::wait_on_exit (int do_wait) +{ + this->automatic_wait_ = do_wait; +} + +ACE_INLINE int +ACE_Thread_Manager::wait_on_exit (void) +{ + return this->automatic_wait_; +} + +ACE_INLINE int +ACE_Thread_Manager::register_as_terminated (ACE_Thread_Descriptor *td) +{ +#if defined (ACE_HAS_VXTHREADS) + ACE_UNUSED_ARG (td); +#else /* ! ACE_HAS_VXTHREADS */ + ACE_Thread_Descriptor_Base *tdb = 0; + ACE_NEW_RETURN (tdb, ACE_Thread_Descriptor_Base (*td), -1); + this->terminated_thr_list_.insert_tail (tdb); +#endif /* !ACE_HAS_VXTHREADS */ + return 0; +} + +ACE_INLINE size_t +ACE_Thread_Manager::count_threads (void) const +{ + return this->thr_list_.size (); +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Mutex.cpp b/dep/acelite/ace/Thread_Mutex.cpp new file mode 100644 index 000000000..b51505f7b --- /dev/null +++ b/dep/acelite/ace/Thread_Mutex.cpp @@ -0,0 +1,60 @@ +/** + * @file Thread_Mutex.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/Thread_Mutex.h" + +#if defined (ACE_HAS_THREADS) + +#if !defined (__ACE_INLINE__) +#include "ace/Thread_Mutex.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Log_Category.h" +#include "ace/Malloc_T.h" + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Mutex) + +void +ACE_Thread_Mutex::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Thread_Mutex::dump"); + + ACELIB_DEBUG ((LM_DEBUG, ACE_BEGIN_DUMP, this)); + ACELIB_DEBUG ((LM_DEBUG, ACE_TEXT ("\n"))); + ACELIB_DEBUG ((LM_DEBUG, ACE_END_DUMP)); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Thread_Mutex::~ACE_Thread_Mutex (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::~ACE_Thread_Mutex"); + this->remove (); +} + +ACE_Thread_Mutex::ACE_Thread_Mutex (const ACE_TCHAR *name, ACE_mutexattr_t *arg) + : removed_ (false) +{ +// ACE_TRACE ("ACE_Thread_Mutex::ACE_Thread_Mutex"); + + if (ACE_OS::thread_mutex_init (&this->lock_, + 0, + name, + arg) != 0) + ACELIB_ERROR ((LM_ERROR, + ACE_TEXT ("%p\n"), + ACE_TEXT ("ACE_Thread_Mutex::ACE_Thread_Mutex"))); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Thread_Mutex.h b/dep/acelite/ace/Thread_Mutex.h new file mode 100644 index 000000000..9270aa68a --- /dev/null +++ b/dep/acelite/ace/Thread_Mutex.h @@ -0,0 +1,173 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Thread_Mutex.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_THREAD_MUTEX_H +#define ACE_THREAD_MUTEX_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_HAS_THREADS) +# include "ace/Null_Mutex.h" +#else /* ACE_HAS_THREADS */ +// ACE platform supports some form of threading. + +#include /**/ "ace/ACE_export.h" +#include "ace/OS_NS_Thread.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Thread_Mutex + * + * @brief ACE_Thread_Mutex wrapper (only valid for threads in the same + * process). + * + * This implementation is optimized for locking threads that are + * in the same process. It maps to s on NT + * and with set to on UNIX. + * ACE_Thread_Mutex is recursive on some platforms (like + * Win32). However, on most platforms (like Solaris) it is not + * recursive. To be totally safe and portable, developers + * should use ACE_Recursive_Thread_Mutex when they need a + * recursive mutex. + */ +class ACE_Export ACE_Thread_Mutex +{ +public: + /// Constructor. + ACE_Thread_Mutex (const ACE_TCHAR *name = 0, + ACE_mutexattr_t *attributes = 0); + + /// Implicitly destroy the mutex. + ~ACE_Thread_Mutex (void); + + /** + * Explicitly destroy the mutex. Note that only one thread should + * call this method since it doesn't protect against race + * conditions. + */ + int remove (void); + + /// Acquire lock ownership (wait on queue if necessary). + int acquire (void); + + /** + * Block the thread until we acquire the mutex or until @a tv times + * out, in which case -1 is returned with @c errno == @c ETIME. Note + * that @a tv is assumed to be in "absolute" rather than "relative" + * time. The value of @a tv is updated upon return to show the + * actual (absolute) acquisition time. + */ + int acquire (ACE_Time_Value &tv); + + /** + * If @a tv == 0 the call acquire() directly. Otherwise, Block the + * thread until we acquire the mutex or until @a tv times out, in + * which case -1 is returned with @c errno == @c ETIME. Note that + * @a tv is assumed to be in "absolute" rather than "relative" time. + * The value of @a tv is updated upon return to show the actual + * (absolute) acquisition time. + */ + int acquire (ACE_Time_Value *tv); + + /** + * Conditionally acquire lock (i.e., don't wait on queue). Returns + * -1 on failure. If we "failed" because someone else already had + * the lock, @c errno is set to @c EBUSY. + */ + int tryacquire (void); + + /// Release lock and unblock a thread at head of queue. + int release (void); + + /** + * Acquire mutex ownership. This calls acquire() and is only here + * to make the ACE_Thread_Mutex interface consistent with the + * other synchronization APIs. + */ + int acquire_read (void); + + /** + * Acquire mutex ownership. This calls acquire() and is only here + * to make the ACE_Thread_Mutex interface consistent with the + * other synchronization APIs. + */ + int acquire_write (void); + + /** + * Conditionally acquire mutex (i.e., won't block). This calls + * tryacquire() and is only here to make the ACE_Thread_Mutex + * interface consistent with the other synchronization APIs. + * Returns -1 on failure. If we "failed" because someone else + * already had the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_read (void); + + /** + * Conditionally acquire mutex (i.e., won't block). This calls + * tryacquire() and is only here to make the ACE_Thread_Mutex + * interface consistent with the other synchronization APIs. + * Returns -1 on failure. If we "failed" because someone else + * already had the lock, @c errno is set to @c EBUSY. + */ + int tryacquire_write (void); + + /** + * This is only here to make the ACE_Thread_Mutex interface + * consistent with the other synchronization APIs. Assumes the + * caller has already acquired the mutex using one of the above + * calls, and returns 0 (success) always. + */ + int tryacquire_write_upgrade (void); + + /// Return the underlying mutex. + const ACE_thread_mutex_t &lock (void) const; + ACE_thread_mutex_t &lock (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +protected: + /// Mutex type that supports single-process locking efficiently. + ACE_thread_mutex_t lock_; + + /// Keeps track of whether remove() has been called yet to avoid + /// multiple calls, e.g., explicitly and implicitly in the + /// destructor. This flag isn't protected by a lock, so make sure + /// that you don't have multiple threads simultaneously calling + /// on the same object, which is a bad idea anyway... + bool removed_; + +private: + // = Prevent assignment and initialization. + void operator= (const ACE_Thread_Mutex &); + ACE_Thread_Mutex (const ACE_Thread_Mutex &); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Thread_Mutex.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* !ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_MUTEX_H */ diff --git a/dep/acelite/ace/Thread_Mutex.inl b/dep/acelite/ace/Thread_Mutex.inl new file mode 100644 index 000000000..e3d271932 --- /dev/null +++ b/dep/acelite/ace/Thread_Mutex.inl @@ -0,0 +1,101 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE const ACE_thread_mutex_t & +ACE_Thread_Mutex::lock (void) const +{ +// ACE_TRACE ("ACE_Thread_Mutex::lock"); + return this->lock_; +} + +ACE_INLINE ACE_thread_mutex_t & +ACE_Thread_Mutex::lock (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::lock"); + return this->lock_; +} + +ACE_INLINE int +ACE_Thread_Mutex::acquire_read (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::acquire_read"); + return ACE_OS::thread_mutex_lock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::acquire_write (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::acquire_write"); + return ACE_OS::thread_mutex_lock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::tryacquire_read (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_read"); + return ACE_OS::thread_mutex_trylock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::tryacquire_write (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_write"); + return ACE_OS::thread_mutex_trylock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::tryacquire_write_upgrade (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::tryacquire_write_upgrade"); + return 0; +} + +ACE_INLINE int +ACE_Thread_Mutex::acquire (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::acquire"); + return ACE_OS::thread_mutex_lock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::acquire (ACE_Time_Value &tv) +{ + // ACE_TRACE ("ACE_Thread_Mutex::acquire"); + return ACE_OS::thread_mutex_lock (&this->lock_, tv); +} + +ACE_INLINE int +ACE_Thread_Mutex::acquire (ACE_Time_Value *tv) +{ + // ACE_TRACE ("ACE_Thread_Mutex::acquire"); + return ACE_OS::thread_mutex_lock (&this->lock_, tv); +} + +ACE_INLINE int +ACE_Thread_Mutex::tryacquire (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::tryacquire"); + return ACE_OS::thread_mutex_trylock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::release (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::release"); + return ACE_OS::thread_mutex_unlock (&this->lock_); +} + +ACE_INLINE int +ACE_Thread_Mutex::remove (void) +{ +// ACE_TRACE ("ACE_Thread_Mutex::remove"); + int result = 0; + if (!this->removed_) + { + this->removed_ = true; + result = ACE_OS::thread_mutex_destroy (&this->lock_); + } + return result; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Thread_Semaphore.cpp b/dep/acelite/ace/Thread_Semaphore.cpp new file mode 100644 index 000000000..1fa0bf178 --- /dev/null +++ b/dep/acelite/ace/Thread_Semaphore.cpp @@ -0,0 +1,66 @@ +/** + * @file Thread_Semaphore.cpp + * + * Originally in Synch.cpp + * + * @author Douglas C. Schmidt + */ + +#include "ace/Thread_Semaphore.h" + +#if defined (ACE_HAS_THREADS) + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Thread_Semaphore.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/ACE.h" + + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_ALLOC_HOOK_DEFINE(ACE_Thread_Semaphore) + +void +ACE_Thread_Semaphore::dump (void) const +{ +#if defined (ACE_HAS_DUMP) +// ACE_TRACE ("ACE_Thread_Semaphore::dump"); + + ACE_Semaphore::dump (); +#endif /* ACE_HAS_DUMP */ +} + +ACE_Thread_Semaphore::ACE_Thread_Semaphore (unsigned int count, + const ACE_TCHAR *name, + void *arg, + int max) + : ACE_Semaphore (count, USYNC_THREAD, name, arg, max) +{ +// ACE_TRACE ("ACE_Thread_Semaphore::ACE_Thread_Semaphore"); +} + +/*****************************************************************************/ + +ACE_Thread_Semaphore * +ACE_Malloc_Lock_Adapter_T::operator () (const ACE_TCHAR *name) +{ + ACE_Thread_Semaphore *p = 0; + if (name == 0) + ACE_NEW_RETURN (p, ACE_Thread_Semaphore (1, name), 0); + else + ACE_NEW_RETURN (p, ACE_Thread_Semaphore (1, ACE::basename (name, + ACE_DIRECTORY_SEPARATOR_CHAR)), + 0); + return p; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_HAS_THREADS */ diff --git a/dep/acelite/ace/Thread_Semaphore.h b/dep/acelite/ace/Thread_Semaphore.h new file mode 100644 index 000000000..c59e25ba9 --- /dev/null +++ b/dep/acelite/ace/Thread_Semaphore.h @@ -0,0 +1,85 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Thread_Semaphore.h + * + * Moved from Synch.h. + * + * @author Douglas C. Schmidt + */ +//========================================================================== + +#ifndef ACE_THREAD_SEMAPHORE_H +#define ACE_THREAD_SEMAPHORE_H +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (ACE_HAS_THREADS) +# include "ace/Null_Semaphore.h" +#else /* ACE_HAS_THREADS */ +// ACE platform supports some form of threading. + +#include "ace/Semaphore.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Thread_Semaphore + * + * @brief Wrapper for Dijkstra style general semaphores that work + * only within one process. + */ +class ACE_Export ACE_Thread_Semaphore : public ACE_Semaphore +{ +public: + /// Initialize the semaphore, with an initial value of @a count, + /// maximum value of @a max, and unlocked by default. + ACE_Thread_Semaphore (unsigned int count = 1, // By default make this unlocked. + const ACE_TCHAR *name = 0, + void * = 0, + int max = 0x7FFFFFFF); + + /// Default destructor. + ~ACE_Thread_Semaphore (void); + + /// Dump the state of an object. + void dump (void) const; + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; +}; + +/*****************************************************************************/ + +template class ACE_Malloc_Lock_Adapter_T; + +/** + * @brief Template specialization of ACE_Malloc_Lock_Adapter_T for + * ACE_Thread_Semaphore. + * + * This is needed since the ctor for ACE_Thread_Semaphore doesn't match + * the standard form used by other lock strategy classes. + */ +template<> +class ACE_Export ACE_Malloc_Lock_Adapter_T +{ +public: + ACE_Thread_Semaphore * operator () (const ACE_TCHAR *name); +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Thread_Semaphore.inl" +#endif /* __ACE_INLINE__ */ + +#endif /* !ACE_HAS_THREADS */ + +#include /**/ "ace/post.h" +#endif /* ACE_THREAD_SEMAPHORE_H */ diff --git a/dep/acelite/ace/Thread_Semaphore.inl b/dep/acelite/ace/Thread_Semaphore.inl new file mode 100644 index 000000000..9a2a0affe --- /dev/null +++ b/dep/acelite/ace/Thread_Semaphore.inl @@ -0,0 +1,9 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE +ACE_Thread_Semaphore::~ACE_Thread_Semaphore (void) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Throughput_Stats.cpp b/dep/acelite/ace/Throughput_Stats.cpp new file mode 100644 index 000000000..6ecc4c8aa --- /dev/null +++ b/dep/acelite/ace/Throughput_Stats.cpp @@ -0,0 +1,94 @@ +#include "ace/Throughput_Stats.h" + +#include "ace/OS_NS_stdio.h" +#include "ace/OS_NS_string.h" +#include "ace/High_Res_Timer.h" +#include "ace/Log_Category.h" + + + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Throughput_Stats::ACE_Throughput_Stats (void) + : ACE_Basic_Stats () + , throughput_last_ (0) +{ +} + +void +ACE_Throughput_Stats::sample (ACE_UINT64 throughput, + ACE_UINT64 latency) +{ + this->ACE_Basic_Stats::sample (latency); + + if (this->samples_count () == 1u) + { + this->throughput_last_ = throughput; + } +} + +void +ACE_Throughput_Stats::accumulate (const ACE_Throughput_Stats &rhs) +{ + if (rhs.samples_count () == 0u) + return; + + this->ACE_Basic_Stats::accumulate (rhs); + + if (this->samples_count () == 0u) + { + this->throughput_last_ = rhs.throughput_last_; + } + else if (this->throughput_last_ < rhs.throughput_last_) + { + this->throughput_last_ = rhs.throughput_last_; + } +} + +void +ACE_Throughput_Stats::dump_results (const ACE_TCHAR* msg, + ACE_Basic_Stats::scale_factor_type sf) +{ + if (this->samples_count () == 0u) + { + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("%s : no data collected\n"), msg)); + return; + } + + this->ACE_Basic_Stats::dump_results (msg, sf); + + ACE_Throughput_Stats::dump_throughput (msg, sf, + this->throughput_last_, + this->samples_count ()); +} + +void +ACE_Throughput_Stats::dump_throughput (const ACE_TCHAR *msg, + ACE_Basic_Stats::scale_factor_type sf, + ACE_UINT64 elapsed_time, + ACE_UINT32 samples_count) +{ +#ifndef ACE_NLOGGING + double seconds = + static_cast (ACE_UINT64_DBLCAST_ADAPTER (elapsed_time / sf)); + seconds /= ACE_HR_SCALE_CONVERSION; + + double t_avg = 0.0; + if (seconds > 0.0) + { + t_avg = samples_count / seconds; + } + + ACELIB_DEBUG ((LM_DEBUG, + ACE_TEXT ("%s throughput: %.2f (events/second)\n"), + msg, t_avg)); +#else + ACE_UNUSED_ARG (msg); + ACE_UNUSED_ARG (sf); + ACE_UNUSED_ARG (elapsed_time); + ACE_UNUSED_ARG (samples_count); +#endif /* ACE_NLOGGING */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Throughput_Stats.h b/dep/acelite/ace/Throughput_Stats.h new file mode 100644 index 000000000..f3d1744c5 --- /dev/null +++ b/dep/acelite/ace/Throughput_Stats.h @@ -0,0 +1,72 @@ +// -*- C++ -*- + +//========================================================================== +/** + * @file Throughput_Stats.h + * + * @author David L. Levine + */ +//========================================================================== + + +#ifndef ACE_THROUGHPUT_STATS_H +#define ACE_THROUGHPUT_STATS_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Basic_Stats.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/// A simple class to make throughput and latency analysis. +/** + * + * Keep the relevant information to perform throughput and latency + * analysis, including: + * -# Minimum, Average and Maximum latency + * -# Jitter for the latency + * -# Linear regression for throughput + * -# Accumulate results from several samples to obtain aggregated + * results, across several threads or experiments. + * + * @todo The idea behind this class was to use linear regression to + * determine if the throughput was linear or exhibited jitter. + * Unfortunately it never worked quite right, so only average + * throughput is computed. + */ +class ACE_Export ACE_Throughput_Stats : public ACE_Basic_Stats +{ +public: + /// Constructor + ACE_Throughput_Stats (void); + + /// Store one sample + void sample (ACE_UINT64 throughput, ACE_UINT64 latency); + + /// Update the values to reflect the stats in @a throughput + void accumulate (const ACE_Throughput_Stats &throughput); + + /// Print down the stats + void dump_results (const ACE_TCHAR* msg, scale_factor_type scale_factor); + + /// Dump the average throughput stats. + static void dump_throughput (const ACE_TCHAR *msg, + scale_factor_type scale_factor, + ACE_UINT64 elapsed_time, + ACE_UINT32 samples_count); +private: + /// The last throughput measurement. + ACE_UINT64 throughput_last_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#endif /* ! ACE_THROUGHPUT_STATS_H */ diff --git a/dep/acelite/ace/Time_Policy.cpp b/dep/acelite/ace/Time_Policy.cpp new file mode 100644 index 000000000..4d2e6880b --- /dev/null +++ b/dep/acelite/ace/Time_Policy.cpp @@ -0,0 +1,32 @@ +#include "ace/Time_Policy.h" + +#if !defined(__ACE_INLINE__) +# include "ace/Time_Policy.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_Dynamic_Time_Policy_Base::~ACE_Dynamic_Time_Policy_Base () +{ +} + + +class NULL_Time_Policy : public ACE_Dynamic_Time_Policy_Base +{ +protected: + virtual ACE_Time_Value_T gettimeofday () const; +}; + +ACE_Time_Value_T NULL_Time_Policy::gettimeofday () const +{ + return ACE_Time_Value_T (ACE_Time_Value::zero); +} + +static NULL_Time_Policy null_policy_; + +ACE_Delegating_Time_Policy::ACE_Delegating_Time_Policy (ACE_Dynamic_Time_Policy_Base const * delegate) + : delegate_ (delegate != 0 ? delegate : &null_policy_) +{ +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Time_Policy.h b/dep/acelite/ace/Time_Policy.h new file mode 100644 index 000000000..01bef1364 --- /dev/null +++ b/dep/acelite/ace/Time_Policy.h @@ -0,0 +1,168 @@ +#ifndef ACE_TIME_POLICY_H +#define ACE_TIME_POLICY_H +// -*- C++ -*- +/** + * @file Time_Policy.h + * + * @author Carlos O'Ryan + * @author Martin Corino + */ +#include /**/ "ace/pre.h" + +#include /**/ "ace/config-all.h" + +#include /**/ "ace/Time_Value_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_System_Time_Policy + * + * @brief Implement the system time policy for ACE. + * + * The most common time policy is to simply use + * ACE_OS::gettimeofday(), this class implements that policy, i.e., it + * simply calls that function. + */ +class ACE_Export ACE_System_Time_Policy +{ +public: + /// Return the current time according to this policy + ACE_Time_Value_T operator() () const; + + /// Noop. Just here to satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +}; + +/** + * @class ACE_HR_Time_Policy + * + * @brief Implement a time policy based on the ACE Highres timer. + */ +class ACE_Export ACE_HR_Time_Policy +{ +public: + /// Return the current time according to this policy + ACE_Time_Value_T operator() () const; + + /// Noop. Just here to satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +}; + +/** + * @class ACE_FPointer_Timer_Policy + * + * @brief Implement a time policy based on a function pointer. + * + * This time policy allows dynamic changes to the source of time by + * using a function pointer. + */ +class ACE_Export ACE_FPointer_Time_Policy +{ +public: + /** + * @brief Default constructor uses ACE_OS::gettimeofday() + * + * ACE_T requires a default constructor that leaves the + * policy in a functional state. Therefore, a null pointer would + * not be desirable, in other words, we need a non-trivial default + * constructor. + */ + ACE_FPointer_Time_Policy(); + + /** + * @typedef FPtr + * + * Short-hand for the right type of pointer to function. + */ + typedef ACE_Time_Value (*FPtr)(); + + /** + * @brief Constructor from a pointer to function. + * + * Construct from a pointer to function. + */ + ACE_FPointer_Time_Policy(FPtr f); + + /// Return the current time according to this policy + ACE_Time_Value_T operator()() const; + + /// Satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +private: + FPtr function_; +}; + +class ACE_Dynamic_Time_Policy_Base; // forward decl + +/** + * @class ACE_Delegating_Time_Policy + * + * @brief Implement a time policy that delegates to a dynamic + * time policy. + */ +class ACE_Export ACE_Delegating_Time_Policy +{ +public: + ACE_Delegating_Time_Policy (ACE_Dynamic_Time_Policy_Base const * delegate = 0); + + /// Return the current time according to this policy + ACE_Time_Value_T operator()() const; + + /// Set delegate + void set_delegate (ACE_Dynamic_Time_Policy_Base const * delegate); + + /// Copy policy + ACE_Delegating_Time_Policy& operator =(ACE_Delegating_Time_Policy const & pol); + + /// Noop. Just here to satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +private: + ACE_Dynamic_Time_Policy_Base const * delegate_; +}; + +/** + * @class ACE_Dynamic_Time_Policy_base + * + * @brief Abstract base class for dynamically loaded and/or shared + * time policies. + */ +class ACE_Export ACE_Dynamic_Time_Policy_Base +{ +public: + virtual ~ACE_Dynamic_Time_Policy_Base (); + + /// Return the current time according to this policy + ACE_Time_Value_T operator()() const; + + /// Noop. Just here to satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +protected: + /// Return the current time according to policy implementation. + virtual ACE_Time_Value_T gettimeofday () const = 0; +}; + +/// Temporarily, for backwards compatibility reasons, this will +/// be the default time policy. In time to be replaced by +/// ACE_System_Time_Policy. +typedef ACE_FPointer_Time_Policy ACE_Default_Time_Policy; + +#if defined ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION_EXPORT +template class ACE_Export ACE_Time_Value_T; +template class ACE_Export ACE_Time_Value_T; +template class ACE_Export ACE_Time_Value_T; +template class ACE_Export ACE_Time_Value_T; +#endif /* ACE_HAS_EXPLICIT_TEMPLATE_INSTANTIATION_EXPORT */ + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (__ACE_INLINE__) +#include "ace/Time_Policy.inl" +#endif /* __ACE_INLINE__ */ + +#include /**/ "ace/post.h" +#endif /* ACE_TIME_POLICY_H */ diff --git a/dep/acelite/ace/Time_Policy.inl b/dep/acelite/ace/Time_Policy.inl new file mode 100644 index 000000000..59650b8e1 --- /dev/null +++ b/dep/acelite/ace/Time_Policy.inl @@ -0,0 +1,92 @@ +// -*- C++ -*- +#include "ace/OS_NS_sys_time.h" +#include "ace/High_Res_Timer.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_INLINE ACE_Time_Value_T +ACE_System_Time_Policy::operator()() const +{ + return ACE_Time_Value_T (ACE_OS::gettimeofday()); +} + +ACE_INLINE void +ACE_System_Time_Policy::set_gettimeofday (ACE_Time_Value (*)(void)) +{ +} + +ACE_INLINE ACE_Time_Value_T +ACE_HR_Time_Policy::operator()() const +{ + return ACE_Time_Value_T (ACE_High_Res_Timer::gettimeofday_hr ()); +} + +ACE_INLINE void +ACE_HR_Time_Policy::set_gettimeofday (ACE_Time_Value (*)(void)) +{ +} + +ACE_INLINE +ACE_FPointer_Time_Policy::ACE_FPointer_Time_Policy() + : function_(ACE_OS::gettimeofday) +{ +} + +ACE_INLINE +ACE_FPointer_Time_Policy:: +ACE_FPointer_Time_Policy(ACE_FPointer_Time_Policy::FPtr f) + : function_(f) +{ +} + +ACE_INLINE ACE_Time_Value_T +ACE_FPointer_Time_Policy::operator()() const +{ + return ACE_Time_Value_T ((*this->function_)(), *this); +} + +ACE_INLINE void +ACE_FPointer_Time_Policy::set_gettimeofday (ACE_Time_Value (*f)(void)) +{ + this->function_ = f; +} + +ACE_INLINE ACE_Time_Value_T +ACE_Dynamic_Time_Policy_Base::operator()() const +{ + return this->gettimeofday (); +} + +ACE_INLINE void +ACE_Dynamic_Time_Policy_Base::set_gettimeofday (ACE_Time_Value (*)(void)) +{ +} + +ACE_INLINE ACE_Time_Value_T +ACE_Delegating_Time_Policy::operator()() const +{ + return (*this->delegate_) (); +} + +ACE_INLINE void +ACE_Delegating_Time_Policy::set_gettimeofday (ACE_Time_Value (*)(void)) +{ +} + +ACE_INLINE void +ACE_Delegating_Time_Policy::set_delegate (ACE_Dynamic_Time_Policy_Base const * delegate) +{ + if (delegate != 0) + { + this->delegate_ = delegate; + } +} + +ACE_INLINE ACE_Delegating_Time_Policy& +ACE_Delegating_Time_Policy::operator =(ACE_Delegating_Time_Policy const & pol) +{ + this->delegate_ = pol.delegate_; + return *this; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Time_Policy_T.cpp b/dep/acelite/ace/Time_Policy_T.cpp new file mode 100644 index 000000000..4ca20433e --- /dev/null +++ b/dep/acelite/ace/Time_Policy_T.cpp @@ -0,0 +1,25 @@ +#ifndef ACE_TIME_POLICY_T_CPP +#define ACE_TIME_POLICY_T_CPP + +#include "ace/Time_Policy_T.h" + +#if !defined (__ACE_INLINE__) +#include "ace/Time_Policy_T.inl" +#endif /* __ACE_INLINE__ */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Time_Policy_T::~ACE_Time_Policy_T () +{ +} + +template ACE_Time_Value_T +ACE_Time_Policy_T::gettimeofday () const +{ + return ACE_Time_Value_T (this->time_policy_ (), ACE_Delegating_Time_Policy (this)); +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TIME_POLICY_T_CPP */ diff --git a/dep/acelite/ace/Time_Policy_T.h b/dep/acelite/ace/Time_Policy_T.h new file mode 100644 index 000000000..85d0dde6a --- /dev/null +++ b/dep/acelite/ace/Time_Policy_T.h @@ -0,0 +1,74 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Time_Policy_T.h + * + * @author Martin Corino + */ +//============================================================================= + +#ifndef ACE_TIME_POLICY_T_H +#define ACE_TIME_POLICY_T_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Time_Policy.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Time_Policy_T + * + * @brief Template class implementing a dynamic time policy based on + * another time policy + */ +template +class ACE_Time_Policy_T : public ACE_Dynamic_Time_Policy_Base +{ +public: + ACE_Time_Policy_T (TIME_POLICY const & time_policy = TIME_POLICY()); + virtual ~ACE_Time_Policy_T (); + + /// Return the current time according to this policy + ACE_Time_Value_T operator()() const; + + /// Allows applications to control how the timer queue gets the time + /// of day. + void set_time_policy(TIME_POLICY const & time_policy); + + /// Noop. Just here to satisfy backwards compatibility demands. + void set_gettimeofday (ACE_Time_Value (*gettimeofday)(void)); +protected: + /// Return the current time according to policy implementation. + virtual ACE_Time_Value_T gettimeofday () const; + +private: + /// The policy to return the current time of day + TIME_POLICY time_policy_; +}; + +ACE_END_VERSIONED_NAMESPACE_DECL + +#include /**/ "ace/post.h" + +#if defined (__ACE_INLINE__) +#include "ace/Time_Policy_T.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (ACE_TEMPLATES_REQUIRE_SOURCE) +#include "ace/Time_Policy_T.cpp" +#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */ + +#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA) +#pragma implementation ("Time_Policy_T.cpp") +#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */ + + +#endif /* ACE_TIME_POLICY_T_H */ diff --git a/dep/acelite/ace/Time_Policy_T.inl b/dep/acelite/ace/Time_Policy_T.inl new file mode 100644 index 000000000..25a5ea079 --- /dev/null +++ b/dep/acelite/ace/Time_Policy_T.inl @@ -0,0 +1,29 @@ +// -*- C++ -*- +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_INLINE +ACE_Time_Policy_T::ACE_Time_Policy_T (TIME_POLICY const & time_policy) + : time_policy_ (time_policy) +{ +} + +template +ACE_INLINE ACE_Time_Value_T +ACE_Time_Policy_T::operator() () const +{ + return this->gettimeofday (); +} + +template ACE_INLINE void +ACE_Time_Policy_T::set_gettimeofday (ACE_Time_Value (*)(void)) +{ +} + +template ACE_INLINE void +ACE_Time_Policy_T::set_time_policy(TIME_POLICY const & time_policy) +{ + this->time_policy_ = time_policy; +} + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Time_Value.cpp b/dep/acelite/ace/Time_Value.cpp new file mode 100644 index 000000000..77c151e13 --- /dev/null +++ b/dep/acelite/ace/Time_Value.cpp @@ -0,0 +1,347 @@ +#include "ace/Time_Value.h" + +#if defined (ACE_HAS_ALLOC_HOOKS) +# include "ace/Malloc_Base.h" +#endif /* ACE_HAS_ALLOC_HOOKS */ + +#if !defined (__ACE_INLINE__) +#include "ace/Time_Value.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/Numeric_Limits.h" +#include "ace/If_Then_Else.h" +#include "ace/OS_NS_math.h" +#include "ace/Time_Policy.h" + +#ifdef ACE_HAS_CPP98_IOSTREAMS +# include +# include +#endif /* ACE_HAS_CPP98_IOSTREAMS */ + +#include + +#ifdef ACE_HAS_CPP11 +# include +#endif /* ACE_HAS_CPP11 */ + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Static constant representing `zero-time'. +/// Note: this object requires static construction. +const ACE_Time_Value ACE_Time_Value::zero; + +/// Constant for maximum time representable. Note that this time +/// is not intended for use with select () or other calls that may +/// have *their own* implementation-specific maximum time representations. +/// Its primary use is in time computations such as those used by the +/// dynamic subpriority strategies in the ACE_Dynamic_Message_Queue class. +/// Note: this object requires static construction. +const ACE_Time_Value ACE_Time_Value::max_time ( + ACE_Numeric_Limits::max (), + ACE_ONE_SECOND_IN_USECS - 1); + +ACE_ALLOC_HOOK_DEFINE (ACE_Time_Value) + +ACE_Time_Value::~ACE_Time_Value() +{} + +/// Increment microseconds (the only reason this is here is to allow +/// the use of ACE_Atomic_Op with ACE_Time_Value). +ACE_Time_Value +ACE_Time_Value::operator ++ (int) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator ++ (int)"); + ACE_Time_Value tv (*this); + ++*this; + return tv; +} + +ACE_Time_Value & +ACE_Time_Value::operator ++ (void) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator ++ (void)"); + this->usec (this->usec () + 1); + this->normalize (); + return *this; +} + +/// Decrement microseconds (the only reason this is here is / to allow +/// the use of ACE_Atomic_Op with ACE_Time_Value). +ACE_Time_Value +ACE_Time_Value::operator -- (int) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator -- (int)"); + ACE_Time_Value tv (*this); + --*this; + return tv; +} + +ACE_Time_Value & +ACE_Time_Value::operator -- (void) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator -- (void)"); + this->usec (this->usec () - 1); + this->normalize (); + return *this; +} + +#if defined (ACE_WIN32) +/// Static constant to remove time skew between FILETIME and POSIX +/// time. POSIX and Win32 use different epochs (Jan. 1, 1970 v.s. +/// Jan. 1, 1601). The following constant defines the difference +/// in 100ns ticks. +/// +/// In the beginning (Jan. 1, 1601), there was no time and no computer. +/// And Bill said: "Let there be time," and there was time.... +const DWORDLONG ACE_Time_Value::FILETIME_to_timval_skew = +ACE_INT64_LITERAL (0x19db1ded53e8000); + +/// Initializes the ACE_Time_Value object from a Win32 FILETIME +ACE_Time_Value::ACE_Time_Value (const FILETIME &file_time) +{ + // // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); + this->set (file_time); +} + +void ACE_Time_Value::set (const FILETIME &file_time) +{ + // Initializes the ACE_Time_Value object from a Win32 FILETIME + // Don't use a struct initializer, gcc don't like it. + ULARGE_INTEGER _100ns; + _100ns.LowPart = file_time.dwLowDateTime; + _100ns.HighPart = file_time.dwHighDateTime; + + _100ns.QuadPart -= ACE_Time_Value::FILETIME_to_timval_skew; + + // Convert 100ns units to seconds; + this->tv_.tv_sec = (time_t) (_100ns.QuadPart / (10000 * 1000)); + // Convert remainder to microseconds; + this->tv_.tv_usec = (suseconds_t) ((_100ns.QuadPart % (10000 * 1000)) / 10); + + this->normalize (); +} + +/// Returns the value of the object as a Win32 FILETIME. +ACE_Time_Value::operator FILETIME () const +{ + FILETIME file_time; + // ACE_OS_TRACE ("ACE_Time_Value::operator FILETIME"); + + ULARGE_INTEGER _100ns; + _100ns.QuadPart = (((DWORDLONG) this->tv_.tv_sec * (10000 * 1000) + + this->tv_.tv_usec * 10) + + ACE_Time_Value::FILETIME_to_timval_skew); + + file_time.dwLowDateTime = _100ns.LowPart; + file_time.dwHighDateTime = _100ns.HighPart; + + return file_time; +} +#endif /* ACE_WIN32 */ + +ACE_Time_Value +ACE_Time_Value::now () const +{ + ACE_System_Time_Policy systp; + return systp (); +} + +ACE_Time_Value +ACE_Time_Value::to_relative_time () const +{ + ACE_System_Time_Policy systp; + return (*this) - systp (); +} + +ACE_Time_Value +ACE_Time_Value::to_absolute_time () const +{ + ACE_System_Time_Policy systp; + return (*this) + systp (); +} + +ACE_Time_Value * +ACE_Time_Value::duplicate () const +{ + ACE_Time_Value * tmp = 0; + ACE_NEW_RETURN (tmp, ACE_Time_Value (*this), 0); + return tmp; +} + +void +ACE_Time_Value::dump (void) const +{ +} + +void +ACE_Time_Value::normalize (bool saturate) +{ + // ACE_OS_TRACE ("ACE_Time_Value::normalize"); + if (this->tv_.tv_usec >= ACE_ONE_SECOND_IN_USECS || + this->tv_.tv_usec <= -ACE_ONE_SECOND_IN_USECS) + { + time_t const sec = std::abs(this->tv_.tv_usec) / ACE_ONE_SECOND_IN_USECS * (this->tv_.tv_usec > 0 ? 1 : -1); + suseconds_t const usec = static_cast (this->tv_.tv_usec - sec * ACE_ONE_SECOND_IN_USECS); + + if (saturate && this->tv_.tv_sec > 0 && sec > 0 && + ACE_Numeric_Limits::max() - this->tv_.tv_sec < sec) + { + this->tv_.tv_sec = ACE_Numeric_Limits::max(); + this->tv_.tv_usec = ACE_ONE_SECOND_IN_USECS - 1; + } + else if (saturate && this->tv_.tv_sec < 0 && sec < 0 && + ACE_Numeric_Limits::min() - this->tv_.tv_sec > sec) + { + this->tv_.tv_sec = ACE_Numeric_Limits::min(); + this->tv_.tv_usec = -ACE_ONE_SECOND_IN_USECS + 1; + } + else + { + this->tv_.tv_sec += sec; + this->tv_.tv_usec = usec; + } + } + + if (this->tv_.tv_sec >= 1 && this->tv_.tv_usec < 0) + { + --this->tv_.tv_sec; + this->tv_.tv_usec += ACE_ONE_SECOND_IN_USECS; + } + // tv_sec in qnxnto is unsigned +#if !defined ( __QNX__) + else if (this->tv_.tv_sec < 0 && this->tv_.tv_usec > 0) + { + ++this->tv_.tv_sec; + this->tv_.tv_usec -= ACE_ONE_SECOND_IN_USECS; + } +#endif /* __QNX__ */ +} + + +ACE_Time_Value & +ACE_Time_Value::operator *= (double d) +{ + // To work around the lack of precision of a long double to contain + // a 64-bits time_t + 6 digits after the decimal point for the usec part, + // we perform the multiplication of the 2 timeval parts separately. + // + // This extra precision step is adding a cost when transfering the + // seconds resulting from the usec multiplication. This operation + // correspond to the normalization process performed in normalize() + // but we must absolutly do it here because the usec multiplication + // result value could exceed what can be stored in a suseconds_t + // type variable. + // + // Since this is a costly operation, we try to detect as soon as + // possible if we are having a saturation in order to abort the rest + // of the computation. + typedef ACE::If_Then_Else<(sizeof (double) > sizeof (time_t)), + double, + long double>::result_type float_type; + + float_type sec_total = static_cast (this->sec()); + sec_total *= d; + + // shall we saturate the result? + static const float_type max_int = + ACE_Numeric_Limits::max() + 0.999999; + static const float_type min_int = + ACE_Numeric_Limits::min() - 0.999999; + + if (sec_total > max_int) + { + this->set(ACE_Numeric_Limits::max(), ACE_ONE_SECOND_IN_USECS-1); + } + else if (sec_total < min_int) + { + this->set(ACE_Numeric_Limits::min(), -ACE_ONE_SECOND_IN_USECS+1); + } + else + { + time_t time_sec = static_cast (sec_total); + + float_type usec_total = this->usec(); + usec_total *= d; + + // adding usec resulting from tv_sec mult + usec_total += (sec_total-time_sec) * ACE_ONE_SECOND_IN_USECS; + + // extract seconds component of the usec mult + sec_total = usec_total / ACE_ONE_SECOND_IN_USECS; + // keep remaining usec + if (sec_total > 0) + { + usec_total = (sec_total - ACE_OS::floor(sec_total)); + } + else + { + usec_total = (sec_total - ACE_OS::ceil(sec_total)); + } + + sec_total -= usec_total; + usec_total *= ACE_ONE_SECOND_IN_USECS; + + // add the seconds component of the usec mult with the tv_sec mult prod. + sec_total += time_sec; + + // recheck for saturation + if (sec_total > max_int) + { + this->set (ACE_Numeric_Limits::max(), ACE_ONE_SECOND_IN_USECS - 1); + } + else if (sec_total < min_int) + { + this->set (ACE_Numeric_Limits::min(), -ACE_ONE_SECOND_IN_USECS + 1); + } + else + { + time_sec = static_cast (sec_total); + suseconds_t time_usec = static_cast (usec_total); + + // round up the result to save the last usec + if (time_usec > 0 && (usec_total - time_usec) >= 0.5) + { + ++time_usec; + } + else if (time_usec < 0 && (usec_total - time_usec) <= -0.5) + { + --time_usec; + } + + this->set (time_sec, time_usec); + } + } + return *this; +} + +#ifdef ACE_HAS_CPP98_IOSTREAMS +ostream &operator<<(ostream &o, const ACE_Time_Value &v) +{ + char const oldFiller = o.fill (); + o.fill ('0'); + const timeval *tv = v; + if (tv->tv_sec) + { + o << tv->tv_sec; + if (tv->tv_usec) +#ifdef ACE_HAS_CPP11 + o << '.' << std::setw (6) << std::labs (tv->tv_usec); +#else + o << '.' << std::setw (6) << ACE_STD_NAMESPACE::labs (tv->tv_usec); +#endif + } + else if (tv->tv_usec < 0) + o << "-0." << std::setw (6) << - tv->tv_usec; + else + { + o << '0'; + if (tv->tv_usec > 0) + o << '.'<< std::setw (6) << tv->tv_usec; + } + + o.fill (oldFiller); + return o; +} +#endif /* ACE_HAS_CPP98_IOSTREAMS */ + +ACE_END_VERSIONED_NAMESPACE_DECL diff --git a/dep/acelite/ace/Time_Value.h b/dep/acelite/ace/Time_Value.h new file mode 100644 index 000000000..7b67867ee --- /dev/null +++ b/dep/acelite/ace/Time_Value.h @@ -0,0 +1,554 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Time_Value.h + * + * @author Douglas C. Schmidt + */ +//============================================================================= + +#ifndef ACE_TIME_VALUE_H +#define ACE_TIME_VALUE_H + +#include /**/ "ace/pre.h" + +#include /**/ "ace/ACE_export.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +# include "ace/os_include/os_time.h" + +#if defined (ACE_HAS_CPP11) +# include +# include "ace/Truncate.h" +#endif /* ACE_HAS_CPP11 */ + +// Define some helpful constants. +// Not type-safe, and signed. For backward compatibility. +#define ACE_ONE_SECOND_IN_MSECS 1000L +suseconds_t const ACE_ONE_SECOND_IN_USECS = 1000000; +#define ACE_ONE_SECOND_IN_NSECS 1000000000L + +// needed for ACE_UINT64 +#include "ace/Basic_Types.h" + +// needed to determine if iostreams are present +#include "ace/iosfwd.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Time_Value + * + * @brief Operations on "timeval" structures, which express time in + * seconds (secs) and microseconds (usecs). + * + * This class centralizes all the time related processing in + * ACE. These time values are typically used in conjunction with OS + * mechanisms like or other calls that may have + * *their own* implementation-specific maximum time representations. + * Its primary use is in time computations such as those used by the + * dynamic subpriority strategies in the ACE_Dynamic_Message_Queue + * class. + */ + static const ACE_Time_Value max_time; + + // = Initialization methods. + + /// Default Constructor. + ACE_Time_Value (void); + + /// Constructor. + explicit ACE_Time_Value (time_t sec, suseconds_t usec = 0); + + // = Methods for converting to/from various time formats. + + /// Construct the ACE_Time_Value from a timeval. + explicit ACE_Time_Value (const struct timeval &t); + + /// Construct the ACE_Time_Value object from a timespec_t. + explicit ACE_Time_Value (const timespec_t &t); + +#if defined (ACE_HAS_CPP11) + /// Construct the ACE_Time_Value object from a chrono duration. + template< class Rep, class Period > + explicit ACE_Time_Value (const std::chrono::duration& duration) + { + this->set (duration); + } +#endif /* ACE_HAS_CPP11 */ + + /// Destructor + virtual ~ACE_Time_Value (); + + /// Declare the dynamic allocation hooks. + ACE_ALLOC_HOOK_DECLARE; + +# if defined (ACE_WIN32) + /// Construct the ACE_Time_Value object from a Win32 FILETIME + explicit ACE_Time_Value (const FILETIME &ft); +# endif /* ACE_WIN32 */ + + /// Initializes the ACE_Time_Value from seconds and useconds. + void set (time_t sec, suseconds_t usec); + + /// Initializes the ACE_Time_Value from a double, which is assumed to be + /// in second format, with any remainder treated as microseconds. + void set (double d); + + /// Initializes the ACE_Time_Value from a timeval. + void set (const timeval &t); + + /// Initializes the ACE_Time_Value object from a timespec_t. + void set (const timespec_t &t); + +# if defined (ACE_WIN32) + /// Initializes the ACE_Time_Value object from a Win32 FILETIME. + void set (const FILETIME &ft); +# endif /* ACE_WIN32 */ + +#if defined (ACE_HAS_CPP11) + /// Initializes the ACE_Time_Value object from a std::duration. + template< class Rep, class Period > + void set (const std::chrono::duration& duration) + { + std::chrono::seconds const s { + std::chrono::duration_cast (duration)}; + + std::chrono::microseconds const usec { + std::chrono::duration_cast( + duration % std::chrono::seconds (1))}; + this->set (s.count (), ACE_Utils::truncate_cast(usec.count ())); + } +#endif /* ACE_HAS_CPP11 */ + + /// Converts from ACE_Time_Value format into milliseconds format. + /** + * @return Sum of second field (in milliseconds) and microsecond field + * (in milliseconds). Note that this method can overflow if + * the second and microsecond field values are large, so use + * the msec (ACE_UINT64 &ms) method instead. + * + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + */ + unsigned long msec (void) const; + + /// Converts from ACE_Time_Value format into milliseconds format. + /** + * @return Sum of second field (in milliseconds) and microsecond field + * (in milliseconds). + * + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + */ + ACE_UINT64 get_msec () const; + + /// Converts from ACE_Time_Value format into milliseconds format. + /** + * @return Sum of second field (in milliseconds) and microsecond field + * (in milliseconds) and return them via the @param ms parameter. + * + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + * + * @deprecated Use get_msec() instead. + */ + void msec (ACE_UINT64 &ms) const; + + /// Converts from ACE_Time_Value format into milliseconds format. + /** + * @return Sum of second field (in milliseconds) and microsecond field + * (in milliseconds) and return them via the @param ms parameter. + * + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + * + * @deprecated Use get_msec() instead. + */ + void msec (ACE_UINT64 &ms) /* const */; + + /// Converts from milli-seconds format into ACE_Time_Value format. + /** + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + */ + void set_msec (const ACE_UINT64 &ms); + + /// Converts from milli-seconds format into ACE_Time_Value format. + /** + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + */ + void msec (long); + + /// Converts from milli-seconds format into ACE_Time_Value format. + /** + * @note The semantics of this method differs from the sec() and + * usec() methods. There is no analogous "millisecond" + * component in an ACE_Time_Value. + */ + void msec (int); // converted to long then calls above. + + /// Returns the value of the object as a timespec_t. + operator timespec_t () const; + + /// Returns the value of the object as a timeval. + operator timeval () const; + + /// Returns a pointer to the object as a timeval. + operator const timeval *() const; + +# if defined (ACE_WIN32) + /// Returns the value of the object as a Win32 FILETIME. + operator FILETIME () const; +# endif /* ACE_WIN32 */ + + // = The following are accessor/mutator methods. + + /// Get seconds. + /** + * @return The second field/component of this ACE_Time_Value. + * + * @note The semantics of this method differs from the msec() + * method. + */ + time_t sec (void) const; + + /// Set seconds. + void sec (time_t sec); + + /// Get microseconds. + /** + * @return The microsecond field/component of this ACE_Time_Value. + * + * @note The semantics of this method differs from the msec() + * method. + */ + suseconds_t usec (void) const; + + /// Set microseconds. + void usec (suseconds_t usec); + + /** + * @return Sum of second field (in microseconds) and microsecond field + * and return them via the @param usec parameter. + */ + void to_usec (ACE_UINT64 &usec) const; + + // = The following arithmetic methods operate on ACE_Time_Value's. + + /// Add @a tv to this. + ACE_Time_Value &operator += (const ACE_Time_Value &tv); + + /// Add @a tv to this. + ACE_Time_Value &operator += (time_t tv); + + /// Assign @a tv to this + ACE_Time_Value &operator = (const ACE_Time_Value &tv); + + /// Assign @a tv to this + ACE_Time_Value &operator = (time_t tv); + + /// Subtract @a tv to this. + ACE_Time_Value &operator -= (const ACE_Time_Value &tv); + + /// Subtract @a tv to this. + ACE_Time_Value &operator -= (time_t tv); + +#if defined (ACE_HAS_CPP11) + /// Add @a std::duration to this. + template< class Rep, class Period > + ACE_Time_Value &operator += (const std::chrono::duration& duration) + { + const ACE_Time_Value tv (duration); + this->sec (this->sec () + tv.sec ()); + this->usec (this->usec () + tv.usec ()); + this->normalize (); + return *this; + } + + /// Assign @a std::duration to this + template< class Rep, class Period > + ACE_Time_Value &operator = (const std::chrono::duration& duration) + { + this->set (duration); + return *this; + } + + /// Subtract @a std::duration to this. + template< class Rep, class Period > + ACE_Time_Value &operator -= (const std::chrono::duration& duration) + { + const ACE_Time_Value tv (duration); + this->sec (this->sec () - tv.sec ()); + this->usec (this->usec () - tv.usec ()); + this->normalize (); + return *this; + } +#endif /* ACE_HAS_CPP11 */ + + + /** + \brief Multiply the time value by the @a d factor. + \note The result of the operator is valid for results from range + < (ACE_INT32_MIN, -999999), (ACE_INT32_MAX, 999999) >. Result + outside this range are saturated to a limit. + */ + ACE_Time_Value &operator *= (double d); + + /// Increment microseconds as postfix. + /** + * @note The only reason this is here is to allow the use of ACE_Atomic_Op + * with ACE_Time_Value. + */ + ACE_Time_Value operator++ (int); + + /// Increment microseconds as prefix. + /** + * @note The only reason this is here is to allow the use of ACE_Atomic_Op + * with ACE_Time_Value. + */ + ACE_Time_Value &operator++ (void); + + /// Decrement microseconds as postfix. + /** + * @note The only reason this is here is to allow the use of ACE_Atomic_Op + * with ACE_Time_Value. + */ + ACE_Time_Value operator-- (int); + + /// Decrement microseconds as prefix. + /** + * @note The only reason this is here is to allow the use of ACE_Atomic_Op + * with ACE_Time_Value. + */ + ACE_Time_Value &operator-- (void); + + /// Adds two ACE_Time_Value objects together, returns the sum. + friend ACE_Export ACE_Time_Value operator + (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// Subtracts two ACE_Time_Value objects, returns the difference. + friend ACE_Export ACE_Time_Value operator - (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 < @a tv2. + friend ACE_Export bool operator < (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 > @a tv2. + friend ACE_Export bool operator > (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 <= @a tv2. + friend ACE_Export bool operator <= (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 >= @a tv2. + friend ACE_Export bool operator >= (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 == @a tv2. + friend ACE_Export bool operator == (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + /// True if @a tv1 != @a tv2. + friend ACE_Export bool operator != (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2); + + //@{ + /// Multiplies the time value by @a d + friend ACE_Export ACE_Time_Value operator * (double d, + const ACE_Time_Value &tv); + + friend ACE_Export ACE_Time_Value operator * (const ACE_Time_Value &tv, + double d); + //@} + + /// Get current time of day. + /** + * @return Time value representing current time of day. + * + * @note This method is overloaded in the time policy based template + * instantiations derived from this class. Allows for time policy + * aware time values. + */ + virtual ACE_Time_Value now () const; + + /// Converts absolute time value to time value relative to current time of day. + /** + * @return Relative time value. + * + * @note This method is overloaded in the time policy based template + * instantiations derived from this class. Allows for time policy + * aware time values. + * The developer is responsible for making sure this is an absolute + * time value compatible with the active time policy (which is system + * time for the base class). + */ + virtual ACE_Time_Value to_relative_time () const; + + /// Converts relative time value to absolute time value based on current time of day. + /** + * @return Absolute time value. + * + * @note This method is overloaded in the time policy based template + * instantiations derived from this class. Allows for time policy + * aware time values. + * The developer is responsible for making sure this is a relative + * time value. Current time of day is determined based on time policy + * (which is system time for the base class). + */ + virtual ACE_Time_Value to_absolute_time () const; + + /// Duplicates this time value (incl. time policy). + /** + * @return Dynamically allocated time value copy. + * + * @note The caller is responsible for freeing the copy when it's not needed + * anymore. + */ + virtual ACE_Time_Value * duplicate () const; + + /// Dump is a no-op. + /** + * The dump() method is a no-op. It's here for backwards compatibility + * only, but does not dump anything. Invoking logging methods here + * violates layering restrictions in ACE because this class is part + * of the OS layer and @c ACE_Log_Msg is at a higher level. + */ + void dump (void) const; + +# if defined (ACE_WIN32) + /// Const time difference between FILETIME and POSIX time. + static const DWORDLONG FILETIME_to_timval_skew; +# endif /* ACE_WIN32 */ + +private: + /// Put the timevalue into a canonical form. + void normalize (bool saturate = false); + + /// Store the values as a timeval. +#if defined (ACE_HAS_TIME_T_LONG_MISMATCH) + // Windows' timeval is non-conformant, so swap in a struct that conforms + // to the proper data types to represent the entire time range that this + // class's API can accept. + // Also, since this class can supply a pointer to a timeval that things + // like select() expect, we need the OS-defined one as well. To make this + // available, use a real timeval called ext_tv_ and set it up when needed. + // Since this is most often for relative times that don't approach 32 bits + // in size, reducing a time_t to fit should be no problem. + struct { + time_t tv_sec; + suseconds_t tv_usec; + } tv_; + timeval ext_tv_; +#else + timeval tv_; +#endif /* ACE_HAS_TIME_T_LONG_MISMATCH */ +}; + +#ifdef ACE_HAS_CPP98_IOSTREAMS +extern ACE_Export ostream &operator<<( ostream &o, const ACE_Time_Value &v ); +#endif + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_CPP11) + +// Additional chrono operators. + +namespace std +{ + namespace chrono + { + /** + * @name Streaming ACE_Time_Value to chrono + * + * Streaming an ACE_Time_Value into one of the chrono types (nanoseconds, + * microseconds, milliseconds, seconds, minutes, or hours). + * + */ + //@{ + ACE_Export nanoseconds& operator <<(nanoseconds &ns, ACE_Time_Value const &tv); + ACE_Export microseconds& operator <<(microseconds &us, ACE_Time_Value const &tv); + ACE_Export milliseconds& operator <<(milliseconds &ms, ACE_Time_Value const &tv); + ACE_Export seconds& operator <<(seconds &s, ACE_Time_Value const &tv); + ACE_Export minutes& operator <<(minutes &m, ACE_Time_Value const &tv); + ACE_Export hours& operator <<(hours &h, ACE_Time_Value const &tv); + //@} + + /** + * @name Adding ACE_Time_Value to chrono + * + * Adding an ACE_Time_Value to one of the chrono types (nanoseconds, + * microseconds, milliseconds, seconds, minutes, or hours). + * + */ + //@{ + ACE_Export nanoseconds& operator +=(nanoseconds &ns, ACE_Time_Value const &tv); + ACE_Export microseconds& operator +=(microseconds &us, ACE_Time_Value const &tv); + ACE_Export milliseconds& operator +=(milliseconds &ms, ACE_Time_Value const &tv); + ACE_Export seconds& operator +=(seconds &s, ACE_Time_Value const &tv); + ACE_Export minutes& operator +=(minutes &m, ACE_Time_Value const &tv); + ACE_Export hours& operator +=(hours &h, ACE_Time_Value const &tv); + //@} + + /** + * @name Substracting ACE_Time_Value from chrono + * + * Substracting an ACE_Time_Value from one of the chrono types (nanoseconds, + * microseconds, milliseconds, seconds, minutes, or hours). + * + */ + //@{ + ACE_Export nanoseconds& operator -=(nanoseconds &ns, ACE_Time_Value const &tv); + ACE_Export microseconds& operator -=(microseconds &us, ACE_Time_Value const &tv); + ACE_Export milliseconds& operator -=(milliseconds &ms, ACE_Time_Value const &tv); + ACE_Export seconds& operator -=(seconds &s, ACE_Time_Value const &tv); + ACE_Export minutes& operator -=(minutes &m, ACE_Time_Value const &tv); + ACE_Export hours& operator -=(hours &h, ACE_Time_Value const &tv); + //@} + } +} + +#endif /* ACE_HAS_CPP11 */ + +#if defined (__ACE_INLINE__) +#include "ace/Time_Value.inl" +#endif /* __ACE_INLINE__ */ + +#if defined (__MINGW32__) +ACE_BEGIN_VERSIONED_NAMESPACE_DECL +// The MingW linker has problems with the exported statics +// zero and max_time with these two statics the linker will be able to +// resolve the static exported symbols. +static const ACE_Time_Value& __zero_time = ACE_Time_Value::zero; +static const ACE_Time_Value& __max_time = ACE_Time_Value::max_time; +ACE_END_VERSIONED_NAMESPACE_DECL +#endif /* __MINGW32__ */ + +#include /**/ "ace/post.h" + +#endif /* ACE_TIME_VALUE_H */ diff --git a/dep/acelite/ace/Time_Value.inl b/dep/acelite/ace/Time_Value.inl new file mode 100644 index 000000000..98459b477 --- /dev/null +++ b/dep/acelite/ace/Time_Value.inl @@ -0,0 +1,565 @@ +// -*- C++ -*- +#include "ace/Truncate.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/// Returns the value of the object as a timeval. +ACE_INLINE +ACE_Time_Value::operator timeval () const +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator timeval"); +#if defined (ACE_HAS_TIME_T_LONG_MISMATCH) + // Recall that on some Windows we substitute another type for timeval in tv_ + ACE_Time_Value *me = const_cast (this); + me->ext_tv_.tv_sec = ACE_Utils::truncate_cast (this->tv_.tv_sec); + me->ext_tv_.tv_usec = ACE_Utils::truncate_cast (this->tv_.tv_usec); + return this->ext_tv_; +#else + return this->tv_; +#endif /* ACE_HAS_TIME_T_LONG_MISMATCH */ +} + +ACE_INLINE void +ACE_Time_Value::set (const timeval &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::set"); + this->tv_.tv_sec = tv.tv_sec; + this->tv_.tv_usec = tv.tv_usec; + + this->normalize (); +} + +ACE_INLINE +ACE_Time_Value::ACE_Time_Value (const struct timeval &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); + this->set (tv); +} + +ACE_INLINE +ACE_Time_Value::operator const timeval * () const +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator const timeval *"); +#if defined (ACE_HAS_TIME_T_LONG_MISMATCH) + // Recall that on some Windows we substitute another type for timeval in tv_ + ACE_Time_Value *me = const_cast (this); + me->ext_tv_.tv_sec = ACE_Utils::truncate_cast (this->tv_.tv_sec); + me->ext_tv_.tv_usec = ACE_Utils::truncate_cast (this->tv_.tv_usec); + return (const timeval *) &this->ext_tv_; +#else + return (const timeval *) &this->tv_; +#endif /* ACE_HAS_TIME_T_LONG_MISMATCH */ +} + +ACE_INLINE void +ACE_Time_Value::set (time_t sec, suseconds_t usec) +{ + // ACE_OS_TRACE ("ACE_Time_Value::set"); + this->tv_.tv_sec = sec; + this->tv_.tv_usec = usec; +#if __GNUC__ && !(__GNUC__ == 3 && __GNUC_MINOR__ == 4) + if ((__builtin_constant_p(sec) & + __builtin_constant_p(usec)) && + (sec >= 0 && usec >= 0 && usec < ACE_ONE_SECOND_IN_USECS)) + return; +#endif + this->normalize (); +} + +ACE_INLINE void +ACE_Time_Value::set (double d) +{ + // ACE_OS_TRACE ("ACE_Time_Value::set"); + if (d < ACE_Numeric_Limits::min()) + { + this->tv_.tv_sec = ACE_Numeric_Limits::min(); + this->tv_.tv_usec = -ACE_ONE_SECOND_IN_USECS + 1; + } + else if (d > ACE_Numeric_Limits::max()) + { + this->tv_.tv_sec = ACE_Numeric_Limits::max(); + this->tv_.tv_usec = ACE_ONE_SECOND_IN_USECS - 1; + } + else + { + time_t l = (time_t) d; + this->tv_.tv_sec = l; + this->tv_.tv_usec = (suseconds_t) ((d - (double) l) * ACE_ONE_SECOND_IN_USECS + (d < 0 ? -0.5 : 0.5)); + } +} + +/// Initializes a timespec_t. Note that this approach loses precision +/// since it converts the nano-seconds into micro-seconds. But then +/// again, do any real systems have nano-second timer precision?! +ACE_INLINE void +ACE_Time_Value::set (const timespec_t &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::set"); + + this->set (tv.tv_sec, + tv.tv_nsec / 1000); // Convert nanoseconds into microseconds. +} + +ACE_INLINE +ACE_Time_Value::ACE_Time_Value (void) + // : tv_ () +{ + // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); + this->set (0, 0); +} + +ACE_INLINE +ACE_Time_Value::ACE_Time_Value (time_t sec, suseconds_t usec) +{ + // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); + this->set (sec, usec); +} + +/// Returns number of seconds. +ACE_INLINE time_t +ACE_Time_Value::sec (void) const +{ + // ACE_OS_TRACE ("ACE_Time_Value::sec"); + return this->tv_.tv_sec; +} + +/// Sets the number of seconds. +ACE_INLINE void +ACE_Time_Value::sec (time_t sec) +{ + // ACE_OS_TRACE ("ACE_Time_Value::sec"); + this->tv_.tv_sec = sec; +} + +/// Converts from Time_Value format into milli-seconds format. +ACE_INLINE unsigned long +ACE_Time_Value::msec (void) const +{ + // ACE_OS_TRACE ("ACE_Time_Value::msec"); + + // Note - we're truncating a value here, which can lose data. This is + // called out in the user documentation for this with a recommendation to + // use msec(ACE_UINT64&) instead, so just go ahead and truncate. + time_t secs = this->tv_.tv_sec * 1000 + this->tv_.tv_usec / 1000; + return ACE_Utils::truncate_cast (secs); +} + +ACE_INLINE ACE_UINT64 +ACE_Time_Value::get_msec () const +{ + // ACE_OS_TRACE ("ACE_Time_Value::get_msec"); + ACE_UINT64 ms = ACE_Utils::truncate_cast (this->tv_.tv_sec); + ms *= 1000; + ms += (this->tv_.tv_usec / 1000); + return ms; +} + +ACE_INLINE void +ACE_Time_Value::msec (ACE_UINT64 &ms) const +{ + // ACE_OS_TRACE ("ACE_Time_Value::msec"); + ms = this->get_msec (); +} + +ACE_INLINE void +ACE_Time_Value::msec (ACE_UINT64 &ms) /*const*/ +{ + // ACE_OS_TRACE ("ACE_Time_Value::msec"); + const ACE_Time_Value *tv = this; + tv->msec (ms); +} + +ACE_INLINE void +ACE_Time_Value::set_msec (const ACE_UINT64 &ms) +{ + // ACE_OS_TRACE ("ACE_Time_Value::set_msec"); + // Convert millisecond units to seconds; + ACE_UINT64 secs = ms / 1000; + this->tv_.tv_sec = static_cast (secs); + // Convert remainder to microseconds; + this->tv_.tv_usec = static_cast((ms - (secs * 1000)) * 1000); +} + +/// Converts from milli-seconds format into Time_Value format. +ACE_INLINE void +ACE_Time_Value::msec (long milliseconds) +{ + // ACE_OS_TRACE ("ACE_Time_Value::msec"); + // Convert millisecond units to seconds; + long secs = milliseconds / 1000; + this->tv_.tv_sec = secs; + // Convert remainder to microseconds; + this->tv_.tv_usec = (milliseconds - (secs * 1000)) * 1000; +} + +/// Converts from milli-seconds format into Time_Value format. +ACE_INLINE void +ACE_Time_Value::msec (int milliseconds) +{ + ACE_Time_Value::msec (static_cast (milliseconds)); +} + +/// Returns number of micro-seconds. +ACE_INLINE suseconds_t +ACE_Time_Value::usec (void) const +{ + // ACE_OS_TRACE ("ACE_Time_Value::usec"); + return this->tv_.tv_usec; +} + +/// Sets the number of micro-seconds. +ACE_INLINE void +ACE_Time_Value::usec (suseconds_t usec) +{ + // ACE_OS_TRACE ("ACE_Time_Value::usec"); + this->tv_.tv_usec = usec; +} + +ACE_INLINE void +ACE_Time_Value::to_usec (ACE_UINT64 & usec) const +{ + // ACE_OS_TRACE ("ACE_Time_Value::to_usec"); + usec = static_cast (this->tv_.tv_sec); + usec *= 1000000; + usec += this->tv_.tv_usec; +} + +ACE_INLINE ACE_Time_Value +operator * (double d, const ACE_Time_Value &tv) +{ + return ACE_Time_Value (tv) *= d; +} + +ACE_INLINE ACE_Time_Value +operator * (const ACE_Time_Value &tv, double d) +{ + return ACE_Time_Value (tv) *= d; +} + +/// True if tv1 > tv2. +ACE_INLINE bool +operator > (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator >"); + if (tv1.sec () > tv2.sec ()) + return 1; + else if (tv1.sec () == tv2.sec () + && tv1.usec () > tv2.usec ()) + return 1; + else + return 0; +} + +/// True if tv1 >= tv2. +ACE_INLINE bool +operator >= (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator >="); + if (tv1.sec () > tv2.sec ()) + return 1; + else if (tv1.sec () == tv2.sec () + && tv1.usec () >= tv2.usec ()) + return 1; + else + return 0; +} + +/// Returns the value of the object as a timespec_t. +ACE_INLINE +ACE_Time_Value::operator timespec_t () const +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator timespec_t"); + timespec_t tv; + tv.tv_sec = this->sec (); + // Convert microseconds into nanoseconds. + tv.tv_nsec = this->tv_.tv_usec * 1000; + return tv; +} + +/// Initializes the ACE_Time_Value object from a timespec_t. +ACE_INLINE +ACE_Time_Value::ACE_Time_Value (const timespec_t &tv) + // : tv_ () +{ + // ACE_OS_TRACE ("ACE_Time_Value::ACE_Time_Value"); + this->set (tv); +} + +/// True if tv1 < tv2. +ACE_INLINE bool +operator < (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator <"); + return tv2 > tv1; +} + +/// True if tv1 >= tv2. +ACE_INLINE bool +operator <= (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator <="); + return tv2 >= tv1; +} + +/// True if tv1 == tv2. +ACE_INLINE bool +operator == (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator =="); + return tv1.sec () == tv2.sec () + && tv1.usec () == tv2.usec (); +} + +/// True if tv1 != tv2. +ACE_INLINE bool +operator != (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator !="); + return !(tv1 == tv2); +} + +/// Add TV to this. +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator+= (const ACE_Time_Value &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator+="); + this->sec (this->sec () + tv.sec ()); + this->usec (this->usec () + tv.usec ()); + this->normalize (); + return *this; +} + +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator+= (time_t tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator+="); + this->sec (this->sec () + tv); + return *this; +} + +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator= (const ACE_Time_Value &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator="); + this->sec (tv.sec ()); + this->usec (tv.usec ()); + return *this; +} + +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator= (time_t tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator="); + this->sec (tv); + this->usec (0); + return *this; +} + +/// Subtract TV to this. +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator-= (const ACE_Time_Value &tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator-="); + this->sec (this->sec () - tv.sec ()); + this->usec (this->usec () - tv.usec ()); + this->normalize (); + return *this; +} + +ACE_INLINE ACE_Time_Value & +ACE_Time_Value::operator-= (time_t tv) +{ + // ACE_OS_TRACE ("ACE_Time_Value::operator-="); + this->sec (this->sec () - tv); + return *this; +} + +/// Adds two ACE_Time_Value objects together, returns the sum. +ACE_INLINE ACE_Time_Value +operator + (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator +"); + ACE_Time_Value sum (tv1); + sum += tv2; + + return sum; +} + +/// Subtracts two ACE_Time_Value objects, returns the difference. +ACE_INLINE ACE_Time_Value +operator - (const ACE_Time_Value &tv1, + const ACE_Time_Value &tv2) +{ + // ACE_OS_TRACE ("operator -"); + ACE_Time_Value delta (tv1); + delta -= tv2; + + return delta; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#if defined (ACE_HAS_CPP11) + +// Additional chrono streaming operators. + +namespace std +{ + namespace chrono + { + ACE_INLINE nanoseconds& + operator <<(nanoseconds &ns, ACE_Time_Value const &tv) + { + ns = duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ns; + } + + ACE_INLINE microseconds& + operator <<(microseconds &us, ACE_Time_Value const &tv) + { + us= duration_cast(seconds{tv.sec ()}) + + microseconds{tv.usec()}; + return us; + } + + ACE_INLINE milliseconds& + operator <<(milliseconds &ms, ACE_Time_Value const &tv) + { + ms = duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ms; + } + + ACE_INLINE seconds& + operator <<(seconds &s, ACE_Time_Value const &tv) + { + s = seconds{tv.sec ()} + + duration_cast(microseconds{tv.usec()}); + return s; + } + + ACE_INLINE minutes& + operator <<(minutes &m, ACE_Time_Value const &tv) + { + m = duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return m; + } + + ACE_INLINE hours& + operator <<(hours &h, ACE_Time_Value const &tv) + { + h = duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return h; + } + + + ACE_INLINE nanoseconds& + operator +=(nanoseconds &ns, ACE_Time_Value const &tv) + { + ns += duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ns; + } + + ACE_INLINE microseconds& + operator +=(microseconds &us, ACE_Time_Value const &tv) + { + us += duration_cast(seconds{tv.sec ()}) + + microseconds{tv.usec()}; + return us; + } + + ACE_INLINE milliseconds& + operator +=(milliseconds &ms, ACE_Time_Value const &tv) + { + ms += duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ms; + } + + ACE_INLINE seconds& + operator +=(seconds &s, ACE_Time_Value const &tv) + { + s += seconds{tv.sec ()} + + duration_cast(microseconds{tv.usec()}); + return s; + } + + ACE_INLINE minutes& + operator +=(minutes &m, ACE_Time_Value const &tv) + { + m += duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return m; + } + + ACE_INLINE hours& + operator +=(hours &h, ACE_Time_Value const &tv) + { + h += duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return h; + } + + + ACE_INLINE nanoseconds& + operator -=(nanoseconds &ns, ACE_Time_Value const &tv) + { + ns -= duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ns; + } + + ACE_INLINE microseconds& + operator -=(microseconds &us, ACE_Time_Value const &tv) + { + us -= duration_cast(seconds{tv.sec ()}) + + microseconds{tv.usec()}; + return us; + } + + ACE_INLINE milliseconds& + operator -=(milliseconds &ms, ACE_Time_Value const &tv) + { + ms -= duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return ms; + } + + ACE_INLINE seconds& + operator -=(seconds &s, ACE_Time_Value const &tv) + { + s -= seconds{tv.sec ()} + + duration_cast(microseconds{tv.usec()}); + return s; + } + + ACE_INLINE minutes& + operator -=(minutes &m, ACE_Time_Value const &tv) + { + m -= duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return m; + } + + ACE_INLINE hours& + operator -=(hours &h, ACE_Time_Value const &tv) + { + h -= duration_cast(seconds{tv.sec ()}) + + duration_cast(microseconds{tv.usec()}); + return h; + } + } +} + +#endif /* ACE_HAS_CPP11 */ diff --git a/dep/acelite/ace/Time_Value_T.cpp b/dep/acelite/ace/Time_Value_T.cpp new file mode 100644 index 000000000..79689d904 --- /dev/null +++ b/dep/acelite/ace/Time_Value_T.cpp @@ -0,0 +1,50 @@ +#ifndef ACE_TIME_VALUE_T_CPP +#define ACE_TIME_VALUE_T_CPP + +#include "ace/Time_Value_T.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#if !defined (__ACE_INLINE__) +#include "ace/Time_Value_T.inl" +#endif /* __ACE_INLINE__ */ + +#include "ace/OS_Memory.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +template +ACE_Time_Value +ACE_Time_Value_T::now () const +{ + return this->time_policy_ (); +} + +template +ACE_Time_Value +ACE_Time_Value_T::to_relative_time () const +{ + return (*this) - this->time_policy_ (); +} + +template +ACE_Time_Value +ACE_Time_Value_T::to_absolute_time () const +{ + return (*this) + this->time_policy_ (); +} + +template +ACE_Time_Value * +ACE_Time_Value_T::duplicate () const +{ + ACE_Time_Value_T * tmp = 0; + ACE_NEW_RETURN (tmp, ACE_Time_Value_T (*this), 0); + return tmp; +} + +ACE_END_VERSIONED_NAMESPACE_DECL + +#endif /* ACE_TIME_VALUE_T_CPP */ diff --git a/dep/acelite/ace/Time_Value_T.h b/dep/acelite/ace/Time_Value_T.h new file mode 100644 index 000000000..4348dccf1 --- /dev/null +++ b/dep/acelite/ace/Time_Value_T.h @@ -0,0 +1,192 @@ +// -*- C++ -*- + +//============================================================================= +/** + * @file Time_Value_T.h + * + * @author Martin Corino + */ +//============================================================================= + +#ifndef ACE_TIME_VALUE_T_H +#define ACE_TIME_VALUE_T_H + +#include /**/ "ace/pre.h" + +#if !defined (ACE_LACKS_PRAGMA_ONCE) +# pragma once +#endif /* ACE_LACKS_PRAGMA_ONCE */ + +#include "ace/Time_Value.h" + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +/** + * @class ACE_Time_Value + * + * @brief Operations on "timeval" structures, which express time in + * seconds (secs) and microseconds (usecs). + * + * This class centralizes all the time related processing in + * ACE. These time values are typically used in conjunction with OS + * mechanisms like