Line data Source code
1 : /**
2 : * @file tools.h
3 : * @brief Legacy tooling inherited from the Cube engine.
4 : *
5 : * This file contains a collection of deprecated, standalone tooling that replicates
6 : * some standard library functionality. It is highly recommended that the std library
7 : * equivalents of these utilities are used in their place.
8 : */
9 :
10 : #ifndef TOOLS_H_
11 : #define TOOLS_H_
12 :
13 : typedef unsigned char uchar;
14 : typedef unsigned short ushort;
15 : typedef unsigned int uint;
16 : typedef unsigned long ulong;
17 : typedef signed long long int llong;
18 : typedef unsigned long long int ullong;
19 :
20 : #if defined(__GNUC__) || defined(_MSC_VER)
21 : #define RESTRICT __restrict
22 : #else
23 : #define RESTRICT
24 : #endif
25 :
26 : #ifdef max
27 : #undef max
28 : #endif
29 : #ifdef min
30 : #undef min
31 : #endif
32 : template<class T>
33 87 : inline T max(T a, T b)
34 : {
35 87 : return a > b ? a : b;
36 : }
37 : template<class T>
38 3 : inline T max(T a, T b, T c)
39 : {
40 3 : return max(max(a, b), c);
41 : }
42 : template<class T>
43 1256 : inline T min(T a, T b)
44 : {
45 1256 : return a < b ? a : b;
46 : }
47 : template<class T>
48 3 : inline T min(T a, T b, T c)
49 : {
50 3 : return min(min(a, b), c);
51 : }
52 :
53 : #ifdef __GNUC__
54 : #define BITSCAN(mask) (__builtin_ffs(mask)-1)
55 : #else
56 : #ifdef WIN32
57 : #pragma intrinsic(_BitScanForward)
58 : inline int BITSCAN(uint mask)
59 : {
60 : ulong i;
61 : return _BitScanForward(&i, mask) ? i : -1;
62 : }
63 : #else
64 : inline int BITSCAN(uint mask)
65 : {
66 : if(!mask) return -1;
67 : int i = 1;
68 : if(!(mask&0xFFFF)) { i += 16; mask >>= 16; }
69 : if(!(mask&0xFF)) { i += 8; mask >>= 8; }
70 : if(!(mask&0xF)) { i += 4; mask >>= 4; }
71 : if(!(mask&3)) { i += 2; mask >>= 2; }
72 : return i - (mask&1);
73 : }
74 : #endif
75 : #endif
76 :
77 1 : inline int randomint(int x)
78 : {
79 1 : return rand()%(x);
80 : }
81 1 : inline float randomfloat(int x)
82 : {
83 1 : return (float((rand()*float(x))/float(RAND_MAX)));
84 : }
85 : //1103515245+12345 are magic constants for LCG psuedorandom generator
86 3 : inline float detrnd(uint s, int x)
87 : {
88 3 : return static_cast<int>(((s*1103515245+12345)>>16)%x);
89 : }
90 :
91 : constexpr double SQRT2 = 1.4142135623731;
92 : constexpr double SQRT3 = 1.73205080756888;
93 :
94 : #ifdef WIN32
95 : #ifndef M_PI
96 : constexpr double M_PI = 3.14159265358979323846;
97 : #endif
98 : #ifndef M_LN2
99 : constexpr double M_LN2 = 0.693147180559945309417;
100 : #endif
101 :
102 : #ifndef __GNUC__
103 : #pragma warning (3: 4189) // local variable is initialized but not referenced
104 : #pragma warning (disable: 4244) // conversion from 'int' to 'float', possible loss of data
105 : #pragma warning (disable: 4267) // conversion from 'size_t' to 'int', possible loss of data
106 : #pragma warning (disable: 4355) // 'this' : used in base member initializer list
107 : #pragma warning (disable: 4996) // 'strncpy' was declared deprecated
108 : #endif
109 :
110 : #define strcasecmp _stricmp
111 : #define strncasecmp _strnicmp
112 : #define PATHDIV '\\'
113 :
114 : #else
115 : #define __cdecl
116 : #define _vsnprintf vsnprintf
117 : #define PATHDIV '/'
118 : #endif
119 :
120 : #define RAD static_cast<float>(180.0f / M_PI) //M_PI is a double
121 :
122 :
123 : #ifdef __GNUC__
124 : #define PRINTFARGS(fmt, args) __attribute__((format(printf, fmt, args)))
125 : #else
126 : #define PRINTFARGS(fmt, args)
127 : #endif
128 :
129 : // easy safe strings
130 : const int maxstrlen = 260;
131 :
132 : typedef char string[maxstrlen];
133 :
134 1622 : inline void vformatstring(char *d, const char *fmt, va_list v, int len) { _vsnprintf(d, len, fmt, v); d[len-1] = 0; }
135 :
136 : template<size_t N>
137 6 : inline void vformatstring(char (&d)[N], const char *fmt, va_list v) { vformatstring(d, fmt, v, N); }
138 :
139 1159 : inline char *copystring(char *d, const char *s, size_t len)
140 : {
141 1159 : size_t slen = min(strlen(s), len-1);
142 1159 : std::memcpy(d, s, slen);
143 1159 : d[slen] = 0;
144 1159 : return d;
145 : }
146 : template<size_t N>
147 16 : inline char *copystring(char (&d)[N], const char *s) { return copystring(d, s, N); }
148 :
149 16 : inline char *concatstring(char *d, const char *s, size_t len) { size_t used = strlen(d); return used < len ? copystring(d+used, s, len-used) : d; }
150 :
151 : template<size_t N>
152 15 : inline char *concatstring(char (&d)[N], const char *s) { return concatstring(d, s, N); }
153 :
154 : inline void nformatstring(char *d, int len, const char *fmt, ...) PRINTFARGS(3, 4);
155 200 : inline void nformatstring(char *d, int len, const char *fmt, ...)
156 : {
157 : va_list v;
158 200 : va_start(v, fmt);
159 200 : vformatstring(d, fmt, v, len);
160 200 : va_end(v);
161 200 : }
162 :
163 : template<size_t N>
164 : inline void formatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
165 :
166 : template<size_t N>
167 19 : inline void formatstring(char (&d)[N], const char *fmt, ...)
168 : {
169 : va_list v;
170 19 : va_start(v, fmt);
171 19 : vformatstring(d, fmt, v, static_cast<int>(N));
172 19 : va_end(v);
173 19 : }
174 :
175 : template<size_t N>
176 : inline void concformatstring(char (&d)[N], const char *fmt, ...) PRINTFARGS(2, 3);
177 :
178 : template<size_t N>
179 1 : inline void concformatstring(char (&d)[N], const char *fmt, ...)
180 : {
181 : va_list v;
182 1 : va_start(v, fmt);
183 1 : int len = strlen(d);
184 1 : vformatstring(d + len, fmt, v, static_cast<int>(N) - len);
185 1 : va_end(v);
186 1 : }
187 :
188 : extern char *tempformatstring(const char *fmt, ...) PRINTFARGS(1, 2);
189 :
190 : #define DEF_FORMAT_STRING(d,...) string d; formatstring(d, __VA_ARGS__)
191 : #define DEFV_FORMAT_STRING(d,last,fmt) string d; { va_list ap; va_start(ap, last); vformatstring(d, fmt, ap); va_end(ap); }
192 :
193 3 : inline bool matchstring(std::string_view s, size_t len, std::string_view d)
194 : {
195 3 : return len == d.size() && !std::memcmp(s.data(), d.data(), d.size());
196 : }
197 :
198 956 : inline char *newstring(size_t l)
199 : {
200 956 : return new char[l+1];
201 : }
202 403 : inline char *newstring(const char *s, size_t l)
203 : {
204 403 : return copystring(newstring(l), s, l+1);
205 : }
206 446 : inline char *newstring(const char *s)
207 : {
208 446 : size_t l = strlen(s);
209 446 : char *d = newstring(l);
210 446 : std::memcpy(d, s, l+1);
211 446 : return d;
212 : }
213 :
214 1 : inline char *newconcatstring(const char *s, const char *t)
215 : {
216 1 : size_t slen = strlen(s),
217 1 : tlen = strlen(t);
218 1 : char *r = newstring(slen + tlen);
219 1 : std::memcpy(r, s, slen);
220 1 : std::memcpy(&r[slen], t, tlen);
221 1 : r[slen+tlen] = '\0';
222 1 : return r;
223 : }
224 :
225 : template <class T>
226 : struct databuf
227 : {
228 : enum
229 : {
230 : OVERREAD = 1<<0,
231 : OVERWROTE = 1<<1
232 : };
233 :
234 : T *buf;
235 : int len, maxlen;
236 : uchar flags;
237 :
238 1 : databuf() : buf(nullptr), len(0), maxlen(0), flags(0) {}
239 :
240 : template<class U>
241 22 : databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen((int)maxlen), flags(0) {}
242 :
243 19 : void reset()
244 : {
245 19 : len = 0;
246 19 : flags = 0;
247 19 : }
248 :
249 1 : void reset(T *buf_, int maxlen_)
250 : {
251 1 : reset();
252 1 : buf = buf_;
253 1 : maxlen = maxlen_;
254 1 : }
255 :
256 : /**
257 : * @brief Adds an existing value in the underlying buffer to the databuf
258 : *
259 : * Increases the length of the databuf by one and incorporates the value at
260 : * the address after the end of the databuf's values.
261 : *
262 : * If the length is equal to or greater than the buffer's maximum length,
263 : * applies the OVERREAD flag and returns a null value.
264 : */
265 33 : const T &get()
266 : {
267 : static const T overreadval = 0;
268 33 : if(len<maxlen)
269 : {
270 32 : return buf[len++];
271 : }
272 1 : flags |= OVERREAD;
273 1 : return overreadval;
274 : }
275 :
276 : /**
277 : * @brief Returns a databuf<T> object containing the first n entries
278 : *
279 : * Returns a databuf object of type T which represents the first n elements
280 : * inside the databuf's array.
281 : *
282 : * If the size passed is larger than the databuf, the entire databuf object is
283 : * copied and returned.
284 : *
285 : * @param sz the size of the output array (aka get the first `sz` entries)
286 : *
287 : * @return the sub-buffer of `this` object
288 : */
289 1 : databuf subbuf(int sz)
290 : {
291 1 : sz = std::clamp(sz, 0, maxlen-len);
292 1 : len += sz;
293 1 : return databuf(&buf[len-sz], sz);
294 : }
295 :
296 : /**
297 : * @brief Adds N empty elements to the end of the array and returns a pointer
298 : *
299 : * Creates an array of size `sz` which is then pointed to and returned as
300 : * a naked pointer.
301 : *
302 : * @param sz the size of the buffer
303 : *
304 : * @return a pointer to the sub-array created
305 : */
306 2 : T *pad(int numvals)
307 : {
308 2 : T *vals = &buf[len];
309 2 : len += min(numvals, maxlen-len);
310 2 : return vals;
311 : }
312 :
313 : /**
314 : * @brief Adds an entry to the databuf if space is available
315 : *
316 : * If no space is available, applies the OVERWROTE flag to the flags field.
317 : *
318 : * @param val A const reference to the object to add
319 : */
320 36 : void put(const T &val)
321 : {
322 36 : if(len<maxlen)
323 : {
324 35 : buf[len++] = val;
325 : }
326 : else
327 : {
328 1 : flags |= OVERWROTE;
329 : }
330 36 : }
331 :
332 4 : void put(const T *vals, int numvals)
333 : {
334 4 : if(maxlen - len < numvals)
335 : {
336 1 : numvals = maxlen - len;
337 1 : flags |= OVERWROTE;
338 : }
339 4 : std::memcpy(&buf[len], (const void *)vals, numvals*sizeof(T));
340 4 : len += numvals;
341 4 : }
342 :
343 2 : int get(T *vals, int numvals)
344 : {
345 2 : if(maxlen - len < numvals)
346 : {
347 0 : numvals = maxlen - len;
348 0 : flags |= OVERREAD;
349 : }
350 2 : std::memcpy(vals, (void *)&buf[len], numvals*sizeof(T));
351 2 : len += numvals;
352 2 : return numvals;
353 : }
354 :
355 1 : void offset(int n)
356 : {
357 1 : n = min(n, maxlen);
358 1 : buf += n;
359 1 : maxlen -= n;
360 1 : len = max(len-n, 0);
361 1 : }
362 :
363 : /**
364 : * @brief Returns a pointer to the internal data array.
365 : *
366 : * This is a naked pointer to the internal data array and can therefore be used
367 : * to potentially break this container, if used carelessly.
368 : *
369 : * @return A pointer the data array
370 : */
371 3 : T *getbuf() const { return buf; }
372 :
373 : /**
374 : * @brief Returns whether any entries have been assigned to the array.
375 : *
376 : * @return true if the array has not been assigned to
377 : * @return false if the array has assigned values
378 : */
379 2 : bool empty() const { return len==0; }
380 :
381 : /**
382 : * @brief Returns the number of allocated entries in the databuf.
383 : *
384 : * Returns the number of entries which have been added to the databuf (not the
385 : * overall databuf size).
386 : *
387 : * @return the number of entries allocated in the databuf.
388 : */
389 8 : int length() const { return len; }
390 :
391 : /**
392 : * @brief Returns the number of values remaining before the databuf overflows.
393 : *
394 : * Returns the allocatable space remaining within the databuf object, in terms
395 : * of the number of entires which can be `put` into it before it becomes
396 : * OVERWROTE.
397 : *
398 : * @return the number of available entries in the databuf.
399 : */
400 17 : int remaining() const { return maxlen-len; }
401 :
402 : /**
403 : * @brief Returns whether the databuf has been accessed with too large of an index.
404 : *
405 : * Returns whether the OVERREAD flag has been set. If the databuf was attempted
406 : * to be accessed with an index larger than the number of allocated members,
407 : * this value will be set.
408 : *
409 : * @return true if the array has been overread
410 : * @return false if all read operations have been to valid entries
411 : */
412 6 : bool overread() const { return (flags&OVERREAD)!=0; }
413 :
414 : /**
415 : * @brief Returns whether the databuf has had invalid writes to it
416 : *
417 : * Returns whether the OVERWROTE flag has been set. If the databuf was attempted
418 : * to be wrote to while the databuf is already full, this flag will be set.
419 : *
420 : * @return true if the databuf has not been overwritten
421 : * @return false if the databuf has had only valid writes
422 : */
423 2 : bool overwrote() const { return (flags&OVERWROTE)!=0; }
424 :
425 4 : bool check(int n) { return remaining() >= n; }
426 :
427 1 : void forceoverread()
428 : {
429 1 : len = maxlen;
430 1 : flags |= OVERREAD;
431 1 : }
432 : };
433 :
434 : typedef databuf<char> charbuf;
435 : typedef databuf<uchar> ucharbuf;
436 :
437 11 : inline uint memhash(const void *ptr, int len)
438 : {
439 11 : const uchar *data = (const uchar *)ptr;
440 11 : uint h = 5381;
441 539 : for(int i = 0; i < static_cast<int>(len); ++i)
442 : {
443 528 : h = ((h<<5)+h)^data[i];
444 : }
445 11 : return h;
446 : }
447 :
448 : template<class T>
449 2 : inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = SDL_Swap32(conv.i); return conv.t; }
450 :
451 : template<>
452 3 : inline uint endianswap<uint>(uint n) { return SDL_Swap32(n); }
453 :
454 : template<>
455 4 : inline int endianswap<int>(int n) { return SDL_Swap32(n); }
456 :
457 : /* workaround for some C platforms that have these two functions as macros - not used anywhere */
458 : #ifdef getchar
459 : #undef getchar
460 : #endif
461 : #ifdef putchar
462 : #undef putchar
463 : #endif
464 :
465 : struct stream
466 : {
467 : #ifdef WIN32
468 : #if defined(__GNUC__) && !defined(__MINGW32__)
469 : typedef off64_t offset;
470 : #else
471 : typedef __int64 offset;
472 : #endif
473 : #else
474 : typedef off_t offset;
475 : #endif
476 : //see file/gz/zipstream children for more interesting forms
477 12 : virtual ~stream() {}
478 : virtual void close() = 0;
479 : virtual bool end() = 0;
480 4 : virtual offset tell() { return -1; }
481 1 : virtual offset rawtell() { return tell(); }
482 1 : virtual bool seek(offset, int) { return false; }
483 : virtual offset size();
484 1 : virtual offset rawsize() { return size(); }
485 4 : virtual size_t read(void *, size_t) { return 0; }
486 8 : virtual size_t write(const void *, size_t) { return 0; }
487 1 : virtual bool flush() { return true; }
488 1 : virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
489 1 : virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
490 : virtual bool getline(char *str, size_t len);
491 2 : virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; }
492 1 : virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
493 : virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3);
494 1 : virtual uint getcrc() { return 0; }
495 :
496 : template<class T>
497 1 : size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
498 :
499 : template<class T>
500 2 : bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
501 :
502 : template<class T>
503 1 : size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
504 :
505 : template<class T>
506 1 : T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
507 :
508 : template<class T>
509 1 : bool putbig(T n) { return put<T>(endianswap(n)); }
510 :
511 : SDL_RWops *rwops();
512 : };
513 :
514 : extern string homedir;
515 :
516 : extern char *path(char *s);
517 : extern std::string path(std::string s);
518 : extern char *copypath(const char *s);
519 : extern const char *sethomedir(const char *dir);
520 : extern const char *findfile(const char *filename, const char *mode);
521 :
522 : /**
523 : * @brief Initializes zip Cubescript commands.
524 : *
525 : * `addzip`
526 : *
527 : * `removezip`
528 : */
529 : extern void initzipcmds();
530 :
531 : extern stream *openrawfile(const char *filename, const char *mode);
532 : extern stream *openzipfile(const char *filename, const char *mode);
533 : extern stream *openfile(const char *filename, const char *mode);
534 : extern stream *opengzfile(const char *filename, const char *mode, stream *file = nullptr, int level = Z_BEST_COMPRESSION);
535 :
536 : template<class T>
537 13 : inline void putint_(T &p, int n)
538 : {
539 13 : if(n<128 && n>-127)
540 : {
541 11 : p.put(n);
542 : }
543 2 : else if(n<0x8000 && n>=-0x8000)
544 : {
545 1 : p.put(0x80);
546 1 : p.put(n);
547 1 : p.put(n>>8);
548 : }
549 : else
550 : {
551 1 : p.put(0x81);
552 1 : p.put(n);
553 1 : p.put(n>>8);
554 1 : p.put(n>>16);
555 1 : p.put(n>>24);
556 : }
557 13 : }
558 :
559 : template<class T>
560 4 : inline void putuint_(T &p, int n)
561 : {
562 4 : if(n < 0 || n >= (1<<21))
563 : {
564 1 : p.put(0x80 | (n & 0x7F));
565 1 : p.put(0x80 | ((n >> 7) & 0x7F));
566 1 : p.put(0x80 | ((n >> 14) & 0x7F));
567 1 : p.put(n >> 21);
568 : }
569 3 : else if(n < (1<<7))
570 : {
571 1 : p.put(n);
572 : }
573 2 : else if(n < (1<<14))
574 : {
575 1 : p.put(0x80 | (n & 0x7F));
576 1 : p.put(n >> 7);
577 : }
578 : else
579 : {
580 1 : p.put(0x80 | (n & 0x7F));
581 1 : p.put(0x80 | ((n >> 7) & 0x7F));
582 1 : p.put(n >> 14);
583 : }
584 4 : }
585 :
586 : extern void putint(std::vector<uchar> &p, int n);
587 :
588 : template<typename T>
589 11 : inline void vectorput(std::vector<uint8_t>& buf, const T& data)
590 : {
591 11 : const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&data);
592 11 : buf.insert(buf.end(), data_ptr, data_ptr + sizeof(T));
593 11 : }
594 :
595 1 : inline void vectorput(std::vector<uint8_t>& buf, const uint8_t* data, size_t size)
596 : {
597 1 : buf.insert(buf.end(), data, data + size);
598 1 : }
599 :
600 : template<class T>
601 2 : inline void sendstring_(const char *t, T &p)
602 : {
603 10 : while(*t)
604 : {
605 8 : putint(p, *t++);
606 : }
607 2 : putint(p, 0);
608 2 : }
609 :
610 : template<class T>
611 2 : inline void putfloat_(T &p, float f)
612 : {
613 2 : p.put((uchar *)&f, sizeof(float));
614 2 : }
615 :
616 : extern void putint(ucharbuf &p, int n);
617 : extern int getint(ucharbuf &p);
618 : extern void putuint(ucharbuf &p, int n);
619 : extern int getuint(ucharbuf &p);
620 : extern void putfloat(ucharbuf &p, float f);
621 : extern float getfloat(ucharbuf &p);
622 : extern void sendstring(const char *t, ucharbuf &p);
623 : extern void getstring(char *t, ucharbuf &p, size_t len);
624 :
625 : template<size_t N>
626 1 : inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); }
627 :
628 : extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len);
629 :
630 : template<size_t N>
631 : inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
632 :
633 : #endif /* TOOLS_H_ */
|