Subversion Repositories tpanel

Rev

Rev 297 | Blame | Last modification | View Log | RSS feed

/*
 * Copyright (C) 2020 to 2022 by Andreas Theofilu <andreas@theosys.at>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

#include <include/core/SkBitmap.h>
#include <include/core/SkData.h>
#include <include/core/SkImage.h>
#include <include/core/SkImageGenerator.h>
#include <include/core/SkStream.h>
#include <include/core/SkFont.h>
#include <include/core/SkTypeface.h>
#include <include/core/SkColorSpace.h>

#include <iconv.h>
#include <libgen.h>

#include <sys/types.h>
#include <sys/stat.h>

#include "tresources.h"
#include "tpagemanager.h"
#include "terror.h"
#include "tconfig.h"

#if __cplusplus < 201402L
#   error "This module requires at least C++14 standard!"
#else
#   if __cplusplus < 201703L
#       include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#       warning "Support for C++14 and experimental filesystem will be removed in a future version!"
#   else
#       include <filesystem>
#       ifdef __ANDROID__
namespace fs = std::__fs::filesystem;
#       else
namespace fs = std::filesystem;
#       endif
#   endif
#endif

using std::string;
using std::endl;
using std::vector;

extern TPageManager *gPageManager;

typedef struct
{
    unsigned char ch;
    unsigned int byte;
}CHTABLE;

static CHTABLE __cht[] = {
    {0x80,      0xE282AC},
    {0x81,      0x0081},    // not used
    {0x82,      0xE2809A},
    {0x83,      0x0192},    // not used
    {0x84,      0xE2809E},
    {0x85,      0xE280A6},
    {0x86,      0xE280A0},
    {0x87,      0xE280A1},
    {0x88,      0x02C6},    // not used
    {0x89,      0xE280B0},
    {0x8A,      0xC5A0},
    {0x8B,      0xE280B9},
    {0x8C,      0xC59A},
    {0x8D,      0xC5A4},
    {0x8E,      0xC5BD},
    {0x8F,      0xC5B9},
    {0x90,      0x0090},    // not used
    {0x91,      0xE28098},
    {0x92,      0xE28099},
    {0x93,      0xE2809C},
    {0x94,      0xE2809D},
    {0x95,      0xE280A2},
    {0x96,      0xE28093},
    {0x97,      0xE28094},
    {0x98,      0x02DC},    // not used
    {0x99,      0xE284A2},
    {0x9A,      0xC5A1},
    {0x9B,      0xE280BA},
    {0x9C,      0xC59B},
    {0x9D,      0xC5A5},
    {0x9E,      0xC5BE},
    {0x9F,      0xC5BA},
    {0xA0,      0xC2A0},
    {0xA1,      0xCB87},
    {0xA2,      0xCB98},
    {0xA3,      0xC581},
    {0xA4,      0xC2A0},
    {0xA5,      0xC484},
    {0xA6,      0xC2A6},
    {0xA7,      0xC2A7},
    {0xA8,      0xC2A8},
    {0xA9,      0xC2A9},
    {0xAA,      0xC59E},
    {0xAB,      0xC2AB},
    {0xAC,      0xC2AC},
    {0xAD,      0xC2AD},
    {0xAE,      0xC2AE},
    {0xAF,      0xC5BB},
    {0xB0,      0xC2B0},
    {0xB1,      0xC2B1},
    {0xB2,      0xCB9B},
    {0xB3,      0xC582},
    {0xB4,      0xC2B4},
    {0xB5,      0xC2B5},
    {0xB6,      0xC2B6},
    {0xB7,      0xC2B7},
    {0xB8,      0xC2B8},
    {0xB9,      0xC485},
    {0xBA,      0xC59F},
    {0xBB,      0xC2BB},
    {0xBC,      0xC4BD},
    {0xBD,      0xCB9D},
    {0xBE,      0xC4BE},
    {0xBF,      0xC5BC},
    {0xC0,      0xC594},
    {0xC1,      0xC381},
    {0xC2,      0xC382},
    {0xC3,      0xC482},
    {0xC4,      0xC384},
    {0xC5,      0xC4B9},
    {0xC6,      0xC486},
    {0xC7,      0xC387},
    {0xC8,      0xC48C},
    {0xC9,      0xC389},
    {0xCA,      0xC489},
    {0xCB,      0xC38b},
    {0xCC,      0xC49A},
    {0xCD,      0xC38D},
    {0xCE,      0xC38E},
    {0xCF,      0xC48E},
    {0xD0,      0xC490},
    {0xD1,      0xC583},
    {0xD2,      0xC587},
    {0xD3,      0xC398},
    {0xD4,      0xC394},
    {0xD5,      0xC590},
    {0xD6,      0xC396},
    {0xD7,      0xC397},
    {0xD8,      0xC598},
    {0xD9,      0xC5AE},
    {0xDA,      0xC39A},
    {0xDB,      0xC5B0},
    {0xDC,      0xC39C},
    {0xDD,      0xC39D},
    {0xDE,      0xC5A2},
    {0xDF,      0xC39F},
    {0xE0,      0xC595},
    {0xE1,      0xC3A1},
    {0xE2,      0xC3A2},
    {0xE3,      0xC483},
    {0xE4,      0xC3A4},
    {0xE5,      0xC4BA},
    {0xE6,      0xC487},
    {0xE7,      0xC3A7},
    {0xE8,      0xC48D},
    {0xE9,      0xC3A9},
    {0xEA,      0xC499},
    {0xEB,      0xC3AB},
    {0xEC,      0xC49B},
    {0xED,      0xC3AD},
    {0xEE,      0xC3AE},
    {0xEF,      0xC48F},
    {0xF0,      0xC491},
    {0xF1,      0xC584},
    {0xF2,      0xC588},
    {0xF3,      0xC3B3},
    {0xF4,      0xC3B4},
    {0xF5,      0xC591},
    {0xF6,      0xC3B6},
    {0xF7,      0xC3B7},
    {0xF8,      0xC599},
    {0xF9,      0xC5AF},
    {0xFA,      0xC3BA},
    {0xFB,      0xC5B1},
    {0xFC,      0xC3BC},
    {0xFD,      0xC3BD},
    {0xFE,      0xC5A3},
    {0xFF,      0xCB99}
};

SkString GetResourcePath(const char* resource, _RESOURCE_TYPE rs)
{
    if (!resource)
        return SkString();

//    if (*resource == '/')       // absolute path?
    if (strstr(resource, "/") != NULL && !endsWith(resource, "/"))
    {                           // yes, then take it as it is
        return SkString(resource);
    }

    string pth;

    switch(rs)
    {
        case RESTYPE_BORDER:    pth = "/borders/"; break;
        case RESTYPE_CURSOR:    pth = "/cursors/"; break;
        case RESTYPE_FONT:      pth = "/fonts/"; break;
        case RESTYPE_UNKNOWN:
        case RESTYPE_IMAGE:     pth = "/images/"; break;
        case RESTYPE_SLIDER:    pth = "/sliders/"; break;
        case RESTYPE_SYSBORDER: pth = "/__system/graphics/borders/"; break;
        case RESTYPE_SYSCURSOR: pth = "/__system/graphics/cursors/"; break;
        case RESTYPE_SYSFONT:   pth = "/__system/graphics/fonts/"; break;
        case RESTYPE_SYSIMAGE:  pth = "/__system/graphics/images/"; break;
        case RESTYPE_SYSSLIDER: pth = "/__system/graphics/sliders/"; break;
    }

    string projectPath = ((gPageManager && gPageManager->isSetupActive()) ? TConfig::getSystemProjectPath() : TConfig::getProjectPath());
    string path = projectPath + pth + resource;
    return SkString(path);
}

bool DecodeDataToBitmap(sk_sp<SkData> data, SkBitmap* dst)
{
    if (!data || !dst)
        return false;

    std::unique_ptr<SkImageGenerator> gen(SkImageGenerator::MakeFromEncoded(std::move(data)));
    return gen && dst->tryAllocPixels(gen->getInfo()) &&
            gen->getPixels(gen->getInfo().makeColorSpace(nullptr), dst->getPixels(), dst->rowBytes());
}

std::unique_ptr<SkStreamAsset> GetResourceAsStream(const char* resource, _RESOURCE_TYPE rs)
{
    sk_sp<SkData> data = GetResourceAsData(resource, rs);
    return data ? std::unique_ptr<SkStreamAsset>(new SkMemoryStream(std::move(data)))
    : nullptr;
}

sk_sp<SkData> GetResourceAsData(const char* resource, _RESOURCE_TYPE rs)
{
    SkString str = GetResourcePath(resource, rs);

    sk_sp<SkData> data = SkData::MakeFromFileName(str.c_str());

    if (data)
        return data;

    MSG_ERROR("GetResourceAsData: Resource \"" << str.c_str() << "\" not found.");
    TError::setError();
#ifdef SK_TOOLS_REQUIRE_RESOURCES
    SK_ABORT("GetResourceAsData: missing resource");
#endif
    return nullptr;
}

sk_sp<SkTypeface> MakeResourceAsTypeface(const char* resource, int ttcIndex, _RESOURCE_TYPE rs)
{
    return SkTypeface::MakeFromStream(GetResourceAsStream(resource, rs), ttcIndex);
}

/*
 * Read the image from a file and save it into a data buffer. This is the base
 * to convert the image.
 */
