[Libreoffice-commits] online.git: discovery.xml wsd/lint-discovery.py wsd/LOOLWSD.cpp

Mike Kaganski (via logerrit) logerrit at kemper.freedesktop.org
Thu Aug 27 09:29:32 UTC 2020


 discovery.xml         |  315 +++++++++++++++++++++++++++++++++++---------------
 wsd/LOOLWSD.cpp       |  158 +++++++++++++++++++++----
 wsd/lint-discovery.py |  277 ++++++++++++++++++++++++++-----------------
 3 files changed, 528 insertions(+), 222 deletions(-)

New commits:
commit 05dba7ad86e4bc5ddde3fcfb3faca2c4458c676b
Author:     Mike Kaganski <mike.kaganski at collabora.com>
AuthorDate: Tue Jul 28 17:52:14 2020 +0300
Commit:     Mike Kaganski <mike.kaganski at collabora.com>
CommitDate: Thu Aug 27 11:29:12 2020 +0200

    Restructure discovery to have less apps
    
    The apps are not meant to represent MIME types of respective
    single file extensions; rather, they represent application/module
    that handles several extensions. So this groups extensions under
    modules (writer/calc/...). This is required for some WOPI hosts
    that whitelist discovery data on per-app base.
    
    The old list of MIME-type-based apps is kept for compatibility
    with existing integrations, until they are fixed to use new-style
    discovery. Extensions are removed from legacy part, to avoid
    duplicating actions.
    
    This also hardcodes content types, to avoid repeated parsing of
    discovery.xml.
    
    lint-discovery.py is updated to process new-style information
    (ignores legacy part).
    
    Change-Id: Ib8d3518f00510cd0788314d8a9da9a286a52e0ba
    Reviewed-on: https://gerrit.libreoffice.org/c/online/+/99637
    Tested-by: Jenkins
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice at gmail.com>
    Reviewed-by: Mike Kaganski <mike.kaganski at collabora.com>

diff --git a/discovery.xml b/discovery.xml
index b0ea602d4..22b284621 100644
--- a/discovery.xml
+++ b/discovery.xml
@@ -1,314 +1,451 @@
 <?xml version="1.0" encoding="utf-8"?>
 <wopi-discovery>
     <net-zone name="external-http">
-        <app name="image/svg+xml">
+
+        <!-- Writer documents -->
+        <app name="writer">
+            <action name="view" default="true" ext="sxw"/>
+            <action name="edit" default="true" ext="odt"/>
+            <action name="edit" default="true" ext="fodt"/>
+            <!-- Text template documents -->
+            <action name="view" default="true" ext="stw"/>
+            <action name="edit" default="true" ext="ott"/>
+            <!-- MS Word -->
+            <action name="edit" default="true" ext="doc"/>
+            <action name="edit" default="true" ext="dot"/>
+            <!-- OOXML wordprocessing -->
+            <action name="edit" default="true" ext="docx"/>
+            <action name="edit" default="true" ext="docm"/>
+            <action name="view" default="true" ext="dotx"/>
+            <action name="view" default="true" ext="dotm"/>
+            <!-- Others -->
+            <action name="view" default="true" ext="wpd"/>
+            <action name="view" default="true" ext="pdb"/>
+            <action name="view" default="true" ext="hwp"/>
+            <action name="view" default="true" ext="wps"/>
+            <action name="view" default="true" ext="wri"/>
+            <action name="view" default="true" ext="lrf"/>
+            <action name="view" default="true" ext="mw"/>
+            <action name="edit" default="true" ext="rtf"/>
+            <action name="edit" default="true" ext="txt"/>
+            <action name="view" default="true" ext="fb2"/>
+            <action name="view" default="true" ext="cwk"/>
+            <action name="view" default="true" ext="pages"/>
+            <action name="view" default="true" ext="abw"/>
+            <action name="view" default="true" ext="602"/>
+        </app>
+
+        <app name="writer-global">
+            <!-- Text master documents -->
+            <action name="view" default="true" ext="sxg"/>
+            <action name="edit" default="true" ext="odm"/>
+            <!-- Writer master document templates -->
+            <action name="edit" default="true" ext="otm"/>
+        </app>
+
+        <app name="writer-web">
+            <action name="edit" default="true" ext="oth"/>
+        </app>
+
+        <!-- Calc documents -->
+        <app name="calc">
+            <action name="view" default="true" ext="sxc"/>
+            <action name="edit" default="true" ext="ods"/>
+            <action name="edit" default="true" ext="fods"/>
+            <!-- Spreadsheet template documents -->
+            <action name="view" default="true" ext="stc"/>
+            <action name="edit" default="true" ext="ots"/>
+            <!-- MS Excel -->
+            <action name="edit" default="true" ext="xls"/>
+            <action name="edit" default="true" ext="xla"/>
+            <!-- OOXML spreadsheet -->
+            <action name="view" default="true" ext="xltx"/>
+            <action name="view" default="true" ext="xltm"/>
+            <action name="edit" default="true" ext="xlsx"/>
+            <action name="edit" default="true" ext="xlsb"/>
+            <action name="edit" default="true" ext="xlsm"/>
+            <!-- Others -->
+            <action name="edit" default="true" ext="dif"/>
+            <action name="edit" default="true" ext="slk"/>
+            <action name="edit" default="true" ext="csv"/>
+            <action name="edit" default="true" ext="dbf"/>
+            <action name="view" default="true" ext="wk1"/>
+            <action name="view" default="true" ext="gnumeric"/>
+            <action name="view" default="true" ext="numbers"/>
+        </app>
+
+        <!-- Impress documents -->
+        <app name="impress">
+            <action name="view" default="true" ext="sxi"/>
+            <action name="edit" default="true" ext="odp"/>
+            <action name="edit" default="true" ext="fodp"/>
+            <!-- Presentation template documents -->
+            <action name="view" default="true" ext="sti"/>
+            <action name="edit" default="true" ext="otp"/>
+            <!-- MS PowerPoint -->
+            <action name="edit" default="true" ext="ppt"/>
+            <action name="edit" default="true" ext="pot"/>
+            <!-- OOXML presentation -->
+            <action name="edit" default="true" ext="pptx"/>
+            <action name="edit" default="true" ext="pptm"/>
+            <action name="edit" default="true" ext="potx"/>
+            <action name="edit" default="true" ext="potm"/>
+            <action name="edit" default="true" ext="ppsx"/>
+            <!-- Others -->
+            <action name="view" default="true" ext="cgm"/>
+            <action name="view" default="true" ext="key"/>
+        </app>
+
+        <!-- Draw documents -->
+        <app name="draw">
+            <action name="view" default="true" ext="sxd"/>
+            <action name="view" default="true" ext="odg"/>
+            <action name="view" default="true" ext="fodg"/>
+            <!-- Drawing template documents -->
+            <action name="view" default="true" ext="std"/>
+            <action name="edit" default="true" ext="otg"/>
+            <!-- Others -->
             <action name="view" ext="svg"/>
+            <action name="view" default="true" ext="dxf"/>
+            <action name="view" default="true" ext="emf"/>
+            <action name="view" default="true" ext="wmf"/>
+            <action name="view" default="true" ext="cdr"/>
+            <action name="view" default="true" ext="vsd"/>
+            <action name="view" default="true" ext="vss"/>
+            <action name="view" default="true" ext="pub"/>
+            <action name="view" default="true" ext="p65"/>
+            <action name="view" default="true" ext="wpg"/>
+            <action name="view" default="true" ext="fh"/>
+            <action name="view" ext="bmp"/>
+            <action name="view" ext="png"/>
+            <action name="view" ext="gif"/>
+            <action name="view" ext="tiff"/>
+            <action name="view" ext="jpg"/>
+            <action name="view" ext="jpeg"/>
+            <action name="view_comment" ext="pdf"/>
+        </app>
+
+        <!-- Math documents -->
+        <!-- In fact Math documents are not supported at all.
+             See: https://bugs.documentfoundation.org/show_bug.cgi?id=97006
+        <app name="math">
+            <action name="view" default="true" ext="sxm"/>
+            <action name="edit" default="true" ext="odf"/>
+        </app>
+        -->
+
+        <!-- Legacy MIME-type actions (compatibility) -->
+
+        <app name="image/svg+xml">
+            <action name="view" ext=""/>
         </app>
         <app name="application/vnd.ms-powerpoint">
-            <action name="edit" default="true" ext="pot"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-excel">
-            <action name="edit" default="true" ext="xla"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Writer documents -->
         <app name="application/vnd.sun.xml.writer">
-            <action name="view" default="true" ext="sxw"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.text">
-            <action name="edit" default="true" ext="odt"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.text-flat-xml">
-            <action name="edit" default="true" ext="fodt"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Calc documents -->
         <app name="application/vnd.sun.xml.calc">
-            <action name="view" default="true" ext="sxc"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.spreadsheet">
-            <action name="edit" default="true" ext="ods"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.spreadsheet-flat-xml">
-            <action name="edit" default="true" ext="fods"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Impress documents -->
         <app name="application/vnd.sun.xml.impress">
-            <action name="view" default="true" ext="sxi"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.presentation">
-            <action name="edit" default="true" ext="odp"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.presentation-flat-xml">
-            <action name="edit" default="true" ext="fodp"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Draw documents -->
         <app name="application/vnd.sun.xml.draw">
-            <action name="view" default="true" ext="sxd"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.graphics">
-            <action name="view" default="true" ext="odg"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.graphics-flat-xml">
-            <action name="view" default="true" ext="fodg"/>
+            <action name="view" default="true" ext=""/>
         </app>
 
         <!-- Chart documents -->
         <app name="application/vnd.oasis.opendocument.chart">
-            <action name="edit" default="true" ext="odc"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Text master documents -->
         <app name="application/vnd.sun.xml.writer.global">
-            <action name="view" default="true" ext="sxg"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.text-master">
-            <action name="edit" default="true" ext="odm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Math documents -->
         <!-- In fact Math documents are not supported at all.
              See: https://bugs.documentfoundation.org/show_bug.cgi?id=97006
         <app name="application/vnd.sun.xml.math">
-            <action name="view" default="true" ext="sxm"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.formula">
-            <action name="edit" default="true" ext="odf"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         -->
         <!-- Text template documents -->
         <app name="application/vnd.sun.xml.writer.template">
-            <action name="view" default="true" ext="stw"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.text-template">
-            <action name="edit" default="true" ext="ott"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Writer master document templates -->
         <app name="application/vnd.oasis.opendocument.text-master-template">
-            <action name="edit" default="true" ext="otm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Spreadsheet template documents -->
         <app name="application/vnd.sun.xml.calc.template">
-            <action name="view" default="true" ext="stc"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.spreadsheet-template">
-            <action name="edit" default="true" ext="ots"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Presentation template documents -->
         <app name="application/vnd.sun.xml.impress.template">
-            <action name="view" default="true" ext="sti"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.presentation-template">
-            <action name="edit" default="true" ext="otp"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Drawing template documents -->
         <app name="application/vnd.sun.xml.draw.template">
-            <action name="view" default="true" ext="std"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.graphics-template">
-            <action name="edit" default="true" ext="otg"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- MS Word -->
         <app name="application/msword">
-            <action name="edit" default="true" ext="doc"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/msword">
-            <action name="edit" default="true" ext="dot"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- MS Excel -->
         <app name="application/vnd.ms-excel">
-            <action name="edit" default="true" ext="xls"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- MS PowerPoint -->
         <app name="application/vnd.ms-powerpoint">
-            <action name="edit" default="true" ext="ppt"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- OOXML wordprocessing -->
         <app name="application/vnd.openxmlformats-officedocument.wordprocessingml.document">
-            <action name="edit" default="true" ext="docx"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-word.document.macroEnabled.12">
-            <action name="edit" default="true" ext="docm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.openxmlformats-officedocument.wordprocessingml.template">
-            <action name="view" default="true" ext="dotx"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-word.template.macroEnabled.12">
-            <action name="view" default="true" ext="dotm"/>
+            <action name="view" default="true" ext=""/>
         </app>
 
         <!-- OOXML spreadsheet -->
         <app name="application/vnd.openxmlformats-officedocument.spreadsheetml.template">
-            <action name="view" default="true" ext="xltx"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-excel.template.macroEnabled.12">
-            <action name="view" default="true" ext="xltm"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet">
-            <action name="edit" default="true" ext="xlsx"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-excel.sheet.binary.macroEnabled.12">
-            <action name="edit" default="true" ext="xlsb"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-excel.sheet.macroEnabled.12">
-            <action name="edit" default="true" ext="xlsm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- OOXML presentation -->
         <app name="application/vnd.openxmlformats-officedocument.presentationml.presentation">
-            <action name="edit" default="true" ext="pptx"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-powerpoint.presentation.macroEnabled.12">
-            <action name="edit" default="true" ext="pptm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.openxmlformats-officedocument.presentationml.template">
-            <action name="edit" default="true" ext="potx"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-powerpoint.template.macroEnabled.12">
-            <action name="edit" default="true" ext="potm"/>
+            <action name="edit" default="true" ext=""/>
         </app>
 
         <!-- Others -->
         <app name="application/vnd.wordperfect">
-            <action name="view" default="true" ext="wpd"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-aportisdoc">
-            <action name="view" default="true" ext="pdb"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-hwp">
-            <action name="view" default="true" ext="hwp"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.ms-works">
-            <action name="view" default="true" ext="wps"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-mswrite">
-            <action name="view" default="true" ext="wri"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-dif-document">
-            <action name="edit" default="true" ext="dif"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="text/spreadsheet">
-            <action name="edit" default="true" ext="slk"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="text/csv">
-            <action name="edit" default="true" ext="csv"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/x-dbase">
-            <action name="edit" default="true" ext="dbf"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/vnd.lotus-1-2-3">
-            <action name="view" default="true" ext="wk1"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/cgm">
-            <action name="view" default="true" ext="cgm"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/vnd.dxf">
-            <action name="view" default="true" ext="dxf"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/x-emf">
-            <action name="view" default="true" ext="emf"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/x-wmf">
-            <action name="view" default="true" ext="wmf"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/coreldraw">
-            <action name="view" default="true" ext="cdr"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.visio2013">
-            <action name="view" default="true" ext="vsd"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.visio">
-            <action name="view" default="true" ext="vss"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-mspublisher">
-            <action name="view" default="true" ext="pub"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-sony-bbeb">
-            <action name="view" default="true" ext="lrf"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-gnumeric">
-            <action name="view" default="true" ext="gnumeric"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/macwriteii">
-            <action name="view" default="true" ext="mw"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-iwork-numbers-sffnumbers">
-            <action name="view" default="true" ext="numbers"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.oasis.opendocument.text-web">
-            <action name="edit" default="true" ext="oth"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/x-pagemaker">
-            <action name="view" default="true" ext="p65"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="text/rtf">
-            <action name="edit" default="true" ext="rtf"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="text/plain">
-            <action name="edit" default="true" ext="txt"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/x-fictionbook+xml">
-            <action name="view" default="true" ext="fb2"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/clarisworks">
-            <action name="view" default="true" ext="cwk"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/x-wpg">
-            <action name="view" default="true" ext="wpg"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-iwork-pages-sffpages">
-            <action name="view" default="true" ext="pages"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.openxmlformats-officedocument.presentationml.slideshow">
-            <action name="edit" default="true" ext="ppsx"/>
+            <action name="edit" default="true" ext=""/>
         </app>
         <app name="application/x-iwork-keynote-sffkey">
-            <action name="view" default="true" ext="key"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-abiword">
-            <action name="view" default="true" ext="abw"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/x-freehand">
-            <action name="view" default="true" ext="fh"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/vnd.sun.xml.chart">
-            <action name="view" default="true" ext="sxs"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="application/x-t602">
-            <action name="view" default="true" ext="602"/>
+            <action name="view" default="true" ext=""/>
         </app>
         <app name="image/bmp">
-            <action name="view" ext="bmp"/>
+            <action name="view" ext=""/>
         </app>
         <app name="image/png">
-            <action name="view" ext="png"/>
+            <action name="view" ext=""/>
         </app>
         <app name="image/gif">
-            <action name="view" ext="gif"/>
+            <action name="view" ext=""/>
         </app>
         <app name="image/tiff">
-            <action name="view" ext="tiff"/>
+            <action name="view" ext=""/>
         </app>
         <app name="image/jpg">
-            <action name="view" ext="jpg"/>
+            <action name="view" ext=""/>
         </app>
         <app name="image/jpeg">
-            <action name="view" ext="jpeg"/>
+            <action name="view" ext=""/>
         </app>
         <app name="application/pdf">
-            <action name="view_comment" ext="pdf"/>
+            <action name="view_comment" ext=""/>
         </app>
 
+        <!-- End of legacy MIME-type actions -->
+
         <app name="Capabilities">
             <action name="getinfo" ext=""/>
         </app>
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 806c22a0d..a901f08b8 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -57,6 +57,7 @@
 #include <mutex>
 #include <sstream>
 #include <thread>
+#include <unordered_map>
 
 #if !MOBILEAPP
 
@@ -2828,26 +2829,143 @@ private:
 
     static std::string getContentType(const std::string& fileName)
     {
-        const std::string nodePath = Poco::format("//[@ext='%s']", Poco::Path(fileName).getExtension());
-        std::string discPath = Path(Application::instance().commandPath()).parent().toString() + "discovery.xml";
-        if (!File(discPath).exists())
-        {
-            discPath = LOOLWSD::FileServerRoot + "/discovery.xml";
-        }
-
-        InputSource input(discPath);
-        DOMParser domParser;
-        AutoPtr<Poco::XML::Document> doc = domParser.parse(&input);
-        if (doc)
-        {
-            Node* node = doc->getNodeByPath(nodePath);
-            if (node && node->parentNode())
-            {
-                Element* elem = dynamic_cast<Element*>(node->parentNode());
-                if (elem && elem->hasAttributes())
-                    return elem->getAttribute("name");
-            }
-        }
+        static std::unordered_map<std::string, std::string> aContentTypes{
+            { "svg", "image/svg+xml" },
+            { "pot", "application/vnd.ms-powerpoint" },
+            { "xla", "application/vnd.ms-excel" },
+
+            // Writer documents
+            { "sxw", "application/vnd.sun.xml.writer" },
+            { "odt", "application/vnd.oasis.opendocument.text" },
+            { "fodt", "application/vnd.oasis.opendocument.text-flat-xml" },
+
+            // Calc documents
+            { "sxc", "application/vnd.sun.xml.calc" },
+            { "ods", "application/vnd.oasis.opendocument.spreadsheet" },
+            { "fods", "application/vnd.oasis.opendocument.spreadsheet-flat-xml" },
+
+            // Impress documents
+            { "sxi", "application/vnd.sun.xml.impress" },
+            { "odp", "application/vnd.oasis.opendocument.presentation" },
+            { "fodp", "application/vnd.oasis.opendocument.presentation-flat-xml" },
+
+            // Draw documents
+            { "sxd", "application/vnd.sun.xml.draw" },
+            { "odg", "application/vnd.oasis.opendocument.graphics" },
+            { "fodg", "application/vnd.oasis.opendocument.graphics-flat-xml" },
+
+            // Chart documents
+            { "odc", "application/vnd.oasis.opendocument.chart" },
+
+            // Text master documents
+            { "sxg", "application/vnd.sun.xml.writer.global" },
+            { "odm", "application/vnd.oasis.opendocument.text-master" },
+
+            // Math documents
+            // In fact Math documents are not supported at all.
+            // See: https://bugs.documentfoundation.org/show_bug.cgi?id=97006
+            { "sxm", "application/vnd.sun.xml.math" },
+            { "odf", "application/vnd.oasis.opendocument.formula" },
+
+            // Text template documents
+            { "stw", "application/vnd.sun.xml.writer.template" },
+            { "ott", "application/vnd.oasis.opendocument.text-template" },
+
+            // Writer master document templates
+            { "otm", "application/vnd.oasis.opendocument.text-master-template" },
+
+            // Spreadsheet template documents
+            { "stc", "application/vnd.sun.xml.calc.template" },
+            { "ots", "application/vnd.oasis.opendocument.spreadsheet-template" },
+
+            // Presentation template documents
+            { "sti", "application/vnd.sun.xml.impress.template" },
+            { "otp", "application/vnd.oasis.opendocument.presentation-template" },
+
+            // Drawing template documents
+            { "std", "application/vnd.sun.xml.draw.template" },
+            { "otg", "application/vnd.oasis.opendocument.graphics-template" },
+
+            // MS Word
+            { "doc", "application/msword" },
+            { "dot", "application/msword" },
+
+            // MS Excel
+            { "xls", "application/vnd.ms-excel" },
+
+            // MS PowerPoint
+            { "ppt", "application/vnd.ms-powerpoint" },
+
+            // OOXML wordprocessing
+            { "docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
+            { "docm", "application/vnd.ms-word.document.macroEnabled.12" },
+            { "dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template" },
+            { "dotm", "application/vnd.ms-word.template.macroEnabled.12" },
+
+            // OOXML spreadsheet
+            { "xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template" },
+            { "xltm", "application/vnd.ms-excel.template.macroEnabled.12" },
+            { "xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
+            { "xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12" },
+            { "xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12" },
+
+            // OOXML presentation
+            { "pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation" },
+            { "pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12" },
+            { "potx", "application/vnd.openxmlformats-officedocument.presentationml.template" },
+            { "potm", "application/vnd.ms-powerpoint.template.macroEnabled.12" },
+
+            // Others
+            { "wpd", "application/vnd.wordperfect" },
+            { "pdb", "application/x-aportisdoc" },
+            { "hwp", "application/x-hwp" },
+            { "wps", "application/vnd.ms-works" },
+            { "wri", "application/x-mswrite" },
+            { "dif", "application/x-dif-document" },
+            { "slk", "text/spreadsheet" },
+            { "csv", "text/csv" },
+            { "dbf", "application/x-dbase" },
+            { "wk1", "application/vnd.lotus-1-2-3" },
+            { "cgm", "image/cgm" },
+            { "dxf", "image/vnd.dxf" },
+            { "emf", "image/x-emf" },
+            { "wmf", "image/x-wmf" },
+            { "cdr", "application/coreldraw" },
+            { "vsd", "application/vnd.visio2013" },
+            { "vss", "application/vnd.visio" },
+            { "pub", "application/x-mspublisher" },
+            { "lrf", "application/x-sony-bbeb" },
+            { "gnumeric", "application/x-gnumeric" },
+            { "mw", "application/macwriteii" },
+            { "numbers", "application/x-iwork-numbers-sffnumbers" },
+            { "oth", "application/vnd.oasis.opendocument.text-web" },
+            { "p65", "application/x-pagemaker" },
+            { "rtf", "text/rtf" },
+            { "txt", "text/plain" },
+            { "fb2", "application/x-fictionbook+xml" },
+            { "cwk", "application/clarisworks" },
+            { "wpg", "image/x-wpg" },
+            { "pages", "application/x-iwork-pages-sffpages" },
+            { "ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow" },
+            { "key", "application/x-iwork-keynote-sffkey" },
+            { "abw", "application/x-abiword" },
+            { "fh", "image/x-freehand" },
+            { "sxs", "application/vnd.sun.xml.chart" },
+            { "602", "application/x-t602" },
+            { "bmp", "image/bmp" },
+            { "png", "image/png" },
+            { "gif", "image/gif" },
+            { "tiff", "image/tiff" },
+            { "jpg", "image/jpg" },
+            { "jpeg", "image/jpeg" },
+            { "pdf", "application/pdf" },
+        };
+
+        const std::string sExt = Poco::Path(fileName).getExtension();
+
+        const auto it = aContentTypes.find(sExt);
+        if (it != aContentTypes.end())
+            return it->second;
 
         return "application/octet-stream";
     }
diff --git a/wsd/lint-discovery.py b/wsd/lint-discovery.py
index 5f381bf2f..730129b4c 100755
--- a/wsd/lint-discovery.py
+++ b/wsd/lint-discovery.py
@@ -14,50 +14,50 @@ import os
 import sys
 import xml.sax
 
-
 # Parses an online.git discovery.xml.
 class DiscoveryHandler(xml.sax.handler.ContentHandler):
     def __init__(self):
-        # List of app <-> action types.
-        self.appActions = []
-        self.inApp = False
+        # Dict of app -> {extension -> action}
+        self.appActions = {}
         self.app = None
-        self.inAction = False
-        self.action = None
-
+        self.allExtensions = set()
     def startElement(self, name, attrs):
         if name == "app":
-            self.inApp = True
             for k, v in list(attrs.items()):
                 if k == "name":
                     self.app = v
-        elif name == "action":
-            self.inAction = True
+                    self.appActions[self.app] = {}
+        elif name == "action" and self.app:
+            action = None
+            ext = None
             for k, v in list(attrs.items()):
                 if k == "name":
-                    self.action = v
-
+                    action = v
+                elif k == "ext":
+                    ext = v
+            if action and ext:
+                self.appActions[self.app][ext] = action
+                if ext in self.allExtensions:
+                    # Potential problem: see 2de5017e329ce09efbd8f4dc6066fdba3e2c080c
+                    # discovery.xml with duplicating "ext" is valid, but can't be
+                    # used directly in e.g. SharePoint, unless specific extensions
+                    # are imported using New-SPWOPIBinding's parameters, avoiding
+                    # the duplication.
+                    print("warning: extension '" + ext + "' exists for '" + self.app + "', " +
+                          "but already used earlier in discovery.xml")
+                self.allExtensions.add(ext)
     def endElement(self, name):
-        if name == "app":
-            self.inApp = False
-            if self.app and self.action:
-                self.appActions.append([self.app, self.action])
-                self.app = None
-                self.action = None
-        elif name == "action":
-            self.inAction = False
-
+        if name == "app" and self.app:
+            self.app = None
 
 # Parses core.git filter/source/config/fragments/types/*.xcu.
 class FilterTypeHandler(xml.sax.handler.ContentHandler):
     def __init__(self):
         self.name = None
-        self.inMediaType = False
         self.inExtensions = False
         self.content = []
-        self.mediaType = None
         self.extensions = None
-
+        self.extensionsSep = " "
     def startElement(self, name, attrs):
         if name == "node":
             for k, v in list(attrs.items()):
@@ -65,26 +65,22 @@ class FilterTypeHandler(xml.sax.handler.ContentHandler):
                     self.name = v
         elif name == "prop":
             for k, v in list(attrs.items()):
-                if k == "oor:name" and v == "MediaType":
-                    self.inMediaType = True
-                elif k == "oor:name" and v == "Extensions":
+                if k == "oor:name" and v == "Extensions":
                     self.inExtensions = True
-
+        elif name == "value" and self.inExtensions:
+            for k, v in list(attrs.items()):
+                if k == "oor:separator":
+                    self.extensionsSep = v
     def endElement(self, name):
-        if name == "prop" and self.inMediaType:
-            self.inMediaType = False
-            self.mediaType = "".join(self.content).strip()
-            self.content = []
-        elif name == "prop" and self.inExtensions:
+        if name == "prop" and self.inExtensions:
             self.inExtensions = False
-            self.extensions = "".join(self.content).strip()
+            self.extensions = "".join(self.content).strip().encode("utf-8").split(self.extensionsSep)
+            self.extensionsSep = " "
             self.content = []
-
     def characters(self, content):
-        if self.inMediaType or self.inExtensions:
+        if self.inExtensions:
             self.content.append(content)
 
-
 # Parses core.git filter/source/config/fragments/filters/*.xcu.
 class FilterFragmentHandler(xml.sax.handler.ContentHandler):
     def __init__(self):
@@ -92,8 +88,9 @@ class FilterFragmentHandler(xml.sax.handler.ContentHandler):
         self.typeName = None
         self.inFlags = False
         self.flags = None
+        self.inDocumentService = False
+        self.documentService = None
         self.content = []
-
     def startElement(self, name, attrs):
         if name == "prop":
             for k, v in list(attrs.items()):
@@ -101,7 +98,8 @@ class FilterFragmentHandler(xml.sax.handler.ContentHandler):
                     self.inType = True
                 elif k == "oor:name" and v == "Flags":
                     self.inFlags = True
-
+                elif k == "oor:name" and v == "DocumentService":
+                    self.inDocumentService = True
     def endElement(self, name):
         if name == "prop" and self.inType:
             self.inType = False
@@ -112,77 +110,86 @@ class FilterFragmentHandler(xml.sax.handler.ContentHandler):
             encodedFlags = "".join(self.content).strip().encode("utf-8")
             self.flags = encodedFlags.split(" ")
             self.content = []
-
+        elif name == "prop" and self.inDocumentService:
+            self.inDocumentService = False
+            self.documentService = "".join(self.content).strip()
+            self.content = []
     def characters(self, content):
-        if self.inType or self.inFlags:
+        if self.inType or self.inFlags or self.inDocumentService:
             self.content.append(content)
 
-
-# Builds a MIME type -> filter flag dictionary.
-def getFilterFlags(filterDir):
-    # Build a MIME type -> type name dictionary.
-    filterNames = {}
+# Builds a 'document service' -> {'extension' -> 'filter flags'} dictionary.
+def getExtensionProperties(filterDir):
+    # Build a 'type name' -> 'extensions' dictionary.
+    typeNameExtensions = {}
     typeFragments = os.path.join(filterDir, "types")
     for typeFragment in os.listdir(typeFragments):
         if not typeFragment.endswith(".xcu"):
             continue
-
         parser = xml.sax.make_parser()
         filterTypeHandler = FilterTypeHandler()
         parser.setContentHandler(filterTypeHandler)
         parser.parse(os.path.join(typeFragments, typeFragment))
-        # Did we find a MIME type?
-        if filterTypeHandler.mediaType:
-            v = (filterTypeHandler.name, filterTypeHandler.extensions)
-            filterNames[filterTypeHandler.mediaType] = v
-
-    # core.git doesn't declares this, but probably this is the intention.
-    filterNames["application/x-dif-document"] = ("calc_DIF", "dif")
-    filterNames["application/x-dbase"] = ("calc_dBase", "dbf")
-
-    # Build a 'type name' -> 'filter flag list' dictionary.
+        # Did we find some extensions?
+        if filterTypeHandler.extensions:
+            typeNameExtensions[filterTypeHandler.name] = filterTypeHandler.extensions
+    # Build a 'type name' -> ('filter flag list', 'document service') dictionary.
     typeNameFlags = {}
     filterFragments = os.path.join(filterDir, "filters")
     for filterFragment in os.listdir(filterFragments):
         if not filterFragment.endswith(".xcu"):
             continue
-
         parser = xml.sax.make_parser()
         handler = FilterFragmentHandler()
         parser.setContentHandler(handler)
         parser.parse(os.path.join(filterFragments, filterFragment))
-        typeNameFlags[handler.typeName] = handler.flags
-
-    # Now build the combined MIME type -> filter flags one.
-    filterFlags = {}
-    for i in filterNames.keys():
-        typeName, extensions = filterNames[i]
-        if typeName in typeNameFlags.keys():
-            filterFlags[i] = (typeNameFlags[typeName], extensions)
-
-    return filterFlags
-
-# How it's described in discovery.xml -> how core.git knows it.
-mimeTypeAliases = {
-    'application/coreldraw': 'application/vnd.corel-draw',
-    'application/vnd.visio2013': 'application/vnd.visio',
+        if "IMPORT" in handler.flags:
+            if handler.typeName in typeNameFlags:
+                if "EXPORT" in typeNameFlags[handler.typeName][0]:
+                    continue # don't modify a filetype with maximal capabilities
+            typeNameFlags[handler.typeName] = (handler.flags, handler.documentService)
+    # Now build the combined 'document service' -> {'extension' -> 'filter flags'}.
+    extensionProperties = {}
+    for typeName in typeNameExtensions:
+        if typeName not in typeNameFlags:
+            continue
+        flags, documentService = typeNameFlags[typeName]
+        if documentService not in extensionProperties:
+            extensionProperties[documentService] = {}
+        for extension in typeNameExtensions[typeName]:
+            extensionProperties[documentService][extension] = flags
+    return extensionProperties
+
+# Map app names to document service names
+appDocumentServices = {
+    'writer': 'com.sun.star.text.TextDocument',
+    'writer-global': 'com.sun.star.text.GlobalDocument',
+    'writer-web': 'com.sun.star.text.WebDocument',
+    'calc': 'com.sun.star.sheet.SpreadsheetDocument',
+    'impress': 'com.sun.star.presentation.PresentationDocument',
+    'draw': 'com.sun.star.drawing.DrawingDocument',
 }
-
-# We know that these can be edited.
-mimeTypeWhiteList = {
-    'application/vnd.ms-excel',
-    'application/vnd.oasis.opendocument.text',
-    'application/msword',
+documentServicesApp = {v: k for k, v in appDocumentServices.items()}
+
+# We know about these extensions
+extensionsSkipList = {
+    'xls', # we know that it can be edited
+    'pdf', # it exists for draw - its entry in core.git is missing document service
+    'zip',
+    'htm',
+    'html',
+    'xhtml',
+    '*',   # well, obvious ;-)
+    '',    # and this :-D
 }
 
-
 def main():
     discoveryXml = "discovery.xml"
     repoGuess = os.path.join(os.environ["HOME"], "git/libreoffice/master")
     filterDir = os.path.join(repoGuess, "filter/source/config/fragments")
     if len(sys.argv) >= 3:
         discoveryXml = sys.argv[1]
-        filterDir = sys.arv[2]
+        filterDir = sys.argv[2]
 
     # Parse discovery.xml, which describes what online.git exposes at the
     # moment.
@@ -191,20 +198,31 @@ def main():
     parser.setContentHandler(discoveryHandler)
     parser.parse(discoveryXml)
 
-    # Parse core.git filter definitions to build a MIME type <-> filter flag
-    # dictionary.
-    filterFlags = getFilterFlags(filterDir)
-
-    # Now look up the filter flags in core.git for the MIME type.
-    for i in discoveryHandler.appActions:
-        mimeType = i[0]
-        discoveryAction = i[1]
-        if mimeType in mimeTypeWhiteList:
+    # Parse core.git filter definitions to build a
+    # 'document service' -> {'extension' -> 'filter flags'} dictionary.
+    extensionProperties = getExtensionProperties(filterDir)
+
+    proposed = {}
+
+    # Now look up the filter flags in core.git for the extension.
+    for app, actions in discoveryHandler.appActions.items():
+        if app not in appDocumentServices:
+            continue # e.g., for "Capabilities"
+        documentService = appDocumentServices[app]
+        if documentService not in extensionProperties:
+            # Inconsistency found.
+            print("warning: actions for '" + app + "' " +
+                  "exist, but not found in core.git")
             continue
-        if mimeType in mimeTypeAliases.keys():
-            mimeType = mimeTypeAliases[mimeType]
-        if mimeType in filterFlags.keys():
-            flags, extensions = filterFlags[mimeType]
+        for extension, discoveryAction in actions.items():
+            if extension in extensionsSkipList:
+                continue
+            if extension not in extensionProperties[documentService]:
+                # Inconsistency found.
+                print("warning: action for '" + app + ":" + extension + "' " +
+                      "exists, but is not found in core.git")
+                continue
+            flags = extensionProperties[documentService][extension]
             if "IMPORT" in flags and "EXPORT" in flags:
                 coreAction = "edit"
             else:
@@ -212,32 +230,65 @@ def main():
 
             if discoveryAction != coreAction:
                 # Inconsistency found.
-                print("warning: action for '" + mimeType + "' " +
+                print("warning: action for '" + app + ":" + extension + "' " +
                       "is '" + discoveryAction + "', " +
                       "but it should be '" + coreAction + "'")
 
+        # Now see if there are any new extensions in the core.git filter config
+        # which are missing.
+        for extension, flags in extensionProperties[documentService].items():
+            if extension not in actions:
+                if "IMPORT" in flags and "EXPORT" in flags:
+                    action = "edit"
+                else:
+                    action = "view"
+                if app not in proposed:
+                    proposed[app] = {}
+                proposed[app][extension] = action
+
     # Now see if there are any new types in the core.git filter config which
     # are missing.
-    discoveryMimeTypes = [i[0] for i in discoveryHandler.appActions]
-    proposed = []
-    for filterMimeType in filterFlags.keys():
-        if filterMimeType not in discoveryMimeTypes:
-            flags, extensions = filterFlags[filterMimeType]
-            if "IMPORT" in flags and "EXPORT" in flags:
-                action = "edit"
-            else:
-                action = "view"
-            print("warning: mime type '" + filterMimeType + "' is known, " +
-                  "but not advertised in discovery.xml " +
-                  "(extension would be '" + extensions + "', and " +
-                  "action would be '"+action+"')")
-            proposed.append((filterMimeType, extensions, action))
+    for documentService, extensions in extensionProperties.items():
+        missingName = None
+        if documentService not in documentServicesApp:
+            # Inconsistency found.
+            print("warning: extensions for '" + documentService + "' " +
+                  "found in core.git, without mapping to apps in discovery.xml")
+            missingName = documentService
+        else:
+            app = documentServicesApp[documentService]
+            if app not in discoveryHandler.appActions:
+                # Inconsistency found.
+                print("warning: extensions for '" + app + "' " +
+                      "found in core.git, all missing in discovery.xml")
+                missingName = app
+
+        if missingName:
+            for extension, flags in extensions.items():
+                if "IMPORT" in flags and "EXPORT" in flags:
+                    action = "edit"
+                else:
+                    action = "view"
+                if missingName not in proposed:
+                    proposed[missingName] = {}
+                proposed[missingName][extension] = action
 
     # Produce a copy&paste-able XML output for the proposed changes.
-    for proposal in proposed:
-        print('        <app name="' + proposal[0] + '">')
-        print('            <action name="' + proposal[2] + '" ' +
-              'ext="' + proposal[1] + '"/>')
+    for app, extensions in proposed.items():
+        newExtensions = {}
+        for extension, action in extensions.items():
+            if extension in extensionsSkipList:
+                continue
+            if extension in discoveryHandler.allExtensions:
+                continue # see 2de5017e329ce09efbd8f4dc6066fdba3e2c080c
+            newExtensions[extension] = action
+        if not newExtensions:
+            continue # no extensions after filtering
+
+        print('        <app name="' + app + '">')
+        for extension, action in newExtensions.items():
+            print('            <action name="' + action + '" default="true" ' +
+                  'ext="' + extension + '"/>')
         print('        </app>')
 
 if __name__ == "__main__":


More information about the Libreoffice-commits mailing list