Leftovers from the previous merge.

This commit is contained in:
Moritz Bunkus 2004-08-28 14:25:23 +00:00
parent f78d588bd4
commit 9e793ffcdb
5 changed files with 1 additions and 1316 deletions

View File

@ -1,86 +0,0 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* Mapping from XML elements to EBML elements
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include "ebml/EbmlElement.h"
#include "chapters.h"
namespace libmatroska {
extern EbmlId KaxChapters_TheId;
extern EbmlId KaxEditionEntry_TheId;
extern EbmlId KaxEditionUID_TheId;
extern EbmlId KaxEditionFlagHidden_TheId;
extern EbmlId KaxEditionFlagDefault_TheId;
extern EbmlId KaxEditionManaged_TheId;
extern EbmlId KaxChapterAtom_TheId;
extern EbmlId KaxChapterUID_TheId;
extern EbmlId KaxChapterTimeStart_TheId;
extern EbmlId KaxChapterTimeEnd_TheId;
extern EbmlId KaxChapterFlagHidden_TheId;
extern EbmlId KaxChapterFlagEnabled_TheId;
extern EbmlId KaxChapterPhysicalEquiv_TheId;
extern EbmlId KaxChapterTrack_TheId;
extern EbmlId KaxChapterTrackNumber_TheId;
extern EbmlId KaxChapterDisplay_TheId;
extern EbmlId KaxChapterString_TheId;
extern EbmlId KaxChapterLanguage_TheId;
extern EbmlId KaxChapterCountry_TheId;
extern EbmlId KaxChapterProcess_TheId;
extern EbmlId KaxChapterProcessTime_TheId;
}
parser_element_t chapter_elements[] = {
{"Chapters", ebmlt_master, 0, 0, 0, KaxChapters_TheId, NULL, NULL},
{"EditionEntry", ebmlt_master, 1, 0, 0, KaxEditionEntry_TheId, NULL, NULL},
{"EditionUID", ebmlt_uint, 2, 0, NO_MAX_VALUE, KaxEditionUID_TheId, NULL,
NULL},
{"EditionFlagHidden", ebmlt_bool, 2, 0, 0, KaxEditionFlagHidden_TheId,
NULL, NULL},
{"EditionManaged", ebmlt_uint, 2, 0, NO_MAX_VALUE, KaxEditionManaged_TheId,
NULL, NULL},
{"EditionFlagDefault", ebmlt_bool, 2, 0, 0, KaxEditionFlagDefault_TheId,
NULL, NULL},
{"ChapterAtom", ebmlt_master, 2, 0, 0, KaxChapterAtom_TheId, NULL,
NULL},
{"ChapterUID", ebmlt_uint, 3, 0, NO_MAX_VALUE, KaxChapterUID_TheId, NULL,
NULL},
{"ChapterTimeStart", ebmlt_time, 3, 0, 0, KaxChapterTimeStart_TheId, NULL,
NULL},
{"ChapterTimeEnd", ebmlt_time, 3, 0, 0, KaxChapterTimeEnd_TheId, NULL,
NULL},
{"ChapterFlagHidden", ebmlt_bool, 3, 0, 0, KaxChapterFlagHidden_TheId,
NULL, NULL},
{"ChapterFlagEnabled", ebmlt_bool, 3, 0, 0, KaxChapterFlagEnabled_TheId,
NULL, NULL},
{"ChapterTrack", ebmlt_master, 3, 0, 0, KaxChapterTrack_TheId,
NULL, NULL},
{"ChapterTrackNumber", ebmlt_uint, 4, 0, NO_MAX_VALUE,
KaxChapterTrackNumber_TheId, NULL, NULL},
{"ChapterDisplay", ebmlt_master, 3, 0, 0, KaxChapterDisplay_TheId,
NULL, NULL},
{"ChapterString", ebmlt_ustring, 4, 0, 0, KaxChapterString_TheId,
NULL, NULL},
{"ChapterLanguage", ebmlt_string, 4, 0, 0, KaxChapterLanguage_TheId,
NULL, NULL},
{"ChapterCountry", ebmlt_string, 4, 0, 0, KaxChapterCountry_TheId,
NULL, NULL},
{NULL, ebmlt_master, 0, 0, 0, EbmlId((uint32_t)0, 0), NULL, NULL}
};

View File

@ -1,45 +0,0 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* Declarations of external EBML Ids found in libebml
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#ifndef __EBML_IDS_H
#define __EBML_IDS_H
#include "ebml/EbmlElement.h"
namespace libmatroska {
extern EbmlId KaxChapters_TheId;
extern EbmlId KaxEditionEntry_TheId;
extern EbmlId KaxEditionUID_TheId;
extern EbmlId KaxEditionFlagHidden_TheId;
extern EbmlId KaxEditionFlagDefault_TheId;
extern EbmlId KaxEditionManaged_TheId;
extern EbmlId KaxChapterAtom_TheId;
extern EbmlId KaxChapterUID_TheId;
extern EbmlId KaxChapterTimeStart_TheId;
extern EbmlId KaxChapterTimeEnd_TheId;
extern EbmlId KaxChapterFlagHidden_TheId;
extern EbmlId KaxChapterFlagEnabled_TheId;
extern EbmlId KaxChapterPhysicalEquiv_TheId;
extern EbmlId KaxChapterTrack_TheId;
extern EbmlId KaxChapterTrackNumber_TheId;
extern EbmlId KaxChapterDisplay_TheId;
extern EbmlId KaxChapterString_TheId;
extern EbmlId KaxChapterLanguage_TheId;
extern EbmlId KaxChapterCountry_TheId;
extern EbmlId KaxChapterProcess_TheId;
extern EbmlId KaxChapterProcessTime_TheId;
}
#endif