sk_sp<SkData> readImage(const string& fname)
{
    sk_sp<SkData> data = GetResourceAsData(fname.c_str());

    if (!data)
    {
        MSG_ERROR("readImage: Error loading the image " << fname);
        TError::setError();
    }

    return data;
}

SkBitmap *allocPixels(int width, int height, SkBitmap *bm)
{
    DECL_TRACER("TButton::allocPixels(int width, int height, SkBitmap *bm)");

    if (!bm)
        return nullptr;

    // Skia reads image files in the natural byte order of the CPU.
    // While on Intel CPUs the byte order is little endian it is
    // mostly big endian on other CPUs. This means that the order of
    // the colors is RGB on big endian CPUs (ARM, ...) and BGR on others.
    // To compensate this, we check the endianess of the CPU and set
    // the byte order according.
    SkImageInfo info;

    if (isBigEndian())
        info = SkImageInfo::Make(width, height, kRGBA_8888_SkColorType, kPremul_SkAlphaType);
    else
        info = SkImageInfo::Make(width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType);

    if (!bm->tryAllocPixels(info))
    {
        MSG_ERROR("Error allocating " << (width * height) << " pixels!");
        return nullptr;
    }

    return bm;
}

SkColor reverseColor(const SkColor& col)
{
    DECL_TRACER("reverseColor(const SkColor& col)");

    int red = SkColorGetR(col);
    int green = SkColorGetG(col);
    int blue = SkColorGetB(col);
    int alpha = SkColorGetA(col);

    return SkColorSetARGB(alpha, blue, green, red);
}

