source: cpp/frams/util/sstringutils.cpp @ 1156

Last change on this file since 1156 was 1156, checked in by Maciej Komosinski, 3 years ago

Added sstringURLEncode(SString& target) and sstringURLDecode(SString &target)

  • Property svn:eol-style set to native
File size: 8.5 KB
RevLine 
[286]1// This file is a part of Framsticks SDK.  http://www.framsticks.com/
[1156]2// Copyright (C) 1999-2021  Maciej Komosinski and Szymon Ulatowski.
[286]3// See LICENSE.txt for details.
[109]4
5#include "sstringutils.h"
[382]6#include <common/virtfile/virtfile.h>
[375]7#include <common/log.h>
[109]8#include <common/nonstd.h>
[691]9#include <common/Convert.h>
[109]10
[529]11int loadSString(const char* filename, SString& s, const char* framsgmodule, const char* error, bool remove_cr)
[109]12{
[257]13        VirtFILE *f;
14        int ret = 0;
15        if (f = Vfopen(filename, FOPEN_READ_BINARY))
[109]16        {
[529]17                loadSString(f, s, remove_cr);
[257]18                ret = 1;
[523]19                delete f;
[109]20        }
[257]21        else if (framsgmodule)
[691]22                logPrintf(framsgmodule, "loadSString", LOG_WARN, error ? error : "Can't open file \"%s\"", filename);
[257]23        return ret;
[109]24}
25
[529]26void loadSString(VirtFILE *f, SString& s, bool remove_cr)
[109]27{
[257]28        char buf[1024];
29        int len;
30        while (!f->Veof())
[109]31        {
[523]32                len = f->Vread(buf, 1, sizeof(buf));
[257]33                s.append(buf, len);
[109]34        }
[529]35        if (remove_cr)
36                removeCR(s);
[109]37}
38
39//load single line, discarding any \r or \n found at the end, return false if nothing could be loaded (error or eof)
[257]40bool loadSStringLine(VirtFILE* f, SString& s)
[109]41{
[257]42        char buf[100];
43        bool eolfound = false;
44        bool ret = false;
45        s = SString::empty();
46        while (!eolfound)
[109]47        {
[523]48                char *r = f->Vgets(buf, sizeof(buf));
[257]49                if (r == NULL) break;
50                ret = true;
51                int d = strlen(r);
52                if (d > 0)
[109]53                {
[257]54                        if (r[d - 1] == '\n') { d--; eolfound = true; }
55                        if (d > 0) if (r[d - 1] == '\r') d--;
56                        s += SString(r, d);
[109]57                }
58        }
[257]59        return ret;
[109]60}
61
62//////////////////////////
63
64/** "x~xx~xxx" -> "x\~xx\~xxx"  */
65int quoteTilde(SString &target)
66{
[348]67        const char* x = target.c_str();
[257]68        SString tmp;
69        char *f;
70        while (1)
[109]71        {
[257]72                f = strchr((char*)x, '~');
73                if (f)
[109]74                {
[257]75                        tmp.append(x, f - x);
76                        tmp += "\\~";
77                        x = f + 1;
[109]78                }
[257]79                else
[109]80                {
[973]81                        if (tmp.length() == 0) return 0; // nothing was changed!
[257]82                        tmp += x;
83                        target = tmp;
84                        return 1;
[109]85                }
86        }
87}
88
89/** "x\~xx\~xxx" -> "x~xx~xxx"  */
90int unquoteTilde(SString &target)
91{
[348]92        const char* x = target.c_str();
[257]93        SString tmp;
94        char *f;
95        while (1)
[109]96        {
[257]97                f = strchr((char*)x, '\\');
98                if (f)
[109]99                {
[257]100                        tmp.append(x, f - x);
101                        if (f[1] == '~')
[109]102                        {
[257]103                                tmp += '~';
104                                x = f + 2;
[109]105                        }
[257]106                        else
[109]107                        {
[257]108                                tmp += "\\";
109                                x = f + 1;
[109]110                        }
111                }
[257]112                else
[109]113                {
[973]114                        if (tmp.length() == 0) return 0; // nothing was changed!
[257]115                        tmp += x;
116                        target = tmp;
117                        return 1;
[109]118                }
119        }
120}
121
122/////////////////
123
[257]124bool strContainsOneOf(const char* str, const char* chars)
[109]125{
[257]126        while (*str)
[109]127        {
[257]128                if (strchr(chars, *str)) return 1;
129                str++;
[109]130        }
[257]131        return 0;
[109]132}
133
134//////////////
135
136bool sstringQuote(SString& target)
137{
[348]138        const char* x = target.c_str();
[257]139        bool changed = 0;
140        SString tmp;
[973]141        tmp.reserve(target.length());
[257]142        while (*x)
[109]143        {
[257]144                switch (*x)
[109]145                {
[257]146                case '\n': tmp += "\\n"; changed = 1; break;
147                case '\r': tmp += "\\r"; changed = 1; break;
148                case '\t': tmp += "\\t"; changed = 1; break;
149                case '\"': tmp += "\\\""; changed = 1; break;
150                case '\\': tmp += "\\\\"; changed = 1; break;
151                default: tmp += *x;
[109]152                }
[257]153                x++;
[109]154        }
[257]155        if (changed) target = tmp;
156        return changed;
[109]157}
158
[786]159SString sstringDelimitAndShorten(const SString &in, int maxlen, bool show_length, const SString& before, const SString& after)
[785]160{
161        SString out;
[973]162        if (in.length() > maxlen)
163                out = in.substr(0, maxlen / 2) + "..." + in.substr(in.length() - maxlen + maxlen / 2);
[785]164        else
[786]165        {
166                out = in; show_length = false;
167        }
[785]168        sstringQuote(out);
[786]169        out = before + out + after;
170        if (show_length)
[973]171                out += SString::sprintf(" (length %d)", in.length());
[785]172        return out;
173}
174
[109]175const char* skipQuoteString(const char* txt, const char* limit)
176{
[257]177        while (*txt)
[109]178        {
[257]179                if (*txt == '\"') return txt;
180                if (*txt == '\\') txt++;
181                txt++;
182                if (txt == limit) break;
[109]183        }
[257]184        return txt;
[109]185}
186
187int sstringUnquote(SString &target)
188{
[348]189        const char* x = target.c_str();
[257]190        SString tmp;
191        char *f;
192        while (1)
[109]193        {
[257]194                f = strchr((char*)x, '\\');
195                if (f)
[109]196                {
[257]197                        tmp.append(x, f - x);
198                        switch (f[1])
[109]199                        {
[257]200                        case 'n': tmp += '\n'; break;
201                        case 'r': tmp += '\r'; break;
202                        case 't': tmp += '\t'; break;
203                        case '\"': tmp += '\"'; break;
204                        default: tmp += f[1];
[109]205                        }
[257]206                        x = f + 2;
[109]207                }
[257]208                else
[109]209                {
[973]210                        if (tmp.length() == 0) return 0; // nothing was changed!
[257]211                        tmp += x;
212                        target = tmp;
213                        return 1;
[109]214                }
215        }
216}
217
[257]218int strFindField(const SString& txt, const SString& name, int &end)
[109]219{
[348]220        const char* t = txt.c_str(), *n;
[257]221        int pos = 0;
222        while (1)
[109]223        {
[257]224                n = strchr(t + pos, ',');
[973]225                if ((!strncmp(t + pos, name.c_str(), name.length())) && (t[pos + name.length()] == '='))
[109]226                {
[973]227                        if (n) end = n - t; else end = txt.length();
[257]228                        return pos;
[109]229                }
[257]230                if (n) pos = n - t + 1; else break;
[109]231        }
[257]232        return -1;
[109]233}
234
[257]235SString strGetField(const SString& txt, const SString& name)
[109]236{
[257]237        int p, e;
238        p = strFindField(txt, name, e);
239        if (p < 0) return SString();
[973]240        p += name.length() + 1;
[257]241        return SString(txt.substr(p, e - p));
[109]242}
243
[257]244void strSetField(SString& txt, const SString& name, const SString& value)
[109]245{
[257]246        int p, e;
247        p = strFindField(txt, name, e);
248        if (p < 0)
[109]249        {
[973]250                if (!value.length()) return;
251                char *t = txt.directAppend(1 + name.length() + value.length());
[257]252                char *b = t;
[973]253                if (txt.length()) *(t++) = ',';
254                strcpy(t, name.c_str()); t += name.length();
[257]255                *(t++) = '=';
[973]256                strcpy(t, value.c_str()); t += value.length();
[257]257                txt.endAppend(t - b);
[109]258        }
[257]259        else
[109]260        {
[973]261                if (!value.length())
[109]262                {
[973]263                        if (p > 0) p--; else if (e < txt.length()) e++;
[257]264                        char *t = txt.directWrite(0);
[973]265                        memmove(t + p, t + e, txt.length() - e);
266                        txt.endWrite(txt.length() + value.length() - (e - p));
[109]267                }
[257]268                else
[109]269                {
[973]270                        p += name.length() + 1;
271                        char *t = txt.directWrite(txt.length() + value.length() - (e - p));
272                        memmove(t + p + value.length(), t + e, txt.length() - e);
273                        memmove(t + p, value.c_str(), value.length());
274                        txt.endWrite(txt.length() + value.length() - (e - p));
[109]275                }
276        }
277}
278
[512]279SString trim(const SString& s)
[109]280{
[348]281        const unsigned char*b = (const unsigned char*)s.c_str();
[973]282        const unsigned char*e = b + s.length();
[257]283        while ((b < e) && (*b <= ' ')) b++;
284        while ((b < e) && (e[-1] <= ' ')) e--;
[973]285        if ((e - b) == s.length()) return s;
[257]286        SString newstring;
287        char* t = newstring.directWrite(e - b);
288        memmove(t, b, e - b);
289        newstring.endWrite(e - b);
290        return newstring;
[109]291}
292
[973]293SString concatPath(const SString& in1, const SString& in2)
[904]294{
[973]295        SString out = in1;
296        if (out.length() > 0 && out[out.length() - 1] != PATH_SEPARATOR_CHAR)
297                out += PATH_SEPARATOR_CHAR;
298        out += in2;
[904]299        return out;
300}
301
[109]302bool removeCR(SString& s)
303{
[348]304        const char* p = s.c_str();
[257]305        const char* cr = strchr(p, '\r');
306        if (!cr) return false;
307        char* begin = s.directWrite();
308        char* src = begin + (cr - p), *dst = src;
309        while (*src)
310                if (*src == '\r')
311                        src++;
312                else
313                        *(dst++) = *(src++);
314        s.endWrite(dst - begin);
315        return true;
[109]316}
[210]317
[257]318bool matchWildcard(const SString& word, const SString& pattern)
[210]319{
[973]320        if (pattern.length() == 0)
321                return word.length() == 0;
[257]322        int aster = pattern.indexOf('*');
323        if (aster >= 0)
[210]324        {
[257]325                SString before = pattern.substr(0, aster);
326                SString after = pattern.substr(aster + 1);
[973]327                if (!word.length()) return false;
328                if (before.length()) if (!word.startsWith(before.c_str())) return false;
329                if (after.length())
330                        if ((word.length() < after.length())
331                                || (strcmp(after.c_str(), word.c_str() + word.length() - after.length())))
[257]332                                return false;
333                return true;
[210]334        }
[257]335        else
336                return word == pattern;
[210]337}
338
[257]339bool matchWildcardList(const SString& word, const SString& patterns)
[210]340{
[973]341        if (patterns.length() == 0)
342                return word.length() == 0;
[257]343        int pos = 0;
344        SString pattern;
345        while (patterns.getNextToken(pos, pattern, ','))
346                if (matchWildcard(word, pattern))
347                        return true;
348        return false;
[210]349}
350
[691]351SString getUIDString(uint64_t uid, char prefix)
352{
353        return SString::sprintf("%c" UINT64_FORMAT, prefix, uid);
354}
355
356bool parseUIDString(const char* str, char prefix, uint64_t &uid, bool err)
357{
358        if ((str[0] == prefix) && (isdigit(str[1])))
359        {
360                char* end;
361                uid = strtoull(str + 1, &end, 10);
362                if (end == (str + 1 + strlen(str + 1)))
363                        return true;
364        }
365        if (err)
366                logPrintf("SString", "parseUIDString", LOG_ERROR, "Invalid uid: '%s'", str);
367        return false;
368}
[1156]369
370bool sstringURLEncode(SString& target)
371{
372        const char* x = target.c_str();
373        bool changed = 0;
374        SString tmp;
375        tmp.reserve(target.length());
376        static constexpr const char* ALLOWED_CHARS = "-_.~";
377        for (; *x; x++)
378        {
379                if (!(isalnum(*x) || strchr(ALLOWED_CHARS, *x)))
380                {
381                        tmp += "%";
382                        tmp += SString::sprintf("%02x", *x);
383                        changed = 1;
384                }
385                else
386                        tmp += *x;
387        }
388        if (changed) target = tmp;
389        return changed;
390}
391
392bool sstringURLDecode(SString &target)
393{
394        const char* x = target.c_str();
395        SString tmp;
396        char *f;
397        while (1)
398        {
399                f = strchr((char*)x, '%');
400                if (f)
401                {
402                        tmp.append(x, f - x);
403                        char hex[3] = { f[1],f[2],0 };
404                        char* after;
405                        unsigned long intvalue = strtoul(hex, &after, 16);
406                        tmp += (char)intvalue;
407                        x = f + 3;
408                }
409                else
410                {
411                        if (tmp.length() == 0) return false; // nothing was changed!
412                        tmp += x;
413                        target = tmp;
414                        return true;
415                }
416        }
417}
Note: See TracBrowser for help on using the repository browser.