<commit_before>/****************************************************************************
#copyright ReportLab Inc. 2000
#see license.txt for license details
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/lib/_rl_accel.c?cvsroot=reportlab
#$Header: /tmp/reportlab/reportlab/lib/_rl_accel.c,v 1.38 2004/02/02 08:43:51 rgbecker Exp $
 ****************************************************************************/
#if 0
static __version__=" $Id: _rl_accel.c,v 1.38 2004/02/02 08:43:51 rgbecker Exp $ "
#endif
#include "Python.h"
#include <stdlib.h>
#include <math.h>
#if defined(__GNUC__) || defined(sun) || defined(_AIX) || defined(__hpux)
#	define STRICMP strcasecmp
#elif defined(_MSC_VER)
#	define STRICMP stricmp
#elif defined(macintosh)
# include <extras.h>
# define strdup _strdup
# define STRICMP _stricmp
#else
#	error "Don't know how to define STRICMP"
#endif
#ifndef max
#	define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#	define min(a,b) ((a)<(b)?(a):(b))
#endif
#define VERSION "0.46"
#define MODULE "_rl_accel"
#ifndef	ATTRDICT
	#if PY_MAJOR_VERSION>=2
	#	define ATTRDICT 1
	#endif
#endif
static PyObject *moduleVersion;

typedef struct _fI_t {
		char*			name;
		int				ascent, descent;
		int				widths[256];
		struct _fI_t*	next;
		} fI_t;

typedef struct _eI_t {
		char*			name;
		fI_t*			fonts;
		struct _eI_t*	next;
		} eI_t;

eI_t		*Encodings=NULL;
eI_t		*defaultEncoding = NULL;
PyObject	*_SWRecover=NULL;

static PyObject *ErrorObject;

static	eI_t*	find_encoding(char* name)
{
	eI_t*	e = Encodings;
	for(;e;e=e->next) if(!STRICMP(name,e->name)) return e;
	return (eI_t*)0;
}

static	fI_t* find_font(char* name, fI_t* f)
{
	for(;f;f=f->next) if(!STRICMP(name,f->name)) return f;
	return (fI_t*)0;
}

static	int _parseSequenceInt(PyObject* e, int i, int *x)
{
	PyObject	*p;
	if((p = PySequence_GetItem(e,i)) && (p = PyNumber_Int(p))){
		*x=PyInt_AS_LONG(p);
		return 1;
		}
	return 0;
}

static PyObject *_pdfmetrics__SWRecover(PyObject* dummy, PyObject* args)
{
	PyObject *result = NULL;
	PyObject *temp=NULL;

	if (PyArg_ParseTuple(args, "|O:_SWRecover", &temp)) {
		if(temp){
			if (!PyCallable_Check(temp)) {
				PyErr_SetString(PyExc_TypeError, "parameter must be callable");
				return NULL;
				}
			Py_INCREF(temp);					/* Add a reference to new callback */
			Py_XDECREF(_SWRecover);	/* Dispose of previous callback */
			_SWRecover = temp;				/* Remember new callback */
			}
		else if(_SWRecover){
			Py_INCREF(_SWRecover);
			return _SWRecover;
			}
		/* Boilerplate to return "None" */
		Py_INCREF(Py_None);
		result = Py_None;
		}
	return result;
}

