summaryrefslogtreecommitdiff
path: root/emojis.cpp
blob: 6e9a293b650772eabbf315b0092896e401819bc2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include "emojis.hpp"
#include <sstream>

EmojiResource::EmojiResource(std::string filepath)
    : m_filepath(filepath) {}

bool EmojiResource::Load() {
    m_fp = std::fopen(m_filepath.c_str(), "rb");
    if (m_fp == nullptr) return false;
    int index_pos;
    std::fread(&index_pos, 4, 1, m_fp);
    std::fseek(m_fp, index_pos, SEEK_SET);
    int num_entries;
    std::fread(&num_entries, 4, 1, m_fp);
    for (int i = 0; i < num_entries; i++) {
        static int strsize, len, pos;
        std::fread(&strsize, 4, 1, m_fp);
        std::vector<char> str(strsize);
        std::fread(str.data(), strsize, 1, m_fp);
        std::fread(&len, 4, 1, m_fp);
        std::fread(&pos, 4, 1, m_fp);
        m_index[std::string(str.begin(), str.end())] = std::make_pair(pos, len);
        m_patterns.push_back(HexToPattern(Glib::ustring(str.begin(), str.end())));
    }
    std::sort(m_patterns.begin(), m_patterns.end(), [](const Glib::ustring &a, const Glib::ustring &b) {
        return a.size() > b.size();
    });
    return true;
}

Glib::RefPtr<Gdk::Pixbuf> EmojiResource::GetPixBuf(const Glib::ustring &pattern) {
    Glib::ustring key = PatternToHex(pattern);
    const auto it = m_index.find(key);
    if (it == m_index.end()) return Glib::RefPtr<Gdk::Pixbuf>();
    const int pos = it->second.first;
    const int len = it->second.second;
    std::fseek(m_fp, pos, SEEK_SET);
    std::vector<uint8_t> data(len);
    std::fread(data.data(), len, 1, m_fp);
    auto loader = Gdk::PixbufLoader::create();
    loader->write(static_cast<const guint8 *>(data.data()), data.size());
    loader->close();
    return loader->get_pixbuf();
}

Glib::ustring EmojiResource::PatternToHex(const Glib::ustring &pattern) {
    Glib::ustring ret;
    for (int i = 0; i < pattern.size(); i++) {
        auto c = pattern.at(i);
        ret += Glib::ustring::format(std::hex, c);
        ret += "-";
    }
    return ret.substr(0, ret.size() - 1);
}

Glib::ustring EmojiResource::HexToPattern(Glib::ustring hex) {
    std::vector<Glib::ustring> parts;
    Glib::ustring::size_type pos = 0;
    Glib::ustring token;
    while ((pos = hex.find("-")) != Glib::ustring::npos) {
        token = hex.substr(0, pos);
        if (token.length() % 2 == 1)
            token = "0" + token;
        parts.push_back(token);
        hex.erase(0, pos + 1);
    }
    parts.push_back(hex);
    Glib::ustring ret;
    for (const auto &part : parts) {
        auto x = static_cast<gunichar>(std::stoul(part.c_str(), nullptr, 16));
        ret += x;
    }
    return ret;
}
void EmojiResource::ReplaceEmojis(Glib::RefPtr<Gtk::TextBuffer> buf, int size) {
    auto get_text = [&]() -> auto {
        Gtk::TextBuffer::iterator a, b;
        buf->get_bounds(a, b);
        return buf->get_slice(a, b, true);
    };
    auto text = get_text();

    int searchpos;
    for (const auto &pattern : m_patterns) {
        searchpos = 0;
        Glib::RefPtr<Gdk::Pixbuf> pixbuf;
        while (true) {
            size_t r = text.find(pattern, searchpos);
            if (r == Glib::ustring::npos) break;
            if (!pixbuf) {
                pixbuf = GetPixBuf(pattern);
                if (pixbuf)
                    pixbuf = pixbuf->scale_simple(size, size, Gdk::INTERP_BILINEAR);
                else
                    break;
            }
            searchpos = r + pattern.size();

            const auto start_it = buf->get_iter_at_offset(r);
            const auto end_it = buf->get_iter_at_offset(r + pattern.size());

            auto it = buf->erase(start_it, end_it);
            buf->insert_pixbuf(it, pixbuf);

            int alen = text.size();
            text = get_text();
            int blen = text.size();
            searchpos -= (alen - blen);
        }
    }
}

const std::vector<Glib::ustring> &EmojiResource::GetPatterns() const {
    return m_patterns;
}