Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
_buffer.c423 linesDownload Raw Back to aioquic
1#define PY_SSIZE_T_CLEAN
2
3#include <Python.h>
4#include <stdint.h>
5
6#define MODULE_NAME "aioquic._buffer"
7
8static PyObject *BufferReadError;
9static PyObject *BufferWriteError;
10
11typedef struct {
12    PyObject_HEAD
13    uint8_t *base;
14    uint8_t *end;
15    uint8_t *pos;
16} BufferObject;
17
18static PyObject *BufferType;
19
20#define CHECK_READ_BOUNDS(self, len) \
21    if (len < 0 || self->pos + len > self->end) { \
22        PyErr_SetString(BufferReadError, "Read out of bounds"); \
23        return NULL; \
24    }
25
26#define CHECK_WRITE_BOUNDS(self, len) \
27    if (self->pos + len > self->end) { \
28        PyErr_SetString(BufferWriteError, "Write out of bounds"); \
29        return NULL; \
30    }
31
32static int
33Buffer_init(BufferObject *self, PyObject *args, PyObject *kwargs)
34{
35    const char *kwlist[] = {"capacity", "data", NULL};
36    Py_ssize_t capacity = 0;
37    const unsigned char *data = NULL;
38    Py_ssize_t data_len = 0;
39
40    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ny#", (char**)kwlist, &capacity, &data, &data_len))
41        return -1;
42
43    if (data != NULL) {
44        self->base = malloc(data_len);
45        self->end = self->base + data_len;
46        memcpy(self->base, data, data_len);
47    } else {
48        self->base = malloc(capacity);
49        self->end = self->base + capacity;
50    }
51    self->pos = self->base;
52    return 0;
53}
54
55static void
56Buffer_dealloc(BufferObject *self)
57{
58    free(self->base);
59    PyTypeObject *tp = Py_TYPE(self);
60    freefunc free = PyType_GetSlot(tp, Py_tp_free);
61    free(self);
62    Py_DECREF(tp);
63}
64
65static PyObject *
66Buffer_data_slice(BufferObject *self, PyObject *args)
67{
68    Py_ssize_t start, stop;
69    if (!PyArg_ParseTuple(args, "nn", &start, &stop))
70        return NULL;
71
72    if (start < 0 || self->base + start > self->end ||
73        stop < 0 || self->base + stop > self->end ||
74        stop < start) {
75        PyErr_SetString(BufferReadError, "Read out of bounds");
76        return NULL;
77    }
78
79    return PyBytes_FromStringAndSize((const char*)(self->base + start), (stop - start));
80}
81
82static PyObject *
83Buffer_eof(BufferObject *self, PyObject *args)
84{
85    if (self->pos == self->end)
86        Py_RETURN_TRUE;
87    Py_RETURN_FALSE;
88}
89
90static PyObject *
91Buffer_pull_bytes(BufferObject *self, PyObject *args)
92{
93    Py_ssize_t len;
94    if (!PyArg_ParseTuple(args, "n", &len))
95        return NULL;
96
97    CHECK_READ_BOUNDS(self, len);
98
99    PyObject *o = PyBytes_FromStringAndSize((const char*)self->pos, len);
100    self->pos += len;
101    return o;
102}
103
104static PyObject *
105Buffer_pull_uint8(BufferObject *self, PyObject *args)
106{
107    CHECK_READ_BOUNDS(self, 1)
108
109    return PyLong_FromUnsignedLong(
110        (uint8_t)(*(self->pos++))
111    );
112}
113
114static PyObject *
115Buffer_pull_uint16(BufferObject *self, PyObject *args)
116{
117    CHECK_READ_BOUNDS(self, 2)
118
119    uint16_t value = (uint16_t)(*(self->pos)) << 8 |
120                     (uint16_t)(*(self->pos + 1));
121    self->pos += 2;
122    return PyLong_FromUnsignedLong(value);
123}
124
125static PyObject *
126Buffer_pull_uint32(BufferObject *self, PyObject *args)
127{
128    CHECK_READ_BOUNDS(self, 4)
129
130    uint32_t value = (uint32_t)(*(self->pos)) << 24 |
131                     (uint32_t)(*(self->pos + 1)) << 16 |
132                     (uint32_t)(*(self->pos + 2)) << 8 |
133                     (uint32_t)(*(self->pos + 3));
134    self->pos += 4;
135    return PyLong_FromUnsignedLong(value);
136}
137
138static PyObject *
139Buffer_pull_uint64(BufferObject *self, PyObject *args)
140{
141    CHECK_READ_BOUNDS(self, 8)
142
143    uint64_t value = (uint64_t)(*(self->pos)) << 56 |
144                     (uint64_t)(*(self->pos + 1)) << 48 |
145                     (uint64_t)(*(self->pos + 2)) << 40 |
146                     (uint64_t)(*(self->pos + 3)) << 32 |
147                     (uint64_t)(*(self->pos + 4)) << 24 |
148                     (uint64_t)(*(self->pos + 5)) << 16 |
149                     (uint64_t)(*(self->pos + 6)) << 8 |
150                     (uint64_t)(*(self->pos + 7));
151    self->pos += 8;
152    return PyLong_FromUnsignedLongLong(value);
153}
154
155static PyObject *
156Buffer_pull_uint_var(BufferObject *self, PyObject *args)
157{
158    uint64_t value;
159    CHECK_READ_BOUNDS(self, 1)
160    switch (*(self->pos) >> 6) {
161    case 0:
162        value = *(self->pos++) & 0x3F;
163        break;
164    case 1:
165        CHECK_READ_BOUNDS(self, 2)
166        value = (uint16_t)(*(self->pos) & 0x3F) << 8 |
167                (uint16_t)(*(self->pos + 1));
168        self->pos += 2;
169        break;
170    case 2:
171        CHECK_READ_BOUNDS(self, 4)
172        value = (uint32_t)(*(self->pos) & 0x3F) << 24 |
173                (uint32_t)(*(self->pos + 1)) << 16 |
174                (uint32_t)(*(self->pos + 2)) << 8 |
175                (uint32_t)(*(self->pos + 3));
176        self->pos += 4;
177        break;
178    default:
179        CHECK_READ_BOUNDS(self, 8)
180        value = (uint64_t)(*(self->pos) & 0x3F) << 56 |
181                (uint64_t)(*(self->pos + 1)) << 48 |
182                (uint64_t)(*(self->pos + 2)) << 40 |
183                (uint64_t)(*(self->pos + 3)) << 32 |
184                (uint64_t)(*(self->pos + 4)) << 24 |
185                (uint64_t)(*(self->pos + 5)) << 16 |
186                (uint64_t)(*(self->pos + 6)) << 8 |
187                (uint64_t)(*(self->pos + 7));
188        self->pos += 8;
189        break;
190    }
191    return PyLong_FromUnsignedLongLong(value);
192}
193
194static PyObject *
195Buffer_push_bytes(BufferObject *self, PyObject *args)
196{
197    const unsigned char *data;
198    Py_ssize_t data_len;
199    if (!PyArg_ParseTuple(args, "y#", &data, &data_len))
200        return NULL;
201
202    CHECK_WRITE_BOUNDS(self, data_len)
203
204    memcpy(self->pos, data, data_len);
205    self->pos += data_len;
206    Py_RETURN_NONE;
207}
208
209static PyObject *
210Buffer_push_uint8(BufferObject *self, PyObject *args)
211{
212    uint8_t value;
213    if (!PyArg_ParseTuple(args, "B", &value))
214        return NULL;
215
216    CHECK_WRITE_BOUNDS(self, 1)
217
218    *(self->pos++) = value;
219    Py_RETURN_NONE;
220}
221
222static PyObject *
223Buffer_push_uint16(BufferObject *self, PyObject *args)
224{
225    uint16_t value;
226    if (!PyArg_ParseTuple(args, "H", &value))
227        return NULL;
228
229    CHECK_WRITE_BOUNDS(self, 2)
230
231    *(self->pos++) = (value >> 8);
232    *(self->pos++) = value;
233    Py_RETURN_NONE;
234}
235
236static PyObject *
237Buffer_push_uint32(BufferObject *self, PyObject *args)
238{
239    uint32_t value;
240    if (!PyArg_ParseTuple(args, "I", &value))
241        return NULL;
242
243    CHECK_WRITE_BOUNDS(self, 4)
244    *(self->pos++) = (value >> 24);
245    *(self->pos++) = (value >> 16);
246    *(self->pos++) = (value >> 8);
247    *(self->pos++) = value;
248    Py_RETURN_NONE;
249}
250
251static PyObject *
252Buffer_push_uint64(BufferObject *self, PyObject *args)
253{
254    uint64_t value;
255    if (!PyArg_ParseTuple(args, "K", &value))
256        return NULL;
257
258    CHECK_WRITE_BOUNDS(self, 8)
259    *(self->pos++) = (value >> 56);
260    *(self->pos++) = (value >> 48);
261    *(self->pos++) = (value >> 40);
262    *(self->pos++) = (value >> 32);
263    *(self->pos++) = (value >> 24);
264    *(self->pos++) = (value >> 16);
265    *(self->pos++) = (value >> 8);
266    *(self->pos++) = value;
267    Py_RETURN_NONE;
268}
269
270static PyObject *
271Buffer_push_uint_var(BufferObject *self, PyObject *args)
272{
273    uint64_t value;
274    if (!PyArg_ParseTuple(args, "K", &value))
275        return NULL;
276
277    if (value <= 0x3F) {
278        CHECK_WRITE_BOUNDS(self, 1)
279        *(self->pos++) = value;
280        Py_RETURN_NONE;
281    } else if (value <= 0x3FFF) {
282        CHECK_WRITE_BOUNDS(self, 2)
283        *(self->pos++) = (value >> 8) | 0x40;
284        *(self->pos++) = value;
285        Py_RETURN_NONE;
286    } else if (value <= 0x3FFFFFFF) {
287        CHECK_WRITE_BOUNDS(self, 4)
288        *(self->pos++) = (value >> 24) | 0x80;
289        *(self->pos++) = (value >> 16);
290        *(self->pos++) = (value >> 8);
291        *(self->pos++) = value;
292        Py_RETURN_NONE;
293    } else if (value <= 0x3FFFFFFFFFFFFFFF) {
294        CHECK_WRITE_BOUNDS(self, 8)
295        *(self->pos++) = (value >> 56) | 0xC0;
296        *(self->pos++) = (value >> 48);
297        *(self->pos++) = (value >> 40);
298        *(self->pos++) = (value >> 32);
299        *(self->pos++) = (value >> 24);
300        *(self->pos++) = (value >> 16);
301        *(self->pos++) = (value >> 8);
302        *(self->pos++) = value;
303        Py_RETURN_NONE;
304    } else {
305        PyErr_SetString(PyExc_ValueError, "Integer is too big for a variable-length integer");
306        return NULL;
307    }
308}
309
310static PyObject *
311Buffer_seek(BufferObject *self, PyObject *args)
312{
313    Py_ssize_t pos;
314    if (!PyArg_ParseTuple(args, "n", &pos))
315        return NULL;
316
317    if (pos < 0 || self->base + pos > self->end) {
318        PyErr_SetString(BufferReadError, "Seek out of bounds");
319        return NULL;
320    }
321
322    self->pos = self->base + pos;
323    Py_RETURN_NONE;
324}
325
326static PyObject *
327Buffer_tell(BufferObject *self, PyObject *args)
328{
329    return PyLong_FromSsize_t(self->pos - self->base);
330}
331
332static PyMethodDef Buffer_methods[] = {
333    {"data_slice", (PyCFunction)Buffer_data_slice, METH_VARARGS, ""},
334    {"eof", (PyCFunction)Buffer_eof, METH_VARARGS, ""},
335    {"pull_bytes", (PyCFunction)Buffer_pull_bytes, METH_VARARGS, "Pull bytes."},
336    {"pull_uint8", (PyCFunction)Buffer_pull_uint8, METH_VARARGS, "Pull an 8-bit unsigned integer."},
337    {"pull_uint16", (PyCFunction)Buffer_pull_uint16, METH_VARARGS, "Pull a 16-bit unsigned integer."},
338    {"pull_uint32", (PyCFunction)Buffer_pull_uint32, METH_VARARGS, "Pull a 32-bit unsigned integer."},
339    {"pull_uint64", (PyCFunction)Buffer_pull_uint64, METH_VARARGS, "Pull a 64-bit unsigned integer."},
340    {"pull_uint_var", (PyCFunction)Buffer_pull_uint_var, METH_VARARGS, "Pull a QUIC variable-length unsigned integer."},
341    {"push_bytes", (PyCFunction)Buffer_push_bytes, METH_VARARGS, "Push bytes."},
342    {"push_uint8", (PyCFunction)Buffer_push_uint8, METH_VARARGS, "Push an 8-bit unsigned integer."},
343    {"push_uint16", (PyCFunction)Buffer_push_uint16, METH_VARARGS, "Push a 16-bit unsigned integer."},
344    {"push_uint32", (PyCFunction)Buffer_push_uint32, METH_VARARGS, "Push a 32-bit unsigned integer."},
345    {"push_uint64", (PyCFunction)Buffer_push_uint64, METH_VARARGS, "Push a 64-bit unsigned integer."},
346    {"push_uint_var", (PyCFunction)Buffer_push_uint_var, METH_VARARGS, "Push a QUIC variable-length unsigned integer."},
347    {"seek", (PyCFunction)Buffer_seek, METH_VARARGS, ""},
348    {"tell", (PyCFunction)Buffer_tell, METH_VARARGS, ""},
349    {NULL}
350};
351
352static PyObject*
353Buffer_capacity_getter(BufferObject* self, void *closure) {
354    return PyLong_FromSsize_t(self->end - self->base);
355}
356
357static PyObject*
358Buffer_data_getter(BufferObject* self, void *closure) {
359    return PyBytes_FromStringAndSize((const char*)self->base, self->pos - self->base);
360}
361
362static PyGetSetDef Buffer_getset[] = {
363    {"capacity", (getter) Buffer_capacity_getter, NULL, "", NULL },
364    {"data", (getter) Buffer_data_getter, NULL, "", NULL },
365    {NULL}
366};
367
368static PyType_Slot BufferType_slots[] = {
369    {Py_tp_dealloc, Buffer_dealloc},
370    {Py_tp_methods, Buffer_methods},
371    {Py_tp_doc, "Buffer objects"},
372    {Py_tp_getset, Buffer_getset},
373    {Py_tp_init, Buffer_init},
374    {0, 0},
375};
376
377static PyType_Spec BufferType_spec = {
378    MODULE_NAME ".Buffer",
379    sizeof(BufferObject),
380    0,
381    Py_TPFLAGS_DEFAULT,
382    BufferType_slots
383};
384
385
386static struct PyModuleDef moduledef = {
387    PyModuleDef_HEAD_INIT,
388    MODULE_NAME,                        /* m_name */
389    "Serialization utilities.",         /* m_doc */
390    -1,                                 /* m_size */
391    NULL,                               /* m_methods */
392    NULL,                               /* m_reload */
393    NULL,                               /* m_traverse */
394    NULL,                               /* m_clear */
395    NULL,                               /* m_free */
396};
397
398
399PyMODINIT_FUNC
400PyInit__buffer(void)
401{
402    PyObject* m;
403
404    m = PyModule_Create(&moduledef);
405    if (m == NULL)
406        return NULL;
407
408    BufferReadError = PyErr_NewException(MODULE_NAME ".BufferReadError", PyExc_ValueError, NULL);
409    Py_INCREF(BufferReadError);
410    PyModule_AddObject(m, "BufferReadError", BufferReadError);
411
412    BufferWriteError = PyErr_NewException(MODULE_NAME ".BufferWriteError", PyExc_ValueError, NULL);
413    Py_INCREF(BufferWriteError);
414    PyModule_AddObject(m, "BufferWriteError", BufferWriteError);
415
416    BufferType = PyType_FromSpec(&BufferType_spec);
417    if (BufferType == NULL)
418        return NULL;
419    PyModule_AddObject(m, "Buffer", BufferType);
420
421    return m;
422}
423 
codekingpro/portable-devtools · Team Ai