OpenMoHAA 0.82.0
Loading...
Searching...
No Matches
str.h
1/*
2===========================================================================
3Copyright (C) 2025 the OpenMoHAA team
4
5This file is part of OpenMoHAA source code.
6
7OpenMoHAA source code is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 2 of the License,
10or (at your option) any later version.
11
12OpenMoHAA source code is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with OpenMoHAA source code; if not, write to the Free Software
19Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20===========================================================================
21*/
22
23// str.cpp: Simple, DLL portable string class
24//
25
26#pragma once
27
28#include <cassert>
29#include <cstring>
30#include <cstdio>
31#include <cstdint>
32#include <cinttypes>
33
34#ifdef _WIN32
35# pragma warning(disable : 4710) // function 'blah' not inlined
36#endif
37
38void TestStringClass();
39
40class strdata
41{
42public:
43 strdata()
44 : len(0)
45 , refcount(0)
46 , data(NULL)
47 , alloced(0)
48 {}
49
50 ~strdata()
51 {
52 if (data) {
53 delete[] data;
54 }
55 }
56
57 void AddRef() { refcount++; }
58
59 bool DelRef() // True if killed
60 {
61 refcount--;
62 if (refcount < 0) {
63 delete this;
64 return true;
65 }
66
67 return false;
68 }
69
70 char *data;
71 int refcount;
72 size_t alloced;
73 size_t len;
74};
75
76class str
77{
78protected:
79 friend class Archiver;
80 strdata *m_data;
81 void EnsureAlloced(size_t, bool keepold = true);
82 void EnsureDataWritable();
83
84public:
85 ~str();
86 str();
87 str(const char *text);
88 str(const str& string);
89 str(const str& string, size_t start, size_t end);
90 str(const char ch);
91 str(const int num);
92 str(const float num);
93 str(const unsigned int num);
94 str(const long num);
95 str(const unsigned long num);
96 str(const long long num);
97 str(const unsigned long long num);
98
99 str(str&& string);
100 str& operator=(str&& string);
101
102 size_t length(void) const;
103 const char *c_str(void) const;
104
105 void append(const char *text);
106 void append(const str& text);
107
108 char operator[](intptr_t index) const;
109 char& operator[](intptr_t index);
110
111 void operator=(const str& text);
112 void operator=(const char *text);
113
114 friend str operator+(const str& a, const str& b);
115 friend str operator+(const str& a, const char *b);
116 friend str operator+(const char *a, const str& b);
117
118 friend str operator+(const str& a, const float b);
119 friend str operator+(const str& a, const int b);
120 friend str operator+(const str& a, const unsigned b);
121 friend str operator+(const str& a, const bool b);
122 friend str operator+(const str& a, const char b);
123
124 str& operator+=(const str& a);
125 str& operator+=(const char *a);
126 str& operator+=(const float a);
127 str& operator+=(const char a);
128 str& operator+=(const int a);
129 str& operator+=(const unsigned a);
130 str& operator+=(const bool a);
131
132 str& operator-=(int c);
133 str& operator--(int);
134
135 friend bool operator==(const str& a, const str& b);
136 friend bool operator==(const str& a, const char *b);
137 friend bool operator==(const char *a, const str& b);
138
139 friend bool operator!=(const str& a, const str& b);
140 friend bool operator!=(const str& a, const char *b);
141 friend bool operator!=(const char *a, const str& b);
142
143 operator const char *() const;
144
145 int icmpn(const char *text, size_t n) const;
146 int icmpn(const str& text, size_t n) const;
147 int icmp(const char *text) const;
148 int icmp(const str& text) const;
149 int cmpn(const char *text, size_t n) const;
150 int cmpn(const str& text, size_t n) const;
151
152 void tolower(void);
153 void toupper(void);
154
155 static char *tolower(char *s1);
156 static char *toupper(char *s1);
157
158 static int icmpn(const char *s1, const char *s2, size_t n);
159 static int icmp(const char *s1, const char *s2);
160 static int cmpn(const char *s1, const char *s2, size_t n);
161 static int cmp(const char *s1, const char *s2);
162
163 static void snprintf(char *dst, int size, const char *fmt, ...);
164 void strip(void);
165
166 static bool isNumeric(const char *str);
167 bool isNumeric(void) const;
168
169 void CapLength(size_t newlen);
170
171 void BackSlashesToSlashes();
172 void SlashesToBackSlashes();
173 void DefaultExtension(const char *extension);
174 const char *GetExtension() const;
175 void StripExtension();
176 void SkipFile();
177 void SkipPath();
178};
179
180char *strstrip(char *string);
181char *strlwc(char *string);
182
183inline char str::operator[](intptr_t index) const
184{
185 assert(m_data);
186
187 if (!m_data) {
188 return 0;
189 }
190
191 // don't include the '/0' in the test, because technically, it's out of bounds
192 assert((index >= 0) && (index < (int)m_data->len));
193
194 // In release mode, give them a null character
195 // don't include the '/0' in the test, because technically, it's out of bounds
196 if ((index < 0) || (index >= (int)m_data->len)) {
197 return 0;
198 }
199
200 return m_data->data[index];
201}
202
203inline size_t str::length(void) const
204{
205 return (m_data != NULL) ? m_data->len : 0;
206}
207
208inline str::~str()
209{
210 if (m_data) {
211 m_data->DelRef();
212 m_data = NULL;
213 }
214}
215
216inline str::str()
217 : m_data(NULL)
218{}
219
220inline str::str(const char *text)
221 : m_data(NULL)
222{
223 size_t len;
224
225 assert(text);
226 if (*text) {
227 len = strlen(text);
228
229 if (len) {
230 EnsureAlloced(len + 1);
231 strcpy(m_data->data, text);
232 m_data->len = len;
233 }
234 }
235}
236
237inline str::str(const str& text)
238 : m_data(NULL)
239{
240 if (text.m_data) {
241 text.m_data->AddRef();
242 }
243
244 if (m_data) {
245 m_data->DelRef();
246 }
247
248 m_data = text.m_data;
249}
250
251inline str::str(const str& text, size_t start, size_t end)
252 : m_data(NULL)
253{
254 size_t i;
255 size_t len;
256
257 if (end > text.length()) {
258 end = text.length();
259 }
260
261 if (start > text.length()) {
262 start = text.length();
263 }
264
265 if (end >= start) {
266 len = end - start;
267 } else {
268 len = 0;
269 }
270
271 if (len > 0) {
272 EnsureAlloced(len + 1);
273
274 for (i = 0; i < len; i++) {
275 m_data->data[i] = text[start + i];
276 }
277
278 m_data->data[len] = 0;
279 m_data->len = len;
280 }
281}
282
283inline str::str(const char ch)
284 : m_data(NULL)
285{
286 EnsureAlloced(2);
287
288 m_data->data[0] = ch;
289 m_data->data[1] = 0;
290 m_data->len = 1;
291}
292
293inline str::str(const float num)
294 : m_data(NULL)
295{
296 char text[32];
297 size_t len;
298
299 snprintf(text, sizeof(text), "%.3f", num);
300 len = strlen(text);
301 EnsureAlloced(len + 1);
302 strcpy(m_data->data, text);
303 m_data->len = len;
304}
305
306inline str::str(const int num)
307 : m_data(NULL)
308{
309 char text[32];
310 size_t len;
311
312 snprintf(text, sizeof(text), "%d", num);
313 len = strlen(text);
314 EnsureAlloced(len + 1);
315 strcpy(m_data->data, text);
316 m_data->len = len;
317}
318
319inline str::str(const unsigned int num)
320 : m_data(NULL)
321{
322 char text[32];
323 size_t len;
324
325 snprintf(text, sizeof(text), "%u", num);
326 len = strlen(text);
327 EnsureAlloced(len + 1);
328 strcpy(m_data->data, text);
329 m_data->len = len;
330}
331
332inline str::str(const long num)
333 : m_data(NULL)
334{
335 char text[64];
336 size_t len;
337
338 snprintf(text, sizeof(text), "%ld", num);
339 len = strlen(text);
340 EnsureAlloced(len + 1);
341 strcpy(m_data->data, text);
342 m_data->len = len;
343}
344
345inline str::str(const unsigned long num)
346 : m_data(NULL)
347{
348 char text[64];
349 size_t len;
350
351 snprintf(text, sizeof(text), "%lu", num);
352 len = strlen(text);
353 EnsureAlloced(len + 1);
354 strcpy(m_data->data, text);
355 m_data->len = len;
356}
357
358inline str::str(const long long num)
359 : m_data(NULL)
360{
361 char text[64];
362 size_t len;
363
364 snprintf(text, sizeof(text), "%lld", num);
365 len = strlen(text);
366 EnsureAlloced(len + 1);
367 strcpy(m_data->data, text);
368 m_data->len = len;
369}
370
371inline str::str(const unsigned long long num)
372 : m_data(NULL)
373{
374 char text[64];
375 size_t len;
376
377 snprintf(text, sizeof(text), "%llu", num);
378 len = strlen(text);
379 EnsureAlloced(len + 1);
380 strcpy(m_data->data, text);
381 m_data->len = len;
382}
383
384inline const char *str::c_str(void) const
385{
386 if (m_data) {
387 return m_data->data;
388 } else {
389 return "";
390 }
391}
392
393inline str::str(str&& string)
394 : m_data(string.m_data)
395{
396 string.m_data = NULL;
397}
398
399inline str& str::operator=(str&& string)
400{
401 if (m_data) {
402 m_data->DelRef();
403 }
404
405 m_data = string.m_data;
406 string.m_data = NULL;
407
408 return *this;
409}
410
411inline void str::append(const char *text)
412{
413 size_t len;
414
415 assert(text);
416
417 if (*text) {
418 len = length();
419 len += strlen(text);
420 EnsureAlloced(len + 1);
421
422 strcat(m_data->data, text);
423 m_data->len = len;
424 }
425}
426
427inline void str::append(const str& text)
428{
429 append(text.c_str());
430}
431
432inline char& str::operator[](intptr_t index)
433{
434 // Used for result for invalid indices
435 static char dummy = 0;
436 assert(m_data);
437
438 // We don't know if they'll write to it or not
439 // if it's not a const object
440 EnsureDataWritable();
441
442 if (!m_data) {
443 return dummy;
444 }
445
446 // don't include the '/0' in the test, because technically, it's out of bounds
447 assert((index >= 0) && (index < (int)m_data->len));
448
449 // In release mode, let them change a safe variable
450 // don't include the '/0' in the test, because technically, it's out of bounds
451 if ((index < 0) || (index >= (int)m_data->len)) {
452 return dummy;
453 }
454
455 return m_data->data[index];
456}
457
458inline void str::operator=(const str& text)
459{
460 // adding the reference before deleting our current reference prevents
461 // us from deleting our string if we are copying from ourself
462 if (text.m_data) {
463 text.m_data->AddRef();
464 }
465
466 if (m_data) {
467 m_data->DelRef();
468 }
469
470 m_data = text.m_data;
471}
472
473inline void str::operator=(const char *text)
474{
475 size_t len;
476
477 assert(text);
478
479 if (m_data) {
480 if (text == m_data->data) {
481 return; // Copying same thing. Punt.
482 }
483
484 m_data->DelRef();
485 m_data = NULL;
486 }
487
488 if (*text) {
489 len = strlen(text);
490
491 m_data = new strdata;
492 m_data->len = len;
493 m_data->alloced = len + 1;
494 m_data->data = new char[len + 1];
495 strcpy(m_data->data, text);
496 }
497}
498
499inline str operator+(const str& a, const str& b)
500{
501 str result(a);
502
503 result.append(b);
504
505 return result;
506}
507
508inline str operator+(const str& a, const char *b)
509{
510 str result(a);
511
512 result.append(b);
513
514 return result;
515}
516
517inline str operator+(const char *a, const str& b)
518{
519 str result(a);
520
521 result.append(b);
522
523 return result;
524}
525
526inline str operator+(const str& a, const bool b)
527{
528 str result(a);
529
530 result.append(b ? "true" : "false");
531
532 return result;
533}
534
535inline str operator+(const str& a, const char b)
536{
537 char text[2];
538
539 text[0] = b;
540 text[1] = 0;
541
542 return a + text;
543}
544
545inline str& str::operator+=(const str& a)
546{
547 append(a);
548 return *this;
549}
550
551inline str& str::operator+=(const char *a)
552{
553 append(a);
554 return *this;
555}
556
557inline str& str::operator+=(const char a)
558{
559 char text[2];
560
561 text[0] = a;
562 text[1] = 0;
563 append(text);
564
565 return *this;
566}
567
568inline str& str::operator+=(const bool a)
569{
570 append(a ? "true" : "false");
571 return *this;
572}
573
574inline bool operator==(const str& a, const str& b)
575{
576 return (!strcmp(a.c_str(), b.c_str()));
577}
578
579inline bool operator==(const str& a, const char *b)
580{
581 assert(b);
582 if (!b) {
583 return false;
584 }
585 return (!strcmp(a.c_str(), b));
586}
587
588inline bool operator==(const char *a, const str& b)
589{
590 assert(a);
591 if (!a) {
592 return false;
593 }
594 return (!strcmp(a, b.c_str()));
595}
596
597inline bool operator!=(const str& a, const str& b)
598{
599 return !(a == b);
600}
601
602inline bool operator!=(const str& a, const char *b)
603{
604 return !(a == b);
605}
606
607inline bool operator!=(const char *a, const str& b)
608{
609 return !(a == b);
610}
611
612inline int str::icmpn(const char *text, size_t n) const
613{
614 assert(text);
615
616 return str::icmpn(c_str(), text, n);
617}
618
619inline int str::icmpn(const str& text, size_t n) const
620{
621 return str::icmpn(c_str(), text.c_str(), n);
622}
623
624inline int str::icmp(const char *text) const
625{
626 assert(text);
627
628 return str::icmp(c_str(), text);
629}
630
631inline int str::icmp(const str& text) const
632{
633 return str::icmp(c_str(), text.c_str());
634}
635
636inline int str::cmpn(const char *text, size_t n) const
637{
638 assert(text);
639
640 return str::cmpn(c_str(), text, n);
641}
642
643inline int str::cmpn(const str& text, size_t n) const
644{
645 return str::cmpn(c_str(), text.c_str(), n);
646}
647
648inline void str::tolower(void)
649{
650 if (m_data) {
651 EnsureDataWritable();
652
653 str::tolower(m_data->data);
654 }
655}
656
657inline void str::toupper(void)
658{
659 if (m_data) {
660 EnsureDataWritable();
661
662 str::toupper(m_data->data);
663 }
664}
665
666inline bool str::isNumeric(void) const
667{
668 assert(m_data);
669 return str::isNumeric(m_data->data);
670}
671
672inline str::operator const char *(void) const
673{
674 return c_str();
675}
Definition str.h:77
Definition str.h:41
@ string
string value
Definition json.hpp:2859