1#include "pyobjc.h" 2#import "OC_PythonUnicode.h" 3 4@implementation OC_PythonUnicode 5 6+ newWithPythonObject:(PyObject*)v; 7{ 8 OC_PythonUnicode* res; 9 10 res = [[OC_PythonUnicode alloc] initWithPythonObject:v]; 11 [res autorelease]; 12 return res; 13} 14 15- initWithPythonObject:(PyObject*)v; 16{ 17 Py_INCREF(v); 18 Py_XDECREF(value); 19 value = v; 20 return self; 21} 22 23 24-(PyObject*)__pyobjc_PythonObject__ 25{ 26 Py_INCREF(value); 27 return value; 28} 29 30-(PyObject*)__pyobjc_PythonTransient__:(int*)cookie 31{ 32 *cookie = 0; 33 Py_INCREF(value); 34 return value; 35} 36 37 38 39-(void)release 40{ 41 /* There is small race condition when an object is almost deallocated 42 * in one thread and fetched from the registration mapping in another 43 * thread. If we don't get the GIL this object might get a -dealloc 44 * message just as the other thread is fetching us from the mapping. 45 * That's why we need to grab the GIL here (getting it in dealloc is 46 * too late, we'd already be dead). 47 */ 48 /* FIXME: it should be possible to grab the lock only when really 49 * needed, but the test below isn't good enough. Be heavy handed to 50 * make sure we're right, rather than crashing sometimes anyway. 51 */ 52 /* FIXME2: in rare occasions we're trying to acquire the GIL during 53 * shutdown and if we're very unlucky this can happen after the 54 * GILState machinery has shut down... 55 */ 56#if 0 57 if ([self retainCount] == 1) { 58#endif 59 PyObjC_BEGIN_WITH_GIL 60 [super release]; 61 PyObjC_END_WITH_GIL 62#if 0 63 } else { 64 [super release]; 65 } 66#endif 67} 68 69-(void)dealloc 70{ 71 PyObjC_BEGIN_WITH_GIL 72 PyObjC_UnregisterObjCProxy(value, self); 73#ifndef PyObjC_UNICODE_FAST_PATH 74 [realObject release]; 75#endif /* !PyObjC_UNICODE_FAST_PATH */ 76 Py_XDECREF(value); 77 PyObjC_END_WITH_GIL 78 79 [super dealloc]; 80} 81 82#ifdef PyObjC_UNICODE_FAST_PATH 83 84-(NSUInteger)length 85{ 86 return (NSUInteger)PyUnicode_GET_SIZE(value); 87} 88 89-(unichar)characterAtIndex:(NSUInteger)anIndex 90{ 91 if (anIndex > PY_SSIZE_T_MAX) { 92 [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"]; 93 } 94 if (anIndex >= (NSUInteger)PyUnicode_GET_SIZE(value)) { 95 [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"]; 96 } 97 return PyUnicode_AS_UNICODE(value)[anIndex]; 98} 99 100-(void)getCharacters:(unichar *)buffer range:(NSRange)aRange 101{ 102 if (aRange.location + aRange.length > (NSUInteger)PyUnicode_GET_SIZE(value)) { 103 [NSException raise:@"NSRangeException" format:@"Range or index out of bounds"]; 104 } 105 memcpy(buffer, 106 PyUnicode_AS_UNICODE(value) + aRange.location, 107 sizeof(unichar) * aRange.length); 108} 109 110#else /* !PyObjC_UNICODE_FAST_PATH */ 111 112-(id)__realObject__ 113{ 114 if (!realObject) { 115 PyObjC_BEGIN_WITH_GIL 116 PyObject* utf8 = PyUnicode_AsUTF8String(value); 117 if (!utf8) { 118 NSLog(@"failed to encode unicode string to UTF8"); 119 PyErr_Clear(); 120 } else { 121 realObject = [[NSString alloc] 122 initWithBytes:PyString_AS_STRING(utf8) 123 length:(NSUInteger)PyString_GET_SIZE(value) 124 encoding:NSUTF8StringEncoding]; 125 Py_DECREF(utf8); 126 } 127 PyObjC_END_WITH_GIL 128 } 129 return realObject; 130} 131 132-(NSUInteger)length 133{ 134 return [((NSString *)[self __realObject__]) length]; 135} 136 137-(unichar)characterAtIndex:(NSUInteger)anIndex 138{ 139 return [((NSString *)[self __realObject__]) characterAtIndex:anIndex]; 140} 141 142-(void)getCharacters:(unichar *)buffer range:(NSRange)aRange 143{ 144 [((NSString *)[self __realObject__]) getCharacters:buffer range:aRange]; 145} 146 147 148#endif /* PyObjC_UNICODE_FAST_PATH */ 149 150/* 151 * NSCoding support 152 * 153 * We need explicit NSCoding support to get full fidelity, otherwise we'll 154 * get archived as generic NSStrings. 155 */ 156- (id)initWithCharactersNoCopy:(unichar *)characters 157 length:(NSUInteger)length 158 freeWhenDone:(BOOL)flag 159{ 160#ifndef PyObjC_UNICODE_FAST_PATH 161# error "Wide UNICODE builds are not supported at the moment" 162#endif 163 PyObjC_BEGIN_WITH_GIL 164 value = PyUnicode_FromUnicode((Py_UNICODE*)characters, length); 165 if (value == NULL) { 166 PyObjC_GIL_FORWARD_EXC(); 167 } 168 169 PyObjC_END_WITH_GIL; 170 if (flag) { 171 free(characters); 172 } 173 return self; 174} 175 176 177/* 178 * Helper method for initWithCoder, needed to deal with 179 * recursive objects (e.g. o.value = o) 180 */ 181-(void)pyobjcSetValue:(NSObject*)other 182{ 183 PyObject* v = PyObjC_IdToPython(other); 184 Py_XDECREF(value); 185 value = v; 186} 187 188- initWithCoder:(NSCoder*)coder 189{ 190 int ver; 191 if ([coder allowsKeyedCoding]) { 192 ver = [coder decodeInt32ForKey:@"pytype"]; 193 } else { 194 [coder decodeValueOfObjCType:@encode(int) at:&ver]; 195 } 196 if (ver == 1) { 197 self = [super initWithCoder:coder]; 198 return self; 199 } else if (ver == 2) { 200 201 if (PyObjC_Decoder != NULL) { 202 PyObjC_BEGIN_WITH_GIL 203 PyObject* cdr = PyObjC_IdToPython(coder); 204 if (cdr == NULL) { 205 PyObjC_GIL_FORWARD_EXC(); 206 } 207 208 PyObject* setValue; 209 PyObject* selfAsPython = PyObjCObject_New(self, 0, YES); 210 setValue = PyObject_GetAttrString(selfAsPython, "pyobjcSetValue_"); 211 212 PyObject* v = PyObject_CallFunction(PyObjC_Decoder, "OO", cdr, setValue); 213 Py_DECREF(cdr); 214 Py_DECREF(setValue); 215 Py_DECREF(selfAsPython); 216 217 if (v == NULL) { 218 PyObjC_GIL_FORWARD_EXC(); 219 } 220 221 Py_XDECREF(value); 222 value = v; 223 224 NSObject* proxy = PyObjC_FindObjCProxy(value); 225 if (proxy == NULL) { 226 PyObjC_RegisterObjCProxy(value, self); 227 } else { 228 [self release]; 229 [proxy retain]; 230 self = (OC_PythonUnicode*)proxy; 231 } 232 233 234 PyObjC_END_WITH_GIL 235 236 return self; 237 238 } else { 239 [NSException raise:NSInvalidArgumentException 240 format:@"decoding Python objects is not supported"]; 241 return nil; 242 243 } 244 } else { 245 [NSException raise:NSInvalidArgumentException 246 format:@"encoding Python objects is not supported"]; 247 return nil; 248 } 249} 250 251-(void)encodeWithCoder:(NSCoder*)coder 252{ 253 if (PyUnicode_CheckExact(value)) { 254 if ([coder allowsKeyedCoding]) { 255 [coder encodeInt32:1 forKey:@"pytype"]; 256 } else { 257 int v = 1; 258 [coder encodeValueOfObjCType:@encode(int) at:&v]; 259 } 260 [super encodeWithCoder:coder]; 261 } else { 262 if ([coder allowsKeyedCoding]) { 263 [coder encodeInt32:2 forKey:@"pytype"]; 264 } else { 265 int v = 2; 266 [coder encodeValueOfObjCType:@encode(int) at:&v]; 267 } 268 269 PyObjC_encodeWithCoder(value, coder); 270 } 271} 272 273#if 1 274 275 276-(NSObject*)replacementObjectForArchiver:(NSArchiver*)archiver 277{ 278 (void)(archiver); 279 return self; 280} 281 282-(NSObject*)replacementObjectForKeyedArchiver:(NSKeyedArchiver*)archiver 283{ 284 (void)(archiver); 285 return self; 286} 287 288-(NSObject*)replacementObjectForCoder:(NSCoder*)archiver 289{ 290 (void)(archiver); 291 return self; 292} 293 294-(NSObject*)replacementObjectForPortCoder:(NSPortCoder*)archiver 295{ 296 (void)(archiver); 297 return self; 298} 299 300-(Class)classForArchiver 301{ 302 return [OC_PythonUnicode class]; 303} 304 305-(Class)classForKeyedArchiver 306{ 307 return [OC_PythonUnicode class]; 308} 309 310-(Class)classForCoder 311{ 312 return [OC_PythonUnicode class]; 313} 314 315-(Class)classForPortCoder 316{ 317 return [OC_PythonUnicode class]; 318} 319 320/* Ensure that we can be unarchived as a generic string by pure ObjC 321 * code. 322 */ 323+classFallbacksForKeyedArchiver 324{ 325 return [NSArray arrayWithObject:@"NSString"]; 326} 327 328#endif 329 330@end /* implementation OC_PythonUnicode */ 331