1 /*
2 mkvmerge -- utility for splicing together matroska files
3 from component media subtypes
4
5 Distributed under the GPL v2
6 see the file COPYING for details
7 or visit https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
8
9 The "value_c" class
10
11 Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13
14 #include "common/common_pch.h"
15
16 #include "common/bitvalue.h"
17 #include "common/error.h"
18 #include "common/memory.h"
19 #include "common/random.h"
20 #include "common/strings/editing.h"
21
22 namespace mtx::bits {
23
24 namespace {
25
26 unsigned char
hex_digit_to_decimal(char c)27 hex_digit_to_decimal(char c) {
28 return isdigit(c) ? (c - '0') : (c - 'a' + 10);
29 }
30
31 }
32
value_c(int bitsize)33 value_c::value_c(int bitsize) {
34 assert((0 < bitsize) && (0 == (bitsize % 8)));
35
36 m_value = memory_c::alloc(bitsize / 8);
37 memset(m_value->get_buffer(), 0, m_value->get_size());
38 }
39
value_c(const value_c & src)40 value_c::value_c(const value_c &src) {
41 *this = src;
42 }
43
value_c(std::string s,unsigned int allowed_bitlength)44 value_c::value_c(std::string s,
45 unsigned int allowed_bitlength) {
46 if ((allowed_bitlength != 0) && ((allowed_bitlength % 8) != 0))
47 throw mtx::invalid_parameter_x();
48
49 unsigned int len = s.size();
50 balg::to_lower(s);
51 std::string s2;
52
53 unsigned int i;
54 for (i = 0; i < len; i++) {
55 // Space or tab?
56 if (mtx::string::is_blank_or_tab(s[i]))
57 continue;
58
59 // Skip hyphens and curly braces. Makes copy & paste a bit easier.
60 if ((s[i] == '-') || (s[i] == '{') || (s[i] == '}'))
61 continue;
62
63 // Space or tab followed by "0x"? Then skip it.
64 if (s.substr(i, 2) == "0x") {
65 i++;
66 continue;
67 }
68
69 // Invalid character?
70 auto is_hex_digit = isdigit(s[i]) || ((s[i] >= 'a') && (s[i] <= 'f'));
71 if (!is_hex_digit)
72 throw mtx::bits::value_parser_x{fmt::format(Y("Not a hex digit at position {0}"), i)};
73
74 // Input too long?
75 if ((allowed_bitlength > 0) && ((s2.length() * 4) >= allowed_bitlength))
76 throw mtx::bits::value_parser_x{fmt::format(Y("Input too long: {0} > {1}"), s2.length() * 4, allowed_bitlength)};
77
78 // Store the value.
79 s2 += s[i];
80 }
81
82 // Is half a byte or more missing?
83 len = s2.length();
84 if (((len % 2) != 0)
85 ||
86 ((allowed_bitlength != 0) && ((len * 4) < allowed_bitlength)))
87 throw mtx::bits::value_parser_x{Y("Missing one hex digit")};
88
89 m_value = memory_c::alloc(len / 2);
90
91 unsigned char *buffer = m_value->get_buffer();
92 for (i = 0; i < len; i += 2)
93 buffer[i / 2] = (hex_digit_to_decimal(s2[i]) << 4) | hex_digit_to_decimal(s2[i + 1]);
94 }
95
value_c(libebml::EbmlBinary const & elt)96 value_c::value_c(libebml::EbmlBinary const &elt)
97 : m_value(memory_c::clone(static_cast<const void *>(elt.GetBuffer()), elt.GetSize()))
98 {
99 }
100
101 value_c &
operator =(const value_c & src)102 value_c::operator =(const value_c &src) {
103 m_value = src.m_value->clone();
104
105 return *this;
106 }
107
108 bool
operator ==(const value_c & cmp) const109 value_c::operator ==(const value_c &cmp)
110 const {
111 return (cmp.m_value->get_size() == m_value->get_size()) && (0 == memcmp(m_value->get_buffer(), cmp.m_value->get_buffer(), m_value->get_size()));
112 }
113
114 unsigned char
operator [](size_t index) const115 value_c::operator [](size_t index)
116 const {
117 assert(m_value->get_size() > index);
118 return m_value->get_buffer()[index];
119 }
120
121 void
generate_random()122 value_c::generate_random() {
123 random_c::generate_bytes(m_value->get_buffer(), m_value->get_size());
124 }
125
126 void
zero_content()127 value_c::zero_content() {
128 std::memset(m_value->get_buffer(), 0, m_value->get_size());
129 }
130
131 }
132