1/*
2 * Some utility functions...
3 *
4 * TODO: Documentation
5 */
6
7#include "pyobjc.h"
8
9#import <Foundation/Foundation.h>
10
11PyObject* PyObjCExc_Error;
12PyObject* PyObjCExc_NoSuchClassError;
13PyObject* PyObjCExc_InternalError;
14PyObject* PyObjCExc_UnInitDeallocWarning;
15PyObject* PyObjCExc_ObjCRevivalWarning;
16PyObject* PyObjCExc_LockError;
17PyObject* PyObjCExc_BadPrototypeError;
18
19
20
21int
22PyObjCUtil_Init(PyObject* module)
23{
24#define NEW_EXC(identifier, name, base_class) \
25	identifier = PyErr_NewException("objc."name, base_class, NULL); \
26	if (identifier == NULL) return -1; \
27	Py_INCREF(identifier); \
28	if (PyModule_AddObject(module, name, identifier) < 0) return -1;
29
30	NEW_EXC(PyObjCExc_Error, "error", NULL);
31	NEW_EXC(PyObjCExc_NoSuchClassError, "nosuchclass_error", PyObjCExc_Error);
32	NEW_EXC(PyObjCExc_InternalError, "internal_error", PyObjCExc_Error);
33	NEW_EXC(PyObjCExc_UnInitDeallocWarning, "UninitializedDeallocWarning", PyExc_Warning);
34	NEW_EXC(PyObjCExc_ObjCRevivalWarning, "RevivedObjectiveCObjectWarning", PyExc_Warning);
35	NEW_EXC(PyObjCExc_LockError, "LockError", PyObjCExc_Error);
36	NEW_EXC(PyObjCExc_BadPrototypeError, "BadPrototypeError", PyObjCExc_Error);
37
38	return 0;
39}
40
41static PyObject*
42ObjCErr_PyExcForName(const char* value)
43{
44	/* XXX: This table should be changeable from python */
45	if (strcmp(value, "NSRangeException") == 0) {
46		return PyExc_IndexError;
47	}  else if (strcmp(value, "NSInvalidArgumentException") == 0) {
48		return PyExc_ValueError;
49	}  else if (strcmp(value, "NSMallocException") == 0) {
50		return PyExc_MemoryError;
51	}  else if (strcmp(value, "NSUnknownKeyException") == 0) {
52		return PyExc_KeyError;
53	}
54
55	return PyObjCExc_Error;
56}
57
58
59void
60PyObjCErr_FromObjC(NSException* localException)
61{
62	NSDictionary* userInfo;
63	PyObject*     dict;
64	PyObject*     exception;
65	PyObject*     v;
66	PyObject*	  buf;
67	PyObject*     exc_type;
68	PyObject*     exc_value;
69	PyObject*     exc_traceback;
70	PyObject*     c_localException_name;
71	PyObject*     c_localException_reason;
72	NSObject* t;
73
74	PyGILState_STATE state;
75
76	state = PyGILState_Ensure();
77
78	if (![localException isKindOfClass:[NSException class]]) {
79		/* We caught some random objects as the exception, so the minimal possible
80		 */
81		PyErr_SetString(PyObjCExc_Error, "non-NSException object caught");
82
83		PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
84		if (!exc_value || !PyObject_IsInstance(exc_value, exc_type)) {
85			PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
86		}
87
88		PyObject* exc = PyObjC_IdToPython(localException);
89		if (exc == NULL) {
90			PyErr_Clear();
91		} else {
92			PyObject_SetAttrString(exc_value, "_pyobjc_exc_", exc);
93		}
94		Py_CLEAR(exc);
95		PyErr_Restore(exc_type, exc_value, exc_traceback);
96		PyGILState_Release(state);
97		return;
98	}
99
100	exception = ObjCErr_PyExcForName([[localException name] UTF8String]);
101
102	userInfo = [localException userInfo];
103	if (userInfo) {
104		id val;
105
106		val = [userInfo objectForKey:@"__pyobjc_exc_type__"];
107		if (val) {
108			exc_type = [val pyObject];
109			exc_value = [[userInfo objectForKey:@"__pyobjc_exc_value__"]  pyObject];
110			exc_traceback = [[userInfo objectForKey:@"__pyobjc_exc_traceback__"]  pyObject];
111
112			/* -pyObject returns a borrowed reference and
113			 * PyErr_Restore steals one from us.
114			 */
115			Py_INCREF(exc_type);
116			Py_XINCREF(exc_value);
117			Py_XINCREF(exc_traceback);
118
119			PyErr_Restore(exc_type, exc_value, exc_traceback);
120			PyGILState_Release(state);
121			return;
122		}
123	}
124
125	t = [localException name];
126	c_localException_name = pythonify_c_value(@encode(NSObject*), &t);
127	if (c_localException_name == NULL) {
128		return;
129	}
130
131	t = [localException reason];
132	c_localException_reason = pythonify_c_value(@encode(NSObject*), &t);
133	if (c_localException_reason == NULL) {
134		Py_DECREF(c_localException_name);
135		return;
136	}
137
138	dict = PyDict_New();
139	if (dict == NULL) {
140		Py_DECREF(c_localException_name);
141		Py_DECREF(c_localException_reason);
142		return;
143	}
144	PyDict_SetItemString(dict, "name", c_localException_name);
145	Py_DECREF(c_localException_name);
146
147	PyDict_SetItemString(dict, "reason",  c_localException_reason);
148	Py_DECREF(c_localException_reason);
149	if (userInfo) {
150		v = PyObjCObject_New(userInfo, PyObjCObject_kDEFAULT, YES);
151		if (v != NULL) {
152			PyDict_SetItemString(dict, "userInfo", v);
153			Py_DECREF(v);
154		} else {
155			PyErr_Clear();
156		}
157	} else {
158		PyDict_SetItemString(dict, "userInfo", Py_None);
159	}
160
161#if 0
162	/* build the description as a NSString to maintain the highest
163	 * fidelity.
164	 * This code is disabled because the base exception class doesn't
165	 * like unicode arguments, that will wreak havoc when converting the
166	 * exception to text, which in turn makes it impossible to find out
167	 * what the exception actually was without poking in the PyObjC
168	 * specific fields.
169	 */
170	NSString* description = [NSString stringWithFormat:@"%@ - %@",
171			[localException name], [localException reason]];
172	if (description == nil) {
173		PyErr_SetString(exception, "<<<UNKNOWN REASON>>>");
174	} else {
175		buf = pythonify_c_value(@encode(NSObject*), &description);
176		if (buf == NULL) {
177			Py_DECREF(dict);
178			PyGILState_Release(state);
179			return;
180		}
181	}
182#else
183	if ([[localException reason] UTF8String]) {
184		 buf = PyText_FromFormat("%s - %s",
185		       [[localException name] UTF8String],
186		       [[localException reason] UTF8String]);
187	} else {
188		 buf = PyText_FromFormat("%s",
189		       [[localException name] UTF8String]);
190	}
191	PyErr_SetObject(exception, buf);
192#endif
193	PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
194	if (!exc_value || !PyObject_IsInstance(exc_value, exc_type)) {
195		PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
196	}
197
198	PyObject_SetAttrString(exc_value, "_pyobjc_info_", dict);
199	Py_DECREF(dict); dict = NULL;
200	PyObject_SetAttrString(exc_value, "name", c_localException_name);
201	PyErr_Restore(exc_type, exc_value, exc_traceback);
202	PyGILState_Release(state);
203}
204
205void
206PyObjCErr_ToObjC(void)
207{
208	PyObjCErr_ToObjCWithGILState(NULL);
209}
210
211
212NSException*
213PyObjCErr_AsExc(void)
214{
215	PyObject* exc_type;
216	PyObject* exc_value;
217	PyObject* exc_traceback;
218	PyObject* args;
219	PyObject* repr;
220	PyObject* typerepr;
221	NSException* val;
222	NSMutableDictionary* userInfo;
223
224	PyErr_Fetch(&exc_type, &exc_value, &exc_traceback);
225	if (exc_type == NULL) {
226		return nil;
227	}
228
229	PyErr_NormalizeException(&exc_type, &exc_value, &exc_traceback);
230
231	args = PyObject_GetAttrString(exc_value, "_pyobjc_exc_");
232	if (args == NULL) {
233		PyErr_Clear();
234	} else {
235		id result;
236
237		if (depythonify_c_value(@encode(id), args, &result) == -1) {
238			abort();
239		}
240		return result;
241	}
242
243	args = PyObject_GetAttrString(exc_value, "_pyobjc_info_");
244	if (args == NULL) {
245		PyErr_Clear();
246	} else {
247		/* This may be an exception that started out in
248		 * Objective-C code.
249		 */
250		PyObject* v;
251		NSString* reason = NULL;
252		NSString* name = NULL;
253
254		v = PyDict_GetItemString(args, "reason");
255		if (v) {
256			if (depythonify_c_value(@encode(NSObject*), v, &reason) < 0) {
257				PyErr_Clear();
258			}
259		}
260
261		v = PyDict_GetItemString(args, "name");
262		if (v) {
263			if (depythonify_c_value(@encode(NSObject*), v, &name) < 0) {
264				PyErr_Clear();
265			}
266		}
267
268		v = PyDict_GetItemString(args, "userInfo");
269		if (v && PyObjCObject_Check(v)) {
270			userInfo = PyObjCObject_GetObject(v);
271		} else {
272			userInfo = nil;
273			PyErr_Clear();
274		}
275
276		if (name && reason) {
277			val = [NSException exceptionWithName:name
278				     reason:reason
279				     userInfo:userInfo];
280			Py_DECREF(args);
281			Py_XDECREF(exc_type);
282			Py_XDECREF(exc_value);
283			Py_XDECREF(exc_traceback);
284
285			return val;
286		}
287	}
288
289	repr = PyObject_Str(exc_value);
290	typerepr = PyObject_Str(exc_type);
291	userInfo = [NSMutableDictionary dictionaryWithCapacity: 3];
292	[userInfo setObject:
293		[[[OC_PythonObject alloc] initWithObject:exc_type] autorelease]
294		forKey:@"__pyobjc_exc_type__"];
295	if (exc_value != NULL)
296		[userInfo setObject:
297			[[[OC_PythonObject alloc] initWithObject:exc_value] autorelease]
298			forKey:@"__pyobjc_exc_value__"];
299	if (exc_traceback != NULL)
300		[userInfo setObject:
301			[[[OC_PythonObject alloc] initWithObject:exc_traceback] autorelease]
302			forKey:@"__pyobjc_exc_traceback__"];
303
304	val = [NSException
305		exceptionWithName:@"OC_PythonException"
306			   reason:[NSString stringWithFormat:@"%@: %@", typerepr?PyObjC_PythonToId(typerepr):NULL, repr?PyObjC_PythonToId(repr):NULL]
307		userInfo:userInfo];
308
309	Py_XDECREF(typerepr);
310	Py_XDECREF(repr);
311
312	if (PyObjC_VerboseLevel) {
313		PyErr_Restore(exc_type, exc_value , exc_traceback);
314		NSLog(@"PyObjC: Converting exception to Objective-C:");
315		PyErr_Print();
316	} else {
317		Py_DECREF(exc_type);
318		Py_XDECREF(exc_value);
319		Py_XDECREF(exc_traceback);
320	}
321	return val;
322}
323
324void
325PyObjCErr_ToObjCWithGILState(PyGILState_STATE* state)
326{
327	NSException* exc = PyObjCErr_AsExc();
328
329	if (state) {
330		PyGILState_Release(*state);
331	}
332	[exc raise];
333}
334
335
336char*
337PyObjCUtil_Strdup(const char* value)
338{
339	Py_ssize_t len;
340	char* result;
341
342	len = strlen(value);
343	result = PyMem_Malloc(len+1);
344	if (result == NULL) return NULL;
345
346	memcpy(result, value, len);
347	result[len] = 0;
348	return result;
349}
350
351
352NSMapTableKeyCallBacks PyObjCUtil_PointerKeyCallBacks = {
353	NULL,
354	NULL,
355	NULL,
356	NULL,
357	NULL,
358	NULL,
359};
360
361NSMapTableValueCallBacks PyObjCUtil_PointerValueCallBacks = {
362	NULL,
363	NULL,
364	NULL,
365};
366
367static void
368nsmaptable_objc_retain(NSMapTable *table __attribute__((__unused__)), const void *datum) {
369	CFRetain((id)datum);
370}
371
372static void
373nsmaptable_objc_release(NSMapTable *table __attribute__((__unused__)), void *datum) {
374	CFRelease((id)datum);
375}
376
377NSMapTableKeyCallBacks PyObjCUtil_ObjCIdentityKeyCallBacks = {
378	NULL,
379	NULL,
380	&nsmaptable_objc_retain,
381	&nsmaptable_objc_release,
382	NULL,
383	NULL,
384};
385
386NSMapTableValueCallBacks PyObjCUtil_ObjCValueCallBacks = {
387	&nsmaptable_objc_retain,
388	&nsmaptable_objc_release,
389	NULL  // generic description
390};
391
392
393#define SHOULD_FREE 1
394#define SHOULD_IGNORE 2
395
396void
397PyObjC_FreeCArray(int code, void* array)
398{
399	if (code == SHOULD_FREE) {
400		PyMem_Free(array);
401	}
402}
403
404static PyTypeObject* array_type = NULL;
405
406static inline PyTypeObject*
407fetch_array_type(void)
408{
409	PyObject* mod;
410	PyObject* name;
411
412	if (array_type != NULL) return array_type;
413
414	name = PyText_FromString("array");
415	if (name == NULL) {
416		return NULL;
417	}
418
419	mod = PyImport_Import(name);
420	Py_DECREF(name);
421	if (mod == NULL) {
422		return NULL;
423	}
424
425	array_type = (PyTypeObject*)PyObject_GetAttrString(mod, "ArrayType");
426	Py_DECREF(mod);
427	if (array_type == NULL) {
428		return NULL;
429	}
430
431	/* XXX: check if array_type is realy a type! */
432
433	return array_type;
434}
435
436#define array_check(obj) PyObject_TypeCheck(obj, fetch_array_type())
437
438static char
439array_typestr(PyObject* array)
440{
441	PyObject* typecode;
442	PyObject* bytes;
443	char res;
444
445	typecode = PyObject_GetAttrString(array, "typecode");
446	if (typecode == NULL) {
447		return '\0';
448	}
449
450	if (PyUnicode_Check(typecode)) {
451		bytes = PyUnicode_AsEncodedString(typecode, NULL, NULL);
452		if (bytes == NULL) {
453			return '\0';
454		}
455#if PY_MAJOR_VERSION == 2
456	} else if (PyString_Check(typecode)) {
457		bytes = typecode; Py_INCREF(bytes);
458#endif
459	} else {
460		PyErr_SetString(PyExc_TypeError, "typecode not a string");
461		return '\0';
462	}
463
464	switch (*PyBytes_AS_STRING(bytes)) {
465	case 'c': res = _C_CHR; break;
466	case 'b': res = _C_CHR; break;
467	case 'B': res = _C_UCHR; break;
468	case 'u': res = _C_SHT; break;
469	case 'h': res = _C_SHT; break;
470	case 'H': res = _C_USHT; break;
471	case 'i': res = _C_INT; break;
472	case 'I': res = _C_UINT; break;
473	case 'l': res = _C_LNG; break;
474	case 'L': res = _C_ULNG; break;
475	case 'f': res = _C_FLT; break;
476	case 'd': res = _C_DBL; break;
477	default:
478		PyErr_SetString(PyExc_TypeError, "unsupported typecode");
479		res = '\0';
480	}
481	Py_DECREF(typecode);
482	Py_DECREF(bytes);
483
484	return res;
485}
486
487static int
488buffer_get(BOOL writable, PyObject* obj, void** bufptr, Py_ssize_t* sizeptr)
489{
490	if (writable) {
491		return PyObject_AsWriteBuffer(obj, bufptr,  sizeptr);
492	} else {
493		return PyObject_AsReadBuffer(obj, (const void**)bufptr,  sizeptr);
494	}
495}
496
497static char struct_elem_code(const char* typestr);
498
499static char
500array_elem_code(const char* typestr)
501{
502	char res = '\0';
503	char tmp;
504
505	if (*typestr++ != _C_ARY_B) {
506		return '\0';
507	}
508	while (isdigit(*typestr)) typestr++;
509
510	if (*typestr == _C_ARY_E) {
511		return '\0';
512	}
513
514	while (typestr && *typestr != _C_ARY_E) {
515		switch(*typestr) {
516		case _C_ARY_B:
517			tmp = array_elem_code(typestr);
518			if (tmp == '\0') return '\0';
519			if (res == '\0') {
520				res = tmp;
521			} else if (tmp != res) {
522				return '\0';
523			}
524			break;
525		case _C_STRUCT_B:
526			tmp = struct_elem_code(typestr);
527			if (tmp == '\0') return '\0';
528			if (res == '\0') {
529				res = tmp;
530			} else if (tmp != res) {
531				return '\0';
532			}
533			break;
534		default:
535			if (res != '\0' && *typestr != res) return '\0';
536			res = *typestr;
537		}
538
539		typestr = PyObjCRT_SkipTypeSpec(typestr);
540	}
541	return res;
542}
543
544static char
545struct_elem_code(const char* typestr)
546{
547	char res = '\0';
548	char tmp;
549
550	if (*typestr++ != _C_STRUCT_B) {
551		return '\0';
552	}
553
554	while (*typestr != '=' && *typestr != _C_STRUCT_E) {
555		typestr++;
556	}
557
558	if (*typestr == _C_STRUCT_E) {
559		return '\0';
560	}
561	typestr++;
562
563	while (typestr && *typestr != _C_STRUCT_E) {
564		switch(*typestr) {
565		case _C_ARY_B:
566			tmp = array_elem_code(typestr);
567			if (tmp == '\0') return '\0';
568			if (res == '\0') {
569				res = tmp;
570			} else if (tmp != res) {
571				return '\0';
572			}
573			break;
574		case _C_STRUCT_B:
575			tmp = struct_elem_code(typestr);
576			if (tmp == '\0') return '\0';
577			if (res == '\0') {
578				res = tmp;
579			} else if (tmp != res) {
580				return '\0';
581			}
582			break;
583		default:
584			if (res != '\0' && *typestr != res) return '\0';
585			res = *typestr;
586		}
587
588		typestr = PyObjCRT_SkipTypeSpec(typestr);
589	}
590	return res;
591}
592
593static BOOL
594code_compatible(char array_code, char type_code)
595{
596	if (array_code == type_code) {
597		return YES;
598	}
599	switch (type_code) {
600	case _C_LNG_LNG:
601#ifdef __LP64__
602		/* fall through */
603#else
604		return NO;
605#endif
606	case _C_LNG:
607		return (array_code == 'l')
608#ifndef __LP64__
609			|| (array_code == 'i')
610#endif
611		;
612	case _C_ULNG_LNG:
613#ifdef __LP64__
614		/* fall through */
615#else
616		return NO;
617#endif
618	case _C_ULNG:
619		return (array_code == 'L')
620#ifndef __LP64__
621			|| (array_code == 'I')
622#endif
623		;
624
625	case _C_INT:
626		return (array_code == 'i')
627#ifndef __LP64__
628			|| (array_code == 'l')
629#endif
630		;
631	case _C_UINT:
632		return (array_code == 'I')
633#ifndef __LP64__
634			|| (array_code == 'L')
635#endif
636		;
637
638	case _C_NSBOOL:
639		return (array_code == _C_CHR) || (array_code == _C_UCHR);
640	case _C_CHAR_AS_INT:
641		return (array_code == _C_CHR) || (array_code == _C_UCHR);
642	case _C_CHAR_AS_TEXT:
643		return (array_code == _C_CHR);
644	case _C_UNICHAR:
645		return (array_code == _C_SHT);
646	}
647	return NO;
648}
649
650
651/*
652 * Convert a Python object to an array of 'elementType'. The array should
653 * contain 'pythonCount' elements, Py_None or NULL is accepted and will result
654 * in converting the entire Python sequence.
655 *
656 * The pythonList should either be a python sequence with appropriate entries,
657 * an array.array whose element-types match the element-types of the
658 * 'elementType' or an appropriatly typed and shaped numeric array.
659 *
660 * XXX: Numeric arrays are not yet supported.
661 * XXX: Unicode arrays are not yet support (_C_UNICHAR)
662 */
663int
664PyObjC_PythonToCArray(
665	BOOL        writable, BOOL exactSize,
666	const char* elementType,
667	PyObject*   pythonList,
668	void** array,
669	Py_ssize_t*   size,
670	PyObject**    bufobj)
671{
672	Py_ssize_t eltsize = PyObjCRT_SizeOfType(elementType);
673	Py_ssize_t i;
674	int r;
675
676
677	if (eltsize == -1) {
678		return -1;
679	}
680
681	if ((eltsize == 1 || eltsize == 0) &&
682		!(*elementType == _C_NSBOOL || *elementType == _C_BOOL || *elementType == _C_CHAR_AS_INT)) {
683		/* A simple byte-array */
684		/* Note: PyUnicode is explicitly excluded because it
685		 * implemenents the character buffer interface giving access
686		 * to the raw implementation. That's almost always not want
687		 * you want.
688		 */
689		char* buf;
690		Py_ssize_t bufsize;
691		int have_buffer;
692
693		if (PyUnicode_Check(pythonList)) {
694			PyErr_Format(PyExc_TypeError,
695				"Expecting byte-buffer, got %s",
696				Py_TYPE(pythonList)->tp_name);
697			return -1;
698		}
699
700
701		have_buffer = buffer_get(writable, pythonList, (void**)&buf, &bufsize);
702		if (have_buffer == -1) {
703			if (writable) {
704				/* Ensure that the expected semantics still work
705				 * when the passed in buffer is read-only
706				 */
707				if (buffer_get(NO, pythonList, (void**)&buf, &bufsize) == -1) {
708					return -1;
709				}
710
711				if (size == NULL || *size == -1) {
712					*array = PyMem_Malloc(bufsize);
713					if (*array == NULL) {
714						return -1;
715					}
716					memcpy(*array, buf, bufsize);
717				} else {
718					if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
719						PyErr_Format(PyExc_ValueError,
720							"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
721							"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
722						return -1;
723					}
724					*array = PyMem_Malloc(*size);
725					if (*array == NULL) {
726						return -1;
727					}
728					memcpy(*array, buf, *size);
729				}
730				return SHOULD_FREE;
731			}
732		}
733
734		if (have_buffer != -1) {
735			if (size == NULL) {
736				*array = buf;
737				*bufobj = pythonList;
738				Py_INCREF(pythonList);
739
740			} else if (*size == -1) {
741				*array = buf;
742				*size = bufsize;
743				*bufobj = pythonList;
744				Py_INCREF(pythonList);
745
746			} else {
747				if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
748					PyErr_Format(PyExc_ValueError,
749						"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
750						"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
751					return -1;
752				}
753				*array = buf;
754				*bufobj = pythonList;
755				Py_INCREF(pythonList);
756			}
757			return SHOULD_IGNORE;
758		}
759
760		PyErr_Clear();
761	}
762
763	if (*elementType == _C_UNICHAR && PyUnicode_Check(pythonList)) {
764		Py_ssize_t bufsize = PyUnicode_GetSize(pythonList);
765
766		if (*size == -1) {
767			*size = bufsize;
768		} else if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
769			PyErr_Format(PyExc_ValueError,
770				"Requesting unicode buffer of %"PY_FORMAT_SIZE_T"d, have unicode buffer "
771				"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
772			return -1;
773		}
774
775		if (writable) {
776			*array = PyMem_Malloc(*size * sizeof(UniChar));
777			memcpy(*array, PyUnicode_AsUnicode(pythonList), *size * sizeof(UniChar));
778			return SHOULD_FREE;
779		} else {
780			*array = PyUnicode_AsUnicode(pythonList);
781			*bufobj = pythonList;
782			Py_INCREF(pythonList);
783			return SHOULD_IGNORE;
784		}
785#if PY_MAJOR_VERSION == 2
786	} else if (*elementType == _C_UNICHAR && PyString_Check(pythonList)) {
787		PyObject* u = PyUnicode_Decode(
788				PyString_AsString(pythonList),
789				PyString_Size(pythonList),
790				NULL, NULL);
791		if (u == NULL) {
792			return -1;
793		}
794
795		Py_ssize_t bufsize = PyUnicode_GetSize(u);
796
797		if (*size == -1) {
798			*size = bufsize;
799		} else if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
800			PyErr_Format(PyExc_ValueError,
801				"Requesting unicode buffer of %"PY_FORMAT_SIZE_T"d, have unicode buffer "
802				"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
803			Py_DECREF(u);
804			return -1;
805		}
806
807		if (writable) {
808			*array = PyMem_Malloc(*size * sizeof(UniChar));
809			memcpy(*array, PyUnicode_AsUnicode(u), *size * sizeof(UniChar));
810			Py_DECREF(u);
811			return SHOULD_FREE;
812		} else {
813			*array = PyUnicode_AsUnicode(u);
814			*bufobj = u;
815			return SHOULD_IGNORE;
816		}
817#endif
818	}
819
820	/* A more complex array */
821
822#if PY_VERSION_HEX >= 0x02060000
823	if (PyObject_CheckBuffer(pythonList)) {
824		/* An object that implements the new-style buffer interface.
825		 * Use the buffer interface description to check if the buffer
826		 * type is compatible with what we expect.
827		 *
828		 * Specifically:
829		 * - If the C code expects an array of basic types:
830		 *   the buffer must be a single-dimensional array of
831		 *   a compatible type.
832		 * - If the C code expects and array of structures:
833		 *   The python array must be two dimensional, one row
834		 *   in the python array corresponds to one struct "instance"
835		 * - If the C code expects a multi-dimensional array:
836		 *   the python buffer must have a compatible dimension.
837		 *
838		 * The array must be large enough and  mustn't contain holes
839		 * in the fragment that gets used by us.
840		 */
841
842	}
843
844#endif
845	if (array_check(pythonList)) {
846		/* An array.array. Only convert if the typestr describes an
847		 * simple type of the same type as the array, or a struct/array
848		 * containing only elements of the type of the array.
849		 */
850		char* buf;
851		Py_ssize_t bufsize;
852		char code = array_typestr(pythonList);
853		if (code_compatible(code, *elementType)) {
854			/* Simple array, ok */
855		} else if (*elementType == _C_ARY_B) {
856			/* Array of arrays, 'code' must be the same as the
857			 * element-type of the array.
858			 */
859			if (!code_compatible(code, array_elem_code(elementType))) {
860				PyErr_Format(PyExc_ValueError,
861					"type mismatch between array.array "
862					"of %c and and C array of %s",
863					code, elementType);
864				return -1;
865			}
866
867		} else if (*elementType == _C_STRUCT_B) {
868			/* Array of structs, 'code' must be the same as the
869			 * the field-types of the structs (that is, the struct
870			 * must contain one or more fields of type 'code').
871			 */
872			if (!code_compatible(code, struct_elem_code(elementType))) {
873				PyErr_Format(PyExc_ValueError,
874					"type mismatch between array.array "
875					"of %c and and C array of %s",
876					code, elementType);
877				return -1;
878			}
879		} else {
880			PyErr_Format(PyExc_ValueError,
881				"type mismatch between array.array "
882				"of %c and and C array of %s",
883				code, elementType);
884			return -1;
885		}
886
887		if (buffer_get(writable, pythonList, (void**)&buf, &bufsize) == -1) {
888			return -1;
889		}
890
891		assert(eltsize != 0);
892		if ((bufsize % eltsize) != 0) {
893			PyErr_SetString(PyExc_ValueError,
894					"Badly shaped array.array");
895			return -1;
896		}
897
898		*array = buf;
899
900		if (size == NULL) {
901			/* pass */
902
903		} else if (*size == -1) {
904			*size = bufsize / eltsize;
905
906		} else {
907			bufsize /= eltsize;
908
909			if ((exactSize && *size != bufsize) || (!exactSize && *size > bufsize)) {
910				PyErr_Format(PyExc_ValueError,
911					"Requesting buffer of %"PY_FORMAT_SIZE_T"d, have buffer "
912					"of %"PY_FORMAT_SIZE_T"d", *size, bufsize);
913				return -1;
914			}
915			*array = buf;
916		}
917		*bufobj = pythonList;
918		Py_INCREF(pythonList);
919		return SHOULD_IGNORE;
920
921#ifdef PyObjC_ENABLE_NUMARRAY
922
923# error "Please implement Numarray/Numeric support"
924
925	} else if (...){
926		/* TODO: Convert the numeric array (or return a pointer to it's
927		 * data), but only if it is the right type:
928		 * - If typestr is a basic type, the array must be a 1D array
929		 *   of that type
930		 * - If typestr is a structured type, the array must be a 2D
931		 *   array where rows match the structured type
932		 *
933		 * XXX: I have no idea if this is feasable, not having used
934		 * numarray/numeric myself.
935		 */
936#endif /* PyObjC_ENABLE_NUMARRAY */
937	} else {
938		Py_ssize_t seqlen;
939		Py_ssize_t pycount;
940
941		if (*elementType == _C_NSBOOL) {
942			if (PyBytes_Check(pythonList)) {
943				PyErr_Format(PyExc_ValueError, "Need array of BOOL, got byte string");
944				return -1;
945			}
946		} else if (*elementType == _C_CHAR_AS_INT) {
947			if (PyBytes_Check(pythonList)) {
948				PyErr_Format(PyExc_ValueError, "Need array of small integers, got byte string");
949				return -1;
950			}
951		}
952		PyObject* seq = PySequence_Fast(pythonList,
953					"converting to a C array");
954		if (seq == NULL) {
955			return -1;
956		}
957
958		seqlen = PySequence_Fast_GET_SIZE(seq);
959		if (size == NULL || *size == -1) {
960			pycount = seqlen;
961		} else {
962			pycount = *size;
963		}
964
965		if ((exactSize && seqlen != pycount) || (!exactSize && seqlen < pycount)) {
966			Py_DECREF(seq);
967			PyErr_Format(PyExc_ValueError,
968					"too few values (%"PY_FORMAT_SIZE_T"d) expecting at "
969					"least %"PY_FORMAT_SIZE_T"d", seqlen, pycount);
970			return -1;
971		}
972		*array = PyMem_Malloc(eltsize * pycount);
973		if (*array == NULL) {
974			Py_DECREF(seq);
975			PyErr_NoMemory();
976			return -1;
977		}
978		if (size) {
979			*size = pycount;
980		}
981		*bufobj = NULL;
982
983		for (i = 0; i < pycount; i++) {
984			PyObject* item = PySequence_Fast_GET_ITEM(seq, i);
985
986			r = depythonify_c_value(elementType, item,
987					((char*)*array)+(i*eltsize));
988			if (r == -1) {
989				Py_DECREF(seq);
990				PyMem_Free(*array); *array = NULL;
991				return -1;
992			}
993		}
994		return SHOULD_FREE;
995	}
996
997}
998
999
1000PyObject*
1001PyObjC_CArrayToPython(
1002	const char* elementType,
1003	void* array,
1004	Py_ssize_t size)
1005{
1006	PyObject* result;
1007	Py_ssize_t i;
1008	Py_ssize_t eltsize;
1009
1010	eltsize = PyObjCRT_SizeOfType(elementType);
1011	if (eltsize == -1) {
1012		return NULL;
1013	}
1014
1015
1016	if (eltsize == 1 || eltsize == 0) {
1017		if (*elementType == _C_CHAR_AS_TEXT) {
1018			return PyBytes_FromStringAndSize(array, size);
1019		}
1020		if (*elementType != _C_NSBOOL && *elementType != _C_BOOL && *elementType != _C_CHAR_AS_INT) {
1021			/* Special case for buffer-like objects */
1022			return PyBytes_FromStringAndSize(array, size);
1023		}
1024	}
1025
1026	if (*elementType == _C_UNICHAR) {
1027#if defined(PyObjC_UNICODE_FAST_PATH)
1028		result = PyUnicode_FromUnicode((Py_UNICODE*)array, size);
1029#else
1030#		error "Sorry, Wide Unicode builds not supported at the moment"
1031#endif
1032		return result;
1033	}
1034
1035	result = PyTuple_New(size);
1036	if (result == NULL) {
1037		return NULL;
1038	}
1039
1040
1041	for (i = 0; i < size; i++) {
1042		PyObject* elt = pythonify_c_value(elementType, array);
1043		if (elt == NULL) {
1044			Py_DECREF(result);
1045			return NULL;
1046		}
1047
1048		PyTuple_SET_ITEM(result, i, elt);
1049		array = ((char*)array) + eltsize;
1050	}
1051
1052	return result;
1053}
1054
1055int
1056PyObjC_IsPythonKeyword(const char* word)
1057{
1058	/*
1059	 * We cheat a little: this list only contains those keywords that
1060	 * are actually used in Cocoa.
1061	 *
1062	 * XXX: If we ever add the complete list here we should optimize
1063	 * this function.
1064	 */
1065	static const char* keywords[] = {
1066		"class",
1067		"raise",
1068		NULL
1069	};
1070	const char** cur;
1071
1072	for (cur = keywords; *cur != NULL; cur++) {
1073		if (strcmp(word, *cur) == 0) {
1074			return 1;
1075		}
1076	}
1077	return 0;
1078}
1079
1080int
1081PyObjCRT_SimplifySignature(char* signature, char* buf, size_t buflen)
1082{
1083	char* cur;
1084	char* end;
1085	char* next;
1086
1087	cur = signature;
1088	*buf = '\0';
1089
1090	while (*cur != '\0') {
1091		next = end = (char*)PyObjCRT_SkipTypeSpec(cur);
1092		end -= 1;
1093		while (end != cur && isdigit(*end)) {
1094			end --;
1095		}
1096		end++;
1097
1098		if ((size_t)(end - cur) > buflen) {
1099			return -1;
1100		}
1101
1102		memcpy(buf, cur, end-cur);
1103		buflen -= (end-cur);
1104		buf += (end-cur);
1105		*buf = '\0';
1106		cur = next;
1107	}
1108	return 0;
1109}
1110
1111
1112PyObject*
1113PyObjC_CArrayToPython2(
1114	const char* elementType,
1115	void* array,
1116	Py_ssize_t size,
1117	bool alreadyRetained,
1118	bool alreadyCFRetained)
1119{
1120	PyObject* result;
1121	Py_ssize_t i;
1122	Py_ssize_t eltsize;
1123
1124	if (size == -1) {
1125		size = 0;
1126	}
1127
1128	eltsize = PyObjCRT_SizeOfType(elementType);
1129	if (eltsize == -1) {
1130		return NULL;
1131	}
1132
1133	if (eltsize == 1 || eltsize == 0) {
1134		if (*elementType == _C_CHAR_AS_TEXT) {
1135			return PyBytes_FromStringAndSize(array, size);
1136		}
1137		if (*elementType != _C_NSBOOL && *elementType != _C_BOOL && *elementType != _C_CHAR_AS_INT) {
1138			/* Special case for buffer-like objects */
1139			return PyBytes_FromStringAndSize(array, size);
1140		}
1141	}
1142	if (*elementType == _C_UNICHAR) {
1143#if defined(PyObjC_UNICODE_FAST_PATH)
1144		result = PyUnicode_FromUnicode((Py_UNICODE*)array, size);
1145#else
1146#		error "Sorry, Wide Unicode builds not supported at the moment"
1147#endif
1148		return result;
1149	}
1150
1151	result = PyTuple_New(size);
1152	if (result == NULL) {
1153		return NULL;
1154	}
1155
1156
1157	for (i = 0; i < size; i++) {
1158		PyObject* elt = pythonify_c_value(elementType, array);
1159		if (elt == NULL) {
1160			Py_DECREF(result);
1161			return NULL;
1162		}
1163
1164		if (alreadyRetained) {
1165			[*(id*)array release];
1166		} else if (alreadyCFRetained) {
1167			CFRelease(*(id*)array);
1168		}
1169
1170		PyTuple_SET_ITEM(result, i, elt);
1171		array = ((char*)array) + eltsize;
1172	}
1173
1174	return result;
1175}
1176
1177int
1178PyObjCObject_Convert(PyObject* object, void* pvar)
1179{
1180	int r;
1181	r = depythonify_c_value(@encode(id), object, (id*)pvar);
1182	if (r == -1) {
1183		return 0;
1184	} else {
1185		return 1;
1186	}
1187}
1188
1189int
1190PyObjCClass_Convert(PyObject* object, void* pvar)
1191{
1192    if (!PyObjCClass_Check(object)) {
1193        PyErr_SetString(PyExc_TypeError, "Expected objective-C class");
1194        return 0;
1195    }
1196
1197    *(Class*)pvar = PyObjCClass_GetClass(object);
1198    if (*(Class*)pvar == NULL) return 0;
1199    return 1;
1200}
1201
1202int PyObjC_is_ascii_string(PyObject* unicode_string, const char* ascii_string)
1203{
1204	size_t uni_sz = PyUnicode_GetSize(unicode_string);
1205	size_t i;
1206	Py_UNICODE* code_points = PyUnicode_AsUnicode(unicode_string);
1207
1208	if (code_points == NULL) {
1209		PyErr_Clear();
1210		return 0;
1211	}
1212
1213	for (i = 0; i < uni_sz; i++) {
1214		if (code_points[i] != (Py_UNICODE)ascii_string[i]) {
1215			return 0;
1216		} else if (ascii_string[i] == '\0') {
1217			return 0;
1218		}
1219	}
1220	if (ascii_string[i] != '\0') {
1221		return 0;
1222	}
1223	return 1;
1224}
1225
1226int PyObjC_is_ascii_prefix(PyObject* unicode_string, const char* ascii_string, size_t n)
1227{
1228	size_t uni_sz = PyUnicode_GetSize(unicode_string);
1229	size_t i;
1230	Py_UNICODE* code_points = PyUnicode_AsUnicode(unicode_string);
1231
1232	if (code_points == NULL) {
1233		PyErr_Clear();
1234		return 0;
1235	}
1236
1237	for (i = 0; i < uni_sz && i < n; i++) {
1238		if (code_points[i] != (Py_UNICODE)ascii_string[i]) {
1239			return 0;
1240		} else if (ascii_string[i] == '\0') {
1241			return 0;
1242		}
1243	}
1244	return 1;
1245}
1246
1247PyObject*
1248PyObjC_ImportName(const char* name)
1249{
1250	PyObject* py_name;
1251	PyObject* mod;
1252	char* c = strrchr(name, '.');
1253
1254	if (c == NULL) {
1255		/* Toplevel module */
1256		py_name = PyText_FromString(name);
1257		mod = PyImport_Import(py_name);
1258		Py_DECREF(py_name);
1259		return mod;
1260	} else {
1261		py_name = PyText_FromStringAndSize(name, c - name);
1262		mod = PyImport_Import(py_name);
1263		Py_DECREF(py_name);
1264		if (mod == NULL) {
1265			return NULL;
1266		}
1267
1268		PyObject* v = PyObject_GetAttrString(mod, c + 1);
1269		Py_DECREF(mod);
1270		return v;
1271	}
1272}
1273