libreoffice-online/ios/Mobile/CODocument.mm
Tor Lillqvist 6d2a6e110c Remove leftover tiles in the iOS app already when the document is closed
Normally (ideally), tiles (.bmp files) are removed as soon as the JS
has displayed them. But occasionally something goes wrong and they are
left behind. (For instance, it seems to happen if the user closes the
document immediately when it shows up.)

Do not leave them on disk until the app starts the next time.

Change-Id: I0c764280a69a16ad3b7b67c329832fd5331c2e1e
Signed-off-by: Tor Lillqvist <tml@collabora.com>
2021-09-01 13:32:23 +03:00

135 lines
5.5 KiB
Text

// -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*-
//
// 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 <algorithm>
// This is not "external" code in the UNO-based extensions sense. To be able to include
// <comphelper/lok.hxx>, we must #define LIBO_INTERNAL_ONLY.
#define LIBO_INTERNAL_ONLY
#include <sal/config.h>
#include <sal/log.hxx>
#include <rtl/ustring.hxx>
#include <comphelper/lok.hxx>
#include <i18nlangtag/languagetag.hxx>
#import "ios.h"
#import "AppDelegate.h"
#import "CODocument.h"
#import "DocumentViewController.h"
#import "ClientSession.hpp"
#import "DocumentBroker.hpp"
#import "FakeSocket.hpp"
#import "Kit.hpp"
#import "KitHelper.hpp"
#import "Log.hpp"
#import "LOOLWSD.hpp"
#import "MobileApp.hpp"
#import "Protocol.hpp"
@implementation CODocument
- (id)contentsForType:(NSString*)typeName error:(NSError **)errorPtr {
return [NSData dataWithContentsOfFile:[copyFileURL path] options:0 error:errorPtr];
}
// We keep a running count of opening documents here. This is not necessarily in sync with the
// DocBrokerId in DocumentBroker due to potential parallelism when opening multiple documents in
// quick succession.
static std::atomic<unsigned> appDocIdCounter(1);
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)errorPtr {
// If this method is called a second time on the same CODocument object, just ignore it. This
// seems to happen occasionally when the device is awakened after sleep. See tdf#122543.
if (fakeClientFd >= 0)
return YES;
fakeClientFd = fakeSocketSocket();
appDocId = appDocIdCounter++;
NSURL *copyFileDirectory = [[NSFileManager.defaultManager temporaryDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:@"%d", appDocId]];
if (![NSFileManager.defaultManager createDirectoryAtURL:copyFileDirectory withIntermediateDirectories:YES attributes:nil error:nil]) {
LOG_ERR("Could not create directory " << [[copyFileDirectory path] UTF8String]);
return NO;
}
copyFileURL = [copyFileDirectory URLByAppendingPathComponent:[[[self fileURL] path] lastPathComponent]];
NSError *error;
[[NSFileManager defaultManager] removeItemAtURL:copyFileURL error:nil];
[[NSFileManager defaultManager] copyItemAtURL:[self fileURL] toURL:copyFileURL error:&error];
if (error != nil)
return NO;
NSURL *url = [[NSBundle mainBundle] URLForResource:@"loleaflet" withExtension:@"html"];
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
DocumentData::allocate(appDocId).coDocument = self;
components.queryItems = @[ [NSURLQueryItem queryItemWithName:@"file_path" value:[copyFileURL absoluteString]],
[NSURLQueryItem queryItemWithName:@"closebutton" value:@"1"],
[NSURLQueryItem queryItemWithName:@"permission" value:@"edit"],
[NSURLQueryItem queryItemWithName:@"lang" value:app_locale],
[NSURLQueryItem queryItemWithName:@"appdocid" value:[NSString stringWithFormat:@"%u", appDocId]],
[NSURLQueryItem queryItemWithName:@"userinterfacemode" value:([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad ? @"notebookbar" : @"classic")],
];
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:components.URL];
[self.viewController.webView loadRequest:request];
return YES;
}
- (void)send2JS:(const char *)buffer length:(int)length {
LOG_TRC("To JS: " << LOOLProtocol::getAbbreviatedMessage(buffer, length).c_str());
NSString *js;
const unsigned char *ubufp = (const unsigned char *)buffer;
std::vector<char> data;
for (int i = 0; i < length; i++) {
if (ubufp[i] < ' ' || ubufp[i] == '\'' || ubufp[i] == '\\') {
data.push_back('\\');
data.push_back('x');
data.push_back("0123456789abcdef"[(ubufp[i] >> 4) & 0x0F]);
data.push_back("0123456789abcdef"[ubufp[i] & 0x0F]);
} else {
data.push_back(ubufp[i]);
}
}
data.push_back(0);
js = @"window.TheFakeWebSocket.onmessage({'data': '";
js = [js stringByAppendingString:[NSString stringWithUTF8String:data.data()]];
js = [js stringByAppendingString:@"'});"];
NSString *subjs = [js substringToIndex:std::min(100ul, js.length)];
if (subjs.length < js.length)
subjs = [subjs stringByAppendingString:@"..."];
// LOG_TRC("Evaluating JavaScript: " << [subjs UTF8String]);
dispatch_async(dispatch_get_main_queue(), ^{
[self.viewController.webView evaluateJavaScript:js
completionHandler:^(id _Nullable obj, NSError * _Nullable error)
{
if (error) {
LOG_ERR("Error after " << [subjs UTF8String] << ": " << [[error localizedDescription] UTF8String]);
NSString *jsException = error.userInfo[@"WKJavaScriptExceptionMessage"];
if (jsException != nil)
LOG_ERR("JavaScript exception: " << [jsException UTF8String]);
}
}
];
});
}
@end
// vim:set shiftwidth=4 softtabstop=4 expandtab: