Skip to content

Commit

Permalink
Far2l TTY clipboard ID - to cache clipboard content to avoid its redu…
Browse files Browse the repository at this point in the history
…ndant network transfer
  • Loading branch information
elfmz committed Dec 1, 2021
1 parent 2ab632e commit 9b4f961
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 6 deletions.
116 changes: 113 additions & 3 deletions WinPort/src/Backend/TTY/TTYFar2lClipboardBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,75 @@ void TTYFar2lClipboardBackend::Far2lInterract(StackSerializer &stk_ser, bool wai
}
}

uint64_t TTYFar2lClipboardBackend::GetDataID(UINT format)
{
if (_fallback_backend || !_data_id_supported) {
return 0;
}

uint64_t out = 0;
try {
StackSerializer stk_ser;
stk_ser.PushPOD(format);
stk_ser.PushPOD('i');
Far2lInterract(stk_ser, true);
stk_ser.PopPOD(out);

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::GetDataID: %s\n", e.what());
_data_id_supported = false;
out = 0;
}

return out;
}

void *TTYFar2lClipboardBackend::GetCachedData(UINT format)
{
std::lock_guard<std::mutex> lock(_cache);

auto cache_it = _cache.find(format);
if (cache_it == _cache.end()) {
return nullptr;
}

const uint64_t id = GetDataID(format);
if (id && id == cache_it->second.id) {
#if (__WCHAR_MAX__ <= 0xffff)
if (format == CF_UNICODETEXT) { // UTF32 -> UTF16
uint32_t len = cache_it->second.id.len;
return UtfConverter<uint32_t, uint16_t>
((const uint32_t*)cache_it->second.data.data(), len / sizeof(uint32_t)).MallocedCopy(len);
}
#endif
unsigned char *data = (unsigned char *)malloc(cache_it->second.data.size());
if (data) {
memcpy(data, cache_it->second.data.data(), cache_it->second.data.size());
return data;
}
}

_cache.erase(cache_it);
return nullptr;
}

void TTYFar2lClipboardBackend::SetCachedData(UINT format, const void *data, uint32_t len, uint64_t id)
{
std::lock_guard<std::mutex> lock(_cache);
try {
CachedData &cd = _cache[format];
cd.id = id;
cd.data.resize(len);
memcpy(cd.data.data(), data, len);

} catch(std::exception &e) {
fprintf(stderr,
"TTYFar2lClipboardBackend::SetCachedData(0x%u, %p, %u, 0x%llx): %s\n",
format, data, len, (unsigned long long)id, e.what());
_cache.erase(format);
}
}

bool TTYFar2lClipboardBackend::OnClipboardOpen()
{
if (_fallback_backend) {
Expand Down Expand Up @@ -121,6 +190,9 @@ void TTYFar2lClipboardBackend::OnClipboardEmpty()
stk_ser.PushPOD('e');
Far2lInterract(stk_ser, false);

std::lock_guard<std::mutex> lock(_cache);
_cache.clear();

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardEmpty: %s\n", e.what());
}
Expand All @@ -140,6 +212,9 @@ bool TTYFar2lClipboardBackend::OnClipboardIsFormatAvailable(UINT format)
if (stk_ser.PopChar() == 1)
return true;

std::lock_guard<std::mutex> lock(_cache);
_cache.erase(format);

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardIsFormatAvailable: %s\n", e.what());
}
Expand All @@ -149,6 +224,7 @@ bool TTYFar2lClipboardBackend::OnClipboardIsFormatAvailable(UINT format)
void *TTYFar2lClipboardBackend::OnClipboardSetData(UINT format, void *data)
{
if (_fallback_backend) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardSetData(0x%x): fallback\n", format);
return _fallback_backend->OnClipboardSetData(format, data);
}

Expand All @@ -174,8 +250,22 @@ void *TTYFar2lClipboardBackend::OnClipboardSetData(UINT format, void *data)
stk_ser.PushPOD(format);
stk_ser.PushPOD('s');
Far2lInterract(stk_ser, true);
if (stk_ser.PopChar() == 1)
if (stk_ser.PopChar() == 1) {
if (_data_id_supported) {
try {
uint64_t id = 0;
stk_ser.PopPOD(id);
if (id) {
SetCachedData(format, data, len, id);
}

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardSetData: ID failed - %s\n", e.what());
_data_id_supported = false;
}
}
return data;
}

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardSetData: %s\n", e.what());
Expand All @@ -186,10 +276,17 @@ void *TTYFar2lClipboardBackend::OnClipboardSetData(UINT format, void *data)
void *TTYFar2lClipboardBackend::OnClipboardGetData(UINT format)
{
if (_fallback_backend) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardGetData(0x%x): fallback\n", format);
return _fallback_backend->OnClipboardGetData(format);
}

void *data = nullptr;
void *data = GetCachedData(format);
if (data) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardGetData(0x%x): cache hit\n", format);
return data;
}
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardGetData(0x%x): cache miss\n", format);

try {
StackSerializer stk_ser;
stk_ser.PushPOD(format);
Expand All @@ -200,16 +297,29 @@ void *TTYFar2lClipboardBackend::OnClipboardGetData(UINT format)
data = malloc(len);
if (data) {
stk_ser.Pop(data, len);
if (_data_id_supported) {
try {
uint64_t id = 0;
stk_ser.PopPOD(id);
if (id) {
SetCachedData(format, data, len, id);
}

} catch (std::exception &e) {
fprintf(stderr, "TTYFar2lClipboardBackend::OnClipboardGetData::ID: %s\n", e.what());
_data_id_supported = false;
}
}
#if (__WCHAR_MAX__ <= 0xffff)
if (format == CF_UNICODETEXT) { // UTF32 -> UTF16
void *new_data = UtfConverter<uint32_t, uint16_t>
((const uint32_t*)data, len / sizeof(uint32_t)).MallocedCopy(len);
if (new_data != nullptr) {
free(data);
data = new_data;
}
}
#endif

return data;
}
}
Expand Down
12 changes: 12 additions & 0 deletions WinPort/src/Backend/TTY/TTYFar2lClipboardBackend.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <atomic>
#include <mutex>
#include <StackSerializer.h>
#include "WinCompat.h"
#include "Backend.h"
Expand All @@ -10,11 +11,22 @@

class TTYFar2lClipboardBackend : public IClipboardBackend
{
struct CachedData
{
uint64_t id;
std::vector<unsigned char> data;
};
struct Cache : std::mutex, std::map<UINT, CachedData> { } _cache;

std::unique_ptr<FSClipboardBackend> _fallback_backend;
IFar2lInterractor *_interractor;
std::string _client_id;
bool _data_id_supported = true;

void Far2lInterract(StackSerializer &stk_ser, bool wait);
uint64_t GetDataID(UINT format);
void *GetCachedData(UINT format);
void SetCachedData(UINT format, const void *data, uint32_t len, uint64_t id);

public:
TTYFar2lClipboardBackend(IFar2lInterractor *interractor);
Expand Down
51 changes: 48 additions & 3 deletions far2l/VTFar2lExtensios.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <assert.h>
#include <base64.h>
#include <crc64.h>
#include <utils.h>
#include <UtfConvert.hpp>
#include <fcntl.h>
Expand Down Expand Up @@ -64,6 +65,21 @@ static void ListFileAppend(const std::string &filename, std::string line)

}

static uint64_t CalculateDataID(UINT fmt, const void *data, uint32_t len)
{
if (fmt == CF_UNICODETEXT) {
len = wcsnlen((const wchar_t *)data, len / sizeof(wchar_t)) * sizeof(wchar_t);
}
uint64_t id = len;
if (len) {
id = crc64(id, (const unsigned char*)data, len);
}
if (id == 0) { // zero means failure, but its not failed
id = 1;
}
return id;
}

///

