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