Subversion Repositories tpanel

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4 andreas 1
/*
99 andreas 2
 * Copyright (C) 2020 to 2022 by Andreas Theofilu <andreas@theosys.at>
4 andreas 3
 *
4
 * This program is free software; you can redistribute it and/or modify
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * This program is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU General Public License
15
 * along with this program; if not, write to the Free Software Foundation,
16
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
17
 */
18
 
19
#include <include/core/SkBitmap.h>
20
#include <include/core/SkData.h>
21
#include <include/core/SkImage.h>
22
#include <include/core/SkImageGenerator.h>
23
#include <include/core/SkStream.h>
57 andreas 24
#include <include/core/SkFont.h>
4 andreas 25
#include <include/core/SkTypeface.h>
179 andreas 26
#include <include/core/SkColorSpace.h>
365 andreas 27
#include <include/codec/SkCodec.h>
4 andreas 28
 
11 andreas 29
#include <iconv.h>
71 andreas 30
#include <libgen.h>
11 andreas 31
 
125 andreas 32
#include <sys/types.h>
33
#include <sys/stat.h>
34
 
4 andreas 35
#include "tresources.h"
197 andreas 36
#include "tpagemanager.h"
431 andreas 37
#include "tcrc32.h"
4 andreas 38
#include "terror.h"
39
#include "tconfig.h"
40
 
186 andreas 41
#if __cplusplus < 201402L
42
#   error "This module requires at least C++14 standard!"
43
#else
44
#   if __cplusplus < 201703L
45
#       include <experimental/filesystem>
46
namespace fs = std::experimental::filesystem;
47
#       warning "Support for C++14 and experimental filesystem will be removed in a future version!"
48
#   else
49
#       include <filesystem>
50
#       ifdef __ANDROID__
51
namespace fs = std::__fs::filesystem;
52
#       else
53
namespace fs = std::filesystem;
54
#       endif
55
#   endif
56
#endif
57
 
4 andreas 58
using std::string;
361 andreas 59
using std::wstring;
4 andreas 60
using std::endl;
11 andreas 61
using std::vector;
4 andreas 62
 
197 andreas 63
extern TPageManager *gPageManager;
64
 
11 andreas 65
typedef struct
66
{
67
    unsigned char ch;
70 andreas 68
    unsigned int byte;
11 andreas 69
}CHTABLE;
70
 
71
static CHTABLE __cht[] = {
70 andreas 72
    {0x80,	0xE282AC},
73
    {0x81,	0x0081},    // not used
74
    {0x82,	0xE2809A},
75
    {0x83,	0x0192},    // not used
76
    {0x84,	0xE2809E},
77
    {0x85,	0xE280A6},
78
    {0x86,	0xE280A0},
79
    {0x87,	0xE280A1},
80
    {0x88,	0x02C6},    // not used
81
    {0x89,	0xE280B0},
82
    {0x8A,	0xC5A0},
83
    {0x8B,	0xE280B9},
84
    {0x8C,	0xC59A},
85
    {0x8D,	0xC5A4},
86
    {0x8E,	0xC5BD},
87
    {0x8F,	0xC5B9},
88
    {0x90,	0x0090},    // not used
89
    {0x91,	0xE28098},
90
    {0x92,	0xE28099},
91
    {0x93,	0xE2809C},
92
    {0x94,	0xE2809D},
93
    {0x95,	0xE280A2},
94
    {0x96,	0xE28093},
95
    {0x97,	0xE28094},
96
    {0x98,	0x02DC},    // not used
97
    {0x99,	0xE284A2},
98
    {0x9A,	0xC5A1},
99
    {0x9B,	0xE280BA},
100
    {0x9C,	0xC59B},
101
    {0x9D,	0xC5A5},
102
    {0x9E,	0xC5BE},
103
    {0x9F,	0xC5BA},
104
    {0xA0,	0xC2A0},
105
    {0xA1,	0xCB87},
106
    {0xA2,	0xCB98},
107
    {0xA3,	0xC581},
108
    {0xA4,	0xC2A0},
109
    {0xA5,	0xC484},
110
    {0xA6,	0xC2A6},
111
    {0xA7,	0xC2A7},
112
    {0xA8,	0xC2A8},
113
    {0xA9,	0xC2A9},
114
    {0xAA,	0xC59E},
115
    {0xAB,	0xC2AB},
116
    {0xAC,	0xC2AC},
117
    {0xAD,	0xC2AD},
118
    {0xAE,	0xC2AE},
119
    {0xAF,	0xC5BB},
120
    {0xB0,	0xC2B0},
121
    {0xB1,	0xC2B1},
122
    {0xB2,	0xCB9B},
123
    {0xB3,	0xC582},
124
    {0xB4,	0xC2B4},
125
    {0xB5,	0xC2B5},
126
    {0xB6,	0xC2B6},
127
    {0xB7,	0xC2B7},
128
    {0xB8,	0xC2B8},
129
    {0xB9,	0xC485},
130
    {0xBA,	0xC59F},
131
    {0xBB,	0xC2BB},
132
    {0xBC,	0xC4BD},
133
    {0xBD,	0xCB9D},
134
    {0xBE,	0xC4BE},
135
    {0xBF,	0xC5BC},
136
    {0xC0,	0xC594},
137
    {0xC1,	0xC381},
138
    {0xC2,	0xC382},
139
    {0xC3,	0xC482},
140
    {0xC4,	0xC384},
141
    {0xC5,	0xC4B9},
142
    {0xC6,	0xC486},
143
    {0xC7,	0xC387},
144
    {0xC8,	0xC48C},
145
    {0xC9,	0xC389},
146
    {0xCA,	0xC489},
147
    {0xCB,	0xC38b},
148
    {0xCC,	0xC49A},
149
    {0xCD,	0xC38D},
150
    {0xCE,	0xC38E},
151
    {0xCF,	0xC48E},
152
    {0xD0,	0xC490},
153
    {0xD1,	0xC583},
154
    {0xD2,	0xC587},
155
    {0xD3,	0xC398},
156
    {0xD4,	0xC394},
157
    {0xD5,	0xC590},
158
    {0xD6,	0xC396},
159
    {0xD7,	0xC397},
160
    {0xD8,	0xC598},
161
    {0xD9,	0xC5AE},
162
    {0xDA,	0xC39A},
163
    {0xDB,	0xC5B0},
164
    {0xDC,	0xC39C},
165
    {0xDD,	0xC39D},
166
    {0xDE,	0xC5A2},
167
    {0xDF,	0xC39F},
168
    {0xE0,	0xC595},
169
    {0xE1,	0xC3A1},
170
    {0xE2,	0xC3A2},
171
    {0xE3,	0xC483},
172
    {0xE4,	0xC3A4},
173
    {0xE5,	0xC4BA},
174
    {0xE6,	0xC487},
175
    {0xE7,	0xC3A7},
176
    {0xE8,	0xC48D},
177
    {0xE9,	0xC3A9},
178
    {0xEA,	0xC499},
179
    {0xEB,	0xC3AB},
180
    {0xEC,	0xC49B},
181
    {0xED,	0xC3AD},
182
    {0xEE,	0xC3AE},
183
    {0xEF,	0xC48F},
184
    {0xF0,	0xC491},
185
    {0xF1,	0xC584},
186
    {0xF2,	0xC588},
187
    {0xF3,	0xC3B3},
188
    {0xF4,	0xC3B4},
189
    {0xF5,	0xC591},
190
    {0xF6,	0xC3B6},
191
    {0xF7,	0xC3B7},
192
    {0xF8,	0xC599},
193
    {0xF9,	0xC5AF},
194
    {0xFA,	0xC3BA},
195
    {0xFB,	0xC5B1},
196
    {0xFC,	0xC3BC},
197
    {0xFD,	0xC3BD},
198
    {0xFE,	0xC5A3},
199
    {0xFF,	0xCB99}
11 andreas 200
};
201
 
