Index: src/sas/sascalc/dataloader/readers/cansas_reader.py
===================================================================
--- src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision 83b6408fbfaefa4819b955c697fef834d8f033f6)
+++ src/sas/sascalc/dataloader/readers/cansas_reader.py	(revision 83b6408fbfaefa4819b955c697fef834d8f033f6)
@@ -957,9 +957,9 @@
             written = written | self.write_node(pix, "z", item.pixel_size.z,
                                                 {"unit": item.pixel_size_unit})
-            written = written | self.write_node(det, "slit_length",
-                                                item.slit_length,
-                                                {"unit": item.slit_length_unit})
             if written == True:
                 self.append(pix, det)
+            self.write_node(det, "slit_length", item.slit_length,
+                {"unit": item.slit_length_unit})
+
 
     def _write_process_notes(self, datainfo, entry_node):
Index: src/sas/sascalc/file_converter/bsl_loader.py
===================================================================
--- src/sas/sascalc/file_converter/bsl_loader.py	(revision 535e18165fb7319948e27d8876a389fd5c738129)
+++ src/sas/sascalc/file_converter/bsl_loader.py	(revision 535e18165fb7319948e27d8876a389fd5c738129)
@@ -0,0 +1,89 @@
+from sas.sascalc.file_converter.core.bsl_loader import CLoader
+from copy import deepcopy
+import os
+import numpy as np
+
+class BSLLoader(CLoader):
+
+    # TODO: Change to __init__(self, filename, frame)
+    # and parse n_(pixels/rasters) from header file
+    def __init__(self, filename):
+        header_file = open(filename, 'r')
+        data_info = {}
+        is_valid = True
+        err_msg = ""
+
+        [folder, filename] = os.path.split(filename)
+
+        # First 2 lines are headers
+        header_file.readline()
+        header_file.readline()
+
+        while True:
+            metadata = header_file.readline().strip()
+            metadata = metadata.split()
+            data_filename = header_file.readline().strip()
+
+            if len(metadata) != 10:
+                is_valid = False
+                err_msg = "Invalid header file: {}".format(filename)
+                break
+            # SAS data will be in file Xnn001.mdd
+            if data_filename != filename.replace('0.', '1.'):
+                continue
+            try:
+                data_info = {
+                    'filename': os.path.join(folder, data_filename),
+                    'pixels': int(metadata[0]),
+                    'rasters': int(metadata[1]),
+                    'frames': int(metadata[2]),
+                    'swap_bytes': int(metadata[3])
+                }
+            except:
+                is_valid = False
+                err_msg = "Invalid metadata in header file for {}"
+                err_msg = err_msg.format(filename.replace('0.', '1.'))
+            break
+
+        if not is_valid:
+            raise Exception(err_msg)
+
+        if data_info['frames'] == 1:
+            # File is actually in OTOKO (1D) format
+            # Number of frames is 2nd indicator,
+            data_info['frames'] = data_info['rasters']
+            data_info['rasters'] = data_info['pixels']
+            data_info['pixels'] = 1
+
+        CLoader.__init__(self, data_info['filename'], data_info['frames'],
+            data_info['pixels'], data_info['rasters'], data_info['swap_bytes'])
+
+    def __setattr__(self, name, value):
+        if name == 'filename':
+            return self.set_filename(value)
+        elif name == 'n_frames':
+            return self.set_n_frames(value)
+        elif name == 'frame':
+            return self.set_frame(value)
+        elif name == 'n_pixels':
+            return self.set_n_pixels(value)
+        elif name == 'n_rasters':
+            return self.set_n_rasters(value)
+        elif name == 'swap_bytes':
+            return self.set_swap_bytes(value)
+        return CLoader.__setattr__(self, name, value)
+
+    def __getattr__(self, name):
+        if name == 'filename':
+            return self.get_filename()
+        elif name == 'n_frames':
+            return self.get_n_frames()
+        elif name == 'frame':
+            return self.get_frame()
+        elif name == 'n_pixels':
+            return self.get_n_pixels()
+        elif name == 'n_rasters':
+            return self.get_n_rasters()
+        elif name == 'swap_bytes':
+            return self.get_swap_bytes()
+        return CLoader.__getattr__(self, name)
Index: src/sas/sascalc/file_converter/c_ext/bsl_loader.c
===================================================================
--- src/sas/sascalc/file_converter/c_ext/bsl_loader.c	(revision e070dc06aecd05816942b4f2152bb4008616e3c8)
+++ src/sas/sascalc/file_converter/c_ext/bsl_loader.c	(revision e070dc06aecd05816942b4f2152bb4008616e3c8)
@@ -0,0 +1,281 @@
+#include <Python.h>
+#include <numpy/arrayobject.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "structmember.h"
+#include "bsl_loader.h"
+
+typedef struct {
+    PyObject_HEAD
+    CLoader_params params;
+} CLoader;
+
+static PyObject *CLoader_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
+    CLoader *self;
+
+    self = (CLoader *)type->tp_alloc(type, 0);
+
+    return (PyObject *)self;
+}
+
+static PyObject *CLoader_init(CLoader *self, PyObject *args, PyObject *kwds) {
+    const char *filename;
+    const int n_frames;
+    const int n_pixels;
+    const int n_rasters;
+    const int swap_bytes;
+
+    if (self != NULL) {
+        if (!PyArg_ParseTuple(args, "siiii", &filename, &n_frames, &n_pixels, &n_rasters, &swap_bytes))
+            Py_RETURN_NONE;
+        if (!(self->params.filename = malloc(strlen(filename) + 1)))
+            Py_RETURN_NONE;
+        strcpy(self->params.filename, filename);
+        self->params.n_frames = n_frames;
+        self->params.n_pixels = n_pixels;
+        self->params.n_rasters = n_rasters;
+        self->params.swap_bytes = swap_bytes;
+    }
+
+    return 0;
+}
+
+static void CLoader_dealloc(CLoader *self) {
+    free(self->params.filename);
+    self->ob_type->tp_free((PyObject *)self);
+}
+
+static PyObject *to_string(CLoader *self, PyObject *params) {
+    char str[100];
+    sprintf(str,
+        "Filename: %s\nn_frames: %d\nframe: %d\nn_pixels: %d\nn_rasters: %d\nswap_bytes: %d",
+        self->params.filename,
+        self->params.n_frames,
+        self->params.frame,
+        self->params.n_pixels,
+        self->params.n_rasters,
+        self->params.swap_bytes);
+    return Py_BuildValue("s", str);
+}
+
+/*                    ----- Setters and Getters -----                        */
+
+static PyObject *get_filename(CLoader *self, PyObject *args) {
+    return Py_BuildValue("s", self->params.filename);
+}
+
+static PyObject *set_filename(CLoader *self, PyObject *args) {
+    const char *new_filename;
+    if (!PyArg_ParseTuple(args, "s", &new_filename))
+        return NULL;
+    strcpy(self->params.filename, new_filename);
+
+    return Py_BuildValue("s", self->params.filename);
+}
+
+static PyObject *get_n_frames(CLoader *self, PyObject *args) {
+    return Py_BuildValue("i", self->params.n_frames);
+}
+
+static PyObject *set_n_frames(CLoader *self, PyObject *args) {
+    int new_frames;
+    if (!PyArg_ParseTuple(args, "i", &new_frames))
+        return NULL;
+    self->params.n_frames = new_frames;
+
+    return Py_BuildValue("i", self->params.n_frames);
+}
+
+static PyObject *get_frame(CLoader *self, PyObject *args) {
+    return Py_BuildValue("i", self->params.frame);
+}
+
+static PyObject *set_frame(CLoader *self, PyObject *args) {
+    int new_frame;
+    if (!PyArg_ParseTuple(args, "i", &new_frame))
+        return NULL;
+    self->params.frame = new_frame;
+
+    return Py_BuildValue("i", self->params.frame);
+}
+
+static PyObject *get_n_pixels(CLoader *self, PyObject *args) {
+    return Py_BuildValue("i", self->params.n_pixels);
+}
+
+static PyObject *set_n_pixels(CLoader *self, PyObject *args) {
+    int new_pixels;
+    if (!PyArg_ParseTuple(args, "i", &new_pixels))
+        return NULL;
+    self->params.n_pixels = new_pixels;
+
+    return Py_BuildValue("i", self->params.n_pixels);
+}
+
+static PyObject *get_n_rasters(CLoader *self, PyObject *args) {
+    return Py_BuildValue("i", self->params.n_rasters);
+}
+
+static PyObject *set_n_rasters(CLoader *self, PyObject *args) {
+    int new_rasters;
+    if (!PyArg_ParseTuple(args, "i", &new_rasters))
+        return NULL;
+    self->params.n_rasters = new_rasters;
+
+    return Py_BuildValue("i", self->params.n_rasters);
+}
+
+static PyObject *get_swap_bytes(CLoader *self, PyObject *args) {
+    return Py_BuildValue("i", self->params.swap_bytes);
+}
+
+static PyObject *set_swap_bytes(CLoader *self, PyObject *args) {
+    int new_swap;
+    if (!PyArg_ParseTuple(args, "i", &new_swap))
+        return NULL;
+    self->params.swap_bytes = new_swap;
+
+    return Py_BuildValue("i", self->params.swap_bytes);
+}
+
+/*                        ----- Instance Methods -----                       */
+
+float reverse_float(const float in_float) {
+    // Reverse the order of the bytes of a float
+    float retval;
+    char *to_convert = (char *)&in_float;
+    char *return_float = (char *)&retval;
+
+    return_float[0] = to_convert[3];
+    return_float[1] = to_convert[2];
+    return_float[2] = to_convert[1];
+    return_float[3] = to_convert[0];
+
+    return retval;
+}
+
+static PyObject *load_data(CLoader *self, PyObject *args) {
+    int raster;
+    int pixel;
+    int frame_pos;
+    npy_intp size[2] = {self->params.n_rasters, self->params.n_pixels};
+    float cur_val;
+    FILE *input_file;
+    PyArrayObject *data;
+
+    // Create a new numpy array to store the data in
+    data = (PyArrayObject *)PyArray_SimpleNew(2, size, NPY_FLOAT);
+
+    // Attempt to open the file specified
+    input_file = fopen(self->params.filename, "rb");
+    if (!input_file) {
+        return NULL;
+    }
+
+    // Move the file cursor the the position where the data we're interested
+    // in begins
+    frame_pos = self->params.n_pixels * self->params.n_rasters * self->params.frame;
+    fseek(input_file, frame_pos*sizeof(float), SEEK_SET);
+
+    for (raster = 0; raster < self->params.n_rasters; raster++) {
+        for (pixel = 0; pixel < self->params.n_pixels; pixel++) {
+            // Try reading the file
+            if (fread(&cur_val, sizeof(float), 1, input_file) == 0) {
+                PyErr_SetString(PyExc_RuntimeError, "Error reading file or EOF reached.");
+                return NULL;
+            }
+
+            // Swap the order of the bytes read, if specified that we should do
+            // so in the header file
+            if (self->params.swap_bytes == 0)
+                cur_val = reverse_float(cur_val);
+
+            // Add the read value to the numpy array
+            PyArray_SETITEM(data, PyArray_GETPTR2(data, raster, pixel), PyFloat_FromDouble(cur_val));
+        }
+    }
+
+    fclose(input_file);
+
+    return Py_BuildValue("N", data);
+}
+
+/*                           ----- Class Registration -----                  */
+
+static PyMethodDef CLoader_methods[] = {
+    { "to_string", (PyCFunction)to_string, METH_VARARGS, "Print the objects params" },
+    { "get_filename", (PyCFunction)get_filename, METH_VARARGS, "Get the filename" },
+    { "set_filename", (PyCFunction)set_filename, METH_VARARGS, "Set the filename" },
+    { "get_n_frames", (PyCFunction)get_n_frames, METH_VARARGS, "Get n_frames" },
+    { "set_n_frames", (PyCFunction)set_n_frames, METH_VARARGS, "Set n_frames" },
+    { "get_frame", (PyCFunction)get_frame, METH_VARARGS, "Get the frame that will be loaded" },
+    { "set_frame", (PyCFunction)set_frame, METH_VARARGS, "Set the frame that will be loaded" },
+    { "get_n_pixels", (PyCFunction)get_n_pixels, METH_VARARGS, "Get n_pixels" },
+    { "set_n_pixels", (PyCFunction)set_n_pixels, METH_VARARGS, "Set n_pixels" },
+    { "get_n_rasters", (PyCFunction)get_n_rasters, METH_VARARGS, "Get n_rasters" },
+    { "set_n_rasters", (PyCFunction)set_n_rasters, METH_VARARGS, "Set n_rasters" },
+    { "get_swap_bytes", (PyCFunction)get_swap_bytes, METH_VARARGS, "Get swap_bytes" },
+    { "set_swap_bytes", (PyCFunction)set_swap_bytes, METH_VARARGS, "Set swap_bytes" },
+    { "load_data", (PyCFunction)load_data, METH_VARARGS, "Load the data into a numpy array" },
+    {NULL}
+};
+
+static PyMemberDef CLoader_members[] = {
+    {NULL}
+};
+
+static PyTypeObject CLoaderType = {
+    PyObject_HEAD_INIT(NULL)
+    0,                         /*ob_size*/
+    "CLoader",             /*tp_name*/
+    sizeof(CLoader),             /*tp_basicsize*/
+    0,                         /*tp_itemsize*/
+    (destructor)CLoader_dealloc, /*tp_dealloc*/
+    0,                         /*tp_print*/
+    0,                         /*tp_getattr*/
+    0,                         /*tp_setattr*/
+    0,                         /*tp_compare*/
+    0,                         /*tp_repr*/
+    0,                         /*tp_as_number*/
+    0,                         /*tp_as_sequence*/
+    0,                         /*tp_as_mapping*/
+    0,                         /*tp_hash */
+    0,                         /*tp_call*/
+    0,                         /*tp_str*/
+    0,                         /*tp_getattro*/
+    0,                         /*tp_setattro*/
+    0,                         /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
+    "CLoader objects",           /* tp_doc */
+    0,		               /* tp_traverse */
+    0,		               /* tp_clear */
+    0,		               /* tp_richcompare */
+    0,		               /* tp_weaklistoffset */
+    0,		               /* tp_iter */
+    0,		               /* tp_iternext */
+    CLoader_methods,             /* tp_methods */
+    CLoader_members,             /* tp_members */
+    0,                         /* tp_getset */
+    0,                         /* tp_base */
+    0,                         /* tp_dict */
+    0,                         /* tp_descr_get */
+    0,                         /* tp_descr_set */
+    0,                         /* tp_dictoffset */
+    (initproc)CLoader_init,      /* tp_init */
+    0,                         /* tp_alloc */
+    CLoader_new,                 /* tp_new */
+};
+
+PyMODINIT_FUNC
+initbsl_loader(void)
+{
+    PyObject *module;
+    module = Py_InitModule("bsl_loader", NULL);
+    import_array();
+
+    if (PyType_Ready(&CLoaderType) < 0)
+        return;
+
+    Py_INCREF(&CLoaderType);
+    PyModule_AddObject(module, "CLoader", (PyObject *)&CLoaderType);
+}
Index: src/sas/sascalc/file_converter/c_ext/bsl_loader.h
===================================================================
--- src/sas/sascalc/file_converter/c_ext/bsl_loader.h	(revision 535e18165fb7319948e27d8876a389fd5c738129)
+++ src/sas/sascalc/file_converter/c_ext/bsl_loader.h	(revision 535e18165fb7319948e27d8876a389fd5c738129)
@@ -0,0 +1,19 @@
+#ifndef bsl_loader_h
+#define bsl_loader_h
+
+typedef struct {
+    // File to load
+    char *filename;
+    // Number of frames in the file
+    int n_frames;
+    // Frame to load
+    int frame;
+    // Number of pixels in the file
+    int n_pixels;
+    // Number of rasters in the file
+    int n_rasters;
+    // Whether or not the bytes are in reverse order
+    int swap_bytes;
+} CLoader_params;
+
+#endif
