xref: /foundation/ability/idl_tool/util/string.cpp (revision ca0551cf)
1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "util/string.h"
17
18#include <atomic>
19#include <cctype>
20#include <cstddef>
21#include <cstdio>
22#include <cstdlib>
23#include <cstring>
24#include <new>
25
26#include "securec.h"
27#include "util/logger.h"
28#include "util/string_builder.h"
29
30namespace OHOS {
31namespace Idl {
32constexpr int LINE_MAX_SIZE = 1024;
33
34using SharedData = struct SharedData {
35    SharedData(int refCount, int size)
36        : refCount_(refCount), shareDataSize(size)
37    {}
38
39    static SharedData* Allocate(int size);
40
41    static void AddRef(const void* handle);
42
43    static void Release(const void* handle);
44
45    static char* ToString(SharedData* header)
46    {
47        return reinterpret_cast<char*>(header + 1);
48    }
49
50    static SharedData* GetHeader(const void* handle)
51    {
52        return reinterpret_cast<SharedData*>(const_cast<void*>(handle)) - 1;
53    }
54
55    std::atomic<int> refCount_;
56    int shareDataSize;
57};
58
59SharedData* SharedData::Allocate(int size)
60{
61    if (size < 0) {
62        Logger::E(String::TAG, "Size %d is illegal.", size);
63        return nullptr;
64    }
65    if (size > String::MAX_SIZE) {
66        Logger::E(String::TAG, "The string is too large to alloc.");
67        return nullptr;
68    }
69
70    SharedData* handle = reinterpret_cast<SharedData*>(malloc(sizeof(SharedData) + size + 1));
71    if (handle == nullptr) {
72        Logger::E(String::TAG, "Fail to malloc %lu bytes memory", size);
73        return handle;
74    }
75
76    new (handle)SharedData(1, size);
77    return handle;
78}
79
80void SharedData::AddRef(const void* handle)
81{
82    if (handle == nullptr) {
83        return;
84    }
85
86    SharedData* data = GetHeader(handle);
87    int before = data->refCount_.fetch_add(1);
88    if (before + 1 <= 1) {
89        Logger::E(String::TAG, "The refCount is error in AddRef.");
90    };
91}
92
93void SharedData::Release(const void* handle)
94{
95    if (handle == nullptr) {
96        return;
97    }
98
99    SharedData* data = GetHeader(handle);
100    int before = data->refCount_.fetch_sub(1);
101    if (before - 1 == 0) {
102        free(data);
103    } else if (before - 1 < 0) {
104        Logger::E(String::TAG, "The refCount is error in Release.");
105    };
106}
107
108
109const char* String::TAG = "String";
110
111String::String(const char* string)
112{
113    if (string != nullptr) {
114        string_ = SharedData::ToString(SharedData::Allocate(strlen(string)));
115        if (string_ != nullptr) {
116            errno_t ret = strcpy_s(string_, strlen(string) + 1, string);
117            if (ret != EOK) {
118                Logger::E(String::TAG, "The String::String is error in strcpy_s.");
119            }
120        }
121    }
122}
123
124String::String(const char* string, size_t length)
125{
126    if (string !=  nullptr) {
127        SharedData* sharedData = SharedData::Allocate(length);
128        if (sharedData == nullptr) {
129            return;
130        }
131        string_ = SharedData::ToString(sharedData);
132        if (string_ != nullptr) {
133            errno_t ret = memcpy_s(string_, length + 1, string, length);
134            if (ret == EOK) {
135                string_[length] = '\0';
136            } else {
137                free(sharedData);
138                string_ = nullptr;
139            }
140        }
141    }
142}
143
144String::String(const String& other)
145{
146    string_ = other.string_;
147    SharedData::AddRef(string_);
148}
149
150String::String(String&& other)
151{
152    string_ = other.string_;
153    other.string_ = nullptr;
154}
155
156String::String(int size)
157{
158    string_ = SharedData::ToString(SharedData::Allocate(size));
159    if (string_ != nullptr) {
160        (void)memset_s(string_, size + 1, 0, size + 1);
161    }
162}
163
164String::~String()
165{
166    SharedData::Release(string_);
167}
168
169int String::GetLength() const
170{
171    if (string_ == nullptr) {
172        return 0;
173    }
174
175    return SharedData::GetHeader(string_)->shareDataSize;
176}
177
178char String::operator[](int index) const
179{
180    if (index < 0 || index >= GetLength()) {
181        return '\0';
182    }
183    return string_[index];
184}
185
186bool String::Equals(const char* string) const
187{
188    if (string_ == nullptr && string == nullptr) {
189        return true;
190    }
191
192    if (string != nullptr && string_ != nullptr) {
193        if ((size_t)GetLength() != strlen(string)) {
194            return false;
195        }
196        return strcmp(string, string_) == 0;
197    }
198
199    return false;
200}
201
202bool String::Equals(const String& other) const
203{
204    if (string_ == nullptr && other.string_ == nullptr) {
205        return true;
206    }
207
208    if (string_ != nullptr && other.string_ != nullptr) {
209        if (GetLength() != other.GetLength()) {
210            return false;
211        }
212        return strcmp(string_, other.string_) == 0;
213    }
214    return false;
215}
216
217int String::GetHashCode() const
218{
219    // BKDR Hash Function
220    unsigned int seed = 31; // 31 131 1313 13131 131313 etc..
221    unsigned int hash = 0;
222
223    const char* string = string_;
224    if (string != nullptr) {
225        for (; *string; ++string) {
226            hash = hash * seed + (*string);
227        }
228    }
229    return (hash & 0x7FFFFFFF);
230}
231
232int String::IndexOf(char c, int fromIndex) const
233{
234    if (IsEmpty() || c == '\0') {
235        return -1;
236    }
237
238    if (fromIndex < 0) {
239        fromIndex = 0;
240    } else if (fromIndex >= GetLength()) {
241        return -1;
242    }
243
244    char* p = string_ + fromIndex;
245    char* end = string_ + GetLength();
246    while (p != end) {
247        if (*p == c) {
248            return p - string_;
249        }
250        p++;
251    }
252    return -1;
253}
254
255int String::IndexOf(const char* string, int fromIndex) const
256{
257    if (IsEmpty() || string == nullptr || string[0] == '\0') {
258        return -1;
259    }
260
261    if (fromIndex < 0) {
262        fromIndex = 0;
263    } else if (fromIndex >= GetLength()) {
264        return -1;
265    }
266
267    char* c = strstr(string_ + fromIndex, string);
268    return c != nullptr ? c - string_ : -1;
269}
270
271int String::IndexOf(const String& other, int fromIndex) const
272{
273    if (IsEmpty() || other.IsEmpty()) {
274        return -1;
275    }
276
277    if (fromIndex < 0) {
278        fromIndex = 0;
279    } else if (fromIndex >= GetLength()) {
280        return -1;
281    }
282
283    char* c = strstr(string_ + fromIndex, other.string_);
284    return c != nullptr ? c - string_ : -1;
285}
286
287int String::LastIndexOf(char c, int fromIndex) const
288{
289    if (IsEmpty() || c == '\0') {
290        return -1;
291    }
292
293    if (fromIndex < 0) {
294        return -1;
295    } else if (fromIndex == 0 || fromIndex >= GetLength()) {
296        fromIndex = GetLength() - 1;
297    }
298    char* p = string_ + fromIndex;
299    while (p != string_) {
300        if (*p == c) {
301            return p - string_;
302        }
303        p--;
304    }
305    return -1;
306}
307
308int String::LastIndexOf(const char* string, int fromIndex) const
309{
310    if (IsEmpty() || string == nullptr || string[0] == '\0') {
311        return -1;
312    }
313
314    if (fromIndex < 0) {
315        return -1;
316    } else if (fromIndex == 0 || fromIndex >= GetLength()) {
317        fromIndex = GetLength() - 1;
318    }
319
320    return LastIndexOfInternal(string, fromIndex);
321}
322
323int String::LastIndexOf(const String& other, int fromIndex) const
324{
325    if (IsEmpty() || other.IsEmpty()) {
326        return -1;
327    }
328
329    if (fromIndex < 0) {
330        return -1;
331    } else if (fromIndex == 0 || fromIndex >= GetLength()) {
332        fromIndex = GetLength() - 1;
333    }
334
335    return LastIndexOfInternal(other.string(), fromIndex);
336}
337
338int String::LastIndexOfInternal(const char* string, int fromIndex) const
339{
340    int sourceLen = GetLength();
341    int stringLen = strlen(string);
342    int rightIndex = sourceLen - stringLen;
343    if (fromIndex > rightIndex) {
344        fromIndex = rightIndex;
345    }
346
347    int stringLastIndex = stringLen - 1;
348    char stringLastChar = string[stringLastIndex];
349    int min = stringLen - 1;
350    int i = min + fromIndex;
351
352startSearchLastChar:
353    while (true) {
354        while (i >= min && string_[i] != stringLastChar) {
355            i--;
356        }
357        if (i < min) {
358            return -1;
359        }
360        int j = i - 1;
361        int start = j - (stringLen - 1);
362        int k = stringLastIndex - 1;
363
364        while (j > start) {
365            if (string_[j--] != string[k--]) {
366                i--;
367                goto startSearchLastChar;
368            }
369        }
370        return start + 1;
371    }
372}
373
374bool String::StartsWith(const char* string) const
375{
376    if (string == nullptr || string_ == nullptr) {
377        return false;
378    }
379
380    if (string[0] == '\0' && string_[0] == '\0') {
381        return true;
382    }
383
384    size_t count = strlen(string);
385    if (count > (size_t)GetLength()) {
386        return false;
387    }
388
389    return memcmp(string_, string, count) == 0;
390}
391
392bool String::StartsWith(const String& other) const
393{
394    if (other.string_ == nullptr || string_ == nullptr) {
395        return false;
396    }
397
398    if (other.string_[0] == '\0' && string_[0] == '\0') {
399        return true;
400    }
401
402    int count = other.GetLength();
403    if (count > GetLength()) {
404        return false;
405    }
406
407    return memcmp(string_, other.string_, count) == 0;
408}
409
410bool String::EndsWith(const char* string) const
411{
412    if (string == nullptr || string_ == nullptr) {
413        return false;
414    }
415
416    if (string[0] == '\0') {
417        return true;
418    }
419
420    size_t count = strlen(string);
421    size_t len = static_cast<size_t>(GetLength());
422    if (count > len) {
423        return false;
424    }
425
426    return memcmp(string_ + len - count, string, count) == 0;
427}
428
429bool String::EndsWith(const String& other) const
430{
431    if (other.string_ == nullptr || string_ == nullptr) {
432        return false;
433    }
434
435    if (other.string_[0] == '\0') {
436        return true;
437    }
438
439    int count = other.GetLength();
440    int len = GetLength();
441    if (count > len) {
442        return false;
443    }
444
445    return memcmp(string_ + len - count, other.string_, count) == 0;
446}
447
448String String::ToLowerCase() const
449{
450    if (IsEmpty()) {
451        return *this;
452    }
453
454    int size = GetLength();
455    for (int i = 0; i < size; i++) {
456        if (isupper(string_[i])) {
457            String newStr(string_);
458            for (int j = i; j < size; j++) {
459                newStr.string_[j] = tolower(newStr.string_[j]);
460            }
461            return newStr;
462        }
463    }
464    return *this;
465}
466
467String String::ToUpperCase() const
468{
469    if (IsEmpty()) {
470        return *this;
471    }
472
473    int size = GetLength();
474    for (int i = 0; i < size; i++) {
475        if (islower(string_[i])) {
476            String newStr(string_);
477            for (int j = i; j < size; j++) {
478                newStr.string_[j] = toupper(newStr.string_[j]);
479            }
480            return newStr;
481        }
482    }
483    return *this;
484}
485
486String String::Substring(int begin) const
487{
488    if (begin < 0 || begin >= GetLength()) {
489        return String();
490    }
491
492    return String(string_ + begin);
493}
494
495String String::Substring(int begin, int end) const
496{
497    if (begin < 0 || end > GetLength() || begin > end) {
498        return String();
499    }
500
501    return String(string_ + begin, end - begin);
502}
503
504String String::Replace(char oldChar, char newChar) const
505{
506    if (oldChar == newChar) {
507        return *this;
508    }
509
510    int size = GetLength();
511    for (int i = 0; i < size; i++) {
512        if (string_[i] != oldChar) {
513            continue;
514        }
515        String newStr(string_);
516        for (int j = i; j < size; j++) {
517            if (newStr.string_[j] == oldChar) {
518                newStr.string_[j] = newChar;
519            }
520        }
521        return newStr;
522    }
523    return *this;
524}
525
526String String::Replace(const char* target, const char* replacement) const
527{
528    if (target == nullptr || target[0] == '\0' || replacement == nullptr) {
529        return *this;
530    }
531
532    int index = IndexOf(target);
533    if (index == -1) {
534        return *this;
535    }
536
537    StringBuilder sb;
538    int begin = 0;
539    int step = strlen(target);
540    while (index != -1) {
541        sb.Append(Substring(begin, index));
542        sb.Append(replacement);
543        begin = index + step;
544        index = IndexOf(target, begin);
545    }
546    sb.Append(Substring(begin));
547    return sb.ToString();
548}
549
550String String::Replace(const String& target, const String& replacement) const
551{
552    if (target.IsEmpty() || replacement.IsNull()) {
553        return *this;
554    }
555
556    int index = IndexOf(target);
557    if (index== -1) {
558        return *this;
559    }
560
561    StringBuilder sb;
562    int begin = 0;
563    int step = target.GetLength();
564    while (index != -1) {
565        sb.Append(Substring(begin, index));
566        sb.Append(replacement);
567        begin = index + step;
568        index = IndexOf(target, begin);
569    }
570    sb.Append(Substring(begin));
571    return sb.ToString();
572}
573
574String& String::operator=(const char* string)
575{
576    SharedData::Release(string_);
577
578    if (string == nullptr) {
579        string_ = nullptr;
580        return *this;
581    }
582
583    string_ = SharedData::ToString(SharedData::Allocate(strlen(string)));
584    if (string_ != nullptr) {
585        errno_t ret = strcpy_s(string_, strlen(string) + 1, string);
586        if (ret != EOK) {
587            Logger::E(String::TAG, "The operator= is error in strcpy_s.");
588        }
589    }
590    return *this;
591}
592
593String& String::operator=(const String& other)
594{
595    if (string_ == other.string_) {
596        return *this;
597    }
598
599    SharedData::Release(string_);
600    SharedData::AddRef(other.string_);
601    string_ = other.string_;
602    return *this;
603}
604
605String& String::operator=(String&& other)
606{
607    SharedData::Release(string_);
608    string_ = other.string_;
609    other.string_ = nullptr;
610    return *this;
611}
612
613String String::operator+=(const char* string) const
614{
615    if (string == nullptr || string[0] == '\0') {
616        return *this;
617    }
618
619    int thisSize = GetLength();
620    int newSize = thisSize + strlen(string);
621    String newString(newSize);
622    if (newString.string_ != nullptr) {
623        errno_t retMem = memcpy_s(newString.string_, newSize + 1, string_, thisSize);
624        if (retMem != EOK) {
625            Logger::E(String::TAG, "The operator+= char* is error in memcpy_s.");
626        }
627        errno_t ret = strcpy_s(newString.string_ + thisSize, newSize + 1 - thisSize,  string);
628        if (ret != EOK) {
629            Logger::E(String::TAG, "The operator+= char* is error in strcpy_s.");
630        }
631    }
632    return newString;
633}
634
635String String::operator+=(const String& other) const
636{
637    if (other.IsEmpty()) {
638        return *this;
639    }
640
641    int thisSize = GetLength();
642    int newSize = thisSize + other.GetLength();
643    String newString(newSize);
644    if (newString.string_ != nullptr) {
645        (void)memcpy_s(newString.string_, newSize + 1, string_, thisSize);
646        errno_t ret = strcpy_s(newString.string_ + thisSize, newSize + 1 - thisSize, other.string_);
647        if (ret != EOK) {
648            Logger::E(String::TAG, "The operator+= is error in strcpy_s.");
649        }
650    }
651    return newString;
652}
653
654String String::Format(const char* format, ...)
655{
656    va_list args, argsCopy;
657
658    va_start(args, format);
659    va_copy(argsCopy, args);
660
661    char buf[LINE_MAX_SIZE] = {0};
662    int len = vsnprintf_s(buf, LINE_MAX_SIZE, LINE_MAX_SIZE - 1, format, args);
663    String string;
664    if (len <= 0) {
665        va_end(args);
666        va_end(argsCopy);
667        return string;
668    }
669
670    string = String(len);
671    if (string.string_ == nullptr) {
672        va_end(args);
673        va_end(argsCopy);
674        return string;
675    }
676
677    if (vsnprintf_s(string.string_, len + 1, len, format, argsCopy) < 0) {
678        va_end(args);
679        va_end(argsCopy);
680        return string;
681    }
682
683    va_end(args);
684    va_end(argsCopy);
685    return string;
686}
687}
688}
689