Pillow/src/map.c

390 lines
9.9 KiB
C
Raw Normal View History

2010-07-31 06:52:47 +04:00
/*
* 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"
/* compatibility wrappers (defined in _imaging.c) */
extern int PyImaging_CheckBuffer(PyObject* buffer);
extern int PyImaging_GetBuffer(PyObject* buffer, Py_buffer *view);
2010-07-31 06:52:47 +04:00
/* -------------------------------------------------------------------- */
/* Standard mapper */
typedef struct {
PyObject_HEAD
char* base;
int size;
int offset;
#ifdef _WIN32
2010-07-31 06:52:47 +04:00
HANDLE hFile;
HANDLE hMap;
#endif
} ImagingMapperObject;
static PyTypeObject ImagingMapperType;
2010-07-31 06:52:47 +04:00
ImagingMapperObject*
PyImaging_MapperNew(const char* filename, int readonly)
{
ImagingMapperObject *mapper;
if (PyType_Ready(&ImagingMapperType) < 0)
return NULL;
2010-07-31 06:52:47 +04:00
mapper = PyObject_New(ImagingMapperObject, &ImagingMapperType);
if (mapper == NULL)
return NULL;
2010-07-31 06:52:47 +04:00
mapper->base = NULL;
mapper->size = mapper->offset = 0;
#ifdef _WIN32
2010-07-31 06:52:47 +04:00
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_OSError, "cannot open file");
Py_DECREF(mapper);
2010-07-31 06:52:47 +04:00
return NULL;
}
mapper->hMap = CreateFileMapping(
mapper->hFile, NULL,
PAGE_READONLY,
0, 0, NULL);
if (mapper->hMap == (HANDLE)-1) {
CloseHandle(mapper->hFile);
PyErr_SetString(PyExc_OSError, "cannot map file");
Py_DECREF(mapper);
2010-07-31 06:52:47 +04:00
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
2010-07-31 06:52:47 +04:00
if (mapper->base != 0)
UnmapViewOfFile(mapper->base);
2010-07-31 06:52:47 +04:00
if (mapper->hMap != (HANDLE)-1)
CloseHandle(mapper->hMap);
2010-07-31 06:52:47 +04:00
if (mapper->hFile != (HANDLE)-1)
CloseHandle(mapper->hFile);
2010-07-31 06:52:47 +04:00
mapper->base = 0;
mapper->hMap = mapper->hFile = (HANDLE)-1;
#endif
PyObject_Del(mapper);
}
/* -------------------------------------------------------------------- */
/* standard file operations */
static PyObject*
2010-07-31 06:52:47 +04:00
mapping_read(ImagingMapperObject* mapper, PyObject* args)
{
PyObject* buf;
int size = -1;
if (!PyArg_ParseTuple(args, "|i", &size))
return NULL;
2010-07-31 06:52:47 +04:00
/* 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);
2010-07-31 06:52:47 +04:00
if (!buf)
return NULL;
2010-07-31 06:52:47 +04:00
if (size > 0) {
memcpy(PyBytes_AsString(buf), mapper->base + mapper->offset, size);
2010-07-31 06:52:47 +04:00
mapper->offset += size;
}
return buf;
}
static PyObject*
2010-07-31 06:52:47 +04:00
mapping_seek(ImagingMapperObject* mapper, PyObject* args)
{
int offset;
int whence = 0;
if (!PyArg_ParseTuple(args, "i|i", &offset, &whence))
return NULL;
2010-07-31 06:52:47 +04:00
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*
2010-07-31 06:52:47 +04:00
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;
2010-07-31 06:52:47 +04:00
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_OSError, "image file truncated");
2010-07-31 06:52:47 +04:00
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;
2010-07-31 06:52:47 +04:00
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*/
2010-07-31 06:52:47 +04:00
};
PyObject*
2010-07-31 06:52:47 +04:00
PyImaging_Mapper(PyObject* self, PyObject* args)
{
char* filename;
if (!PyArg_ParseTuple(args, "s", &filename))
return NULL;
2010-07-31 06:52:47 +04:00
return (PyObject*) PyImaging_MapperNew(filename, 1);
}
/* -------------------------------------------------------------------- */
/* Buffer mapper */
typedef struct ImagingBufferInstance {
struct ImagingMemoryInstance im;
PyObject* target;
Py_buffer view;
2010-07-31 06:52:47 +04:00
} ImagingBufferInstance;
static void
mapping_destroy_buffer(Imaging im)
{
ImagingBufferInstance* buffer = (ImagingBufferInstance*) im;
PyBuffer_Release(&buffer->view);
2010-07-31 06:52:47 +04:00
Py_XDECREF(buffer->target);
}
PyObject*
2010-07-31 06:52:47 +04:00
PyImaging_MapBuffer(PyObject* self, PyObject* args)
{
2013-12-14 03:13:19 +04:00
Py_ssize_t y, size;
2010-07-31 06:52:47 +04:00
Imaging im;
PyObject* target;
Py_buffer view;
2010-07-31 06:52:47 +04:00
char* mode;
char* codec;
2013-12-14 03:13:19 +04:00
Py_ssize_t offset;
2010-07-31 06:52:47 +04:00
int xsize, ysize;
int stride;
int ystep;
2020-01-25 14:37:26 +03:00
if (!PyArg_ParseTuple(args, "O(ii)sn(sii)", &target, &xsize, &ysize,
&codec, &offset, &mode, &stride, &ystep))
return NULL;
2010-07-31 06:52:47 +04:00
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) {
2016-09-29 17:05:00 +03:00
PyErr_SetString(PyExc_MemoryError, "Integer overflow in ysize");
return NULL;
}
2013-12-14 03:13:19 +04:00
size = (Py_ssize_t) ysize * stride;
2016-09-29 17:05:00 +03:00
if (offset > PY_SSIZE_T_MAX - size) {
2016-09-29 17:05:00 +03:00
PyErr_SetString(PyExc_MemoryError, "Integer overflow in offset");
return NULL;
2017-02-22 09:28:20 +03:00
}
2010-07-31 06:52:47 +04:00
/* check buffer size */
if (PyImaging_GetBuffer(target, &view) < 0)
return NULL;
if (view.len < 0) {
2010-07-31 06:52:47 +04:00
PyErr_SetString(PyExc_ValueError, "buffer has negative size");
PyBuffer_Release(&view);
2010-07-31 06:52:47 +04:00
return NULL;
}
if (offset + size > view.len) {
2010-07-31 06:52:47 +04:00
PyErr_SetString(PyExc_ValueError, "buffer is not large enough");
PyBuffer_Release(&view);
2010-07-31 06:52:47 +04:00
return NULL;
}
im = ImagingNewPrologueSubtype(
mode, xsize, ysize, sizeof(ImagingBufferInstance));
if (!im) {
PyBuffer_Release(&view);
2010-07-31 06:52:47 +04:00
return NULL;
}
2010-07-31 06:52:47 +04:00
/* setup file pointers */
if (ystep > 0)
for (y = 0; y < ysize; y++)
im->image[y] = (char*)view.buf + offset + y * stride;
2010-07-31 06:52:47 +04:00
else
for (y = 0; y < ysize; y++)
im->image[ysize-y-1] = (char*)view.buf + offset + y * stride;
2010-07-31 06:52:47 +04:00
im->destroy = mapping_destroy_buffer;
Py_INCREF(target);
((ImagingBufferInstance*) im)->target = target;
((ImagingBufferInstance*) im)->view = view;
2010-07-31 06:52:47 +04:00
return PyImagingNew(im);
}