[Checkins] SVN: Sandbox/nadako/z3c.mimetype/ Initial sandbox import.

Dan Korostelev nadako at gmail.com
Wed Feb 18 07:33:04 EST 2009


Log message for revision 96694:
  Initial sandbox import.

Changed:
  _U  Sandbox/nadako/z3c.mimetype/
  A   Sandbox/nadako/z3c.mimetype/CHANGES.txt
  A   Sandbox/nadako/z3c.mimetype/bootstrap.py
  A   Sandbox/nadako/z3c.mimetype/buildout.cfg
  A   Sandbox/nadako/z3c.mimetype/setup.py
  A   Sandbox/nadako/z3c.mimetype/src/
  A   Sandbox/nadako/z3c.mimetype/src/z3c/
  A   Sandbox/nadako/z3c.mimetype/src/z3c/__init__.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/README.txt
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/__init__.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/configure.zcml
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/index.txt
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/interfaces.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/magic.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/mimetype.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/__init__.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.binary
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.doc
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.html
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.pdf
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.png
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.unknown
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/test_doc.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/util.py
  A   Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/utility.py

-=-

Property changes on: Sandbox/nadako/z3c.mimetype
___________________________________________________________________
Added: svn:ignore
   + bin
coverage
docs
parts
.installed.cfg


Added: Sandbox/nadako/z3c.mimetype/CHANGES.txt
===================================================================
--- Sandbox/nadako/z3c.mimetype/CHANGES.txt	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/CHANGES.txt	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,8 @@
+=======
+CHANGES
+=======
+
+0.1.0 (unreleased)
+------------------
+
+- Initial release.

Added: Sandbox/nadako/z3c.mimetype/bootstrap.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/bootstrap.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/bootstrap.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,69 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Bootstrap a buildout-based project
+
+Simply run this script in a directory containing a buildout.cfg.
+The script accepts buildout command-line options, so you can
+use the -c option to specify an alternate configuration file.
+
+$Id: bootstrap.py 90507 2008-08-27 23:46:35Z georgyberdyshev $
+"""
+
+import os, shutil, sys, tempfile, urllib2
+
+tmpeggs = tempfile.mkdtemp()
+
+ez = {}
+exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py'
+                     ).read() in ez
+ez['use_setuptools'](to_dir=tmpeggs, download_delay=0)
+
+import pkg_resources
+
+is_jython = sys.platform.startswith('java')
+
+if is_jython:
+    import subprocess
+
+cmd = 'from setuptools.command.easy_install import main; main()'
+if sys.platform == 'win32':
+    cmd = '"%s"' % cmd # work around spawn lamosity on windows
+
+ws = pkg_resources.working_set
+
+if is_jython:
+    assert subprocess.Popen(
+           [sys.executable] + ['-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout'],
+           env = dict(os.environ,
+                 PYTHONPATH = 
+                 ws.find(pkg_resources.Requirement.parse('setuptools')).location
+                 ),
+           ).wait() == 0
+
+else:
+    assert os.spawnle(
+        os.P_WAIT, sys.executable, sys.executable,
+        '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout',
+        dict(os.environ,
+            PYTHONPATH=
+            ws.find(pkg_resources.Requirement.parse('setuptools')).location
+            ),
+        ) == 0
+
+
+ws.add_entry(tmpeggs)
+ws.require('zc.buildout')
+import zc.buildout.buildout
+zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap'])
+shutil.rmtree(tmpeggs)

Added: Sandbox/nadako/z3c.mimetype/buildout.cfg
===================================================================
--- Sandbox/nadako/z3c.mimetype/buildout.cfg	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/buildout.cfg	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,25 @@
+[buildout]
+develop = .
+parts = test coverage-test coverage-report docs
+
+[test]
+recipe = zc.recipe.testrunner
+eggs = z3c.mimetype [test]
+
+[docs]
+recipe = z3c.recipe.sphinxdoc
+eggs = z3c.mimetype [docs]
+build-dir = ${buildout:directory}/docs
+default.css =
+layout.html =
+
+[coverage-test]
+recipe = zc.recipe.testrunner
+eggs = z3c.mimetype [test]
+defaults = ['--coverage', '../../coverage']
+
+[coverage-report]
+recipe = zc.recipe.egg
+eggs = z3c.coverage
+scripts = coverage=coverage-report
+arguments = ('coverage', 'coverage/report')

Added: Sandbox/nadako/z3c.mimetype/setup.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/setup.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/setup.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,54 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Setup for z3c.mimetype package
+
+$Id$
+"""
+import os
+
+from setuptools import setup, find_packages
+
+def read(*rnames):
+    return open(os.path.join(os.path.dirname(__file__), *rnames)).read()
+
+setup(
+    name='z3c.mimetype',
+    version='0.1.0dev',
+    url='http://pypi.python.org/pypi/z3c.mimetype',
+    license='ZPL 2.1',
+    description='',
+    author='Dan Korostelev and Zope Community',
+    author_email='zope-dev at zope.org',
+    long_description=\
+        read('src', 'z3c', 'mimetype', 'README.txt') + \
+        '\n\n' + \
+        read('CHANGES.txt'),
+    packages=find_packages('src'),
+    package_dir={'': 'src'},
+    namespace_packages=['z3c'],
+    install_requires=[
+      'setuptools',
+      'zope.component [zcml]',
+      'zope.interface',
+      'zope.i18n',
+      'zope.i18nmessageid',
+      'zope.schema',
+      ],
+    extras_require = dict(
+        docs=['Sphinx', 'z3c.recipe.sphinxdoc'],
+        test=['zope.testing'],
+        ),
+    include_package_data=True,
+    zip_safe=False,
+    )


