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 1618 : 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 15 : inline void formatstring(char (&d)[N], const char *fmt, ...)
168 : {
169 : va_list v;
170 15 : va_start(v, fmt);
171 15 : vformatstring(d, fmt, v, static_cast<int>(N));
172 15 : va_end(v);
173 15 : }
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 959 : inline char *newstring(size_t l)
194 : {
195 959 : return new char[l+1];
196 : }
197 :
198 403 : inline char *newstring(const char *s, size_t l)
199 : {
200 403 : return copystring(newstring(l), s, l+1);
201 : }
202 :
203 449 : inline char *newstring(const char *s)
204 : {
205 449 : size_t l = strlen(s);
206 449 : char *d = newstring(l);
207 449 : std::memcpy(d, s, l+1);
208 449 : return d;
209 : }
210 :
211 1 : inline char *newconcatstring(const char *s, const char *t)
212 : {
213 1 : size_t slen = strlen(s),
214 1 : tlen = strlen(t);
215 1 : char *r = newstring(slen + tlen);
216 1 : std::memcpy(r, s, slen);
217 1 : std::memcpy(&r[slen], t, tlen);
218 1 : r[slen+tlen] = '\0';
219 1 : return r;
220 : }
221 :
222 : template <class T>
223 : struct databuf
224 : {
225 : enum
226 : {
227 : OVERREAD = 1<<0,
228 : OVERWROTE = 1<<1
229 : };
230 :
231 : T *buf;
232 : int len, maxlen;
233 : uchar flags;
234 :
235 1 : databuf() : buf(nullptr), len(0), maxlen(0), flags(0) {}
236 :
237 : template<class U>
238 22 : databuf(T *buf, U maxlen) : buf(buf), len(0), maxlen(static_cast<int>(maxlen)), flags(0) {}
239 :
240 19 : void reset()
241 : {
242 19 : len = 0;
243 19 : flags = 0;
244 19 : }
245 :
246 1 : void reset(T *buf_, int maxlen_)
247 : {
248 1 : reset();
249 1 : buf = buf_;
250 1 : maxlen = maxlen_;
251 1 : }
252 :
253 : /**
254 : * @brief Adds an existing value in the underlying buffer to the databuf
255 : *
256 : * Increases the length of the databuf by one and incorporates the value at
257 : * the address after the end of the databuf's values.
258 : *
259 : * If the length is equal to or greater than the buffer's maximum length,
260 : * applies the OVERREAD flag and returns a null value.
261 : */
262 33 : const T &get()
263 : {
264 : static const T overreadval = 0;
265 33 : if(len<maxlen)
266 : {
267 32 : return buf[len++];
268 : }
269 1 : flags |= OVERREAD;
270 1 : return overreadval;
271 : }
272 :
273 : /**
274 : * @brief Returns a databuf<T> object containing the first n entries
275 : *
276 : * Returns a databuf object of type T which represents the first n elements
277 : * inside the databuf's array.
278 : *
279 : * If the size passed is larger than the databuf, the entire databuf object is
280 : * copied and returned.
281 : *
282 : * @param sz the size of the output array (aka get the first `sz` entries)
283 : *
284 : * @return the sub-buffer of `this` object
285 : */
286 1 : databuf subbuf(int sz)
287 : {
288 1 : sz = std::clamp(sz, 0, maxlen-len);
289 1 : len += sz;
290 1 : return databuf(&buf[len-sz], sz);
291 : }
292 :
293 : /**
294 : * @brief Adds N empty elements to the end of the array and returns a pointer
295 : *
296 : * Creates an array of size `sz` which is then pointed to and returned as
297 : * a naked pointer.
298 : *
299 : * @param sz the size of the buffer
300 : *
301 : * @return a pointer to the sub-array created
302 : */
303 2 : T *pad(int numvals)
304 : {
305 2 : T *vals = &buf[len];
306 2 : len += min(numvals, maxlen-len);
307 2 : return vals;
308 : }
309 :
310 : /**
311 : * @brief Adds an entry to the databuf if space is available
312 : *
313 : * If no space is available, applies the OVERWROTE flag to the flags field.
314 : *
315 : * @param val A const reference to the object to add
316 : */
317 36 : void put(const T &val)
318 : {
319 36 : if(len<maxlen)
320 : {
321 35 : buf[len++] = val;
322 : }
323 : else
324 : {
325 1 : flags |= OVERWROTE;
326 : }
327 36 : }
328 :
329 4 : void put(const T *vals, int numvals)
330 : {
331 4 : if(maxlen - len < numvals)
332 : {
333 1 : numvals = maxlen - len;
334 1 : flags |= OVERWROTE;
335 : }
336 4 : std::memcpy(&buf[len], static_cast<const void *>(vals), numvals*sizeof(T));
337 4 : len += numvals;
338 4 : }
339 :
340 2 : int get(T *vals, int numvals)
341 : {
342 2 : if(maxlen - len < numvals)
343 : {
344 0 : numvals = maxlen - len;
345 0 : flags |= OVERREAD;
346 : }
347 2 : std::memcpy(vals, static_cast<void *>(&buf[len]), numvals*sizeof(T));
348 2 : len += numvals;
349 2 : return numvals;
350 : }
351 :
352 1 : void offset(int n)
353 : {
354 1 : n = min(n, maxlen);
355 1 : buf += n;
356 1 : maxlen -= n;
357 1 : len = max(len-n, 0);
358 1 : }
359 :
360 : /**
361 : * @brief Returns a pointer to the internal data array.
362 : *
363 : * This is a naked pointer to the internal data array and can therefore be used
364 : * to potentially break this container, if used carelessly.
365 : *
366 : * @return A pointer the data array
367 : */
368 3 : T *getbuf() const { return buf; }
369 :
370 : /**
371 : * @brief Returns whether any entries have been assigned to the array.
372 : *
373 : * @return true if the array has not been assigned to
374 : * @return false if the array has assigned values
375 : */
376 2 : bool empty() const { return len==0; }
377 :
378 : /**
379 : * @brief Returns the number of allocated entries in the databuf.
380 : *
381 : * Returns the number of entries which have been added to the databuf (not the
382 : * overall databuf size).
383 : *
384 : * @return the number of entries allocated in the databuf.
385 : */
386 8 : int length() const { return len; }
387 :
388 : /**
389 : * @brief Returns the number of values remaining before the databuf overflows.
390 : *
391 : * Returns the allocatable space remaining within the databuf object, in terms
392 : * of the number of entires which can be `put` into it before it becomes
393 : * OVERWROTE.
394 : *
395 : * @return the number of available entries in the databuf.
396 : */
397 17 : int remaining() const { return maxlen-len; }
398 :
399 : /**
400 : * @brief Returns whether the databuf has been accessed with too large of an index.
401 : *
402 : * Returns whether the OVERREAD flag has been set. If the databuf was attempted
403 : * to be accessed with an index larger than the number of allocated members,
404 : * this value will be set.
405 : *
406 : * @return true if the array has been overread
407 : * @return false if all read operations have been to valid entries
408 : */
409 6 : bool overread() const { return (flags&OVERREAD)!=0; }
410 :
411 : /**
412 : * @brief Returns whether the databuf has had invalid writes to it
413 : *
414 : * Returns whether the OVERWROTE flag has been set. If the databuf was attempted
415 : * to be wrote to while the databuf is already full, this flag will be set.
416 : *
417 : * @return true if the databuf has not been overwritten
418 : * @return false if the databuf has had only valid writes
419 : */
420 2 : bool overwrote() const { return (flags&OVERWROTE)!=0; }
421 :
422 4 : bool check(int n) { return remaining() >= n; }
423 :
424 1 : void forceoverread()
425 : {
426 1 : len = maxlen;
427 1 : flags |= OVERREAD;
428 1 : }
429 : };
430 :
431 : typedef databuf<char> charbuf;
432 : typedef databuf<uchar> ucharbuf;
433 :
434 11 : inline uint memhash(const void *ptr, int len)
435 : {
436 11 : const uchar *data = static_cast<const uchar *>(ptr);
437 11 : uint h = 5381;
438 539 : for(int i = 0; i < static_cast<int>(len); ++i)
439 : {
440 528 : h = ((h<<5)+h)^data[i];
441 : }
442 11 : return h;
443 : }
444 :
445 : template<class T>
446 : inline T endianswap(T n) { union { T t; uint i; } conv; conv.t = n; conv.i = SDL_Swap32(conv.i); return conv.t; }
447 :
448 : template<>
449 5 : inline uint endianswap<uint>(uint n) { return SDL_Swap32(n); }
450 :
451 : template<>
452 4 : inline int endianswap<int>(int n) { return SDL_Swap32(n); }
453 :
454 : /* workaround for some C platforms that have these two functions as macros - not used anywhere */
455 : #ifdef getchar
456 : #undef getchar
457 : #endif
458 : #ifdef putchar
459 : #undef putchar
460 : #endif
461 :
462 : struct stream
463 : {
464 : #ifdef WIN32
465 : #if defined(__GNUC__) && !defined(__MINGW32__)
466 : typedef off64_t offset;
467 : #else
468 : typedef __int64 offset;
469 : #endif
470 : #else
471 : typedef off_t offset;
472 : #endif
473 : //see file/gz/zipstream children for more interesting forms
474 12 : virtual ~stream() {}
475 : virtual void close() = 0;
476 : virtual bool end() = 0;
477 4 : virtual offset tell() const { return -1; }
478 1 : virtual offset rawtell() const { return tell(); }
479 1 : virtual bool seek(offset, int) { return false; }
480 : virtual offset size();
481 1 : virtual offset rawsize() { return size(); }
482 4 : virtual size_t read(void *, size_t) { return 0; }
483 8 : virtual size_t write(const void *, size_t) { return 0; }
484 1 : virtual bool flush() { return true; }
485 2 : virtual int getchar() { uchar c; return read(&c, 1) == 1 ? c : -1; }
486 2 : virtual bool putchar(int n) { uchar c = n; return write(&c, 1) == 1; }
487 : virtual bool getline(char *str, size_t len);
488 2 : virtual bool putstring(const char *str) { size_t len = strlen(str); return write(str, len) == len; }
489 1 : virtual bool putline(const char *str) { return putstring(str) && putchar('\n'); }
490 : virtual size_t printf(const char *fmt, ...) PRINTFARGS(2, 3);
491 1 : virtual uint getcrc() { return 0; }
492 :
493 : template<class T>
494 1 : size_t put(const T *v, size_t n) { return write(v, n*sizeof(T))/sizeof(T); }
495 :
496 : template<class T>
497 2 : bool put(T n) { return write(&n, sizeof(n)) == sizeof(n); }
498 :
499 : template<class T>
500 1 : size_t get(T *v, size_t n) { return read(v, n*sizeof(T))/sizeof(T); }
501 :
502 : template<class T>
503 2 : T get() { T n; return read(&n, sizeof(n)) == sizeof(n) ? n : 0; }
504 :
505 : template<class T>
506 1 : bool putbig(T n) { return put<T>(endianswap(n)); }
507 :
508 : SDL_RWops *rwops();
509 : };
510 :
511 : extern std::string homedir;
512 :
513 : extern char *path(char *s);
514 : extern std::string path(std::string s);
515 : extern char *copypath(const char *s);
516 : extern const char *sethomedir(const char *dir);
517 : extern const char *findfile(const char *filename, const char *mode);
518 :
519 : /**
520 : * @brief Initializes zip Cubescript commands.
521 : *
522 : * `addzip`
523 : *
524 : * `removezip`
525 : */
526 : extern void initzipcmds();
527 :
528 : extern stream *openrawfile(const char *filename, const char *mode);
529 : extern stream *openzipfile(const char *filename, const char *mode);
530 : extern stream *openfile(const char *filename, const char *mode);
531 : extern stream *opengzfile(const char *filename, const char *mode, stream *file = nullptr, int level = Z_BEST_COMPRESSION);
532 :
533 : template<class T>
534 13 : inline void putint_(T &p, int n)
535 : {
536 13 : if(n<128 && n>-127)
537 : {
538 11 : p.put(n);
539 : }
540 2 : else if(n<0x8000 && n>=-0x8000)
541 : {
542 1 : p.put(0x80);
543 1 : p.put(n);
544 1 : p.put(n>>8);
545 : }
546 : else
547 : {
548 1 : p.put(0x81);
549 1 : p.put(n);
550 1 : p.put(n>>8);
551 1 : p.put(n>>16);
552 1 : p.put(n>>24);
553 : }
554 13 : }
555 :
556 : template<class T>
557 4 : inline void putuint_(T &p, int n)
558 : {
559 4 : if(n < 0 || n >= (1<<21))
560 : {
561 1 : p.put(0x80 | (n & 0x7F));
562 1 : p.put(0x80 | ((n >> 7) & 0x7F));
563 1 : p.put(0x80 | ((n >> 14) & 0x7F));
564 1 : p.put(n >> 21);
565 : }
566 3 : else if(n < (1<<7))
567 : {
568 1 : p.put(n);
569 : }
570 2 : else if(n < (1<<14))
571 : {
572 1 : p.put(0x80 | (n & 0x7F));
573 1 : p.put(n >> 7);
574 : }
575 : else
576 : {
577 1 : p.put(0x80 | (n & 0x7F));
578 1 : p.put(0x80 | ((n >> 7) & 0x7F));
579 1 : p.put(n >> 14);
580 : }
581 4 : }
582 :
583 : extern void putint(std::vector<uchar> &p, int n);
584 :
585 : template<typename T>
586 11 : inline void vectorput(std::vector<uint8_t>& buf, const T& data)
587 : {
588 11 : const uint8_t* data_ptr = reinterpret_cast<const uint8_t*>(&data);
589 11 : buf.insert(buf.end(), data_ptr, data_ptr + sizeof(T));
590 11 : }
591 :
592 1 : inline void vectorput(std::vector<uint8_t>& buf, const uint8_t* data, size_t size)
593 : {
594 1 : buf.insert(buf.end(), data, data + size);
595 1 : }
596 :
597 : template<class T>
598 2 : inline void sendstring_(const char *t, T &p)
599 : {
600 10 : while(*t)
601 : {
602 8 : putint(p, *t++);
603 : }
604 2 : putint(p, 0);
605 2 : }
606 :
607 : template<class T>
608 2 : inline void putfloat_(T &p, float f)
609 : {
610 2 : p.put(reinterpret_cast<uchar *>(&f), sizeof(float));
611 2 : }
612 :
613 : extern void putint(ucharbuf &p, int n);
614 : extern int getint(ucharbuf &p);
615 : extern void putuint(ucharbuf &p, int n);
616 : extern int getuint(ucharbuf &p);
617 : extern void putfloat(ucharbuf &p, float f);
618 : extern float getfloat(ucharbuf &p);
619 : extern void sendstring(const char *t, ucharbuf &p);
620 : extern void getstring(char *t, ucharbuf &p, size_t len);
621 :
622 : template<size_t N>
623 1 : inline void getstring(char (&t)[N], ucharbuf &p) { getstring(t, p, N); }
624 :
625 : extern void filtertext(char *dst, const char *src, bool whitespace, bool forcespace, size_t len);
626 :
627 : template<size_t N>
628 : inline void filtertext(char (&dst)[N], const char *src, bool whitespace = true, bool forcespace = false) { filtertext(dst, src, whitespace, forcespace, N-1); }
629 :
630 : #endif /* TOOLS_H_ */
|