static PyObject *_pdfmetrics_defaultEncoding(PyObject *self, PyObject* args)
{
	char*	encoding=NULL;
	eI_t*	e;
	if (!PyArg_ParseTuple(args, "|s", &encoding)) return NULL;
	if(encoding){
		if(!(e= find_encoding(encoding))){
			e = (eI_t*)malloc(sizeof(eI_t));
			e->name = strdup(encoding);
			e->next = Encodings;
			e->fonts = NULL;
			Encodings = e;
			}
		defaultEncoding = e;
		}
	else if(defaultEncoding) return Py_BuildValue("s",defaultEncoding->name);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *_pdfmetrics_setFontInfo(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding;
	int			ascent, descent;
	PyObject	*pW;
	int			i;
	eI_t*		e;
	fI_t*		f;

	if (!PyArg_ParseTuple(args, "ssiiO", &fontName, &encoding, &ascent, &descent,&pW)) return NULL;
	i = PySequence_Length(pW);
	if(i!=256){
badSeq:	PyErr_SetString(ErrorObject,"widths should be a length 256 sequence of integers");
		return NULL;
		}
	e = find_encoding(encoding);
	if(!e){
		e = (eI_t*)malloc(sizeof(eI_t));
		e->name = strdup(encoding);
		e->next = Encodings;
		e->fonts = NULL;
		Encodings = e;
		f = NULL;
		}
	else
		f = find_font(fontName,e->fonts);

	if(!f){
		f = (fI_t*)malloc(sizeof(fI_t));
		f->name = strdup(fontName);
		f->next = e->fonts;
		e->fonts = f;
		}
	f->ascent = ascent;
	f->descent = descent;
	for(i=0;i<256;i++)
		if(!_parseSequenceInt(pW,i,&f->widths[i])) goto badSeq;

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *_pdfmetrics_getFonts(PyObject *self, PyObject *args)
{
	char		*encoding=0;
	fI_t*		f;
	eI_t*		e;
	int			nf;
	PyObject	*r;
	if (!PyArg_ParseTuple(args, "|s:getFonts", &encoding)) return NULL;
	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	for(nf=0,f=e->fonts;f;f=f->next) nf++;

	r = PyList_New(nf);
	for(nf=0,f=e->fonts;f;f=f->next) PyList_SetItem(r,nf++,PyString_FromString(f->name));

	return r;
}

static PyObject *_pdfmetrics_getFontInfo(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding=0;
	eI_t*		e;
	fI_t*		f;
	int			i;
	PyObject	*r, *t;

	if (!PyArg_ParseTuple(args, "s|s", &fontName, &encoding)) return NULL;
	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	if(!(f = find_font(fontName,e->fonts))){
		PyErr_SetString(ErrorObject,"unknown font");
		return NULL;
		}

	t = PyList_New(256);
	for(i=0;i<256;i++){
		PyList_SetItem(t,i,PyInt_FromLong(f->widths[i]));
		}
	r = PyTuple_New(3);
	PyTuple_SetItem(r,0,t);
	PyTuple_SetItem(r,1,PyInt_FromLong(f->ascent));
	PyTuple_SetItem(r,2,PyInt_FromLong(f->descent));
	return r;
}

static PyObject *_pdfmetrics_stringWidth(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding=NULL;
	unsigned char *text;
	double		fontSize;
	fI_t		*fI;
	eI_t		*e;
	int			w, *width, i, textLen;
	static int	recover=1;

	if (!PyArg_ParseTuple(args, "s#sd|s", &text, &textLen, &fontName, &fontSize, &encoding)) return NULL;
	if(fontSize<=0){
		PyErr_SetString(ErrorObject,"bad fontSize");
		return NULL;
		}

	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	if(!(fI=find_font(fontName,e->fonts))){
		if(_SWRecover && recover){
			PyObject *arglist = Py_BuildValue("(s#sds)",text,textLen,fontName,fontSize,e->name);
			PyObject *result;
			if(!arglist){
				PyErr_SetString(ErrorObject,"recovery failed!");
				return NULL;
				}
			recover = 0;
			result = PyEval_CallObject(_SWRecover, arglist);
			recover = 1;
			Py_DECREF(arglist);
			if(!result) return NULL;
			if(result!=Py_None) return result;
			Py_DECREF(result);
			if((fI=find_font(fontName,e->fonts))) goto L2;
			}
		PyErr_SetString(ErrorObject,"unknown font");
		return NULL;
		}

L2:
	width = fI->widths;
	for(i=w=0;i<textLen;i++)
		w += width[text[i]];

	return Py_BuildValue("f",0.001*fontSize*w);
}

static PyObject *_pdfmetrics_instanceStringWidth(PyObject *unused, PyObject* args)
{
	PyObject	*pfontName, *self;
	char		*fontName;
	unsigned char *text;
	double		fontSize;
	fI_t		*fI;
	eI_t		*e;
	int			w, *width, i, textLen;
	static int	recover=1;

	if (!PyArg_ParseTuple(args, "Os#d", &self, &text, &textLen, &fontSize)) return NULL;
	if(fontSize<=0){
		PyErr_SetString(ErrorObject,"bad fontSize");
		return NULL;
		}

	pfontName = PyObject_GetAttrString(self,"fontName");
	if(!pfontName){
		PyErr_SetString(PyExc_AttributeError,"No attribute fontName");
		return NULL;
		}

	if(!PyString_Check(pfontName)){
		Py_DECREF(pfontName);
		PyErr_SetString(PyExc_TypeError,"Attribute fontName is not a string");
		return NULL;
		}
	fontName = PyString_AsString(pfontName);

	e = defaultEncoding;

	if(!(fI=find_font(fontName,e->fonts))){
		if(_SWRecover && recover){
			PyObject *arglist = Py_BuildValue("(s#sd)",text,textLen,fontName,fontSize);
			PyObject *result;
			if(!arglist){
				PyErr_SetString(ErrorObject,"recovery failed!");
				goto L1;
				}
			recover = 0;
			result = PyEval_CallObject(_SWRecover, arglist);
			recover = 1;
			Py_DECREF(arglist);
			if(!result) goto L1;
			if(result!=Py_None) return result;
			Py_DECREF(result);
			if((fI=find_font(fontName,e->fonts))) goto L2;
			}
		PyErr_SetString(ErrorObject,"unknown font");
L1:		Py_DECREF(pfontName);
		return NULL;
		}

L2:	Py_DECREF(pfontName);
	width = fI->widths;
	for(i=w=0;i<textLen;i++)
		w += width[text[i]];

	return Py_BuildValue("f",0.001*fontSize*w);
}

#define a85_0		   1L
#define a85_1		   85L
#define a85_2		 7225L
#define a85_3	   614125L
#define a85_4	 52200625L

PyObject *_a85_encode(PyObject *self, PyObject *args)
{
	unsigned char	*inData;
	int				length, blocks, extra, i, k, lim;
	unsigned long	block, res;
	char			*buf;
	PyObject		*retVal;

	if (!PyArg_ParseTuple(args, "z#", &inData, &length)) return NULL;

	blocks = length / 4;
	extra = length % 4;

	buf = (char*)malloc((blocks+1)*5+3);
	lim = 4*blocks;

	for(k=i=0; i<lim; i += 4){
		/*
		 * If you evere have trouble with this consider using masking to ensure
		 * that the shifted quantity is only 8 bits long
		 */
		block = ((unsigned long)inData[i]<<24)|((unsigned long)inData[i+1]<<16)
				|((unsigned long)inData[i+2]<<8)|((unsigned long)inData[i+3]);
		if (block == 0) buf[k++] = 'z';
		else {
			res = block/a85_4;
			buf[k++] = (char)(res+33);
			block -= res*a85_4;

			res = block/a85_3;
			buf[k++] = (char)(res+33);
			block -= res*a85_3;

			res = block/a85_2;
			buf[k++] = (char)(res+33);
			block -= res*a85_2;

			res = block / a85_1;
			buf[k++] = (char)(res+33);

			buf[k++] = (char)(block-res*a85_1+33);
			}
		}

	if(extra>0){
		block = 0L;

		for (i=0; i<extra; i++)
			block += (unsigned long)inData[length-extra+i] << (24-8*i);

		res = block/a85_4;
		buf[k++] = (char)(res+33);
		if(extra>=1){
			block -= res*a85_4;

			res = block/a85_3;
			buf[k++] = (char)(res+33);
			if(extra>=2){
				block -= res*a85_3;

				res = block/a85_2;
				buf[k++] = (char)(res+33);
				if(extra>=3) buf[k++] = (char)((block-res*a85_2)/a85_1+33);
				}
			}
		}

	buf[k++] = '~';
	buf[k++] = '>';
	retVal = PyString_FromStringAndSize(buf, k);
	free(buf);
	return retVal;
}

PyObject *_a85_decode(PyObject *self, PyObject *args)
{
	unsigned char	*inData, *p, *q, *tmp, *buf;
	unsigned int	length, blocks, extra, k, num, c1, c2, c3, c4, c5;
	static unsigned pad[] = {0,0,0xffffff,0xffff,0xff};
	PyObject		*retVal;

	if (!PyArg_ParseTuple(args, "z#", &inData, &length)) return NULL;
	for(k=0,q=inData, p=q+length;q<p && (q=(unsigned char*)strchr((const char*)q,'z'));k++, q++);	/*count 'z'*/
	length += k*4;
	tmp = q = (unsigned char*)malloc(length+1);
	while(inData<p && (k = *inData++)){
		if(isspace(k)) continue;
		if(k=='z'){
			/*turn 'z' into '!!!!!'*/
			memcpy(q,"!!!!!",5);
			q += 5;
			}
		else
			*q++ = k;
		}
	inData = tmp;
	length = q - inData;
	buf = inData+length-2;
	if(buf[0]!='~' || buf[1]!='>'){
		PyErr_SetString(ErrorObject, "Invalid terminator for Ascii Base 85 Stream");
		free(inData);
		return NULL;
		}
	length -= 2;
	buf[0] = 0;

	blocks = length / 5;
	extra = length % 5;

	buf = (unsigned char*)malloc((blocks+1)*4);
	q = inData+blocks*5;
	for(k=0;inData<q;inData+=5){
		c1 = inData[0]-33;
		c2 = inData[1]-33;
		c3 = inData[2]-33;
		c4 = inData[3]-33;
		c5 = inData[4]-33;
		num = (((c1*85+c2)*85+c3)*85+c4)*85+c5;
		buf[k++] = num>>24;
		buf[k++] = num>>16;
		buf[k++] = num>>8;
		buf[k++] = num;
		}
	if(extra>1){
		c1 = inData[0]-33;
		c2 = extra>=2 ? inData[1]-33: 0;
		c3 = extra>=3 ? inData[2]-33: 0;
		c4 = extra>=4 ? inData[3]-33: 0;
		c5 = 0;
		num = (((c1*85+c2)*85+c3)*85+c4)*85+c5 + pad[extra];
		if(extra>1){
			buf[k++] = num>>24;
			if(extra>2){
				buf[k++] = num>>16;
				if(extra>3){
					buf[k++] = num>>8;
					}
				}
			}
		}
	retVal = PyString_FromStringAndSize((const char*)buf, k);
	free(buf);
	free(tmp);
	return retVal;
}

static	char* _fp_fmts[]={"%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f"};
static	char *_fp_one(PyObject *pD)
{
	double	d;
	static	char s[30];
	int l;
	char*	dot;
	if((pD=PyNumber_Float(pD))){
		d = PyFloat_AS_DOUBLE(pD);
		Py_DECREF(pD);
		}
	else {
		PyErr_SetString(ErrorObject, "bad numeric value");
		return NULL;
		}
	if(fabs(d)<=1.0e-7){
		s[0]='0';
		s[1]=0;
		}
	else{
		if(fabs(d)>1) l = min(max(0,6-(int)log10(fabs(d))),6);
		else l = 6;
		sprintf(s,_fp_fmts[l], d);
		l = strlen(s)-1;
		while(l && s[l]=='0') l--;
		if(s[l]=='.' || s[l]==',') s[l]=0;
		else {
			s[l+1]=0;
			if(s[0]=='0' && (s[1]=='.'||s[1]==',')){
				if(s[1]==',') s[1] = '.';
				return s+1;
				}
			}
		if((dot=strchr(s,','))) *dot = '.';
		}
	return s;
}

PyObject *_fp_str(PyObject *self, PyObject *args)
{
	int				aL;
	PyObject		*retVal;
	char			*pD;
	char			*buf, *pB;
	int				i;

	if((aL=PySequence_Length(args))>=0){
		if(aL==1){
			retVal = PySequence_GetItem(args,0);
			if((i=PySequence_Length(retVal))>=0){
				aL = i;
				args = retVal;
				}
			else PyErr_Clear();
			Py_DECREF(retVal);
			}
		buf=malloc(31*aL);
		pB = buf;
		for(i=0;i<aL;i++){
			retVal = PySequence_GetItem(args,i);
			if(retVal){
				pD = _fp_one(retVal);
				Py_DECREF(retVal);
				}
			else pD = NULL;
			if(!pD){
				free(buf);
				return NULL;
				}
			if(pB!=buf){
				*pB++ = ' ';
				}
			strcpy(pB,pD);
			pB = pB + strlen(pB);
			}
		*pB = 0;
		retVal = PyString_FromString(buf);
		free(buf);
		return retVal;
		}
	else {
		PyErr_Clear();
		PyArg_ParseTuple(args, "O:_fp_str", &retVal);
		return NULL;
		}
}

#ifdef	ATTRDICT
static PyTypeObject _AttrDictType = {
	PyObject_HEAD_INIT(0)
	0,								/*ob_size*/
	0,								/*tp_name*/
	0,								/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	0,								/*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*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	/* Documentation string */
	NULL
};
static char* _AttrDict_tp_doc=
	"_AttrDict instance\n\
\n\
";

static PyObject * _AttrDict_copy(register PyObject *self, PyObject *args)
{
	PyObject *r;
	if (!PyArg_NoArgs(args)) return NULL;
	self->ob_type=&PyDict_Type;
	r = PyDict_Copy((PyObject*)self);
	self->ob_type=&_AttrDictType;
	if(r) r->ob_type=&_AttrDictType;
	return r;
}
static PyObject * _AttrDict_clear(register PyObject *self, PyObject *args)
{
	if (!PyArg_NoArgs(args)) return NULL;
	self->ob_type=&PyDict_Type;
	PyDict_Clear(self);
	self->ob_type=&_AttrDictType;
	Py_INCREF(Py_None);
	return Py_None;
}

static PyMethodDef mapp_methods[] = {
	{"clear",	(PyCFunction)_AttrDict_clear, METH_OLDARGS, "D.clear() -> None.  Remove all items from D."},
	{"copy",	(PyCFunction)_AttrDict_copy, METH_OLDARGS, "D.copy() -> a shallow copy of D"},
	{NULL,		NULL}		/* sentinel */
	};
static PyMethodChain _AttrDict_MethodChain[2];

static	PyObject *_AttrDict_getattr(PyObject* self, char* name)
{
	PyObject* r;
	self->ob_type=&PyDict_Type;
	r = PyDict_GetItemString(self,name);
	if(!r) r = Py_FindMethodInChain(&_AttrDict_MethodChain[0],self,name);
	self->ob_type=&_AttrDictType;
	return r;
}

static int _AttrDict_setattr(PyObject* self, char *name, PyObject* value)
{
	int	r;
	self->ob_type=&PyDict_Type;
	if(value){
		r = PyDict_SetItemString(self,name,value);
		}
	else {
		r = PyDict_DelItemString(self,name);
		}
	self->ob_type=&_AttrDictType;
	return r;
}

static PyObject *_AttrDict(PyObject *self, PyObject *args)
{
	PyObject *r;
	if (!PyArg_ParseTuple(args,":_attrDict")) return NULL;

	r = PyDict_New();
	if(!r) return NULL;
	r->ob_type = &_AttrDictType;
	return r;
}

static binaryfunc dict_subscript;
static objobjargproc dict_ass_sub;
static PyObject * _AttrDict_subscript(PyObject *self, register PyObject *key)
{
	PyObject* r;
	self->ob_type=&PyDict_Type;
	r = dict_subscript(self,key);
	self->ob_type=&_AttrDictType;
	return r;
}

static int _AttrDict_ass_sub(PyObject *self, PyObject *v, PyObject *w)
{
	int r;
	self->ob_type=&PyDict_Type;
	r = dict_ass_sub(self,v,w);
	self->ob_type=&_AttrDictType;
	return r;
}

static PyMappingMethods _AttrDict_as_mapping = {
	(inquiry)0, /*mp_length*/
	(binaryfunc)_AttrDict_subscript, /*mp_subscript*/
	(objobjargproc)_AttrDict_ass_sub, /*mp_ass_subscript*/
};
#endif

static PyObject *_escapePDF(unsigned char* text, int textlen)
{
	unsigned char*	out = PyMem_Malloc((textlen<<2)+1);
	int				j=0, i=0;
	char			buf[4];
	PyObject*		ret;

	while(i<textlen){
		unsigned char c = text[i++];
		if(c<32 || c>=127){
			sprintf(buf,"%03o",c);
			out[j++] = '\\';
			out[j++] = buf[0];
			out[j++] = buf[1];
			out[j++] = buf[2];
			}
		else {
			if(c=='\\' || c=='(' || c==')') out[j++] = '\\';
			out[j++] = c;
			}
		}
	ret = PyString_FromStringAndSize((const char *)out,j);
	PyMem_Free(out);
	return ret;
}

static PyObject *escapePDF(PyObject *self, PyObject* args)
{
	unsigned char	*text;
	int				textLen;

	if (!PyArg_ParseTuple(args, "s#:escapePDF", &text, &textLen)) return NULL;
	return _escapePDF(text,textLen);
}

static PyObject *_instanceEscapePDF(PyObject *unused, PyObject* args)
{
	PyObject		*self;
	unsigned char	*text;
	int				textLen;

	if (!PyArg_ParseTuple(args, "Os#:_instanceEscapePDF", &self, &text, &textLen)) return NULL;
	return _escapePDF(text,textLen);
}

static PyObject *_sameFrag(PyObject *self, PyObject* args)
{
	PyObject *f, *g;
	static char *names[] = {"fontName", "fontSize", "textColor", "rise", "underline", NULL};
	int	r=0, t;
	char **p;
	if (!PyArg_ParseTuple(args, "OO:_sameFrag", &f, &g)) return NULL;
	if(PyObject_HasAttrString(f,"cbDefn")||PyObject_HasAttrString(g,"cbDefn")) goto L0;
	for(p=names;*p;p++){
		PyObject *fa, *ga;
		fa = PyObject_GetAttrString(f,*p);
		if(!fa){
L1:			return NULL;
			}
		ga = PyObject_GetAttrString(g,*p);
		if(!ga){
			Py_DECREF(fa);
			goto L1;
			}
		t = PyObject_Compare(fa,ga);
		Py_DECREF(fa);
		Py_DECREF(ga);
		if(PyErr_Occurred()) goto L1;
		if(t) goto L0;
		}
	r = 1;
L0:	return PyInt_FromLong((long)r);
}

static PyObject *ttfonts_calcChecksum(PyObject *self, PyObject* args)
{
	unsigned char	*data;
	int				dataLen;
	unsigned long	Sum = 0L;
	unsigned char	*EndPtr;
	unsigned long n;
	int leftover;


	if (!PyArg_ParseTuple(args, "s#:calcChecksum", &data, &dataLen)) return NULL;
	EndPtr = data + (dataLen & ~3);

	/*full ULONGs*/
	while(data < EndPtr){
		n = ((*data++) << 24);
		n += ((*data++) << 16);
		n += ((*data++) << 8);
		n += ((*data++));
		Sum += n;
		}

	/*pad with zeros*/
	leftover = dataLen & 3;
	if(leftover){
		n = ((*data++) << 24);
		if (leftover>1) n += ((*data++) << 16);
		if (leftover>2) n += ((*data++) << 8);
		Sum += n;
		}

	return PyInt_FromLong(Sum);
}

static PyObject *ttfonts_add32(PyObject *self, PyObject* args)
{
	unsigned long x, y;
#if PY_MAJOR_VERSION>=2 && PY_MINOR_VERSION>=3
	PyObject	*ox, *oy;
	if(!PyArg_ParseTuple(args, "OO:add32", &ox, &oy)) return NULL;
	if(PyLong_Check(ox)){
		x = PyLong_AsUnsignedLongMask(ox);
		}
	else{
		x = PyInt_AsLong(ox);
		if(PyErr_Occurred()) return NULL;
		}
	if(PyLong_Check(oy)){
		y = PyLong_AsUnsignedLongMask(oy);
		}
	else{
		y = PyInt_AsLong(oy);
		if(PyErr_Occurred()) return NULL;
		}
#else
	if(!PyArg_ParseTuple(args, "ii:add32", &x, &y)) return NULL;
#endif
	x += y;
	return PyInt_FromLong(x);
}

static PyObject *hex32(PyObject *self, PyObject* args)
{
	unsigned long x;
	char	buf[20];
#if PY_MAJOR_VERSION>=2 && PY_MINOR_VERSION>=3
	PyObject	*ox;
	if(!PyArg_ParseTuple(args, "O:hex32", &ox)) return NULL;
	if(PyLong_Check(ox)){
		x = PyLong_AsUnsignedLongMask(ox);
		}
	else{
		x = PyInt_AsLong(ox);
		if(PyErr_Occurred()) return NULL;
		}
#else
	if(!PyArg_ParseTuple(args, "i:hex32", &x)) return NULL;
#endif
	sprintf(buf,"0X%8.8X",x);
	return PyString_FromString(buf);
}

/*Box start**************/
typedef struct {
	PyObject_HEAD
	unsigned	is_box:1;
	unsigned	is_glue:1;
	unsigned	is_penalty:1;
	double		width;
	char		character;
	unsigned	character_isNone:1;
	} BoxObject;

static void BoxFree(BoxObject* self)
{
	PyMem_DEL(self);
}

static int Box_set_double(char* name, double* pd, PyObject *value)
{
	PyObject *v = PyNumber_Float(value);
	if(!v) return -1;
	*pd = PyFloat_AsDouble(v);
	Py_DECREF(v);
	return 0;
}

static int Box_set_character(BoxObject *self, PyObject *value)
{
	if(value==Py_None){
		self->character_isNone = 1;
		}
	else {
		char *v = PyString_AsString(value);
		if(!v) return -1;
		if(PyString_GET_SIZE(value)!=1){
			PyErr_Format(PyExc_AttributeError,"Bad size %d('%s') for attribute character",PyString_GET_SIZE(value),v);
			return -1;
			}
		self->character = v[0];
		self->character_isNone = 0;
		}

	return 0;
}

static int Box_setattr(BoxObject *self, char *name, PyObject* value)
{
	if(!strcmp(name,"width")) return Box_set_double(name,&self->width,value);
	else if(!strcmp(name,"character")) return Box_set_character(self,value);
	else if(
			!strcmp(name,"stretch") ||
			!strcmp(name,"shrink") ||
			!strcmp(name,"penalty") ||
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"flagged") ||
			!strcmp(name,"is_box") ||
			!strcmp(name,"is_glue")
			) PyErr_Format(PyExc_AttributeError, "readonly attribute %s", name);
	else PyErr_Format(PyExc_AttributeError, "no attribute %s", name);
	return -1;
}

static struct PyMethodDef Box_methods[] = {
	{NULL, NULL}		/* sentinel */
	};

static PyObject* Box_get_character(unsigned isNone, char c)
{
	if(!isNone) return PyString_FromStringAndSize(&c,1);
	else {
		Py_INCREF(Py_None);
		return Py_None;
		}
}

static PyObject* Box_getattr(BoxObject *self, char *name)
{
	if(!strcmp(name,"width")) return PyFloat_FromDouble(self->width);
	else if(!strcmp(name,"character")) return Box_get_character(self->character_isNone,self->character);
	else if(!strcmp(name,"is_box")) return PyInt_FromLong(1L);
	else if(
			!strcmp(name,"stretch") ||
			!strcmp(name,"shrink") ||
			!strcmp(name,"penalty") ||
			!strcmp(name,"flagged") ||
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"is_glue")
			)  return PyInt_FromLong(0L);
	return Py_FindMethod(Box_methods, (PyObject *)self, name);
}