Property changes on: Sandbox/nadako/z3c.mimetype/src
___________________________________________________________________
Added: svn:ignore
   + z3c.mimetype.egg-info


Added: Sandbox/nadako/z3c.mimetype/src/z3c/__init__.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/__init__.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/__init__.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,7 @@
+# this is a namespace package
+try:
+    import pkg_resources
+    pkg_resources.declare_namespace(__name__)
+except ImportError:
+    import pkgutil
+    __path__ = pkgutil.extend_path(__path__, __name__)

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/README.txt
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/README.txt	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/README.txt	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,174 @@
+Mime type guessing
+==================
+
+This package provides an utility for guessing mime type from filename and/or 
+file contents. It's based on freedesktop.org's shared-mime-info database.
+
+The `shared-mime-info <http://freedesktop.org/wiki/Software/shared-mime-info>`_
+is a extensible database of common mime types. It provides powerful mime type
+detection mechanism as well as multi-lingual type descriptions.
+
+This package requires shared-mime-info to be installed and accessible. The
+easiest way to do that is to install it system-wide, for example installing
+the ``shared-mime-info`` package on Ubuntu. The specification_ also describes
+other ways to install and extend the database.
+
+.. _specification: http://standards.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-0.13.html#s2_layout
+
+The core of this package is the global IMIMETypesUtility component.
+
+  >>> from zope.component import getUtility
+  >>> from zope.interface.verify import verifyObject
+  >>> from z3c.mimetype.interfaces import IMIMETypesUtility
+
+  >>> util = getUtility(IMIMETypesUtility)
+  >>> verifyObject(IMIMETypesUtility, util)
+  True
+
+It has three methods for getting mime type. The mime type is the
+IMIMEType object.
+
+  >>> from zope.interface.verify import verifyClass
+  >>> from z3c.mimetype.mimetype import MIMEType
+  >>> from z3c.mimetype.interfaces import IMIMEType
+
+  >>> verifyClass(IMIMEType, MIMEType)
+  True
+
+Those three methods are ``getTypeByFileName``, ``getTypeByContents`` and
+``getType``. We will describe them in that order, but for applications,
+it's reccommended to use the latter, ``getType`` method as it's most
+generic and easy-to use.
+
+The simpliest method is ``getTypeByFileName`` that looks up the type by
+filename.
+
+  >>> mt = util.getTypeByFileName('example.doc')
+
+  >>> mt.media
+  'application'
+
+  >>> mt.subtype
+  'msword'
+
+  >>> str(mt)
+  'application/msword'
+
+MIMEType object also has a title attribute that is a translatable string.
+
+  >>> mt.title
+  u'application/msword'  
+
+  >>> from zope.i18nmessageid.message import Message
+  >>> isinstance(mt.title, Message)
+  True
+
+Shared-Mime-Info is nice, it can even detect mime type for file names like
+``Makefile``.
+
+  >>> print util.getTypeByFileName('Makefile')
+  text/x-makefile
+
+Also, it know the difference in extension letter case. For example the ``.C``
+should be detected as C++ file, when ``.c`` is plain C file.
+
+  >>> print util.getTypeByFileName('hello.C')
+  text/x-c++src
+  
+  >>> print util.getTypeByFileName('main.c')
+  text/x-csrc
+
+The method returns None if it can determine type from file name.
+
+  >>> print util.getTypeByFileName('somefilename')
+  None
+
+Another useful method is ``getTypeByContents``. It's first argument should
+be an opened file. Also, it can take min_priority and max_priority arguments,
+but it's only useful if you know the shared-mime-info specification.
+
+We have some sample files that should be detected by contents
+
+  >>> import os
+  >>> def openSample(extension):
+  ...     return open(os.path.join(SAMPLE_DATA_DIR, 'sample.' + extension))
+
+  >>> fdoc = openSample('doc')
+  >>> print util.getTypeByContents(fdoc)
+  application/msword
+
+  >>> fhtml = openSample('html')
+  >>> print util.getTypeByContents(fhtml)
+  text/html
+  
+  >>> fpdf = openSample('pdf')
+  >>> print util.getTypeByContents(fpdf)
+  application/pdf
+
+  >>> fpng = openSample('png')
+  >>> print util.getTypeByContents(fpng)
+  image/png
+
+If we pass the file without any magic bytes, it will return None
+
+  >>> funknown = openSample('unknown')
+  >>> print util.getTypeByContents(funknown)
+  None
+
+And finally, the most useful method is simply ``getType``. It accepts
+two arguments - the filename and opened file object. At least one of
+them should be specified. This method tries to guess the mime type
+as specified in shared-mime-info specification document and always returns
+some useful mimetype (application/octet-stream or text/plain if cannot 
+detect).
+
+It needs at least one argument, so you can't call it with no arguments.
+
+  >>> util.getType()
+  Traceback (most recent call last):
+  ...
+  TypeError: Either filename or file should be provided or both of them
+
+  >>> print util.getType(filename='wrong.doc')
+  application/msword
+
+  >>> print util.getType(file=fpng)
+  image/png
+
+If type cannot be detected, it WILL return either text/plain or
+application/octet-stream mime type. It will try to guess is it text
+or binary by checking first 32 bytes. 
+
+  >>> print util.getType(filename='somefile', file=funknown)
+  text/plain
+
+  >>> funknownbinary = openSample('binary')
+  >>> print util.getType(filename='somefile2', file=funknownbinary)
+  application/octet-stream
+
+Let's close files, because we won't need them anymore.
+
+  >>> del fdoc, fhtml, fpdf, fpng, funknown, funknownbinary
+
+Finally, let's check the i18n features that comes with shared-mime-info
+and are supported by this package. All mimetype titles are translatable
+messages and can be easily rendered in UI.
+
+Let's get some mime type to play with.
+
+  >>> mt = util.getTypeByFileName('example.png')
+
+By default, mimetype title message id is its media/subtype form.
+
+  >>> mt.title
+  u'image/png'
+
+But if we translate it, we'll get a human-friendly string.
+
+  >>> from zope.i18n import translate
+  
+  >>> translate(mt.title)
+  u'PNG image'
+
+  >>> translate(mt.title, target_language='ru')
+  u'\u0438\u0437\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 PNG'

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/__init__.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/__init__.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/__init__.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,13 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/configure.zcml
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/configure.zcml	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/configure.zcml	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,10 @@
+<configure xmlns="http://namespaces.zope.org/zope">
+
+	<utility component=".utility.globalMIMETypesUtility" />
+
+	<utility
+	  component=".mimetype.mimeTypesTranslationDomain"
+	  name="shared-mime-info"
+	  />
+
+</configure>

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/index.txt
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/index.txt	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/index.txt	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,16 @@
+Welcome to z3c.mimetype's documentation!
+========================================
+
+Contents:
+
+.. toctree::
+   :maxdepth: 2
+
+   README
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/interfaces.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/interfaces.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/interfaces.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,46 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+from zope.interface import Interface
+from zope.schema import ASCIILine, TextLine
+
+class IMIMETypesUtility(Interface):
+    
+    def getTypeByFileName(filename):
+        '''Return type guessed by filename'''
+    
+    def getTypeByContents(file, min_priority=0, max_priority=100):
+        '''Return type guessed by data. Accepts file-like object'''
+        
+    def getType(filename=None, file=None):
+        '''Try to guess content type either by file name or contents or both'''
+
+class IMIMEType(Interface):
+    
+    media = ASCIILine(
+        title=u'Media',
+        required=True,
+        readonly=True)
+
+    subtype = ASCIILine(
+        title=u'Subtype',
+        required=True,
+        readonly=True)
+
+    title = TextLine(
+        title=u'Title',
+        required=True,
+        readonly=True)
+
+    def __str__():
+        '''Return a ``media/subtype`` presentation of mime type'''

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/magic.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/magic.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/magic.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,188 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+from z3c.mimetype.mimetype import lookup
+
+class MagicRule(object):
+
+    def __init__(self, f):
+        self.next = None
+        self.prev = None
+
+        indent = ''
+        while True:
+            c = f.read(1)
+            if c == '>':
+                break
+            indent += c
+        if not indent:
+            self.nest = 0
+        else:
+            self.nest = int(indent)
+
+        start = ''
+        while True:
+            c = f.read(1)
+            if c == '=':
+                break
+            start += c
+        self.start = int(start)
+        
+        hb = f.read(1)
+        lb = f.read(1)
+        self.lenvalue = ord(lb) + (ord(hb) << 8)
+
+        self.value = f.read(self.lenvalue)
+
+        c = f.read(1)
+        if c == '&':
+            self.mask = f.read(self.lenvalue)
+            c = f.read(1)
+        else:
+            self.mask = None
+
+        if c == '~':
+            w = ''
+            while c != '+' and c!='\n':
+                c = f.read(1)
+                if c == '+' or c == '\n':
+                    break
+                w += c
+            self.word = int(w)
+        else:
+            self.word = 1
+
+        if c == '+':
+            r = ''
+            while c != '\n':
+                c = f.read(1)
+                if c == '\n':
+                    break
+                r += c
+            self.range = int(r)
+        else:
+            self.range = 1
+
+        if c != '\n':
+            raise Exception('Malformed MIME magic line')
+
+    def getLength(self):
+        return self.start + self.lenvalue + self.range
+
+    def appendRule(self, rule):
+        if self.nest < rule.nest:
+            self.next = rule
+            rule.prev = self
+        elif self.prev:
+            self.prev.appendRule(rule)
+
+    def match(self, buffer):
+        if self.match0(buffer):
+            if self.next:
+                return self.next.match(buffer)
+            return True
+
+    def match0(self, buffer):
+        l = len(buffer)
+        for o in xrange(self.range):
+            s = self.start + o
+            e = s + self.lenvalue
+            if l < e:
+                return False
+            if self.mask:
+                test = ''
+                for i in xrange(self.lenvalue):
+                    c = ord(buffer[s + i]) & ord(self.mask[i])
+                    test += chr(c)
+            else:
+                test = buffer[s:e]
+
+            if test == self.value:
+                return True
+
+class MagicType(object):
+
+    def __init__(self, mtype):
+        self.mtype = mtype
+        self.top_rules = []
+        self.last_rule = None
+
+    def getLine(self, f):
+        nrule = MagicRule(f)
+        if nrule.nest and self.last_rule:
+            self.last_rule.appendRule(nrule)
+        else:
+            self.top_rules.append(nrule)
+        self.last_rule = nrule
+        return nrule
+
+    def match(self, buffer):
+        for rule in self.top_rules:
+            if rule.match(buffer):
+                return self.mtype
+
+class MagicDB(object):
+
+    def __init__(self):
+        self.types = {}
+        self.maxlen = 0
+
+    def mergeFile(self, fname):
+        f = open(fname, 'r')
+
+        line = f.readline()
+        if line != 'MIME-Magic\0\n':
+            raise Exception('Not a MIME magic file')
+
+        while True:
+            shead = f.readline()
+            if not shead:
+                break
+            if shead[0] != '[' or shead[-2:] != ']\n':
+                raise Exception('Malformed section heading')
+            pri, tname = shead[1:-2].split(':')
+            pri = int(pri)
+            mtype = lookup(tname)
+
+            ents = self.types.setdefault(pri, [])
+            magictype = MagicType(mtype)
+
+            c = f.read(1)
+            f.seek(-1, 1)
+            while c and c!='[':
+                rule = magictype.getLine(f)
+                if rule:
+                    rulelen = rule.getLength()
+                    if rulelen > self.maxlen:
+                        self.maxlen = rulelen
+                c = f.read(1)
+                f.seek(-1, 1)
+
+            ents.append(magictype)
+
+            if not c:
+                break
+
+    def match(self, file, min_priority=0, max_priority=100):
+        file.seek(0, 0)
+        buf = file.read(self.maxlen)
+        for priority, types in sorted(self.types.items(), key=lambda ob:ob[0], reverse=True):
+            if priority > max_priority:
+                continue
+            if priority < min_priority:
+                break
+            for type in types:
+                m = type.match(buf)
+                if m:
+                    return m
+        return None

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/mimetype.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/mimetype.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/mimetype.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,68 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import os
+from xml.dom import minidom, XML_NAMESPACE
+
+from zope.interface import implements
+from zope.i18n.simpletranslationdomain import SimpleTranslationDomain
+from zope.i18nmessageid import MessageFactory
+
+from z3c.mimetype.interfaces import IMIMEType
+from z3c.mimetype.util import iterDataPaths
+
+SMI_NAMESPACE = 'http://www.freedesktop.org/standards/shared-mime-info'
+MIME_TYPES = {}
+
+msgfactory = MessageFactory('shared-mime-info')
+
+mimeTypesTranslationDomain = SimpleTranslationDomain('shared-mime-info')
+
+class MIMEType(object):
+
+    implements(IMIMEType)
+
+    _title = None
+
+    def __init__(self, media, subtype):
+        assert media and '/' not in media
+        assert subtype and '/' not in subtype
+        assert (media, subtype) not in MIME_TYPES
+        self.media = media
+        self.subtype = subtype
+        for path in iterDataPaths(os.path.join('mime', media, subtype + '.xml')):
+            doc = minidom.parse(path)
+            if doc is None:
+                continue
+            for comment in doc.documentElement.getElementsByTagNameNS(SMI_NAMESPACE, 'comment'):
+                data = ''.join([n.nodeValue for n in comment.childNodes]).strip()
+                lang = comment.getAttributeNS(XML_NAMESPACE, 'lang')
+                msgid = '%s/%s' % (media, subtype)
+                if not lang:
+                    self._title = msgfactory(msgid, default=data)
+                else:
+                    mimeTypesTranslationDomain.messages[(lang, msgid)] = data
+
+    @property
+    def title(self):
+        return self._title or unicode(self)
+
+    def __str__(self):
+        return self.media + '/' + self.subtype
+
+def lookup(media, subtype=None):
+    if subtype is None and '/' in media:
+        media, subtype = media.split('/', 1)
+    if (media, subtype) not in MIME_TYPES:
+        MIME_TYPES[(media, subtype)] = MIMEType(media, subtype)
+    return MIME_TYPES[(media, subtype)]

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/__init__.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/__init__.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/__init__.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,13 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.binary
===================================================================
(Binary files differ)


