#include "util.hpp" #ifdef __ANDROID__ #include #endif #include #include #include #include "log.hpp" #include #include std::string PadZeros(std::string input, size_t required_length) { return std::string(required_length - std::min(required_length, input.length()), '0') + input; } uint8_t TimeToComponentCount(double time_code) { int seconds = (int)time_code; int minutes = seconds / 60; seconds -= minutes * 60; int hours = minutes / 60; minutes -= hours * 60; if (hours > 0) { return 3; } else if (minutes > 0) { return 2; } else { return 1; } } std::string TimeToString(double time_code, uint8_t min_components) { uint8_t components = std::max(TimeToComponentCount(time_code), min_components); int seconds = (int)time_code; int minutes = seconds / 60; seconds -= minutes * 60; int hours = minutes / 60; minutes -= hours * 60; std::string output = PadZeros(std::to_string(seconds), components < 2 ? 1 : 2); if (components >= 2) { output = PadZeros(std::to_string(minutes), components == 2 ? 1 : 2) + ":" + output; } if (components >= 3) { output = PadZeros(std::to_string(hours), components == 3 ? 1 : 2) + ":" + output; } return output; } #ifdef _WIN32 #include #include #else #include #endif std::string get_prefs_path() { std::string path; #ifdef __ANDROID__ path = SDL_AndroidGetInternalStoragePath(); #elif defined(_WIN32) PWSTR str; if (SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &str) != S_OK) { CoTaskMemFree(str); path = "."; } else { path = std::string(str); CoTaskMemFree(str); } path = path + "\\"; #else const char *str = getenv("XDG_CONFIG_HOME"); if (str == NULL) { str = getenv("HOME"); if (str == NULL) { path = "."; } else { path = std::string(str) + "/.config"; } } else { path = std::string(str); } path = path + "/"; #endif return path; } int launch(std::vector args) { char **argv; bool err = false; argv = (char**)calloc(args.size() + 1, sizeof(char*)); for (size_t i = 0; i < args.size(); i++) { argv[i] = strdup(args[i].c_str()); } int pid = fork(); if (pid < 0) { err = true; } else if (pid == 0) { execvp(argv[0], argv); } for (size_t i = 0; i < args.size(); i++) { free(argv[i]); } free(argv); if (err) { throw std::exception(); } return pid; } extern char *executable_path; int launch_self(std::string process_type, std::vector extra_args) { extra_args.push_back(fmt::format("--process-type={0}", process_type)); extra_args.insert(extra_args.cbegin(), executable_path); extra_args.push_back(fmt::format("--log-level={0}", Looper::Log::LogStream::log_level)); return launch(extra_args); } fs::path get_base_dir() { auto path = fs::path(executable_path); return path.parent_path(); } void blocking_write(int fd, const void *buf, const size_t len) { ssize_t tmp; size_t i = 0; while (i < len) { tmp = write(fd, ((uint8_t*)buf) + i, len - i); if (tmp < 0) { throw std::exception(); } i += tmp; } assert(i == len); } void blocking_read(int fd, void *buf, const size_t len) { ssize_t tmp; size_t i = 0; while (i < len) { tmp = read(fd, ((uint8_t*)buf) + i, len - i); if (tmp < 0) { throw std::exception(); } i += tmp; } assert(i == len); } int NotSDL_ConvertAudioSamples(const SDL_AudioSpec *src_spec, const Uint8 *src_data, int src_len, const SDL_AudioSpec *dst_spec, Uint8 **dst_data, int *dst_len) { if (dst_data) { *dst_data = NULL; } if (dst_len) { *dst_len = 0; } if (!src_data) { return 0; } else if (src_len < 0) { return 0; } else if (!dst_data) { return 0; } else if (!dst_len) { return 0; } int retval = -1; Uint8 *dst = NULL; int dstlen = 0; SDL_AudioStream *stream = SDL_NewAudioStream(src_spec->format, src_spec->channels, src_spec->freq, dst_spec->format, dst_spec->channels, dst_spec->freq); if (stream) { SDL_AudioStreamPut(stream, src_data, src_len); SDL_AudioStreamFlush(stream); dstlen = SDL_AudioStreamAvailable(stream); if (dstlen >= 0) { dst = (Uint8 *)SDL_malloc(dstlen); if (dst) { retval = (SDL_AudioStreamGet(stream, dst, dstlen) >= 0) ? 0 : -1; } } } *dst_data = dst; *dst_len = dstlen; SDL_FreeAudioStream(stream); return retval; } PropertyHint make_hint(double min, double max) { PropertyHint output; auto range = output.mutable_range(); range->set_min(min); range->set_max(max); return output; } Property make_property(PropertyType type, std::string name, PropertyId id, std::optional path, std::optional hint) { Property output; output.set_id(id); output.set_name(name); output.set_type(type); if (path.has_value()) output.set_path(path.value()); if (hint.has_value()) output.mutable_hint()->CopyFrom(hint.value()); return output; } Property make_property(PropertyType type, std::string name, std::string path, std::optional hint) { return make_property(type, name, PropertyId::BackendSpecific, path, hint); } Property make_property(PropertyType type, std::string name, PropertyId id, std::optional hint) { return make_property(type, name, id, {}, hint); } PropertyHint make_hint(std::optional min = {}, std::optional max = {}) { PropertyHint output; PropertyHintRange &range = *output.mutable_range(); if (min.has_value()) { range.set_min(min.value()); } if (max.has_value()) { range.set_max(max.value()); } return output; }