vector<string> StrSplit(const string& str, const string& seps, const bool trimEmpty)
{
    size_t pos = 0, mark = 0;
    vector<string> parts;
    string::const_iterator it, sepIt;

    if (str.empty())
        return parts;

    for (it = str.begin(); it != str.end(); ++it)
    {
        for (sepIt = seps.begin(); sepIt != seps.end(); ++sepIt)
        {
            if (pos > 0 && *it == *sepIt)
            {
                size_t len = pos - mark;

                if (len > 0 && *sepIt != '\n')
                    parts.push_back(str.substr(mark, len));
                else if (len > 0)
                    parts.push_back(str.substr(mark, len) + "\n");
                else if (*sepIt == '\n')
                    parts.push_back("\n");
                else
                    parts.push_back(string());

                mark = pos + 1;
                break;
            }
            else if (*it == *sepIt)
            {
                if (*sepIt == '\n')
                    parts.push_back("\n");

                mark = pos + 1;
            }
        }

        pos++;
    }

    parts.push_back(str.substr(mark));

    if (trimEmpty)
    {
        vector<string> nparts;

        for (auto iter = parts.begin(); iter != parts.end(); ++iter)
        {
            if (iter->empty())
                continue;

            nparts.push_back(*iter);
        }

        return nparts;
    }

    return parts;
}

string latin1ToUTF8(const string& str)
{
    DECL_TRACER("NameFormat::latin1ToUTF8(const string& str)");
    string out;

    for (size_t i = 0; i < str.length(); i++)
    {
        uint8_t ch = str.at(i);

        if (ch < 0x80)
        {
            out.push_back(ch);
        }
        else
        {
            out.push_back(0xc0 | ch >> 6);
            out.push_back(0x80 | (ch & 0x3f));
        }
    }

    return out;
}