static PyTypeObject BoxType = {
	PyObject_HEAD_INIT(0)
	0,								/*ob_size*/
	"Box",							/*tp_name*/
	sizeof(BoxObject),				/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)BoxFree,			/*tp_dealloc*/
	(printfunc)0,					/*tp_print*/
	(getattrfunc)Box_getattr,		/*tp_getattr*/
	(setattrfunc)Box_setattr,		/*tp_setattr*/
	(cmpfunc)0,						/*tp_compare*/
	(reprfunc)0,					/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	(hashfunc)0,					/*tp_hash*/
	(ternaryfunc)0,					/*tp_call*/
	(reprfunc)0,					/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	/* Documentation string */
	"Box instance, see doc string for details."
};

static BoxObject* Box(PyObject* module, PyObject* args, PyObject* kw)
{
	BoxObject* self;
	char	*kwlist[] = {"width","character",NULL};
	PyObject	*pC=NULL;
	double		w;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"d|O:Box",kwlist,&w,&pC)) return NULL;
	if(!(self = PyObject_NEW(BoxObject, &BoxType))) return NULL;
	self->is_glue = self->is_penalty = 0;
	self->is_box = 1;
	self->width = w;
	if(Box_set_character(self, pC ? pC : Py_None)){
		BoxFree(self);
		return NULL;
		}

	return self;
}
/*Box end****************/
/*Glue start**************/
typedef struct {
	PyObject_HEAD
	unsigned	is_box:1;
	unsigned	is_glue:1;
	unsigned	is_penalty:1;
	double		width;
	double		stretch,shrink;
	} GlueObject;

static int Glue_setattr(GlueObject *self, char *name, PyObject* value)
{
	if(!strcmp(name,"width")) return Box_set_double(name,&self->width,value);
	else if(!strcmp(name,"stretch")) return Box_set_double(name,&self->stretch,value);
	else if(!strcmp(name,"shrink")) return Box_set_double(name,&self->shrink,value);
	else if(
			!strcmp(name,"character") ||
			!strcmp(name,"penalty") ||
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"flagged") ||
			!strcmp(name,"is_box") ||
			!strcmp(name,"is_glue")
			) PyErr_Format(PyExc_AttributeError, "readonly attribute %s", name);
	else PyErr_Format(PyExc_AttributeError, "no attribute %s", name);
	return -1;
}

static double _Glue_compute_width(GlueObject *self, double r)
{
	return self->width+r*(r<0?self->shrink:self->stretch);
}

static PyObject* Glue_compute_width(GlueObject *self, PyObject *args)
{
	double r;
	if(!PyArg_ParseTuple(args, "d:compute_width", &r)) return NULL;
	return PyFloat_FromDouble(_Glue_compute_width(self,r));
}

