Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Open sidebar
Xiph.Org
Icecast-Server
Commits
903ac2f1
Commit
903ac2f1
authored
Jun 07, 2018
by
Philipp Schafft
🦁
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Feature: Added fundamental report xml handling
parent
5df79580
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
669 additions
and
0 deletions
+669
-0
src/Makefile.am
src/Makefile.am
+2
-0
src/icecasttypes.h
src/icecasttypes.h
+7
-0
src/reportxml.c
src/reportxml.c
+606
-0
src/reportxml.h
src/reportxml.h
+54
-0
No files found.
src/Makefile.am
View file @
903ac2f1
...
...
@@ -31,6 +31,7 @@ noinst_HEADERS = \
tls.h
\
refobject.h
\
module.h
\
reportxml.h
\
event.h
\
event_log.h
\
event_exec.h
\
...
...
@@ -72,6 +73,7 @@ icecast_SOURCES = \
tls.c
\
refobject.c
\
module.c
\
reportxml.c
\
format.c
\
format_ogg.c
\
format_mp3.c
\
...
...
src/icecasttypes.h
View file @
903ac2f1
...
...
@@ -98,6 +98,11 @@ typedef struct module_tag module_t;
typedef
struct
module_container_tag
module_container_t
;
/* ---[ reportxml.[ch] ]--- */
typedef
struct
reportxml_tag
reportxml_t
;
typedef
struct
reportxml_node_tag
reportxml_node_t
;
/* ---[ refobject.[ch] ]--- */
typedef
struct
refobject_base_tag
refobject_base_t
;
...
...
@@ -107,6 +112,8 @@ typedef union __attribute__ ((__transparent_union__)) {
refobject_base_t
*
refobject_base
;
module_t
*
module
;
module_container_t
*
module_container
;
reportxml_t
*
reportxml
;
reportxml_node_t
*
reportxml_node
;
}
refobject_t
;
#else
typedef
void
*
refobject_t
;
...
...
src/reportxml.c
0 → 100644
View file @
903ac2f1
/* Icecast
*
* This program is distributed under the GNU General Public License, version 2.
* A copy of this license is included with this source.
*
* Copyright 2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
*/
/**
* Special fast event functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include "reportxml.h"
#include "refobject.h"
/* For XMLSTR() */
#include "cfgfile.h"
#include "logging.h"
#define CATMODULE "reportxml"
struct
reportxml_tag
{
refobject_base_t
__base
;
reportxml_node_t
*
root
;
};
struct
reportxml_node_tag
{
refobject_base_t
__base
;
xmlNodePtr
xmlnode
;
reportxml_node_type_t
type
;
reportxml_node_t
**
childs
;
size_t
childs_len
;
char
*
content
;
};
struct
nodeattr
;
struct
nodeattr
{
const
char
*
name
;
const
char
*
type
;
const
char
*
def
;
int
required
;
int
(
*
checker
)(
const
struct
nodeattr
*
attr
,
const
char
*
str
);
const
char
*
values
[
32
];
};
struct
nodedef
{
reportxml_node_type_t
type
;
const
char
*
name
;
int
has_content
;
const
struct
nodeattr
*
attr
[
12
];
};
static
const
struct
nodeattr
__attr__eol
[
1
]
=
{{
NULL
,
NULL
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_version
[
1
]
=
{{
"version"
,
"CDATA"
,
"0.0.1"
,
1
,
NULL
,
{
"0.0.1"
,
NULL
}}};
static
const
struct
nodeattr
__attr_xmlns
[
1
]
=
{{
"xmlns"
,
"URI"
,
"xxx"
,
1
,
NULL
,
{
"xxx"
,
NULL
}}};
static
const
struct
nodeattr
__attr_id
[
1
]
=
{{
"id"
,
"ID"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_definition
[
1
]
=
{{
"definition"
,
"UUID"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_akindof
[
1
]
=
{{
"akindof"
,
"UUIDs"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_lang
[
1
]
=
{{
"lang"
,
"LanguageCode"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_dir
[
1
]
=
{{
"dir"
,
NULL
,
NULL
,
0
,
NULL
,
{
"ltr"
,
"rtl"
,
NULL
}}};
static
const
struct
nodeattr
__attr_template
[
1
]
=
{{
"template"
,
"UUID"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_defines
[
1
]
=
{{
"defines"
,
"UUID"
,
NULL
,
1
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_function
[
1
]
=
{{
"function"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_filename
[
1
]
=
{{
"filename"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_line
[
1
]
=
{{
"line"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_binary
[
1
]
=
{{
"binary"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_offset
[
1
]
=
{{
"offset"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_absolute
[
1
]
=
{{
"absolute"
,
"iso8601"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_relative
[
1
]
=
{{
"relative"
,
"iso8601"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_name
[
1
]
=
{{
"name"
,
"CDATA"
,
NULL
,
1
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_member
[
1
]
=
{{
"member"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_value
[
1
]
=
{{
"value"
,
"CDATA"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr_state
[
1
]
=
{{
"state"
,
NULL
,
"set"
,
1
,
NULL
,
{
"declared"
,
"set"
,
"uninitialized"
,
"missing"
,
NULL
}}};
static
const
struct
nodeattr
__attr_href
[
1
]
=
{{
"href"
,
"URI"
,
NULL
,
0
,
NULL
,
{
NULL
}}};
static
const
struct
nodeattr
__attr__action_type
[
1
]
=
{{
"type"
,
NULL
,
NULL
,
1
,
NULL
,
{
"retry"
,
"choice"
,
"see-other"
,
"authenticate"
,
"pay"
,
"change-protocol"
,
"slow-down"
,
"ask-user"
,
"ask-admin"
,
"bug"
,
NULL
}}};
static
const
struct
nodeattr
__attr__resource_type
[
1
]
=
{{
"type"
,
NULL
,
NULL
,
1
,
NULL
,
{
"actor"
,
"manipulation-target"
,
"helper"
,
"related"
,
"result"
,
"parameter"
,
NULL
}}};
static
const
struct
nodeattr
__attr__value_type
[
1
]
=
{{
"type"
,
NULL
,
NULL
,
1
,
NULL
,
{
"null"
,
"int"
,
"float"
,
"uuid"
,
"string"
,
"structure"
,
"uri"
,
"pointer"
,
"version"
,
"protocol"
,
"username"
,
"password"
,
NULL
}}};
static
const
struct
nodeattr
__attr__reference_type
[
1
]
=
{{
"type"
,
NULL
,
NULL
,
1
,
NULL
,
{
"documentation"
,
"log"
,
"report"
,
"related"
,
NULL
}}};
/* Helper:
* grep '^ *REPORTXML_NODE_TYPE_' reportxml.h | sed 's/^\( *REPORTXML_NODE_TYPE_\([^,]*\)\),*$/\1 \2/;' | while read l s; do c=$(tr A-Z a-z <<<"$s"); printf " {%-32s \"%-16s 0, {__attr__eol}},\n" "$l," "$c\","; done
*/
#define __BASIC_ELEMENT __attr_id, __attr_definition, __attr_akindof
static
const
struct
nodedef
__nodedef
[]
=
{
{
REPORTXML_NODE_TYPE_REPORT
,
"report"
,
0
,
{
__attr_id
,
__attr_version
,
__attr_xmlns
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_DEFINITION
,
"definition"
,
0
,
{
__BASIC_ELEMENT
,
__attr_template
,
__attr_defines
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_INCIDENT
,
"incident"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_STATE
,
"state"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_BACKTRACE
,
"backtrace"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_POSITION
,
"position"
,
0
,
{
__BASIC_ELEMENT
,
__attr_function
,
__attr_filename
,
__attr_line
,
__attr_binary
,
__attr_offset
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_MORE
,
"more"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_FIX
,
"fix"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_ACTION
,
"action"
,
0
,
{
__BASIC_ELEMENT
,
__attr__action_type
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_REASON
,
"reason"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_TEXT
,
"text"
,
1
,
{
__BASIC_ELEMENT
,
__attr_lang
,
__attr_dir
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_TIMESTAMP
,
"timestamp"
,
0
,
{
__BASIC_ELEMENT
,
__attr_absolute
,
__attr_relative
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_RESOURCE
,
"resource"
,
0
,
{
__BASIC_ELEMENT
,
__attr__resource_type
,
__attr_name
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_VALUE
,
"value"
,
0
,
{
__BASIC_ELEMENT
,
__attr_member
,
__attr_value
,
__attr_state
,
__attr__value_type
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_REFERENCE
,
"reference"
,
0
,
{
__BASIC_ELEMENT
,
__attr__reference_type
,
__attr_href
,
__attr__eol
}},
{
REPORTXML_NODE_TYPE_EXTENSION
,
"extension"
,
0
,
{
__BASIC_ELEMENT
,
__attr__eol
}},
};
static
const
struct
nodedef
*
__get_nodedef
(
reportxml_node_type_t
type
)
{
size_t
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
__nodedef
)
/
sizeof
(
*
__nodedef
));
i
++
)
{
if
(
__nodedef
[
i
].
type
==
type
)
{
return
&
(
__nodedef
[
i
]);
}
}
return
NULL
;
}
static
const
struct
nodedef
*
__get_nodedef_by_name
(
const
char
*
name
)
{
size_t
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
__nodedef
)
/
sizeof
(
*
__nodedef
));
i
++
)
{
if
(
strcmp
(
__nodedef
[
i
].
name
,
name
)
==
0
)
{
return
&
(
__nodedef
[
i
]);
}
}
return
NULL
;
}
static
const
struct
nodeattr
*
__get_nodeattr
(
const
struct
nodedef
*
nodedef
,
const
char
*
key
)
{
size_t
i
;
if
(
!
nodedef
||
!
key
)
return
NULL
;
for
(
i
=
0
;
i
<
(
sizeof
(
nodedef
->
attr
)
/
sizeof
(
*
nodedef
->
attr
));
i
++
)
{
if
(
nodedef
->
attr
[
i
]
->
name
==
NULL
)
{
/* we reached the end of the list */
return
NULL
;
}
if
(
strcmp
(
nodedef
->
attr
[
i
]
->
name
,
key
)
==
0
)
{
return
nodedef
->
attr
[
i
];
}
}
return
NULL
;
}
static
void
__report_free
(
refobject_t
self
,
void
**
userdata
)
{
reportxml_t
*
report
=
REFOBJECT_TO_TYPE
(
self
,
reportxml_t
*
);
refobject_unref
(
report
->
root
);
}
static
reportxml_t
*
reportxml_new_with_root
(
reportxml_node_t
*
root
)
{
reportxml_t
*
ret
;
if
(
!
root
)
return
NULL
;
ret
=
REFOBJECT_TO_TYPE
(
refobject_new
(
sizeof
(
reportxml_t
),
__report_free
,
NULL
,
NULL
,
NULL
),
reportxml_t
*
);
ret
->
root
=
root
;
return
ret
;
}
reportxml_t
*
reportxml_new
(
void
)
{
reportxml_node_t
*
root
=
reportxml_node_new
(
REPORTXML_NODE_TYPE_REPORT
,
NULL
,
NULL
,
NULL
);
reportxml_t
*
ret
;
if
(
!
root
)
return
NULL
;
ret
=
reportxml_new_with_root
(
root
);
if
(
!
ret
)
{
refobject_unref
(
root
);
return
NULL
;
}
return
ret
;
}
reportxml_node_t
*
reportxml_get_root_node
(
reportxml_t
*
report
)
{
if
(
!
report
)
return
NULL
;
if
(
refobject_ref
(
report
->
root
)
!=
0
)
return
NULL
;
return
report
->
root
;
}
reportxml_t
*
reportxml_parse_xmldoc
(
xmlDocPtr
doc
)
{
reportxml_node_t
*
root
;
reportxml_t
*
ret
;
xmlNodePtr
xmlroot
;
if
(
!
doc
)
return
NULL
;
xmlroot
=
xmlDocGetRootElement
(
doc
);
if
(
!
xmlroot
)
return
NULL
;
root
=
reportxml_node_parse_xmlnode
(
xmlroot
);
if
(
!
root
)
return
NULL
;
if
(
reportxml_node_get_type
(
root
)
!=
REPORTXML_NODE_TYPE_REPORT
)
{
refobject_unref
(
root
);
return
NULL
;
}
ret
=
reportxml_new_with_root
(
root
);
if
(
!
ret
)
{
refobject_unref
(
root
);
return
NULL
;
}
return
ret
;
}
xmlDocPtr
reportxml_render_xmldoc
(
reportxml_t
*
report
)
{
xmlDocPtr
ret
;
xmlNodePtr
node
;
if
(
!
report
)
return
NULL
;
node
=
reportxml_node_render_xmlnode
(
report
->
root
);
if
(
!
node
)
return
NULL
;
ret
=
xmlNewDoc
(
XMLSTR
(
"1.0"
));
if
(
!
ret
)
{
xmlFreeNode
(
node
);
return
NULL
;
}
xmlDocSetRootElement
(
ret
,
node
);
return
ret
;
}
static
void
__report_node_free
(
refobject_t
self
,
void
**
userdata
)
{
size_t
i
;
reportxml_node_t
*
node
=
REFOBJECT_TO_TYPE
(
self
,
reportxml_node_t
*
);
xmlFreeNode
(
node
->
xmlnode
);
for
(
i
=
0
;
i
<
node
->
childs_len
;
i
++
)
{
refobject_unref
(
node
->
childs
[
i
]);
}
free
(
node
->
content
);
free
(
node
->
childs
);
}
reportxml_node_t
*
reportxml_node_new
(
reportxml_node_type_t
type
,
const
char
*
id
,
const
char
*
definition
,
const
char
*
akindof
)
{
reportxml_node_t
*
ret
;
const
struct
nodedef
*
nodedef
=
__get_nodedef
(
type
);
size_t
i
;
if
(
!
nodedef
)
return
NULL
;
ret
=
REFOBJECT_TO_TYPE
(
refobject_new
(
sizeof
(
reportxml_node_t
),
__report_node_free
,
NULL
,
NULL
,
NULL
),
reportxml_node_t
*
);
if
(
ret
==
NULL
)
return
NULL
;
ret
->
type
=
type
;
ret
->
xmlnode
=
xmlNewNode
(
NULL
,
XMLSTR
(
nodedef
->
name
));
if
(
!
ret
->
xmlnode
)
{
refobject_unref
(
ret
);
return
NULL
;
}
for
(
i
=
0
;
i
<
(
sizeof
(
nodedef
->
attr
)
/
sizeof
(
*
nodedef
->
attr
));
i
++
)
{
const
struct
nodeattr
*
nodeattr
=
nodedef
->
attr
[
i
];
if
(
nodeattr
->
name
==
NULL
)
break
;
if
(
nodeattr
->
def
)
{
if
(
reportxml_node_set_attribute
(
ret
,
nodeattr
->
name
,
nodeattr
->
def
)
!=
0
)
{
refobject_unref
(
ret
);
return
NULL
;
}
}
}
#define _set_attr(x) \
if ((x)) { \
if (reportxml_node_set_attribute(ret, # x , (x)) != 0) { \
refobject_unref(ret); \
return NULL; \
} \
}
_set_attr
(
id
)
_set_attr
(
definition
)
_set_attr
(
akindof
)
return
ret
;
}
reportxml_node_t
*
reportxml_node_parse_xmlnode
(
xmlNodePtr
xmlnode
)
{
reportxml_node_t
*
node
;
const
struct
nodedef
*
nodedef
;
if
(
!
xmlnode
)
return
NULL
;
nodedef
=
__get_nodedef_by_name
((
const
char
*
)
xmlnode
->
name
);
if
(
!
nodedef
)
return
NULL
;
node
=
reportxml_node_new
(
nodedef
->
type
,
NULL
,
NULL
,
NULL
);
if
(
!
node
)
return
NULL
;
if
(
xmlnode
->
properties
)
{
xmlAttrPtr
cur
=
xmlnode
->
properties
;
do
{
xmlChar
*
value
=
xmlNodeListGetString
(
xmlnode
->
doc
,
cur
->
children
,
1
);
if
(
!
value
)
{
refobject_unref
(
node
);
return
NULL
;
}
if
(
reportxml_node_set_attribute
(
node
,
(
const
char
*
)
cur
->
name
,
(
const
char
*
)
value
)
!=
0
)
{
refobject_unref
(
node
);
return
NULL
;
}
xmlFree
(
value
);
}
while
((
cur
=
cur
->
next
));
}
if
(
xmlnode
->
xmlChildrenNode
)
{
xmlNodePtr
cur
=
xmlnode
->
xmlChildrenNode
;
do
{
reportxml_node_t
*
child
;
if
(
xmlIsBlankNode
(
cur
))
continue
;
if
(
cur
->
type
==
XML_COMMENT_NODE
)
continue
;
if
(
cur
->
type
==
XML_TEXT_NODE
)
{
xmlChar
*
value
=
xmlNodeListGetString
(
xmlnode
->
doc
,
cur
,
1
);
if
(
!
value
)
{
refobject_unref
(
node
);
return
NULL
;
}
if
(
reportxml_node_set_content
(
node
,
(
const
char
*
)
value
)
!=
0
)
{
refobject_unref
(
node
);
return
NULL
;
}
xmlFree
(
value
);
continue
;
}
child
=
reportxml_node_parse_xmlnode
(
cur
);
if
(
!
child
)
{
refobject_unref
(
node
);
return
NULL
;
}
if
(
reportxml_node_add_child
(
node
,
child
)
!=
0
)
{
refobject_unref
(
node
);
return
NULL
;
}
}
while
((
cur
=
cur
->
next
));
}
return
node
;
}
xmlNodePtr
reportxml_node_render_xmlnode
(
reportxml_node_t
*
node
)
{
xmlNodePtr
ret
;
ssize_t
count
;
size_t
i
;
if
(
!
node
)
return
NULL
;
count
=
reportxml_node_count_child
(
node
);
if
(
count
<
0
)
return
NULL
;
ret
=
xmlCopyNode
(
node
->
xmlnode
,
2
);
if
(
!
ret
)
return
NULL
;
for
(
i
=
0
;
i
<
(
size_t
)
count
;
i
++
)
{
reportxml_node_t
*
child
=
reportxml_node_get_child
(
node
,
i
);
xmlNodePtr
xmlchild
;
if
(
!
child
)
{
xmlFreeNode
(
ret
);
return
NULL
;
}
xmlchild
=
reportxml_node_render_xmlnode
(
child
);
refobject_unref
(
child
);
if
(
!
xmlchild
)
{
xmlFreeNode
(
ret
);
return
NULL
;
}
xmlAddChild
(
ret
,
xmlchild
);
}
if
(
node
->
content
)
{
xmlNodePtr
xmlchild
=
xmlNewText
(
XMLSTR
(
node
->
content
));
if
(
!
xmlchild
)
{
xmlFreeNode
(
ret
);
return
NULL
;
}
xmlAddChild
(
ret
,
xmlchild
);
}
return
ret
;
}
reportxml_node_type_t
reportxml_node_get_type
(
reportxml_node_t
*
node
)
{
if
(
!
node
)
return
REPORTXML_NODE_TYPE__ERROR
;
return
node
->
type
;
}
int
reportxml_node_set_attribute
(
reportxml_node_t
*
node
,
const
char
*
key
,
const
char
*
value
)
{
const
struct
nodedef
*
nodedef
;
const
struct
nodeattr
*
nodeattr
;
size_t
i
;
if
(
!
node
||
!
key
||
!
value
)
return
-
1
;
nodedef
=
__get_nodedef
(
node
->
type
);
nodeattr
=
__get_nodeattr
(
nodedef
,
key
);
if
(
!
nodeattr
)
return
-
1
;
if
(
nodeattr
->
values
[
0
]
!=
NULL
)
{
int
found
=
0
;
for
(
i
=
0
;
i
<
(
sizeof
(
nodeattr
->
values
)
/
sizeof
(
*
nodeattr
->
values
));
i
++
)
{
if
(
nodeattr
->
values
[
i
]
==
NULL
)
break
;
if
(
strcmp
(
nodeattr
->
values
[
i
],
value
)
==
0
)
{
found
=
1
;
break
;
}
}
if
(
!
found
)
return
-
1
;
}
if
(
nodeattr
->
checker
)
{
if
(
nodeattr
->
checker
(
nodeattr
,
value
)
!=
0
)
{
return
-
1
;
}
}
xmlSetProp
(
node
->
xmlnode
,
XMLSTR
(
key
),
XMLSTR
(
value
));
return
0
;
}
char
*
reportxml_node_get_attribute
(
reportxml_node_t
*
node
,
const
char
*
key
)
{
xmlChar
*
k
;
char
*
n
;
if
(
!
node
||
!
key
)
return
NULL
;
/* We do this super complicated thing as we do not know if we can use free() to free a xmlChar* object. */
k
=
xmlGetProp
(
node
->
xmlnode
,
XMLSTR
(
key
));
if
(
!
k
)
return
NULL
;
n
=
strdup
((
char
*
)
k
);
xmlFree
(
k
);
return
n
;
}
int
reportxml_node_add_child
(
reportxml_node_t
*
node
,
reportxml_node_t
*
child
)
{
reportxml_node_t
**
n
;
if
(
!
node
||
!
child
)
return
-
1
;
n
=
realloc
(
node
->
childs
,
sizeof
(
*
n
)
*
(
node
->
childs_len
+
1
));
if
(
!
n
)
return
-
1
;
node
->
childs
=
n
;
if
(
refobject_ref
(
child
)
!=
0
)
return
-
1
;
node
->
childs
[
node
->
childs_len
++
]
=
child
;
ICECAST_LOG_DEBUG
(
"Child %p added to Node %p"
,
child
,
node
);
return
0
;
}
ssize_t
reportxml_node_count_child
(
reportxml_node_t
*
node
)
{
if
(
!
node
)
return
-
1
;
return
node
->
childs_len
;
}
reportxml_node_t
*
reportxml_node_get_child
(
reportxml_node_t
*
node
,
size_t
idx
)
{
if
(
!
node
)
return
NULL
;
if
(
idx
>=
node
->
childs_len
)
return
NULL
;
if
(
refobject_ref
(
node
->
childs
[
idx
])
!=
0
)
return
NULL
;
return
node
->
childs
[
idx
];
}
int
reportxml_node_set_content
(
reportxml_node_t
*
node
,
const
char
*
value
)
{
const
struct
nodedef
*
nodedef
;
char
*
n
=
NULL
;
if
(
!
node
)
return
-
1
;
nodedef
=
__get_nodedef
(
node
->
type
);
if
(
!
nodedef
->
has_content
)
return
-
1
;
if
(
value
)
{
n
=
strdup
(
value
);