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