static struct PyMethodDef Glue_methods[] = {
	{"compute_width", (PyCFunction)Glue_compute_width, METH_VARARGS|METH_KEYWORDS, "compute_width(r)"},
	{NULL, NULL}		/* sentinel */
	};

static PyObject* Glue_getattr(GlueObject *self, char *name)
{
	if(!strcmp(name,"width")) return PyFloat_FromDouble(self->width);
	else if(!strcmp(name,"stretch")) return PyFloat_FromDouble(self->stretch);
	else if(!strcmp(name,"shrink")) return PyFloat_FromDouble(self->shrink);
	else if(!strcmp(name,"character")) return Box_get_character(1,0);
	else if(!strcmp(name,"is_glue")) return PyInt_FromLong(1L);
	else if(
			!strcmp(name,"penalty") ||
			!strcmp(name,"flagged") ||
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"is_box")
			)  return PyInt_FromLong(0L);
	return Py_FindMethod(Glue_methods, (PyObject *)self, name);
}

static PyTypeObject GlueType = {
	PyObject_HEAD_INIT(0)
	0,								/*ob_size*/
	"Glue",							/*tp_name*/
	sizeof(GlueObject),				/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)BoxFree,			/*tp_dealloc*/
	(printfunc)0,					/*tp_print*/
	(getattrfunc)Glue_getattr,		/*tp_getattr*/
	(setattrfunc)Glue_setattr,		/*tp_setattr*/
	(cmpfunc)0,						/*tp_compare*/
	(reprfunc)0,					/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	(hashfunc)0,					/*tp_hash*/
	(ternaryfunc)0,					/*tp_call*/
	(reprfunc)0,					/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	/* Documentation string */
	"Glue instance, see doc string for details."
};

static GlueObject* Glue(PyObject* module, PyObject* args, PyObject* kw)
{
	GlueObject* self;
	char	*kwlist[] = {"width","stretch","shrink",NULL};
	double		width,stretch,shrink;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"ddd:Glue",kwlist,&width,&stretch,&shrink)) return NULL;
	if(!(self = PyObject_NEW(GlueObject, &GlueType))) return NULL;
	self->is_box = self->is_penalty = 0;
	self->is_glue = 1;
	self->width = width;
	self->stretch = stretch;
	self->shrink = shrink;

	return self;
}
/*Glue end****************/
/*Penalty start**************/
typedef struct {
	PyObject_HEAD
	unsigned	is_box:1;
	unsigned	is_glue:1;
	unsigned	is_penalty:1;
	double		width;
	double		penalty;
	int			flagged;
	} PenaltyObject;

static int Penalty_set_int(char* name, int* pd, PyObject *value)
{
	PyObject *v = PyNumber_Int(value);
	if(!v) return -1;
	*pd = PyInt_AsLong(v);
	Py_DECREF(v);
	return 0;
}

static int Penalty_setattr(PenaltyObject *self, char *name, PyObject* value)
{
	if(!strcmp(name,"width")) return Box_set_double(name,&self->width,value);
	else if(!strcmp(name,"penalty")) return Box_set_double(name,&self->penalty,value);
	else if(!strcmp(name,"flagged")) return Penalty_set_int(name,&self->flagged,value);
	else if(
			!strcmp(name,"stretch") ||
			!strcmp(name,"shrink") ||
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"character") ||
			!strcmp(name,"is_box") ||
			!strcmp(name,"is_glue")
			) PyErr_Format(PyExc_AttributeError, "readonly attribute %s", name);
	else PyErr_Format(PyExc_AttributeError, "no attribute %s", name);
	return -1;
}

static PyObject* Penalty_getattr(PenaltyObject *self, char *name)
{
	if(!strcmp(name,"width")) return PyFloat_FromDouble(self->width);
	else if(!strcmp(name,"penalty")) return PyFloat_FromDouble(self->penalty);
	else if(!strcmp(name,"flagged")) return PyInt_FromLong(self->flagged);
	else if(!strcmp(name,"character")) return Box_get_character(1,0);
	else if(!strcmp(name,"is_penalty")) return PyInt_FromLong(1L);
	else if(
			!strcmp(name,"stretch") ||
			!strcmp(name,"shrink") ||
			!strcmp(name,"is_box") ||
			!strcmp(name,"is_glue")
			)  return PyInt_FromLong(0L);
	return Py_FindMethod(Box_methods, (PyObject *)self, name);
}

static PyTypeObject PenaltyType = {
	PyObject_HEAD_INIT(0)
	0,								/*ob_size*/
	"Penalty",							/*tp_name*/
	sizeof(PenaltyObject),				/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)BoxFree,			/*tp_dealloc*/
	(printfunc)0,					/*tp_print*/
	(getattrfunc)Penalty_getattr,		/*tp_getattr*/
	(setattrfunc)Penalty_setattr,		/*tp_setattr*/
	(cmpfunc)0,						/*tp_compare*/
	(reprfunc)0,					/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	(hashfunc)0,					/*tp_hash*/
	(ternaryfunc)0,					/*tp_call*/
	(reprfunc)0,					/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	/* Documentation string */
	"Penalty instance, see doc string for details."
};

static PenaltyObject* Penalty(PyObject* module, PyObject* args, PyObject* kw)
{
	PenaltyObject* self;
	char	*kwlist[] = {"width","penalty","flagged",NULL};
	double	width,penalty;
	int		flagged = 0;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"dd|i:Penalty",kwlist,&width,&penalty,&flagged)) return NULL;
	if(!(self = PyObject_NEW(PenaltyObject, &PenaltyType))) return NULL;
	self->is_box = self->is_glue = 0;
	self->is_penalty = 1;
	self->width = width;
	self->penalty = penalty;
	self->flagged = flagged;

	return self;
}
/*Penalty end****************/

static char *__doc__=
"_rl_accel contains various accelerated utilities\n\
\tstringWidth a fast string width function\n\
\t_instanceStringWidth a method version of stringWidth\n\
\tdefaultEncoding gets/sets the default encoding for stringWidth\n\
\tgetFonts gets font names from the internal table\n\
\tgetFontInfo gets font info from the internal table\n\
\tsetFontInfo adds a font to the internal table\n\
\t_SWRecover gets/sets a callback for stringWidth recovery\n\
\tescapePDF makes a string safe for PDF\n\
\t_instanceEscapePDF method equivalent of escapePDF\n\
\n\
\t_AsciiBase85Encode does what is says\n\
\t_AsciiBase85Decode does what is says\n\
\n\
\tfp_str converts numeric arguments to a single blank separated string\n"
#ifdef ATTRDICT
"\t_AttrDict creates a dict object which can do setattr/getattr type things\n"
#endif
"\tcalcChecksum calculate checksums for TTFs\n"
"\tadd32 32 bit unsigned addition\n"
"\thex32 32 bit unsigned to 0X8.8X string\n"
"\tBox(width,character=None) creates a Knuth character Box with the specified width.\n"
"\tGlue(width,stretch,shrink) creates a Knuth glue Box with the specified width, stretch and shrink.\n"
"\tPenalty(width,penalty,flagged=0) creates a Knuth penalty Box with the specified width and penalty.\n"
;

static struct PyMethodDef _methods[] = {
	{"defaultEncoding", _pdfmetrics_defaultEncoding, 1, "defaultEncoding([encoding])\ngets/sets the default encoding."},
	{"getFonts", _pdfmetrics_getFonts, 1, "getFonts()\nreturns font names."},
	{"getFontInfo", _pdfmetrics_getFontInfo, 1, "getFontInfo(fontName,encoding)\nreturns info ([widths],ascent,descent)."},
	{"setFontInfo", _pdfmetrics_setFontInfo, 1, "setFontInfo(fontName,encoding,ascent, descent, widths)\nadds the font to the table for encoding"},
	{"stringWidth", _pdfmetrics_stringWidth, 1, "stringWidth(text,fontName,fontSize,[encoding]) returns width of text in points"},
	{"_instanceStringWidth", _pdfmetrics_instanceStringWidth, 1, "_instanceStringWidth(text,fontSize) like stringWidth, but gets fontName from self"},
	{"_SWRecover", _pdfmetrics__SWRecover, 1,
					"_SWRecover([callable])\n"
					"get/set the string width recovery\n"
					"callback callable(text,font,size,encoding)\n"
					"return None to retry or the correct result."},
	{"_AsciiBase85Encode", _a85_encode, METH_VARARGS, "_AsciiBase85Encode(\".....\") return encoded string"},
	{"_AsciiBase85Decode", _a85_decode, METH_VARARGS, "_AsciiBase85Decode(\".....\") return decoded string"},
	{"escapePDF", escapePDF, METH_VARARGS, "escapePDF(s) return PDF safed string"},
	{"_instanceEscapePDF", _instanceEscapePDF, METH_VARARGS, "_instanceEscapePDF(s) return PDF safed string"},
	{"fp_str", _fp_str, METH_VARARGS, "fp_str(a0, a1,...) convert numerics to blank separated string"},
	{"_sameFrag", _sameFrag, 1, "_sameFrag(f,g) return 1 if fragments have same style"},
#ifdef	ATTRDICT
	{"_AttrDict", _AttrDict, METH_VARARGS, "_AttrDict() create a dict which can use attribute notation"},
#endif
	{"calcChecksum", ttfonts_calcChecksum, METH_VARARGS, "calcChecksum(string) calculate checksums for TTFs"},
	{"add32", ttfonts_add32, METH_VARARGS, "add32(x,y)  32 bit unsigned x+y"},
	{"hex32", hex32, METH_VARARGS, "hex32(x)  32 bit unsigned-->0X8.8X string"},
	{"Box",	(PyCFunction)Box,	METH_VARARGS|METH_KEYWORDS, "Box(width,character=None) create a Knuth Box instance"},
	{"Glue", (PyCFunction)Glue,	METH_VARARGS|METH_KEYWORDS, "Glue(width,stretch,shrink) create a Knuth Glue instance"},
	{"Penalty", (PyCFunction)Penalty,	METH_VARARGS|METH_KEYWORDS, "Penalty(width,penalty,flagged=0) create a Knuth Penalty instance"},
	{NULL,		NULL}		/* sentinel */
	};

