Files
orbithub/third_party/FreeRDP/winpr/include/winpr/stream.h

1456 lines
43 KiB
C

/*
* WinPR: Windows Portable Runtime
* Stream Utils
*
* Copyright 2011 Vic Lee
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2017 Armin Novak <armin.novak@thincast.com>
* Copyright 2017 Thincast Technologies GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef WINPR_UTILS_STREAM_H
#define WINPR_UTILS_STREAM_H
#include <winpr/winpr.h>
#include <winpr/wtypes.h>
#include <winpr/endian.h>
#include <winpr/synch.h>
#include <winpr/assert.h>
#include <winpr/cast.h>
#include <winpr/wlog.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct s_wStreamPool wStreamPool;
typedef struct
{
BYTE* buffer;
BYTE* pointer;
size_t length;
size_t capacity;
DWORD count;
wStreamPool* pool;
BOOL isAllocatedStream;
BOOL isOwner;
} wStream;
/** @brief helper initializing a \b wStream context
*
* @return The initialized context
* @since version 3.24.0
*/
static inline wStream Stream_Init(void)
{
const wStream empty = { nullptr, nullptr, 0, 0, 0, nullptr, FALSE, FALSE };
return empty;
}
static inline size_t Stream_Capacity(const wStream* _s);
WINPR_API size_t Stream_GetRemainingCapacity(const wStream* _s);
WINPR_API size_t Stream_GetRemainingLength(const wStream* _s);
WINPR_API BOOL Stream_EnsureCapacity(wStream* s, size_t size);
WINPR_API BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size);
#define WINPR_STREAM_CAST(t, val) WINPR_CXX_COMPAT_CAST(t, val)
#define Stream_CheckAndLogRequiredCapacityOfSize(tag, s, nmemb, size) \
Stream_CheckAndLogRequiredCapacityEx(tag, WLOG_WARN, s, nmemb, size, "%s(%s:%" PRIuz ")", \
__func__, __FILE__, (size_t)__LINE__)
#define Stream_CheckAndLogRequiredCapacity(tag, s, len) \
Stream_CheckAndLogRequiredCapacityOfSize((tag), (s), (len), 1)
WINPR_API BOOL Stream_CheckAndLogRequiredCapacityEx(const char* tag, DWORD level, wStream* s,
size_t nmemb, size_t size, const char* fmt,
...);
WINPR_API BOOL Stream_CheckAndLogRequiredCapacityExVa(const char* tag, DWORD level, wStream* s,
size_t nmemb, size_t size,
const char* fmt, va_list args);
#define Stream_CheckAndLogRequiredCapacityOfSizeWLog(log, s, nmemb, size) \
Stream_CheckAndLogRequiredCapacityWLogEx(log, WLOG_WARN, s, nmemb, size, "%s(%s:%" PRIuz ")", \
__func__, __FILE__, (size_t)__LINE__)
#define Stream_CheckAndLogRequiredCapacityWLog(log, s, len) \
Stream_CheckAndLogRequiredCapacityOfSizeWLog((log), (s), (len), 1)
WINPR_API BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level, wStream* s,
size_t nmemb, size_t size,
const char* fmt, ...);
WINPR_API BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level, wStream* s,
size_t nmemb, size_t size,
const char* fmt, va_list args);
WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer);
WINPR_ATTR_MALLOC(Stream_Free, 1)
WINPR_ATTR_NODISCARD
WINPR_API wStream* Stream_New(BYTE* buffer, size_t size);
WINPR_API wStream* Stream_StaticConstInit(wStream* s, const BYTE* buffer, size_t size);
WINPR_API wStream* Stream_StaticInit(wStream* s, BYTE* buffer, size_t size);
#define Stream_CheckAndLogRequiredLengthOfSize(tag, s, nmemb, size) \
Stream_CheckAndLogRequiredLengthEx(tag, WLOG_WARN, s, nmemb, size, "%s(%s:%" PRIuz ")", \
__func__, __FILE__, (size_t)__LINE__)
#define Stream_CheckAndLogRequiredLength(tag, s, len) \
Stream_CheckAndLogRequiredLengthOfSize(tag, s, len, 1)
WINPR_API BOOL Stream_CheckAndLogRequiredLengthEx(const char* tag, DWORD level, wStream* s,
size_t nmemb, size_t size, const char* fmt,
...);
WINPR_API BOOL Stream_CheckAndLogRequiredLengthExVa(const char* tag, DWORD level, wStream* s,
size_t nmemb, size_t size, const char* fmt,
va_list args);
#define Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, nmemb, size) \
Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, nmemb, size, "%s(%s:%" PRIuz ")", \
__func__, __FILE__, (size_t)__LINE__)
#define Stream_CheckAndLogRequiredLengthWLog(log, s, len) \
Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, len, 1)
WINPR_API BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level, wStream* s,
size_t nmemb, size_t size,
const char* fmt, ...);
WINPR_API BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level, wStream* s,
size_t nmemb, size_t size,
const char* fmt, va_list args);
static inline void Stream_Seek(wStream* s, size_t _offset)
{
WINPR_ASSERT(s);
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= _offset);
s->pointer += (_offset);
}
static inline void Stream_Rewind(wStream* s, size_t _offset)
{
size_t cur = 0;
WINPR_ASSERT(s);
WINPR_ASSERT(s->buffer <= s->pointer);
cur = WINPR_STREAM_CAST(size_t, s->pointer - s->buffer);
WINPR_ASSERT(cur >= _offset);
if (cur >= _offset)
s->pointer -= (_offset);
else
s->pointer = s->buffer;
}
static inline UINT8 stream_read_u8(wStream* _s, BOOL seek)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= sizeof(UINT8));
const UINT8 v = winpr_Data_Get_UINT8(_s->pointer);
if (seek)
Stream_Seek(_s, sizeof(UINT8));
return v;
}
static inline INT8 stream_read_i8(wStream* _s, BOOL seek)
{
const INT8 v = winpr_Data_Get_INT8(_s->pointer);
if (seek)
Stream_Seek(_s, sizeof(INT8));
return v;
}
static inline UINT16 stream_read_u16_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT16);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT16 v = winpr_Data_Get_UINT16(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline UINT16 stream_read_u16_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT16);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT16 v = winpr_Data_Get_UINT16_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT16 stream_read_i16_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT16);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT16 v = winpr_Data_Get_INT16(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT16 stream_read_i16_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT16);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT16 v = winpr_Data_Get_INT16_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline UINT32 stream_read_u32_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT32);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT32 v = winpr_Data_Get_UINT32(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline UINT32 stream_read_u32_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT32);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT32 v = winpr_Data_Get_UINT32_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT32 stream_read_i32_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT32);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT32 v = winpr_Data_Get_INT32(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT32 stream_read_i32_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT32);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT32 v = winpr_Data_Get_INT32_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline UINT64 stream_read_u64_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT64);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT64 v = winpr_Data_Get_UINT64(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline UINT64 stream_read_u64_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(UINT64);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const UINT64 v = winpr_Data_Get_UINT64_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT64 stream_read_i64_le(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT64);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT64 v = winpr_Data_Get_INT64(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
static inline INT64 stream_read_i64_be(wStream* _s, BOOL seek)
{
const size_t typesize = sizeof(INT64);
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingLength(_s) >= typesize);
const INT64 v = winpr_Data_Get_INT64_BE(_s->pointer);
if (seek)
Stream_Seek(_s, typesize);
return v;
}
/**
* @brief Stream_Get_UINT8
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT8 Stream_Get_UINT8(wStream* _s)
{
return stream_read_u8(_s, TRUE);
}
/**
* @brief Stream_Get_INT8
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT8 Stream_Get_INT8(wStream* _s)
{
return stream_read_i8(_s, TRUE);
}
/**
* @brief Stream_Get_UINT16
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT16 Stream_Get_UINT16(wStream* _s)
{
return stream_read_u16_le(_s, TRUE);
}
/**
* @brief Stream_Get_INT16
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT16 Stream_Get_INT16(wStream* _s)
{
return stream_read_i16_le(_s, TRUE);
}
/**
* @brief Stream_Get_UINT16 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT16 Stream_Get_UINT16_BE(wStream* _s)
{
return stream_read_u16_be(_s, TRUE);
}
/**
* @brief Stream_Get_INT16 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT16 Stream_Get_INT16_BE(wStream* _s)
{
return stream_read_i16_be(_s, TRUE);
}
/**
* @brief Stream_Get_UINT32
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT32 Stream_Get_UINT32(wStream* _s)
{
return stream_read_u32_le(_s, TRUE);
}
/**
* @brief Stream_Get_INT32
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT32 Stream_Get_INT32(wStream* _s)
{
return stream_read_i32_le(_s, TRUE);
}
/**
* @brief Stream_Get_UINT32 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT32 Stream_Get_UINT32_BE(wStream* _s)
{
return stream_read_u32_be(_s, TRUE);
}
/**
* @brief Stream_Get_INT32 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT32 Stream_Get_INT32_BE(wStream* _s)
{
return stream_read_i32_be(_s, TRUE);
}
/**
* @brief Stream_Get_UINT64
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT64 Stream_Get_UINT64(wStream* _s)
{
return stream_read_u64_le(_s, TRUE);
}
/**
* @brief Stream_Get_INT64
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT64 Stream_Get_INT64(wStream* _s)
{
return stream_read_i64_le(_s, TRUE);
}
/**
* @brief Stream_Get_UINT64 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT64 Stream_Get_UINT64_BE(wStream* _s)
{
return stream_read_u64_be(_s, TRUE);
}
/**
* @brief Stream_Get_INT64 big endian
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT64 Stream_Get_INT64_BE(wStream* _s)
{
return stream_read_i64_be(_s, TRUE);
}
/**
* @brief Read a UINT8 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT8 Stream_Peek_Get_UINT8(wStream* _s)
{
return stream_read_u8(_s, FALSE);
}
/**
* @brief Read a INT8 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT8 Stream_Peek_Get_INT8(wStream* _s)
{
return stream_read_i8(_s, FALSE);
}
/**
* @brief Read a UINT16 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT16 Stream_Peek_Get_UINT16(wStream* _s)
{
return stream_read_u16_le(_s, FALSE);
}
/**
* @brief Read a INT16 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT16 Stream_Peek_Get_INT16(wStream* _s)
{
return stream_read_i16_le(_s, FALSE);
}
/**
* @brief Read a UINT16 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT16 Stream_Peek_Get_UINT16_BE(wStream* _s)
{
return stream_read_u16_be(_s, FALSE);
}
/**
* @brief Read a INT16 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT16 Stream_Peek_Get_INT16_BE(wStream* _s)
{
return stream_read_i16_be(_s, FALSE);
}
/**
* @brief Read a UINT32 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT32 Stream_Peek_Get_UINT32(wStream* _s)
{
return stream_read_u32_le(_s, FALSE);
}
/**
* @brief Read a INT32 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT32 Stream_Peek_Get_INT32(wStream* _s)
{
return stream_read_i32_le(_s, FALSE);
}
/**
* @brief Read a UINT32 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT32 Stream_Peek_Get_UINT32_BE(wStream* _s)
{
return stream_read_u32_be(_s, FALSE);
}
/**
* @brief Read a INT32 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT32 Stream_Peek_Get_INT32_BE(wStream* _s)
{
return stream_read_i32_be(_s, FALSE);
}
/**
* @brief Read a UINT64 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT64 Stream_Peek_Get_UINT64(wStream* _s)
{
return stream_read_u64_le(_s, FALSE);
}
/**
* @brief Read a INT64 from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT64 Stream_Peek_Get_INT64(wStream* _s)
{
return stream_read_i64_le(_s, FALSE);
}
/**
* @brief Read a UINT64 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline UINT64 Stream_Peek_Get_UINT64_BE(wStream* _s)
{
return stream_read_u64_be(_s, FALSE);
}
/**
* @brief Read a INT64 big endian from the stream, do not increment stream position
* @param _s The stream to read from
* @return an integer
* @since version 3.9.0
*/
static inline INT64 Stream_Peek_Get_INT64_BE(wStream* _s)
{
return stream_read_i64_be(_s, FALSE);
}
#define Stream_Read_UINT8(_s, _v) \
do \
{ \
_v = stream_read_u8(_s, TRUE); \
} while (0)
#define Stream_Read_INT8(_s, _v) \
do \
{ \
_v = stream_read_i8(_s, TRUE); \
} while (0)
#define Stream_Read_UINT16(_s, _v) \
do \
{ \
_v = stream_read_u16_le(_s, TRUE); \
} while (0)
#define Stream_Read_INT16(_s, _v) \
do \
{ \
_v = stream_read_i16_le(_s, TRUE); \
} while (0)
#define Stream_Read_UINT16_BE(_s, _v) \
do \
{ \
_v = stream_read_u16_be(_s, TRUE); \
} while (0)
#define Stream_Read_INT16_BE(_s, _v) \
do \
{ \
_v = stream_read_i16_be(_s, TRUE); \
} while (0)
#define Stream_Read_UINT32(_s, _v) \
do \
{ \
_v = stream_read_u32_le(_s, TRUE); \
} while (0)
#define Stream_Read_INT32(_s, _v) \
do \
{ \
_v = stream_read_i32_le(_s, TRUE); \
} while (0)
#define Stream_Read_UINT32_BE(_s, _v) \
do \
{ \
_v = stream_read_u32_be(_s, TRUE); \
} while (0)
#define Stream_Read_INT32_BE(_s, _v) \
do \
{ \
_v = stream_read_i32_be(_s, TRUE); \
} while (0)
#define Stream_Read_UINT64(_s, _v) \
do \
{ \
_v = stream_read_u64_le(_s, TRUE); \
} while (0)
#define Stream_Read_INT64(_s, _v) \
do \
{ \
_v = stream_read_i64_le(_s, TRUE); \
} while (0)
#define Stream_Read_UINT64_BE(_s, _v) \
do \
{ \
_v = stream_read_u64_be(_s, TRUE); \
} while (0)
#define Stream_Read_INT64_BE(_s, _v) \
do \
{ \
_v = stream_read_i64_be(_s, TRUE); \
} while (0)
static inline void Stream_Read(wStream* _s, void* _b, size_t _n)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_b || (_n == 0));
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n);
memcpy(_b, (_s->pointer), (_n));
Stream_Seek(_s, _n);
}
#define Stream_Peek_UINT8(_s, _v) \
do \
{ \
_v = stream_read_u8(_s, FALSE); \
} while (0)
#define Stream_Peek_INT8(_s, _v) \
do \
{ \
_v = stream_read_i8(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT16(_s, _v) \
do \
{ \
_v = stream_read_u16_le(_s, FALSE); \
} while (0)
#define Stream_Peek_INT16(_s, _v) \
do \
{ \
_v = stream_read_i16_le(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT16_BE(_s, _v) \
do \
{ \
_v = stream_read_u16_be(_s, FALSE); \
} while (0)
#define Stream_Peek_INT16_BE(_s, _v) \
do \
{ \
_v = stream_read_i16_be(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT32(_s, _v) \
do \
{ \
_v = stream_read_u32_le(_s, FALSE); \
} while (0)
#define Stream_Peek_INT32(_s, _v) \
do \
{ \
_v = stream_read_i32_le(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT32_BE(_s, _v) \
do \
{ \
_v = stream_read_u32_be(_s, FALSE); \
} while (0)
#define Stream_Peek_INT32_BE(_s, _v) \
do \
{ \
_v = stream_read_i32_be(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT64(_s, _v) \
do \
{ \
_v = stream_read_u64_le(_s, FALSE); \
} while (0)
#define Stream_Peek_INT64(_s, _v) \
do \
{ \
_v = stream_read_i64_le(_s, FALSE); \
} while (0)
#define Stream_Peek_UINT64_BE(_s, _v) \
do \
{ \
_v = stream_read_u64_be(_s, FALSE); \
} while (0)
#define Stream_Peek_INT64_BE(_s, _v) \
do \
{ \
_v = stream_read_i64_be(_s, FALSE); \
} while (0)
static inline void Stream_Peek(const wStream* _s, void* _b, size_t _n)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_b || (_n == 0));
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n);
memcpy(_b, (_s->pointer), (_n));
}
#define Stream_Write_INT8(s, v) \
do \
{ \
WINPR_ASSERT((v) <= INT8_MAX); \
WINPR_ASSERT((v) >= INT8_MIN); \
Stream_Write_INT8_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b INT8 to a \b wStream. The stream must be large enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_INT8 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_INT8_unchecked(wStream* _s, INT8 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 1);
winpr_Data_Write_INT8(_s->pointer, _v);
_s->pointer += 1;
}
#define Stream_Write_UINT8(s, v) \
do \
{ \
WINPR_ASSERT((v) <= UINT8_MAX); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT8_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT8 to a \b wStream. The stream must be large enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT8 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT8_unchecked(wStream* _s, UINT8 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 1);
winpr_Data_Write_UINT8(_s->pointer, _v);
_s->pointer += 1;
}
#define Stream_Write_INT16(s, v) \
do \
{ \
WINPR_ASSERT((v) >= INT16_MIN); \
WINPR_ASSERT((v) <= INT16_MAX); \
Stream_Write_INT16_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b INT16 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_INT16 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_INT16_unchecked(wStream* _s, INT16 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2);
winpr_Data_Write_INT16(_s->pointer, _v);
_s->pointer += 2;
}
#define Stream_Write_UINT16(s, v) \
do \
{ \
WINPR_ASSERT((v) <= UINT16_MAX); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT16_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT16 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT16 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT16_unchecked(wStream* _s, UINT16 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2);
winpr_Data_Write_UINT16(_s->pointer, _v);
_s->pointer += 2;
}
#define Stream_Write_UINT16_BE(s, v) \
do \
{ \
WINPR_ASSERT((v) <= UINT16_MAX); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT16_BE_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT16 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT16_BE instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT16_BE_unchecked(wStream* _s, UINT16 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2);
winpr_Data_Write_UINT16_BE(_s->pointer, _v);
_s->pointer += 2;
}
#define Stream_Write_INT16_BE(s, v) \
do \
{ \
WINPR_ASSERT((v) <= INT16_MAX); \
WINPR_ASSERT((v) >= INT16_MIN); \
Stream_Write_INT16_BE_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT16 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT16_BE instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*
* @since version 3.10.0
*/
static inline void Stream_Write_INT16_BE_unchecked(wStream* _s, INT16 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2);
winpr_Data_Write_INT16_BE(_s->pointer, _v);
_s->pointer += 2;
}
#define Stream_Write_UINT24_BE(s, v) \
do \
{ \
WINPR_ASSERT((v) <= 0xFFFFFF); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT24_BE_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT24 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT24_BE instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT24_BE_unchecked(wStream* _s, UINT32 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(_v <= 0x00FFFFFF);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 3);
*_s->pointer++ = ((_v) >> 16) & 0xFF;
*_s->pointer++ = ((_v) >> 8) & 0xFF;
*_s->pointer++ = (_v) & 0xFF;
}
#define Stream_Write_INT32(s, v) \
do \
{ \
WINPR_ASSERT((v) <= INT32_MAX); \
WINPR_ASSERT((v) >= INT32_MIN); \
Stream_Write_INT32_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b INT32 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_INT32 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_INT32_unchecked(wStream* _s, INT32 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4);
winpr_Data_Write_INT32(_s->pointer, _v);
_s->pointer += 4;
}
#define Stream_Write_INT32_BE(s, v) \
do \
{ \
WINPR_ASSERT((v) <= INT32_MAX); \
WINPR_ASSERT((v) >= INT32_MIN); \
Stream_Write_INT32_BE_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b INT32 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_INT32 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*
* @since version 3.10.0
*/
static inline void Stream_Write_INT32_BE_unchecked(wStream* _s, INT32 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4);
winpr_Data_Write_INT32_BE(_s->pointer, _v);
_s->pointer += 4;
}
#define Stream_Write_UINT32(s, v) \
do \
{ \
WINPR_ASSERT((v) <= UINT32_MAX); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT32_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT32 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT32 instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT32_unchecked(wStream* _s, UINT32 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4);
winpr_Data_Write_UINT32(_s->pointer, _v);
_s->pointer += 4;
}
#define Stream_Write_UINT32_BE(s, v) \
do \
{ \
WINPR_ASSERT((v) <= UINT32_MAX); \
WINPR_ASSERT((v) >= 0); \
Stream_Write_UINT32_BE_unchecked((s), (v)); \
} while (0)
/** @brief writes a \b UINT32 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* Do not use directly, use the define @ref Stream_Write_UINT32_BE instead
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT32_BE_unchecked(wStream* _s, UINT32 _v)
{
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4);
winpr_Data_Write_UINT32_BE(_s->pointer, _v);
_s->pointer += 4;
}
/** @brief writes a \b UINT64 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT64(wStream* _s, UINT64 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 8);
winpr_Data_Write_UINT64(_s->pointer, _v);
_s->pointer += 8;
}
/** @brief writes a \b UINT64 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
*/
static inline void Stream_Write_UINT64_BE(wStream* _s, UINT64 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 8);
winpr_Data_Write_UINT64_BE(_s->pointer, _v);
_s->pointer += 8;
}
/** @brief writes a \b INT64 as \b little endian to a \b wStream. The stream must be large
* enough to hold the data.
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
* \since version 3.10.0
*/
static inline void Stream_Write_INT64(wStream* _s, INT64 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 8);
winpr_Data_Write_INT64(_s->pointer, _v);
_s->pointer += 8;
}
/** @brief writes a \b INT64 as \b big endian to a \b wStream. The stream must be large enough
* to hold the data.
*
* \param _s The stream to write to, must not be \b nullptr
* \param _v The value to write
* \since version 3.10.0
*/
static inline void Stream_Write_INT64_BE(wStream* _s, INT64 _v)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->pointer);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 8);
winpr_Data_Write_INT64_BE(_s->pointer, _v);
_s->pointer += 8;
}
static inline void Stream_Write(wStream* _s, const void* _b, size_t _n)
{
if (_n > 0)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_b);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n);
memcpy(_s->pointer, (_b), (_n));
Stream_Seek(_s, _n);
}
}
static inline void Stream_Seek_UINT8(wStream* _s)
{
Stream_Seek(_s, sizeof(UINT8));
}
static inline void Stream_Seek_UINT16(wStream* _s)
{
Stream_Seek(_s, sizeof(UINT16));
}
static inline void Stream_Seek_UINT32(wStream* _s)
{
Stream_Seek(_s, sizeof(UINT32));
}
static inline void Stream_Seek_UINT64(wStream* _s)
{
Stream_Seek(_s, sizeof(UINT64));
}
static inline void Stream_Rewind_UINT8(wStream* _s)
{
Stream_Rewind(_s, sizeof(UINT8));
}
static inline void Stream_Rewind_UINT16(wStream* _s)
{
Stream_Rewind(_s, sizeof(UINT16));
}
static inline void Stream_Rewind_UINT32(wStream* _s)
{
Stream_Rewind(_s, sizeof(UINT32));
}
static inline void Stream_Rewind_UINT64(wStream* _s)
{
Stream_Rewind(_s, sizeof(UINT64));
}
static inline void Stream_Fill(wStream* _s, int _v, size_t _n)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= (_n));
memset(_s->pointer, _v, (_n));
Stream_Seek(_s, _n);
}
static inline void Stream_Zero(wStream* _s, size_t _n)
{
Stream_Fill(_s, '\0', _n);
}
static inline void Stream_Copy(wStream* _src, wStream* _dst, size_t _n)
{
WINPR_ASSERT(_src);
WINPR_ASSERT(_dst);
WINPR_ASSERT(Stream_GetRemainingCapacity(_src) >= (_n));
WINPR_ASSERT(Stream_GetRemainingCapacity(_dst) >= (_n));
memcpy(_dst->pointer, _src->pointer, _n);
Stream_Seek(_dst, _n);
Stream_Seek(_src, _n);
}
/** @brief Convenience macro to get a pointer to the stream buffer casted to a specific type
*
* @since version 3.9.0
*/
#define Stream_BufferAs(s, type) WINPR_STREAM_CAST(type*, Stream_Buffer(s))
static inline BYTE* Stream_Buffer(wStream* _s)
{
WINPR_ASSERT(_s);
return _s->buffer;
}
/** @brief Convenience macro to get a const pointer to the stream buffer casted to a specific type
*
* @since version 3.9.0
*/
#define Stream_ConstBufferAs(s, type) WINPR_STREAM_CAST(type*, Stream_ConstBuffer(s))
static inline const BYTE* Stream_ConstBuffer(const wStream* _s)
{
WINPR_ASSERT(_s);
return _s->buffer;
}
#define Stream_GetBuffer(_s, _b) _b = Stream_Buffer(_s)
/** @brief Convenience macro to get a pointer to the stream buffer casted to a specific type
*
* @since version 3.9.0
*/
#define Stream_GetBufferAs(_s, _b) _b = Stream_BufferAs(_s, __typeof(_b))
#define Stream_PointerAs(s, type) WINPR_STREAM_CAST(type*, Stream_Pointer(s))
static inline void* Stream_Pointer(wStream* _s)
{
WINPR_ASSERT(_s);
return _s->pointer;
}
static inline const void* Stream_ConstPointer(const wStream* _s)
{
WINPR_ASSERT(_s);
return _s->pointer;
}
#define Stream_GetPointer(_s, _p) _p = Stream_Pointer(_s)
/** @brief Convenience macro to get a pointer to the stream pointer casted to a specific type
*
* @since version 3.9.0
*/
#define Stream_GetPointerAs(_s, _p) _p = Stream_PointerAs(_s, __typeof(_p))
#if defined(WITH_WINPR_DEPRECATED)
WINPR_DEPRECATED_VAR("Use Stream_SetPosition instead",
WINPR_API BOOL Stream_SetPointer(wStream* _s, BYTE* _p));
WINPR_DEPRECATED_VAR("Use Stream_New(buffer, capacity) instead",
WINPR_API BOOL Stream_SetBuffer(wStream* _s, BYTE* _b));
WINPR_DEPRECATED_VAR("Use Stream_New(buffer, capacity) instead",
WINPR_API void Stream_SetCapacity(wStream* _s, size_t capacity));
#endif
static inline size_t Stream_Length(const wStream* _s)
{
WINPR_ASSERT(_s);
return _s->length;
}
#define Stream_GetLength(_s, _l) _l = Stream_Length(_s)
WINPR_API BOOL Stream_SetLength(wStream* _s, size_t _l);
static inline size_t Stream_Capacity(const wStream* _s)
{
WINPR_ASSERT(_s);
return _s->capacity;
}
#define Stream_GetCapacity(_s, _c) _c = Stream_Capacity(_s);
static inline size_t Stream_GetPosition(const wStream* _s)
{
WINPR_ASSERT(_s);
WINPR_ASSERT(_s->buffer <= _s->pointer);
return WINPR_STREAM_CAST(size_t, (_s->pointer - _s->buffer));
}
/** @brief helper to reset stream read/write position to beginning of stream.
*
* Same as \ref Stream_SetPosition(s, 0) but does not need bounds checks.
*
* @param _s A stream to reset the position on. Must not be \b nullptr
*
* @since version 3.24.0
*/
static inline void Stream_ResetPosition(wStream* _s)
{
WINPR_ASSERT(_s);
_s->pointer = _s->buffer;
}
WINPR_API BOOL Stream_SetPosition(wStream* _s, size_t _p);
WINPR_API void Stream_SealLength(wStream* _s);
static inline void Stream_Clear(wStream* _s)
{
WINPR_ASSERT(_s);
memset(_s->buffer, 0, _s->capacity);
}
#define Stream_SafeSeek(s, size) Stream_SafeSeekEx(s, size, __FILE__, __LINE__, __func__)
WINPR_API BOOL Stream_SafeSeekEx(wStream* s, size_t size, const char* file, size_t line,
const char* fkt);
WINPR_API BOOL Stream_Read_UTF16_String(wStream* s, WCHAR* dst, size_t charLength);
WINPR_API BOOL Stream_Write_UTF16_String(wStream* s, const WCHAR* src, size_t charLength);
/** \brief Reads a WCHAR string from a stream and converts it to UTF-8 and returns a newly
* allocated string
*
* \param s The stream to read data from
* \param wcharLength The number of WCHAR characters to read (NOT the size in bytes!)
* \param pUtfCharLength Ignored if \b nullptr, otherwise will be set to the number of
* characters in the resulting UTF-8 string
* \return A '\0' terminated UTF-8 encoded string or nullptr for any failure.
*/
WINPR_API char* Stream_Read_UTF16_String_As_UTF8(wStream* s, size_t wcharLength,
size_t* pUtfCharLength);
/** \brief Reads a WCHAR string from a stream and converts it to UTF-8 and
* writes it to the supplied buffer
*
* \param s The stream to read data from
* \param wcharLength The number of WCHAR characters to read (NOT the size in bytes!)
* \param utfBuffer A pointer to a buffer holding the result string
* \param utfBufferCharLength The size of the result buffer
* \return The char length (strlen) of the result string or -1 for failure
*/
WINPR_API SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(wStream* s, size_t wcharLength,
char* utfBuffer,
size_t utfBufferCharLength);
/** \brief Writes a UTF-8 string UTF16 encoded to the stream. If the UTF-8
* string is short, the remaining characters are filled up with '\0'
*
* \param s The stream to write to
* \param wcharLength the length (in WCHAR characters) to write
* \param src The source data buffer with the UTF-8 data
* \param length The length in bytes of the UTF-8 buffer
* \param fill If \b TRUE fill the unused parts of the wcharLength with 0
*
* \b return number of used characters for success, /b -1 for failure
*/
WINPR_API SSIZE_T Stream_Write_UTF16_String_From_UTF8(wStream* s, size_t wcharLength,
const char* src, size_t length,
BOOL fill);
/* StreamPool */
WINPR_API void StreamPool_Return(wStreamPool* pool, wStream* s);
/** @brief increment reference count of stream
*
* @param s The stream to reference
* @bug versions < 3.13.0 did only handle streams returned by StreamPool_Take
*/
WINPR_API void Stream_AddRef(wStream* s);
/** @brief Release a reference to a stream.
* If the reference count reaches \b 0 it is returned to the StreamPool it was taken from or \b
* Stream_Free is called.
*
* @param s The stream to release
* @bug versions < 3.13.0 did only handle streams returned by StreamPool_Take
*/
WINPR_API void Stream_Release(wStream* s);
WINPR_ATTR_MALLOC(Stream_Release, 1)
WINPR_ATTR_NODISCARD
WINPR_API wStream* StreamPool_Take(wStreamPool* pool, size_t size);
WINPR_API wStream* StreamPool_Find(wStreamPool* pool, const BYTE* ptr);
/** Return the number of streams still not returned to the pool
*
* @param pool The pool to query, must not be \b nullptr
*
* @return the number of streams still in use
*
* @since version 3.10.0
*/
WINPR_API size_t StreamPool_UsedCount(wStreamPool* pool);
/** Wait up to \b timeoutMS milliseconds for streams to be returned to the pool.
* Use \b INFINITE for an infinite timeout
*
* @param pool The pool to query, must not be \b nullptr
* @param timeoutMS Milliseconds to wait at most, use \b INFINITE for no timeout.
*
* @return \b TRUE in case all streams were returned, \b FALSE otherwise.
*
* @since version 3.10.0
*/
WINPR_API BOOL StreamPool_WaitForReturn(wStreamPool* pool, UINT32 timeoutMS);
WINPR_API void StreamPool_Clear(wStreamPool* pool);
WINPR_API void StreamPool_Free(wStreamPool* pool);
WINPR_ATTR_MALLOC(StreamPool_Free, 1)
WINPR_ATTR_NODISCARD
WINPR_API wStreamPool* StreamPool_New(BOOL synchronized, size_t defaultSize);
WINPR_API char* StreamPool_GetStatistics(wStreamPool* pool, char* buffer, size_t size);
#ifdef __cplusplus
}
#endif
#endif /* WINPR_UTILS_STREAM_H */