View File

@ -1,705 +0,0 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* XML tag parser. Functions for the end tags + value parsers
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <string>
#include <vector>
#include <expat.h>
#include "base64.h"
#include "common.h"
#include "commonebml.h"
#include "iso639.h"
#include "mm_io.h"
#include "tagparser.h"
using namespace std;
using namespace libebml;
using namespace libmatroska;
static void
el_get_uint(parser_data_t *pdata,
EbmlElement *el,
uint64_t min_value = 0,
uint64_t max_value = 9223372036854775807ULL) {
int64 value;
strip(*pdata->bin);
if (!parse_int(pdata->bin->c_str(), value))
tperror(pdata, "Expected an unsigned integer but found '%s'.",
pdata->bin->c_str());
if (value < min_value)
tperror(pdata, "Unsigned integer (%lld) is too small. Mininum value is "
"%lld.", value, min_value);
if (value > max_value)
tperror(pdata, "Unsigned integer (%lld) is too big. Maximum value is "
"%lld.", value, max_value);
*(static_cast<EbmlUInteger *>(el)) = value;
}
static void
el_get_sint(parser_data_t *pdata,
EbmlElement *el,
int64_t min_value = -9223372036854775807LL-1) {
int64 value;
strip(*pdata->bin);
if (!parse_int(pdata->bin->c_str(), value))
tperror(pdata, "Expected a signed integer but found '%s'.",
pdata->bin->c_str());
if (value < min_value)
tperror(pdata, "Signed integer (%lld) is too small. Mininum value is "
"%lld.\n", value, min_value);
*(static_cast<EbmlSInteger *>(el)) = value;
}
static void
el_get_float(parser_data_t *pdata,
EbmlElement *el,
float min_value = (float)1.40129846432481707e-45) {
char *endptr;
float value;
strip(*pdata->bin);
value = (float)strtod(pdata->bin->c_str(), &endptr);
if (((value == 0.0) && (endptr == pdata->bin->c_str())) ||
(errno == ERANGE))
tperror(pdata, "Expected a floating point number but found '%s'.",
pdata->bin->c_str());
*(static_cast<EbmlFloat *>(el)) = value;
}
static void
el_get_string(parser_data_t *pdata,
EbmlElement *el,
bool check_language = false) {
strip(*pdata->bin);
if (pdata->bin->length() == 0)
tperror(pdata, "Expected a string but found only whitespaces.");
if (check_language && !is_valid_iso639_2_code(pdata->bin->c_str()))
tperror(pdata, "'%s' is not a valid ISO639-2 language code. See the "
"output of 'mkvmerge --list-languages' for a list of all "
"valid language codes.", pdata->bin->c_str());
*(static_cast<EbmlString *>(el)) = pdata->bin->c_str();
}
static void
el_get_utf8string(parser_data_t *pdata,
EbmlElement *el) {
strip(*pdata->bin);
if (pdata->bin->length() == 0)
tperror(pdata, "Expected a string but found only whitespaces.");
*(static_cast<EbmlUnicodeString *>(el)) =
cstrutf8_to_UTFstring(pdata->bin->c_str());
}
static void
el_get_binary(parser_data_t *pdata,
EbmlElement *el) {
int64_t result;
binary *buffer;
mm_io_c *io;
result = 0;
buffer = NULL;
strip(*pdata->bin, true);
if (pdata->bin->length() == 0)
tperror(pdata, "Found neither Base64 encoded data nor '@file' to read "
"binary data from.");
if ((*pdata->bin)[0] == '@') {
if (pdata->bin->length() == 1)
tperror(pdata, "No filename found after the '@'.");
try {
io = new mm_io_c(&(pdata->bin->c_str())[1], MODE_READ);
io->setFilePointer(0, seek_end);
result = io->getFilePointer();
io->setFilePointer(0, seek_beginning);
if (result <= 0)
tperror(pdata, "The file '%s' is empty.", &(pdata->bin->c_str())[1]);
buffer = new binary[result];
io->read(buffer, result);
delete io;
} catch(...) {
tperror(pdata, "Could not open/read the file '%s'.",
&(pdata->bin->c_str())[1]);
}
} else {
buffer = new binary[pdata->bin->length() / 4 * 3 + 1];
result = base64_decode(*pdata->bin, (unsigned char *)buffer);
if (result < 0)
tperror(pdata, "Could not decode the Base64 encoded data - it seems to "
"be broken.");
}
(static_cast<EbmlBinary *>(el))->SetBuffer(buffer, result);
}
// ISO 8601 format: 2003-07-17T19:50:53+0200
// 012345678901234567890123
// 1 2
static void
el_get_date(parser_data_t *pdata,
EbmlElement *el) {
const char *errmsg = "Expected a date in ISO 8601 format but found '%s'. "
"The ISO 8601 date format looks like this: YYYY-MM-DDTHH:MM:SS:-TZTZ, "
"e.g. 2003-07-17T19:50:52+0200. The time zone (TZ) may also be negative.";
char *p;
int year, month, day, hour, minute, second, time_zone, offset;
char tz_sign;
struct tm t;
time_t tme;
#ifdef SYS_UNIX
struct timezone tz;
#else
time_t tme_local, tme_gm;
#endif
strip(*pdata->bin);
p = safestrdup(pdata->bin->c_str());
if (pdata->bin->length() != 24)
tperror(pdata, errmsg, pdata->bin->c_str());
if ((p[4] != '-') || (p[7] != '-') || (p[10] != 'T') ||
(p[13] != ':') || (p[16] != ':') || (p[19] != '+'))
tperror(pdata, errmsg, pdata->bin->c_str());
p[4] = 0;
p[7] = 0;
p[10] = 0;
p[13] = 0;
p[16] = 0;
tz_sign = p[19];
p[19] = 0;
if (!parse_int(p, year) || !parse_int(&p[5], month) ||
!parse_int(&p[8], day) || !parse_int(&p[11], hour) ||
!parse_int(&p[14], minute) || !parse_int(&p[17], second) ||
!parse_int(&p[20], time_zone))
tperror(pdata, errmsg, pdata->bin->c_str());
if (year < 1900)
tperror(pdata, "Invalid year given (%d).", year);
if ((month < 1) || (month > 12))
tperror(pdata, "Invalid month given (%d).", month);
if ((day < 1) || (day > 31))
tperror(pdata, "Invalid day given (%d).", day);
if ((hour < 0) || (hour > 23))
tperror(pdata, "Invalid hour given (%d).", hour);
if ((minute < 0) || (minute > 59))
tperror(pdata, "Invalid minute given (%d).", minute);
if ((second < 0) || (second > 59))
tperror(pdata, "Invalid second given (%d).", second);
if ((tz_sign != '+') && (tz_sign != '-'))
tperror(pdata, "Invalid time zone given (%c%s).", tz_sign, &p[20]);
if ((time_zone < 0) || (time_zone > 1200))
tperror(pdata, "Invalid time zone given (%c%s).", tz_sign, &p[20]);
memset(&t, 0, sizeof(struct tm));
t.tm_year = year - 1900;
t.tm_mon = month - 1;
t.tm_mday = day;
t.tm_hour = hour;
t.tm_min = minute;
t.tm_sec = second;
t.tm_isdst = -1;
tme = mktime(&t);
if (tme == (time_t)-1)
tperror(pdata, "Invalid date specified (%s).", pdata->bin->c_str());
offset = (((time_zone / 100) * 60) + (time_zone % 100)) * 60;
if (tz_sign == '+')
offset *= -1;
tme += offset;
#ifdef SYS_UNIX
gettimeofday(NULL, &tz);
tme -= tz.tz_minuteswest * 60;
#else
tme_local = mktime(localtime(&tme));
tme_gm = mktime(gmtime(&tme));
tme -= (tme_gm - tme_local);
#endif
if (tme < 0)
tperror(pdata, "Invalid date specified (%s).", pdata->bin->c_str());
safefree(p);
(static_cast<EbmlDate *>(el))->SetEpochDate(tme);
}
static bool
is_multicomment(parser_data_t *pdata,
const char *name) {
int parent;
parent = (*pdata->parents)[pdata->parents->size() - 2];
if (parent != E_MultiComment)
return false;
if (!strcmp(name, "Name"))
el_get_string(pdata, &GetChild<KaxTagMultiCommentName>(*pdata->m_comment));
else if (!strcmp(name, "Comments"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiCommentComments>
(*pdata->m_comment));
else if (!strcmp(name, "Language"))
el_get_string(pdata, &GetChild<KaxTagMultiCommentLanguage>
(*pdata->m_comment), true);
return true;
}
static void
end_level1(parser_data_t *pdata,
const char *) {
// Can only be "Tag"
pdata->targets = NULL;
pdata->general = NULL;
pdata->genres = NULL;
pdata->audio_specific = NULL;
pdata->image_specific = NULL;
pdata->m_commercial = NULL;
pdata->m_date = NULL;
pdata->m_entity = NULL;
pdata->m_identifier = NULL;
pdata->m_legal = NULL;
pdata->m_title = NULL;
pdata->m_comment = NULL;
}
static void
end_level2(parser_data_t *pdata,
const char *name) {
if (!strcmp(name, "Targets")) {
GetChild<KaxTagTargetTypeValue>(*pdata->targets);
pdata->track_uid = NULL;
pdata->chapter_uid = NULL;
pdata->edition_uid = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "General")) {
pdata->keywords = NULL;
pdata->rec_location = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "Genres")) {
pdata->audio_genre = NULL;
pdata->video_genre = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "AudioSpecific")) {
pdata->m_comment = NULL;
} else if (!strcmp(name, "ImageSpecific")) {
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiCommercial")) {
pdata->commercial = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiDate")) {
pdata->date = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiEntity")) {
pdata->entity = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiIdentifier")) {
pdata->identifier = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiLegal")) {
pdata->legal = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiTitle")) {
pdata->title = NULL;
pdata->m_comment = NULL;
} else if (!strcmp(name, "MultiComment")) {
}
}
static void
end_level3(parser_data_t *pdata,
const char *name) {
string parent_name;
int parent;
if (is_multicomment(pdata, name))
return;
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
parent = (*pdata->parents)[pdata->parents->size() - 2];
if (parent == E_Targets) {
if (!strcmp(name, "TrackUID"))
el_get_uint(pdata, pdata->track_uid);
else if (!strcmp(name, "ChapterUID"))
el_get_uint(pdata, pdata->chapter_uid);
else if (!strcmp(name, "EditionUID"))
el_get_uint(pdata, pdata->edition_uid);
else if (!strcmp(name, "TargetType"))
el_get_string(pdata, &GetChild<KaxTagTargetType>(*pdata->targets));
} else if (parent == E_General) {
if (!strcmp(name, "Subject"))
el_get_utf8string(pdata, &GetChild<KaxTagSubject>(*pdata->general));
else if (!strcmp(name, "Bibliography"))
el_get_utf8string(pdata, &GetChild<KaxTagBibliography>(*pdata->general));
else if (!strcmp(name, "Language"))
el_get_string(pdata, &GetChild<KaxTagLanguage>(*pdata->general), true);
else if (!strcmp(name, "Rating"))
el_get_binary(pdata, &GetChild<KaxTagRating>(*pdata->general));
else if (!strcmp(name, "Encoder"))
el_get_utf8string(pdata, &GetChild<KaxTagEncoder>(*pdata->general));
else if (!strcmp(name, "EncodeSettings"))
el_get_utf8string(pdata,
&GetChild<KaxTagEncodeSettings>(*pdata->general));
else if (!strcmp(name, "File"))
el_get_utf8string(pdata, &GetChild<KaxTagFile>(*pdata->general));
else if (!strcmp(name, "ArchivalLocation"))
el_get_utf8string(pdata,
&GetChild<KaxTagArchivalLocation>(*pdata->general));
else if (!strcmp(name, "Keywords"))
el_get_utf8string(pdata, pdata->keywords);
else if (!strcmp(name, "Mood"))
el_get_utf8string(pdata, &GetChild<KaxTagMood>(*pdata->general));
else if (!strcmp(name, "RecordLocation"))
el_get_string(pdata, pdata->rec_location);
else if (!strcmp(name, "Source"))
el_get_utf8string(pdata, &GetChild<KaxTagSource>(*pdata->general));
else if (!strcmp(name, "SourceForm"))
el_get_utf8string(pdata, &GetChild<KaxTagSourceForm>(*pdata->general));
else if (!strcmp(name, "Product"))
el_get_utf8string(pdata, &GetChild<KaxTagProduct>(*pdata->general));
else if (!strcmp(name, "OriginalMediaType"))
el_get_utf8string(pdata,
&GetChild<KaxTagOriginalMediaType>(*pdata->general));
else if (!strcmp(name, "PlayCounter"))
el_get_uint(pdata, &GetChild<KaxTagPlayCounter>(*pdata->general));
else if (!strcmp(name, "Popularimeter"))
el_get_sint(pdata, &GetChild<KaxTagPopularimeter>(*pdata->general));
} else if (parent == E_Genres) {
if (!strcmp(name, "AudioGenre"))
el_get_string(pdata, pdata->audio_genre);
else if (!strcmp(name, "VideoGenre"))
el_get_binary(pdata, pdata->video_genre);
else if (!strcmp(name, "SubGenre"))
el_get_string(pdata, &GetChild<KaxTagSubGenre>(*pdata->genres));
} else if (parent == E_AudioSpecific) {
if (!strcmp(name, "AudioEncryption"))
el_get_binary(pdata,
&GetChild<KaxTagAudioEncryption>(*pdata->audio_specific));
else if (!strcmp(name, "AudioGain"))
el_get_float(pdata,
&GetChild<KaxTagAudioGain>(*pdata->audio_specific),
0.000000001);
else if (!strcmp(name, "AudioPeak"))
el_get_float(pdata, &GetChild<KaxTagAudioPeak>(*pdata->audio_specific));
else if (!strcmp(name, "BPM"))
el_get_float(pdata, &GetChild<KaxTagBPM>(*pdata->audio_specific));
else if (!strcmp(name, "Equalisation"))
el_get_binary(pdata,
&GetChild<KaxTagEqualisation>(*pdata->audio_specific));
else if (!strcmp(name, "DiscTrack"))
el_get_uint(pdata, &GetChild<KaxTagDiscTrack>(*pdata->audio_specific));
else if (!strcmp(name, "SetPart"))
el_get_uint(pdata, &GetChild<KaxTagSetPart>(*pdata->audio_specific));
else if (!strcmp(name, "InitialKey"))
el_get_string(pdata,
&GetChild<KaxTagInitialKey>(*pdata->audio_specific));
else if (!strcmp(name, "OfficialAudioFileURL"))
el_get_string(pdata, &GetChild<KaxTagOfficialAudioFileURL>
(*pdata->audio_specific));
else if (!strcmp(name, "OfficialAudioSourceURL"))
el_get_string(pdata, &GetChild<KaxTagOfficialAudioSourceURL>
(*pdata->audio_specific));
} else if (parent == E_ImageSpecific) {
if (!strcmp(name, "CaptureDPI"))
el_get_uint(pdata, &GetChild<KaxTagCaptureDPI>(*pdata->image_specific));
else if (!strcmp(name, "CaptureLightness"))
el_get_binary(pdata, &GetChild<KaxTagCaptureLightness>
(*pdata->image_specific));
else if (!strcmp(name, "CapturePaletteSetting"))
el_get_uint(pdata, &GetChild<KaxTagCapturePaletteSetting>
(*pdata->image_specific));
else if (!strcmp(name, "CaptureSharpness"))
el_get_binary(pdata, &GetChild<KaxTagCaptureSharpness>
(*pdata->image_specific));
else if (!strcmp(name, "Cropped"))
el_get_utf8string(pdata, &GetChild<KaxTagCropped>
(*pdata->image_specific));
else if (!strcmp(name, "OriginalDimensions"))
el_get_string(pdata, &GetChild<KaxTagOriginalDimensions>
(*pdata->image_specific));
} else if (parent == E_MultiCommercial) {
pdata->c_url = NULL;
pdata->c_email = NULL;
pdata->m_price = NULL;
pdata->m_comment = NULL;
} else if (parent == E_MultiDate) {
pdata->m_comment = NULL;
} else if (parent == E_MultiEntity) {
pdata->e_url = NULL;
pdata->e_email = NULL;
pdata->m_comment = NULL;
} else if (parent == E_MultiIdentifier) {
pdata->m_comment = NULL;
} else if (parent == E_MultiLegal) {
pdata->l_url = NULL;
pdata->m_comment = NULL;
} else if (parent == E_MultiTitle) {
pdata->t_url = NULL;
pdata->t_email = NULL;
pdata->m_comment = NULL;
} else
die("Unknown parent: level 3, %d", parent);
}
static void
end_level4(parser_data_t *pdata,
const char *name) {
string parent_name;
int parent;
if (is_multicomment(pdata, name))
return;
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
parent = (*pdata->parents)[pdata->parents->size() - 2];
if (parent == E_Commercial) {
if (!strcmp(name, "CommercialType"))
el_get_uint(pdata, &GetChild<KaxTagMultiCommercialType>
(*pdata->commercial), 1);
else if (!strcmp(name, "Address"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiCommercialAddress>
(*pdata->commercial));
else if (!strcmp(name, "URL"))
el_get_string(pdata, pdata->c_url);
else if (!strcmp(name, "Email"))
el_get_string(pdata, pdata->c_email);
else if (!strcmp(name, "MultiPrice")) {
pdata->m_comment = NULL;
}
} else if (parent == E_Date) {
if (!strcmp(name, "DateType"))
el_get_uint(pdata, &GetChild<KaxTagMultiDateType>
(*pdata->date), 1);
else if (!strcmp(name, "Begin"))
el_get_date(pdata, &GetChild<KaxTagMultiDateDateBegin>
(*pdata->date));
else if (!strcmp(name, "End"))
el_get_date(pdata, &GetChild<KaxTagMultiDateDateEnd>
(*pdata->date));
} else if (parent == E_Entity) {
if (!strcmp(name, "EntityType"))
el_get_uint(pdata, &GetChild<KaxTagMultiEntityType>
(*pdata->entity), 1);
else if (!strcmp(name, "Name"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiEntityName>
(*pdata->entity));
else if (!strcmp(name, "URL"))
el_get_string(pdata, pdata->e_url);
else if (!strcmp(name, "Email"))
el_get_string(pdata, pdata->e_email);
else if (!strcmp(name, "Address"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiEntityAddress>
(*pdata->entity));
} else if (parent == E_Identifier) {
if (!strcmp(name, "IdentifierType"))
el_get_uint(pdata, &GetChild<KaxTagMultiIdentifierType>
(*pdata->identifier), 1);
else if (!strcmp(name, "Binary"))
el_get_binary(pdata, &GetChild<KaxTagMultiIdentifierBinary>
(*pdata->identifier));
else if (!strcmp(name, "String"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiIdentifierString>
(*pdata->identifier));
} else if (parent == E_Legal) {
if (!strcmp(name, "LegalType"))
el_get_uint(pdata, &GetChild<KaxTagMultiLegalType>
(*pdata->legal), 1);
else if (!strcmp(name, "URL"))
el_get_string(pdata, pdata->l_url);
else if (!strcmp(name, "Address"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiLegalAddress>
(*pdata->legal));
else if (!strcmp(name, "Content"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiLegalContent>
(*pdata->legal));
} else if (parent == E_Title) {
if (!strcmp(name, "TitleType"))
el_get_uint(pdata, &GetChild<KaxTagMultiTitleType>
(*pdata->title), 1);
else if (!strcmp(name, "Name"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleName>
(*pdata->title));
else if (!strcmp(name, "SubTitle"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleSubTitle>
(*pdata->title));
else if (!strcmp(name, "Edition"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleEdition>
(*pdata->title));
else if (!strcmp(name, "Address"))
el_get_utf8string(pdata, &GetChild<KaxTagMultiTitleAddress>
(*pdata->title));
else if (!strcmp(name, "URL"))
el_get_string(pdata, pdata->t_url);
else if (!strcmp(name, "Email"))
el_get_string(pdata, pdata->t_email);
else if (!strcmp(name, "Language"))
el_get_string(pdata, &GetChild<KaxTagMultiTitleLanguage>
(*pdata->title), true);
} else
die("Unknown parent: level 4, %d", parent);
}
static void
end_level5(parser_data_t *pdata,
const char *name) {
string parent_name;
int parent;
if (is_multicomment(pdata, name))
return;
parent_name = (*pdata->parent_names)[pdata->parent_names->size() - 2];
parent = (*pdata->parents)[pdata->parents->size() - 2];
if (parent == E_MultiPrice) {
if (!strcmp(name, "Currency"))
el_get_string(pdata, &GetChild<KaxTagMultiPriceCurrency>
(*pdata->m_price));
else if (!strcmp(name, "Amount"))
el_get_float(pdata, &GetChild<KaxTagMultiPriceAmount>
(*pdata->m_price));
else if (!strcmp(name, "PriceDate"))
el_get_date(pdata, &GetChild<KaxTagMultiPricePriceDate>
(*pdata->m_price));
} else
die("Unknown parent: level 4, %d", parent);
}
static void
end_level6(parser_data_t *pdata,
const char *name) {
if (is_multicomment(pdata, name))
return;
die("tagparser_end: Unknown element. This should not have happened.");
}
static void
end_simple(parser_data_t *pdata,
const char *name) {
if (!strcmp(name, "Simple")) {
pdata->simple_tags->pop_back();
if (pdata->simple_tags->size() == 0)
pdata->parsing_simple = false;
} else {
KaxTagSimple *simple =
(*pdata->simple_tags)[pdata->simple_tags->size() - 1];
if (!strcmp(name, "Name"))
el_get_utf8string(pdata, &GetChild<KaxTagName>(*simple));
else if (!strcmp(name, "String"))
el_get_utf8string(pdata, &GetChild<KaxTagString>(*simple));
else if (!strcmp(name, "Binary"))
el_get_binary(pdata, &GetChild<KaxTagBinary>(*simple));
else if (!strcmp(name, "TagLanguage"))
el_get_string(pdata, &GetChild<KaxTagLangue>(*simple), true);
else if (!strcmp(name, "DefaultLanguage"))
el_get_uint(pdata, &GetChild<KaxTagDefault>(*simple), 0, 1);
}
}
void
end_xml_tag_element(void *user_data,
const char *name) {
parser_data_t *pdata;
pdata = (parser_data_t *)user_data;
if (pdata->data_allowed && (pdata->bin == NULL))
tperror(pdata, "Element <%s> does not contain any data.", name);
if (pdata->parsing_simple)
end_simple(pdata, name);
else if (pdata->depth == 1)
; // Nothing to do here!
else if (pdata->depth == 2)
end_level1(pdata, name);
else if (pdata->depth == 3)
end_level2(pdata, name);
else if (pdata->depth == 4)
end_level3(pdata, name);
else if (pdata->depth == 5)
end_level4(pdata, name);
else if (pdata->depth == 6)
end_level5(pdata, name);
else if (pdata->depth == 7)
end_level6(pdata, name);
else
die("tagparser_end: depth > 7: %d", pdata->depth);
if (pdata->bin != NULL) {
delete pdata->bin;
pdata->bin = NULL;
}
pdata->data_allowed = false;
pdata->depth--;
pdata->parent_names->pop_back();
pdata->parents->pop_back();
}

View File

@ -1,479 +0,0 @@
/*
* mkvmerge -- utility for splicing together matroska files
* from component media subtypes
*
* Distributed under the GPL
* see the file COPYING for details
* or visit http://www.gnu.org/copyleft/gpl.html
*
* $Id$
*
* XML tag parser. Functions for the start tags + helper functions
*
* Written by Moritz Bunkus <moritz@bunkus.org>.
*/
#include <ctype.h>
#include <errno.h>
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
#include <expat.h>
#include "base64.h"
#include "common.h"
#include "commonebml.h"
#include "mm_io.h"
#include "tagparser.h"
#include "xml_element_mapping.h"
#include <matroska/KaxTags.h>
#include <matroska/KaxTag.h>
using namespace std;
using namespace libebml;
using namespace libmatroska;
typedef struct {
XML_Parser parser;
const char *file_name;
int depth;
bool done_reading, data_allowed;
string *bin;
vector<EbmlElement *> *parents;
vector<int> *parent_idxs;
KaxTags *tags;
jmp_buf parse_error_jmp;
string *parse_error_msg;
} parser_data_t;
#define parent_elt (*((parser_data_t *)pdata)->parents) \
[((parser_data_t *)pdata)->parents->size() - 1]
#define parent_name _parent_name(parent_elt)
#define CPDATA (parser_data_t *)pdata
static const char *
_parent_name(EbmlElement *e) {
int i;
for (i = 0; tag_elements[i].name != NULL; i++)
if (tag_elements[i].id == e->Generic().GlobalId)
return tag_elements[i].name;
return "(none)";
}
static void
tperror(parser_data_t *pdata,
const char *fmt,
...) {
va_list ap;
string new_fmt;
char *new_string;
int len;
fix_format(fmt, new_fmt);
len = get_arg_len("Error: Tag parser failed for '%s', line %d, "
"column %d: ", pdata->file_name,
XML_GetCurrentLineNumber(pdata->parser),
XML_GetCurrentColumnNumber(pdata->parser));
va_start(ap, fmt);
len += get_varg_len(new_fmt.c_str(), ap);
new_string = (char *)safemalloc(len + 2);
sprintf(new_string, "Error: Tag parser failed for '%s', line %d, "
"column %d: ", pdata->file_name,
XML_GetCurrentLineNumber(pdata->parser),
XML_GetCurrentColumnNumber(pdata->parser));
vsprintf(&new_string[strlen(new_string)], new_fmt.c_str(), ap);
va_end(ap);
strcat(new_string, "\n");
*pdata->parse_error_msg = new_string;
safefree(new_string);
longjmp(pdata->parse_error_jmp, 1);
}
static void
el_get_uint(parser_data_t *pdata,
EbmlElement *el,
uint64_t min_value = 0,
bool is_bool = false) {
int64 value;
strip(*pdata->bin);
if (!parse_int(pdata->bin->c_str(), value))
tperror(pdata, "Expected an unsigned integer but found '%s'.",
pdata->bin->c_str());
if (value < min_value)
tperror(pdata, "Unsigned integer (%lld) is too small. Mininum value is "
"%lld.", value, min_value);
if (is_bool && (value > 0))
value = 1;
*(static_cast<EbmlUInteger *>(el)) = value;
}
static void
el_get_string(parser_data_t *pdata,
EbmlElement *el) {
strip(*pdata->bin);
if (pdata->bin->length() == 0)
tperror(pdata, "Expected a string but found only whitespaces.");
*(static_cast<EbmlString *>(el)) = pdata->bin->c_str();
}
static void
el_get_utf8string(parser_data_t *pdata,
EbmlElement *el) {
strip(*pdata->bin);
if (pdata->bin->length() == 0)
tperror(pdata, "Expected a string but found only whitespaces.");
*(static_cast<EbmlUnicodeString *>(el)) =
cstrutf8_to_UTFstring(pdata->bin->c_str());
}
static void
el_get_binary(parser_data_t *pdata,
EbmlElement *el) {
int64_t result;
binary *buffer;
mm_io_c *io;
result = 0;
buffer = NULL;
strip(*pdata->bin, true);
if (pdata->bin->length() == 0)
tperror(pdata, "Found neither Base64 encoded data nor '@file' to read "
"binary data from.");
if ((*pdata->bin)[0] == '@') {
if (pdata->bin->length() == 1)
tperror(pdata, "No filename found after the '@'.");
try {
io = new mm_io_c(&(pdata->bin->c_str())[1], MODE_READ);
io->setFilePointer(0, seek_end);
result = io->getFilePointer();
io->setFilePointer(0, seek_beginning);
if (result <= 0)
tperror(pdata, "The file '%s' is empty.", &(pdata->bin->c_str())[1]);
buffer = new binary[result];
io->read(buffer, result);
delete io;
} catch(...) {
tperror(pdata, "Could not open/read the file '%s'.",
&(pdata->bin->c_str())[1]);
}
} else {
buffer = new binary[pdata->bin->length() / 4 * 3 + 1];
result = base64_decode(*pdata->bin, (unsigned char *)buffer);
if (result < 0)
tperror(pdata, "Could not decode the Base64 encoded data - it seems to "
"be broken.");
}
(static_cast<EbmlBinary *>(el))->SetBuffer(buffer, result);
}
static void
add_data(void *user_data,
const XML_Char *s,
int len) {
parser_data_t *pdata;
int i;
pdata = (parser_data_t *)user_data;
if (!pdata->data_allowed) {
for (i = 0; i < len; i++)
if (!isblanktab(s[i]) && !iscr(s[i]))
tperror(pdata, "Data is not allowed inside <%s>.", parent_name);
return;
}
if (pdata->bin == NULL)
pdata->bin = new string;
for (i = 0; i < len; i++)
(*pdata->bin) += s[i];
}
static void
start_element(void *user_data,
const char *name,
const char **atts) {
parser_data_t *pdata;
pdata = (parser_data_t *)user_data;
if (atts[0] != NULL)
tperror(pdata, "Attributes are not allowed.");
if (pdata->data_allowed)
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
parent_name);
pdata->data_allowed = false;
if (pdata->bin != NULL)
die("start_element: pdata->bin != NULL");
if (pdata->depth == 0) {
if (pdata->done_reading)
tperror(pdata, "More than one root element found.");
if (strcmp(name, "Tags"))
tperror(pdata, "Root element must be <Tags>.");
pdata->parents->push_back(pdata->tags);
pdata->parent_idxs->push_back(0);
} else {
EbmlElement *e;
EbmlMaster *m;
int elt_idx, parent_idx, i;
bool found;
parent_idx = (*pdata->parent_idxs)[pdata->parent_idxs->size() - 1];
elt_idx = parent_idx;
found = false;
while (tag_elements[elt_idx].name != NULL) {
if (!strcmp(tag_elements[elt_idx].name, name)) {
found = true;
break;
}
elt_idx++;
}
if (!found)
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
tag_elements[parent_idx].name);
const EbmlSemanticContext &context =
find_ebml_callbacks(KaxTags::ClassInfos,
tag_elements[parent_idx].id).Context;
found = false;
for (i = 0; i < context.Size; i++)
if (tag_elements[elt_idx].id ==
context.MyTable[i].GetCallbacks.GlobalId) {
found = true;
break;
}
if (!found)
tperror(pdata, "<%s> is not a valid child element of <%s>.", name,
tag_elements[parent_idx].name);
const EbmlSemantic &semantic =
find_ebml_semantic(KaxTags::ClassInfos,
tag_elements[elt_idx].id);
if (semantic.Unique) {
m = dynamic_cast<EbmlMaster *>(parent_elt);
assert(m != NULL);
for (i = 0; i < m->ListSize(); i++)
if ((*m)[i]->Generic().GlobalId == tag_elements[elt_idx].id)
tperror(pdata, "Only one instance of <%s> is allowed beneath <%s>.",
name, tag_elements[parent_idx].name);
}
e = create_ebml_element(KaxTags::ClassInfos,
tag_elements[elt_idx].id);
assert(e != NULL);
m = dynamic_cast<EbmlMaster *>(parent_elt);
assert(m != NULL);
m->PushElement(*e);
if (tag_elements[elt_idx].start_hook != NULL)
tag_elements[elt_idx].start_hook(pdata);
pdata->parents->push_back(e);
pdata->parent_idxs->push_back(elt_idx);
pdata->data_allowed = tag_elements[elt_idx].type != ebmlt_master;
}
(pdata->depth)++;
}
static void
end_element(void *user_data,
const char *name) {
parser_data_t *pdata;
EbmlMaster *m;
pdata = (parser_data_t *)user_data;
if (pdata->data_allowed && (pdata->bin == NULL))
tperror(pdata, "Element <%s> does not contain any data.", name);
if (pdata->depth == 1) {
m = static_cast<EbmlMaster *>(parent_elt);
if (m->ListSize() == 0)
tperror(pdata, "At least one <EditionEntry> element is needed.");
} else {
int elt_idx;
bool found;
found = false;
for (elt_idx = 0; tag_elements[elt_idx].name != NULL; elt_idx++)
if (!strcmp(tag_elements[elt_idx].name, name)) {
found = true;
break;
}
assert(found);
switch (tag_elements[elt_idx].type) {
case ebmlt_master:
break;
case ebmlt_uint:
el_get_uint(pdata, parent_elt, tag_elements[elt_idx].min_value,
false);
break;
case ebmlt_bool:
el_get_uint(pdata, parent_elt, 0, true);
break;
case ebmlt_string:
el_get_string(pdata, parent_elt);
break;
case ebmlt_ustring:
el_get_utf8string(pdata, parent_elt);
break;
case ebmlt_binary:
el_get_binary(pdata, parent_elt);
break;
default:
assert(0);
}
if (tag_elements[elt_idx].end_hook != NULL)
tag_elements[elt_idx].end_hook(pdata);
}
if (pdata->bin != NULL) {
delete pdata->bin;
pdata->bin = NULL;
}
pdata->data_allowed = false;
pdata->depth--;
pdata->parents->pop_back();
pdata->parent_idxs->pop_back();
}
static void
end_simple_tag(void *pdata) {
KaxTagSimple *simple;
simple = dynamic_cast<KaxTagSimple *>(parent_elt);
assert(simple != NULL);
if ((FINDFIRST(simple, KaxTagString) != NULL) &&
(FINDFIRST(simple, KaxTagBinary) != NULL))
tperror(CPDATA, "Only one of <String> and <Binary> may be used beneath "
"<Simple> but not both at the same time.");
}
void
parse_xml_tags(const char *name,
KaxTags *tags) {
char buffer[5000];
int len, done, i;
parser_data_t *pdata;
mm_io_c *io;
XML_Parser parser;
XML_Error xerror;
char *emsg;
io = NULL;
try {
io = new mm_io_c(name, MODE_READ);
} catch(...) {
mxerror("Could not open '%s' for reading.\n", name);
}
done = 0;
for (i = 0; tag_elements[i].name != NULL; i++) {
tag_elements[i].start_hook = NULL;
tag_elements[i].end_hook = NULL;
}
tag_elements[tag_element_map_index("Simple")].end_hook = end_simple_tag;
parser = XML_ParserCreate(NULL);
pdata = (parser_data_t *)safemalloc(sizeof(parser_data_t));
memset(pdata, 0, sizeof(parser_data_t));
pdata->parser = parser;
pdata->file_name = name;
pdata->parents = new vector<EbmlElement *>;
pdata->parent_idxs = new vector<int>;
pdata->parse_error_msg = new string;
pdata->tags = tags;
XML_SetUserData(parser, pdata);
XML_SetElementHandler(parser, start_element, end_element);
XML_SetCharacterDataHandler(parser, add_data);
if (setjmp(pdata->parse_error_jmp) == 1)
mxerror(pdata->parse_error_msg->c_str());
do {
len = io->read(buffer, 5000);
if (len != 5000)
done = 1;
if (XML_Parse(parser, buffer, len, done) == 0) {
xerror = XML_GetErrorCode(parser);
if (xerror == XML_ERROR_INVALID_TOKEN)
emsg = " Remember that special characters like &, <, > and \" "
"must be escaped in the usual HTML way: &amp; for '&', "
"&lt; for '<', &gt; for '>' and &quot; for '\"'.";
else
emsg = "";
mxerror("XML parser error at line %d of '%s': %s.%s Aborting.\n",
XML_GetCurrentLineNumber(parser), name,
XML_ErrorString(xerror), emsg);
}
} while (!done);
delete io;
XML_ParserFree(parser);
delete pdata->parents;
delete pdata->parent_idxs;
safefree(pdata);
}
void
fix_mandatory_tag_elements(EbmlElement *e) {
if (dynamic_cast<KaxTagSimple *>(e) != NULL) {
KaxTagSimple &s = *static_cast<KaxTagSimple *>(e);
GetChild<KaxTagLangue>(s);
GetChild<KaxTagDefault>(s);
} else if (dynamic_cast<KaxTagTargets *>(e) != NULL) {
KaxTagTargets &t = *static_cast<KaxTagTargets *>(e);
GetChild<KaxTagTargetTypeValue>(t);
}
if (dynamic_cast<EbmlMaster *>(e) != NULL) {
EbmlMaster *m;
int i;
m = static_cast<EbmlMaster *>(e);
for (i = 0; i < m->ListSize(); i++)
fix_mandatory_tag_elements((*m)[i]);
}
}

View File

@ -17,7 +17,7 @@ T_016cuesheet:701de008087d3e3be9ad34621df8d6c2:passed:20040825-175700
T_017chapters:d123294267704fd88f6d730a6ad5f970-3bf90270c5b8abcee3c68b23ff038176:passed:20040825-175700
T_018attachments:de6a7f61b9c707dbf8b635abdc95f6f6-61bd952ae52eb9b4cd331dc805e3af0c:passed:20040825-175700
T_019attachments2:73eee65d12723bc0d7e3ebfbd9b7c27e-5326411491c8d8f14f09efac0c134d5f-73eee65d12723bc0d7e3ebfbd9b7c27e-5a6e6eeea02af14a78361a7032228c2a:passed:20040825-175700
T_020languages:654d90f508b44b4cf3d2a44ffb12dae0:passed:20040825-234208
T_020languages:654d90f508b44b4cf3d2a44ffb12dae0:failed:20040825-234208
T_021aspect_ratio:22bd828492ccc4a16a8918d6535b8f26-aaf9ad30cf4d23219088df35fb18f396:passed:20040825-234244
T_022display_dimensions:d8918ad515a670b30f2d927e29034675:passed:20040825-234339
T_023no_x:b934ba7d0e44d79c7a4a020da90cfc3a-a4db5d036681d15ef61e7b2c099e09bc-c95a138583be3bc614ab57e6cbbb14cd:passed:20040825-234343