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