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