void join(const char* path_a, const char* path_b, DynamicString& path) { CE_ENSURE(NULL != path_a); CE_ENSURE(NULL != path_b); const u32 la = strlen32(path_a); const u32 lb = strlen32(path_b); path.reserve(la + lb + 1); path += path_a; path += PATH_SEPARATOR; path += path_b; }
void ResourceManager::register_type(StringId64 type, LoadFunction load, UnloadFunction unload, OnlineFunction online, OfflineFunction offline) { CE_ENSURE(NULL != load); CE_ENSURE(NULL != unload); ResourceTypeData data; data.load = load; data.online = online; data.offline = offline; data.unload = unload; sort_map::set(_type_data, type, data); sort_map::sort(_type_data); }
void parse_array(const char* json, JsonArray& array) { CE_ENSURE(NULL != json); if (*json == '[') { json = skip_spaces(++json); if (*json == ']') return; while (*json) { array::push_back(array, json); json = skip_value(json); json = skip_spaces(json); if (*json == ']') return; json = skip_spaces(json); } } CE_FATAL("Bad array"); }
static const char* skip_comments(const char* json) { CE_ENSURE(NULL != json); if (*json == '/') { ++json; if (*json == '/') { json = next(json, '/'); while (*json && *json != '\n') ++json; } else if (*json == '*') { ++json; while (*json && *json != '*') ++json; json = next(json, '*'); json = next(json, '/'); } else CE_FATAL("Bad comment"); } return json; }
bool parse_bool(const char* json) { CE_ENSURE(NULL != json); switch (*json) { case 't': json = next(json, 't'); json = next(json, 'r'); json = next(json, 'u'); json = next(json, 'e'); return true; case 'f': json = next(json, 'f'); json = next(json, 'a'); json = next(json, 'l'); json = next(json, 's'); json = next(json, 'e'); return false; default: CE_FATAL("Bad boolean"); return false; } }
bool is_root(const char* path) { CE_ENSURE(NULL != path); #if CROWN_PLATFORM_POSIX return is_absolute(path) && strlen32(path) == 1; #elif CROWN_PLATFORM_WINDOWS return is_absolute(path) && strlen32(path) == 3; #endif }
void parse(const char* json, JsonObject& object) { CE_ENSURE(NULL != json); json = skip_spaces(json); if (*json == '{') parse_object(json, object); else parse_root_object(json, object); }
static const char* next(const char* json, const char c = 0) { CE_ENSURE(NULL != json); if (c && c != *json) { CE_ASSERT(false, "Expected '%c' got '%c'", c, *json); } return ++json; }
static f64 parse_number(const char* json) { CE_ENSURE(NULL != json); TempAllocator512 alloc; Array<char> number(alloc); if (*json == '-') { array::push_back(number, '-'); ++json; } while (isdigit(*json)) { array::push_back(number, *json); ++json; } if (*json == '.') { array::push_back(number, '.'); while (*++json && isdigit(*json)) { array::push_back(number, *json); } } if (*json == 'e' || *json == 'E') { array::push_back(number, *json); ++json; if (*json == '-' || *json == '+') { array::push_back(number, *json); ++json; } while (isdigit(*json)) { array::push_back(number, *json); ++json; } } array::push_back(number, '\0'); f64 val; int ok = sscanf(array::begin(number), "%lf", &val); CE_ASSERT(ok == 1, "Failed to parse f64: %s", array::begin(number)); CE_UNUSED(ok); return val; }
JsonValueType::Enum type(const char* json) { CE_ENSURE(NULL != json); switch (*json) { case '"': return JsonValueType::STRING; case '{': return JsonValueType::OBJECT; case '[': return JsonValueType::ARRAY; case '-': return JsonValueType::NUMBER; default: return (isdigit(*json)) ? JsonValueType::NUMBER : (*json == 'n' ? JsonValueType::NIL : JsonValueType::BOOL); } }
static const char* skip_spaces(const char* json) { CE_ENSURE(NULL != json); while (*json) { if (*json == '/') json = skip_comments(json); else if (isspace(*json) || *json == ',') ++json; else break; } return json; }
static const char* skip_value(const char* json) { CE_ENSURE(NULL != json); switch (*json) { case '"': json = skip_string(json); break; case '[': json = skip_block(json, '[', ']'); break; case '{': json = skip_block(json, '{', '}'); break; default: for (; *json != '\0' && *json != ',' && *json != '\n' && *json != ' ' && *json != '}' && *json != ']'; ++json) ; break; } return json; }
bool is_absolute(const char* path) { CE_ENSURE(NULL != path); #if CROWN_PLATFORM_POSIX return strlen32(path) > 0 && path[0] == PATH_SEPARATOR ; #elif CROWN_PLATFORM_WINDOWS return strlen32(path) > 2 && isalpha(path[0]) && path[1] == ':' && path[2] == PATH_SEPARATOR ; #endif }
static const char* skip_string(const char* json) { CE_ENSURE(NULL != json); while (*++json) { if (*json == '"') { ++json; return json; } else if (*json == '\\') { ++json; } } return json; }
static const char* parse_key(const char* json, DynamicString& key) { CE_ENSURE(NULL != json); if (*json == '"') { parse_string(json, key); return skip_string(json); } while (true) { if (isspace(*json) || *json == '=' || *json == ':') return json; key += *json++; } CE_FATAL("Bad key"); return NULL; }
void parse_string(const char* json, DynamicString& string) { CE_ENSURE(NULL != json); if (*json == '"') { while (*++json) { // Empty string if (*json == '"') { ++json; return; } else if (*json == '\\') { ++json; switch (*json) { case '"': string += '"'; break; case '\\': string += '\\'; break; case '/': string += '/'; break; case 'b': string += '\b'; break; case 'f': string += '\f'; break; case 'n': string += '\n'; break; case 'r': string += '\r'; break; case 't': string += '\t'; break; default: CE_FATAL("Bad escape character"); break; } } else { string += *json; } } } CE_FATAL("Bad string"); }
void parse_object(const char* json, JsonObject& object) { CE_ENSURE(NULL != json); if (*json == '{') { json = skip_spaces(++json); if (*json == '}') return; while (*json) { const char* key_begin = *json == '"' ? (json + 1) : json; TempAllocator256 ta; DynamicString key(ta); json = parse_key(json, key); FixedString fs_key(key_begin, key.length()); json = skip_spaces(json); json = next(json, (*json == '=') ? '=' : ':'); json = skip_spaces(json); map::set(object._map, fs_key, json); json = skip_value(json); json = skip_spaces(json); if (*json == '}') return; json = skip_spaces(json); } } CE_FATAL("Bad object"); }
const char* basename(const char* path) { CE_ENSURE(NULL != path); const char* ls = strrchr(path, '/'); return ls == NULL ? path : ls + 1; }
const char* extension(const char* path) { CE_ENSURE(NULL != path); const char* ld = strrchr(path, '.'); return ld == NULL ? NULL : ld + 1; }
bool is_relative(const char* path) { CE_ENSURE(NULL != path); return !is_absolute(path); }