refactor(common): de-Qt oakcommon and wrap it in a pure C ABI

- de-Qt all classes under src/common (std::string/vector/mutex,
  std::filesystem, expat-based XmlStreamReader/Writer)
- add pure C ABI in include/common + src/common/c_api: opaque handles,
  init returns NULL on failure, free(NULL) is a no-op, out-params with
  negative OAKCOMMON_E_* error codes (include/common/error.h)
- remove single-consumer classes from oakcommon (html, jobtime,
  otioutils, playbackaudioclock, tohex, util, avframeptr,
  crashpadinterface/crashpadutils, autoscroll, digit, range); their
  destinations are recorded in docs/zh/plans/riir/notes.md
- add gtest suites under src/common/tests (127 cases), standalone
  build driver in src/common/standalone
This commit is contained in:
2026-08-05 17:20:19 +08:00
parent bb09872a2f
commit bad52feda3
73 changed files with 8851 additions and 2 deletions
+14
View File
@@ -0,0 +1,14 @@
target_sources(oakcommon PRIVATE
commandlineparser.cpp
current.cpp
debug.cpp
dropworkflowbehavior.cpp
ffmpegutils.cpp
filefunctions.cpp
miscutils.cpp
ocioutils.cpp
oiioutils.cpp
power.cpp
qtutils.cpp
xmlutils.cpp
)
+282
View File
@@ -0,0 +1,282 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/commandlineparser.h"
#include <cstring>
#include <new>
#include <string>
#include <vector>
#include "../src/commandlineparser.h"
struct OakCommonCommandLineParser {
CommandLineParser impl;
};
struct OakCommonCommandLineOption {
CommandLineParser::Option *option;
};
struct OakCommonCommandLinePositionalArgument {
CommandLineParser::PositionalArgument *argument;
};
OakCommonCommandLineParser *oakcommon_commandlineparser_init(void)
{
try {
return new (std::nothrow) OakCommonCommandLineParser();
} catch (...) {
return NULL;
}
}
void oakcommon_commandlineparser_free(OakCommonCommandLineParser *parser)
{
delete parser;
}
int oakcommon_commandlineparser_set_app_info(OakCommonCommandLineParser *parser,
const char *name,
const char *version)
{
if (!parser || !name) {
return OAKCOMMON_E_INVALID;
}
try {
parser->impl.set_app_info(name, version ? version : "");
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineparser_add_option(
OakCommonCommandLineParser *parser, const char *const *names, int name_count,
const char *description, int takes_arg, const char *arg_placeholder,
int hidden, OakCommonCommandLineOption **out_option)
{
if (!parser || !names || name_count <= 0) {
return OAKCOMMON_E_INVALID;
}
try {
std::vector<std::string> strings;
strings.reserve(static_cast<size_t>(name_count));
for (int i = 0; i < name_count; i++) {
if (!names[i]) {
return OAKCOMMON_E_INVALID;
}
strings.emplace_back(names[i]);
}
const CommandLineParser::Option *option = parser->impl.add_option(
strings, description ? description : "", takes_arg != 0,
arg_placeholder ? arg_placeholder : "", hidden != 0);
if (out_option) {
auto *handle =
new (std::nothrow) OakCommonCommandLineOption();
if (!handle) {
return OAKCOMMON_E_NOMEM;
}
handle->option = const_cast<CommandLineParser::Option *>(option);
*out_option = handle;
}
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineparser_add_positional_argument(
OakCommonCommandLineParser *parser, const char *name,
const char *description, int required,
OakCommonCommandLinePositionalArgument **out_argument)
{
if (!parser || !name) {
return OAKCOMMON_E_INVALID;
}
try {
const CommandLineParser::PositionalArgument *argument =
parser->impl.add_positional_argument(
name, description ? description : "", required != 0);
if (out_argument) {
auto *handle =
new (std::nothrow) OakCommonCommandLinePositionalArgument();
if (!handle) {
return OAKCOMMON_E_NOMEM;
}
handle->argument =
const_cast<CommandLineParser::PositionalArgument *>(argument);
*out_argument = handle;
}
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineparser_process(OakCommonCommandLineParser *parser,
const char *const *argv, int argc)
{
if (!parser || !argv || argc < 0) {
return OAKCOMMON_E_INVALID;
}
try {
std::vector<std::string> args;
args.reserve(static_cast<size_t>(argc));
for (int i = 0; i < argc; i++) {
args.emplace_back(argv[i] ? argv[i] : "");
}
parser->impl.process(args);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineparser_print_help(OakCommonCommandLineParser *parser,
const char *filename)
{
if (!parser || !filename) {
return OAKCOMMON_E_INVALID;
}
try {
parser->impl.print_help(filename);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineoption_is_set(OakCommonCommandLineOption *option,
bool *is_set)
{
if (!option || !option->option || !is_set) {
return OAKCOMMON_E_INVALID;
}
try {
*is_set = option->option->is_set();
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
/**
* @brief Shared two-stage string getter.
*
* Returns the required buffer size in bytes (including the terminating
* NUL) as a non-negative value, or a negative error code.
*/
static int copy_setting(const std::string &value, char *buf, int buf_size)
{
int required = static_cast<int>(value.size()) + 1;
if (buf && buf_size > 0) {
size_t copy_len = value.size();
if (copy_len > static_cast<size_t>(buf_size) - 1) {
copy_len = static_cast<size_t>(buf_size) - 1;
}
memcpy(buf, value.data(), copy_len);
buf[copy_len] = '\0';
}
return required;
}
int oakcommon_commandlineoption_get_setting(OakCommonCommandLineOption *option,
char *buf, int buf_size)
{
if (!option || !option->option) {
return OAKCOMMON_E_INVALID;
}
try {
return copy_setting(option->option->get_setting(), buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlineoption_set_setting(OakCommonCommandLineOption *option,
const char *value)
{
if (!option || !option->option || !value) {
return OAKCOMMON_E_INVALID;
}
try {
option->option->set_setting(value);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlinepositionalargument_get_setting(
OakCommonCommandLinePositionalArgument *argument, char *buf, int buf_size)
{
if (!argument || !argument->argument) {
return OAKCOMMON_E_INVALID;
}
try {
return copy_setting(argument->argument->get_setting(), buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_commandlinepositionalargument_set_setting(
OakCommonCommandLinePositionalArgument *argument, const char *value)
{
if (!argument || !argument->argument || !value) {
return OAKCOMMON_E_INVALID;
}
try {
argument->argument->set_setting(value);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
void oakcommon_commandlineoption_free(OakCommonCommandLineOption *option)
{
delete option;
}
void oakcommon_commandlinepositionalargument_free(
OakCommonCommandLinePositionalArgument *argument)
{
delete argument;
}
+149
View File
@@ -0,0 +1,149 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/current.h"
#include "../src/current.h"
struct OakCommonCurrent {
Current *current;
};
OakCommonCurrent *oakcommon_current_instance(void)
{
static OakCommonCurrent handle = { &Current::get_instance() };
return &handle;
}
void oakcommon_current_free(OakCommonCurrent *self)
{
// No-op: the handle wraps a process-wide singleton.
(void)self;
}
static int current_set(Current *current,
void (Current::*set_fn)(std::shared_ptr<void>),
void *obj, OakCommonDestroyFn destroy)
{
try {
std::shared_ptr<void> value;
if (obj) {
if (destroy)
value = std::shared_ptr<void>(obj, destroy);
else
value = std::shared_ptr<void>(
obj, [](void *) {});
}
(current->*set_fn)(value);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
static int current_get(Current *current,
std::shared_ptr<void> (Current::*get_fn)() const,
void **out)
{
try {
*out = (current->*get_fn)().get();
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_current_set_video_params(OakCommonCurrent *self, void *obj,
OakCommonDestroyFn destroy)
{
if (!self)
return OAKCOMMON_E_INVALID;
return current_set(self->current, &Current::set_current_video_params,
obj, destroy);
}
int oakcommon_current_set_audio_params(OakCommonCurrent *self, void *obj,
OakCommonDestroyFn destroy)
{
if (!self)
return OAKCOMMON_E_INVALID;
return current_set(self->current, &Current::set_current_audio_params,
obj, destroy);
}
int oakcommon_current_set_plugin_host(OakCommonCurrent *self, void *obj,
OakCommonDestroyFn destroy)
{
if (!self)
return OAKCOMMON_E_INVALID;
return current_set(self->current, &Current::set_plugin_host, obj,
destroy);
}
int oakcommon_current_set_plugin_cache(OakCommonCurrent *self, void *obj,
OakCommonDestroyFn destroy)
{
if (!self)
return OAKCOMMON_E_INVALID;
return current_set(self->current, &Current::set_plugin_cache, obj,
destroy);
}
int oakcommon_current_get_video_params(OakCommonCurrent *self, void **out)
{
if (!self || !out)
return OAKCOMMON_E_INVALID;
return current_get(self->current, &Current::current_video_params,
out);
}
int oakcommon_current_get_audio_params(OakCommonCurrent *self, void **out)
{
if (!self || !out)
return OAKCOMMON_E_INVALID;
return current_get(self->current, &Current::current_audio_params,
out);
}
int oakcommon_current_get_plugin_host(OakCommonCurrent *self, void **out)
{
if (!self || !out)
return OAKCOMMON_E_INVALID;
return current_get(self->current, &Current::plugin_host, out);
}
int oakcommon_current_get_plugin_cache(OakCommonCurrent *self, void **out)
{
if (!self || !out)
return OAKCOMMON_E_INVALID;
return current_get(self->current, &Current::plugin_cache, out);
}
int oakcommon_current_is_interactive(OakCommonCurrent *self, int *out)
{
if (!self || !out)
return OAKCOMMON_E_INVALID;
try {
*out = self->current->interactive() ? 1 : 0;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
+45
View File
@@ -0,0 +1,45 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/debug.h"
#include "../src/debug.h"
int oakcommon_debug_log(int level, const char *msg)
{
if (!msg)
return OAKCOMMON_E_INVALID;
try {
olive::debug_handler(level, msg);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_debug_level_name(int level, char *buf, int buf_size)
{
try {
return olive::debug_level_name(level, buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+66
View File
@@ -0,0 +1,66 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/dropworkflowbehavior.h"
#include <cstring>
#include "../src/dropworkflowbehavior.h"
static const char *behavior_name(int value)
{
switch (value) {
case olive::k_dws_ask:
return "ASK";
case olive::k_dws_auto:
return "AUTO";
case olive::k_dws_manual:
return "MANUAL";
case olive::k_dws_disable:
return "DISABLE";
}
return "UNKNOWN";
}
int oakcommon_drop_workflow_behavior_is_valid(int value)
{
switch (value) {
case olive::k_dws_ask:
case olive::k_dws_auto:
case olive::k_dws_manual:
case olive::k_dws_disable:
return 1;
}
return 0;
}
int oakcommon_drop_workflow_behavior_name(int value, char *buf, int buf_size)
{
try {
const char *name = behavior_name(value);
int needed = (int)strlen(name) + 1;
if (buf && buf_size >= needed)
memcpy(buf, name, needed);
return needed;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+118
View File
@@ -0,0 +1,118 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/ffmpegutils.h"
#include "../src/ffmpegutils.h"
int oakcommon_ffmpegutils_get_compatible_bridge_pixel_format(
int pix_fmt, int maximum_pix_fmt, int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::get_compatible_bridge_pixel_format(
pix_fmt,
static_cast<olive::core::PixelFormat::Format>(
maximum_pix_fmt));
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_ffmpegutils_get_compatible_pixel_format(int pix_fmt, int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::get_compatible_pixel_format(
static_cast<olive::core::PixelFormat::Format>(pix_fmt));
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_ffmpegutils_get_ffmpeg_pixel_format(int pix_fmt,
int channel_count, int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::get_ffmpeg_pixel_format(
static_cast<olive::core::PixelFormat::Format>(pix_fmt),
channel_count);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_ffmpegutils_get_native_sample_format(int smp_fmt, int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::get_native_sample_format(smp_fmt);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_ffmpegutils_get_ffmpeg_sample_format(int smp_fmt, int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::get_ffmpeg_sample_format(
static_cast<olive::core::SampleFormat::Format>(smp_fmt));
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
int oakcommon_ffmpegutils_convert_jpeg_space_to_regular_space(int pix_fmt,
int *out)
{
if (!out)
return OAKCOMMON_E_INVALID;
try {
*out = olive::FFmpegUtils::convert_jpeg_space_to_regular_space(
pix_fmt);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
return OAKCOMMON_OK;
}
+295
View File
@@ -0,0 +1,295 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/filefunctions.h"
#include <cstring>
#include <string>
#include "../src/filefunctions.h"
struct OakCommonFileFunctions {
int unused; /**< Stateless family; handle kept for API uniformity. */
};
namespace
{
/**
* @brief Copies `value` into the caller's two-stage buffer
*
* @return Required buffer size in bytes (including the terminating NUL).
* Always non-negative; error codes are handled by the callers.
*/
int write_string_result(const std::string &value, char *buf, int buf_size)
{
int required = static_cast<int>(value.size()) + 1;
if (buf != nullptr && buf_size >= required) {
memcpy(buf, value.c_str(), required);
}
return required;
}
bool is_valid_string_out(const char *buf, int buf_size)
{
return buf_size >= 0 && (buf_size == 0 || buf != nullptr);
}
} // namespace
OakCommonFileFunctions *oakcommon_filefunctions_init(void)
{
try {
return new OakCommonFileFunctions{0};
} catch (...) {
return nullptr;
}
}
void oakcommon_filefunctions_free(OakCommonFileFunctions *self)
{
delete self;
}
int oakcommon_filefunctions_get_unique_file_identifier(
OakCommonFileFunctions *self, const char *filename, char *buf,
int buf_size)
{
if (self == nullptr || filename == nullptr ||
!is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::get_unique_file_identifier(filename), buf,
buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_configuration_location(
OakCommonFileFunctions *self, char *buf, int buf_size)
{
if (self == nullptr || !is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::get_configuration_location(), buf,
buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_application_path(
OakCommonFileFunctions *self, char *buf, int buf_size)
{
if (self == nullptr || !is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(FileFunctions::get_application_path(),
buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_temp_file_path(
OakCommonFileFunctions *self, char *buf, int buf_size)
{
if (self == nullptr || !is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(FileFunctions::get_temp_file_path(),
buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_auto_recovery_root(
OakCommonFileFunctions *self, char *buf, int buf_size)
{
if (self == nullptr || !is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::get_auto_recovery_root(), buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_can_copy_directory_without_overwriting(
OakCommonFileFunctions *self, const char *source, const char *dest,
int *out)
{
if (self == nullptr || source == nullptr || dest == nullptr ||
out == nullptr) {
return OAKCOMMON_E_INVALID;
}
try {
*out = FileFunctions::can_copy_directory_without_overwriting(
source, dest)
? 1
: 0;
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_copy_directory(OakCommonFileFunctions *self,
const char *source,
const char *dest, int overwrite)
{
if (self == nullptr || source == nullptr || dest == nullptr) {
return OAKCOMMON_E_INVALID;
}
try {
FileFunctions::copy_directory(source, dest, overwrite != 0);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_directory_is_valid(
OakCommonFileFunctions *self, const char *dir,
int try_to_create_if_not_exists, int *out)
{
if (self == nullptr || dir == nullptr || out == nullptr) {
return OAKCOMMON_E_INVALID;
}
try {
*out = FileFunctions::directory_is_valid(
dir, try_to_create_if_not_exists != 0)
? 1
: 0;
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_ensure_filename_extension(
OakCommonFileFunctions *self, const char *filename,
const char *extension, char *buf, int buf_size)
{
if (self == nullptr || filename == nullptr || extension == nullptr ||
!is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::ensure_filename_extension(filename,
extension),
buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_read_file_as_string(
OakCommonFileFunctions *self, const char *filename, char *buf,
int buf_size)
{
if (self == nullptr || filename == nullptr ||
!is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::read_file_as_string(filename), buf,
buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_safe_temporary_filename(
OakCommonFileFunctions *self, const char *original, char *buf,
int buf_size)
{
if (self == nullptr || original == nullptr ||
!is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::get_safe_temporary_filename(original),
buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_rename_file_allow_overwrite(
OakCommonFileFunctions *self, const char *from, const char *to,
int *out)
{
if (self == nullptr || from == nullptr || to == nullptr ||
out == nullptr) {
return OAKCOMMON_E_INVALID;
}
try {
*out = FileFunctions::rename_file_allow_overwrite(from, to) ? 1
: 0;
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_filefunctions_get_formatted_executable_for_platform(
OakCommonFileFunctions *self, const char *unformatted, char *buf,
int buf_size)
{
if (self == nullptr || unformatted == nullptr ||
!is_valid_string_out(buf, buf_size)) {
return OAKCOMMON_E_INVALID;
}
try {
return write_string_result(
FileFunctions::get_formatted_executable_for_platform(
unformatted),
buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+117
View File
@@ -0,0 +1,117 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/miscutils.h"
#include "../src/decibel.h"
#include "../src/lerp.h"
int oakcommon_decibel_from_linear(double linear, double *out_db)
{
if (!out_db) {
return OAKCOMMON_E_INVALID;
}
try {
*out_db = olive::Decibel::from_linear(linear);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_decibel_to_linear(double db, double *out_linear)
{
if (!out_linear) {
return OAKCOMMON_E_INVALID;
}
try {
*out_linear = olive::Decibel::to_linear(db);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_decibel_from_logarithmic(double logarithmic, double *out_db)
{
if (!out_db) {
return OAKCOMMON_E_INVALID;
}
try {
*out_db = olive::Decibel::from_logarithmic(logarithmic);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_decibel_to_logarithmic(double db, double *out_logarithmic)
{
if (!out_logarithmic) {
return OAKCOMMON_E_INVALID;
}
try {
*out_logarithmic = olive::Decibel::to_logarithmic(db);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_decibel_linear_to_logarithmic(double linear,
double *out_logarithmic)
{
if (!out_logarithmic) {
return OAKCOMMON_E_INVALID;
}
try {
*out_logarithmic = olive::Decibel::linear_to_logarithmic(linear);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_decibel_logarithmic_to_linear(double logarithmic,
double *out_linear)
{
if (!out_linear) {
return OAKCOMMON_E_INVALID;
}
try {
*out_linear = olive::Decibel::logarithmic_to_linear(logarithmic);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_lerp(double a, double b, double t, double *out_value)
{
if (!out_value) {
return OAKCOMMON_E_INVALID;
}
try {
*out_value = lerp(a, b, t);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+62
View File
@@ -0,0 +1,62 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/ocioutils.h"
#include <new>
#include "../src/ocioutils.h"
struct OakCommonOCIOUtils {
int unused; /**< Stateless; only the address matters. */
};
OakCommonOCIOUtils *oakcommon_ocioutils_init(void)
{
try {
return new (std::nothrow) OakCommonOCIOUtils{};
} catch (...) {
return NULL;
}
}
void oakcommon_ocioutils_free(OakCommonOCIOUtils *self)
{
delete self;
}
int oakcommon_ocioutils_get_ocio_bit_depth_from_pixel_format(
OakCommonOCIOUtils *self, int pixel_format, int *out_bit_depth)
{
try {
if (self == NULL || out_bit_depth == NULL)
return OAKCOMMON_E_INVALID;
if (pixel_format < OAKCOMMON_PIXEL_FORMAT_INVALID ||
pixel_format >= OAKCOMMON_PIXEL_FORMAT_COUNT)
return OAKCOMMON_E_INVALID;
ocio::BitDepth depth = OCIOUtils::get_ocio_bit_depth_from_pixel_format(
static_cast<olive::core::PixelFormat::Format>(pixel_format));
*out_bit_depth = static_cast<int>(depth);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+100
View File
@@ -0,0 +1,100 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/oiioutils.h"
#include <new>
#include "../src/oiioutils.h"
struct OakCommonOIIOUtils {
int unused; /**< Stateless; only the address matters. */
};
OakCommonOIIOUtils *oakcommon_oiioutils_init(void)
{
try {
return new (std::nothrow) OakCommonOIIOUtils{};
} catch (...) {
return NULL;
}
}
void oakcommon_oiioutils_free(OakCommonOIIOUtils *self)
{
delete self;
}
int oakcommon_oiioutils_get_oiio_base_type_from_format(
OakCommonOIIOUtils *self, int pixel_format, int *out_base_type)
{
try {
if (self == NULL || out_base_type == NULL)
return OAKCOMMON_E_INVALID;
if (pixel_format < OAKCOMMON_PIXEL_FORMAT_INVALID ||
pixel_format >= OAKCOMMON_PIXEL_FORMAT_COUNT)
return OAKCOMMON_E_INVALID;
OIIO::TypeDesc::BASETYPE base_type =
OIIOUtils::get_oiio_base_type_from_format(
static_cast<olive::core::PixelFormat::Format>(pixel_format));
*out_base_type = static_cast<int>(base_type);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_oiioutils_get_format_from_oiio_basetype(
OakCommonOIIOUtils *self, int base_type, int *out_pixel_format)
{
try {
if (self == NULL || out_pixel_format == NULL)
return OAKCOMMON_E_INVALID;
if (base_type < 0 || base_type >= OIIO::TypeDesc::LASTBASE)
return OAKCOMMON_E_INVALID;
olive::core::PixelFormat format =
OIIOUtils::get_format_from_oiio_basetype(
static_cast<OIIO::TypeDesc::BASETYPE>(base_type));
*out_pixel_format = static_cast<int>(format);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_oiioutils_get_pixel_aspect_ratio(
OakCommonOIIOUtils *self, double pixel_aspect_ratio, int *out_numerator,
int *out_denominator)
{
try {
if (self == NULL || out_numerator == NULL || out_denominator == NULL)
return OAKCOMMON_E_INVALID;
olive::core::Rational par =
olive::core::Rational::from_double(pixel_aspect_ratio);
*out_numerator = par.numerator();
*out_denominator = par.denominator();
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+53
View File
@@ -0,0 +1,53 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "../../include/common/power.h"
#include "../src/power.h"
int oakcommon_power_ceil_to_power_of_2(uint32_t value, uint32_t *out)
{
try {
if (!out) {
return OAKCOMMON_E_INVALID;
}
*out = olive::ceil_to_power_of_2(value);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_power_floor_to_power_of_2(uint32_t value, uint32_t *out)
{
try {
if (!out) {
return OAKCOMMON_E_INVALID;
}
*out = olive::floor_to_power_of_2(value);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+74
View File
@@ -0,0 +1,74 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/qtutils.h"
#include "../src/qtutils.h"
int oakcommon_qtutils_ptr_to_value(void *ptr, uint64_t *out_value)
{
if (!out_value) {
return OAKCOMMON_E_INVALID;
}
try {
*out_value = static_cast<uint64_t>(olive::QtUtils::ptr_to_value(ptr));
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_qtutils_value_to_ptr(uint64_t value, void **out_ptr)
{
if (!out_ptr) {
return OAKCOMMON_E_INVALID;
}
try {
*out_ptr =
olive::QtUtils::value_to_ptr<void>(static_cast<uintptr_t>(value));
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_qtutils_get_creation_date(const char *path, int64_t *out_secs)
{
if (!path || !out_secs) {
return OAKCOMMON_E_INVALID;
}
try {
std::chrono::system_clock::time_point t =
olive::QtUtils::get_creation_date(std::filesystem::path(path));
if (t == std::chrono::system_clock::time_point{}) {
return OAKCOMMON_E_NOT_FOUND;
}
*out_secs = static_cast<int64_t>(
std::chrono::system_clock::to_time_t(t));
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
+297
View File
@@ -0,0 +1,297 @@
/***
Oak Video Editor - Non-Linear Video Editor
Copyright (C) 2026 Oak Team
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 3 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, see <http://www.gnu.org/licenses/>.
***/
#include "common/xmlutils.h"
#include <cstring>
#include <new>
#include "../src/xmlutils.h"
struct OakCommonXmlReader {
olive::XmlStreamReader reader;
std::string cached_text;
bool has_cached_text = false;
explicit OakCommonXmlReader(const char *data)
: reader(data)
{
}
};
struct OakCommonXmlWriter {
olive::XmlStreamWriter writer;
};
namespace
{
/**
* @brief Copy @p value into the two-stage string buffer.
*
* @return Required buffer size in bytes (including NUL). The buffer is only
* written to when it is large enough.
*/
int copy_string(const std::string &value, char *buf, int buf_size)
{
int needed = static_cast<int>(value.size()) + 1;
if (buf && buf_size >= needed) {
memcpy(buf, value.c_str(), needed);
}
return needed;
}
} // namespace
extern "C" {
OakCommonXmlReader *oakcommon_xml_reader_init(const char *data)
{
if (!data)
return nullptr;
try {
return new (std::nothrow) OakCommonXmlReader(data);
} catch (...) {
return nullptr;
}
}
void oakcommon_xml_reader_free(OakCommonXmlReader *reader)
{
delete reader;
}
int oakcommon_xml_reader_read_next_start_element(OakCommonXmlReader *reader,
int *found)
{
if (!reader || !found)
return OAKCOMMON_E_INVALID;
try {
reader->has_cached_text = false;
*found = olive::xml_read_next_start_element(&reader->reader) ? 1 : 0;
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_name(OakCommonXmlReader *reader, char *buf,
int buf_size)
{
if (!reader)
return OAKCOMMON_E_INVALID;
try {
return copy_string(reader->reader.name(), buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_read_element_text(OakCommonXmlReader *reader,
char *buf, int buf_size)
{
if (!reader)
return OAKCOMMON_E_INVALID;
try {
// read_element_text() consumes the stream, so cache the result to
// keep the two-stage (size query then copy) buffer convention working.
if (!reader->has_cached_text) {
reader->cached_text = reader->reader.read_element_text();
reader->has_cached_text = true;
}
return copy_string(reader->cached_text, buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_skip_current_element(OakCommonXmlReader *reader)
{
if (!reader)
return OAKCOMMON_E_INVALID;
try {
reader->has_cached_text = false;
reader->reader.skip_current_element();
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_attribute_count(OakCommonXmlReader *reader,
int *count)
{
if (!reader || !count)
return OAKCOMMON_E_INVALID;
try {
*count = static_cast<int>(reader->reader.attributes().size());
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_attribute_name(OakCommonXmlReader *reader, int index,
char *buf, int buf_size)
{
if (!reader)
return OAKCOMMON_E_INVALID;
try {
const auto &attrs = reader->reader.attributes();
if (index < 0 || index >= static_cast<int>(attrs.size()))
return OAKCOMMON_E_NOT_FOUND;
return copy_string(attrs[index].name, buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_attribute_value(OakCommonXmlReader *reader,
int index, char *buf, int buf_size)
{
if (!reader)
return OAKCOMMON_E_INVALID;
try {
const auto &attrs = reader->reader.attributes();
if (index < 0 || index >= static_cast<int>(attrs.size()))
return OAKCOMMON_E_NOT_FOUND;
return copy_string(attrs[index].value, buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_reader_has_error(OakCommonXmlReader *reader,
int *has_error)
{
if (!reader || !has_error)
return OAKCOMMON_E_INVALID;
try {
*has_error = reader->reader.has_error() ? 1 : 0;
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
OakCommonXmlWriter *oakcommon_xml_writer_init(void)
{
try {
return new (std::nothrow) OakCommonXmlWriter();
} catch (...) {
return nullptr;
}
}
void oakcommon_xml_writer_free(OakCommonXmlWriter *writer)
{
delete writer;
}
int oakcommon_xml_writer_write_start_element(OakCommonXmlWriter *writer,
const char *name)
{
if (!writer || !name)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_start_element(name);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_write_attribute(OakCommonXmlWriter *writer,
const char *name, const char *value)
{
if (!writer || !name || !value)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_attribute(name, value);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_write_characters(OakCommonXmlWriter *writer,
const char *text)
{
if (!writer || !text)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_characters(text);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_write_text_element(OakCommonXmlWriter *writer,
const char *name,
const char *text)
{
if (!writer || !name || !text)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_text_element(name, text);
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_write_end_element(OakCommonXmlWriter *writer)
{
if (!writer)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_end_element();
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_write_end_document(OakCommonXmlWriter *writer)
{
if (!writer)
return OAKCOMMON_E_INVALID;
try {
writer->writer.write_end_document();
return OAKCOMMON_OK;
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
int oakcommon_xml_writer_output(OakCommonXmlWriter *writer, char *buf,
int buf_size)
{
if (!writer)
return OAKCOMMON_E_INVALID;
try {
return copy_string(writer->writer.output(), buf, buf_size);
} catch (...) {
return OAKCOMMON_E_FAILED;
}
}
} // extern "C"