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