156 andreas 202
SkString GetResourcePath(const char* resource, _RESOURCE_TYPE rs)
4 andreas 203
{
163 andreas 204
    if (!resource)
205
        return SkString();
206
 
330 andreas 207
//    if (*resource == '/')       // absolute path?
208
    if (strstr(resource, "/") != NULL && !endsWith(resource, "/"))
163 andreas 209
    {                           // yes, then take it as it is
210
        return SkString(resource);
211
    }
212
 
156 andreas 213
    string pth;
67 andreas 214
 
156 andreas 215
    switch(rs)
216
    {
217
        case RESTYPE_BORDER:    pth = "/borders/"; break;
218
        case RESTYPE_CURSOR:    pth = "/cursors/"; break;
219
        case RESTYPE_FONT:      pth = "/fonts/"; break;
220
        case RESTYPE_UNKNOWN:
221
        case RESTYPE_IMAGE:     pth = "/images/"; break;
161 andreas 222
        case RESTYPE_SLIDER:    pth = "/sliders/"; break;
223
        case RESTYPE_SYSBORDER: pth = "/__system/graphics/borders/"; break;
224
        case RESTYPE_SYSCURSOR: pth = "/__system/graphics/cursors/"; break;
225
        case RESTYPE_SYSFONT:   pth = "/__system/graphics/fonts/"; break;
226
        case RESTYPE_SYSIMAGE:  pth = "/__system/graphics/images/"; break;
227
        case RESTYPE_SYSSLIDER: pth = "/__system/graphics/sliders/"; break;
156 andreas 228
    }
229
 
197 andreas 230
    string projectPath = ((gPageManager && gPageManager->isSetupActive()) ? TConfig::getSystemProjectPath() : TConfig::getProjectPath());
186 andreas 231
    string path = projectPath + pth + resource;
4 andreas 232
    return SkString(path);
233
}
234
 
235
bool DecodeDataToBitmap(sk_sp<SkData> data, SkBitmap* dst)
236
{
365 andreas 237
    DECL_TRACER("DecodeDataToBitmap(sk_sp<SkData> data, SkBitmap* dst)");
238
 
262 andreas 239
    if (!data || !dst)
240
        return false;
241
 
365 andreas 242
//    std::unique_ptr<SkImageGenerator> gen(SkImageGenerators::MakeFromEncoded(std::move(data)));
243
//    return gen && dst->tryAllocPixels(gen->getInfo()) &&
244
//           gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst->getPixels(), dst->rowBytes());
245
 
246
 
247
    std::unique_ptr<SkCodec> codec = SkCodec::MakeFromData(std::move(data));
248
 
249
    if (!codec)
250
        return false;
251
 
252
    SkImageInfo info = codec->getInfo();
253
 
254
    if(dst->tryAllocPixels(info))
255
    {
256
        if(codec->getPixels(info, dst->getPixels(), dst->rowBytes()) == SkCodec::kSuccess)
257
            return true;
258
    }
259
 
260
    return false;
4 andreas 261
}
262
 
156 andreas 263
std::unique_ptr<SkStreamAsset> GetResourceAsStream(const char* resource, _RESOURCE_TYPE rs)
4 andreas 264
{
156 andreas 265
    sk_sp<SkData> data = GetResourceAsData(resource, rs);
4 andreas 266
    return data ? std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data)))
267
    : nullptr;
268
}
269
 
156 andreas 270
sk_sp<SkData> GetResourceAsData(const char* resource, _RESOURCE_TYPE rs)
4 andreas 271
{
365 andreas 272
    DECL_TRACER("GetResourceAsData(const char* resource, _RESOURCE_TYPE rs)");
273
 
163 andreas 274
    SkString str = GetResourcePath(resource, rs);
262 andreas 275
 
163 andreas 276
    sk_sp<SkData> data = SkData::MakeFromFileName(str.c_str());
277
 
278
    if (data)
4 andreas 279
        return data;
280
 
163 andreas 281
    MSG_ERROR("GetResourceAsData: Resource \"" << str.c_str() << "\" not found.");
4 andreas 282
    TError::setError();
283
#ifdef SK_TOOLS_REQUIRE_RESOURCES
6 andreas 284
    SK_ABORT("GetResourceAsData: missing resource");
4 andreas 285
#endif
286
    return nullptr;
287
}
288
 
