/src/FreeRDP/winpr/libwinpr/utils/stream.c
Line | Count | Source |
1 | | /* |
2 | | * WinPR: Windows Portable Runtime |
3 | | * Stream Utils |
4 | | * |
5 | | * Copyright 2011 Vic Lee |
6 | | * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> |
7 | | * |
8 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | | * you may not use this file except in compliance with the License. |
10 | | * You may obtain a copy of the License at |
11 | | * |
12 | | * http://www.apache.org/licenses/LICENSE-2.0 |
13 | | * |
14 | | * Unless required by applicable law or agreed to in writing, software |
15 | | * distributed under the License is distributed on an "AS IS" BASIS, |
16 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
17 | | * See the License for the specific language governing permissions and |
18 | | * limitations under the License. |
19 | | */ |
20 | | |
21 | | #include <winpr/config.h> |
22 | | |
23 | | #include <winpr/assert.h> |
24 | | #include <winpr/crt.h> |
25 | | #include <winpr/stream.h> |
26 | | |
27 | | #include "stream.h" |
28 | | #include "../log.h" |
29 | | |
30 | 184k | #define STREAM_TAG WINPR_TAG("wStream") |
31 | | |
32 | | #define STREAM_ASSERT(cond) \ |
33 | 343k | do \ |
34 | 343k | { \ |
35 | 343k | if (!(cond)) \ |
36 | 343k | { \ |
37 | 0 | WLog_FATAL(STREAM_TAG, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __func__, \ |
38 | 0 | (size_t)__LINE__); \ |
39 | 0 | winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); \ |
40 | 0 | abort(); \ |
41 | 0 | } \ |
42 | 343k | } while (0) |
43 | | |
44 | | BOOL Stream_EnsureCapacity(wStream* s, size_t size) |
45 | 2.38k | { |
46 | 2.38k | WINPR_ASSERT(s); |
47 | 2.38k | if (s->capacity >= size) |
48 | 0 | return TRUE; |
49 | | |
50 | 2.38k | const size_t increment = 128ull; |
51 | 2.38k | const size_t old_capacity = s->capacity; |
52 | 2.38k | const size_t new_capacity = size + increment - size % increment; |
53 | 2.38k | const size_t position = Stream_GetPosition(s); |
54 | | |
55 | 2.38k | BYTE* new_buf = NULL; |
56 | 2.38k | if (!s->isOwner) |
57 | 0 | { |
58 | 0 | new_buf = (BYTE*)malloc(new_capacity); |
59 | 0 | if (!new_buf) |
60 | 0 | return FALSE; |
61 | | |
62 | 0 | CopyMemory(new_buf, s->buffer, s->capacity); |
63 | 0 | s->isOwner = TRUE; |
64 | 0 | } |
65 | 2.38k | else |
66 | 2.38k | { |
67 | 2.38k | new_buf = (BYTE*)realloc(s->buffer, new_capacity); |
68 | 2.38k | if (!new_buf) |
69 | 0 | return FALSE; |
70 | 2.38k | } |
71 | | |
72 | 2.38k | s->buffer = new_buf; |
73 | 2.38k | s->capacity = new_capacity; |
74 | 2.38k | s->length = new_capacity; |
75 | 2.38k | ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity); |
76 | | |
77 | 2.38k | return Stream_SetPosition(s, position); |
78 | 2.38k | } |
79 | | |
80 | | BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size) |
81 | 67.6k | { |
82 | 67.6k | if (Stream_GetPosition(s) + size > Stream_Capacity(s)) |
83 | 2.38k | return Stream_EnsureCapacity(s, Stream_Capacity(s) + size); |
84 | 65.2k | return TRUE; |
85 | 67.6k | } |
86 | | |
87 | | wStream* Stream_New(BYTE* buffer, size_t size) |
88 | 71.3k | { |
89 | 71.3k | wStream* s = NULL; |
90 | | |
91 | 71.3k | if (!buffer && !size) |
92 | 0 | return NULL; |
93 | | |
94 | 71.3k | s = calloc(1, sizeof(wStream)); |
95 | 71.3k | if (!s) |
96 | 0 | return NULL; |
97 | | |
98 | 71.3k | if (buffer) |
99 | 0 | s->buffer = buffer; |
100 | 71.3k | else |
101 | 71.3k | s->buffer = (BYTE*)malloc(size); |
102 | | |
103 | 71.3k | if (!s->buffer) |
104 | 0 | { |
105 | 0 | free(s); |
106 | 0 | return NULL; |
107 | 0 | } |
108 | | |
109 | 71.3k | s->pointer = s->buffer; |
110 | 71.3k | s->capacity = size; |
111 | 71.3k | s->length = size; |
112 | | |
113 | 71.3k | s->pool = NULL; |
114 | 71.3k | s->count = 1; |
115 | 71.3k | s->isAllocatedStream = TRUE; |
116 | 71.3k | s->isOwner = TRUE; |
117 | 71.3k | return s; |
118 | 71.3k | } |
119 | | |
120 | | wStream* Stream_StaticConstInit(wStream* s, const BYTE* buffer, size_t size) |
121 | 113k | { |
122 | 113k | union |
123 | 113k | { |
124 | 113k | BYTE* b; |
125 | 113k | const BYTE* cb; |
126 | 113k | } cnv; |
127 | | |
128 | 113k | cnv.cb = buffer; |
129 | 113k | return Stream_StaticInit(s, cnv.b, size); |
130 | 113k | } |
131 | | |
132 | | wStream* Stream_StaticInit(wStream* s, BYTE* buffer, size_t size) |
133 | 212k | { |
134 | 212k | const wStream empty = WINPR_C_ARRAY_INIT; |
135 | | |
136 | 212k | WINPR_ASSERT(s); |
137 | 212k | WINPR_ASSERT(buffer); |
138 | | |
139 | 212k | *s = empty; |
140 | 212k | s->buffer = s->pointer = buffer; |
141 | 212k | s->capacity = s->length = size; |
142 | 212k | s->pool = NULL; |
143 | 212k | s->count = 1; |
144 | 212k | s->isAllocatedStream = FALSE; |
145 | 212k | s->isOwner = FALSE; |
146 | 212k | return s; |
147 | 212k | } |
148 | | |
149 | | void Stream_EnsureValidity(wStream* s) |
150 | 85.7k | { |
151 | 85.7k | size_t cur = 0; |
152 | | |
153 | 85.7k | STREAM_ASSERT(s); |
154 | 85.7k | STREAM_ASSERT(s->pointer >= s->buffer); |
155 | | |
156 | 85.7k | cur = (size_t)(s->pointer - s->buffer); |
157 | 85.7k | STREAM_ASSERT(cur <= s->capacity); |
158 | 85.7k | STREAM_ASSERT(s->length <= s->capacity); |
159 | 85.7k | } |
160 | | |
161 | | void Stream_Free(wStream* s, BOOL bFreeBuffer) |
162 | 71.3k | { |
163 | 71.3k | if (s) |
164 | 71.3k | { |
165 | 71.3k | Stream_EnsureValidity(s); |
166 | 71.3k | if (bFreeBuffer && s->isOwner) |
167 | 71.3k | free(s->buffer); |
168 | | |
169 | 71.3k | if (s->isAllocatedStream) |
170 | 71.3k | free(s); |
171 | 71.3k | } |
172 | 71.3k | } |
173 | | |
174 | | BOOL Stream_SetLength(wStream* _s, size_t _l) |
175 | 0 | { |
176 | 0 | if ((_l) > Stream_Capacity(_s)) |
177 | 0 | { |
178 | 0 | _s->length = 0; |
179 | 0 | return FALSE; |
180 | 0 | } |
181 | 0 | _s->length = _l; |
182 | 0 | return TRUE; |
183 | 0 | } |
184 | | |
185 | | BOOL Stream_SetPosition(wStream* _s, size_t _p) |
186 | 54.5k | { |
187 | 54.5k | if ((_p) > Stream_Capacity(_s)) |
188 | 0 | { |
189 | 0 | _s->pointer = _s->buffer; |
190 | 0 | return FALSE; |
191 | 0 | } |
192 | 54.5k | _s->pointer = _s->buffer + (_p); |
193 | 54.5k | return TRUE; |
194 | 54.5k | } |
195 | | |
196 | | void Stream_SealLength(wStream* _s) |
197 | 30.3k | { |
198 | 30.3k | size_t cur = 0; |
199 | 30.3k | WINPR_ASSERT(_s); |
200 | 30.3k | WINPR_ASSERT(_s->buffer <= _s->pointer); |
201 | 30.3k | cur = (size_t)(_s->pointer - _s->buffer); |
202 | 30.3k | WINPR_ASSERT(cur <= _s->capacity); |
203 | 30.3k | if (cur <= _s->capacity) |
204 | 30.3k | _s->length = cur; |
205 | 0 | else |
206 | 0 | { |
207 | 0 | WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was written out of bounds"); |
208 | 0 | winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); |
209 | 0 | _s->length = 0; |
210 | 0 | } |
211 | 30.3k | } |
212 | | |
213 | | #if defined(WITH_WINPR_DEPRECATED) |
214 | | BOOL Stream_SetPointer(wStream* _s, BYTE* _p) |
215 | | { |
216 | | WINPR_ASSERT(_s); |
217 | | if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p)) |
218 | | { |
219 | | _s->pointer = _s->buffer; |
220 | | return FALSE; |
221 | | } |
222 | | _s->pointer = _p; |
223 | | return TRUE; |
224 | | } |
225 | | |
226 | | BOOL Stream_SetBuffer(wStream* _s, BYTE* _b) |
227 | | { |
228 | | WINPR_ASSERT(_s); |
229 | | WINPR_ASSERT(_b); |
230 | | |
231 | | _s->buffer = _b; |
232 | | _s->pointer = _b; |
233 | | return _s->buffer != NULL; |
234 | | } |
235 | | |
236 | | void Stream_SetCapacity(wStream* _s, size_t _c) |
237 | | { |
238 | | WINPR_ASSERT(_s); |
239 | | _s->capacity = _c; |
240 | | } |
241 | | |
242 | | #endif |
243 | | |
244 | | size_t Stream_GetRemainingCapacity(const wStream* _s) |
245 | 16.3M | { |
246 | 16.3M | size_t cur = 0; |
247 | 16.3M | WINPR_ASSERT(_s); |
248 | 16.3M | WINPR_ASSERT(_s->buffer <= _s->pointer); |
249 | 16.3M | cur = (size_t)(_s->pointer - _s->buffer); |
250 | 16.3M | WINPR_ASSERT(cur <= _s->capacity); |
251 | 16.3M | if (cur > _s->capacity) |
252 | 0 | { |
253 | 0 | WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was written out of bounds"); |
254 | 0 | winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); |
255 | 0 | return 0; |
256 | 0 | } |
257 | 16.3M | return (_s->capacity - cur); |
258 | 16.3M | } |
259 | | |
260 | | size_t Stream_GetRemainingLength(const wStream* _s) |
261 | 24.2M | { |
262 | 24.2M | size_t cur = 0; |
263 | 24.2M | WINPR_ASSERT(_s); |
264 | 24.2M | WINPR_ASSERT(_s->buffer <= _s->pointer); |
265 | 24.2M | WINPR_ASSERT(_s->length <= _s->capacity); |
266 | 24.2M | cur = (size_t)(_s->pointer - _s->buffer); |
267 | 24.2M | WINPR_ASSERT(cur <= _s->length); |
268 | 24.2M | if (cur > _s->length) |
269 | 0 | { |
270 | 0 | WLog_FATAL(STREAM_TAG, "wStream API misuse: stream was read out of bounds"); |
271 | 0 | winpr_log_backtrace(STREAM_TAG, WLOG_FATAL, 20); |
272 | 0 | return 0; |
273 | 0 | } |
274 | 24.2M | return (_s->length - cur); |
275 | 24.2M | } |
276 | | |
277 | | BOOL Stream_Write_UTF16_String(wStream* s, const WCHAR* src, size_t length) |
278 | 0 | { |
279 | 0 | WINPR_ASSERT(s); |
280 | 0 | WINPR_ASSERT(src || (length == 0)); |
281 | 0 | if (!s || !src) |
282 | 0 | return FALSE; |
283 | | |
284 | 0 | if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, (s), length, sizeof(WCHAR))) |
285 | 0 | return FALSE; |
286 | | |
287 | 0 | for (size_t x = 0; x < length; x++) |
288 | 0 | Stream_Write_UINT16(s, src[x]); |
289 | |
|
290 | 0 | return TRUE; |
291 | 0 | } |
292 | | |
293 | | BOOL Stream_Read_UTF16_String(wStream* s, WCHAR* dst, size_t length) |
294 | 21.6k | { |
295 | 21.6k | WINPR_ASSERT(s); |
296 | 21.6k | WINPR_ASSERT(dst); |
297 | | |
298 | 21.6k | if (!Stream_CheckAndLogRequiredLengthOfSize(STREAM_TAG, s, length, sizeof(WCHAR))) |
299 | 0 | return FALSE; |
300 | | |
301 | 715k | for (size_t x = 0; x < length; x++) |
302 | 694k | Stream_Read_UINT16(s, dst[x]); |
303 | | |
304 | 21.6k | return TRUE; |
305 | 21.6k | } |
306 | | |
307 | | BOOL Stream_CheckAndLogRequiredCapacityEx(const char* tag, DWORD level, wStream* s, size_t nmemb, |
308 | | size_t size, const char* fmt, ...) |
309 | 5.60k | { |
310 | 5.60k | WINPR_ASSERT(size != 0); |
311 | 5.60k | const size_t actual = Stream_GetRemainingCapacity(s) / size; |
312 | | |
313 | 5.60k | if (actual < nmemb) |
314 | 0 | { |
315 | 0 | va_list args = WINPR_C_ARRAY_INIT; |
316 | |
|
317 | 0 | va_start(args, fmt); |
318 | 0 | Stream_CheckAndLogRequiredCapacityExVa(tag, level, s, nmemb, size, fmt, args); |
319 | 0 | va_end(args); |
320 | |
|
321 | 0 | return FALSE; |
322 | 0 | } |
323 | 5.60k | return TRUE; |
324 | 5.60k | } |
325 | | |
326 | | BOOL Stream_CheckAndLogRequiredCapacityExVa(const char* tag, DWORD level, wStream* s, size_t nmemb, |
327 | | size_t size, const char* fmt, va_list args) |
328 | 0 | { |
329 | 0 | WINPR_ASSERT(size != 0); |
330 | 0 | const size_t actual = Stream_GetRemainingCapacity(s) / size; |
331 | |
|
332 | 0 | if (actual < nmemb) |
333 | 0 | return Stream_CheckAndLogRequiredCapacityWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt, |
334 | 0 | args); |
335 | 0 | return TRUE; |
336 | 0 | } |
337 | | |
338 | | WINPR_ATTR_FORMAT_ARG(6, 0) |
339 | | BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level, wStream* s, size_t nmemb, |
340 | | size_t size, WINPR_FORMAT_ARG const char* fmt, |
341 | | va_list args) |
342 | 10 | { |
343 | | |
344 | 10 | WINPR_ASSERT(size != 0); |
345 | 10 | const size_t actual = Stream_GetRemainingCapacity(s) / size; |
346 | | |
347 | 10 | if (actual < nmemb) |
348 | 10 | { |
349 | 10 | char prefix[1024] = WINPR_C_ARRAY_INIT; |
350 | | |
351 | 10 | (void)vsnprintf(prefix, sizeof(prefix), fmt, args); |
352 | | |
353 | 10 | WLog_Print(log, level, |
354 | 10 | "[%s] invalid remaining capacity, got %" PRIuz ", require at least %" PRIuz |
355 | 10 | " [element size=%" PRIuz "]", |
356 | 10 | prefix, actual, nmemb, size); |
357 | 10 | winpr_log_backtrace_ex(log, level, 20); |
358 | 10 | return FALSE; |
359 | 10 | } |
360 | 0 | return TRUE; |
361 | 10 | } |
362 | | |
363 | | WINPR_ATTR_FORMAT_ARG(6, 7) |
364 | | BOOL Stream_CheckAndLogRequiredCapacityWLogEx(wLog* log, DWORD level, wStream* s, size_t nmemb, |
365 | | size_t size, WINPR_FORMAT_ARG const char* fmt, ...) |
366 | 11 | { |
367 | | |
368 | 11 | WINPR_ASSERT(size != 0); |
369 | 11 | const size_t actual = Stream_GetRemainingCapacity(s) / size; |
370 | | |
371 | 11 | if (actual < nmemb) |
372 | 10 | { |
373 | 10 | va_list args = WINPR_C_ARRAY_INIT; |
374 | | |
375 | 10 | va_start(args, fmt); |
376 | 10 | Stream_CheckAndLogRequiredCapacityWLogExVa(log, level, s, nmemb, size, fmt, args); |
377 | 10 | va_end(args); |
378 | | |
379 | 10 | return FALSE; |
380 | 10 | } |
381 | 1 | return TRUE; |
382 | 11 | } |
383 | | |
384 | | WINPR_ATTR_FORMAT_ARG(6, 7) |
385 | | BOOL Stream_CheckAndLogRequiredLengthEx(const char* tag, DWORD level, wStream* s, size_t nmemb, |
386 | | size_t size, WINPR_FORMAT_ARG const char* fmt, ...) |
387 | 8.29M | { |
388 | 8.29M | WINPR_ASSERT(size > 0); |
389 | 8.29M | const size_t actual = Stream_GetRemainingLength(s) / size; |
390 | | |
391 | 8.29M | if (actual < nmemb) |
392 | 159k | { |
393 | 159k | va_list args = WINPR_C_ARRAY_INIT; |
394 | | |
395 | 159k | va_start(args, fmt); |
396 | 159k | Stream_CheckAndLogRequiredLengthExVa(tag, level, s, nmemb, size, fmt, args); |
397 | 159k | va_end(args); |
398 | | |
399 | 159k | return FALSE; |
400 | 159k | } |
401 | 8.13M | return TRUE; |
402 | 8.29M | } |
403 | | |
404 | | BOOL Stream_CheckAndLogRequiredLengthExVa(const char* tag, DWORD level, wStream* s, size_t nmemb, |
405 | | size_t size, const char* fmt, va_list args) |
406 | 159k | { |
407 | 159k | WINPR_ASSERT(size > 0); |
408 | 159k | const size_t actual = Stream_GetRemainingLength(s) / size; |
409 | | |
410 | 159k | if (actual < nmemb) |
411 | 159k | return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, nmemb, size, fmt, |
412 | 159k | args); |
413 | 0 | return TRUE; |
414 | 159k | } |
415 | | |
416 | | BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level, wStream* s, size_t nmemb, |
417 | | size_t size, const char* fmt, ...) |
418 | 439k | { |
419 | 439k | WINPR_ASSERT(size > 0); |
420 | 439k | const size_t actual = Stream_GetRemainingLength(s) / size; |
421 | | |
422 | 439k | if (actual < nmemb) |
423 | 65.2k | { |
424 | 65.2k | va_list args = WINPR_C_ARRAY_INIT; |
425 | | |
426 | 65.2k | va_start(args, fmt); |
427 | 65.2k | Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, nmemb, size, fmt, args); |
428 | 65.2k | va_end(args); |
429 | | |
430 | 65.2k | return FALSE; |
431 | 65.2k | } |
432 | 374k | return TRUE; |
433 | 439k | } |
434 | | |
435 | | WINPR_ATTR_FORMAT_ARG(6, 0) |
436 | | BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level, wStream* s, size_t nmemb, |
437 | | size_t size, WINPR_FORMAT_ARG const char* fmt, |
438 | | va_list args) |
439 | 225k | { |
440 | 225k | WINPR_ASSERT(size > 0); |
441 | 225k | const size_t actual = Stream_GetRemainingLength(s) / size; |
442 | | |
443 | 225k | if (actual < nmemb) |
444 | 225k | { |
445 | 225k | char prefix[1024] = WINPR_C_ARRAY_INIT; |
446 | | |
447 | 225k | (void)vsnprintf(prefix, sizeof(prefix), fmt, args); |
448 | | |
449 | 225k | WLog_Print(log, level, |
450 | 225k | "[%s] invalid length, got %" PRIuz ", require at least %" PRIuz |
451 | 225k | " [element size=%" PRIuz "]", |
452 | 225k | prefix, actual, nmemb, size); |
453 | 225k | winpr_log_backtrace_ex(log, level, 20); |
454 | 225k | return FALSE; |
455 | 225k | } |
456 | 0 | return TRUE; |
457 | 225k | } |
458 | | |
459 | | SSIZE_T Stream_Write_UTF16_String_From_UTF8(wStream* s, size_t wcharLength, const char* src, |
460 | | size_t length, BOOL fill) |
461 | 0 | { |
462 | 0 | SSIZE_T rc = 0; |
463 | 0 | WCHAR* str = Stream_PointerAs(s, WCHAR); |
464 | |
|
465 | 0 | if (length != 0) |
466 | 0 | { |
467 | 0 | if (!Stream_CheckAndLogRequiredCapacityOfSize(STREAM_TAG, s, wcharLength, sizeof(WCHAR))) |
468 | 0 | return -1; |
469 | | |
470 | 0 | rc = ConvertUtf8NToWChar(src, length, str, wcharLength); |
471 | 0 | if (rc < 0) |
472 | 0 | return -1; |
473 | | |
474 | 0 | Stream_Seek(s, (size_t)rc * sizeof(WCHAR)); |
475 | 0 | } |
476 | | |
477 | 0 | if (fill) |
478 | 0 | Stream_Zero(s, (wcharLength - (size_t)rc) * sizeof(WCHAR)); |
479 | 0 | return rc; |
480 | 0 | } |
481 | | |
482 | | char* Stream_Read_UTF16_String_As_UTF8(wStream* s, size_t wcharLength, size_t* pUtfCharLength) |
483 | 0 | { |
484 | 0 | const WCHAR* str = Stream_ConstPointer(s); |
485 | 0 | if (wcharLength > SIZE_MAX / sizeof(WCHAR)) |
486 | 0 | return NULL; |
487 | | |
488 | 0 | if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength * sizeof(WCHAR))) |
489 | 0 | return NULL; |
490 | | |
491 | 0 | Stream_Seek(s, wcharLength * sizeof(WCHAR)); |
492 | 0 | return ConvertWCharNToUtf8Alloc(str, wcharLength, pUtfCharLength); |
493 | 0 | } |
494 | | |
495 | | SSIZE_T Stream_Read_UTF16_String_As_UTF8_Buffer(wStream* s, size_t wcharLength, char* utfBuffer, |
496 | | size_t utfBufferCharLength) |
497 | 876 | { |
498 | 876 | const WCHAR* ptr = Stream_ConstPointer(s); |
499 | 876 | if (wcharLength > SIZE_MAX / sizeof(WCHAR)) |
500 | 0 | return -1; |
501 | | |
502 | 876 | if (!Stream_CheckAndLogRequiredLength(STREAM_TAG, s, wcharLength * sizeof(WCHAR))) |
503 | 0 | return -1; |
504 | | |
505 | 876 | Stream_Seek(s, wcharLength * sizeof(WCHAR)); |
506 | 876 | return ConvertWCharNToUtf8(ptr, wcharLength, utfBuffer, utfBufferCharLength); |
507 | 876 | } |
508 | | |
509 | | BOOL Stream_SafeSeekEx(wStream* s, size_t size, const char* file, size_t line, const char* fkt) |
510 | 184k | { |
511 | 184k | if (!Stream_CheckAndLogRequiredLengthEx(STREAM_TAG, WLOG_WARN, s, size, 1, "%s(%s:%" PRIuz ")", |
512 | 184k | fkt, file, line)) |
513 | 27.1k | return FALSE; |
514 | | |
515 | 157k | Stream_Seek(s, size); |
516 | 157k | return TRUE; |
517 | 184k | } |