mirror of
https://github.com/Relintai/sfw.git
synced 2025-02-06 15:05:54 +01:00
Added some of the utils from rcpp_fw.
This commit is contained in:
parent
b22a755150
commit
eeb4e7dba0
19
core/SCsub
Normal file
19
core/SCsub
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env.core_sources = []
|
||||||
|
|
||||||
|
env.add_source_files(env.core_sources, "*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./math/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./containers/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./log/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./os/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./image/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./threading/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./settings/*.cpp")
|
||||||
|
env.add_source_files(env.core_sources, "./nodes/*.cpp")
|
||||||
|
|
||||||
|
# Build it all as a library
|
||||||
|
lib = env.add_library("core", env.core_sources)
|
||||||
|
env.Prepend(LIBS=[lib])
|
229
core/containers/queue.h
Normal file
229
core/containers/queue.h
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
#ifndef QUEUE_H
|
||||||
|
#define QUEUE_H
|
||||||
|
|
||||||
|
#include "core/error_macros.h"
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
class Queue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void enqueue(const T &job);
|
||||||
|
T dequeue();
|
||||||
|
const T &peek() const;
|
||||||
|
|
||||||
|
bool is_empty() const;
|
||||||
|
bool is_full() const;
|
||||||
|
|
||||||
|
int size() const;
|
||||||
|
int capacity() const;
|
||||||
|
void ensure_capacity(const int capacity);
|
||||||
|
void resize(const int s);
|
||||||
|
|
||||||
|
void pack();
|
||||||
|
|
||||||
|
Queue();
|
||||||
|
Queue(int prealloc);
|
||||||
|
Queue(int prealloc, int grow_by);
|
||||||
|
~Queue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* _data;
|
||||||
|
int _head;
|
||||||
|
int _tail;
|
||||||
|
|
||||||
|
int _capacity;
|
||||||
|
int _grow_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Queue<T>::pack()
|
||||||
|
{
|
||||||
|
if (_head == _tail)
|
||||||
|
{
|
||||||
|
_head = 0;
|
||||||
|
_tail = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_head == 0 && _tail == _capacity)
|
||||||
|
{
|
||||||
|
resize(_capacity + _grow_size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
|
||||||
|
for (int i = _head; i < _tail; ++i)
|
||||||
|
{
|
||||||
|
_data[j++] = _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_head = 0;
|
||||||
|
_tail = j;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Queue<T>::enqueue(const T &job)
|
||||||
|
{
|
||||||
|
if (_tail == _capacity)
|
||||||
|
{
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
_data[_tail++] = job;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Queue<T>::dequeue()
|
||||||
|
{
|
||||||
|
CRASH_COND(is_empty());
|
||||||
|
|
||||||
|
return _data[_head++];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
const T &Queue<T>::peek() const
|
||||||
|
{
|
||||||
|
CRASH_COND(is_empty());
|
||||||
|
|
||||||
|
return _data[_head];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool Queue<T>::is_empty() const
|
||||||
|
{
|
||||||
|
return _head == _tail;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool Queue<T>::is_full() const
|
||||||
|
{
|
||||||
|
return (_head == 0) && (_tail == _capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int Queue<T>::size() const
|
||||||
|
{
|
||||||
|
return _tail - _head;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int Queue<T>::capacity() const
|
||||||
|
{
|
||||||
|
return _capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Queue<T>::ensure_capacity(const int capacity)
|
||||||
|
{
|
||||||
|
if (_capacity < capacity)
|
||||||
|
{
|
||||||
|
resize(capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Queue<T>::resize(const int s)
|
||||||
|
{
|
||||||
|
if (s == 0 && _data)
|
||||||
|
{
|
||||||
|
delete[] _data;
|
||||||
|
|
||||||
|
_data = nullptr;
|
||||||
|
|
||||||
|
_capacity = s;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_data)
|
||||||
|
{
|
||||||
|
_data = new T[s];
|
||||||
|
_capacity = s;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_empty())
|
||||||
|
{
|
||||||
|
delete[] _data;
|
||||||
|
|
||||||
|
_data = new T[s];
|
||||||
|
|
||||||
|
_capacity = s;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_full())
|
||||||
|
{
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* nd = new T[s];
|
||||||
|
|
||||||
|
int to = s > _tail ? _tail : s;
|
||||||
|
|
||||||
|
for (int i = 0; i < to; ++i)
|
||||||
|
{
|
||||||
|
nd[i] = _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] _data;
|
||||||
|
_data = nd;
|
||||||
|
_capacity = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Queue<T>::Queue()
|
||||||
|
{
|
||||||
|
_data = nullptr;
|
||||||
|
|
||||||
|
_head = 0;
|
||||||
|
_tail = 0;
|
||||||
|
|
||||||
|
_capacity = 20;
|
||||||
|
_grow_size = 10;
|
||||||
|
resize(_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Queue<T>::Queue(int prealloc)
|
||||||
|
{
|
||||||
|
_data = nullptr;
|
||||||
|
|
||||||
|
_head = 0;
|
||||||
|
_tail = 0;
|
||||||
|
|
||||||
|
_capacity = prealloc;
|
||||||
|
_grow_size = 10;
|
||||||
|
resize(_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Queue<T>::Queue(int prealloc, int grow_by)
|
||||||
|
{
|
||||||
|
_data = nullptr;
|
||||||
|
|
||||||
|
_head = 0;
|
||||||
|
_tail = 0;
|
||||||
|
|
||||||
|
_capacity = prealloc;
|
||||||
|
_grow_size = grow_by;
|
||||||
|
resize(_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Queue<T>::~Queue()
|
||||||
|
{
|
||||||
|
if (_data)
|
||||||
|
{
|
||||||
|
delete[] _data;
|
||||||
|
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
287
core/containers/vector.h
Normal file
287
core/containers/vector.h
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
#ifndef VECTOR_H
|
||||||
|
#define VECTOR_H
|
||||||
|
|
||||||
|
#include "core/error_macros.h"
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Vector {
|
||||||
|
|
||||||
|
public:
|
||||||
|
void push_back(const T &element);
|
||||||
|
void pop_back();
|
||||||
|
void remove(const int index);
|
||||||
|
void remove_keep_order(const int index);
|
||||||
|
void erase(const T &element);
|
||||||
|
void clear();
|
||||||
|
bool empty() const;
|
||||||
|
T get(const int index);
|
||||||
|
const T &get(const int index) const;
|
||||||
|
void set(const int index, const T &value);
|
||||||
|
void swap(const int index1, const int index2);
|
||||||
|
|
||||||
|
void sort_inc();
|
||||||
|
void sort_dec();
|
||||||
|
|
||||||
|
int size() const;
|
||||||
|
int capacity() const;
|
||||||
|
void ensure_capacity(const int capacity);
|
||||||
|
void resize(const int s);
|
||||||
|
void append_array(const Vector<T> &other);
|
||||||
|
int find(const T &val) const;
|
||||||
|
|
||||||
|
T *dataw();
|
||||||
|
const T *data() const;
|
||||||
|
|
||||||
|
const T &operator[](const int index) const;
|
||||||
|
T &operator[](const int index);
|
||||||
|
|
||||||
|
Vector &operator=(const Vector &other);
|
||||||
|
|
||||||
|
Vector();
|
||||||
|
Vector(int prealloc);
|
||||||
|
Vector(int prealloc, int grow_by);
|
||||||
|
Vector(const Vector &other);
|
||||||
|
~Vector();
|
||||||
|
|
||||||
|
private:
|
||||||
|
T *_data;
|
||||||
|
int _actual_size;
|
||||||
|
int _size;
|
||||||
|
int _grow_by;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::push_back(const T &element) {
|
||||||
|
ensure_capacity(_size + 1);
|
||||||
|
|
||||||
|
_data[_size++] = element;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::pop_back() {
|
||||||
|
if (_size == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::remove(const int index) {
|
||||||
|
_data[index] = _data[_size - 1];
|
||||||
|
|
||||||
|
--_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::remove_keep_order(const int index) {
|
||||||
|
--_size;
|
||||||
|
|
||||||
|
for (int i = index; i < _size; ++i) {
|
||||||
|
_data[i] = _data[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::erase(const T &element) {
|
||||||
|
int index = find(element);
|
||||||
|
|
||||||
|
if (index != -1) {
|
||||||
|
remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::clear() {
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool Vector<T>::empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T Vector<T>::get(const int index) {
|
||||||
|
return _data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
const T &Vector<T>::get(const int index) const {
|
||||||
|
return _data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::set(const int index, const T &value) {
|
||||||
|
_data[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::swap(const int index1, const int index2) {
|
||||||
|
T e = _data[index1];
|
||||||
|
_data[index1] = _data[index2];
|
||||||
|
_data[index2] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::sort_inc() {
|
||||||
|
for (int i = 0; i < _size; ++i) {
|
||||||
|
for (int j = i + 1; j < _size; ++j) {
|
||||||
|
if (_data[j] < _data[i]) {
|
||||||
|
swap(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::sort_dec() {
|
||||||
|
for (int i = 0; i < _size; ++i) {
|
||||||
|
for (int j = i + 1; j < _size; ++j) {
|
||||||
|
if (_data[j] > _data[i]) {
|
||||||
|
swap(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int Vector<T>::size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int Vector<T>::capacity() const {
|
||||||
|
return _actual_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::ensure_capacity(const int capacity) {
|
||||||
|
if (capacity <= _actual_size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tsize = capacity + _grow_by;
|
||||||
|
|
||||||
|
T *nd = new T[tsize];
|
||||||
|
|
||||||
|
if (_data) {
|
||||||
|
for (int i = 0; i < _size; ++i) {
|
||||||
|
nd[i] = _data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_data = nd;
|
||||||
|
_actual_size = tsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::resize(const int s) {
|
||||||
|
ensure_capacity(s);
|
||||||
|
|
||||||
|
_size = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void Vector<T>::append_array(const Vector<T> &other) {
|
||||||
|
ensure_capacity(_size + other._size);
|
||||||
|
|
||||||
|
for (int i = 0; i < other._size; ++i) {
|
||||||
|
_data[_size++] = other._data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
int Vector<T>::find(const T &val) const {
|
||||||
|
for (int i = 0; i < _size; ++i) {
|
||||||
|
if (_data[i] == val) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T *Vector<T>::dataw() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
const T *Vector<T>::data() const {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
const T &Vector<T>::operator[](const int index) const {
|
||||||
|
return _data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
T &Vector<T>::operator[](const int index) {
|
||||||
|
return _data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T> &Vector<T>::operator=(const Vector<T> &other) {
|
||||||
|
resize(0);
|
||||||
|
ensure_capacity(other.size());
|
||||||
|
append_array(other);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T>::Vector() {
|
||||||
|
_data = nullptr;
|
||||||
|
_actual_size = 0;
|
||||||
|
_size = 0;
|
||||||
|
_grow_by = 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T>::Vector(int prealloc) {
|
||||||
|
_data = nullptr;
|
||||||
|
_actual_size = 0;
|
||||||
|
_size = 0;
|
||||||
|
_grow_by = 100;
|
||||||
|
|
||||||
|
ensure_capacity(prealloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T>::Vector(int prealloc, int grow_by) {
|
||||||
|
_data = nullptr;
|
||||||
|
_actual_size = 0;
|
||||||
|
_size = 0;
|
||||||
|
_grow_by = grow_by;
|
||||||
|
|
||||||
|
ensure_capacity(prealloc);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T>::Vector(const Vector<T> &other) {
|
||||||
|
_actual_size = other._actual_size;
|
||||||
|
_size = other._size;
|
||||||
|
_grow_by = other._grow_by;
|
||||||
|
|
||||||
|
if (other._data) {
|
||||||
|
_data = new T[_actual_size];
|
||||||
|
|
||||||
|
for (int i = 0; i < _size; ++i) {
|
||||||
|
_data[i] = other._data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
Vector<T>::~Vector() {
|
||||||
|
if (_data) {
|
||||||
|
delete[] _data;
|
||||||
|
_data = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
93
core/error_list.h
Normal file
93
core/error_list.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* error_list.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef ERROR_LIST_H
|
||||||
|
#define ERROR_LIST_H
|
||||||
|
|
||||||
|
/** Error List. Please never compare an error against FAILED
|
||||||
|
* Either do result != OK , or !result. This way, Error fail
|
||||||
|
* values can be more detailed in the future.
|
||||||
|
*
|
||||||
|
* This is a generic error list, mainly for organizing a language of returning errors.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum Error {
|
||||||
|
OK, // (0)
|
||||||
|
FAILED, ///< Generic fail error
|
||||||
|
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
|
||||||
|
ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
|
||||||
|
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
|
||||||
|
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
|
||||||
|
ERR_OUT_OF_MEMORY, ///< Out of memory
|
||||||
|
ERR_FILE_NOT_FOUND,
|
||||||
|
ERR_FILE_BAD_DRIVE,
|
||||||
|
ERR_FILE_BAD_PATH,
|
||||||
|
ERR_FILE_NO_PERMISSION, // (10)
|
||||||
|
ERR_FILE_ALREADY_IN_USE,
|
||||||
|
ERR_FILE_CANT_OPEN,
|
||||||
|
ERR_FILE_CANT_WRITE,
|
||||||
|
ERR_FILE_CANT_READ,
|
||||||
|
ERR_FILE_UNRECOGNIZED, // (15)
|
||||||
|
ERR_FILE_CORRUPT,
|
||||||
|
ERR_FILE_MISSING_DEPENDENCIES,
|
||||||
|
ERR_FILE_EOF,
|
||||||
|
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
|
||||||
|
ERR_CANT_CREATE, // (20)
|
||||||
|
ERR_QUERY_FAILED,
|
||||||
|
ERR_ALREADY_IN_USE,
|
||||||
|
ERR_LOCKED, ///< resource is locked
|
||||||
|
ERR_TIMEOUT,
|
||||||
|
ERR_CANT_CONNECT, // (25)
|
||||||
|
ERR_CANT_RESOLVE,
|
||||||
|
ERR_CONNECTION_ERROR,
|
||||||
|
ERR_CANT_ACQUIRE_RESOURCE,
|
||||||
|
ERR_CANT_FORK,
|
||||||
|
ERR_INVALID_DATA, ///< Data passed is invalid (30)
|
||||||
|
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
|
||||||
|
ERR_ALREADY_EXISTS, ///< When adding, item already exists
|
||||||
|
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
|
||||||
|
ERR_DATABASE_CANT_READ, ///< database is full
|
||||||
|
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
|
||||||
|
ERR_COMPILATION_FAILED,
|
||||||
|
ERR_METHOD_NOT_FOUND,
|
||||||
|
ERR_LINK_FAILED,
|
||||||
|
ERR_SCRIPT_FAILED,
|
||||||
|
ERR_CYCLIC_LINK, // (40)
|
||||||
|
ERR_INVALID_DECLARATION,
|
||||||
|
ERR_DUPLICATE_SYMBOL,
|
||||||
|
ERR_PARSE_ERROR,
|
||||||
|
ERR_BUSY,
|
||||||
|
ERR_SKIP, // (45)
|
||||||
|
ERR_HELP, ///< user requested help!!
|
||||||
|
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
|
||||||
|
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
216
core/error_macros.h
Normal file
216
core/error_macros.h
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#ifndef ERROR_MACROS_H
|
||||||
|
#define ERROR_MACROS_H
|
||||||
|
|
||||||
|
#include "core/log/logger.h"
|
||||||
|
#include "typedefs.h"
|
||||||
|
|
||||||
|
// Based on Godot Engine's error_macros.h
|
||||||
|
// MIT License
|
||||||
|
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
|
||||||
|
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define GENERATE_TRAP \
|
||||||
|
__debugbreak(); \
|
||||||
|
/* Avoid warning about control paths */ \
|
||||||
|
for (;;) { \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define GENERATE_TRAP __builtin_trap();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// template methods for the variadic log macros. Add more as needed.
|
||||||
|
template <class STR, class A>
|
||||||
|
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0) {
|
||||||
|
str->append(p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class STR, class A, class B>
|
||||||
|
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1) {
|
||||||
|
str->append(p0);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class STR, class A, class B, class C>
|
||||||
|
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2) {
|
||||||
|
str->append(p0);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p1);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class STR, class A, class B, class C, class D>
|
||||||
|
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3) {
|
||||||
|
str->append(p0);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p1);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p2);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p3);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class STR, class A, class B, class C, class D, class E>
|
||||||
|
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E p4) {
|
||||||
|
str->append(p0);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p1);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p2);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p3);
|
||||||
|
str->push_back(' ');
|
||||||
|
str->append(p4);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RPRINT_TRACE(str) \
|
||||||
|
RLogger::print_trace(__FUNCTION__, __FILE__, __LINE__, str);
|
||||||
|
|
||||||
|
#define RLOG_TRACE(...) \
|
||||||
|
{ \
|
||||||
|
String *_rlogger_string_ptr = RLogger::get_trace_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
|
||||||
|
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
|
||||||
|
RLogger::log_ret_ptr(_rlogger_string_ptr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RPRINT_MSG(str) \
|
||||||
|
RLogger::print_message(__FUNCTION__, __FILE__, __LINE__, str);
|
||||||
|
|
||||||
|
#define RLOG_MSG(...) \
|
||||||
|
{ \
|
||||||
|
String *_rlogger_string_ptr = RLogger::get_message_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
|
||||||
|
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
|
||||||
|
RLogger::log_ret_ptr(_rlogger_string_ptr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RPRINT_WARN(str) \
|
||||||
|
RLogger::print_warning(__FUNCTION__, __FILE__, __LINE__, str);
|
||||||
|
|
||||||
|
#define RLOG_WARN(...) \
|
||||||
|
{ \
|
||||||
|
String *_rlogger_string_ptr = RLogger::get_warning_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
|
||||||
|
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
|
||||||
|
RLogger::log_ret_ptr(_rlogger_string_ptr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RPRINT_ERR(str) \
|
||||||
|
RLogger::print_error(__FUNCTION__, __FILE__, __LINE__, str);
|
||||||
|
|
||||||
|
#define RLOG_ERR(...) \
|
||||||
|
{ \
|
||||||
|
String *_rlogger_string_ptr = RLogger::get_error_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
|
||||||
|
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
|
||||||
|
RLogger::log_ret_ptr(_rlogger_string_ptr); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ERR_FAIL_MSG(msg) \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
return;
|
||||||
|
|
||||||
|
#define ERR_FAIL_V_MSG(val, msg) \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
return val;
|
||||||
|
|
||||||
|
#define ERR_FAIL_INDEX(index, size) \
|
||||||
|
if ((index < 0) || (index >= size)) { \
|
||||||
|
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, ""); \
|
||||||
|
return; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_INDEX_MSG(index, size, msg) \
|
||||||
|
if ((index < 0) || (index >= size)) { \
|
||||||
|
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, msg); \
|
||||||
|
return; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_INDEX_V(index, size, val) \
|
||||||
|
if ((index < 0) || (index >= size)) { \
|
||||||
|
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, ""); \
|
||||||
|
return val; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_INDEX_V_MSG(index, size, val, msg) \
|
||||||
|
if ((index < 0) || (index >= size)) { \
|
||||||
|
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, msg); \
|
||||||
|
return val; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_COND(cond) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_FAIL_COND: \"" #cond "\" is true!"); \
|
||||||
|
return; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_COND_MSG(cond, msg) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
return; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_COND_V(cond, val) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_FAIL_COND: \"" #cond "\" is true!"); \
|
||||||
|
return val; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_FAIL_COND_V_MSG(cond, val, msg) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
return val; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_CONTINUE(cond) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_CONTINUE: \"" #cond "\" is true!"); \
|
||||||
|
continue; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_CONTINUE_MSG(cond, msg) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
continue; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_CONTINUE_ACTION(cond, action) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_CONTINUE: \"" #cond "\" is true!"); \
|
||||||
|
action; \
|
||||||
|
continue; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define ERR_CONTINUE_ACTION_MSG(cond, action, msg) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
|
||||||
|
action; \
|
||||||
|
continue; \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define CRASH_INDEX(index, size) \
|
||||||
|
if ((index < 0) || (index >= size)) { \
|
||||||
|
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, "CRASH!"); \
|
||||||
|
GENERATE_TRAP \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#define CRASH_COND(cond) \
|
||||||
|
if (cond) { \
|
||||||
|
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "CRASH_COND: \"" #cond "\" is true!"); \
|
||||||
|
GENERATE_TRAP \
|
||||||
|
} else \
|
||||||
|
((void)0)
|
||||||
|
|
||||||
|
#endif
|
3005
core/image/image.cpp
Normal file
3005
core/image/image.cpp
Normal file
File diff suppressed because it is too large
Load Diff
310
core/image/image.h
Normal file
310
core/image/image.h
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* image.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef IMAGE_H
|
||||||
|
#define IMAGE_H
|
||||||
|
|
||||||
|
#include "core/math/color.h"
|
||||||
|
#include "core/math/rect2.h"
|
||||||
|
#include "core/containers/vector.h"
|
||||||
|
#include "core/resource.h"
|
||||||
|
#include "core/math/rect2i.h"
|
||||||
|
#include "core/math/vector2i.h"
|
||||||
|
|
||||||
|
class Image : public Resource {
|
||||||
|
RCPP_OBJECT(Image, Resource);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
MAX_WIDTH = 16384, // force a limit somehow
|
||||||
|
MAX_HEIGHT = 16384 // force a limit somehow
|
||||||
|
};
|
||||||
|
|
||||||
|
enum Format {
|
||||||
|
|
||||||
|
FORMAT_L8, //luminance
|
||||||
|
FORMAT_LA8, //luminance-alpha
|
||||||
|
FORMAT_R8,
|
||||||
|
FORMAT_RG8,
|
||||||
|
FORMAT_RGB8,
|
||||||
|
FORMAT_RGBA8,
|
||||||
|
FORMAT_RGBA4444,
|
||||||
|
FORMAT_RGBA5551,
|
||||||
|
FORMAT_RF, //float
|
||||||
|
FORMAT_RGF,
|
||||||
|
FORMAT_RGBF,
|
||||||
|
FORMAT_RGBAF,
|
||||||
|
FORMAT_RH, //half float
|
||||||
|
FORMAT_RGH,
|
||||||
|
FORMAT_RGBH,
|
||||||
|
FORMAT_RGBAH,
|
||||||
|
FORMAT_RGBE9995,
|
||||||
|
FORMAT_DXT1, //s3tc bc1
|
||||||
|
FORMAT_DXT3, //bc2
|
||||||
|
FORMAT_DXT5, //bc3
|
||||||
|
FORMAT_RGTC_R,
|
||||||
|
FORMAT_RGTC_RG,
|
||||||
|
FORMAT_BPTC_RGBA, //btpc bc7
|
||||||
|
FORMAT_BPTC_RGBF, //float bc6h
|
||||||
|
FORMAT_BPTC_RGBFU, //unsigned float bc6hu
|
||||||
|
FORMAT_PVRTC2, //pvrtc
|
||||||
|
FORMAT_PVRTC2A,
|
||||||
|
FORMAT_PVRTC4,
|
||||||
|
FORMAT_PVRTC4A,
|
||||||
|
FORMAT_ETC, //etc1
|
||||||
|
FORMAT_ETC2_R11, //etc2
|
||||||
|
FORMAT_ETC2_R11S, //signed, NOT srgb.
|
||||||
|
FORMAT_ETC2_RG11,
|
||||||
|
FORMAT_ETC2_RG11S,
|
||||||
|
FORMAT_ETC2_RGB8,
|
||||||
|
FORMAT_ETC2_RGBA8,
|
||||||
|
FORMAT_ETC2_RGB8A1,
|
||||||
|
FORMAT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *format_names[FORMAT_MAX];
|
||||||
|
enum Interpolation {
|
||||||
|
|
||||||
|
INTERPOLATE_NEAREST,
|
||||||
|
INTERPOLATE_BILINEAR,
|
||||||
|
INTERPOLATE_CUBIC,
|
||||||
|
INTERPOLATE_TRILINEAR,
|
||||||
|
INTERPOLATE_LANCZOS,
|
||||||
|
/* INTERPOLATE_TRICUBIC, */
|
||||||
|
/* INTERPOLATE GAUSS */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum CompressSource {
|
||||||
|
COMPRESS_SOURCE_GENERIC,
|
||||||
|
COMPRESS_SOURCE_SRGB,
|
||||||
|
COMPRESS_SOURCE_NORMAL,
|
||||||
|
COMPRESS_SOURCE_LAYERED,
|
||||||
|
COMPRESS_SOURCE_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool write_lock;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
|
||||||
|
create(p_width, p_height, p_use_mipmaps, p_format);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
|
||||||
|
create(p_width, p_height, p_use_mipmaps, p_format, p_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
Format format;
|
||||||
|
Vector<uint8_t> data;
|
||||||
|
int width, height;
|
||||||
|
bool mipmaps;
|
||||||
|
|
||||||
|
void _copy_internals_from(const Image &p_image) {
|
||||||
|
format = p_image.format;
|
||||||
|
width = p_image.width;
|
||||||
|
height = p_image.height;
|
||||||
|
mipmaps = p_image.mipmaps;
|
||||||
|
data = p_image.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
|
||||||
|
|
||||||
|
static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1);
|
||||||
|
bool _can_modify(Format p_format) const;
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel);
|
||||||
|
_FORCE_INLINE_ void _get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel);
|
||||||
|
|
||||||
|
_FORCE_INLINE_ void _repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_size, int p_count);
|
||||||
|
|
||||||
|
static void average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d);
|
||||||
|
static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d);
|
||||||
|
static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d);
|
||||||
|
static void average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d);
|
||||||
|
static void renormalize_uint8(uint8_t *p_rgb);
|
||||||
|
static void renormalize_float(float *p_rgb);
|
||||||
|
static void renormalize_half(uint16_t *p_rgb);
|
||||||
|
static void renormalize_rgbe9995(uint32_t *p_rgb);
|
||||||
|
|
||||||
|
public:
|
||||||
|
int get_width() const; ///< Get image width
|
||||||
|
int get_height() const; ///< Get image height
|
||||||
|
Vector2 get_size() const;
|
||||||
|
bool has_mipmaps() const;
|
||||||
|
int get_mipmap_count() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the image to another format, conversion only to raw byte format
|
||||||
|
*/
|
||||||
|
void convert(Format p_new_format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current image format.
|
||||||
|
*/
|
||||||
|
Format get_format() const;
|
||||||
|
|
||||||
|
int get_mipmap_offset(int p_mipmap) const; //get where the mipmap begins in data
|
||||||
|
void get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const; //get where the mipmap begins in data
|
||||||
|
void get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const; //get where the mipmap begins in data
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the image, using the preferred interpolation method.
|
||||||
|
*/
|
||||||
|
void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
|
||||||
|
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
|
||||||
|
void shrink_x2();
|
||||||
|
bool is_size_po2() const;
|
||||||
|
/**
|
||||||
|
* Crop the image to a specific size, if larger, then the image is filled by black
|
||||||
|
*/
|
||||||
|
void crop_from_point(int p_x, int p_y, int p_width, int p_height);
|
||||||
|
void crop(int p_width, int p_height);
|
||||||
|
|
||||||
|
void flip_x();
|
||||||
|
void flip_y();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
|
||||||
|
*/
|
||||||
|
int generate_mipmaps(bool p_renormalize = false);
|
||||||
|
|
||||||
|
void clear_mipmaps();
|
||||||
|
void normalize(); //for normal maps
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new image of a given size and format. Current image will be lost
|
||||||
|
*/
|
||||||
|
void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
|
||||||
|
void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
|
||||||
|
|
||||||
|
void create(const char **p_xpm);
|
||||||
|
/**
|
||||||
|
* returns true when the image is empty (0,0) in size
|
||||||
|
*/
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
Vector<uint8_t> get_data() const;
|
||||||
|
const uint8_t* datar() const;
|
||||||
|
uint8_t* dataw();
|
||||||
|
int get_data_size() const;
|
||||||
|
|
||||||
|
Image();
|
||||||
|
Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
|
||||||
|
Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
|
||||||
|
|
||||||
|
enum AlphaMode {
|
||||||
|
ALPHA_NONE,
|
||||||
|
ALPHA_BIT,
|
||||||
|
ALPHA_BLEND
|
||||||
|
};
|
||||||
|
|
||||||
|
AlphaMode detect_alpha() const;
|
||||||
|
bool is_invisible() const;
|
||||||
|
|
||||||
|
static int get_format_pixel_size(Format p_format);
|
||||||
|
static int get_format_pixel_rshift(Format p_format);
|
||||||
|
static int get_format_block_size(Format p_format);
|
||||||
|
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
|
||||||
|
|
||||||
|
static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false);
|
||||||
|
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
|
||||||
|
static int get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
|
||||||
|
|
||||||
|
enum CompressMode {
|
||||||
|
COMPRESS_S3TC,
|
||||||
|
COMPRESS_PVRTC2,
|
||||||
|
COMPRESS_PVRTC4,
|
||||||
|
COMPRESS_ETC,
|
||||||
|
COMPRESS_ETC2,
|
||||||
|
COMPRESS_BPTC,
|
||||||
|
COMPRESS_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_compressed() const;
|
||||||
|
|
||||||
|
void fix_alpha_edges();
|
||||||
|
void premultiply_alpha();
|
||||||
|
void srgb_to_linear();
|
||||||
|
void normalmap_to_xy();
|
||||||
|
Ref<Image> rgbe_to_srgb();
|
||||||
|
void bumpmap_to_normalmap(float bump_scale = 1.0);
|
||||||
|
|
||||||
|
void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Vector2 &p_dest);
|
||||||
|
void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Vector2 &p_dest);
|
||||||
|
void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Vector2 &p_dest);
|
||||||
|
void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Vector2 &p_dest);
|
||||||
|
void fill(const Color &p_color);
|
||||||
|
void fill_rect(const Rect2 &p_rect, const Color &p_color);
|
||||||
|
|
||||||
|
Rect2 get_used_rect() const;
|
||||||
|
Ref<Image> get_rect(const Rect2 &p_area) const;
|
||||||
|
|
||||||
|
static void set_compress_bc_func(void (*p_compress_func)(Image *, float, CompressSource));
|
||||||
|
static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, CompressSource));
|
||||||
|
static String get_format_name(Format p_format);
|
||||||
|
|
||||||
|
Image(const char **p_xpm);
|
||||||
|
|
||||||
|
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
//this is used for compression
|
||||||
|
enum DetectChannels {
|
||||||
|
DETECTED_L,
|
||||||
|
DETECTED_LA,
|
||||||
|
DETECTED_R,
|
||||||
|
DETECTED_RG,
|
||||||
|
DETECTED_RGB,
|
||||||
|
DETECTED_RGBA,
|
||||||
|
};
|
||||||
|
|
||||||
|
DetectChannels get_detected_channels();
|
||||||
|
void optimize_channels();
|
||||||
|
|
||||||
|
Color get_pixelv(const Vector2 &p_src) const;
|
||||||
|
Color get_pixel(int p_x, int p_y) const;
|
||||||
|
void set_pixelv(const Vector2 &p_dst, const Color &p_color);
|
||||||
|
void set_pixel(int p_x, int p_y, const Color &p_color);
|
||||||
|
|
||||||
|
void copy_internals_from(const Ref<Image> &p_image) {
|
||||||
|
ERR_FAIL_COND(p_image.is_null());
|
||||||
|
|
||||||
|
format = p_image->format;
|
||||||
|
width = p_image->width;
|
||||||
|
height = p_image->height;
|
||||||
|
mipmaps = p_image->mipmaps;
|
||||||
|
data = p_image->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Image();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
57
core/int_types.h
Normal file
57
core/int_types.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* int_types.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#ifdef NO_STDINT_H
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef signed short int16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef signed int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
205
core/log/logger.cpp
Normal file
205
core/log/logger.cpp
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
#include "core/string.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "logger.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
|
||||||
|
void RLogger::print_trace(const String &str) {
|
||||||
|
print_trace(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::print_trace(const char *str) {
|
||||||
|
printf("T %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::print_trace(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::print_trace(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::print_message(const String &str) {
|
||||||
|
print_message(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::print_message(const char *str) {
|
||||||
|
printf("M %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::print_message(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::print_message(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::print_warning(const String &str) {
|
||||||
|
print_warning(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::print_warning(const char *str) {
|
||||||
|
printf("W %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::print_warning(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::print_warning(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::print_error(const String &str) {
|
||||||
|
print_error(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::print_error(const char *str) {
|
||||||
|
printf("E %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::print_error(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::print_error(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
void RLogger::print_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str) {
|
||||||
|
printf("E | %s::%s:%d | :: %s. %s\n", p_file, p_function, p_line, str, p_msg);
|
||||||
|
}
|
||||||
|
void RLogger::print_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str) {
|
||||||
|
printf("E (INDEX) | %s::%s:%d | :: index: %d/%d. %s\n", p_file, p_function, p_line, index, size, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_trace(const String &str) {
|
||||||
|
log_trace(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::log_trace(const char *str) {
|
||||||
|
printf("T %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::log_trace(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::log_trace(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_message(const String &str) {
|
||||||
|
log_message(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::log_message(const char *str) {
|
||||||
|
printf("M %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::log_message(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::log_message(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_warning(const String &str) {
|
||||||
|
log_warning(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::log_warning(const char *str) {
|
||||||
|
printf("W %s\n", str);
|
||||||
|
}
|
||||||
|
void RLogger::log_warning(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::log_warning(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_error(const String &str) {
|
||||||
|
log_error(str.data());
|
||||||
|
}
|
||||||
|
void RLogger::log_error(const char *str) {
|
||||||
|
printf("E %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *str) {
|
||||||
|
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
|
||||||
|
}
|
||||||
|
void RLogger::log_error(const char *p_function, const char *p_file, int p_line, const String &str) {
|
||||||
|
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
|
||||||
|
}
|
||||||
|
void RLogger::log_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str) {
|
||||||
|
printf("E | %s::%s:%d | :: %s. %s\n", p_file, p_function, p_line, str, p_msg);
|
||||||
|
}
|
||||||
|
void RLogger::log_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str) {
|
||||||
|
printf("E (INDEX) | %s::%s:%d | :: index: %d/%d. %s\n", p_file, p_function, p_line, index, size, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
String *RLogger::get_string_ptr(const int p_default_size) {
|
||||||
|
return new String(p_default_size);
|
||||||
|
}
|
||||||
|
String *RLogger::get_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
String *s = new String(p_default_size);
|
||||||
|
|
||||||
|
s->append_str(p_function);
|
||||||
|
s->append_str("::");
|
||||||
|
s->append_str(p_file);
|
||||||
|
s->append_str(":");
|
||||||
|
s->append_str(String::num(p_line));
|
||||||
|
s->append_str(" | ");
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
String *RLogger::get_string_ptr(const char *p_prefix, const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
String *s = new String(p_default_size);
|
||||||
|
|
||||||
|
s->append_str(p_prefix);
|
||||||
|
s->append_str(" | ");
|
||||||
|
s->append_str(p_function);
|
||||||
|
s->append_str("::");
|
||||||
|
s->append_str(p_file);
|
||||||
|
s->append_str(":");
|
||||||
|
s->append_str(String::num(p_line));
|
||||||
|
s->append_str(" | ");
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
void RLogger::return_string_ptr(String *str) {
|
||||||
|
delete str;
|
||||||
|
}
|
||||||
|
|
||||||
|
String *RLogger::get_trace_string_ptr(const int p_default_size) {
|
||||||
|
String *str = get_string_ptr(p_default_size);
|
||||||
|
str->append_str("T ");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
String *RLogger::get_message_string_ptr(const int p_default_size) {
|
||||||
|
String *str = get_string_ptr(p_default_size);
|
||||||
|
str->append_str("M ");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
String *RLogger::get_warning_string_ptr(const int p_default_size) {
|
||||||
|
String *str = get_string_ptr(p_default_size);
|
||||||
|
str->append_str("W ");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
String *RLogger::get_error_string_ptr(const int p_default_size) {
|
||||||
|
String *str = get_string_ptr(p_default_size);
|
||||||
|
str->append_str("E ");
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
String *RLogger::get_trace_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
return get_string_ptr("T", p_function, p_file, p_line, p_default_size);
|
||||||
|
}
|
||||||
|
String *RLogger::get_message_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
return get_string_ptr("M", p_function, p_file, p_line, p_default_size);
|
||||||
|
}
|
||||||
|
String *RLogger::get_warning_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
return get_string_ptr("W", p_function, p_file, p_line, p_default_size);
|
||||||
|
}
|
||||||
|
String *RLogger::get_error_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
|
||||||
|
return get_string_ptr("E", p_function, p_file, p_line, p_default_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_ptr(String *str) {
|
||||||
|
printf("%s\n", str->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RLogger::log_ret_ptr(String *str) {
|
||||||
|
log_ptr(str);
|
||||||
|
|
||||||
|
return_string_ptr(str);
|
||||||
|
}
|
77
core/log/logger.h
Normal file
77
core/log/logger.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class String;
|
||||||
|
|
||||||
|
class RLogger {
|
||||||
|
public:
|
||||||
|
static void print_trace(const String &str);
|
||||||
|
static void print_trace(const char *str);
|
||||||
|
static void print_trace(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void print_trace(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void print_message(const String &str);
|
||||||
|
static void print_message(const char *str);
|
||||||
|
static void print_message(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void print_message(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void print_warning(const String &str);
|
||||||
|
static void print_warning(const char *str);
|
||||||
|
static void print_warning(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void print_warning(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void print_error(const String &str);
|
||||||
|
static void print_error(const char *str);
|
||||||
|
static void print_error(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
static void print_error(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void print_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str);
|
||||||
|
static void print_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str);
|
||||||
|
|
||||||
|
static void log_trace(const String &str);
|
||||||
|
static void log_trace(const char *str);
|
||||||
|
static void log_trace(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void log_trace(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void log_message(const String &str);
|
||||||
|
static void log_message(const char *str);
|
||||||
|
static void log_message(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void log_message(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void log_warning(const String &str);
|
||||||
|
static void log_warning(const char *str);
|
||||||
|
static void log_warning(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void log_warning(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
|
||||||
|
static void log_error(const String &str);
|
||||||
|
static void log_error(const char *str);
|
||||||
|
static void log_error(const char *p_function, const char *p_file, int p_line, const char *str);
|
||||||
|
static void log_error(const char *p_function, const char *p_file, int p_line, const String &str);
|
||||||
|
static void log_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str);
|
||||||
|
static void log_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str);
|
||||||
|
|
||||||
|
static String *get_string_ptr(const int p_default_size = 100);
|
||||||
|
static String *get_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
static String *get_string_ptr(const char *p_prefix, const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
static void return_string_ptr(String *str);
|
||||||
|
|
||||||
|
static String *get_trace_string_ptr(const int p_default_size = 100);
|
||||||
|
static String *get_message_string_ptr(const int p_default_size = 100);
|
||||||
|
static String *get_warning_string_ptr(const int p_default_size = 100);
|
||||||
|
static String *get_error_string_ptr(const int p_default_size = 100);
|
||||||
|
|
||||||
|
static String *get_trace_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
static String *get_message_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
static String *get_warning_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
static String *get_error_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
|
||||||
|
|
||||||
|
static void log_ptr(String *str);
|
||||||
|
static void log_ret_ptr(String *str);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
14
core/memory.h
Normal file
14
core/memory.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#ifndef MEMORY_H
|
||||||
|
#define MEMORY_H
|
||||||
|
|
||||||
|
//Simple memnew and memdelete macros so stuff that I took from the godotengine can use it.
|
||||||
|
//Not yet sure whether to use their allocator or not.
|
||||||
|
//This will be here until I decide.
|
||||||
|
|
||||||
|
#define memnew(m_class) new m_class
|
||||||
|
#define memdelete(instance) delete instance
|
||||||
|
#define memnew_arr(m_class, size) new m_class[size]
|
||||||
|
#define memdelete_arr(instance) delete[] instance
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
122
core/nodes/node.cpp
Normal file
122
core/nodes/node.cpp
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
#include "node_tree.h"
|
||||||
|
|
||||||
|
bool Node::is_in_tree() const {
|
||||||
|
return _in_tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *Node::get_parent() {
|
||||||
|
return _parent;
|
||||||
|
}
|
||||||
|
void Node::set_parent(Node *parent) {
|
||||||
|
if (_parent == parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_parent) {
|
||||||
|
notification(NOTIFICATION_UNPARENTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
_parent = parent;
|
||||||
|
|
||||||
|
if (_parent) {
|
||||||
|
notification(NOTIFICATION_PARENTED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Node::get_child_count() {
|
||||||
|
return _children.size();
|
||||||
|
}
|
||||||
|
Node *Node::get_child(int index) {
|
||||||
|
return _children[index];
|
||||||
|
}
|
||||||
|
void Node::add_child(Node *child) {
|
||||||
|
ERR_FAIL_COND(!child);
|
||||||
|
ERR_FAIL_COND(child->get_parent());
|
||||||
|
|
||||||
|
_children.push_back(child);
|
||||||
|
child->set_parent(this);
|
||||||
|
|
||||||
|
if (_in_tree) {
|
||||||
|
child->set_tree(_tree);
|
||||||
|
child->notification(NOTIFICATION_EXIT_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
notification(NOTIFICATION_CHILD_ADDED);
|
||||||
|
}
|
||||||
|
void Node::remove_child_index(int index) {
|
||||||
|
Node *c = _children[index];
|
||||||
|
|
||||||
|
_children.remove_keep_order(index);
|
||||||
|
c->set_parent(nullptr);
|
||||||
|
|
||||||
|
notification(NOTIFICATION_CHILD_REMOVED);
|
||||||
|
}
|
||||||
|
void Node::remove_child(Node *child) {
|
||||||
|
ERR_FAIL_COND(!child);
|
||||||
|
|
||||||
|
for (int i = 0; i < _children.size(); ++i) {
|
||||||
|
Node *c = _children[i];
|
||||||
|
|
||||||
|
if (c == child) {
|
||||||
|
_children.remove_keep_order(i);
|
||||||
|
child->set_parent(nullptr);
|
||||||
|
notification(NOTIFICATION_CHILD_REMOVED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeTree *Node::get_tree() {
|
||||||
|
return _tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::set_tree(NodeTree *tree) {
|
||||||
|
if (_tree) {
|
||||||
|
_in_tree = false;
|
||||||
|
_notification(NOTIFICATION_EXIT_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
_tree = tree;
|
||||||
|
|
||||||
|
if (_tree) {
|
||||||
|
_in_tree = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < _children.size(); ++i) {
|
||||||
|
_children[i]->set_tree(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tree) {
|
||||||
|
_notification(NOTIFICATION_ENTER_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Node::notification(const int what) {
|
||||||
|
_notification(what);
|
||||||
|
|
||||||
|
for (int i = 0; i < _children.size(); ++i) {
|
||||||
|
_children[i]->notification(what);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Node::_notification(const int what) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::Node() :
|
||||||
|
Object() {
|
||||||
|
|
||||||
|
_in_tree = false;
|
||||||
|
_parent = nullptr;
|
||||||
|
_tree = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::~Node() {
|
||||||
|
for (int i = 0; i < _children.size(); ++i) {
|
||||||
|
delete _children[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_children.clear();
|
||||||
|
}
|
52
core/nodes/node.h
Normal file
52
core/nodes/node.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef NODE_H
|
||||||
|
#define NODE_H
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/containers/vector.h"
|
||||||
|
|
||||||
|
class NodeTree;
|
||||||
|
|
||||||
|
class Node : public Object {
|
||||||
|
RCPP_OBJECT(Node, Object);
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
NOTIFICATION_ENTER_TREE = 0,
|
||||||
|
NOTIFICATION_EXIT_TREE = 1,
|
||||||
|
NOTIFICATION_PARENTED = 2,
|
||||||
|
NOTIFICATION_UNPARENTED = 3,
|
||||||
|
NOTIFICATION_CHILD_ADDED = 4,
|
||||||
|
NOTIFICATION_CHILD_REMOVED = 5,
|
||||||
|
NOTIFICATION_CHILD_MOVED = 6,
|
||||||
|
NOTIFICATION_UPDATE = 7,
|
||||||
|
NOTIFICATION_TREE_WRITE_LOCKED = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
bool is_in_tree() const;
|
||||||
|
|
||||||
|
Node *get_parent();
|
||||||
|
void set_parent(Node *parent);
|
||||||
|
|
||||||
|
int get_child_count();
|
||||||
|
Node *get_child(int index);
|
||||||
|
void add_child(Node *child);
|
||||||
|
void remove_child_index(int index);
|
||||||
|
void remove_child(Node *child);
|
||||||
|
|
||||||
|
NodeTree *get_tree();
|
||||||
|
void set_tree(NodeTree *tree);
|
||||||
|
|
||||||
|
virtual void notification(const int what);
|
||||||
|
virtual void _notification(const int what);
|
||||||
|
|
||||||
|
Node();
|
||||||
|
~Node();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _in_tree;
|
||||||
|
Node * _parent;
|
||||||
|
Vector<Node *> _children;
|
||||||
|
NodeTree *_tree;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
60
core/nodes/node_tree.cpp
Normal file
60
core/nodes/node_tree.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
|
||||||
|
#include "node_tree.h"
|
||||||
|
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
Node *NodeTree::get_root() {
|
||||||
|
return _root_node;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeTree::set_root(Node *root) {
|
||||||
|
if (_root_node) {
|
||||||
|
_root_node->set_tree(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_root_node = root;
|
||||||
|
|
||||||
|
if (_root_node) {
|
||||||
|
_root_node->set_tree(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeTree::update() {
|
||||||
|
if (!_root_node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_root_node->notification(Node::NOTIFICATION_UPDATE);
|
||||||
|
|
||||||
|
if (_write_lock_requested) {
|
||||||
|
_rw_lock.write_lock();
|
||||||
|
_root_node->notification(Node::NOTIFICATION_TREE_WRITE_LOCKED);
|
||||||
|
_rw_lock.write_unlock();
|
||||||
|
|
||||||
|
_write_lock_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeTree::_send_update() {
|
||||||
|
if (_root_node) {
|
||||||
|
_root_node->notification(Node::NOTIFICATION_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float NodeTree::get_update_delta_time() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeTree::NodeTree() :
|
||||||
|
Object() {
|
||||||
|
|
||||||
|
_root_node = nullptr;
|
||||||
|
_update_interval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeTree::~NodeTree() {
|
||||||
|
if (_root_node) {
|
||||||
|
delete _root_node;
|
||||||
|
_root_node = nullptr;
|
||||||
|
}
|
||||||
|
}
|
35
core/nodes/node_tree.h
Normal file
35
core/nodes/node_tree.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef NODE_TREE_H
|
||||||
|
#define NODE_TREE_H
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/threading/rw_lock.h"
|
||||||
|
|
||||||
|
class Node;
|
||||||
|
|
||||||
|
class NodeTree : public Object {
|
||||||
|
RCPP_OBJECT(NodeTree, Object);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Node *get_root();
|
||||||
|
virtual void set_root(Node *root);
|
||||||
|
|
||||||
|
virtual void update();
|
||||||
|
|
||||||
|
void request_write_lock();
|
||||||
|
|
||||||
|
virtual float get_update_delta_time();
|
||||||
|
|
||||||
|
NodeTree();
|
||||||
|
~NodeTree();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void _send_update();
|
||||||
|
|
||||||
|
Node *_root_node;
|
||||||
|
float _update_interval;
|
||||||
|
|
||||||
|
bool _write_lock_requested;
|
||||||
|
RWLock _rw_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
11
core/object.cpp
Normal file
11
core/object.cpp
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
#include "database/database.h"
|
||||||
|
|
||||||
|
Object::Object() {
|
||||||
|
db = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object::~Object() {
|
||||||
|
|
||||||
|
}
|
93
core/object.h
Normal file
93
core/object.h
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
#ifndef OBJECT_H
|
||||||
|
#define OBJECT_H
|
||||||
|
|
||||||
|
#include "core/string.h"
|
||||||
|
#include "core/containers/vector.h"
|
||||||
|
|
||||||
|
class Database;
|
||||||
|
|
||||||
|
//taken from GodotEngine's object.h
|
||||||
|
#define RCPP_OBJECT(m_class, m_inherits) \
|
||||||
|
private: \
|
||||||
|
void operator=(const m_class &p_rval) {} \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
virtual String get_class() const override { \
|
||||||
|
return String(#m_class); \
|
||||||
|
} \
|
||||||
|
static void *get_class_ptr_static() { \
|
||||||
|
static int ptr; \
|
||||||
|
return &ptr; \
|
||||||
|
} \
|
||||||
|
static String get_class_static() { \
|
||||||
|
return String(#m_class); \
|
||||||
|
} \
|
||||||
|
static String get_parent_class_static() { \
|
||||||
|
return m_inherits::get_class_static(); \
|
||||||
|
} \
|
||||||
|
static void get_inheritance_list_static(Vector<String> *p_inheritance_list) { \
|
||||||
|
m_inherits::get_inheritance_list_static(p_inheritance_list); \
|
||||||
|
p_inheritance_list->push_back(String(#m_class)); \
|
||||||
|
} \
|
||||||
|
static String inherits_static() { \
|
||||||
|
return String(#m_inherits); \
|
||||||
|
} \
|
||||||
|
virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
|
||||||
|
virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
|
||||||
|
\
|
||||||
|
static void get_valid_parents_static(Vector<String> *p_parents) { \
|
||||||
|
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
|
||||||
|
m_class::_get_valid_parents_static(p_parents); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
m_inherits::get_valid_parents_static(p_parents); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private:
|
||||||
|
|
||||||
|
class Object {
|
||||||
|
public:
|
||||||
|
Database *db;
|
||||||
|
|
||||||
|
virtual String get_class() const { return "Object"; }
|
||||||
|
static void *get_class_ptr_static() {
|
||||||
|
static int ptr;
|
||||||
|
return &ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static String get_class_static() { return "Object"; }
|
||||||
|
static String get_parent_class_static() { return String(); }
|
||||||
|
|
||||||
|
static void get_inheritance_list_static(Vector<String> *p_inheritance_list) { p_inheritance_list->push_back("Object"); }
|
||||||
|
|
||||||
|
virtual bool is_class(const String &p_class) const { return (p_class == "Object"); }
|
||||||
|
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
|
||||||
|
|
||||||
|
static void get_valid_parents_static(Vector<String> *p_parents) {}
|
||||||
|
static void _get_valid_parents_static(Vector<String> *p_parents) {}
|
||||||
|
|
||||||
|
Object();
|
||||||
|
virtual ~Object();
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static T *cast_to(Object *p_object) {
|
||||||
|
if (!p_object)
|
||||||
|
return NULL;
|
||||||
|
if (p_object->is_class_ptr(T::get_class_ptr_static()))
|
||||||
|
return static_cast<T *>(p_object);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static const T *cast_to(const Object *p_object) {
|
||||||
|
if (!p_object)
|
||||||
|
return NULL;
|
||||||
|
if (p_object->is_class_ptr(T::get_class_ptr_static()))
|
||||||
|
return static_cast<const T *>(p_object);
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
240
core/os/directory.cpp
Normal file
240
core/os/directory.cpp
Normal file
@ -0,0 +1,240 @@
|
|||||||
|
#include "directory.h"
|
||||||
|
|
||||||
|
Error Directory::open_dir(const String &path, bool skip_specials) {
|
||||||
|
if (_dir_open) {
|
||||||
|
return ERR_CANT_ACQUIRE_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_skip_specials = skip_specials;
|
||||||
|
|
||||||
|
if (tinydir_open(&_dir, path.c_str()) == -1) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dir_open = true;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Directory::open_dir(const char *path, bool skip_specials) {
|
||||||
|
if (_dir_open) {
|
||||||
|
return ERR_CANT_ACQUIRE_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
_skip_specials = skip_specials;
|
||||||
|
|
||||||
|
if (tinydir_open(&_dir, path) == -1) {
|
||||||
|
return FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
_dir_open = true;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Directory::close_dir() {
|
||||||
|
if (!_dir_open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tinydir_close(&_dir);
|
||||||
|
|
||||||
|
_dir_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Directory::has_next() {
|
||||||
|
return _dir.has_next;
|
||||||
|
}
|
||||||
|
bool Directory::read() {
|
||||||
|
_read_file_result = tinydir_readfile(&_dir, &_file);
|
||||||
|
|
||||||
|
return _read_file_result != -1;
|
||||||
|
}
|
||||||
|
bool Directory::next() {
|
||||||
|
if (!_dir.has_next) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rres = read();
|
||||||
|
while (!rres && _dir.has_next) {
|
||||||
|
tinydir_next(&_dir);
|
||||||
|
rres = read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rres) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_dir.has_next) {
|
||||||
|
tinydir_next(&_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_skip_specials && current_is_dir() && current_is_special_dir()) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Directory::current_is_ok() {
|
||||||
|
return _read_file_result == 01;
|
||||||
|
}
|
||||||
|
String Directory::current_get_name() {
|
||||||
|
return String(_file.name);
|
||||||
|
}
|
||||||
|
String Directory::current_get_path() {
|
||||||
|
return String(_file.path);
|
||||||
|
}
|
||||||
|
String Directory::current_get_extension() {
|
||||||
|
return String(_file.extension);
|
||||||
|
}
|
||||||
|
const char *Directory::current_get_name_cstr() {
|
||||||
|
return _file.name;
|
||||||
|
}
|
||||||
|
const char *Directory::current_get_path_cstr() {
|
||||||
|
return _file.path;
|
||||||
|
}
|
||||||
|
const char *Directory::current_get_extension_cstr() {
|
||||||
|
return _file.extension;
|
||||||
|
}
|
||||||
|
bool Directory::current_is_file() {
|
||||||
|
return !_file.is_dir;
|
||||||
|
}
|
||||||
|
bool Directory::current_is_dir() {
|
||||||
|
return _file.is_dir;
|
||||||
|
}
|
||||||
|
bool Directory::current_is_special_dir() {
|
||||||
|
if (_file.name[0] == '.' && _file.name[1] == '\0' || _file.name[0] == '.' && _file.name[1] == '.') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String Directory::read_file(const String &path) {
|
||||||
|
FILE *f = fopen(path.c_str(), "r");
|
||||||
|
|
||||||
|
String fd;
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V_MSG(!f, fd, "Error opening file! " + path);
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
fd.resize(fsize);
|
||||||
|
|
||||||
|
fread(fd.dataw(), 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Directory::read_file_into(const String &path, String *str) {
|
||||||
|
if (!str) {
|
||||||
|
return ERR_PARAMETER_RANGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(path.c_str(), "r");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
return ERR_FILE_CANT_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
str->resize(fsize);
|
||||||
|
|
||||||
|
fread(str->dataw(), 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<uint8_t> Directory::read_file_bin(const String &path) {
|
||||||
|
FILE *f = fopen(path.c_str(), "rb");
|
||||||
|
|
||||||
|
Vector<uint8_t> fd;
|
||||||
|
|
||||||
|
ERR_FAIL_COND_V_MSG(!f, fd, "Error opening file! " + path);
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
fd.resize(fsize);
|
||||||
|
|
||||||
|
fread(fd.dataw(), 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Directory::read_file_into_bin(const String &path, Vector<uint8_t> *data) {
|
||||||
|
if (!data) {
|
||||||
|
return ERR_PARAMETER_RANGE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *f = fopen(path.c_str(), "rb");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
return ERR_FILE_CANT_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
data->resize(fsize);
|
||||||
|
|
||||||
|
fread(data->dataw(), 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Directory::write_file(const String &path, const String &str) {
|
||||||
|
FILE *f = fopen(path.c_str(), "w");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
return ERR_FILE_CANT_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(str.data(), sizeof(char), str.size(), f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error Directory::write_file_bin(const String &path, const Vector<uint8_t> &data) {
|
||||||
|
FILE *f = fopen(path.c_str(), "wb");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
return ERR_FILE_CANT_OPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite(data.data(), sizeof(uint8_t), data.size(), f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Directory::is_dir_open() {
|
||||||
|
return _dir_open;
|
||||||
|
}
|
||||||
|
bool Directory::is_dir_closed() {
|
||||||
|
return !_dir_open;
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory::Directory() {
|
||||||
|
_skip_specials = true;
|
||||||
|
_read_file_result = 0;
|
||||||
|
_dir_open = false;
|
||||||
|
}
|
||||||
|
Directory::~Directory() {
|
||||||
|
if (is_dir_open()) {
|
||||||
|
close_dir();
|
||||||
|
}
|
||||||
|
}
|
55
core/os/directory.h
Normal file
55
core/os/directory.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#ifndef DIRECTORY_H
|
||||||
|
#define DIRECTORY_H
|
||||||
|
|
||||||
|
#include "core/string.h"
|
||||||
|
#include "core/error_list.h"
|
||||||
|
#include <tinydir/tinydir.h>
|
||||||
|
|
||||||
|
#include "core/reference.h"
|
||||||
|
|
||||||
|
class Directory : public Reference {
|
||||||
|
RCPP_OBJECT(Directory, Reference);
|
||||||
|
public:
|
||||||
|
Error open_dir(const String &path, bool skip_specials = true);
|
||||||
|
Error open_dir(const char *path, bool skip_specials = true);
|
||||||
|
void close_dir();
|
||||||
|
|
||||||
|
bool has_next();
|
||||||
|
bool read();
|
||||||
|
bool next();
|
||||||
|
|
||||||
|
bool current_is_ok();
|
||||||
|
String current_get_name();
|
||||||
|
String current_get_path();
|
||||||
|
String current_get_extension();
|
||||||
|
const char *current_get_name_cstr();
|
||||||
|
const char *current_get_path_cstr();
|
||||||
|
const char *current_get_extension_cstr();
|
||||||
|
bool current_is_file();
|
||||||
|
bool current_is_dir();
|
||||||
|
bool current_is_special_dir();
|
||||||
|
|
||||||
|
String read_file(const String &path);
|
||||||
|
Error read_file_into(const String &path, String *str);
|
||||||
|
Vector<uint8_t> read_file_bin(const String &path);
|
||||||
|
Error read_file_into_bin(const String &path, Vector<uint8_t> *data);
|
||||||
|
|
||||||
|
Error write_file(const String &path, const String &str);
|
||||||
|
Error write_file_bin(const String &path, const Vector<uint8_t> &data);
|
||||||
|
|
||||||
|
bool is_dir_open();
|
||||||
|
bool is_dir_closed();
|
||||||
|
|
||||||
|
Directory();
|
||||||
|
virtual ~Directory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _skip_specials;
|
||||||
|
int _read_file_result;
|
||||||
|
tinydir_dir _dir;
|
||||||
|
tinydir_file _file;
|
||||||
|
|
||||||
|
bool _dir_open;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
26
core/os/tinydir/COPYING
Normal file
26
core/os/tinydir/COPYING
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Copyright (c) 2013-2016, tinydir authors:
|
||||||
|
- Cong Xu
|
||||||
|
- Lautis Sun
|
||||||
|
- Baudouin Feildel
|
||||||
|
- Andargor <andargor@yahoo.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
79
core/os/tinydir/README.md
Normal file
79
core/os/tinydir/README.md
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
TinyDir
|
||||||
|
=======
|
||||||
|
[![Build Status](https://travis-ci.org/cxong/tinydir.svg?branch=master)](https://travis-ci.org/cxong/tinydir)
|
||||||
|
[![Release](http://img.shields.io/github/release/cxong/tinydir.svg)](https://github.com/cxong/tinydir/releases/latest)
|
||||||
|
|
||||||
|
Lightweight, portable and easy to integrate C directory and file reader. TinyDir wraps dirent for POSIX and FindFirstFile for Windows.
|
||||||
|
|
||||||
|
Windows unicode is supported by defining `UNICODE` and `_UNICODE` before including `tinydir.h`.
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
There are two methods. Error checking omitted:
|
||||||
|
|
||||||
|
```C
|
||||||
|
tinydir_dir dir;
|
||||||
|
tinydir_open(&dir, "/path/to/dir");
|
||||||
|
|
||||||
|
while (dir.has_next)
|
||||||
|
{
|
||||||
|
tinydir_file file;
|
||||||
|
tinydir_readfile(&dir, &file);
|
||||||
|
|
||||||
|
printf("%s", file.name);
|
||||||
|
if (file.is_dir)
|
||||||
|
{
|
||||||
|
printf("/");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
tinydir_next(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
tinydir_close(&dir);
|
||||||
|
```
|
||||||
|
|
||||||
|
```C
|
||||||
|
tinydir_dir dir;
|
||||||
|
int i;
|
||||||
|
tinydir_open_sorted(&dir, "/path/to/dir");
|
||||||
|
|
||||||
|
for (i = 0; i < dir.n_files; i++)
|
||||||
|
{
|
||||||
|
tinydir_file file;
|
||||||
|
tinydir_readfile_n(&dir, &file, i);
|
||||||
|
|
||||||
|
printf("%s", file.name);
|
||||||
|
if (file.is_dir)
|
||||||
|
{
|
||||||
|
printf("/");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tinydir_close(&dir);
|
||||||
|
```
|
||||||
|
|
||||||
|
See the `/samples` folder for more examples, including an interactive command-line directory navigator.
|
||||||
|
|
||||||
|
Language
|
||||||
|
========
|
||||||
|
|
||||||
|
ANSI C, or C90.
|
||||||
|
|
||||||
|
Platforms
|
||||||
|
=========
|
||||||
|
|
||||||
|
POSIX and Windows supported. Open to the possibility of supporting other platforms.
|
||||||
|
|
||||||
|
License
|
||||||
|
=======
|
||||||
|
|
||||||
|
Simplified BSD; if you use tinydir you can comply by including `tinydir.h` or `COPYING` somewhere in your package.
|
||||||
|
|
||||||
|
Known Limitations
|
||||||
|
=================
|
||||||
|
|
||||||
|
- Limited path and filename sizes
|
||||||
|
- [Possible race condition bug if folder being read has changing content](https://github.com/cxong/tinydir/issues/13)
|
17
core/os/tinydir/package.json
Normal file
17
core/os/tinydir/package.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"name": "tinydir",
|
||||||
|
"description": "Lightweight, portable and easy to integrate C directory and file reader",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"keywords": [
|
||||||
|
"dir",
|
||||||
|
"directory",
|
||||||
|
"file",
|
||||||
|
"reader",
|
||||||
|
"filesystem"
|
||||||
|
],
|
||||||
|
"src": [
|
||||||
|
"tinydir.h"
|
||||||
|
],
|
||||||
|
"version": "1.2.4",
|
||||||
|
"repo": "cxong/tinydir"
|
||||||
|
}
|
831
core/os/tinydir/tinydir.h
Normal file
831
core/os/tinydir/tinydir.h
Normal file
@ -0,0 +1,831 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2013-2019, tinydir authors:
|
||||||
|
- Cong Xu
|
||||||
|
- Lautis Sun
|
||||||
|
- Baudouin Feildel
|
||||||
|
- Andargor <andargor@yahoo.com>
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef TINYDIR_H
|
||||||
|
#define TINYDIR_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((defined _UNICODE) && !(defined UNICODE))
|
||||||
|
#define UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ((defined UNICODE) && !(defined _UNICODE))
|
||||||
|
#define _UNICODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# endif
|
||||||
|
# include <windows.h>
|
||||||
|
# include <tchar.h>
|
||||||
|
# pragma warning(push)
|
||||||
|
# pragma warning (disable : 4996)
|
||||||
|
#else
|
||||||
|
# include <dirent.h>
|
||||||
|
# include <libgen.h>
|
||||||
|
# include <sys/stat.h>
|
||||||
|
# include <stddef.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
# include <tchar.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* types */
|
||||||
|
|
||||||
|
/* Windows UNICODE wide character support */
|
||||||
|
#if defined _MSC_VER || defined __MINGW32__
|
||||||
|
# define _tinydir_char_t TCHAR
|
||||||
|
# define TINYDIR_STRING(s) _TEXT(s)
|
||||||
|
# define _tinydir_strlen _tcslen
|
||||||
|
# define _tinydir_strcpy _tcscpy
|
||||||
|
# define _tinydir_strcat _tcscat
|
||||||
|
# define _tinydir_strcmp _tcscmp
|
||||||
|
# define _tinydir_strrchr _tcsrchr
|
||||||
|
# define _tinydir_strncmp _tcsncmp
|
||||||
|
#else
|
||||||
|
# define _tinydir_char_t char
|
||||||
|
# define TINYDIR_STRING(s) s
|
||||||
|
# define _tinydir_strlen strlen
|
||||||
|
# define _tinydir_strcpy strcpy
|
||||||
|
# define _tinydir_strcat strcat
|
||||||
|
# define _tinydir_strcmp strcmp
|
||||||
|
# define _tinydir_strrchr strrchr
|
||||||
|
# define _tinydir_strncmp strncmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
# include <windows.h>
|
||||||
|
# define _TINYDIR_PATH_MAX MAX_PATH
|
||||||
|
#elif defined __linux__
|
||||||
|
# include <limits.h>
|
||||||
|
# ifdef PATH_MAX
|
||||||
|
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||||
|
# endif
|
||||||
|
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
|
# include <sys/param.h>
|
||||||
|
# if defined(BSD)
|
||||||
|
# include <limits.h>
|
||||||
|
# ifdef PATH_MAX
|
||||||
|
# define _TINYDIR_PATH_MAX PATH_MAX
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _TINYDIR_PATH_MAX
|
||||||
|
#define _TINYDIR_PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
/* extra chars for the "\\*" mask */
|
||||||
|
# define _TINYDIR_PATH_EXTRA 2
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_PATH_EXTRA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _TINYDIR_FILENAME_MAX 256
|
||||||
|
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
#define _TINYDIR_DRIVE_MAX 3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define _TINYDIR_FUNC static __inline
|
||||||
|
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
|
||||||
|
# define _TINYDIR_FUNC static __inline__
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_FUNC static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
|
||||||
|
#ifdef TINYDIR_USE_READDIR_R
|
||||||
|
|
||||||
|
/* readdir_r is a POSIX-only function, and may not be available under various
|
||||||
|
* environments/settings, e.g. MinGW. Use readdir fallback */
|
||||||
|
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
|
||||||
|
_POSIX_SOURCE
|
||||||
|
# define _TINYDIR_HAS_READDIR_R
|
||||||
|
#endif
|
||||||
|
#if _POSIX_C_SOURCE >= 200112L
|
||||||
|
# define _TINYDIR_HAS_FPATHCONF
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
#if _BSD_SOURCE || _SVID_SOURCE || \
|
||||||
|
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
|
||||||
|
# define _TINYDIR_HAS_DIRFD
|
||||||
|
# include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
|
||||||
|
defined _PC_NAME_MAX
|
||||||
|
# define _TINYDIR_USE_FPATHCONF
|
||||||
|
#endif
|
||||||
|
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
|
||||||
|
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
|
||||||
|
# define _TINYDIR_USE_READDIR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Use readdir by default */
|
||||||
|
#else
|
||||||
|
# define _TINYDIR_USE_READDIR
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#if (defined __MINGW32__) && (defined _UNICODE)
|
||||||
|
#define _TINYDIR_DIR _WDIR
|
||||||
|
#define _tinydir_dirent _wdirent
|
||||||
|
#define _tinydir_opendir _wopendir
|
||||||
|
#define _tinydir_readdir _wreaddir
|
||||||
|
#define _tinydir_closedir _wclosedir
|
||||||
|
#else
|
||||||
|
#define _TINYDIR_DIR DIR
|
||||||
|
#define _tinydir_dirent dirent
|
||||||
|
#define _tinydir_opendir opendir
|
||||||
|
#define _tinydir_readdir readdir
|
||||||
|
#define _tinydir_closedir closedir
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
|
||||||
|
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
|
||||||
|
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
|
||||||
|
#else
|
||||||
|
#error "Either define both alloc and free or none of them!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_TINYDIR_MALLOC)
|
||||||
|
#define _TINYDIR_MALLOC(_size) malloc(_size)
|
||||||
|
#define _TINYDIR_FREE(_ptr) free(_ptr)
|
||||||
|
#endif /* !defined(_TINYDIR_MALLOC) */
|
||||||
|
|
||||||
|
typedef struct tinydir_file
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
|
||||||
|
_tinydir_char_t *extension;
|
||||||
|
int is_dir;
|
||||||
|
int is_reg;
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
struct _stat _s;
|
||||||
|
#else
|
||||||
|
struct stat _s;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} tinydir_file;
|
||||||
|
|
||||||
|
typedef struct tinydir_dir
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
int has_next;
|
||||||
|
size_t n_files;
|
||||||
|
|
||||||
|
tinydir_file *_files;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
HANDLE _h;
|
||||||
|
WIN32_FIND_DATA _f;
|
||||||
|
#else
|
||||||
|
_TINYDIR_DIR *_d;
|
||||||
|
struct _tinydir_dirent *_e;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
struct _tinydir_dirent *_ep;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
} tinydir_dir;
|
||||||
|
|
||||||
|
|
||||||
|
/* declarations */
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void tinydir_close(tinydir_dir *dir);
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_next(tinydir_dir *dir);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void _tinydir_get_ext(tinydir_file *file);
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int _tinydir_file_cmp(const void *a, const void *b);
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* definitions*/
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
int error;
|
||||||
|
int size; /* using int size */
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
|
||||||
|
#endif
|
||||||
|
_tinydir_char_t *pathp;
|
||||||
|
|
||||||
|
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialise dir */
|
||||||
|
dir->_files = NULL;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_h = INVALID_HANDLE_VALUE;
|
||||||
|
#else
|
||||||
|
dir->_d = NULL;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
dir->_ep = NULL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
tinydir_close(dir);
|
||||||
|
|
||||||
|
_tinydir_strcpy(dir->path, path);
|
||||||
|
/* Remove trailing slashes */
|
||||||
|
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
|
||||||
|
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
|
||||||
|
{
|
||||||
|
*pathp = TINYDIR_STRING('\0');
|
||||||
|
pathp++;
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_tinydir_strcpy(path_buf, dir->path);
|
||||||
|
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
|
||||||
|
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
|
||||||
|
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
|
||||||
|
#else
|
||||||
|
dir->_h = FindFirstFile(path_buf, &dir->_f);
|
||||||
|
#endif
|
||||||
|
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
#else
|
||||||
|
dir->_d = _tinydir_opendir(path);
|
||||||
|
if (dir->_d == NULL)
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read first file */
|
||||||
|
dir->has_next = 1;
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef _TINYDIR_USE_READDIR
|
||||||
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
|
#else
|
||||||
|
/* allocate dirent buffer for readdir_r */
|
||||||
|
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
|
||||||
|
if (size == -1) return -1;
|
||||||
|
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
|
||||||
|
if (dir->_ep == NULL) return -1;
|
||||||
|
|
||||||
|
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
|
||||||
|
if (error != 0) return -1;
|
||||||
|
#endif
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
{
|
||||||
|
dir->has_next = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
/* Count the number of files first, to pre-allocate the files array */
|
||||||
|
size_t n_files = 0;
|
||||||
|
if (tinydir_open(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
while (dir->has_next)
|
||||||
|
{
|
||||||
|
n_files++;
|
||||||
|
if (tinydir_next(dir) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tinydir_close(dir);
|
||||||
|
|
||||||
|
if (n_files == 0 || tinydir_open(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir->n_files = 0;
|
||||||
|
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
|
||||||
|
if (dir->_files == NULL)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
while (dir->has_next)
|
||||||
|
{
|
||||||
|
tinydir_file *p_file;
|
||||||
|
dir->n_files++;
|
||||||
|
|
||||||
|
p_file = &dir->_files[dir->n_files - 1];
|
||||||
|
if (tinydir_readfile(dir, p_file) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tinydir_next(dir) == -1)
|
||||||
|
{
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Just in case the number of files has changed between the first and
|
||||||
|
second reads, terminate without writing into unallocated memory */
|
||||||
|
if (dir->n_files == n_files)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void tinydir_close(tinydir_dir *dir)
|
||||||
|
{
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(dir->path, 0, sizeof(dir->path));
|
||||||
|
dir->has_next = 0;
|
||||||
|
dir->n_files = 0;
|
||||||
|
_TINYDIR_FREE(dir->_files);
|
||||||
|
dir->_files = NULL;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (dir->_h != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
FindClose(dir->_h);
|
||||||
|
}
|
||||||
|
dir->_h = INVALID_HANDLE_VALUE;
|
||||||
|
#else
|
||||||
|
if (dir->_d)
|
||||||
|
{
|
||||||
|
_tinydir_closedir(dir->_d);
|
||||||
|
}
|
||||||
|
dir->_d = NULL;
|
||||||
|
dir->_e = NULL;
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
_TINYDIR_FREE(dir->_ep);
|
||||||
|
dir->_ep = NULL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_next(tinydir_dir *dir)
|
||||||
|
{
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!dir->has_next)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (FindNextFile(dir->_h, &dir->_f) == 0)
|
||||||
|
#else
|
||||||
|
#ifdef _TINYDIR_USE_READDIR
|
||||||
|
dir->_e = _tinydir_readdir(dir->_d);
|
||||||
|
#else
|
||||||
|
if (dir->_ep == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
dir->has_next = 0;
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (GetLastError() != ERROR_SUCCESS &&
|
||||||
|
GetLastError() != ERROR_NO_MORE_FILES)
|
||||||
|
{
|
||||||
|
tinydir_close(dir);
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
|
||||||
|
{
|
||||||
|
const _tinydir_char_t *filename;
|
||||||
|
if (dir == NULL || file == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
if (dir->_h == INVALID_HANDLE_VALUE)
|
||||||
|
#else
|
||||||
|
if (dir->_e == NULL)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
filename =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
dir->_f.cFileName;
|
||||||
|
#else
|
||||||
|
dir->_e->d_name;
|
||||||
|
#endif
|
||||||
|
if (_tinydir_strlen(dir->path) +
|
||||||
|
_tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
|
||||||
|
_TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
/* the path for the file will be too long */
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tinydir_strcpy(file->path, dir->path);
|
||||||
|
if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0)
|
||||||
|
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
|
||||||
|
_tinydir_strcpy(file->name, filename);
|
||||||
|
_tinydir_strcat(file->path, filename);
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifdef __MINGW32__
|
||||||
|
if (_tstat(
|
||||||
|
#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \
|
||||||
|
|| ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
|
||||||
|
|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
|
||||||
|
if (lstat(
|
||||||
|
#else
|
||||||
|
if (stat(
|
||||||
|
#endif
|
||||||
|
file->path, &file->_s) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
_tinydir_get_ext(file);
|
||||||
|
|
||||||
|
file->is_dir =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||||
|
#else
|
||||||
|
S_ISDIR(file->_s.st_mode);
|
||||||
|
#endif
|
||||||
|
file->is_reg =
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
|
||||||
|
(
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
|
||||||
|
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
|
||||||
|
#endif
|
||||||
|
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
|
||||||
|
#endif
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
|
||||||
|
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
|
||||||
|
#else
|
||||||
|
S_ISREG(file->_s.st_mode);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
|
||||||
|
{
|
||||||
|
if (dir == NULL || file == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (i >= dir->n_files)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
|
||||||
|
_tinydir_get_ext(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
|
||||||
|
{
|
||||||
|
_tinydir_char_t path[_TINYDIR_PATH_MAX];
|
||||||
|
if (dir == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (i >= dir->n_files || !dir->_files[i].is_dir)
|
||||||
|
{
|
||||||
|
errno = ENOENT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tinydir_strcpy(path, dir->_files[i].path);
|
||||||
|
tinydir_close(dir);
|
||||||
|
if (tinydir_open_sorted(dir, path) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open a single file given its path */
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
|
||||||
|
{
|
||||||
|
tinydir_dir dir;
|
||||||
|
int result = 0;
|
||||||
|
int found = 0;
|
||||||
|
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
|
||||||
|
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
|
||||||
|
_tinydir_char_t *dir_name;
|
||||||
|
_tinydir_char_t *base_name;
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
|
||||||
|
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
|
||||||
|
{
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the parent path */
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
|
||||||
|
errno = _tsplitpath_s(
|
||||||
|
path,
|
||||||
|
drive_buf, _TINYDIR_DRIVE_MAX,
|
||||||
|
dir_name_buf, _TINYDIR_FILENAME_MAX,
|
||||||
|
file_name_buf, _TINYDIR_FILENAME_MAX,
|
||||||
|
ext_buf, _TINYDIR_FILENAME_MAX);
|
||||||
|
#else
|
||||||
|
_tsplitpath(
|
||||||
|
path,
|
||||||
|
drive_buf,
|
||||||
|
dir_name_buf,
|
||||||
|
file_name_buf,
|
||||||
|
ext_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (errno)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _splitpath_s not work fine with only filename and widechar support */
|
||||||
|
#ifdef _UNICODE
|
||||||
|
if (drive_buf[0] == L'\xFEFE')
|
||||||
|
drive_buf[0] = '\0';
|
||||||
|
if (dir_name_buf[0] == L'\xFEFE')
|
||||||
|
dir_name_buf[0] = '\0';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Emulate the behavior of dirname by returning "." for dir name if it's
|
||||||
|
empty */
|
||||||
|
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
|
||||||
|
{
|
||||||
|
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
|
||||||
|
}
|
||||||
|
/* Concatenate the drive letter and dir name to form full dir name */
|
||||||
|
_tinydir_strcat(drive_buf, dir_name_buf);
|
||||||
|
dir_name = drive_buf;
|
||||||
|
/* Concatenate the file name and extension to form base name */
|
||||||
|
_tinydir_strcat(file_name_buf, ext_buf);
|
||||||
|
base_name = file_name_buf;
|
||||||
|
#else
|
||||||
|
_tinydir_strcpy(dir_name_buf, path);
|
||||||
|
dir_name = dirname(dir_name_buf);
|
||||||
|
_tinydir_strcpy(file_name_buf, path);
|
||||||
|
base_name = basename(file_name_buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Special case: if the path is a root dir, open the parent dir as the file */
|
||||||
|
#if (defined _MSC_VER || defined __MINGW32__)
|
||||||
|
if (_tinydir_strlen(base_name) == 0)
|
||||||
|
#else
|
||||||
|
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
memset(file, 0, sizeof * file);
|
||||||
|
file->is_dir = 1;
|
||||||
|
file->is_reg = 0;
|
||||||
|
_tinydir_strcpy(file->path, dir_name);
|
||||||
|
file->extension = file->path + _tinydir_strlen(file->path);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open the parent directory */
|
||||||
|
if (tinydir_open(&dir, dir_name) == -1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read through the parent directory and look for the file */
|
||||||
|
while (dir.has_next)
|
||||||
|
{
|
||||||
|
if (tinydir_readfile(&dir, file) == -1)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
if (_tinydir_strcmp(file->name, base_name) == 0)
|
||||||
|
{
|
||||||
|
/* File found */
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tinydir_next(&dir);
|
||||||
|
}
|
||||||
|
if (!found)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
errno = ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bail:
|
||||||
|
tinydir_close(&dir);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
void _tinydir_get_ext(tinydir_file *file)
|
||||||
|
{
|
||||||
|
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
|
||||||
|
if (period == NULL)
|
||||||
|
{
|
||||||
|
file->extension = &(file->name[_tinydir_strlen(file->name)]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
file->extension = period + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
int _tinydir_file_cmp(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const tinydir_file *fa = (const tinydir_file *)a;
|
||||||
|
const tinydir_file *fb = (const tinydir_file *)b;
|
||||||
|
if (fa->is_dir != fb->is_dir)
|
||||||
|
{
|
||||||
|
return -(fa->is_dir - fb->is_dir);
|
||||||
|
}
|
||||||
|
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
#ifndef _TINYDIR_USE_READDIR
|
||||||
|
/*
|
||||||
|
The following authored by Ben Hutchings <ben@decadent.org.uk>
|
||||||
|
from https://womble.decadent.org.uk/readdir_r-advisory.html
|
||||||
|
*/
|
||||||
|
/* Calculate the required buffer size (in bytes) for directory *
|
||||||
|
* entries read from the given directory handle. Return -1 if this *
|
||||||
|
* this cannot be done. *
|
||||||
|
* *
|
||||||
|
* This code does not trust values of NAME_MAX that are less than *
|
||||||
|
* 255, since some systems (including at least HP-UX) incorrectly *
|
||||||
|
* define it to be a smaller value. */
|
||||||
|
_TINYDIR_FUNC
|
||||||
|
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
|
||||||
|
{
|
||||||
|
long name_max;
|
||||||
|
size_t name_end;
|
||||||
|
/* parameter may be unused */
|
||||||
|
(void)dirp;
|
||||||
|
|
||||||
|
#if defined _TINYDIR_USE_FPATHCONF
|
||||||
|
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
|
||||||
|
if (name_max == -1)
|
||||||
|
#if defined(NAME_MAX)
|
||||||
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
|
#else
|
||||||
|
return (size_t)(-1);
|
||||||
|
#endif
|
||||||
|
#elif defined(NAME_MAX)
|
||||||
|
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
|
||||||
|
#else
|
||||||
|
#error "buffer size for readdir_r cannot be determined"
|
||||||
|
#endif
|
||||||
|
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
|
||||||
|
return (name_end > sizeof(struct _tinydir_dirent) ?
|
||||||
|
name_end : sizeof(struct _tinydir_dirent));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
# if defined (_MSC_VER)
|
||||||
|
# pragma warning(pop)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
54
core/reference.cpp
Normal file
54
core/reference.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "reference.h"
|
||||||
|
|
||||||
|
bool Reference::init_ref() {
|
||||||
|
if (reference()) {
|
||||||
|
if (!is_referenced() && refcount_init.unref()) {
|
||||||
|
unreference(); // first referencing is already 1, so compensate for the ref above
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int Reference::reference_get_count() const {
|
||||||
|
return refcount.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reference::reference() {
|
||||||
|
uint32_t rc_val = refcount.refval();
|
||||||
|
bool success = rc_val != 0;
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reference::unreference() {
|
||||||
|
uint32_t rc_val = refcount.unrefval();
|
||||||
|
bool die = rc_val == 0;
|
||||||
|
|
||||||
|
return die;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference::Reference() :
|
||||||
|
Object() {
|
||||||
|
refcount.init();
|
||||||
|
refcount_init.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
Reference::~Reference() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void WeakRef::set_obj(Object *p_object) {
|
||||||
|
//ref = p_object ? p_object->get_instance_id() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WeakRef::set_ref(const REF &p_ref) {
|
||||||
|
//ref = p_ref.is_valid() ? p_ref->get_instance_id() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WeakRef::WeakRef() :
|
||||||
|
ref(0) {
|
||||||
|
}
|
||||||
|
*/
|
201
core/reference.h
Normal file
201
core/reference.h
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
#ifndef REFERENCE_H
|
||||||
|
#define REFERENCE_H
|
||||||
|
|
||||||
|
// Most of the code is from the godot engine's reference.h
|
||||||
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
|
||||||
|
|
||||||
|
#include "safe_refcount.h"
|
||||||
|
#include "object.h"
|
||||||
|
#include "object_id.h"
|
||||||
|
#include "memory.h"
|
||||||
|
|
||||||
|
class Reference : public Object {
|
||||||
|
RCPP_OBJECT(Reference, Object);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*_FORCE_INLINE_*/ bool is_referenced() const { return refcount_init.get() != 1; }
|
||||||
|
bool init_ref();
|
||||||
|
bool reference(); // returns false if refcount is at zero and didn't get increased
|
||||||
|
bool unreference();
|
||||||
|
int reference_get_count() const;
|
||||||
|
|
||||||
|
Reference();
|
||||||
|
virtual ~Reference();
|
||||||
|
|
||||||
|
private:
|
||||||
|
SafeRefCount refcount;
|
||||||
|
SafeRefCount refcount_init;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class Ref {
|
||||||
|
T *reference;
|
||||||
|
|
||||||
|
void ref(const Ref &p_from) {
|
||||||
|
if (p_from.reference == reference) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unref();
|
||||||
|
|
||||||
|
reference = p_from.reference;
|
||||||
|
if (reference) {
|
||||||
|
reference->reference();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ref_pointer(T *p_ref) {
|
||||||
|
//ERR_FAIL_COND(!p_ref);
|
||||||
|
|
||||||
|
if (p_ref->init_ref()) {
|
||||||
|
reference = p_ref;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//virtual Reference * get_reference() const { return reference; }
|
||||||
|
public:
|
||||||
|
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
|
||||||
|
return reference == p_ptr;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
|
||||||
|
return reference != p_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
|
||||||
|
return reference < p_r.reference;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
|
||||||
|
return reference == p_r.reference;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
|
||||||
|
return reference != p_r.reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ T *operator->() {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ T *operator*() {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ const T *operator->() const {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ const T *ptr() const {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
_FORCE_INLINE_ T *ptr() {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
_FORCE_INLINE_ const T *operator*() const {
|
||||||
|
return reference;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator=(const Ref &p_from) {
|
||||||
|
ref(p_from);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T_Other>
|
||||||
|
void operator=(const Ref<T_Other> &p_from) {
|
||||||
|
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||||
|
if (!refb) {
|
||||||
|
unref();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ref r;
|
||||||
|
r.reference = Object::cast_to<T>(refb);
|
||||||
|
ref(r);
|
||||||
|
r.reference = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T_Other>
|
||||||
|
void reference_ptr(T_Other *p_ptr) {
|
||||||
|
if (reference == p_ptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unref();
|
||||||
|
|
||||||
|
T *r = Object::cast_to<T>(p_ptr);
|
||||||
|
if (r) {
|
||||||
|
ref_pointer(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref(const Ref &p_from) {
|
||||||
|
reference = nullptr;
|
||||||
|
ref(p_from);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T_Other>
|
||||||
|
Ref(const Ref<T_Other> &p_from) {
|
||||||
|
reference = nullptr;
|
||||||
|
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
|
||||||
|
if (!refb) {
|
||||||
|
unref();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ref r;
|
||||||
|
r.reference = Object::cast_to<T>(refb);
|
||||||
|
ref(r);
|
||||||
|
r.reference = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref(T *p_reference) {
|
||||||
|
reference = nullptr;
|
||||||
|
if (p_reference) {
|
||||||
|
ref_pointer(p_reference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool is_valid() const { return reference != nullptr; }
|
||||||
|
inline bool is_null() const { return reference == nullptr; }
|
||||||
|
|
||||||
|
void unref() {
|
||||||
|
//TODO this should be moved to mutexes, since this engine does not really
|
||||||
|
// do a lot of referencing on references and stuff
|
||||||
|
// mutexes will avoid more crashes?
|
||||||
|
|
||||||
|
if (reference && reference->unreference()) {
|
||||||
|
memdelete(reference);
|
||||||
|
}
|
||||||
|
reference = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void instance() {
|
||||||
|
ref(memnew(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref() {
|
||||||
|
reference = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~Ref() {
|
||||||
|
unref();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef Ref<Reference> REF;
|
||||||
|
|
||||||
|
/*
|
||||||
|
class WeakRef : public Reference {
|
||||||
|
RCPP_OBJECT(WeakRef, Reference);
|
||||||
|
|
||||||
|
ObjectID ref;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void _bind_methods();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void set_obj(Object *p_object);
|
||||||
|
void set_ref(const REF &p_ref);
|
||||||
|
|
||||||
|
WeakRef();
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif
|
118
core/signal.cpp
Normal file
118
core/signal.cpp
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#include "signal.h"
|
||||||
|
|
||||||
|
void Signal::connect_static(void (*func)(Signal *)) {
|
||||||
|
StaticSignalEntry *se = new StaticSignalEntry();
|
||||||
|
se->func = func;
|
||||||
|
|
||||||
|
entries.push_back(se);
|
||||||
|
}
|
||||||
|
void Signal::disconnect_static(void (*func)(Signal *)) {
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
SignalEntry *e = entries[i];
|
||||||
|
|
||||||
|
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
|
||||||
|
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
|
||||||
|
|
||||||
|
if (se->func == func) {
|
||||||
|
entries.remove_keep_order(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool Signal::is_connected_static(void (*func)(Signal *)) {
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
SignalEntry *e = entries[i];
|
||||||
|
|
||||||
|
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
|
||||||
|
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
|
||||||
|
|
||||||
|
if (se->func == func) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal::emit(Object *p_emitter) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal::emit(Object *p_emitter, const Variant &p1) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
params.push_back(p1);
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
}
|
||||||
|
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
params.push_back(p1);
|
||||||
|
params.push_back(p2);
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
}
|
||||||
|
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
params.push_back(p1);
|
||||||
|
params.push_back(p2);
|
||||||
|
params.push_back(p3);
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
params.push_back(p1);
|
||||||
|
params.push_back(p2);
|
||||||
|
params.push_back(p3);
|
||||||
|
params.push_back(p4);
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
|
||||||
|
emitter = p_emitter;
|
||||||
|
|
||||||
|
params.push_back(p1);
|
||||||
|
params.push_back(p2);
|
||||||
|
params.push_back(p3);
|
||||||
|
params.push_back(p4);
|
||||||
|
params.push_back(p5);
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
entries[i]->call(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
params.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal::Signal() {
|
||||||
|
}
|
||||||
|
Signal::~Signal() {
|
||||||
|
}
|
172
core/signal.h
Normal file
172
core/signal.h
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
#ifndef SIGNAL_H
|
||||||
|
#define SIGNAL_H
|
||||||
|
|
||||||
|
#include "core/containers/vector.h"
|
||||||
|
#include "core/string.h"
|
||||||
|
#include "core/variant.h"
|
||||||
|
|
||||||
|
#include "reference.h"
|
||||||
|
|
||||||
|
class Signal {
|
||||||
|
public:
|
||||||
|
Object *emitter;
|
||||||
|
Vector<Variant> params;
|
||||||
|
Vector<Variant> static_data;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void connect(T *obj, void (*func)(T*, Signal *));
|
||||||
|
template <class T>
|
||||||
|
void disconnect(T *obj, void (*func)(T*, Signal *));
|
||||||
|
template <class T>
|
||||||
|
bool is_connected(T *obj, void (*func)(T*, Signal *));
|
||||||
|
|
||||||
|
void connect_static(void (*func)(Signal *));
|
||||||
|
void disconnect_static(void (*func)(Signal *));
|
||||||
|
bool is_connected_static(void (*func)(Signal *));
|
||||||
|
|
||||||
|
void emit(Object *p_emitter);
|
||||||
|
void emit(Object *p_emitter, const Variant &p1);
|
||||||
|
void emit(Object *p_emitter, const Variant &p1, const Variant &p2);
|
||||||
|
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3);
|
||||||
|
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4);
|
||||||
|
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5);
|
||||||
|
|
||||||
|
Signal();
|
||||||
|
~Signal();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum SignalEntryType {
|
||||||
|
SIGNAL_ENTRY_TYPE_NONE = 0,
|
||||||
|
SIGNAL_ENTRY_TYPE_STATIC = 1,
|
||||||
|
SIGNAL_ENTRY_TYPE_CLASS = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SignalEntry {
|
||||||
|
SignalEntryType type;
|
||||||
|
|
||||||
|
virtual void call(Signal *s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
SignalEntry() {
|
||||||
|
type = SIGNAL_ENTRY_TYPE_NONE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StaticSignalEntry : public SignalEntry {
|
||||||
|
void (*func)(Signal *);
|
||||||
|
|
||||||
|
virtual void call(Signal *s) {
|
||||||
|
func(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
StaticSignalEntry() {
|
||||||
|
type = SIGNAL_ENTRY_TYPE_STATIC;
|
||||||
|
func = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClassSignalEntry : public SignalEntry {
|
||||||
|
|
||||||
|
virtual void* get_obj_ptr() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void* get_func_ptr() {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassSignalEntry() {
|
||||||
|
type = SIGNAL_ENTRY_TYPE_CLASS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ClassSignalEntrySpec : public ClassSignalEntry {
|
||||||
|
union {
|
||||||
|
T* obj;
|
||||||
|
void* obj_ptr;
|
||||||
|
};
|
||||||
|
union {
|
||||||
|
void (*func)(T*, Signal *);
|
||||||
|
void* func_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void call(Signal *s) {
|
||||||
|
func(obj, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* get_obj_ptr() {
|
||||||
|
return obj_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* get_func_ptr() {
|
||||||
|
return func_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassSignalEntrySpec() {
|
||||||
|
obj = nullptr;
|
||||||
|
func = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Vector<SignalEntry *> entries;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Signal::connect(T *obj, void (*func)(T*, Signal *)) {
|
||||||
|
ClassSignalEntrySpec<T> *ce = new ClassSignalEntrySpec<T>();
|
||||||
|
ce->obj = obj;
|
||||||
|
ce->func = func;
|
||||||
|
|
||||||
|
entries.push_back(ce);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Signal::disconnect(T *obj, void (*func)(T*, Signal *)) {
|
||||||
|
ClassSignalEntrySpec<T> t;
|
||||||
|
t.obj = obj;
|
||||||
|
t.func = func;
|
||||||
|
|
||||||
|
void* obj_ptr = t.obj_ptr;
|
||||||
|
void* func_ptr = t.func_ptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
SignalEntry *e = entries[i];
|
||||||
|
|
||||||
|
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
|
||||||
|
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
|
||||||
|
|
||||||
|
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
|
||||||
|
entries.remove_keep_order(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) {
|
||||||
|
ClassSignalEntrySpec<T> t;
|
||||||
|
t.obj = obj;
|
||||||
|
t.func = func;
|
||||||
|
|
||||||
|
void* obj_ptr = t.obj_ptr;
|
||||||
|
void* func_ptr = t.func_ptr;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.size(); ++i) {
|
||||||
|
SignalEntry *e = entries[i];
|
||||||
|
|
||||||
|
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
|
||||||
|
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
|
||||||
|
|
||||||
|
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
2528
core/string.cpp
Normal file
2528
core/string.cpp
Normal file
File diff suppressed because it is too large
Load Diff
280
core/string.h
Normal file
280
core/string.h
Normal file
@ -0,0 +1,280 @@
|
|||||||
|
#ifndef STRING_H
|
||||||
|
#define STRING_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "core/containers/vector.h"
|
||||||
|
|
||||||
|
#ifndef DEFAULT_DIRECTORY_SEPARATOR
|
||||||
|
#define DEFAULT_DIRECTORY_SEPARATOR '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Variant;
|
||||||
|
|
||||||
|
// TODO move to wchar_t!
|
||||||
|
|
||||||
|
class String {
|
||||||
|
public:
|
||||||
|
void push_back(const char element);
|
||||||
|
void push_back(const wchar_t element);
|
||||||
|
void pop_back();
|
||||||
|
void remove(const int index);
|
||||||
|
void erase(const char element);
|
||||||
|
void erase(const int start_index, const int length);
|
||||||
|
void clear();
|
||||||
|
bool empty() const;
|
||||||
|
char get(const int index);
|
||||||
|
const char get(const int index) const;
|
||||||
|
void set(const int index, const char value);
|
||||||
|
|
||||||
|
int size() const;
|
||||||
|
int capacity() const;
|
||||||
|
void ensure_capacity(const int capacity);
|
||||||
|
void resize(const int s);
|
||||||
|
int find(const char val, const int from = 0) const;
|
||||||
|
int find(const String &val, const int from = 0) const;
|
||||||
|
int find_reversed(const char val, const int from = -1) const;
|
||||||
|
int find_reversed(const String &val, const int from = -1) const;
|
||||||
|
void get_substr(char *into_buf, const int start_index, const int len);
|
||||||
|
void get_substr_nt(char *into_buf, const int start_index, const int len);
|
||||||
|
String substr(const int start_index, const int len) const;
|
||||||
|
String substr_index(const int start_index, const int end_index) const; //end_index is not included
|
||||||
|
bool contains(const char val) const;
|
||||||
|
bool contains(const String &val) const;
|
||||||
|
|
||||||
|
bool is_word_at(const int index, const char *str) const;
|
||||||
|
bool is_word_at(const int index, const String &val) const;
|
||||||
|
|
||||||
|
void replace_from(const int start_index, const int length, const String &with);
|
||||||
|
void replace(const String &find_str, const String &with);
|
||||||
|
void replace(const String &find_str, const String &with, const int count);
|
||||||
|
|
||||||
|
int compare(const String &other) const;
|
||||||
|
|
||||||
|
int first_difference_index(const String &other) const;
|
||||||
|
|
||||||
|
void to_lower();
|
||||||
|
String as_lower() const;
|
||||||
|
|
||||||
|
void trim();
|
||||||
|
void trim_beginning();
|
||||||
|
void trim_end();
|
||||||
|
|
||||||
|
bool ends_with(const char c) const;
|
||||||
|
bool ends_with(const String &str) const;
|
||||||
|
|
||||||
|
bool starts_with(const char c) const;
|
||||||
|
bool starts_with(const String &str) const;
|
||||||
|
|
||||||
|
int get_slice_count(const char splitter) const;
|
||||||
|
int get_slice_count(const String &splitter) const;
|
||||||
|
String get_slice(const char splitter, int index);
|
||||||
|
String get_slice(const String &splitter, int index);
|
||||||
|
|
||||||
|
Vector<String> split(const char splitter) const;
|
||||||
|
Vector<String> split(const String &splitter) const;
|
||||||
|
|
||||||
|
uint8_t read_uint8_bytes_at(int &index, bool advance_index = true);
|
||||||
|
uint16_t read_uint16_bytes_at(int &index, bool advance_index = true);
|
||||||
|
uint32_t read_uint32_bytes_at(int &index, bool advance_index = true);
|
||||||
|
uint64_t read_uint64_bytes_at(int &index, bool advance_index = true);
|
||||||
|
|
||||||
|
int8_t read_int8_bytes_at(int &index, bool advance_index = true);
|
||||||
|
int16_t read_int16_bytes_at(int &index, bool advance_index = true);
|
||||||
|
int32_t read_int32_bytes_at(int &index, bool advance_index = true);
|
||||||
|
int64_t read_int64_bytes_at(int &index, bool advance_index = true);
|
||||||
|
|
||||||
|
void append_uint8_bytes(const uint8_t val);
|
||||||
|
void append_uint16_bytes(const uint16_t val);
|
||||||
|
void append_uint32_bytes(const uint32_t val);
|
||||||
|
void append_uint64_bytes(const uint64_t val);
|
||||||
|
|
||||||
|
void append_int8_bytes(const int8_t val);
|
||||||
|
void append_int16_bytes(const int16_t val);
|
||||||
|
void append_int32_bytes(const int32_t val);
|
||||||
|
void append_int64_bytes(const int64_t val);
|
||||||
|
|
||||||
|
float read_float_bytes_at(int &index, bool advance_index = true);
|
||||||
|
void append_float_bytes(const float val);
|
||||||
|
double read_double_bytes_at(int &index, bool advance_index = true);
|
||||||
|
void append_double_bytes(const double val);
|
||||||
|
|
||||||
|
void append_str(const char *str);
|
||||||
|
void append_str(const wchar_t *str);
|
||||||
|
void append_str(const String &other);
|
||||||
|
void append_str(const std::string &str);
|
||||||
|
void append_str(const String &other, const int from);
|
||||||
|
void append_str(const std::string &str, const int from);
|
||||||
|
|
||||||
|
void append_repeat(const char *str, const int times);
|
||||||
|
void append_repeat(const String &other, const int times);
|
||||||
|
|
||||||
|
void append_path(const char *path);
|
||||||
|
void append_path(const String &path);
|
||||||
|
void path_clean_end_slash();
|
||||||
|
void path_ensure_end_slash();
|
||||||
|
String path_get_basename() const;
|
||||||
|
String path_get_last_segment() const;
|
||||||
|
String path_get_prev_dir() const;
|
||||||
|
String file_get_extension() const;
|
||||||
|
|
||||||
|
void to_html_special_chars();
|
||||||
|
void from_html_special_chars();
|
||||||
|
void newline_to_br();
|
||||||
|
|
||||||
|
bool to_bool() const;
|
||||||
|
float to_float() const;
|
||||||
|
double to_double() const;
|
||||||
|
int to_int() const;
|
||||||
|
|
||||||
|
bool is_bool() const;
|
||||||
|
bool is_numeric() const;
|
||||||
|
bool is_int() const;
|
||||||
|
bool is_uint() const;
|
||||||
|
bool is_zero() const;
|
||||||
|
|
||||||
|
uint32_t to_uint() const;
|
||||||
|
std::string to_string() const;
|
||||||
|
void print() const;
|
||||||
|
|
||||||
|
// Generic set of append helpers
|
||||||
|
void append(const char *str);
|
||||||
|
void append(const wchar_t *str);
|
||||||
|
void append(const String &other);
|
||||||
|
void append(const std::string &str);
|
||||||
|
void append(const char chr);
|
||||||
|
void append(const wchar_t chr);
|
||||||
|
void append(const int num);
|
||||||
|
void append(const unsigned int num);
|
||||||
|
void append(const float num);
|
||||||
|
void append(const double num);
|
||||||
|
void append(const Variant &variant);
|
||||||
|
|
||||||
|
static String bool_num(bool val);
|
||||||
|
static String bool_str(bool val);
|
||||||
|
|
||||||
|
// Taken from the Godot Engine (MIT License)
|
||||||
|
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
|
||||||
|
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
|
||||||
|
static String num(double p_num, int p_decimals = -1);
|
||||||
|
static String num_scientific(double p_num);
|
||||||
|
static String num_real(double p_num, bool p_trailing = true);
|
||||||
|
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
|
||||||
|
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
|
||||||
|
static String chr(char32_t p_char);
|
||||||
|
|
||||||
|
// Taken from the Godot Engine (MIT License)
|
||||||
|
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
|
||||||
|
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
|
||||||
|
String ascii(bool p_allow_extended = false) const;
|
||||||
|
String utf8() const;
|
||||||
|
bool parse_utf8(const char *p_utf8, int p_len = -1); // return true on error
|
||||||
|
static String utf8(const char *p_utf8, int p_len = -1);
|
||||||
|
|
||||||
|
// Taken from the Godot Engine (MIT License)
|
||||||
|
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
|
||||||
|
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
|
||||||
|
static uint32_t hash(const wchar_t *p_cstr, int p_len); /* hash the string */
|
||||||
|
static uint32_t hash(const wchar_t *p_cstr); /* hash the string */
|
||||||
|
static uint32_t hash(const char *p_cstr, int p_len); /* hash the string */
|
||||||
|
static uint32_t hash(const char *p_cstr); /* hash the string */
|
||||||
|
uint32_t hash() const; /* hash the string */
|
||||||
|
uint64_t hash64() const; /* hash the string */
|
||||||
|
|
||||||
|
char *c_str();
|
||||||
|
const char *c_str() const;
|
||||||
|
|
||||||
|
char *dataw();
|
||||||
|
const char *data() const;
|
||||||
|
|
||||||
|
const char operator[](const int index) const;
|
||||||
|
char &operator[](const int index);
|
||||||
|
|
||||||
|
String &operator+=(const String &b);
|
||||||
|
String &operator+=(const char chr);
|
||||||
|
String &operator+=(const char *p_c_str);
|
||||||
|
String &operator+=(const std::string &b);
|
||||||
|
|
||||||
|
friend String operator+(String lhs, const String &rhs);
|
||||||
|
friend String operator+(String lhs, const char *rhs);
|
||||||
|
friend String operator+(String lhs, const char rhs);
|
||||||
|
friend String operator+(String lhs, const std::string &rhs);
|
||||||
|
|
||||||
|
friend bool operator==(const String &a, const String &b);
|
||||||
|
friend bool operator!=(const String &a, const String &b);
|
||||||
|
|
||||||
|
friend bool operator==(const String &a, const char *b);
|
||||||
|
friend bool operator!=(const String &a, const char *b);
|
||||||
|
|
||||||
|
friend bool operator==(const char *b, const String &a);
|
||||||
|
friend bool operator!=(const char *b, const String &a);
|
||||||
|
|
||||||
|
friend bool operator==(const String &a, const wchar_t *b);
|
||||||
|
friend bool operator!=(const String &a, const wchar_t *b);
|
||||||
|
|
||||||
|
friend bool operator==(const wchar_t *b, const String &a);
|
||||||
|
friend bool operator!=(const wchar_t *b, const String &a);
|
||||||
|
|
||||||
|
friend bool operator==(const String &a, std::string &b);
|
||||||
|
friend bool operator!=(const String &a, std::string &b);
|
||||||
|
|
||||||
|
friend bool operator==(std::string &b, const String &a);
|
||||||
|
friend bool operator!=(std::string &b, const String &a);
|
||||||
|
|
||||||
|
friend bool operator<(const String &a, const String &b);
|
||||||
|
friend bool operator>(const String &a, const String &b);
|
||||||
|
friend bool operator<=(const String &a, const String &b);
|
||||||
|
friend bool operator>=(const String &a, const String &b);
|
||||||
|
|
||||||
|
operator std::string() { return to_string(); }
|
||||||
|
operator std::string() const { return to_string(); }
|
||||||
|
|
||||||
|
String &operator=(const String &other);
|
||||||
|
String &operator=(const std::string &other);
|
||||||
|
String &operator=(const char *other);
|
||||||
|
String &operator=(const wchar_t *other);
|
||||||
|
|
||||||
|
String();
|
||||||
|
String(const String &other);
|
||||||
|
String(const String &other, const int grow_by);
|
||||||
|
String(const char *p_c_str);
|
||||||
|
String(const char *p_c_str, const int grow_by);
|
||||||
|
String(const wchar_t *p_c_str);
|
||||||
|
String(const int prealloc);
|
||||||
|
String(const int prealloc, const int grow_by);
|
||||||
|
String(const std::string &str);
|
||||||
|
~String();
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *_data;
|
||||||
|
int _actual_size;
|
||||||
|
int _size;
|
||||||
|
int _grow_by;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Taken from the Godot Engine (MIT License)
|
||||||
|
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
|
||||||
|
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
|
||||||
|
template <typename L, typename R>
|
||||||
|
bool is_str_less(const L *l_ptr, const R *r_ptr) {
|
||||||
|
while (true) {
|
||||||
|
if (*l_ptr == 0 && *r_ptr == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (*l_ptr == 0) {
|
||||||
|
return true;
|
||||||
|
} else if (*r_ptr == 0) {
|
||||||
|
return false;
|
||||||
|
} else if (*l_ptr < *r_ptr) {
|
||||||
|
return true;
|
||||||
|
} else if (*l_ptr > *r_ptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
l_ptr++;
|
||||||
|
r_ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
354
core/typedefs.h
Normal file
354
core/typedefs.h
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/*************************************************************************/
|
||||||
|
/* typedefs.h */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* This file is part of: */
|
||||||
|
/* GODOT ENGINE */
|
||||||
|
/* https://godotengine.org */
|
||||||
|
/*************************************************************************/
|
||||||
|
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
|
||||||
|
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
|
||||||
|
/* */
|
||||||
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||||
|
/* a copy of this software and associated documentation files (the */
|
||||||
|
/* "Software"), to deal in the Software without restriction, including */
|
||||||
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||||
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||||
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||||
|
/* the following conditions: */
|
||||||
|
/* */
|
||||||
|
/* The above copyright notice and this permission notice shall be */
|
||||||
|
/* included in all copies or substantial portions of the Software. */
|
||||||
|
/* */
|
||||||
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||||
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||||
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||||
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||||
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||||
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||||
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
|
/*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef TYPEDEFS_H
|
||||||
|
#define TYPEDEFS_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic definitions and simple functions to be used everywhere.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//#include "platform_config.h"
|
||||||
|
|
||||||
|
#ifndef _STR
|
||||||
|
#define _STR(m_x) #m_x
|
||||||
|
#define _MKSTR(m_x) _STR(m_x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//should always inline no matter what
|
||||||
|
#ifndef _ALWAYS_INLINE_
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ >= 4)
|
||||||
|
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
|
||||||
|
#elif defined(__llvm__)
|
||||||
|
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define _ALWAYS_INLINE_ __forceinline
|
||||||
|
#else
|
||||||
|
#define _ALWAYS_INLINE_ inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//should always inline, except in some cases because it makes debugging harder
|
||||||
|
#ifndef _FORCE_INLINE_
|
||||||
|
|
||||||
|
#ifdef DISABLE_FORCED_INLINE
|
||||||
|
#define _FORCE_INLINE_ inline
|
||||||
|
#else
|
||||||
|
#define _FORCE_INLINE_ _ALWAYS_INLINE_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//custom, gcc-safe offsetof, because gcc complains a lot.
|
||||||
|
template <class T>
|
||||||
|
T *_nullptr() {
|
||||||
|
T *t = NULL;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OFFSET_OF(st, m) \
|
||||||
|
((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
|
||||||
|
/**
|
||||||
|
* Some platforms (devices) don't define NULL
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Windows badly defines a lot of stuff we'll never use. Undefine it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#undef min // override standard definition
|
||||||
|
#undef max // override standard definition
|
||||||
|
#undef ERROR // override (really stupid) wingdi.h standard definition
|
||||||
|
#undef DELETE // override (another really stupid) winnt.h standard definition
|
||||||
|
#undef MessageBox // override winuser.h standard definition
|
||||||
|
#undef MIN // override standard definition
|
||||||
|
#undef MAX // override standard definition
|
||||||
|
#undef CLAMP // override standard definition
|
||||||
|
#undef Error
|
||||||
|
#undef OK
|
||||||
|
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "int_types.h"
|
||||||
|
|
||||||
|
//#include "core/error_list.h"
|
||||||
|
|
||||||
|
/** Generic ABS function, for math uses please use Math::abs */
|
||||||
|
|
||||||
|
#ifndef ABS
|
||||||
|
#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
|
||||||
|
|
||||||
|
#ifndef SGN
|
||||||
|
#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MIN
|
||||||
|
#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX
|
||||||
|
#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CLAMP
|
||||||
|
#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Generic swap template */
|
||||||
|
#ifndef SWAP
|
||||||
|
|
||||||
|
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
|
||||||
|
template <class T>
|
||||||
|
inline void __swap_tmpl(T &x, T &y) {
|
||||||
|
T aux = x;
|
||||||
|
x = y;
|
||||||
|
y = aux;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //swap
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
#define HEX2CHR(m_hex) \
|
||||||
|
((m_hex >= '0' && m_hex <= '9') ? (m_hex - '0') : \
|
||||||
|
((m_hex >= 'A' && m_hex <= 'F') ? (10 + m_hex - 'A') : \
|
||||||
|
((m_hex >= 'a' && m_hex <= 'f') ? (10 + m_hex - 'a') : 0)))
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
// Macro to check whether we are compiled by clang
|
||||||
|
// and we have a specific builtin
|
||||||
|
#if defined(__llvm__) && defined(__has_builtin)
|
||||||
|
#define _llvm_has_builtin(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define _llvm_has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_mul_overflow)
|
||||||
|
#define _mul_overflow __builtin_mul_overflow
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_add_overflow)
|
||||||
|
#define _add_overflow __builtin_add_overflow
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Function to find the next power of 2 to an integer */
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
|
||||||
|
if (x == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
--x;
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
|
||||||
|
return ++x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
|
||||||
|
x |= x >> 1;
|
||||||
|
x |= x >> 2;
|
||||||
|
x |= x >> 4;
|
||||||
|
x |= x >> 8;
|
||||||
|
x |= x >> 16;
|
||||||
|
return x - (x >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
|
||||||
|
unsigned int nx = next_power_of_2(x);
|
||||||
|
unsigned int px = previous_power_of_2(x);
|
||||||
|
return (nx - x) > (x - px) ? px : nx;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need this definition inside the function below.
|
||||||
|
static inline int get_shift_from_power_of_2(unsigned int p_pixel);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
|
||||||
|
--x;
|
||||||
|
|
||||||
|
// The number of operations on x is the base two logarithm
|
||||||
|
// of the p_number of bits in the type. Add three to account
|
||||||
|
// for sizeof(T) being in bytes.
|
||||||
|
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
|
||||||
|
|
||||||
|
// If the compiler is smart, it unrolls this loop
|
||||||
|
// If its dumb, this is a bit slow.
|
||||||
|
for (size_t i = 0; i < num; i++) {
|
||||||
|
x |= x >> (1 << i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ++x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Function to find the nearest (bigger) power of 2 to an integer */
|
||||||
|
|
||||||
|
static inline unsigned int nearest_shift(unsigned int p_number) {
|
||||||
|
for (int i = 30; i >= 0; i--) {
|
||||||
|
if (p_number & (1 << i)) {
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** get a shift value from a power of 2 */
|
||||||
|
static inline int get_shift_from_power_of_2(unsigned int p_pixel) {
|
||||||
|
// return a GL_TEXTURE_SIZE_ENUM
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < 32; i++) {
|
||||||
|
if (p_pixel == (unsigned int)(1 << i)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Swap 16 bits value for endianness */
|
||||||
|
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap16)
|
||||||
|
#define BSWAP16(x) __builtin_bswap16(x)
|
||||||
|
#else
|
||||||
|
static inline uint16_t BSWAP16(uint16_t x) {
|
||||||
|
return (x >> 8) | (x << 8);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Swap 32 bits value for endianness */
|
||||||
|
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap32)
|
||||||
|
#define BSWAP32(x) __builtin_bswap32(x)
|
||||||
|
#else
|
||||||
|
static inline uint32_t BSWAP32(uint32_t x) {
|
||||||
|
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Swap 64 bits value for endianness */
|
||||||
|
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap64)
|
||||||
|
#define BSWAP64(x) __builtin_bswap64(x)
|
||||||
|
#else
|
||||||
|
static inline uint64_t BSWAP64(uint64_t x) {
|
||||||
|
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
|
||||||
|
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
|
||||||
|
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** When compiling with RTTI, we can add an "extra"
|
||||||
|
* layer of safeness in many operations, so dynamic_cast
|
||||||
|
* is used besides casting by enum.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct Comparator {
|
||||||
|
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
|
||||||
|
};
|
||||||
|
|
||||||
|
void _global_lock();
|
||||||
|
void _global_unlock();
|
||||||
|
|
||||||
|
struct _GlobalLock {
|
||||||
|
_GlobalLock() { _global_lock(); }
|
||||||
|
~_GlobalLock() { _global_unlock(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
|
||||||
|
|
||||||
|
#ifdef NO_SAFE_CAST
|
||||||
|
#define SAFE_CAST static_cast
|
||||||
|
#else
|
||||||
|
#define SAFE_CAST dynamic_cast
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MT_SAFE
|
||||||
|
|
||||||
|
#define __STRX(m_index) #m_index
|
||||||
|
#define __STR(m_index) __STRX(m_index)
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define likely(x) __builtin_expect(!!(x), 1)
|
||||||
|
#define unlikely(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
#define likely(x) x
|
||||||
|
#define unlikely(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
|
||||||
|
#else
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_2_0
|
||||||
|
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** This is needed due to a strange OpenGL API that expects a pointer
|
||||||
|
* type for an argument that is actually an offset.
|
||||||
|
*/
|
||||||
|
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
|
||||||
|
|
||||||
|
/** Hint for compilers that this fallthrough in a switch is intentional.
|
||||||
|
* Can be replaced by [[fallthrough]] annotation if we move to C++17.
|
||||||
|
* Including conditional support for it for people who set -std=c++17
|
||||||
|
* themselves.
|
||||||
|
* Requires a trailing semicolon when used.
|
||||||
|
*/
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#define FALLTHROUGH [[fallthrough]]
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 7
|
||||||
|
#define FALLTHROUGH __attribute__((fallthrough))
|
||||||
|
#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature)
|
||||||
|
#if __has_feature(cxx_attributes) && defined(__has_warning)
|
||||||
|
#if __has_warning("-Wimplicit-fallthrough")
|
||||||
|
#define FALLTHROUGH [[clang::fallthrough]]
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALLTHROUGH
|
||||||
|
#define FALLTHROUGH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TYPEDEFS_H
|
624
core/variant.cpp
Normal file
624
core/variant.cpp
Normal file
@ -0,0 +1,624 @@
|
|||||||
|
#include "variant.h"
|
||||||
|
|
||||||
|
#include "core/math/math.h"
|
||||||
|
#include "core/reference.h"
|
||||||
|
|
||||||
|
Variant::Type Variant::get_type() const {
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variant::clear() {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
break;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
_bool = false;
|
||||||
|
break;
|
||||||
|
case TYPE_INT:
|
||||||
|
_int = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_UINT:
|
||||||
|
_uint = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
_float = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_STRING:
|
||||||
|
if (_string->owner) {
|
||||||
|
delete _string->string;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete _string;
|
||||||
|
_string = nullptr;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
delete _object;
|
||||||
|
_object = nullptr;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
_pointer = nullptr;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
}
|
||||||
|
void Variant::zero() {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
break;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
_bool = false;
|
||||||
|
break;
|
||||||
|
case TYPE_INT:
|
||||||
|
_int = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_UINT:
|
||||||
|
_uint = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
_float = 0;
|
||||||
|
break;
|
||||||
|
case TYPE_STRING:
|
||||||
|
_string->string->resize(0);
|
||||||
|
break;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
_object->object = nullptr;
|
||||||
|
_object->reference.unref();
|
||||||
|
break;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
_pointer = nullptr;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variant::parse(const String &str) {
|
||||||
|
if (str.is_int()) {
|
||||||
|
set_int(str.to_int());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.is_uint()) {
|
||||||
|
set_uint(str.to_uint());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.is_numeric()) {
|
||||||
|
set_float(str.to_float());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.is_bool()) {
|
||||||
|
set_bool(str.to_bool());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_string(str);
|
||||||
|
}
|
||||||
|
Variant Variant::parse_string(const String &str) {
|
||||||
|
Variant v = Variant();
|
||||||
|
|
||||||
|
v.parse(str);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Variant::is_null() const {
|
||||||
|
return _type == TYPE_NULL;
|
||||||
|
}
|
||||||
|
bool Variant::is_bool() const {
|
||||||
|
return _type == TYPE_BOOL;
|
||||||
|
}
|
||||||
|
bool Variant::is_int() const {
|
||||||
|
return _type == TYPE_INT;
|
||||||
|
}
|
||||||
|
bool Variant::is_uint() const {
|
||||||
|
return _type == TYPE_UINT;
|
||||||
|
}
|
||||||
|
bool Variant::is_float() const {
|
||||||
|
return _type == TYPE_FLOAT;
|
||||||
|
}
|
||||||
|
bool Variant::is_numeric() const {
|
||||||
|
return _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT;
|
||||||
|
}
|
||||||
|
bool Variant::is_string() const {
|
||||||
|
return _type == TYPE_STRING;
|
||||||
|
}
|
||||||
|
bool Variant::is_object() const {
|
||||||
|
return _type == TYPE_OBJECT;
|
||||||
|
}
|
||||||
|
bool Variant::is_pointer() const {
|
||||||
|
return _type == TYPE_POINTER;
|
||||||
|
}
|
||||||
|
bool Variant::is_reference() const {
|
||||||
|
if (_type == TYPE_OBJECT) {
|
||||||
|
return _object->reference.is_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Variant::is_primitive_type() const {
|
||||||
|
return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Variant::is_simple_type() const {
|
||||||
|
return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT || _type == TYPE_STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Variant::to_bool() const {
|
||||||
|
return _bool;
|
||||||
|
}
|
||||||
|
int Variant::to_int() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return 0;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
if (_bool) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case TYPE_INT:
|
||||||
|
case TYPE_UINT:
|
||||||
|
return _int;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return static_cast<float>(_int);
|
||||||
|
case TYPE_STRING:
|
||||||
|
return _string->string->to_int();
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
// just read the value of the pointer as int
|
||||||
|
// Could return 1 or 0, but this is almost the same, but hopefully it's more useful
|
||||||
|
return _int;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint64_t Variant::to_uint() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return 0;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
if (_bool) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case TYPE_INT:
|
||||||
|
case TYPE_UINT:
|
||||||
|
return _uint;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return static_cast<uint64_t>(_float);
|
||||||
|
case TYPE_STRING:
|
||||||
|
return _string->string->to_uint();
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
// just read the value of the pointer as uint
|
||||||
|
// Could return 1 or 0, but this is almost the same, but hopefully it's more useful
|
||||||
|
return _uint;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float Variant::to_float() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return 0;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
if (_bool) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case TYPE_INT:
|
||||||
|
return static_cast<float>(_int);
|
||||||
|
case TYPE_UINT:
|
||||||
|
return static_cast<float>(_uint);
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return _float;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return _string->string->to_float();
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
if (_uint) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String Variant::to_string() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return "NULL";
|
||||||
|
case TYPE_BOOL:
|
||||||
|
if (Math::is_zero_approx(_float)) {
|
||||||
|
return "false";
|
||||||
|
} else {
|
||||||
|
return "true";
|
||||||
|
}
|
||||||
|
case TYPE_INT:
|
||||||
|
return String::num(_int);
|
||||||
|
case TYPE_UINT:
|
||||||
|
return String::num(_uint);
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return String::num(_float);
|
||||||
|
case TYPE_STRING:
|
||||||
|
return *(_string->string);
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
case TYPE_POINTER:
|
||||||
|
if (_uint) {
|
||||||
|
return "[ Object ]";
|
||||||
|
} else {
|
||||||
|
return "[ Object (NULL) ]";
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object *Variant::to_object() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_INT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_UINT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
return _object->object;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
return nullptr;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference *Variant::to_reference() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_INT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_UINT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
return Object::cast_to<Reference>(_object->object);
|
||||||
|
case TYPE_POINTER:
|
||||||
|
return nullptr;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void *Variant::to_pointer() const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_INT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_UINT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
return nullptr;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
return _pointer;
|
||||||
|
default:
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String *Variant::get_string_ptr() const {
|
||||||
|
if (_type == TYPE_STRING) {
|
||||||
|
return _string->string;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool Variant::is_string_owned() const {
|
||||||
|
if (_type == TYPE_STRING) {
|
||||||
|
return _string->owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variant::set_null() {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
}
|
||||||
|
void Variant::set_bool(const bool value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_BOOL;
|
||||||
|
_bool = value;
|
||||||
|
}
|
||||||
|
void Variant::set_int(const int value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_INT;
|
||||||
|
_int = value;
|
||||||
|
}
|
||||||
|
void Variant::set_uint(const uint64_t value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_UINT;
|
||||||
|
_uint = value;
|
||||||
|
}
|
||||||
|
void Variant::set_float(const float value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_FLOAT;
|
||||||
|
_float = value;
|
||||||
|
}
|
||||||
|
void Variant::set_float(const double value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_FLOAT;
|
||||||
|
_float = value;
|
||||||
|
}
|
||||||
|
void Variant::set_string(String *value, const bool copy) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_type = TYPE_STRING;
|
||||||
|
|
||||||
|
_string = new StringData();
|
||||||
|
|
||||||
|
if (copy) {
|
||||||
|
_string->string = new String(*value);
|
||||||
|
_string->owner = true;
|
||||||
|
} else {
|
||||||
|
_string->string = value;
|
||||||
|
_string->owner = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Variant::set_string(const String &value, const bool copy) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_STRING;
|
||||||
|
|
||||||
|
_string = new StringData();
|
||||||
|
|
||||||
|
if (copy) {
|
||||||
|
_string->string = new String(value);
|
||||||
|
_string->owner = true;
|
||||||
|
} else {
|
||||||
|
_string->string = &const_cast<String &>(value);
|
||||||
|
_string->owner = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Variant::set_object(Object *value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_object = new ObjectData();
|
||||||
|
_object->object = value;
|
||||||
|
|
||||||
|
if (value->is_class_ptr(Reference::get_class_ptr_static())) {
|
||||||
|
_object->reference = Ref<Reference>(Object::cast_to<Reference>(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Variant::set_pointer(void *value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
_type = TYPE_POINTER;
|
||||||
|
_pointer = value;
|
||||||
|
}
|
||||||
|
void Variant::set_variant(const Variant &value) {
|
||||||
|
clear();
|
||||||
|
|
||||||
|
switch (value._type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
break;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
_bool = value._bool;
|
||||||
|
break;
|
||||||
|
case TYPE_INT:
|
||||||
|
_int = value._int;
|
||||||
|
break;
|
||||||
|
case TYPE_UINT:
|
||||||
|
_uint = value._uint;
|
||||||
|
break;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
_float = value._float;
|
||||||
|
break;
|
||||||
|
case TYPE_STRING:
|
||||||
|
set_string(value._string->string, true);
|
||||||
|
break;
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
set_object(value._object->object);
|
||||||
|
break;
|
||||||
|
case TYPE_POINTER:
|
||||||
|
_pointer = value._pointer;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_type = value._type;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant::operator bool() const {
|
||||||
|
return to_bool();
|
||||||
|
}
|
||||||
|
Variant::operator int() const {
|
||||||
|
return to_int();
|
||||||
|
}
|
||||||
|
Variant::operator uint64_t() const {
|
||||||
|
return to_uint();
|
||||||
|
}
|
||||||
|
Variant::operator float() const {
|
||||||
|
return to_float();
|
||||||
|
}
|
||||||
|
Variant::operator double() const {
|
||||||
|
return to_float();
|
||||||
|
}
|
||||||
|
Variant::operator String() const {
|
||||||
|
return to_string();
|
||||||
|
}
|
||||||
|
Variant::operator Object *() const {
|
||||||
|
return to_object();
|
||||||
|
}
|
||||||
|
Variant::operator Reference *() const {
|
||||||
|
return to_reference();
|
||||||
|
}
|
||||||
|
Variant::operator void *() const {
|
||||||
|
return to_pointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Variant::operator=(const Variant &other) {
|
||||||
|
set_variant(other);
|
||||||
|
}
|
||||||
|
bool Variant::operator==(const Variant &other) const {
|
||||||
|
if (_type != other._type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL:
|
||||||
|
return true;
|
||||||
|
case TYPE_BOOL:
|
||||||
|
return _bool == other._bool;
|
||||||
|
case TYPE_INT:
|
||||||
|
return _int == other._int;
|
||||||
|
case TYPE_UINT:
|
||||||
|
return _uint == other._uint;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return _float == other._float;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return (*_string->string) == (*other._string->string);
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
return (_object->object) == (other._object->object);
|
||||||
|
case TYPE_POINTER:
|
||||||
|
return _pointer == other._pointer;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool Variant::operator!=(const Variant &other) const {
|
||||||
|
return !(operator==(other));
|
||||||
|
}
|
||||||
|
bool Variant::operator<(const Variant &other) const {
|
||||||
|
switch (_type) {
|
||||||
|
case TYPE_NULL: {
|
||||||
|
if (other.is_null()) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case TYPE_BOOL: {
|
||||||
|
return _bool < other.to_bool();
|
||||||
|
}
|
||||||
|
case TYPE_INT:
|
||||||
|
return _int < other.to_int();
|
||||||
|
return _int == other._int;
|
||||||
|
case TYPE_UINT:
|
||||||
|
return _uint < other.to_uint();
|
||||||
|
return _uint == other._uint;
|
||||||
|
case TYPE_FLOAT:
|
||||||
|
return _float < other.to_float();
|
||||||
|
return _float == other._float;
|
||||||
|
case TYPE_STRING:
|
||||||
|
return (*_string->string) < other.to_string();
|
||||||
|
case TYPE_OBJECT:
|
||||||
|
return (_object->object) < other.to_object();
|
||||||
|
case TYPE_POINTER:
|
||||||
|
return _pointer < other.to_pointer();
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant::Variant(const bool value) {
|
||||||
|
_type = TYPE_BOOL;
|
||||||
|
|
||||||
|
_bool = value;
|
||||||
|
}
|
||||||
|
Variant::Variant(const int value) {
|
||||||
|
_type = TYPE_INT;
|
||||||
|
|
||||||
|
_int = value;
|
||||||
|
}
|
||||||
|
Variant::Variant(const uint64_t value) {
|
||||||
|
_type = TYPE_UINT;
|
||||||
|
|
||||||
|
_uint = value;
|
||||||
|
}
|
||||||
|
Variant::Variant(const float value) {
|
||||||
|
_type = TYPE_FLOAT;
|
||||||
|
|
||||||
|
_float = value;
|
||||||
|
}
|
||||||
|
Variant::Variant(const double value) {
|
||||||
|
_type = TYPE_FLOAT;
|
||||||
|
|
||||||
|
_float = value;
|
||||||
|
}
|
||||||
|
Variant::Variant(String *value, bool copy) {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
|
||||||
|
set_string(value, copy);
|
||||||
|
}
|
||||||
|
Variant::Variant(const String &value, bool copy) {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
|
||||||
|
set_string(value, copy);
|
||||||
|
}
|
||||||
|
Variant::Variant(Object *value) {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
|
||||||
|
set_object(value);
|
||||||
|
}
|
||||||
|
Variant::Variant(void *value) {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
|
||||||
|
set_pointer(value);
|
||||||
|
}
|
||||||
|
Variant::Variant(const Variant &value) {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
|
||||||
|
set_variant(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant::Variant() {
|
||||||
|
_type = TYPE_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant::~Variant() {
|
||||||
|
clear();
|
||||||
|
}
|
120
core/variant.h
Normal file
120
core/variant.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#ifndef VARIANT_H
|
||||||
|
#define VARIANT_H
|
||||||
|
|
||||||
|
#include "core/object.h"
|
||||||
|
#include "core/reference.h"
|
||||||
|
#include "core/string.h"
|
||||||
|
|
||||||
|
class Variant {
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum Type {
|
||||||
|
TYPE_NULL = 0,
|
||||||
|
TYPE_BOOL,
|
||||||
|
TYPE_INT,
|
||||||
|
TYPE_UINT,
|
||||||
|
TYPE_FLOAT,
|
||||||
|
TYPE_STRING,
|
||||||
|
TYPE_OBJECT,
|
||||||
|
TYPE_POINTER,
|
||||||
|
};
|
||||||
|
|
||||||
|
Type get_type() const;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
void zero();
|
||||||
|
|
||||||
|
void parse(const String &str);
|
||||||
|
static Variant parse_string(const String &str);
|
||||||
|
|
||||||
|
bool is_null() const;
|
||||||
|
bool is_bool() const;
|
||||||
|
bool is_int() const;
|
||||||
|
bool is_uint() const;
|
||||||
|
bool is_float() const;
|
||||||
|
bool is_numeric() const;
|
||||||
|
bool is_string() const;
|
||||||
|
bool is_object() const;
|
||||||
|
bool is_pointer() const;
|
||||||
|
bool is_reference() const;
|
||||||
|
|
||||||
|
bool is_primitive_type() const;
|
||||||
|
bool is_simple_type() const;
|
||||||
|
|
||||||
|
bool to_bool() const;
|
||||||
|
int to_int() const;
|
||||||
|
uint64_t to_uint() const;
|
||||||
|
float to_float() const;
|
||||||
|
String to_string() const;
|
||||||
|
Object *to_object() const;
|
||||||
|
Reference *to_reference() const;
|
||||||
|
void *to_pointer() const;
|
||||||
|
String *get_string_ptr() const;
|
||||||
|
bool is_string_owned() const;
|
||||||
|
|
||||||
|
void set_null();
|
||||||
|
void set_bool(const bool value);
|
||||||
|
void set_int(const int value);
|
||||||
|
void set_uint(const uint64_t value);
|
||||||
|
void set_float(const float value);
|
||||||
|
void set_float(const double value);
|
||||||
|
void set_string(String *value, bool copy = false);
|
||||||
|
void set_string(const String &value, bool copy = true);
|
||||||
|
void set_object(Object *value);
|
||||||
|
void set_pointer(void *value);
|
||||||
|
void set_variant(const Variant &value);
|
||||||
|
|
||||||
|
operator bool() const;
|
||||||
|
operator int() const;
|
||||||
|
operator uint64_t() const;
|
||||||
|
operator float() const;
|
||||||
|
operator double() const;
|
||||||
|
operator String() const;
|
||||||
|
operator Object *() const;
|
||||||
|
operator Reference *() const;
|
||||||
|
operator void *() const;
|
||||||
|
|
||||||
|
void operator=(const Variant &other);
|
||||||
|
bool operator==(const Variant &other) const;
|
||||||
|
bool operator!=(const Variant &other) const;
|
||||||
|
bool operator<(const Variant &other) const;
|
||||||
|
|
||||||
|
Variant(const bool value);
|
||||||
|
Variant(const int value);
|
||||||
|
Variant(const uint64_t value);
|
||||||
|
Variant(const float value);
|
||||||
|
Variant(const double value);
|
||||||
|
Variant(String *value, const bool copy = false);
|
||||||
|
Variant(const String &value, const bool copy = true);
|
||||||
|
Variant(Object *value);
|
||||||
|
Variant(void *value);
|
||||||
|
Variant(const Variant &value);
|
||||||
|
|
||||||
|
Variant();
|
||||||
|
~Variant();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct StringData {
|
||||||
|
bool owner;
|
||||||
|
String *string;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ObjectData {
|
||||||
|
Object *object;
|
||||||
|
Ref<Reference> reference;
|
||||||
|
};
|
||||||
|
|
||||||
|
union {
|
||||||
|
bool _bool;
|
||||||
|
int _int;
|
||||||
|
uint64_t _uint;
|
||||||
|
float _float;
|
||||||
|
StringData *_string;
|
||||||
|
ObjectData *_object;
|
||||||
|
void *_pointer;
|
||||||
|
};
|
||||||
|
|
||||||
|
Type _type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user