2021-09-17 11:53:00 +02:00
|
|
|
/*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
|
* \ingroup bli
|
|
|
|
|
*/
|
|
|
|
|
|
2021-09-23 17:55:43 +02:00
|
|
|
#include "BLI_assert.h"
|
2021-09-17 11:53:00 +02:00
|
|
|
#include "BLI_uuid.h"
|
|
|
|
|
|
2021-09-17 14:51:34 +02:00
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
2021-09-18 13:36:20 +02:00
|
|
|
#include <ctime>
|
2021-09-17 11:53:00 +02:00
|
|
|
#include <random>
|
Assets: add Asset Catalog system
Catalogs work like directories on disk (without hard-/symlinks), in that
an asset is only contained in one catalog.
See T90066 for design considerations.
#### Known Limitations
Only a single catalog definition file (CDF), is supported, at
`${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`. In the future this is
to be expanded to support arbitrary CDFs (like one per blend file, one
per subdirectory, etc.).
The current implementation is based on the asset browser, which in
practice means that the asset browser owns the `AssetCatalogService`
instance for the selected asset library. In the future these instances
will be accessible via a less UI-bound asset system.
The UI is still very rudimentary, only showing the catalog ID for the
currently selected asset. Most notably, the loaded catalogs are not
shown yet. The UI is being implemented and will be merged soon.
#### Catalog Identifiers
Catalogs are internally identified by UUID. In older designs this was a
human-readable name, which has the problem that it has to be kept in
sync with its semantics (so when renaming a catalog from X to Y, the
UUID can be kept the same).
Since UUIDs don't communicate any human-readable information, the
mapping from catalog UUID to its path (stored in the Catalog Definition
File, CDF) is critical for understanding which asset is stored in which
human-readable catalog. To make this less critical, and to allow manual
data reconstruction after a CDF is lost/corrupted, each catalog also has
a "simple name" that's stored along with the UUID. This is also stored
on each asset, next to the catalog UUID.
#### Writing to Disk
Before saving asset catalogs to disk, the to-be-overwritten file gets
inspected. Any new catalogs that are found thre are loaded to memory
before writing the catalogs back to disk:
- Changed catalog path: in-memory data wins
- Catalogs deleted on disk: they are recreated based on in-memory data
- Catalogs deleted in memory: deleted on disk as well
- New catalogs on disk: are loaded and thus survive the overwriting
#### Tree Design
This implements the initial tree structure to load catalogs into. See
T90608, and the basic design in T90066.
Reviewed By: Severin
Maniphest Tasks: T91552
Differential Revision: https://developer.blender.org/D12589
2021-09-23 14:56:45 +02:00
|
|
|
#include <sstream>
|
2021-09-18 13:36:20 +02:00
|
|
|
#include <string>
|
2021-09-24 12:55:26 +02:00
|
|
|
#include <tuple>
|
2021-09-17 11:53:00 +02:00
|
|
|
|
|
|
|
|
/* Ensure the UUID struct doesn't have any padding, to be compatible with memcmp(). */
|
2021-09-21 21:54:53 +02:00
|
|
|
static_assert(sizeof(bUUID) == 16, "expect UUIDs to be 128 bit exactly");
|
2021-09-17 11:53:00 +02:00
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bUUID BLI_uuid_generate_random()
|
2021-09-17 11:53:00 +02:00
|
|
|
{
|
|
|
|
|
static std::mt19937_64 rng = []() {
|
|
|
|
|
std::mt19937_64 rng;
|
|
|
|
|
|
|
|
|
|
/* Ensure the RNG really can output 64-bit values. */
|
2021-09-17 14:51:34 +02:00
|
|
|
static_assert(std::mt19937_64::min() == 0LL);
|
|
|
|
|
static_assert(std::mt19937_64::max() == 0xffffffffffffffffLL);
|
2021-09-17 11:53:00 +02:00
|
|
|
|
|
|
|
|
struct timespec ts;
|
2021-09-20 12:10:19 +02:00
|
|
|
#ifdef __APPLE__
|
|
|
|
|
/* `timespec_get()` is only available on macOS 10.15+, so until that's the minimum version
|
|
|
|
|
* supported by Blender, use another function to get the timespec.
|
|
|
|
|
*
|
|
|
|
|
* `clock_gettime()` is only available on POSIX, so not on Windows; Linux uses the newer C++11
|
|
|
|
|
* function `timespec_get()` as well. */
|
|
|
|
|
clock_gettime(CLOCK_REALTIME, &ts);
|
|
|
|
|
#else
|
2021-09-17 11:53:00 +02:00
|
|
|
timespec_get(&ts, TIME_UTC);
|
2021-09-20 12:10:19 +02:00
|
|
|
#endif
|
2021-09-20 12:01:59 +02:00
|
|
|
/* XOR the nanosecond and second fields, just in case the clock only has seconds resolution. */
|
|
|
|
|
uint64_t seed = ts.tv_nsec;
|
|
|
|
|
seed ^= ts.tv_sec;
|
|
|
|
|
rng.seed(seed);
|
2021-09-17 11:53:00 +02:00
|
|
|
|
|
|
|
|
return rng;
|
|
|
|
|
}();
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bUUID uuid;
|
2021-09-17 11:53:00 +02:00
|
|
|
|
|
|
|
|
/* RFC4122 suggests setting certain bits to a fixed value, and then randomizing the remaining
|
|
|
|
|
* bits. The opposite is easier to implement, though, so that's what's done here. */
|
|
|
|
|
|
|
|
|
|
/* Read two 64-bit numbers to randomize all 128 bits of the UUID. */
|
|
|
|
|
uint64_t *uuid_as_int64 = reinterpret_cast<uint64_t *>(&uuid);
|
|
|
|
|
uuid_as_int64[0] = rng();
|
|
|
|
|
uuid_as_int64[1] = rng();
|
|
|
|
|
|
|
|
|
|
/* Set the most significant four bits to 0b0100 to indicate version 4 (random UUID). */
|
|
|
|
|
uuid.time_hi_and_version &= ~0xF000;
|
|
|
|
|
uuid.time_hi_and_version |= 0x4000;
|
|
|
|
|
|
|
|
|
|
/* Set the most significant two bits to 0b10 to indicate compatibility with RFC4122. */
|
|
|
|
|
uuid.clock_seq_hi_and_reserved &= ~0x40;
|
|
|
|
|
uuid.clock_seq_hi_and_reserved |= 0x80;
|
|
|
|
|
|
|
|
|
|
return uuid;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bUUID BLI_uuid_nil(void)
|
2021-09-20 12:15:37 +02:00
|
|
|
{
|
2021-09-21 21:54:53 +02:00
|
|
|
const bUUID nil = {0, 0, 0, 0, 0, 0};
|
2021-09-20 12:15:37 +02:00
|
|
|
return nil;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bool BLI_uuid_is_nil(bUUID uuid)
|
2021-09-20 12:15:37 +02:00
|
|
|
{
|
|
|
|
|
return BLI_uuid_equal(BLI_uuid_nil(), uuid);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bool BLI_uuid_equal(const bUUID uuid1, const bUUID uuid2)
|
2021-09-17 11:53:00 +02:00
|
|
|
{
|
2021-09-17 14:51:34 +02:00
|
|
|
return std::memcmp(&uuid1, &uuid2, sizeof(uuid1)) == 0;
|
2021-09-17 11:53:00 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
void BLI_uuid_format(char *buffer, const bUUID uuid)
|
2021-09-17 11:53:00 +02:00
|
|
|
{
|
2021-09-17 14:51:34 +02:00
|
|
|
std::sprintf(buffer,
|
|
|
|
|
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
|
|
|
uuid.time_low,
|
|
|
|
|
uuid.time_mid,
|
|
|
|
|
uuid.time_hi_and_version,
|
|
|
|
|
uuid.clock_seq_hi_and_reserved,
|
|
|
|
|
uuid.clock_seq_low,
|
|
|
|
|
uuid.node[0],
|
|
|
|
|
uuid.node[1],
|
|
|
|
|
uuid.node[2],
|
|
|
|
|
uuid.node[3],
|
|
|
|
|
uuid.node[4],
|
|
|
|
|
uuid.node[5]);
|
2021-09-17 11:53:00 +02:00
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
bool BLI_uuid_parse_string(bUUID *uuid, const char *buffer)
|
2021-09-17 11:53:00 +02:00
|
|
|
{
|
2021-09-17 14:51:34 +02:00
|
|
|
const int num_fields_parsed = std::sscanf(
|
|
|
|
|
buffer,
|
|
|
|
|
"%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
|
|
|
|
|
&uuid->time_low,
|
|
|
|
|
&uuid->time_mid,
|
|
|
|
|
&uuid->time_hi_and_version,
|
|
|
|
|
&uuid->clock_seq_hi_and_reserved,
|
|
|
|
|
&uuid->clock_seq_low,
|
|
|
|
|
&uuid->node[0],
|
|
|
|
|
&uuid->node[1],
|
|
|
|
|
&uuid->node[2],
|
|
|
|
|
&uuid->node[3],
|
|
|
|
|
&uuid->node[4],
|
|
|
|
|
&uuid->node[5]);
|
2021-09-17 11:53:00 +02:00
|
|
|
return num_fields_parsed == 11;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-21 21:54:53 +02:00
|
|
|
std::ostream &operator<<(std::ostream &stream, bUUID uuid)
|
2021-09-17 11:53:00 +02:00
|
|
|
{
|
|
|
|
|
std::string buffer(36, '\0');
|
|
|
|
|
BLI_uuid_format(buffer.data(), uuid);
|
|
|
|
|
stream << buffer;
|
|
|
|
|
return stream;
|
|
|
|
|
}
|
Assets: add Asset Catalog system
Catalogs work like directories on disk (without hard-/symlinks), in that
an asset is only contained in one catalog.
See T90066 for design considerations.
#### Known Limitations
Only a single catalog definition file (CDF), is supported, at
`${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`. In the future this is
to be expanded to support arbitrary CDFs (like one per blend file, one
per subdirectory, etc.).
The current implementation is based on the asset browser, which in
practice means that the asset browser owns the `AssetCatalogService`
instance for the selected asset library. In the future these instances
will be accessible via a less UI-bound asset system.
The UI is still very rudimentary, only showing the catalog ID for the
currently selected asset. Most notably, the loaded catalogs are not
shown yet. The UI is being implemented and will be merged soon.
#### Catalog Identifiers
Catalogs are internally identified by UUID. In older designs this was a
human-readable name, which has the problem that it has to be kept in
sync with its semantics (so when renaming a catalog from X to Y, the
UUID can be kept the same).
Since UUIDs don't communicate any human-readable information, the
mapping from catalog UUID to its path (stored in the Catalog Definition
File, CDF) is critical for understanding which asset is stored in which
human-readable catalog. To make this less critical, and to allow manual
data reconstruction after a CDF is lost/corrupted, each catalog also has
a "simple name" that's stored along with the UUID. This is also stored
on each asset, next to the catalog UUID.
#### Writing to Disk
Before saving asset catalogs to disk, the to-be-overwritten file gets
inspected. Any new catalogs that are found thre are loaded to memory
before writing the catalogs back to disk:
- Changed catalog path: in-memory data wins
- Catalogs deleted on disk: they are recreated based on in-memory data
- Catalogs deleted in memory: deleted on disk as well
- New catalogs on disk: are loaded and thus survive the overwriting
#### Tree Design
This implements the initial tree structure to load catalogs into. See
T90608, and the basic design in T90066.
Reviewed By: Severin
Maniphest Tasks: T91552
Differential Revision: https://developer.blender.org/D12589
2021-09-23 14:56:45 +02:00
|
|
|
|
2021-09-23 17:55:43 +02:00
|
|
|
namespace blender {
|
|
|
|
|
|
2021-09-23 18:22:47 +02:00
|
|
|
bUUID::bUUID(const std::initializer_list<uint32_t> field_values)
|
2021-09-23 17:55:43 +02:00
|
|
|
{
|
|
|
|
|
BLI_assert_msg(field_values.size() == 11, "bUUID requires 5 regular fields + 6 `node` values");
|
|
|
|
|
|
2021-09-23 18:22:47 +02:00
|
|
|
const auto *field_iter = field_values.begin();
|
2021-09-23 17:55:43 +02:00
|
|
|
|
2021-09-23 18:22:47 +02:00
|
|
|
this->time_low = *field_iter++;
|
2021-09-23 17:55:43 +02:00
|
|
|
this->time_mid = static_cast<uint16_t>(*field_iter++);
|
|
|
|
|
this->time_hi_and_version = static_cast<uint16_t>(*field_iter++);
|
|
|
|
|
this->clock_seq_hi_and_reserved = static_cast<uint8_t>(*field_iter++);
|
|
|
|
|
this->clock_seq_low = static_cast<uint8_t>(*field_iter++);
|
|
|
|
|
|
|
|
|
|
std::copy(field_iter, field_values.end(), this->node);
|
|
|
|
|
}
|
Assets: add Asset Catalog system
Catalogs work like directories on disk (without hard-/symlinks), in that
an asset is only contained in one catalog.
See T90066 for design considerations.
#### Known Limitations
Only a single catalog definition file (CDF), is supported, at
`${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`. In the future this is
to be expanded to support arbitrary CDFs (like one per blend file, one
per subdirectory, etc.).
The current implementation is based on the asset browser, which in
practice means that the asset browser owns the `AssetCatalogService`
instance for the selected asset library. In the future these instances
will be accessible via a less UI-bound asset system.
The UI is still very rudimentary, only showing the catalog ID for the
currently selected asset. Most notably, the loaded catalogs are not
shown yet. The UI is being implemented and will be merged soon.
#### Catalog Identifiers
Catalogs are internally identified by UUID. In older designs this was a
human-readable name, which has the problem that it has to be kept in
sync with its semantics (so when renaming a catalog from X to Y, the
UUID can be kept the same).
Since UUIDs don't communicate any human-readable information, the
mapping from catalog UUID to its path (stored in the Catalog Definition
File, CDF) is critical for understanding which asset is stored in which
human-readable catalog. To make this less critical, and to allow manual
data reconstruction after a CDF is lost/corrupted, each catalog also has
a "simple name" that's stored along with the UUID. This is also stored
on each asset, next to the catalog UUID.
#### Writing to Disk
Before saving asset catalogs to disk, the to-be-overwritten file gets
inspected. Any new catalogs that are found thre are loaded to memory
before writing the catalogs back to disk:
- Changed catalog path: in-memory data wins
- Catalogs deleted on disk: they are recreated based on in-memory data
- Catalogs deleted in memory: deleted on disk as well
- New catalogs on disk: are loaded and thus survive the overwriting
#### Tree Design
This implements the initial tree structure to load catalogs into. See
T90608, and the basic design in T90066.
Reviewed By: Severin
Maniphest Tasks: T91552
Differential Revision: https://developer.blender.org/D12589
2021-09-23 14:56:45 +02:00
|
|
|
|
|
|
|
|
bUUID::bUUID(const std::string &string_formatted_uuid)
|
|
|
|
|
{
|
|
|
|
|
const bool parsed_ok = BLI_uuid_parse_string(this, string_formatted_uuid.c_str());
|
|
|
|
|
if (!parsed_ok) {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "invalid UUID string " << string_formatted_uuid;
|
|
|
|
|
throw std::runtime_error(ss.str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bUUID::bUUID(const ::bUUID &struct_uuid)
|
|
|
|
|
{
|
|
|
|
|
*(static_cast<::bUUID *>(this)) = struct_uuid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t bUUID::hash() const
|
|
|
|
|
{
|
|
|
|
|
/* Convert the struct into two 64-bit numbers, and XOR them to get the hash. */
|
|
|
|
|
const uint64_t *uuid_as_int64 = reinterpret_cast<const uint64_t *>(this);
|
|
|
|
|
return uuid_as_int64[0] ^ uuid_as_int64[1];
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:55:43 +02:00
|
|
|
bool operator==(const bUUID uuid1, const bUUID uuid2)
|
Assets: add Asset Catalog system
Catalogs work like directories on disk (without hard-/symlinks), in that
an asset is only contained in one catalog.
See T90066 for design considerations.
#### Known Limitations
Only a single catalog definition file (CDF), is supported, at
`${ASSET_LIBRARY_ROOT}/blender_assets.cats.txt`. In the future this is
to be expanded to support arbitrary CDFs (like one per blend file, one
per subdirectory, etc.).
The current implementation is based on the asset browser, which in
practice means that the asset browser owns the `AssetCatalogService`
instance for the selected asset library. In the future these instances
will be accessible via a less UI-bound asset system.
The UI is still very rudimentary, only showing the catalog ID for the
currently selected asset. Most notably, the loaded catalogs are not
shown yet. The UI is being implemented and will be merged soon.
#### Catalog Identifiers
Catalogs are internally identified by UUID. In older designs this was a
human-readable name, which has the problem that it has to be kept in
sync with its semantics (so when renaming a catalog from X to Y, the
UUID can be kept the same).
Since UUIDs don't communicate any human-readable information, the
mapping from catalog UUID to its path (stored in the Catalog Definition
File, CDF) is critical for understanding which asset is stored in which
human-readable catalog. To make this less critical, and to allow manual
data reconstruction after a CDF is lost/corrupted, each catalog also has
a "simple name" that's stored along with the UUID. This is also stored
on each asset, next to the catalog UUID.
#### Writing to Disk
Before saving asset catalogs to disk, the to-be-overwritten file gets
inspected. Any new catalogs that are found thre are loaded to memory
before writing the catalogs back to disk:
- Changed catalog path: in-memory data wins
- Catalogs deleted on disk: they are recreated based on in-memory data
- Catalogs deleted in memory: deleted on disk as well
- New catalogs on disk: are loaded and thus survive the overwriting
#### Tree Design
This implements the initial tree structure to load catalogs into. See
T90608, and the basic design in T90066.
Reviewed By: Severin
Maniphest Tasks: T91552
Differential Revision: https://developer.blender.org/D12589
2021-09-23 14:56:45 +02:00
|
|
|
{
|
|
|
|
|
return BLI_uuid_equal(uuid1, uuid2);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:22:17 +02:00
|
|
|
bool operator!=(const bUUID uuid1, const bUUID uuid2)
|
|
|
|
|
{
|
|
|
|
|
return !(uuid1 == uuid2);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 12:55:26 +02:00
|
|
|
bool operator<(const bUUID uuid1, const bUUID uuid2)
|
|
|
|
|
{
|
|
|
|
|
auto simple_fields1 = std::tie(uuid1.time_low,
|
|
|
|
|
uuid1.time_mid,
|
|
|
|
|
uuid1.time_hi_and_version,
|
|
|
|
|
uuid1.clock_seq_hi_and_reserved,
|
|
|
|
|
uuid1.clock_seq_low);
|
|
|
|
|
auto simple_fields2 = std::tie(uuid2.time_low,
|
|
|
|
|
uuid2.time_mid,
|
|
|
|
|
uuid2.time_hi_and_version,
|
|
|
|
|
uuid2.clock_seq_hi_and_reserved,
|
|
|
|
|
uuid2.clock_seq_low);
|
|
|
|
|
if (simple_fields1 == simple_fields2) {
|
|
|
|
|
return std::memcmp(uuid1.node, uuid2.node, sizeof(uuid1.node)) < 0;
|
|
|
|
|
}
|
|
|
|
|
return simple_fields1 < simple_fields2;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-23 17:55:43 +02:00
|
|
|
} // namespace blender
|