+ PyGILState_Release(gstate);
+
+ return SRD_ERR_PYTHON;
+}
+
+/* Convert annotation class attribute to GSList of char **. */
+static int get_annotations(struct srd_decoder *dec)
+{
+ PyObject *py_annlist, *py_ann;
+ GSList *annotations;
+ char **annpair;
+ ssize_t i;
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ if (!PyObject_HasAttrString(dec->py_dec, "annotations")) {
+ PyGILState_Release(gstate);
+ return SRD_OK;
+ }
+
+ annotations = NULL;
+
+ py_annlist = PyObject_GetAttrString(dec->py_dec, "annotations");
+ if (!py_annlist)
+ goto except_out;
+
+ if (!PyTuple_Check(py_annlist)) {
+ srd_err("Protocol decoder %s annotations should "
+ "be a tuple.", dec->name);
+ goto err_out;
+ }
+
+ for (i = PyTuple_Size(py_annlist) - 1; i >= 0; i--) {
+ py_ann = PyTuple_GetItem(py_annlist, i);
+ if (!py_ann)
+ goto except_out;
+
+ if (!PyTuple_Check(py_ann) || PyTuple_Size(py_ann) != 2) {
+ srd_err("Protocol decoder %s annotation %zd should "
+ "be a tuple with two elements.",
+ dec->name, i + 1);
+ goto err_out;
+ }
+ if (py_strseq_to_char(py_ann, &annpair) != SRD_OK)
+ goto err_out;
+
+ annotations = g_slist_prepend(annotations, annpair);
+ }
+ dec->annotations = annotations;
+ Py_DECREF(py_annlist);
+ PyGILState_Release(gstate);
+
+ return SRD_OK;
+
+except_out:
+ srd_exception_catch("Failed to get %s decoder annotations", dec->name);
+
+err_out:
+ g_slist_free_full(annotations, (GDestroyNotify)&g_strfreev);
+ Py_XDECREF(py_annlist);
+ PyGILState_Release(gstate);
+
+ return SRD_ERR_PYTHON;
+}
+
+/* Convert annotation_rows to GSList of 'struct srd_decoder_annotation_row'. */
+static int get_annotation_rows(struct srd_decoder *dec)
+{
+ PyObject *py_ann_rows, *py_ann_row, *py_ann_classes, *py_item;
+ GSList *annotation_rows;
+ struct srd_decoder_annotation_row *ann_row;
+ ssize_t i, k;
+ size_t class_idx;
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ if (!PyObject_HasAttrString(dec->py_dec, "annotation_rows")) {
+ PyGILState_Release(gstate);
+ return SRD_OK;
+ }
+
+ annotation_rows = NULL;
+
+ py_ann_rows = PyObject_GetAttrString(dec->py_dec, "annotation_rows");
+ if (!py_ann_rows)
+ goto except_out;
+
+ if (!PyTuple_Check(py_ann_rows)) {
+ srd_err("Protocol decoder %s annotation_rows "
+ "must be a tuple.", dec->name);
+ goto err_out;
+ }
+
+ for (i = PyTuple_Size(py_ann_rows) - 1; i >= 0; i--) {
+ py_ann_row = PyTuple_GetItem(py_ann_rows, i);
+ if (!py_ann_row)
+ goto except_out;
+
+ if (!PyTuple_Check(py_ann_row) || PyTuple_Size(py_ann_row) != 3) {
+ srd_err("Protocol decoder %s annotation_rows "
+ "must contain only tuples of 3 elements.",
+ dec->name);
+ goto err_out;
+ }
+ ann_row = g_malloc0(sizeof(struct srd_decoder_annotation_row));
+ /* Add to list right away so it doesn't get lost. */
+ annotation_rows = g_slist_prepend(annotation_rows, ann_row);
+
+ py_item = PyTuple_GetItem(py_ann_row, 0);
+ if (!py_item)
+ goto except_out;
+ if (py_str_as_str(py_item, &ann_row->id) != SRD_OK)
+ goto err_out;
+
+ py_item = PyTuple_GetItem(py_ann_row, 1);
+ if (!py_item)
+ goto except_out;
+ if (py_str_as_str(py_item, &ann_row->desc) != SRD_OK)
+ goto err_out;
+
+ py_ann_classes = PyTuple_GetItem(py_ann_row, 2);
+ if (!py_ann_classes)
+ goto except_out;
+
+ if (!PyTuple_Check(py_ann_classes)) {
+ srd_err("Protocol decoder %s annotation_rows tuples "
+ "must have a tuple of numbers as 3rd element.",
+ dec->name);
+ goto err_out;
+ }
+
+ for (k = PyTuple_Size(py_ann_classes) - 1; k >= 0; k--) {
+ py_item = PyTuple_GetItem(py_ann_classes, k);
+ if (!py_item)
+ goto except_out;
+
+ if (!PyLong_Check(py_item)) {
+ srd_err("Protocol decoder %s annotation row "
+ "class tuple must only contain numbers.",
+ dec->name);
+ goto err_out;
+ }
+ class_idx = PyLong_AsSize_t(py_item);
+ if (PyErr_Occurred())
+ goto except_out;
+
+ ann_row->ann_classes = g_slist_prepend(ann_row->ann_classes,
+ GSIZE_TO_POINTER(class_idx));
+ }
+ }
+ dec->annotation_rows = annotation_rows;
+ Py_DECREF(py_ann_rows);
+ PyGILState_Release(gstate);
+
+ return SRD_OK;
+
+except_out:
+ srd_exception_catch("Failed to get %s decoder annotation rows",
+ dec->name);
+
+err_out:
+ g_slist_free_full(annotation_rows, &annotation_row_free);
+ Py_XDECREF(py_ann_rows);
+ PyGILState_Release(gstate);
+
+ return SRD_ERR_PYTHON;
+}
+
+/* Convert binary classes to GSList of char **. */
+static int get_binary_classes(struct srd_decoder *dec)
+{
+ PyObject *py_bin_classes, *py_bin_class;
+ GSList *bin_classes;
+ char **bin;
+ ssize_t i;
+ PyGILState_STATE gstate;
+
+ gstate = PyGILState_Ensure();
+
+ if (!PyObject_HasAttrString(dec->py_dec, "binary")) {
+ PyGILState_Release(gstate);
+ return SRD_OK;
+ }
+
+ bin_classes = NULL;
+
+ py_bin_classes = PyObject_GetAttrString(dec->py_dec, "binary");
+ if (!py_bin_classes)
+ goto except_out;
+
+ if (!PyTuple_Check(py_bin_classes)) {
+ srd_err("Protocol decoder %s binary classes should "
+ "be a tuple.", dec->name);
+ goto err_out;
+ }
+
+ for (i = PyTuple_Size(py_bin_classes) - 1; i >= 0; i--) {
+ py_bin_class = PyTuple_GetItem(py_bin_classes, i);
+ if (!py_bin_class)
+ goto except_out;
+
+ if (!PyTuple_Check(py_bin_class)
+ || PyTuple_Size(py_bin_class) != 2) {
+ srd_err("Protocol decoder %s binary classes should "
+ "consist only of tuples of 2 elements.",
+ dec->name);
+ goto err_out;
+ }
+ if (py_strseq_to_char(py_bin_class, &bin) != SRD_OK)
+ goto err_out;
+
+ bin_classes = g_slist_prepend(bin_classes, bin);
+ }
+ dec->binary = bin_classes;
+ Py_DECREF(py_bin_classes);
+ PyGILState_Release(gstate);
+
+ return SRD_OK;
+
+except_out:
+ srd_exception_catch("Failed to get %s decoder binary classes",
+ dec->name);