1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "upb/io/chunked_input_stream.h"
9
10 // Must be last.
11 #include "upb/port/def.inc"
12
13 typedef struct {
14 upb_ZeroCopyInputStream base;
15
16 const char* data;
17 size_t size;
18 size_t limit;
19 size_t position;
20 size_t last_returned_size;
21 } upb_ChunkedInputStream;
22
upb_ChunkedInputStream_Next(upb_ZeroCopyInputStream * z,size_t * count,upb_Status * status)23 static const void* upb_ChunkedInputStream_Next(upb_ZeroCopyInputStream* z,
24 size_t* count,
25 upb_Status* status) {
26 upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z;
27 UPB_ASSERT(c->position <= c->size);
28
29 const char* out = c->data + c->position;
30
31 const size_t chunk = UPB_MIN(c->limit, c->size - c->position);
32 c->position += chunk;
33 c->last_returned_size = chunk;
34 *count = chunk;
35
36 return chunk ? out : NULL;
37 }
38
upb_ChunkedInputStream_BackUp(upb_ZeroCopyInputStream * z,size_t count)39 static void upb_ChunkedInputStream_BackUp(upb_ZeroCopyInputStream* z,
40 size_t count) {
41 upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z;
42
43 UPB_ASSERT(c->last_returned_size >= count);
44 c->position -= count;
45 c->last_returned_size -= count;
46 }
47
upb_ChunkedInputStream_Skip(upb_ZeroCopyInputStream * z,size_t count)48 static bool upb_ChunkedInputStream_Skip(upb_ZeroCopyInputStream* z,
49 size_t count) {
50 upb_ChunkedInputStream* c = (upb_ChunkedInputStream*)z;
51
52 c->last_returned_size = 0; // Don't let caller back up.
53 if (count > c->size - c->position) {
54 c->position = c->size;
55 return false;
56 }
57
58 c->position += count;
59 return true;
60 }
61
upb_ChunkedInputStream_ByteCount(const upb_ZeroCopyInputStream * z)62 static size_t upb_ChunkedInputStream_ByteCount(
63 const upb_ZeroCopyInputStream* z) {
64 const upb_ChunkedInputStream* c = (const upb_ChunkedInputStream*)z;
65
66 return c->position;
67 }
68
69 static const _upb_ZeroCopyInputStream_VTable upb_ChunkedInputStream_vtable = {
70 upb_ChunkedInputStream_Next,
71 upb_ChunkedInputStream_BackUp,
72 upb_ChunkedInputStream_Skip,
73 upb_ChunkedInputStream_ByteCount,
74 };
75
upb_ChunkedInputStream_New(const void * data,size_t size,size_t limit,upb_Arena * arena)76 upb_ZeroCopyInputStream* upb_ChunkedInputStream_New(const void* data,
77 size_t size, size_t limit,
78 upb_Arena* arena) {
79 upb_ChunkedInputStream* c = upb_Arena_Malloc(arena, sizeof(*c));
80 if (!c || !limit) return NULL;
81
82 c->base.vtable = &upb_ChunkedInputStream_vtable;
83 c->data = data;
84 c->size = size;
85 c->limit = limit;
86 c->position = 0;
87 c->last_returned_size = 0;
88
89 return (upb_ZeroCopyInputStream*)c;
90 }
91