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_ResizeToCapacity(
wStream* s,
size_t size)
46 const size_t old_capacity = s->capacity;
47 const size_t new_capacity = size;
48 size_t position = Stream_GetPosition(s);
50 BYTE* new_buf =
nullptr;
53 new_buf = (BYTE*)malloc(new_capacity);
57 CopyMemory(new_buf, s->buffer, s->capacity);
62 new_buf = (BYTE*)realloc(s->buffer, new_capacity);
68 s->capacity = new_capacity;
69 s->length = new_capacity;
70 if (old_capacity < new_capacity)
71 ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity);
73 if (position > new_capacity)
74 position = new_capacity;
75 return Stream_SetPosition(s, position);
78BOOL Stream_EnsureCapacity(
wStream* s,
size_t size)
81 if (s->capacity >= size)
84 const size_t increment = 128ull;
85 if (size > SIZE_MAX - increment)
88 const size_t new_capacity = size + increment - size % increment;
89 return Stream_ResizeToCapacity(s, new_capacity);
92BOOL Stream_EnsureRemainingCapacity(
wStream* s,
size_t size)
94 const size_t pos = Stream_GetPosition(s);
95 if (pos > SIZE_MAX - size)
97 if (pos + size > Stream_Capacity(s))
98 return Stream_EnsureCapacity(s, Stream_Capacity(s) + size);
102wStream* Stream_New(BYTE* buffer,
size_t size)
106 if (!buffer && !size)
109 s = calloc(1,
sizeof(
wStream));
116 s->buffer = (BYTE*)calloc(size,
sizeof(BYTE));
124 s->pointer = s->buffer;
130 s->isAllocatedStream = TRUE;
135wStream* Stream_StaticConstInit(
wStream* s,
const BYTE* buffer,
size_t size)
144 return Stream_StaticInit(s, cnv.b, size);
149 const wStream empty = WINPR_C_ARRAY_INIT;
152 WINPR_ASSERT(buffer);
155 s->buffer = s->pointer = buffer;
156 s->capacity = s->length = size;
159 s->isAllocatedStream = FALSE;
164void Stream_EnsureValidity(
wStream* s)
169 STREAM_ASSERT(s->pointer >= s->buffer);
171 cur = (size_t)(s->pointer - s->buffer);
172 STREAM_ASSERT(cur <= s->capacity);
173 STREAM_ASSERT(s->length <= s->capacity);
176void Stream_Free(
wStream* s, BOOL bFreeBuffer)
180 Stream_EnsureValidity(s);
181 if (bFreeBuffer && s->isOwner)
184 if (s->isAllocatedStream)
189BOOL Stream_SetLength(
wStream* _s,
size_t _l)
191 if ((_l) > Stream_Capacity(_s))
200BOOL Stream_SetPosition(
wStream* _s,
size_t _p)
202 if ((_p) > Stream_Capacity(_s))
204 _s->pointer = _s->buffer;
207 _s->pointer = _s->buffer + (_p);
211void Stream_SealLength(
wStream* _s)
215 WINPR_ASSERT(_s->buffer <= _s->pointer);
216 cur = (size_t)(_s->pointer - _s->buffer);
217 WINPR_ASSERT(cur <= _s->capacity);
218 if (cur <= _s->capacity)
222 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
223 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
228#if defined(WITH_WINPR_DEPRECATED)
229BOOL Stream_SetPointer(
wStream* _s, BYTE* _p)
232 if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p))
234 _s->pointer = _s->buffer;
241BOOL Stream_SetBuffer(
wStream* _s, BYTE* _b)
248 return _s->buffer !=
nullptr;
251void Stream_SetCapacity(
wStream* _s,
size_t _c)
259size_t Stream_GetRemainingCapacity(
const wStream* _s)
263 WINPR_ASSERT(_s->buffer <= _s->pointer);
264 cur = (size_t)(_s->pointer - _s->buffer);
265 WINPR_ASSERT(cur <= _s->capacity);
266 if (cur > _s->capacity)
268 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
269 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
272 return (_s->capacity - cur);
275size_t Stream_GetRemainingLength(
const wStream* _s)
279 WINPR_ASSERT(_s->buffer <= _s->pointer);
280 WINPR_ASSERT(_s->length <= _s->capacity);
281 cur = (size_t)(_s->pointer - _s->buffer);
282 WINPR_ASSERT(cur <= _s->length);
283 if (cur > _s->length)
285 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was read out of bounds");
286 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
289 return (_s->length - cur);
292BOOL Stream_Write_UTF16_String(
wStream* s,
const WCHAR* src,
size_t length)
295 WINPR_ASSERT(src || (length == 0));
299 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, (s), length,
sizeof(WCHAR)))
302 for (
size_t x = 0; x < length; x++)
303 Stream_Write_UINT16(s, src[x]);
308BOOL Stream_Read_UTF16_String(
wStream* s, WCHAR* dst,
size_t length)
313 if (!Stream_CheckAndLogRequiredLengthOfSize(STREAM_TAG, s, length,
sizeof(WCHAR)))
316 for (
size_t x = 0; x < length; x++)
317 Stream_Read_UINT16(s, dst[x]);
322BOOL Stream_CheckAndLogRequiredCapacityEx(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
323 size_t size,
const char* fmt, ...)
325 WINPR_ASSERT(size != 0);
326 const size_t actual = Stream_GetRemainingCapacity(s) / size;
330 va_list args = WINPR_C_ARRAY_INIT;
334 Stream_CheckAndLogRequiredCapacityExVa(tag, level, s, nmemb, size, fmt, args);
341BOOL Stream_CheckAndLogRequiredCapacityExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
342 size_t size,
const char* fmt, va_list args)
344 WINPR_ASSERT(size != 0);
345 const size_t actual = Stream_GetRemainingCapacity(s) / size;
348 return Stream_CheckAndLogRequiredCapacityWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
353WINPR_ATTR_FORMAT_ARG(6, 0)
354BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
355 size_t size, WINPR_FORMAT_ARG const
char* fmt,
359 WINPR_ASSERT(size != 0);
360 const size_t actual = Stream_GetRemainingCapacity(s) / size;
364 char prefix[1024] = WINPR_C_ARRAY_INIT;
366 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
368 WLog_Print(log, level,
369 "[%s] invalid remaining capacity, got %" PRIuz
", require at least %" PRIuz
370 " [element size=%" PRIuz
"]",
371 prefix, actual, nmemb, size);
372 winpr_log_backtrace_ex(log, level, 20);
378WINPR_ATTR_FORMAT_ARG(6, 7)
379BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
380 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
383 WINPR_ASSERT(size != 0);
384 const size_t actual = Stream_GetRemainingCapacity(s) / size;
388 va_list args = WINPR_C_ARRAY_INIT;
392 Stream_CheckAndLogRequiredCapacityWLogExVa(log, level, s, nmemb, size, fmt, args);
399WINPR_ATTR_FORMAT_ARG(6, 7)
400BOOL Stream_CheckAndLogRequiredLengthEx(const
char* tag, DWORD level,
wStream* s,
size_t nmemb,
401 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
403 WINPR_ASSERT(size > 0);
404 const size_t actual = Stream_GetRemainingLength(s) / size;
408 va_list args = WINPR_C_ARRAY_INIT;
411 const BOOL rc = Stream_CheckAndLogRequiredLengthExVa(tag, level, s, nmemb, size, fmt, args);
418BOOL Stream_CheckAndLogRequiredLengthExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
419 size_t size,
const char* fmt, va_list args)
421 WINPR_ASSERT(size > 0);
422 const size_t actual = Stream_GetRemainingLength(s) / size;
425 return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
430BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
431 size_t size,
const char* fmt, ...)
433 WINPR_ASSERT(size > 0);
434 const size_t actual = Stream_GetRemainingLength(s) / size;
438 va_list args = WINPR_C_ARRAY_INIT;
442 Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, nmemb, size, fmt, args);
449WINPR_ATTR_FORMAT_ARG(6, 0)
450BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
451 size_t size, WINPR_FORMAT_ARG const
char* fmt,
454 WINPR_ASSERT(size > 0);
455 const size_t actual = Stream_GetRemainingLength(s) / size;
459 if (WLog_IsLevelActive(log, level))
461 char prefix[1024] = WINPR_C_ARRAY_INIT;
463 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
465 WLog_Print(log, level,
466 "[%s] invalid length, got %" PRIuz
", require at least %" PRIuz
467 " [element size=%" PRIuz
"]",
468 prefix, actual, nmemb, size);
469 winpr_log_backtrace_ex(log, level, 20);
476SSIZE_T Stream_Write_UTF16_String_From_UTF8(
wStream* s,
size_t wcharLength,
const char* src,
477 size_t length, BOOL fill)
480 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, s, wcharLength,
sizeof(WCHAR)))
486 WCHAR* str = ConvertUtf8NToWCharAlloc(src, length, &wlen);
490 if (wlen > wcharLength)
492 Stream_Write(s, str, wlen *
sizeof(WCHAR));
494 rc = WINPR_ASSERTING_INT_CAST(SSIZE_T, wlen);
498 Stream_Zero(s, (wcharLength - WINPR_ASSERTING_INT_CAST(
size_t, rc)) *
sizeof(WCHAR));
502char* Stream_Read_UTF16_String_As_UTF8(
wStream* s,
size_t wcharLength,
size_t* pUtfCharLength)
504 const WCHAR* str = Stream_ConstPointer(s);
505 if (wcharLength > SIZE_MAX /
sizeof(WCHAR))
508 if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength *
sizeof(WCHAR)))
511 Stream_Seek(s, wcharLength *
sizeof(WCHAR));
512 return ConvertWCharNToUtf8Alloc(str, wcharLength, pUtfCharLength);
515SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(
wStream* s,
size_t wcharLength,
char* utfBuffer,
516 size_t utfBufferCharLength)
518 const WCHAR* ptr = Stream_ConstPointer(s);
519 if (wcharLength > SIZE_MAX /
sizeof(WCHAR))
522 if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength *
sizeof(WCHAR)))
525 Stream_Seek(s, wcharLength *
sizeof(WCHAR));
526 return ConvertWCharNToUtf8(ptr, wcharLength, utfBuffer, utfBufferCharLength);
529BOOL Stream_SafeSeekEx(
wStream* s,
size_t size,
const char* file,
size_t line,
const char* fkt)
531 if (!Stream_CheckAndLogRequiredLengthEx(STREAM_TAG, WLOG_WARN, s, size, 1,
"%s(%s:%" PRIuz
")",
535 Stream_Seek(s, size);
539BOOL Stream_SafeZeroEx(
wStream* s,
size_t size,
const char* file,
size_t line,
const char* fkt)
541 if (!Stream_CheckAndLogRequiredCapacityEx(STREAM_TAG, WLOG_WARN, s, size, 1,
542 "%s(%s:%" PRIuz
")", fkt, file, line))
545 Stream_Zero(s, size);