blob: de945ab334ca2cca15ddcaf6969f55cfb4a8259a [file] [log] [blame]
Tim Hall79d07d22020-04-27 18:20:16 +01001/*
2 * Copyright (c) 2020 Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Licensed under the Apache License, Version 2.0 (the License); you may
7 * not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
14 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#define PY_SSIZE_T_CLEAN
20#include <Python.h>
21
22#include "mlw_decode.h"
23#include "mlw_encode.h"
24
25/* C extension wrapper for mlw_encode
26 *
27 * This method is exposed directly in python with the arguments with a
28 * prototype of the form:
29 *
30 * output = mlw_codec.encode(input, verbose=0)
31 *
32 * input: [int]
33 * verbose: int
34 * output: bytearray
35 */
36
37static PyObject *
38method_encode (PyObject *self, PyObject *args)
39{
40 /* Object to hold the input integer list. */
41 PyObject *input_list_object;
42
43 /* Object to hold the input verbosity integer, the verbose argument
44 * is optional so defaulted to 0.
45 */
46 int verbose = 0;
47
48 /* Arguments to the method are delivered as a tuple, unpack the
49 * tuple to get the individual arguments, note the second is
50 * optional.
51 */
52 if (!PyArg_ParseTuple(args, "O|i", &input_list_object, &verbose))
53 return NULL;
54
55 /* Unpack the length of the input integer list. */
56 int input_length = PyObject_Length (input_list_object);
57 if (input_length < 0)
58 input_length = 0;
59
60 /* We need to marshall the integer list into an input buffer
61 * suitable for mlw_encode, use a temporary heap allocated buffer
62 * for that purpose.
63 */
64 int16_t *input_buffer = (int16_t *) malloc(sizeof(int16_t *) * input_length);
65 if (input_buffer == NULL)
66 return PyErr_NoMemory();
67
68 /* Unpack the input integer list into the temporary buffer.
69 */
70 for (int i = 0; i < input_length; i++)
71 {
72 PyObject *item;
73 item = PyList_GetItem(input_list_object, i);
74 if (!PyLong_Check(item))
75 input_buffer[i] = 0;
76 input_buffer[i] = PyLong_AsLong(item);
77 }
78
79 /* We don't know the output length required, we guess worst case,
80 * the mlw_encode call will do a resize (downwards) anyway.
81 */
82 uint8_t *output_buffer = malloc(input_length);
83 if (output_buffer == NULL)
84 return PyErr_NoMemory();
85
86 int output_length = mlw_encode(input_buffer, input_length, &output_buffer, verbose);
87
88 PyObject *output_byte_array = PyByteArray_FromStringAndSize ((char *) output_buffer, output_length);
89
90 /* Discard the temporary input and output buffers. */
91 free (input_buffer);
92 free (output_buffer);
93
94 return output_byte_array;
95}
96
97/* C extension wrapper for mlw_decode
98 *
99 * This method is exposed directly in python with the arguments with a
100 * prototype of the form:
101 *
102 * output = mlw_codec.decode(input, verbose=0)
103 *
104 * input: bytearray
105 * verbose: int
106 * output: [int]
107 */
108
109static PyObject *
110method_decode(PyObject *self, PyObject *args)
111{
112 /* Object to hold the input bytearray. */
113 PyObject *input_bytearray_object;
114
115 /* Object to hold the input verbosity integer, the verbose argument
116 * is optional so defaulted to 0.
117 */
118 int verbose = 0;
119
120 /* Arguments to the method are delivered as a tuple, unpack the
121 * tuple to get the individual arguments, note the second is
122 * optional.
123 */
124 if (!PyArg_ParseTuple(args, "Y|i", &input_bytearray_object, &verbose))
125 return NULL;
126
127 /* Unpack the input buffer and length from the bytearray object. */
128 uint8_t *input_buffer = (uint8_t *) PyByteArray_AsString(input_bytearray_object);
129 int input_length = PyByteArray_Size(input_bytearray_object);
130
131 /* We don't know the output length required, we guess, but the guess
132 * will be too small, the mlw_decode call will do a resize (upwards)
133 * anyway.
134 */
135 int16_t *output_buffer = malloc (input_length);
136 if (output_buffer == NULL)
137 return PyErr_NoMemory();
138
139 int output_length = mlw_decode (input_buffer, input_length, &output_buffer, verbose);
140
141 /* Construct a new integer list and marshall the output buffer
142 * contents into the list. */
143 PyObject *output_list = PyList_New(output_length);
144 for (int i = 0; i <output_length; i++)
145 PyList_SetItem (output_list, i, PyLong_FromLong (output_buffer[i]));
146
147 free (output_buffer);
148
149 return output_list;
150}
151
152/* mlw_codec method descriptors.
153 */
154
155static PyMethodDef mlw_methods[] = {
156 {"decode", method_decode, METH_VARARGS, "Python interface for decode"},
157 {"encode", method_encode, METH_VARARGS, "Python interface for encode"},
158 {NULL, NULL, 0, NULL}
159};
160
161/* mlw_codec module descriptor.
162 */
163
164static struct PyModuleDef mlw_codecmodule = {
165 PyModuleDef_HEAD_INIT,
166 "mlw_codec",
167 "Python interface for the mlw encoder",
168 -1,
169 mlw_methods
170};
171
172PyMODINIT_FUNC PyInit_mlw_codec(void) {
173 return PyModule_Create(&mlw_codecmodule);
174}