/*Initialization function for the module (*must* be called init_pdfmetrics)*/
void init_rl_accel(void)
{
	PyObject *m, *d, *v;
	BoxType.ob_type = &PyType_Type;
	GlueType.ob_type = &PyType_Type;
	PenaltyType.ob_type = &PyType_Type;

	/*Create the module and add the functions */
	m = Py_InitModule("_rl_accel", _methods);

	/*Add some symbolic constants to the module */
	d = PyModule_GetDict(m);

#ifdef	ATTRDICT
	/*set up our modified dictionary type*/
	_AttrDictType = PyDict_Type;
	_AttrDictType.tp_doc = _AttrDict_tp_doc;
	_AttrDictType.tp_name = "_AttrDict";
	_AttrDictType.tp_getattr = _AttrDict_getattr;
	_AttrDictType.tp_setattr = _AttrDict_setattr;
	_AttrDict_as_mapping.mp_length = _AttrDictType.tp_as_mapping->mp_length;
	dict_subscript = _AttrDictType.tp_as_mapping->mp_subscript;
	dict_ass_sub = _AttrDictType.tp_as_mapping->mp_ass_subscript;
	_AttrDictType.tp_as_mapping = &_AttrDict_as_mapping;
	v = PyObject_GetAttrString(d,"has_key");
	_AttrDict_MethodChain[0].methods = mapp_methods;
	_AttrDict_MethodChain[0].link = &_AttrDict_MethodChain[1];
	_AttrDict_MethodChain[1].methods = (PyMethodDef*)(((PyCFunctionObject*)v)->m_ml);
	_AttrDict_MethodChain[1].link = NULL;
	Py_DECREF(v);
#endif
	ErrorObject = PyString_FromString("_rl_accel.error");
	PyDict_SetItemString(d, "error", ErrorObject);
	moduleVersion = PyString_FromString(VERSION);
	PyDict_SetItemString(d, "version", moduleVersion );

	/*add in the docstring */
	PyDict_SetItemString(d, "__doc__", Py_BuildValue("s", __doc__));

	/* Check for errors */
	if (PyErr_Occurred()) Py_FatalError("can't initialize module _rl_accel");
}<commit_msg>Added in BoxList, removed AttrDict<commit_after>/****************************************************************************
#copyright ReportLab Inc. 2000
#see license.txt for license details
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/lib/_rl_accel.c?cvsroot=reportlab
#$Header: /tmp/reportlab/reportlab/lib/_rl_accel.c,v 1.39 2004/04/05 07:47:18 rgbecker Exp $
 ****************************************************************************/
#if 0
static __version__=" $Id: _rl_accel.c,v 1.39 2004/04/05 07:47:18 rgbecker Exp $ "
#endif
#include "Python.h"
#include <stdlib.h>
#include <math.h>
#define DEFERRED_ADDRESS(A) 0
#if defined(__GNUC__) || defined(sun) || defined(_AIX) || defined(__hpux)
#	define STRICMP strcasecmp
#elif defined(_MSC_VER)
#	define STRICMP stricmp
#elif defined(macintosh)
# include <extras.h>
# define strdup _strdup
# define STRICMP _stricmp
#else
#	error "Don't know how to define STRICMP"
#endif
#ifndef max
#	define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#	define min(a,b) ((a)<(b)?(a):(b))
#endif
#define VERSION "0.47"
#define MODULE "_rl_accel"


static PyObject *moduleVersion;
typedef struct _fI_t {
		char*			name;
		int				ascent, descent;
		int				widths[256];
		struct _fI_t*	next;
		} fI_t;

typedef struct _eI_t {
		char*			name;
		fI_t*			fonts;
		struct _eI_t*	next;
		} eI_t;

eI_t		*Encodings=NULL;
eI_t		*defaultEncoding = NULL;
PyObject	*_SWRecover=NULL;

static PyObject *ErrorObject;

static	eI_t*	find_encoding(char* name)
{
	eI_t*	e = Encodings;
	for(;e;e=e->next) if(!STRICMP(name,e->name)) return e;
	return (eI_t*)0;
}

static	fI_t* find_font(char* name, fI_t* f)
{
	for(;f;f=f->next) if(!STRICMP(name,f->name)) return f;
	return (fI_t*)0;
}

static	int _parseSequenceInt(PyObject* e, int i, int *x)
{
	PyObject	*p;
	if((p = PySequence_GetItem(e,i)) && (p = PyNumber_Int(p))){
		*x=PyInt_AS_LONG(p);
		return 1;
		}
	return 0;
}

static PyObject *_pdfmetrics__SWRecover(PyObject* dummy, PyObject* args)
{
	PyObject *result = NULL;
	PyObject *temp=NULL;

	if (PyArg_ParseTuple(args, "|O:_SWRecover", &temp)) {
		if(temp){
			if (!PyCallable_Check(temp)) {
				PyErr_SetString(PyExc_TypeError, "parameter must be callable");
				return NULL;
				}
			Py_INCREF(temp);					/* Add a reference to new callback */
			Py_XDECREF(_SWRecover);	/* Dispose of previous callback */
			_SWRecover = temp;				/* Remember new callback */
			}
		else if(_SWRecover){
			Py_INCREF(_SWRecover);
			return _SWRecover;
			}
		/* Boilerplate to return "None" */
		Py_INCREF(Py_None);
		result = Py_None;
		}
	return result;
}

