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

📄 structmodule.c

📁 python s60 1.4.5版本的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* Portions Copyright (c) 2005 Nokia Corporation */
/* Portions Copyright (c) 2005 Nokia Corporation */
/* struct module -- pack values into and (out of) strings */

/* New version supporting byte order, alignment and size options,
   character strings, and unsigned numbers */

const static char struct__doc__[] = "\
Functions to convert between Python values and C structs.\n\
Python strings are used to hold the data representing the C struct\n\
and also as format strings to describe the layout of data in the C struct.\n\
\n\
The optional first format char indicates byte order, size and alignment:\n\
 @: native order, size & alignment (default)\n\
 =: native order, std. size & alignment\n\
 <: little-endian, std. size & alignment\n\
 >: big-endian, std. size & alignment\n\
 !: same as >\n\
\n\
The remaining chars indicate types of args and must match exactly;\n\
these can be preceded by a decimal repeat count:\n\
 x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\
 h:short; H:unsigned short; i:int; I:unsigned int;\n\
 l:long; L:unsigned long; f:float; d:double.\n\
Special cases (preceding decimal count indicates length):\n\
 s:string (array of char); p: pascal string (with count byte).\n\
Special case (only available in native format):\n\
 P:an integer type that is wide enough to hold a pointer.\n\
Special case (not in native mode unless 'long long' in platform C):\n\
 q:long long; Q:unsigned long long\n\
Whitespace between formats is ignored.\n\
\n\
The variable struct.error is an exception raised on errors.";

#include "Python.h"

#include <ctype.h>


/* Exception */

#ifndef SYMBIAN
static PyObject *StructError;
#else
#define StructError (PYTHON_GLOBALS->StructError)
#endif

/* Define various structs to figure out the alignments of types */

#ifdef __MWERKS__
/*
** XXXX We have a problem here. There are no unique alignment rules
** on the PowerPC mac.
*/
#ifdef __powerc
#pragma options align=mac68k
#endif
#endif /* __MWERKS__ */

typedef struct { char c; short x; } st_short;
typedef struct { char c; int x; } st_int;
typedef struct { char c; long x; } st_long;
typedef struct { char c; float x; } st_float;
typedef struct { char c; double x; } st_double;
typedef struct { char c; void *x; } st_void_p;

#define SHORT_ALIGN (sizeof(st_short) - sizeof(short))
#define INT_ALIGN (sizeof(st_int) - sizeof(int))
#define LONG_ALIGN (sizeof(st_long) - sizeof(long))
#define FLOAT_ALIGN (sizeof(st_float) - sizeof(float))
#define DOUBLE_ALIGN (sizeof(st_double) - sizeof(double))
#define VOID_P_ALIGN (sizeof(st_void_p) - sizeof(void *))

/* We can't support q and Q in native mode unless the compiler does;
   in std mode, they're 8 bytes on all platforms. */
#ifdef HAVE_LONG_LONG
typedef struct { char c; LONG_LONG x; } s_long_long;
#define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(LONG_LONG))
#endif

#define STRINGIFY(x)    #x

#ifdef __powerc
#pragma options align=reset
#endif

/* Helper to get a PyLongObject by hook or by crook.  Caller should decref. */

static PyObject *
get_pylong(PyObject *v)
{
	PyNumberMethods *m;

	assert(v != NULL);
	if (PyInt_Check(v))
		return PyLong_FromLong(PyInt_AS_LONG(v));
	if (PyLong_Check(v)) {
		Py_INCREF(v);
		return v;
	}
	// XXX:CW32
	m = (PyNumberMethods *)v->ob_type->tp_as_number;

	if (m != NULL && m->nb_long != NULL) {
		v = m->nb_long(v);
		if (v == NULL)
			return NULL;
		if (PyLong_Check(v))
			return v;
		Py_DECREF(v);
	}
	PyErr_SetString(StructError,
			"cannot convert argument to long");
	return NULL;
}

/* Helper routine to get a Python integer and raise the appropriate error
   if it isn't one */

static int
get_long(PyObject *v, long *p)
{
	long x = PyInt_AsLong(v);
	if (x == -1 && PyErr_Occurred()) {
		if (PyErr_ExceptionMatches(PyExc_TypeError))
			PyErr_SetString(StructError,
					"required argument is not an integer");
		return -1;
	}
	*p = x;
	return 0;
}


/* Same, but handling unsigned long */

static int
get_ulong(PyObject *v, unsigned long *p)
{
	if (PyLong_Check(v)) {
		unsigned long x = PyLong_AsUnsignedLong(v);
		if (x == (unsigned long)(-1) && PyErr_Occurred())
			return -1;
		*p = x;
		return 0;
	}
	else {
		return get_long(v, (long *)p);
	}
}

