⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmapmodule.c

📁 python s60 1.4.5版本的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Portions Copyright (c) 2005 Nokia Corporation */
/*
 /  Author: Sam Rushing <rushing@nightmare.com>
 /  Hacked for Unix by AMK
 /  $Id: mmapmodule.c,v 1.1 2003/10/27 08:23:53 riva Exp $

 / mmapmodule.cpp -- map a view of a file into memory
 /
 / todo: need permission flags, perhaps a 'chsize' analog
 /   not all functions check range yet!!!
 /
 /
 / Note: This module currently only deals with 32-bit file
 /   sizes.
 /
 / This version of mmapmodule.c has been changed significantly
 / from the original mmapfile.c on which it was based.
 / The original version of mmapfile is maintained by Sam at
 / ftp://squirl.nightmare.com/pub/python/python-ext.
*/

#include <Python.h>

#ifndef MS_WIN32
#define UNIX
#endif

#ifdef MS_WIN32
#include <windows.h>
static int
my_getpagesize(void)
{
	SYSTEM_INFO si;
	GetSystemInfo(&si);
	return si.dwPageSize;
}
#endif

#ifdef UNIX
#include <sys/mman.h>
#include <sys/stat.h>

#ifndef MS_SYNC
/* This is missing e.g. on SunOS 4.1.4 */
#define MS_SYNC 0
#endif

#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
static int
my_getpagesize(void)
{
	return sysconf(_SC_PAGESIZE);
}
#else
#define my_getpagesize getpagesize
#endif

#endif /* UNIX */

#include <string.h>
#include <sys/types.h>

static PyObject *mmap_module_error;

typedef enum
{
	ACCESS_DEFAULT,
	ACCESS_READ,
	ACCESS_WRITE,
	ACCESS_COPY
} access_mode;

typedef struct {
	PyObject_HEAD
	char *	data;
	size_t	size;
	size_t	pos;

#ifdef MS_WIN32
	HANDLE	map_handle;
	HANDLE	file_handle;
	char *	tagname;
#endif

#ifdef UNIX
        int fd;
#endif

        access_mode access;
} mmap_object;


static void
mmap_object_dealloc(mmap_object *m_obj)
{
#ifdef MS_WIN32
	if (m_obj->data != NULL)
		UnmapViewOfFile (m_obj->data);
	if (m_obj->map_handle != INVALID_HANDLE_VALUE)
		CloseHandle (m_obj->map_handle);
	if (m_obj->file_handle != INVALID_HANDLE_VALUE)
		CloseHandle (m_obj->file_handle);
	if (m_obj->tagname)
		PyMem_Free(m_obj->tagname);
#endif /* MS_WIN32 */

#ifdef UNIX
	if (m_obj->data!=NULL) {
		msync(m_obj->data, m_obj->size, MS_SYNC);
		munmap(m_obj->data, m_obj->size);
	}
#endif /* UNIX */

	PyObject_Del(m_obj);
}

static PyObject *
mmap_close_method(mmap_object *self, PyObject *args)
{
        if (!PyArg_ParseTuple(args, ":close"))
		return NULL;
#ifdef MS_WIN32
	/* For each resource we maintain, we need to check
	   the value is valid, and if so, free the resource 
	   and set the member value to an invalid value so
	   the dealloc does not attempt to resource clearing
	   again.
	   TODO - should we check for errors in the close operations???
	*/
	if (self->data != NULL) {
		UnmapViewOfFile (self->data);
		self->data = NULL;
	}
	if (self->map_handle != INVALID_HANDLE_VALUE) {
		CloseHandle (self->map_handle);
		self->map_handle = INVALID_HANDLE_VALUE;
	}
	if (self->file_handle != INVALID_HANDLE_VALUE) {
		CloseHandle (self->file_handle);
		self->file_handle = INVALID_HANDLE_VALUE;
	}
#endif /* MS_WIN32 */

#ifdef UNIX
	munmap(self->data, self->size);
	self->data = NULL;
#endif

	Py_INCREF (Py_None);
	return (Py_None);
}

#ifdef MS_WIN32
#define CHECK_VALID(err)						\
do {									\
    if (!self->map_handle) {						\
	PyErr_SetString (PyExc_ValueError, "mmap closed or invalid");	\
	return err;							\
    }									\
} while (0)
#endif /* MS_WIN32 */

#ifdef UNIX
#define CHECK_VALID(err)						\
do {									\
    if (self->data == NULL) {						\
	PyErr_SetString (PyExc_ValueError, "mmap closed or invalid");	\
	return err;							\
	}								\
} while (0)
#endif /* UNIX */

