6 #include "../exceptions.h" 8 #include <c++utilities/conversion/stringbuilder.h> 9 #include <c++utilities/io/binaryreader.h> 10 #include <c++utilities/io/binarywriter.h> 30 Mp4TagField::Mp4TagField() :
31 m_parsedRawDataType(RawDataType::
Reserved),
32 m_countryIndicator(0),
41 m_parsedRawDataType(RawDataType::
Reserved),
42 m_countryIndicator(0),
75 using namespace Mp4AtomIds;
76 using namespace Mp4TagAtomIds;
78 string context(
"parsing MP4 tag field");
82 context =
"parsing MP4 tag field " + ilstChild.
idToString();
83 iostream &stream = ilstChild.
stream();
84 BinaryReader &reader = ilstChild.
container().reader();
85 int dataAtomFound = 0, meanAtomFound = 0, nameAtomFound = 0;
86 for(
Mp4Atom *dataAtom = ilstChild.
firstChild(); dataAtom; dataAtom = dataAtom->nextSibling()) {
90 if(dataAtom->dataSize() < 8) {
94 if(++dataAtomFound > 1) {
95 if(dataAtomFound == 2) {
100 stream.seekg(dataAtom->dataOffset());
101 if(reader.readByte() != 0) {
104 setTypeInfo(m_parsedRawDataType = reader.readUInt24BE());
113 m_countryIndicator = reader.readUInt16BE();
114 m_langIndicator = reader.readUInt16BE();
115 switch(m_parsedRawDataType) {
117 stream.seekg(dataAtom->dataOffset() + 8);
121 switch(m_parsedRawDataType) {
137 const streamsize coverSize = dataAtom->dataSize() - 8;
138 unique_ptr<char []> coverData = make_unique<char []>(coverSize);
139 stream.read(coverData.get(), coverSize);
144 if(dataAtom->dataSize() > (8 + 4)) {
147 if(dataAtom->dataSize() >= (8 + 4)) {
148 number = reader.readInt32BE();
149 }
else if(dataAtom->dataSize() == (8 + 2)) {
150 number = reader.readInt16BE();
151 }
else if(dataAtom->dataSize() == (8 + 1)) {
152 number = reader.readChar();
154 switch(ilstChild.
id()) {
164 if(dataAtom->dataSize() > (8 + 4)) {
167 if(dataAtom->dataSize() >= (8 + 4)) {
168 number =
static_cast<int>(reader.readUInt32BE());
169 }
else if(dataAtom->dataSize() == (8 + 2)) {
170 number =
static_cast<int>(reader.readUInt16BE());
171 }
else if(dataAtom->dataSize() == (8 + 1)) {
172 number =
static_cast<int>(reader.readByte());
174 switch(ilstChild.
id()) {
183 switch(ilstChild.
id()) {
187 if(dataAtom->dataSize() < (8 + 6)) {
190 uint16 pos = 0, total = 0;
191 if(dataAtom->dataSize() >= (8 + 4)) {
192 stream.seekg(2, ios_base::cur);
193 pos = reader.readUInt16BE();
195 if(dataAtom->dataSize() >= (8 + 6)) {
196 total = reader.readUInt16BE();
202 if(dataAtom->dataSize() < (8 + 2)) {
209 streamsize dataSize = dataAtom->dataSize() - 8;
210 unique_ptr<char []> data = make_unique<char[]>(dataSize);
211 stream.read(data.get(), dataSize);
220 if(dataAtom->dataSize() < 8) {
224 if(++meanAtomFound > 1) {
225 if(meanAtomFound == 2) {
230 stream.seekg(dataAtom->dataOffset() + 4);
231 m_mean = reader.readString(dataAtom->dataSize() - 4);
233 if(dataAtom->dataSize() < 4) {
237 if(++nameAtomFound > 1) {
238 if(nameAtomFound == 2) {
243 stream.seekg(dataAtom->dataOffset() + 4);
244 m_name = reader.readString(dataAtom->dataSize() - 4);
252 if(
value().isEmpty()) {
289 using namespace Mp4TagAtomIds;
290 std::vector<uint32> res;
336 using namespace Mp4TagAtomIds;
351 switch(
value().dataEncoding()) {
363 if(mimeType ==
"image/jpg" || mimeType ==
"image/jpeg") {
365 }
else if(mimeType ==
"image/png") {
367 }
else if(mimeType ==
"image/bmp") {
376 switch(
value().dataEncoding()) {
396 m_countryIndicator = 0;
411 Mp4TagFieldMaker::Mp4TagFieldMaker(
Mp4TagField &field) :
413 m_convertedData(stringstream::in | stringstream::out | stringstream::binary),
414 m_writer(&m_convertedData),
417 m_field.invalidateStatus();
423 if(m_field.value().isEmpty() && (!m_field.mean().empty() || !m_field.name().empty())) {
425 throw InvalidDataException();
430 m_rawDataType = m_field.appropriateRawDataType();
431 }
catch(
const Failure &) {
436 m_field.addNotification(
NotificationType::Warning,
"It was not possible to find an appropriate raw data type id. JPEG image will be assumed.", context);
440 m_field.addNotification(
NotificationType::Warning,
"It was not possible to find an appropriate raw data type id. UTF-8 will be assumed.", context);
445 if(!m_field.value().isEmpty()) {
446 m_convertedData.exceptions(std::stringstream::failbit | std::stringstream::badbit);
447 switch(m_rawDataType) {
450 m_writer.writeString(m_field.value().toString());
453 int number = m_field.value().toInteger();
454 if(number <= numeric_limits<int16>::max()
455 && number >= numeric_limits<int16>::min()) {
456 m_writer.writeInt16BE(static_cast<int16>(number));
458 m_writer.writeInt32BE(number);
462 int number = m_field.value().toInteger();
463 if(number <= numeric_limits<uint16>::max()
464 && number >= numeric_limits<uint16>::min()) {
465 m_writer.writeUInt16BE(static_cast<uint16>(number));
466 }
else if(number > 0) {
467 m_writer.writeUInt32BE(number);
469 throw ConversionException(
"Negative integer can not be assigned to the field with the id \"" % interpretIntegerAsString<uint32>(m_field.id()) +
"\".");
475 switch(m_field.id()) {
480 m_writer.writeInt32BE(pos.position());
481 if(pos.total() <= numeric_limits<int16>::max()) {
482 m_writer.writeInt16BE(static_cast<int16>(pos.total()));
484 throw ConversionException(
"Integer can not be assigned to the field with the id \"" % interpretIntegerAsString<uint32>(m_field.id()) +
"\" because it is to big.");
486 m_writer.writeUInt16BE(0);
490 m_writer.writeUInt16BE(m_field.value().toStandardGenreIndex());
497 }
catch (ConversionException &ex) {
499 if(char_traits<char>::length(ex.what())) {
502 m_field.addNotification(
NotificationType::Critical,
"The assigned tag value can not be converted to be written appropriately.", context);
504 throw InvalidDataException();
508 m_dataSize = m_field.value().isEmpty()
509 ? 0 : (m_convertedData.tellp() ?
static_cast<size_t>(m_convertedData.tellp()) : m_field.value().dataSize());
511 + (m_field.name().empty() ? 0 : (12 + m_field.name().length()))
512 + (m_field.mean().empty() ? 0 : (12 + m_field.mean().length()))
513 + (m_dataSize ? (16 + m_dataSize) : 0);
525 m_writer.setStream(&stream);
527 m_writer.writeUInt32BE(m_totalSize);
529 m_writer.writeUInt32BE(m_field.
id());
530 if(!m_field.
mean().empty()) {
532 m_writer.writeUInt32BE(12 + m_field.
mean().size());
534 m_writer.writeUInt32BE(0);
535 m_writer.writeString(m_field.
mean());
537 if(!m_field.
name().empty()) {
539 m_writer.writeUInt32BE(12 + m_field.
name().length());
541 m_writer.writeUInt32BE(0);
542 m_writer.writeString(m_field.
name());
545 m_writer.writeUInt32BE(16 + m_dataSize);
547 m_writer.writeByte(0);
548 m_writer.writeUInt24BE(m_rawDataType);
551 if(m_convertedData.tellp()) {
553 stream << m_convertedData.rdbuf();
Contains utility classes helping to read and write streams.