Property changes on: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.binary
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.doc
===================================================================
(Binary files differ)


Property changes on: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.doc
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.html
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.html	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.html	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+	<title>Sample HTML</title>
+</head>
+<body>
+	<h1>Hello, world</h1>
+	<p>Welcome to my page</p>
+</body>
+</html>

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.pdf
===================================================================
(Binary files differ)


Property changes on: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.pdf
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.png
===================================================================
(Binary files differ)


Property changes on: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.png
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.unknown
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.unknown	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/sample_data/sample.unknown	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1 @@
+No magic bytes here, so its mime type can not be detected by contents.

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/test_doc.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/test_doc.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/tests/test_doc.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,34 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import os
+import unittest
+
+from zope.testing import doctest
+from zope.component import provideUtility
+
+from z3c.mimetype.utility import globalMIMETypesUtility
+from z3c.mimetype.mimetype import mimeTypesTranslationDomain
+
+def setUp(test):
+    provideUtility(globalMIMETypesUtility)
+    provideUtility(mimeTypesTranslationDomain, name='shared-mime-info')
+    test.globs['SAMPLE_DATA_DIR'] = os.path.join(os.path.dirname(__file__), 'sample_data')
+
+def test_suite():
+    return unittest.TestSuite(
+        doctest.DocFileSuite(
+            '../README.txt',
+            setUp=setUp,
+            optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS)
+    )

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/util.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/util.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/util.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,24 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import os
+
+XDG_DATA_HOME = os.environ.get('XDG_DATA_HOME', os.path.join(os.environ.get('HOME', '/'), '.local', 'share'))
+XDG_DATA_DIRS = [XDG_DATA_HOME] + [dir for dir in os.environ.get('XDG_DATA_DIRS', '/usr/local/share:/usr/share').split(':') if dir]
+
+def iterDataPaths(*resource):
+    resource = os.path.join(*resource)
+    for data_dir in XDG_DATA_DIRS:
+        path = os.path.join(data_dir, resource)
+        if os.path.exists(path):
+            yield path