static PyObject *_pdfmetrics_defaultEncoding(PyObject *self, PyObject* args)
{
	char*	encoding=NULL;
	eI_t*	e;
	if (!PyArg_ParseTuple(args, "|s", &encoding)) return NULL;
	if(encoding){
		if(!(e= find_encoding(encoding))){
			e = (eI_t*)malloc(sizeof(eI_t));
			e->name = strdup(encoding);
			e->next = Encodings;
			e->fonts = NULL;
			Encodings = e;
			}
		defaultEncoding = e;
		}
	else if(defaultEncoding) return Py_BuildValue("s",defaultEncoding->name);
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *_pdfmetrics_setFontInfo(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding;
	int			ascent, descent;
	PyObject	*pW;
	int			i;
	eI_t*		e;
	fI_t*		f;

	if (!PyArg_ParseTuple(args, "ssiiO", &fontName, &encoding, &ascent, &descent,&pW)) return NULL;
	i = PySequence_Length(pW);
	if(i!=256){
badSeq:	PyErr_SetString(ErrorObject,"widths should be a length 256 sequence of integers");
		return NULL;
		}
	e = find_encoding(encoding);
	if(!e){
		e = (eI_t*)malloc(sizeof(eI_t));
		e->name = strdup(encoding);
		e->next = Encodings;
		e->fonts = NULL;
		Encodings = e;
		f = NULL;
		}
	else
		f = find_font(fontName,e->fonts);

	if(!f){
		f = (fI_t*)malloc(sizeof(fI_t));
		f->name = strdup(fontName);
		f->next = e->fonts;
		e->fonts = f;
		}
	f->ascent = ascent;
	f->descent = descent;
	for(i=0;i<256;i++)
		if(!_parseSequenceInt(pW,i,&f->widths[i])) goto badSeq;

	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *_pdfmetrics_getFonts(PyObject *self, PyObject *args)
{
	char		*encoding=0;
	fI_t*		f;
	eI_t*		e;
	int			nf;
	PyObject	*r;
	if (!PyArg_ParseTuple(args, "|s:getFonts", &encoding)) return NULL;
	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	for(nf=0,f=e->fonts;f;f=f->next) nf++;

	r = PyList_New(nf);
	for(nf=0,f=e->fonts;f;f=f->next) PyList_SetItem(r,nf++,PyString_FromString(f->name));

	return r;
}

static PyObject *_pdfmetrics_getFontInfo(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding=0;
	eI_t*		e;
	fI_t*		f;
	int			i;
	PyObject	*r, *t;

	if (!PyArg_ParseTuple(args, "s|s", &fontName, &encoding)) return NULL;
	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	if(!(f = find_font(fontName,e->fonts))){
		PyErr_SetString(ErrorObject,"unknown font");
		return NULL;
		}

	t = PyList_New(256);
	for(i=0;i<256;i++){
		PyList_SetItem(t,i,PyInt_FromLong(f->widths[i]));
		}
	r = PyTuple_New(3);
	PyTuple_SetItem(r,0,t);
	PyTuple_SetItem(r,1,PyInt_FromLong(f->ascent));
	PyTuple_SetItem(r,2,PyInt_FromLong(f->descent));
	return r;
}

static PyObject *_pdfmetrics_stringWidth(PyObject *self, PyObject* args)
{
	char		*fontName, *encoding=NULL;
	unsigned char *text;
	double		fontSize;
	fI_t		*fI;
	eI_t		*e;
	int			w, *width, i, textLen;
	static int	recover=1;

	if (!PyArg_ParseTuple(args, "s#sd|s", &text, &textLen, &fontName, &fontSize, &encoding)) return NULL;
	if(fontSize<=0){
		PyErr_SetString(ErrorObject,"bad fontSize");
		return NULL;
		}

	if(!(e=encoding?find_encoding(encoding):defaultEncoding)){
		PyErr_SetString(ErrorObject,"unknown encoding");
		return NULL;
		}

	if(!(fI=find_font(fontName,e->fonts))){
		if(_SWRecover && recover){
			PyObject *arglist = Py_BuildValue("(s#sds)",text,textLen,fontName,fontSize,e->name);
			PyObject *result;
			if(!arglist){
				PyErr_SetString(ErrorObject,"recovery failed!");
				return NULL;
				}
			recover = 0;
			result = PyEval_CallObject(_SWRecover, arglist);
			recover = 1;
			Py_DECREF(arglist);
			if(!result) return NULL;
			if(result!=Py_None) return result;
			Py_DECREF(result);
			if((fI=find_font(fontName,e->fonts))) goto L2;
			}
		PyErr_SetString(ErrorObject,"unknown font");
		return NULL;
		}

L2:
	width = fI->widths;
	for(i=w=0;i<textLen;i++)
		w += width[text[i]];

	return Py_BuildValue("f",0.001*fontSize*w);
}

static PyObject *_pdfmetrics_instanceStringWidth(PyObject *unused, PyObject* args)
{
	PyObject	*pfontName, *self;
	char		*fontName;
	unsigned char *text;
	double		fontSize;
	fI_t		*fI;
	eI_t		*e;
	int			w, *width, i, textLen;
	static int	recover=1;

	if (!PyArg_ParseTuple(args, "Os#d", &self, &text, &textLen, &fontSize)) return NULL;
	if(fontSize<=0){
		PyErr_SetString(ErrorObject,"bad fontSize");
		return NULL;
		}

	pfontName = PyObject_GetAttrString(self,"fontName");
	if(!pfontName){
		PyErr_SetString(PyExc_AttributeError,"No attribute fontName");
		return NULL;
		}

	if(!PyString_Check(pfontName)){
		Py_DECREF(pfontName);
		PyErr_SetString(PyExc_TypeError,"Attribute fontName is not a string");
		return NULL;
		}
	fontName = PyString_AsString(pfontName);

	e = defaultEncoding;

	if(!(fI=find_font(fontName,e->fonts))){
		if(_SWRecover && recover){
			PyObject *arglist = Py_BuildValue("(s#sd)",text,textLen,fontName,fontSize);
			PyObject *result;
			if(!arglist){
				PyErr_SetString(ErrorObject,"recovery failed!");
				goto L1;
				}
			recover = 0;
			result = PyEval_CallObject(_SWRecover, arglist);
			recover = 1;
			Py_DECREF(arglist);
			if(!result) goto L1;
			if(result!=Py_None) return result;
			Py_DECREF(result);
			if((fI=find_font(fontName,e->fonts))) goto L2;
			}
		PyErr_SetString(ErrorObject,"unknown font");
L1:		Py_DECREF(pfontName);
		return NULL;
		}

L2:	Py_DECREF(pfontName);
	width = fI->widths;
	for(i=w=0;i<textLen;i++)
		w += width[text[i]];

	return Py_BuildValue("f",0.001*fontSize*w);
}

#define a85_0		   1L
#define a85_1		   85L
#define a85_2		 7225L
#define a85_3	   614125L
#define a85_4	 52200625L

PyObject *_a85_encode(PyObject *self, PyObject *args)
{
	unsigned char	*inData;
	int				length, blocks, extra, i, k, lim;
	unsigned long	block, res;
	char			*buf;
	PyObject		*retVal;

	if (!PyArg_ParseTuple(args, "z#", &inData, &length)) return NULL;

	blocks = length / 4;
	extra = length % 4;

	buf = (char*)malloc((blocks+1)*5+3);
	lim = 4*blocks;

	for(k=i=0; i<lim; i += 4){
		/*
		 * If you evere have trouble with this consider using masking to ensure
		 * that the shifted quantity is only 8 bits long
		 */
		block = ((unsigned long)inData[i]<<24)|((unsigned long)inData[i+1]<<16)
				|((unsigned long)inData[i+2]<<8)|((unsigned long)inData[i+3]);
		if (block == 0) buf[k++] = 'z';
		else {
			res = block/a85_4;
			buf[k++] = (char)(res+33);
			block -= res*a85_4;

			res = block/a85_3;
			buf[k++] = (char)(res+33);
			block -= res*a85_3;

			res = block/a85_2;
			buf[k++] = (char)(res+33);
			block -= res*a85_2;

			res = block / a85_1;
			buf[k++] = (char)(res+33);

			buf[k++] = (char)(block-res*a85_1+33);
			}
		}

	if(extra>0){
		block = 0L;

		for (i=0; i<extra; i++)
			block += (unsigned long)inData[length-extra+i] << (24-8*i);

		res = block/a85_4;
		buf[k++] = (char)(res+33);
		if(extra>=1){
			block -= res*a85_4;

			res = block/a85_3;
			buf[k++] = (char)(res+33);
			if(extra>=2){
				block -= res*a85_3;

				res = block/a85_2;
				buf[k++] = (char)(res+33);
				if(extra>=3) buf[k++] = (char)((block-res*a85_2)/a85_1+33);
				}
			}
		}

	buf[k++] = '~';
	buf[k++] = '>';
	retVal = PyString_FromStringAndSize(buf, k);
	free(buf);
	return retVal;
}

PyObject *_a85_decode(PyObject *self, PyObject *args)
{
	unsigned char	*inData, *p, *q, *tmp, *buf;
	unsigned int	length, blocks, extra, k, num, c1, c2, c3, c4, c5;
	static unsigned pad[] = {0,0,0xffffff,0xffff,0xff};
	PyObject		*retVal;

	if (!PyArg_ParseTuple(args, "z#", &inData, &length)) return NULL;
	for(k=0,q=inData, p=q+length;q<p && (q=(unsigned char*)strchr((const char*)q,'z'));k++, q++);	/*count 'z'*/
	length += k*4;
	tmp = q = (unsigned char*)malloc(length+1);
	while(inData<p && (k = *inData++)){
		if(isspace(k)) continue;
		if(k=='z'){
			/*turn 'z' into '!!!!!'*/
			memcpy(q,"!!!!!",5);
			q += 5;
			}
		else
			*q++ = k;
		}
	inData = tmp;
	length = q - inData;
	buf = inData+length-2;
	if(buf[0]!='~' || buf[1]!='>'){
		PyErr_SetString(ErrorObject, "Invalid terminator for Ascii Base 85 Stream");
		free(inData);
		return NULL;
		}
	length -= 2;
	buf[0] = 0;

	blocks = length / 5;
	extra = length % 5;

	buf = (unsigned char*)malloc((blocks+1)*4);
	q = inData+blocks*5;
	for(k=0;inData<q;inData+=5){
		c1 = inData[0]-33;
		c2 = inData[1]-33;
		c3 = inData[2]-33;
		c4 = inData[3]-33;
		c5 = inData[4]-33;
		num = (((c1*85+c2)*85+c3)*85+c4)*85+c5;
		buf[k++] = num>>24;
		buf[k++] = num>>16;
		buf[k++] = num>>8;
		buf[k++] = num;
		}
	if(extra>1){
		c1 = inData[0]-33;
		c2 = extra>=2 ? inData[1]-33: 0;
		c3 = extra>=3 ? inData[2]-33: 0;
		c4 = extra>=4 ? inData[3]-33: 0;
		c5 = 0;
		num = (((c1*85+c2)*85+c3)*85+c4)*85+c5 + pad[extra];
		if(extra>1){
			buf[k++] = num>>24;
			if(extra>2){
				buf[k++] = num>>16;
				if(extra>3){
					buf[k++] = num>>8;
					}
				}
			}
		}
	retVal = PyString_FromStringAndSize((const char*)buf, k);
	free(buf);
	free(tmp);
	return retVal;
}

static	char* _fp_fmts[]={"%.0f", "%.1f", "%.2f", "%.3f", "%.4f", "%.5f", "%.6f"};
static	char *_fp_one(PyObject *pD)
{
	double	d;
	static	char s[30];
	int l;
	char*	dot;
	if((pD=PyNumber_Float(pD))){
		d = PyFloat_AS_DOUBLE(pD);
		Py_DECREF(pD);
		}
	else {
		PyErr_SetString(ErrorObject, "bad numeric value");
		return NULL;
		}
	if(fabs(d)<=1.0e-7){
		s[0]='0';
		s[1]=0;
		}
	else{
		if(fabs(d)>1) l = min(max(0,6-(int)log10(fabs(d))),6);
		else l = 6;
		sprintf(s,_fp_fmts[l], d);
		l = strlen(s)-1;
		while(l && s[l]=='0') l--;
		if(s[l]=='.' || s[l]==',') s[l]=0;
		else {
			s[l+1]=0;
			if(s[0]=='0' && (s[1]=='.'||s[1]==',')){
				if(s[1]==',') s[1] = '.';
				return s+1;
				}
			}
		if((dot=strchr(s,','))) *dot = '.';
		}
	return s;
}

PyObject *_fp_str(PyObject *self, PyObject *args)
{
	int				aL;
	PyObject		*retVal;
	char			*pD;
	char			*buf, *pB;
	int				i;

	if((aL=PySequence_Length(args))>=0){
		if(aL==1){
			retVal = PySequence_GetItem(args,0);
			if((i=PySequence_Length(retVal))>=0){
				aL = i;
				args = retVal;
				}
			else PyErr_Clear();
			Py_DECREF(retVal);
			}
		buf=malloc(31*aL);
		pB = buf;
		for(i=0;i<aL;i++){
			retVal = PySequence_GetItem(args,i);
			if(retVal){
				pD = _fp_one(retVal);
				Py_DECREF(retVal);
				}
			else pD = NULL;
			if(!pD){
				free(buf);
				return NULL;
				}
			if(pB!=buf){
				*pB++ = ' ';
				}
			strcpy(pB,pD);
			pB = pB + strlen(pB);
			}
		*pB = 0;
		retVal = PyString_FromString(buf);
		free(buf);
		return retVal;
		}
	else {
		PyErr_Clear();
		PyArg_ParseTuple(args, "O:_fp_str", &retVal);
		return NULL;
		}
}

static PyObject *_escapePDF(unsigned char* text, int textlen)
{
	unsigned char*	out = PyMem_Malloc((textlen<<2)+1);
	int				j=0, i=0;
	char			buf[4];
	PyObject*		ret;

	while(i<textlen){
		unsigned char c = text[i++];
		if(c<32 || c>=127){
			sprintf(buf,"%03o",c);
			out[j++] = '\\';
			out[j++] = buf[0];
			out[j++] = buf[1];
			out[j++] = buf[2];
			}
		else {
			if(c=='\\' || c=='(' || c==')') out[j++] = '\\';
			out[j++] = c;
			}
		}
	ret = PyString_FromStringAndSize((const char *)out,j);
	PyMem_Free(out);
	return ret;
}

static PyObject *escapePDF(PyObject *self, PyObject* args)
{
	unsigned char	*text;
	int				textLen;

	if (!PyArg_ParseTuple(args, "s#:escapePDF", &text, &textLen)) return NULL;
	return _escapePDF(text,textLen);
}

static PyObject *_instanceEscapePDF(PyObject *unused, PyObject* args)
{
	PyObject		*self;
	unsigned char	*text;
	int				textLen;

	if (!PyArg_ParseTuple(args, "Os#:_instanceEscapePDF", &self, &text, &textLen)) return NULL;
	return _escapePDF(text,textLen);
}

static PyObject *_sameFrag(PyObject *self, PyObject* args)
{
	PyObject *f, *g;
	static char *names[] = {"fontName", "fontSize", "textColor", "rise", "underline", NULL};
	int	r=0, t;
	char **p;
	if (!PyArg_ParseTuple(args, "OO:_sameFrag", &f, &g)) return NULL;
	if(PyObject_HasAttrString(f,"cbDefn")||PyObject_HasAttrString(g,"cbDefn")) goto L0;
	for(p=names;*p;p++){
		PyObject *fa, *ga;
		fa = PyObject_GetAttrString(f,*p);
		if(!fa){
L1:			return NULL;
			}
		ga = PyObject_GetAttrString(g,*p);
		if(!ga){
			Py_DECREF(fa);
			goto L1;
			}
		t = PyObject_Compare(fa,ga);
		Py_DECREF(fa);
		Py_DECREF(ga);
		if(PyErr_Occurred()) goto L1;
		if(t) goto L0;
		}
	r = 1;
L0:	return PyInt_FromLong((long)r);
}

static PyObject *ttfonts_calcChecksum(PyObject *self, PyObject* args)
{
	unsigned char	*data;
	int				dataLen;
	unsigned long	Sum = 0L;
	unsigned char	*EndPtr;
	unsigned long n;
	int leftover;


	if (!PyArg_ParseTuple(args, "s#:calcChecksum", &data, &dataLen)) return NULL;
	EndPtr = data + (dataLen & ~3);

	/*full ULONGs*/
	while(data < EndPtr){
		n = ((*data++) << 24);
		n += ((*data++) << 16);
		n += ((*data++) << 8);
		n += ((*data++));
		Sum += n;
		}

	/*pad with zeros*/
	leftover = dataLen & 3;
	if(leftover){
		n = ((*data++) << 24);
		if (leftover>1) n += ((*data++) << 16);
		if (leftover>2) n += ((*data++) << 8);
		Sum += n;
		}

	return PyInt_FromLong(Sum);
}

static PyObject *ttfonts_add32(PyObject *self, PyObject* args)
{
	unsigned long x, y;
#if PY_MAJOR_VERSION>=2 && PY_MINOR_VERSION>=3
	PyObject	*ox, *oy;
	if(!PyArg_ParseTuple(args, "OO:add32", &ox, &oy)) return NULL;
	if(PyLong_Check(ox)){
		x = PyLong_AsUnsignedLongMask(ox);
		}
	else{
		x = PyInt_AsLong(ox);
		if(PyErr_Occurred()) return NULL;
		}
	if(PyLong_Check(oy)){
		y = PyLong_AsUnsignedLongMask(oy);
		}
	else{
		y = PyInt_AsLong(oy);
		if(PyErr_Occurred()) return NULL;
		}
#else
	if(!PyArg_ParseTuple(args, "ii:add32", &x, &y)) return NULL;
#endif
	x += y;
	return PyInt_FromLong(x);
}

static PyObject *hex32(PyObject *self, PyObject* args)
{
	unsigned long x;
	char	buf[20];
#if PY_MAJOR_VERSION>=2 && PY_MINOR_VERSION>=3
	PyObject	*ox;
	if(!PyArg_ParseTuple(args, "O:hex32", &ox)) return NULL;
	if(PyLong_Check(ox)){
		x = PyLong_AsUnsignedLongMask(ox);
		}
	else{
		x = PyInt_AsLong(ox);
		if(PyErr_Occurred()) return NULL;
		}
#else
	if(!PyArg_ParseTuple(args, "i:hex32", &x)) return NULL;
#endif
	sprintf(buf,"0X%8.8X",x);
	return PyString_FromString(buf);
}

#if PY_VERSION_HEX>=0x02020000
#define HAVE_BOX
/*Box start**************/
typedef struct {
	PyObject_HEAD
	unsigned	is_box:1;
	unsigned	is_glue:1;
	unsigned	is_penalty:1;
	unsigned	is_none:1;
	double		width,stretch,shrink,penalty;
	int			flagged;
	char		character;
	} BoxObject;

static void BoxFree(BoxObject* self)
{
	PyMem_DEL(self);
}

static int Box_set_int(char* name, int* pd, PyObject *value)
{
	PyObject *v = PyNumber_Int(value);
	if(!v) return -1;
	*pd = PyInt_AsLong(v);
	Py_DECREF(v);
	return 0;
}

static int Box_set_double(char* name, double* pd, PyObject *value)
{
	PyObject *v = PyNumber_Float(value);
	if(!v) return -1;
	*pd = PyFloat_AsDouble(v);
	Py_DECREF(v);
	return 0;
}

static int Box_set_character(BoxObject *self, PyObject *value)
{
	if(value==Py_None){
		self->is_none = 1;
		}
	else {
		char *v = PyString_AsString(value);
		if(!v) return -1;
		if(PyString_GET_SIZE(value)!=1){
			PyErr_Format(PyExc_AttributeError,"Bad size %d('%s') for attribute character",PyString_GET_SIZE(value),v);
			return -1;
			}
		self->character = v[0];
		self->is_none = 0;
		}

	return 0;
}

static int Box_setattr(BoxObject *self, char *name, PyObject* value)
{
	if(!strcmp(name,"width")) return Box_set_double(name,&self->width,value);
	else if(!strcmp(name,"character")) return Box_set_character(self,value);
	else if(!strcmp(name,"stretch")) return Box_set_double(name,&self->stretch,value);
	else if(!strcmp(name,"shrink")) return Box_set_double(name,&self->shrink,value);
	else if(!strcmp(name,"penalty")) return Box_set_double(name,&self->penalty,value);
	else if(!strcmp(name,"flagged")) return Box_set_int(name,&self->flagged,value);
	else if(
			!strcmp(name,"is_penalty") ||
			!strcmp(name,"is_box") ||
			!strcmp(name,"is_glue")
			) PyErr_Format(PyExc_AttributeError, "readonly attribute %s", name);
	else PyErr_Format(PyExc_AttributeError, "no attribute %s", name);
	return -1;
}

static double _Glue_compute_width(BoxObject *self, double r)
{
	if(self->is_glue) return self->width+r*(r<0?self->shrink:self->stretch);
	return self->width;
}

static PyObject* Glue_compute_width(BoxObject *self, PyObject *args)
{
	double r;
	if(!PyArg_ParseTuple(args, "d:compute_width", &r)) return NULL;
	return PyFloat_FromDouble(_Glue_compute_width(self,r));
}

static struct PyMethodDef Box_methods[] = {
	{"compute_width", (PyCFunction)Glue_compute_width, METH_VARARGS|METH_KEYWORDS, "compute_width(r)"},
	{NULL, NULL}		/* sentinel */
	};

static PyObject* Box_get_character(unsigned is_none, char c)
{
	if(!is_none) return PyString_FromStringAndSize(&c,1);
	else {
		Py_INCREF(Py_None);
		return Py_None;
		}
}

static PyObject* Box_getattr(BoxObject *self, char *name)
{
	if(!strcmp(name,"width")) return PyFloat_FromDouble(self->width);
	else if(!strcmp(name,"character")) return Box_get_character(self->is_none,self->character);
	else if(!strcmp(name,"is_box")) return PyInt_FromLong(self->is_box);
	else if(!strcmp(name,"is_glue")) return PyInt_FromLong(self->is_glue);
	else if(!strcmp(name,"is_penalty")) return PyInt_FromLong(self->is_penalty);
	else if(!strcmp(name,"stretch")) return PyFloat_FromDouble(self->stretch);
	else if(!strcmp(name,"shrink")) return PyFloat_FromDouble(self->shrink);
	else if(!strcmp(name,"penalty")) return PyFloat_FromDouble(self->penalty);
	else if(!strcmp(name,"flagged")) return PyInt_FromLong(self->flagged);
	return Py_FindMethod(Box_methods, (PyObject *)self, name);
}

static PyTypeObject BoxType = {
	PyObject_HEAD_INIT(0)
	0,								/*ob_size*/
	"Box",							/*tp_name*/
	sizeof(BoxObject),				/*tp_basicsize*/
	0,								/*tp_itemsize*/
	/* methods */
	(destructor)BoxFree,			/*tp_dealloc*/
	(printfunc)0,					/*tp_print*/
	(getattrfunc)Box_getattr,		/*tp_getattr*/
	(setattrfunc)Box_setattr,		/*tp_setattr*/
	(cmpfunc)0,						/*tp_compare*/
	(reprfunc)0,					/*tp_repr*/
	0,								/*tp_as_number*/
	0,								/*tp_as_sequence*/
	0,								/*tp_as_mapping*/
	(hashfunc)0,					/*tp_hash*/
	(ternaryfunc)0,					/*tp_call*/
	(reprfunc)0,					/*tp_str*/

	/* Space for future expansion */
	0L,0L,0L,0L,
	/* Documentation string */
	"Box instance, see doc string for details."
};

static BoxObject* Box(PyObject* module, PyObject* args, PyObject* kw)
{
	BoxObject* self;
	char	*kwlist[] = {"width","character",NULL};
	PyObject	*pC=NULL;
	double		w;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"d|O:Box",kwlist,&w,&pC)) return NULL;
	if(!(self = PyObject_NEW(BoxObject, &BoxType))) return NULL;
	self->shrink = self->stretch = self->penalty = (double)(self->is_glue = self->is_penalty = 0);
	self->is_box = 1;
	self->width = w;
	if(Box_set_character(self, pC ? pC : Py_None)){
		BoxFree(self);
		return NULL;
		}

	return self;
}

