diff --git a/product/ERP5OOo/OOoTemplate.py b/product/ERP5OOo/OOoTemplate.py
index ce1b9378202003fe42b07d1bffb4434d45b5812f..17c9c9a0c677a7648ba313ca53385f0dbd9d92e3 100755
--- a/product/ERP5OOo/OOoTemplate.py
+++ b/product/ERP5OOo/OOoTemplate.py
@@ -27,6 +27,7 @@
 ##############################################################################
 
 from Products.CMFCore.utils import getToolByName
+from types import StringType
 from Products.CMFCore.FSPageTemplate import FSPageTemplate
 from Products.CMFCore.DirectoryView import registerFileExtension, registerMetaType
 from Products.Formulator.Form import BasicForm
@@ -86,16 +87,6 @@ class OOoTemplate(ZopePageTemplate):
         A page template which is able to embed and OpenOffice
         file (zip archive) and replace content.xml at render time
         with XML dynamically generated through TAL/TALES/METAL expressions
-
-        WARNING:
-          - In order to render in UTF-8, Template must contain the expression:
-            tal:define="dummy python:
-       request.RESPONSE.setHeader('Content-Type','text/xml;; charset=utf-8')"
-
-        TODO:
-          - upload of OOo documents must be able to extract content.xml
-            from the archive, remove DTD definition and include
-            CR/LF to produce a nice looking XML source.
     """
     meta_type = "ERP5 OOo Template"
     icon = "www/OOo.png"
@@ -126,8 +117,26 @@ class OOoTemplate(ZopePageTemplate):
       )
 
     security.declareProtected('View management screens', 'formSettings')
-    formSettings = PageTemplateFile('www/formSettings', globals(), __name__='formSettings')
+    formSettings = PageTemplateFile('www/formSettings', globals(),
+                                     __name__='formSettings')
     formSettings._owner = None
+    
+    def pt_upload(self, REQUEST, file=''):
+      """Replace the document with the text in file."""
+      if SUPPORTS_WEBDAV_LOCKS and self.wl_isLocked():
+          raise ResourceLockedError, "File is locked via WebDAV"
+
+      if type(file) is not StringType:
+          if not file: raise ValueError, 'File not specified'
+          file = file.read()
+           
+      if file.startswith("PK") : # FIXME: this condition is probably not enough
+        # this is a OOo zip file, extract the content
+        builder = OOoBuilder(file)
+        self.content_type = builder.getMimeType()
+        file = builder.prepareContentXml()
+        
+      return ZopePageTemplate.pt_upload(self, REQUEST, file)
 
     security.declareProtected('Change Page Templates', 'doSettings')
     def doSettings(self, REQUEST, title, ooo_stylesheet):
@@ -178,7 +187,8 @@ class OOoTemplate(ZopePageTemplate):
       if request and not batch_mode:
         request.RESPONSE.setHeader('Content-Type','%s;; charset=utf-8' % self.content_type)
         request.RESPONSE.setHeader('Content-Length',len(ooo))
-        request.RESPONSE.setHeader('Content-Disposition','inline;filename=%s' % self.id)
+        request.RESPONSE.setHeader('Content-Disposition','inline;filename=%s' %
+                                     self.title_or_id())
 
       return ooo
 
diff --git a/product/ERP5OOo/OOoUtils.py b/product/ERP5OOo/OOoUtils.py
index b6c15b1bd08b0b356b88ab61f815fa291b5a03f9..b6c4484f7c7b190667cfe43e215e29a9f397342d 100755
--- a/product/ERP5OOo/OOoUtils.py
+++ b/product/ERP5OOo/OOoUtils.py
@@ -65,7 +65,12 @@ class OOoBuilder:
 
   security.declarePrivate('__init__')
   def __init__(self, document):
-    self._document = StringIO(document.data)
+    if hasattr(document, 'data') :
+      self._document = StringIO(document.data)
+    elif hasattr(document, 'read') :
+      self._document = document
+    else :
+      self._document = StringIO(document)
     self._image_count = 0    
 
   security.declarePublic('replace')
@@ -80,7 +85,46 @@ class OOoBuilder:
       zf = ZipFile(self._document, mode='a')
     zf.writestr(filename, stream)
     zf.close()
-
+  
+  security.declarePublic('extract')
+  def extract(self, filename):
+    """
+    Extracts a file from the archive
+    """
+    try:
+      zf = ZipFile(self._document, mode='r', compression=ZIP_DEFLATED)
+    except RuntimeError:
+      zf = ZipFile(self._document, mode='r')
+    return zf.read(filename)
+  
+  security.declarePublic('getMimeType')
+  def getMimeType(self):
+    return self.extract('mimetype')
+
+  security.declarePublic('prepareContentXml')
+  def prepareContentXml(self) :
+    """
+      extracts content.xml text and prepare it :
+        - add tal namespace
+        - indent the xml
+    """
+    import pprint
+    content_xml = self.extract('content.xml')
+    reader = PyExpat.Reader()
+    document = reader.fromString(content_xml)
+    document_element = document.documentElement
+    from xml.dom.ext import PrettyPrint
+    output = StringIO()
+    PrettyPrint(document_element, output)
+    return output.getvalue().replace(
+      "office:version='1.0'",
+      """ xmlns:tal='http://xml.zope.org/namespaces/tal'
+          xmlns:i18n='http://xml.zope.org/namespaces/i18n'
+          xmlns:metal='http://xml.zope.org/namespaces/metal'
+          tal:attributes='dummy python:request.RESPONSE.setHeader("Content-Type", "text/html;; charset=utf-8")'
+         office:version='1.0'""")
+
+  security.declarePublic('addImage')
   def addImage(self, image, format='png'):
     """
     Add an image to the current document and return its id