Loading...
Searching...
No Matches
StringBytes.hpp
1#pragma once
2
3/* SPDX-License-Identifier: GPL-3.0-or-later */
4
5#include <ossia/network/value/value.hpp>
6
7#include <halp/callback.hpp>
8#include <halp/controls.hpp>
9#include <halp/meta.hpp>
10
11#include <bit>
12#include <cstddef>
13#include <string>
14#include <utility>
15#include <vector>
16
17namespace avnd_tools
18{
19// Byte limits bound both the string and the number of integer list elements.
20// Inlets retain ossia::value so host conversion cannot silently coerce floats,
21// booleans or strings into integer bytes. Errors never publish partial data;
22// successful messages clear Error before publishing the converted value.
24{
25 halp_meta(name, "String to Bytes")
26 halp_meta(c_name, "avnd_string_to_bytes")
27 halp_meta(category, "Control/Strings")
28 halp_meta(author, "ossia team")
29 halp_meta(uuid, "ab157b25-7233-46bb-a134-92547242bf09")
30 halp_meta(
31 description,
32 "Convert raw string bytes to integers from 0 to 255, preserving NUL and arbitrary "
33 "binary data without UTF-8 validation.")
34
35 struct ins
36 {
37 struct : halp::val_port<"String", ossia::value>
38 {
39 halp_meta(
40 description,
41 "Raw string bytes, not Unicode codepoints. Only string values are accepted.")
42 void update(StringToBytes& self) { self.process(); }
43 } input;
44 struct : halp::spinbox_i32<"Max bytes", halp::range{1, 1048576, 1048576}>
45 {
46 halp_meta(
47 description,
48 "Maximum input bytes and output integer count; hard ceiling 1048576. Changing "
49 "this control does not replay input.")
50 } max_bytes;
51 } inputs;
52 struct outs
53 {
54 struct : halp::callback<"Bytes", std::vector<int>>
55 {
56 halp_meta(description, "One integer from 0 to 255 for each raw input byte.")
57 } bytes;
58 halp::callback<"Error", std::string> error;
59 } outputs;
60
61 void process()
62 {
63 const auto fail = [this](const char* message) { outputs.error(message); };
64 if(inputs.max_bytes < 1 || inputs.max_bytes > 1048576)
65 return fail("Max bytes must be between 1 and 1048576");
66 const auto* text = inputs.input.value.target<std::string>();
67 if(!text)
68 return fail("Input must be a string");
69 if(text->size() > std::size_t(inputs.max_bytes.value))
70 return fail("Input exceeds byte limit");
71 std::vector<int> bytes;
72 bytes.reserve(text->size());
73 for(unsigned char byte : *text)
74 bytes.push_back(byte);
75 outputs.error(std::string{});
76 outputs.bytes(std::move(bytes));
77 }
78};
79
81{
82 halp_meta(name, "Bytes to String")
83 halp_meta(c_name, "avnd_bytes_to_string")
84 halp_meta(category, "Control/Strings")
85 halp_meta(author, "ossia team")
86 halp_meta(uuid, "f398ff8f-1836-4d49-80a4-d786c12d13c6")
87 halp_meta(
88 description,
89 "Convert an integer byte list to a raw string, preserving NUL and arbitrary "
90 "binary data. Rejects nonintegers and values outside 0 to 255; no UTF-8 "
91 "validation.")
92
93 struct ins
94 {
95 struct : halp::val_port<"Bytes", ossia::value>
96 {
97 halp_meta(
98 description,
99 "A list containing only integers from 0 to 255; floats, booleans, strings and "
100 "nested lists are errors.")
101 void update(BytesToString& self) { self.process(); }
102 } input;
103 struct : halp::spinbox_i32<"Max bytes", halp::range{1, 1048576, 1048576}>
104 {
105 halp_meta(
106 description,
107 "Maximum input integer count and output bytes; hard ceiling 1048576. Changing "
108 "this control does not replay input.")
109 } max_bytes;
110 } inputs;
111 struct outs
112 {
113 struct : halp::callback<"String", std::string>
114 {
115 halp_meta(
116 description, "Raw string bytes, including NUL and invalid UTF-8 sequences.")
117 } text;
118 halp::callback<"Error", std::string> error;
119 } outputs;
120
121 void process()
122 {
123 const auto fail = [this](const char* message) { outputs.error(message); };
124 if(inputs.max_bytes < 1 || inputs.max_bytes > 1048576)
125 return fail("Max bytes must be between 1 and 1048576");
126 const auto* bytes = inputs.input.value.target<std::vector<ossia::value>>();
127 if(!bytes)
128 return fail("Input must be a list of integer bytes");
129 if(bytes->size() > std::size_t(inputs.max_bytes.value))
130 return fail("Input exceeds byte limit");
131 // Validate before allocating the destination or publishing any bytes.
132 for(const auto& byte : *bytes)
133 {
134 const auto* integer = byte.target<int>();
135 if(!integer || *integer < 0 || *integer > 255)
136 return fail("Every byte must be an integer between 0 and 255");
137 }
138 std::string text(bytes->size(), '\0');
139 for(std::size_t i = 0; i < bytes->size(); ++i)
140 text[i] = std::bit_cast<char>(static_cast<unsigned char>((*bytes)[i].get<int>()));
141 outputs.error(std::string{});
142 outputs.text(std::move(text));
143 }
144};
145}
Definition StringBytes.hpp:94
Definition StringBytes.hpp:112
Definition StringBytes.hpp:81
Definition StringBytes.hpp:36
Definition StringBytes.hpp:53
Definition StringBytes.hpp:24