static BoxObject* Glue(PyObject* module, PyObject* args, PyObject* kw)
{
	BoxObject* self;
	char	*kwlist[] = {"width","stretch","shrink",NULL};
	double		width,stretch,shrink;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"ddd:Glue",kwlist,&width,&stretch,&shrink)) return NULL;
	if(!(self = PyObject_NEW(BoxObject, &BoxType))) return NULL;
	self->is_box = self->is_penalty = 0;
	self->is_glue = self->is_none = 1;
	self->width = width;
	self->stretch = stretch;
	self->shrink = shrink;

	return self;
}

static BoxObject* Penalty(PyObject* module, PyObject* args, PyObject* kw)
{
	BoxObject* self;
	char	*kwlist[] = {"width","penalty","flagged",NULL};
	double	width,penalty;
	int		flagged = 0;

	if(!PyArg_ParseTupleAndKeywords(args,kw,"dd|i:Penalty",kwlist,&width,&penalty,&flagged)) return NULL;
	if(!(self = PyObject_NEW(BoxObject, &BoxType))) return NULL;
	self->shrink = self->stretch = (double)(self->is_box = self->is_glue = 0);
	self->is_penalty = self->is_none = 1;
	self->width = width;
	self->penalty = penalty;
	self->flagged = flagged;
	return self;
}
/*Box end****************/
/* BoxList -- a list subtype */
typedef struct {
	PyListObject list;
	int state;
	} BoxListobject;