VTFar2lExtensios::VTFar2lExtensios(IVTShell *vt_shell)
Expand Down Expand Up @@ -272,6 +288,7 @@ void VTFar2lExtensios::OnInterract_ClipboardIsFormatAvailable(StackSerializer &s
void VTFar2lExtensios::OnInterract_ClipboardSetData(StackSerializer &stk_ser)
{
char out = -1;
uint64_t id = 0;
if (_clipboard_opens > 0) {
UINT fmt;
uint32_t len;
Expand All @@ -296,10 +313,15 @@ void VTFar2lExtensios::OnInterract_ClipboardSetData(StackSerializer &stk_ser)
data = nullptr;

out = WINPORT(SetClipboardData)(fmt, data) ? 1 : 0;
if (out == 1) {
id = CalculateDataID(fmt, data, GetMallocSize(data));
}
}
stk_ser.Clear();
if (out == 1) {
stk_ser.PushPOD(id);
}
stk_ser.PushPOD(out);

}

void VTFar2lExtensios::OnInterract_ClipboardGetData(StackSerializer &stk_ser)
Expand All @@ -309,9 +331,15 @@ void VTFar2lExtensios::OnInterract_ClipboardGetData(StackSerializer &stk_ser)

UINT fmt;
stk_ser.PopPOD(fmt);
void *data = allowed ? WINPORT(GetClipboardData)(fmt) : nullptr;
stk_ser.Clear();
uint32_t len = data ? GetMallocSize(data) : 0;
void *data = allowed ? WINPORT(GetClipboardData)(fmt) : nullptr;
uint64_t id = 0;
uint32_t len = 0;
if (data) {
len = GetMallocSize(data);
id = CalculateDataID(fmt, data, len);
}
stk_ser.PushPOD(id);
if (len) {
#if (__WCHAR_MAX__ <= 0xffff)
void *new_data = nullptr;
Expand All @@ -335,6 +363,22 @@ void VTFar2lExtensios::OnInterract_ClipboardGetData(StackSerializer &stk_ser)
}
}

void VTFar2lExtensios::OnInterract_ClipboardGetDataID(StackSerializer &stk_ser)
{
uint64_t id = 0;
if (_clipboard_opens > 0 && IsAllowedClipboardRead()) {
UINT fmt = 0;
stk_ser.PopPOD(fmt);
void *data = WINPORT(GetClipboardData)(fmt);
if (data) {
id = CalculateDataID(fmt, data, GetMallocSize(data));
}
}

stk_ser.Clear();
stk_ser.PushPOD(id);
}

void VTFar2lExtensios::OnInterract_ClipboardRegisterFormat(StackSerializer &stk_ser)
{
const std::wstring &fmt_name = StrMB2Wide(stk_ser.PopStr());
Expand All @@ -356,6 +400,7 @@ void VTFar2lExtensios::OnInterract_Clipboard(StackSerializer &stk_ser)
case 'a': OnInterract_ClipboardIsFormatAvailable(stk_ser); break;
case 's': OnInterract_ClipboardSetData(stk_ser); break;
case 'g': OnInterract_ClipboardGetData(stk_ser); break;
case 'i': OnInterract_ClipboardGetDataID(stk_ser); break;
case 'r': OnInterract_ClipboardRegisterFormat(stk_ser); break;

default:
Expand Down
1 change: 1 addition & 0 deletions far2l/VTFar2lExtensios.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class VTFar2lExtensios
void OnInterract_ClipboardIsFormatAvailable(StackSerializer &stk_ser);
void OnInterract_ClipboardSetData(StackSerializer &stk_ser);
void OnInterract_ClipboardGetData(StackSerializer &stk_ser);
void OnInterract_ClipboardGetDataID(StackSerializer &stk_ser);
void OnInterract_ClipboardRegisterFormat(StackSerializer &stk_ser);
void OnInterract_Clipboard(StackSerializer &stk_ser);
void OnInterract_GetLargestWindowSize(StackSerializer &stk_ser);
Expand Down

0 comments on commit 9b4f961

Please sign in to comment.