source: sasview/src/sas/sascalc/file_converter/c_ext/bsl_loader.c @ 71ac835

Last change on this file since 71ac835 was dc8a553, checked in by lewis, 8 years ago

Show error message when binary file can't be loaded

  • Property mode set to 100644
File size: 9.7 KB
Line 
1#include <Python.h>
2#include <numpy/arrayobject.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include "structmember.h"
6#include "bsl_loader.h"
7
8typedef struct {
9    PyObject_HEAD
10    CLoader_params params;
11} CLoader;
12
13static PyObject *CLoader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
14    CLoader *self;
15
16    self = (CLoader *)type->tp_alloc(type, 0);
17
18    return (PyObject *)self;
19}
20
21static PyObject *CLoader_init(CLoader *self, PyObject *args, PyObject *kwds) {
22    const char *filename;
23    const int n_frames;
24    const int n_pixels;
25    const int n_rasters;
26    const int swap_bytes;
27
28    if (self != NULL) {
29        if (!PyArg_ParseTuple(args, "siiii", &filename, &n_frames, &n_pixels, &n_rasters, &swap_bytes))
30            Py_RETURN_NONE;
31        if (!(self->params.filename = malloc(strlen(filename) + 1)))
32            Py_RETURN_NONE;
33        strcpy(self->params.filename, filename);
34        self->params.n_frames = n_frames;
35        self->params.n_pixels = n_pixels;
36        self->params.n_rasters = n_rasters;
37        self->params.swap_bytes = swap_bytes;
38    }
39
40    return 0;
41}
42
43static void CLoader_dealloc(CLoader *self) {
44    free(self->params.filename);
45    self->ob_type->tp_free((PyObject *)self);
46}
47
48static PyObject *to_string(CLoader *self, PyObject *params) {
49    char str[100];
50    sprintf(str,
51        "Filename: %s\nn_frames: %d\nframe: %d\nn_pixels: %d\nn_rasters: %d\nswap_bytes: %d",
52        self->params.filename,
53        self->params.n_frames,
54        self->params.frame,
55        self->params.n_pixels,
56        self->params.n_rasters,
57        self->params.swap_bytes);
58    return Py_BuildValue("s", str);
59}
60
61/*                    ----- Setters and Getters -----                        */
62
63static PyObject *get_filename(CLoader *self, PyObject *args) {
64    return Py_BuildValue("s", self->params.filename);
65}
66
67static PyObject *set_filename(CLoader *self, PyObject *args) {
68    const char *new_filename;
69    if (!PyArg_ParseTuple(args, "s", &new_filename))
70        return NULL;
71    strcpy(self->params.filename, new_filename);
72
73    return Py_BuildValue("s", self->params.filename);
74}
75
76static PyObject *get_n_frames(CLoader *self, PyObject *args) {
77    return Py_BuildValue("i", self->params.n_frames);
78}
79
80static PyObject *set_n_frames(CLoader *self, PyObject *args) {
81    int new_frames;
82    if (!PyArg_ParseTuple(args, "i", &new_frames))
83        return NULL;
84    self->params.n_frames = new_frames;
85
86    return Py_BuildValue("i", self->params.n_frames);
87}
88
89static PyObject *get_frame(CLoader *self, PyObject *args) {
90    return Py_BuildValue("i", self->params.frame);
91}
92
93static PyObject *set_frame(CLoader *self, PyObject *args) {
94    int new_frame;
95    if (!PyArg_ParseTuple(args, "i", &new_frame))
96        return NULL;
97    self->params.frame = new_frame;
98
99    return Py_BuildValue("i", self->params.frame);
100}
101
102static PyObject *get_n_pixels(CLoader *self, PyObject *args) {
103    return Py_BuildValue("i", self->params.n_pixels);
104}
105
106static PyObject *set_n_pixels(CLoader *self, PyObject *args) {
107    int new_pixels;
108    if (!PyArg_ParseTuple(args, "i", &new_pixels))
109        return NULL;
110    self->params.n_pixels = new_pixels;
111
112    return Py_BuildValue("i", self->params.n_pixels);
113}
114
115static PyObject *get_n_rasters(CLoader *self, PyObject *args) {
116    return Py_BuildValue("i", self->params.n_rasters);
117}
118
119static PyObject *set_n_rasters(CLoader *self, PyObject *args) {
120    int new_rasters;
121    if (!PyArg_ParseTuple(args, "i", &new_rasters))
122        return NULL;
123    self->params.n_rasters = new_rasters;
124
125    return Py_BuildValue("i", self->params.n_rasters);
126}
127
128static PyObject *get_swap_bytes(CLoader *self, PyObject *args) {
129    return Py_BuildValue("i", self->params.swap_bytes);
130}
131
132static PyObject *set_swap_bytes(CLoader *self, PyObject *args) {
133    int new_swap;
134    if (!PyArg_ParseTuple(args, "i", &new_swap))
135        return NULL;
136    self->params.swap_bytes = new_swap;
137
138    return Py_BuildValue("i", self->params.swap_bytes);
139}
140
141/*                        ----- Instance Methods -----                       */
142
143float reverse_float(const float in_float) {
144    // Reverse the order of the bytes of a float
145    float retval;
146    char *to_convert = (char *)&in_float;
147    char *return_float = (char *)&retval;
148
149    return_float[0] = to_convert[3];
150    return_float[1] = to_convert[2];
151    return_float[2] = to_convert[1];
152    return_float[3] = to_convert[0];
153
154    return retval;
155}
156
157static PyObject *load_data(CLoader *self, PyObject *args) {
158    int raster;
159    int pixel;
160    int frame_pos;
161    npy_intp size[2] = {self->params.n_rasters, self->params.n_pixels};
162    float cur_val;
163    FILE *input_file;
164    PyArrayObject *data;
165
166    // Create a new numpy array to store the data in
167    data = (PyArrayObject *)PyArray_SimpleNew(2, size, NPY_FLOAT);
168
169    // Attempt to open the file specified
170    input_file = fopen(self->params.filename, "rb");
171    if (!input_file) {
172        // BSL filenames are 10 characters long
173        // Filename validity checked in bsl_loader.py
174        size_t filename_start = strlen(self->params.filename) - 10;
175        char *filename = self->params.filename + filename_start;
176        char *err_msg = (char *)malloc(sizeof(char) * 32);
177
178        sprintf(err_msg, "Unable to open file: %s", filename);
179
180        PyErr_SetString(PyExc_RuntimeError, err_msg);
181        free(err_msg);
182        return NULL;
183    }
184
185    // Move the file cursor the the position where the data we're interested
186    // in begins
187    frame_pos = self->params.n_pixels * self->params.n_rasters * self->params.frame;
188    fseek(input_file, frame_pos*sizeof(float), SEEK_SET);
189
190    for (raster = 0; raster < self->params.n_rasters; raster++) {
191        for (pixel = 0; pixel < self->params.n_pixels; pixel++) {
192            // Try reading the file
193            if (fread(&cur_val, sizeof(float), 1, input_file) == 0) {
194                PyErr_SetString(PyExc_RuntimeError, "Error reading file or EOF reached.");
195                return NULL;
196            }
197
198            // Swap the order of the bytes read, if specified that we should do
199            // so in the header file
200            if (self->params.swap_bytes == 0)
201                cur_val = reverse_float(cur_val);
202
203            // Add the read value to the numpy array
204            PyArray_SETITEM(data, PyArray_GETPTR2(data, raster, pixel), PyFloat_FromDouble(cur_val));
205        }
206    }
207
208    fclose(input_file);
209
210    return Py_BuildValue("N", data);
211}
212
213/*                           ----- Class Registration -----                  */
214
215static PyMethodDef CLoader_methods[] = {
216    { "to_string", (PyCFunction)to_string, METH_VARARGS, "Print the objects params" },
217    { "get_filename", (PyCFunction)get_filename, METH_VARARGS, "Get the filename" },
218    { "set_filename", (PyCFunction)set_filename, METH_VARARGS, "Set the filename" },
219    { "get_n_frames", (PyCFunction)get_n_frames, METH_VARARGS, "Get n_frames" },
220    { "set_n_frames", (PyCFunction)set_n_frames, METH_VARARGS, "Set n_frames" },
221    { "get_frame", (PyCFunction)get_frame, METH_VARARGS, "Get the frame that will be loaded" },
222    { "set_frame", (PyCFunction)set_frame, METH_VARARGS, "Set the frame that will be loaded" },
223    { "get_n_pixels", (PyCFunction)get_n_pixels, METH_VARARGS, "Get n_pixels" },
224    { "set_n_pixels", (PyCFunction)set_n_pixels, METH_VARARGS, "Set n_pixels" },
225    { "get_n_rasters", (PyCFunction)get_n_rasters, METH_VARARGS, "Get n_rasters" },
226    { "set_n_rasters", (PyCFunction)set_n_rasters, METH_VARARGS, "Set n_rasters" },
227    { "get_swap_bytes", (PyCFunction)get_swap_bytes, METH_VARARGS, "Get swap_bytes" },
228    { "set_swap_bytes", (PyCFunction)set_swap_bytes, METH_VARARGS, "Set swap_bytes" },
229    { "load_data", (PyCFunction)load_data, METH_VARARGS, "Load the data into a numpy array" },
230    {NULL}
231};
232
233static PyMemberDef CLoader_members[] = {
234    {NULL}
235};
236
237static PyTypeObject CLoaderType = {
238    PyObject_HEAD_INIT(NULL)
239    0,                         /*ob_size*/
240    "CLoader",             /*tp_name*/
241    sizeof(CLoader),             /*tp_basicsize*/
242    0,                         /*tp_itemsize*/
243    (destructor)CLoader_dealloc, /*tp_dealloc*/
244    0,                         /*tp_print*/
245    0,                         /*tp_getattr*/
246    0,                         /*tp_setattr*/
247    0,                         /*tp_compare*/
248    0,                         /*tp_repr*/
249    0,                         /*tp_as_number*/
250    0,                         /*tp_as_sequence*/
251    0,                         /*tp_as_mapping*/
252    0,                         /*tp_hash */
253    0,                         /*tp_call*/
254    0,                         /*tp_str*/
255    0,                         /*tp_getattro*/
256    0,                         /*tp_setattro*/
257    0,                         /*tp_as_buffer*/
258    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
259    "CLoader objects",           /* tp_doc */
260    0,                         /* tp_traverse */
261    0,                         /* tp_clear */
262    0,                         /* tp_richcompare */
263    0,                         /* tp_weaklistoffset */
264    0,                         /* tp_iter */
265    0,                         /* tp_iternext */
266    CLoader_methods,             /* tp_methods */
267    CLoader_members,             /* tp_members */
268    0,                         /* tp_getset */
269    0,                         /* tp_base */
270    0,                         /* tp_dict */
271    0,                         /* tp_descr_get */
272    0,                         /* tp_descr_set */
273    0,                         /* tp_dictoffset */
274    (initproc)CLoader_init,      /* tp_init */
275    0,                         /* tp_alloc */
276    CLoader_new,                 /* tp_new */
277};
278
279PyMODINIT_FUNC
280initbsl_loader(void)
281{
282    PyObject *module;
283    module = Py_InitModule("bsl_loader", NULL);
284    import_array();
285
286    if (PyType_Ready(&CLoaderType) < 0)
287        return;
288
289    Py_INCREF(&CLoaderType);
290    PyModule_AddObject(module, "CLoader", (PyObject *)&CLoaderType);
291}
Note: See TracBrowser for help on using the repository browser.