1#include "pyobjc.h"
2#import "OC_PythonArray.h"
3
4static PyObject* mapTypes = NULL;
5
6@implementation OC_PythonArray 
7
8+ (OC_PythonArray*)depythonifyObject:(PyObject*)object
9{
10	Py_ssize_t i, len;
11	
12	if (mapTypes == NULL) return NULL;
13
14	len = PyList_GET_SIZE(mapTypes);
15
16	for (i = 0; i < len; i++) {
17		PyObject* tp = PyList_GET_ITEM(mapTypes, i);
18		int r = PyObject_IsInstance(object, tp);
19		if (r == -1) {
20			return nil;
21		}
22
23		if (!r) continue;
24
25		/* Instance of this type should be pythonifyed as a sequence */
26		return [[[OC_PythonArray alloc] initWithPythonObject:object] autorelease];
27	}
28
29	return nil;
30}
31
32+ (id)depythonifyTable
33{
34	NSObject* result; 
35
36	PyObjC_BEGIN_WITH_GIL
37
38		if (mapTypes == NULL) {
39			mapTypes = PyList_New(0);
40			if (mapTypes == NULL) {
41				PyObjC_GIL_FORWARD_EXC();
42			}
43		}
44		result = PyObjC_PythonToId(mapTypes);
45		if (result == NULL) {
46			PyObjC_GIL_FORWARD_EXC();
47		}
48
49	PyObjC_END_WITH_GIL
50
51	return result;
52}
53
54+ (OC_PythonArray*)arrayWithPythonObject:(PyObject*)v
55{
56	OC_PythonArray* res;
57
58	res = [[OC_PythonArray alloc] initWithPythonObject:v];
59	[res autorelease];
60	return res;
61}
62
63- (id)initWithPythonObject:(PyObject*)v
64{
65	self = [super init];
66	if (unlikely(self == nil)) return nil;
67
68	Py_INCREF(v);
69	Py_XDECREF(value);
70	value = v;
71	return self;
72}
73
74-(PyObject*)__pyobjc_PythonObject__
75{
76	Py_INCREF(value);
77	return value;
78}
79
80-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
81{
82	*cookie = 0;
83	Py_INCREF(value);
84	return value;
85}
86
87-(BOOL)supportsWeakPointers { return YES; }
88
89-(oneway void)release
90{
91	/* See comment in OC_PythonUnicode */
92	PyObjC_BEGIN_WITH_GIL
93		[super release];
94	PyObjC_END_WITH_GIL
95}
96
97-(void)dealloc
98{
99	PyObjC_BEGIN_WITH_GIL
100		PyObjC_UnregisterObjCProxy(value, self);
101		Py_XDECREF(value);
102
103	PyObjC_END_WITH_GIL
104
105	[super dealloc];
106}
107
108-(NSUInteger)count
109{
110	Py_ssize_t result;
111
112	PyObjC_BEGIN_WITH_GIL
113		result = PySequence_Length(value);
114
115	PyObjC_END_WITH_GIL
116
117	if (result > INT_MAX) {
118		return INT_MAX;
119	}
120
121	return result;
122}
123
124-(id)objectAtIndex:(NSUInteger)idx
125{
126	PyObject* v;
127	id result;
128	int err;
129
130	PyObjC_BEGIN_WITH_GIL
131		if (idx > PY_SSIZE_T_MAX) {
132			PyErr_SetString(PyExc_IndexError, "out of range");
133			PyObjC_GIL_FORWARD_EXC();
134		}
135
136		v = PySequence_GetItem(value, idx);
137		if (unlikely(v == NULL)) {
138			PyObjC_GIL_FORWARD_EXC();
139		}
140
141		err = depythonify_c_value(@encode(id), v, &result);
142		if (unlikely(err == -1)) {
143			PyObjC_GIL_FORWARD_EXC();
144		} 
145		Py_CLEAR(v);
146	
147	PyObjC_END_WITH_GIL
148
149	if (!result) {
150		result = [NSNull null];
151	}
152	return result;
153}
154
155
156-(void)replaceObjectAtIndex:(NSUInteger)idx withObject:newValue
157{
158	PyObject* v;
159
160	PyObjC_BEGIN_WITH_GIL
161		if (idx > PY_SSIZE_T_MAX) {
162			PyErr_SetString(PyExc_IndexError, "out of range");
163			PyObjC_GIL_FORWARD_EXC();
164		}
165
166		if (unlikely(newValue == [NSNull null])) {
167			Py_INCREF(Py_None);
168			v = Py_None;
169
170		} else {
171			v = PyObjC_IdToPython(newValue);
172			if (v == NULL) {
173				PyObjC_GIL_FORWARD_EXC();
174			}
175		}
176
177		if (PySequence_SetItem(value, idx, v) < 0) {
178			Py_DECREF(v);
179			PyObjC_GIL_FORWARD_EXC();
180		}
181		Py_DECREF(v);
182
183	PyObjC_END_WITH_GIL;
184}
185
186-(void)getObjects:(id*)buffer inRange:(NSRange)range
187{
188	unsigned int i;
189
190	for (i = 0; i < range.length; i++) {
191		buffer[i] = [self objectAtIndex:i+range.location];
192	}
193}
194
195-(void)addObject:(id)anObject
196{
197	PyObject* v;
198	PyObject* w;
199
200	PyObjC_BEGIN_WITH_GIL
201
202		if (unlikely(anObject == [NSNull null])) {
203			Py_INCREF(Py_None);
204			v = Py_None;
205
206		} else {
207			v = PyObjC_IdToPython(anObject);
208			if (v == NULL) {
209				PyObjC_GIL_FORWARD_EXC();
210			}
211		}
212
213		w = PyObject_CallMethod(value, "append", "O", v);
214		if (unlikely(w == NULL)) {
215			Py_DECREF(v);
216			PyObjC_GIL_FORWARD_EXC();
217		}
218		Py_DECREF(v);
219		Py_DECREF(w);
220
221	PyObjC_END_WITH_GIL;
222}
223
224-(void)insertObject:(id)anObject atIndex:(NSUInteger)idx
225{
226	Py_ssize_t theIndex;
227	PyObject* v;
228	PyObject* w;
229
230	if (idx > PY_SSIZE_T_MAX) {
231		PyObjC_BEGIN_WITH_GIL
232			PyErr_SetString(PyExc_IndexError, "No such index");
233			PyObjC_GIL_FORWARD_EXC();
234		PyObjC_END_WITH_GIL
235	}
236	theIndex = idx;
237
238	PyObjC_BEGIN_WITH_GIL
239		if (unlikely(anObject == [NSNull null])) {
240			Py_INCREF(Py_None);
241			v = Py_None;
242		} else {
243			v = PyObjC_IdToPython(anObject);
244			if (v == NULL) {
245				PyObjC_GIL_FORWARD_EXC();
246			}
247		}
248
249		w = PyObject_CallMethod(value, "insert", Py_ARG_SIZE_T "O", theIndex, v);
250		if (unlikely(w == NULL)) {
251			Py_DECREF(v);
252			PyObjC_GIL_FORWARD_EXC();
253		}
254		Py_DECREF(v);
255		Py_DECREF(w);
256
257	PyObjC_END_WITH_GIL;
258}
259
260-(void)removeLastObject
261{
262	int r;
263	Py_ssize_t idx;
264
265	PyObjC_BEGIN_WITH_GIL
266		idx = PySequence_Length(value);
267		if (unlikely(idx == -1)) {
268			PyObjC_GIL_FORWARD_EXC();
269		}
270
271		if (unlikely(idx == 0)) {
272			PyErr_SetString(PyExc_ValueError, "pop empty sequence");
273			PyObjC_GIL_FORWARD_EXC();
274		}
275
276		r = PySequence_DelItem(value, idx-1);
277		if (unlikely(r == -1)) {
278			PyObjC_GIL_FORWARD_EXC();
279		}
280
281	PyObjC_END_WITH_GIL;
282}
283
284-(void)removeObjectAtIndex:(NSUInteger)idx
285{
286	int r;
287
288	PyObjC_BEGIN_WITH_GIL
289		if (unlikely(idx > PY_SSIZE_T_MAX)) {
290			PyErr_SetString(PyExc_IndexError, "No such index");
291			PyObjC_GIL_FORWARD_EXC();
292		}
293
294		r = PySequence_DelItem(value, (Py_ssize_t)idx);
295		if (unlikely(r == -1)) {
296			PyObjC_GIL_FORWARD_EXC();
297		}
298
299	PyObjC_END_WITH_GIL;
300}
301
302-(void)encodeWithCoder:(NSCoder*)coder
303{
304	/*
305	 * Instances of 'list' and 'tuple' are encoded directly,
306	 * for other sequences use the generic pickle support code.
307	 */
308	if (PyTuple_CheckExact(value)) {
309		/* Encode tuples as type 4 with an explicit length, this allows
310		 * us to create the tuple during decoding instead of having to
311		 * create a temporary list. This is needed to get full support
312		 * for encoding all datastructures, and is needed to pass the
313		 * unittests for pickle in python2.7.
314		 *
315		 * NOTE: older versions used type 1 and no length.
316		 */
317		if ([coder allowsKeyedCoding]) {
318			[coder encodeInt32:4 forKey:@"pytype"];
319			[coder encodeInt32:PyTuple_Size(value) forKey:@"pylength"];
320		} else {
321			int v = 4;
322			[coder encodeValueOfObjCType:@encode(int) at:&v];
323			v = (int)PyTuple_Size(value);
324			[coder encodeValueOfObjCType:@encode(int) at:&v];
325		}
326		[super encodeWithCoder:coder];
327	} else if (PyList_CheckExact(value)) {
328		if ([coder allowsKeyedCoding]) {
329			[coder encodeInt32:2 forKey:@"pytype"];
330		} else {
331			int v = 2;
332			[coder encodeValueOfObjCType:@encode(int) at:&v];
333		}
334		[super encodeWithCoder:coder];
335	} else {
336		if ([coder allowsKeyedCoding]) {
337			[coder encodeInt32:3 forKey:@"pytype"];
338		} else {
339			int v = 3;
340			[coder encodeValueOfObjCType:@encode(int) at:&v];
341		}
342		PyObjC_encodeWithCoder(value, coder);
343
344	}
345}
346
347/*
348 * A basic implementation of -initWithObjects:count:. This method is needed
349 * to support NSCoding for Python sequences.
350 */
351-(Class)classForCoder
352{
353	return [OC_PythonArray class];
354}
355
356-(id)initWithObjects:(NSObject**)objects count:(NSUInteger)count
357{
358	NSUInteger i;
359	PyObjC_BEGIN_WITH_GIL
360		if (PyTuple_CheckExact(value) && (NSUInteger)PyTuple_Size(value) == count) {
361			for  (i = 0; i < count; i++) {
362				PyObject* v;
363				if (objects[i] == [NSNull null]) {
364					v = Py_None; Py_INCREF(Py_None);
365				} else {
366					v = PyObjC_IdToPython(objects[i]);
367				}
368				if (v == NULL) {
369					PyObjC_GIL_FORWARD_EXC();
370				}
371				if (PyTuple_GET_ITEM(value, i) != NULL) {
372					/* use temporary option to avoid race condition */
373					PyObject* t = PyTuple_GET_ITEM(value, i);
374					PyTuple_SET_ITEM(value, i, NULL);
375					Py_DECREF(t);
376				}
377				PyTuple_SET_ITEM(value, i, v);
378				/* Don't DECREF v; SetItem stole a reference */
379			}
380		} else {
381
382			for  (i = 0; i < count; i++) {
383				PyObject* v;
384				int r;
385				if (objects[i] == [NSNull null]) {
386					v = Py_None; Py_INCREF(Py_None);
387				} else {
388					v = PyObjC_IdToPython(objects[i]);
389				}
390				if (v == NULL) {
391					PyObjC_GIL_FORWARD_EXC();
392				}
393				r = PyList_Append(value,  v);
394				if (r == -1) {
395					PyObjC_GIL_FORWARD_EXC();
396				}
397				Py_DECREF(v);
398			}
399		}
400
401	PyObjC_END_WITH_GIL
402	return self;
403}
404
405/* 
406 * Helper method for initWithCoder, needed to deal with
407 * recursive objects (e.g. o.value = o)
408 */
409-(void)pyobjcSetValue:(NSObject*)other
410{
411	PyObjC_BEGIN_WITH_GIL
412		PyObject* v = PyObjC_IdToPython(other);
413		Py_XDECREF(value);
414		value = v;
415	PyObjC_END_WITH_GIL
416}
417
418-(id)initWithCoder:(NSCoder*)coder
419{
420	PyObject* t;
421	int code;
422        int size;
423
424
425	if ([coder allowsKeyedCoding]) {
426		code = [coder decodeInt32ForKey:@"pytype"];
427	} else {
428		[coder decodeValueOfObjCType:@encode(int) at:&code];
429	}
430
431	switch (code) {
432	case 4: 
433	      if ([coder allowsKeyedCoding]) {
434		      size = [coder decodeInt32ForKey:@"pylength"];
435	      } else {
436		      [coder decodeValueOfObjCType:@encode(int) at:&size];
437	      }
438
439	      PyObjC_BEGIN_WITH_GIL
440	          value = PyTuple_New(size);
441		  if (value == NULL){
442			PyObjC_GIL_FORWARD_EXC();
443		  }
444	      PyObjC_END_WITH_GIL
445	      [super initWithCoder:coder];
446	      return self;
447
448
449	case 1:
450	      /* This code was created by some previous versions of PyObjC
451	       * (before 2.2) and is kept around for backward compatibilty.
452	       */
453	      PyObjC_BEGIN_WITH_GIL
454	          value = PyList_New(0);
455		  if (value == NULL){
456			PyObjC_GIL_FORWARD_EXC();
457		  }
458	      PyObjC_END_WITH_GIL
459	      
460	      [super initWithCoder:coder];
461	      PyObjC_BEGIN_WITH_GIL
462		      t = value;
463		      value = PyList_AsTuple(t);
464		      Py_DECREF(t);
465		      if (value == NULL) {
466				PyObjC_GIL_FORWARD_EXC();
467		      }
468	      PyObjC_END_WITH_GIL
469	      return self;
470
471	case 2:
472	      PyObjC_BEGIN_WITH_GIL
473	          value = PyList_New(0);
474		  if (value == NULL) {
475			PyObjC_GIL_FORWARD_EXC();
476		   }
477	      PyObjC_END_WITH_GIL
478	      [super initWithCoder:coder];
479	      return self;
480
481	case 3:
482		PyObjC_BEGIN_WITH_GIL
483			value = PyList_New(0);
484			if (value == NULL) {
485				PyObjC_GIL_FORWARD_EXC();
486			}
487		PyObjC_END_WITH_GIL
488
489		if (PyObjC_Decoder != NULL) {
490			PyObjC_BEGIN_WITH_GIL
491				PyObject* cdr = PyObjC_IdToPython(coder);
492				if (cdr == NULL) {
493					PyObjC_GIL_FORWARD_EXC();
494				}
495
496				PyObject* setValue;
497				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
498				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
499
500				PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
501				Py_DECREF(cdr);
502				Py_DECREF(setValue);
503				Py_DECREF(selfAsPython);
504
505				if (v == NULL) {
506					PyObjC_GIL_FORWARD_EXC();
507				}
508
509				Py_XDECREF(value);
510				value = v;
511
512				NSObject* proxy = PyObjC_FindObjCProxy(value);
513				if (proxy == NULL) {
514					PyObjC_RegisterObjCProxy(value, self);
515				} else {
516					[proxy retain];
517					[self release];
518					self = (OC_PythonArray*)proxy;
519				}
520
521
522			PyObjC_END_WITH_GIL
523
524			return self;
525		}
526	}
527
528	[NSException raise:NSInvalidArgumentException
529			format:@"decoding Python objects is not supported"];
530	[self release];
531	return nil;
532}
533
534
535-(id)copyWithZone:(NSZone*)zone
536{
537	if (PyObjC_CopyFunc) {
538		PyObjC_BEGIN_WITH_GIL
539			PyObject* copy = PyObject_CallFunctionObjArgs(PyObjC_CopyFunc,
540					value, NULL);
541
542			if (copy == NULL) {
543				PyObjC_GIL_FORWARD_EXC();
544			} 
545
546			NSObject* result = PyObjC_PythonToId(copy);
547			Py_DECREF(copy);
548
549			if (PyErr_Occurred()) {
550				PyObjC_GIL_FORWARD_EXC();
551			}
552
553			[result retain];
554
555			PyObjC_GIL_RETURN(result);
556
557		PyObjC_END_WITH_GIL
558	} else {
559		return [super copyWithZone:zone];
560	}
561}
562
563-(id)mutableCopyWithZone:(NSZone*)zone
564{
565	if (PyObjC_CopyFunc) {
566		PyObjC_BEGIN_WITH_GIL
567			PyObject* copy = PySequence_List(value);
568			if (copy == NULL) {
569				PyObjC_GIL_FORWARD_EXC();
570			} 
571
572			NSObject* result = PyObjC_PythonToId(copy);
573			Py_DECREF(copy);
574
575			if (PyErr_Occurred()) {
576				PyObjC_GIL_FORWARD_EXC();
577			}
578
579			[result retain];
580			PyObjC_GIL_RETURN(result);
581
582		PyObjC_END_WITH_GIL
583	} else {
584		return [super mutableCopyWithZone:zone];
585	}
586}
587@end /* implementation OC_PythonArray */
588