#ifdef HAVE_LONG_LONG

/* Same, but handling native long long. */

static int
get_longlong(PyObject *v, LONG_LONG *p)
{
	LONG_LONG x;

	v = get_pylong(v);
	if (v == NULL)
		return -1;
	assert(PyLong_Check(v));
	x = PyLong_AsLongLong(v);
	Py_DECREF(v);
	if (x == (LONG_LONG)-1 && PyErr_Occurred())
		return -1;
	*p = x;
	return 0;
}

/* Same, but handling native unsigned long long. */

static int
get_ulonglong(PyObject *v, unsigned LONG_LONG *p)
{
	unsigned LONG_LONG x;

	v = get_pylong(v);
	if (v == NULL)
		return -1;
	assert(PyLong_Check(v));
	x = PyLong_AsUnsignedLongLong(v);
	Py_DECREF(v);
	if (x == (unsigned LONG_LONG)-1 && PyErr_Occurred())
		return -1;
	*p = x;
	return 0;
}

#endif

/* Floating point helpers */

/* These use ANSI/IEEE Standard 754-1985 (Standard for Binary Floating
   Point Arithmetic).  See the following URL:
   http://www.psc.edu/general/software/packages/ieee/ieee.html */

/* XXX Inf/NaN are not handled quite right (but underflow is!) */

static int
pack_float(double x, /* The number to pack */
           char *p,  /* Where to pack the high order byte */
           int incr) /* 1 for big-endian; -1 for little-endian */
{
	int s;
	int e;
	double f;
	long fbits;

	if (x < 0) {
		s = 1;
		x = -x;
	}
	else
		s = 0;

	f = frexp(x, &e);

	/* Normalize f to be in the range [1.0, 2.0) */
	if (0.5 <= f && f < 1.0) {
		f *= 2.0;
		e--;
	}
	else if (f == 0.0) {
		e = 0;
	}
	else {
		PyErr_SetString(PyExc_SystemError,
				"frexp() result out of range");
		return -1;
	}

	if (e >= 128) {
		/* XXX 128 itself is reserved for Inf/NaN */
		PyErr_SetString(PyExc_OverflowError,
				"float too large to pack with f format");
		return -1;
	}
	else if (e < -126) {
		/* Gradual underflow */
		f = ldexp(f, 126 + e);
		e = 0;
	}
	else if (!(e == 0 && f == 0.0)) {
		e += 127;
		f -= 1.0; /* Get rid of leading 1 */
	}

	f *= 8388608.0; /* 2**23 */
	fbits = (long) floor(f + 0.5); /* Round */

	/* First byte */
	*p = (s<<7) | (e>>1);
	p += incr;

	/* Second byte */
	*p = (char) (((e&1)<<7) | (fbits>>16));
	p += incr;

	/* Third byte */
	*p = (fbits>>8) & 0xFF;
	p += incr;

	/* Fourth byte */
	*p = fbits&0xFF;

	/* Done */
	return 0;
}

static int
pack_double(double x, /* The number to pack */
            char *p,  /* Where to pack the high order byte */
            int incr) /* 1 for big-endian; -1 for little-endian */
{
	int s;
	int e;
	double f;
	long fhi, flo;

	if (x < 0) {
		s = 1;
		x = -x;
	}
	else
		s = 0;

	f = frexp(x, &e);

	/* Normalize f to be in the range [1.0, 2.0) */
	if (0.5 <= f && f < 1.0) {
		f *= 2.0;
		e--;
	}
	else if (f == 0.0) {
		e = 0;
	}
	else {
		PyErr_SetString(PyExc_SystemError,
				"frexp() result out of range");
		return -1;
	}

	if (e >= 1024) {
		/* XXX 1024 itself is reserved for Inf/NaN */
		PyErr_SetString(PyExc_OverflowError,
				"float too large to pack with d format");
		return -1;
	}
	else if (e < -1022) {
		/* Gradual underflow */
		f = ldexp(f, 1022 + e);
		e = 0;
	}
	else if (!(e == 0 && f == 0.0)) {
		e += 1023;
		f -= 1.0; /* Get rid of leading 1 */
	}

	/* fhi receives the high 28 bits; flo the low 24 bits (== 52 bits) */
	f *= 268435456.0; /* 2**28 */
	fhi = (long) floor(f); /* Truncate */
	f -= (double)fhi;
	f *= 16777216.0; /* 2**24 */
	flo = (long) floor(f + 0.5); /* Round */

	/* First byte */
	*p = (s<<7) | (e>>4);
	p += incr;

	/* Second byte */
	*p = (char) (((e&0xF)<<4) | (fhi>>24));
	p += incr;

	/* Third byte */
	*p = (fhi>>16) & 0xFF;
	p += incr;

	/* Fourth byte */
	*p = (fhi>>8) & 0xFF;
	p += incr;

	/* Fifth byte */
	*p = fhi & 0xFF;
	p += incr;

	/* Sixth byte */
	*p = (flo>>16) & 0xFF;
	p += incr;

	/* Seventh byte */
	*p = (flo>>8) & 0xFF;
	p += incr;

	/* Eighth byte */
	*p = flo & 0xFF;
	p += incr;

	/* Done */
	return 0;
}

