/* Copyright (c) 1996,97,98 by Lele Gaifax. All Rights Reserved * Copyright (c) 2002, 2003 Ronald Oussoren * * This software may be used and distributed freely for any purpose * provided that this notice is included unchanged on any and all * copies. The author does not warrant or guarantee this software in * any way. * * This file is part of the PyObjC package. * * RCSfile: objc_support.m,v * Revision: 1.24 * Date: 1998/08/18 15:35:58 * * Created Tue Sep 10 14:16:02 1996. */#include "pyobjc.h"#include <objc/Protocol.h>#include <unistd.h>#ifdef MACOSX/* OSX 10.1 doesn't define LLONG_MIN, LLONG_MAX and ULLONG_MAX */#ifndef LLONG_MIN#error "Mac OS X 10.1 not supported"#endif#endif#import <Foundation/NSInvocation.h>#import <Foundation/NSData.h> #import <Foundation/NSValue.h> #import <Foundation/NSDecimalNumber.h> #ifdef MACOSX#include <CoreFoundation/CFNumber.h>#endif /* MACOSX *//* * Category on NSObject to make sure that every object supports * the method __pyobjc_PythonObject__, this helps to simplify * pythonify_c_value. */@interfaceNSObject(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;+(PyObject*)__pyobjc_PythonObject__;@end/* PyObjCSupport */@implementationNSObject(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=(PyObject*)PyObjCObject_New(self,PyObjCObject_kDEFAULT,YES);PyObjC_RegisterPythonProxy(self,rval);}returnrval;}+(PyObject*)__pyobjc_PythonObject__{PyObject*rval;//rval = PyObjC_FindPythonProxy(self);rval=NULL;if(rval==NULL){rval=(PyObject*)PyObjCClass_New(self);//PyObjC_RegisterPythonProxy(self, rval);}returnrval;}@end/* PyObjCSupport */@interfaceNSProxy(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;+(PyObject*)__pyobjc_PythonObject__;@end/* PyObjCSupport */@implementationNSProxy(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=(PyObject*)PyObjCObject_New(self,PyObjCObject_kDEFAULT,YES);PyObjC_RegisterPythonProxy(self,rval);}returnrval;}+(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=NULL;//rval = PyObjC_FindPythonProxy(self);if(rval==NULL){rval=(PyObject*)PyObjCClass_New(self);//PyObjC_RegisterPythonProxy(self, rval);}returnrval;}@end/* PyObjCSupport */@interfaceProtocol(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;@end/* PyObjCSupport */@implementationProtocol(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=PyObjCFormalProtocol_ForProtocol(self);}returnrval;}@end/* PyObjCSupport */@interfaceObject(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;@end/* PyObjCSupport */@implementationObject(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=(PyObject*)PyObjCObject_New(self,PyObjCObject_kCLASSIC,NO);PyObjC_RegisterPythonProxy(self,rval);}returnrval;}@end/* PyObjCSupport */@interfaceNSString(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;@end/* NSString (PyObjCSupport) */@implementationNSString(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{/* Don't register the proxy, see XXX */PyObject*rval=(PyObject*)PyObjCUnicode_New(self);returnrval;}@end/* NSString (PyObjCSupport) */@interfaceNSNumber(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;@end/* NSNumber (PyObjCSupport) */@implementationNSNumber(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{/* FIXME: rewrite PyObjC_NSNumberWrapper in C */PyObject*rval;#ifdef MACOSX/* shortcut for booleans */if(kCFBooleanTrue==(CFBooleanRef)self){returnPyBool_FromLong(1);}elseif(kCFBooleanFalse==(CFBooleanRef)self){returnPyBool_FromLong(0);}#endifrval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=PyObjCObject_New(self,PyObjCObject_kDEFAULT,YES);if(PyObjC_NSNumberWrapper&&rval){PyObject*val=rval;rval=PyObject_CallFunctionObjArgs(PyObjC_NSNumberWrapper,val,NULL);Py_DECREF(val);}}returnrval;}@end@interfaceNSDecimalNumber(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__;@end/* NSDecimalNumber (PyObjCSupport) */@implementationNSDecimalNumber(PyObjCSupport)-(PyObject*)__pyobjc_PythonObject__{PyObject*rval;rval=PyObjC_FindPythonProxy(self);if(rval==NULL){rval=(PyObject*)PyObjCObject_New(self,PyObjCObject_kDEFAULT,YES);PyObjC_RegisterPythonProxy(self,rval);}returnrval;}@end#ifndef MAXstaticinlineintMAX(intx,inty){returnx>y?x:y;}#endif#if 0static inline intROUND(int v, int a){ return a * ((v+a-1)/a);}#elsestaticinlineintROUND(intv,inta){if(v%a==0){returnv;}else{returnv+a-(v%a);}}#endifstaticinlineconstchar*PyObjCRT_SkipTypeQualifiers(constchar*type){while(*type==_C_CONST||*type==_C_IN||*type==_C_INOUT||*type==_C_OUT||*type==_C_BYCOPY||*type==_C_ONEWAY){type++;}while(*type&&isdigit(*type))type++;returntype;}constchar*PyObjCRT_SkipTypeSpec(constchar*type){type=PyObjCRT_SkipTypeQualifiers(type);switch(*type){/* The following are one character type codes */case_C_UNDEF:case_C_CLASS:case_C_SEL:case_C_CHR:case_C_UCHR:case_C_CHARPTR:#ifdef _C_ATOMcase_C_ATOM:#endif#ifdef _C_BOOLcase_C_BOOL:#endifcase_C_SHT:case_C_USHT:case_C_INT:case_C_UINT:case_C_LNG:case_C_ULNG:case_C_FLT:case_C_DBL:case_C_VOID:case_C_LNGLNG:case_C_ULNGLNG:case_C_BFLD:/* Not really 1 character, but close enough */++type;break;case_C_ID:++type;#ifdef MACOSXif(*type=='"'){/* embedded field name in an ivar_type */type=strchr(type+1,'"');if(type!=NULL){type++;}}#endifbreak;case_C_ARY_B:/* skip digits, typespec and closing ']' */while(isdigit(*++type));type=PyObjCRT_SkipTypeSpec(type);assert(type==NULL||*type==_C_ARY_E);if(type)type++;break;case_C_STRUCT_B:/* skip name, and elements until closing '}' */while(*type!=_C_STRUCT_E&&*type++!='=');while(type&&*type!=_C_STRUCT_E){if(*type=='"'){/* embedded field names */type=strchr(type+1,'"');if(type!=NULL){type++;}else{returnNULL;}}type=PyObjCRT_SkipTypeSpec(type);}if(type)type++;break;case_C_UNION_B:/* skip name, and elements until closing ')' */while(*type!=_C_UNION_E&&*type++!='=');while(type&&*type!=_C_UNION_E){type=PyObjCRT_SkipTypeSpec(type);}if(type)type++;break;case_C_PTR:case_C_CONST:case_C_IN:case_C_INOUT:case_C_OUT:case_C_BYCOPY:case_C_ONEWAY:/* Just skip the following typespec */type=PyObjCRT_SkipTypeSpec(type+1);break;default:PyErr_Format(PyObjCExc_InternalError,"PyObjCRT_SkipTypeSpec: Unhandled type '%#x'",*type);returnNULL;}/* The compiler inserts a number after the actual signature, * this number may or may not be usefull depending on the compiler * version. We never use it. */while(type&&*type&&isdigit(*type))type++;returntype;}/*Return the alignment of an object specified by type *//** On MacOS X, the elements of a struct are aligned differently inside the* struct than outside. That is, the maximum alignment of any struct field* (except the first) is 4, doubles outside of a struct have an alignment of* 8.** Other platform don't seem to have this inconsistency.* * XXX: sizeof_struct, alignof_struct and {de,}pythonify_c_struct should* probably be moved to platform dependend files. As long as this is the* only platform dependent code this isn't worth the effort.*/#ifdef MACOSXstaticinlineintPyObjC_EmbeddedAlignOfType(constchar*type){intalign=PyObjCRT_AlignOfType(type);if(align<4){returnalign;}else{return4;}}#elsestaticinlineintPyObjC_EmbeddedAlignOfType(constchar*type){intalign=PyObjCRT_AlignOfType(type);/* GNUstep/ix86 seems to behave like this: */if(align<4){returnalign;}else{return4;}}#endifintPyObjCRT_AlignOfType(constchar*type){switch(*type){case_C_ID:return__alignof__(id);case_C_CLASS:return__alignof__(Class);case_C_SEL:return__alignof__(SEL);case_C_CHR:return__alignof__(char);case_C_UCHR:return__alignof__(unsignedchar);case_C_SHT:return__alignof__(short);case_C_USHT:return__alignof__(unsignedshort);#ifdef _C_BOOLcase_C_BOOL:return__alignof__(bool);#endifcase_C_INT:return__alignof__(int);case_C_UINT:return__alignof__(unsignedint);case_C_LNG:return__alignof__(long);case_C_ULNG:return__alignof__(unsignedlong);case_C_FLT:return__alignof__(float);case_C_DBL:return__alignof__(double);case_C_CHARPTR:return__alignof__(char*);#ifdef _C_ATOMcase_C_ATOM:return__alignof__(char*);#endifcase_C_PTR:return__alignof__(void*);case_C_LNGLNG:return__alignof__(longlong);case_C_ULNGLNG:return__alignof__(unsignedlonglong);case_C_ARY_B:while(isdigit(*++type))/* do nothing */;returnPyObjCRT_AlignOfType(type);case_C_STRUCT_B:{/* The alignment of a struct is the alignment of it's first * member */struct{intx;doubley;}fooalign;while(*type!=_C_STRUCT_E&&*type++!='=')/* do nothing */;if(*type!=_C_STRUCT_E){inthave_align=0;intalign=0;while(type!=NULL&&*type!=_C_STRUCT_E){if(*type=='"'){type=strchr(type+1,'"');if(type)type++;}if(have_align){align=MAX(align,PyObjC_EmbeddedAlignOfType(type));}else{align=PyObjCRT_AlignOfType(type);have_align=1;}type=PyObjCRT_SkipTypeSpec(type);}if(type==NULL)return-1;returnalign;}else{return__alignof__(fooalign);}}case_C_UNION_B:{intmaxalign=0;type++;while(*type!=_C_UNION_E){intitem_align=PyObjCRT_AlignOfType(type);if(item_align==-1)return-1;maxalign=MAX(maxalign,item_align);type=PyObjCRT_SkipTypeSpec(type);}returnmaxalign;}case_C_CONST:case_C_IN:case_C_INOUT:case_C_OUT:case_C_BYCOPY:case_C_ONEWAY:returnPyObjCRT_AlignOfType(type+1);default:PyErr_Format(PyObjCExc_InternalError,"PyObjCRT_AlignOfType: Unhandled type '%#x'",*type);return-1;}}/*The aligned size if the size rounded up to the nearest alignment.*/staticintPyObjCRT_AlignedSize(constchar*type){intsize=PyObjCRT_SizeOfType(type);intalign=PyObjCRT_AlignOfType(type);if(size==-1||align==-1)return-1;returnROUND(size,align);}/*return the size of an object specified by type */intPyObjCRT_SizeOfType(constchar*type){intitemSize;switch(*type){case_C_VOID:return0;case_C_ID:returnsizeof(id);case_C_CLASS:returnsizeof(Class);case_C_SEL:returnsizeof(SEL);case_C_CHR:returnsizeof(char);case_C_UCHR:returnsizeof(unsignedchar);case_C_SHT:returnsizeof(short);case_C_USHT:returnsizeof(unsignedshort);#ifdef _C_BOOLcase_C_BOOL:returnsizeof(bool);#endifcase_C_INT:returnsizeof(int);case_C_UINT:returnsizeof(unsignedint);case_C_LNG:returnsizeof(long);case_C_ULNG:returnsizeof(unsignedlong);case_C_FLT:returnsizeof(float);case_C_DBL:returnsizeof(double);case_C_LNGLNG:returnsizeof(longlong);case_C_ULNGLNG:returnsizeof(unsignedlonglong);case_C_PTR:case_C_CHARPTR:#ifdef _C_ATOMcase_C_ATOM:#endifreturnsizeof(char*);case_C_ARY_B:{intlen=atoi(type+1);intitem_align;while(isdigit(*++type));item_align=PyObjCRT_AlignedSize(type);if(item_align==-1)return-1;returnlen*item_align;}break;case_C_STRUCT_B:{intacc_size=0;inthave_align=0;intalign;intmax_align=0;while(*type!=_C_STRUCT_E&&*type++!='=');/* skip "<name>=" */while(*type!=_C_STRUCT_E){if(*type=='"'){type=strchr(type+1,'"');if(type)type++;}if(have_align){align=PyObjC_EmbeddedAlignOfType(type);if(align==-1)return-1;}else{align=PyObjCRT_AlignOfType(type);if(align==-1)return-1;have_align=1;}max_align=MAX(align,max_align);acc_size=ROUND(acc_size,align);itemSize=PyObjCRT_SizeOfType(type);if(itemSize==-1)return-1;acc_size+=itemSize;type=PyObjCRT_SkipTypeSpec(type);}if(max_align){acc_size=ROUND(acc_size,max_align);}returnacc_size;}case_C_UNION_B:{intmax_size=0;type++;while(*type!=_C_UNION_E){itemSize=PyObjCRT_SizeOfType(type);if(itemSize==-1)return-1;max_size=MAX(max_size,itemSize);type=PyObjCRT_SkipTypeSpec(type);}returnmax_size;}case_C_CONST:case_C_IN:case_C_INOUT:case_C_OUT:case_C_BYCOPY:case_C_ONEWAY:returnPyObjCRT_SizeOfType(type+1);default:PyErr_Format(PyObjCExc_InternalError,"PyObjCRT_SizeOfType: Unhandled type '%#x",*type);return-1;}}/*#F Returns a tuple of objects representing the content of a C arrayof type @var{type} pointed by @var{datum}. */staticPyObject*pythonify_c_array(constchar*type,void*datum){PyObject*ret;intnitems,itemidx,sizeofitem;unsignedchar*curdatum;nitems=atoi(type+1);while(isdigit(*++type));sizeofitem=PyObjCRT_SizeOfType(type);if(sizeofitem==-1)returnNULL;ret=PyTuple_New(nitems);if(!ret)returnNULL;curdatum=datum;for(itemidx=0;itemidx<nitems;itemidx++){PyObject*pyitem=NULL;pyitem=pythonify_c_value(type,curdatum);if(pyitem){PyTuple_SET_ITEM(ret,itemidx,pyitem);}else{Py_DECREF(ret);returnNULL;}curdatum+=sizeofitem;}returnret;}/*#F Returns a tuple of objects representing the content of a C structureof type @var{type} pointed by @var{datum}. */staticPyObject*pythonify_c_struct(constchar*type,void*datum){PyObject*ret;PyObject*converted;unsignedintoffset,itemidx;constchar*item;inthave_align=0,align;inthaveTuple;constchar*type_start=type;constchar*type_end=PyObjCRT_SkipTypeSpec(type);constchar*type_real_start=type;inttype_real_length=type_end-type_start;/* The compiler adds useless digits at the end of the signature */while(type_end!=type_start+1&&type_end[-1]!=_C_STRUCT_E){type_end--;}while(*type!=_C_STRUCT_E&&*type++!='='){/* skip "<name>=" */}haveTuple=0;ret=PyObjC_CreateRegisteredStruct(type_start,type_end-type_start);if(ret==NULL){intnitems;nitems=0;item=type;while(*item!=_C_STRUCT_E){nitems++;if(*item=='"'){item=strchr(item+1,'"');if(item)item++;}item=PyObjCRT_SkipTypeSpec(item);}haveTuple=1;ret=PyTuple_New(nitems);if(!ret)returnNULL;}item=type;offset=itemidx=0;while(*item!=_C_STRUCT_E){PyObject*pyitem;if(*item=='"'){item=strchr(item+1,'"');if(item)item++;}if(!have_align){align=PyObjCRT_AlignOfType(item);have_align=1;}else{align=PyObjC_EmbeddedAlignOfType(item);}offset=ROUND(offset,align);pyitem=pythonify_c_value(item,((char*)datum)+offset);if(pyitem){if(haveTuple){PyTuple_SET_ITEM(ret,itemidx,pyitem);}else{intr;r=PySequence_SetItem(ret,itemidx,pyitem);Py_DECREF(pyitem);if(r==-1){Py_DECREF(ret);returnNULL;}}}else{Py_DECREF(ret);returnNULL;}itemidx++;offset+=PyObjCRT_SizeOfType(item);item=PyObjCRT_SkipTypeSpec(item);}converted=[OC_PythonObject__pythonifyStruct:retwithType:type_real_startlength:type_real_length];Py_DECREF(ret);returnconverted;}/*#F Extracts the elements from the tuple @var{arg} and fills a C arrayof type @var{type} pointed by @var{datum}. Returns an error message, orNULL on success. */staticintdepythonify_c_array(constchar*type,PyObject*arg,void*datum){intnitems,itemidx,sizeofitem;unsignedchar*curdatum;PyObject*seq;nitems=atoi(type+1);while(isdigit(*++type));sizeofitem=PyObjCRT_AlignedSize(type);if(sizeofitem==-1){PyErr_Format(PyExc_ValueError,"cannot depythonify array of unknown type");return-1;}seq=PySequence_Fast(arg,"depythonifying array, got no sequence");if(seq==NULL){return-1;}if(nitems!=PySequence_Fast_GET_SIZE(seq)){Py_DECREF(seq);PyErr_Format(PyExc_ValueError,"depythonifying array of %d items, got one of %d",nitems,PyTuple_Size(arg));return-1;}curdatum=datum;for(itemidx=0;itemidx<nitems;itemidx++){PyObject*pyarg=PySequence_Fast_GET_ITEM(seq,itemidx);interr;err=depythonify_c_value(type,pyarg,curdatum);if(err==-1){Py_DECREF(seq);returnerr;}curdatum+=sizeofitem;}Py_DECREF(seq);return0;}/*#F Extracts the elements from the tuple @var{arg} and fills a C structureof type @var{type} pointed by @var{datum}. Returns an error message, orNULL on success. */staticintdepythonify_c_struct(constchar*types,PyObject*arg,void*datum){intnitems,offset,itemidx;inthave_align=0,align;constchar*type;PyObject*seq;while(*types!=_C_STRUCT_E&&*types++!='=');/* skip "<name>=" */type=types;nitems=0;while(*type!=_C_STRUCT_E){if(*type=='"'){type=strchr(type+1,'"');type++;}nitems++;type=PyObjCRT_SkipTypeSpec(type);}seq=PySequence_Fast(arg,"depythonifying struct, got no sequence");if(seq==NULL){return-1;}if(nitems!=PySequence_Fast_GET_SIZE(seq)){Py_DECREF(seq);PyErr_Format(PyExc_ValueError,"depythonifying struct of %d members, got tuple of %d",nitems,PyTuple_Size(arg));return-1;}type=types;offset=itemidx=0;while(*type!=_C_STRUCT_E){PyObject*argument;if(*type=='"'){type=strchr(type+1,'"');type++;}argument=PySequence_Fast_GET_ITEM(seq,itemidx);interror;if(!have_align){align=PyObjCRT_AlignOfType(type);have_align=1;}else{align=PyObjC_EmbeddedAlignOfType(type);}offset=ROUND(offset,align);error=depythonify_c_value(type,argument,((char*)datum)+offset);if(error==-1){Py_DECREF(seq);returnerror;}itemidx++;offset+=PyObjCRT_SizeOfType(type);type=PyObjCRT_SkipTypeSpec(type);}Py_DECREF(seq);return0;}PyObject*pythonify_c_value(constchar*type,void*datum){PyObject*retobject=NULL;type=PyObjCRT_SkipTypeQualifiers(type);switch(*type){case_C_CHR:/* * We don't return a string because BOOL is an alias for * char (at least on MacOS X) */retobject=(PyObject*)PyInt_FromLong((int)(*(char*)datum));break;case_C_UCHR:retobject=(PyObject*)PyInt_FromLong((long)(*(unsignedchar*)datum));break;case_C_CHARPTR:#ifdef _C_ATOMcase_C_ATOM:#endif{char*cp=*(char**)datum;if(cp==NULL){Py_INCREF(Py_None);retobject=Py_None;}else{retobject=(PyObject*)PyString_FromString(cp);}break;}#ifdef _C_BOOLcase_C_BOOL:retobject=(PyObject*)PyInt_FromLong(*(bool*)datum);break;#endifcase_C_INT:retobject=(PyObject*)PyInt_FromLong(*(int*)datum);break;case_C_UINT:if(*(unsignedint*)datum>LONG_MAX){retobject=(PyObject*)PyLong_FromUnsignedLongLong(*(unsignedint*)datum);}else{retobject=(PyObject*)PyInt_FromLong(*(unsignedint*)datum);}break;case_C_SHT:retobject=(PyObject*)PyInt_FromLong(*(short*)datum);break;case_C_USHT:retobject=(PyObject*)PyInt_FromLong(*(unsignedshort*)datum);break;case_C_LNG:retobject=(PyObject*)PyInt_FromLong(*(long*)datum);break;case_C_ULNG:if(*(unsignedlong*)datum>LONG_MAX){retobject=(PyObject*)PyLong_FromUnsignedLongLong(*(unsignedlong*)datum);}else{retobject=(PyObject*)PyInt_FromLong(*(unsignedlong*)datum);}break;case_C_ULNGLNG:retobject=(PyObject*)PyLong_FromUnsignedLongLong(*(unsignedlonglong*)datum);break;case_C_LNGLNG:retobject=(PyObject*)PyLong_FromLongLong(*(longlong*)datum);break;case_C_FLT:retobject=(PyObject*)PyFloat_FromDouble(*(float*)datum);break;case_C_DBL:retobject=(PyObject*)PyFloat_FromDouble(*(double*)datum);break;case_C_ID:{idobj=*(id*)datum;#if 1/* In theory this is a no-op, in practice this gives us EOF 4.5 * support. * * EOF can return references to 'to-be-restored' objects, * calling any method on them fully restores them, 'self' is * the safest method to call. */obj=[objself];#endifif(obj==nil){retobject=Py_None;Py_INCREF(retobject);}else{retobject=[obj__pyobjc_PythonObject__];}break;}case_C_SEL:if(*(SEL*)datum==NULL){retobject=Py_None;Py_INCREF(retobject);}else{retobject=PyString_FromString(PyObjCRT_SELName(*(SEL*)datum));}break;case_C_CLASS:{Classc=*(Class*)datum;if(c==Nil){retobject=Py_None;Py_INCREF(retobject);}else{retobject=(PyObject*)PyObjCClass_New(c);}break;}case_C_PTR:if(*(void**)datum==NULL){retobject=Py_None;Py_INCREF(retobject);}else{retobject=PyObjCPointerWrapper_ToPython(type,datum);if(retobject==NULL&&!PyErr_Occurred()){retobject=(PyObject*)PyObjCPointer_New(*(void**)datum,type+1);}}break;case_C_UNION_B:{intsize=PyObjCRT_SizeOfType(type);if(size==-1)returnNULL;retobject=PyString_FromStringAndSize((void*)datum,size);break;}case_C_STRUCT_B:retobject=pythonify_c_struct(type,datum);break;case_C_ARY_B:retobject=pythonify_c_array(type,datum);break;case_C_VOID:retobject=Py_None;Py_INCREF(retobject);break;default:PyErr_Format(PyObjCExc_Error,"pythonify_c_value: unhandled value type (%c|%d|%s)",*type,*type,type);break;}returnretobject;}intPyObjCRT_SizeOfReturnType(constchar*type){switch(*type){case_C_CHR:case_C_UCHR:case_C_SHT:case_C_USHT:returnsizeof(int);default:returnPyObjCRT_SizeOfType(type);}}/** Convert a python value to a basic C unsigned integer value.*/staticintdepythonify_unsigned_int_value(PyObject*argument,char*descr,unsignedlonglong*out,unsignedlonglongmax){if(PyInt_Check(argument)){longtemp=PyInt_AsLong(argument);if(temp<0){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got negative '%s'",descr,argument->ob_type->tp_name);return-1;}elseif((unsignedlonglong)temp>max){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}*out=temp;return0;}elseif(PyLong_Check(argument)){*out=PyLong_AsUnsignedLongLong(argument);if(PyErr_Occurred()){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}if(*out>max){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}return0;}else{PyObject*tmp;if(PyString_Check(argument)||PyUnicode_Check(argument)){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s'",descr,argument->ob_type->tp_name);return-1;}tmp=PyNumber_Long(argument);if(tmp!=NULL){*out=PyLong_AsUnsignedLongLong(tmp);Py_DECREF(tmp);if(*out<=max){return0;}}PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s'",descr,argument->ob_type->tp_name);return-1;}}/** Convert a python value to a basic C signed integer value.*/staticintdepythonify_signed_int_value(PyObject*argument,char*descr,longlong*out,longlongmin,longlongmax){if(PyInt_Check(argument)){*out=(longlong)PyInt_AsLong(argument);if(*out<min||*out>max){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}return0;}elseif(PyLong_Check(argument)){*out=PyLong_AsLongLong(argument);if(PyErr_Occurred()){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}if(*out<min||*out>max){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of ""wrong magnitude",descr,argument->ob_type->tp_name);return-1;}return0;}else{PyObject*tmp;if(PyString_Check(argument)||PyUnicode_Check(argument)){PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s' of %d",descr,argument->ob_type->tp_name,PyString_Size(argument));return-1;}tmp=PyNumber_Long(argument);if(tmp!=NULL){*out=PyLong_AsLongLong(tmp);Py_DECREF(tmp);if(*out>=min&&*out<=max){return0;}}PyErr_Format(PyExc_ValueError,"depythonifying '%s', got '%s'",descr,argument->ob_type->tp_name);return-1;}}intdepythonify_c_return_value(constchar*type,PyObject*argument,void*datum){longlongtemp;unsignedlonglongutemp;intr;#ifndef __i386__switch(*type){case_C_CHR:if(PyString_Check(argument)&&PyString_Size(argument)==1){*(int*)datum=PyString_AsString(argument)[0];return0;}r=depythonify_signed_int_value(argument,"char",&temp,CHAR_MIN,CHAR_MAX);if(r==0){*(int*)datum=temp;}returnr;case_C_UCHR:if(PyString_Check(argument)&&PyString_Size(argument)==1){*(unsignedint*)datum=PyString_AsString(argument)[0];return0;}r=depythonify_unsigned_int_value(argument,"unsigned short",&utemp,UCHAR_MAX);if(r==0){*(unsignedint*)datum=utemp;}returnr;case_C_SHT:r=depythonify_signed_int_value(argument,"short",&temp,SHRT_MIN,SHRT_MAX);if(r==0){*(int*)datum=temp;}returnr;case_C_USHT:r=depythonify_unsigned_int_value(argument,"unsigned short",&utemp,USHRT_MAX);if(r==0){*(unsignedint*)datum=utemp;}returnr;default:returndepythonify_c_value(type,argument,datum);}#else returndepythonify_c_value(type,argument,datum);#endif}PyObject*pythonify_c_return_value(constchar*type,void*datum){#ifndef __i386__/* * On PowerPC short and char return values are passed * as full-size ints. */staticconstcharintType[]={_C_INT,0};staticconstcharuintType[]={_C_UINT,0};switch(*type){case_C_CHR:case_C_SHT:returnpythonify_c_value(intType,datum);case_C_UCHR:case_C_USHT:returnpythonify_c_value(uintType,datum);default:returnpythonify_c_value(type,datum);}#elsereturnpythonify_c_value(type,datum);#endif}intdepythonify_c_value(constchar*type,PyObject*argument,void*datum){/* Pass by reference output arguments are sometimes passed a NULL * pointer, this surpresses a core dump. */longlongtemp;unsignedlonglongutemp;intr;if(!datum)return0;type=PyObjCRT_SkipTypeQualifiers(type);switch(*type){#ifdef _C_ATOMcase_C_ATOM:#endifcase_C_CHARPTR:if(!PyString_Check(argument)&&argument!=Py_None){PyErr_Format(PyExc_ValueError,"depythonifying 'charptr', got '%s'",argument->ob_type->tp_name);return-1;}elseif(argument==Py_None){*(char**)datum=NULL;}else{*(char**)datum=PyString_AS_STRING((PyStringObject*)argument);}break;case_C_CHR:if(PyString_Check(argument)&&PyString_Size(argument)==1){*(char*)datum=PyString_AsString(argument)[0];return0;}r=depythonify_signed_int_value(argument,"char",&temp,CHAR_MIN,CHAR_MAX);if(r==0){*(char*)datum=temp;}returnr;case_C_UCHR:if(PyString_Check(argument)&&PyString_Size(argument)==1){*(unsignedchar*)datum=PyString_AsString(argument)[0];return0;}r=depythonify_unsigned_int_value(argument,"unsigned short",&utemp,UCHAR_MAX);if(r==0){*(unsignedchar*)datum=utemp;}returnr;case_C_SHT:r=depythonify_signed_int_value(argument,"short",&temp,SHRT_MIN,SHRT_MAX);if(r==0){*(short*)datum=temp;}returnr;case_C_USHT:r=depythonify_unsigned_int_value(argument,"unsigned short",&utemp,USHRT_MAX);if(r==0){*(unsignedshort*)datum=utemp;}returnr;#ifdef _C_BOOLcase_C_BOOL:*(bool*)datum=PyObject_IsTrue(argument);return0;#endifcase_C_INT:r=depythonify_signed_int_value(argument,"int",&temp,INT_MIN,INT_MAX);if(r==0){*(int*)datum=temp;}returnr;case_C_UINT:r=depythonify_unsigned_int_value(argument,"unsigned int",&utemp,UINT_MAX);if(r==0){*(unsignedint*)datum=utemp;}returnr;case_C_LNG:r=depythonify_signed_int_value(argument,"long",&temp,LONG_MIN,LONG_MAX);if(r==0){*(long*)datum=temp;}returnr;case_C_ULNG:r=depythonify_unsigned_int_value(argument,"unsigned long",&utemp,ULONG_MAX);if(r==0){*(unsignedlong*)datum=utemp;}returnr;case_C_LNGLNG:r=depythonify_signed_int_value(argument,"long long",&temp,LLONG_MIN,LLONG_MAX);if(r==0){*(longlong*)datum=temp;}returnr;case_C_ULNGLNG:r=depythonify_unsigned_int_value(argument,"unsigned long long",&utemp,ULLONG_MAX);if(r==0){*(unsignedlonglong*)datum=utemp;}returnr;case_C_ID:/* XXX This should, for values other than Py_None, always return the same id for the same PyObject for as long as that id lives. I think that the implementation of this should be moved to OC_PythonObject, which would itself have a map of PyObject->id. The dealloc of each of these custom objects should notify OC_PythonObject to remove map entry. We need to significantly change how immutable types are bridged, and create OC_PythonString, OC_PythonBool, etc. which are subclasses of what they should be from the the Objective C side. If we don't do this, we break binary plist serialization, and likely other things, which assume that foo[bar] is foo[bar] for the duration of the serialization process. I would imagine that other things also assume this kind of invariant, so we should do it here rather than in every container object. */return[OC_PythonObjectwrapPyObject:argumenttoId:(id*)datum];case_C_CLASS:if(PyObjCClass_Check(argument)){*(Class*)datum=PyObjCClass_GetClass(argument);}elseif(argument==Py_None){*(Class*)datum=nil;}else{PyErr_Format(PyExc_ValueError,"depythonifying 'Class', got '%s'",argument->ob_type->tp_name);return-1;}break;case_C_SEL:if(argument==Py_None){*(SEL*)datum=NULL;}elseif(PyObjCSelector_Check(argument)){*(SEL*)datum=PyObjCSelector_GetSelector(argument);}elseif(PyString_Check(argument)){char*selname=PyString_AsString(argument);SELsel;if(*selname=='\0'){*(SEL*)datum=NULL;}else{sel=PyObjCRT_SELUID(selname);if(sel){*(SEL*)datum=sel;}else{PyErr_Format(PyExc_ValueError,"depythonifying 'SEL', cannot ""register string with runtime");return-1;}}}else{PyErr_Format(PyExc_ValueError,"depythonifying 'SEL', got '%s'",argument->ob_type->tp_name);return-1;}break;case_C_PTR:if(argument==Py_None){*(void**)datum=NULL;return0;}r=PyObjCPointerWrapper_FromPython(type,argument,datum);if(r==-1){if(PyErr_Occurred()){return-1;}elseif(PyObjCPointer_Check(argument)){*(void**)datum=PyObjCPointer_Ptr(argument);}else{PyErr_Format(PyExc_ValueError,"depythonifying 'pointer', got '%s'",argument->ob_type->tp_name);return-1;}}break;case_C_FLT:if(PyFloat_Check(argument)){*(float*)datum=(float)PyFloat_AsDouble(argument);}elseif(PyInt_Check(argument)){*(float*)datum=(float)PyInt_AsLong(argument);}elseif(PyString_Check(argument)||PyUnicode_Check(argument)){PyErr_Format(PyExc_ValueError,"depythonifying 'float', got '%s'",argument->ob_type->tp_name);return-1;}else{PyObject*tmp=PyNumber_Float(argument);if(tmp!=NULL){doubledblval=PyFloat_AsDouble(tmp);Py_DECREF(tmp);*(float*)datum=dblval;return0;}PyErr_Format(PyExc_ValueError,"depythonifying 'float', got '%s'",argument->ob_type->tp_name);return-1;}break;case_C_DBL:if(PyFloat_Check(argument)){*(double*)datum=PyFloat_AsDouble(argument);}elseif(PyInt_Check(argument)){*(double*)datum=(double)PyInt_AsLong(argument);}elseif(PyString_Check(argument)||PyUnicode_Check(argument)){PyErr_Format(PyExc_ValueError,"depythonifying 'float', got '%s'",argument->ob_type->tp_name);return-1;}else{PyObject*tmp=PyNumber_Float(argument);if(tmp!=NULL){doubledblval=PyFloat_AsDouble(tmp);Py_DECREF(tmp);*(double*)datum=dblval;return0;}PyErr_Format(PyExc_ValueError,"depythonifying 'double', got '%s'",argument->ob_type->tp_name);return-1;}break;case_C_UNION_B:if(PyString_Check(argument)){intexpected_size=PyObjCRT_SizeOfType(type);if(expected_size==-1){PyErr_Format(PyExc_ValueError,"depythonifying 'union' of ""unknown size");return-1;}elseif(expected_size!=PyString_Size(argument)){PyErr_Format(PyExc_ValueError,"depythonifying 'union' of size %d, ""got string of %d",expected_size,PyString_Size(argument));return-1;}else{memcpy((void*)datum,PyString_AS_STRING(argument),expected_size);}}else{PyErr_Format(PyExc_ValueError,"depythonifying 'union', got '%s'",argument->ob_type->tp_name);return-1;}break;case_C_STRUCT_B:returndepythonify_c_struct(type,argument,datum);case_C_ARY_B:returndepythonify_c_array(type,argument,datum);default:PyErr_Format(PyExc_ValueError,"depythonifying unknown typespec %#x",*type);return-1;}return0;}