21 #include <winpr/config.h>
23 #include <winpr/assert.h>
24 #include <winpr/crt.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); \
44 BOOL Stream_EnsureCapacity(
wStream* s,
size_t size)
47 if (s->capacity < size)
50 size_t old_capacity = 0;
51 size_t new_capacity = 0;
54 old_capacity = s->capacity;
55 new_capacity = old_capacity;
60 }
while (new_capacity < size);
62 position = Stream_GetPosition(s);
66 new_buf = (BYTE*)malloc(new_capacity);
67 CopyMemory(new_buf, s->buffer, s->capacity);
72 new_buf = (BYTE*)realloc(s->buffer, new_capacity);
78 s->capacity = new_capacity;
79 s->length = new_capacity;
80 ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity);
82 Stream_SetPosition(s, position);
87 BOOL Stream_EnsureRemainingCapacity(
wStream* s,
size_t size)
89 if (Stream_GetPosition(s) + size > Stream_Capacity(s))
90 return Stream_EnsureCapacity(s, Stream_Capacity(s) + size);
94 wStream* Stream_New(BYTE* buffer,
size_t size)
108 s->buffer = (BYTE*)malloc(size);
116 s->pointer = s->buffer;
122 s->isAllocatedStream = TRUE;
127 wStream* Stream_StaticConstInit(
wStream* s,
const BYTE* buffer,
size_t size)
136 return Stream_StaticInit(s, cnv.b, size);
144 WINPR_ASSERT(buffer);
147 s->buffer = s->pointer = buffer;
148 s->capacity = s->length = size;
151 s->isAllocatedStream = FALSE;
156 void Stream_EnsureValidity(
wStream* s)
161 STREAM_ASSERT(s->pointer >= s->buffer);
163 cur = (size_t)(s->pointer - s->buffer);
164 STREAM_ASSERT(cur <= s->capacity);
165 STREAM_ASSERT(s->length <= s->capacity);
168 void Stream_Free(
wStream* s, BOOL bFreeBuffer)
172 Stream_EnsureValidity(s);
173 if (bFreeBuffer && s->isOwner)
176 if (s->isAllocatedStream)
181 BOOL Stream_SetLength(
wStream* _s,
size_t _l)
183 if ((_l) > Stream_Capacity(_s))
192 BOOL Stream_SetPosition(
wStream* _s,
size_t _p)
194 if ((_p) > Stream_Capacity(_s))
196 _s->pointer = _s->buffer;
199 _s->pointer = _s->buffer + (_p);
203 void Stream_SealLength(
wStream* _s)
207 WINPR_ASSERT(_s->buffer <= _s->pointer);
208 cur = (size_t)(_s->pointer - _s->buffer);
209 WINPR_ASSERT(cur <= _s->capacity);
210 if (cur <= _s->capacity)
214 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
215 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
220 #if defined(WITH_WINPR_DEPRECATED)
221 BOOL Stream_SetPointer(
wStream* _s, BYTE* _p)
224 if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p))
226 _s->pointer = _s->buffer;
233 BOOL Stream_SetBuffer(
wStream* _s, BYTE* _b)
240 return _s->buffer != NULL;
243 void Stream_SetCapacity(
wStream* _s,
size_t _c)
251 size_t Stream_GetRemainingCapacity(
const wStream* _s)
255 WINPR_ASSERT(_s->buffer <= _s->pointer);
256 cur = (size_t)(_s->pointer - _s->buffer);
257 WINPR_ASSERT(cur <= _s->capacity);
258 if (cur > _s->capacity)
260 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was written out of bounds");
261 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
264 return (_s->capacity - cur);
267 size_t Stream_GetRemainingLength(
const wStream* _s)
271 WINPR_ASSERT(_s->buffer <= _s->pointer);
272 WINPR_ASSERT(_s->length <= _s->capacity);
273 cur = (size_t)(_s->pointer - _s->buffer);
274 WINPR_ASSERT(cur <= _s->length);
275 if (cur > _s->length)
277 WLog_FATAL(STREAM_TAG,
"wStream API misuse: stream was read out of bounds");
278 winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20);
281 return (_s->length - cur);
284 BOOL Stream_Write_UTF16_String(
wStream* s,
const WCHAR* src,
size_t length)
287 WINPR_ASSERT(src || (length == 0));
291 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, (s), length,
sizeof(WCHAR)))
294 for (
size_t x = 0; x < length; x++)
295 Stream_Write_UINT16(s, src[x]);
300 BOOL Stream_Read_UTF16_String(
wStream* s, WCHAR* dst,
size_t length)
305 if (!Stream_CheckAndLogRequiredLengthOfSize(STREAM_TAG, s, length,
sizeof(WCHAR)))
308 for (
size_t x = 0; x < length; x++)
309 Stream_Read_UINT16(s, dst[x]);
314 BOOL Stream_CheckAndLogRequiredCapacityEx(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
315 size_t size,
const char* fmt, ...)
317 WINPR_ASSERT(size != 0);
318 const size_t actual = Stream_GetRemainingCapacity(s) / size;
325 Stream_CheckAndLogRequiredCapacityExVa(tag, level, s, nmemb, size, fmt, args);
333 BOOL Stream_CheckAndLogRequiredCapacityExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
334 size_t size,
const char* fmt, va_list args)
336 WINPR_ASSERT(size != 0);
337 const size_t actual = Stream_GetRemainingCapacity(s) / size;
340 return Stream_CheckAndLogRequiredCapacityWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
345 WINPR_ATTR_FORMAT_ARG(6, 0)
346 BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
347 size_t size, WINPR_FORMAT_ARG const
char* fmt,
351 WINPR_ASSERT(size != 0);
352 const size_t actual = Stream_GetRemainingCapacity(s) / size;
356 char prefix[1024] = { 0 };
358 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
360 WLog_Print(log, level,
361 "[%s] invalid remaining capacity, got %" PRIuz
", require at least %" PRIu64
362 " [element size=%" PRIuz
"]",
363 prefix, actual, nmemb, size);
364 winpr_log_backtrace_ex(log, level, 20);
370 WINPR_ATTR_FORMAT_ARG(6, 7)
371 BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
372 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
375 WINPR_ASSERT(size != 0);
376 const size_t actual = Stream_GetRemainingCapacity(s) / size;
383 Stream_CheckAndLogRequiredCapacityWLogExVa(log, level, s, nmemb, size, fmt, args);
391 WINPR_ATTR_FORMAT_ARG(6, 7)
392 BOOL Stream_CheckAndLogRequiredLengthEx(const
char* tag, DWORD level,
wStream* s,
size_t nmemb,
393 size_t size, WINPR_FORMAT_ARG const
char* fmt, ...)
395 WINPR_ASSERT(size > 0);
396 const size_t actual = Stream_GetRemainingLength(s) / size;
403 Stream_CheckAndLogRequiredLengthExVa(tag, level, s, nmemb, size, fmt, args);
411 BOOL Stream_CheckAndLogRequiredLengthExVa(
const char* tag, DWORD level,
wStream* s,
size_t nmemb,
412 size_t size,
const char* fmt, va_list args)
414 WINPR_ASSERT(size > 0);
415 const size_t actual = Stream_GetRemainingLength(s) / size;
418 return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt,
423 BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
424 size_t size,
const char* fmt, ...)
426 WINPR_ASSERT(size > 0);
427 const size_t actual = Stream_GetRemainingLength(s) / size;
434 Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, nmemb, size, fmt, args);
442 WINPR_ATTR_FORMAT_ARG(6, 0)
443 BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level,
wStream* s,
size_t nmemb,
444 size_t size, WINPR_FORMAT_ARG const
char* fmt,
447 WINPR_ASSERT(size > 0);
448 const size_t actual = Stream_GetRemainingLength(s) / size;
452 char prefix[1024] = { 0 };
454 (void)vsnprintf(prefix,
sizeof(prefix), fmt, args);
456 WLog_Print(log, level,
457 "[%s] invalid length, got %" PRIuz
", require at least %" PRIuz
458 " [element size=%" PRIuz
"]",
459 prefix, actual, nmemb, size);
460 winpr_log_backtrace_ex(log, level, 20);
466 SSIZE_T Stream_Write_UTF16_String_From_UTF8(
wStream* s,
size_t dlen,
const char* src,
size_t length,
469 WCHAR* str = Stream_PointerAs(s, WCHAR);
474 if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, s, dlen,
sizeof(WCHAR)))
477 SSIZE_T rc = ConvertUtf8NToWChar(src, length, str, dlen);
481 Stream_Seek(s, (
size_t)rc *
sizeof(WCHAR));
484 Stream_Zero(s, (dlen - (
size_t)rc) *
sizeof(WCHAR));
488 char* Stream_Read_UTF16_String_As_UTF8(
wStream* s,
size_t dlen,
size_t* psize)
490 const WCHAR* str = Stream_ConstPointer(s);
491 if (dlen > SIZE_MAX /
sizeof(WCHAR))
494 if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, dlen *
sizeof(WCHAR)))
497 Stream_Seek(s, dlen *
sizeof(WCHAR));
498 return ConvertWCharNToUtf8Alloc(str, dlen, psize);
501 SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(
wStream* s,
size_t wcharLength,
char* utfBuffer,
502 size_t utfBufferCharLength)
504 const WCHAR* ptr = 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 ConvertWCharNToUtf8(ptr, wcharLength, utfBuffer, utfBufferCharLength);
515 BOOL Stream_SafeSeekEx(
wStream* s,
size_t size,
const char* file,
size_t line,
const char* fkt)
517 if (!Stream_CheckAndLogRequiredLengthEx(STREAM_TAG, WLOG_WARN, s, size, 1,
"%s(%s:%" PRIuz
")",
521 Stream_Seek(s, size);