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