+#include <FLAC/metadata.h>
+
+#include <Python.h>
+
+static PyObject *flac_error;
+
+static PyObject *
+flac_pictures(char *fn)
+{
+ FLAC__Metadata_Chain *chain;
+ FLAC__Metadata_Iterator *iterator;
+ FLAC__StreamMetadata *block;
+ PyObject *description, *tuple, *list;
+
+ chain = FLAC__metadata_chain_new();
+ if (chain == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ if(!FLAC__metadata_chain_read(chain, fn)) {
+ PyObject *s = PyString_FromFormat("metadata_chain_read (%d)",
+ FLAC__metadata_chain_status(chain));
+ if (s != NULL) {
+ PyErr_SetObject(flac_error, s);
+ }
+ return NULL;
+ }
+
+ iterator = FLAC__metadata_iterator_new();
+ if (iterator == NULL) {
+ return PyErr_NoMemory();
+ }
+
+ FLAC__metadata_iterator_init(iterator, chain);
+
+ list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ do {
+ /* This can fail, but the documentation doesn't say how, why,
+ * or how to react. metaflac/operations.c just prints a
+ * useless error message and keeps going. */
+ block = FLAC__metadata_iterator_get_block(iterator);
+ if (block == NULL) {
+ PyErr_SetString(flac_error,
+ "metadata_iterator_get_block returned NULL");
+ return NULL;
+ }
+
+ if (block->type != FLAC__METADATA_TYPE_PICTURE) {
+ continue;
+ }
+
+ description = PyUnicode_DecodeUTF8(
+ (const char *)block->data.picture.description,
+ strlen((const char *)block->data.picture.description),
+ "strict");
+ if (description == NULL) {
+ return NULL;
+ }
+
+ tuple = Py_BuildValue("(isOiiiis#)",
+ block->data.picture.type,
+ block->data.picture.mime_type,
+ description,
+ block->data.picture.width,
+ block->data.picture.height,
+ block->data.picture.depth,
+ block->data.picture.colors,
+ block->data.picture.data,
+ block->data.picture.data_length);
+ if (tuple == NULL) {
+ return NULL;
+ }
+
+ if (PyList_Append(list, tuple) == -1) {
+ return NULL;
+ }
+ } while(FLAC__metadata_iterator_next(iterator));
+
+ FLAC__metadata_iterator_delete(iterator);
+ FLAC__metadata_chain_delete(chain);
+
+ return list;
+}
+
+static PyObject *
+get_pictures(PyObject *self, PyObject *args)
+{
+ char *fn;
+
+ if (!PyArg_ParseTuple(args, "s", &fn)) {
+ return NULL;
+ }
+
+ return flac_pictures(fn);
+}
+
+static
+PyMethodDef methods[] = {
+ {"get_pictures", get_pictures, METH_VARARGS,
+ "document me"},
+
+ {NULL, NULL, 0, NULL}
+};
+
+static void
+export_constants(PyObject *m)
+{
+ PyObject *n;
+
+#define foo(x) \
+ n = PyInt_FromLong(FLAC__STREAM_METADATA_ ## x); \
+ if (n == NULL || PyModule_AddObject(m, #x, n) == -1) return;
+
+ foo(PICTURE_TYPE_OTHER);
+ foo(PICTURE_TYPE_FILE_ICON_STANDARD);
+ foo(PICTURE_TYPE_FILE_ICON);
+ foo(PICTURE_TYPE_FRONT_COVER);
+ foo(PICTURE_TYPE_BACK_COVER);
+ foo(PICTURE_TYPE_LEAFLET_PAGE);
+ foo(PICTURE_TYPE_MEDIA);
+ foo(PICTURE_TYPE_LEAD_ARTIST);
+ foo(PICTURE_TYPE_ARTIST);
+ foo(PICTURE_TYPE_CONDUCTOR);
+ foo(PICTURE_TYPE_BAND);
+ foo(PICTURE_TYPE_COMPOSER);
+ foo(PICTURE_TYPE_LYRICIST);
+ foo(PICTURE_TYPE_RECORDING_LOCATION);
+ foo(PICTURE_TYPE_DURING_RECORDING);
+ foo(PICTURE_TYPE_DURING_PERFORMANCE);
+ foo(PICTURE_TYPE_VIDEO_SCREEN_CAPTURE);
+ foo(PICTURE_TYPE_FISH);
+ foo(PICTURE_TYPE_ILLUSTRATION);
+ foo(PICTURE_TYPE_BAND_LOGOTYPE);
+ foo(PICTURE_TYPE_PUBLISHER_LOGOTYPE);
+ foo(PICTURE_TYPE_UNDEFINED);
+
+#undef foo
+}
+
+PyMODINIT_FUNC
+initflac(void)
+{
+ PyObject *m = Py_InitModule("flac", methods);
+ if (m == NULL) {
+ return;
+ }
+
+ flac_error = PyErr_NewException("flac_archive.flac.error", NULL, NULL);
+ if (flac_error == NULL) {
+ return;
+ }
+ PyModule_AddObject(m, "error", flac_error);
+
+ export_constants(m);
+}