1 #include "internal.h"
2 #include "script_int.h"
3
4 #include <assert.h>
5 #include <limits.h>
6 #include <stdbool.h>
7 #include "pullpush.h"
8
push_bytes(unsigned char ** cursor,size_t * max,const void * src,size_t len)9 unsigned char *push_bytes(unsigned char **cursor, size_t *max,
10 const void *src, size_t len)
11 {
12 if (cursor == NULL || *cursor == NULL) {
13 *max += len;
14 return NULL;
15 }
16 if (len > *max) {
17 if (src)
18 memcpy(*cursor, src, *max);
19 /* From now on, max records the room we *needed* */
20 *max = len - *max;
21 *cursor = NULL;
22 return NULL;
23 }
24 if (src)
25 memcpy(*cursor, src, len);
26
27 *cursor += len;
28 *max -= len;
29
30 return *cursor - len;
31 }
32
pull_bytes(void * dst,size_t len,const unsigned char ** cursor,size_t * max)33 void pull_bytes(void *dst, size_t len,
34 const unsigned char **cursor, size_t *max)
35 {
36 if (len > *max) {
37 memcpy(dst, *cursor, *max);
38 memset((char *)dst + *max, 0, len - *max);
39 pull_failed(cursor, max);
40 return;
41 }
42 memcpy(dst, *cursor, len);
43 *cursor += len;
44 *max -= len;
45 }
46
pull_skip(const unsigned char ** cursor,size_t * max,size_t len)47 const unsigned char *pull_skip(const unsigned char **cursor, size_t *max,
48 size_t len)
49 {
50 const unsigned char *p;
51
52 if (*cursor == NULL) {
53 return NULL;
54 }
55
56 if (len > *max) {
57 pull_failed(cursor, max);
58 return NULL;
59 }
60
61 p = *cursor;
62 *cursor += len;
63 *max -= len;
64 return p;
65 }
66
pull_failed(const unsigned char ** cursor,size_t * max)67 void pull_failed(const unsigned char **cursor, size_t *max)
68 {
69 *cursor = NULL;
70 *max = 0;
71 }
72
push_le64(unsigned char ** cursor,size_t * max,uint64_t v)73 void push_le64(unsigned char **cursor, size_t *max, uint64_t v)
74 {
75 leint64_t lev = cpu_to_le64(v);
76 push_bytes(cursor, max, &lev, sizeof(lev));
77 }
78
pull_le64(const unsigned char ** cursor,size_t * max)79 uint64_t pull_le64(const unsigned char **cursor, size_t *max)
80 {
81 leint64_t lev;
82 pull_bytes(&lev, sizeof(lev), cursor, max);
83 return le64_to_cpu(lev);
84 }
85
push_le32(unsigned char ** cursor,size_t * max,uint32_t v)86 void push_le32(unsigned char **cursor, size_t *max, uint32_t v)
87 {
88 leint32_t lev = cpu_to_le32(v);
89 push_bytes(cursor, max, &lev, sizeof(lev));
90 }
91
pull_le32(const unsigned char ** cursor,size_t * max)92 uint32_t pull_le32(const unsigned char **cursor, size_t *max)
93 {
94 leint32_t lev;
95 pull_bytes(&lev, sizeof(lev), cursor, max);
96 return le32_to_cpu(lev);
97 }
98
push_u8(unsigned char ** cursor,size_t * max,uint8_t v)99 void push_u8(unsigned char **cursor, size_t *max, uint8_t v)
100 {
101 push_bytes(cursor, max, &v, sizeof(uint8_t));
102 }
103
pull_u8(const unsigned char ** cursor,size_t * max)104 uint8_t pull_u8(const unsigned char **cursor, size_t *max)
105 {
106 uint8_t v;
107 pull_bytes(&v, sizeof(v), cursor, max);
108 return v;
109 }
110
peek_u8(const unsigned char ** cursor,size_t * max)111 uint8_t peek_u8(const unsigned char **cursor, size_t *max)
112 {
113 uint8_t v = pull_u8(cursor, max);
114 if (*cursor) {
115 *cursor -= sizeof(v);
116 *max += sizeof(v);
117 }
118 return v;
119 }
120
push_varint(unsigned char ** cursor,size_t * max,uint64_t v)121 void push_varint(unsigned char **cursor, size_t *max, uint64_t v)
122 {
123 unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)];
124 size_t len = varint_to_bytes(v, buf);
125
126 push_bytes(cursor, max, buf, len);
127 }
128
pull_varint(const unsigned char ** cursor,size_t * max)129 uint64_t pull_varint(const unsigned char **cursor, size_t *max)
130 {
131 unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)];
132 uint64_t v;
133
134 /* FIXME: Would be more efficient to opencode varint here! */
135 pull_bytes(buf, 1, cursor, max);
136 pull_bytes(buf + 1, varint_length_from_bytes(buf) - 1, cursor, max);
137 varint_from_bytes(buf, &v);
138
139 return v;
140 }
141
push_varbuff(unsigned char ** cursor,size_t * max,const unsigned char * bytes,size_t bytes_len)142 void push_varbuff(unsigned char **cursor, size_t *max,
143 const unsigned char *bytes, size_t bytes_len)
144 {
145 push_varint(cursor, max, bytes_len);
146 push_bytes(cursor, max, bytes, bytes_len);
147 }
148
pull_varlength(const unsigned char ** cursor,size_t * max)149 size_t pull_varlength(const unsigned char **cursor, size_t *max)
150 {
151 uint64_t len = pull_varint(cursor, max);
152
153 if (len > *max) {
154 /* Impossible length. */
155 pull_failed(cursor, max);
156 return 0;
157 }
158 return len;
159 }
160
pull_subfield_start(const unsigned char * const * cursor,const size_t * max,size_t subfield_len,const unsigned char ** subcursor,size_t * submax)161 void pull_subfield_start(const unsigned char *const *cursor, const size_t *max,
162 size_t subfield_len,
163 const unsigned char **subcursor, size_t *submax)
164 {
165 if (subfield_len > *max) {
166 pull_failed(subcursor, submax);
167 } else {
168 *subcursor = *cursor;
169 *submax = subfield_len;
170 }
171 }
172
pull_subfield_end(const unsigned char ** cursor,size_t * max,const unsigned char * subcursor,size_t submax)173 void pull_subfield_end(const unsigned char **cursor, size_t *max,
174 const unsigned char *subcursor, size_t submax)
175 {
176 if (subcursor == NULL) {
177 pull_failed(cursor, max);
178 } else if (*cursor != NULL) {
179 const unsigned char *subend = subcursor + submax;
180 assert(subcursor >= *cursor);
181 assert(subend <= *cursor + *max);
182 *max -= (subend - *cursor);
183 *cursor = subend;
184 }
185 }
186