Added: Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/utility.py
===================================================================
--- Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/utility.py	                        (rev 0)
+++ Sandbox/nadako/z3c.mimetype/src/z3c/mimetype/utility.py	2009-02-18 12:33:03 UTC (rev 96694)
@@ -0,0 +1,130 @@
+##############################################################################
+#
+# Copyright (c) 2009 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+import re
+import os
+import fnmatch
+
+from zope.interface import implements
+
+from z3c.mimetype.magic import MagicDB
+from z3c.mimetype.mimetype import lookup
+from z3c.mimetype.util import iterDataPaths
+from z3c.mimetype.interfaces import IMIMETypesUtility
+
+findBinary = re.compile('[\0-\7]').search
+
+class MIMETypesUtility(object):
+	
+	implements(IMIMETypesUtility)
+
+	_extensions = None
+	_literals = None
+	_globs = None
+	_magicDB = None
+
+	def __init__(self):
+		self._extensions = {}
+		self._literals = {}
+		self._globs = []
+		self._magicDB = MagicDB()
+
+		for path in iterDataPaths(os.path.join('mime', 'globs')):
+			self._importGlobFile(path)
+		self._globs.sort(key=lambda ob:len(ob[0]), reverse=True)
+		
+		for path in iterDataPaths(os.path.join('mime', 'magic')):
+			self._magicDB.mergeFile(path)
+
+	def _importGlobFile(self, path):
+		for line in open(path, 'r'):
+			if line.startswith('#'):
+				continue
+			line = line[:-1]
+	
+			type_name, pattern = line.split(':', 1)
+			mtype = lookup(type_name)
+	
+			if pattern.startswith('*.'):
+				rest = pattern[2:]
+				if not ('*' in rest or '[' in rest or '?' in rest):
+					self._extensions[rest] = mtype
+					continue
+	
+			if '*' in pattern or '[' in pattern or '?' in pattern:
+				self._globs.append((pattern, mtype))
+			else:
+				self._literals[pattern] = mtype
+
+	def getTypeByFileName(self, filename):
+		if filename in self._literals:
+			return self._literals[filename]
+	
+		lfilename = filename.lower()
+		if lfilename in self._literals:
+			return self._literals[lfilename]
+	
+		ext = filename
+		while True:
+			p = ext.find('.')
+			if p < 0:
+				break
+			ext = ext[p + 1:]
+			if ext in self._extensions:
+				return self._extensions[ext]
+	
+		ext = lfilename
+		while True:
+			p = ext.find('.')
+			if p < 0:
+				break
+			ext = ext[p + 1:]
+			if ext in self._extensions:
+				return self._extensions[ext]
+	
+		for (glob, mime_type) in self._globs:
+			if fnmatch.fnmatch(filename, glob):
+				return mime_type
+			if fnmatch.fnmatch(lfilename, glob):
+				return mime_type
+	
+		return None
+
+	def getTypeByContents(self, file, min_priority=0, max_priority=100):
+		return self._magicDB.match(file, min_priority, max_priority)
+
+	def getType(self, filename=None, file=None):
+		if (filename is None) and (file is None):
+			raise TypeError('Either filename or file should be provided or both of them')
+		
+		type = None
+		
+		if file:
+			type = self.getTypeByContents(file, min_priority=80)
+
+		if not type and filename:
+			type = self.getTypeByFileName(filename)
+
+		if not type and file:
+			type = self.getTypeByContents(file, max_priority=80)
+		
+		if not type:
+			type = lookup('application', 'octet-stream')
+			if file:
+				file.seek(0, 0)
+				if not findBinary(file.read(32)):
+					type = lookup('text', 'plain')
+
+		return type
+
+globalMIMETypesUtility = MIMETypesUtility()



More information about the Checkins mailing list