static PyObject *BoxList_getstate(BoxListobject *self, PyObject *args)
{
	if (!PyArg_ParseTuple(args, ":getstate")) return NULL;
	return PyInt_FromLong(self->state);
}

static PyObject *BoxList_setstate(BoxListobject *self, PyObject *args)
{
	int state;

	if (!PyArg_ParseTuple(args, "i:setstate", &state))
		return NULL;
	self->state = state;
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *BoxList_specialmeth(PyObject *self, PyObject *args, PyObject *kw)
{
	PyObject *result = PyTuple_New(3);
	if(result!=NULL){
		if(self==NULL) self = Py_None;
		if(kw==NULL) kw = Py_None;
		Py_INCREF(self);
		PyTuple_SET_ITEM(result, 0, self);
		Py_INCREF(args);
		PyTuple_SET_ITEM(result, 1, args);
		Py_INCREF(kw);
		PyTuple_SET_ITEM(result, 2, kw);
		}
	return result;
}

static PyMethodDef BoxList_methods[] = {
	{"getstate", (PyCFunction)BoxList_getstate, METH_VARARGS, PyDoc_STR("getstate() -> state")},
	{"setstate", (PyCFunction)BoxList_setstate, METH_VARARGS, PyDoc_STR("setstate(state)")},
	/* These entries differ only in the flags; they are used by the tests in test.test_descr. */
	{"classmeth", (PyCFunction)BoxList_specialmeth, METH_VARARGS | METH_KEYWORDS | METH_CLASS, PyDoc_STR("classmeth(*args, **kw)")},
	{"staticmeth", (PyCFunction)BoxList_specialmeth, METH_VARARGS | METH_KEYWORDS | METH_STATIC, PyDoc_STR("staticmeth(*args, **kw)")},
	{NULL,	NULL},
	};

static PyTypeObject BoxList_type;

static int BoxList_init(BoxListobject *self, PyObject *args, PyObject *kwds)
{
	if(PyList_Type.tp_init((PyObject *)self, args, kwds)<0) return -1;
	self->state = 0;
	return 0;
}

static PyObject *BoxList_state_get(BoxListobject *self)
{
	return PyInt_FromLong(self->state);
}

static PyGetSetDef BoxList_getsets[] = {
	{"state", (getter)BoxList_state_get, NULL, PyDoc_STR("an int variable for demonstration purposes")},
	{0}
	};

static PyTypeObject BoxList_type = {
	PyObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type))
	0,
	"_rl_accel.BoxList",
	sizeof(BoxListobject),
	0,
	0,					/* 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 | Py_TPFLAGS_BASETYPE, /* tp_flags */
	0,					/* tp_doc */
	0,					/* tp_traverse */
	0,					/* tp_clear */
	0,					/* tp_richcompare */
	0,					/* tp_weaklistoffset */
	0,					/* tp_iter */
	0,					/* tp_iternext */
	BoxList_methods,			/* tp_methods */
	0,					/* tp_members */
	BoxList_getsets,			/* tp_getset */
	DEFERRED_ADDRESS(&PyList_Type),		/* tp_base */
	0,					/* tp_dict */
	0,					/* tp_descr_get */
	0,					/* tp_descr_set */
	0,					/* tp_dictoffset */
	(initproc)BoxList_init,		/* tp_init */
	0,					/* tp_alloc */
	0,					/* tp_new */
};
#endif

static char *__doc__=
"_rl_accel contains various accelerated utilities\n\
\tstringWidth a fast string width function\n\
\t_instanceStringWidth a method version of stringWidth\n\
\tdefaultEncoding gets/sets the default encoding for stringWidth\n\
\tgetFonts gets font names from the internal table\n\
\tgetFontInfo gets font info from the internal table\n\
\tsetFontInfo adds a font to the internal table\n\
\t_SWRecover gets/sets a callback for stringWidth recovery\n\
\tescapePDF makes a string safe for PDF\n\
\t_instanceEscapePDF method equivalent of escapePDF\n\
\n\
\t_AsciiBase85Encode does what is says\n\
\t_AsciiBase85Decode does what is says\n\
\n\
\tfp_str converts numeric arguments to a single blank separated string\n"
"\tcalcChecksum calculate checksums for TTFs\n"
"\tadd32 32 bit unsigned addition\n"
"\thex32 32 bit unsigned to 0X8.8X string\n"
#ifdef	HAVE_BOX
"\tBox(width,character=None) creates a Knuth character Box with the specified width.\n"
"\tGlue(width,stretch,shrink) creates a Knuth glue Box with the specified width, stretch and shrink.\n"
"\tPenalty(width,penalty,flagged=0) creates a Knuth penalty Box with the specified width and penalty.\n"
"\tBoxList() creates a knuth box list.\n"
#endif
;

static struct PyMethodDef _methods[] = {
	{"defaultEncoding", _pdfmetrics_defaultEncoding, 1, "defaultEncoding([encoding])\ngets/sets the default encoding."},
	{"getFonts", _pdfmetrics_getFonts, 1, "getFonts()\nreturns font names."},
	{"getFontInfo", _pdfmetrics_getFontInfo, 1, "getFontInfo(fontName,encoding)\nreturns info ([widths],ascent,descent)."},
	{"setFontInfo", _pdfmetrics_setFontInfo, 1, "setFontInfo(fontName,encoding,ascent, descent, widths)\nadds the font to the table for encoding"},
	{"stringWidth", _pdfmetrics_stringWidth, 1, "stringWidth(text,fontName,fontSize,[encoding]) returns width of text in points"},
	{"_instanceStringWidth", _pdfmetrics_instanceStringWidth, 1, "_instanceStringWidth(text,fontSize) like stringWidth, but gets fontName from self"},
	{"_SWRecover", _pdfmetrics__SWRecover, 1,
					"_SWRecover([callable])\n"
					"get/set the string width recovery\n"
					"callback callable(text,font,size,encoding)\n"
					"return None to retry or the correct result."},
	{"_AsciiBase85Encode", _a85_encode, METH_VARARGS, "_AsciiBase85Encode(\".....\") return encoded string"},
	{"_AsciiBase85Decode", _a85_decode, METH_VARARGS, "_AsciiBase85Decode(\".....\") return decoded string"},
	{"escapePDF", escapePDF, METH_VARARGS, "escapePDF(s) return PDF safed string"},
	{"_instanceEscapePDF", _instanceEscapePDF, METH_VARARGS, "_instanceEscapePDF(s) return PDF safed string"},
	{"fp_str", _fp_str, METH_VARARGS, "fp_str(a0, a1,...) convert numerics to blank separated string"},
	{"_sameFrag", _sameFrag, 1, "_sameFrag(f,g) return 1 if fragments have same style"},
	{"calcChecksum", ttfonts_calcChecksum, METH_VARARGS, "calcChecksum(string) calculate checksums for TTFs"},
	{"add32", ttfonts_add32, METH_VARARGS, "add32(x,y)  32 bit unsigned x+y"},
	{"hex32", hex32, METH_VARARGS, "hex32(x)  32 bit unsigned-->0X8.8X string"},
#ifdef	HAVE_BOX
	{"Box",	(PyCFunction)Box,	METH_VARARGS|METH_KEYWORDS, "Box(width,character=None) create a Knuth Box instance"},
	{"Glue", (PyCFunction)Glue,	METH_VARARGS|METH_KEYWORDS, "Glue(width,stretch,shrink) create a Knuth Glue instance"},
	{"Penalty", (PyCFunction)Penalty,	METH_VARARGS|METH_KEYWORDS, "Penalty(width,penalty,flagged=0) create a Knuth Penalty instance"},
#endif
	{NULL,		NULL}		/* sentinel */
	};

/*Initialization function for the module (*must* be called init_pdfmetrics)*/
void init_rl_accel(void)
{
	PyObject *m, *d;

	/*Create the module and add the functions and module doc string*/
	m = Py_InitModule3("_rl_accel", _methods,__doc__);

	/*Add some symbolic constants to the module */
	d = PyModule_GetDict(m);

	if(!ErrorObject){
		ErrorObject = PyErr_NewException("_rl_accel.error", NULL, NULL);
		if(!ErrorObject) goto err;
		}
	Py_INCREF(ErrorObject);
	PyModule_AddObject(m, "error", ErrorObject);
	moduleVersion = PyString_FromString(VERSION);
	PyDict_SetItemString(d, "version", moduleVersion );

#ifdef	HAVE_BOX
	BoxType.ob_type = &PyType_Type;
	BoxList_type.tp_base = &PyList_Type;
	if(PyType_Ready(&BoxList_type)<0) goto err;
	Py_INCREF(&BoxList_type);
	if(PyModule_AddObject(m, "BoxList", (PyObject *)&BoxList_type)<0)goto err;
#endif

err:/*Check for errors*/
	if (PyErr_Occurred()) Py_FatalError("can't initialize module _rl_accel");
}
{'fraction_non_alphanumeric': 0.17627245508982037, 'fraction_numerical': 0.01908682634730539, 'mean_word_length': 4.737072821613884, 'pattern_counts': {'":': 2, '<': 92, '<?xml version=': 0, '>': 264, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1520452', 'n_tokens_mistral': 28343, 'n_tokens_neox': 26210, 'n_words': 5240}