mirror of
https://gitlab.com/mbunkus/mkvtoolnix.git
synced 2024-12-24 20:01:53 +00:00
Unified the chapter and tag XML output code just like the parser code for both was unified a long time ago. Also output binary content of XML elements in hex format.
This commit is contained in:
parent
5d91d53bd9
commit
3bb0591e5c
@ -21,10 +21,10 @@
|
||||
|
||||
#include <matroska/KaxChapters.h>
|
||||
|
||||
#include "chapters.h"
|
||||
#include "commonebml.h"
|
||||
#include "mm_io.h"
|
||||
#include "chapters.h"
|
||||
#include "xml_element_mapping.h"
|
||||
#include "xml_element_writer.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace libmatroska;
|
||||
@ -203,16 +203,8 @@ write_chapters_simple(int &chapter_num,
|
||||
|
||||
// {{{ XML chapter output
|
||||
|
||||
typedef struct {
|
||||
int level;
|
||||
int parent_idx;
|
||||
int elt_idx;
|
||||
EbmlElement *e;
|
||||
mm_io_c *out;
|
||||
} chapter_writer_cb_t;
|
||||
|
||||
static void
|
||||
pt(chapter_writer_cb_t *cb,
|
||||
pt(xml_writer_cb_t *cb,
|
||||
const char *tag) {
|
||||
int i;
|
||||
|
||||
@ -221,91 +213,6 @@ pt(chapter_writer_cb_t *cb,
|
||||
cb->out->printf("%s", tag);
|
||||
}
|
||||
|
||||
static void
|
||||
write_xml_element_rec(int level,
|
||||
int parent_idx,
|
||||
EbmlElement *e,
|
||||
mm_io_c *out) {
|
||||
EbmlMaster *m;
|
||||
int elt_idx, i;
|
||||
bool found;
|
||||
string s;
|
||||
|
||||
elt_idx = parent_idx;
|
||||
found = false;
|
||||
while ((chapter_elements[elt_idx].name != NULL) &&
|
||||
(chapter_elements[elt_idx].level >=
|
||||
chapter_elements[parent_idx].level)) {
|
||||
if (chapter_elements[elt_idx].id == e->Generic().GlobalId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
elt_idx++;
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
|
||||
if (!found) {
|
||||
out->printf("<!-- Unknown element '%s' -->\n", e->Generic().DebugName);
|
||||
return;
|
||||
}
|
||||
|
||||
out->printf("<%s>", chapter_elements[elt_idx].name);
|
||||
switch (chapter_elements[elt_idx].type) {
|
||||
case EBMLT_MASTER:
|
||||
out->printf("\n");
|
||||
m = dynamic_cast<EbmlMaster *>(e);
|
||||
assert(m != NULL);
|
||||
for (i = 0; i < m->ListSize(); i++)
|
||||
write_xml_element_rec(level + 1, elt_idx, (*m)[i], out);
|
||||
|
||||
if (chapter_elements[elt_idx].end_hook != NULL) {
|
||||
chapter_writer_cb_t cb;
|
||||
|
||||
cb.level = level;
|
||||
cb.parent_idx = parent_idx;
|
||||
cb.elt_idx = elt_idx;
|
||||
cb.e = e;
|
||||
cb.out = out;
|
||||
|
||||
chapter_elements[elt_idx].end_hook(&cb);
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
out->printf("</%s>\n", chapter_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_UINT:
|
||||
case EBMLT_BOOL:
|
||||
out->printf("%llu</%s>\n", uint64(*dynamic_cast<EbmlUInteger *>(e)),
|
||||
chapter_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_STRING:
|
||||
s = escape_xml(string(*dynamic_cast<EbmlString *>(e)));
|
||||
out->printf("%s</%s>\n", s.c_str(), chapter_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_USTRING:
|
||||
s = UTFstring_to_cstrutf8(UTFstring(*static_cast
|
||||
<EbmlUnicodeString *>(e)).c_str());
|
||||
s = escape_xml(s);
|
||||
out->printf("%s</%s>\n", s.c_str(), chapter_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_TIME:
|
||||
out->printf(FMT_TIMECODEN "</%s>\n",
|
||||
ARG_TIMECODEN(uint64(*dynamic_cast<EbmlUInteger *>(e))),
|
||||
chapter_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cet_index(const char *name) {
|
||||
int i;
|
||||
@ -321,9 +228,9 @@ cet_index(const char *name) {
|
||||
static void
|
||||
end_write_chapter_atom(void *data) {
|
||||
KaxChapterAtom *atom;
|
||||
chapter_writer_cb_t *cb;
|
||||
xml_writer_cb_t *cb;
|
||||
|
||||
cb = (chapter_writer_cb_t *)data;
|
||||
cb = (xml_writer_cb_t *)data;
|
||||
atom = dynamic_cast<KaxChapterAtom *>(cb->e);
|
||||
assert(atom != NULL);
|
||||
if (FINDFIRST(atom, KaxChapterTimeStart) == NULL)
|
||||
@ -333,9 +240,9 @@ end_write_chapter_atom(void *data) {
|
||||
static void
|
||||
end_write_chapter_display(void *data) {
|
||||
KaxChapterDisplay *display;
|
||||
chapter_writer_cb_t *cb;
|
||||
xml_writer_cb_t *cb;
|
||||
|
||||
cb = (chapter_writer_cb_t *)data;
|
||||
cb = (xml_writer_cb_t *)data;
|
||||
display = dynamic_cast<KaxChapterDisplay *>(cb->e);
|
||||
assert(display != NULL);
|
||||
if (FINDFIRST(display, KaxChapterString) == NULL)
|
||||
@ -359,7 +266,7 @@ write_chapters_xml(KaxChapters *chapters,
|
||||
end_write_chapter_display;
|
||||
|
||||
for (i = 0; i < chapters->ListSize(); i++)
|
||||
write_xml_element_rec(1, 0, (*chapters)[i], out);
|
||||
write_xml_element_rec(1, 0, (*chapters)[i], out, chapter_elements);
|
||||
}
|
||||
|
||||
// }}}
|
||||
|
@ -14,163 +14,13 @@
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <matroska/KaxTag.h>
|
||||
#include <matroska/KaxTags.h>
|
||||
#include <matroska/KaxTagMulti.h>
|
||||
|
||||
#include "xml_element_writer.h"
|
||||
|
||||
using namespace libmatroska;
|
||||
using namespace std;
|
||||
|
||||
#include "base64.h"
|
||||
#include "common.h"
|
||||
#include "commonebml.h"
|
||||
#include "matroska.h"
|
||||
#include "mm_io.h"
|
||||
#include "xml_element_mapping.h"
|
||||
|
||||
static void
|
||||
print_binary(int level,
|
||||
const char *name,
|
||||
EbmlElement *e,
|
||||
mm_io_c *out) {
|
||||
EbmlBinary *b;
|
||||
string s;
|
||||
int i, idx, old_idx;
|
||||
|
||||
b = (EbmlBinary *)e;
|
||||
s = base64_encode((const unsigned char *)b->GetBuffer(), b->GetSize(), true,
|
||||
72 - level - 2);
|
||||
if (s[s.length() - 1] == '\n')
|
||||
s.erase(s.length() - 1);
|
||||
|
||||
if ((level * 2 + 2 * strlen(name) + 2 + 3 + s.length()) <= 78) {
|
||||
out->printf("%s</%s>\n", s.c_str(), name);
|
||||
return;
|
||||
}
|
||||
|
||||
out->printf("\n");
|
||||
|
||||
for (i = 0; i < (level + 2); i++)
|
||||
out->printf(" ");
|
||||
|
||||
old_idx = 0;
|
||||
for (idx = 0; idx < s.length(); idx++)
|
||||
if (s[idx] == '\n') {
|
||||
out->printf("%s\n", s.substr(old_idx, idx - old_idx).c_str());
|
||||
for (i = 0; i < (level + 2); i++)
|
||||
out->printf(" ");
|
||||
old_idx = idx + 1;
|
||||
}
|
||||
|
||||
if (old_idx < s.length())
|
||||
out->printf("%s", s.substr(old_idx).c_str());
|
||||
|
||||
out->printf("\n");
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
out->printf("</%s>\n", name);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int level;
|
||||
int parent_idx;
|
||||
int elt_idx;
|
||||
EbmlElement *e;
|
||||
} tag_writer_cb_t;
|
||||
|
||||
static void
|
||||
write_xml_element_rec(int level,
|
||||
int parent_idx,
|
||||
EbmlElement *e,
|
||||
mm_io_c *out) {
|
||||
EbmlMaster *m;
|
||||
int elt_idx, i;
|
||||
bool found;
|
||||
string s;
|
||||
|
||||
elt_idx = parent_idx;
|
||||
found = false;
|
||||
while ((tag_elements[elt_idx].name != NULL) &&
|
||||
(tag_elements[elt_idx].level >=
|
||||
tag_elements[parent_idx].level)) {
|
||||
if (tag_elements[elt_idx].id == e->Generic().GlobalId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
elt_idx++;
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
|
||||
if (!found) {
|
||||
out->printf("<!-- Unknown element '%s' -->\n", e->Generic().DebugName);
|
||||
return;
|
||||
}
|
||||
|
||||
out->printf("<%s>", tag_elements[elt_idx].name);
|
||||
switch (tag_elements[elt_idx].type) {
|
||||
case EBMLT_MASTER:
|
||||
out->printf("\n");
|
||||
m = dynamic_cast<EbmlMaster *>(e);
|
||||
assert(m != NULL);
|
||||
for (i = 0; i < m->ListSize(); i++)
|
||||
write_xml_element_rec(level + 1, elt_idx, (*m)[i], out);
|
||||
|
||||
if (tag_elements[elt_idx].end_hook != NULL) {
|
||||
tag_writer_cb_t cb;
|
||||
|
||||
cb.level = level;
|
||||
cb.parent_idx = parent_idx;
|
||||
cb.elt_idx = elt_idx;
|
||||
cb.e = e;
|
||||
|
||||
tag_elements[elt_idx].end_hook(&cb);
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
out->printf("</%s>\n", tag_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_UINT:
|
||||
case EBMLT_BOOL:
|
||||
out->printf("%llu</%s>\n", uint64(*dynamic_cast<EbmlUInteger *>(e)),
|
||||
tag_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_STRING:
|
||||
s = escape_xml(string(*dynamic_cast<EbmlString *>(e)));
|
||||
out->printf("%s</%s>\n", s.c_str(), tag_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_USTRING:
|
||||
s = UTFstring_to_cstrutf8(UTFstring(*static_cast
|
||||
<EbmlUnicodeString *>(e)).c_str());
|
||||
s = escape_xml(s);
|
||||
out->printf("%s</%s>\n", s.c_str(), tag_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_TIME:
|
||||
out->printf(FMT_TIMECODEN "</%s>\n",
|
||||
ARG_TIMECODEN(uint64(*dynamic_cast<EbmlUInteger *>(e))),
|
||||
tag_elements[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_BINARY:
|
||||
print_binary(level, tag_elements[elt_idx].name, e, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
write_tags_xml(KaxTags &tags,
|
||||
mm_io_c *out) {
|
||||
@ -182,5 +32,5 @@ write_tags_xml(KaxTags &tags,
|
||||
}
|
||||
|
||||
for (i = 0; i < tags.ListSize(); i++)
|
||||
write_xml_element_rec(1, 0, tags[i], out);
|
||||
write_xml_element_rec(1, 0, tags[i], out, tag_elements);
|
||||
}
|
||||
|
@ -15,8 +15,6 @@
|
||||
#ifndef __TAGWRITER_H
|
||||
#define __TAGWRITER_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <matroska/KaxTags.h>
|
||||
#include <matroska/KaxTag.h>
|
||||
|
||||
|
153
src/common/xml_element_writer.cpp
Normal file
153
src/common/xml_element_writer.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
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 chapter writer functions
|
||||
|
||||
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#include <ebml/EbmlBinary.h>
|
||||
#include <ebml/EbmlMaster.h>
|
||||
#include <ebml/EbmlSInteger.h>
|
||||
#include <ebml/EbmlString.h>
|
||||
#include <ebml/EbmlUInteger.h>
|
||||
#include <ebml/EbmlUnicodeString.h>
|
||||
#include <ebml/EbmlDate.h>
|
||||
|
||||
#include "base64.h"
|
||||
#include "common.h"
|
||||
#include "commonebml.h"
|
||||
#include "mm_io.h"
|
||||
#include "xml_element_writer.h"
|
||||
|
||||
using namespace libebml;
|
||||
|
||||
static void
|
||||
print_binary(int level,
|
||||
const char *name,
|
||||
EbmlElement *e,
|
||||
mm_io_c *out) {
|
||||
EbmlBinary *b;
|
||||
const unsigned char *p;
|
||||
string s;
|
||||
int i, size;
|
||||
|
||||
b = (EbmlBinary *)e;
|
||||
p = (const unsigned char *)b->GetBuffer();
|
||||
size = b->GetSize();
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((i % 16) != 0)
|
||||
s += " ";
|
||||
s += mxsprintf("%02x", *p);
|
||||
++p;
|
||||
if ((((i + 1) % 16) == 0) && ((i + 1) < size))
|
||||
s += mxsprintf("\n%*s", (level + 1) * 2, "");
|
||||
}
|
||||
|
||||
if ((level * 2 + 2 * strlen(name) + 2 + 3 + s.length()) <= 78)
|
||||
out->printf("%s</%s>\n", s.c_str(), name);
|
||||
else
|
||||
out->printf("\n%*s%s\n%*s</%s>\n", (level + 1) * 2, "", s.c_str(),
|
||||
level * 2, "", name);
|
||||
}
|
||||
|
||||
void
|
||||
write_xml_element_rec(int level,
|
||||
int parent_idx,
|
||||
EbmlElement *e,
|
||||
mm_io_c *out,
|
||||
const parser_element_t *element_map) {
|
||||
EbmlMaster *m;
|
||||
int elt_idx, i;
|
||||
bool found;
|
||||
string s;
|
||||
|
||||
elt_idx = parent_idx;
|
||||
found = false;
|
||||
while ((element_map[elt_idx].name != NULL) &&
|
||||
(element_map[elt_idx].level >=
|
||||
element_map[parent_idx].level)) {
|
||||
if (element_map[elt_idx].id == e->Generic().GlobalId) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
elt_idx++;
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
|
||||
if (!found) {
|
||||
out->printf("<!-- Unknown element '%s' -->\n", e->Generic().DebugName);
|
||||
return;
|
||||
}
|
||||
|
||||
out->printf("<%s%s>", element_map[elt_idx].name,
|
||||
element_map[elt_idx].type == EBMLT_BINARY ?
|
||||
" format=\"hex\"" : "");
|
||||
switch (element_map[elt_idx].type) {
|
||||
case EBMLT_MASTER:
|
||||
out->printf("\n");
|
||||
m = dynamic_cast<EbmlMaster *>(e);
|
||||
assert(m != NULL);
|
||||
for (i = 0; i < m->ListSize(); i++)
|
||||
write_xml_element_rec(level + 1, elt_idx, (*m)[i], out, element_map);
|
||||
|
||||
if (element_map[elt_idx].end_hook != NULL) {
|
||||
xml_writer_cb_t cb;
|
||||
|
||||
cb.level = level;
|
||||
cb.parent_idx = parent_idx;
|
||||
cb.elt_idx = elt_idx;
|
||||
cb.e = e;
|
||||
cb.out = out;
|
||||
|
||||
element_map[elt_idx].end_hook(&cb);
|
||||
}
|
||||
|
||||
for (i = 0; i < level; i++)
|
||||
out->printf(" ");
|
||||
out->printf("</%s>\n", element_map[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_UINT:
|
||||
case EBMLT_BOOL:
|
||||
out->printf("%llu</%s>\n", uint64(*dynamic_cast<EbmlUInteger *>(e)),
|
||||
element_map[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_STRING:
|
||||
s = escape_xml(string(*dynamic_cast<EbmlString *>(e)));
|
||||
out->printf("%s</%s>\n", s.c_str(), element_map[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_USTRING:
|
||||
s = UTFstring_to_cstrutf8(UTFstring(*static_cast
|
||||
<EbmlUnicodeString *>(e)).c_str());
|
||||
s = escape_xml(s);
|
||||
out->printf("%s</%s>\n", s.c_str(), element_map[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_TIME:
|
||||
out->printf(FMT_TIMECODEN "</%s>\n",
|
||||
ARG_TIMECODEN(uint64(*dynamic_cast<EbmlUInteger *>(e))),
|
||||
element_map[elt_idx].name);
|
||||
break;
|
||||
|
||||
case EBMLT_BINARY:
|
||||
print_binary(level, element_map[elt_idx].name, e, out);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
42
src/common/xml_element_writer.h
Normal file
42
src/common/xml_element_writer.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 chapter writer functions
|
||||
|
||||
Written by Moritz Bunkus <moritz@bunkus.org>.
|
||||
*/
|
||||
|
||||
#ifndef __XML_ELEMENT_WRITER_H
|
||||
#define __XML_ELEMENT_WRITER_H
|
||||
|
||||
#include "xml_element_parser.h"
|
||||
|
||||
namespace libebml {
|
||||
class EbmlElement;
|
||||
};
|
||||
|
||||
using namespace libebml;
|
||||
|
||||
class mm_io_c;
|
||||
|
||||
struct xml_writer_cb_t {
|
||||
int level;
|
||||
int parent_idx;
|
||||
int elt_idx;
|
||||
EbmlElement *e;
|
||||
mm_io_c *out;
|
||||
};
|
||||
|
||||
void MTX_DLL_API
|
||||
write_xml_element_rec(int level, int parent_idx,
|
||||
EbmlElement *e, mm_io_c *out,
|
||||
const parser_element_t *element_map);
|
||||
|
||||
#endif // __XML_ELEMENT_WRITER_H
|
Loading…
Reference in New Issue
Block a user