static PyObject *
mmap_read_byte_method(mmap_object *self,
		      PyObject *args)
{
	CHECK_VALID(NULL);
        if (!PyArg_ParseTuple(args, ":read_byte"))
		return NULL;
	if (self->pos < self->size) {
	        char value = self->data[self->pos];
		self->pos += 1;
		return Py_BuildValue("c", value);
	} else {
		PyErr_SetString (PyExc_ValueError, "read byte out of range");
		return NULL;
	}
}

static PyObject *
mmap_read_line_method(mmap_object *self,
		      PyObject *args)
{
	char *start = self->data+self->pos;
	char *eof = self->data+self->size;
	char *eol;
	PyObject *result;

	CHECK_VALID(NULL);
        if (!PyArg_ParseTuple(args, ":readline"))
		return NULL;

	eol = memchr(start, '\n', self->size - self->pos);
	if (!eol)
		eol = eof;
	else
		++eol;		/* we're interested in the position after the
				   newline. */
	result = PyString_FromStringAndSize(start, (eol - start));
	self->pos += (eol - start);
	return (result);
}

static PyObject *
mmap_read_method(mmap_object *self,
		 PyObject *args)
{
	long num_bytes;
	PyObject *result;

	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple(args, "l:read", &num_bytes))
		return(NULL);

	/* silently 'adjust' out-of-range requests */
	if ((self->pos + num_bytes) > self->size) {
		num_bytes -= (self->pos+num_bytes) - self->size;
	}
	result = Py_BuildValue("s#", self->data+self->pos, num_bytes);
	self->pos += num_bytes;	 
	return (result);
}

static PyObject *
mmap_find_method(mmap_object *self,
		 PyObject *args)
{
	long start = self->pos;
	char *needle;
	int len;

	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "s#|l:find", &needle, &len, &start)) {
		return NULL;
	} else {
		char *p;
		char *e = self->data + self->size;

                if (start < 0)
			start += self->size;
                if (start < 0)
			start = 0;
                else if ((size_t)start > self->size)
			start = self->size;

		for (p = self->data + start; p + len <= e; ++p) {
			int i;
			for (i = 0; i < len && needle[i] == p[i]; ++i)
				/* nothing */;
			if (i == len) {
				return Py_BuildValue (
					"l",
					(long) (p - self->data));
			}
		}
		return Py_BuildValue ("l", (long) -1);
	}
}

static int 
is_writeable(mmap_object *self)
{
	if (self->access != ACCESS_READ)
		return 1; 
	PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
	return 0;
}

static int 
is_resizeable(mmap_object *self)
{
	if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
		return 1; 
	PyErr_Format(PyExc_TypeError, 
		     "mmap can't resize a readonly or copy-on-write memory map.");
	return 0;
}


static PyObject *
mmap_write_method(mmap_object *self,
		  PyObject *args)
{
	long length;
	char *data;

	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "s#:write", &data, &length))
		return(NULL);

	if (!is_writeable(self))
		return NULL;

	if ((self->pos + length) > self->size) {
		PyErr_SetString (PyExc_ValueError, "data out of range");
		return NULL;
	}
	memcpy (self->data+self->pos, data, length);
	self->pos = self->pos+length;
	Py_INCREF (Py_None);
	return (Py_None);
}

static PyObject *
mmap_write_byte_method(mmap_object *self,
		       PyObject *args)
{
	char value;

	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "c:write_byte", &value))
		return(NULL);

	if (!is_writeable(self))
		return NULL;
	*(self->data+self->pos) = value;
	self->pos += 1;
	Py_INCREF (Py_None);
	return (Py_None);
}
 
