21#include <winpr/config.h>
23#include <winpr/assert.h>
25#include <winpr/stream.h>
30#define STREAM_TAG WINPR_TAG("wStream")
32#define STREAM_ASSERT(cond) \
37 WLog_FATAL(STREAM_TAG, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __func__, \
39 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); \
44BOOL Stream_EnsureCapacity(
wStream* s,
size_t size)
47 if (s->capacity >= size)
50 const size_t increment = 128ull;
51 if (size > SIZE_MAX - increment)
54 const size_t old_capacity = s->capacity;
55 const size_t new_capacity = size + increment - size % increment;
56 const size_t position = Stream_GetPosition(s);
58 BYTE* new_buf =
nullptr;
61 new_buf = (BYTE*)malloc(new_capacity);
65 CopyMemory(new_buf, s->buffer, s->capacity);
70 new_buf = (BYTE*)realloc(s->buffer, new_capacity);
76 s->capacity = new_capacity;
77 s->length = new_capacity;
78 ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity);
80 return Stream_SetPosition(s, position);
83BOOL Stream_EnsureRemainingCapacity(
wStream* s,
size_t size)
85 const size_t pos = Stream_GetPosition(s);
86 if (pos > SIZE_MAX - size)
88 if (pos + size > Stream_Capacity(s))
89 return Stream_EnsureCapacity(s, Stream_Capacity(s) + size);
93wStream* Stream_New(BYTE* buffer,
size_t size)
100 s = calloc(1,
sizeof(
wStream));
107 s->buffer = (BYTE*)calloc(size,
sizeof(BYTE));
115 s->pointer = s->buffer;
121 s->isAllocatedStream = TRUE;
126wStream* Stream_StaticConstInit(
wStream* s,
const BYTE* buffer,
size_t size)
135 return Stream_StaticInit(s, cnv.b, size);
140 const wStream empty = WINPR_C_ARRAY_INIT;
143 WINPR_ASSERT(buffer);
146 s->buffer = s->pointer = buffer;
147 s->capacity = s->length = size;
150 s->isAllocatedStream = FALSE;
155void Stream_EnsureValidity(
wStream* s)
160 STREAM_ASSERT(s->pointer >= s->buffer);
162 cur = (size_t)(s->pointer - s->buffer);
163 STREAM_ASSERT(cur <= s->capacity);
164 STREAM_ASSERT(s->length <= s->capacity);
167void Stream_Free(
wStream* s, BOOL bFreeBuffer)
171 Stream_EnsureValidity(s);
172 if (bFreeBuffer && s->isOwner)
175 if (s->isAllocatedStream)
180BOOL Stream_SetLength(
wStream* _s,
size_t _l)
182 if ((_l) > Stream_Capacity(_s))
191BOOL Stream_SetPosition(
wStream* _s,
size_t _p)
193 if ((_p) > Stream_Capacity(_s))
195 _s->pointer = _s->buffer;
198 _s->pointer = _s->buffer + (_p);
202void Stream_SealLength(
wStream* _s)
206 WINPR_ASSERT(_s->buffer <= _s->pointer);
207 cur = (size_t)(_s->pointer - _s->buffer);
208 WINPR_ASSERT(cur <= _s->capacity);
209 if (cur <= _s->capacity)
213 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
214 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
219#if defined(WITH_WINPR_DEPRECATED)
220BOOL Stream_SetPointer(
wStream* _s, BYTE* _p)
223 if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p))
225 _s->pointer = _s->buffer;
232BOOL Stream_SetBuffer(
wStream* _s, BYTE* _b)
239 return _s->buffer !=
nullptr;
242void Stream_SetCapacity(
wStream* _s,
size_t _c)
250size_t Stream_GetRemainingCapacity(
const wStream* _s)
254 WINPR_ASSERT(_s->buffer <= _s->pointer);
255 cur = (size_t)(_s->pointer - _s->buffer);
256 WINPR_ASSERT(cur <= _s->capacity);
257 if (cur > _s->capacity)
259 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
260 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
263 return (_s->capacity - cur);
266size_t Stream_GetRemainingLength(
const wStream* _s)
270 WINPR_ASSERT(_s->buffer <= _s->pointer);
271 WINPR_ASSERT(_s->length <= _s->capacity);
272 cur = (size_t)(_s->pointer - _s->buffer);
273 WINPR_ASSERT(cur <= _s->length);
274 if (cur > _s->length)
276 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was read out of bounds");
277 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
280 return (_s->length - cur);
283BOOL Stream_Write_UTF16_String(
wStream* s,
const WCHAR* src,
size_t length)
286 WINPR_ASSERT(src || (length == 0));
290 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, (s), length,
sizeof(WCHAR)))
293 for (
size_t x = 0; x < length; x++)
294 Stream_Write_UINT16(s, src[x]);
299BOOL Stream_Read_UTF16_String(
wStream* s, WCHAR* dst,
size_t length)
304 if (!Stream_CheckAndLogRequiredLengthOfSize(STREAM_TAG, s, length,
sizeof(WCHAR)))
307 for (
size_t x = 0; x < length; x++)
308 Stream_Read_UINT16(s, dst[x]);
313BOOL Stream_CheckAndLogRequiredCapacityEx(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
314 size_t size,
const char* fmt, ...)
316 WINPR_ASSERT(size != 0);
317 const size_t actual = Stream_GetRemainingCapacity(s) / size;
321 va_list args = WINPR_C_ARRAY_INIT;
325 Stream_CheckAndLogRequiredCapacityExVa(tag, level, s, nmemb, size, fmt, args);
332BOOL Stream_CheckAndLogRequiredCapacityExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
333 size_t size,
const char* fmt, va_list args)
335 WINPR_ASSERT(size != 0);
336 const size_t actual = Stream_GetRemainingCapacity(s) / size;
339 return Stream_CheckAndLogRequiredCapacityWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
344WINPR_ATTR_FORMAT_ARG(6, 0)
345BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
346 size_t size, WINPR_FORMAT_ARG const
char* fmt,
350 WINPR_ASSERT(size != 0);
351 const size_t actual = Stream_GetRemainingCapacity(s) / size;
355 char prefix[1024] = WINPR_C_ARRAY_INIT;
357 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
359 WLog_Print(log, level,
360 "[%s] invalid remaining capacity, got %" PRIuz
", require at least %" PRIuz
361 " [element size=%" PRIuz
"]",
362 prefix, actual, nmemb, size);
363 winpr_log_backtrace_ex(log, level, 20);
369WINPR_ATTR_FORMAT_ARG(6, 7)
370BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
371 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
374 WINPR_ASSERT(size != 0);
375 const size_t actual = Stream_GetRemainingCapacity(s) / size;
379 va_list args = WINPR_C_ARRAY_INIT;
383 Stream_CheckAndLogRequiredCapacityWLogExVa(log, level, s, nmemb, size, fmt, args);
390WINPR_ATTR_FORMAT_ARG(6, 7)
391BOOL Stream_CheckAndLogRequiredLengthEx(const
char* tag, DWORD level,
wStream* s,
size_t nmemb,
392 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
394 WINPR_ASSERT(size > 0);
395 const size_t actual = Stream_GetRemainingLength(s) / size;
399 va_list args = WINPR_C_ARRAY_INIT;
402 const BOOL rc = Stream_CheckAndLogRequiredLengthExVa(tag, level, s, nmemb, size, fmt, args);
409BOOL Stream_CheckAndLogRequiredLengthExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
410 size_t size,
const char* fmt, va_list args)
412 WINPR_ASSERT(size > 0);
413 const size_t actual = Stream_GetRemainingLength(s) / size;
416 return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
421BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
422 size_t size,
const char* fmt, ...)
424 WINPR_ASSERT(size > 0);
425 const size_t actual = Stream_GetRemainingLength(s) / size;
429 va_list args = WINPR_C_ARRAY_INIT;
433 Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, nmemb, size, fmt, args);
440WINPR_ATTR_FORMAT_ARG(6, 0)
441BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
442 size_t size, WINPR_FORMAT_ARG const
char* fmt,
445 WINPR_ASSERT(size > 0);
446 const size_t actual = Stream_GetRemainingLength(s) / size;
450 char prefix[1024] = WINPR_C_ARRAY_INIT;
452 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
454 WLog_Print(log, level,
455 "[%s] invalid length, got %" PRIuz
", require at least %" PRIuz
456 " [element size=%" PRIuz
"]",
457 prefix, actual, nmemb, size);
458 winpr_log_backtrace_ex(log, level, 20);
464SSIZE_T Stream_Write_UTF16_String_From_UTF8(
wStream* s,
size_t wcharLength,
const char* src,
465 size_t length, BOOL fill)
468 WCHAR* str = Stream_PointerAs(s, WCHAR);
472 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, s, wcharLength,
sizeof(WCHAR)))
475 rc = ConvertUtf8NToWChar(src, length, str, wcharLength);
479 Stream_Seek(s, (
size_t)rc *
sizeof(WCHAR));
483 Stream_Zero(s, (wcharLength - (
size_t)rc) *
sizeof(WCHAR));
487char* Stream_Read_UTF16_String_As_UTF8(
wStream* s,
size_t wcharLength,
size_t* pUtfCharLength)
489 const WCHAR* str = Stream_ConstPointer(s);
490 if (wcharLength > SIZE_MAX /
sizeof(WCHAR))
493 if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength *
sizeof(WCHAR)))
496 Stream_Seek(s, wcharLength *
sizeof(WCHAR));
497 return ConvertWCharNToUtf8Alloc(str, wcharLength, pUtfCharLength);
500SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(
wStream* s,
size_t wcharLength,
char* utfBuffer,
501 size_t utfBufferCharLength)
503 const WCHAR* ptr = Stream_ConstPointer(s);
504 if (wcharLength > SIZE_MAX /
sizeof(WCHAR))
507 if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength *
sizeof(WCHAR)))
510 Stream_Seek(s, wcharLength *
sizeof(WCHAR));
511 return ConvertWCharNToUtf8(ptr, wcharLength, utfBuffer, utfBufferCharLength);
514BOOL Stream_SafeSeekEx(
wStream* s,
size_t size,
const char* file,
size_t line,
const char* fkt)
516 if (!Stream_CheckAndLogRequiredLengthEx(STREAM_TAG, WLOG_WARN, s, size, 1,
"%s(%s:%" PRIuz
")",
520 Stream_Seek(s, size);