from StringIO import StringIO # This code is taken from CMFPlone.patches.unicodehacks def _unicode_replace(structure): if isinstance(structure, str): try: text = structure.decode('utf-8') except UnicodeDecodeError: # XXX the next line is fool-proof and will substitute ??-s if the encoding was not # unicode text = structure.decode('utf-8', 'replace') else: text = unicode(structure) return text def _nulljoin(valuelist): try: return u''.join(valuelist) except UnicodeDecodeError: pass return u''.join([_unicode_replace(value) for value in valuelist]) def new__call__(self, econtext): try: return self._expr % tuple([var(econtext) for var in self._vars]) except UnicodeDecodeError: pass return self._expr % tuple([_unicode_replace(var(econtext)) for var in self._vars]) class FasterStringIO(StringIO): """Append-only version of StringIO, which ignores any initial buffer. This let's us have much faster write() and getvalue methods. Most of this code was taken from zope.tal.talinterpreter.py licenced under the ZPL 2.1. """ def __init__(self, buf=None): self.buf = '' self.len = 0 self.buflist = [] self.bufappend = self.buflist.append self.pos = 0 self.closed = False self.softspace = 0 def close(self): if not self.closed: self.write = _write_ValueError StringIO.close(self) def seek(self, pos, mode=0): raise RuntimeError("FasterStringIO.seek() not allowed") def write(self, s): self.bufappend(s) self.len = self.pos = self.pos + len(s) def getvalue(self): if self.buflist: try: self.buf = u''.join(self.buflist) except UnicodeDecodeError: self.buf = u''.join([_unicode_replace(value) for value in self.buflist]) self.buflist = [] return self.buf # import the poor victims of our monkey patches from zope.tal import talinterpreter from zope.tales import expressions from zope.pagetemplate import pagetemplate from Products.Five import i18n talinterpreter.unicode = _unicode_replace i18n.unicode = _unicode_replace talinterpreter._nulljoin_old = talinterpreter._nulljoin talinterpreter._nulljoin = _nulljoin talinterpreter.TALInterpreter.StringIO = FasterStringIO pagetemplate.StringIO = FasterStringIO expressions.StringExpr._old_call = expressions.StringExpr.__call__ expressions.StringExpr.__call__ = new__call__ from zope.interface import implements from Products.PageTemplates.interfaces import IUnicodeEncodingConflictResolver class UTF8EncodingConflictResolver(object): """This resolver tries to decode a string from utf-8 and replaces it otherwise but logs a warning. """ implements(IUnicodeEncodingConflictResolver) def resolve(self, context, text, expression): return _unicode_replace(text) UTF8EncodingConflictResolver = UTF8EncodingConflictResolver()