static PyObject *
mmap_size_method(mmap_object *self,
		 PyObject *args)
{
	CHECK_VALID(NULL);
        if (!PyArg_ParseTuple(args, ":size"))
		return NULL;

#ifdef MS_WIN32
	if (self->file_handle != INVALID_HANDLE_VALUE) {
		return (Py_BuildValue (
			"l", (long)
			GetFileSize (self->file_handle, NULL)));
	} else {
		return (Py_BuildValue ("l", (long) self->size) );
	}
#endif /* MS_WIN32 */

#ifdef UNIX
	{
		struct stat buf;
		if (-1 == fstat(self->fd, &buf)) {
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
		return (Py_BuildValue ("l", (long) buf.st_size) );
	}
#endif /* UNIX */
}

/* This assumes that you want the entire file mapped,
 / and when recreating the map will make the new file
 / have the new size
 /
 / Is this really necessary?  This could easily be done
 / from python by just closing and re-opening with the
 / new size?
 */

static PyObject *
mmap_resize_method(mmap_object *self,
		   PyObject *args)
{
	unsigned long new_size;
	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "l:resize", &new_size) || 
	    !is_resizeable(self)) {
		return NULL;
#ifdef MS_WIN32
	} else { 
		DWORD dwErrCode = 0;
		/* First, unmap the file view */
		UnmapViewOfFile (self->data);
		/* Close the mapping object */
		CloseHandle (self->map_handle);
		/* Move to the desired EOF position */
		SetFilePointer (self->file_handle,
				new_size, NULL, FILE_BEGIN);
		/* Change the size of the file */
		SetEndOfFile (self->file_handle);
		/* Create another mapping object and remap the file view */
		self->map_handle = CreateFileMapping (
			self->file_handle,
			NULL,
			PAGE_READWRITE,
			0,
			new_size,
			self->tagname);
		if (self->map_handle != NULL) {
			self->data = (char *) MapViewOfFile (self->map_handle,
							     FILE_MAP_WRITE,
							     0,
							     0,
							     0);
			if (self->data != NULL) {
				self->size = new_size;
				Py_INCREF (Py_None);
				return Py_None;
			} else {
				dwErrCode = GetLastError();
			}
		} else {
			dwErrCode = GetLastError();
		}
		PyErr_SetFromWindowsErr(dwErrCode);
		return (NULL);
#endif /* MS_WIN32 */

#ifdef UNIX
#ifndef HAVE_MREMAP 
	} else {
		PyErr_SetString(PyExc_SystemError,
				"mmap: resizing not available--no mremap()");
		return NULL;
#else
	} else {
		void *newmap;

#ifdef MREMAP_MAYMOVE
		newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
#else
		newmap = mremap(self->data, self->size, new_size, 0);
#endif
		if (newmap == (void *)-1) 
		{
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
		self->data = newmap;
		self->size = new_size;
		Py_INCREF(Py_None);
		return Py_None;
#endif /* HAVE_MREMAP */
#endif /* UNIX */
	}
}

static PyObject *
mmap_tell_method(mmap_object *self, PyObject *args)
{
	CHECK_VALID(NULL);
        if (!PyArg_ParseTuple(args, ":tell"))
		return NULL;
	return (Py_BuildValue ("l", (long) self->pos) );
}

static PyObject *
mmap_flush_method(mmap_object *self, PyObject *args)
{
	size_t offset	= 0;
	size_t size = self->size;
	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "|ll:flush", &offset, &size)) {
		return NULL;
	} else if ((offset + size) > self->size) {
		PyErr_SetString (PyExc_ValueError,
				 "flush values out of range");
		return NULL;
	} else {
#ifdef MS_WIN32
		return (Py_BuildValue("l", (long)
                                      FlushViewOfFile(self->data+offset, size)));
#endif /* MS_WIN32 */
#ifdef UNIX
		/* XXX semantics of return value? */
		/* XXX flags for msync? */
		if (-1 == msync(self->data + offset, size,
				MS_SYNC))
		{
			PyErr_SetFromErrno(mmap_module_error);
			return NULL;
		}
		return Py_BuildValue ("l", (long) 0);	
#endif /* UNIX */   
	}
}

static PyObject *
mmap_seek_method(mmap_object *self, PyObject *args)
{
	int dist;
	int how=0;
	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "i|i:seek", &dist, &how)) {
		return(NULL);
	} else {
		size_t where;
		switch (how) {
		case 0: /* relative to start */
			if (dist < 0)
				goto onoutofrange;
			where = dist;
			break;
		case 1: /* relative to current position */
			if ((int)self->pos + dist < 0)
				goto onoutofrange;
			where = self->pos + dist;
			break;
		case 2: /* relative to end */
			if ((int)self->size + dist < 0)
				goto onoutofrange;
			where = self->size + dist;
			break;
		default:
			PyErr_SetString (PyExc_ValueError,
					 "unknown seek type");
			return NULL;
		}
		if (where > self->size)
			goto onoutofrange;
		self->pos = where;
		Py_INCREF (Py_None);
		return (Py_None);
	}

  onoutofrange:
	PyErr_SetString (PyExc_ValueError, "seek out of range");
	return NULL;
}

static PyObject *
mmap_move_method(mmap_object *self, PyObject *args)
{
	unsigned long dest, src, count;
	CHECK_VALID(NULL);
	if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
	    !is_writeable(self)) {
		return NULL;
	} else {
		/* bounds check the values */
		if (/* end of source after end of data?? */
			((src+count) > self->size)
			/* dest will fit? */
			|| (dest+count > self->size)) {
			PyErr_SetString (PyExc_ValueError,
					 "source or destination out of range");
			return NULL;
		} else {
			memmove (self->data+dest, self->data+src, count);
			Py_INCREF (Py_None);
			return Py_None;
		}
	}
}

static struct PyMethodDef mmap_object_methods[] = {
	{"close",	(PyCFunction) mmap_close_method,	1},
	{"find",	(PyCFunction) mmap_find_method,		1},
	{"flush",	(PyCFunction) mmap_flush_method,	1},

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -