[Libreoffice-commits] online.git: common/Util.cpp common/Util.hpp ios/ios.h ios/ios.mm kit/ChildSession.cpp kit/ChildSession.hpp kit/Kit.cpp kit/Kit.hpp Mobile/Mobile Mobile/Mobile.xcodeproj net/Socket.cpp net/Socket.hpp net/WebSocketHandler.hpp wsd/DocumentBroker.hpp

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Wed Sep 12 15:38:31 UTC 2018


 Mobile/Mobile.xcodeproj/project.pbxproj                        |  659 ++++++++++
 Mobile/Mobile/AppDelegate.h                                    |   22 
 Mobile/Mobile/AppDelegate.mm                                   |   78 +
 Mobile/Mobile/Assets.xcassets/AppIcon.appiconset/Contents.json |   98 +
 Mobile/Mobile/Assets.xcassets/Contents.json                    |    6 
 Mobile/Mobile/Base.lproj/LaunchScreen.storyboard               |   25 
 Mobile/Mobile/Base.lproj/Main.storyboard                       |   44 
 Mobile/Mobile/Document.h                                       |   29 
 Mobile/Mobile/Document.mm                                      |  118 +
 Mobile/Mobile/DocumentBrowserViewController.h                  |   17 
 Mobile/Mobile/DocumentBrowserViewController.mm                 |   78 +
 Mobile/Mobile/DocumentViewController.h                         |   21 
 Mobile/Mobile/DocumentViewController.mm                        |  168 ++
 Mobile/Mobile/Info.plist                                       |  147 ++
 Mobile/Mobile/main.m                                           |   18 
 common/Util.cpp                                                |    4 
 common/Util.hpp                                                |    4 
 ios/ios.h                                                      |   12 
 ios/ios.mm                                                     |   25 
 kit/ChildSession.cpp                                           |    8 
 kit/ChildSession.hpp                                           |    8 
 kit/Kit.cpp                                                    |   90 +
 kit/Kit.hpp                                                    |   47 
 net/Socket.cpp                                                 |   19 
 net/Socket.hpp                                                 |   36 
 net/WebSocketHandler.hpp                                       |   17 
 wsd/DocumentBroker.hpp                                         |   24 
 27 files changed, 1810 insertions(+), 12 deletions(-)

New commits:
commit b59d160a085796c567e114a62483438ed761c31a
Author:     Tor Lillqvist <tml at iki.fi>
AuthorDate: Tue Sep 11 09:30:55 2018 +0300
Commit:     Tor Lillqvist <tml at iki.fi>
CommitDate: Wed Sep 12 18:32:05 2018 +0300

    Intermediate commit of work in progress on an iOS app
    
    The app is unimaginatively called "Mobile" for now.
    
    Runs but crashes pretty quickly after loading the document by the LO
    core. Will need some heavy changes to get a ClientSession object
    created in there, too, to handle the (emulated) WebSocket messages
    from the JavaScript. It would then handle some of these messages
    itself, and forwards some to the ChildSession, which in this case is
    in the same process. Now the messsages from the JavaScript go to a
    ChildSession, which is wrong. As the assertion says, "Tile traffic
    should go through the DocumentBroker-LoKit WS"

diff --git a/Mobile/Mobile.xcodeproj/project.pbxproj b/Mobile/Mobile.xcodeproj/project.pbxproj
new file mode 100644
index 000000000..1bb123e3b
--- /dev/null
+++ b/Mobile/Mobile.xcodeproj/project.pbxproj
@@ -0,0 +1,659 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 50;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		BE00F8A021396585001CE2D4 /* loleaflet.html in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89621396585001CE2D4 /* loleaflet.html */; };
+		BE00F8A121396585001CE2D4 /* bundle.css in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89721396585001CE2D4 /* bundle.css */; };
+		BE00F8A321396585001CE2D4 /* bundle.js in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89921396585001CE2D4 /* bundle.js */; };
+		BE00F8A521396585001CE2D4 /* l10n in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89B21396585001CE2D4 /* l10n */; };
+		BE00F8A621396585001CE2D4 /* loading.html in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89C21396585001CE2D4 /* loading.html */; };
+		BE00F8A721396585001CE2D4 /* loleaflet-help.html in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89D21396585001CE2D4 /* loleaflet-help.html */; };
+		BE00F8A821396585001CE2D4 /* images in Resources */ = {isa = PBXBuildFile; fileRef = BE00F89E21396585001CE2D4 /* images */; };
+		BE00F8B5213ED543001CE2D4 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE00F8B4213ED543001CE2D4 /* libiconv.tbd */; };
+		BE00F8B7213ED573001CE2D4 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BE00F8B6213ED573001CE2D4 /* libz.tbd */; };
+		BE5EB5C1213FE29900E0826C /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5B9213FE29900E0826C /* Log.cpp */; };
+		BE5EB5C2213FE29900E0826C /* SpookyV2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BA213FE29900E0826C /* SpookyV2.cpp */; };
+		BE5EB5C3213FE29900E0826C /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BB213FE29900E0826C /* Session.cpp */; };
+		BE5EB5C4213FE29900E0826C /* Util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BC213FE29900E0826C /* Util.cpp */; };
+		BE5EB5C5213FE29900E0826C /* MessageQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */; };
+		BE5EB5C6213FE29900E0826C /* SigUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BE213FE29900E0826C /* SigUtil.cpp */; };
+		BE5EB5C7213FE29900E0826C /* Protocol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5BF213FE29900E0826C /* Protocol.cpp */; };
+		BE5EB5C8213FE29900E0826C /* FileUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5C0213FE29900E0826C /* FileUtil.cpp */; };
+		BE5EB5CA213FE2B100E0826C /* Socket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5C9213FE2B100E0826C /* Socket.cpp */; };
+		BE5EB5CF213FE2D000E0826C /* ClientSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */; };
+		BE5EB5D0213FE2D000E0826C /* TileCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5CD213FE2D000E0826C /* TileCache.cpp */; };
+		BE5EB5D22140039100E0826C /* LOOLWSD.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D12140039100E0826C /* LOOLWSD.cpp */; };
+		BE5EB5D421400DC100E0826C /* DocumentBroker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */; };
+		BE5EB5D621401E0F00E0826C /* Storage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D521401E0F00E0826C /* Storage.cpp */; };
+		BE5EB5DA2140363100E0826C /* ios.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE5EB5D92140363100E0826C /* ios.mm */; };
+		BE5EB5DC2140480B00E0826C /* icudt62l.dat in Resources */ = {isa = PBXBuildFile; fileRef = BE5EB5DB2140480B00E0826C /* icudt62l.dat */; };
+		BE8D772C2136762500AC58EA /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE8D772B2136762500AC58EA /* AppDelegate.mm */; };
+		BE8D772F2136762500AC58EA /* DocumentBrowserViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE8D772E2136762500AC58EA /* DocumentBrowserViewController.mm */; };
+		BE8D77322136762500AC58EA /* DocumentViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE8D77312136762500AC58EA /* DocumentViewController.mm */; };
+		BE8D77352136762500AC58EA /* Document.mm in Sources */ = {isa = PBXBuildFile; fileRef = BE8D77342136762500AC58EA /* Document.mm */; };
+		BE8D77382136762500AC58EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE8D77362136762500AC58EA /* Main.storyboard */; };
+		BE8D773A2136762600AC58EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BE8D77392136762600AC58EA /* Assets.xcassets */; };
+		BE8D773D2136762600AC58EA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE8D773B2136762600AC58EA /* LaunchScreen.storyboard */; };
+		BE8D77402136762600AC58EA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE8D773F2136762600AC58EA /* main.m */; };
+		BE8D85C9214055F3009F1860 /* filter in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85BB214055F2009F1860 /* filter */; };
+		BE8D85CA214055F3009F1860 /* offapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85BC214055F2009F1860 /* offapi.rdb */; };
+		BE8D85CB214055F3009F1860 /* share in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85BD214055F2009F1860 /* share */; };
+		BE8D85CC214055F3009F1860 /* config in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85BE214055F2009F1860 /* config */; };
+		BE8D85CD214055F3009F1860 /* registry in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85BF214055F2009F1860 /* registry */; };
+		BE8D85CE214055F3009F1860 /* oovbaapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C0214055F2009F1860 /* oovbaapi.rdb */; };
+		BE8D85CF214055F3009F1860 /* udkapi.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C1214055F2009F1860 /* udkapi.rdb */; };
+		BE8D85D0214055F3009F1860 /* services in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C2214055F2009F1860 /* services */; };
+		BE8D85D1214055F3009F1860 /* services.rdb in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C3214055F2009F1860 /* services.rdb */; };
+		BE8D85D2214055F3009F1860 /* program in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C4214055F3009F1860 /* program */; };
+		BE8D85D3214055F3009F1860 /* welcome.odt in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C5214055F3009F1860 /* welcome.odt */; };
+		BE8D85D4214055F3009F1860 /* fundamentalrc in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C6214055F3009F1860 /* fundamentalrc */; };
+		BE8D85D5214055F3009F1860 /* unorc in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C7214055F3009F1860 /* unorc */; };
+		BE8D85D6214055F3009F1860 /* rc in Resources */ = {isa = PBXBuildFile; fileRef = BE8D85C8214055F3009F1860 /* rc */; };
+		BEA2835621467FDD00848631 /* Kit.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA2835521467FDD00848631 /* Kit.cpp */; };
+		BEA283582146945500848631 /* ChildSession.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEA283572146945500848631 /* ChildSession.cpp */; };
+		BEA2835A21470A1C00848631 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BEA2835921470A1C00848631 /* WebKit.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+		BE00F89621396585001CE2D4 /* loleaflet.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = loleaflet.html; path = ../../../loleaflet/dist/loleaflet.html; sourceTree = "<group>"; };
+		BE00F89721396585001CE2D4 /* bundle.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = bundle.css; path = ../../../loleaflet/dist/bundle.css; sourceTree = "<group>"; };
+		BE00F89921396585001CE2D4 /* bundle.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = bundle.js; path = ../../../loleaflet/dist/bundle.js; sourceTree = "<group>"; };
+		BE00F89B21396585001CE2D4 /* l10n */ = {isa = PBXFileReference; lastKnownFileType = folder; name = l10n; path = ../../../loleaflet/dist/l10n; sourceTree = "<group>"; };
+		BE00F89C21396585001CE2D4 /* loading.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = loading.html; path = ../../../loleaflet/dist/loading.html; sourceTree = "<group>"; };
+		BE00F89D21396585001CE2D4 /* loleaflet-help.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = "loleaflet-help.html"; path = "../../../loleaflet/dist/loleaflet-help.html"; sourceTree = "<group>"; };
+		BE00F89E21396585001CE2D4 /* images */ = {isa = PBXFileReference; lastKnownFileType = folder; name = images; path = ../../../loleaflet/dist/images; sourceTree = "<group>"; };
+		BE00F8B4213ED543001CE2D4 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
+		BE00F8B6213ED573001CE2D4 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; };
+		BE5EB5B9213FE29900E0826C /* Log.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Log.cpp; path = ../../../common/Log.cpp; sourceTree = "<group>"; };
+		BE5EB5BA213FE29900E0826C /* SpookyV2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SpookyV2.cpp; path = ../../../common/SpookyV2.cpp; sourceTree = "<group>"; };
+		BE5EB5BB213FE29900E0826C /* Session.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Session.cpp; path = ../../../common/Session.cpp; sourceTree = "<group>"; };
+		BE5EB5BC213FE29900E0826C /* Util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Util.cpp; path = ../../../common/Util.cpp; sourceTree = "<group>"; };
+		BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MessageQueue.cpp; path = ../../../common/MessageQueue.cpp; sourceTree = "<group>"; };
+		BE5EB5BE213FE29900E0826C /* SigUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SigUtil.cpp; path = ../../../common/SigUtil.cpp; sourceTree = "<group>"; };
+		BE5EB5BF213FE29900E0826C /* Protocol.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Protocol.cpp; path = ../../../common/Protocol.cpp; sourceTree = "<group>"; };
+		BE5EB5C0213FE29900E0826C /* FileUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FileUtil.cpp; path = ../../../common/FileUtil.cpp; sourceTree = "<group>"; };
+		BE5EB5C9213FE2B100E0826C /* Socket.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Socket.cpp; path = ../../../net/Socket.cpp; sourceTree = "<group>"; };
+		BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ClientSession.cpp; path = ../../../wsd/ClientSession.cpp; sourceTree = "<group>"; };
+		BE5EB5CD213FE2D000E0826C /* TileCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TileCache.cpp; path = ../../../wsd/TileCache.cpp; sourceTree = "<group>"; };
+		BE5EB5D12140039100E0826C /* LOOLWSD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LOOLWSD.cpp; path = ../../../wsd/LOOLWSD.cpp; sourceTree = "<group>"; };
+		BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DocumentBroker.cpp; path = ../../../wsd/DocumentBroker.cpp; sourceTree = "<group>"; };
+		BE5EB5D521401E0F00E0826C /* Storage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Storage.cpp; path = ../../../wsd/Storage.cpp; sourceTree = "<group>"; };
+		BE5EB5D92140363100E0826C /* ios.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios.mm; path = ../../ios/ios.mm; sourceTree = "<group>"; };
+		BE5EB5DB2140480B00E0826C /* icudt62l.dat */ = {isa = PBXFileReference; lastKnownFileType = file; name = icudt62l.dat; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/icudt62l.dat"; sourceTree = "<group>"; };
+		BE8D77272136762500AC58EA /* Mobile.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mobile.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		BE8D772A2136762500AC58EA /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+		BE8D772B2136762500AC58EA /* AppDelegate.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = AppDelegate.mm; sourceTree = "<group>"; };
+		BE8D772D2136762500AC58EA /* DocumentBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DocumentBrowserViewController.h; sourceTree = "<group>"; };
+		BE8D772E2136762500AC58EA /* DocumentBrowserViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DocumentBrowserViewController.mm; sourceTree = "<group>"; };
+		BE8D77302136762500AC58EA /* DocumentViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DocumentViewController.h; sourceTree = "<group>"; };
+		BE8D77312136762500AC58EA /* DocumentViewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DocumentViewController.mm; sourceTree = "<group>"; };
+		BE8D77332136762500AC58EA /* Document.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Document.h; sourceTree = "<group>"; };
+		BE8D77342136762500AC58EA /* Document.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objcpp; path = Document.mm; sourceTree = "<group>"; };
+		BE8D77372136762500AC58EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+		BE8D77392136762600AC58EA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		BE8D773C2136762600AC58EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
+		BE8D773E2136762600AC58EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		BE8D773F2136762600AC58EA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+		BE8D85BB214055F2009F1860 /* filter */ = {isa = PBXFileReference; lastKnownFileType = folder; name = filter; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/filter"; sourceTree = "<group>"; };
+		BE8D85BC214055F2009F1860 /* offapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = offapi.rdb; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/offapi.rdb"; sourceTree = "<group>"; };
+		BE8D85BD214055F2009F1860 /* share */ = {isa = PBXFileReference; lastKnownFileType = folder; name = share; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/share"; sourceTree = "<group>"; };
+		BE8D85BE214055F2009F1860 /* config */ = {isa = PBXFileReference; lastKnownFileType = folder; name = config; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/config"; sourceTree = "<group>"; };
+		BE8D85BF214055F2009F1860 /* registry */ = {isa = PBXFileReference; lastKnownFileType = folder; name = registry; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/registry"; sourceTree = "<group>"; };
+		BE8D85C0214055F2009F1860 /* oovbaapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = oovbaapi.rdb; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/oovbaapi.rdb"; sourceTree = "<group>"; };
+		BE8D85C1214055F2009F1860 /* udkapi.rdb */ = {isa = PBXFileReference; lastKnownFileType = file; name = udkapi.rdb; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/udkapi.rdb"; sourceTree = "<group>"; };
+		BE8D85C2214055F2009F1860 /* services */ = {isa = PBXFileReference; lastKnownFileType = folder; name = services; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/services"; sourceTree = "<group>"; };
+		BE8D85C3214055F2009F1860 /* services.rdb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = services.rdb; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/services.rdb"; sourceTree = "<group>"; };
+		BE8D85C4214055F3009F1860 /* program */ = {isa = PBXFileReference; lastKnownFileType = folder; name = program; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/program"; sourceTree = "<group>"; };
+		BE8D85C5214055F3009F1860 /* welcome.odt */ = {isa = PBXFileReference; lastKnownFileType = file; name = welcome.odt; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/welcome.odt"; sourceTree = "<group>"; };
+		BE8D85C6214055F3009F1860 /* fundamentalrc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = fundamentalrc; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/fundamentalrc"; sourceTree = "<group>"; };
+		BE8D85C7214055F3009F1860 /* unorc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = unorc; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/unorc"; sourceTree = "<group>"; };
+		BE8D85C8214055F3009F1860 /* rc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = rc; path = "$(LOBUILDDIR)/workdir/CustomTarget/ios/resources/rc"; sourceTree = "<group>"; };
+		BEA2835521467FDD00848631 /* Kit.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Kit.cpp; path = ../../../kit/Kit.cpp; sourceTree = "<group>"; };
+		BEA283572146945500848631 /* ChildSession.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ChildSession.cpp; path = ../../../kit/ChildSession.cpp; sourceTree = "<group>"; };
+		BEA2835921470A1C00848631 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		BE8D77242136762500AC58EA /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BEA2835A21470A1C00848631 /* WebKit.framework in Frameworks */,
+				BE00F8B7213ED573001CE2D4 /* libz.tbd in Frameworks */,
+				BE00F8B5213ED543001CE2D4 /* libiconv.tbd in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		BE00F8922139494E001CE2D4 /* Resources */ = {
+			isa = PBXGroup;
+			children = (
+				BE8D85BE214055F2009F1860 /* config */,
+				BE8D85BB214055F2009F1860 /* filter */,
+				BE8D85C6214055F3009F1860 /* fundamentalrc */,
+				BE8D85BC214055F2009F1860 /* offapi.rdb */,
+				BE8D85C0214055F2009F1860 /* oovbaapi.rdb */,
+				BE8D85C4214055F3009F1860 /* program */,
+				BE8D85C8214055F3009F1860 /* rc */,
+				BE8D85BF214055F2009F1860 /* registry */,
+				BE8D85C2214055F2009F1860 /* services */,
+				BE8D85C3214055F2009F1860 /* services.rdb */,
+				BE8D85BD214055F2009F1860 /* share */,
+				BE8D85C1214055F2009F1860 /* udkapi.rdb */,
+				BE8D85C7214055F3009F1860 /* unorc */,
+				BE8D85C5214055F3009F1860 /* welcome.odt */,
+				BE5EB5DB2140480B00E0826C /* icudt62l.dat */,
+				BE00F89721396585001CE2D4 /* bundle.css */,
+				BE00F89921396585001CE2D4 /* bundle.js */,
+				BE00F89E21396585001CE2D4 /* images */,
+				BE00F89B21396585001CE2D4 /* l10n */,
+				BE00F89C21396585001CE2D4 /* loading.html */,
+				BE00F89D21396585001CE2D4 /* loleaflet-help.html */,
+				BE00F89621396585001CE2D4 /* loleaflet.html */,
+			);
+			path = Resources;
+			sourceTree = "<group>";
+		};
+		BE00F8B3213ED542001CE2D4 /* Frameworks */ = {
+			isa = PBXGroup;
+			children = (
+				BEA2835921470A1C00848631 /* WebKit.framework */,
+				BE00F8B6213ED573001CE2D4 /* libz.tbd */,
+				BE00F8B4213ED543001CE2D4 /* libiconv.tbd */,
+			);
+			name = Frameworks;
+			sourceTree = "<group>";
+		};
+		BE5EB5B5213FE1F900E0826C /* Online */ = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5B6213FE21000E0826C /* common */,
+				BEA2835421467F8200848631 /* kit */,
+				BE5EB5B8213FE22200E0826C /* net */,
+				BE5EB5B7213FE21600E0826C /* wsd */,
+			);
+			path = Online;
+			sourceTree = "<group>";
+		};
+		BE5EB5B6213FE21000E0826C /* common */ = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5C0213FE29900E0826C /* FileUtil.cpp */,
+				BE5EB5B9213FE29900E0826C /* Log.cpp */,
+				BE5EB5BD213FE29900E0826C /* MessageQueue.cpp */,
+				BE5EB5BF213FE29900E0826C /* Protocol.cpp */,
+				BE5EB5BB213FE29900E0826C /* Session.cpp */,
+				BE5EB5BE213FE29900E0826C /* SigUtil.cpp */,
+				BE5EB5BA213FE29900E0826C /* SpookyV2.cpp */,
+				BE5EB5BC213FE29900E0826C /* Util.cpp */,
+			);
+			path = common;
+			sourceTree = "<group>";
+		};
+		BE5EB5B7213FE21600E0826C /* wsd */ = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5CC213FE2D000E0826C /* ClientSession.cpp */,
+				BE5EB5D321400DC100E0826C /* DocumentBroker.cpp */,
+				BE5EB5D12140039100E0826C /* LOOLWSD.cpp */,
+				BE5EB5D521401E0F00E0826C /* Storage.cpp */,
+				BE5EB5CD213FE2D000E0826C /* TileCache.cpp */,
+			);
+			path = wsd;
+			sourceTree = "<group>";
+		};
+		BE5EB5B8213FE22200E0826C /* net */ = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5C9213FE2B100E0826C /* Socket.cpp */,
+			);
+			path = net;
+			sourceTree = "<group>";
+		};
+		BE8D771E2136762500AC58EA = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5B5213FE1F900E0826C /* Online */,
+				BE8D77292136762500AC58EA /* Mobile */,
+				BE8D77282136762500AC58EA /* Products */,
+				BE00F8B3213ED542001CE2D4 /* Frameworks */,
+			);
+			sourceTree = "<group>";
+		};
+		BE8D77282136762500AC58EA /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				BE8D77272136762500AC58EA /* Mobile.app */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		BE8D77292136762500AC58EA /* Mobile */ = {
+			isa = PBXGroup;
+			children = (
+				BE5EB5D92140363100E0826C /* ios.mm */,
+				BE00F8922139494E001CE2D4 /* Resources */,
+				BE8D772A2136762500AC58EA /* AppDelegate.h */,
+				BE8D772B2136762500AC58EA /* AppDelegate.mm */,
+				BE8D772D2136762500AC58EA /* DocumentBrowserViewController.h */,
+				BE8D772E2136762500AC58EA /* DocumentBrowserViewController.mm */,
+				BE8D77302136762500AC58EA /* DocumentViewController.h */,
+				BE8D77312136762500AC58EA /* DocumentViewController.mm */,
+				BE8D77332136762500AC58EA /* Document.h */,
+				BE8D77342136762500AC58EA /* Document.mm */,
+				BE8D77362136762500AC58EA /* Main.storyboard */,
+				BE8D77392136762600AC58EA /* Assets.xcassets */,
+				BE8D773B2136762600AC58EA /* LaunchScreen.storyboard */,
+				BE8D773E2136762600AC58EA /* Info.plist */,
+				BE8D773F2136762600AC58EA /* main.m */,
+			);
+			path = Mobile;
+			sourceTree = "<group>";
+		};
+		BEA2835421467F8200848631 /* kit */ = {
+			isa = PBXGroup;
+			children = (
+				BEA283572146945500848631 /* ChildSession.cpp */,
+				BEA2835521467FDD00848631 /* Kit.cpp */,
+			);
+			path = kit;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		BE8D77262136762500AC58EA /* Mobile */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = BE8D77432136762600AC58EA /* Build configuration list for PBXNativeTarget "Mobile" */;
+			buildPhases = (
+				BE8D77232136762500AC58EA /* Sources */,
+				BE8D77242136762500AC58EA /* Frameworks */,
+				BE8D77252136762500AC58EA /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = Mobile;
+			productName = Mobile;
+			productReference = BE8D77272136762500AC58EA /* Mobile.app */;
+			productType = "com.apple.product-type.application";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		BE8D771F2136762500AC58EA /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0940;
+				ORGANIZATIONNAME = Collabora;
+				TargetAttributes = {
+					BE8D77262136762500AC58EA = {
+						CreatedOnToolsVersion = 9.4.1;
+					};
+				};
+			};
+			buildConfigurationList = BE8D77222136762500AC58EA /* Build configuration list for PBXProject "Mobile" */;
+			compatibilityVersion = "Xcode 9.3";
+			developmentRegion = en;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+				Base,
+			);
+			mainGroup = BE8D771E2136762500AC58EA;
+			productRefGroup = BE8D77282136762500AC58EA /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				BE8D77262136762500AC58EA /* Mobile */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+		BE8D77252136762500AC58EA /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BE8D85D6214055F3009F1860 /* rc in Resources */,
+				BE8D85D0214055F3009F1860 /* services in Resources */,
+				BE8D85D4214055F3009F1860 /* fundamentalrc in Resources */,
+				BE8D85C9214055F3009F1860 /* filter in Resources */,
+				BE8D85CD214055F3009F1860 /* registry in Resources */,
+				BE00F8A821396585001CE2D4 /* images in Resources */,
+				BE8D85D3214055F3009F1860 /* welcome.odt in Resources */,
+				BE5EB5DC2140480B00E0826C /* icudt62l.dat in Resources */,
+				BE8D85CE214055F3009F1860 /* oovbaapi.rdb in Resources */,
+				BE00F8A721396585001CE2D4 /* loleaflet-help.html in Resources */,
+				BE8D773D2136762600AC58EA /* LaunchScreen.storyboard in Resources */,
+				BE00F8A121396585001CE2D4 /* bundle.css in Resources */,
+				BE8D85CF214055F3009F1860 /* udkapi.rdb in Resources */,
+				BE8D85D5214055F3009F1860 /* unorc in Resources */,
+				BE8D85D1214055F3009F1860 /* services.rdb in Resources */,
+				BE00F8A021396585001CE2D4 /* loleaflet.html in Resources */,
+				BE8D85CA214055F3009F1860 /* offapi.rdb in Resources */,
+				BE8D773A2136762600AC58EA /* Assets.xcassets in Resources */,
+				BE00F8A521396585001CE2D4 /* l10n in Resources */,
+				BE8D85CC214055F3009F1860 /* config in Resources */,
+				BE00F8A321396585001CE2D4 /* bundle.js in Resources */,
+				BE8D77382136762500AC58EA /* Main.storyboard in Resources */,
+				BE8D85D2214055F3009F1860 /* program in Resources */,
+				BE8D85CB214055F3009F1860 /* share in Resources */,
+				BE00F8A621396585001CE2D4 /* loading.html in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+		BE8D77232136762500AC58EA /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				BE5EB5C4213FE29900E0826C /* Util.cpp in Sources */,
+				BEA283582146945500848631 /* ChildSession.cpp in Sources */,
+				BE5EB5C3213FE29900E0826C /* Session.cpp in Sources */,
+				BE5EB5D22140039100E0826C /* LOOLWSD.cpp in Sources */,
+				BE5EB5C6213FE29900E0826C /* SigUtil.cpp in Sources */,
+				BE5EB5C1213FE29900E0826C /* Log.cpp in Sources */,
+				BE5EB5DA2140363100E0826C /* ios.mm in Sources */,
+				BE5EB5D421400DC100E0826C /* DocumentBroker.cpp in Sources */,
+				BE5EB5CF213FE2D000E0826C /* ClientSession.cpp in Sources */,
+				BE5EB5C2213FE29900E0826C /* SpookyV2.cpp in Sources */,
+				BE8D77402136762600AC58EA /* main.m in Sources */,
+				BE5EB5C8213FE29900E0826C /* FileUtil.cpp in Sources */,
+				BE8D77352136762500AC58EA /* Document.mm in Sources */,
+				BE5EB5CA213FE2B100E0826C /* Socket.cpp in Sources */,
+				BE5EB5C7213FE29900E0826C /* Protocol.cpp in Sources */,
+				BE8D772F2136762500AC58EA /* DocumentBrowserViewController.mm in Sources */,
+				BE5EB5D0213FE2D000E0826C /* TileCache.cpp in Sources */,
+				BE5EB5C5213FE29900E0826C /* MessageQueue.cpp in Sources */,
+				BE5EB5D621401E0F00E0826C /* Storage.cpp in Sources */,
+				BEA2835621467FDD00848631 /* Kit.cpp in Sources */,
+				BE8D77322136762500AC58EA /* DocumentViewController.mm in Sources */,
+				BE8D772C2136762500AC58EA /* AppDelegate.mm in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXVariantGroup section */
+		BE8D77362136762500AC58EA /* Main.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				BE8D77372136762500AC58EA /* Base */,
+			);
+			name = Main.storyboard;
+			sourceTree = "<group>";
+		};
+		BE8D773B2136762600AC58EA /* LaunchScreen.storyboard */ = {
+			isa = PBXVariantGroup;
+			children = (
+				BE8D773C2136762600AC58EA /* Base */,
+			);
+			name = LaunchScreen.storyboard;
+			sourceTree = "<group>";
+		};
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+		BE8D77412136762600AC58EA /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = dwarf;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				ENABLE_TESTABILITY = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"DEBUG=1",
+					"$(inherited)",
+				);
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.4;
+				LOBUILDDIR = "$(SOURCE_ROOT)/../../ios-device";
+				LOSRCDIR = "$(SOURCE_ROOT)/../../ios-device";
+				MTL_ENABLE_DEBUG_INFO = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PNGINSTDIR = "/opt/ios-libpng";
+				POCOINSTDIR = "/opt/ios-poco";
+				SDKROOT = iphoneos;
+			};
+			name = Debug;
+		};
+		BE8D77422136762600AC58EA /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				CLANG_ANALYZER_NONNULL = YES;
+				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+				CLANG_CXX_LIBRARY = "libc++";
+				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_OBJC_ARC = YES;
+				CLANG_ENABLE_OBJC_WEAK = YES;
+				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+				CLANG_WARN_BOOL_CONVERSION = YES;
+				CLANG_WARN_COMMA = YES;
+				CLANG_WARN_CONSTANT_CONVERSION = YES;
+				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+				CLANG_WARN_EMPTY_BODY = YES;
+				CLANG_WARN_ENUM_CONVERSION = YES;
+				CLANG_WARN_INFINITE_RECURSION = YES;
+				CLANG_WARN_INT_CONVERSION = YES;
+				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+				CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+				CLANG_WARN_STRICT_PROTOTYPES = YES;
+				CLANG_WARN_SUSPICIOUS_MOVE = YES;
+				CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+				CLANG_WARN_UNREACHABLE_CODE = YES;
+				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+				CODE_SIGN_IDENTITY = "iPhone Developer";
+				COPY_PHASE_STRIP = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				ENABLE_NS_ASSERTIONS = NO;
+				ENABLE_STRICT_OBJC_MSGSEND = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu11;
+				GCC_NO_COMMON_BLOCKS = YES;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+				GCC_WARN_UNDECLARED_SELECTOR = YES;
+				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+				GCC_WARN_UNUSED_FUNCTION = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				IPHONEOS_DEPLOYMENT_TARGET = 11.4;
+				LOBUILDDIR = "$(SOURCE_ROOT)/../../ios-device";
+				LOSRCDIR = "$(SOURCE_ROOT)/../../ios-device";
+				MTL_ENABLE_DEBUG_INFO = NO;
+				PNGINSTDIR = "/opt/ios-libpng";
+				POCOINSTDIR = "/opt/ios-poco";
+				SDKROOT = iphoneos;
+				VALIDATE_PRODUCT = YES;
+			};
+			name = Release;
+		};
+		BE8D77442136762600AC58EA /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = J4FQ687VJK;
+				ENABLE_BITCODE = NO;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"MOBILEAPP=1",
+					"IOS=IOS",
+					"DISABLE_DYNLOADING=1",
+					"DEBUG=1",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(SOURCE_ROOT)/..",
+					"$(SOURCE_ROOT)/../ios",
+					"$(SOURCE_ROOT)/../kit",
+					"$(SOURCE_ROOT)/../common",
+					"$(SOURCE_ROOT)/../wsd",
+					"$(SOURCE_ROOT)/../net",
+					"$(LOBUILDDIR)/config_host",
+					"$(LOSRCDIR)/include",
+					"$(LOBUILDDIR)/workdir/CustomTarget/ios",
+					"$(PNGINSTDIR)/include",
+					"$(POCOINSTDIR)/include",
+				);
+				INFOPLIST_FILE = Mobile/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				OTHER_CPLUSPLUSFLAGS = (
+					"-x",
+					"objective-c++",
+					"$(OTHER_CFLAGS)",
+				);
+				OTHER_LDFLAGS = (
+					"-filelist",
+					"$(LOBUILDDIR)/workdir/CustomTarget/ios/ios-all-static-libs.list",
+					"-L",
+					"$(PNGINSTDIR)/lib",
+					"-L",
+					"$(POCOINSTDIR)/lib",
+					"-lPocoFoundation",
+					"-lPocoUtil",
+					"-lPocoXML",
+					"-lPocoJSON",
+					"-lPocoNet",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.collabora.office.Mobile;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Debug;
+		};
+		BE8D77452136762600AC58EA /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				CODE_SIGN_STYLE = Automatic;
+				DEVELOPMENT_TEAM = J4FQ687VJK;
+				ENABLE_BITCODE = NO;
+				GCC_PREPROCESSOR_DEFINITIONS = (
+					"MOBILEAPP=1",
+					"IOS=IOS",
+					"DISABLE_DYNLOADING=1",
+				);
+				HEADER_SEARCH_PATHS = (
+					"$(SOURCE_ROOT)/..",
+					"$(SOURCE_ROOT)/../ios",
+					"$(SOURCE_ROOT)/../kit",
+					"$(SOURCE_ROOT)/../common",
+					"$(SOURCE_ROOT)/../wsd",
+					"$(SOURCE_ROOT)/../net",
+					"$(LOBUILDDIR)/config_host",
+					"$(LOSRCDIR)/include",
+					"$(LOBUILDDIR)/workdir/CustomTarget/ios",
+					"$(PNGINSTDIR)/include",
+					"$(POCOINSTDIR)/include",
+				);
+				INFOPLIST_FILE = Mobile/Info.plist;
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+				);
+				OTHER_CPLUSPLUSFLAGS = (
+					"-x",
+					"objective-c++",
+					"$(OTHER_CFLAGS)",
+				);
+				OTHER_LDFLAGS = (
+					"-filelist",
+					"$(LOBUILDDIR)/workdir/CustomTarget/ios/ios-all-static-libs.list",
+					"-L",
+					"$(PNGINSTDIR)/lib",
+					"-L",
+					"$(POCOINSTDIR)/lib",
+					"-lPocoFoundation",
+					"-lPocoUtil",
+					"-lPocoXML",
+					"-lPocoJSON",
+					"-lPocoNet",
+				);
+				PRODUCT_BUNDLE_IDENTIFIER = com.collabora.office.Mobile;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				TARGETED_DEVICE_FAMILY = "1,2";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		BE8D77222136762500AC58EA /* Build configuration list for PBXProject "Mobile" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BE8D77412136762600AC58EA /* Debug */,
+				BE8D77422136762600AC58EA /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		BE8D77432136762600AC58EA /* Build configuration list for PBXNativeTarget "Mobile" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				BE8D77442136762600AC58EA /* Debug */,
+				BE8D77452136762600AC58EA /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = BE8D771F2136762500AC58EA /* Project object */;
+}
diff --git a/Mobile/Mobile/AppDelegate.h b/Mobile/Mobile/AppDelegate.h
new file mode 100644
index 000000000..8ac770b59
--- /dev/null
+++ b/Mobile/Mobile/AppDelegate.h
@@ -0,0 +1,22 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import <UIKit/UIKit.h>
+
+//#define LOK_USE_UNSTABLE_API
+//#import <LibreOfficeKit/LibreOfficeKit.h>
+
+ at interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+ at property (strong, nonatomic) UIWindow *window;
+//@property (nonatomic, assign) LibreOfficeKit *kit;
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
+
diff --git a/Mobile/Mobile/AppDelegate.mm b/Mobile/Mobile/AppDelegate.mm
new file mode 100644
index 000000000..bb0fefe4e
--- /dev/null
+++ b/Mobile/Mobile/AppDelegate.mm
@@ -0,0 +1,78 @@
+// -*- Mode: objc; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import "config.h"
+
+//#define LOK_USE_UNSTABLE_API
+//#import <LibreOfficeKit/LibreOfficeKitInit.h>
+
+#import "AppDelegate.h"
+#import "DocumentBrowserViewController.h"
+#import "DocumentViewController.h"
+#import "Document.h"
+
+ at interface AppDelegate ()
+
+ at end
+
+ at implementation AppDelegate {
+    LibreOfficeKit *_kit;
+}
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
+//    _kit = lok_init_2(nullptr, nullptr);
+
+    return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application {
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application {
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application {
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+- (BOOL)application:(UIApplication *)app openURL:(NSURL *)inputURL options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
+    // Ensure the URL is a file URL
+    if (!inputURL.isFileURL) {
+        return NO;
+    }
+
+    // Reveal / import the document at the URL
+    DocumentBrowserViewController *documentBrowserViewController = (DocumentBrowserViewController *)self.window.rootViewController;
+    [documentBrowserViewController revealDocumentAtURL:inputURL importIfNeeded:YES completion:^(NSURL * _Nullable revealedDocumentURL, NSError * _Nullable error) {
+        if (error) {
+            // Handle the error appropriately
+            NSLog(@"Failed to reveal the document at URL %@ with error: '%@'", inputURL, error);
+            return;
+        }
+
+        // Present the Document View Controller for the revealed URL
+        [documentBrowserViewController presentDocumentAtURL:revealedDocumentURL];
+    }];
+    return YES;
+}
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/Assets.xcassets/AppIcon.appiconset/Contents.json b/Mobile/Mobile/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 000000000..d8db8d65f
--- /dev/null
+++ b/Mobile/Mobile/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,98 @@
+{
+  "images" : [
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "20x20",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "29x29",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "40x40",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "iphone",
+      "size" : "60x60",
+      "scale" : "3x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "20x20",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "29x29",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "40x40",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "76x76",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ipad",
+      "size" : "83.5x83.5",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "ios-marketing",
+      "size" : "1024x1024",
+      "scale" : "1x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/Mobile/Mobile/Assets.xcassets/Contents.json b/Mobile/Mobile/Assets.xcassets/Contents.json
new file mode 100644
index 000000000..da4a164c9
--- /dev/null
+++ b/Mobile/Mobile/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/Mobile/Mobile/Base.lproj/LaunchScreen.storyboard b/Mobile/Mobile/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 000000000..f83f6fd58
--- /dev/null
+++ b/Mobile/Mobile/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" systemVersion="17A277" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--View Controller-->
+        <scene sceneID="EHf-IW-A2E">
+            <objects>
+                <viewController id="01J-lp-oVM" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="53" y="375"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/Mobile/Mobile/Base.lproj/Main.storyboard b/Mobile/Mobile/Base.lproj/Main.storyboard
new file mode 100644
index 000000000..5f41f1abf
--- /dev/null
+++ b/Mobile/Mobile/Base.lproj/Main.storyboard
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
+    <device id="retina4_7" orientation="portrait">
+        <adaptation id="fullscreen"/>
+    </device>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Document Browser View Controller-->
+        <scene sceneID="tne-QT-ifu">
+            <objects>
+                <viewController id="BYZ-38-t0r" customClass="DocumentBrowserViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                        <viewLayoutGuide key="safeArea" id="0fo-ii-Aj5"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="26" y="654"/>
+        </scene>
+        <!--Document View Controller-->
+        <scene sceneID="dkP-xk-x6W">
+            <objects>
+                <viewController storyboardIdentifier="DocumentViewController" id="M2k-L8-Olo" customClass="DocumentViewController" sceneMemberID="viewController">
+                    <view key="view" contentMode="scaleToFill" id="SIE-Uh-Zny">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                        <viewLayoutGuide key="safeArea" id="BoZ-jc-2Y8"/>
+                    </view>
+                </viewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="Rl9-ES-qQn" userLabel="First Responder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="1031" y="654"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/Mobile/Mobile/Document.h b/Mobile/Mobile/Document.h
new file mode 100644
index 000000000..875ec2e80
--- /dev/null
+++ b/Mobile/Mobile/Document.h
@@ -0,0 +1,29 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import <UIKit/UIKit.h>
+
+#define LOK_USE_UNSTABLE_API
+#import <LibreOfficeKit/LibreOfficeKit.h>
+
+#import "Kit.hpp"
+
+ at class DocumentViewController;
+
+ at interface Document : UIDocument {
+ at public
+    JS2OnlineBridge bridge;
+}
+
+ at property (strong) DocumentViewController *viewController;
+
+- (void)send2JS:(const char*)buffer length:(int)length;
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/Document.mm b/Mobile/Mobile/Document.mm
new file mode 100644
index 000000000..14229777d
--- /dev/null
+++ b/Mobile/Mobile/Document.mm
@@ -0,0 +1,118 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import "config.h"
+
+#import "AppDelegate.h"
+#import "Document.h"
+#import "DocumentViewController.h"
+
+#import "Kit.hpp"
+#import "KitHelper.hpp"
+#import "Log.hpp"
+#import "Protocol.hpp"
+
+ at implementation Document
+
+// https://github.com/google/google-api-cpp-client/blob/master/src/googleapis/strings/memutil.cc,
+// Apache licensed
+
+static size_t memspn(const char* s, size_t slen, const char* accept) {
+  const char* p = s;
+  const char* spanp;
+  char c, sc;
+
+cont:
+  c = *p++;
+  if (slen-- == 0) return p - 1 - s;
+  for (spanp = accept; (sc = *spanp++) != '\0';)
+    if (sc == c) goto cont;
+  return p - 1 - s;
+}
+
+static const char* setupSafeNonBinaryCharSpan()
+{
+    static char result[256];
+
+    memset(result, 0, 256);
+    char *p = result;
+    for (char c = ' '; c <= '~'; c++)
+        if (c != '\'' && c != '\\')
+            *p++ = c;
+    return result;
+}
+
+static void send2JS(const char *buffer, int length, void *data)
+{
+    Document *doc = (__bridge Document*) data;
+    [doc send2JS:buffer length:length];
+}
+
+- (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr {
+    // Encode your document with an instance of NSData or NSFileWrapper
+    return [[NSData alloc] init];
+}
+
+- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)errorPtr {
+    Log::initialize("", "trace", false, false, {});
+
+    bridge.registerJSSender(send2JS, (__bridge void*) self);
+
+    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
+                   ^{
+                       lokit_main(std::string([[[self fileURL] absoluteString] UTF8String]), self->bridge);
+                   });
+
+    return YES;
+}
+
+- (void)send2JS:(const char *)buffer length:(int)length {
+    NSLog(@"send to JS: %s", LOOLProtocol::getAbbreviatedMessage(buffer, length).c_str());
+
+    static const char * const safeChar = setupSafeNonBinaryCharSpan();
+
+    NSString *js;
+    // Check if the message is non-binary and doesn't contain any single quotes or backslashes either.
+
+    // Yes, this doesn't accept non-ASCII UTF-8 sequences even if they would be perfectly fine. I
+    // think we don't send any such to this, though?
+
+    if (memspn(buffer, length, safeChar) == length) {
+        js = @"window.TheFakeWebSocket.onmessage({'data': '";
+        js = [js stringByAppendingString: [NSString stringWithCString:buffer encoding:NSASCIIStringEncoding]];
+        js = [js stringByAppendingString:@"'});"];
+        dispatch_async(dispatch_get_main_queue(), ^{
+                [self.viewController.webView evaluateJavaScript:js
+                                              completionHandler:^(id _Nullable obj, NSError * _Nullable error)
+                     {
+                         if (error) {
+                             NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
+                         }
+                     }
+                 ];
+            });
+    } else {
+        js = @"window.TheFakeWebSocket.onmessage({'data': atob('";
+        js = [js stringByAppendingString: [[NSData dataWithBytes:buffer length:length] base64EncodedStringWithOptions:0]];
+        js = [js stringByAppendingString:@"')});"];
+        dispatch_async(dispatch_get_main_queue(), ^{
+                [self.viewController.webView evaluateJavaScript:js
+                                              completionHandler:^(id _Nullable obj, NSError * _Nullable error)
+                     {
+                         if (error) {
+                             NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
+                         }
+                     }
+                 ];
+            });
+    }
+}
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/DocumentBrowserViewController.h b/Mobile/Mobile/DocumentBrowserViewController.h
new file mode 100644
index 000000000..542ab3fbc
--- /dev/null
+++ b/Mobile/Mobile/DocumentBrowserViewController.h
@@ -0,0 +1,17 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import <UIKit/UIKit.h>
+
+ at interface DocumentBrowserViewController : UIDocumentBrowserViewController
+
+- (void)presentDocumentAtURL:(NSURL *)documentURL;
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/DocumentBrowserViewController.mm b/Mobile/Mobile/DocumentBrowserViewController.mm
new file mode 100644
index 000000000..633b4353b
--- /dev/null
+++ b/Mobile/Mobile/DocumentBrowserViewController.mm
@@ -0,0 +1,78 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import "config.h"
+
+#import "DocumentBrowserViewController.h"
+#import "Document.h"
+#import "DocumentViewController.h"
+
+ at interface DocumentBrowserViewController () <UIDocumentBrowserViewControllerDelegate>
+
+ at end
+
+ at implementation DocumentBrowserViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.delegate = self;
+    self.allowsDocumentCreation = YES;
+    self.allowsPickingMultipleItems = NO;
+
+    // Update the style of the UIDocumentBrowserViewController
+    // self.browserUserInterfaceStyle = UIDocumentBrowserUserInterfaceStyleDark;
+    // self.view.tintColor = [UIColor whiteColor];
+
+    // Specify the allowed content types of your application via the Info.plist.
+
+    // Do any additional setup after loading the view, typically from a nib.
+}
+
+- (void)documentBrowser:(UIDocumentBrowserViewController *)controller didRequestDocumentCreationWithHandler:(void (^)(NSURL * _Nullable, UIDocumentBrowserImportMode))importHandler {
+    NSURL *newDocumentURL = nil;
+
+    // Set the URL for the new document here. Optionally, you can present a template chooser before calling the importHandler.
+    // Make sure the importHandler is always called, even if the user cancels the creation request.
+    if (newDocumentURL != nil) {
+        importHandler(newDocumentURL, UIDocumentBrowserImportModeMove);
+    } else {
+        importHandler(newDocumentURL, UIDocumentBrowserImportModeNone);
+    }
+}
+
+-(void)documentBrowser:(UIDocumentBrowserViewController *)controller didPickDocumentURLs:(NSArray<NSURL *> *)documentURLs {
+    NSURL *sourceURL = documentURLs.firstObject;
+    if (!sourceURL) {
+        return;
+    }
+
+    // Present the Document View Controller for the first document that was picked.
+    // If you support picking multiple items, make sure you handle them all.
+    [self presentDocumentAtURL:sourceURL];
+}
+
+- (void)documentBrowser:(UIDocumentBrowserViewController *)controller didImportDocumentAtURL:(NSURL *)sourceURL toDestinationURL:(NSURL *)destinationURL {
+    // Present the Document View Controller for the new newly created document
+    [self presentDocumentAtURL:destinationURL];
+}
+
+- (void)documentBrowser:(UIDocumentBrowserViewController *)controller failedToImportDocumentAtURL:(NSURL *)documentURL error:(NSError * _Nullable)error {
+    // Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user.
+}
+
+- (void)presentDocumentAtURL:(NSURL *)documentURL {
+    UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
+    DocumentViewController *documentViewController = [storyBoard instantiateViewControllerWithIdentifier:@"DocumentViewController"];
+    documentViewController.document = [[Document alloc] initWithFileURL:documentURL];
+    documentViewController.document.viewController = documentViewController;
+    [self presentViewController:documentViewController animated:YES completion:nil];
+}
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/DocumentViewController.h b/Mobile/Mobile/DocumentViewController.h
new file mode 100644
index 000000000..61e317176
--- /dev/null
+++ b/Mobile/Mobile/DocumentViewController.h
@@ -0,0 +1,21 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import <UIKit/UIKit.h>
+#import <WebKit/WebKit.h>
+
+#import "Document.h"
+
+ at interface DocumentViewController : UIViewController
+
+ at property (strong) Document *document;
+ at property (strong) WKWebView *webView;
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/DocumentViewController.mm b/Mobile/Mobile/DocumentViewController.mm
new file mode 100644
index 000000000..83b344850
--- /dev/null
+++ b/Mobile/Mobile/DocumentViewController.mm
@@ -0,0 +1,168 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import "config.h"
+
+#import "DocumentViewController.h"
+
+ at interface DocumentViewController() <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler> {
+    BOOL waitingForInitialLoad;
+}
+
+ at end
+
+ at implementation DocumentViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
+    WKUserContentController *userContentController = [[WKUserContentController alloc] init];
+
+    [userContentController addScriptMessageHandler:self name:@"debug"];
+    [userContentController addScriptMessageHandler:self name:@"lool"];
+    [userContentController addScriptMessageHandler:self name:@"error"];
+
+    configuration.userContentController = userContentController;
+
+    self.webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:configuration];
+    self.webView.translatesAutoresizingMaskIntoConstraints = NO;
+    [self.view addSubview:self.webView];
+
+    self.webView.navigationDelegate = self;
+    self.webView.UIDelegate = self;
+
+    WKWebView *webViewP = self.webView;
+    NSDictionary *views = NSDictionaryOfVariableBindings(webViewP);
+    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[webViewP(>=0)]-0-|"
+                                                                      options:0
+                                                                      metrics:nil
+                                                                        views:views]];
+    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[webViewP(>=0)]-0-|"
+                                                                      options:0
+                                                                      metrics:nil
+                                                                        views:views]];
+
+    NSURL *loleafletURL = [[NSBundle mainBundle] URLForResource:@"loleaflet" withExtension:@"html"];
+    NSURLRequest * myNSURLRequest = [[NSURLRequest alloc]initWithURL:loleafletURL];
+    waitingForInitialLoad = YES;
+    [self.webView loadRequest:myNSURLRequest];
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    [super viewWillAppear:animated];
+
+    // Access the document
+    [self.document openWithCompletionHandler:^(BOOL success) {
+        if (success) {
+            // Display the content of the document
+
+        } else {
+            // Make sure to handle the failed import appropriately, e.g., by presenting an error message to the user.
+        }
+    }];
+}
+
+- (IBAction)dismissDocumentViewController {
+    [self dismissViewControllerAnimated:YES completion:^ {
+        [self.document closeWithCompletionHandler:nil];
+    }];
+}
+
+- (void)webView:(WKWebView *)webView didCommitNavigation:(WKNavigation *)navigation {
+    NSLog(@"didCommitNavigation: %@", navigation);
+}
+
+- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error {
+    NSLog(@"didFailNavigation: %@", navigation);
+}
+
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error {
+    NSLog(@"didFailProvisionalNavigation: %@", navigation);
+}
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
+    NSLog(@"didFinishNavigation: %@", navigation);
+
+    // Huh, this is horrible.
+    if (waitingForInitialLoad) {
+        waitingForInitialLoad = NO;
+        NSString *js;
+
+        js = @"window.postMessage(JSON.stringify({'MessageId': 'Host_PostmessageReady'}), '*');";
+        [webView evaluateJavaScript:js
+                  completionHandler:^(id _Nullable obj, NSError * _Nullable error)
+                 {
+                     if (error) {
+                         NSLog(@"name = %@ error = %@",@"", error.localizedDescription);
+                     }
+                 }
+         ];
+    }
+}
+
+- (void)webView:(WKWebView *)webView didReceiveServerRedirectForProvisionalNavigation:(WKNavigation *)navigation {
+    NSLog(@"didReceiveServerRedirectForProvisionalNavigation: %@", navigation);
+}
+
+- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation {
+    NSLog(@"didStartProvisionalNavigation: %@", navigation);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
+    NSLog(@"decidePolicyForNavigationAction: %@", navigationAction);
+    decisionHandler(WKNavigationActionPolicyAllow);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler {
+    NSLog(@"decidePolicyForNavigationResponse: %@", navigationResponse);
+    decisionHandler(WKNavigationResponsePolicyAllow);
+}
+
+- (WKWebView *)webView:(WKWebView *)webView createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration forNavigationAction:(WKNavigationAction *)navigationAction windowFeatures:(WKWindowFeatures *)windowFeatures {
+    NSLog(@"createWebViewWithConfiguration");
+    return webView;
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
+    NSLog(@"runJavaScriptAlertPanelWithMessage: %@", message);
+    //    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
+    //                                                    message:message
+    //                                                   delegate:nil
+    //                                          cancelButtonTitle:nil
+    //                                          otherButtonTitles:@"OK", nil];
+    //    [alert show];
+    completionHandler();
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL result))completionHandler {
+    NSLog(@"runJavaScriptConfirmPanelWithMessage: %@", message);
+    completionHandler(YES);
+}
+
+- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *result))completionHandler {
+    NSLog(@"runJavaScriptTextInputPanelWithPrompt: %@", prompt);
+    completionHandler(@"Something happened.");
+}
+
+- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
+    if ([message.name isEqualToString:@"error"]) {
+        NSLog(@"Error from WebView: %@", message.body);
+    } else if ([message.name isEqualToString:@"debug"]) {
+        NSLog(@"===== %@", message.body);
+    } else if ([message.name isEqualToString:@"lool"]) {
+        NSLog(@"===== To Online: %@", message.body);
+        self.document->bridge.sendToOnline([[@"child-0001 " stringByAppendingString:(NSString*)message.body] UTF8String]);
+    } else {
+        NSLog(@"Unrecognized kind of message received from WebView: %@: %@", message.name, message.body);
+    }
+}
+
+ at end
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/Mobile/Mobile/Info.plist b/Mobile/Mobile/Info.plist
new file mode 100644
index 000000000..b142a9205
--- /dev/null
+++ b/Mobile/Mobile/Info.plist
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>$(DEVELOPMENT_LANGUAGE)</string>
+	<key>CFBundleDocumentTypes</key>
+	<array>
+		<dict>
+			<key>CFBundleTypeIconFiles</key>
+			<array/>
+			<key>CFBundleTypeName</key>
+			<string>Plain Text</string>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>LSHandlerRank</key>
+			<string>Alternate</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>public.text</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleTypeIconFiles</key>
+			<array/>
+			<key>CFBundleTypeName</key>
+			<string>OpenDocument Text</string>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>LSHandlerRank</key>
+			<string>Owner</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>org.oasis-open.opendocument.text</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleTypeIconFiles</key>
+			<array/>
+			<key>CFBundleTypeName</key>
+			<string>Microsoft Word Document</string>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>LSHandlerRank</key>
+			<string>Alternate</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>com.microsoft.word.doc</string>
+			</array>
+		</dict>
+		<dict>
+			<key>CFBundleTypeIconFiles</key>
+			<array/>
+			<key>CFBundleTypeName</key>
+			<string>OpenDocument Spreadsheet</string>
+			<key>CFBundleTypeRole</key>
+			<string>Editor</string>
+			<key>LSHandlerRank</key>
+			<string>Owner</string>
+			<key>LSItemContentTypes</key>
+			<array>
+				<string>org.oasis-open.opendocument.spreadsheet</string>
+			</array>
+		</dict>
+	</array>
+	<key>CFBundleExecutable</key>
+	<string>$(EXECUTABLE_NAME)</string>
+	<key>CFBundleIdentifier</key>
+	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+	<key>CFBundleInfoDictionaryVersion</key>
+	<string>6.0</string>
+	<key>CFBundleName</key>
+	<string>$(PRODUCT_NAME)</string>
+	<key>CFBundlePackageType</key>
+	<string>APPL</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1</string>
+	<key>LSRequiresIPhoneOS</key>
+	<true/>
+	<key>UILaunchStoryboardName</key>
+	<string>LaunchScreen</string>
+	<key>UIMainStoryboardFile</key>
+	<string>Main</string>
+	<key>UIRequiredDeviceCapabilities</key>
+	<array>
+		<string>armv7</string>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationPortrait</string>
+		<string>UIInterfaceOrientationPortraitUpsideDown</string>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportsDocumentBrowser</key>
+	<true/>
+	<key>UTExportedTypeDeclarations</key>
+	<array>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.data</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>OpenDocument Text</string>
+			<key>UTTypeIconFiles</key>
+			<array/>
+			<key>UTTypeIdentifier</key>
+			<string>org.oasis-open.opendocument.text</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<string>odt</string>
+			</dict>
+		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.data</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>OpenDocument Spreadsheet</string>
+			<key>UTTypeIconFiles</key>
+			<array/>
+			<key>UTTypeIdentifier</key>
+			<string>org.oasis-open.opendocument.spreadsheet</string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<string>ods</string>
+			</dict>
+		</dict>
+	</array>
+	<key>UTImportedTypeDeclarations</key>
+	<array>
+		<dict/>
+	</array>
+</dict>
+</plist>
diff --git a/Mobile/Mobile/main.m b/Mobile/Mobile/main.m
new file mode 100644
index 000000000..001200608
--- /dev/null
+++ b/Mobile/Mobile/main.m
@@ -0,0 +1,18 @@
+// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#import <UIKit/UIKit.h>
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[]) {
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/common/Util.cpp b/common/Util.cpp
index b193304c1..25a7be80b 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -145,6 +145,7 @@ namespace Util
         return newTmp;
     }
 
+#ifndef MOBILEAPP
     int getProcessThreadCount()
     {
         DIR *fdDir = opendir("/proc/self/task");
@@ -247,6 +248,7 @@ namespace Util
         }
         return pid;
     }
+#endif
 
     bool dataFromHexString(const std::string& hexString, std::vector<unsigned char>& data)
     {
@@ -304,6 +306,7 @@ namespace Util
         return nullptr;
     }
 
+#ifndef MOBILEAPP
     std::string getHumanizedBytes(unsigned long nBytes)
     {
         constexpr unsigned factor = 1024;
@@ -461,6 +464,7 @@ namespace Util
         }
         return 0;
     }
+#endif
 
     std::string replace(std::string result, const std::string& a, const std::string& b)
     {
diff --git a/common/Util.hpp b/common/Util.hpp
index c6df31ab5..75ceea529 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -53,6 +53,7 @@ namespace Util
     /// Create randomized temporary directory
     std::string createRandomTmpDir();
 
+#ifndef MOBILEAPP
     /// Get number of threads in this process or -1 on error
     int getProcessThreadCount();
 
@@ -60,6 +61,7 @@ namespace Util
     /// to send data to the child.
     int spawnProcess(const std::string &cmd, const std::vector<std::string> &args,
                      int *stdInput = nullptr);
+#endif
 
     /// Hex to unsigned char
     bool dataFromHexString(const std::string& hexString, std::vector<unsigned char>& data);
@@ -114,6 +116,7 @@ namespace Util
 #endif
     }
 
+#ifndef MOBILEAPP
     /// Print given number of bytes in human-understandable form (KB,MB, etc.)
     std::string getHumanizedBytes(unsigned long nBytes);
 
@@ -133,6 +136,7 @@ namespace Util
     size_t getCpuUsage(const Poco::Process::PID pid);
 
     size_t getStatFromPid(const Poco::Process::PID pid, int ind);
+#endif
 
     std::string replace(std::string s, const std::string& a, const std::string& b);
 
diff --git a/ios/ios.h b/ios/ios.h
new file mode 100644
index 000000000..fb7a68dc7
--- /dev/null
+++ b/ios/ios.h
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+extern const char* getCacheDir();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/ios/ios.mm b/ios/ios.mm
new file mode 100644
index 000000000..e608627c6
--- /dev/null
+++ b/ios/ios.mm
@@ -0,0 +1,25 @@
+// -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
+//
+// This file is part of the LibreOffice project.
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <cstring>
+
+#import <Foundation/Foundation.h>
+
+extern "C" {
+#import <native-code.h>
+}
+
+const char* getCacheDir()
+{
+    static NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
+    static const char* result = strdup([cachePath UTF8String]);
+
+    return result;
+}
+
+// vim:set shiftwidth=4 softtabstop=4 expandtab:
diff --git a/kit/ChildSession.cpp b/kit/ChildSession.cpp
index d56a81597..d5324f4ad 100644
--- a/kit/ChildSession.cpp
+++ b/kit/ChildSession.cpp
@@ -213,6 +213,14 @@ bool ChildSession::_handleInput(const char *buffer, int length)
     {
         assert(false && "Tile traffic should go through the DocumentBroker-LoKit WS.");
     }
+#ifdef MOBILEAPP
+    else if (tokens[0] == "requestloksession" ||
+             tokens[0] == "canceltiles")
+    {
+        // Just ignore these.
+        // FIXME: We probably should do something for "canceltiles" at least?
+    }
+#endif
     else
     {
         // All other commands are such that they always require a LibreOfficeKitDocument session,
diff --git a/kit/ChildSession.hpp b/kit/ChildSession.hpp
index b1cd90133..b690d95cd 100644
--- a/kit/ChildSession.hpp
+++ b/kit/ChildSession.hpp
@@ -159,16 +159,24 @@ public:
 
     bool sendTextFrame(const char* buffer, int length) override
     {
+#ifndef MOBILEAPP
         const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
         const std::unique_lock<std::mutex> lock = getLock();
         return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Text);
+#else
+        return _docManager.sendFrame(buffer, length, WSOpCode::Text);
+#endif
     }
 
     bool sendBinaryFrame(const char* buffer, int length) override
     {
+#ifndef MOBILEAPP
         const auto msg = "client-" + getId() + ' ' + std::string(buffer, length);
         const std::unique_lock<std::mutex> lock = getLock();
         return _docManager.sendFrame(msg.data(), msg.size(), WSOpCode::Binary);
+#else
+        return _docManager.sendFrame(buffer, length, WSOpCode::Text);
+#endif
     }
 
     using Session::sendTextFrame;
diff --git a/kit/Kit.cpp b/kit/Kit.cpp
index dc792b865..278000392 100644
--- a/kit/Kit.cpp
+++ b/kit/Kit.cpp
@@ -68,8 +68,10 @@
 #include <Util.hpp>
 #include "Delta.hpp"
 
+#ifndef MOBILEAPP
 #include <common/SigUtil.hpp>
 #include <common/Seccomp.hpp>
+#endif
 
 #ifdef FUZZER
 #include <kit/DummyLibreOfficeKit.hpp>
@@ -102,6 +104,10 @@ using namespace LOOLProtocol;
 class Document;
 static std::shared_ptr<Document> document;
 
+#ifdef MOBILEAPP
+static JS2OnlineBridge *theBridge;
+#endif
+
 #if ENABLE_DEBUG
 #  define ADD_DEBUG_RENDERID(s) ((s)+ " renderid=" + Util::UniqueId())
 #else
@@ -814,7 +820,9 @@ public:
             return false;
         }
 
-        _socketPoll.addCallback([=] { _websocketHandler->sendMessage(message->data(), message->size(), code); });
+        _socketPoll.addCallback([=]{
+                _websocketHandler->sendMessage(message->data(), message->size(), code);
+            });
         return true;
     }
 
@@ -1137,11 +1145,17 @@ public:
 
     bool sendTextFrame(const std::string& message)
     {
+#ifndef MOBILEAPP
         return sendFrame(message.data(), message.size());
+#else
+        theBridge->sendToJS(message.data(), message.size());
+        return true;
+#endif
     }
 
     bool sendFrame(const char* buffer, int length, WSOpCode opCode = WSOpCode::Text) override
     {
+#ifndef MOBILEAPP
         try
         {
             std::shared_ptr<std::vector<char>> message = std::make_shared<std::vector<char>>();
@@ -1155,8 +1169,11 @@ public:
             LOG_ERR("Document::sendFrame: Exception: " << exc.displayText() <<
                     (exc.nested() ? "( " + exc.nested()->displayText() + ")" : ""));
         }
-
         return false;
+#else
+        theBridge->sendToJS(buffer, length);
+        return true;
+#endif
     }
 
     static void GlobalCallback(const int type, const char* p, void* data)
@@ -1806,12 +1823,12 @@ private:
         Util::setThreadName("lokit_" + _docId);
 
         LOG_DBG("Thread started.");
-
+#ifndef MOBILEAPP
         // Update memory stats and editor every 5 seconds.
         const int memStatsPeriodMs = 5000;
         auto lastMemStatsTime = std::chrono::steady_clock::now();
         sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
-
+#endif
         try
         {
             while (!_stop && !TerminationFlag)
@@ -1819,6 +1836,7 @@ private:
                 const TileQueue::Payload input = _tileQueue->get(POLL_TIMEOUT_MS * 2);
                 if (input.empty())
                 {
+#ifndef MOBILEAPP
                     auto duration = (std::chrono::steady_clock::now() - lastMemStatsTime);
                     std::chrono::milliseconds::rep durationMs = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
                     if (durationMs > memStatsPeriodMs)
@@ -1826,6 +1844,7 @@ private:
                         sendTextFrame(Util::getMemoryStats(ProcSMapsFile));
                         lastMemStatsTime = std::chrono::steady_clock::now();
                     }
+#endif
                     continue;
                 }
 
@@ -2035,6 +2054,12 @@ protected:
     {
         std::string message(data.data(), data.size());
 
+        handleMessage(message);
+    }
+
+    void handleMessage(const std::string& message) override
+    {
+
 #if 0 // FIXME might be needed for unit tests #ifndef KIT_IN_PROCESS
         if (UnitKit::get().filterKitMessage(ws, message))
         {
@@ -2092,11 +2117,13 @@ protected:
         }
         else if (tokens.size() == 3 && tokens[0] == "setconfig")
         {
+#ifndef MOBILEAPP
             // Currently onlly rlimit entries are supported.
             if (!Rlimit::handleSetrlimitCommand(tokens))
             {
                 LOG_ERR("Unknown setconfig command: " << message);
             }
+#endif
         }
         else
         {
@@ -2116,11 +2143,11 @@ void documentViewCallback(const int type, const char* payload, void* data)
     Document::ViewCallback(type, payload, data);
 }
 
-#ifndef MOBILEAPP
-
 #ifndef BUILDING_TESTS
 
-void lokit_main(const std::string& childRoot,
+void lokit_main(
+#ifndef MOBILEAPP
+                const std::string& childRoot,
                 const std::string& jailId,
                 const std::string& sysTemplate,
                 const std::string& loTemplate,
@@ -2128,8 +2155,15 @@ void lokit_main(const std::string& childRoot,
                 bool noCapabilities,
                 bool noSeccomp,
                 bool queryVersion,
-                bool displayVersion)
+                bool displayVersion
+#else
+                const std::string& documentUri,
+                JS2OnlineBridge& bridge
+#endif
+                )
 {
+#ifndef MOBILEAPP
+
 #ifndef FUZZER
     SigUtil::setFatalSignals();
     SigUtil::setTerminationSignals();
@@ -2174,8 +2208,12 @@ void lokit_main(const std::string& childRoot,
     std::shared_ptr<lok::Office> loKit;
     Path jailPath;
     bool bRunInsideJail = !noCapabilities;
+
+#endif // MOBILEAPP
+
     try
     {
+#ifndef MOBILEAPP
         jailPath = Path::forDirectory(childRoot + "/" + jailId);
         LOG_INF("Jail path: " << jailPath.toString());
         File(jailPath).createDirectories();
@@ -2366,8 +2404,38 @@ void lokit_main(const std::string& childRoot,
             free(versionInfo);
         }
 
+#else // MOBILEAPP
+
+        LibreOfficeKit *kit = lok_init_2(nullptr, nullptr);
+
+        std::shared_ptr<lok::Office> loKit = std::make_shared<lok::Office>(kit);
+        if (!loKit)
+        {
+            LOG_FTL("LibreOfficeKit initialization failed. Exiting.");
+            std::_Exit(Application::EXIT_SOFTWARE);
+        }
+
+        // Dummies
+        Poco::URI uri;
+        const std::string jailId;
+        const std::string pid;
+
+#endif // MOBILEAPP
+
         SocketPoll mainKit("kit");
 
+#ifdef MOBILEAPP
+        // Ugly, but not ay uglier than the singleton 'document' variable.
+        theBridge = &bridge;
+        theBridge->registerSocket(mainKit);
+        std::thread([&] {
+                theBridge->sendToOnline("session 0001 foo 0001");
+                // No jailing in the mobile app, just use the same URI for the "jail" parameter to
+                // the "load" command, too.
+                theBridge->sendToOnline("child-0001 load url=" + documentUri + " jail=" + documentUri);
+            }).detach();
+#endif
+
         mainKit.insertNewWebSocketSync(uri, std::make_shared<KitWebSocketHandler>("child_ws_" + pid, loKit, jailId, mainKit));
         LOG_INF("New kit client websocket inserted.");
 
@@ -2396,14 +2464,20 @@ void lokit_main(const std::string& childRoot,
         LOG_ERR("Exception: " << exc.what());
     }
 
+#ifndef MOBILEAPP
+
     // Trap the signal handler, if invoked,
     // to prevent exiting.
     LOG_INF("Process finished.");
     std::unique_lock<std::mutex> lock(SigHandlerTrap);
     std::_Exit(Application::EXIT_OK);
+
+#endif
 }
 #endif
 
+#ifndef MOBILEAPP
+
 /// Initializes LibreOfficeKit for cross-fork re-use.
 bool globalPreinit(const std::string &loTemplate)
 {
diff --git a/kit/Kit.hpp b/kit/Kit.hpp
index ac80b4869..b2c768baa 100644
--- a/kit/Kit.hpp
+++ b/kit/Kit.hpp
@@ -14,7 +14,45 @@
 
 #include <common/Util.hpp>
 
-void lokit_main(const std::string& childRoot,
+#ifdef MOBILEAPP
+
+#include "Socket.hpp"
+
+class JS2OnlineBridge
+{
+public:
+    void registerSocket(SocketPoll& socketPoll)
+    {
+        _SocketPoll = &socketPoll;
+    }
+
+    void registerJSSender(void (*function)(const char *, int, void *), void *data)
+    {
+        _JSCallbackFunction = function;
+        _JSCallbackData = data;
+    }
+
+    void sendToOnline(const std::string& payload)
+    {
+        _SocketPoll->feed(payload);
+    }
+
+    void sendToJS(const char *data, int length)
+    {
+        _JSCallbackFunction(data, length, _JSCallbackData);
+    }
+
+private:
+    SocketPoll *_SocketPoll;
+    void (*_JSCallbackFunction)(const char *, int, void *);
+    void *_JSCallbackData;
+};
+
+#endif
+
+void lokit_main(
+#ifndef MOBILEAPP
+                const std::string& childRoot,
                 const std::string& jailId,
                 const std::string& sysTemplate,
                 const std::string& loTemplate,
@@ -22,7 +60,12 @@ void lokit_main(const std::string& childRoot,
                 bool noCapabilities,
                 bool noSeccomp,
                 bool queryVersionInfo,
-                bool displayVersion);
+                bool displayVersion
+#else
+                const std::string& documentUri,
+                JS2OnlineBridge& bridge
+#endif
+                );
 
 bool globalPreinit(const std::string& loTemplate);
 /// Wrapper around private Document::ViewCallback().
diff --git a/net/Socket.cpp b/net/Socket.cpp
index 38bacdde8..74a0dff16 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -74,6 +74,8 @@ SocketPoll::SocketPoll(const std::string& threadName)
 
     std::lock_guard<std::mutex> lock(getPollWakeupsMutex());
     getWakeupsArray().push_back(_wakeup[1]);
+#else
+    _bufferEmpty = true;
 #endif
 }
 
@@ -136,6 +138,21 @@ void SocketPoll::joinThread()
 
 #endif
 
+#ifdef MOBILEAPP
+
+void SocketPoll::feed(const std::string& payload)
+{
+    std::unique_lock<std::mutex> lock(_bufferMutex);
+    if (!_bufferEmpty)
+        _bufferCV.wait(lock, [&]{return _bufferEmpty;});
+    _buffer = payload;
+    _bufferEmpty = false;
+    lock.unlock();
+    _bufferCV.notify_one();
+}
+
+#endif
+
 void SocketPoll::wakeupWorld()
 {
 #ifndef MOBILEAPP
@@ -231,6 +248,8 @@ void SocketPoll::insertNewWebSocketSync(const Poco::URI &uri, const std::shared_
     }
     else
         LOG_ERR("Failed to lookup client websocket host '" << uri.getHost() << "' skipping");
+#else
+    _socketHandler = websocketHandler;
 #endif
 }
 
diff --git a/net/Socket.hpp b/net/Socket.hpp
index 2a336f8fc..074734ca9 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -31,7 +31,6 @@
 #include <mutex>
 #include <sstream>
 #include <thread>
-#include <atomic>
 
 #include "Common.hpp"
 #include "Log.hpp"
@@ -341,6 +340,10 @@ public:
 
     /// Append pretty printed internal state to a line
     virtual void dumpState(std::ostream& os) { os << "\n"; }
+
+    virtual void handleMessage(const std::string& /*message*/)
+    {
+    }
 };
 
 /// Handles non-blocking socket event polling.
@@ -528,9 +531,18 @@ public:
 
             disposition.execute();
         }
+#else
+        std::unique_lock<std::mutex> lock(_bufferMutex);
+        if (_bufferEmpty)
+            _bufferCV.wait(lock, [&]{return !_bufferEmpty;});
+        _socketHandler->handleMessage(_buffer);
+        _bufferEmpty = true;
+        lock.unlock();
+        _bufferCV.notify_one();
 #endif
     }
 
+#ifndef MOBILEAPP
     /// Write to a wakeup descriptor
     static void wakeup (int fd)
     {
@@ -543,15 +555,18 @@ public:
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
             LOG_SYS("wakeup socket #" << fd << " is closed at wakeup?");
     }
+#endif
 
     /// Wakeup the main polling loop in another thread
     void wakeup()
     {
+#ifndef MOBILEAPP
         if (!isAlive())
             LOG_WRN("Waking up dead poll thread [" << _name << "], started: " <<
                     _threadStarted << ", finished: " << _threadFinished);
 
         wakeup(_wakeup[1]);
+#endif
     }
 
     /// Global wakeup - signal safe: wakeup all socket polls.
@@ -618,7 +633,15 @@ public:
     /// Stop and join the polling thread before returning (if active)
     void joinThread();
 
+#ifdef MOBILEAPP
+    // In the mobile app(s), a SocketPoll doesn't actually "poll" any "sockets" but simply acts as a
+    // conduit for sending messages that correspond to what we would receive as WebSocket messages
+    // in the server online from the app code into the shared online code.
+    void feed(const std::string& payload);
+#endif
+
 private:
+#ifndef MOBILEAPP
     /// Initialize the poll fds array with the right events
     void setupPollFds(std::chrono::steady_clock::time_point now,
                       int &timeoutMaxMs)
@@ -648,6 +671,7 @@ private:
         _pollFds[size].events = POLLIN;
         _pollFds[size].revents = 0;
     }
+#endif
 
     /// The polling thread entry.
     /// Used to set the thread name and mark the thread as stopped when done.
@@ -681,8 +705,10 @@ private:
     /// Debug name used for logging.
     const std::string _name;
 
+#ifndef MOBILEAPP
     /// main-loop wakeup pipe
     int _wakeup[2];
+#endif
     /// The sockets we're controlling
     std::vector<std::shared_ptr<Socket>> _pollSockets;
     /// Protects _newSockets
@@ -700,6 +726,14 @@ protected:
     std::atomic<bool> _threadStarted;
     std::atomic<bool> _threadFinished;
     std::thread::id _owner;
+
+#ifdef MOBILEAPP
+    std::mutex _bufferMutex;
+    std::condition_variable _bufferCV;
+    bool _bufferEmpty;
+    std::string _buffer;
+    std::shared_ptr<SocketHandlerInterface> _socketHandler;
+#endif
 };
 
 /// A plain, non-blocking, data streaming socket.
diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp
index 3e1faabb4..0bb0ddc1f 100644
--- a/net/WebSocketHandler.hpp
+++ b/net/WebSocketHandler.hpp
@@ -133,6 +133,7 @@ public:
         if (len == 0)
             return false; // avoid logging.
 
+#ifndef MOBILEAPP
         if (len < 2) // partial read
         {
             LOG_TRC("#" << socket->getFD() << ": Still incomplete WebSocket message, have " << len << " bytes");
@@ -200,11 +201,20 @@ public:
                 *wsData++ = data[i] ^ mask[i % 4];
         } else
             _wsPayload.insert(_wsPayload.end(), data, data + payloadLen);
+#else
+        unsigned char * const p = reinterpret_cast<unsigned char*>(&socket->_inBuffer[0]);
+        _wsPayload.insert(_wsPayload.end(), p, p + len);
+        const size_t headerLen = 0;
+        const size_t payloadLen = len;
+        const bool hasMask = false;
+#endif
 
         assert(_wsPayload.size() >= payloadLen);
 
         socket->_inBuffer.erase(socket->_inBuffer.begin(), socket->_inBuffer.begin() + headerLen + payloadLen);
 
+#ifndef MOBILEAPP
+
         // FIXME: fin, aggregating payloads into _wsPayload etc.
         LOG_TRC("#" << socket->getFD() << ": Incoming WebSocket message code " << static_cast<unsigned>(code) <<
                 ", fin? " << fin << ", mask? " << hasMask << ", payload length: " << _wsPayload.size() <<
@@ -253,6 +263,12 @@ public:
             break;
         }
 
+#else
+        handleMessage(true, WSOpCode::Binary, _wsPayload);
+
+#endif
+
+#ifndef MOBILEAPP
         if (doClose)
         {
             if (!_shuttingDown)
@@ -280,6 +296,7 @@ public:
             // TCP Close.
             socket->closeConnection();
         }
+#endif
 
         _wsPayload.clear();
 
diff --git a/wsd/DocumentBroker.hpp b/wsd/DocumentBroker.hpp
index 863a3d664..c52cbf243 100644
--- a/wsd/DocumentBroker.hpp
+++ b/wsd/DocumentBroker.hpp
@@ -57,6 +57,7 @@ public:
 class ChildProcess
 {
 public:
+#ifndef MOBILEAPP
     /// @param pid is the process ID of the child.
     /// @param socket is the underlying Sockeet to the child.
     ChildProcess(const Poco::Process::PID pid,
@@ -71,6 +72,16 @@ public:
     {
         LOG_INF("ChildProcess ctor [" << _pid << "].");
     }
+#else
+    ChildProcess(const std::shared_ptr<WebSocketHandler>& ws) :
+        _pid(0),
+        _jailId(""),
+        _ws(ws)
+    {
+        LOG_INF("ChildProcess ctor.");
+    }
+#endif
+
 
     ChildProcess(ChildProcess&& other) = delete;
 
@@ -78,6 +89,7 @@ public:
 
     ~ChildProcess()
     {
+#ifndef MOBILEAPP
         if (_pid <= 0)
             return;
 
@@ -87,7 +99,7 @@ public:
         // No need for the socket anymore.
         _ws.reset();
         _socket.reset();
-
+#endif
     }
 
     void setDocumentBroker(const std::shared_ptr<DocumentBroker>& docBroker);
@@ -96,6 +108,7 @@ public:
     /// Let the child close a nice way.
     void close()
     {
+#ifndef MOBILEAPP
         if (_pid < 0)
             return;
 
@@ -120,11 +133,13 @@ public:
         }
 
         _pid = -1;
+#endif
     }
 
     /// Kill or abandon the child.
     void terminate()
     {
+#ifndef MOBILEAPP
         if (_pid < 0)
             return;
 
@@ -138,6 +153,7 @@ public:
         }
 
         _pid = -1;
+#endif
     }
 
     Poco::Process::PID getPid() const { return _pid; }
@@ -171,6 +187,7 @@ public:
     /// time after the other end-point closes. So this isn't accurate.
     bool isAlive() const
     {
+#ifndef MOBILEAPP
         try
         {
             return _pid > 1 && _ws && ::kill(_pid, 0) == 0;
@@ -180,13 +197,18 @@ public:
         }
 
         return false;
+#else
+        return true;
+#endif
     }
 
 private:
     Poco::Process::PID _pid;
     const std::string _jailId;
     std::shared_ptr<WebSocketHandler> _ws;
+#ifndef MOBILEAP
     std::shared_ptr<Socket> _socket;
+#endif
     std::weak_ptr<DocumentBroker> _docBroker;
 };
 


More information about the Libreoffice-commits mailing list