static PyObject *
unpack_float(const char *p,  /* Where the high order byte is */
             int incr)       /* 1 for big-endian; -1 for little-endian */
{
	int s;
	int e;
	long f;
	double x;

	/* First byte */
	s = (*p>>7) & 1;
	e = (*p & 0x7F) << 1;
	p += incr;

	/* Second byte */
	e |= (*p>>7) & 1;
	f = (*p & 0x7F) << 16;
	p += incr;

	/* Third byte */
	f |= (*p & 0xFF) << 8;
	p += incr;

	/* Fourth byte */
	f |= *p & 0xFF;

	x = (double)f / 8388608.0;

	/* XXX This sadly ignores Inf/NaN issues */
	if (e == 0)
		e = -126;
	else {
		x += 1.0;
		e -= 127;
	}
	x = ldexp(x, e);

	if (s)
		x = -x;

	return PyFloat_FromDouble(x);
}

static PyObject *
unpack_double(const char *p,  /* Where the high order byte is */
              int incr)       /* 1 for big-endian; -1 for little-endian */
{
	int s;
	int e;
	long fhi, flo;
	double x;

	/* First byte */
	s = (*p>>7) & 1;
	e = (*p & 0x7F) << 4;
	p += incr;

	/* Second byte */
	e |= (*p>>4) & 0xF;
	fhi = (*p & 0xF) << 24;
	p += incr;

	/* Third byte */
	fhi |= (*p & 0xFF) << 16;
	p += incr;

	/* Fourth byte */
	fhi |= (*p & 0xFF) << 8;
	p += incr;

	/* Fifth byte */
	fhi |= *p & 0xFF;
	p += incr;

	/* Sixth byte */
	flo = (*p & 0xFF) << 16;
	p += incr;

	/* Seventh byte */
	flo |= (*p & 0xFF) << 8;
	p += incr;

	/* Eighth byte */
	flo |= *p & 0xFF;
	p += incr;

	x = (double)fhi + (double)flo / 16777216.0; /* 2**24 */
	x /= 268435456.0; /* 2**28 */

	/* XXX This sadly ignores Inf/NaN */
	if (e == 0)
		e = -1022;
	else {
		x += 1.0;
		e -= 1023;
	}
	x = ldexp(x, e);

	if (s)
		x = -x;

	return PyFloat_FromDouble(x);
}


/* The translation function for each format character is table driven */

typedef struct _formatdef {
	char format;
	int size;
	int alignment;
	PyObject* (*unpack)(const char *,
			    const struct _formatdef *);
	int (*pack)(char *, PyObject *,
		    const struct _formatdef *);
} formatdef;

/* A large number of small routines follow, with names of the form

	[bln][up]_TYPE

   [bln] distiguishes among big-endian, little-endian and native.
   [pu] distiguishes between pack (to struct) and unpack (from struct).
   TYPE is one of char, byte, ubyte, etc.
*/

/* Native mode routines. ****************************************************/
/* NOTE:
   In all n[up]_<type> routines handling types larger than 1 byte, there is
   *no* guarantee that the p pointer is properly aligned for each type,
   therefore memcpy is called.  An intermediate variable is used to
   compensate for big-endian architectures.
   Normally both the intermediate variable and the memcpy call will be
   skipped by C optimisation in little-endian architectures (gcc >= 2.91
   does this). */

static PyObject *
nu_char(const char *p, const formatdef *f)
{
	return PyString_FromStringAndSize(p, 1);
}

static PyObject *
nu_byte(const char *p, const formatdef *f)
{
	return PyInt_FromLong((long) *(signed char *)p);
}

static PyObject *
nu_ubyte(const char *p, const formatdef *f)
{
	return PyInt_FromLong((long) *(unsigned char *)p);
}

⌨️ 快捷键说明

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