156 andreas 289
sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource, int ttcIndex, _RESOURCE_TYPE rs)
4 andreas 290
{
156 andreas 291
    return SkTypeface::MakeFromStream(GetResourceAsStream(resource, rs), ttcIndex);
4 andreas 292
}
6 andreas 293
 
294
/*
295
 * Read the image from a file and save it into a data buffer. This is the base
296
 * to convert the image.
297
 */
298
sk_sp<SkData> readImage(const string& fname)
299
{
365 andreas 300
    DECL_TRACER("readImage(const string& fname)");
301
 
424 andreas 302
    if (fname.empty())
303
    {
304
        MSG_ERROR("readImage: Empty file name!");
305
        TError::setError();
306
        return nullptr;
307
    }
308
 
6 andreas 309
    sk_sp<SkData> data = GetResourceAsData(fname.c_str());
310
 
311
    if (!data)
312
    {
424 andreas 313
        MSG_ERROR("readImage: Error loading the image \"" << fname << "\"");
6 andreas 314
        TError::setError();
315
    }
316
 
317
    return data;
318
}
11 andreas 319
 
254 andreas 320
SkBitmap *allocPixels(int width, int height, SkBitmap *bm)
321
{
322
    DECL_TRACER("TButton::allocPixels(int width, int height, SkBitmap *bm)");
323
 
324
    if (!bm)
325
        return nullptr;
326
 
327
    // Skia reads image files in the natural byte order of the CPU.
328
    // While on Intel CPUs the byte order is little endian it is
329
    // mostly big endian on other CPUs. This means that the order of
260 andreas 330
    // the colors is RGB on big endian CPUs (ARM, ...) and BGR on others.
331
    // To compensate this, we check the endianess of the CPU and set
332
    // the byte order according.
333
    SkImageInfo info;
334
 
335
    if (isBigEndian())
336
        info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
337
    else
338
        info = SkImageInfo::Make(width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
339
 
254 andreas 340
    if (!bm->tryAllocPixels(info))
341
    {
342
        MSG_ERROR("Error allocating " << (width * height) << " pixels!");
343
        return nullptr;
344
    }
345
 
346
    return bm;
347
}
348
 
349
SkColor reverseColor(const SkColor& col)
350
{
351
    DECL_TRACER("reverseColor(const SkColor& col)");
352
 
353
    int red = SkColorGetR(col);
354
    int green = SkColorGetG(col);
355
    int blue = SkColorGetB(col);
356
    int alpha = SkColorGetA(col);
357
 
358
    return SkColorSetARGB(alpha, blue, green, red);
359
}
360
 
11 andreas 361
vector<string> StrSplit(const string& str, const string& seps, const bool trimEmpty)
362
{
363
    size_t pos = 0, mark = 0;
364
    vector<string> parts;
365
    string::const_iterator it, sepIt;
366
 
96 andreas 367
    if (str.empty())
368
        return parts;
369
 
11 andreas 370
    for (it = str.begin(); it != str.end(); ++it)
371
    {
372
        for (sepIt = seps.begin(); sepIt != seps.end(); ++sepIt)
373
        {
21 andreas 374
            if (pos > 0 && *it == *sepIt)
11 andreas 375
            {
376
                size_t len = pos - mark;
21 andreas 377
 
96 andreas 378
                if (len > 0 && *sepIt != '\n')
21 andreas 379
                    parts.push_back(str.substr(mark, len));
96 andreas 380
                else if (len > 0)
381
                    parts.push_back(str.substr(mark, len) + "\n");
164 andreas 382
                else if (*sepIt == '\n')
383
                    parts.push_back("\n");
21 andreas 384
                else
385
                    parts.push_back(string());
386
 
11 andreas 387
                mark = pos + 1;
388
                break;
389
            }
21 andreas 390
            else if (*it == *sepIt)
96 andreas 391
            {
392
                if (*sepIt == '\n')
393
                    parts.push_back("\n");
394
 
21 andreas 395
                mark = pos + 1;
96 andreas 396
            }
11 andreas 397
        }
398
 
399
        pos++;
400
    }
401
 
402
    parts.push_back(str.substr(mark));
403
 
404
    if (trimEmpty)
405
    {
406
        vector<string> nparts;
407
 
96 andreas 408
        for (auto iter = parts.begin(); iter != parts.end(); ++iter)
11 andreas 409
        {
96 andreas 410
            if (iter->empty())
11 andreas 411
                continue;
412
 
96 andreas 413
            nparts.push_back(*iter);
11 andreas 414
        }
415
 
416
        return nparts;
417
    }
418
 
419
    return parts;
420
}
421
 
422
string latin1ToUTF8(const string& str)
423
{
424
    DECL_TRACER("NameFormat::latin1ToUTF8(const string& str)");
425
    string out;
426
 
427
    for (size_t i = 0; i < str.length(); i++)
428
    {
429
        uint8_t ch = str.at(i);
430
 
431
        if (ch < 0x80)
432
        {
433
            out.push_back(ch);
434
        }
435
        else
436
        {
437
            out.push_back(0xc0 | ch >> 6);
438
            out.push_back(0x80 | (ch & 0x3f));
439
        }
440
    }
441
 
442
    return out;
443
}
444
 
445
string cp1250ToUTF8(const string& str)
446
{
447
    DECL_TRACER("cp1250ToUTF8(const string& str)");
448
 
449
    string out;
450
 
451
    for (size_t j = 0; j < str.length(); j++)
452
    {
453
        int i = -1;
454
        unsigned char ch = str.at(j);
70 andreas 455
        unsigned int utf = 0x80000000;
11 andreas 456
 
70 andreas 457
        if (ch >= 0x80)
11 andreas 458
        {
459
            do
460
            {
461
                i++;
462
 
463
                if (__cht[i].ch == ch)
464
                {
465
                    utf = __cht[i].byte;
466
                    break;
467
                }
468
            }
469
            while (__cht[i].ch != 0xff);
470
 
70 andreas 471
            if (utf == 0x80000000)
11 andreas 472
                utf = ch;
473
        }
474
        else
475
            utf = ch;
476
 
70 andreas 477
        if (utf > 0x00ffff)
11 andreas 478
        {
70 andreas 479
            out.push_back((utf >> 16) & 0x0000ff);
480
            out.push_back((utf >> 8) & 0x0000ff);
481
            out.push_back(utf & 0x0000ff);
11 andreas 482
        }
70 andreas 483
        else if (utf > 0x0000ff)
484
        {
485
            out.push_back((utf >> 8) & 0x0000ff);
486
            out.push_back(utf & 0x0000ff);
487
        }
11 andreas 488
        else if (ch > 0x7f)
489
        {
490
            out.push_back(0xc0 | ch >> 6);
491
            out.push_back(0x80 | (ch & 0x3f));
492
        }
493
        else
494
            out.push_back(ch);
495
    }
496
 
497
    return out;
498
}
499
 
500
string UTF8ToCp1250(const string& str)
501
{
502
    DECL_TRACER("UTF8ToCp1250(const string& str)");
370 andreas 503
#if defined(__ANDROID__) || (defined(__APPLE__) && (TARGET_OS_IOS || TARGET_OS_SIMULATOR))
70 andreas 504
    string out;
505
    string::const_iterator iter;
506
    bool three = false;
11 andreas 507
 
70 andreas 508
    for (iter = str.begin(); iter != str.end(); ++iter)
509
    {
510
        unsigned int uch;
511
 
512
        if ((*iter & 0xc0) == 0xc0)     // If UTF8 then we need the next char also
513
        {
514
            uch = 0;
515
 
516
            if ((*iter & 0xe0) == 0xe0) // UTF8 consists of 3 bytes?
517
            {
518
                uch = (*iter << 16) & 0x00ff0000;
519
                ++iter;
520
                three = true;
521
            }
522
 
523
            uch |= ((*iter << 8) & 0x0000ff00);
524
            ++iter;
525
            uch |= (*iter & 0x000000ff);
526
        }
527
        else
528
            uch = *iter;
529
 
530
        if (three || uch > 0x00ff)
531
        {
532
            int i = 0;
533
            bool found = false;
534
 
535
            while(three && __cht[i].ch != 0xff)
536
            {
537
                if (__cht[i].byte == uch)
538
                {
539
                    out.push_back(__cht[i].ch);
540
                    found = true;
541
                    break;
542
                }
543
 
544
                i++;
545
            }
546
 
547
            three = false;
548
 
549
            if (!found)
550
            {
551
                unsigned ch = ((uch & 0x0300) >> 2) | (uch & 0x003f);
552
                out.push_back(ch);
553
            }
554
        }
555
        else
556
            out.push_back(uch);
557
    }
162 andreas 558
 
70 andreas 559
    return out;
560
#else
11 andreas 561
    char dst[1024];
562
    size_t srclen = 0;
563
    char* pIn, *pInSave;
564
 
565
    srclen = str.length();
566
    memset(&dst[0], 0, sizeof(dst));
567
 
568
    try
569
    {
570
        pIn = new char[srclen + 1];
571
        memcpy(pIn, str.c_str(), srclen);
572
        *(pIn+srclen) = 0;
573
        pInSave = pIn;
574
    }
575
    catch(std::exception& e)
576
    {
577
        MSG_ERROR("Error: " << e.what());
578
        return "";
579
    }
580
 
581
    size_t dstlen = sizeof(dst) - 1;
582
    char* pOut = (char *)dst;
583
 
70 andreas 584
    iconv_t conv = iconv_open("UTF-8", "CP1250");
11 andreas 585
 
586
    if (conv == (iconv_t)-1)
587
    {
70 andreas 588
        MSG_ERROR("Error opening iconv: " << strerror(errno));
11 andreas 589
        delete[] pInSave;
590
        return str;
591
    }
592
 
593
    size_t ret = iconv(conv, &pIn, &srclen, &pOut, &dstlen);
594
    iconv_close(conv);
595
    delete[] pInSave;
596
 
597
    if (ret == (size_t)-1)
598
    {
599
        MSG_ERROR("Error converting a string!");
600
        return str;
601
    }
602
 
603
    return string(dst);
371 andreas 604
#endif
11 andreas 605
}
21 andreas 606
 
263 andreas 607
std::string intToString(int num)
608
{
609
    std::stringstream ss;
610
    ss << num;
611
    return ss.str();
612
}
613
 
93 andreas 614
void *renew(char **mem, size_t old_size, size_t new_size)
21 andreas 615
{
616
    if (old_size == new_size)
93 andreas 617
        return *mem;
21 andreas 618
 
93 andreas 619
    if (!mem || !*mem)
620
        return nullptr;
621
 
21 andreas 622
    try
623
    {
93 andreas 624
        char *memory = new char[new_size];
21 andreas 625
        size_t len = (new_size < old_size) ? new_size : old_size;
93 andreas 626
        memcpy(memory, *mem, len);
627
        delete[] *mem;
628
        *mem = memory;
21 andreas 629
        return memory;
630
    }
631
    catch(std::exception& e)
632
    {
633
        MSG_ERROR(e.what());
93 andreas 634
        throw;
21 andreas 635
    }
636
 
637
    return nullptr;
638
}
639
 
417 andreas 640
/**
641
 * @brief Converts characters to uppercase letters.
642
 * Converts the string to uppercase letters according to the character
643
 * conversion rules defined by the currently installed C locale.
644
 * In the default "C" locale, the following lowercase letters
645
 * abcdefghijklmnopqrstuvwxyz are replaced with respective uppercase letters
646
 * ABCDEFGHIJKLMNOPQRSTUVWXYZ.
647
 * !!This method destroys the content of \n str!!
648
 * !!This method does not work correct with UTF-8!!
649
 *
650
 * @param str   String to be converted.
651
 * @return Returns the \b str with the content converted to uppercase letters.
652
 */
653
string& toUpper(string& str)
21 andreas 654
{
655
    string::iterator iter;
656
 
369 andreas 657
    for (iter = str.begin(); iter != str.end(); ++iter)
21 andreas 658
        *iter = std::toupper(*iter);
659
 
660
    return str;
661
}
662
 
417 andreas 663
/**
664
 * @brief Converts characters to lowercase letters.
665
 * Converts the string to lowercase letters according to the character
666
 * conversion rules defined by the currently installed C locale.
667
 * In the default "C" locale, the following uppercase letters
668
 * ABCDEFGHIJKLMNOPQRSTUVWXYZ are replaced with respective lowercase letters
669
 * abcdefghijklmnopqrstuvwxyz.
670
 * !!This method destroys the content of \n str!!
671
 * !!This method does not work correct with UTF-8!!
672
 *
673
 * @param str   String to be converted.
674
 * @return Returns the \b str with the content converted to lowercase letters.
675
 */
676
string& toLower(string& str)
21 andreas 677
{
678
    string::iterator iter;
679
 
369 andreas 680
    for (iter = str.begin(); iter != str.end(); ++iter)
21 andreas 681
        *iter = std::tolower(*iter);
682
 
683
    return str;
684
}
54 andreas 685
 
409 andreas 686
vector<string> splitLine(const string& str, bool multiline)
54 andreas 687
{
409 andreas 688
    DECL_TRACER("splitLine(const string& str, bool multiline)");
54 andreas 689
 
690
    vector<string> lines;
691
    string sl;
96 andreas 692
    string::const_iterator iter;
54 andreas 693
 
96 andreas 694
    if (str.empty())
695
        return lines;
696
 
369 andreas 697
    for (iter = str.begin(); iter != str.end(); ++iter)
54 andreas 698
    {
96 andreas 699
        if (*iter == '\r')  // ignore bloating byte coming from brain death windows
54 andreas 700
            continue;
701
 
409 andreas 702
        if (*iter == '\n' || (multiline && *iter == '|'))
54 andreas 703
        {
704
            lines.push_back(sl);
705
            sl.clear();
706
            continue;
707
        }
708
 
57 andreas 709
        char ch[2];
96 andreas 710
        ch[0] = *iter;
57 andreas 711
        ch[1] = 0;
712
        sl.append(ch);
54 andreas 713
    }
714
 
715
    if (!sl.empty())
716
        lines.push_back(sl);
717
 
718
    return lines;
719
}
720
 
57 andreas 721
vector<string> splitLine(const string& str, int width, int height, SkFont& font, SkPaint& paint)
722
{
723
    DECL_TRACER("splitLine(const string& str, int width, int height, SkFont& font, SkPaint& paint)");
724
 
725
    SkRect rect;
70 andreas 726
    vector<string> lines, words;
57 andreas 727
    SkScalar lnHeight = font.getSize();
728
    int maxLines = (int)((SkScalar)height / lnHeight);
70 andreas 729
    string part, oldPart;
96 andreas 730
 
731
    if (str.empty())
732
        return lines;
733
 
421 andreas 734
    words = StrSplit(str, " \n");
96 andreas 735
    MSG_DEBUG("Found " << words.size() << " words.");
70 andreas 736
    vector<string>::iterator iter;
57 andreas 737
 
96 andreas 738
    if (words.size() == 0)
739
        return lines;
740
 
421 andreas 741
    // Split the words with a | too but let the | pipe at start to mark it for line break.
742
    bool repeat = true;
743
 
744
    while (repeat)
745
    {
746
        repeat = false;
747
 
748
        for (iter = words.begin(); iter != words.end(); ++iter)
749
        {
750
            size_t pos = 0;
751
 
752
            if ((pos = iter->find("|")) != string::npos && pos > 0)
753
            {
754
                string left = iter->substr(0, pos);
755
                string right = iter->substr(pos);
756
                *iter = left;
757
                ++iter;
758
 
759
                if (iter != words.end())
760
                    words.insert(iter, right);
761
                else
762
                    words.push_back(right);
763
 
764
                repeat = true;
765
                break;
766
            }
767
 
768
            pos++;
769
        }
770
    }
771
 
70 andreas 772
    for (iter = words.begin(); iter != words.end(); ++iter)
57 andreas 773
    {
96 andreas 774
        size_t pos;
775
        bool lineBreak = false;
776
 
421 andreas 777
        if ((pos = iter->find("|")) != string::npos)
96 andreas 778
        {
421 andreas 779
            *iter = iter->substr(1);
96 andreas 780
            lineBreak = true;
781
        }
782
 
421 andreas 783
        if (!lineBreak)
784
        {
785
            if (part.empty())
786
                part += *iter;
787
            else
788
                part += " " + *iter;
789
        }
70 andreas 790
 
57 andreas 791
        font.measureText(part.c_str(), part.length(), SkTextEncoding::kUTF8, &rect, &paint);
792
 
421 andreas 793
        if (rect.width() > (width - 8) && !lineBreak)
57 andreas 794
        {
70 andreas 795
            if (oldPart.empty())
796
            {
797
                string sample;
798
                size_t len = part.length();
369 andreas 799
                size_t p = 1, start = 0;
57 andreas 800
 
70 andreas 801
                for (size_t i = 0; i < len; i++)
802
                {
369 andreas 803
                    sample = part.substr(start, p);
70 andreas 804
                    font.measureText(sample.c_str(), sample.length(), SkTextEncoding::kUTF8, &rect, &paint);
805
 
806
                    if (rect.width() > (width - 8))
807
                    {
163 andreas 808
                        lines.push_back(sample.substr(0, sample.length() - 1)); // Cut off the last character because it is already out of bounds.
70 andreas 809
                        start = i;                                              // Set the new start of the string
810
                        i--;                                                    // We must repeat the last character
369 andreas 811
                        p = 0;                                                // Reset the pition counter
70 andreas 812
                        sample = sample.substr(sample.length() - 1);            // Put the last character into the part.
813
 
814
                        if (lines.size() >= (size_t)maxLines)                   // Break if we've reached the maximum of lines
815
                            return lines;
816
                    }
817
 
369 andreas 818
                    p++;
70 andreas 819
                }
820
 
821
                oldPart.clear();
822
                part = sample;
823
                continue;
824
            }
825
            else
826
            {
827
                lines.push_back(oldPart);
828
                oldPart.clear();
829
                part = *iter;
830
 
831
                if (lines.size() >= (size_t)maxLines)               // Break if we've reached the maximum of lines
832
                    return lines;
833
 
834
                font.measureText(part.c_str(), part.length(), SkTextEncoding::kUTF8, &rect, &paint);
835
 
836
                if (rect.width() > (width - 8))
837
                    continue;
838
            }
57 andreas 839
        }
96 andreas 840
        else if (lineBreak)
841
        {
842
            lines.push_back(part);
421 andreas 843
            part = *iter;
96 andreas 844
        }
57 andreas 845
 
70 andreas 846
        oldPart = part;
57 andreas 847
    }
848
 
70 andreas 849
    if (lines.empty())
850
        lines.push_back(str);
851
    else if (!part.empty())
57 andreas 852
        lines.push_back(part);
853
 
854
    return lines;
855
}
60 andreas 856
 
857
bool isHex(int c)
858
{
859
    if ((c >= '0' && c <= '9') ||
860
        (c >= 'a' && c <= 'f') ||
861
        (c >= 'A' && c <= 'F'))
862
        return true;
863
 
864
    return false;
865
}
866
 
867
int strCaseCompare(const string& str1, const string& str2)
868
{
869
    return strcasecmp(str1.c_str(), str2.c_str());
870
}
63 andreas 871
 
872
std::string fillString(int c, int len)
873
{
874
    if (len < 1 || c < 1 || c > 0x00ffffff)
875
        return string();
876
 
877
    string str;
878
    char ch[4];
879
 
880
    if (c <= 0x00ff)
881
    {
882
        ch[0] = c;
883
        ch[1] = 0;
884
    }
885
    else if (c <= 0x00ffff)
886
    {
887
        ch[0] = c >> 8;
888
        ch[1] = c;
889
        ch[2] = 0;
890
    }
891
    else
892
    {
893
        ch[0] = c >> 16;
894
        ch[1] = c >> 8;
895
        ch[2] = c;
896
        ch[3] = 0;
897
    }
898
 
899
    for (int i = 0; i < len; i++)
900
        str.append(ch);
901
 
902
    return str;
903
}
67 andreas 904
 
905
bool isUTF8(const string& str)
906
{
907
    int c,i,ix,n,j;
908
 
909
    for (i=0, ix = str.length(); i < ix; i++)
910
    {
911
        c = (unsigned char) str[i];
912
 
913
        if (0x00 <= c && c <= 0x7f)
914
            n=0; // 0bbbbbbb
915
        else if ((c & 0xE0) == 0xC0)
916
            n=1; // 110bbbbb
917
        else if ( c==0xed && i<(ix-1) && ((unsigned char)str[i+1] & 0xa0)==0xa0)
918
            return false; //U+d800 to U+dfff
919
        else if ((c & 0xF0) == 0xE0)
920
            n=2; // 1110bbbb
921
        else if ((c & 0xF8) == 0xF0)
922
            n=3; // 11110bbb
923
        else
924
            return false;
925
 
926
        for (j=0; j<n && i<ix; j++) // n bytes matching 10bbbbbb follow ?
927
        {
928
            if ((++i == ix) || (( (unsigned char)str[i] & 0xC0) != 0x80))
929
                return false;
930
        }
931
    }
932
 
933
    return true;
934
}
935
 
936
size_t utf8Strlen(const std::string& str)
937
{
938
    int c,i,ix;
939
    size_t q;
940
 
941
    for (q = 0, i = 0, ix = str.length(); i < ix; i++, q++)
942
    {
157 andreas 943
        c = (unsigned char)str[i];
67 andreas 944
 
157 andreas 945
        if (c >= 0 && c <= 127)
946
            i += 0;
67 andreas 947
        else if ((c & 0xE0) == 0xC0)
157 andreas 948
            i += 1;
67 andreas 949
        else if ((c & 0xF0) == 0xE0)
157 andreas 950
            i += 2;
67 andreas 951
        else if ((c & 0xF8) == 0xF0)
157 andreas 952
            i += 3;
67 andreas 953
        else
954
            return 0;   //invalid utf8
955
    }
956
 
957
    return q;
958
}
959
 
960
uint16_t getUint16(const unsigned char *p, bool big_endian)
961
{
962
    if (!p)
963
        return 0;
964
 
965
    uint16_t num;
966
    memmove(&num, p, sizeof(uint16_t));
967
 
968
    if (!big_endian)
969
    {
970
        uint16_t le_num = ((num >> 8) & 0x00ff) | ((num << 8) & 0xff00);
971
        num = le_num;
972
    }
973
 
974
    return num;
975
}
976
 
977
uint32_t getUint32(const unsigned char *p, bool big_endian)
978
{
979
    if (!p)
980
        return 0;
981
 
982
    uint32_t num;
983
    memmove(&num, p, sizeof(uint32_t));
984
 
985
    if (!big_endian)
986
    {
987
        uint32_t le_num = ((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000);
988
        num = le_num;
989
    }
990
 
991
    return num;
992
}
71 andreas 993
 
361 andreas 994
string UnicodeToUTF8(const wstring& ws)
995
{
996
    string s;
997
 
998
    for(size_t i = 0; i < ws.size(); ++i)
999
    {
1000
        wchar_t wc = ws[i];
1001
 
1002
        if ( 0 <= wc && wc <= 0x7f )
1003
        {
1004
            s += (char)wc;
1005
        }
1006
        else if ( 0x80 <= wc && wc <= 0x7ff )
1007
        {
1008
            s += ( 0xc0 | (wc >> 6) );
1009
            s += ( 0x80 | (wc & 0x3f) );
1010
        }
1011
        else if ( 0x800 <= wc && wc <= 0xffff )
1012
        {
1013
            s += ( 0xe0 | (wc >> 12) );
1014
            s += ( 0x80 | ((wc >> 6) & 0x3f) );
1015
            s += ( 0x80 | (wc & 0x3f) );
1016
        }
1017
        else if ( 0x10000 <= wc && wc <= 0x1fffff )
1018
        {
1019
            s += ( 0xf0 | (wc >> 18) );
1020
            s += ( 0x80 | ((wc >> 12) & 0x3f) );
1021
            s += ( 0x80 | ((wc >> 6) & 0x3f) );
1022
            s += ( 0x80 | (wc & 0x3f) );
1023
        }
1024
        else if ( 0x200000 <= wc && wc <= 0x3ffffff )
1025
        {
1026
            s += ( 0xf8 | (wc >> 24) );
1027
            s += ( 0x80 | ((wc >> 18) & 0x3f) );
1028
            s += ( 0x80 | ((wc >> 12) & 0x3f) );
1029
            s += ( 0x80 | ((wc >> 6) & 0x3f) );
1030
            s += ( 0x80 | (wc & 0x3f) );
1031
        }
1032
        else if ( 0x4000000 <= wc && wc <= 0x7fffffff )
1033
        {
1034
            s += ( 0xfc | (wc >> 30) );
1035
            s += ( 0x80 | ((wc >> 24) & 0x3f) );
1036
            s += ( 0x80 | ((wc >> 18) & 0x3f) );
1037
            s += ( 0x80 | ((wc >> 12) & 0x3f) );
1038
            s += ( 0x80 | ((wc >> 6) & 0x3f) );
1039
            s += ( 0x80 | (wc & 0x3f) );
1040
        }
1041
    }
1042
 
1043
    return s;
1044
}
1045
 
71 andreas 1046
bool endsWith (const std::string &src, const std::string &end)
1047
{
1048
    vector<string> list;
1049
 
1050
    if (end.find("|") == string::npos)
1051
        list.push_back(end);
1052
    else
1053
        list = StrSplit(end, "|", false);
1054
 
1055
    vector<string>::iterator iter;
1056
 
1057
    for (iter = list.begin(); iter != list.end(); ++iter)
1058
    {
1059
        size_t len = iter->length();
1060
 
1061
        if (len > src.length())
1062
            continue;
1063
 
1064
        string part = src.substr(src.length() - len);
1065
 
1066
        if (part.compare(*iter) == 0)
1067
            return true;
1068
    }
1069
 
1070
    return false;
1071
}
1072
 
1073
bool startsWith (const std::string &src, const std::string &start)
1074
{
1075
    vector<string> list;
1076
 
1077
    if (start.find("|") == string::npos)
1078
        list.push_back(start);
1079
    else
1080
        list = StrSplit(start, "|", false);
1081
 
1082
    vector<string>::iterator iter;
1083
 
1084
    for (iter = list.begin(); iter != list.end(); ++iter)
1085
    {
1086
        size_t len = iter->length();
1087
 
1088
        if (len > src.length())
1089
            continue;
1090
 
1091
        string part = src.substr(0, len);
1092
 
1093
        if (part.compare(*iter) == 0)
1094
            return true;
1095
    }
1096
 
1097
    return false;
1098
}
1099
 
1100
std::string dirName (const std::string &path)
1101
{
1102
    if (path.empty())
1103
        return ".";
1104
 
1105
    size_t len = path.length();
1106
 
1107
    char *buffer = new char[len+1];
1108
    memset(buffer, 0, len+1);
1109
    strncpy(buffer, path.c_str(), len);
1110
 
1111
    char *dir = dirname(buffer);
1112
    string ret(dir);
1113
    delete[] buffer;
1114
    return ret;
1115
}
1116
 
1117
std::string baseName (const std::string &path)
1118
{
1119
    if (path.empty())
1120
        return ".";
1121
 
1122
    size_t len = path.length();
1123
 
1124
    char *buffer = new char[len+1];
1125
    memset(buffer, 0, len+1);
1126
    strncpy(buffer, path.c_str(), len);
1127
 
1128
    char *dir = basename(buffer);
1129
    string ret(dir);
1130
    delete[] buffer;
1131
    return ret;
1132
}
97 andreas 1133
 
222 andreas 1134
/**
1135
 * @brief strnstr - Find the needle in a haystack
1136
 * The function searches for a string in a larger string. In case the wanted
1137
 * string is found it returns a pointer to the start of the string in \b haystack.
1138
 *
1139
 * @param haystack  The string who may contain \b needle.
1140
 * @param needle    The string to search for in \b haystack.
1141
 * @param len       The length of the \b haystack.
1142
 *
1143
 * @return If the \b needle was found in \b haystack a pointer to the start of
1144
 * the string in \b haystack is returned. Otherwise a NULL pointer is returned.
1145
 */
97 andreas 1146
char *strnstr(const char* haystack, const char* needle, size_t len)
1147
{
1148
    if (!haystack || !needle)
1149
        return nullptr;
1150
 
1151
    size_t needleLen = strlen(needle);
1152
 
1153
    if (needleLen > len)
1154
        return nullptr;
1155
 
1156
    char *start = (char *)haystack;
1157
    size_t pos = 0;
1158
 
1159
    while ((pos + needleLen) < len)
1160
    {
1161
        bool match = true;
1162
 
1163
        for (size_t i = 0; i < needleLen; i++)
1164
        {
1165
            if (*(start + i) != *(needle + i))
1166
            {
1167
                match = false;
1168
                break;
1169
            }
1170
        }
1171
 
1172
        if (match)
1173
            return start;
1174
 
1175
        pos++;
1176
        start++;
1177
    }
1178
 
1179
    return nullptr;
1180
}
104 andreas 1181
 
222 andreas 1182
bool StrContains(const std::string& str, const std::string& part)
1183
{
1184
    return str.find(part) != string::npos;
1185
}
1186
 
268 andreas 1187
std::string ReplaceString(const std::string subject, const std::string& search, const std::string& replace)
1188
{
1189
    size_t pos = 0;
1190
    string sub = subject;
1191
 
1192
    while ((pos = sub.find(search, pos)) != std::string::npos)
1193
    {
1194
        sub.replace(pos, search.length(), replace);
1195
        pos += replace.length();
1196
    }
1197
 
1198
    return sub;
1199
}
1200
 
104 andreas 1201
string getCommand(const string& fullCmd)
1202
{
1203
    DECL_TRACER("getCommand(const string& fullCmd)");
1204
 
1205
    size_t pos = fullCmd.find_first_of("-");
1206
    string cmd;
1207
 
1208
    if (pos != string::npos)
153 andreas 1209
    {
104 andreas 1210
        cmd = fullCmd.substr(0, pos);
153 andreas 1211
        cmd = toUpper(cmd);
1212
    }
104 andreas 1213
    else
153 andreas 1214
    {
104 andreas 1215
        cmd = fullCmd;
153 andreas 1216
        cmd = toUpper(cmd);
1217
    }
104 andreas 1218
 
1219
    return cmd;
1220
}
162 andreas 1221
 
233 andreas 1222
bool isTrue(const std::string &value)
1223
{
1224
    std::string v = value;
1225
    std::string low = toLower(v);
1226
 
1227
    if (low.find("true") != std::string::npos ||
1228
        low.find("on") != std::string::npos ||
1229
        low.find("yes") != std::string::npos ||
1230
        low.find("1") != std::string::npos)
1231
        return true;
1232
 
1233
    return false;
1234
}
1235
 
1236
bool isFalse(const std::string &value)
1237
{
1238
    std::string v = value;
1239
    std::string low = toLower(v);
1240
 
1241
    if (low.find("false") != std::string::npos ||
1242
        low.find("off") != std::string::npos ||
1243
        low.find("no") != std::string::npos ||
1244
        low.find("0") != std::string::npos)
1245
        return true;
1246
 
1247
    return false;
1248
}
1249
 
1250
bool isNumeric(const std::string &str, bool blank)
1251
{
1252
    std::string::const_iterator iter;
1253
 
1254
    for (iter = str.begin(); iter != str.end(); ++iter)
1255
    {
1256
        if (*iter < '0' || *iter > '9')
1257
        {
1258
            if (blank && *iter == ' ')
1259
                continue;
1260
 
1261
            return false;
1262
        }
1263
    }
1264
 
1265
    return true;
1266
}
260 andreas 1267
 
1268
bool isBigEndian()
1269
{
1270
    union
1271
    {
1272
        uint32_t i;
1273
        char c[4];
409 andreas 1274
    }bint;
260 andreas 1275
 
409 andreas 1276
    bint.i = 0x01020304;
1277
 
260 andreas 1278
    return bint.c[0] == 1;
1279
}
271 andreas 1280
 
1281
std::string handleToString(ulong handle)
1282
{
1283
    ulong part1 = (handle >> 16) & 0x0000ffff;
1284
    ulong part2 = handle & 0x0000ffff;
1285
    return std::to_string(part1)+":"+std::to_string(part2);
1286
}
297 andreas 1287
 
1288
ulong extractHandle(const std::string& obname)
1289
{
1290
    size_t pos = obname.rfind("_");
1291
 
1292
    if (pos == std::string::npos)
1293
        return 0;
1294
 
1295
    std::string part = obname.substr(pos + 1);
1296
    ulong handle = 0;
1297
 
1298
    if ((pos = part.find(":")) != std::string::npos)
1299
    {
1300
        std::string slt = part.substr(0, pos);
1301
        std::string srt = part.substr(pos + 1);
1302
        ulong lt = atoi(slt.c_str());
1303
        ulong rt = atoi(srt.c_str());
1304
        handle = ((lt << 16) & 0xffff0000) | (rt & 0x0000ffff);
1305
    }
1306
 
1307
    return handle;
1308
}
431 andreas 1309
 
1310
uint32_t createButtonID(int type, int ap, int ad, int cp, int ch, int lp, int lv)
1311
{
1312
    vector<uint8_t> bytes;
433 andreas 1313
    uint8_t bt1, bt2;
1314
    bytes.push_back(static_cast<uint8_t>(type));
431 andreas 1315
 
1316
    if (ap >= 0)
1317
    {
1318
        // ap
433 andreas 1319
        bt1 = static_cast<uint8_t>((ap >> 8) & 0x00ff);
1320
        bt2 = static_cast<uint8_t>(ap & 0x00ff);
431 andreas 1321
        bytes.push_back(bt1);
1322
        bytes.push_back(bt2);
1323
    }
1324
 
1325
    if (ad >= 0)
1326
    {
1327
        // ad
433 andreas 1328
        bt1 = static_cast<uint8_t>((ad >> 8) & 0x00ff);
1329
        bt2 = static_cast<uint8_t>(ad & 0x00ff);
431 andreas 1330
        bytes.push_back(bt1);
1331
        bytes.push_back(bt2);
1332
    }
1333
 
1334
    if (cp >= 0)
1335
    {
1336
        // cp
433 andreas 1337
        bt1 = static_cast<uint8_t>((cp >> 8) & 0x00ff);
1338
        bt2 = static_cast<uint8_t>(cp & 0x00ff);
431 andreas 1339
        bytes.push_back(bt1);
1340
        bytes.push_back(bt2);
1341
    }
1342
 
1343
    if (ch >= 0)
1344
    {
1345
        // ch
433 andreas 1346
        bt1 = static_cast<uint8_t>((ch >> 8) & 0x00ff);
1347
        bt2 = static_cast<uint8_t>(ch & 0x00ff);
431 andreas 1348
        bytes.push_back(bt1);
1349
        bytes.push_back(bt2);
1350
    }
1351
 
1352
    if (lp >= 0)
1353
    {
1354
        // lp
433 andreas 1355
        bt1 = static_cast<uint8_t>((lp >> 8) & 0x00ff);
1356
        bt2 = static_cast<uint8_t>(lp & 0x00ff);
431 andreas 1357
        bytes.push_back(bt1);
1358
        bytes.push_back(bt2);
1359
    }
1360
 
1361
    if (lv >= 0)
1362
    {
1363
        // lv
433 andreas 1364
        bt1 = static_cast<uint8_t>((lv >> 8) & 0x00ff);
1365
        bt2 = static_cast<uint8_t>(lv & 0x00ff);
431 andreas 1366
        bytes.push_back(bt1);
1367
        bytes.push_back(bt2);
1368
    }
1369
 
1370
    TCrc32 crc(bytes);
434 andreas 1371
    std::stringstream s;
1372
    s << "0x" << std::setw(8) << std::setfill('0') << std::hex << crc.getCrc32();
1373
    MSG_DEBUG("CRC32: " << s.str());
431 andreas 1374
    return crc.getCrc32();
1375
}