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    FourCC handling
10 
11    Written by Moritz Bunkus <moritz@bunkus.org>.
12 */
13 
14 #include "common/common_pch.h"
15 
16 #include "common/bswap.h"
17 #include "common/codec.h"
18 #include "common/endian.h"
19 #include "common/fourcc.h"
20 
21 namespace {
22 
23 uint32_t
val(uint32_t value,fourcc_c::byte_order_e byte_order)24 val(uint32_t value,
25     fourcc_c::byte_order_e byte_order) {
26   return fourcc_c::byte_order_e::big_endian == byte_order ? value : mtx::bytes::swap_32(value);
27 }
28 
29 char
printable_char(unsigned char c)30 printable_char(unsigned char c) {
31   return (32 <= c) && (127 > c) ? static_cast<char>(c) : '?';
32 }
33 
34 } // anonymous namespace
35 
fourcc_c()36 fourcc_c::fourcc_c()
37   : m_value{}
38 {
39 }
40 
fourcc_c(uint32_t value,fourcc_c::byte_order_e byte_order)41 fourcc_c::fourcc_c(uint32_t value,
42                    fourcc_c::byte_order_e byte_order)
43   : m_value{val(value, byte_order)}
44 {
45 }
46 
fourcc_c(std::string const & value)47 fourcc_c::fourcc_c(std::string const &value)
48   : m_value{read(value.c_str(), byte_order_e::big_endian)}
49 {
50 }
51 
fourcc_c(char const * value)52 fourcc_c::fourcc_c(char const *value)
53   : m_value{read(value, byte_order_e::big_endian)}
54 {
55 }
56 
fourcc_c(memory_cptr const & mem,fourcc_c::byte_order_e byte_order)57 fourcc_c::fourcc_c(memory_cptr const &mem,
58                    fourcc_c::byte_order_e byte_order)
59   : m_value{read(mem->get_buffer(), byte_order)}
60 {
61 }
62 
fourcc_c(unsigned char const * mem,fourcc_c::byte_order_e byte_order)63 fourcc_c::fourcc_c(unsigned char const *mem,
64                    fourcc_c::byte_order_e byte_order)
65   : m_value{read(mem, byte_order)}
66 {
67 }
68 
fourcc_c(uint32_t const * mem,fourcc_c::byte_order_e byte_order)69 fourcc_c::fourcc_c(uint32_t const *mem,
70                    fourcc_c::byte_order_e byte_order)
71   : m_value{read(mem, byte_order)}
72 {
73 }
74 
fourcc_c(mm_io_cptr const & io,fourcc_c::byte_order_e byte_order)75 fourcc_c::fourcc_c(mm_io_cptr const &io,
76                    fourcc_c::byte_order_e byte_order)
77   : m_value{read(*io, byte_order)}
78 {
79 }
80 
fourcc_c(mm_io_c & io,fourcc_c::byte_order_e byte_order)81 fourcc_c::fourcc_c(mm_io_c &io,
82                    fourcc_c::byte_order_e byte_order)
83   : m_value{read(io, byte_order)}
84 {
85 }
86 
fourcc_c(mm_io_c * io,fourcc_c::byte_order_e byte_order)87 fourcc_c::fourcc_c(mm_io_c *io,
88                    fourcc_c::byte_order_e byte_order)
89   : m_value{read(*io, byte_order)}
90 {
91 }
92 
93 size_t
write(memory_cptr const & mem,fourcc_c::byte_order_e byte_order)94 fourcc_c::write(memory_cptr const &mem,
95                 fourcc_c::byte_order_e byte_order) {
96   return write(mem->get_buffer(), byte_order);
97 }
98 
99 size_t
write(unsigned char * mem,fourcc_c::byte_order_e byte_order)100 fourcc_c::write(unsigned char *mem,
101                 fourcc_c::byte_order_e byte_order) {
102   put_uint32_be(mem, val(m_value, byte_order));
103   return 4;
104 }
105 
106 size_t
write(mm_io_cptr const & io,fourcc_c::byte_order_e byte_order)107 fourcc_c::write(mm_io_cptr const &io,
108                 fourcc_c::byte_order_e byte_order) {
109   return write(io.get(), byte_order);
110 }
111 
112 size_t
write(mm_io_c & io,fourcc_c::byte_order_e byte_order)113 fourcc_c::write(mm_io_c &io,
114                 fourcc_c::byte_order_e byte_order) {
115   return write(&io, byte_order);
116 }
117 
118 size_t
write(mm_io_c * io,fourcc_c::byte_order_e byte_order)119 fourcc_c::write(mm_io_c *io,
120                 fourcc_c::byte_order_e byte_order) {
121   return io->write_uint32_be(val(m_value, byte_order));
122 }
123 
124 uint32_t
value(fourcc_c::byte_order_e byte_order) const125 fourcc_c::value(fourcc_c::byte_order_e byte_order)
126   const {
127   return val(m_value, byte_order);
128 }
129 
130 std::string
str() const131 fourcc_c::str()
132   const {
133   char buffer[4];
134   put_uint32_be(buffer, m_value);
135   for (auto &c : buffer)
136     c = 32 <= c ? c : '?';
137 
138   return std::string{buffer, 4};
139 }
140 
141 std::string
description() const142 fourcc_c::description()
143   const {
144   unsigned char buffer[4];
145   put_uint32_be(buffer, m_value);
146 
147   auto result = fmt::format("0x{0:08x} \"{1}{2}{3}{4}\"", m_value, printable_char(buffer[0]), printable_char(buffer[1]), printable_char(buffer[2]), printable_char(buffer[3]));
148   auto codec  = codec_c::look_up(*this);
149   if (codec.valid())
150     result += fmt::format(": {0}", codec.get_name());
151 
152   return result;
153 }
154 
operator bool() const155 fourcc_c::operator bool()
156   const {
157   return !!m_value;
158 }
159 
160 fourcc_c &
reset()161 fourcc_c::reset() {
162   m_value = 0;
163   return *this;
164 }
165 
166 bool
operator ==(fourcc_c const & cmp) const167 fourcc_c::operator ==(fourcc_c const &cmp)
168   const {
169   return m_value == cmp.m_value;
170 }
171 
172 bool
operator !=(fourcc_c const & cmp) const173 fourcc_c::operator !=(fourcc_c const &cmp)
174   const {
175   return m_value != cmp.m_value;
176 }
177 
178 bool
equiv(char const * cmp) const179 fourcc_c::equiv(char const *cmp)
180   const {
181   return balg::to_lower_copy(str()) == balg::to_lower_copy(std::string{cmp});
182 }
183 
184 bool
equiv(std::vector<std::string> const & cmp) const185 fourcc_c::equiv(std::vector<std::string> const &cmp)
186   const {
187   auto lower = balg::to_lower_copy(str());
188   for (auto &s : cmp)
189     if (lower == balg::to_lower_copy(s))
190       return true;
191   return false;
192 }
193 
194 bool
human_readable(size_t min_num) const195 fourcc_c::human_readable(size_t min_num)
196   const {
197   static auto byte_ok = [](int c) { return (('a' <= c) && ('z' >= c)) || (('A' <= c) && ('Z' >= c)) || (('0' <= c) && ('9' >= c)) || (0xa9 == c); };
198   auto num            = 0u;
199   for (auto shift = 0; 3 >= shift; ++shift)
200     num += byte_ok((m_value >> (shift * 8)) & 0xff) ? 1 : 0;
201   return min_num <= num;
202 }
203 
204 uint32_t
read(void const * mem,fourcc_c::byte_order_e byte_order)205 fourcc_c::read(void const *mem,
206                fourcc_c::byte_order_e byte_order) {
207   return val(get_uint32_be(mem), byte_order);
208 }
209 
210 uint32_t
read(mm_io_c & io,fourcc_c::byte_order_e byte_order)211 fourcc_c::read(mm_io_c &io,
212                fourcc_c::byte_order_e byte_order) {
213   return val(io.read_uint32_be(), byte_order);
214 }
215 
216 fourcc_c &
shift_read(mm_io_cptr const & io,byte_order_e byte_order)217 fourcc_c::shift_read(mm_io_cptr const &io,
218                      byte_order_e byte_order) {
219   return shift_read(*io, byte_order);
220 }
221 
222 fourcc_c &
shift_read(mm_io_c & io,byte_order_e byte_order)223 fourcc_c::shift_read(mm_io_c &io,
224                      byte_order_e byte_order) {
225   m_value = byte_order_e::big_endian == byte_order ? (m_value << 8) | io.read_uint8() : (m_value >> 8) | (io.read_uint8() << 24);
226   return *this;
227 }
228 
229 fourcc_c &
shift_read(mm_io_c * io,byte_order_e byte_order)230 fourcc_c::shift_read(mm_io_c *io,
231                      byte_order_e byte_order) {
232   return shift_read(*io, byte_order);
233 }
234