string cp1250ToUTF8(const string& str)
{
    DECL_TRACER("cp1250ToUTF8(const string& str)");

    string out;

    for (size_t j = 0; j < str.length(); j++)
    {
        int i = -1;
        unsigned char ch = str.at(j);
        unsigned int utf = 0x80000000;

        if (ch >= 0x80)
        {
            do
            {
                i++;

                if (__cht[i].ch == ch)
                {
                    utf = __cht[i].byte;
                    break;
                }
            }
            while (__cht[i].ch != 0xff);

            if (utf == 0x80000000)
                utf = ch;
        }
        else
            utf = ch;

        if (utf > 0x00ffff)
        {
            out.push_back((utf >> 16) & 0x0000ff);
            out.push_back((utf >> 8) & 0x0000ff);
            out.push_back(utf & 0x0000ff);
        }
        else if (utf > 0x0000ff)
        {
            out.push_back((utf >> 8) & 0x0000ff);
            out.push_back(utf & 0x0000ff);
        }
        else if (ch > 0x7f)
        {
            out.push_back(0xc0 | ch >> 6);
            out.push_back(0x80 | (ch & 0x3f));
        }
        else
            out.push_back(ch);
    }

    return out;
}

string UTF8ToCp1250(const string& str)
{
    DECL_TRACER("UTF8ToCp1250(const string& str)");
#ifdef __ANDROID__
    string out;
    string::const_iterator iter;
    bool three = false;

    for (iter = str.begin(); iter != str.end(); ++iter)
    {
        unsigned int uch;

        if ((*iter & 0xc0) == 0xc0)     // If UTF8 then we need the next char also
        {
            uch = 0;

            if ((*iter & 0xe0) == 0xe0) // UTF8 consists of 3 bytes?
            {
                uch = (*iter << 16) & 0x00ff0000;
                ++iter;
                three = true;
            }

            uch |= ((*iter << 8) & 0x0000ff00);
            ++iter;
            uch |= (*iter & 0x000000ff);
        }
        else
            uch = *iter;

        if (three || uch > 0x00ff)
        {
            int i = 0;
            bool found = false;

            while(three && __cht[i].ch != 0xff)
            {
                if (__cht[i].byte == uch)
                {
                    out.push_back(__cht[i].ch);
                    found = true;
                    break;
                }

                i++;
            }

            three = false;

            if (!found)
            {
                unsigned ch = ((uch & 0x0300) >> 2) | (uch & 0x003f);
                out.push_back(ch);
            }
        }
        else
            out.push_back(uch);
    }

    return out;
#else
    char dst[1024];
    size_t srclen = 0;
    char* pIn, *pInSave;

    srclen = str.length();
    memset(&dst[0], 0, sizeof(dst));

    try
    {
        pIn = new char[srclen + 1];
        memcpy(pIn, str.c_str(), srclen);
        *(pIn+srclen) = 0;
        pInSave = pIn;
    }
    catch(std::exception& e)
    {
        MSG_ERROR("Error: " << e.what());
        return "";
    }

    size_t dstlen = sizeof(dst) - 1;
    char* pOut = (char *)dst;

    iconv_t conv = iconv_open("UTF-8", "CP1250");

    if (conv == (iconv_t)-1)
    {
        MSG_ERROR("Error opening iconv: " << strerror(errno));
        delete[] pInSave;
        return str;
    }

    size_t ret = iconv(conv, &pIn, &srclen, &pOut, &dstlen);
    iconv_close(conv);
    delete[] pInSave;

    if (ret == (size_t)-1)
    {
        MSG_ERROR("Error converting a string!");
        return str;
    }

    return string(dst);
#endif
}

std::string intToString(int num)
{
    std::stringstream ss;
    ss << num;
    return ss.str();
}

void *renew(char **mem, size_t old_size, size_t new_size)
{
    if (old_size == new_size)
        return *mem;

    if (!mem || !*mem)
        return nullptr;

    try
    {
        char *memory = new char[new_size];
        size_t len = (new_size < old_size) ? new_size : old_size;
        memcpy(memory, *mem, len);
        delete[] *mem;
        *mem = memory;
        return memory;
    }
    catch(std::exception& e)
    {
        MSG_ERROR(e.what());
        throw;
    }

    return nullptr;
}

string toUpper(string& str)
{
    string::iterator iter;

    for (iter = str.begin(); iter != str.end(); iter++)
        *iter = std::toupper(*iter);

    return str;
}

string toLower(string& str)
{
    string::iterator iter;

    for (iter = str.begin(); iter != str.end(); iter++)
        *iter = std::tolower(*iter);

    return str;
}

vector<string> splitLine(const string& str)
{
    DECL_TRACER("splitLine(const string& str)");

    vector<string> lines;
    string sl;
    string::const_iterator iter;

    if (str.empty())
        return lines;

    for (iter = str.begin(); iter != str.end(); iter++)
    {
        if (*iter == '\r')  // ignore bloating byte coming from brain death windows
            continue;

        if (*iter == '\n')
        {
            lines.push_back(sl);
            sl.clear();
            continue;
        }

        char ch[2];
        ch[0] = *iter;
        ch[1] = 0;
        sl.append(ch);
    }

    if (!sl.empty())
        lines.push_back(sl);

    return lines;
}

vector<string> splitLine(const string& str, int width, int height, SkFont& font, SkPaint& paint)
{
    DECL_TRACER("splitLine(const string& str, int width, int height, SkFont& font, SkPaint& paint)");

    SkRect rect;
    vector<string> lines, words;
    SkScalar lnHeight = font.getSize();
    int maxLines = (int)((SkScalar)height / lnHeight);
    string part, oldPart;

    if (str.empty())
        return lines;

    words = StrSplit(str, " \n");
    MSG_DEBUG("Found " << words.size() << " words.");
    vector<string>::iterator iter;

    if (words.size() == 0)
        return lines;

    for (iter = words.begin(); iter != words.end(); ++iter)
    {
        size_t pos;
        bool lineBreak = false;

        if ((pos = iter->find("\n")) != string::npos)
        {
            if (pos > 0)
                *iter = iter->substr(0, pos);
            else
                *iter = "";

            lineBreak = true;
        }

        if (part.empty())
            part += *iter;
        else
            part += " " + *iter;

        font.measureText(part.c_str(), part.length(), SkTextEncoding::kUTF8, &rect, &paint);

        if (rect.width() > (width - 8))
        {
            if (oldPart.empty())
            {
                string sample;
                size_t len = part.length();
                size_t pos = 1, start = 0;

                for (size_t i = 0; i < len; i++)
                {
                    sample = part.substr(start, pos);
                    font.measureText(sample.c_str(), sample.length(), SkTextEncoding::kUTF8, &rect, &paint);

                    if (rect.width() > (width - 8))
                    {
                        lines.push_back(sample.substr(0, sample.length() - 1)); // Cut off the last character because it is already out of bounds.
                        start = i;                                              // Set the new start of the string
                        i--;                                                    // We must repeat the last character
                        pos = 0;                                                // Reset the position counter
                        sample = sample.substr(sample.length() - 1);            // Put the last character into the part.

                        if (lines.size() >= (size_t)maxLines)                   // Break if we've reached the maximum of lines
                            return lines;
                    }

                    pos++;
                }

                oldPart.clear();
                part = sample;
                continue;
            }
            else
            {
                lines.push_back(oldPart);
                oldPart.clear();
                part = *iter;

                if (lines.size() >= (size_t)maxLines)               // Break if we've reached the maximum of lines
                    return lines;

                font.measureText(part.c_str(), part.length(), SkTextEncoding::kUTF8, &rect, &paint);

                if (rect.width() > (width - 8))
                    continue;
            }
        }
        else if (lineBreak)
        {
            lines.push_back(part);
            part.clear();
        }

        oldPart = part;
    }

    if (lines.empty())
        lines.push_back(str);
    else if (!part.empty())
        lines.push_back(part);

    return lines;
}

bool isHex(int c)
{
    if ((c >= '0' && c <= '9') ||
        (c >= 'a' && c <= 'f') ||
        (c >= 'A' && c <= 'F'))
        return true;

    return false;
}

int strCaseCompare(const string& str1, const string& str2)
{
    return strcasecmp(str1.c_str(), str2.c_str());
}

std::string fillString(int c, int len)
{
    if (len < 1 || c < 1 || c > 0x00ffffff)
        return string();

    string str;
    char ch[4];

    if (c <= 0x00ff)
    {
        ch[0] = c;
        ch[1] = 0;
    }
    else if (c <= 0x00ffff)
    {
        ch[0] = c >> 8;
        ch[1] = c;
        ch[2] = 0;
    }
    else
    {
        ch[0] = c >> 16;
        ch[1] = c >> 8;
        ch[2] = c;
        ch[3] = 0;
    }

    for (int i = 0; i < len; i++)
        str.append(ch);

    return str;
}

bool isUTF8(const string& str)
{
    int c,i,ix,n,j;

    for (i=0, ix = str.length(); i < ix; i++)
    {
        c = (unsigned char) str[i];

        if (0x00 <= c && c <= 0x7f)
            n=0; // 0bbbbbbb
        else if ((c & 0xE0) == 0xC0)
            n=1; // 110bbbbb
        else if ( c==0xed && i<(ix-1) && ((unsigned char)str[i+1] & 0xa0)==0xa0)
            return false; //U+d800 to U+dfff
        else if ((c & 0xF0) == 0xE0)
            n=2; // 1110bbbb
        else if ((c & 0xF8) == 0xF0)
            n=3; // 11110bbb
        else
            return false;

        for (j=0; j<n && i<ix; j++) // n bytes matching 10bbbbbb follow ?
        {
            if ((++i == ix) || (( (unsigned char)str[i] & 0xC0) != 0x80))
                return false;
        }
    }

    return true;
}

size_t utf8Strlen(const std::string& str)
{
    int c,i,ix;
    size_t q;

    for (q = 0, i = 0, ix = str.length(); i < ix; i++, q++)
    {
        c = (unsigned char)str[i];

        if (c >= 0 && c <= 127)
            i += 0;
        else if ((c & 0xE0) == 0xC0)
            i += 1;
        else if ((c & 0xF0) == 0xE0)
            i += 2;
        else if ((c & 0xF8) == 0xF0)
            i += 3;
        else
            return 0;   //invalid utf8
    }

    return q;
}

uint16_t getUint16(const unsigned char *p, bool big_endian)
{
    if (!p)
        return 0;

    uint16_t num;
    memmove(&num, p, sizeof(uint16_t));

    if (!big_endian)
    {
        uint16_t le_num = ((num >> 8) & 0x00ff) | ((num << 8) & 0xff00);
        num = le_num;
    }

    return num;
}

uint32_t getUint32(const unsigned char *p, bool big_endian)
{
    if (!p)
        return 0;

    uint32_t num;
    memmove(&num, p, sizeof(uint32_t));

    if (!big_endian)
    {
        uint32_t le_num = ((num >> 24) & 0x000000ff) | ((num >> 8) & 0x0000ff00) | ((num << 8) & 0x00ff0000) | ((num << 24) & 0xff000000);
        num = le_num;
    }

    return num;
}

bool endsWith (const std::string &src, const std::string &end)
{
    vector<string> list;

    if (end.find("|") == string::npos)
        list.push_back(end);
    else
        list = StrSplit(end, "|", false);

    vector<string>::iterator iter;

    for (iter = list.begin(); iter != list.end(); ++iter)
    {
        size_t len = iter->length();

        if (len > src.length())
            continue;

        string part = src.substr(src.length() - len);

        if (part.compare(*iter) == 0)
            return true;
    }

    return false;
}

bool startsWith (const std::string &src, const std::string &start)
{
    vector<string> list;

    if (start.find("|") == string::npos)
        list.push_back(start);
    else
        list = StrSplit(start, "|", false);

    vector<string>::iterator iter;

    for (iter = list.begin(); iter != list.end(); ++iter)
    {
        size_t len = iter->length();

        if (len > src.length())
            continue;

        string part = src.substr(0, len);

        if (part.compare(*iter) == 0)
            return true;
    }

    return false;
}

std::string dirName (const std::string &path)
{
    if (path.empty())
        return ".";

    size_t len = path.length();

    char *buffer = new char[len+1];
    memset(buffer, 0, len+1);
    strncpy(buffer, path.c_str(), len);

    char *dir = dirname(buffer);
    string ret(dir);
    delete[] buffer;
    return ret;
}

std::string baseName (const std::string &path)
{
    if (path.empty())
        return ".";

    size_t len = path.length();

    char *buffer = new char[len+1];
    memset(buffer, 0, len+1);
    strncpy(buffer, path.c_str(), len);

    char *dir = basename(buffer);
    string ret(dir);
    delete[] buffer;
    return ret;
}

/**
 * @brief strnstr - Find the needle in a haystack
 * The function searches for a string in a larger string. In case the wanted
 * string is found it returns a pointer to the start of the string in \b haystack.
 *
 * @param haystack  The string who may contain \b needle.
 * @param needle    The string to search for in \b haystack.
 * @param len       The length of the \b haystack.
 *
 * @return If the \b needle was found in \b haystack a pointer to the start of
 * the string in \b haystack is returned. Otherwise a NULL pointer is returned.
 */
char *strnstr(const char* haystack, const char* needle, size_t len)
{
    if (!haystack || !needle)
        return nullptr;

    size_t needleLen = strlen(needle);

    if (needleLen > len)
        return nullptr;

    char *start = (char *)haystack;
    size_t pos = 0;

    while ((pos + needleLen) < len)
    {
        bool match = true;

        for (size_t i = 0; i < needleLen; i++)
        {
            if (*(start + i) != *(needle + i))
            {
                match = false;
                break;
            }
        }

        if (match)
            return start;

        pos++;
        start++;
    }

    return nullptr;
}

bool StrContains(const std::string& str, const std::string& part)
{
    return str.find(part) != string::npos;
}

std::string ReplaceString(const std::string subject, const std::string& search, const std::string& replace)
{
    size_t pos = 0;
    string sub = subject;

    while ((pos = sub.find(search, pos)) != std::string::npos)
    {
        sub.replace(pos, search.length(), replace);
        pos += replace.length();
    }

    return sub;
}

string getCommand(const string& fullCmd)
{
    DECL_TRACER("getCommand(const string& fullCmd)");

    size_t pos = fullCmd.find_first_of("-");
    string cmd;

    if (pos != string::npos)
    {
        cmd = fullCmd.substr(0, pos);
        cmd = toUpper(cmd);
    }
    else
    {
        cmd = fullCmd;
        cmd = toUpper(cmd);
    }

    return cmd;
}

bool isTrue(const std::string &value)
{
    std::string v = value;
    std::string low = toLower(v);

    if (low.find("true") != std::string::npos ||
        low.find("on") != std::string::npos ||
        low.find("yes") != std::string::npos ||
        low.find("1") != std::string::npos)
        return true;

    return false;
}

bool isFalse(const std::string &value)
{
    std::string v = value;
    std::string low = toLower(v);

    if (low.find("false") != std::string::npos ||
        low.find("off") != std::string::npos ||
        low.find("no") != std::string::npos ||
        low.find("0") != std::string::npos)
        return true;

    return false;
}

bool isNumeric(const std::string &str, bool blank)
{
    std::string::const_iterator iter;

    for (iter = str.begin(); iter != str.end(); ++iter)
    {
        if (*iter < '0' || *iter > '9')
        {
            if (blank && *iter == ' ')
                continue;

            return false;
        }
    }

    return true;
}

bool isBigEndian()
{
    union
    {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1;
}

std::string handleToString(ulong handle)
{
    ulong part1 = (handle >> 16) & 0x0000ffff;
    ulong part2 = handle & 0x0000ffff;
    return std::to_string(part1)+":"+std::to_string(part2);
}

ulong extractHandle(const std::string& obname)
{
    size_t pos = obname.rfind("_");

    if (pos == std::string::npos)
        return 0;

    std::string part = obname.substr(pos + 1);
    ulong handle = 0;

    if ((pos = part.find(":")) != std::string::npos)
    {
        std::string slt = part.substr(0, pos);
        std::string srt = part.substr(pos + 1);
        ulong lt = atoi(slt.c_str());
        ulong rt = atoi(srt.c_str());
        handle = ((lt << 16) & 0xffff0000) | (rt & 0x0000ffff);
    }

    return handle;
}