aboutsummaryrefslogtreecommitdiff
path: root/src/OutgoingMessage.cpp
blob: e7749403aa5663b40125827ca6ec92f27dfcc195 (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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#include "../include/dchat/OutgoingMessage.hpp"
#include <assert.h>

namespace dchat
{
    namespace OutgoingMessage
    {
        enum class Token
        {
            NONE,
            END_OF_FILE,

            TEXT,
            BIND
        };

        struct Tokenizer
        {
            Tokenizer(const char *_text, usize _size, const EmojiBindMap *_emojiBindMap)
            {
                assert(_text);
                assert(_emojiBindMap);
                text = _text;
                size = _size;
                index = 0;
                emoji = nullptr;
                emojiBindMap = _emojiBindMap;
                textRange = { 0, 0 };
            }

            // returns -1 if character can't be found in the string
            usize find(const char *str, usize size, char c) const
            {
                for(usize i = 0; i < size; ++i)
                {
                    if(str[i] == c)
                        return i;
                }
                return -1;
            }

            // Return nullptr if bind is not found
            const std::string* getBindEmoji(const char *text, usize size) const
            {
                // TODO: unecessary conversion to string, convert emojibindmap to const char* and uses custom hasher
                auto it = emojiBindMap->find(std::string(text, size));
                if(it != emojiBindMap->end())
                    return &it->second;
                return nullptr;
            }

            Token next()
            {
                if(index >= size)
                    return Token::END_OF_FILE;

                char c = getChar();
                usize start = index;
                ++index;
                if(c == ':')
                {
                    while(index < size)
                    {
                        c = getChar();
                        ++index;
                        if(c == ':')
                        {
                            usize end = index - 1;
                            const std::string *_emoji = getBindEmoji(text + start + 1, end - (start + 1));
                            if(_emoji)
                            {
                                emoji = _emoji;
                                return Token::BIND;
                            }
                            break;
                        }
                    }

                    textRange.start = start;
                    textRange.end = index;
                    return Token::TEXT;
                }
                else
                {
                    while(index < size)
                    {
                        c = getChar();
                        if(c == ':')
                            break;
                        ++index;
                    }

                    textRange.start = start;
                    textRange.end = index;
                    return Token::TEXT;
                }

                assert(false);
                return Token::NONE;
            }

            char getChar() const
            {
                assert(index < size);
                return text[index];
            }

            const char *text;
            usize size;
            usize index;
            const std::string *emoji;
            const EmojiBindMap *emojiBindMap;

            Range textRange;
        };
    }

    void parseOutgoingMessage(const char *text, usize size, const EmojiBindMap &emojiBindMap, std::function<void(OutgoingMessagePart)> callbackFunc)
    {
        OutgoingMessage::Tokenizer tokenizer(text, size, &emojiBindMap);
        OutgoingMessage::Token token = tokenizer.next();
        while(token != OutgoingMessage::Token::END_OF_FILE)
        {
            if(token == OutgoingMessage::Token::TEXT)
            {
                callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::TEXT, tokenizer.textRange });
                token = tokenizer.next();
            }
            else if(token == OutgoingMessage::Token::BIND)
            {
                callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::EMOJI, tokenizer.emoji });
                token = tokenizer.next();
            }
        }
    }
}