Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
L
libplist
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
pwn
libplist
Commits
66df32ee
Commit
66df32ee
authored
Jan 04, 2009
by
Jonathan Beck
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix some warnings and correct binary tag enum (false and true were inverted).
parent
ca400904
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
46 additions
and
47 deletions
+46
-47
bplist.c
src/bplist.c
+36
-37
plist.h
src/plist.h
+1
-1
xplist.c
src/xplist.c
+9
-9
No files found.
src/bplist.c
View file @
66df32ee
...
@@ -43,8 +43,8 @@
...
@@ -43,8 +43,8 @@
enum
{
enum
{
BPLIST_NULL
=
0x00
,
BPLIST_NULL
=
0x00
,
BPLIST_
TRU
E
=
0x08
,
BPLIST_
FALS
E
=
0x08
,
BPLIST_
FALS
E
=
0x09
,
BPLIST_
TRU
E
=
0x09
,
BPLIST_FILL
=
0x0F
,
/* will be used for length grabbing */
BPLIST_FILL
=
0x0F
,
/* will be used for length grabbing */
BPLIST_UINT
=
0x10
,
BPLIST_UINT
=
0x10
,
BPLIST_REAL
=
0x20
,
BPLIST_REAL
=
0x20
,
...
@@ -61,6 +61,7 @@ enum {
...
@@ -61,6 +61,7 @@ enum {
static
void
byte_convert
(
char
*
address
,
size_t
size
)
static
void
byte_convert
(
char
*
address
,
size_t
size
)
{
{
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
uint8_t
i
=
0
,
j
=
0
;
uint8_t
i
=
0
,
j
=
0
;
char
tmp
=
'\0'
;
char
tmp
=
'\0'
;
...
@@ -70,19 +71,23 @@ static void byte_convert(char *address, size_t size)
...
@@ -70,19 +71,23 @@ static void byte_convert(char *address, size_t size)
address
[
i
]
=
address
[
j
];
address
[
i
]
=
address
[
j
];
address
[
j
]
=
tmp
;
address
[
j
]
=
tmp
;
}
}
#endif
}
}
#include <byteswap.h>
#define swap_n_bytes(x, n) \
#define swap_n_bytes(x, n) \
n == 8 ?
bswap_64(*(uint64_t *)(x)
) : \
n == 8 ?
GUINT64_FROM_BE( *(uint64_t *)(x)
) : \
(n == 4 ?
bswap_32(*(uint32_t *)(x)
) : \
(n == 4 ?
GUINT32_FROM_BE( *(uint32_t *)(x)
) : \
(n == 2 ?
bswap_16(*(uint16_t *)(x)) : *
(x) ))
(n == 2 ?
GUINT16_FROM_BE( *(uint16_t *)(x) ) : *(uint8_t *)
(x) ))
#define be64dec(x)
bswap_64
( *(uint64_t*)(x) )
#define be64dec(x)
GUINT64_FROM_BE
( *(uint64_t*)(x) )
#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= (uint64_t)1<<32 ? 4 : 8)))
#define get_needed_bytes(x) (x <= 1<<8 ? 1 : ( x <= 1<<16 ? 2 : ( x <= (uint64_t)1<<32 ? 4 : 8)))
#define get_real_bytes(x) (x >> 32 ? 4 : 8)
#define get_real_bytes(x) (x >> 32 ? 4 : 8)
static
plist_t
parse_uint_node
(
char
*
bnode
,
uint8_t
size
,
char
**
next_object
)
static
plist_t
parse_uint_node
(
char
*
bnode
,
uint8_t
size
,
char
**
next_object
)
{
{
plist_data_t
data
=
plist_new_plist_data
();
plist_data_t
data
=
plist_new_plist_data
();
...
@@ -90,19 +95,11 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
...
@@ -90,19 +95,11 @@ static plist_t parse_uint_node(char *bnode, uint8_t size, char **next_object)
size
=
1
<<
size
;
// make length less misleading
size
=
1
<<
size
;
// make length less misleading
switch
(
size
)
{
switch
(
size
)
{
case
sizeof
(
uint8_t
):
case
sizeof
(
uint8_t
):
data
->
intval
=
bnode
[
0
];
break
;
case
sizeof
(
uint16_t
):
case
sizeof
(
uint16_t
):
memcpy
(
&
data
->
intval
,
bnode
,
size
);
data
->
intval
=
ntohs
(
data
->
intval
);
break
;
case
sizeof
(
uint32_t
):
case
sizeof
(
uint32_t
):
memcpy
(
&
data
->
intval
,
bnode
,
size
);
data
->
intval
=
ntohl
(
data
->
intval
);
break
;
case
sizeof
(
uint64_t
):
case
sizeof
(
uint64_t
):
memcpy
(
&
data
->
intval
,
bnode
,
size
);
memcpy
(
&
data
->
intval
,
bnode
,
size
);
byte_convert
((
char
*
)
&
data
->
intval
,
size
);
data
->
intval
=
swap_n_bytes
(
&
data
->
intval
,
size
);
break
;
break
;
default:
default:
free
(
data
);
free
(
data
);
...
@@ -160,7 +157,7 @@ static plist_t parse_unicode_node(char *bnode, uint8_t size)
...
@@ -160,7 +157,7 @@ static plist_t parse_unicode_node(char *bnode, uint8_t size)
return
g_node_new
(
data
);
return
g_node_new
(
data
);
}
}
static
plist_t
parse_data_node
(
char
*
bnode
,
uint64_t
size
,
uint32_t
ref_size
)
static
plist_t
parse_data_node
(
char
*
bnode
,
uint64_t
size
)
{
{
plist_data_t
data
=
plist_new_plist_data
();
plist_data_t
data
=
plist_new_plist_data
();
...
@@ -252,7 +249,7 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
...
@@ -252,7 +249,7 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
return
NULL
;
return
NULL
;
size
=
plist_get_node_uint_val
(
size_node
);
size
=
plist_get_node_uint_val
(
size_node
);
}
}
return
parse_data_node
(
object
,
size
,
dict_size
);
return
parse_data_node
(
object
,
size
);
case
BPLIST_STRING
:
case
BPLIST_STRING
:
if
(
0x0F
==
size
)
{
if
(
0x0F
==
size
)
{
...
@@ -292,7 +289,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
...
@@ -292,7 +289,8 @@ static plist_t parse_bin_node(char *object, uint8_t dict_size, char **next_objec
size
=
plist_get_node_uint_val
(
size_node
);
size
=
plist_get_node_uint_val
(
size_node
);
}
}
return
parse_dict_node
(
object
,
size
,
dict_size
);
return
parse_dict_node
(
object
,
size
,
dict_size
);
default:
return
NULL
;
}
}
return
NULL
;
return
NULL
;
}
}
...
@@ -324,11 +322,13 @@ static gpointer copy_plist_data(gconstpointer src, gpointer data)
...
@@ -324,11 +322,13 @@ static gpointer copy_plist_data(gconstpointer src, gpointer data)
break
;
break
;
case
PLIST_DATA
:
case
PLIST_DATA
:
case
PLIST_ARRAY
:
case
PLIST_ARRAY
:
case
PLIST_DICT
:
dstdata
->
buff
=
(
char
*
)
malloc
(
sizeof
(
char
*
)
*
srcdata
->
length
);
dstdata
->
buff
=
(
char
*
)
malloc
(
sizeof
(
char
*
)
*
srcdata
->
length
);
memcpy
(
dstdata
->
buff
,
srcdata
->
buff
,
sizeof
(
char
*
)
*
srcdata
->
length
);
memcpy
(
dstdata
->
buff
,
srcdata
->
buff
,
sizeof
(
char
*
)
*
srcdata
->
length
);
break
;
break
;
case
PLIST_DICT
:
dstdata
->
buff
=
(
char
*
)
malloc
(
sizeof
(
char
*
)
*
srcdata
->
length
*
2
);
memcpy
(
dstdata
->
buff
,
srcdata
->
buff
,
sizeof
(
char
*
)
*
srcdata
->
length
*
2
);
break
;
default:
default:
break
;
break
;
}
}
...
@@ -408,14 +408,14 @@ void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist)
...
@@ -408,14 +408,14 @@ void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist)
//first one is actually a key
//first one is actually a key
plist_get_data
(
nodeslist
[
index1
])
->
type
=
PLIST_KEY
;
plist_get_data
(
nodeslist
[
index1
])
->
type
=
PLIST_KEY
;
if
(
index1
>=
0
&&
index1
<
num_objects
)
{
if
(
index1
<
num_objects
)
{
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index1
]))
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index1
]))
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index1
]);
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index1
]);
else
else
g_node_append
(
nodeslist
[
i
],
g_node_copy_deep
(
nodeslist
[
index1
],
copy_plist_data
,
NULL
));
g_node_append
(
nodeslist
[
i
],
g_node_copy_deep
(
nodeslist
[
index1
],
copy_plist_data
,
NULL
));
}
}
if
(
index2
>=
0
&&
index2
<
num_objects
)
{
if
(
index2
<
num_objects
)
{
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index2
]))
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index2
]))
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index2
]);
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index2
]);
else
else
...
@@ -432,7 +432,7 @@ void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist)
...
@@ -432,7 +432,7 @@ void plist_from_bin(const char *plist_bin, uint32_t length, plist_t * plist)
str_j
=
j
*
dict_param_size
;
str_j
=
j
*
dict_param_size
;
index1
=
swap_n_bytes
(
data
->
buff
+
str_j
,
dict_param_size
);
index1
=
swap_n_bytes
(
data
->
buff
+
str_j
,
dict_param_size
);
if
(
index1
>=
0
&&
index1
<
num_objects
)
{
if
(
index1
<
num_objects
)
{
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index1
]))
if
(
G_NODE_IS_ROOT
(
nodeslist
[
index1
]))
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index1
]);
g_node_append
(
nodeslist
[
i
],
nodeslist
[
index1
]);
else
else
...
@@ -574,7 +574,7 @@ static void serialize_plist(GNode * node, gpointer data)
...
@@ -574,7 +574,7 @@ static void serialize_plist(GNode * node, gpointer data)
#define Log2(x) (x == 8 ? 3 : (x == 4 ? 2 : (x == 2 ? 1 : 0)))
#define Log2(x) (x == 8 ? 3 : (x == 4 ? 2 : (x == 2 ? 1 : 0)))
void
write_int
(
GByteArray
*
bplist
,
uint64_t
val
)
static
void
write_int
(
GByteArray
*
bplist
,
uint64_t
val
)
{
{
uint64_t
size
=
get_needed_bytes
(
val
);
uint64_t
size
=
get_needed_bytes
(
val
);
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
sizeof
(
uint8_t
)
+
size
);
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
sizeof
(
uint8_t
)
+
size
);
...
@@ -639,7 +639,7 @@ static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_tabl
...
@@ -639,7 +639,7 @@ static void write_array(GByteArray * bplist, GNode * node, GHashTable * ref_tabl
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
size
*
dict_param_size
);
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
size
*
dict_param_size
);
GNode
*
cur
=
NULL
;
GNode
*
cur
=
NULL
;
in
t
i
=
0
;
uint64_
t
i
=
0
;
for
(
i
=
0
,
cur
=
node
->
children
;
cur
&&
i
<
size
;
cur
=
cur
->
next
,
i
++
)
{
for
(
i
=
0
,
cur
=
node
->
children
;
cur
&&
i
<
size
;
cur
=
cur
->
next
,
i
++
)
{
idx
=
GPOINTER_TO_UINT
(
g_hash_table_lookup
(
ref_table
,
cur
));
idx
=
GPOINTER_TO_UINT
(
g_hash_table_lookup
(
ref_table
,
cur
));
memcpy
(
buff
+
i
*
dict_param_size
,
&
idx
,
dict_param_size
);
memcpy
(
buff
+
i
*
dict_param_size
,
&
idx
,
dict_param_size
);
...
@@ -669,7 +669,7 @@ static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table
...
@@ -669,7 +669,7 @@ static void write_dict(GByteArray * bplist, GNode * node, GHashTable * ref_table
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
size
*
2
*
dict_param_size
);
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
size
*
2
*
dict_param_size
);
GNode
*
cur
=
NULL
;
GNode
*
cur
=
NULL
;
in
t
i
=
0
;
uint64_
t
i
=
0
;
for
(
i
=
0
,
cur
=
node
->
children
;
cur
&&
i
<
size
;
cur
=
cur
->
next
->
next
,
i
++
)
{
for
(
i
=
0
,
cur
=
node
->
children
;
cur
&&
i
<
size
;
cur
=
cur
->
next
->
next
,
i
++
)
{
idx1
=
GPOINTER_TO_UINT
(
g_hash_table_lookup
(
ref_table
,
cur
));
idx1
=
GPOINTER_TO_UINT
(
g_hash_table_lookup
(
ref_table
,
cur
));
memcpy
(
buff
+
i
*
dict_param_size
,
&
idx1
,
dict_param_size
);
memcpy
(
buff
+
i
*
dict_param_size
,
&
idx1
,
dict_param_size
);
...
@@ -716,9 +716,8 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
...
@@ -716,9 +716,8 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
g_byte_array_append
(
bplist_buff
,
BPLIST_VERSION
,
BPLIST_VERSION_SIZE
);
g_byte_array_append
(
bplist_buff
,
BPLIST_VERSION
,
BPLIST_VERSION_SIZE
);
//write objects and table
//write objects and table
in
t
i
=
0
;
uint64_
t
i
=
0
;
uint8_t
*
buff
=
NULL
;
uint8_t
*
buff
=
NULL
;
uint8_t
size
=
0
;
uint64_t
offsets
[
num_objects
];
uint64_t
offsets
[
num_objects
];
for
(
i
=
0
;
i
<
num_objects
;
i
++
)
{
for
(
i
=
0
;
i
<
num_objects
;
i
++
)
{
...
@@ -768,17 +767,17 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
...
@@ -768,17 +767,17 @@ void plist_to_bin(plist_t plist, char **plist_bin, uint32_t * length)
offset_size
=
get_needed_bytes
(
bplist_buff
->
len
);
offset_size
=
get_needed_bytes
(
bplist_buff
->
len
);
offset_table_index
=
bplist_buff
->
len
;
offset_table_index
=
bplist_buff
->
len
;
for
(
i
=
0
;
i
<=
num_objects
;
i
++
)
{
for
(
i
=
0
;
i
<=
num_objects
;
i
++
)
{
uint8_t
*
buff
=
(
uint8_t
*
)
malloc
(
offset_size
);
uint8_t
*
offset
buff
=
(
uint8_t
*
)
malloc
(
offset_size
);
memcpy
(
buff
,
offsets
+
i
,
offset_size
);
memcpy
(
offset
buff
,
offsets
+
i
,
offset_size
);
byte_convert
(
buff
,
offset_size
);
byte_convert
(
offset
buff
,
offset_size
);
g_byte_array_append
(
bplist_buff
,
buff
,
offset_size
);
g_byte_array_append
(
bplist_buff
,
offset
buff
,
offset_size
);
free
(
buff
);
free
(
offset
buff
);
}
}
//setup trailer
//setup trailer
num_objects
=
bswap_64
(
num_objects
);
num_objects
=
GUINT64_FROM_BE
(
num_objects
);
root_object
=
bswap_64
(
root_object
);
root_object
=
GUINT64_FROM_BE
(
root_object
);
offset_table_index
=
bswap_64
(
offset_table_index
);
offset_table_index
=
GUINT64_FROM_BE
(
offset_table_index
);
char
trailer
[
BPLIST_TRL_SIZE
];
char
trailer
[
BPLIST_TRL_SIZE
];
memcpy
(
trailer
+
BPLIST_TRL_OFFSIZE_IDX
,
&
offset_size
,
sizeof
(
uint8_t
));
memcpy
(
trailer
+
BPLIST_TRL_OFFSIZE_IDX
,
&
offset_size
,
sizeof
(
uint8_t
));
...
...
src/plist.h
View file @
66df32ee
...
@@ -31,7 +31,7 @@
...
@@ -31,7 +31,7 @@
#include <sys/stat.h>
#include <sys/stat.h>
#include <unistd.h>
#include <unistd.h>
#include <glib.h>
#include <glib.h>
#include "utils.h"
...
...
src/xplist.c
View file @
66df32ee
...
@@ -49,7 +49,7 @@ const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
...
@@ -49,7 +49,7 @@ const char *plist_base = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
*
*
* @return The formatted string.
* @return The formatted string.
*/
*/
char
*
format_string
(
const
char
*
buf
,
int
cols
,
int
depth
)
static
char
*
format_string
(
const
char
*
buf
,
int
cols
,
int
depth
)
{
{
int
colw
=
depth
+
cols
+
1
;
int
colw
=
depth
+
cols
+
1
;
int
len
=
strlen
(
buf
);
int
len
=
strlen
(
buf
);
...
@@ -89,7 +89,7 @@ struct xml_node {
...
@@ -89,7 +89,7 @@ struct xml_node {
*
*
* @return The plist XML document.
* @return The plist XML document.
*/
*/
xmlDocPtr
new_xml_plist
()
static
xmlDocPtr
new_xml_plist
()
{
{
char
*
plist
=
strdup
(
plist_base
);
char
*
plist
=
strdup
(
plist_base
);
xmlDocPtr
plist_xml
=
xmlReadMemory
(
plist
,
strlen
(
plist
),
NULL
,
NULL
,
0
);
xmlDocPtr
plist_xml
=
xmlReadMemory
(
plist
,
strlen
(
plist
),
NULL
,
NULL
,
0
);
...
@@ -106,7 +106,7 @@ xmlDocPtr new_xml_plist()
...
@@ -106,7 +106,7 @@ xmlDocPtr new_xml_plist()
*
*
* @param plist The XML document to destroy.
* @param plist The XML document to destroy.
*/
*/
void
free_plist
(
xmlDocPtr
plist
)
static
void
free_plist
(
xmlDocPtr
plist
)
{
{
if
(
!
plist
)
if
(
!
plist
)
return
;
return
;
...
@@ -114,7 +114,7 @@ void free_plist(xmlDocPtr plist)
...
@@ -114,7 +114,7 @@ void free_plist(xmlDocPtr plist)
xmlFreeDoc
(
plist
);
xmlFreeDoc
(
plist
);
}
}
void
node_to_xml
(
GNode
*
node
,
gpointer
xml_struct
)
static
void
node_to_xml
(
GNode
*
node
,
gpointer
xml_struct
)
{
{
if
(
!
node
)
if
(
!
node
)
return
;
return
;
...
@@ -125,8 +125,8 @@ void node_to_xml(GNode * node, gpointer xml_struct)
...
@@ -125,8 +125,8 @@ void node_to_xml(GNode * node, gpointer xml_struct)
xmlNodePtr
child_node
=
NULL
;
xmlNodePtr
child_node
=
NULL
;
char
isStruct
=
FALSE
;
char
isStruct
=
FALSE
;
gchar
*
tag
=
NULL
;
const
gchar
*
tag
=
NULL
;
gchar
*
val
=
NULL
;
const
gchar
*
val
=
NULL
;
switch
(
node_data
->
type
)
{
switch
(
node_data
->
type
)
{
case
PLIST_BOOLEAN
:
case
PLIST_BOOLEAN
:
...
@@ -166,7 +166,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
...
@@ -166,7 +166,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
case
PLIST_DATA
:
case
PLIST_DATA
:
tag
=
"data"
;
tag
=
"data"
;
gchar
*
valtmp
=
g_base64_encode
(
node_data
->
buff
,
node_data
->
length
);
gchar
*
valtmp
=
g_base64_encode
(
node_data
->
buff
,
node_data
->
length
);
val
=
format_string
(
valtmp
,
6
0
,
xstruct
->
depth
);
val
=
format_string
(
valtmp
,
6
8
,
xstruct
->
depth
);
g_free
(
valtmp
);
g_free
(
valtmp
);
break
;
break
;
case
PLIST_ARRAY
:
case
PLIST_ARRAY
:
...
@@ -191,7 +191,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
...
@@ -191,7 +191,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
g_free
(
val
);
g_free
(
val
);
//add return for structured types
//add return for structured types
if
(
node_data
->
type
==
PLIST_ARRAY
||
node_data
->
type
==
PLIST_DICT
||
node_data
->
type
==
PLIST_DATA
)
if
(
node_data
->
type
==
PLIST_ARRAY
||
node_data
->
type
==
PLIST_DICT
)
xmlNodeAddContent
(
child_node
,
"
\n
"
);
xmlNodeAddContent
(
child_node
,
"
\n
"
);
if
(
isStruct
)
{
if
(
isStruct
)
{
...
@@ -199,7 +199,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
...
@@ -199,7 +199,7 @@ void node_to_xml(GNode * node, gpointer xml_struct)
g_node_children_foreach
(
node
,
G_TRAVERSE_ALL
,
node_to_xml
,
&
child
);
g_node_children_foreach
(
node
,
G_TRAVERSE_ALL
,
node_to_xml
,
&
child
);
}
}
//fix indent for structured types
//fix indent for structured types
if
(
node_data
->
type
==
PLIST_ARRAY
||
node_data
->
type
==
PLIST_DICT
||
node_data
->
type
==
PLIST_DATA
)
{
if
(
node_data
->
type
==
PLIST_ARRAY
||
node_data
->
type
==
PLIST_DICT
)
{
for
(
i
=
0
;
i
<
xstruct
->
depth
;
i
++
)
{
for
(
i
=
0
;
i
<
xstruct
->
depth
;
i
++
)
{
xmlNodeAddContent
(
child_node
,
"
\t
"
);
xmlNodeAddContent
(
child_node
,
"
\t
"
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment