From 90578eaf9dfe3dd0a3c469819317df449a2f97e1 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Wed, 16 Apr 2025 13:37:36 +0530 Subject: [PATCH 01/13] replaced nanomsg with nanomsg_sys --- src/lib_ccx/ccx_share.c | 55 +- src/lib_ccx/ccx_share.h | 1 - src/rust/Cargo.lock | 80 ++- src/rust/Cargo.toml | 1 + src/rust/lib_ccxr/Cargo.lock | 114 ++++ src/rust/lib_ccxr/Cargo.toml | 4 + src/rust/lib_ccxr/src/lib.rs | 2 + .../src/share/ccxr_sub_entry_message.rs | 16 + src/rust/lib_ccxr/src/share/mod.rs | 3 + src/rust/lib_ccxr/src/share/share.rs | 516 ++++++++++++++++++ src/rust/lib_ccxr/src/share/tests.rs | 260 +++++++++ src/rust/src/libccxr_exports/mod.rs | 2 + src/rust/src/libccxr_exports/share.rs | 115 ++++ 13 files changed, 1165 insertions(+), 4 deletions(-) create mode 100644 src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs create mode 100644 src/rust/lib_ccxr/src/share/mod.rs create mode 100644 src/rust/lib_ccxr/src/share/share.rs create mode 100644 src/rust/lib_ccxr/src/share/tests.rs create mode 100644 src/rust/src/libccxr_exports/share.rs diff --git a/src/lib_ccx/ccx_share.c b/src/lib_ccx/ccx_share.c index e5026b9e2..4c13c2d8c 100644 --- a/src/lib_ccx/ccx_share.c +++ b/src/lib_ccx/ccx_share.c @@ -8,26 +8,46 @@ #include "ccx_common_option.h" #include "ccx_decoders_structs.h" #include "lib_ccx.h" - #ifdef ENABLE_SHARING #include #include ccx_share_service_ctx ccx_share_ctx; +#ifndef DISABLE_RUST +extern void ccxr_sub_entry_msg_cleanup_c(CcxSubEntryMessage *msg); +extern void ccxr_sub_entry_msg_print_c(const CcxSubEntryMessage *msg); +extern void ccxr_sub_entries_cleanup_c(ccx_sub_entries *entries); +extern void ccxr_sub_entries_print_c(const ccx_sub_entries *entries); +extern ccx_share_status ccxr_share_start_c(const char *stream_name); +extern ccx_share_status ccxr_share_stop_c(void); +extern ccx_share_status _ccxr_share_send_c(const CcxSubEntryMessage *msg); +extern ccx_share_status ccxr_share_send_c(const struct cc_subtitle *sub); +extern ccx_share_status ccxr_share_stream_done_c(const char *stream_name); +extern ccx_share_status _ccxr_share_sub_to_entries_c(const struct cc_subtitle *sub, ccx_sub_entries *entries); + +#endif void ccx_sub_entry_msg_cleanup(CcxSubEntryMessage *msg) { +#ifndef DISABLE_RUST + return ccxr_sub_entry_msg_cleanup_c(msg); +#else + for (int i = 0; i < msg->n_lines; i++) { free(msg->lines[i]); } free(msg->lines); free(msg->stream_name); +#endif } void ccx_sub_entry_msg_print(CcxSubEntryMessage *msg) { +#ifndef DISABLE_RUST + return ccxr_sub_entry_msg_print_c(msg); +#else if (!msg) { dbg_print(CCX_DMT_SHARE, "[share] print(!msg)\n"); @@ -55,6 +75,7 @@ void ccx_sub_entry_msg_print(CcxSubEntryMessage *msg) } dbg_print(CCX_DMT_SHARE, "[share] %s\n", msg->lines[i]); } +#endif } void ccx_sub_entries_init(ccx_sub_entries *entries) @@ -65,6 +86,9 @@ void ccx_sub_entries_init(ccx_sub_entries *entries) void ccx_sub_entries_cleanup(ccx_sub_entries *entries) { +#ifndef DISABLE_RUST + return ccxr_sub_entries_cleanup_c(entries); +#else for (int i = 0; i < entries->count; i++) { ccx_sub_entry_msg_cleanup(entries->messages + i); @@ -72,19 +96,27 @@ void ccx_sub_entries_cleanup(ccx_sub_entries *entries) free(entries->messages); entries->messages = NULL; entries->count = 0; +#endif } void ccx_sub_entries_print(ccx_sub_entries *entries) { +#ifndef DISABLE_RUST + return ccxr_sub_entries_print_c(entries); +#else dbg_print(CCX_DMT_SHARE, "[share] ccx_sub_entries_print (%u entries)\n", entries->count); for (int i = 0; i < entries->count; i++) { ccx_sub_entry_msg_print(entries->messages + i); } +#endif } ccx_share_status ccx_share_start(const char *stream_name) // TODO add stream { +#ifndef DISABLE_RUST + return ccxr_share_start_c(stream_name); +#else dbg_print(CCX_DMT_SHARE, "[share] ccx_share_start: starting service\n"); // TODO for multiple files we have to move creation to ccx_share_init ccx_share_ctx.nn_sock = nn_socket(AF_SP, NN_PUB); @@ -121,18 +153,26 @@ ccx_share_status ccx_share_start(const char *stream_name) // TODO add stream sleep(1); // We have to sleep a while, because it takes some time for subscribers to subscribe return CCX_SHARE_OK; +#endif } ccx_share_status ccx_share_stop() { +#ifndef DISABLE_RUST + return ccxr_share_stop_c(); +#else dbg_print(CCX_DMT_SHARE, "[share] ccx_share_stop: stopping service\n"); nn_shutdown(ccx_share_ctx.nn_sock, ccx_share_ctx.nn_binder); free(ccx_share_ctx.stream_name); return CCX_SHARE_OK; +#endif } ccx_share_status ccx_share_send(struct cc_subtitle *sub) { +#ifndef DISABLE_RUST + return ccxr_share_send_c(sub); +#else dbg_print(CCX_DMT_SHARE, "[share] ccx_share_send: sending\n"); ccx_sub_entries entries; ccx_sub_entries_init(&entries); @@ -154,10 +194,14 @@ ccx_share_status ccx_share_send(struct cc_subtitle *sub) ccx_sub_entries_cleanup(&entries); return CCX_SHARE_OK; +#endif } ccx_share_status _ccx_share_send(CcxSubEntryMessage *msg) { +#ifndef DISABLE_RUST + return _ccxr_share_send_c(msg); +#else dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send\n"); size_t len = ccx_sub_entry_message__get_packed_size(msg); void *buf = malloc(len); @@ -175,10 +219,14 @@ ccx_share_status _ccx_share_send(CcxSubEntryMessage *msg) free(buf); dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send: sent\n"); return CCX_SHARE_OK; +#endif } ccx_share_status ccx_share_stream_done(char *stream_name) { +#ifndef DISABLE_RUST + return ccxr_share_stream_done_c(stream_name); +#else CcxSubEntryMessage msg = CCX_SUB_ENTRY_MESSAGE__INIT; msg.eos = 1; msg.stream_name = strdup(stream_name); @@ -197,10 +245,14 @@ ccx_share_status ccx_share_stream_done(char *stream_name) ccx_sub_entry_msg_cleanup(&msg); return CCX_SHARE_OK; +#endif } ccx_share_status _ccx_share_sub_to_entries(struct cc_subtitle *sub, ccx_sub_entries *entries) { +#ifndef DISABLE_RUST + return _ccxr_share_sub_to_entries_c(sub, entries); +#else dbg_print(CCX_DMT_SHARE, "\n[share] _ccx_share_sub_to_entry\n"); if (sub->type == CC_608) { @@ -295,6 +347,7 @@ ccx_share_status _ccx_share_sub_to_entries(struct cc_subtitle *sub, ccx_sub_entr dbg_print(CCX_DMT_SHARE, "[share] done\n"); return CCX_SHARE_OK; +#endif } ccx_share_status ccx_share_launch_translator(char *langs, char *auth) diff --git a/src/lib_ccx/ccx_share.h b/src/lib_ccx/ccx_share.h index c6ddd6b0a..6148f7053 100644 --- a/src/lib_ccx/ccx_share.h +++ b/src/lib_ccx/ccx_share.h @@ -1,7 +1,6 @@ // // Created by Oleg Kisselef (olegkisselef at gmail dot com) on 6/21/15 // - #ifndef CCEXTRACTOR_CCX_SHARE_H #define CCEXTRACTOR_CCX_SHARE_H diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index d9b3d3ec0..6c061b946 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -61,6 +61,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "approx" version = "0.5.1" @@ -144,12 +150,27 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + [[package]] name = "camino" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + [[package]] name = "ccx_rust" version = "0.1.0" @@ -161,6 +182,7 @@ dependencies = [ "env_logger", "leptonica-sys", "lib_ccxr", + "libc", "log", "num-integer", "palette", @@ -239,6 +261,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -355,6 +386,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "glob" version = "0.3.2" @@ -603,7 +640,11 @@ dependencies = [ "bitflags 2.9.0", "crc32fast", "derive_more", + "lazy_static", + "libc", + "nanomsg-sys", "num_enum", + "prost", "strum 0.26.3", "strum_macros 0.26.4", "thiserror", @@ -613,9 +654,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libloading" @@ -657,6 +698,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "nanomsg-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78aa3ccb6d007dfecb4f7070725c4b1670a87677babb6621cb0c8cce9cfdc004" +dependencies = [ + "cmake", + "gcc", + "libc", + "pkg-config", +] + [[package]] name = "nom" version = "7.1.3" @@ -843,6 +896,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "quote" version = "1.0.39" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 7a0701195..87f784528 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -28,6 +28,7 @@ num-integer = "0.1.46" lib_ccxr = { path = "lib_ccxr" } url = "2.5.4" encoding_rs = "0.8.5" +libc = "0.2.172" [build-dependencies] bindgen = "0.64.0" diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock index 8ec94ecf1..7b0338bae 100644 --- a/src/rust/lib_ccxr/Cargo.lock +++ b/src/rust/lib_ccxr/Cargo.lock @@ -2,18 +2,48 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "bytes" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +dependencies = [ + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cmake" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +dependencies = [ + "cc", +] + [[package]] name = "convert_case" version = "0.4.0" @@ -62,6 +92,12 @@ dependencies = [ "syn", ] +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + [[package]] name = "equivalent" version = "1.0.2" @@ -77,6 +113,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "gcc" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" + [[package]] name = "hashbrown" version = "0.15.2" @@ -238,12 +280,27 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "lib_ccxr" version = "0.1.0" @@ -251,7 +308,11 @@ dependencies = [ "bitflags", "crc32fast", "derive_more", + "lazy_static", + "libc", + "nanomsg-sys", "num_enum", + "prost", "strum", "strum_macros", "thiserror", @@ -259,6 +320,12 @@ dependencies = [ "url", ] +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + [[package]] name = "litemap" version = "0.7.5" @@ -271,6 +338,18 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "nanomsg-sys" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78aa3ccb6d007dfecb4f7070725c4b1670a87677babb6621cb0c8cce9cfdc004" +dependencies = [ + "cmake", + "gcc", + "libc", + "pkg-config", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -310,6 +389,12 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + [[package]] name = "powerfmt" version = "0.2.0" @@ -335,6 +420,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" +dependencies = [ + "anyhow", + "itertools", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "quote" version = "1.0.39" @@ -385,6 +493,12 @@ dependencies = [ "syn", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "smallvec" version = "1.14.0" diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index 6162aef3a..7d0bcb141 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -15,6 +15,10 @@ strum = "0.26.3" strum_macros = "0.26.4" crc32fast = "1.4.2" num_enum = "0.6.1" +prost = "0.13.5" +lazy_static = "1.5.0" +nanomsg-sys = "0.7.2" +libc = "0.2.172" [features] default = [ diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs index 4b02a4dfa..09470a1d5 100644 --- a/src/rust/lib_ccxr/src/lib.rs +++ b/src/rust/lib_ccxr/src/lib.rs @@ -6,3 +6,5 @@ pub mod subtitle; pub mod teletext; pub mod time; pub mod util; +#[cfg(feature = "enable_sharing")] +pub mod share; \ No newline at end of file diff --git a/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs b/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs new file mode 100644 index 000000000..2cabcdc56 --- /dev/null +++ b/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs @@ -0,0 +1,16 @@ +// This file is @generated by prost-build. +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CcxSubEntryMessage { + #[prost(int32, required, tag = "1")] + pub eos: i32, + #[prost(string, required, tag = "2")] + pub stream_name: ::prost::alloc::string::String, + #[prost(int64, required, tag = "3")] + pub counter: i64, + #[prost(int64, required, tag = "4")] + pub start_time: i64, + #[prost(int64, required, tag = "5")] + pub end_time: i64, + #[prost(string, repeated, tag = "7")] + pub lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, +} diff --git a/src/rust/lib_ccxr/src/share/mod.rs b/src/rust/lib_ccxr/src/share/mod.rs new file mode 100644 index 000000000..8938af992 --- /dev/null +++ b/src/rust/lib_ccxr/src/share/mod.rs @@ -0,0 +1,3 @@ +pub mod share; +pub mod ccxr_sub_entry_message; +mod tests; diff --git a/src/rust/lib_ccxr/src/share/share.rs b/src/rust/lib_ccxr/src/share/share.rs new file mode 100644 index 000000000..31c4138fa --- /dev/null +++ b/src/rust/lib_ccxr/src/share/share.rs @@ -0,0 +1,516 @@ +use crate::common::Options; +use crate::share::ccxr_sub_entry_message::CcxSubEntryMessage; +use crate::util::log::{debug, DebugMessageFlag}; +use lazy_static::lazy_static; +use libc::size_t; +use nanomsg_sys::{nn_bind, nn_send, nn_setsockopt, nn_shutdown, nn_socket, AF_SP, NN_LINGER, NN_PUB, NN_SOL_SOCKET}; +use prost::Message; +use std::cmp::PartialEq; +use std::ffi::c_void; +use std::os::raw::{c_char, c_int}; +use std::sync::{LazyLock, Mutex}; +use std::{ffi::{CStr, CString}, thread, time::Duration}; +// use crate::bindings::{cc_subtitle, ccx_output_format}; + +pub const CCX_DECODER_608_SCREEN_ROWS: usize = 15; +pub const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; +pub static CCX_OPTIONS: LazyLock> = LazyLock::new(|| Mutex::new(Options::default())); + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CcxEia608Format { + SFormatCcScreen = 0, + SFormatCcLine = 1, + SFormatXds = 2, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CcModes { + ModePopOn = 0, + ModeRollUp2 = 1, + ModeRollUp3 = 2, + ModeRollUp4 = 3, + ModeText = 4, + ModePaintOn = 5, + ModeFakeRollUp1 = 100, +} + + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum CcxDecoder608ColorCode { + White = 0, + Green = 1, + Blue = 2, + Cyan = 3, + Red = 4, + Yellow = 5, + Magenta = 6, + UserDefined = 7, + Black = 8, + Transparent = 9, + Max = 10, +} + +#[repr(C)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum FontBits { + Normal = 0, + Italics = 1, + Underline = 2, + UnderlineItalics = 3, +} + + +#[repr(C)] +#[derive(Debug, Clone)] +pub struct Eia608Screen { + pub format: CcxEia608Format, + pub characters: [[c_char; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + pub colors: [[CcxDecoder608ColorCode; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + pub fonts: [[FontBits; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + pub row_used: [c_int; CCX_DECODER_608_SCREEN_ROWS], + pub empty: c_int, + pub start_time: i64, + pub end_time: i64, + pub mode: CcModes, + pub channel: c_int, + pub my_field: c_int, + pub xds_str: *mut c_char, + pub xds_len: usize, + pub cur_xds_packet_class: c_int, +} + +impl Default for Eia608Screen { + fn default() -> Self { + Self { + format: CcxEia608Format::SFormatCcScreen, + characters: [[0; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + colors: [[CcxDecoder608ColorCode::Black; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + fonts: [[FontBits::Normal; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + row_used: [0; CCX_DECODER_608_SCREEN_ROWS], + empty: 1, + start_time: 0, + end_time: 0, + mode: CcModes::ModePopOn, + channel: 0, + my_field: 0, + xds_str: std::ptr::null_mut(), + xds_len: 0, + cur_xds_packet_class: 0, + } + } +} + +impl Eia608Screen { + pub fn new() -> Self { + Self::default() + } + + pub fn set_xds_str(&mut self, xds: &str) { + let c_string = CString::new(xds).expect("CString::new failed"); + self.xds_str = c_string.into_raw(); + self.xds_len = xds.len(); + } + + pub fn free_xds_str(&mut self) { + if !self.xds_str.is_null() { + unsafe { + let _ = CString::from_raw(self.xds_str); + } + self.xds_str = std::ptr::null_mut(); + self.xds_len = 0; + } + } +} + +impl Drop for Eia608Screen { + fn drop(&mut self) { + self.free_xds_str(); + } +} + + +pub type SubDataType = std::os::raw::c_uint; +pub type LLONG = i64; +pub const SUBTYPE_CC_BITMAP: Subtype = 0; +pub const SUBTYPE_CC_608: Subtype = 1; +pub const SUBTYPE_CC_TEXT: Subtype = 2; +pub const SUBTYPE_CC_RAW: Subtype = 3; +pub type Subtype = std::os::raw::c_uint; + +pub type CcxEncodingType = std::os::raw::c_uint; + +pub struct CcSubtitle { + #[doc = " A generic data which contain data according to decoder\n @warn decoder cant output multiple types of data"] + pub data: *mut std::os::raw::c_void, + pub datatype: SubDataType, + #[doc = " number of data"] + pub nb_data: std::os::raw::c_uint, + #[doc = " type of subtitle"] + pub type_: Subtype, + #[doc = " Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen"] + pub enc_type: CcxEncodingType, + pub start_time: LLONG, + pub end_time: LLONG, + pub flags: c_int, + pub lang_index: c_int, + #[doc = " flag to tell that decoder has given output"] + pub got_output: c_int, + pub mode: [c_char; 5usize], + pub info: [c_char; 4usize], + #[doc = " Used for DVB end time in ms"] + pub time_out: c_int, + pub next: *mut CcSubtitle, + pub prev: *mut CcSubtitle, +} + +#[repr(C)] +#[derive(Debug)] +pub enum CcxShareStatus { + Ok = 0, + Fail, +} +impl PartialEq for CcxShareStatus { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (CcxShareStatus::Ok, CcxShareStatus::Ok) => true, + (CcxShareStatus::Fail, CcxShareStatus::Fail) => true, + _ => false, + } + } +} +pub struct CcxShareServiceCtx { + counter: i64, + stream_name: Option, + nn_sock: libc::c_int, + nn_binder: libc::c_int, +} + +pub struct CcxSubEntries { + pub messages: Vec, +} +impl CcxShareServiceCtx { + fn new() -> Self { + CcxShareServiceCtx { + counter: 0, + stream_name: None, + nn_sock: 0, + nn_binder: 0, + } + } +} + + +lazy_static! { + pub static ref CCX_SHARE_CTX: Mutex = Mutex::new(CcxShareServiceCtx::new()); +} + + + +pub fn ccxr_sub_entry_msg_init(msg: &mut CcxSubEntryMessage) { + msg.eos = 0; + msg.stream_name = "".parse().unwrap(); + msg.counter = 0; + msg.start_time = 0; + msg.end_time = 0; + msg.lines.clear(); +} + + +pub fn ccxr_sub_entry_msg_cleanup(msg: &mut CcxSubEntryMessage) { + msg.lines.clear(); + msg.stream_name = "".parse().unwrap(); +} + +pub fn ccxr_sub_entry_msg_print(msg: &CcxSubEntryMessage) { + if msg.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); + return; + } + + debug!(msg_type = DebugMessageFlag::SHARE; "\n[share] sub msg #{}", msg.counter); + if !msg.stream_name.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: {}", msg.stream_name); + } else { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: None"); + } + debug!(msg_type = DebugMessageFlag::SHARE; "[share] start: {}", msg.start_time); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] end: {}", msg.end_time); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] lines count: {}", msg.lines.len()); + + if msg.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); + return; + } + for (i, line) in msg.lines.iter().enumerate() { + if !line.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}]: {}", i, line); + } else { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}] is not allocated", i); + } + } +} + + +pub fn ccxr_sub_entries_cleanup(entries: &mut CcxSubEntries) { + entries.messages.clear(); +} + +pub fn ccxr_sub_entries_print(entries: &CcxSubEntries) { + eprintln!("[share] ccxr_sub_entries_print ({} entries)", entries.messages.len()); + for message in &entries.messages { + ccxr_sub_entry_msg_print(message); + } +} + +pub unsafe fn ccxr_share_start(stream_name: Option<&str>) -> CcxShareStatus { + let mut ccx_options = CCX_OPTIONS.lock().unwrap(); + + // Debug print similar to dbg_print in C + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: starting service\n"); + + // Create a nanomsg socket with domain AF_SP and protocol NN_PUB + let nn_sock = nn_socket(AF_SP, NN_PUB); + if nn_sock < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_socket()\n"); + return CcxShareStatus::Fail; + } + CCX_SHARE_CTX.lock().unwrap().nn_sock = nn_sock; + // Set a default URL if one was not already provided. + if ccx_options.sharing_url.is_none() { + ccx_options.sharing_url = Some("tcp://*:3269".to_string().parse().unwrap()); + } + + // Convert the sharing URL into a C-compatible string. + let url = ccx_options.sharing_url.as_ref().unwrap(); + let sharing_url_cstr = CString::new(url.as_str()).expect("Failed to create CString"); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: url={}", ccx_options.sharing_url.as_mut().unwrap()); + + // Bind the socket to the URL. + let nn_binder = nn_bind(nn_sock, sharing_url_cstr.as_ptr()); + if nn_binder < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_bind()"); + return CcxShareStatus::Fail; + } + CCX_SHARE_CTX.lock().unwrap().nn_binder = nn_binder; + + // Set the linger socket option to -1. + let linger: i32 = -1; + let ret = nn_setsockopt( + nn_sock, + NN_SOL_SOCKET, + NN_LINGER, + &linger as *const _ as *const c_void, + std::mem::size_of::() as size_t, + ); + if ret < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_setsockopt()"); + return CcxShareStatus::Fail; + } + + // Save the stream name into the context, defaulting to "unknown" if not provided. + CCX_SHARE_CTX.lock().unwrap().stream_name = Some(stream_name.unwrap_or("unknown").to_string()); + + // Sleep for 1 second to allow subscribers to connect. + thread::sleep(Duration::from_secs(1)); + + CcxShareStatus::Ok +} + + +pub unsafe fn ccxr_share_stop() -> CcxShareStatus { + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stop: stopping service"); + + + nn_shutdown(CCX_SHARE_CTX.lock().unwrap().nn_sock, CCX_SHARE_CTX.lock().unwrap().nn_binder); + ctx.stream_name = None; + CcxShareStatus::Ok +} + + +pub unsafe fn ccxr_share_send(sub: *mut CcSubtitle) -> CcxShareStatus { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending"); + + // Create an entries structure and populate it from the subtitle. + let mut entries = CcxSubEntries { messages: Vec::new() }; + if ccxr_share_sub_to_entries( &*sub , &mut entries) == CcxShareStatus::Fail { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] failed to convert subtitle to entries"); + return CcxShareStatus::Fail; + } + + // Debug print of entries. + ccxr_sub_entries_print(&entries); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] entry obtained:"); + + // Iterate over all entries and send them. + for (i, message) in entries.messages.iter().enumerate() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending entry {}", i); + if entries.messages[i].lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] skipping empty message"); + continue; + } + if _ccxr_share_send(message) != CcxShareStatus::Ok { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] can't send message"); + return CcxShareStatus::Fail; + } + } + + ccxr_sub_entries_cleanup(&mut entries); + CcxShareStatus::Ok +} + +pub fn ccxr_sub_entry_message_get_packed_size(message: &CcxSubEntryMessage) -> usize { + message.encoded_len() +} + +pub fn ccxr_sub_entry_message_pack(message: &CcxSubEntryMessage, buf: &mut Vec) -> Result<(), prost::EncodeError> { + message.encode(buf) +} + + + +pub unsafe fn _ccxr_share_send(msg: &CcxSubEntryMessage) -> CcxShareStatus { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send"); + + let len: usize = ccxr_sub_entry_message_get_packed_size(msg); + + // Allocate a buffer to hold the packed message. + let mut buf = Vec::with_capacity(len); + if buf.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: malloc failed"); + return CcxShareStatus::Fail; + } + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: packing"); + ccxr_sub_entry_message_pack(msg, &mut buf).expect( + "Failed to pack message", + ); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sending"); + let sent: c_int = nn_send( + CCX_SHARE_CTX.lock().unwrap().nn_sock, + buf.as_ptr() as *const c_void, + len, + 0, + ); + if sent != len as c_int { + buf.clear(); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: len={} sent={}", len, sent); + return CcxShareStatus::Fail; + } + buf.clear(); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sent"); + CcxShareStatus::Ok +} + +pub unsafe fn ccxr_share_stream_done(stream_name: &str) -> CcxShareStatus { + let mut msg = CcxSubEntryMessage { + eos: 1, + stream_name: stream_name.parse().unwrap(), + counter: 0, + start_time: 0, + end_time: 0, + lines: Vec::new(), + }; + #[allow(unused)] + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + if _ccxr_share_send(&msg) != CcxShareStatus::Ok { + ccxr_sub_entry_msg_cleanup(&mut msg); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: can't send message"); + return CcxShareStatus::Fail; + } + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: message sent successfully"); + CcxShareStatus::Ok +} + +pub fn ccxr_share_sub_to_entries(sub: &CcSubtitle, entries: &mut CcxSubEntries) -> CcxShareStatus { + unsafe { + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_sub_to_entries"); + + if sub.type_ == SUBTYPE_CC_608 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_608"); + + let data_ptr = sub.data as *const Eia608Screen; + let mut nb_data = sub.nb_data; + + while nb_data > 0 { + let data = &*data_ptr.add(sub.nb_data as usize - nb_data as usize); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] data item"); + + if data.format == CcxEia608Format::SFormatXds { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] XDS. Skipping"); + nb_data -= 1; + continue; + } + + if data.start_time == 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] No start time. Skipping"); + break; + } + + entries.messages.push(CcxSubEntryMessage { + eos: 0, + stream_name: String::new(), + counter: ctx.counter + 1, + start_time: data.start_time, + end_time: data.end_time, + lines: Vec::new(), + }); + + let entry_index = entries.messages.len() - 1; + let entry = &mut entries.messages[entry_index]; + + for row in 0..CCX_DECODER_608_SCREEN_ROWS { + if data.row_used[row] != 0 { + let characters = CStr::from_ptr(data.characters[row].as_ptr()) + .to_string_lossy() + .to_string(); + entry.lines.push(characters); + } + } + + if entry.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] buffer is empty"); + entries.messages.pop(); + return CcxShareStatus::Ok; + } + + debug!( + msg_type = DebugMessageFlag::SHARE; + "[share] Copied {} lines", entry.lines.len() + ); + + ctx.counter += 1; + nb_data -= 1; + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] item done"); + } + } else { + match sub.type_ { + SUBTYPE_CC_BITMAP => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_BITMAP. Skipping"); + } + SUBTYPE_CC_RAW => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_RAW. Skipping"); + } + SUBTYPE_CC_TEXT => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_TEXT. Skipping"); + } + _ => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] Unknown subtitle type"); + } + } + } + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] done"); + CcxShareStatus::Ok + } +} diff --git a/src/rust/lib_ccxr/src/share/tests.rs b/src/rust/lib_ccxr/src/share/tests.rs new file mode 100644 index 000000000..b9c2c712e --- /dev/null +++ b/src/rust/lib_ccxr/src/share/tests.rs @@ -0,0 +1,260 @@ +#![allow(unused_imports)] +#![allow(unused)] +use libc::c_char; +use crate::share::share::*; +use crate::share::ccxr_sub_entry_message::*; +use std::sync::Once; +use crate::util::log::{set_logger, CCExtractorLogger, DebugMessageFlag, DebugMessageMask, OutputTarget}; + +mod test { + use super::*; + + static INIT: Once = Once::new(); + + fn initialize_logger() { + INIT.call_once(|| { + set_logger(CCExtractorLogger::new( + OutputTarget::Stdout, + DebugMessageMask::new(DebugMessageFlag::VERBOSE, DebugMessageFlag::VERBOSE), + false, + )) + .ok(); + }); + } + #[test] + fn test_ffi_sub_entry_msg_cleanup() { + let mut msg = CcxSubEntryMessage { + eos: 0, + stream_name: "test".to_string(), + counter: 0, + start_time: 0, + end_time: 0, + lines: vec!["test".to_string()], + }; + + unsafe { + ccxr_sub_entry_msg_cleanup(&mut *(&mut msg as *mut CcxSubEntryMessage)); + } + + assert!(msg.lines.is_empty()); + assert_eq!(msg.stream_name, ""); + } + + #[test] + fn test_ffi_sub_entry_msg_print() { + let msg = CcxSubEntryMessage { + eos: 0, + stream_name: "test".to_string(), + counter: 0, + start_time: 0, + end_time: 0, + lines: vec![ + "test".to_string(), + "test".to_string(), + "test".to_string(), + ], + }; + + unsafe { + ccxr_sub_entry_msg_print(&*(&msg as *const CcxSubEntryMessage)); + } + } + #[test] + fn test_ffi_sub_entries_init() { + let mut entries = CcxSubEntries { + messages: vec![CcxSubEntryMessage { + eos: 0, + counter: 1, + stream_name: "Test".parse().unwrap(), + start_time: 0, + end_time: 0, + lines: vec![], + }], + }; + + unsafe { + ccxr_sub_entries_cleanup(&mut *(&mut entries as *mut CcxSubEntries)); + } + + assert!(entries.messages.is_empty()); + } + + #[test] + fn test_ffi_sub_entries_cleanup() { + let mut entries = CcxSubEntries { + messages: vec![CcxSubEntryMessage { + eos: 0, + counter: 1, + stream_name: "Test".parse().unwrap(), + start_time: 0, + end_time: 0, + lines: vec![], + }], + }; + + unsafe { + ccxr_sub_entries_cleanup(&mut *(&mut entries as *mut CcxSubEntries)); + } + + assert!(entries.messages.is_empty()); + } + + #[test] + fn test_ffi_sub_entries_print() { + let entries = CcxSubEntries { + messages: vec![CcxSubEntryMessage { + eos: 0, + counter: 1, + stream_name: "Test".parse().unwrap(), + start_time: 0, + end_time: 0, + lines: vec![], + }], + }; + + unsafe { + ccxr_sub_entries_print(&*(&entries as *const CcxSubEntries)); + } + } + + + #[test] + fn test_ccxr_share_send() { + initialize_logger(); + + let mut sub = CcSubtitle { + data: std::ptr::null_mut(), + datatype: 1, + nb_data: 0, + type_: 1, + enc_type: 1, + start_time: 0, + end_time: 0, + flags: 0, + lang_index: 0, + got_output: 0, + mode: [0; 5], + info: [0; 4], + time_out: 0, + next: std::ptr::null_mut(), + prev: std::ptr::null_mut(), + + }; + let status = unsafe { ccxr_share_send(&mut sub as *mut CcSubtitle) }; + assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); + } + + #[test] + fn test_ccxr_share_send_c() { + initialize_logger(); + let msg = CcxSubEntryMessage { + eos: 0, + stream_name: "test_stream".to_string(), + counter: 1, + start_time: 0, + end_time: 0, + lines: vec!["Line 1".to_string(), "Line 2".to_string()], + }; + + let status = unsafe { _ccxr_share_send(&*(&msg as *const CcxSubEntryMessage)) }; + assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); + } + + + const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; + const CCX_DECODER_608_SCREEN_ROWS: usize = 15; + + #[test] + fn test_ccxr_share_sub_to_entries() { + initialize_logger(); + const NUM_ROWS: usize = CCX_DECODER_608_SCREEN_ROWS; + let mut screen = Eia608Screen::new(); + screen.row_used[0] = 1; + screen.row_used[2] = 1; + screen.row_used[4] = 1; + + let row_0_content = b"Hello, World!"; + let row_2_content = b"Subtitle line 2"; + let row_4_content = b"Subtitle line 3"; + + for (i, &ch) in row_0_content.iter().enumerate() { + screen.characters[0][i] = ch as c_char; + } + for (i, &ch) in row_2_content.iter().enumerate() { + screen.characters[2][i] = ch as c_char; + } + for (i, &ch) in row_4_content.iter().enumerate() { + screen.characters[4][i] = ch as c_char; + } + + screen.start_time = 1000; + screen.end_time = 2000; + screen.mode = CcModes::ModePaintOn; + screen.channel = 1; + screen.my_field = 42; + + let sub = CcSubtitle { + data: &screen as *const _ as *mut std::os::raw::c_void, + datatype: 1, + nb_data: 1, + type_: SUBTYPE_CC_608, + enc_type: 1, + start_time: 0, + end_time: 0, + flags: 0, + lang_index: 0, + got_output: 1, + mode: [b'M' as c_char, b'O' as c_char, b'D' as c_char, b'E' as c_char, 0], + info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], + time_out: 0, + next: std::ptr::null_mut(), + prev: std::ptr::null_mut(), + }; + let mut entries = CcxSubEntries { messages: Vec::new() }; + let status = ccxr_share_sub_to_entries(&sub, &mut entries); + assert_eq!(status, CcxShareStatus::Ok, "Function should return OK status"); + assert_eq!(entries.messages.len(), 1, "There should be one entry in messages"); + + let message = &entries.messages[0]; + assert_eq!(message.start_time, 1000, "Start time should match input"); + assert_eq!(message.end_time, 2000, "End time should match input"); + assert_eq!(message.lines.len(), 3, "There should be 3 lines of content"); + + assert_eq!(message.lines[0], "Hello, World!", "First line content mismatch"); + assert_eq!(message.lines[1], "Subtitle line 2", "Second line content mismatch"); + assert_eq!(message.lines[2], "Subtitle line 3", "Third line content mismatch"); + } + + #[test] + fn test_ccxr_share_sub_to_entries_empty_rows() { + let mut screen = Eia608Screen::new(); + + screen.start_time = 1000; + screen.end_time = 2000; + + let sub = CcSubtitle { + data: &screen as *const _ as *mut std::os::raw::c_void, + datatype: 1, + nb_data: 1, + type_: SUBTYPE_CC_608, + enc_type: 1, + start_time: 0, + end_time: 0, + flags: 0, + lang_index: 0, + got_output: 1, + mode: [b'M' as c_char, b'O' as c_char, b'D' as c_char, b'E' as c_char, 0], + info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], + time_out: 0, + next: std::ptr::null_mut(), + prev: std::ptr::null_mut(), + }; + + let mut entries = CcxSubEntries { messages: Vec::new() }; + + let status = ccxr_share_sub_to_entries(&sub, &mut entries); + + assert_eq!(status, CcxShareStatus::Ok, "Function should return OK status"); + assert_eq!(entries.messages.len(), 0, "There should be no messages for empty rows"); + } +} diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index ca65bb36f..d658a24e0 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -3,6 +3,8 @@ pub mod bitstream; pub mod time; +#[cfg(feature = "enable_sharing")] +pub mod share; use crate::ccx_options; use lib_ccxr::util::log::*; use lib_ccxr::util::{bits::*, levenshtein::*}; diff --git a/src/rust/src/libccxr_exports/share.rs b/src/rust/src/libccxr_exports/share.rs new file mode 100644 index 000000000..50136f509 --- /dev/null +++ b/src/rust/src/libccxr_exports/share.rs @@ -0,0 +1,115 @@ +use lib_ccxr::share::ccxr_sub_entry_message::*; +use lib_ccxr::share::share::*; +use lib_ccxr::util::log::{debug, DebugMessageFlag}; +use std::ffi::CStr; +/// C-compatible function to clean up a `CcxSubEntryMessage`. +#[no_mangle] +pub extern "C" fn ccxr_sub_entry_msg_cleanup_c(msg: *mut CcxSubEntryMessage) { + unsafe { + if msg.is_null() { + return; + } + let msg = &mut *msg; + ccxr_sub_entry_msg_cleanup(msg); + } +} + +/// C-compatible function to print a `CcxSubEntryMessage`. +#[no_mangle] +pub unsafe extern "C" fn ccxr_sub_entry_msg_print_c(msg: *const CcxSubEntryMessage) { + if msg.is_null() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] print(!msg)\n"); + return; + } + + let msg = &*msg; + + // Call the main Rust function + ccxr_sub_entry_msg_print(msg); +} + + +#[no_mangle] +pub unsafe extern "C" fn ccxr_sub_entries_cleanup_c(entries: *mut CcxSubEntries) { + if entries.is_null() { + return; + } + let entries = &mut *entries; + ccxr_sub_entries_cleanup(entries); +} + +#[no_mangle] +pub unsafe extern "C" fn ccxr_sub_entries_print_c(entries: *const CcxSubEntries) { + if entries.is_null() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccxr_sub_entries_print (null entries)\n"); + return; + } + let entries = &*entries; + ccxr_sub_entries_print(entries); +} + +/// C-compatible function to start the sharing service. +#[no_mangle] +pub unsafe extern "C" fn ccxr_share_start_c(stream_name: *const libc::c_char) -> CcxShareStatus { + if stream_name.is_null() { + return ccxr_share_start(Option::from("unknown")); + } + + let c_str = CStr::from_ptr(stream_name); + let stream_name = match c_str.to_str() { + Ok(name) => name, + Err(_) => return CcxShareStatus::Fail, + }; + + ccxr_share_start(Option::from(stream_name)) +} +#[no_mangle] +pub unsafe extern "C" fn ccxr_share_stop_c() -> CcxShareStatus { + ccxr_share_stop() +} + +#[no_mangle] +pub unsafe extern "C" fn _ccxr_share_send_c(msg: *const CcxSubEntryMessage) -> CcxShareStatus { + if msg.is_null() { + return CcxShareStatus::Fail; + } + _ccxr_share_send(&*msg) +} + +#[no_mangle] +pub unsafe extern "C" fn ccxr_share_send_c(sub: *const CcSubtitle) -> CcxShareStatus { + if sub.is_null() { + return CcxShareStatus::Fail; + } + ccxr_share_send(sub as *mut CcSubtitle) +} + +#[no_mangle] +pub unsafe extern "C" fn ccxr_share_stream_done_c(stream_name: *const libc::c_char) -> CcxShareStatus { + if stream_name.is_null() { + return CcxShareStatus::Fail; + } + + let c_str = CStr::from_ptr(stream_name); + match c_str.to_str() { + Ok(name) => ccxr_share_stream_done(name), + Err(_) => CcxShareStatus::Fail, + } +} + +/// C-compatible function to convert subtitles to sub-entry messages. +#[no_mangle] +pub unsafe extern "C" fn _ccxr_share_sub_to_entries_c( + sub: *const CcSubtitle, + entries: *mut CcxSubEntries, +) -> CcxShareStatus { + if sub.is_null() || entries.is_null() { + return CcxShareStatus::Fail; + } + + // Dereference the pointers safely + let sub_ref = &*sub; + let entries_ref = &mut *entries; + + ccxr_share_sub_to_entries(sub_ref, entries_ref) +} From da6b1e51b29e5683aacd460b29c37745392e5f2e Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 20 Apr 2025 13:18:42 +0530 Subject: [PATCH 02/13] feat: Share Module - squash commits --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_mac.yml | 2 +- docs/CHANGES.TXT | 1 + linux/Makefile.am | 2 +- mac/Makefile.am | 2 +- src/rust/Cargo.lock | 8 +- src/rust/Cargo.toml | 1 + src/rust/lib_ccxr/Cargo.lock | 1 - src/rust/lib_ccxr/Cargo.toml | 16 +- src/rust/lib_ccxr/src/lib.rs | 4 +- src/rust/lib_ccxr/src/share/functions.rs | 536 +++++++++++++++++++++++ src/rust/lib_ccxr/src/share/mod.rs | 4 +- src/rust/lib_ccxr/src/share/share.rs | 516 ---------------------- src/rust/lib_ccxr/src/share/tests.rs | 88 ++-- src/rust/src/libccxr_exports/mod.rs | 3 + src/rust/src/libccxr_exports/share.rs | 11 +- 16 files changed, 628 insertions(+), 569 deletions(-) create mode 100644 src/rust/lib_ccxr/src/share/functions.rs delete mode 100644 src/rust/lib_ccxr/src/share/share.rs diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index cd3349ecb..153ca43d4 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install dependencies - run: sudo apt update && sudo apt-get install libgpac-dev + run: sudo apt update && sudo apt-get install libgpac-dev libnanomsg-dev - uses: actions/checkout@v4 - name: run autogen run: ./autogen.sh diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index c81af5327..7dfebd82a 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -47,7 +47,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install dependencies - run: brew install pkg-config autoconf automake libtool gpac + run: brew install pkg-config autoconf automake libtool gpac nanomsg - name: run autogen run: ./autogen.sh working-directory: ./mac diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 8b3576635..d5b2d04f3 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1297,3 +1297,4 @@ version of CCExtractor. - Added video information (as extracted from sequence header). - Some code clean-up. - FF sanity check enabled by default. +- Added Share Module to lib_ccxr \ No newline at end of file diff --git a/linux/Makefile.am b/linux/Makefile.am index 0b8c167fc..7491c1f7d 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -334,7 +334,7 @@ ccextractor_LDADD += $(LEPT_LIB) endif if WITH_RUST -ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a +ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a -lnanomsg else ccextractor_CFLAGS += -DDISABLE_RUST ccextractor_CPPFLAGS += -DDISABLE_RUST diff --git a/mac/Makefile.am b/mac/Makefile.am index 9870c07bf..13f0a039e 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -244,7 +244,7 @@ endif ccextractor_CFLAGS = -std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP -ccextractor_LDFLAGS = $(shell pkg-config --libs gpac) +ccextractor_LDFLAGS = $(shell pkg-config --libs gpac nanomsg) GPAC_CPPFLAGS = $(shell pkg-config --cflags gpac) ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty/protobuf-c/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 6c061b946..9594b709b 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -182,7 +182,6 @@ dependencies = [ "env_logger", "leptonica-sys", "lib_ccxr", - "libc", "log", "num-integer", "palette", @@ -641,7 +640,6 @@ dependencies = [ "crc32fast", "derive_more", "lazy_static", - "libc", "nanomsg-sys", "num_enum", "prost", @@ -654,9 +652,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.172" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libloading" @@ -1510,4 +1508,4 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.99", -] +] \ No newline at end of file diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 87f784528..05804864b 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -30,6 +30,7 @@ url = "2.5.4" encoding_rs = "0.8.5" libc = "0.2.172" + [build-dependencies] bindgen = "0.64.0" pkg-config = "0.3.32" diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock index 7b0338bae..fa7a432fa 100644 --- a/src/rust/lib_ccxr/Cargo.lock +++ b/src/rust/lib_ccxr/Cargo.lock @@ -309,7 +309,6 @@ dependencies = [ "crc32fast", "derive_more", "lazy_static", - "libc", "nanomsg-sys", "num_enum", "prost", diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index 7d0bcb141..dae77c866 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -17,18 +17,16 @@ crc32fast = "1.4.2" num_enum = "0.6.1" prost = "0.13.5" lazy_static = "1.5.0" -nanomsg-sys = "0.7.2" -libc = "0.2.172" - +nanomsg-sys = { version = "0.7.2", optional = true, default-features = false, features = ["bundled"] } [features] default = [ - "enable_sharing", - "wtv_debug", - "enable_ffmpeg", - "debug", - "with_libcurl", + "enable_sharing", + "wtv_debug", + "enable_ffmpeg", + "debug", + "with_libcurl", ] -enable_sharing = [] +enable_sharing = ["nanomsg-sys"] wtv_debug = [] enable_ffmpeg = [] debug_out = [] diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs index 09470a1d5..205b670f2 100644 --- a/src/rust/lib_ccxr/src/lib.rs +++ b/src/rust/lib_ccxr/src/lib.rs @@ -2,9 +2,9 @@ pub mod activity; pub mod common; pub mod encoder; pub mod hardsubx; +#[cfg(feature = "enable_sharing")] +pub mod share; pub mod subtitle; pub mod teletext; pub mod time; pub mod util; -#[cfg(feature = "enable_sharing")] -pub mod share; \ No newline at end of file diff --git a/src/rust/lib_ccxr/src/share/functions.rs b/src/rust/lib_ccxr/src/share/functions.rs new file mode 100644 index 000000000..8329f5990 --- /dev/null +++ b/src/rust/lib_ccxr/src/share/functions.rs @@ -0,0 +1,536 @@ +#[cfg(feature = "enable_sharing")] +pub mod sharing { + use crate::common::Options; + use crate::share::ccxr_sub_entry_message::CcxSubEntryMessage; + use crate::util::log::{debug, DebugMessageFlag}; + use lazy_static::lazy_static; + use nanomsg_sys::{ + nn_bind, nn_send, nn_setsockopt, nn_shutdown, nn_socket, AF_SP, NN_LINGER, NN_PUB, + NN_SOL_SOCKET, + }; + use prost::Message; + use std::cmp::PartialEq; + use std::ffi::c_void; + use std::os::raw::{c_char, c_int}; + use std::sync::{LazyLock, Mutex}; + use std::{ + ffi::{CStr, CString}, + thread, + time::Duration, + }; + + pub const CCX_DECODER_608_SCREEN_ROWS: usize = 15; + pub const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; + pub static CCX_OPTIONS: LazyLock> = + LazyLock::new(|| Mutex::new(Options::default())); + + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum CcxEia608Format { + SFormatCcScreen = 0, + SFormatCcLine = 1, + SFormatXds = 2, + } + + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum CcModes { + ModePopOn = 0, + ModeRollUp2 = 1, + ModeRollUp3 = 2, + ModeRollUp4 = 3, + ModeText = 4, + ModePaintOn = 5, + ModeFakeRollUp1 = 100, + } + + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum CcxDecoder608ColorCode { + White = 0, + Green = 1, + Blue = 2, + Cyan = 3, + Red = 4, + Yellow = 5, + Magenta = 6, + UserDefined = 7, + Black = 8, + Transparent = 9, + Max = 10, + } + + #[repr(C)] + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub enum FontBits { + Normal = 0, + Italics = 1, + Underline = 2, + UnderlineItalics = 3, + } + + #[repr(C)] + #[derive(Debug, Clone)] + pub struct Eia608Screen { + pub format: CcxEia608Format, + pub characters: [[c_char; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + pub colors: [[CcxDecoder608ColorCode; CCX_DECODER_608_SCREEN_WIDTH + 1]; + CCX_DECODER_608_SCREEN_ROWS], + pub fonts: [[FontBits; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + pub row_used: [c_int; CCX_DECODER_608_SCREEN_ROWS], + pub empty: c_int, + pub start_time: i64, + pub end_time: i64, + pub mode: CcModes, + pub channel: c_int, + pub my_field: c_int, + pub xds_str: *mut c_char, + pub xds_len: usize, + pub cur_xds_packet_class: c_int, + } + + impl Default for Eia608Screen { + fn default() -> Self { + Self { + format: CcxEia608Format::SFormatCcScreen, + characters: [[0; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], + colors: [[CcxDecoder608ColorCode::Black; CCX_DECODER_608_SCREEN_WIDTH + 1]; + CCX_DECODER_608_SCREEN_ROWS], + fonts: [[FontBits::Normal; CCX_DECODER_608_SCREEN_WIDTH + 1]; + CCX_DECODER_608_SCREEN_ROWS], + row_used: [0; CCX_DECODER_608_SCREEN_ROWS], + empty: 1, + start_time: 0, + end_time: 0, + mode: CcModes::ModePopOn, + channel: 0, + my_field: 0, + xds_str: std::ptr::null_mut(), + xds_len: 0, + cur_xds_packet_class: 0, + } + } + } + + impl Eia608Screen { + pub fn new() -> Self { + Self::default() + } + + pub fn set_xds_str(&mut self, xds: &str) { + let c_string = CString::new(xds).expect("CString::new failed"); + self.xds_str = c_string.into_raw(); + self.xds_len = xds.len(); + } + + pub fn free_xds_str(&mut self) { + if !self.xds_str.is_null() { + unsafe { + let _ = CString::from_raw(self.xds_str); + } + self.xds_str = std::ptr::null_mut(); + self.xds_len = 0; + } + } + } + + impl Drop for Eia608Screen { + fn drop(&mut self) { + self.free_xds_str(); + } + } + + pub type SubDataType = std::os::raw::c_uint; + pub type LLONG = i64; + pub const SUBTYPE_CC_BITMAP: Subtype = 0; + pub const SUBTYPE_CC_608: Subtype = 1; + pub const SUBTYPE_CC_TEXT: Subtype = 2; + pub const SUBTYPE_CC_RAW: Subtype = 3; + pub type Subtype = std::os::raw::c_uint; + + pub type CcxEncodingType = std::os::raw::c_uint; + + pub struct CcSubtitle { + #[doc = " A generic data which contain data according to decoder\n @warn decoder cant output multiple types of data"] + pub data: *mut std::os::raw::c_void, + pub datatype: SubDataType, + #[doc = " number of data"] + pub nb_data: std::os::raw::c_uint, + #[doc = " type of subtitle"] + pub type_: Subtype, + #[doc = " Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen"] + pub enc_type: CcxEncodingType, + pub start_time: LLONG, + pub end_time: LLONG, + pub flags: c_int, + pub lang_index: c_int, + #[doc = " flag to tell that decoder has given output"] + pub got_output: c_int, + pub mode: [c_char; 5usize], + pub info: [c_char; 4usize], + #[doc = " Used for DVB end time in ms"] + pub time_out: c_int, + pub next: *mut CcSubtitle, + pub prev: *mut CcSubtitle, + } + + #[repr(C)] + #[derive(Debug)] + pub enum CcxShareStatus { + Ok = 0, + Fail, + } + impl PartialEq for CcxShareStatus { + fn eq(&self, other: &Self) -> bool { + matches!( + (self, other), + (CcxShareStatus::Ok, CcxShareStatus::Ok) + | (CcxShareStatus::Fail, CcxShareStatus::Fail) + ) + } + } + pub struct CcxShareServiceCtx { + counter: i64, + stream_name: Option, + nn_sock: c_int, + nn_binder: c_int, + } + + pub struct CcxSubEntries { + pub messages: Vec, + } + impl CcxShareServiceCtx { + fn new() -> Self { + CcxShareServiceCtx { + counter: 0, + stream_name: None, + nn_sock: 0, + nn_binder: 0, + } + } + } + + lazy_static! { + pub static ref CCX_SHARE_CTX: Mutex = + Mutex::new(CcxShareServiceCtx::new()); + } + + pub fn ccxr_sub_entry_msg_init(msg: &mut CcxSubEntryMessage) { + msg.eos = 0; + msg.stream_name = "".parse().unwrap(); + msg.counter = 0; + msg.start_time = 0; + msg.end_time = 0; + msg.lines.clear(); + } + + pub fn ccxr_sub_entry_msg_cleanup(msg: &mut CcxSubEntryMessage) { + msg.lines.clear(); + msg.stream_name = "".parse().unwrap(); + } + + pub fn ccxr_sub_entry_msg_print(msg: &CcxSubEntryMessage) { + if msg.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); + return; + } + + debug!(msg_type = DebugMessageFlag::SHARE; "\n[share] sub msg #{}", msg.counter); + if !msg.stream_name.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: {}", msg.stream_name); + } else { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: None"); + } + debug!(msg_type = DebugMessageFlag::SHARE; "[share] start: {}", msg.start_time); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] end: {}", msg.end_time); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] lines count: {}", msg.lines.len()); + + if msg.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); + return; + } + for (i, line) in msg.lines.iter().enumerate() { + if !line.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}]: {}", i, line); + } else { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}] is not allocated", i); + } + } + } + + pub fn ccxr_sub_entries_cleanup(entries: &mut CcxSubEntries) { + entries.messages.clear(); + } + + pub fn ccxr_sub_entries_print(entries: &CcxSubEntries) { + eprintln!( + "[share] ccxr_sub_entries_print ({} entries)", + entries.messages.len() + ); + for message in &entries.messages { + ccxr_sub_entry_msg_print(message); + } + } + /// # Safety + /// This function is unsafe as it calls unsafe functions like nn_socket and nn_bind. + pub unsafe fn ccxr_share_start(stream_name: Option<&str>) -> CcxShareStatus { + let mut ccx_options = CCX_OPTIONS.lock().unwrap(); + + // Debug print similar to dbg_print in C + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: starting service\n"); + + // Create a nanomsg socket with domain AF_SP and protocol NN_PUB + let nn_sock = nn_socket(AF_SP, NN_PUB); + if nn_sock < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_socket()\n"); + return CcxShareStatus::Fail; + } + CCX_SHARE_CTX.lock().unwrap().nn_sock = nn_sock; + // Set a default URL if one was not already provided. + if ccx_options.sharing_url.is_none() { + ccx_options.sharing_url = Some("tcp://*:3269".to_string().parse().unwrap()); + } + + // Convert the sharing URL into a C-compatible string. + let url = ccx_options.sharing_url.as_ref().unwrap(); + let sharing_url_cstr = CString::new(url.as_str()).expect("Failed to create CString"); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: url={}", ccx_options.sharing_url.as_mut().unwrap()); + + // Bind the socket to the URL. + let nn_binder = nn_bind(nn_sock, sharing_url_cstr.as_ptr()); + if nn_binder < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_bind()"); + return CcxShareStatus::Fail; + } + CCX_SHARE_CTX.lock().unwrap().nn_binder = nn_binder; + + // Set the linger socket option to -1. + let linger: i32 = -1; + let ret = nn_setsockopt( + nn_sock, + NN_SOL_SOCKET, + NN_LINGER, + &linger as *const _ as *const c_void, + size_of::(), + ); + if ret < 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_setsockopt()"); + return CcxShareStatus::Fail; + } + + // Save the stream name into the context, defaulting to "unknown" if not provided. + CCX_SHARE_CTX.lock().unwrap().stream_name = + Some(stream_name.unwrap_or("unknown").to_string()); + + // Sleep for 1 second to allow subscribers to connect. + thread::sleep(Duration::from_secs(1)); + + CcxShareStatus::Ok + } + /// # Safety + /// This function is unsafe as it calls unsafe functions like nn_shutdown. + pub unsafe fn ccxr_share_stop() -> CcxShareStatus { + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stop: stopping service"); + + nn_shutdown( + CCX_SHARE_CTX.lock().unwrap().nn_sock, + CCX_SHARE_CTX.lock().unwrap().nn_binder, + ); + ctx.stream_name = None; + CcxShareStatus::Ok + } + /// # Safety + /// This function is unsafe as it calls unsafe functions like _ccxr_share_send. + pub unsafe fn ccxr_share_send(sub: *mut CcSubtitle) -> CcxShareStatus { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending"); + + // Create an entries structure and populate it from the subtitle. + let mut entries = CcxSubEntries { + messages: Vec::new(), + }; + if ccxr_share_sub_to_entries(&*sub, &mut entries) == CcxShareStatus::Fail { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] failed to convert subtitle to entries"); + return CcxShareStatus::Fail; + } + + // Debug print of entries. + ccxr_sub_entries_print(&entries); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] entry obtained:"); + + // Iterate over all entries and send them. + for (i, message) in entries.messages.iter().enumerate() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending entry {}", i); + if entries.messages[i].lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] skipping empty message"); + continue; + } + if _ccxr_share_send(message) != CcxShareStatus::Ok { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] can't send message"); + return CcxShareStatus::Fail; + } + } + + ccxr_sub_entries_cleanup(&mut entries); + CcxShareStatus::Ok + } + + pub fn ccxr_sub_entry_message_get_packed_size(message: &CcxSubEntryMessage) -> usize { + message.encoded_len() + } + + pub fn ccxr_sub_entry_message_pack( + message: &CcxSubEntryMessage, + buf: &mut Vec, + ) -> Result<(), prost::EncodeError> { + message.encode(buf) + } + + /// # Safety + /// This function is unsafe as it calls unsafe functions like nn_send + pub unsafe fn _ccxr_share_send(msg: &CcxSubEntryMessage) -> CcxShareStatus { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send"); + + let len: usize = ccxr_sub_entry_message_get_packed_size(msg); + + // Allocate a buffer to hold the packed message. + let mut buf = Vec::with_capacity(len); + if buf.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: malloc failed"); + return CcxShareStatus::Fail; + } + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: packing"); + ccxr_sub_entry_message_pack(msg, &mut buf).expect("Failed to pack message"); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sending"); + let sent: c_int = nn_send( + CCX_SHARE_CTX.lock().unwrap().nn_sock, + buf.as_ptr() as *const c_void, + len, + 0, + ); + if sent != len as c_int { + buf.clear(); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: len={} sent={}", len, sent); + return CcxShareStatus::Fail; + } + buf.clear(); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sent"); + CcxShareStatus::Ok + } + + /// # Safety + /// This function is unsafe as it calls unsafe functions like _ccxr_share_send + pub unsafe fn ccxr_share_stream_done(stream_name: &str) -> CcxShareStatus { + let mut msg = CcxSubEntryMessage { + eos: 1, + stream_name: stream_name.parse().unwrap(), + counter: 0, + start_time: 0, + end_time: 0, + lines: Vec::new(), + }; + #[allow(unused)] + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + if _ccxr_share_send(&msg) != CcxShareStatus::Ok { + ccxr_sub_entry_msg_cleanup(&mut msg); + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: can't send message"); + return CcxShareStatus::Fail; + } + debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: message sent successfully"); + CcxShareStatus::Ok + } + + pub fn ccxr_share_sub_to_entries( + sub: &CcSubtitle, + entries: &mut CcxSubEntries, + ) -> CcxShareStatus { + unsafe { + let mut ctx = CCX_SHARE_CTX.lock().unwrap(); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_sub_to_entries"); + + if sub.type_ == SUBTYPE_CC_608 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_608"); + + let data_ptr = sub.data as *const Eia608Screen; + let mut nb_data = sub.nb_data; + + while nb_data > 0 { + let data = &*data_ptr.add(sub.nb_data as usize - nb_data as usize); + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] data item"); + + if data.format == CcxEia608Format::SFormatXds { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] XDS. Skipping"); + nb_data -= 1; + continue; + } + + if data.start_time == 0 { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] No start time. Skipping"); + break; + } + + entries.messages.push(CcxSubEntryMessage { + eos: 0, + stream_name: String::new(), + counter: ctx.counter + 1, + start_time: data.start_time, + end_time: data.end_time, + lines: Vec::new(), + }); + + let entry_index = entries.messages.len() - 1; + let entry = &mut entries.messages[entry_index]; + + for row in 0..CCX_DECODER_608_SCREEN_ROWS { + if data.row_used[row] != 0 { + let characters = CStr::from_ptr(data.characters[row].as_ptr()) + .to_string_lossy() + .to_string(); + entry.lines.push(characters); + } + } + + if entry.lines.is_empty() { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] buffer is empty"); + entries.messages.pop(); + return CcxShareStatus::Ok; + } + + debug!( + msg_type = DebugMessageFlag::SHARE; + "[share] Copied {} lines", entry.lines.len() + ); + + ctx.counter += 1; + nb_data -= 1; + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] item done"); + } + } else { + match sub.type_ { + SUBTYPE_CC_BITMAP => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_BITMAP. Skipping"); + } + SUBTYPE_CC_RAW => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_RAW. Skipping"); + } + SUBTYPE_CC_TEXT => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_TEXT. Skipping"); + } + _ => { + debug!(msg_type = DebugMessageFlag::SHARE; "[share] Unknown subtitle type"); + } + } + } + + debug!(msg_type = DebugMessageFlag::SHARE; "[share] done"); + CcxShareStatus::Ok + } + } +} diff --git a/src/rust/lib_ccxr/src/share/mod.rs b/src/rust/lib_ccxr/src/share/mod.rs index 8938af992..d981ff34c 100644 --- a/src/rust/lib_ccxr/src/share/mod.rs +++ b/src/rust/lib_ccxr/src/share/mod.rs @@ -1,3 +1,3 @@ -pub mod share; pub mod ccxr_sub_entry_message; -mod tests; +pub mod functions; +pub mod tests; diff --git a/src/rust/lib_ccxr/src/share/share.rs b/src/rust/lib_ccxr/src/share/share.rs deleted file mode 100644 index 31c4138fa..000000000 --- a/src/rust/lib_ccxr/src/share/share.rs +++ /dev/null @@ -1,516 +0,0 @@ -use crate::common::Options; -use crate::share::ccxr_sub_entry_message::CcxSubEntryMessage; -use crate::util::log::{debug, DebugMessageFlag}; -use lazy_static::lazy_static; -use libc::size_t; -use nanomsg_sys::{nn_bind, nn_send, nn_setsockopt, nn_shutdown, nn_socket, AF_SP, NN_LINGER, NN_PUB, NN_SOL_SOCKET}; -use prost::Message; -use std::cmp::PartialEq; -use std::ffi::c_void; -use std::os::raw::{c_char, c_int}; -use std::sync::{LazyLock, Mutex}; -use std::{ffi::{CStr, CString}, thread, time::Duration}; -// use crate::bindings::{cc_subtitle, ccx_output_format}; - -pub const CCX_DECODER_608_SCREEN_ROWS: usize = 15; -pub const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; -pub static CCX_OPTIONS: LazyLock> = LazyLock::new(|| Mutex::new(Options::default())); - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum CcxEia608Format { - SFormatCcScreen = 0, - SFormatCcLine = 1, - SFormatXds = 2, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum CcModes { - ModePopOn = 0, - ModeRollUp2 = 1, - ModeRollUp3 = 2, - ModeRollUp4 = 3, - ModeText = 4, - ModePaintOn = 5, - ModeFakeRollUp1 = 100, -} - - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum CcxDecoder608ColorCode { - White = 0, - Green = 1, - Blue = 2, - Cyan = 3, - Red = 4, - Yellow = 5, - Magenta = 6, - UserDefined = 7, - Black = 8, - Transparent = 9, - Max = 10, -} - -#[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum FontBits { - Normal = 0, - Italics = 1, - Underline = 2, - UnderlineItalics = 3, -} - - -#[repr(C)] -#[derive(Debug, Clone)] -pub struct Eia608Screen { - pub format: CcxEia608Format, - pub characters: [[c_char; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - pub colors: [[CcxDecoder608ColorCode; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - pub fonts: [[FontBits; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - pub row_used: [c_int; CCX_DECODER_608_SCREEN_ROWS], - pub empty: c_int, - pub start_time: i64, - pub end_time: i64, - pub mode: CcModes, - pub channel: c_int, - pub my_field: c_int, - pub xds_str: *mut c_char, - pub xds_len: usize, - pub cur_xds_packet_class: c_int, -} - -impl Default for Eia608Screen { - fn default() -> Self { - Self { - format: CcxEia608Format::SFormatCcScreen, - characters: [[0; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - colors: [[CcxDecoder608ColorCode::Black; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - fonts: [[FontBits::Normal; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - row_used: [0; CCX_DECODER_608_SCREEN_ROWS], - empty: 1, - start_time: 0, - end_time: 0, - mode: CcModes::ModePopOn, - channel: 0, - my_field: 0, - xds_str: std::ptr::null_mut(), - xds_len: 0, - cur_xds_packet_class: 0, - } - } -} - -impl Eia608Screen { - pub fn new() -> Self { - Self::default() - } - - pub fn set_xds_str(&mut self, xds: &str) { - let c_string = CString::new(xds).expect("CString::new failed"); - self.xds_str = c_string.into_raw(); - self.xds_len = xds.len(); - } - - pub fn free_xds_str(&mut self) { - if !self.xds_str.is_null() { - unsafe { - let _ = CString::from_raw(self.xds_str); - } - self.xds_str = std::ptr::null_mut(); - self.xds_len = 0; - } - } -} - -impl Drop for Eia608Screen { - fn drop(&mut self) { - self.free_xds_str(); - } -} - - -pub type SubDataType = std::os::raw::c_uint; -pub type LLONG = i64; -pub const SUBTYPE_CC_BITMAP: Subtype = 0; -pub const SUBTYPE_CC_608: Subtype = 1; -pub const SUBTYPE_CC_TEXT: Subtype = 2; -pub const SUBTYPE_CC_RAW: Subtype = 3; -pub type Subtype = std::os::raw::c_uint; - -pub type CcxEncodingType = std::os::raw::c_uint; - -pub struct CcSubtitle { - #[doc = " A generic data which contain data according to decoder\n @warn decoder cant output multiple types of data"] - pub data: *mut std::os::raw::c_void, - pub datatype: SubDataType, - #[doc = " number of data"] - pub nb_data: std::os::raw::c_uint, - #[doc = " type of subtitle"] - pub type_: Subtype, - #[doc = " Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen"] - pub enc_type: CcxEncodingType, - pub start_time: LLONG, - pub end_time: LLONG, - pub flags: c_int, - pub lang_index: c_int, - #[doc = " flag to tell that decoder has given output"] - pub got_output: c_int, - pub mode: [c_char; 5usize], - pub info: [c_char; 4usize], - #[doc = " Used for DVB end time in ms"] - pub time_out: c_int, - pub next: *mut CcSubtitle, - pub prev: *mut CcSubtitle, -} - -#[repr(C)] -#[derive(Debug)] -pub enum CcxShareStatus { - Ok = 0, - Fail, -} -impl PartialEq for CcxShareStatus { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (CcxShareStatus::Ok, CcxShareStatus::Ok) => true, - (CcxShareStatus::Fail, CcxShareStatus::Fail) => true, - _ => false, - } - } -} -pub struct CcxShareServiceCtx { - counter: i64, - stream_name: Option, - nn_sock: libc::c_int, - nn_binder: libc::c_int, -} - -pub struct CcxSubEntries { - pub messages: Vec, -} -impl CcxShareServiceCtx { - fn new() -> Self { - CcxShareServiceCtx { - counter: 0, - stream_name: None, - nn_sock: 0, - nn_binder: 0, - } - } -} - - -lazy_static! { - pub static ref CCX_SHARE_CTX: Mutex = Mutex::new(CcxShareServiceCtx::new()); -} - - - -pub fn ccxr_sub_entry_msg_init(msg: &mut CcxSubEntryMessage) { - msg.eos = 0; - msg.stream_name = "".parse().unwrap(); - msg.counter = 0; - msg.start_time = 0; - msg.end_time = 0; - msg.lines.clear(); -} - - -pub fn ccxr_sub_entry_msg_cleanup(msg: &mut CcxSubEntryMessage) { - msg.lines.clear(); - msg.stream_name = "".parse().unwrap(); -} - -pub fn ccxr_sub_entry_msg_print(msg: &CcxSubEntryMessage) { - if msg.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); - return; - } - - debug!(msg_type = DebugMessageFlag::SHARE; "\n[share] sub msg #{}", msg.counter); - if !msg.stream_name.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: {}", msg.stream_name); - } else { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: None"); - } - debug!(msg_type = DebugMessageFlag::SHARE; "[share] start: {}", msg.start_time); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] end: {}", msg.end_time); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] lines count: {}", msg.lines.len()); - - if msg.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); - return; - } - for (i, line) in msg.lines.iter().enumerate() { - if !line.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}]: {}", i, line); - } else { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}] is not allocated", i); - } - } -} - - -pub fn ccxr_sub_entries_cleanup(entries: &mut CcxSubEntries) { - entries.messages.clear(); -} - -pub fn ccxr_sub_entries_print(entries: &CcxSubEntries) { - eprintln!("[share] ccxr_sub_entries_print ({} entries)", entries.messages.len()); - for message in &entries.messages { - ccxr_sub_entry_msg_print(message); - } -} - -pub unsafe fn ccxr_share_start(stream_name: Option<&str>) -> CcxShareStatus { - let mut ccx_options = CCX_OPTIONS.lock().unwrap(); - - // Debug print similar to dbg_print in C - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: starting service\n"); - - // Create a nanomsg socket with domain AF_SP and protocol NN_PUB - let nn_sock = nn_socket(AF_SP, NN_PUB); - if nn_sock < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_socket()\n"); - return CcxShareStatus::Fail; - } - CCX_SHARE_CTX.lock().unwrap().nn_sock = nn_sock; - // Set a default URL if one was not already provided. - if ccx_options.sharing_url.is_none() { - ccx_options.sharing_url = Some("tcp://*:3269".to_string().parse().unwrap()); - } - - // Convert the sharing URL into a C-compatible string. - let url = ccx_options.sharing_url.as_ref().unwrap(); - let sharing_url_cstr = CString::new(url.as_str()).expect("Failed to create CString"); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: url={}", ccx_options.sharing_url.as_mut().unwrap()); - - // Bind the socket to the URL. - let nn_binder = nn_bind(nn_sock, sharing_url_cstr.as_ptr()); - if nn_binder < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_bind()"); - return CcxShareStatus::Fail; - } - CCX_SHARE_CTX.lock().unwrap().nn_binder = nn_binder; - - // Set the linger socket option to -1. - let linger: i32 = -1; - let ret = nn_setsockopt( - nn_sock, - NN_SOL_SOCKET, - NN_LINGER, - &linger as *const _ as *const c_void, - std::mem::size_of::() as size_t, - ); - if ret < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_setsockopt()"); - return CcxShareStatus::Fail; - } - - // Save the stream name into the context, defaulting to "unknown" if not provided. - CCX_SHARE_CTX.lock().unwrap().stream_name = Some(stream_name.unwrap_or("unknown").to_string()); - - // Sleep for 1 second to allow subscribers to connect. - thread::sleep(Duration::from_secs(1)); - - CcxShareStatus::Ok -} - - -pub unsafe fn ccxr_share_stop() -> CcxShareStatus { - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stop: stopping service"); - - - nn_shutdown(CCX_SHARE_CTX.lock().unwrap().nn_sock, CCX_SHARE_CTX.lock().unwrap().nn_binder); - ctx.stream_name = None; - CcxShareStatus::Ok -} - - -pub unsafe fn ccxr_share_send(sub: *mut CcSubtitle) -> CcxShareStatus { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending"); - - // Create an entries structure and populate it from the subtitle. - let mut entries = CcxSubEntries { messages: Vec::new() }; - if ccxr_share_sub_to_entries( &*sub , &mut entries) == CcxShareStatus::Fail { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] failed to convert subtitle to entries"); - return CcxShareStatus::Fail; - } - - // Debug print of entries. - ccxr_sub_entries_print(&entries); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] entry obtained:"); - - // Iterate over all entries and send them. - for (i, message) in entries.messages.iter().enumerate() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending entry {}", i); - if entries.messages[i].lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] skipping empty message"); - continue; - } - if _ccxr_share_send(message) != CcxShareStatus::Ok { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] can't send message"); - return CcxShareStatus::Fail; - } - } - - ccxr_sub_entries_cleanup(&mut entries); - CcxShareStatus::Ok -} - -pub fn ccxr_sub_entry_message_get_packed_size(message: &CcxSubEntryMessage) -> usize { - message.encoded_len() -} - -pub fn ccxr_sub_entry_message_pack(message: &CcxSubEntryMessage, buf: &mut Vec) -> Result<(), prost::EncodeError> { - message.encode(buf) -} - - - -pub unsafe fn _ccxr_share_send(msg: &CcxSubEntryMessage) -> CcxShareStatus { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send"); - - let len: usize = ccxr_sub_entry_message_get_packed_size(msg); - - // Allocate a buffer to hold the packed message. - let mut buf = Vec::with_capacity(len); - if buf.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: malloc failed"); - return CcxShareStatus::Fail; - } - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: packing"); - ccxr_sub_entry_message_pack(msg, &mut buf).expect( - "Failed to pack message", - ); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sending"); - let sent: c_int = nn_send( - CCX_SHARE_CTX.lock().unwrap().nn_sock, - buf.as_ptr() as *const c_void, - len, - 0, - ); - if sent != len as c_int { - buf.clear(); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: len={} sent={}", len, sent); - return CcxShareStatus::Fail; - } - buf.clear(); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sent"); - CcxShareStatus::Ok -} - -pub unsafe fn ccxr_share_stream_done(stream_name: &str) -> CcxShareStatus { - let mut msg = CcxSubEntryMessage { - eos: 1, - stream_name: stream_name.parse().unwrap(), - counter: 0, - start_time: 0, - end_time: 0, - lines: Vec::new(), - }; - #[allow(unused)] - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - if _ccxr_share_send(&msg) != CcxShareStatus::Ok { - ccxr_sub_entry_msg_cleanup(&mut msg); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: can't send message"); - return CcxShareStatus::Fail; - } - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: message sent successfully"); - CcxShareStatus::Ok -} - -pub fn ccxr_share_sub_to_entries(sub: &CcSubtitle, entries: &mut CcxSubEntries) -> CcxShareStatus { - unsafe { - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_sub_to_entries"); - - if sub.type_ == SUBTYPE_CC_608 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_608"); - - let data_ptr = sub.data as *const Eia608Screen; - let mut nb_data = sub.nb_data; - - while nb_data > 0 { - let data = &*data_ptr.add(sub.nb_data as usize - nb_data as usize); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] data item"); - - if data.format == CcxEia608Format::SFormatXds { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] XDS. Skipping"); - nb_data -= 1; - continue; - } - - if data.start_time == 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] No start time. Skipping"); - break; - } - - entries.messages.push(CcxSubEntryMessage { - eos: 0, - stream_name: String::new(), - counter: ctx.counter + 1, - start_time: data.start_time, - end_time: data.end_time, - lines: Vec::new(), - }); - - let entry_index = entries.messages.len() - 1; - let entry = &mut entries.messages[entry_index]; - - for row in 0..CCX_DECODER_608_SCREEN_ROWS { - if data.row_used[row] != 0 { - let characters = CStr::from_ptr(data.characters[row].as_ptr()) - .to_string_lossy() - .to_string(); - entry.lines.push(characters); - } - } - - if entry.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] buffer is empty"); - entries.messages.pop(); - return CcxShareStatus::Ok; - } - - debug!( - msg_type = DebugMessageFlag::SHARE; - "[share] Copied {} lines", entry.lines.len() - ); - - ctx.counter += 1; - nb_data -= 1; - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] item done"); - } - } else { - match sub.type_ { - SUBTYPE_CC_BITMAP => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_BITMAP. Skipping"); - } - SUBTYPE_CC_RAW => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_RAW. Skipping"); - } - SUBTYPE_CC_TEXT => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_TEXT. Skipping"); - } - _ => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] Unknown subtitle type"); - } - } - } - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] done"); - CcxShareStatus::Ok - } -} diff --git a/src/rust/lib_ccxr/src/share/tests.rs b/src/rust/lib_ccxr/src/share/tests.rs index b9c2c712e..ecb845222 100644 --- a/src/rust/lib_ccxr/src/share/tests.rs +++ b/src/rust/lib_ccxr/src/share/tests.rs @@ -1,13 +1,15 @@ #![allow(unused_imports)] #![allow(unused)] -use libc::c_char; -use crate::share::share::*; -use crate::share::ccxr_sub_entry_message::*; -use std::sync::Once; -use crate::util::log::{set_logger, CCExtractorLogger, DebugMessageFlag, DebugMessageMask, OutputTarget}; +#[cfg(feature = "enable_sharing")] mod test { - use super::*; + use crate::share::ccxr_sub_entry_message::*; + use crate::share::functions::sharing::*; + use crate::util::log::{ + set_logger, CCExtractorLogger, DebugMessageFlag, DebugMessageMask, OutputTarget, + }; + use std::os::raw::c_char; + use std::sync::Once; static INIT: Once = Once::new(); @@ -18,7 +20,7 @@ mod test { DebugMessageMask::new(DebugMessageFlag::VERBOSE, DebugMessageFlag::VERBOSE), false, )) - .ok(); + .ok(); }); } #[test] @@ -48,11 +50,7 @@ mod test { counter: 0, start_time: 0, end_time: 0, - lines: vec![ - "test".to_string(), - "test".to_string(), - "test".to_string(), - ], + lines: vec!["test".to_string(), "test".to_string(), "test".to_string()], }; unsafe { @@ -117,7 +115,6 @@ mod test { } } - #[test] fn test_ccxr_share_send() { initialize_logger(); @@ -138,7 +135,6 @@ mod test { time_out: 0, next: std::ptr::null_mut(), prev: std::ptr::null_mut(), - }; let status = unsafe { ccxr_share_send(&mut sub as *mut CcSubtitle) }; assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); @@ -160,7 +156,6 @@ mod test { assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); } - const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; const CCX_DECODER_608_SCREEN_ROWS: usize = 15; @@ -204,25 +199,50 @@ mod test { flags: 0, lang_index: 0, got_output: 1, - mode: [b'M' as c_char, b'O' as c_char, b'D' as c_char, b'E' as c_char, 0], + mode: [ + b'M' as c_char, + b'O' as c_char, + b'D' as c_char, + b'E' as c_char, + 0, + ], info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], time_out: 0, next: std::ptr::null_mut(), prev: std::ptr::null_mut(), }; - let mut entries = CcxSubEntries { messages: Vec::new() }; + let mut entries = CcxSubEntries { + messages: Vec::new(), + }; let status = ccxr_share_sub_to_entries(&sub, &mut entries); - assert_eq!(status, CcxShareStatus::Ok, "Function should return OK status"); - assert_eq!(entries.messages.len(), 1, "There should be one entry in messages"); + assert_eq!( + status, + CcxShareStatus::Ok, + "Function should return OK status" + ); + assert_eq!( + entries.messages.len(), + 1, + "There should be one entry in messages" + ); let message = &entries.messages[0]; assert_eq!(message.start_time, 1000, "Start time should match input"); assert_eq!(message.end_time, 2000, "End time should match input"); assert_eq!(message.lines.len(), 3, "There should be 3 lines of content"); - assert_eq!(message.lines[0], "Hello, World!", "First line content mismatch"); - assert_eq!(message.lines[1], "Subtitle line 2", "Second line content mismatch"); - assert_eq!(message.lines[2], "Subtitle line 3", "Third line content mismatch"); + assert_eq!( + message.lines[0], "Hello, World!", + "First line content mismatch" + ); + assert_eq!( + message.lines[1], "Subtitle line 2", + "Second line content mismatch" + ); + assert_eq!( + message.lines[2], "Subtitle line 3", + "Third line content mismatch" + ); } #[test] @@ -243,18 +263,34 @@ mod test { flags: 0, lang_index: 0, got_output: 1, - mode: [b'M' as c_char, b'O' as c_char, b'D' as c_char, b'E' as c_char, 0], + mode: [ + b'M' as c_char, + b'O' as c_char, + b'D' as c_char, + b'E' as c_char, + 0, + ], info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], time_out: 0, next: std::ptr::null_mut(), prev: std::ptr::null_mut(), }; - let mut entries = CcxSubEntries { messages: Vec::new() }; + let mut entries = CcxSubEntries { + messages: Vec::new(), + }; let status = ccxr_share_sub_to_entries(&sub, &mut entries); - assert_eq!(status, CcxShareStatus::Ok, "Function should return OK status"); - assert_eq!(entries.messages.len(), 0, "There should be no messages for empty rows"); + assert_eq!( + status, + CcxShareStatus::Ok, + "Function should return OK status" + ); + assert_eq!( + entries.messages.len(), + 0, + "There should be no messages for empty rows" + ); } } diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index d658a24e0..7b971dbf8 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -1,10 +1,13 @@ //! Provides C-FFI functions that are direct equivalent of functions available in C. + pub mod bitstream; pub mod time; + #[cfg(feature = "enable_sharing")] pub mod share; +pub mod time; use crate::ccx_options; use lib_ccxr::util::log::*; use lib_ccxr::util::{bits::*, levenshtein::*}; diff --git a/src/rust/src/libccxr_exports/share.rs b/src/rust/src/libccxr_exports/share.rs index 50136f509..6213876a8 100644 --- a/src/rust/src/libccxr_exports/share.rs +++ b/src/rust/src/libccxr_exports/share.rs @@ -1,5 +1,5 @@ use lib_ccxr::share::ccxr_sub_entry_message::*; -use lib_ccxr::share::share::*; +use lib_ccxr::share::functions::sharing::*; use lib_ccxr::util::log::{debug, DebugMessageFlag}; use std::ffi::CStr; /// C-compatible function to clean up a `CcxSubEntryMessage`. @@ -28,7 +28,6 @@ pub unsafe extern "C" fn ccxr_sub_entry_msg_print_c(msg: *const CcxSubEntryMessa ccxr_sub_entry_msg_print(msg); } - #[no_mangle] pub unsafe extern "C" fn ccxr_sub_entries_cleanup_c(entries: *mut CcxSubEntries) { if entries.is_null() { @@ -50,7 +49,9 @@ pub unsafe extern "C" fn ccxr_sub_entries_print_c(entries: *const CcxSubEntries) /// C-compatible function to start the sharing service. #[no_mangle] -pub unsafe extern "C" fn ccxr_share_start_c(stream_name: *const libc::c_char) -> CcxShareStatus { +pub unsafe extern "C" fn ccxr_share_start_c( + stream_name: *const std::os::raw::c_char, +) -> CcxShareStatus { if stream_name.is_null() { return ccxr_share_start(Option::from("unknown")); } @@ -85,7 +86,9 @@ pub unsafe extern "C" fn ccxr_share_send_c(sub: *const CcSubtitle) -> CcxShareSt } #[no_mangle] -pub unsafe extern "C" fn ccxr_share_stream_done_c(stream_name: *const libc::c_char) -> CcxShareStatus { +pub unsafe extern "C" fn ccxr_share_stream_done_c( + stream_name: *const std::os::raw::c_char, +) -> CcxShareStatus { if stream_name.is_null() { return CcxShareStatus::Fail; } From d8dd4c9de5101b8325765407236b0ef7a34cd36a Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 3 May 2025 22:32:28 +0530 Subject: [PATCH 03/13] Share Module: Added Documentation --- src/rust/lib_ccxr/src/share/mod.rs | 59 ++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/rust/lib_ccxr/src/share/mod.rs b/src/rust/lib_ccxr/src/share/mod.rs index d981ff34c..f23d0d08d 100644 --- a/src/rust/lib_ccxr/src/share/mod.rs +++ b/src/rust/lib_ccxr/src/share/mod.rs @@ -1,3 +1,62 @@ +//! Module `share` broadcasts subtitle entries over a pub/sub message bus +//! (Nanomsg) and to interoperate with C code via C-compatible FFI bindings. +//! +//! # Overview +//! +//! - CcxSubEntryMessage Represents a single subtitle entry, including timing and text lines. +//! - CcxSubEntries is A collection of `CcxSubEntryMessage` instances generated from a subtitle frame. +//! - CcxShareStatus Enumeration of possible return statuses for share operations. +//! - Ccx_share_ctx Global context holding the Nanomsg socket and stream metadata. +//! +//! ## Features +//! +//! - Initialize and manage a Nanomsg PUB socket for broadcasting messages. +//! - Convert internal `CcSubtitle` frames into one or more [`CcxSubEntryMessage`] instances. +//! - Send packed protobuf messages over the socket, handling lifecycle of messages. +//! - Signal end-of-stream events to subscribers. +//! - Launch external translation processes via system calls. +//! +//! # C-Compatible API +//! +//! All `extern "C"` functions are safe to call from C code and mirror the underlying Rust logic. +//! +//! ## Message Cleanup and Printing +//!| C Function | Rust Binding | +//!|---------------------------------------|--------------------------------------| +//!| [`ccx_sub_entry_msg_cleanup`] | [`ccxr_sub_entry_msg_cleanup`] | +//!| [`ccx_sub_entry_msg_print`] | [`ccxr_sub_entry_msg_print`] | +//!| [`ccx_sub_entries_cleanup`] | [`ccxr_sub_entries_cleanup`] | +//!| [`ccx_sub_entries_print`] | [`ccxr_sub_entries_print`] | +//! +//! ## Service Control +//!| C Function | Rust Binding | +//!|----------------------|-------------------------------| +//!| [`ccx_share_start`] | [`ccxr_share_start`] | +//!| [`ccx_share_stop`] | [`ccxr_share_stop`] | +//! +//! ## Sending Subtitles +//!| C Function | Rust Binding | +//!|-----------------------------|-------------------------------| +//!| [`ccx_share_send`] | [`ccxr_share_send`] | +//!| [`_ccx_share_send`] | [`_ccxr_share_send`] | +//!| [`ccx_share_stream_done`] | [`ccxr_share_stream_done`] | +//!| [`_ccx_share_sub_to_entries`] | [`_ccxr_share_sub_to_entries`]| +//! +//! ## Translator Launch +//!| C Function | Description | +//!|-------------------------------|-------------------------------------------------| +//!| `ccx_share_launch_translator` | Spawn external `cctranslate` process for translation. +//! +//!# Nanomsg Options +//! +//! - Default URL: `tcp://*:3269` (configurable via `ccx_options.sharing_url`). +//! - Linger option set to infinite to ensure messages are delivered before shutdown. + +use crate::share::functions::sharing::{ + ccxr_sub_entries_cleanup, ccxr_sub_entries_print, ccxr_sub_entry_msg_cleanup, + ccxr_sub_entry_msg_print, +}; + pub mod ccxr_sub_entry_message; pub mod functions; pub mod tests; From 1d8b36309effbcbdf9598bdf60a5b50bc898f1c3 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 16 Aug 2025 01:41:45 +0530 Subject: [PATCH 04/13] Share Module: Removed Sharing Service --- docs/using_cmake_build.txt | 5 +- linux/Makefile.am | 1 - mac/Makefile.am | 1 - src/CMakeLists.txt | 16 - src/ccextractor.c | 25 - src/ccextractor.h | 1 - src/lib_ccx/CMakeLists.txt | 3 - src/lib_ccx/ccx_common_constants.h | 3 - src/lib_ccx/ccx_common_option.c | 7 - src/lib_ccx/ccx_common_option.h | 11 - src/lib_ccx/ccx_encoders_common.c | 7 - src/lib_ccx/ccx_encoders_splitbysentence.c | 3 - src/lib_ccx/ccx_encoders_transcript.c | 4 - src/lib_ccx/ccx_share.c | 375 ------------ src/lib_ccx/ccx_share.h | 50 -- src/lib_ccx/ccx_sub_entry_message.pb-c.c | 154 ----- src/lib_ccx/ccx_sub_entry_message.pb-c.h | 81 --- src/lib_ccx/ccx_sub_entry_message.proto | 8 - src/lib_ccx/params.c | 71 --- src/rust/Cargo.lock | 44 +- src/rust/Cargo.toml | 1 - src/rust/lib_ccxr/Cargo.toml | 2 - src/rust/lib_ccxr/src/common/options.rs | 18 - src/rust/lib_ccxr/src/encoder/txt_helpers.rs | 4 +- src/rust/lib_ccxr/src/lib.rs | 2 - .../src/share/ccxr_sub_entry_message.rs | 16 - src/rust/lib_ccxr/src/share/functions.rs | 536 ------------------ src/rust/lib_ccxr/src/share/mod.rs | 62 -- src/rust/lib_ccxr/src/share/tests.rs | 296 ---------- src/rust/lib_ccxr/src/util/log.rs | 3 - src/rust/src/args.rs | 29 - src/rust/src/common.rs | 15 - src/rust/src/libccxr_exports/mod.rs | 6 - src/rust/src/libccxr_exports/share.rs | 118 ---- src/rust/src/parser.rs | 30 - windows/ccextractor.vcxproj | 1 - windows/ccextractor.vcxproj.filters | 3 - 37 files changed, 7 insertions(+), 2005 deletions(-) delete mode 100644 src/lib_ccx/ccx_share.c delete mode 100644 src/lib_ccx/ccx_share.h delete mode 100644 src/lib_ccx/ccx_sub_entry_message.pb-c.c delete mode 100644 src/lib_ccx/ccx_sub_entry_message.pb-c.h delete mode 100644 src/lib_ccx/ccx_sub_entry_message.proto delete mode 100644 src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs delete mode 100644 src/rust/lib_ccxr/src/share/functions.rs delete mode 100644 src/rust/lib_ccxr/src/share/mod.rs delete mode 100644 src/rust/lib_ccxr/src/share/tests.rs delete mode 100644 src/rust/src/libccxr_exports/share.rs diff --git a/docs/using_cmake_build.txt b/docs/using_cmake_build.txt index 05ecb87f1..af842fbb8 100644 --- a/docs/using_cmake_build.txt +++ b/docs/using_cmake_build.txt @@ -13,7 +13,7 @@ Step 2) create a separate directory where you want to build the target. Step 3) make the build system using cmake. Params in [] are optional and have been explained later in the document. - ~> cmake [-DWITH_FFMPEG=ON] [-DWITH_OCR=ON] [-DWITH_SHARING=ON] + ~> cmake [-DWITH_FFMPEG=ON] [-DWITH_OCR=ON] [-DWITH_HARDSUBX=ON] ../src/ Step 4) Compile the code. @@ -29,9 +29,6 @@ cmake -DWITH_FFMPEG=ON ../src/ If you want to build CCExtractor with OCR you need to pass cmake -DWITH_OCR=ON ../src/ -If you want to build CCExtractor with Sharing and Translating service: -cmake -DWITH_SHARING=ON ../src/ - If you want to build CCExtractor with HARDSUBX support cmake -DWITH_HARDSUBX=ON ../src/ diff --git a/linux/Makefile.am b/linux/Makefile.am index 7491c1f7d..9996acf3f 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -124,7 +124,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ ../src/lib_ccx/ccx_share.c \ - ../src/lib_ccx/ccx_share.h \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ diff --git a/mac/Makefile.am b/mac/Makefile.am index 13f0a039e..20ce21451 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -96,7 +96,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ ../src/lib_ccx/ccx_share.c \ - ../src/lib_ccx/ccx_share.h \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3852799b4..5031182f0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,7 +5,6 @@ include (CTest) option (WITH_FFMPEG "Build using FFmpeg demuxer and decoder" OFF) option (WITH_OCR "Build with OCR (Optical Character Recognition) feature" OFF) -option (WITH_SHARING "Build with sharing and translation support" OFF) option (WITH_HARDSUBX "Build with support for burned-in subtitles" OFF) option (WITHOUT_RUST "Build without Rust library" OFF) @@ -206,21 +205,6 @@ if (PKG_CONFIG_FOUND AND WITH_OCR) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR") endif (PKG_CONFIG_FOUND AND WITH_OCR) -######################################################## -# Build with CC sharing and translation support -######################################################## - -if (PKG_CONFIG_FOUND AND WITH_SHARING) - - pkg_check_modules (NANOMSG REQUIRED libnanomsg) - set (EXTRA_LIBS ${EXTRA_LIBS} ${NANOMSG_STATIC_LIBRARIES}) - - include_directories ("${PROJECT_SOURCE_DIR}/thirdparty/protobuf-c/") - aux_source_directory ("${PROJECT_SOURCE_DIR}/thirdparty/protobuf-c/" SOURCEFILE) - - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_SHARING") -endif (PKG_CONFIG_FOUND AND WITH_SHARING) - ######################################################## # Build for hardsubx using avformat, avutil, avcodec and # swscale diff --git a/src/ccextractor.c b/src/ccextractor.c index 62bd604ae..c33d14cda 100644 --- a/src/ccextractor.c +++ b/src/ccextractor.c @@ -138,27 +138,10 @@ int api_start(struct ccx_s_options api_options) #endif terminate_asap = 0; -#ifdef ENABLE_SHARING - if (api_options.translate_enabled && ctx->num_input_files > 1) - { - mprint("[share] WARNING: simultaneous translation of several input files is not supported yet\n"); - api_options.translate_enabled = 0; - api_options.sharing_enabled = 0; - } - if (api_options.translate_enabled) - { - mprint("[share] launching translate service\n"); - ccx_share_launch_translator(api_options.translate_langs, api_options.translate_key); - } -#endif // ENABLE_SHARING ret = 0; while (switch_to_next_file(ctx, 0)) { prepare_for_new_file(ctx); -#ifdef ENABLE_SHARING - if (api_options.sharing_enabled) - ccx_share_start(ctx->basefilename); -#endif // ENABLE_SHARING stream_mode = ctx->demux_ctx->get_stream_mode(ctx->demux_ctx); // Disable sync check for raw formats - they have the right timeline. @@ -310,14 +293,6 @@ int api_start(struct ccx_s_options api_options) dec_ctx->timing->fts_now = 0; dec_ctx->timing->fts_max = 0; -#ifdef ENABLE_SHARING - if (api_options.sharing_enabled) - { - ccx_share_stream_done(ctx->basefilename); - ccx_share_stop(); - } -#endif // ENABLE_SHARING - if (dec_ctx->total_pulldownframes) mprint("incl. pulldown frames: %s (%u frames at %.2ffps)\n", print_mstime_static((LLONG)(dec_ctx->total_pulldownframes * 1000 / current_fps)), diff --git a/src/ccextractor.h b/src/ccextractor.h index baede3f48..481505350 100644 --- a/src/ccextractor.h +++ b/src/ccextractor.h @@ -19,7 +19,6 @@ #include "lib_ccx/ccx_common_option.h" #include "lib_ccx/ccx_mp4.h" #include "lib_ccx/hardsubx.h" -#include "lib_ccx/ccx_share.h" #ifdef WITH_LIBCURL CURL *curl; CURLcode res; diff --git a/src/lib_ccx/CMakeLists.txt b/src/lib_ccx/CMakeLists.txt index 4f329bcaa..11b25b52f 100644 --- a/src/lib_ccx/CMakeLists.txt +++ b/src/lib_ccx/CMakeLists.txt @@ -56,9 +56,6 @@ if (WITH_OCR) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_OCR") endif (WITH_OCR) -if (WITH_SHARING) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DENABLE_SHARING") -endif (WITH_SHARING) aux_source_directory ("${PROJECT_SOURCE_DIR}/lib_ccx/" SOURCEFILE) diff --git a/src/lib_ccx/ccx_common_constants.h b/src/lib_ccx/ccx_common_constants.h index 68d6d52e3..6224ff0ba 100644 --- a/src/lib_ccx/ccx_common_constants.h +++ b/src/lib_ccx/ccx_common_constants.h @@ -58,9 +58,6 @@ enum ccx_debug_message_types CCX_DMT_LEVENSHTEIN = 0x1000, // Levenshtein distance calculations CCX_DMT_DVB = 0x2000, // DVB CCX_DMT_DUMPDEF = 0x4000 // Dump defective TS packets -#ifdef ENABLE_SHARING - CCX_DMT_SHARE = 0x8000, // Extracted captions sharing service -#endif //ENABLE_SHARING }; // AVC NAL types diff --git a/src/lib_ccx/ccx_common_option.c b/src/lib_ccx/ccx_common_option.c index eb61f6412..6b8327344 100644 --- a/src/lib_ccx/ccx_common_option.c +++ b/src/lib_ccx/ccx_common_option.c @@ -151,13 +151,6 @@ void init_options(struct ccx_s_options *options) options->settings_dtvcc.services_enabled, 0, CCX_DTVCC_MAX_SERVICES * sizeof(options->settings_dtvcc.services_enabled[0])); -#ifdef ENABLE_SHARING - options->sharing_enabled = 0; - options->sharing_url = NULL; - options->translate_enabled = 0; - options->translate_key = NULL; - options->translate_langs = NULL; -#endif // ENABLE_SHARING #ifdef WITH_LIBCURL options->curlposturl = NULL; #endif diff --git a/src/lib_ccx/ccx_common_option.h b/src/lib_ccx/ccx_common_option.h index 7bc35ac1a..104b6e027 100644 --- a/src/lib_ccx/ccx_common_option.h +++ b/src/lib_ccx/ccx_common_option.h @@ -198,17 +198,6 @@ struct ccx_s_options // Options from user parameters #ifdef WITH_LIBCURL char *curlposturl; #endif - - -#ifdef ENABLE_SHARING - //CC sharing - int sharing_enabled; - char *sharing_url; - //Translating - int translate_enabled; - char *translate_langs; - char *translate_key; -#endif }; extern struct ccx_s_options ccx_options; diff --git a/src/lib_ccx/ccx_encoders_common.c b/src/lib_ccx/ccx_encoders_common.c index 2c77e3f90..04281a49d 100644 --- a/src/lib_ccx/ccx_encoders_common.c +++ b/src/lib_ccx/ccx_encoders_common.c @@ -8,9 +8,6 @@ #include "ccx_encoders_xds.h" #include "ccx_encoders_helpers.h" #include "ccextractor.h" -#ifdef ENABLE_SHARING -#include "ccx_share.h" -#endif // ENABLE_SHARING #ifdef WIN32 int fsync(int fd) @@ -1094,10 +1091,6 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub) context = change_filename(context); -#ifdef ENABLE_SHARING - if (ccx_options.sharing_enabled) - ccx_share_send(sub); -#endif // ENABLE_SHARING if (context->sbs_enabled) { diff --git a/src/lib_ccx/ccx_encoders_splitbysentence.c b/src/lib_ccx/ccx_encoders_splitbysentence.c index d821e1223..34a49b871 100644 --- a/src/lib_ccx/ccx_encoders_splitbysentence.c +++ b/src/lib_ccx/ccx_encoders_splitbysentence.c @@ -27,9 +27,6 @@ #define LOG_DEBUG(...) #endif -#ifdef ENABLE_SHARING -#include "ccx_share.h" -#endif // ENABLE_SHARING //--------------------------- // BEGIN of #BUG639 diff --git a/src/lib_ccx/ccx_encoders_transcript.c b/src/lib_ccx/ccx_encoders_transcript.c index 9d89a31a3..55e227e80 100644 --- a/src/lib_ccx/ccx_encoders_transcript.c +++ b/src/lib_ccx/ccx_encoders_transcript.c @@ -9,10 +9,6 @@ #include "ccx_encoders_helpers.h" #include "lib_ccx.h" -#ifdef ENABLE_SHARING -#include "ccx_share.h" -#endif // ENABLE_SHARING - int write_cc_bitmap_as_transcript(struct cc_subtitle *sub, struct encoder_ctx *context) { int ret = 0; diff --git a/src/lib_ccx/ccx_share.c b/src/lib_ccx/ccx_share.c deleted file mode 100644 index 4c13c2d8c..000000000 --- a/src/lib_ccx/ccx_share.c +++ /dev/null @@ -1,375 +0,0 @@ -// -// Created by Oleg Kisselef (olegkisselef at gmail dot com) on 6/21/15 -// - -#include -#include -#include "ccx_share.h" -#include "ccx_common_option.h" -#include "ccx_decoders_structs.h" -#include "lib_ccx.h" -#ifdef ENABLE_SHARING - -#include -#include - -ccx_share_service_ctx ccx_share_ctx; -#ifndef DISABLE_RUST -extern void ccxr_sub_entry_msg_cleanup_c(CcxSubEntryMessage *msg); -extern void ccxr_sub_entry_msg_print_c(const CcxSubEntryMessage *msg); -extern void ccxr_sub_entries_cleanup_c(ccx_sub_entries *entries); -extern void ccxr_sub_entries_print_c(const ccx_sub_entries *entries); -extern ccx_share_status ccxr_share_start_c(const char *stream_name); -extern ccx_share_status ccxr_share_stop_c(void); -extern ccx_share_status _ccxr_share_send_c(const CcxSubEntryMessage *msg); -extern ccx_share_status ccxr_share_send_c(const struct cc_subtitle *sub); -extern ccx_share_status ccxr_share_stream_done_c(const char *stream_name); -extern ccx_share_status _ccxr_share_sub_to_entries_c(const struct cc_subtitle *sub, ccx_sub_entries *entries); - -#endif - -void ccx_sub_entry_msg_cleanup(CcxSubEntryMessage *msg) -{ -#ifndef DISABLE_RUST - return ccxr_sub_entry_msg_cleanup_c(msg); -#else - - for (int i = 0; i < msg->n_lines; i++) - { - free(msg->lines[i]); - } - free(msg->lines); - free(msg->stream_name); -#endif -} - -void ccx_sub_entry_msg_print(CcxSubEntryMessage *msg) -{ -#ifndef DISABLE_RUST - return ccxr_sub_entry_msg_print_c(msg); -#else - if (!msg) - { - dbg_print(CCX_DMT_SHARE, "[share] print(!msg)\n"); - return; - } - - dbg_print(CCX_DMT_SHARE, "\n[share] sub msg #%lu\n", msg->counter); - dbg_print(CCX_DMT_SHARE, "[share] name: %s\n", msg->stream_name); - dbg_print(CCX_DMT_SHARE, "[share] start: %llu\n", msg->start_time); - dbg_print(CCX_DMT_SHARE, "[share] end: %llu\n", msg->end_time); - - dbg_print(CCX_DMT_SHARE, "[share] lines count: %d\n", msg->n_lines); - if (!msg->lines) - { - dbg_print(CCX_DMT_SHARE, "[share] no lines allocated\n"); - return; - } - - dbg_print(CCX_DMT_SHARE, "[share] lines:\n"); - for (unsigned int i = 0; i < msg->n_lines; i++) - { - if (!msg->lines[i]) - { - dbg_print(CCX_DMT_SHARE, "[share] line[%d] is not allocated\n", i); - } - dbg_print(CCX_DMT_SHARE, "[share] %s\n", msg->lines[i]); - } -#endif -} - -void ccx_sub_entries_init(ccx_sub_entries *entries) -{ - entries->count = 0; - entries->messages = NULL; -} - -void ccx_sub_entries_cleanup(ccx_sub_entries *entries) -{ -#ifndef DISABLE_RUST - return ccxr_sub_entries_cleanup_c(entries); -#else - for (int i = 0; i < entries->count; i++) - { - ccx_sub_entry_msg_cleanup(entries->messages + i); - } - free(entries->messages); - entries->messages = NULL; - entries->count = 0; -#endif -} - -void ccx_sub_entries_print(ccx_sub_entries *entries) -{ -#ifndef DISABLE_RUST - return ccxr_sub_entries_print_c(entries); -#else - dbg_print(CCX_DMT_SHARE, "[share] ccx_sub_entries_print (%u entries)\n", entries->count); - for (int i = 0; i < entries->count; i++) - { - ccx_sub_entry_msg_print(entries->messages + i); - } -#endif -} - -ccx_share_status ccx_share_start(const char *stream_name) // TODO add stream -{ -#ifndef DISABLE_RUST - return ccxr_share_start_c(stream_name); -#else - dbg_print(CCX_DMT_SHARE, "[share] ccx_share_start: starting service\n"); - // TODO for multiple files we have to move creation to ccx_share_init - ccx_share_ctx.nn_sock = nn_socket(AF_SP, NN_PUB); - if (ccx_share_ctx.nn_sock < 0) - { - perror("[share] ccx_share_start: can't nn_socket()\n"); - fatal(EXIT_NOT_CLASSIFIED, "In ccx_share_start: can't nn_socket()."); - } - - if (!ccx_options.sharing_url) - { - ccx_options.sharing_url = strdup("tcp://*:3269"); - } - - dbg_print(CCX_DMT_SHARE, "[share] ccx_share_start: url=%s\n", ccx_options.sharing_url); - - ccx_share_ctx.nn_binder = nn_bind(ccx_share_ctx.nn_sock, ccx_options.sharing_url); - if (ccx_share_ctx.nn_binder < 0) - { - perror("[share] ccx_share_start: can't nn_bind()\n"); - fatal(EXIT_NOT_CLASSIFIED, "In ccx_share_start: can't nn_bind()"); - } - - int linger = -1; - int rc = nn_setsockopt(ccx_share_ctx.nn_sock, NN_SOL_SOCKET, NN_LINGER, &linger, sizeof(int)); - if (rc < 0) - { - perror("[share] ccx_share_start: can't nn_setsockopt()\n"); - fatal(EXIT_NOT_CLASSIFIED, "In ccx_share_start: can't nn_setsockopt()"); - } - - // TODO remove path from stream name to minimize traffic (/?) - ccx_share_ctx.stream_name = strdup(stream_name ? stream_name : "unknown"); - - sleep(1); // We have to sleep a while, because it takes some time for subscribers to subscribe - return CCX_SHARE_OK; -#endif -} - -ccx_share_status ccx_share_stop() -{ -#ifndef DISABLE_RUST - return ccxr_share_stop_c(); -#else - dbg_print(CCX_DMT_SHARE, "[share] ccx_share_stop: stopping service\n"); - nn_shutdown(ccx_share_ctx.nn_sock, ccx_share_ctx.nn_binder); - free(ccx_share_ctx.stream_name); - return CCX_SHARE_OK; -#endif -} - -ccx_share_status ccx_share_send(struct cc_subtitle *sub) -{ -#ifndef DISABLE_RUST - return ccxr_share_send_c(sub); -#else - dbg_print(CCX_DMT_SHARE, "[share] ccx_share_send: sending\n"); - ccx_sub_entries entries; - ccx_sub_entries_init(&entries); - _ccx_share_sub_to_entries(sub, &entries); - ccx_sub_entries_print(&entries); - dbg_print(CCX_DMT_SHARE, "[share] entry obtained:\n"); - - for (unsigned int i = 0; i < entries.count; i++) - { - dbg_print(CCX_DMT_SHARE, "[share] ccx_share_send: _sending %u\n", i); - // TODO prevent sending empty messages - if (_ccx_share_send(entries.messages + i) != CCX_SHARE_OK) - { - dbg_print(CCX_DMT_SHARE, "[share] can't send message\n"); - return CCX_SHARE_FAIL; - } - } - - ccx_sub_entries_cleanup(&entries); - - return CCX_SHARE_OK; -#endif -} - -ccx_share_status _ccx_share_send(CcxSubEntryMessage *msg) -{ -#ifndef DISABLE_RUST - return _ccxr_share_send_c(msg); -#else - dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send\n"); - size_t len = ccx_sub_entry_message__get_packed_size(msg); - void *buf = malloc(len); - dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send: packing\n"); - ccx_sub_entry_message__pack(msg, buf); - - dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send: sending\n"); - int sent = nn_send(ccx_share_ctx.nn_sock, buf, len, 0); - if (sent != len) - { - free(buf); - dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send: len=%zd sent=%d\n", len, sent); - return CCX_SHARE_FAIL; - } - free(buf); - dbg_print(CCX_DMT_SHARE, "[share] _ccx_share_send: sent\n"); - return CCX_SHARE_OK; -#endif -} - -ccx_share_status ccx_share_stream_done(char *stream_name) -{ -#ifndef DISABLE_RUST - return ccxr_share_stream_done_c(stream_name); -#else - CcxSubEntryMessage msg = CCX_SUB_ENTRY_MESSAGE__INIT; - msg.eos = 1; - msg.stream_name = strdup(stream_name); - msg.counter = 0; - msg.start_time = 0; - msg.end_time = 0; - msg.n_lines = 0; - msg.lines = NULL; - - if (_ccx_share_send(&msg) != CCX_SHARE_OK) - { - ccx_sub_entry_msg_cleanup(&msg); - dbg_print(CCX_DMT_SHARE, "[share] can't send message\n"); - return CCX_SHARE_FAIL; - } - ccx_sub_entry_msg_cleanup(&msg); - - return CCX_SHARE_OK; -#endif -} - -ccx_share_status _ccx_share_sub_to_entries(struct cc_subtitle *sub, ccx_sub_entries *entries) -{ -#ifndef DISABLE_RUST - return _ccxr_share_sub_to_entries_c(sub, entries); -#else - dbg_print(CCX_DMT_SHARE, "\n[share] _ccx_share_sub_to_entry\n"); - if (sub->type == CC_608) - { - dbg_print(CCX_DMT_SHARE, "[share] CC_608\n"); - struct eia608_screen *data; - unsigned int nb_data = sub->nb_data; - for (data = sub->data; nb_data; nb_data--, data++) - { - dbg_print(CCX_DMT_SHARE, "[share] data item\n"); - if (data->format == SFORMAT_XDS) - { - dbg_print(CCX_DMT_SHARE, "[share] XDS. Skipping\n"); - continue; - } - if (!data->start_time) - { - dbg_print(CCX_DMT_SHARE, "[share] No start time. Skipping\n"); - break; - } - - entries->messages = realloc(entries->messages, ++entries->count * sizeof(CcxSubEntryMessage)); - if (!entries->messages) - { - fatal(EXIT_NOT_ENOUGH_MEMORY, "In _ccx_share_sub_to_entry: Not enough memory to store sub-entry-messages\n"); - } - - unsigned int entry_index = entries->count - 1; - CcxSubEntryMessage msg = CCX_SUB_ENTRY_MESSAGE__INIT; - entries->messages[entry_index] = msg; - - entries->messages[entry_index].n_lines = 0; - for (int i = 0; i < 15; i++) - { - if (data->row_used[i]) - { - entries->messages[entry_index].n_lines++; - } - } - if (!entries->messages[entry_index].n_lines) - { // Prevent writing empty screens. Not needed in .srt - dbg_print(CCX_DMT_SHARE, "[share] buffer is empty\n"); - dbg_print(CCX_DMT_SHARE, "[share] done\n"); - return CCX_SHARE_OK; - } - entries->messages[entry_index].lines = (char **)malloc(entries->messages[entry_index].n_lines * sizeof(char *)); - if (!entries->messages[entry_index].lines) - { - fatal(EXIT_NOT_ENOUGH_MEMORY, "In _ccx_share_sub_to_entry: Out of memory for entries->messages[entry_index].lines\n"); - } - - dbg_print(CCX_DMT_SHARE, "[share] Copying %u lines\n", entries->messages[entry_index].n_lines); - int i = 0, j = 0; - while (i < 15) - { - if (data->row_used[i]) - { - entries->messages[entry_index].lines[j] = - (char *)malloc((strnlen((char *)data->characters[i], 32) + 1) * sizeof(char)); - if (!entries->messages[entry_index].lines[j]) - { - fatal(EXIT_NOT_ENOUGH_MEMORY, - "In _ccx_share_sub_to_entry: Out of memory for entries->messages[entry_index].lines[j]\n"); - } - strncpy(entries->messages[entry_index].lines[j], (char *)data->characters[i], 32); - entries->messages[entry_index].lines[j][strnlen((char *)data->characters[i], 32)] = '\0'; - dbg_print(CCX_DMT_SHARE, "[share] line (len=%zd): %s\n", - strlen(entries->messages[entry_index].lines[j]), - entries->messages[entry_index].lines[j]); - j++; - } - i++; - } - entries->messages[entry_index].eos = 0; - entries->messages[entry_index].start_time = data->start_time; - entries->messages[entry_index].end_time = data->end_time; - entries->messages[entry_index].counter = ++ccx_share_ctx.counter; - dbg_print(CCX_DMT_SHARE, "[share] item done\n"); - } - } - if (sub->type == CC_BITMAP) - { - dbg_print(CCX_DMT_SHARE, "[share] CC_BITMAP. Skipping\n"); - } - if (sub->type == CC_RAW) - { - dbg_print(CCX_DMT_SHARE, "[share] CC_RAW. Skipping\n"); - } - if (sub->type == CC_TEXT) - { - dbg_print(CCX_DMT_SHARE, "[share] CC_TEXT. Skipping\n"); - } - dbg_print(CCX_DMT_SHARE, "[share] done\n"); - - return CCX_SHARE_OK; -#endif -} - -ccx_share_status ccx_share_launch_translator(char *langs, char *auth) -{ - if (!langs) - { - fatal(EXIT_NOT_CLASSIFIED, "In ccx_share_launch_translator: Launching translator failed as target languages are not specified\n"); - } - if (!auth) - { - fatal(EXIT_NOT_CLASSIFIED, "In ccx_share_launch_translator: Launching translator failed as no auth data is provided\n"); - } - - char buf[1024]; -#ifdef _WIN32 - sprintf(buf, "start cctranslate -s=extractor -l=%s -k=%s", langs, auth); -#else - sprintf(buf, "./cctranslate -s=extractor -l=%s -k=%s &", langs, auth); -#endif - dbg_print(CCX_DMT_SHARE, "[share] launching translator: \"%s\"\n", buf); - system(buf); - return CCX_SHARE_OK; -} - -#endif // ENABLE_SHARING diff --git a/src/lib_ccx/ccx_share.h b/src/lib_ccx/ccx_share.h deleted file mode 100644 index 6148f7053..000000000 --- a/src/lib_ccx/ccx_share.h +++ /dev/null @@ -1,50 +0,0 @@ -// -// Created by Oleg Kisselef (olegkisselef at gmail dot com) on 6/21/15 -// -#ifndef CCEXTRACTOR_CCX_SHARE_H -#define CCEXTRACTOR_CCX_SHARE_H - -#include "ccx_common_platform.h" -#include "ccx_common_structs.h" -#include "ccx_sub_entry_message.pb-c.h" -#include "lib_ccx.h" - -#ifdef ENABLE_SHARING - -typedef struct _ccx_sub_entries { - CcxSubEntryMessage *messages; - unsigned int count; -} ccx_sub_entries; - -typedef struct _ccx_share_service_ctx { - LLONG counter; - char *stream_name; - int nn_sock; - int nn_binder; -} ccx_share_service_ctx; - -extern ccx_share_service_ctx ccx_share_ctx; - -typedef enum _ccx_share_status { - CCX_SHARE_OK = 0, - CCX_SHARE_FAIL -} ccx_share_status; - -void ccx_sub_entry_message_cleanup(CcxSubEntryMessage *); -void ccx_sub_entry_message_print(CcxSubEntryMessage *); - -void ccx_sub_entries_init(ccx_sub_entries *); -void ccx_sub_entries_cleanup(ccx_sub_entries *); -void ccx_sub_entries_print(ccx_sub_entries *); - -ccx_share_status ccx_share_launch_translator(char *langs, char *google_api_key); -ccx_share_status ccx_share_start(const char *); -ccx_share_status ccx_share_stop(); -ccx_share_status ccx_share_send(struct cc_subtitle *); -ccx_share_status ccx_share_stream_done(char *); -ccx_share_status _ccx_share_sub_to_entries(struct cc_subtitle *, ccx_sub_entries *); -ccx_share_status _ccx_share_send(CcxSubEntryMessage *); - -#endif //ENABLE_SHARING - -#endif //CCEXTRACTOR_CCX_SHARE_H diff --git a/src/lib_ccx/ccx_sub_entry_message.pb-c.c b/src/lib_ccx/ccx_sub_entry_message.pb-c.c deleted file mode 100644 index 69b0f2997..000000000 --- a/src/lib_ccx/ccx_sub_entry_message.pb-c.c +++ /dev/null @@ -1,154 +0,0 @@ -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: ccx_sub_entry_message.proto */ - -/* Do not generate deprecated warnings for self */ -#ifndef PROTOBUF_C__NO_DEPRECATED -#define PROTOBUF_C__NO_DEPRECATED -#endif - -#include "ccx_sub_entry_message.pb-c.h" - -#ifdef ENABLE_SHARING - -void ccx_sub_entry_message__init(CcxSubEntryMessage *message) -{ - static CcxSubEntryMessage init_value = CCX_SUB_ENTRY_MESSAGE__INIT; - *message = init_value; -} -size_t ccx_sub_entry_message__get_packed_size(const CcxSubEntryMessage *message) -{ - assert(message->base.descriptor == &ccx_sub_entry_message__descriptor); - return protobuf_c_message_get_packed_size((const ProtobufCMessage *)(message)); -} -size_t ccx_sub_entry_message__pack(const CcxSubEntryMessage *message, - uint8_t *out) -{ - assert(message->base.descriptor == &ccx_sub_entry_message__descriptor); - return protobuf_c_message_pack((const ProtobufCMessage *)message, out); -} -size_t ccx_sub_entry_message__pack_to_buffer(const CcxSubEntryMessage *message, - ProtobufCBuffer *buffer) -{ - assert(message->base.descriptor == &ccx_sub_entry_message__descriptor); - return protobuf_c_message_pack_to_buffer((const ProtobufCMessage *)message, buffer); -} -CcxSubEntryMessage * -ccx_sub_entry_message__unpack(ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data) -{ - return (CcxSubEntryMessage *) - protobuf_c_message_unpack(&ccx_sub_entry_message__descriptor, - allocator, len, data); -} -void ccx_sub_entry_message__free_unpacked(CcxSubEntryMessage *message, - ProtobufCAllocator *allocator) -{ - assert(message->base.descriptor == &ccx_sub_entry_message__descriptor); - protobuf_c_message_free_unpacked((ProtobufCMessage *)message, allocator); -} -static const ProtobufCFieldDescriptor ccx_sub_entry_message__field_descriptors[6] = - { - { - "eos", - 1, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT32, - 0, /* quantifier_offset */ - offsetof(CcxSubEntryMessage, eos), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, - { - "stream_name", - 2, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_STRING, - 0, /* quantifier_offset */ - offsetof(CcxSubEntryMessage, stream_name), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, - { - "counter", - 3, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT64, - 0, /* quantifier_offset */ - offsetof(CcxSubEntryMessage, counter), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, - { - "start_time", - 4, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT64, - 0, /* quantifier_offset */ - offsetof(CcxSubEntryMessage, start_time), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, - { - "end_time", - 5, - PROTOBUF_C_LABEL_REQUIRED, - PROTOBUF_C_TYPE_INT64, - 0, /* quantifier_offset */ - offsetof(CcxSubEntryMessage, end_time), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, - { - "lines", - 7, - PROTOBUF_C_LABEL_REPEATED, - PROTOBUF_C_TYPE_STRING, - offsetof(CcxSubEntryMessage, n_lines), - offsetof(CcxSubEntryMessage, lines), - NULL, - NULL, - 0, /* flags */ - 0, NULL, NULL /* reserved1,reserved2, etc */ - }, -}; -static const unsigned ccx_sub_entry_message__field_indices_by_name[] = { - 2, /* field[2] = counter */ - 4, /* field[4] = end_time */ - 0, /* field[0] = eos */ - 5, /* field[5] = lines */ - 3, /* field[3] = start_time */ - 1, /* field[1] = stream_name */ -}; -static const ProtobufCIntRange ccx_sub_entry_message__number_ranges[2 + 1] = - { - {1, 0}, - {7, 5}, - {0, 6}}; -const ProtobufCMessageDescriptor ccx_sub_entry_message__descriptor = - { - PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC, - "ccx_sub_entry_message", - "CcxSubEntryMessage", - "CcxSubEntryMessage", - "", - sizeof(CcxSubEntryMessage), - 6, - ccx_sub_entry_message__field_descriptors, - ccx_sub_entry_message__field_indices_by_name, - 2, ccx_sub_entry_message__number_ranges, - (ProtobufCMessageInit)ccx_sub_entry_message__init, - NULL, NULL, NULL /* reserved[123] */ -}; - -#endif // ENABLE_SHARING diff --git a/src/lib_ccx/ccx_sub_entry_message.pb-c.h b/src/lib_ccx/ccx_sub_entry_message.pb-c.h deleted file mode 100644 index 055384daf..000000000 --- a/src/lib_ccx/ccx_sub_entry_message.pb-c.h +++ /dev/null @@ -1,81 +0,0 @@ -/* Generated by the protocol buffer compiler. DO NOT EDIT! */ -/* Generated from: ccx_sub_entry_message.proto */ - -#ifndef PROTOBUF_C_ccx_5fsub_5fentry_5fmessage_2eproto__INCLUDED -#define PROTOBUF_C_ccx_5fsub_5fentry_5fmessage_2eproto__INCLUDED - -#include "protobuf-c.h" -#include "lib_ccx.h" - -#ifdef ENABLE_SHARING - -PROTOBUF_C__BEGIN_DECLS - -#if PROTOBUF_C_VERSION_NUMBER < 1000000 -# error This file was generated by a newer version of protoc-c which is incompatible with your libprotobuf-c headers. Please update your headers. -#elif 1001001 < PROTOBUF_C_MIN_COMPILER_VERSION -# error This file was generated by an older version of protoc-c which is incompatible with your libprotobuf-c headers. Please regenerate this file with a newer version of protoc-c. -#endif - - -typedef struct _CcxSubEntryMessage CcxSubEntryMessage; - - -/* --- enums --- */ - - -/* --- messages --- */ - -struct _CcxSubEntryMessage -{ - ProtobufCMessage base; - int32_t eos; - char *stream_name; - int64_t counter; - int64_t start_time; - int64_t end_time; - size_t n_lines; - char **lines; -}; -#define CCX_SUB_ENTRY_MESSAGE__INIT \ - { PROTOBUF_C_MESSAGE_INIT (&ccx_sub_entry_message__descriptor) \ - , 0, NULL, 0, 0, 0, 0,NULL } - - -/* CcxSubEntryMessage methods */ -void ccx_sub_entry_message__init -(CcxSubEntryMessage *message); -size_t ccx_sub_entry_message__get_packed_size -(const CcxSubEntryMessage *message); -size_t ccx_sub_entry_message__pack -(const CcxSubEntryMessage *message, -uint8_t *out); -size_t ccx_sub_entry_message__pack_to_buffer -(const CcxSubEntryMessage *message, -ProtobufCBuffer *buffer); -CcxSubEntryMessage * -ccx_sub_entry_message__unpack -(ProtobufCAllocator *allocator, -size_t len, -const uint8_t *data); -void ccx_sub_entry_message__free_unpacked -(CcxSubEntryMessage *message, -ProtobufCAllocator *allocator); -/* --- per-message closures --- */ - -typedef void(*CcxSubEntryMessage_Closure) -(const CcxSubEntryMessage *message, -void *closure_data); - -/* --- services --- */ - - -/* --- descriptors --- */ - -extern const ProtobufCMessageDescriptor ccx_sub_entry_message__descriptor; - -PROTOBUF_C__END_DECLS - -#endif //ENABLE_SHARING - -#endif /* PROTOBUF_C_ccx_5fsub_5fentry_5fmessage_2eproto__INCLUDED */ diff --git a/src/lib_ccx/ccx_sub_entry_message.proto b/src/lib_ccx/ccx_sub_entry_message.proto deleted file mode 100644 index cc44044f6..000000000 --- a/src/lib_ccx/ccx_sub_entry_message.proto +++ /dev/null @@ -1,8 +0,0 @@ -message ccx_sub_entry_message { - required int32 eos = 1; - required string stream_name = 2; - required int64 counter = 3; - required int64 start_time = 4; - required int64 end_time = 5; - repeated string lines = 7; -} diff --git a/src/lib_ccx/params.c b/src/lib_ccx/params.c index 570b18084..0b557fed1 100644 --- a/src/lib_ccx/params.c +++ b/src/lib_ccx/params.c @@ -825,9 +825,6 @@ void print_usage(void) mprint(" --dumpdef: Hex-dump defective TS packets.\n"); mprint(" --investigate-packets: If no CC packets are detected based on the PMT, try\n"); mprint(" to find data in all packets by scanning.\n"); -#ifdef ENABLE_SHARING - mprint(" -sharing-debug: Print extracted CC sharing service messages\n"); -#endif // ENABLE_SHARING mprint("\n"); mprint("Teletext related options:\n"); @@ -878,18 +875,6 @@ void print_usage(void) mprint(" --no-progress-bar: Suppress the output of the progress bar\n"); mprint(" --quiet: Don't write any message.\n"); mprint("\n"); -#ifdef ENABLE_SHARING - mprint("Sharing extracted captions via TCP:\n"); - mprint(" --enable-sharing: Enables real-time sharing of extracted captions\n"); - mprint(" --sharing-url: Set url for sharing service in nanomsg format. Default: \"tcp://*:3269\"\n"); - mprint("\n"); - - mprint("CCTranslate application integration:\n"); - mprint(" --translate: Enable Translation tool and set target languages\n"); - mprint(" in csv format (e.g. --translate ru,fr,it\n"); - mprint(" --translate-auth: Set Translation Service authorization data to make translation possible\n"); - mprint(" In case of Google Translate API - API Key\n"); -#endif // ENABLE_SHARING mprint("Burned-in subtitle extraction:\n"); mprint(" --hardsubx : Enable the burned-in subtitle extraction subsystem.\n"); mprint("\n"); @@ -2327,13 +2312,6 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) tlt_config.verbose = 1; continue; } -#ifdef ENABLE_SHARING - if (strcmp(argv[i], "--sharing-debug") == 0) - { - opt->debug_mask |= CCX_DMT_SHARE; - continue; - } -#endif // ENABLE_SHARING if (strcmp(argv[i], "--fullbin") == 0) { opt->fullbin = 1; @@ -2831,55 +2809,6 @@ int parse_parameters(struct ccx_s_options *opt, int argc, char *argv[]) } #endif // WITH_LIBCURL -#ifdef ENABLE_SHARING - if (strcmp(argv[i], "--enable-sharing") == 0) - { - opt->sharing_enabled = 1; - continue; - } - if (strcmp(argv[i], "--sharing-url") == 0) - { - if (i < argc - 1) - { - i++; - opt->sharing_url = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--sharing-url has no argument.\n"); - } - } - if (strcmp(argv[i], "--translate") == 0) - { - if (i < argc - 1) - { - i++; - opt->translate_enabled = 1; - opt->sharing_enabled = 1; - opt->translate_langs = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--translate has no argument.\n"); - } - } - if (strcmp(argv[i], "--translate-auth") == 0) - { - if (i < argc - 1) - { - i++; - opt->translate_key = argv[i]; - continue; - } - else - { - fatal(EXIT_MALFORMED_PARAMETER, "--translate-auth has no argument.\n"); - } - } -#endif // ENABLE_SHARING - fatal(EXIT_INCOMPATIBLE_PARAMETERS, "Error: Parameter %s not understood.\n", argv[i]); } diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 9594b709b..c577a04d3 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -162,15 +162,6 @@ version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -[[package]] -name = "cc" -version = "1.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" -dependencies = [ - "shlex", -] - [[package]] name = "ccx_rust" version = "0.1.0" @@ -182,6 +173,7 @@ dependencies = [ "env_logger", "leptonica-sys", "lib_ccxr", + "libc", "log", "num-integer", "palette", @@ -260,15 +252,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - [[package]] name = "colorchoice" version = "1.0.3" @@ -385,12 +368,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - [[package]] name = "glob" version = "0.3.2" @@ -640,7 +617,6 @@ dependencies = [ "crc32fast", "derive_more", "lazy_static", - "nanomsg-sys", "num_enum", "prost", "strum 0.26.3", @@ -652,9 +628,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libloading" @@ -696,18 +672,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "nanomsg-sys" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78aa3ccb6d007dfecb4f7070725c4b1670a87677babb6621cb0c8cce9cfdc004" -dependencies = [ - "cmake", - "gcc", - "libc", - "pkg-config", -] - [[package]] name = "nom" version = "7.1.3" @@ -1508,4 +1472,4 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.99", -] \ No newline at end of file +] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 05804864b..a26467faf 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -36,7 +36,6 @@ bindgen = "0.64.0" pkg-config = "0.3.32" [features] -enable_sharing = [] wtv_debug = [] enable_ffmpeg = [] with_libcurl = [] diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index dae77c866..0fd69c8a0 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -20,13 +20,11 @@ lazy_static = "1.5.0" nanomsg-sys = { version = "0.7.2", optional = true, default-features = false, features = ["bundled"] } [features] default = [ - "enable_sharing", "wtv_debug", "enable_ffmpeg", "debug", "with_libcurl", ] -enable_sharing = ["nanomsg-sys"] wtv_debug = [] enable_ffmpeg = [] debug_out = [] diff --git a/src/rust/lib_ccxr/src/common/options.rs b/src/rust/lib_ccxr/src/common/options.rs index 489605c44..e20433d4b 100644 --- a/src/rust/lib_ccxr/src/common/options.rs +++ b/src/rust/lib_ccxr/src/common/options.rs @@ -520,19 +520,6 @@ pub struct Options { #[cfg(feature = "with_libcurl")] pub curlposturl: Option, - - //CC sharing - #[cfg(feature = "enable_sharing")] - pub sharing_enabled: bool, - #[cfg(feature = "enable_sharing")] - pub sharing_url: Option, - #[cfg(feature = "enable_sharing")] - //Translating - pub translate_enabled: bool, - #[cfg(feature = "enable_sharing")] - pub translate_langs: Option, - #[cfg(feature = "enable_sharing")] - pub translate_key: Option, } impl Default for Options { @@ -634,11 +621,6 @@ impl Default for Options { DebugMessageFlag::VERBOSE, ), curlposturl: Default::default(), - sharing_enabled: Default::default(), - sharing_url: Default::default(), - translate_enabled: Default::default(), - translate_langs: Default::default(), - translate_key: Default::default(), } } } diff --git a/src/rust/lib_ccxr/src/encoder/txt_helpers.rs b/src/rust/lib_ccxr/src/encoder/txt_helpers.rs index a1986b9ee..8b2af4ff8 100644 --- a/src/rust/lib_ccxr/src/encoder/txt_helpers.rs +++ b/src/rust/lib_ccxr/src/encoder/txt_helpers.rs @@ -282,10 +282,10 @@ pub fn get_str_basic( info!("WARNING: Encoding is not yet supported\n"); out_buffer.clear(); out_buffer.push(0); - return 0; + 0 } else { out_buffer.push(0); - return len; + len } } diff --git a/src/rust/lib_ccxr/src/lib.rs b/src/rust/lib_ccxr/src/lib.rs index 205b670f2..4b02a4dfa 100644 --- a/src/rust/lib_ccxr/src/lib.rs +++ b/src/rust/lib_ccxr/src/lib.rs @@ -2,8 +2,6 @@ pub mod activity; pub mod common; pub mod encoder; pub mod hardsubx; -#[cfg(feature = "enable_sharing")] -pub mod share; pub mod subtitle; pub mod teletext; pub mod time; diff --git a/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs b/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs deleted file mode 100644 index 2cabcdc56..000000000 --- a/src/rust/lib_ccxr/src/share/ccxr_sub_entry_message.rs +++ /dev/null @@ -1,16 +0,0 @@ -// This file is @generated by prost-build. -#[derive(Clone, PartialEq, ::prost::Message)] -pub struct CcxSubEntryMessage { - #[prost(int32, required, tag = "1")] - pub eos: i32, - #[prost(string, required, tag = "2")] - pub stream_name: ::prost::alloc::string::String, - #[prost(int64, required, tag = "3")] - pub counter: i64, - #[prost(int64, required, tag = "4")] - pub start_time: i64, - #[prost(int64, required, tag = "5")] - pub end_time: i64, - #[prost(string, repeated, tag = "7")] - pub lines: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, -} diff --git a/src/rust/lib_ccxr/src/share/functions.rs b/src/rust/lib_ccxr/src/share/functions.rs deleted file mode 100644 index 8329f5990..000000000 --- a/src/rust/lib_ccxr/src/share/functions.rs +++ /dev/null @@ -1,536 +0,0 @@ -#[cfg(feature = "enable_sharing")] -pub mod sharing { - use crate::common::Options; - use crate::share::ccxr_sub_entry_message::CcxSubEntryMessage; - use crate::util::log::{debug, DebugMessageFlag}; - use lazy_static::lazy_static; - use nanomsg_sys::{ - nn_bind, nn_send, nn_setsockopt, nn_shutdown, nn_socket, AF_SP, NN_LINGER, NN_PUB, - NN_SOL_SOCKET, - }; - use prost::Message; - use std::cmp::PartialEq; - use std::ffi::c_void; - use std::os::raw::{c_char, c_int}; - use std::sync::{LazyLock, Mutex}; - use std::{ - ffi::{CStr, CString}, - thread, - time::Duration, - }; - - pub const CCX_DECODER_608_SCREEN_ROWS: usize = 15; - pub const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; - pub static CCX_OPTIONS: LazyLock> = - LazyLock::new(|| Mutex::new(Options::default())); - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum CcxEia608Format { - SFormatCcScreen = 0, - SFormatCcLine = 1, - SFormatXds = 2, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum CcModes { - ModePopOn = 0, - ModeRollUp2 = 1, - ModeRollUp3 = 2, - ModeRollUp4 = 3, - ModeText = 4, - ModePaintOn = 5, - ModeFakeRollUp1 = 100, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum CcxDecoder608ColorCode { - White = 0, - Green = 1, - Blue = 2, - Cyan = 3, - Red = 4, - Yellow = 5, - Magenta = 6, - UserDefined = 7, - Black = 8, - Transparent = 9, - Max = 10, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub enum FontBits { - Normal = 0, - Italics = 1, - Underline = 2, - UnderlineItalics = 3, - } - - #[repr(C)] - #[derive(Debug, Clone)] - pub struct Eia608Screen { - pub format: CcxEia608Format, - pub characters: [[c_char; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - pub colors: [[CcxDecoder608ColorCode; CCX_DECODER_608_SCREEN_WIDTH + 1]; - CCX_DECODER_608_SCREEN_ROWS], - pub fonts: [[FontBits; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - pub row_used: [c_int; CCX_DECODER_608_SCREEN_ROWS], - pub empty: c_int, - pub start_time: i64, - pub end_time: i64, - pub mode: CcModes, - pub channel: c_int, - pub my_field: c_int, - pub xds_str: *mut c_char, - pub xds_len: usize, - pub cur_xds_packet_class: c_int, - } - - impl Default for Eia608Screen { - fn default() -> Self { - Self { - format: CcxEia608Format::SFormatCcScreen, - characters: [[0; CCX_DECODER_608_SCREEN_WIDTH + 1]; CCX_DECODER_608_SCREEN_ROWS], - colors: [[CcxDecoder608ColorCode::Black; CCX_DECODER_608_SCREEN_WIDTH + 1]; - CCX_DECODER_608_SCREEN_ROWS], - fonts: [[FontBits::Normal; CCX_DECODER_608_SCREEN_WIDTH + 1]; - CCX_DECODER_608_SCREEN_ROWS], - row_used: [0; CCX_DECODER_608_SCREEN_ROWS], - empty: 1, - start_time: 0, - end_time: 0, - mode: CcModes::ModePopOn, - channel: 0, - my_field: 0, - xds_str: std::ptr::null_mut(), - xds_len: 0, - cur_xds_packet_class: 0, - } - } - } - - impl Eia608Screen { - pub fn new() -> Self { - Self::default() - } - - pub fn set_xds_str(&mut self, xds: &str) { - let c_string = CString::new(xds).expect("CString::new failed"); - self.xds_str = c_string.into_raw(); - self.xds_len = xds.len(); - } - - pub fn free_xds_str(&mut self) { - if !self.xds_str.is_null() { - unsafe { - let _ = CString::from_raw(self.xds_str); - } - self.xds_str = std::ptr::null_mut(); - self.xds_len = 0; - } - } - } - - impl Drop for Eia608Screen { - fn drop(&mut self) { - self.free_xds_str(); - } - } - - pub type SubDataType = std::os::raw::c_uint; - pub type LLONG = i64; - pub const SUBTYPE_CC_BITMAP: Subtype = 0; - pub const SUBTYPE_CC_608: Subtype = 1; - pub const SUBTYPE_CC_TEXT: Subtype = 2; - pub const SUBTYPE_CC_RAW: Subtype = 3; - pub type Subtype = std::os::raw::c_uint; - - pub type CcxEncodingType = std::os::raw::c_uint; - - pub struct CcSubtitle { - #[doc = " A generic data which contain data according to decoder\n @warn decoder cant output multiple types of data"] - pub data: *mut std::os::raw::c_void, - pub datatype: SubDataType, - #[doc = " number of data"] - pub nb_data: std::os::raw::c_uint, - #[doc = " type of subtitle"] - pub type_: Subtype, - #[doc = " Encoding type of Text, must be ignored in case of subtype as bitmap or cc_screen"] - pub enc_type: CcxEncodingType, - pub start_time: LLONG, - pub end_time: LLONG, - pub flags: c_int, - pub lang_index: c_int, - #[doc = " flag to tell that decoder has given output"] - pub got_output: c_int, - pub mode: [c_char; 5usize], - pub info: [c_char; 4usize], - #[doc = " Used for DVB end time in ms"] - pub time_out: c_int, - pub next: *mut CcSubtitle, - pub prev: *mut CcSubtitle, - } - - #[repr(C)] - #[derive(Debug)] - pub enum CcxShareStatus { - Ok = 0, - Fail, - } - impl PartialEq for CcxShareStatus { - fn eq(&self, other: &Self) -> bool { - matches!( - (self, other), - (CcxShareStatus::Ok, CcxShareStatus::Ok) - | (CcxShareStatus::Fail, CcxShareStatus::Fail) - ) - } - } - pub struct CcxShareServiceCtx { - counter: i64, - stream_name: Option, - nn_sock: c_int, - nn_binder: c_int, - } - - pub struct CcxSubEntries { - pub messages: Vec, - } - impl CcxShareServiceCtx { - fn new() -> Self { - CcxShareServiceCtx { - counter: 0, - stream_name: None, - nn_sock: 0, - nn_binder: 0, - } - } - } - - lazy_static! { - pub static ref CCX_SHARE_CTX: Mutex = - Mutex::new(CcxShareServiceCtx::new()); - } - - pub fn ccxr_sub_entry_msg_init(msg: &mut CcxSubEntryMessage) { - msg.eos = 0; - msg.stream_name = "".parse().unwrap(); - msg.counter = 0; - msg.start_time = 0; - msg.end_time = 0; - msg.lines.clear(); - } - - pub fn ccxr_sub_entry_msg_cleanup(msg: &mut CcxSubEntryMessage) { - msg.lines.clear(); - msg.stream_name = "".parse().unwrap(); - } - - pub fn ccxr_sub_entry_msg_print(msg: &CcxSubEntryMessage) { - if msg.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); - return; - } - - debug!(msg_type = DebugMessageFlag::SHARE; "\n[share] sub msg #{}", msg.counter); - if !msg.stream_name.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: {}", msg.stream_name); - } else { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] name: None"); - } - debug!(msg_type = DebugMessageFlag::SHARE; "[share] start: {}", msg.start_time); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] end: {}", msg.end_time); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] lines count: {}", msg.lines.len()); - - if msg.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] no lines allocated"); - return; - } - for (i, line) in msg.lines.iter().enumerate() { - if !line.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}]: {}", i, line); - } else { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] line[{}] is not allocated", i); - } - } - } - - pub fn ccxr_sub_entries_cleanup(entries: &mut CcxSubEntries) { - entries.messages.clear(); - } - - pub fn ccxr_sub_entries_print(entries: &CcxSubEntries) { - eprintln!( - "[share] ccxr_sub_entries_print ({} entries)", - entries.messages.len() - ); - for message in &entries.messages { - ccxr_sub_entry_msg_print(message); - } - } - /// # Safety - /// This function is unsafe as it calls unsafe functions like nn_socket and nn_bind. - pub unsafe fn ccxr_share_start(stream_name: Option<&str>) -> CcxShareStatus { - let mut ccx_options = CCX_OPTIONS.lock().unwrap(); - - // Debug print similar to dbg_print in C - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: starting service\n"); - - // Create a nanomsg socket with domain AF_SP and protocol NN_PUB - let nn_sock = nn_socket(AF_SP, NN_PUB); - if nn_sock < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_socket()\n"); - return CcxShareStatus::Fail; - } - CCX_SHARE_CTX.lock().unwrap().nn_sock = nn_sock; - // Set a default URL if one was not already provided. - if ccx_options.sharing_url.is_none() { - ccx_options.sharing_url = Some("tcp://*:3269".to_string().parse().unwrap()); - } - - // Convert the sharing URL into a C-compatible string. - let url = ccx_options.sharing_url.as_ref().unwrap(); - let sharing_url_cstr = CString::new(url.as_str()).expect("Failed to create CString"); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: url={}", ccx_options.sharing_url.as_mut().unwrap()); - - // Bind the socket to the URL. - let nn_binder = nn_bind(nn_sock, sharing_url_cstr.as_ptr()); - if nn_binder < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_bind()"); - return CcxShareStatus::Fail; - } - CCX_SHARE_CTX.lock().unwrap().nn_binder = nn_binder; - - // Set the linger socket option to -1. - let linger: i32 = -1; - let ret = nn_setsockopt( - nn_sock, - NN_SOL_SOCKET, - NN_LINGER, - &linger as *const _ as *const c_void, - size_of::(), - ); - if ret < 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_start: can't nn_setsockopt()"); - return CcxShareStatus::Fail; - } - - // Save the stream name into the context, defaulting to "unknown" if not provided. - CCX_SHARE_CTX.lock().unwrap().stream_name = - Some(stream_name.unwrap_or("unknown").to_string()); - - // Sleep for 1 second to allow subscribers to connect. - thread::sleep(Duration::from_secs(1)); - - CcxShareStatus::Ok - } - /// # Safety - /// This function is unsafe as it calls unsafe functions like nn_shutdown. - pub unsafe fn ccxr_share_stop() -> CcxShareStatus { - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stop: stopping service"); - - nn_shutdown( - CCX_SHARE_CTX.lock().unwrap().nn_sock, - CCX_SHARE_CTX.lock().unwrap().nn_binder, - ); - ctx.stream_name = None; - CcxShareStatus::Ok - } - /// # Safety - /// This function is unsafe as it calls unsafe functions like _ccxr_share_send. - pub unsafe fn ccxr_share_send(sub: *mut CcSubtitle) -> CcxShareStatus { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending"); - - // Create an entries structure and populate it from the subtitle. - let mut entries = CcxSubEntries { - messages: Vec::new(), - }; - if ccxr_share_sub_to_entries(&*sub, &mut entries) == CcxShareStatus::Fail { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] failed to convert subtitle to entries"); - return CcxShareStatus::Fail; - } - - // Debug print of entries. - ccxr_sub_entries_print(&entries); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] entry obtained:"); - - // Iterate over all entries and send them. - for (i, message) in entries.messages.iter().enumerate() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_send: sending entry {}", i); - if entries.messages[i].lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] skipping empty message"); - continue; - } - if _ccxr_share_send(message) != CcxShareStatus::Ok { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] can't send message"); - return CcxShareStatus::Fail; - } - } - - ccxr_sub_entries_cleanup(&mut entries); - CcxShareStatus::Ok - } - - pub fn ccxr_sub_entry_message_get_packed_size(message: &CcxSubEntryMessage) -> usize { - message.encoded_len() - } - - pub fn ccxr_sub_entry_message_pack( - message: &CcxSubEntryMessage, - buf: &mut Vec, - ) -> Result<(), prost::EncodeError> { - message.encode(buf) - } - - /// # Safety - /// This function is unsafe as it calls unsafe functions like nn_send - pub unsafe fn _ccxr_share_send(msg: &CcxSubEntryMessage) -> CcxShareStatus { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send"); - - let len: usize = ccxr_sub_entry_message_get_packed_size(msg); - - // Allocate a buffer to hold the packed message. - let mut buf = Vec::with_capacity(len); - if buf.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: malloc failed"); - return CcxShareStatus::Fail; - } - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: packing"); - ccxr_sub_entry_message_pack(msg, &mut buf).expect("Failed to pack message"); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sending"); - let sent: c_int = nn_send( - CCX_SHARE_CTX.lock().unwrap().nn_sock, - buf.as_ptr() as *const c_void, - len, - 0, - ); - if sent != len as c_int { - buf.clear(); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: len={} sent={}", len, sent); - return CcxShareStatus::Fail; - } - buf.clear(); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_send: sent"); - CcxShareStatus::Ok - } - - /// # Safety - /// This function is unsafe as it calls unsafe functions like _ccxr_share_send - pub unsafe fn ccxr_share_stream_done(stream_name: &str) -> CcxShareStatus { - let mut msg = CcxSubEntryMessage { - eos: 1, - stream_name: stream_name.parse().unwrap(), - counter: 0, - start_time: 0, - end_time: 0, - lines: Vec::new(), - }; - #[allow(unused)] - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - if _ccxr_share_send(&msg) != CcxShareStatus::Ok { - ccxr_sub_entry_msg_cleanup(&mut msg); - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: can't send message"); - return CcxShareStatus::Fail; - } - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccx_share_stream_done: message sent successfully"); - CcxShareStatus::Ok - } - - pub fn ccxr_share_sub_to_entries( - sub: &CcSubtitle, - entries: &mut CcxSubEntries, - ) -> CcxShareStatus { - unsafe { - let mut ctx = CCX_SHARE_CTX.lock().unwrap(); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] _ccx_share_sub_to_entries"); - - if sub.type_ == SUBTYPE_CC_608 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_608"); - - let data_ptr = sub.data as *const Eia608Screen; - let mut nb_data = sub.nb_data; - - while nb_data > 0 { - let data = &*data_ptr.add(sub.nb_data as usize - nb_data as usize); - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] data item"); - - if data.format == CcxEia608Format::SFormatXds { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] XDS. Skipping"); - nb_data -= 1; - continue; - } - - if data.start_time == 0 { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] No start time. Skipping"); - break; - } - - entries.messages.push(CcxSubEntryMessage { - eos: 0, - stream_name: String::new(), - counter: ctx.counter + 1, - start_time: data.start_time, - end_time: data.end_time, - lines: Vec::new(), - }); - - let entry_index = entries.messages.len() - 1; - let entry = &mut entries.messages[entry_index]; - - for row in 0..CCX_DECODER_608_SCREEN_ROWS { - if data.row_used[row] != 0 { - let characters = CStr::from_ptr(data.characters[row].as_ptr()) - .to_string_lossy() - .to_string(); - entry.lines.push(characters); - } - } - - if entry.lines.is_empty() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] buffer is empty"); - entries.messages.pop(); - return CcxShareStatus::Ok; - } - - debug!( - msg_type = DebugMessageFlag::SHARE; - "[share] Copied {} lines", entry.lines.len() - ); - - ctx.counter += 1; - nb_data -= 1; - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] item done"); - } - } else { - match sub.type_ { - SUBTYPE_CC_BITMAP => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_BITMAP. Skipping"); - } - SUBTYPE_CC_RAW => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_RAW. Skipping"); - } - SUBTYPE_CC_TEXT => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] CC_TEXT. Skipping"); - } - _ => { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] Unknown subtitle type"); - } - } - } - - debug!(msg_type = DebugMessageFlag::SHARE; "[share] done"); - CcxShareStatus::Ok - } - } -} diff --git a/src/rust/lib_ccxr/src/share/mod.rs b/src/rust/lib_ccxr/src/share/mod.rs deleted file mode 100644 index f23d0d08d..000000000 --- a/src/rust/lib_ccxr/src/share/mod.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! Module `share` broadcasts subtitle entries over a pub/sub message bus -//! (Nanomsg) and to interoperate with C code via C-compatible FFI bindings. -//! -//! # Overview -//! -//! - CcxSubEntryMessage Represents a single subtitle entry, including timing and text lines. -//! - CcxSubEntries is A collection of `CcxSubEntryMessage` instances generated from a subtitle frame. -//! - CcxShareStatus Enumeration of possible return statuses for share operations. -//! - Ccx_share_ctx Global context holding the Nanomsg socket and stream metadata. -//! -//! ## Features -//! -//! - Initialize and manage a Nanomsg PUB socket for broadcasting messages. -//! - Convert internal `CcSubtitle` frames into one or more [`CcxSubEntryMessage`] instances. -//! - Send packed protobuf messages over the socket, handling lifecycle of messages. -//! - Signal end-of-stream events to subscribers. -//! - Launch external translation processes via system calls. -//! -//! # C-Compatible API -//! -//! All `extern "C"` functions are safe to call from C code and mirror the underlying Rust logic. -//! -//! ## Message Cleanup and Printing -//!| C Function | Rust Binding | -//!|---------------------------------------|--------------------------------------| -//!| [`ccx_sub_entry_msg_cleanup`] | [`ccxr_sub_entry_msg_cleanup`] | -//!| [`ccx_sub_entry_msg_print`] | [`ccxr_sub_entry_msg_print`] | -//!| [`ccx_sub_entries_cleanup`] | [`ccxr_sub_entries_cleanup`] | -//!| [`ccx_sub_entries_print`] | [`ccxr_sub_entries_print`] | -//! -//! ## Service Control -//!| C Function | Rust Binding | -//!|----------------------|-------------------------------| -//!| [`ccx_share_start`] | [`ccxr_share_start`] | -//!| [`ccx_share_stop`] | [`ccxr_share_stop`] | -//! -//! ## Sending Subtitles -//!| C Function | Rust Binding | -//!|-----------------------------|-------------------------------| -//!| [`ccx_share_send`] | [`ccxr_share_send`] | -//!| [`_ccx_share_send`] | [`_ccxr_share_send`] | -//!| [`ccx_share_stream_done`] | [`ccxr_share_stream_done`] | -//!| [`_ccx_share_sub_to_entries`] | [`_ccxr_share_sub_to_entries`]| -//! -//! ## Translator Launch -//!| C Function | Description | -//!|-------------------------------|-------------------------------------------------| -//!| `ccx_share_launch_translator` | Spawn external `cctranslate` process for translation. -//! -//!# Nanomsg Options -//! -//! - Default URL: `tcp://*:3269` (configurable via `ccx_options.sharing_url`). -//! - Linger option set to infinite to ensure messages are delivered before shutdown. - -use crate::share::functions::sharing::{ - ccxr_sub_entries_cleanup, ccxr_sub_entries_print, ccxr_sub_entry_msg_cleanup, - ccxr_sub_entry_msg_print, -}; - -pub mod ccxr_sub_entry_message; -pub mod functions; -pub mod tests; diff --git a/src/rust/lib_ccxr/src/share/tests.rs b/src/rust/lib_ccxr/src/share/tests.rs deleted file mode 100644 index ecb845222..000000000 --- a/src/rust/lib_ccxr/src/share/tests.rs +++ /dev/null @@ -1,296 +0,0 @@ -#![allow(unused_imports)] -#![allow(unused)] - -#[cfg(feature = "enable_sharing")] -mod test { - use crate::share::ccxr_sub_entry_message::*; - use crate::share::functions::sharing::*; - use crate::util::log::{ - set_logger, CCExtractorLogger, DebugMessageFlag, DebugMessageMask, OutputTarget, - }; - use std::os::raw::c_char; - use std::sync::Once; - - static INIT: Once = Once::new(); - - fn initialize_logger() { - INIT.call_once(|| { - set_logger(CCExtractorLogger::new( - OutputTarget::Stdout, - DebugMessageMask::new(DebugMessageFlag::VERBOSE, DebugMessageFlag::VERBOSE), - false, - )) - .ok(); - }); - } - #[test] - fn test_ffi_sub_entry_msg_cleanup() { - let mut msg = CcxSubEntryMessage { - eos: 0, - stream_name: "test".to_string(), - counter: 0, - start_time: 0, - end_time: 0, - lines: vec!["test".to_string()], - }; - - unsafe { - ccxr_sub_entry_msg_cleanup(&mut *(&mut msg as *mut CcxSubEntryMessage)); - } - - assert!(msg.lines.is_empty()); - assert_eq!(msg.stream_name, ""); - } - - #[test] - fn test_ffi_sub_entry_msg_print() { - let msg = CcxSubEntryMessage { - eos: 0, - stream_name: "test".to_string(), - counter: 0, - start_time: 0, - end_time: 0, - lines: vec!["test".to_string(), "test".to_string(), "test".to_string()], - }; - - unsafe { - ccxr_sub_entry_msg_print(&*(&msg as *const CcxSubEntryMessage)); - } - } - #[test] - fn test_ffi_sub_entries_init() { - let mut entries = CcxSubEntries { - messages: vec![CcxSubEntryMessage { - eos: 0, - counter: 1, - stream_name: "Test".parse().unwrap(), - start_time: 0, - end_time: 0, - lines: vec![], - }], - }; - - unsafe { - ccxr_sub_entries_cleanup(&mut *(&mut entries as *mut CcxSubEntries)); - } - - assert!(entries.messages.is_empty()); - } - - #[test] - fn test_ffi_sub_entries_cleanup() { - let mut entries = CcxSubEntries { - messages: vec![CcxSubEntryMessage { - eos: 0, - counter: 1, - stream_name: "Test".parse().unwrap(), - start_time: 0, - end_time: 0, - lines: vec![], - }], - }; - - unsafe { - ccxr_sub_entries_cleanup(&mut *(&mut entries as *mut CcxSubEntries)); - } - - assert!(entries.messages.is_empty()); - } - - #[test] - fn test_ffi_sub_entries_print() { - let entries = CcxSubEntries { - messages: vec![CcxSubEntryMessage { - eos: 0, - counter: 1, - stream_name: "Test".parse().unwrap(), - start_time: 0, - end_time: 0, - lines: vec![], - }], - }; - - unsafe { - ccxr_sub_entries_print(&*(&entries as *const CcxSubEntries)); - } - } - - #[test] - fn test_ccxr_share_send() { - initialize_logger(); - - let mut sub = CcSubtitle { - data: std::ptr::null_mut(), - datatype: 1, - nb_data: 0, - type_: 1, - enc_type: 1, - start_time: 0, - end_time: 0, - flags: 0, - lang_index: 0, - got_output: 0, - mode: [0; 5], - info: [0; 4], - time_out: 0, - next: std::ptr::null_mut(), - prev: std::ptr::null_mut(), - }; - let status = unsafe { ccxr_share_send(&mut sub as *mut CcSubtitle) }; - assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); - } - - #[test] - fn test_ccxr_share_send_c() { - initialize_logger(); - let msg = CcxSubEntryMessage { - eos: 0, - stream_name: "test_stream".to_string(), - counter: 1, - start_time: 0, - end_time: 0, - lines: vec!["Line 1".to_string(), "Line 2".to_string()], - }; - - let status = unsafe { _ccxr_share_send(&*(&msg as *const CcxSubEntryMessage)) }; - assert!(matches!(status, CcxShareStatus::Ok | CcxShareStatus::Fail)); - } - - const CCX_DECODER_608_SCREEN_WIDTH: usize = 32; - const CCX_DECODER_608_SCREEN_ROWS: usize = 15; - - #[test] - fn test_ccxr_share_sub_to_entries() { - initialize_logger(); - const NUM_ROWS: usize = CCX_DECODER_608_SCREEN_ROWS; - let mut screen = Eia608Screen::new(); - screen.row_used[0] = 1; - screen.row_used[2] = 1; - screen.row_used[4] = 1; - - let row_0_content = b"Hello, World!"; - let row_2_content = b"Subtitle line 2"; - let row_4_content = b"Subtitle line 3"; - - for (i, &ch) in row_0_content.iter().enumerate() { - screen.characters[0][i] = ch as c_char; - } - for (i, &ch) in row_2_content.iter().enumerate() { - screen.characters[2][i] = ch as c_char; - } - for (i, &ch) in row_4_content.iter().enumerate() { - screen.characters[4][i] = ch as c_char; - } - - screen.start_time = 1000; - screen.end_time = 2000; - screen.mode = CcModes::ModePaintOn; - screen.channel = 1; - screen.my_field = 42; - - let sub = CcSubtitle { - data: &screen as *const _ as *mut std::os::raw::c_void, - datatype: 1, - nb_data: 1, - type_: SUBTYPE_CC_608, - enc_type: 1, - start_time: 0, - end_time: 0, - flags: 0, - lang_index: 0, - got_output: 1, - mode: [ - b'M' as c_char, - b'O' as c_char, - b'D' as c_char, - b'E' as c_char, - 0, - ], - info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], - time_out: 0, - next: std::ptr::null_mut(), - prev: std::ptr::null_mut(), - }; - let mut entries = CcxSubEntries { - messages: Vec::new(), - }; - let status = ccxr_share_sub_to_entries(&sub, &mut entries); - assert_eq!( - status, - CcxShareStatus::Ok, - "Function should return OK status" - ); - assert_eq!( - entries.messages.len(), - 1, - "There should be one entry in messages" - ); - - let message = &entries.messages[0]; - assert_eq!(message.start_time, 1000, "Start time should match input"); - assert_eq!(message.end_time, 2000, "End time should match input"); - assert_eq!(message.lines.len(), 3, "There should be 3 lines of content"); - - assert_eq!( - message.lines[0], "Hello, World!", - "First line content mismatch" - ); - assert_eq!( - message.lines[1], "Subtitle line 2", - "Second line content mismatch" - ); - assert_eq!( - message.lines[2], "Subtitle line 3", - "Third line content mismatch" - ); - } - - #[test] - fn test_ccxr_share_sub_to_entries_empty_rows() { - let mut screen = Eia608Screen::new(); - - screen.start_time = 1000; - screen.end_time = 2000; - - let sub = CcSubtitle { - data: &screen as *const _ as *mut std::os::raw::c_void, - datatype: 1, - nb_data: 1, - type_: SUBTYPE_CC_608, - enc_type: 1, - start_time: 0, - end_time: 0, - flags: 0, - lang_index: 0, - got_output: 1, - mode: [ - b'M' as c_char, - b'O' as c_char, - b'D' as c_char, - b'E' as c_char, - 0, - ], - info: [b'I' as c_char, b'N' as c_char, b'F' as c_char, 0], - time_out: 0, - next: std::ptr::null_mut(), - prev: std::ptr::null_mut(), - }; - - let mut entries = CcxSubEntries { - messages: Vec::new(), - }; - - let status = ccxr_share_sub_to_entries(&sub, &mut entries); - - assert_eq!( - status, - CcxShareStatus::Ok, - "Function should return OK status" - ); - assert_eq!( - entries.messages.len(), - 0, - "There should be no messages for empty rows" - ); - } -} diff --git a/src/rust/lib_ccxr/src/util/log.rs b/src/rust/lib_ccxr/src/util/log.rs index 5aa7d9952..66d8bb154 100644 --- a/src/rust/lib_ccxr/src/util/log.rs +++ b/src/rust/lib_ccxr/src/util/log.rs @@ -86,9 +86,6 @@ bitflags! { const DVB = 0x2000; /// Dump defective TS packets const DUMP_DEF = 0x4000; - /// Extracted captions sharing service - #[cfg(feature = "enable_sharing")] - const SHARE = 0x8000; } } diff --git a/src/rust/src/args.rs b/src/rust/src/args.rs index dbc9cb1ec..bdc6bcca5 100644 --- a/src/rust/src/args.rs +++ b/src/rust/src/args.rs @@ -1,4 +1,3 @@ -use cfg_if::cfg_if; use clap::{Parser, ValueEnum}; use strum_macros::Display; @@ -26,13 +25,6 @@ const TRANSCRIPT_OPTIONS: &str = "Transcript customizing options"; const COMMUNICATION_PROTOCOL: &str = "Communication with other programs and console output"; const BURNEDIN_SUBTITLE_EXTRACTION: &str = "Burned-in subtitle extraction"; -cfg_if! { - if #[cfg(feature = "enable_sharing")] { - const SHARING_EXTRACTED_CAPTIONS: &str = "Sharing extracted captions via TCP"; - const CCTRANSLATE_INTEGRATION: &str = "CCTranslate application integration"; - } -} - #[derive(Debug, Parser)] #[command(name = "CCExtractor")] #[command(author = "Carlos Fernandez Sanz, Volker Quetschke.")] @@ -818,10 +810,6 @@ pub struct Args { /// to find data in all packets by scanning. #[arg(long, verbatim_doc_comment, help_heading=OUTPUT_AFFECTING_DEBUG_DATA)] pub investigate_packets: bool, - #[cfg(feature = "enable_sharing")] - /// Print extracted CC sharing service messages - #[arg(long, verbatim_doc_comment, help_heading=OUTPUT_AFFECTING_DEBUG_DATA)] - pub sharing_debug: bool, /// Use this page for subtitles (if this parameter /// is not used, try to autodetect). In Spain the /// page is always 888, may vary in other countries. @@ -874,23 +862,6 @@ pub struct Args { /// Don't write any message. #[arg(long, verbatim_doc_comment, help_heading=COMMUNICATION_PROTOCOL)] pub quiet: bool, - #[cfg(feature = "enable_sharing")] - /// Enables real-time sharing of extracted captions - #[arg(long, verbatim_doc_comment, help_heading=SHARING_EXTRACTED_CAPTIONS)] - pub enable_sharing: bool, - #[cfg(feature = "enable_sharing")] - /// Set url for sharing service in nanomsg format. Default: tcp://*:3269 - #[arg(long, value_name="url", verbatim_doc_comment, help_heading=SHARING_EXTRACTED_CAPTIONS)] - pub sharing_url: Option, - #[cfg(feature = "enable_sharing")] - /// Enables real-time sharing of extracted captions - #[arg(long, value_name="languages", verbatim_doc_comment, help_heading=CCTRANSLATE_INTEGRATION)] - pub translate: Option, - #[cfg(feature = "enable_sharing")] - /// Set Translation Service authorization data to make translation possible - /// In case of Google Translate API - API Key - #[arg(long, verbatim_doc_comment, help_heading=CCTRANSLATE_INTEGRATION)] - pub translate_auth: Option, /// Enable the burned-in subtitle extraction subsystem. /// /// NOTE: This is needed to use the below burned-in diff --git a/src/rust/src/common.rs b/src/rust/src/common.rs index 4de6dd7e0..3e3db5b6a 100644 --- a/src/rust/src/common.rs +++ b/src/rust/src/common.rs @@ -222,21 +222,6 @@ pub unsafe fn copy_from_rust(ccx_s_options: *mut ccx_s_options, options: Options string_to_c_char(&options.curlposturl.as_ref().unwrap_or_default().as_str()); } } - #[cfg(feature = "enable_sharing")] - { - (*ccx_s_options).sharing_enabled = options.sharing_enabled as _; - if options.sharing_url.is_some() { - (*ccx_s_options).sharing_url = - string_to_c_char(&options.sharing_url.as_ref().unwrap().as_str()); - } - (*ccx_s_options).translate_enabled = options.translate_enabled as _; - if options.translate_langs.is_some() { - (*ccx_s_options).translate_langs = string_to_c_char(&options.translate_langs.unwrap()); - } - if options.translate_key.is_some() { - (*ccx_s_options).translate_key = string_to_c_char(&options.translate_key.unwrap()); - } - } } impl CType2 for TeletextConfig { diff --git a/src/rust/src/libccxr_exports/mod.rs b/src/rust/src/libccxr_exports/mod.rs index 7b971dbf8..d4ed4ef8c 100644 --- a/src/rust/src/libccxr_exports/mod.rs +++ b/src/rust/src/libccxr_exports/mod.rs @@ -1,13 +1,7 @@ //! Provides C-FFI functions that are direct equivalent of functions available in C. - pub mod bitstream; pub mod time; - - -#[cfg(feature = "enable_sharing")] -pub mod share; -pub mod time; use crate::ccx_options; use lib_ccxr::util::log::*; use lib_ccxr::util::{bits::*, levenshtein::*}; diff --git a/src/rust/src/libccxr_exports/share.rs b/src/rust/src/libccxr_exports/share.rs deleted file mode 100644 index 6213876a8..000000000 --- a/src/rust/src/libccxr_exports/share.rs +++ /dev/null @@ -1,118 +0,0 @@ -use lib_ccxr::share::ccxr_sub_entry_message::*; -use lib_ccxr::share::functions::sharing::*; -use lib_ccxr::util::log::{debug, DebugMessageFlag}; -use std::ffi::CStr; -/// C-compatible function to clean up a `CcxSubEntryMessage`. -#[no_mangle] -pub extern "C" fn ccxr_sub_entry_msg_cleanup_c(msg: *mut CcxSubEntryMessage) { - unsafe { - if msg.is_null() { - return; - } - let msg = &mut *msg; - ccxr_sub_entry_msg_cleanup(msg); - } -} - -/// C-compatible function to print a `CcxSubEntryMessage`. -#[no_mangle] -pub unsafe extern "C" fn ccxr_sub_entry_msg_print_c(msg: *const CcxSubEntryMessage) { - if msg.is_null() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] print(!msg)\n"); - return; - } - - let msg = &*msg; - - // Call the main Rust function - ccxr_sub_entry_msg_print(msg); -} - -#[no_mangle] -pub unsafe extern "C" fn ccxr_sub_entries_cleanup_c(entries: *mut CcxSubEntries) { - if entries.is_null() { - return; - } - let entries = &mut *entries; - ccxr_sub_entries_cleanup(entries); -} - -#[no_mangle] -pub unsafe extern "C" fn ccxr_sub_entries_print_c(entries: *const CcxSubEntries) { - if entries.is_null() { - debug!(msg_type = DebugMessageFlag::SHARE; "[share] ccxr_sub_entries_print (null entries)\n"); - return; - } - let entries = &*entries; - ccxr_sub_entries_print(entries); -} - -/// C-compatible function to start the sharing service. -#[no_mangle] -pub unsafe extern "C" fn ccxr_share_start_c( - stream_name: *const std::os::raw::c_char, -) -> CcxShareStatus { - if stream_name.is_null() { - return ccxr_share_start(Option::from("unknown")); - } - - let c_str = CStr::from_ptr(stream_name); - let stream_name = match c_str.to_str() { - Ok(name) => name, - Err(_) => return CcxShareStatus::Fail, - }; - - ccxr_share_start(Option::from(stream_name)) -} -#[no_mangle] -pub unsafe extern "C" fn ccxr_share_stop_c() -> CcxShareStatus { - ccxr_share_stop() -} - -#[no_mangle] -pub unsafe extern "C" fn _ccxr_share_send_c(msg: *const CcxSubEntryMessage) -> CcxShareStatus { - if msg.is_null() { - return CcxShareStatus::Fail; - } - _ccxr_share_send(&*msg) -} - -#[no_mangle] -pub unsafe extern "C" fn ccxr_share_send_c(sub: *const CcSubtitle) -> CcxShareStatus { - if sub.is_null() { - return CcxShareStatus::Fail; - } - ccxr_share_send(sub as *mut CcSubtitle) -} - -#[no_mangle] -pub unsafe extern "C" fn ccxr_share_stream_done_c( - stream_name: *const std::os::raw::c_char, -) -> CcxShareStatus { - if stream_name.is_null() { - return CcxShareStatus::Fail; - } - - let c_str = CStr::from_ptr(stream_name); - match c_str.to_str() { - Ok(name) => ccxr_share_stream_done(name), - Err(_) => CcxShareStatus::Fail, - } -} - -/// C-compatible function to convert subtitles to sub-entry messages. -#[no_mangle] -pub unsafe extern "C" fn _ccxr_share_sub_to_entries_c( - sub: *const CcSubtitle, - entries: *mut CcxSubEntries, -) -> CcxShareStatus { - if sub.is_null() || entries.is_null() { - return CcxShareStatus::Fail; - } - - // Dereference the pointers safely - let sub_ref = &*sub; - let entries_ref = &mut *entries; - - ccxr_share_sub_to_entries(sub_ref, entries_ref) -} diff --git a/src/rust/src/parser.rs b/src/rust/src/parser.rs index 98b3e56a2..34cf95be5 100644 --- a/src/rust/src/parser.rs +++ b/src/rust/src/parser.rs @@ -1124,15 +1124,6 @@ impl OptionsExt for Options { tlt_config.verbose = true; } - #[cfg(feature = "enable_sharing")] - { - if args.sharing_debug { - self.debug_mask = - DebugMessageMask::new(DebugMessageFlag::SHARE, DebugMessageFlag::VERBOSE); - tlt_config.verbose = true; - } - } - if args.fullbin { self.fullbin = true; } @@ -1425,27 +1416,6 @@ impl OptionsExt for Options { } } - #[cfg(feature = "enable_sharing")] - { - if args.enable_sharing { - self.sharing_enabled = true; - } - - if let Some(ref sharingurl) = args.sharing_url { - self.sharing_url = Some(sharingurl.to_string().parse().unwrap()); - } - - if let Some(ref translate) = args.translate { - self.translate_enabled = true; - self.sharing_enabled = true; - self.translate_langs = Some(translate.to_string()); - } - - if let Some(ref translateauth) = args.translate_auth { - self.translate_key = Some(translateauth.to_string()); - } - } - if self.demux_cfg.auto_stream == StreamMode::Mp4 && self.input_source == DataSource::Stdin { fatal!( cause = ExitCause::IncompatibleParameters; diff --git a/windows/ccextractor.vcxproj b/windows/ccextractor.vcxproj index 296793c4e..033a802ae 100644 --- a/windows/ccextractor.vcxproj +++ b/windows/ccextractor.vcxproj @@ -15,7 +15,6 @@ - diff --git a/windows/ccextractor.vcxproj.filters b/windows/ccextractor.vcxproj.filters index b7afa5a48..4c9560492 100644 --- a/windows/ccextractor.vcxproj.filters +++ b/windows/ccextractor.vcxproj.filters @@ -165,9 +165,6 @@ Header Files - - Header Files\lib_ccx - Header Files\lib_ccx From 20a32a5b53bf688aa86326d5151ed1a4b0b4fa22 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 16 Aug 2025 01:45:52 +0530 Subject: [PATCH 05/13] Share: formatting issues --- src/lib_ccx/ccx_encoders_common.c | 1 - src/lib_ccx/ccx_encoders_splitbysentence.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/lib_ccx/ccx_encoders_common.c b/src/lib_ccx/ccx_encoders_common.c index 04281a49d..3196d3500 100644 --- a/src/lib_ccx/ccx_encoders_common.c +++ b/src/lib_ccx/ccx_encoders_common.c @@ -1091,7 +1091,6 @@ int encode_sub(struct encoder_ctx *context, struct cc_subtitle *sub) context = change_filename(context); - if (context->sbs_enabled) { // Write to a buffer that is later s+plit to generate split diff --git a/src/lib_ccx/ccx_encoders_splitbysentence.c b/src/lib_ccx/ccx_encoders_splitbysentence.c index 34a49b871..c9bacfac1 100644 --- a/src/lib_ccx/ccx_encoders_splitbysentence.c +++ b/src/lib_ccx/ccx_encoders_splitbysentence.c @@ -27,7 +27,6 @@ #define LOG_DEBUG(...) #endif - //--------------------------- // BEGIN of #BUG639 // HACK: this is workaround for https://github.com/CCExtractor/ccextractor/issues/639 From 009febeab360effc1b1169a9d8a56139274d3f16 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 16 Aug 2025 01:51:56 +0530 Subject: [PATCH 06/13] Share: failing CI --- linux/Makefile.am | 1 - mac/Makefile.am | 1 - windows/ccextractor.vcxproj | 1 - windows/ccextractor.vcxproj.filters | 3 --- 4 files changed, 6 deletions(-) diff --git a/linux/Makefile.am b/linux/Makefile.am index 9996acf3f..f705e4d64 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -123,7 +123,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.c \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ - ../src/lib_ccx/ccx_share.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ diff --git a/mac/Makefile.am b/mac/Makefile.am index 20ce21451..83c492fc7 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -95,7 +95,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.c \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ - ../src/lib_ccx/ccx_share.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ diff --git a/windows/ccextractor.vcxproj b/windows/ccextractor.vcxproj index 033a802ae..d5667022f 100644 --- a/windows/ccextractor.vcxproj +++ b/windows/ccextractor.vcxproj @@ -103,7 +103,6 @@ - diff --git a/windows/ccextractor.vcxproj.filters b/windows/ccextractor.vcxproj.filters index 4c9560492..123738e93 100644 --- a/windows/ccextractor.vcxproj.filters +++ b/windows/ccextractor.vcxproj.filters @@ -380,9 +380,6 @@ Source Files - - Source Files - Source Files From c3e471784594a581cd66a68723003da6fc50d3e5 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 16 Aug 2025 01:54:18 +0530 Subject: [PATCH 07/13] Share: failing CI --- linux/Makefile.am | 2 -- mac/Makefile.am | 2 -- windows/ccextractor.vcxproj | 5 ----- windows/ccextractor.vcxproj.filters | 9 --------- 4 files changed, 18 deletions(-) diff --git a/linux/Makefile.am b/linux/Makefile.am index f705e4d64..ec06dc760 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -123,8 +123,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.c \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ - ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ - ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ ../src/lib_ccx/compile_info_real.h \ ../src/lib_ccx/configuration.c \ diff --git a/mac/Makefile.am b/mac/Makefile.am index 83c492fc7..df0ec8072 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -95,8 +95,6 @@ ccextractor_SOURCES = \ ../src/lib_ccx/ccx_gxf.c \ ../src/lib_ccx/ccx_gxf.h \ ../src/lib_ccx/ccx_mp4.h \ - ../src/lib_ccx/ccx_sub_entry_message.pb-c.c \ - ../src/lib_ccx/ccx_sub_entry_message.pb-c.h \ ../src/lib_ccx/compile_info.h \ ../src/lib_ccx/compile_info_real.h \ ../src/lib_ccx/configuration.c \ diff --git a/windows/ccextractor.vcxproj b/windows/ccextractor.vcxproj index d5667022f..225bf11ec 100644 --- a/windows/ccextractor.vcxproj +++ b/windows/ccextractor.vcxproj @@ -15,7 +15,6 @@ - @@ -103,7 +102,6 @@ - @@ -181,9 +179,6 @@ - - - {0F0063C4-BCBC-4379-A6D5-84A5669C940A} ccextractor diff --git a/windows/ccextractor.vcxproj.filters b/windows/ccextractor.vcxproj.filters index 123738e93..6490853fe 100644 --- a/windows/ccextractor.vcxproj.filters +++ b/windows/ccextractor.vcxproj.filters @@ -165,9 +165,6 @@ Header Files - - Header Files\lib_ccx - Header Files\lib_ccx @@ -380,9 +377,6 @@ Source Files - - Source Files - Source Files @@ -612,7 +606,4 @@ Source Files - - - \ No newline at end of file From a0b2ca28c96357465d0d9154d94a1b53280a44c1 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sat, 16 Aug 2025 12:03:13 +0530 Subject: [PATCH 08/13] Share: Removed protobuf --- .gitignore | 2 - linux/Makefile.am | 4 +- linux/build | 5 +- linux/module_generator | 3 +- mac/Makefile.am | 4 +- mac/build.command | 5 +- src/BUILD | 3 +- src/CMakeLists.txt | 2 - src/lib_ccx/BUILD | 6 +- src/lib_ccx/params.c | 2 - src/thirdparty/protobuf-c/BUILD | 16 - src/thirdparty/protobuf-c/protobuf-c.c | 3646 ------------------------ src/thirdparty/protobuf-c/protobuf-c.h | 1108 ------- windows/ccextractor.vcxproj | 6 +- windows/ccextractor.vcxproj.filters | 12 - 15 files changed, 12 insertions(+), 4812 deletions(-) delete mode 100644 src/thirdparty/protobuf-c/BUILD delete mode 100644 src/thirdparty/protobuf-c/protobuf-c.c delete mode 100644 src/thirdparty/protobuf-c/protobuf-c.h diff --git a/.gitignore b/.gitignore index 0628f64fb..986573c9e 100644 --- a/.gitignore +++ b/.gitignore @@ -106,8 +106,6 @@ src/lib_hash/.deps/ src/lib_hash/.dirstamp src/libpng/.deps/ src/libpng/.dirstamp -src/protobuf-c/.deps/ -src/protobuf-c/.dirstamp src/utf8proc/.deps/ src/utf8proc/.dirstamp src/zlib/.deps/ diff --git a/linux/Makefile.am b/linux/Makefile.am index ec06dc760..4151f94de 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -202,8 +202,6 @@ ccextractor_SOURCES = \ ../src/thirdparty/utf8proc/utf8proc.h \ ../src/thirdparty/lib_hash/sha2.c \ ../src/thirdparty/lib_hash/sha2.h \ - ../src/thirdparty/protobuf-c/protobuf-c.c \ - ../src/thirdparty/protobuf-c/protobuf-c.h \ ../src/lib_ccx/zvbi/bcd.h \ ../src/lib_ccx/zvbi/bit_slicer.c \ ../src/lib_ccx/zvbi/bit_slicer.h \ @@ -268,7 +266,7 @@ endif ccextractor_CFLAGS = -std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP -ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I/usr/include/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty/protobuf-c/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ +ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I/usr/include/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ ccextractor_LDADD=-lm -lpthread -ldl -lgpac diff --git a/linux/build b/linux/build index 224e0633d..78fa63c8f 100755 --- a/linux/build +++ b/linux/build @@ -35,13 +35,12 @@ if [ "$bit_os" == "64" ] then BLD_FLAGS="$BLD_FLAGS -DGPAC_64_BITS" fi -BLD_INCLUDE="-I../src -I /usr/include/leptonica/ -I /usr/include/tesseract/ -I../src/lib_ccx/ -I /usr/include/gpac/ -I../src/thirdparty/libpng -I../src/thirdparty/zlib -I../src/lib_ccx/zvbi -I../src/thirdparty/lib_hash -I../src/thirdparty/protobuf-c -I../src/thirdparty -I../src/thirdparty/freetype/include" +BLD_INCLUDE="-I../src -I /usr/include/leptonica/ -I /usr/include/tesseract/ -I../src/lib_ccx/ -I /usr/include/gpac/ -I../src/thirdparty/libpng -I../src/thirdparty/zlib -I../src/lib_ccx/zvbi -I../src/thirdparty/lib_hash -I../src/thirdparty -I../src/thirdparty/freetype/include" SRC_LIBPNG="$(find ../src/thirdparty/libpng/ -name '*.c')" SRC_ZLIB="$(find ../src/thirdparty/zlib/ -name '*.c')" SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')" SRC_GPAC="$(find /usr/include/gpac/ -name '*.c')" SRC_HASH="$(find ../src/thirdparty/lib_hash/ -name '*.c')" -SRC_PROTOBUF="$(find ../src/thirdparty/protobuf-c/ -name '*.c')" SRC_UTF8PROC="../src/thirdparty/utf8proc/utf8proc.c" SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c ../src/thirdparty/freetype/base/ftbase.c @@ -84,7 +83,7 @@ SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c ../src/thirdparty/freetype/type1/type1.c ../src/thirdparty/freetype/type42/type42.c ../src/thirdparty/freetype/winfonts/winfnt.c" -BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG $SRC_HASH $SRC_PROTOBUF $SRC_UTF8PROC $SRC_FREETYPE" +BLD_SOURCES="../src/ccextractor.c $SRC_CCX $SRC_GPAC $SRC_ZLIB $SRC_LIBPNG $SRC_HASH $SRC_UTF8PROC $SRC_FREETYPE" BLD_LINKER="$BLD_LINKER -lm -zmuldefs -l tesseract -l leptonica -lpthread -ldl -lgpac" echo "Running pre-build script..." diff --git a/linux/module_generator b/linux/module_generator index 1da6d7537..b76cf9234 100755 --- a/linux/module_generator +++ b/linux/module_generator @@ -4,8 +4,7 @@ SRC_ZLIB="$(find ../src/thirdparty/zlib/ -name '*.c')" SRC_ZVBI="$(find ../src/thirdparty/zvbi/ -name '*.c')" SRC_CCX="$(find ../src/lib_ccx/ -name '*.c')" SRC_HASH="$(find ../src/thirdparty/lib_hash/ -name '*.c')" -SRC_PROTOBUF="$(find ../src/thirdparty/protobuf-c/ -name '*.c')" SRC_UTF8PROC="../src/utf8proc/utf8proc.c" -BLD_SOURCES="../src/ccextractor.c ../src/ccextractorapi_wrap.c $SRC_CCX $SRC_ZLIB $SRC_ZVBI $SRC_LIBPNG $SRC_HASH $SRC_PROTOBUF $SRC_UTF8PROC" +BLD_SOURCES="../src/ccextractor.c ../src/ccextractorapi_wrap.c $SRC_CCX $SRC_ZLIB $SRC_ZVBI $SRC_LIBPNG $SRC_HASH $SRC_UTF8PROC" python setup.py $BLD_SOURCES diff --git a/mac/Makefile.am b/mac/Makefile.am index df0ec8072..cdd0595c6 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -174,8 +174,6 @@ ccextractor_SOURCES = \ ../src/thirdparty/utf8proc/utf8proc.h \ ../src/thirdparty/lib_hash/sha2.c \ ../src/thirdparty/lib_hash/sha2.h \ - ../src/thirdparty/protobuf-c/protobuf-c.c \ - ../src/thirdparty/protobuf-c/protobuf-c.h \ ../src/lib_ccx/zvbi/bcd.h \ ../src/lib_ccx/zvbi/bit_slicer.c \ ../src/lib_ccx/zvbi/bit_slicer.h \ @@ -243,7 +241,7 @@ ccextractor_CFLAGS = -std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFF ccextractor_LDFLAGS = $(shell pkg-config --libs gpac nanomsg) GPAC_CPPFLAGS = $(shell pkg-config --cflags gpac) -ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty/protobuf-c/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ +ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ ccextractor_CPPFLAGS += $(GPAC_CPPFLAGS) ccextractor_CPPFLAGS += $(FFMPEG_CPPFLAGS) diff --git a/mac/build.command b/mac/build.command index 3d47d2533..1e0b83281 100755 --- a/mac/build.command +++ b/mac/build.command @@ -2,12 +2,11 @@ cd `dirname $0` BLD_FLAGS="-std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -Dfopen64=fopen -Dopen64=open -Dlseek64=lseek -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP -DDISABLE_RUST" [[ $1 = "OCR" ]] && BLD_FLAGS="$BLD_FLAGS -DENABLE_OCR" -BLD_INCLUDE="-I../src/ -I../src/lib_ccx -I../src/lib_hash -I../src/thirdparty/libpng -I../src/thirdparty -I../src/thirdparty/protobuf-c -I../src/thirdparty/zlib -I../src/thirdparty/freetype/include `pkg-config --cflags --silence-errors gpac`" +BLD_INCLUDE="-I../src/ -I../src/lib_ccx -I../src/lib_hash -I../src/thirdparty/libpng -I../src/thirdparty -I../src/thirdparty/zlib -I../src/thirdparty/freetype/include `pkg-config --cflags --silence-errors gpac`" [[ $1 = "OCR" ]] && BLD_INCLUDE="$BLD_INCLUDE `pkg-config --cflags --silence-errors tesseract`" SRC_CCX="$(find ../src/lib_ccx -name '*.c')" SRC_LIB_HASH="$(find ../src/thirdparty/lib_hash -name '*.c')" SRC_LIBPNG="$(find ../src/thirdparty/libpng -name '*.c')" -SRC_PROTOBUF="$(find ../src/thirdparty/protobuf-c -name '*.c')" SRC_UTF8="../src/thirdparty/utf8proc/utf8proc.c" SRC_ZLIB="$(find ../src/thirdparty/zlib -name '*.c')" SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c \ @@ -51,7 +50,7 @@ SRC_FREETYPE="../src/thirdparty/freetype/autofit/autofit.c \ ../src/thirdparty/freetype/type1/type1.c \ ../src/thirdparty/freetype/type42/type42.c \ ../src/thirdparty/freetype/winfonts/winfnt.c" -BLD_SOURCES="../src/ccextractor.c $SRC_API $SRC_CCX $SRC_LIB_HASH $SRC_LIBPNG $SRC_PROTOBUF $SRC_UTF8 $SRC_ZLIB $SRC_ZVBI $SRC_FREETYPE" +BLD_SOURCES="../src/ccextractor.c $SRC_API $SRC_CCX $SRC_LIB_HASH $SRC_LIBPNG $SRC_UTF8 $SRC_ZLIB $SRC_ZVBI $SRC_FREETYPE" BLD_LINKER="-lm -liconv -lpthread -ldl `pkg-config --libs --silence-errors tesseract` `pkg-config --libs --silence-errors gpac`" [[ $1 = "OCR" ]] && BLD_LINKER="$BLD_LINKER `pkg-config --libs --silence-errors tesseract` `pkg-config --libs --silence-errors lept`" diff --git a/src/BUILD b/src/BUILD index b2add66c6..52a9a9cc6 100644 --- a/src/BUILD +++ b/src/BUILD @@ -4,11 +4,10 @@ cc_binary( "ccextractor.h"], deps = [ "//src/lib_ccx:lib_ccx", - "//src/thirdparty/protobuf-c:protobuf-c", "//src/thirdparty/zlib:zlib", "//src/thirdparty/freetype:freetype" ], - copts = [ "-Isrc/thirdparty/protobuf-c", "-Isrc/thirdparty/libpng", "-Isrc" ] + copts = [ "-Isrc/thirdparty/libpng", "-Isrc" ] ) exports_files (["ccextractor.h"], ["//src/lib_ccx:__pkg__"]) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5031182f0..5bd1526fd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -51,7 +51,6 @@ include_directories(${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_SOURCE_DIR}/lib_ccx) include_directories(${PROJECT_SOURCE_DIR}/lib_ccx/zvbi) include_directories(${PROJECT_SOURCE_DIR}/thirdparty) -include_directories(${PROJECT_SOURCE_DIR}/thirdparty/protobuf-c) include_directories(${PROJECT_SOURCE_DIR}/thirdparty/lib_hash) include_directories(${PROJECT_SOURCE_DIR}/thirdparty/libpng) @@ -71,7 +70,6 @@ include_directories(${PROJECT_SOURCE_DIR}/thirdparty/zlib) include_directories(${PROJECT_SOURCE_DIR}/thirdparty/freetype/include) aux_source_directory(${PROJECT_SOURCE_DIR}/thirdparty/lib_hash/ SOURCEFILE) aux_source_directory(${PROJECT_SOURCE_DIR}/thirdparty/libpng/ SOURCEFILE) -aux_source_directory(${PROJECT_SOURCE_DIR}/thirdparty/protobuf-c/ SOURCEFILE) aux_source_directory(${PROJECT_SOURCE_DIR}/thirdparty/zlib/ SOURCEFILE) aux_source_directory(${PROJECT_SOURCE_DIR}/lib_ccx/zvbi/ SOURCEFILE) diff --git a/src/lib_ccx/BUILD b/src/lib_ccx/BUILD index 9b4404acb..f6f5dfae7 100644 --- a/src/lib_ccx/BUILD +++ b/src/lib_ccx/BUILD @@ -6,16 +6,14 @@ cc_library( hdrs = glob (["*.h", "zvbi/*.h", "*.xbm"]) + [ "//src:ccextractor.h" ], visibility = ["//visibility:public"], deps = [ - "//src/thirdparty/protobuf-c:protobuf-c", "//src/thirdparty/libpng:libpng", "//src/thirdparty/freetype:freetype", "//src/thirdparty/lib_hash:lib_hash", "//src/thirdparty/utf8proc:utf8proc", ], - includes = [ "thirdparty/protobuf-c", "thirdparty/libpng", "." , + includes = [ "thirdparty/libpng", "." , "thirdparty/freetype/include" ], - copts = [ "-Isrc/thirdparty/protobuf-c", - "-Isrc/thirdparty/libpng", + copts = [ "-Isrc/thirdparty/libpng", "-Isrc/", "-Isrc/thirdparty/freetype", "-Isrc/thirdparty/lib_hash", diff --git a/src/lib_ccx/params.c b/src/lib_ccx/params.c index 0b557fed1..d46d30cdf 100644 --- a/src/lib_ccx/params.c +++ b/src/lib_ccx/params.c @@ -1,5 +1,4 @@ #include -#include "protobuf-c.h" #include "zlib.h" #include "gpac/setup.h" #include "gpac/version.h" @@ -1070,7 +1069,6 @@ void version(char *location) mprint(" libGPAC Version: %s\n", GPAC_VERSION); mprint(" zlib: %s\n", ZLIB_VERSION); mprint(" utf8proc Version: %s\n", (const char *)utf8proc_version()); - mprint(" protobuf-c Version: %s\n", (const char *)protobuf_c_version()); mprint(" libpng Version: %s\n", PNG_LIBPNG_VER_STRING); mprint(" FreeType \n"); mprint(" libhash\n"); diff --git a/src/thirdparty/protobuf-c/BUILD b/src/thirdparty/protobuf-c/BUILD deleted file mode 100644 index ce939593f..000000000 --- a/src/thirdparty/protobuf-c/BUILD +++ /dev/null @@ -1,16 +0,0 @@ -cc_library( - name = "protobuf-c", - srcs = ["protobuf-c.c"], - hdrs = ["protobuf-c.h"], - visibility = ["//visibility:public"], -) - -cc_test( - name = "protobuf-c_test", - srcs = ["protobuf-c_test.cc"], - deps = [":protobuf-c"] -) - - - - diff --git a/src/thirdparty/protobuf-c/protobuf-c.c b/src/thirdparty/protobuf-c/protobuf-c.c deleted file mode 100644 index e2a60ee61..000000000 --- a/src/thirdparty/protobuf-c/protobuf-c.c +++ /dev/null @@ -1,3646 +0,0 @@ -/* -* Copyright (c) 2008-2015, Dave Benson and the protobuf-c authors. -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * 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. -*/ - -/*! \file -* Support library for `protoc-c` generated code. -* -* This file implements the public API used by the code generated -* by `protoc-c`. -* -* \authors Dave Benson and the protobuf-c authors -* -* \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. -*/ - -/** -* \todo 64-BIT OPTIMIZATION: certain implementations use 32-bit math -* even on 64-bit platforms (uint64_size, uint64_pack, parse_uint64). -* -* \todo Use size_t consistently. -*/ - -#include /* for malloc, free */ -#include /* for strcmp, strlen, memcpy, memmove, memset */ - -#include "protobuf-c.h" - -#define TRUE 1 -#define FALSE 0 - -#define PROTOBUF_C__ASSERT_NOT_REACHED() assert(0) - -/* Workaround for Microsoft compilers. */ -#ifdef _MSC_VER -# define inline __inline -#endif - -/** -* \defgroup internal Internal functions and macros -* -* These are not exported by the library but are useful to developers working -* on `libprotobuf-c` itself. -*/ - -/** -* \defgroup macros Utility macros for manipulating structures -* -* Macros and constants used to manipulate the base "classes" generated by -* `protobuf-c`. They also define limits and check correctness. -* -* \ingroup internal -* @{ -*/ - -/** The maximum length of a 64-bit integer in varint encoding. */ -#define MAX_UINT64_ENCODED_SIZE 10 - -#ifndef PROTOBUF_C_UNPACK_ERROR -# define PROTOBUF_C_UNPACK_ERROR(...) -#endif - -const char protobuf_c_empty_string[] = ""; - -/** -* Internal `ProtobufCMessage` manipulation macro. -* -* Base macro for manipulating a `ProtobufCMessage`. Used by STRUCT_MEMBER() and -* STRUCT_MEMBER_PTR(). -*/ -#define STRUCT_MEMBER_P(struct_p, struct_offset) \ -((void *) ((uint8_t *) (struct_p) + (struct_offset))) - -/** -* Return field in a `ProtobufCMessage` based on offset. -* -* Take a pointer to a `ProtobufCMessage` and find the field at the offset. -* Cast it to the passed type. -*/ -#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ -(*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) - -/** -* Return field in a `ProtobufCMessage` based on offset. -* -* Take a pointer to a `ProtobufCMessage` and find the field at the offset. Cast -* it to a pointer to the passed type. -*/ -#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ -((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) - -/* Assertions for magic numbers. */ - -#define ASSERT_IS_ENUM_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC) - -#define ASSERT_IS_MESSAGE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) - -#define ASSERT_IS_MESSAGE(message) \ - ASSERT_IS_MESSAGE_DESCRIPTOR((message)->descriptor) - -#define ASSERT_IS_SERVICE_DESCRIPTOR(desc) \ - assert((desc)->magic == PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC) - -/**@}*/ - -/* --- version --- */ - -const char * -protobuf_c_version(void) -{ - return PROTOBUF_C_VERSION; -} - -uint32_t -protobuf_c_version_number(void) -{ - return PROTOBUF_C_VERSION_NUMBER; -} - -/* --- allocator --- */ - -static void * -system_alloc(void *allocator_data, size_t size) -{ - return malloc(size); -} - -static void -system_free(void *allocator_data, void *data) -{ - free(data); -} - -static inline void * -do_alloc(ProtobufCAllocator *allocator, size_t size) -{ - return allocator->alloc(allocator->allocator_data, size); -} - -static inline void -do_free(ProtobufCAllocator *allocator, void *data) -{ - if (data != NULL) - allocator->free(allocator->allocator_data, data); -} - -/* -* This allocator uses the system's malloc() and free(). It is the default -* allocator used if NULL is passed as the ProtobufCAllocator to an exported -* function. -*/ -static ProtobufCAllocator protobuf_c__allocator = { - .alloc = &system_alloc, - .free = &system_free, - .allocator_data = NULL, -}; - -/* === buffer-simple === */ - -void -protobuf_c_buffer_simple_append(ProtobufCBuffer *buffer, - size_t len, const uint8_t *data) -{ - ProtobufCBufferSimple *simp = (ProtobufCBufferSimple *) buffer; - size_t new_len = simp->len + len; - - if (new_len > simp->alloced) { - ProtobufCAllocator *allocator = simp->allocator; - size_t new_alloced = simp->alloced * 2; - uint8_t *new_data; - - if (allocator == NULL) - allocator = &protobuf_c__allocator; - while (new_alloced < new_len) - new_alloced += new_alloced; - new_data = do_alloc(allocator, new_alloced); - if (!new_data) - return; - memcpy(new_data, simp->data, simp->len); - if (simp->must_free_data) - do_free(allocator, simp->data); - else - simp->must_free_data = TRUE; - simp->data = new_data; - simp->alloced = new_alloced; - } - memcpy(simp->data + simp->len, data, len); - simp->len = new_len; -} - -/** -* \defgroup packedsz protobuf_c_message_get_packed_size() implementation -* -* Routines mainly used by protobuf_c_message_get_packed_size(). -* -* \ingroup internal -* @{ -*/ - -/** -* Return the number of bytes required to store the tag for the field. Includes -* 3 bits for the wire-type, and a single bit that denotes the end-of-tag. -* -* \param number -* Field tag to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -get_tag_size(uint32_t number) -{ - if (number < (1UL << 4)) { - return 1; - } else if (number < (1UL << 11)) { - return 2; - } else if (number < (1UL << 18)) { - return 3; - } else if (number < (1UL << 25)) { - return 4; - } else { - return 5; - } -} - -/** -* Return the number of bytes required to store a variable-length unsigned -* 32-bit integer in base-128 varint encoding. -* -* \param v -* Value to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -uint32_size(uint32_t v) -{ - if (v < (1UL << 7)) { - return 1; - } else if (v < (1UL << 14)) { - return 2; - } else if (v < (1UL << 21)) { - return 3; - } else if (v < (1UL << 28)) { - return 4; - } else { - return 5; - } -} - -/** -* Return the number of bytes required to store a variable-length signed 32-bit -* integer in base-128 varint encoding. -* -* \param v -* Value to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -int32_size(int32_t v) -{ - if (v < 0) { - return 10; - } else if (v < (1L << 7)) { - return 1; - } else if (v < (1L << 14)) { - return 2; - } else if (v < (1L << 21)) { - return 3; - } else if (v < (1L << 28)) { - return 4; - } else { - return 5; - } -} - -/** -* Return the ZigZag-encoded 32-bit unsigned integer form of a 32-bit signed -* integer. -* -* \param v -* Value to encode. -* \return -* ZigZag encoded integer. -*/ -static inline uint32_t -zigzag32(int32_t v) -{ - if (v < 0) - return (-(uint32_t)v) * 2 - 1; - else - return (uint32_t)(v) * 2; -} - -/** -* Return the number of bytes required to store a signed 32-bit integer, -* converted to an unsigned 32-bit integer with ZigZag encoding, using base-128 -* varint encoding. -* -* \param v -* Value to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -sint32_size(int32_t v) -{ - return uint32_size(zigzag32(v)); -} - -/** -* Return the number of bytes required to store a 64-bit unsigned integer in -* base-128 varint encoding. -* -* \param v -* Value to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -uint64_size(uint64_t v) -{ - uint32_t upper_v = (uint32_t) (v >> 32); - - if (upper_v == 0) { - return uint32_size((uint32_t) v); - } else if (upper_v < (1UL << 3)) { - return 5; - } else if (upper_v < (1UL << 10)) { - return 6; - } else if (upper_v < (1UL << 17)) { - return 7; - } else if (upper_v < (1UL << 24)) { - return 8; - } else if (upper_v < (1UL << 31)) { - return 9; - } else { - return 10; - } -} - -/** -* Return the ZigZag-encoded 64-bit unsigned integer form of a 64-bit signed -* integer. -* -* \param v -* Value to encode. -* \return -* ZigZag encoded integer. -*/ -static inline uint64_t -zigzag64(int64_t v) -{ - if (v < 0) - return (-(uint64_t)v) * 2 - 1; - else - return (uint64_t)(v) * 2; -} - -/** -* Return the number of bytes required to store a signed 64-bit integer, -* converted to an unsigned 64-bit integer with ZigZag encoding, using base-128 -* varint encoding. -* -* \param v -* Value to encode. -* \return -* Number of bytes required. -*/ -static inline size_t -sint64_size(int64_t v) -{ - return uint64_size(zigzag64(v)); -} - -/** -* Calculate the serialized size of a single required message field, including -* the space needed by the preceding tag. -* -* \param field -* Field descriptor for member. -* \param member -* Field to encode. -* \return -* Number of bytes required. -*/ -static size_t -required_field_get_packed_size(const ProtobufCFieldDescriptor *field, - const void *member) -{ - size_t rv = get_tag_size(field->id); - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - return rv + sint32_size(*(const int32_t *) member); - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - return rv + int32_size(*(const int32_t *) member); - case PROTOBUF_C_TYPE_UINT32: - return rv + uint32_size(*(const uint32_t *) member); - case PROTOBUF_C_TYPE_SINT64: - return rv + sint64_size(*(const int64_t *) member); - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - return rv + uint64_size(*(const uint64_t *) member); - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - return rv + 4; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - return rv + 8; - case PROTOBUF_C_TYPE_BOOL: - return rv + 1; - case PROTOBUF_C_TYPE_FLOAT: - return rv + 4; - case PROTOBUF_C_TYPE_DOUBLE: - return rv + 8; - case PROTOBUF_C_TYPE_STRING: { - const char *str = *(char * const *) member; - size_t len = str ? strlen(str) : 0; - return rv + uint32_size(len) + len; - } - case PROTOBUF_C_TYPE_BYTES: { - size_t len = ((const ProtobufCBinaryData *) member)->len; - return rv + uint32_size(len) + len; - } - case PROTOBUF_C_TYPE_MESSAGE: { - const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; - size_t subrv = msg ? protobuf_c_message_get_packed_size(msg) : 0; - return rv + uint32_size(subrv) + subrv; - } - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** -* Calculate the serialized size of a single oneof message field, including -* the space needed by the preceding tag. Returns 0 if the oneof field isn't -* selected or is not set. -* -* \param field -* Field descriptor for member. -* \param oneof_case -* Enum value that selects the field in the oneof. -* \param member -* Field to encode. -* \return -* Number of bytes required. -*/ -static size_t -oneof_field_get_packed_size(const ProtobufCFieldDescriptor *field, - uint32_t oneof_case, - const void *member) -{ - if (oneof_case != field->id) { - return 0; - } - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } - return required_field_get_packed_size(field, member); -} - -/** -* Calculate the serialized size of a single optional message field, including -* the space needed by the preceding tag. Returns 0 if the optional field isn't -* set. -* -* \param field -* Field descriptor for member. -* \param has -* True if the field exists, false if not. -* \param member -* Field to encode. -* \return -* Number of bytes required. -*/ -static size_t -optional_field_get_packed_size(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean has, - const void *member) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!has) - return 0; - } - return required_field_get_packed_size(field, member); -} - -static protobuf_c_boolean -field_is_zeroish(const ProtobufCFieldDescriptor *field, - const void *member) -{ - protobuf_c_boolean ret = FALSE; - - switch (field->type) { - case PROTOBUF_C_TYPE_BOOL: - ret = (0 == *(const protobuf_c_boolean *) member); - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - ret = (0 == *(const uint32_t *) member); - break; - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - ret = (0 == *(const uint64_t *) member); - break; - case PROTOBUF_C_TYPE_FLOAT: - ret = (0 == *(const float *) member); - break; - case PROTOBUF_C_TYPE_DOUBLE: - ret = (0 == *(const double *) member); - break; - case PROTOBUF_C_TYPE_STRING: - ret = (NULL == *(const char * const *) member) || - ('\0' == **(const char * const *) member); - break; - case PROTOBUF_C_TYPE_BYTES: - case PROTOBUF_C_TYPE_MESSAGE: - ret = (NULL == *(const void * const *) member); - break; - default: - ret = TRUE; - break; - } - - return ret; -} - -/** -* Calculate the serialized size of a single unlabeled message field, including -* the space needed by the preceding tag. Returns 0 if the field isn't set or -* if it is set to a "zeroish" value (null pointer or 0 for numerical values). -* Unlabeled fields are supported only in proto3. -* -* \param field -* Field descriptor for member. -* \param member -* Field to encode. -* \return -* Number of bytes required. -*/ -static size_t -unlabeled_field_get_packed_size(const ProtobufCFieldDescriptor *field, - const void *member) -{ - if (field_is_zeroish(field, member)) - return 0; - return required_field_get_packed_size(field, member); -} - -/** -* Calculate the serialized size of repeated message fields, which may consist -* of any number of values (including 0). Includes the space needed by the -* preceding tags (as needed). -* -* \param field -* Field descriptor for member. -* \param count -* Number of repeated field members. -* \param member -* Field to encode. -* \return -* Number of bytes required. -*/ -static size_t -repeated_field_get_packed_size(const ProtobufCFieldDescriptor *field, - size_t count, const void *member) -{ - size_t header_size; - size_t rv = 0; - unsigned i; - void *array = *(void * const *) member; - - if (count == 0) - return 0; - header_size = get_tag_size(field->id); - if (0 == (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) - header_size *= count; - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - for (i = 0; i < count; i++) - rv += sint32_size(((int32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - for (i = 0; i < count; i++) - rv += int32_size(((int32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_UINT32: - for (i = 0; i < count; i++) - rv += uint32_size(((uint32_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_SINT64: - for (i = 0; i < count; i++) - rv += sint64_size(((int64_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - for (i = 0; i < count; i++) - rv += uint64_size(((uint64_t *) array)[i]); - break; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - rv += 4 * count; - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - rv += 8 * count; - break; - case PROTOBUF_C_TYPE_BOOL: - rv += count; - break; - case PROTOBUF_C_TYPE_STRING: - for (i = 0; i < count; i++) { - size_t len = strlen(((char **) array)[i]); - rv += uint32_size(len) + len; - } - break; - case PROTOBUF_C_TYPE_BYTES: - for (i = 0; i < count; i++) { - size_t len = ((ProtobufCBinaryData *) array)[i].len; - rv += uint32_size(len) + len; - } - break; - case PROTOBUF_C_TYPE_MESSAGE: - for (i = 0; i < count; i++) { - size_t len = protobuf_c_message_get_packed_size( - ((ProtobufCMessage **) array)[i]); - rv += uint32_size(len) + len; - } - break; - } - - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) - header_size += uint32_size(rv); - return header_size + rv; -} - -/** -* Calculate the serialized size of an unknown field, i.e. one that is passed -* through mostly uninterpreted. This is required for forward compatibility if -* new fields are added to the message descriptor. -* -* \param field -* Unknown field type. -* \return -* Number of bytes required. -*/ -static inline size_t -unknown_field_get_packed_size(const ProtobufCMessageUnknownField *field) -{ - return get_tag_size(field->tag) + field->len; -} - -/**@}*/ - -/* -* Calculate the serialized size of the message. -*/ -size_t protobuf_c_message_get_packed_size(const ProtobufCMessage *message) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = - ((const char *) message) + field->offset; - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_get_packed_size(field, member); - } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || - field->label == PROTOBUF_C_LABEL_NONE) && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { - rv += oneof_field_get_packed_size( - field, - *(const uint32_t *) qmember, - member - ); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - rv += optional_field_get_packed_size( - field, - *(protobuf_c_boolean *) qmember, - member - ); - } else if (field->label == PROTOBUF_C_LABEL_NONE) { - rv += unlabeled_field_get_packed_size( - field, - member - ); - } else { - rv += repeated_field_get_packed_size( - field, - *(const size_t *) qmember, - member - ); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_get_packed_size(&message->unknown_fields[i]); - return rv; -} - -/** -* \defgroup pack protobuf_c_message_pack() implementation -* -* Routines mainly used by protobuf_c_message_pack(). -* -* \ingroup internal -* @{ -*/ - -/** -* Pack an unsigned 32-bit integer in base-128 varint encoding and return the -* number of bytes written, which must be 5 or less. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -uint32_pack(uint32_t value, uint8_t *out) -{ - unsigned rv = 0; - - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - if (value >= 0x80) { - out[rv++] = value | 0x80; - value >>= 7; - } - } - } - } - /* assert: value<128 */ - out[rv++] = value; - return rv; -} - -/** -* Pack a signed 32-bit integer and return the number of bytes written. -* Negative numbers are encoded as two's complement 64-bit integers. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -int32_pack(int32_t value, uint8_t *out) -{ - if (value < 0) { - out[0] = value | 0x80; - out[1] = (value >> 7) | 0x80; - out[2] = (value >> 14) | 0x80; - out[3] = (value >> 21) | 0x80; - out[4] = (value >> 28) | 0x80; - out[5] = out[6] = out[7] = out[8] = 0xff; - out[9] = 0x01; - return 10; - } else { - return uint32_pack(value, out); - } -} - -/** -* Pack a signed 32-bit integer using ZigZag encoding and return the number of -* bytes written. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -sint32_pack(int32_t value, uint8_t *out) -{ - return uint32_pack(zigzag32(value), out); -} - -/** -* Pack a 64-bit unsigned integer using base-128 varint encoding and return the -* number of bytes written. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -uint64_pack(uint64_t value, uint8_t *out) -{ - uint32_t hi = (uint32_t) (value >> 32); - uint32_t lo = (uint32_t) value; - unsigned rv; - - if (hi == 0) - return uint32_pack((uint32_t) lo, out); - out[0] = (lo) | 0x80; - out[1] = (lo >> 7) | 0x80; - out[2] = (lo >> 14) | 0x80; - out[3] = (lo >> 21) | 0x80; - if (hi < 8) { - out[4] = (hi << 4) | (lo >> 28); - return 5; - } else { - out[4] = ((hi & 7) << 4) | (lo >> 28) | 0x80; - hi >>= 3; - } - rv = 5; - while (hi >= 128) { - out[rv++] = hi | 0x80; - hi >>= 7; - } - out[rv++] = hi; - return rv; -} - -/** -* Pack a 64-bit signed integer in ZigZag encoding and return the number of -* bytes written. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -sint64_pack(int64_t value, uint8_t *out) -{ - return uint64_pack(zigzag64(value), out); -} - -/** -* Pack a 32-bit quantity in little-endian byte order. Used for protobuf wire -* types fixed32, sfixed32, float. Similar to "htole32". -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -fixed32_pack(uint32_t value, void *out) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, &value, 4); -#else - uint8_t *buf = out; - - buf[0] = value; - buf[1] = value >> 8; - buf[2] = value >> 16; - buf[3] = value >> 24; -#endif - return 4; -} - -/** -* Pack a 64-bit quantity in little-endian byte order. Used for protobuf wire -* types fixed64, sfixed64, double. Similar to "htole64". -* -* \todo The big-endian impl is really only good for 32-bit machines, a 64-bit -* version would be appreciated, plus a way to decide to use 64-bit math where -* convenient. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -fixed64_pack(uint64_t value, void *out) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, &value, 8); -#else - fixed32_pack(value, out); - fixed32_pack(value >> 32, ((char *) out) + 4); -#endif - return 8; -} - -/** -* Pack a boolean value as an integer and return the number of bytes written. -* -* \todo Perhaps on some platforms *out = !!value would be a better impl, b/c -* that is idiomatic C++ in some STL implementations. -* -* \param value -* Value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -boolean_pack(protobuf_c_boolean value, uint8_t *out) -{ - *out = value ? TRUE : FALSE; - return 1; -} - -/** -* Pack a NUL-terminated C string and return the number of bytes written. The -* output includes a length delimiter. -* -* The NULL pointer is treated as an empty string. This isn't really necessary, -* but it allows people to leave required strings blank. (See Issue #13 in the -* bug tracker for a little more explanation). -* -* \param str -* String to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -string_pack(const char *str, uint8_t *out) -{ - if (str == NULL) { - out[0] = 0; - return 1; - } else { - size_t len = strlen(str); - size_t rv = uint32_pack(len, out); - memcpy(out + rv, str, len); - return rv + len; - } -} - -/** -* Pack a ProtobufCBinaryData and return the number of bytes written. The output -* includes a length delimiter. -* -* \param bd -* ProtobufCBinaryData to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -binary_data_pack(const ProtobufCBinaryData *bd, uint8_t *out) -{ - size_t len = bd->len; - size_t rv = uint32_pack(len, out); - memcpy(out + rv, bd->data, len); - return rv + len; -} - -/** -* Pack a ProtobufCMessage and return the number of bytes written. The output -* includes a length delimiter. -* -* \param message -* ProtobufCMessage object to pack. -* \param[out] out -* Packed message. -* \return -* Number of bytes written to `out`. -*/ -static inline size_t -prefixed_message_pack(const ProtobufCMessage *message, uint8_t *out) -{ - if (message == NULL) { - out[0] = 0; - return 1; - } else { - size_t rv = protobuf_c_message_pack(message, out + 1); - uint32_t rv_packed_size = uint32_size(rv); - if (rv_packed_size != 1) - memmove(out + rv_packed_size, out + 1, rv); - return uint32_pack(rv, out) + rv; - } -} - -/** -* Pack a field tag. -* -* Wire-type will be added in required_field_pack(). -* -* \todo Just call uint64_pack on 64-bit platforms. -* -* \param id -* Tag value to encode. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -tag_pack(uint32_t id, uint8_t *out) -{ - if (id < (1UL << (32 - 3))) - return uint32_pack(id << 3, out); - else - return uint64_pack(((uint64_t) id) << 3, out); -} - -/** -* Pack a required field and return the number of bytes written. -* -* \param field -* Field descriptor. -* \param member -* The field member. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -required_field_pack(const ProtobufCFieldDescriptor *field, - const void *member, uint8_t *out) -{ - size_t rv = tag_pack(field->id, out); - - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + sint32_pack(*(const int32_t *) member, out + rv); - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + int32_pack(*(const int32_t *) member, out + rv); - case PROTOBUF_C_TYPE_UINT32: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + uint32_pack(*(const uint32_t *) member, out + rv); - case PROTOBUF_C_TYPE_SINT64: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + sint64_pack(*(const int64_t *) member, out + rv); - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + uint64_pack(*(const uint64_t *) member, out + rv); - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - out[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; - return rv + fixed32_pack(*(const uint32_t *) member, out + rv); - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - out[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; - return rv + fixed64_pack(*(const uint64_t *) member, out + rv); - case PROTOBUF_C_TYPE_BOOL: - out[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - return rv + boolean_pack(*(const protobuf_c_boolean *) member, out + rv); - case PROTOBUF_C_TYPE_STRING: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + string_pack(*(char *const *) member, out + rv); - case PROTOBUF_C_TYPE_BYTES: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + binary_data_pack((const ProtobufCBinaryData *) member, out + rv); - case PROTOBUF_C_TYPE_MESSAGE: - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - return rv + prefixed_message_pack(*(ProtobufCMessage * const *) member, out + rv); - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** -* Pack a oneof field and return the number of bytes written. Only packs the -* field that is selected by the case enum. -* -* \param field -* Field descriptor. -* \param oneof_case -* Enum value that selects the field in the oneof. -* \param member -* The field member. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -oneof_field_pack(const ProtobufCFieldDescriptor *field, - uint32_t oneof_case, - const void *member, uint8_t *out) -{ - if (oneof_case != field->id) { - return 0; - } - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } - return required_field_pack(field, member, out); -} - -/** -* Pack an optional field and return the number of bytes written. -* -* \param field -* Field descriptor. -* \param has -* Whether the field is set. -* \param member -* The field member. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -optional_field_pack(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean has, - const void *member, uint8_t *out) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void * const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!has) - return 0; - } - return required_field_pack(field, member, out); -} - -/** -* Pack an unlabeled field and return the number of bytes written. -* -* \param field -* Field descriptor. -* \param member -* The field member. -* \param[out] out -* Packed value. -* \return -* Number of bytes written to `out`. -*/ -static size_t -unlabeled_field_pack(const ProtobufCFieldDescriptor *field, - const void *member, uint8_t *out) -{ - if (field_is_zeroish(field, member)) - return 0; - return required_field_pack(field, member, out); -} - -/** -* Given a field type, return the in-memory size. -* -* \todo Implement as a table lookup. -* -* \param type -* Field type. -* \return -* Size of the field. -*/ -static inline size_t -sizeof_elt_in_repeated_array(ProtobufCType type) -{ - switch (type) { - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - case PROTOBUF_C_TYPE_ENUM: - return 4; - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - return 8; - case PROTOBUF_C_TYPE_BOOL: - return sizeof(protobuf_c_boolean); - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_MESSAGE: - return sizeof(void *); - case PROTOBUF_C_TYPE_BYTES: - return sizeof(ProtobufCBinaryData); - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** -* Pack an array of 32-bit quantities. -* -* \param[out] out -* Destination. -* \param[in] in -* Source. -* \param[in] n -* Number of elements in the source array. -*/ -static void -copy_to_little_endian_32(void *out, const void *in, const unsigned n) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, in, n * 4); -#else - unsigned i; - const uint32_t *ini = in; - for (i = 0; i < n; i++) - fixed32_pack(ini[i], (uint32_t *) out + i); -#endif -} - -/** -* Pack an array of 64-bit quantities. -* -* \param[out] out -* Destination. -* \param[in] in -* Source. -* \param[in] n -* Number of elements in the source array. -*/ -static void -copy_to_little_endian_64(void *out, const void *in, const unsigned n) -{ -#if !defined(WORDS_BIGENDIAN) - memcpy(out, in, n * 8); -#else - unsigned i; - const uint64_t *ini = in; - for (i = 0; i < n; i++) - fixed64_pack(ini[i], (uint64_t *) out + i); -#endif -} - -/** -* Get the minimum number of bytes required to pack a field value of a -* particular type. -* -* \param type -* Field type. -* \return -* Number of bytes. -*/ -static unsigned -get_type_min_size(ProtobufCType type) -{ - if (type == PROTOBUF_C_TYPE_SFIXED32 || - type == PROTOBUF_C_TYPE_FIXED32 || - type == PROTOBUF_C_TYPE_FLOAT) - { - return 4; - } - if (type == PROTOBUF_C_TYPE_SFIXED64 || - type == PROTOBUF_C_TYPE_FIXED64 || - type == PROTOBUF_C_TYPE_DOUBLE) - { - return 8; - } - return 1; -} - -/** -* Packs the elements of a repeated field and returns the serialised field and -* its length. -* -* \param field -* Field descriptor. -* \param count -* Number of elements in the repeated field array. -* \param member -* Pointer to the elements for this repeated field. -* \param[out] out -* Serialised representation of the repeated field. -* \return -* Number of bytes serialised to `out`. -*/ -static size_t -repeated_field_pack(const ProtobufCFieldDescriptor *field, - size_t count, const void *member, uint8_t *out) -{ - void *array = *(void * const *) member; - unsigned i; - - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { - unsigned header_len; - unsigned len_start; - unsigned min_length; - unsigned payload_len; - unsigned length_size_min; - unsigned actual_length_size; - uint8_t *payload_at; - - if (count == 0) - return 0; - header_len = tag_pack(field->id, out); - out[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - len_start = header_len; - min_length = get_type_min_size(field->type) * count; - length_size_min = uint32_size(min_length); - header_len += length_size_min; - payload_at = out + header_len; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - copy_to_little_endian_32(payload_at, array, count); - payload_at += count * 4; - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - copy_to_little_endian_64(payload_at, array, count); - payload_at += count * 8; - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - payload_at += int32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_SINT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - payload_at += sint32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_SINT64: { - const int64_t *arr = (const int64_t *) array; - for (i = 0; i < count; i++) - payload_at += sint64_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_UINT32: { - const uint32_t *arr = (const uint32_t *) array; - for (i = 0; i < count; i++) - payload_at += uint32_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: { - const uint64_t *arr = (const uint64_t *) array; - for (i = 0; i < count; i++) - payload_at += uint64_pack(arr[i], payload_at); - break; - } - case PROTOBUF_C_TYPE_BOOL: { - const protobuf_c_boolean *arr = (const protobuf_c_boolean *) array; - for (i = 0; i < count; i++) - payload_at += boolean_pack(arr[i], payload_at); - break; - } - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - - payload_len = payload_at - (out + header_len); - actual_length_size = uint32_size(payload_len); - if (length_size_min != actual_length_size) { - assert(actual_length_size == length_size_min + 1); - memmove(out + header_len + 1, out + header_len, - payload_len); - header_len++; - } - uint32_pack(payload_len, out + len_start); - return header_len + payload_len; - } else { - /* not "packed" cased */ - /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ - size_t rv = 0; - unsigned siz = sizeof_elt_in_repeated_array(field->type); - - for (i = 0; i < count; i++) { - rv += required_field_pack(field, array, out + rv); - array = (char *)array + siz; - } - return rv; - } -} - -static size_t -unknown_field_pack(const ProtobufCMessageUnknownField *field, uint8_t *out) -{ - size_t rv = tag_pack(field->tag, out); - out[0] |= field->wire_type; - memcpy(out + rv, field->data, field->len); - return rv + field->len; -} - -/**@}*/ - -size_t -protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = ((const char *) message) + field->offset; - - /* - * It doesn't hurt to compute qmember (a pointer to the - * quantifier field of the structure), but the pointer is only - * valid if the field is: - * - a repeated field, or - * - a field that is part of a oneof - * - an optional field that isn't a pointer type - * (Meaning: not a message or a string). - */ - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_pack(field, member, out + rv); - } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || - field->label == PROTOBUF_C_LABEL_NONE) && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { - rv += oneof_field_pack( - field, - *(const uint32_t *) qmember, - member, - out + rv - ); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - rv += optional_field_pack( - field, - *(const protobuf_c_boolean *) qmember, - member, - out + rv - ); - } else if (field->label == PROTOBUF_C_LABEL_NONE) { - rv += unlabeled_field_pack(field, member, out + rv); - } else { - rv += repeated_field_pack(field, *(const size_t *) qmember, - member, out + rv); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_pack(&message->unknown_fields[i], out + rv); - return rv; -} - -/** -* \defgroup packbuf protobuf_c_message_pack_to_buffer() implementation -* -* Routines mainly used by protobuf_c_message_pack_to_buffer(). -* -* \ingroup internal -* @{ -*/ - -/** -* Pack a required field to a virtual buffer. -* -* \param field -* Field descriptor. -* \param member -* The element to be packed. -* \param[out] buffer -* Virtual buffer to append data to. -* \return -* Number of bytes packed. -*/ -static size_t -required_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - const void *member, ProtobufCBuffer *buffer) -{ - size_t rv; - uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; - - rv = tag_pack(field->id, scratch); - switch (field->type) { - case PROTOBUF_C_TYPE_SINT32: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += sint32_pack(*(const int32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += int32_pack(*(const int32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_UINT32: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += uint32_pack(*(const uint32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SINT64: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += sint64_pack(*(const int64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += uint64_pack(*(const uint64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_32BIT; - rv += fixed32_pack(*(const uint32_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_64BIT; - rv += fixed64_pack(*(const uint64_t *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_BOOL: - scratch[0] |= PROTOBUF_C_WIRE_TYPE_VARINT; - rv += boolean_pack(*(const protobuf_c_boolean *) member, scratch + rv); - buffer->append(buffer, rv, scratch); - break; - case PROTOBUF_C_TYPE_STRING: { - const char *str = *(char *const *) member; - size_t sublen = str ? strlen(str) : 0; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, (const uint8_t *) str); - rv += sublen; - break; - } - case PROTOBUF_C_TYPE_BYTES: { - const ProtobufCBinaryData *bd = ((const ProtobufCBinaryData *) member); - size_t sublen = bd->len; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, bd->data); - rv += sublen; - break; - } - case PROTOBUF_C_TYPE_MESSAGE: { - uint8_t simple_buffer_scratch[256]; - size_t sublen; - const ProtobufCMessage *msg = *(ProtobufCMessage * const *) member; - ProtobufCBufferSimple simple_buffer = - PROTOBUF_C_BUFFER_SIMPLE_INIT(simple_buffer_scratch); - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - if (msg == NULL) - sublen = 0; - else - sublen = protobuf_c_message_pack_to_buffer(msg, &simple_buffer.base); - rv += uint32_pack(sublen, scratch + rv); - buffer->append(buffer, rv, scratch); - buffer->append(buffer, sublen, simple_buffer.data); - rv += sublen; - PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple_buffer); - break; - } - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; -} - -/** -* Pack a oneof field to a buffer. Only packs the field that is selected by the case enum. -* -* \param field -* Field descriptor. -* \param oneof_case -* Enum value that selects the field in the oneof. -* \param member -* The element to be packed. -* \param[out] buffer -* Virtual buffer to append data to. -* \return -* Number of bytes serialised to `buffer`. -*/ -static size_t -oneof_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - uint32_t oneof_case, - const void *member, ProtobufCBuffer *buffer) -{ - if (oneof_case != field->id) { - return 0; - } - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void *const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } - return required_field_pack_to_buffer(field, member, buffer); -} - -/** -* Pack an optional field to a buffer. -* -* \param field -* Field descriptor. -* \param has -* Whether the field is set. -* \param member -* The element to be packed. -* \param[out] buffer -* Virtual buffer to append data to. -* \return -* Number of bytes serialised to `buffer`. -*/ -static size_t -optional_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - const protobuf_c_boolean has, - const void *member, ProtobufCBuffer *buffer) -{ - if (field->type == PROTOBUF_C_TYPE_MESSAGE || - field->type == PROTOBUF_C_TYPE_STRING) - { - const void *ptr = *(const void *const *) member; - if (ptr == NULL || ptr == field->default_value) - return 0; - } else { - if (!has) - return 0; - } - return required_field_pack_to_buffer(field, member, buffer); -} - -/** -* Pack an unlabeled field to a buffer. -* -* \param field -* Field descriptor. -* \param member -* The element to be packed. -* \param[out] buffer -* Virtual buffer to append data to. -* \return -* Number of bytes serialised to `buffer`. -*/ -static size_t -unlabeled_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - const void *member, ProtobufCBuffer *buffer) -{ - if (field_is_zeroish(field, member)) - return 0; - return required_field_pack_to_buffer(field, member, buffer); -} - -/** -* Get the packed size of an array of same field type. -* -* \param field -* Field descriptor. -* \param count -* Number of elements of this type. -* \param array -* The elements to get the size of. -* \return -* Number of bytes required. -*/ -static size_t -get_packed_payload_length(const ProtobufCFieldDescriptor *field, - unsigned count, const void *array) -{ - unsigned rv = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - return count * 4; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - return count * 8; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - rv += int32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_SINT32: { - const int32_t *arr = (const int32_t *) array; - for (i = 0; i < count; i++) - rv += sint32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_UINT32: { - const uint32_t *arr = (const uint32_t *) array; - for (i = 0; i < count; i++) - rv += uint32_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_SINT64: { - const int64_t *arr = (const int64_t *) array; - for (i = 0; i < count; i++) - rv += sint64_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: { - const uint64_t *arr = (const uint64_t *) array; - for (i = 0; i < count; i++) - rv += uint64_size(arr[i]); - break; - } - case PROTOBUF_C_TYPE_BOOL: - return count; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; -} - -/** -* Pack an array of same field type to a virtual buffer. -* -* \param field -* Field descriptor. -* \param count -* Number of elements of this type. -* \param array -* The elements to get the size of. -* \param[out] buffer -* Virtual buffer to append data to. -* \return -* Number of bytes packed. -*/ -static size_t -pack_buffer_packed_payload(const ProtobufCFieldDescriptor *field, - unsigned count, const void *array, - ProtobufCBuffer *buffer) -{ - uint8_t scratch[16]; - size_t rv = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: -#if !defined(WORDS_BIGENDIAN) - rv = count * 4; - goto no_packing_needed; -#else - for (i = 0; i < count; i++) { - unsigned len = fixed32_pack(((uint32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; -#endif - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: -#if !defined(WORDS_BIGENDIAN) - rv = count * 8; - goto no_packing_needed; -#else - for (i = 0; i < count; i++) { - unsigned len = fixed64_pack(((uint64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; -#endif - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - for (i = 0; i < count; i++) { - unsigned len = int32_pack(((int32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_SINT32: - for (i = 0; i < count; i++) { - unsigned len = sint32_pack(((int32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_UINT32: - for (i = 0; i < count; i++) { - unsigned len = uint32_pack(((uint32_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_SINT64: - for (i = 0; i < count; i++) { - unsigned len = sint64_pack(((int64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - for (i = 0; i < count; i++) { - unsigned len = uint64_pack(((uint64_t *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - break; - case PROTOBUF_C_TYPE_BOOL: - for (i = 0; i < count; i++) { - unsigned len = boolean_pack(((protobuf_c_boolean *) array)[i], scratch); - buffer->append(buffer, len, scratch); - rv += len; - } - return count; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - return rv; - -#if !defined(WORDS_BIGENDIAN) -no_packing_needed: - buffer->append(buffer, rv, array); - return rv; -#endif -} - -static size_t -repeated_field_pack_to_buffer(const ProtobufCFieldDescriptor *field, - unsigned count, const void *member, - ProtobufCBuffer *buffer) -{ - char *array = *(char * const *) member; - - if (count == 0) - return 0; - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED)) { - uint8_t scratch[MAX_UINT64_ENCODED_SIZE * 2]; - size_t rv = tag_pack(field->id, scratch); - size_t payload_len = get_packed_payload_length(field, count, array); - size_t tmp; - - scratch[0] |= PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED; - rv += uint32_pack(payload_len, scratch + rv); - buffer->append(buffer, rv, scratch); - tmp = pack_buffer_packed_payload(field, count, array, buffer); - assert(tmp == payload_len); - return rv + payload_len; - } else { - size_t siz; - unsigned i; - /* CONSIDER: optimize this case a bit (by putting the loop inside the switch) */ - unsigned rv = 0; - - siz = sizeof_elt_in_repeated_array(field->type); - for (i = 0; i < count; i++) { - rv += required_field_pack_to_buffer(field, array, buffer); - array += siz; - } - return rv; - } -} - -static size_t -unknown_field_pack_to_buffer(const ProtobufCMessageUnknownField *field, - ProtobufCBuffer *buffer) -{ - uint8_t header[MAX_UINT64_ENCODED_SIZE]; - size_t rv = tag_pack(field->tag, header); - - header[0] |= field->wire_type; - buffer->append(buffer, rv, header); - buffer->append(buffer, field->len, field->data); - return rv + field->len; -} - -/**@}*/ - -size_t -protobuf_c_message_pack_to_buffer(const ProtobufCMessage *message, - ProtobufCBuffer *buffer) -{ - unsigned i; - size_t rv = 0; - - ASSERT_IS_MESSAGE(message); - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *field = - message->descriptor->fields + i; - const void *member = - ((const char *) message) + field->offset; - const void *qmember = - ((const char *) message) + field->quantifier_offset; - - if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - rv += required_field_pack_to_buffer(field, member, buffer); - } else if ((field->label == PROTOBUF_C_LABEL_OPTIONAL || - field->label == PROTOBUF_C_LABEL_NONE) && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF))) { - rv += oneof_field_pack_to_buffer( - field, - *(const uint32_t *) qmember, - member, - buffer - ); - } else if (field->label == PROTOBUF_C_LABEL_OPTIONAL) { - rv += optional_field_pack_to_buffer( - field, - *(const protobuf_c_boolean *) qmember, - member, - buffer - ); - } else if (field->label == PROTOBUF_C_LABEL_NONE) { - rv += unlabeled_field_pack_to_buffer( - field, - member, - buffer - ); - } else { - rv += repeated_field_pack_to_buffer( - field, - *(const size_t *) qmember, - member, - buffer - ); - } - } - for (i = 0; i < message->n_unknown_fields; i++) - rv += unknown_field_pack_to_buffer(&message->unknown_fields[i], buffer); - - return rv; -} - -/** -* \defgroup unpack unpacking implementation -* -* Routines mainly used by the unpacking functions. -* -* \ingroup internal -* @{ -*/ - -static inline int -int_range_lookup(unsigned n_ranges, const ProtobufCIntRange *ranges, int value) -{ - unsigned n; - unsigned start; - - if (n_ranges == 0) - return -1; - start = 0; - n = n_ranges; - while (n > 1) { - unsigned mid = start + n / 2; - - if (value < ranges[mid].start_value) { - n = mid - start; - } else if (value >= ranges[mid].start_value + - (int) (ranges[mid + 1].orig_index - - ranges[mid].orig_index)) - { - unsigned new_start = mid + 1; - n = start + n - new_start; - start = new_start; - } else - return (value - ranges[mid].start_value) + - ranges[mid].orig_index; - } - if (n > 0) { - unsigned start_orig_index = ranges[start].orig_index; - unsigned range_size = - ranges[start + 1].orig_index - start_orig_index; - - if (ranges[start].start_value <= value && - value < (int) (ranges[start].start_value + range_size)) - { - return (value - ranges[start].start_value) + - start_orig_index; - } - } - return -1; -} - -static size_t -parse_tag_and_wiretype(size_t len, - const uint8_t *data, - uint32_t *tag_out, - ProtobufCWireType *wiretype_out) -{ - unsigned max_rv = len > 5 ? 5 : len; - uint32_t tag = (data[0] & 0x7f) >> 3; - unsigned shift = 4; - unsigned rv; - - *wiretype_out = data[0] & 7; - if ((data[0] & 0x80) == 0) { - *tag_out = tag; - return 1; - } - for (rv = 1; rv < max_rv; rv++) { - if (data[rv] & 0x80) { - tag |= (data[rv] & 0x7f) << shift; - shift += 7; - } else { - tag |= data[rv] << shift; - *tag_out = tag; - return rv + 1; - } - } - return 0; /* error: bad header */ -} - -/* sizeof(ScannedMember) must be <= (1UL< len) { - PROTOBUF_C_UNPACK_ERROR("data too short after length-prefix of %u", val); - return 0; - } - return hdr_len + val; -} - -static size_t -max_b128_numbers(size_t len, const uint8_t *data) -{ - size_t rv = 0; - while (len--) - if ((*data++ & 0x80) == 0) - ++rv; - return rv; -} - -/**@}*/ - -/** -* Merge earlier message into a latter message. -* -* For numeric types and strings, if the same value appears multiple -* times, the parser accepts the last value it sees. For embedded -* message fields, the parser merges multiple instances of the same -* field. That is, all singular scalar fields in the latter instance -* replace those in the former, singular embedded messages are merged, -* and repeated fields are concatenated. -* -* The earlier message should be freed after calling this function, as -* some of its fields may have been reused and changed to their default -* values during the merge. -*/ -static protobuf_c_boolean -merge_messages(ProtobufCMessage *earlier_msg, - ProtobufCMessage *latter_msg, - ProtobufCAllocator *allocator) -{ - unsigned i; - const ProtobufCFieldDescriptor *fields = - latter_msg->descriptor->fields; - for (i = 0; i < latter_msg->descriptor->n_fields; i++) { - if (fields[i].label == PROTOBUF_C_LABEL_REPEATED) { - size_t *n_earlier = - STRUCT_MEMBER_PTR(size_t, earlier_msg, - fields[i].quantifier_offset); - uint8_t **p_earlier = - STRUCT_MEMBER_PTR(uint8_t *, earlier_msg, - fields[i].offset); - size_t *n_latter = - STRUCT_MEMBER_PTR(size_t, latter_msg, - fields[i].quantifier_offset); - uint8_t **p_latter = - STRUCT_MEMBER_PTR(uint8_t *, latter_msg, - fields[i].offset); - - if (*n_earlier > 0) { - if (*n_latter > 0) { - /* Concatenate the repeated field */ - size_t el_size = - sizeof_elt_in_repeated_array(fields[i].type); - uint8_t *new_field; - - new_field = do_alloc(allocator, - (*n_earlier + *n_latter) * el_size); - if (!new_field) - return FALSE; - - memcpy(new_field, *p_earlier, - *n_earlier * el_size); - memcpy(new_field + - *n_earlier * el_size, - *p_latter, - *n_latter * el_size); - - do_free(allocator, *p_latter); - do_free(allocator, *p_earlier); - *p_latter = new_field; - *n_latter = *n_earlier + *n_latter; - } else { - /* Zero copy the repeated field from the earlier message */ - *n_latter = *n_earlier; - *p_latter = *p_earlier; - } - /* Make sure the field does not get double freed */ - *n_earlier = 0; - *p_earlier = 0; - } - } else if (fields[i].label == PROTOBUF_C_LABEL_OPTIONAL || - fields[i].label == PROTOBUF_C_LABEL_NONE) { - const ProtobufCFieldDescriptor *field; - uint32_t *earlier_case_p = STRUCT_MEMBER_PTR(uint32_t, - earlier_msg, - fields[i]. - quantifier_offset); - uint32_t *latter_case_p = STRUCT_MEMBER_PTR(uint32_t, - latter_msg, - fields[i]. - quantifier_offset); - protobuf_c_boolean need_to_merge = FALSE; - void *earlier_elem; - void *latter_elem; - const void *def_val; - - if (fields[i].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) { - if (*latter_case_p == 0) { - /* lookup correct oneof field */ - int field_index = - int_range_lookup( - latter_msg->descriptor - ->n_field_ranges, - latter_msg->descriptor - ->field_ranges, - *earlier_case_p); - if (field_index < 0) - return FALSE; - field = latter_msg->descriptor->fields + - field_index; - } else { - /* Oneof is present in the latter message, move on */ - continue; - } - } else { - field = &fields[i]; - } - - earlier_elem = STRUCT_MEMBER_P(earlier_msg, field->offset); - latter_elem = STRUCT_MEMBER_P(latter_msg, field->offset); - def_val = field->default_value; - - switch (field->type) { - case PROTOBUF_C_TYPE_MESSAGE: { - ProtobufCMessage *em = *(ProtobufCMessage **) earlier_elem; - ProtobufCMessage *lm = *(ProtobufCMessage **) latter_elem; - if (em != NULL) { - if (lm != NULL) { - if (!merge_messages(em, lm, allocator)) - return FALSE; - /* Already merged */ - need_to_merge = FALSE; - } else { - /* Zero copy the message */ - need_to_merge = TRUE; - } - } - break; - } - case PROTOBUF_C_TYPE_BYTES: { - uint8_t *e_data = - ((ProtobufCBinaryData *) earlier_elem)->data; - uint8_t *l_data = - ((ProtobufCBinaryData *) latter_elem)->data; - const ProtobufCBinaryData *d_bd = - (ProtobufCBinaryData *) def_val; - - need_to_merge = - (e_data != NULL && - (d_bd == NULL || - e_data != d_bd->data)) && - (l_data == NULL || - (d_bd != NULL && - l_data == d_bd->data)); - break; - } - case PROTOBUF_C_TYPE_STRING: { - char *e_str = *(char **) earlier_elem; - char *l_str = *(char **) latter_elem; - const char *d_str = def_val; - - need_to_merge = e_str != d_str && l_str == d_str; - break; - } - default: { - /* Could be has field or case enum, the logic is - * equivalent, since 0 (FALSE) means not set for - * oneof */ - need_to_merge = (*earlier_case_p != 0) && - (*latter_case_p == 0); - break; - } - } - - if (need_to_merge) { - size_t el_size = - sizeof_elt_in_repeated_array(field->type); - memcpy(latter_elem, earlier_elem, el_size); - /* - * Reset the element from the old message to 0 - * to make sure earlier message deallocation - * doesn't corrupt zero-copied data in the new - * message, earlier message will be freed after - * this function is called anyway - */ - memset(earlier_elem, 0, el_size); - - if (field->quantifier_offset != 0) { - /* Set the has field or the case enum, - * if applicable */ - *latter_case_p = *earlier_case_p; - *earlier_case_p = 0; - } - } - } - } - return TRUE; -} - -/** -* Count packed elements. -* -* Given a raw slab of packed-repeated values, determine the number of -* elements. This function detects certain kinds of errors but not -* others; the remaining error checking is done by -* parse_packed_repeated_member(). -*/ -static protobuf_c_boolean -count_packed_elements(ProtobufCType type, - size_t len, const uint8_t *data, size_t *count_out) -{ - switch (type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - if (len % 4 != 0) { - PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 4 for fixed-length 32-bit types"); - return FALSE; - } - *count_out = len / 4; - return TRUE; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - if (len % 8 != 0) { - PROTOBUF_C_UNPACK_ERROR("length must be a multiple of 8 for fixed-length 64-bit types"); - return FALSE; - } - *count_out = len / 8; - return TRUE; - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_UINT64: - *count_out = max_b128_numbers(len, data); - return TRUE; - case PROTOBUF_C_TYPE_BOOL: - *count_out = len; - return TRUE; - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_BYTES: - case PROTOBUF_C_TYPE_MESSAGE: - default: - PROTOBUF_C_UNPACK_ERROR("bad protobuf-c type %u for packed-repeated", type); - return FALSE; - } -} - -static inline uint32_t -parse_uint32(unsigned len, const uint8_t *data) -{ - uint32_t rv = data[0] & 0x7f; - if (len > 1) { - rv |= ((uint32_t) (data[1] & 0x7f) << 7); - if (len > 2) { - rv |= ((uint32_t) (data[2] & 0x7f) << 14); - if (len > 3) { - rv |= ((uint32_t) (data[3] & 0x7f) << 21); - if (len > 4) - rv |= ((uint32_t) (data[4]) << 28); - } - } - } - return rv; -} - -static inline uint32_t -parse_int32(unsigned len, const uint8_t *data) -{ - return parse_uint32(len, data); -} - -static inline int32_t -unzigzag32(uint32_t v) -{ - if (v & 1) - return -(v >> 1) - 1; - else - return v >> 1; -} - -static inline uint32_t -parse_fixed_uint32(const uint8_t *data) -{ -#if !defined(WORDS_BIGENDIAN) - uint32_t t; - memcpy(&t, data, 4); - return t; -#else - return data[0] | - ((uint32_t) (data[1]) << 8) | - ((uint32_t) (data[2]) << 16) | - ((uint32_t) (data[3]) << 24); -#endif -} - -static uint64_t -parse_uint64(unsigned len, const uint8_t *data) -{ - unsigned shift, i; - uint64_t rv; - - if (len < 5) - return parse_uint32(len, data); - rv = ((uint64_t) (data[0] & 0x7f)) | - ((uint64_t) (data[1] & 0x7f) << 7) | - ((uint64_t) (data[2] & 0x7f) << 14) | - ((uint64_t) (data[3] & 0x7f) << 21); - shift = 28; - for (i = 4; i < len; i++) { - rv |= (((uint64_t) (data[i] & 0x7f)) << shift); - shift += 7; - } - return rv; -} - -static inline int64_t -unzigzag64(uint64_t v) -{ - if (v & 1) - return -(v >> 1) - 1; - else - return v >> 1; -} - -static inline uint64_t -parse_fixed_uint64(const uint8_t *data) -{ -#if !defined(WORDS_BIGENDIAN) - uint64_t t; - memcpy(&t, data, 8); - return t; -#else - return (uint64_t) parse_fixed_uint32(data) | - (((uint64_t) parse_fixed_uint32(data + 4)) << 32); -#endif -} - -static protobuf_c_boolean -parse_boolean(unsigned len, const uint8_t *data) -{ - unsigned i; - for (i = 0; i < len; i++) - if (data[i] & 0x7f) - return TRUE; - return FALSE; -} - -static protobuf_c_boolean -parse_required_member(ScannedMember *scanned_member, - void *member, - ProtobufCAllocator *allocator, - protobuf_c_boolean maybe_clear) -{ - unsigned len = scanned_member->len; - const uint8_t *data = scanned_member->data; - ProtobufCWireType wire_type = scanned_member->wire_type; - - switch (scanned_member->field->type) { - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(int32_t *) member = parse_int32(len, data); - return TRUE; - case PROTOBUF_C_TYPE_UINT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint32_t *) member = parse_uint32(len, data); - return TRUE; - case PROTOBUF_C_TYPE_SINT32: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(int32_t *) member = unzigzag32(parse_uint32(len, data)); - return TRUE; - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - if (wire_type != PROTOBUF_C_WIRE_TYPE_32BIT) - return FALSE; - *(uint32_t *) member = parse_fixed_uint32(data); - return TRUE; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(uint64_t *) member = parse_uint64(len, data); - return TRUE; - case PROTOBUF_C_TYPE_SINT64: - if (wire_type != PROTOBUF_C_WIRE_TYPE_VARINT) - return FALSE; - *(int64_t *) member = unzigzag64(parse_uint64(len, data)); - return TRUE; - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - if (wire_type != PROTOBUF_C_WIRE_TYPE_64BIT) - return FALSE; - *(uint64_t *) member = parse_fixed_uint64(data); - return TRUE; - case PROTOBUF_C_TYPE_BOOL: - *(protobuf_c_boolean *) member = parse_boolean(len, data); - return TRUE; - case PROTOBUF_C_TYPE_STRING: { - char **pstr = member; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - if (maybe_clear && *pstr != NULL) { - const char *def = scanned_member->field->default_value; - if (*pstr != NULL && *pstr != def) - do_free(allocator, *pstr); - } - *pstr = do_alloc(allocator, len - pref_len + 1); - if (*pstr == NULL) - return FALSE; - memcpy(*pstr, data + pref_len, len - pref_len); - (*pstr)[len - pref_len] = 0; - return TRUE; - } - case PROTOBUF_C_TYPE_BYTES: { - ProtobufCBinaryData *bd = member; - const ProtobufCBinaryData *def_bd; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - def_bd = scanned_member->field->default_value; - if (maybe_clear && - bd->data != NULL && - (def_bd == NULL || bd->data != def_bd->data)) - { - do_free(allocator, bd->data); - } - if (len - pref_len > 0) { - bd->data = do_alloc(allocator, len - pref_len); - if (bd->data == NULL) - return FALSE; - memcpy(bd->data, data + pref_len, len - pref_len); - } else { - bd->data = NULL; - } - bd->len = len - pref_len; - return TRUE; - } - case PROTOBUF_C_TYPE_MESSAGE: { - ProtobufCMessage **pmessage = member; - ProtobufCMessage *subm; - const ProtobufCMessage *def_mess; - protobuf_c_boolean merge_successful = TRUE; - unsigned pref_len = scanned_member->length_prefix_len; - - if (wire_type != PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED) - return FALSE; - - def_mess = scanned_member->field->default_value; - subm = protobuf_c_message_unpack(scanned_member->field->descriptor, - allocator, - len - pref_len, - data + pref_len); - - if (maybe_clear && - *pmessage != NULL && - *pmessage != def_mess) - { - if (subm != NULL) - merge_successful = merge_messages(*pmessage, subm, allocator); - /* Delete the previous message */ - protobuf_c_message_free_unpacked(*pmessage, allocator); - } - *pmessage = subm; - if (subm == NULL || !merge_successful) - return FALSE; - return TRUE; - } - } - return FALSE; -} - -static protobuf_c_boolean -parse_oneof_member (ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - uint32_t *oneof_case = STRUCT_MEMBER_PTR(uint32_t, message, - scanned_member->field->quantifier_offset); - - /* If we have already parsed a member of this oneof, free it. */ - if (*oneof_case != 0) { - /* lookup field */ - int field_index = - int_range_lookup(message->descriptor->n_field_ranges, - message->descriptor->field_ranges, - *oneof_case); - if (field_index < 0) - return FALSE; - const ProtobufCFieldDescriptor *old_field = - message->descriptor->fields + field_index; - size_t el_size = sizeof_elt_in_repeated_array(old_field->type); - - switch (old_field->type) { - case PROTOBUF_C_TYPE_STRING: { - char **pstr = member; - const char *def = old_field->default_value; - if (*pstr != NULL && *pstr != def) - do_free(allocator, *pstr); - break; - } - case PROTOBUF_C_TYPE_BYTES: { - ProtobufCBinaryData *bd = member; - const ProtobufCBinaryData *def_bd = old_field->default_value; - if (bd->data != NULL && - (def_bd == NULL || bd->data != def_bd->data)) - { - do_free(allocator, bd->data); - } - break; - } - case PROTOBUF_C_TYPE_MESSAGE: { - ProtobufCMessage **pmessage = member; - const ProtobufCMessage *def_mess = old_field->default_value; - if (*pmessage != NULL && *pmessage != def_mess) - protobuf_c_message_free_unpacked(*pmessage, allocator); - break; - } - default: - break; - } - - memset (member, 0, el_size); - } - if (!parse_required_member (scanned_member, member, allocator, TRUE)) - return FALSE; - - *oneof_case = scanned_member->tag; - return TRUE; -} - - -static protobuf_c_boolean -parse_optional_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - if (!parse_required_member(scanned_member, member, allocator, TRUE)) - return FALSE; - if (scanned_member->field->quantifier_offset != 0) - STRUCT_MEMBER(protobuf_c_boolean, - message, - scanned_member->field->quantifier_offset) = TRUE; - return TRUE; -} - -static protobuf_c_boolean -parse_repeated_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); - size_t siz = sizeof_elt_in_repeated_array(field->type); - char *array = *(char **) member; - - if (!parse_required_member(scanned_member, array + siz * (*p_n), - allocator, FALSE)) - { - return FALSE; - } - *p_n += 1; - return TRUE; -} - -static unsigned -scan_varint(unsigned len, const uint8_t *data) -{ - unsigned i; - if (len > 10) - len = 10; - for (i = 0; i < len; i++) - if ((data[i] & 0x80) == 0) - break; - if (i == len) - return 0; - return i + 1; -} - -static protobuf_c_boolean -parse_packed_repeated_member(ScannedMember *scanned_member, - void *member, - ProtobufCMessage *message) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - size_t *p_n = STRUCT_MEMBER_PTR(size_t, message, field->quantifier_offset); - size_t siz = sizeof_elt_in_repeated_array(field->type); - void *array = *(char **) member + siz * (*p_n); - const uint8_t *at = scanned_member->data + scanned_member->length_prefix_len; - size_t rem = scanned_member->len - scanned_member->length_prefix_len; - size_t count = 0; - unsigned i; - - switch (field->type) { - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - count = (scanned_member->len - scanned_member->length_prefix_len) / 4; -#if !defined(WORDS_BIGENDIAN) - goto no_unpacking_needed; -#else - for (i = 0; i < count; i++) { - ((uint32_t *) array)[i] = parse_fixed_uint32(at); - at += 4; - } - break; -#endif - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - count = (scanned_member->len - scanned_member->length_prefix_len) / 8; -#if !defined(WORDS_BIGENDIAN) - goto no_unpacking_needed; -#else - for (i = 0; i < count; i++) { - ((uint64_t *) array)[i] = parse_fixed_uint64(at); - at += 8; - } - break; -#endif - case PROTOBUF_C_TYPE_ENUM: - case PROTOBUF_C_TYPE_INT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int32 value"); - return FALSE; - } - ((int32_t *) array)[count++] = parse_int32(s, at); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_SINT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint32 value"); - return FALSE; - } - ((int32_t *) array)[count++] = unzigzag32(parse_uint32(s, at)); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_UINT32: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated enum or uint32 value"); - return FALSE; - } - ((uint32_t *) array)[count++] = parse_uint32(s, at); - at += s; - rem -= s; - } - break; - - case PROTOBUF_C_TYPE_SINT64: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated sint64 value"); - return FALSE; - } - ((int64_t *) array)[count++] = unzigzag64(parse_uint64(s, at)); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_UINT64: - while (rem > 0) { - unsigned s = scan_varint(rem, at); - if (s == 0) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated int64/uint64 value"); - return FALSE; - } - ((int64_t *) array)[count++] = parse_uint64(s, at); - at += s; - rem -= s; - } - break; - case PROTOBUF_C_TYPE_BOOL: - count = rem; - for (i = 0; i < count; i++) { - if (at[i] > 1) { - PROTOBUF_C_UNPACK_ERROR("bad packed-repeated boolean value"); - return FALSE; - } - ((protobuf_c_boolean *) array)[i] = at[i]; - } - break; - default: - PROTOBUF_C__ASSERT_NOT_REACHED(); - } - *p_n += count; - return TRUE; - -#if !defined(WORDS_BIGENDIAN) -no_unpacking_needed: - memcpy(array, at, count * siz); - *p_n += count; - return TRUE; -#endif -} - -static protobuf_c_boolean -is_packable_type(ProtobufCType type) -{ - return - type != PROTOBUF_C_TYPE_STRING && - type != PROTOBUF_C_TYPE_BYTES && - type != PROTOBUF_C_TYPE_MESSAGE; -} - -static protobuf_c_boolean -parse_member(ScannedMember *scanned_member, - ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCFieldDescriptor *field = scanned_member->field; - void *member; - - if (field == NULL) { - ProtobufCMessageUnknownField *ufield = - message->unknown_fields + - (message->n_unknown_fields++); - ufield->tag = scanned_member->tag; - ufield->wire_type = scanned_member->wire_type; - ufield->len = scanned_member->len; - ufield->data = do_alloc(allocator, scanned_member->len); - if (ufield->data == NULL) - return FALSE; - memcpy(ufield->data, scanned_member->data, ufield->len); - return TRUE; - } - member = (char *) message + field->offset; - switch (field->label) { - case PROTOBUF_C_LABEL_REQUIRED: - return parse_required_member(scanned_member, member, - allocator, TRUE); - case PROTOBUF_C_LABEL_OPTIONAL: - case PROTOBUF_C_LABEL_NONE: - if (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_ONEOF)) { - return parse_oneof_member(scanned_member, member, - message, allocator); - } else { - return parse_optional_member(scanned_member, member, - message, allocator); - } - case PROTOBUF_C_LABEL_REPEATED: - if (scanned_member->wire_type == - PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || - is_packable_type(field->type))) - { - return parse_packed_repeated_member(scanned_member, - member, message); - } else { - return parse_repeated_member(scanned_member, - member, message, - allocator); - } - } - PROTOBUF_C__ASSERT_NOT_REACHED(); - return 0; -} - -/** -* Initialise messages generated by old code. -* -* This function is used if desc->message_init == NULL (which occurs -* for old code, and which would be useful to support allocating -* descriptors dynamically). -*/ -static void -message_init_generic(const ProtobufCMessageDescriptor *desc, - ProtobufCMessage *message) -{ - unsigned i; - - memset(message, 0, desc->sizeof_message); - message->descriptor = desc; - for (i = 0; i < desc->n_fields; i++) { - if (desc->fields[i].default_value != NULL && - desc->fields[i].label != PROTOBUF_C_LABEL_REPEATED) - { - void *field = - STRUCT_MEMBER_P(message, desc->fields[i].offset); - const void *dv = desc->fields[i].default_value; - - switch (desc->fields[i].type) { - case PROTOBUF_C_TYPE_INT32: - case PROTOBUF_C_TYPE_SINT32: - case PROTOBUF_C_TYPE_SFIXED32: - case PROTOBUF_C_TYPE_UINT32: - case PROTOBUF_C_TYPE_FIXED32: - case PROTOBUF_C_TYPE_FLOAT: - case PROTOBUF_C_TYPE_ENUM: - memcpy(field, dv, 4); - break; - case PROTOBUF_C_TYPE_INT64: - case PROTOBUF_C_TYPE_SINT64: - case PROTOBUF_C_TYPE_SFIXED64: - case PROTOBUF_C_TYPE_UINT64: - case PROTOBUF_C_TYPE_FIXED64: - case PROTOBUF_C_TYPE_DOUBLE: - memcpy(field, dv, 8); - break; - case PROTOBUF_C_TYPE_BOOL: - memcpy(field, dv, sizeof(protobuf_c_boolean)); - break; - case PROTOBUF_C_TYPE_BYTES: - memcpy(field, dv, sizeof(ProtobufCBinaryData)); - break; - - case PROTOBUF_C_TYPE_STRING: - case PROTOBUF_C_TYPE_MESSAGE: - /* - * The next line essentially implements a cast - * from const, which is totally unavoidable. - */ - *(const void **) field = dv; - break; - } - } - } -} - -/**@}*/ - -/* -* ScannedMember slabs (an unpacking implementation detail). Before doing real -* unpacking, we first scan through the elements to see how many there are (for -* repeated fields), and which field to use (for non-repeated fields given -* twice). -* -* In order to avoid allocations for small messages, we keep a stack-allocated -* slab of ScannedMembers of size FIRST_SCANNED_MEMBER_SLAB_SIZE (16). After we -* fill that up, we allocate each slab twice as large as the previous one. -*/ -#define FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2 4 - -/* -* The number of slabs, including the stack-allocated ones; choose the number so -* that we would overflow if we needed a slab larger than provided. -*/ -#define MAX_SCANNED_MEMBER_SLAB \ -(sizeof(unsigned int)*8 - 1 \ -- BOUND_SIZEOF_SCANNED_MEMBER_LOG2 \ -- FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2) - -#define REQUIRED_FIELD_BITMAP_SET(index) \ - (required_fields_bitmap[(index)/8] |= (1UL<<((index)%8))) - -#define REQUIRED_FIELD_BITMAP_IS_SET(index) \ - (required_fields_bitmap[(index)/8] & (1UL<<((index)%8))) - -ProtobufCMessage * -protobuf_c_message_unpack(const ProtobufCMessageDescriptor *desc, - ProtobufCAllocator *allocator, - size_t len, const uint8_t *data) -{ - ProtobufCMessage *rv; - size_t rem = len; - const uint8_t *at = data; - const ProtobufCFieldDescriptor *last_field = desc->fields + 0; - ScannedMember first_member_slab[1UL << - FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2]; - - /* - * scanned_member_slabs[i] is an array of arrays of ScannedMember. - * The first slab (scanned_member_slabs[0] is just a pointer to - * first_member_slab), above. All subsequent slabs will be allocated - * using the allocator. - */ - ScannedMember *scanned_member_slabs[MAX_SCANNED_MEMBER_SLAB + 1]; - unsigned which_slab = 0; /* the slab we are currently populating */ - unsigned in_slab_index = 0; /* number of members in the slab */ - size_t n_unknown = 0; - unsigned f; - unsigned j; - unsigned i_slab; - unsigned last_field_index = 0; - unsigned required_fields_bitmap_len; - unsigned char required_fields_bitmap_stack[16]; - unsigned char *required_fields_bitmap = required_fields_bitmap_stack; - protobuf_c_boolean required_fields_bitmap_alloced = FALSE; - - ASSERT_IS_MESSAGE_DESCRIPTOR(desc); - - if (allocator == NULL) - allocator = &protobuf_c__allocator; - - rv = do_alloc(allocator, desc->sizeof_message); - if (!rv) - return (NULL); - scanned_member_slabs[0] = first_member_slab; - - required_fields_bitmap_len = (desc->n_fields + 7) / 8; - if (required_fields_bitmap_len > sizeof(required_fields_bitmap_stack)) { - required_fields_bitmap = do_alloc(allocator, required_fields_bitmap_len); - if (!required_fields_bitmap) { - do_free(allocator, rv); - return (NULL); - } - required_fields_bitmap_alloced = TRUE; - } - memset(required_fields_bitmap, 0, required_fields_bitmap_len); - - /* - * Generated code always defines "message_init". However, we provide a - * fallback for (1) users of old protobuf-c generated-code that do not - * provide the function, and (2) descriptors constructed from some other - * source (most likely, direct construction from the .proto file). - */ - if (desc->message_init != NULL) - protobuf_c_message_init(desc, rv); - else - message_init_generic(desc, rv); - - while (rem > 0) { - uint32_t tag; - ProtobufCWireType wire_type; - size_t used = parse_tag_and_wiretype(rem, at, &tag, &wire_type); - const ProtobufCFieldDescriptor *field; - ScannedMember tmp; - - if (used == 0) { - PROTOBUF_C_UNPACK_ERROR("error parsing tag/wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - /* - * \todo Consider optimizing for field[1].id == tag, if field[1] - * exists! - */ - if (last_field == NULL || last_field->id != tag) { - /* lookup field */ - int field_index = - int_range_lookup(desc->n_field_ranges, - desc->field_ranges, - tag); - if (field_index < 0) { - field = NULL; - n_unknown++; - } else { - field = desc->fields + field_index; - last_field = field; - last_field_index = field_index; - } - } else { - field = last_field; - } - - if (field != NULL && field->label == PROTOBUF_C_LABEL_REQUIRED) - REQUIRED_FIELD_BITMAP_SET(last_field_index); - - at += used; - rem -= used; - tmp.tag = tag; - tmp.wire_type = wire_type; - tmp.field = field; - tmp.data = at; - tmp.length_prefix_len = 0; - - switch (wire_type) { - case PROTOBUF_C_WIRE_TYPE_VARINT: { - unsigned max_len = rem < 10 ? rem : 10; - unsigned i; - - for (i = 0; i < max_len; i++) - if ((at[i] & 0x80) == 0) - break; - if (i == max_len) { - PROTOBUF_C_UNPACK_ERROR("unterminated varint at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = i + 1; - break; - } - case PROTOBUF_C_WIRE_TYPE_64BIT: - if (rem < 8) { - PROTOBUF_C_UNPACK_ERROR("too short after 64bit wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = 8; - break; - case PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED: { - size_t pref_len; - - tmp.len = scan_length_prefixed_data(rem, at, &pref_len); - if (tmp.len == 0) { - /* NOTE: scan_length_prefixed_data calls UNPACK_ERROR */ - goto error_cleanup_during_scan; - } - tmp.length_prefix_len = pref_len; - break; - } - case PROTOBUF_C_WIRE_TYPE_32BIT: - if (rem < 4) { - PROTOBUF_C_UNPACK_ERROR("too short after 32bit wiretype at offset %u", - (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - tmp.len = 4; - break; - default: - PROTOBUF_C_UNPACK_ERROR("unsupported tag %u at offset %u", - wire_type, (unsigned) (at - data)); - goto error_cleanup_during_scan; - } - - if (in_slab_index == (1UL << - (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2))) - { - size_t size; - - in_slab_index = 0; - if (which_slab == MAX_SCANNED_MEMBER_SLAB) { - PROTOBUF_C_UNPACK_ERROR("too many fields"); - goto error_cleanup_during_scan; - } - which_slab++; - size = sizeof(ScannedMember) - << (which_slab + FIRST_SCANNED_MEMBER_SLAB_SIZE_LOG2); - scanned_member_slabs[which_slab] = do_alloc(allocator, size); - if (scanned_member_slabs[which_slab] == NULL) - goto error_cleanup_during_scan; - } - scanned_member_slabs[which_slab][in_slab_index++] = tmp; - - if (field != NULL && field->label == PROTOBUF_C_LABEL_REPEATED) { - size_t *n = STRUCT_MEMBER_PTR(size_t, rv, - field->quantifier_offset); - if (wire_type == PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED && - (0 != (field->flags & PROTOBUF_C_FIELD_FLAG_PACKED) || - is_packable_type(field->type))) - { - size_t count; - if (!count_packed_elements(field->type, - tmp.len - - tmp.length_prefix_len, - tmp.data + - tmp.length_prefix_len, - &count)) - { - PROTOBUF_C_UNPACK_ERROR("counting packed elements"); - goto error_cleanup_during_scan; - } - *n += count; - } else { - *n += 1; - } - } - - at += tmp.len; - rem -= tmp.len; - } - - /* allocate space for repeated fields, also check that all required fields have been set */ - for (f = 0; f < desc->n_fields; f++) { - const ProtobufCFieldDescriptor *field = desc->fields + f; - if (field->label == PROTOBUF_C_LABEL_REPEATED) { - size_t siz = - sizeof_elt_in_repeated_array(field->type); - size_t *n_ptr = - STRUCT_MEMBER_PTR(size_t, rv, - field->quantifier_offset); - if (*n_ptr != 0) { - unsigned n = *n_ptr; - void *a; - *n_ptr = 0; - assert(rv->descriptor != NULL); -#define CLEAR_REMAINING_N_PTRS() \ -for(f++;f < desc->n_fields; f++) \ -{ \ -field = desc->fields + f; \ -if (field->label == PROTOBUF_C_LABEL_REPEATED) \ -STRUCT_MEMBER (size_t, rv, field->quantifier_offset) = 0; \ -} - a = do_alloc(allocator, siz * n); - if (!a) { - CLEAR_REMAINING_N_PTRS(); - goto error_cleanup; - } - STRUCT_MEMBER(void *, rv, field->offset) = a; - } - } else if (field->label == PROTOBUF_C_LABEL_REQUIRED) { - if (field->default_value == NULL && - !REQUIRED_FIELD_BITMAP_IS_SET(f)) - { - CLEAR_REMAINING_N_PTRS(); - PROTOBUF_C_UNPACK_ERROR("message '%s': missing required field '%s'", - desc->name, field->name); - goto error_cleanup; - } - } - } -#undef CLEAR_REMAINING_N_PTRS - - /* allocate space for unknown fields */ - if (n_unknown) { - rv->unknown_fields = do_alloc(allocator, - n_unknown * sizeof(ProtobufCMessageUnknownField)); - if (rv->unknown_fields == NULL) - goto error_cleanup; - } - - /* do real parsing */ - for (i_slab = 0; i_slab <= which_slab; i_slab++) { - unsigned max = (i_slab == which_slab) ? - in_slab_index : (1UL << (i_slab + 4)); - ScannedMember *slab = scanned_member_slabs[i_slab]; - - for (j = 0; j < max; j++) { - if (!parse_member(slab + j, rv, allocator)) { - PROTOBUF_C_UNPACK_ERROR("error parsing member %s of %s", - slab->field ? slab->field->name : "*unknown-field*", - desc->name); - goto error_cleanup; - } - } - } - - /* cleanup */ - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return rv; - -error_cleanup: - protobuf_c_message_free_unpacked(rv, allocator); - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return NULL; - -error_cleanup_during_scan: - do_free(allocator, rv); - for (j = 1; j <= which_slab; j++) - do_free(allocator, scanned_member_slabs[j]); - if (required_fields_bitmap_alloced) - do_free(allocator, required_fields_bitmap); - return NULL; -} - -void -protobuf_c_message_free_unpacked(ProtobufCMessage *message, - ProtobufCAllocator *allocator) -{ - const ProtobufCMessageDescriptor *desc; - unsigned f; - - if (message == NULL) - return; - - desc = message->descriptor; - - ASSERT_IS_MESSAGE(message); - - if (allocator == NULL) - allocator = &protobuf_c__allocator; - message->descriptor = NULL; - for (f = 0; f < desc->n_fields; f++) { - if (0 != (desc->fields[f].flags & PROTOBUF_C_FIELD_FLAG_ONEOF) && - desc->fields[f].id != - STRUCT_MEMBER(uint32_t, message, desc->fields[f].quantifier_offset)) - { - /* This is not the selected oneof, skip it */ - continue; - } - - if (desc->fields[f].label == PROTOBUF_C_LABEL_REPEATED) { - size_t n = STRUCT_MEMBER(size_t, - message, - desc->fields[f].quantifier_offset); - void *arr = STRUCT_MEMBER(void *, - message, - desc->fields[f].offset); - - if (arr != NULL) { - if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { - unsigned i; - for (i = 0; i < n; i++) - do_free(allocator, ((char **) arr)[i]); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { - unsigned i; - for (i = 0; i < n; i++) - do_free(allocator, ((ProtobufCBinaryData *) arr)[i].data); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { - unsigned i; - for (i = 0; i < n; i++) - protobuf_c_message_free_unpacked( - ((ProtobufCMessage **) arr)[i], - allocator - ); - } - do_free(allocator, arr); - } - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_STRING) { - char *str = STRUCT_MEMBER(char *, message, - desc->fields[f].offset); - - if (str && str != desc->fields[f].default_value) - do_free(allocator, str); - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_BYTES) { - void *data = STRUCT_MEMBER(ProtobufCBinaryData, message, - desc->fields[f].offset).data; - const ProtobufCBinaryData *default_bd; - - default_bd = desc->fields[f].default_value; - if (data != NULL && - (default_bd == NULL || - default_bd->data != data)) - { - do_free(allocator, data); - } - } else if (desc->fields[f].type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage *sm; - - sm = STRUCT_MEMBER(ProtobufCMessage *, message, - desc->fields[f].offset); - if (sm && sm != desc->fields[f].default_value) - protobuf_c_message_free_unpacked(sm, allocator); - } - } - - for (f = 0; f < message->n_unknown_fields; f++) - do_free(allocator, message->unknown_fields[f].data); - if (message->unknown_fields != NULL) - do_free(allocator, message->unknown_fields); - - do_free(allocator, message); -} - -void -protobuf_c_message_init(const ProtobufCMessageDescriptor * descriptor, - void *message) -{ - descriptor->message_init((ProtobufCMessage *) (message)); -} - -protobuf_c_boolean -protobuf_c_message_check(const ProtobufCMessage *message) -{ - unsigned i; - - if (!message || - !message->descriptor || - message->descriptor->magic != PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC) - { - return FALSE; - } - - for (i = 0; i < message->descriptor->n_fields; i++) { - const ProtobufCFieldDescriptor *f = message->descriptor->fields + i; - ProtobufCType type = f->type; - ProtobufCLabel label = f->label; - void *field = STRUCT_MEMBER_P (message, f->offset); - - if (label == PROTOBUF_C_LABEL_REPEATED) { - size_t *quantity = STRUCT_MEMBER_P (message, f->quantifier_offset); - - if (*quantity > 0 && *(void **) field == NULL) { - return FALSE; - } - - if (type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage **submessage = *(ProtobufCMessage ***) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (!protobuf_c_message_check(submessage[j])) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_STRING) { - char **string = *(char ***) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (!string[j]) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_BYTES) { - ProtobufCBinaryData *bd = *(ProtobufCBinaryData **) field; - unsigned j; - for (j = 0; j < *quantity; j++) { - if (bd[j].len > 0 && bd[j].data == NULL) - return FALSE; - } - } - - } else { /* PROTOBUF_C_LABEL_REQUIRED or PROTOBUF_C_LABEL_OPTIONAL */ - - if (type == PROTOBUF_C_TYPE_MESSAGE) { - ProtobufCMessage *submessage = *(ProtobufCMessage **) field; - if (label == PROTOBUF_C_LABEL_REQUIRED || submessage != NULL) { - if (!protobuf_c_message_check(submessage)) - return FALSE; - } - } else if (type == PROTOBUF_C_TYPE_STRING) { - char *string = *(char **) field; - if (label == PROTOBUF_C_LABEL_REQUIRED && string == NULL) - return FALSE; - } else if (type == PROTOBUF_C_TYPE_BYTES) { - protobuf_c_boolean *has = STRUCT_MEMBER_P (message, f->quantifier_offset); - ProtobufCBinaryData *bd = field; - if (label == PROTOBUF_C_LABEL_REQUIRED || *has == TRUE) { - if (bd->len > 0 && bd->data == NULL) - return FALSE; - } - } - } - } - - return TRUE; -} - -/* === services === */ - -typedef void (*GenericHandler) (void *service, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); -void -protobuf_c_service_invoke_internal(ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data) -{ - GenericHandler *handlers; - GenericHandler handler; - - /* - * Verify that method_index is within range. If this fails, you are - * likely invoking a newly added method on an old service. (Although - * other memory corruption bugs can cause this assertion too.) - */ - assert(method_index < service->descriptor->n_methods); - - /* - * Get the array of virtual methods (which are enumerated by the - * generated code). - */ - handlers = (GenericHandler *) (service + 1); - - /* - * Get our method and invoke it. - * \todo Seems like handler == NULL is a situation that needs handling. - */ - handler = handlers[method_index]; - (*handler)(service, input, closure, closure_data); -} - -void -protobuf_c_service_generated_init(ProtobufCService *service, - const ProtobufCServiceDescriptor *descriptor, - ProtobufCServiceDestroy destroy) -{ - ASSERT_IS_SERVICE_DESCRIPTOR(descriptor); - service->descriptor = descriptor; - service->destroy = destroy; - service->invoke = protobuf_c_service_invoke_internal; - memset(service + 1, 0, descriptor->n_methods * sizeof(GenericHandler)); -} - -void protobuf_c_service_destroy(ProtobufCService *service) -{ - service->destroy(service); -} - -/* --- querying the descriptors --- */ - -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value_by_name(const ProtobufCEnumDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count; - - if (desc == NULL || desc->values_by_name == NULL) - return NULL; - - count = desc->n_value_names; - - while (count > 1) { - unsigned mid = start + count / 2; - int rv = strcmp(desc->values_by_name[mid].name, name); - if (rv == 0) - return desc->values + desc->values_by_name[mid].index; - else if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else - count = mid - start; - } - if (count == 0) - return NULL; - if (strcmp(desc->values_by_name[start].name, name) == 0) - return desc->values + desc->values_by_name[start].index; - return NULL; -} - -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value(const ProtobufCEnumDescriptor *desc, - int value) -{ - int rv = int_range_lookup(desc->n_value_ranges, desc->value_ranges, value); - if (rv < 0) - return NULL; - return desc->values + rv; -} - -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field_by_name(const ProtobufCMessageDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count; - const ProtobufCFieldDescriptor *field; - - if (desc == NULL || desc->fields_sorted_by_name == NULL) - return NULL; - - count = desc->n_fields; - - while (count > 1) { - unsigned mid = start + count / 2; - int rv; - field = desc->fields + desc->fields_sorted_by_name[mid]; - rv = strcmp(field->name, name); - if (rv == 0) - return field; - else if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else - count = mid - start; - } - if (count == 0) - return NULL; - field = desc->fields + desc->fields_sorted_by_name[start]; - if (strcmp(field->name, name) == 0) - return field; - return NULL; -} - -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field(const ProtobufCMessageDescriptor *desc, - unsigned value) -{ - int rv = int_range_lookup(desc->n_field_ranges,desc->field_ranges, value); - if (rv < 0) - return NULL; - return desc->fields + rv; -} - -const ProtobufCMethodDescriptor * -protobuf_c_service_descriptor_get_method_by_name(const ProtobufCServiceDescriptor *desc, - const char *name) -{ - unsigned start = 0; - unsigned count; - - if (desc == NULL || desc->method_indices_by_name == NULL) - return NULL; - - count = desc->n_methods; - - while (count > 1) { - unsigned mid = start + count / 2; - unsigned mid_index = desc->method_indices_by_name[mid]; - const char *mid_name = desc->methods[mid_index].name; - int rv = strcmp(mid_name, name); - - if (rv == 0) - return desc->methods + desc->method_indices_by_name[mid]; - if (rv < 0) { - count = start + count - (mid + 1); - start = mid + 1; - } else { - count = mid - start; - } - } - if (count == 0) - return NULL; - if (strcmp(desc->methods[desc->method_indices_by_name[start]].name, name) == 0) - return desc->methods + desc->method_indices_by_name[start]; - return NULL; -} diff --git a/src/thirdparty/protobuf-c/protobuf-c.h b/src/thirdparty/protobuf-c/protobuf-c.h deleted file mode 100644 index 33a9597d4..000000000 --- a/src/thirdparty/protobuf-c/protobuf-c.h +++ /dev/null @@ -1,1108 +0,0 @@ -/* -* Copyright (c) 2008-2018, Dave Benson and the protobuf-c authors. -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions are -* met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * 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. -*/ - -/*! \file -* \mainpage Introduction -* -* This is [protobuf-c], a C implementation of [Protocol Buffers]. -* -* This file defines the public API for the `libprotobuf-c` support library. -* This API includes interfaces that can be used directly by client code as well -* as the interfaces used by the code generated by the `protoc-c` compiler. -* -* The `libprotobuf-c` support library performs the actual serialization and -* deserialization of Protocol Buffers messages. It interacts with structures, -* definitions, and metadata generated by the `protoc-c` compiler from .proto -* files. -* -* \authors Dave Benson and the `protobuf-c` authors. -* -* \copyright 2008-2014. Licensed under the terms of the [BSD-2-Clause] license. -* -* [protobuf-c]: https://github.com/protobuf-c/protobuf-c -* [Protocol Buffers]: https://developers.google.com/protocol-buffers/ -* [BSD-2-Clause]: http://opensource.org/licenses/BSD-2-Clause -* -* \page gencode Generated Code -* -* For each enum, we generate a C enum. For each message, we generate a C -* structure which can be cast to a `ProtobufCMessage`. -* -* For each enum and message, we generate a descriptor object that allows us to -* implement a kind of reflection on the structures. -* -* First, some naming conventions: -* -* - The name of the type for enums and messages and services is camel case -* (meaning WordsAreCrammedTogether) except that double underscores are used -* to delimit scopes. For example, the following `.proto` file: -* -~~~{.proto} -package foo.bar; -message BazBah { -optional int32 val = 1; -} -~~~ -* -* would generate a C type `Foo__Bar__BazBah`. -* -* - Identifiers for functions and globals are all lowercase, with camel case -* words separated by single underscores. For example, one of the function -* prototypes generated by `protoc-c` for the above example: -* -~~~{.c} -Foo__Bar__BazBah * -foo__bar__baz_bah__unpack -(ProtobufCAllocator *allocator, -size_t len, -const uint8_t *data); -~~~ -* -* - Identifiers for enum values contain an uppercase prefix which embeds the -* package name and the enum type name. -* -* - A double underscore is used to separate further components of identifier -* names. -* -* For example, in the name of the unpack function above, the package name -* `foo.bar` has become `foo__bar`, the message name BazBah has become -* `baz_bah`, and the method name is `unpack`. These are all joined with double -* underscores to form the C identifier `foo__bar__baz_bah__unpack`. -* -* We also generate descriptor objects for messages and enums. These are -* declared in the `.pb-c.h` files: -* -~~~{.c} -extern const ProtobufCMessageDescriptor foo__bar__baz_bah__descriptor; -~~~ -* -* The message structures all begin with `ProtobufCMessageDescriptor *` which is -* sufficient to allow them to be cast to `ProtobufCMessage`. -* -* For each message defined in a `.proto` file, we generate a number of -* functions and macros. Each function name contains a prefix based on the -* package name and message name in order to make it a unique C identifier. -* -* - `INIT`. Statically initializes a message object, initializing its -* descriptor and setting its fields to default values. Uninitialized -* messages cannot be processed by the protobuf-c library. -* -~~~{.c} -#define FOO__BAR__BAZ_BAH__INIT \ -{ PROTOBUF_C_MESSAGE_INIT (&foo__bar__baz_bah__descriptor), 0 } -~~~ -* - `init()`. Initializes a message object, initializing its descriptor and -* setting its fields to default values. Uninitialized messages cannot be -* processed by the protobuf-c library. -* -~~~{.c} -void foo__bar__baz_bah__init -(Foo__Bar__BazBah *message); -~~~ -* - `unpack()`. Unpacks data for a particular message format. Note that the -* `allocator` parameter is usually `NULL` to indicate that the system's -* `malloc()` and `free()` functions should be used for dynamically allocating -* memory. -* -~~~{.c} -Foo__Bar__BazBah * -foo__bar__baz_bah__unpack -(ProtobufCAllocator *allocator, -size_t len, -const uint8_t *data); -~~~ -* -* - `free_unpacked()`. Frees a message object obtained with the `unpack()` -* method. Freeing `NULL` is allowed (the same as with `free()`). -* -~~~{.c} -void foo__bar__baz_bah__free_unpacked -(Foo__Bar__BazBah *message, -ProtobufCAllocator *allocator); -~~~ -* -* - `get_packed_size()`. Calculates the length in bytes of the serialized -* representation of the message object. -* -~~~{.c} -size_t foo__bar__baz_bah__get_packed_size -(const Foo__Bar__BazBah *message); -~~~ -* -* - `pack()`. Pack a message object into a preallocated buffer. Assumes that -* the buffer is large enough. (Use `get_packed_size()` first.) -* -~~~{.c} -size_t foo__bar__baz_bah__pack -(const Foo__Bar__BazBah *message, -uint8_t *out); -~~~ -* -* - `pack_to_buffer()`. Packs a message into a "virtual buffer". This is an -* object which defines an "append bytes" callback to consume data as it is -* serialized. -* -~~~{.c} -size_t foo__bar__baz_bah__pack_to_buffer -(const Foo__Bar__BazBah *message, -ProtobufCBuffer *buffer); -~~~ -* -* \page pack Packing and unpacking messages -* -* To pack a message, first compute the packed size of the message with -* protobuf_c_message_get_packed_size(), then allocate a buffer of at least -* that size, then call protobuf_c_message_pack(). -* -* Alternatively, a message can be serialized without calculating the final size -* first. Use the protobuf_c_message_pack_to_buffer() function and provide a -* ProtobufCBuffer object which implements an "append" method that consumes -* data. -* -* To unpack a message, call the protobuf_c_message_unpack() function. The -* result can be cast to an object of the type that matches the descriptor for -* the message. -* -* The result of unpacking a message should be freed with -* protobuf_c_message_free_unpacked(). -*/ - -#ifndef PROTOBUF_C_H -#define PROTOBUF_C_H - -#include -#include -#include -#include - -#ifdef __cplusplus -# define PROTOBUF_C__BEGIN_DECLS extern "C" { -# define PROTOBUF_C__END_DECLS } -#else -# define PROTOBUF_C__BEGIN_DECLS -# define PROTOBUF_C__END_DECLS -#endif - -#define PROTOBUF_C__API - -PROTOBUF_C__BEGIN_DECLS - -#if defined(_WIN32) && defined(PROTOBUF_C_USE_SHARED_LIB) -# ifdef PROTOBUF_C_EXPORT -# define PROTOBUF_C__API __declspec(dllexport) -# else -# define PROTOBUF_C__API __declspec(dllimport) -# endif -#else -# define PROTOBUF_C__API -#endif - -#if !defined(PROTOBUF_C__NO_DEPRECATED) && \ - ((__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) -# define PROTOBUF_C__DEPRECATED __attribute__((__deprecated__)) -#else -# define PROTOBUF_C__DEPRECATED -#endif - -#ifndef PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE -#define PROTOBUF_C__FORCE_ENUM_TO_BE_INT_SIZE(enum_name) \ -, _##enum_name##_IS_INT_SIZE = INT_MAX -#endif - -#define PROTOBUF_C__SERVICE_DESCRIPTOR_MAGIC 0x14159bc3 -#define PROTOBUF_C__MESSAGE_DESCRIPTOR_MAGIC 0x28aaeef9 -#define PROTOBUF_C__ENUM_DESCRIPTOR_MAGIC 0x114315af - -/* Empty string used for initializers */ -extern const char protobuf_c_empty_string[]; - -/** -* \defgroup api Public API -* -* This is the public API for `libprotobuf-c`. These interfaces are stable and -* subject to Semantic Versioning guarantees. -* -* @{ -*/ - -/** -* Values for the `flags` word in `ProtobufCFieldDescriptor`. -*/ -typedef enum { - /** Set if the field is repeated and marked with the `packed` option. */ - PROTOBUF_C_FIELD_FLAG_PACKED = (1 << 0), - - /** Set if the field is marked with the `deprecated` option. */ - PROTOBUF_C_FIELD_FLAG_DEPRECATED = (1 << 1), - - /** Set if the field is a member of a oneof (union). */ - PROTOBUF_C_FIELD_FLAG_ONEOF = (1 << 2), -} ProtobufCFieldFlag; - -/** -* Message field rules. -* -* \see [Defining A Message Type] in the Protocol Buffers documentation. -* -* [Defining A Message Type]: -* https://developers.google.com/protocol-buffers/docs/proto#simple -*/ -typedef enum { - /** A well-formed message must have exactly one of this field. */ - PROTOBUF_C_LABEL_REQUIRED, - - /** - * A well-formed message can have zero or one of this field (but not - * more than one). - */ - PROTOBUF_C_LABEL_OPTIONAL, - - /** - * This field can be repeated any number of times (including zero) in a - * well-formed message. The order of the repeated values will be - * preserved. - */ - PROTOBUF_C_LABEL_REPEATED, - - /** - * This field has no label. This is valid only in proto3 and is - * equivalent to OPTIONAL but no "has" quantifier will be consulted. - */ - PROTOBUF_C_LABEL_NONE, -} ProtobufCLabel; - -/** -* Field value types. -* -* \see [Scalar Value Types] in the Protocol Buffers documentation. -* -* [Scalar Value Types]: -* https://developers.google.com/protocol-buffers/docs/proto#scalar -*/ -typedef enum { - PROTOBUF_C_TYPE_INT32, /**< int32 */ - PROTOBUF_C_TYPE_SINT32, /**< signed int32 */ - PROTOBUF_C_TYPE_SFIXED32, /**< signed int32 (4 bytes) */ - PROTOBUF_C_TYPE_INT64, /**< int64 */ - PROTOBUF_C_TYPE_SINT64, /**< signed int64 */ - PROTOBUF_C_TYPE_SFIXED64, /**< signed int64 (8 bytes) */ - PROTOBUF_C_TYPE_UINT32, /**< unsigned int32 */ - PROTOBUF_C_TYPE_FIXED32, /**< unsigned int32 (4 bytes) */ - PROTOBUF_C_TYPE_UINT64, /**< unsigned int64 */ - PROTOBUF_C_TYPE_FIXED64, /**< unsigned int64 (8 bytes) */ - PROTOBUF_C_TYPE_FLOAT, /**< float */ - PROTOBUF_C_TYPE_DOUBLE, /**< double */ - PROTOBUF_C_TYPE_BOOL, /**< boolean */ - PROTOBUF_C_TYPE_ENUM, /**< enumerated type */ - PROTOBUF_C_TYPE_STRING, /**< UTF-8 or ASCII string */ - PROTOBUF_C_TYPE_BYTES, /**< arbitrary byte sequence */ - PROTOBUF_C_TYPE_MESSAGE, /**< nested message */ -} ProtobufCType; - -/** -* Field wire types. -* -* \see [Message Structure] in the Protocol Buffers documentation. -* -* [Message Structure]: -* https://developers.google.com/protocol-buffers/docs/encoding#structure -*/ -typedef enum { - PROTOBUF_C_WIRE_TYPE_VARINT = 0, - PROTOBUF_C_WIRE_TYPE_64BIT = 1, - PROTOBUF_C_WIRE_TYPE_LENGTH_PREFIXED = 2, - /* "Start group" and "end group" wire types are unsupported. */ - PROTOBUF_C_WIRE_TYPE_32BIT = 5, -} ProtobufCWireType; - -struct ProtobufCAllocator; -struct ProtobufCBinaryData; -struct ProtobufCBuffer; -struct ProtobufCBufferSimple; -struct ProtobufCEnumDescriptor; -struct ProtobufCEnumValue; -struct ProtobufCEnumValueIndex; -struct ProtobufCFieldDescriptor; -struct ProtobufCIntRange; -struct ProtobufCMessage; -struct ProtobufCMessageDescriptor; -struct ProtobufCMessageUnknownField; -struct ProtobufCMethodDescriptor; -struct ProtobufCService; -struct ProtobufCServiceDescriptor; - -typedef struct ProtobufCAllocator ProtobufCAllocator; -typedef struct ProtobufCBinaryData ProtobufCBinaryData; -typedef struct ProtobufCBuffer ProtobufCBuffer; -typedef struct ProtobufCBufferSimple ProtobufCBufferSimple; -typedef struct ProtobufCEnumDescriptor ProtobufCEnumDescriptor; -typedef struct ProtobufCEnumValue ProtobufCEnumValue; -typedef struct ProtobufCEnumValueIndex ProtobufCEnumValueIndex; -typedef struct ProtobufCFieldDescriptor ProtobufCFieldDescriptor; -typedef struct ProtobufCIntRange ProtobufCIntRange; -typedef struct ProtobufCMessage ProtobufCMessage; -typedef struct ProtobufCMessageDescriptor ProtobufCMessageDescriptor; -typedef struct ProtobufCMessageUnknownField ProtobufCMessageUnknownField; -typedef struct ProtobufCMethodDescriptor ProtobufCMethodDescriptor; -typedef struct ProtobufCService ProtobufCService; -typedef struct ProtobufCServiceDescriptor ProtobufCServiceDescriptor; - -/** Boolean type. */ -typedef int protobuf_c_boolean; - -typedef void (*ProtobufCClosure)(const ProtobufCMessage *, void *closure_data); -typedef void (*ProtobufCMessageInit)(ProtobufCMessage *); -typedef void (*ProtobufCServiceDestroy)(ProtobufCService *); - -/** -* Structure for defining a custom memory allocator. -*/ -struct ProtobufCAllocator { - /** Function to allocate memory. */ - void *(*alloc)(void *allocator_data, size_t size); - - /** Function to free memory. */ - void (*free)(void *allocator_data, void *pointer); - - /** Opaque pointer passed to `alloc` and `free` functions. */ - void *allocator_data; -}; - -/** -* Structure for the protobuf `bytes` scalar type. -* -* The data contained in a `ProtobufCBinaryData` is an arbitrary sequence of -* bytes. It may contain embedded `NUL` characters and is not required to be -* `NUL`-terminated. -*/ -struct ProtobufCBinaryData { - size_t len; /**< Number of bytes in the `data` field. */ - uint8_t *data; /**< Data bytes. */ -}; - -/** -* Structure for defining a virtual append-only buffer. Used by -* protobuf_c_message_pack_to_buffer() to abstract the consumption of serialized -* bytes. -* -* `ProtobufCBuffer` "subclasses" may be defined on the stack. For example, to -* write to a `FILE` object: -* -~~~{.c} -typedef struct { -ProtobufCBuffer base; -FILE *fp; -} BufferAppendToFile; - -static void -my_buffer_file_append(ProtobufCBuffer *buffer, -size_t len, -const uint8_t *data) -{ -BufferAppendToFile *file_buf = (BufferAppendToFile *) buffer; -fwrite(data, len, 1, file_buf->fp); // XXX: No error handling! -} -~~~ -* -* To use this new type of ProtobufCBuffer, it could be called as follows: -* -~~~{.c} -... -BufferAppendToFile tmp = {0}; -tmp.base.append = my_buffer_file_append; -tmp.fp = fp; -protobuf_c_message_pack_to_buffer(&message, &tmp); -... -~~~ -*/ -struct ProtobufCBuffer { - /** Append function. Consumes the `len` bytes stored at `data`. */ - void (*append)(ProtobufCBuffer *buffer, - size_t len, - const uint8_t *data); -}; - -/** -* Simple buffer "subclass" of `ProtobufCBuffer`. -* -* A `ProtobufCBufferSimple` object is declared on the stack and uses a -* scratch buffer provided by the user for the initial allocation. It performs -* exponential resizing, using dynamically allocated memory. A -* `ProtobufCBufferSimple` object can be created and used as follows: -* -~~~{.c} -uint8_t pad[128]; -ProtobufCBufferSimple simple = PROTOBUF_C_BUFFER_SIMPLE_INIT(pad); -ProtobufCBuffer *buffer = (ProtobufCBuffer *) &simple; -~~~ -* -* `buffer` can now be used with `protobuf_c_message_pack_to_buffer()`. Once a -* message has been serialized to a `ProtobufCBufferSimple` object, the -* serialized data bytes can be accessed from the `.data` field. -* -* To free the memory allocated by a `ProtobufCBufferSimple` object, if any, -* call PROTOBUF_C_BUFFER_SIMPLE_CLEAR() on the object, for example: -* -~~~{.c} -PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&simple); -~~~ -* -* \see PROTOBUF_C_BUFFER_SIMPLE_INIT -* \see PROTOBUF_C_BUFFER_SIMPLE_CLEAR -*/ -struct ProtobufCBufferSimple { - /** "Base class". */ - ProtobufCBuffer base; - /** Number of bytes allocated in `data`. */ - size_t alloced; - /** Number of bytes currently stored in `data`. */ - size_t len; - /** Data bytes. */ - uint8_t *data; - /** Whether `data` must be freed. */ - protobuf_c_boolean must_free_data; - /** Allocator to use. May be NULL to indicate the system allocator. */ - ProtobufCAllocator *allocator; -}; - -/** -* Describes an enumeration as a whole, with all of its values. -*/ -struct ProtobufCEnumDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** The qualified name (e.g., "namespace.Type"). */ - const char *name; - /** The unqualified name as given in the .proto file (e.g., "Type"). */ - const char *short_name; - /** Identifier used in generated C code. */ - const char *c_name; - /** The dot-separated namespace. */ - const char *package_name; - - /** Number elements in `values`. */ - unsigned n_values; - /** Array of distinct values, sorted by numeric value. */ - const ProtobufCEnumValue *values; - - /** Number of elements in `values_by_name`. */ - unsigned n_value_names; - /** Array of named values, including aliases, sorted by name. */ - const ProtobufCEnumValueIndex *values_by_name; - - /** Number of elements in `value_ranges`. */ - unsigned n_value_ranges; - /** Value ranges, for faster lookups by numeric value. */ - const ProtobufCIntRange *value_ranges; - - /** Reserved for future use. */ - void *reserved1; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; - /** Reserved for future use. */ - void *reserved4; -}; - -/** -* Represents a single value of an enumeration. -*/ -struct ProtobufCEnumValue { - /** The string identifying this value in the .proto file. */ - const char *name; - - /** The string identifying this value in generated C code. */ - const char *c_name; - - /** The numeric value assigned in the .proto file. */ - int value; -}; - -/** -* Used by `ProtobufCEnumDescriptor` to look up enum values. -*/ -struct ProtobufCEnumValueIndex { - /** Name of the enum value. */ - const char *name; - /** Index into values[] array. */ - unsigned index; -}; - -/** -* Describes a single field in a message. -*/ -struct ProtobufCFieldDescriptor { - /** Name of the field as given in the .proto file. */ - const char *name; - - /** Tag value of the field as given in the .proto file. */ - uint32_t id; - - /** Whether the field is `REQUIRED`, `OPTIONAL`, or `REPEATED`. */ - ProtobufCLabel label; - - /** The type of the field. */ - ProtobufCType type; - - /** - * The offset in bytes of the message's C structure's quantifier field - * (the `has_MEMBER` field for optional members or the `n_MEMBER` field - * for repeated members or the case enum for oneofs). - */ - unsigned quantifier_offset; - - /** - * The offset in bytes into the message's C structure for the member - * itself. - */ - unsigned offset; - - /** - * A type-specific descriptor. - * - * If `type` is `PROTOBUF_C_TYPE_ENUM`, then `descriptor` points to the - * corresponding `ProtobufCEnumDescriptor`. - * - * If `type` is `PROTOBUF_C_TYPE_MESSAGE`, then `descriptor` points to - * the corresponding `ProtobufCMessageDescriptor`. - * - * Otherwise this field is NULL. - */ - const void *descriptor; /* for MESSAGE and ENUM types */ - - /** The default value for this field, if defined. May be NULL. */ - const void *default_value; - - /** - * A flag word. Zero or more of the bits defined in the - * `ProtobufCFieldFlag` enum may be set. - */ - uint32_t flags; - - /** Reserved for future use. */ - unsigned reserved_flags; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; -}; - -/** -* Helper structure for optimizing int => index lookups in the case -* where the keys are mostly consecutive values, as they presumably are for -* enums and fields. -* -* The data structures requires that the values in the original array are -* sorted. -*/ -struct ProtobufCIntRange { - int start_value; - unsigned orig_index; - /* - * NOTE: the number of values in the range can be inferred by looking - * at the next element's orig_index. A dummy element is added to make - * this simple. - */ -}; - -/** -* An instance of a message. -* -* `ProtobufCMessage` is a light-weight "base class" for all messages. -* -* In particular, `ProtobufCMessage` doesn't have any allocation policy -* associated with it. That's because it's common to create `ProtobufCMessage` -* objects on the stack. In fact, that's what we recommend for sending messages. -* If the object is allocated from the stack, you can't really have a memory -* leak. -* -* This means that calls to functions like protobuf_c_message_unpack() which -* return a `ProtobufCMessage` must be paired with a call to a free function, -* like protobuf_c_message_free_unpacked(). -*/ -struct ProtobufCMessage { - /** The descriptor for this message type. */ - const ProtobufCMessageDescriptor *descriptor; - /** The number of elements in `unknown_fields`. */ - unsigned n_unknown_fields; - /** The fields that weren't recognized by the parser. */ - ProtobufCMessageUnknownField *unknown_fields; -}; - -/** -* Describes a message. -*/ -struct ProtobufCMessageDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** The qualified name (e.g., "namespace.Type"). */ - const char *name; - /** The unqualified name as given in the .proto file (e.g., "Type"). */ - const char *short_name; - /** Identifier used in generated C code. */ - const char *c_name; - /** The dot-separated namespace. */ - const char *package_name; - - /** - * Size in bytes of the C structure representing an instance of this - * type of message. - */ - size_t sizeof_message; - - /** Number of elements in `fields`. */ - unsigned n_fields; - /** Field descriptors, sorted by tag number. */ - const ProtobufCFieldDescriptor *fields; - /** Used for looking up fields by name. */ - const unsigned *fields_sorted_by_name; - - /** Number of elements in `field_ranges`. */ - unsigned n_field_ranges; - /** Used for looking up fields by id. */ - const ProtobufCIntRange *field_ranges; - - /** Message initialisation function. */ - ProtobufCMessageInit message_init; - - /** Reserved for future use. */ - void *reserved1; - /** Reserved for future use. */ - void *reserved2; - /** Reserved for future use. */ - void *reserved3; -}; - -/** -* An unknown message field. -*/ -struct ProtobufCMessageUnknownField { - /** The tag number. */ - uint32_t tag; - /** The wire type of the field. */ - ProtobufCWireType wire_type; - /** Number of bytes in `data`. */ - size_t len; - /** Field data. */ - uint8_t *data; -}; - -/** -* Method descriptor. -*/ -struct ProtobufCMethodDescriptor { - /** Method name. */ - const char *name; - /** Input message descriptor. */ - const ProtobufCMessageDescriptor *input; - /** Output message descriptor. */ - const ProtobufCMessageDescriptor *output; -}; - -/** -* Service. -*/ -struct ProtobufCService { - /** Service descriptor. */ - const ProtobufCServiceDescriptor *descriptor; - /** Function to invoke the service. */ - void (*invoke)(ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); - /** Function to destroy the service. */ - void (*destroy)(ProtobufCService *service); -}; - -/** -* Service descriptor. -*/ -struct ProtobufCServiceDescriptor { - /** Magic value checked to ensure that the API is used correctly. */ - uint32_t magic; - - /** Service name. */ - const char *name; - /** Short version of service name. */ - const char *short_name; - /** C identifier for the service name. */ - const char *c_name; - /** Package name. */ - const char *package; - /** Number of elements in `methods`. */ - unsigned n_methods; - /** Method descriptors, in the order defined in the .proto file. */ - const ProtobufCMethodDescriptor *methods; - /** Sort index of methods. */ - const unsigned *method_indices_by_name; -}; - -/** -* Get the version of the protobuf-c library. Note that this is the version of -* the library linked against, not the version of the headers compiled against. -* -* \return A string containing the version number of protobuf-c. -*/ -PROTOBUF_C__API -const char * -protobuf_c_version(void); - -/** -* Get the version of the protobuf-c library. Note that this is the version of -* the library linked against, not the version of the headers compiled against. -* -* \return A 32 bit unsigned integer containing the version number of -* protobuf-c, represented in base-10 as (MAJOR*1E6) + (MINOR*1E3) + PATCH. -*/ -PROTOBUF_C__API -uint32_t -protobuf_c_version_number(void); - -/** -* The version of the protobuf-c headers, represented as a string using the same -* format as protobuf_c_version(). -*/ -#define PROTOBUF_C_VERSION "1.3.1" - -/** -* The version of the protobuf-c headers, represented as an integer using the -* same format as protobuf_c_version_number(). -*/ -#define PROTOBUF_C_VERSION_NUMBER 1003001 - -/** -* The minimum protoc-c version which works with the current version of the -* protobuf-c headers. -*/ -#define PROTOBUF_C_MIN_COMPILER_VERSION 1000000 - -/** -* Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by name. -* -* \param desc -* The `ProtobufCEnumDescriptor` object. -* \param name -* The `name` field from the corresponding `ProtobufCEnumValue` object to -* match. -* \return -* A `ProtobufCEnumValue` object. -* \retval NULL -* If not found or if the optimize_for = CODE_SIZE option was set. -*/ -PROTOBUF_C__API -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value_by_name( - const ProtobufCEnumDescriptor *desc, - const char *name); - -/** -* Look up a `ProtobufCEnumValue` from a `ProtobufCEnumDescriptor` by numeric -* value. -* -* \param desc -* The `ProtobufCEnumDescriptor` object. -* \param value -* The `value` field from the corresponding `ProtobufCEnumValue` object to -* match. -* -* \return -* A `ProtobufCEnumValue` object. -* \retval NULL -* If not found. -*/ -PROTOBUF_C__API -const ProtobufCEnumValue * -protobuf_c_enum_descriptor_get_value( - const ProtobufCEnumDescriptor *desc, - int value); - -/** -* Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by -* the name of the field. -* -* \param desc -* The `ProtobufCMessageDescriptor` object. -* \param name -* The name of the field. -* \return -* A `ProtobufCFieldDescriptor` object. -* \retval NULL -* If not found or if the optimize_for = CODE_SIZE option was set. -*/ -PROTOBUF_C__API -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field_by_name( - const ProtobufCMessageDescriptor *desc, - const char *name); - -/** -* Look up a `ProtobufCFieldDescriptor` from a `ProtobufCMessageDescriptor` by -* the tag value of the field. -* -* \param desc -* The `ProtobufCMessageDescriptor` object. -* \param value -* The tag value of the field. -* \return -* A `ProtobufCFieldDescriptor` object. -* \retval NULL -* If not found. -*/ -PROTOBUF_C__API -const ProtobufCFieldDescriptor * -protobuf_c_message_descriptor_get_field( - const ProtobufCMessageDescriptor *desc, - unsigned value); - -/** -* Determine the number of bytes required to store the serialised message. -* -* \param message -* The message object to serialise. -* \return -* Number of bytes. -*/ -PROTOBUF_C__API -size_t -protobuf_c_message_get_packed_size(const ProtobufCMessage *message); - -/** -* Serialise a message from its in-memory representation. -* -* This function stores the serialised bytes of the message in a pre-allocated -* buffer. -* -* \param message -* The message object to serialise. -* \param[out] out -* Buffer to store the bytes of the serialised message. This buffer must -* have enough space to store the packed message. Use -* protobuf_c_message_get_packed_size() to determine the number of bytes -* required. -* \return -* Number of bytes stored in `out`. -*/ -PROTOBUF_C__API -size_t -protobuf_c_message_pack(const ProtobufCMessage *message, uint8_t *out); - -/** -* Serialise a message from its in-memory representation to a virtual buffer. -* -* This function calls the `append` method of a `ProtobufCBuffer` object to -* consume the bytes generated by the serialiser. -* -* \param message -* The message object to serialise. -* \param buffer -* The virtual buffer object. -* \return -* Number of bytes passed to the virtual buffer. -*/ -PROTOBUF_C__API -size_t -protobuf_c_message_pack_to_buffer( - const ProtobufCMessage *message, - ProtobufCBuffer *buffer); - -/** -* Unpack a serialised message into an in-memory representation. -* -* \param descriptor -* The message descriptor. -* \param allocator -* `ProtobufCAllocator` to use for memory allocation. May be NULL to -* specify the default allocator. -* \param len -* Length in bytes of the serialised message. -* \param data -* Pointer to the serialised message. -* \return -* An unpacked message object. -* \retval NULL -* If an error occurred during unpacking. -*/ -PROTOBUF_C__API -ProtobufCMessage * -protobuf_c_message_unpack( - const ProtobufCMessageDescriptor *descriptor, - ProtobufCAllocator *allocator, - size_t len, - const uint8_t *data); - -/** -* Free an unpacked message object. -* -* This function should be used to deallocate the memory used by a call to -* protobuf_c_message_unpack(). -* -* \param message -* The message object to free. May be NULL. -* \param allocator -* `ProtobufCAllocator` to use for memory deallocation. May be NULL to -* specify the default allocator. -*/ -PROTOBUF_C__API -void -protobuf_c_message_free_unpacked( - ProtobufCMessage *message, - ProtobufCAllocator *allocator); - -/** -* Check the validity of a message object. -* -* Makes sure all required fields (`PROTOBUF_C_LABEL_REQUIRED`) are present. -* Recursively checks nested messages. -* -* \retval TRUE -* Message is valid. -* \retval FALSE -* Message is invalid. -*/ -PROTOBUF_C__API -protobuf_c_boolean -protobuf_c_message_check(const ProtobufCMessage *); - -/** Message initialiser. */ -#define PROTOBUF_C_MESSAGE_INIT(descriptor) { descriptor, 0, NULL } - -/** -* Initialise a message object from a message descriptor. -* -* \param descriptor -* Message descriptor. -* \param message -* Allocated block of memory of size `descriptor->sizeof_message`. -*/ -PROTOBUF_C__API -void -protobuf_c_message_init( - const ProtobufCMessageDescriptor *descriptor, - void *message); - -/** -* Free a service. -* -* \param service -* The service object to free. -*/ -PROTOBUF_C__API -void -protobuf_c_service_destroy(ProtobufCService *service); - -/** -* Look up a `ProtobufCMethodDescriptor` by name. -* -* \param desc -* Service descriptor. -* \param name -* Name of the method. -* -* \return -* A `ProtobufCMethodDescriptor` object. -* \retval NULL -* If not found or if the optimize_for = CODE_SIZE option was set. -*/ -PROTOBUF_C__API -const ProtobufCMethodDescriptor * -protobuf_c_service_descriptor_get_method_by_name( - const ProtobufCServiceDescriptor *desc, - const char *name); - -/** -* Initialise a `ProtobufCBufferSimple` object. -*/ -#define PROTOBUF_C_BUFFER_SIMPLE_INIT(array_of_bytes) \ -{ \ - { protobuf_c_buffer_simple_append }, \ - sizeof(array_of_bytes), \ - 0, \ - (array_of_bytes), \ - 0, \ - NULL \ -} - -/** -* Clear a `ProtobufCBufferSimple` object, freeing any allocated memory. -*/ -#define PROTOBUF_C_BUFFER_SIMPLE_CLEAR(simp_buf) \ -do { \ - if ((simp_buf)->must_free_data) { \ - if ((simp_buf)->allocator != NULL) \ - (simp_buf)->allocator->free( \ - (simp_buf)->allocator, \ - (simp_buf)->data); \ - else \ - free((simp_buf)->data); \ - } \ -} while (0) - -/** -* The `append` method for `ProtobufCBufferSimple`. -* -* \param buffer -* The buffer object to append to. Must actually be a -* `ProtobufCBufferSimple` object. -* \param len -* Number of bytes in `data`. -* \param data -* Data to append. -*/ -PROTOBUF_C__API -void -protobuf_c_buffer_simple_append( - ProtobufCBuffer *buffer, - size_t len, - const unsigned char *data); - -PROTOBUF_C__API -void -protobuf_c_service_generated_init( - ProtobufCService *service, - const ProtobufCServiceDescriptor *descriptor, - ProtobufCServiceDestroy destroy); - -PROTOBUF_C__API -void -protobuf_c_service_invoke_internal( - ProtobufCService *service, - unsigned method_index, - const ProtobufCMessage *input, - ProtobufCClosure closure, - void *closure_data); - -/**@}*/ - -PROTOBUF_C__END_DECLS - -#endif /* PROTOBUF_C_H */ diff --git a/windows/ccextractor.vcxproj b/windows/ccextractor.vcxproj index 225bf11ec..5d6824172 100644 --- a/windows/ccextractor.vcxproj +++ b/windows/ccextractor.vcxproj @@ -40,7 +40,6 @@ - @@ -134,7 +133,6 @@ - @@ -243,7 +241,7 @@ Disabled - ..\src\thirdparty\freetype\include;..\src;..\src\thirdparty\win_spec_incld;..\src\lib_ccx;..\src\thirdparty\lib_hash;..\src\lib_ccx\zvbi;..\src\thirdparty\protobuf-c;..\src\thirdparty\win_iconv;..\src\thirdparty\;..\src;$(VCPKG_ROOT)\installed\$(VCPKG_DEFAULT_TRIPLET)\include; + ..\src\thirdparty\freetype\include;..\src;..\src\thirdparty\win_spec_incld;..\src\lib_ccx;..\src\thirdparty\lib_hash;..\src\lib_ccx\zvbi;..\src\thirdparty\win_iconv;..\src\thirdparty\;..\src;$(VCPKG_ROOT)\installed\$(VCPKG_DEFAULT_TRIPLET)\include; "C:\Program Files\GPAC\sdk\include";%(AdditionalIncludeDirectories) SEGMENT_BY_FILE_TIME;ENABLE_HARDSUBX;FT2_BUILD_LIBRARY;GPAC_DISABLE_VTT;GPAC_DISABLE_OD_DUMP;ENABLE_OCR;WIN32;_DEBUG;_CONSOLE;_FILE_OFFSET_BITS=64;GPAC_DISABLE_REMOTERY;GPAC_DISABLE_ZLIB;%(PreprocessorDefinitions) @@ -290,7 +288,7 @@ Disabled - ..\src\thirdparty\freetype\include;..\src;..\src\thirdparty\win_spec_incld;..\src\lib_ccx;..\src\thirdparty\lib_hash;..\src\lib_ccx\zvbi;..\src\thirdparty\protobuf-c;..\src\thirdparty\win_iconv;..\src\thirdparty\;..\src;$(VCPKG_ROOT)\installed\$(VCPKG_DEFAULT_TRIPLET)\include; + ..\src\thirdparty\freetype\include;..\src;..\src\thirdparty\win_spec_incld;..\src\lib_ccx;..\src\thirdparty\lib_hash;..\src\lib_ccx\zvbi;..\src\thirdparty\win_iconv;..\src\thirdparty\;..\src;$(VCPKG_ROOT)\installed\$(VCPKG_DEFAULT_TRIPLET)\include; "C:\Program Files\GPAC\sdk\include";%(AdditionalIncludeDirectories) ENABLE_HARDSUBX;FT2_BUILD_LIBRARY;GPAC_DISABLE_VTT;GPAC_DISABLE_OD_DUMP;VERSION_FILE_PRESENT;ENABLE_OCR;WIN32;NDEBUG;_CONSOLE;_FILE_OFFSET_BITS=64;GPAC_DISABLE_REMOTERY;GPAC_DISABLE_ZLIB;%(PreprocessorDefinitions) diff --git a/windows/ccextractor.vcxproj.filters b/windows/ccextractor.vcxproj.filters index 6490853fe..bff144de0 100644 --- a/windows/ccextractor.vcxproj.filters +++ b/windows/ccextractor.vcxproj.filters @@ -70,12 +70,6 @@ {7ef5506d-d575-4661-84a1-dbbb99780e32} - - {3c0bdb0a-e3f8-4fc4-a27b-b795ed32c965} - - - {fce551b0-7304-4677-8e66-61b475fdb924} - {6e23dd8b-166b-4a80-92e2-194e7b6e6c86} @@ -180,9 +174,6 @@ Header Files - - Header Files - Header Files @@ -473,9 +464,6 @@ Source Files - - Source Files - Source Files From 25eb7071f3ffd469c169fd0c95d03087dfd83ffa Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 24 Aug 2025 20:58:56 +0530 Subject: [PATCH 09/13] Share Module: Update CHANGES.txt --- .github/workflows/build_linux.yml | 2 +- .github/workflows/build_mac.yml | 2 +- docs/CHANGES.TXT | 2 +- linux/Makefile.am | 2 +- mac/Makefile.am | 2 +- src/rust/Cargo.lock | 37 ------------------------------- src/rust/lib_ccxr/Cargo.toml | 4 +--- 7 files changed, 6 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 153ca43d4..cd3349ecb 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -46,7 +46,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Install dependencies - run: sudo apt update && sudo apt-get install libgpac-dev libnanomsg-dev + run: sudo apt update && sudo apt-get install libgpac-dev - uses: actions/checkout@v4 - name: run autogen run: ./autogen.sh diff --git a/.github/workflows/build_mac.yml b/.github/workflows/build_mac.yml index 7dfebd82a..c81af5327 100644 --- a/.github/workflows/build_mac.yml +++ b/.github/workflows/build_mac.yml @@ -47,7 +47,7 @@ jobs: steps: - uses: actions/checkout@v4 - name: Install dependencies - run: brew install pkg-config autoconf automake libtool gpac nanomsg + run: brew install pkg-config autoconf automake libtool gpac - name: run autogen run: ./autogen.sh working-directory: ./mac diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index 66a378aef..f02ce7188 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,5 +1,6 @@ 1.0 (to be released) ----------------- +- Removed Share Module to lib_ccxr - Refactor: Remove API structures from ccextractor - New: Add Encoder Module to Rust - Fix: Elementary stream regressions @@ -1298,4 +1299,3 @@ version of CCExtractor. - Added video information (as extracted from sequence header). - Some code clean-up. - FF sanity check enabled by default. -- Added Share Module to lib_ccxr \ No newline at end of file diff --git a/linux/Makefile.am b/linux/Makefile.am index 4151f94de..0b45a5d99 100644 --- a/linux/Makefile.am +++ b/linux/Makefile.am @@ -328,7 +328,7 @@ ccextractor_LDADD += $(LEPT_LIB) endif if WITH_RUST -ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a -lnanomsg +ccextractor_LDADD += ./rust/@RUST_TARGET_SUBDIR@/libccx_rust.a else ccextractor_CFLAGS += -DDISABLE_RUST ccextractor_CPPFLAGS += -DDISABLE_RUST diff --git a/mac/Makefile.am b/mac/Makefile.am index cdd0595c6..478d9c706 100644 --- a/mac/Makefile.am +++ b/mac/Makefile.am @@ -238,7 +238,7 @@ endif ccextractor_CFLAGS = -std=gnu99 -Wno-write-strings -Wno-pointer-sign -D_FILE_OFFSET_BITS=64 -DVERSION_FILE_PRESENT -DFT2_BUILD_LIBRARY -DGPAC_DISABLE_VTT -DGPAC_DISABLE_OD_DUMP -DGPAC_DISABLE_REMOTERY -DNO_GZIP -ccextractor_LDFLAGS = $(shell pkg-config --libs gpac nanomsg) +ccextractor_LDFLAGS = $(shell pkg-config --libs gpac) GPAC_CPPFLAGS = $(shell pkg-config --cflags gpac) ccextractor_CPPFLAGS =-I../src/lib_ccx/ -I../src/thirdparty/libpng/ -I../src/thirdparty/zlib/ -I../src/lib_ccx/zvbi/ -I../src/thirdparty/lib_hash/ -I../src/thirdparty -I../src/ -I../src/thirdparty/freetype/include/ diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index c577a04d3..b513e6d13 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -61,12 +61,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - [[package]] name = "approx" version = "0.5.1" @@ -150,12 +144,6 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - [[package]] name = "camino" version = "1.1.9" @@ -616,9 +604,7 @@ dependencies = [ "bitflags 2.9.0", "crc32fast", "derive_more", - "lazy_static", "num_enum", - "prost", "strum 0.26.3", "strum_macros 0.26.4", "thiserror", @@ -858,29 +844,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn 2.0.99", -] - [[package]] name = "quote" version = "1.0.39" diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index 0fd69c8a0..44ccb8054 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -15,9 +15,7 @@ strum = "0.26.3" strum_macros = "0.26.4" crc32fast = "1.4.2" num_enum = "0.6.1" -prost = "0.13.5" -lazy_static = "1.5.0" -nanomsg-sys = { version = "0.7.2", optional = true, default-features = false, features = ["bundled"] } + [features] default = [ "wtv_debug", From aa7a6db9b3c31b01009ff08b6ad1d48ee532d012 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 24 Aug 2025 21:36:01 +0530 Subject: [PATCH 10/13] Share Module: Update Cargo.lock --- src/rust/lib_ccxr/Cargo.lock | 113 ----------------------------------- 1 file changed, 113 deletions(-) diff --git a/src/rust/lib_ccxr/Cargo.lock b/src/rust/lib_ccxr/Cargo.lock index fa7a432fa..8ec94ecf1 100644 --- a/src/rust/lib_ccxr/Cargo.lock +++ b/src/rust/lib_ccxr/Cargo.lock @@ -2,48 +2,18 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - [[package]] name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "cc" -version = "1.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" -dependencies = [ - "shlex", -] - [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - [[package]] name = "convert_case" version = "0.4.0" @@ -92,12 +62,6 @@ dependencies = [ "syn", ] -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "equivalent" version = "1.0.2" @@ -113,12 +77,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - [[package]] name = "hashbrown" version = "0.15.2" @@ -280,27 +238,12 @@ dependencies = [ "hashbrown", ] -[[package]] -name = "itertools" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - [[package]] name = "lib_ccxr" version = "0.1.0" @@ -308,10 +251,7 @@ dependencies = [ "bitflags", "crc32fast", "derive_more", - "lazy_static", - "nanomsg-sys", "num_enum", - "prost", "strum", "strum_macros", "thiserror", @@ -319,12 +259,6 @@ dependencies = [ "url", ] -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - [[package]] name = "litemap" version = "0.7.5" @@ -337,18 +271,6 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "nanomsg-sys" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78aa3ccb6d007dfecb4f7070725c4b1670a87677babb6621cb0c8cce9cfdc004" -dependencies = [ - "cmake", - "gcc", - "libc", - "pkg-config", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -388,12 +310,6 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - [[package]] name = "powerfmt" version = "0.2.0" @@ -419,29 +335,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "prost" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" -dependencies = [ - "anyhow", - "itertools", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "quote" version = "1.0.39" @@ -492,12 +385,6 @@ dependencies = [ "syn", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - [[package]] name = "smallvec" version = "1.14.0" From 310f06ce3a26e0ec0eb3331a78afd2951b39459b Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 24 Aug 2025 21:44:43 +0530 Subject: [PATCH 11/13] Share Module: Update CHANGES.txt --- docs/CHANGES.TXT | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CHANGES.TXT b/docs/CHANGES.TXT index a3510e11b..405255026 100644 --- a/docs/CHANGES.TXT +++ b/docs/CHANGES.TXT @@ -1,6 +1,6 @@ 1.0 (to be released) ----------------- -- Removed Share Module to lib_ccxr +- Removed the Share Module - Fix: Regression failures on DVD files - Fix: Segmentation faults on MP4 files with CEA-708 captions - Refactor: Remove API structures from ccextractor From 93aa48f38b99d92c3e2fb850da30ac78dc653345 Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 24 Aug 2025 21:49:30 +0530 Subject: [PATCH 12/13] Share Module: Update Cargo.toml --- src/rust/Cargo.lock | 1 - src/rust/Cargo.toml | 1 - src/rust/lib_ccxr/Cargo.toml | 8 ++++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index b513e6d13..c864a6c04 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -161,7 +161,6 @@ dependencies = [ "env_logger", "leptonica-sys", "lib_ccxr", - "libc", "log", "num-integer", "palette", diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index a26467faf..f703e13f8 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -28,7 +28,6 @@ num-integer = "0.1.46" lib_ccxr = { path = "lib_ccxr" } url = "2.5.4" encoding_rs = "0.8.5" -libc = "0.2.172" [build-dependencies] diff --git a/src/rust/lib_ccxr/Cargo.toml b/src/rust/lib_ccxr/Cargo.toml index 44ccb8054..7ec3fb4c9 100644 --- a/src/rust/lib_ccxr/Cargo.toml +++ b/src/rust/lib_ccxr/Cargo.toml @@ -18,10 +18,10 @@ num_enum = "0.6.1" [features] default = [ - "wtv_debug", - "enable_ffmpeg", - "debug", - "with_libcurl", + "wtv_debug", + "enable_ffmpeg", + "debug", + "with_libcurl", ] wtv_debug = [] enable_ffmpeg = [] From 72aa5cec33dac3eda3fbc6a19aa2ddb3778cbfab Mon Sep 17 00:00:00 2001 From: Deepnarayan Sett Date: Sun, 24 Aug 2025 21:51:35 +0530 Subject: [PATCH 13/13] Share Module: Update Cargo.toml --- src/rust/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index f703e13f8..af2b53740 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -29,7 +29,6 @@ lib_ccxr = { path = "lib_ccxr" } url = "2.5.4" encoding_rs = "0.8.5" - [build-dependencies] bindgen = "0.64.0" pkg-config = "0.3.32"