242 lines
8.6 KiB
Python
Executable File
242 lines
8.6 KiB
Python
Executable File
#!/home/shrekrequiem/Projets/AF2C/CCR/.venv/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
|
#
|
|
# This is free software. You may redistribute it under the terms
|
|
# of the Apache license and the GNU General Public License Version
|
|
# 2 or at your option any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public
|
|
# License along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
#
|
|
# Contributor(s):
|
|
#
|
|
#
|
|
|
|
# OpenDocument can be a complete office document in a single
|
|
# XML document. This script will take such a document and create
|
|
# a package
|
|
import io
|
|
import zipfile,time, sys, getopt
|
|
import xml.sax, xml.sax.saxutils
|
|
from odf import manifest
|
|
|
|
class SplitWriter:
|
|
def __init__(self):
|
|
self.activefiles = []
|
|
self._content = []
|
|
self._meta = []
|
|
self._styles = []
|
|
self._settings = []
|
|
|
|
self.files = {'content': self._content, 'meta': self._meta,
|
|
'styles':self._styles, 'settings': self._settings }
|
|
|
|
def write(self, str):
|
|
for f in self.activefiles:
|
|
f.append(str)
|
|
|
|
def activate(self, filename):
|
|
file = self.files[filename]
|
|
if file not in self.activefiles:
|
|
self.activefiles.append(file)
|
|
|
|
def deactivate(self, filename):
|
|
file = self.files[filename]
|
|
if file in self.activefiles:
|
|
self.activefiles.remove(file)
|
|
|
|
odmimetypes = {
|
|
'application/vnd.oasis.opendocument.text': '.odt',
|
|
'application/vnd.oasis.opendocument.text-template': '.ott',
|
|
'application/vnd.oasis.opendocument.graphics': '.odg',
|
|
'application/vnd.oasis.opendocument.graphics-template': '.otg',
|
|
'application/vnd.oasis.opendocument.presentation': '.odp',
|
|
'application/vnd.oasis.opendocument.presentation-template': '.otp',
|
|
'application/vnd.oasis.opendocument.spreadsheet': '.ods',
|
|
'application/vnd.oasis.opendocument.spreadsheet-template': '.ots',
|
|
'application/vnd.oasis.opendocument.chart': '.odc',
|
|
'application/vnd.oasis.opendocument.chart-template': '.otc',
|
|
'application/vnd.oasis.opendocument.image': '.odi',
|
|
'application/vnd.oasis.opendocument.image-template': '.oti',
|
|
'application/vnd.oasis.opendocument.formula': '.odf',
|
|
'application/vnd.oasis.opendocument.formula-template': '.otf',
|
|
'application/vnd.oasis.opendocument.text-master': '.odm',
|
|
'application/vnd.oasis.opendocument.text-web': '.oth',
|
|
}
|
|
|
|
OFFICENS = u"urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
|
base = xml.sax.saxutils.XMLGenerator
|
|
|
|
class odfsplitter(base):
|
|
|
|
def __init__(self):
|
|
self._mimetype = ''
|
|
self.output = SplitWriter()
|
|
self._prefixes = []
|
|
base.__init__(self, self.output, 'utf-8')
|
|
|
|
def startPrefixMapping(self, prefix, uri):
|
|
base.startPrefixMapping(self, prefix, uri)
|
|
self._prefixes.append('xmlns:%s="%s"' % (prefix, uri))
|
|
|
|
def startElementNS(self, name, qname, attrs):
|
|
if name == (OFFICENS, u"document"):
|
|
self._mimetype = attrs.get((OFFICENS, "mimetype"))
|
|
elif name == (OFFICENS, u"meta"):
|
|
self.output.activate('meta')
|
|
|
|
elif name == (OFFICENS, u"settings"):
|
|
self.output.activate('settings')
|
|
elif name == (OFFICENS, u"scripts"):
|
|
self.output.activate('content')
|
|
elif name == (OFFICENS, u"font-face-decls"):
|
|
self.output.activate('content')
|
|
self.output.activate('styles')
|
|
elif name == (OFFICENS, u"styles"):
|
|
self.output.activate('styles')
|
|
elif name == (OFFICENS, u"automatic-styles"):
|
|
self.output.activate('content')
|
|
self.output.activate('styles')
|
|
elif name == (OFFICENS, u"master-styles"):
|
|
self.output.activate('styles')
|
|
elif name == (OFFICENS, u"body"):
|
|
self.output.activate('content')
|
|
base.startElementNS(self, name, qname, attrs)
|
|
|
|
def endElementNS(self, name, qname):
|
|
base.endElementNS(self, name, qname)
|
|
if name == (OFFICENS, u"meta"):
|
|
self.output.deactivate('meta')
|
|
elif name == (OFFICENS, u"settings"):
|
|
self.output.deactivate('settings')
|
|
elif name == (OFFICENS, u"scripts"):
|
|
self.output.deactivate('content')
|
|
elif name == (OFFICENS, u"font-face-decls"):
|
|
self.output.deactivate('content')
|
|
self.output.deactivate('styles')
|
|
elif name == (OFFICENS, u"styles"):
|
|
self.output.deactivate('styles')
|
|
elif name == (OFFICENS, u"automatic-styles"):
|
|
self.output.deactivate('content')
|
|
self.output.deactivate('styles')
|
|
elif name == (OFFICENS, u"master-styles"):
|
|
self.output.deactivate('styles')
|
|
elif name == (OFFICENS, u"body"):
|
|
self.output.deactivate('content')
|
|
|
|
|
|
def content(self):
|
|
""" Return the content inside a wrapper called <office:document-content>
|
|
"""
|
|
prefixes = ' '.join(self._prefixes)
|
|
return ''.join(['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-content %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._content)) + ['</office:document-content>'])
|
|
|
|
def settings(self):
|
|
prefixes = ' '.join(self._prefixes).encode('utf-8')
|
|
return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-settings %s office:version="1.0">' % prefixes] + self.output._settings + ['''</office:document-settings>'''])
|
|
|
|
def styles(self):
|
|
prefixes = ' '.join(self._prefixes)
|
|
return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-styles %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._styles)) + ['''</office:document-styles>'''])
|
|
|
|
def meta(self):
|
|
prefixes = ' '.join(self._prefixes)
|
|
return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-meta %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._meta)) + ['''</office:document-meta>'''])
|
|
|
|
def usage():
|
|
sys.stderr.write("Usage: %s [-o outputfile] [-s] inputfile\n" % sys.argv[0])
|
|
|
|
def manifestxml(m):
|
|
""" Generates the content of the manifest.xml file """
|
|
xml=io.StringIO()
|
|
xml.write(u"<?xml version='1.0' encoding='UTF-8'?>\n")
|
|
m.toXml(0,xml)
|
|
return xml.getvalue()
|
|
|
|
try:
|
|
opts, args = getopt.getopt(sys.argv[1:], "o:s", ["output=","suffix"])
|
|
except getopt.GetoptError:
|
|
usage()
|
|
sys.exit(2)
|
|
|
|
outputfile = '-'
|
|
addsuffix = False
|
|
|
|
for o, a in opts:
|
|
if o in ("-o", "--output"):
|
|
outputfile = a
|
|
if o in ("-s", "--suffix"):
|
|
addsuffix = True
|
|
|
|
if len(args) > 1:
|
|
usage()
|
|
sys.exit(2)
|
|
|
|
odfs = odfsplitter()
|
|
parser = xml.sax.make_parser()
|
|
parser.setFeature(xml.sax.handler.feature_namespaces, 1)
|
|
parser.setContentHandler(odfs)
|
|
if len(args) == 0:
|
|
parser.parse(sys.stdin)
|
|
else:
|
|
parser.parse(open(args[0],"r"))
|
|
|
|
mimetype = odfs._mimetype
|
|
suffix = odmimetypes.get(mimetype,'.xxx')
|
|
|
|
if outputfile == '-':
|
|
if sys.stdout.isatty():
|
|
sys.stderr.write("Won't write ODF file to terminal\n")
|
|
sys.exit(1)
|
|
z = zipfile.ZipFile(sys.stdout,"w")
|
|
else:
|
|
if addsuffix:
|
|
outputfile = outputfile + suffix
|
|
z = zipfile.ZipFile(outputfile,"w")
|
|
|
|
now = time.localtime()[:6]
|
|
|
|
# Write mimetype
|
|
zi = zipfile.ZipInfo('mimetype', now)
|
|
zi.compress_type = zipfile.ZIP_STORED
|
|
z.writestr(zi,mimetype)
|
|
|
|
# Write content
|
|
zi = zipfile.ZipInfo("content.xml", now)
|
|
zi.compress_type = zipfile.ZIP_DEFLATED
|
|
z.writestr(zi,odfs.content() )
|
|
# Write styles
|
|
zi = zipfile.ZipInfo("styles.xml", now)
|
|
zi.compress_type = zipfile.ZIP_DEFLATED
|
|
z.writestr(zi,odfs.styles() )
|
|
|
|
# Write meta
|
|
zi = zipfile.ZipInfo("meta.xml", now)
|
|
zi.compress_type = zipfile.ZIP_DEFLATED
|
|
z.writestr(zi,odfs.meta() )
|
|
|
|
m = manifest.Manifest()
|
|
m.addElement(manifest.FileEntry(fullpath="/", mediatype=mimetype))
|
|
m.addElement(manifest.FileEntry(fullpath="content.xml",mediatype="text/xml"))
|
|
m.addElement(manifest.FileEntry(fullpath="styles.xml", mediatype="text/xml"))
|
|
m.addElement(manifest.FileEntry(fullpath="meta.xml", mediatype="text/xml"))
|
|
|
|
# Write manifest
|
|
zi = zipfile.ZipInfo("META-INF/manifest.xml", now)
|
|
zi.compress_type = zipfile.ZIP_DEFLATED
|
|
z.writestr(zi, manifestxml(m).encode("utf-8") )
|
|
z.close()
|
|
|
|
|
|
|
|
# Local Variables: ***
|
|
# mode: python ***
|
|
# End: ***
|