123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- /*
- * The Python Imaging Library.
- *
- * standard memory mapping interface for the Imaging library
- *
- * history:
- * 1998-03-05 fl added Win32 read mapping
- * 1999-02-06 fl added "I;16" support
- * 2003-04-21 fl added PyImaging_MapBuffer primitive
- *
- * Copyright (c) 1998-2003 by Secret Labs AB.
- * Copyright (c) 2003 by Fredrik Lundh.
- *
- * See the README file for information on usage and redistribution.
- */
- /*
- * FIXME: should move the memory mapping primitives into libImaging!
- */
- #include "Python.h"
- #include "Imaging.h"
- #include "py3.h"
- /* compatibility wrappers (defined in _imaging.c) */
- extern int PyImaging_CheckBuffer(PyObject* buffer);
- extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
- /* -------------------------------------------------------------------- */
- /* Standard mapper */
- typedef struct {
- PyObject_HEAD
- char* base;
- int size;
- int offset;
- #ifdef _WIN32
- HANDLE hFile;
- HANDLE hMap;
- #endif
- } ImagingMapperObject;
- static PyTypeObject ImagingMapperType;
- ImagingMapperObject*
- PyImaging_MapperNew(const char* filename, int readonly)
- {
- ImagingMapperObject *mapper;
- if (PyType_Ready(&ImagingMapperType) < 0)
- return NULL;
- mapper = PyObject_New(ImagingMapperObject, &ImagingMapperType);
- if (mapper == NULL)
- return NULL;
- mapper->base = NULL;
- mapper->size = mapper->offset = 0;
- #ifdef _WIN32
- mapper->hFile = (HANDLE)-1;
- mapper->hMap = (HANDLE)-1;
- /* FIXME: currently supports readonly mappings only */
- mapper->hFile = CreateFile(
- filename,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (mapper->hFile == (HANDLE)-1) {
- PyErr_SetString(PyExc_IOError, "cannot open file");
- Py_DECREF(mapper);
- return NULL;
- }
- mapper->hMap = CreateFileMapping(
- mapper->hFile, NULL,
- PAGE_READONLY,
- 0, 0, NULL);
- if (mapper->hMap == (HANDLE)-1) {
- CloseHandle(mapper->hFile);
- PyErr_SetString(PyExc_IOError, "cannot map file");
- Py_DECREF(mapper);
- return NULL;
- }
- mapper->base = (char*) MapViewOfFile(
- mapper->hMap,
- FILE_MAP_READ,
- 0, 0, 0);
- mapper->size = GetFileSize(mapper->hFile, 0);
- #endif
- return mapper;
- }
- static void
- mapping_dealloc(ImagingMapperObject* mapper)
- {
- #ifdef _WIN32
- if (mapper->base != 0)
- UnmapViewOfFile(mapper->base);
- if (mapper->hMap != (HANDLE)-1)
- CloseHandle(mapper->hMap);
- if (mapper->hFile != (HANDLE)-1)
- CloseHandle(mapper->hFile);
- mapper->base = 0;
- mapper->hMap = mapper->hFile = (HANDLE)-1;
- #endif
- PyObject_Del(mapper);
- }
- /* -------------------------------------------------------------------- */
- /* standard file operations */
- static PyObject*
- mapping_read(ImagingMapperObject* mapper, PyObject* args)
- {
- PyObject* buf;
- int size = -1;
- if (!PyArg_ParseTuple(args, "|i", &size))
- return NULL;
- /* check size */
- if (size < 0 || mapper->offset + size > mapper->size)
- size = mapper->size - mapper->offset;
- if (size < 0)
- size = 0;
- buf = PyBytes_FromStringAndSize(NULL, size);
- if (!buf)
- return NULL;
- if (size > 0) {
- memcpy(PyBytes_AsString(buf), mapper->base + mapper->offset, size);
- mapper->offset += size;
- }
- return buf;
- }
- static PyObject*
- mapping_seek(ImagingMapperObject* mapper, PyObject* args)
- {
- int offset;
- int whence = 0;
- if (!PyArg_ParseTuple(args, "i|i", &offset, &whence))
- return NULL;
- switch (whence) {
- case 0: /* SEEK_SET */
- mapper->offset = offset;
- break;
- case 1: /* SEEK_CUR */
- mapper->offset += offset;
- break;
- case 2: /* SEEK_END */
- mapper->offset = mapper->size + offset;
- break;
- default:
- /* FIXME: raise ValueError? */
- break;
- }
- Py_INCREF(Py_None);
- return Py_None;
- }
- /* -------------------------------------------------------------------- */
- /* map entire image */
- extern PyObject*PyImagingNew(Imaging im);
- static void
- ImagingDestroyMap(Imaging im)
- {
- return; /* nothing to do! */
- }
- static PyObject*
- mapping_readimage(ImagingMapperObject* mapper, PyObject* args)
- {
- int y, size;
- Imaging im;
- char* mode;
- int xsize;
- int ysize;
- int stride;
- int orientation;
- if (!PyArg_ParseTuple(args, "s(ii)ii", &mode, &xsize, &ysize,
- &stride, &orientation))
- return NULL;
- if (stride <= 0) {
- /* FIXME: maybe we should call ImagingNewPrologue instead */
- if (!strcmp(mode, "L") || !strcmp(mode, "P"))
- stride = xsize;
- else if (!strcmp(mode, "I;16") || !strcmp(mode, "I;16B"))
- stride = xsize * 2;
- else
- stride = xsize * 4;
- }
- size = ysize * stride;
- if (mapper->offset + size > mapper->size) {
- PyErr_SetString(PyExc_IOError, "image file truncated");
- return NULL;
- }
- im = ImagingNewPrologue(mode, xsize, ysize);
- if (!im)
- return NULL;
- /* setup file pointers */
- if (orientation > 0)
- for (y = 0; y < ysize; y++)
- im->image[y] = mapper->base + mapper->offset + y * stride;
- else
- for (y = 0; y < ysize; y++)
- im->image[ysize-y-1] = mapper->base + mapper->offset + y * stride;
- im->destroy = ImagingDestroyMap;
- mapper->offset += size;
- return PyImagingNew(im);
- }
- static struct PyMethodDef methods[] = {
- /* standard file interface */
- {"read", (PyCFunction)mapping_read, 1},
- {"seek", (PyCFunction)mapping_seek, 1},
- /* extensions */
- {"readimage", (PyCFunction)mapping_readimage, 1},
- {NULL, NULL} /* sentinel */
- };
- static PyTypeObject ImagingMapperType = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "ImagingMapper", /*tp_name*/
- sizeof(ImagingMapperObject), /*tp_size*/
- 0, /*tp_itemsize*/
- /* methods */
- (destructor)mapping_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, /*tp_flags*/
- 0, /*tp_doc*/
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- methods, /*tp_methods*/
- 0, /*tp_members*/
- 0, /*tp_getset*/
- };
- PyObject*
- PyImaging_Mapper(PyObject* self, PyObject* args)
- {
- char* filename;
- if (!PyArg_ParseTuple(args, "s", &filename))
- return NULL;
- return (PyObject*) PyImaging_MapperNew(filename, 1);
- }
- /* -------------------------------------------------------------------- */
- /* Buffer mapper */
- typedef struct ImagingBufferInstance {
- struct ImagingMemoryInstance im;
- PyObject* target;
- Py_buffer view;
- } ImagingBufferInstance;
- static void
- mapping_destroy_buffer(Imaging im)
- {
- ImagingBufferInstance* buffer = (ImagingBufferInstance*) im;
- PyBuffer_Release(&buffer->view);
- Py_XDECREF(buffer->target);
- }
- PyObject*
- PyImaging_MapBuffer(PyObject* self, PyObject* args)
- {
- Py_ssize_t y, size;
- Imaging im;
- PyObject* target;
- Py_buffer view;
- char* mode;
- char* codec;
- PyObject* bbox;
- Py_ssize_t offset;
- int xsize, ysize;
- int stride;
- int ystep;
- if (!PyArg_ParseTuple(args, "O(ii)sOn(sii)", &target, &xsize, &ysize,
- &codec, &bbox, &offset, &mode, &stride, &ystep))
- return NULL;
- if (!PyImaging_CheckBuffer(target)) {
- PyErr_SetString(PyExc_TypeError, "expected string or buffer");
- return NULL;
- }
- if (stride <= 0) {
- if (!strcmp(mode, "L") || !strcmp(mode, "P"))
- stride = xsize;
- else if (!strncmp(mode, "I;16", 4))
- stride = xsize * 2;
- else
- stride = xsize * 4;
- }
- if (stride > 0 && ysize > PY_SSIZE_T_MAX / stride) {
- PyErr_SetString(PyExc_MemoryError, "Integer overflow in ysize");
- return NULL;
- }
- size = (Py_ssize_t) ysize * stride;
- if (offset > PY_SSIZE_T_MAX - size) {
- PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset");
- return NULL;
- }
- /* check buffer size */
- if (PyImaging_GetBuffer(target, &view) < 0)
- return NULL;
- if (view.len < 0) {
- PyErr_SetString(PyExc_ValueError, "buffer has negative size");
- return NULL;
- }
- if (offset + size > view.len) {
- PyErr_SetString(PyExc_ValueError, "buffer is not large enough");
- return NULL;
- }
- im = ImagingNewPrologueSubtype(
- mode, xsize, ysize, sizeof(ImagingBufferInstance));
- if (!im)
- return NULL;
- /* setup file pointers */
- if (ystep > 0)
- for (y = 0; y < ysize; y++)
- im->image[y] = (char*)view.buf + offset + y * stride;
- else
- for (y = 0; y < ysize; y++)
- im->image[ysize-y-1] = (char*)view.buf + offset + y * stride;
- im->destroy = mapping_destroy_buffer;
- Py_INCREF(target);
- ((ImagingBufferInstance*) im)->target = target;
- ((ImagingBufferInstance*) im)->view = view;
- return PyImagingNew(im);
- }
|