1#include "pyobjc.h"
2#import "OC_PythonData.h"
3
4@implementation OC_PythonData 
5
6+ (OC_PythonData*)dataWithPythonObject:(PyObject*)v
7{
8	OC_PythonData* res;
9
10	res = [[OC_PythonData alloc] initWithPythonObject:v];
11	[res autorelease];
12	return res;
13}
14
15
16- (OC_PythonData*)initWithPythonObject:(PyObject*)v
17{
18	self = [super init];
19	if (unlikely(self == nil)) return nil;
20
21	if (unlikely(PyObject_AsReadBuffer(v, &buffer, &buffer_len) == -1)) {
22		[super dealloc];
23		return nil;
24	}
25	Py_INCREF(v);
26	Py_XDECREF(value);
27	value = v;
28	return self;
29}
30
31-(PyObject*)__pyobjc_PythonObject__
32{
33	Py_INCREF(value);
34	return value;
35}
36
37-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie
38{
39	*cookie = 0;
40	Py_INCREF(value);
41	return value;
42}
43
44-(BOOL)supportsWeakPointers { return YES; }
45
46-(oneway void)release
47{
48	/* See comment in OC_PythonUnicode */
49	PyObjC_BEGIN_WITH_GIL
50		[super release];
51	PyObjC_END_WITH_GIL
52}
53        
54
55
56-(void)dealloc
57{
58	PyObjC_BEGIN_WITH_GIL
59		PyObjC_UnregisterObjCProxy(value, self);
60		Py_XDECREF(value);
61
62	PyObjC_END_WITH_GIL
63
64	[super dealloc];
65}
66
67-(NSUInteger)length
68{
69	NSUInteger rval;
70	
71	PyObjC_BEGIN_WITH_GIL
72		if (unlikely(PyObject_AsReadBuffer(value, &buffer, &buffer_len) == -1)) {
73			PyErr_Clear();
74			rval = 0;
75		} else {
76			if ((NSUInteger)buffer_len > NSUIntegerMax) {
77				rval = NSUIntegerMax;
78			} else {
79				rval = buffer_len;
80			}
81		}
82	PyObjC_END_WITH_GIL
83	return rval;
84}
85
86-(const void *)bytes
87{
88	const void *rval;
89	PyObjC_BEGIN_WITH_GIL
90		if (unlikely(PyObject_AsReadBuffer(value, &buffer, &buffer_len) == -1)) {
91			PyErr_Clear();
92			rval = NULL;
93		}
94		rval = buffer;
95	PyObjC_END_WITH_GIL
96	return rval;
97}
98
99-(Class)classForCoder
100{
101	return [OC_PythonData class];
102}
103
104
105-(void)encodeWithCoder:(NSCoder*)coder
106{
107
108	PyObjC_BEGIN_WITH_GIL
109		if (PyBytes_CheckExact(value)) {
110			if (unlikely(PyObject_AsReadBuffer(value, &buffer, &buffer_len) == -1)) {
111				PyObjC_GIL_FORWARD_EXC();
112			}
113
114
115			if ([coder allowsKeyedCoding]) {
116				[coder encodeInt32:1 forKey:@"pytype"];
117				[coder encodeBytes:buffer length:buffer_len forKey: @"pybytes"];
118
119			} else {
120				int v = 1;
121				[coder encodeValueOfObjCType:@encode(int) at:&v];
122				[coder encodeBytes:buffer length:buffer_len];
123			}
124			
125		} else {
126			if ([coder allowsKeyedCoding]) {
127				[coder encodeInt32:2 forKey:@"pytype"];
128			} else {
129				int v = 2;
130				[coder encodeValueOfObjCType:@encode(int) at:&v];
131			}
132
133			PyObjC_encodeWithCoder(value, coder);
134		}
135	PyObjC_END_WITH_GIL
136}
137
138/* 
139 * Helper method for initWithCoder, needed to deal with
140 * recursive objects (e.g. o.value = o)
141 */
142-(void)pyobjcSetValue:(NSObject*)other
143{
144	PyObjC_BEGIN_WITH_GIL
145		PyObject* v = PyObjC_IdToPython(other);
146		Py_XDECREF(value);
147		value = v;
148	PyObjC_END_WITH_GIL
149}
150
151- (id)initWithCoder:(NSCoder*)coder
152{
153	int v;
154	
155	if ([coder allowsKeyedCoding]) {
156
157		v = [coder decodeInt32ForKey:@"pytype"];
158	} else {
159		[coder decodeValueOfObjCType:@encode(int) at:&v];
160	}
161	if (v == 1) {
162		self = [super init];
163		if (unlikely(self == nil)) return nil;
164
165		const void *bytes;
166		NSUInteger length;
167
168		if ([coder allowsKeyedCoding]) {
169			bytes = [coder decodeBytesForKey:@"pybytes" returnedLength:&length];
170		} else {
171			bytes = [coder decodeBytesWithReturnedLength:&length];
172		}
173		PyObjC_BEGIN_WITH_GIL
174			value = PyBytes_FromStringAndSize(bytes, length);
175			if (value == NULL) {
176				[super dealloc];
177				PyObjC_GIL_FORWARD_EXC();
178			}
179		PyObjC_END_WITH_GIL;
180		return self;
181
182	} else if (v == 2) {
183
184		if (PyObjC_Decoder != NULL) {
185			PyObjC_BEGIN_WITH_GIL
186				PyObject* cdr = PyObjC_IdToPython(coder);
187				if (cdr == NULL) {
188					PyObjC_GIL_FORWARD_EXC();
189				}
190
191				PyObject* setValue;
192				PyObject* selfAsPython = PyObjCObject_New(self, 0, YES);
193				setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_");
194
195				PyObject* v2 = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue);
196				Py_DECREF(cdr);
197				Py_DECREF(setValue);
198				Py_DECREF(selfAsPython);
199
200				if (v2 == NULL) {
201					PyObjC_GIL_FORWARD_EXC();
202				}
203
204				Py_XDECREF(value);
205				value = v2;
206
207				NSObject* proxy = PyObjC_FindObjCProxy(value);
208				if (proxy == NULL) {
209					PyObjC_RegisterObjCProxy(value, self);
210				} else {
211					[self release];
212					[proxy retain];
213					self = (OC_PythonData*)proxy;
214				}
215
216
217			PyObjC_END_WITH_GIL
218
219			return self;
220
221		} else {
222			[NSException raise:NSInvalidArgumentException
223					format:@"decoding Python objects is not supported"];
224			return nil;
225
226		}
227
228	} else {
229		[NSException raise:NSInvalidArgumentException
230				format:@"encoding Python objects is not supported"];
231	}
232	return self;
233}
234
235
236@end /* implementation OC_PythonData */
237