if (mapping->ob_type == &EncodingMapType) { int res = encoding_map_lookup(c, mapping); Py_ssize_t requiredsize = *outpos+1; if (res == -1) return enc_FAILED; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) return enc_EXCEPTION; outstart = PyString_AS_STRING(*outobj); outstart[(*outpos)++] = (char)res; return enc_SUCCESS; } rep = charmapencode_lookup(c, mapping); if (rep==NULL) return enc_EXCEPTION; else if (rep==Py_None) { Py_DECREF(rep); return enc_FAILED; } else { if (PyInt_Check(rep)) { Py_ssize_t requiredsize = *outpos+1; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } outstart = PyString_AS_STRING(*outobj); outstart[(*outpos)++] = (char)PyInt_AS_LONG(rep); } else { const char *repchars = PyString_AS_STRING(rep); Py_ssize_t repsize = PyString_GET_SIZE(rep); Py_ssize_t requiredsize = *outpos+repsize; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } outstart = PyString_AS_STRING(*outobj); memcpy(outstart + *outpos, repchars, repsize); *outpos += repsize; } } Py_DECREF(rep); return enc_SUCCESS;} /* handle an error in PyUnicode_EncodeCharmap Return 0 on success, -1 on error */staticint charmap_encoding_error( const Py_UNICODE *p, Py_ssize_t size, Py_ssize_t *inpos, PyObject *mapping, PyObject **exceptionObject, int *known_errorHandler, PyObject **errorHandler, const char *errors, PyObject **res, Py_ssize_t *respos){ PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ Py_ssize_t repsize; Py_ssize_t newpos; Py_UNICODE *uni2; /* startpos for collecting unencodable chars */ Py_ssize_t collstartpos = *inpos; Py_ssize_t collendpos = *inpos+1; Py_ssize_t collpos; char *encoding = "charmap"; char *reason = "character maps to <undefined>"; charmapencode_result x; /* find all unencodable characters */ while (collendpos < size) { PyObject *rep; if (mapping->ob_type == &EncodingMapType) { int res = encoding_map_lookup(p[collendpos], mapping); if (res != -1) break; ++collendpos; continue; } rep = charmapencode_lookup(p[collendpos], mapping); if (rep==NULL) return -1; else if (rep!=Py_None) { Py_DECREF(rep); break; } Py_DECREF(rep); ++collendpos; } /* cache callback name lookup * (if not done yet, i.e. it's the first error) */ if (*known_errorHandler==-1) { if ((errors==NULL) || (!strcmp(errors, "strict"))) *known_errorHandler = 1; else if (!strcmp(errors, "replace")) *known_errorHandler = 2; else if (!strcmp(errors, "ignore")) *known_errorHandler = 3; else if (!strcmp(errors, "xmlcharrefreplace")) *known_errorHandler = 4; else *known_errorHandler = 0; } switch (*known_errorHandler) { case 1: /* strict */ raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; case 2: /* replace */ for (collpos = collstartpos; collpos<collendpos; ++collpos) { x = charmapencode_output('?', mapping, res, respos); if (x==enc_EXCEPTION) { return -1; } else if (x==enc_FAILED) { raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } /* fall through */ case 3: /* ignore */ *inpos = collendpos; break; case 4: /* xmlcharrefreplace */ /* generate replacement (temporarily (mis)uses p) */ for (collpos = collstartpos; collpos < collendpos; ++collpos) { char buffer[2+29+1+1]; char *cp; sprintf(buffer, "&#%d;", (int)p[collpos]); for (cp = buffer; *cp; ++cp) { x = charmapencode_output(*cp, mapping, res, respos); if (x==enc_EXCEPTION) return -1; else if (x==enc_FAILED) { raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } } *inpos = collendpos; break; default: repunicode = unicode_encode_call_errorhandler(errors, errorHandler, encoding, reason, p, size, exceptionObject, collstartpos, collendpos, &newpos); if (repunicode == NULL) return -1; /* generate replacement */ repsize = PyUnicode_GET_SIZE(repunicode); for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { x = charmapencode_output(*uni2, mapping, res, respos); if (x==enc_EXCEPTION) { return -1; } else if (x==enc_FAILED) { Py_DECREF(repunicode); raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } *inpos = newpos; Py_DECREF(repunicode); } return 0;} PyObject *PyUnicode_EncodeCharmap(const Py_UNICODE *p, Py_ssize_t size, PyObject *mapping, const char *errors){ /* output object */ PyObject *res = NULL; /* current input position */ Py_ssize_t inpos = 0; /* current output position */ Py_ssize_t respos = 0; PyObject *errorHandler = NULL; PyObject *exc = NULL; /* the following variable is used for caching string comparisons * -1=not initialized, 0=unknown, 1=strict, 2=replace, * 3=ignore, 4=xmlcharrefreplace */ int known_errorHandler = -1; /* Default to Latin-1 */ if (mapping == NULL) return PyUnicode_EncodeLatin1(p, size, errors); /* allocate enough for a simple encoding without replacements, if we need more, we'll resize */ res = PyString_FromStringAndSize(NULL, size); if (res == NULL) goto onError; if (size == 0) return res; while (inpos<size) { /* try to encode it */ charmapencode_result x = charmapencode_output(p[inpos], mapping, &res, &respos); if (x==enc_EXCEPTION) /* error */ goto onError; if (x==enc_FAILED) { /* unencodable character */ if (charmap_encoding_error(p, size, &inpos, mapping, &exc, &known_errorHandler, &errorHandler, errors, &res, &respos)) { goto onError; } } else /* done with this character => adjust input position */ ++inpos; } /* Resize if we allocated to much */ if (respos<PyString_GET_SIZE(res)) { if (_PyString_Resize(&res, respos)) goto onError; } Py_XDECREF(exc); Py_XDECREF(errorHandler); return res; onError: Py_XDECREF(res); Py_XDECREF(exc); Py_XDECREF(errorHandler); return NULL;} PyObject *PyUnicode_AsCharmapString(PyObject *unicode, PyObject *mapping){ if (!PyUnicode_Check(unicode) || mapping == NULL) { PyErr_BadArgument(); return NULL; } return PyUnicode_EncodeCharmap(PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), mapping, NULL);} /* create or adjust a UnicodeTranslateError */static void make_translate_exception(PyObject **exceptionObject, const Py_UNICODE *unicode, Py_ssize_t size, Py_ssize_t startpos, Py_ssize_t endpos, const char *reason){ if (*exceptionObject == NULL) { *exceptionObject = PyUnicodeTranslateError_Create( unicode, size, startpos, endpos, reason); } else { if (PyUnicodeTranslateError_SetStart(*exceptionObject, startpos)) goto onError; if (PyUnicodeTranslateError_SetEnd(*exceptionObject, endpos)) goto onError; if (PyUnicodeTranslateError_SetReason(*exceptionObject, reason)) goto onError; return; onError: Py_DECREF(*exceptionObject); *exceptionObject = NULL; }} /* raises a UnicodeTranslateError */static void raise_translate_exception(PyObject **exceptionObject, const Py_UNICODE *unicode, Py_ssize_t size, Py_ssize_t startpos, Py_ssize_t endpos, const char *reason){ make_translate_exception(exceptionObject, unicode, size, startpos, endpos, reason); if (*exceptionObject != NULL) PyCodec_StrictErrors(*exceptionObject);} /* error handling callback helper: build arguments, call the callback and check the arguments, put the result into newpos and return the replacement string, which has to be freed by the caller */static PyObject *unicode_translate_call_errorhandler(const char *errors, PyObject **errorHandler, const char *reason, const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, Py_ssize_t startpos, Py_ssize_t endpos, Py_ssize_t *newpos){ static char *argparse = "O!n;translating error handler must return (unicode, int) tuple"; Py_ssize_t i_newpos; PyObject *restuple; PyObject *resunicode; if (*errorHandler == NULL) { *errorHandler = PyCodec_LookupError(errors); if (*errorHandler == NULL) return NULL; } make_translate_exception(exceptionObject, unicode, size, startpos, endpos, reason); if (*exceptionObject == NULL) return NULL; restuple = PyObject_CallFunctionObjArgs( *errorHandler, *exceptionObject, NULL); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { PyErr_Format(PyExc_TypeError, &argparse[4]); Py_DECREF(restuple); return NULL; } if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &resunicode, &i_newpos)) { Py_DECREF(restuple); return NULL; } if (i_newpos<0) *newpos = size+i_newpos; else *newpos = i_newpos; if (*newpos<0 || *newpos>size) { PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); Py_DECREF(restuple); return NULL; } Py_INCREF(resunicode); Py_DECREF(restuple); return resunicode;} /* Lookup the character ch in the mapping and put the result in result, which must be decrefed by the caller. Return 0 on success, -1 on error */staticint charmaptranslate_lookup(Py_UNICODE c, PyObject *mapping, PyObject **result){ PyObject *w = PyInt_FromLong((long)c); PyObject *x; if (w == NULL) return -1; x = PyObject_GetItem(mapping, w); Py_DECREF(w); if (x == NULL) { if (PyErr_ExceptionMatches(PyExc_LookupError)) { /* No mapping found means: use 1:1 mapping. */ PyErr_Clear(); *result = NULL; return 0; } else return -1; } else if (x == Py_None) { *result = x; return 0; } else if (PyInt_Check(x)) { long value = PyInt_AS_LONG(x); long max = PyUnicode_GetMax(); if (value < 0 || value > max) { PyErr_Format(PyExc_TypeError, "character mapping must be in range(0x%lx)", max+1); Py_DECREF(x); return -1; } *result = x; return 0; } else if (PyUnicode_Check(x)) { *result = x; return 0; } else { /* wrong return value */ PyErr_SetString(PyExc_TypeError, "character mapping must return integer, None or unicode"); Py_DECREF(x); return -1; }}/* ensure that *outobj is at least requiredsize characters long,if not reallocate and adjust various state variables.Return 0 on success, -1 on error */staticint charmaptranslate_makespace(PyObject **outobj, Py_UNICODE **outp, Py_ssize_t requiredsize){ Py_ssize_t oldsize = PyUnicode_GET_SIZE(*outobj); if (requiredsize > oldsize) { /* remember old output position */ Py_ssize_t outpos = *outp-PyUnicode_AS_UNICODE(*outobj); /* exponentially overallocate to minimize reallocations */ if (requiredsize < 2 * oldsize) requiredsize = 2 * oldsize; if (_PyUnicode_Resize(outobj, requiredsize) < 0) return -1; *outp = PyUnicode_AS_UNICODE(*outobj) + outpos; } return 0;}/* lookup the character, put the result in the output string and adjust various state variables. Return a new reference to the object that was put in the output buffer in *result, or Py_None, if the mapping was undefined (in which case no character was written). The called must decref result. Return 0 on success, -1 on error. */staticint charmaptranslate_output(const Py_UNICODE *startinp, const Py_UNICODE *curinp, Py_ssize_t insize, PyObject *mapping, PyObject **outobj, Py_UNICODE **outp, PyObject **res){ if (charmaptranslate_lookup(*curinp, mapping, res)) return -1; if (*res==NULL) { /* not found => default to 1:1 mapping */ *(*outp)++ = *curinp; } else if (*res==Py_None) ; else if (PyInt_Check(*res)) { /* no overflow check, because we know that the space is enough */ *(*outp)++ = (Py_UNICODE)PyInt_AS_LONG(*res); } else if (PyUnicode_Check(*res)) { Py_ssize_t repsize = PyUnicode_GET_SIZE(*res); if (repsize==1) { /* no overflow check, because we know that the space is enough */ *(*outp)++ = *PyUnicode_AS_UNICODE(*res); } else if (repsize!=0) { /* more than one character */ Py_ssize_t requiredsize = (*outp-PyUnicode_AS_UNICODE(*outobj)) + (insize - (curinp-startinp)) + repsize - 1; if (charmaptranslate_makespace(outobj, outp, requiredsize)) return -1; memcpy(*outp, PyUnicode_AS_UNICODE(*res), sizeof(Py_UNICODE)*repsize); *outp += repsize; } } else return -1; return 0;} PyObject *PyUnicode_TranslateCharmap(const Py_UNICODE *p, Py_ssize_t size, PyObject *mapping, const char *errors){ /* output object */ PyObject *res = NULL; /* pointers to the beginning and end+1 of input */ const Py_UNICODE *startp = p; const Py_UNICODE *endp = p + size; /* pointer into the output */ Py_UNICODE *str; /* current output position */ Py_ssize_t respos = 0; char *reason = "character maps to <undefined>"; PyObject *errorHandler = NULL; PyObject *exc = NULL; /* the following variable is used for caching string comparisons * -1=not initialized, 0=unknown, 1=strict, 2=replace, * 3=ignore, 4=xmlcharrefreplace */ int known_errorHandler = -1; if (mapping == NULL) { PyErr_BadArgument(); return NULL; } /* allocate enough for a simple 1:1 translation without replacements, if we need more, we'll resize */ res = PyUnicode_FromUnicode(NULL, size); if (res == NULL) goto onError; if (size == 0) return res; str = PyUnicode_AS_UNICODE(res); while (p<endp) { /* try to encode it */ PyObject *x = NULL; if (charmaptranslate_output(startp, p, size, mapping, &res, &str, &x)) { Py_XDECREF(x); goto onError; } Py_XDECREF(x); if (x!=Py_None) /* it worked => adjust input pointer */ ++p; else { /* untranslatable character */ PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ Py_ssize_t repsize; Py_ssize_t newpos;Lines 3501–4000 of 8067. Previous lines Load more
if (mapping->ob_type == &EncodingMapType) { int res = encoding_map_lookup(c, mapping); Py_ssize_t requiredsize = *outpos+1; if (res == -1) return enc_FAILED; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) return enc_EXCEPTION; outstart = PyString_AS_STRING(*outobj); outstart[(*outpos)++] = (char)res; return enc_SUCCESS; } rep = charmapencode_lookup(c, mapping); if (rep==NULL) return enc_EXCEPTION; else if (rep==Py_None) { Py_DECREF(rep); return enc_FAILED; } else { if (PyInt_Check(rep)) { Py_ssize_t requiredsize = *outpos+1; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } outstart = PyString_AS_STRING(*outobj); outstart[(*outpos)++] = (char)PyInt_AS_LONG(rep); } else { const char *repchars = PyString_AS_STRING(rep); Py_ssize_t repsize = PyString_GET_SIZE(rep); Py_ssize_t requiredsize = *outpos+repsize; if (outsize<requiredsize) if (!charmapencode_resize(outobj, outpos, requiredsize)) { Py_DECREF(rep); return enc_EXCEPTION; } outstart = PyString_AS_STRING(*outobj); memcpy(outstart + *outpos, repchars, repsize); *outpos += repsize; } } Py_DECREF(rep); return enc_SUCCESS; } /* handle an error in PyUnicode_EncodeCharmap Return 0 on success, -1 on error */ static int charmap_encoding_error( const Py_UNICODE *p, Py_ssize_t size, Py_ssize_t *inpos, PyObject *mapping, PyObject **exceptionObject, int *known_errorHandler, PyObject **errorHandler, const char *errors, PyObject **res, Py_ssize_t *respos) { PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ Py_ssize_t repsize; Py_ssize_t newpos; Py_UNICODE *uni2; /* startpos for collecting unencodable chars */ Py_ssize_t collstartpos = *inpos; Py_ssize_t collendpos = *inpos+1; Py_ssize_t collpos; char *encoding = "charmap"; char *reason = "character maps to <undefined>"; charmapencode_result x; /* find all unencodable characters */ while (collendpos < size) { PyObject *rep; if (mapping->ob_type == &EncodingMapType) { int res = encoding_map_lookup(p[collendpos], mapping); if (res != -1) break; ++collendpos; continue; } rep = charmapencode_lookup(p[collendpos], mapping); if (rep==NULL) return -1; else if (rep!=Py_None) { Py_DECREF(rep); break; } Py_DECREF(rep); ++collendpos; } /* cache callback name lookup * (if not done yet, i.e. it's the first error) */ if (*known_errorHandler==-1) { if ((errors==NULL) || (!strcmp(errors, "strict"))) *known_errorHandler = 1; else if (!strcmp(errors, "replace")) *known_errorHandler = 2; else if (!strcmp(errors, "ignore")) *known_errorHandler = 3; else if (!strcmp(errors, "xmlcharrefreplace")) *known_errorHandler = 4; else *known_errorHandler = 0; } switch (*known_errorHandler) { case 1: /* strict */ raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; case 2: /* replace */ for (collpos = collstartpos; collpos<collendpos; ++collpos) { x = charmapencode_output('?', mapping, res, respos); if (x==enc_EXCEPTION) { return -1; } else if (x==enc_FAILED) { raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } /* fall through */ case 3: /* ignore */ *inpos = collendpos; break; case 4: /* xmlcharrefreplace */ /* generate replacement (temporarily (mis)uses p) */ for (collpos = collstartpos; collpos < collendpos; ++collpos) { char buffer[2+29+1+1]; char *cp; sprintf(buffer, "&#%d;", (int)p[collpos]); for (cp = buffer; *cp; ++cp) { x = charmapencode_output(*cp, mapping, res, respos); if (x==enc_EXCEPTION) return -1; else if (x==enc_FAILED) { raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } } *inpos = collendpos; break; default: repunicode = unicode_encode_call_errorhandler(errors, errorHandler, encoding, reason, p, size, exceptionObject, collstartpos, collendpos, &newpos); if (repunicode == NULL) return -1; /* generate replacement */ repsize = PyUnicode_GET_SIZE(repunicode); for (uni2 = PyUnicode_AS_UNICODE(repunicode); repsize-->0; ++uni2) { x = charmapencode_output(*uni2, mapping, res, respos); if (x==enc_EXCEPTION) { return -1; } else if (x==enc_FAILED) { Py_DECREF(repunicode); raise_encode_exception(exceptionObject, encoding, p, size, collstartpos, collendpos, reason); return -1; } } *inpos = newpos; Py_DECREF(repunicode); } return 0; } PyObject *PyUnicode_EncodeCharmap(const Py_UNICODE *p, Py_ssize_t size, PyObject *mapping, const char *errors) { /* output object */ PyObject *res = NULL; /* current input position */ Py_ssize_t inpos = 0; /* current output position */ Py_ssize_t respos = 0; PyObject *errorHandler = NULL; PyObject *exc = NULL; /* the following variable is used for caching string comparisons * -1=not initialized, 0=unknown, 1=strict, 2=replace, * 3=ignore, 4=xmlcharrefreplace */ int known_errorHandler = -1; /* Default to Latin-1 */ if (mapping == NULL) return PyUnicode_EncodeLatin1(p, size, errors); /* allocate enough for a simple encoding without replacements, if we need more, we'll resize */ res = PyString_FromStringAndSize(NULL, size); if (res == NULL) goto onError; if (size == 0) return res; while (inpos<size) { /* try to encode it */ charmapencode_result x = charmapencode_output(p[inpos], mapping, &res, &respos); if (x==enc_EXCEPTION) /* error */ goto onError; if (x==enc_FAILED) { /* unencodable character */ if (charmap_encoding_error(p, size, &inpos, mapping, &exc, &known_errorHandler, &errorHandler, errors, &res, &respos)) { goto onError; } } else /* done with this character => adjust input position */ ++inpos; } /* Resize if we allocated to much */ if (respos<PyString_GET_SIZE(res)) { if (_PyString_Resize(&res, respos)) goto onError; } Py_XDECREF(exc); Py_XDECREF(errorHandler); return res; onError: Py_XDECREF(res); Py_XDECREF(exc); Py_XDECREF(errorHandler); return NULL; } PyObject *PyUnicode_AsCharmapString(PyObject *unicode, PyObject *mapping) { if (!PyUnicode_Check(unicode) || mapping == NULL) { PyErr_BadArgument(); return NULL; } return PyUnicode_EncodeCharmap(PyUnicode_AS_UNICODE(unicode), PyUnicode_GET_SIZE(unicode), mapping, NULL); } /* create or adjust a UnicodeTranslateError */ static void make_translate_exception(PyObject **exceptionObject, const Py_UNICODE *unicode, Py_ssize_t size, Py_ssize_t startpos, Py_ssize_t endpos, const char *reason) { if (*exceptionObject == NULL) { *exceptionObject = PyUnicodeTranslateError_Create( unicode, size, startpos, endpos, reason); } else { if (PyUnicodeTranslateError_SetStart(*exceptionObject, startpos)) goto onError; if (PyUnicodeTranslateError_SetEnd(*exceptionObject, endpos)) goto onError; if (PyUnicodeTranslateError_SetReason(*exceptionObject, reason)) goto onError; return; onError: Py_DECREF(*exceptionObject); *exceptionObject = NULL; } } /* raises a UnicodeTranslateError */ static void raise_translate_exception(PyObject **exceptionObject, const Py_UNICODE *unicode, Py_ssize_t size, Py_ssize_t startpos, Py_ssize_t endpos, const char *reason) { make_translate_exception(exceptionObject, unicode, size, startpos, endpos, reason); if (*exceptionObject != NULL) PyCodec_StrictErrors(*exceptionObject); } /* error handling callback helper: build arguments, call the callback and check the arguments, put the result into newpos and return the replacement string, which has to be freed by the caller */ static PyObject *unicode_translate_call_errorhandler(const char *errors, PyObject **errorHandler, const char *reason, const Py_UNICODE *unicode, Py_ssize_t size, PyObject **exceptionObject, Py_ssize_t startpos, Py_ssize_t endpos, Py_ssize_t *newpos) { static char *argparse = "O!n;translating error handler must return (unicode, int) tuple"; Py_ssize_t i_newpos; PyObject *restuple; PyObject *resunicode; if (*errorHandler == NULL) { *errorHandler = PyCodec_LookupError(errors); if (*errorHandler == NULL) return NULL; } make_translate_exception(exceptionObject, unicode, size, startpos, endpos, reason); if (*exceptionObject == NULL) return NULL; restuple = PyObject_CallFunctionObjArgs( *errorHandler, *exceptionObject, NULL); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { PyErr_Format(PyExc_TypeError, &argparse[4]); Py_DECREF(restuple); return NULL; } if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &resunicode, &i_newpos)) { Py_DECREF(restuple); return NULL; } if (i_newpos<0) *newpos = size+i_newpos; else *newpos = i_newpos; if (*newpos<0 || *newpos>size) { PyErr_Format(PyExc_IndexError, "position %zd from error handler out of bounds", *newpos); Py_DECREF(restuple); return NULL; } Py_INCREF(resunicode); Py_DECREF(restuple); return resunicode; } /* Lookup the character ch in the mapping and put the result in result, which must be decrefed by the caller. Return 0 on success, -1 on error */ static int charmaptranslate_lookup(Py_UNICODE c, PyObject *mapping, PyObject **result) { PyObject *w = PyInt_FromLong((long)c); PyObject *x; if (w == NULL) return -1; x = PyObject_GetItem(mapping, w); Py_DECREF(w); if (x == NULL) { if (PyErr_ExceptionMatches(PyExc_LookupError)) { /* No mapping found means: use 1:1 mapping. */ PyErr_Clear(); *result = NULL; return 0; } else return -1; } else if (x == Py_None) { *result = x; return 0; } else if (PyInt_Check(x)) { long value = PyInt_AS_LONG(x); long max = PyUnicode_GetMax(); if (value < 0 || value > max) { PyErr_Format(PyExc_TypeError, "character mapping must be in range(0x%lx)", max+1); Py_DECREF(x); return -1; } *result = x; return 0; } else if (PyUnicode_Check(x)) { *result = x; return 0; } else { /* wrong return value */ PyErr_SetString(PyExc_TypeError, "character mapping must return integer, None or unicode"); Py_DECREF(x); return -1; } } /* ensure that *outobj is at least requiredsize characters long, if not reallocate and adjust various state variables. Return 0 on success, -1 on error */ static int charmaptranslate_makespace(PyObject **outobj, Py_UNICODE **outp, Py_ssize_t requiredsize) { Py_ssize_t oldsize = PyUnicode_GET_SIZE(*outobj); if (requiredsize > oldsize) { /* remember old output position */ Py_ssize_t outpos = *outp-PyUnicode_AS_UNICODE(*outobj); /* exponentially overallocate to minimize reallocations */ if (requiredsize < 2 * oldsize) requiredsize = 2 * oldsize; if (_PyUnicode_Resize(outobj, requiredsize) < 0) return -1; *outp = PyUnicode_AS_UNICODE(*outobj) + outpos; } return 0; } /* lookup the character, put the result in the output string and adjust various state variables. Return a new reference to the object that was put in the output buffer in *result, or Py_None, if the mapping was undefined (in which case no character was written). The called must decref result. Return 0 on success, -1 on error. */ static int charmaptranslate_output(const Py_UNICODE *startinp, const Py_UNICODE *curinp, Py_ssize_t insize, PyObject *mapping, PyObject **outobj, Py_UNICODE **outp, PyObject **res) { if (charmaptranslate_lookup(*curinp, mapping, res)) return -1; if (*res==NULL) { /* not found => default to 1:1 mapping */ *(*outp)++ = *curinp; } else if (*res==Py_None) ; else if (PyInt_Check(*res)) { /* no overflow check, because we know that the space is enough */ *(*outp)++ = (Py_UNICODE)PyInt_AS_LONG(*res); } else if (PyUnicode_Check(*res)) { Py_ssize_t repsize = PyUnicode_GET_SIZE(*res); if (repsize==1) { /* no overflow check, because we know that the space is enough */ *(*outp)++ = *PyUnicode_AS_UNICODE(*res); } else if (repsize!=0) { /* more than one character */ Py_ssize_t requiredsize = (*outp-PyUnicode_AS_UNICODE(*outobj)) + (insize - (curinp-startinp)) + repsize - 1; if (charmaptranslate_makespace(outobj, outp, requiredsize)) return -1; memcpy(*outp, PyUnicode_AS_UNICODE(*res), sizeof(Py_UNICODE)*repsize); *outp += repsize; } } else return -1; return 0; } PyObject *PyUnicode_TranslateCharmap(const Py_UNICODE *p, Py_ssize_t size, PyObject *mapping, const char *errors) { /* output object */ PyObject *res = NULL; /* pointers to the beginning and end+1 of input */ const Py_UNICODE *startp = p; const Py_UNICODE *endp = p + size; /* pointer into the output */ Py_UNICODE *str; /* current output position */ Py_ssize_t respos = 0; char *reason = "character maps to <undefined>"; PyObject *errorHandler = NULL; PyObject *exc = NULL; /* the following variable is used for caching string comparisons * -1=not initialized, 0=unknown, 1=strict, 2=replace, * 3=ignore, 4=xmlcharrefreplace */ int known_errorHandler = -1; if (mapping == NULL) { PyErr_BadArgument(); return NULL; } /* allocate enough for a simple 1:1 translation without replacements, if we need more, we'll resize */ res = PyUnicode_FromUnicode(NULL, size); if (res == NULL) goto onError; if (size == 0) return res; str = PyUnicode_AS_UNICODE(res); while (p<endp) { /* try to encode it */ PyObject *x = NULL; if (charmaptranslate_output(startp, p, size, mapping, &res, &str, &x)) { Py_XDECREF(x); goto onError; } Py_XDECREF(x); if (x!=Py_None) /* it worked => adjust input pointer */ ++p; else { /* untranslatable character */ PyObject *repunicode = NULL; /* initialize to prevent gcc warning */ Py_ssize_t repsize; Py_ssize_t newpos;