/contrib/other/kpm/Makefile |
---|
0,0 → 1,63 |
NAME= kpm |
FASM= fasm.exe |
CC = kos32-gcc |
AR = kos32-ar |
LD = kos32-ld |
CPP= kos32-g++ |
STRIP = kos32-strip |
CFLAGS = -U_Win32 -U_WIN32 -U__MINGW32__ -c -Os -fno-ident -fomit-frame-pointer -mno-ms-bitfields |
ARFLAG = crs |
SDK_DIR:= $(abspath ../../sdk) |
LIB_DIR:= $(SDK_DIR)/lib |
INCLUDES= -I. -I$(SDK_DIR)/sources/newlib/libc/include |
INCLUDES+=-I$(SDK_DIR)/sources/freetype/include |
#DEFINES= -DDEBUG=1 |
DEFINES= -DNDEBUG |
LIBS:= -lsupc++ -lgcc_eh -lc.dll -lapp -lgcc |
LIBPATH:= -L$(LIB_DIR) -L/home/autobuild/tools/win32/mingw32/lib |
LDFLAGS = -static -nostdlib --stack 0x30000 -Map kpm.map -T$(SDK_DIR)/sources/newlib/app.lds --image-base 0 |
SOURCES = http.asm \ |
kpm.c \ |
collection.cpp \ |
tinyxml/tinyxml.cpp \ |
tinyxml/tinystr.cpp \ |
tinyxml/tinyxmlparser.cpp \ |
tinyxml/tinyxmlerror.cpp \ |
$(NULL) |
OBJECTS = $(patsubst %.asm, %.o, $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SOURCES)))) |
# targets |
all:$(NAME) |
$(NAME): $(OBJECTS) Makefile |
$(LD) $(LDFLAGS) $(LIBPATH) -o $@ $(OBJECTS) $(LIBS) |
kos32-objcopy $@ -O binary |
%.o : %.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< |
%.o : %.cpp Makefile |
$(CPP) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< |
%.o : %.asm Makefile |
$(FASM) $< $@ |
clean: |
-rm -f *.o |
/contrib/other/kpm/collection.cpp |
---|
0,0 → 1,101 |
#include "tinyxml/tinyxml.h" |
#include "collection.h" |
const char *key_collection = "collection"; |
const char *key_package = "package"; |
const char *key_name = "name"; |
const char *key_version = "version"; |
const char *key_description = "description"; |
const char *key_title = "title"; |
const char *key_release = "release"; |
const char *key_file = "file"; |
int package_id; |
void parse_group(pkg_group_t* gr, TiXmlElement *xmlgroup) |
{ |
TiXmlElement *xmlpkg; |
TiXmlElement *xmle; |
xmlpkg = xmlgroup->FirstChildElement(key_package); |
while (xmlpkg) |
{ |
package_t *pkg; |
pkg = (package_t*)malloc(sizeof(package_t)); |
pkg->id = package_id++; |
pkg->name = strdup(xmlpkg->Attribute(key_name)); |
pkg->version = strdup(xmlpkg->Attribute(key_version)); |
xmle = xmlpkg->FirstChildElement(key_description); |
pkg->description = strdup(xmle->Attribute(key_title)); |
xmle = xmlpkg->FirstChildElement(key_release); |
pkg->filename = strdup(xmle->Attribute(key_file)); |
list_add_tail(&pkg->list, &gr->packages); |
xmlpkg = xmlpkg->NextSiblingElement(); |
}; |
}; |
collection_t* load_collection_file(const char *name) |
{ |
TiXmlDocument doc; |
TiXmlElement *col; |
collection_t *collection = NULL; |
doc.LoadFile(name); |
col = doc.FirstChildElement(key_collection); |
if (col) |
{ |
collection = (collection_t*)malloc(sizeof(collection_t)); |
INIT_LIST_HEAD(&collection->groups); |
TiXmlElement* xmlgroup = col->FirstChildElement(); |
if (xmlgroup) |
{ |
pkg_group_t *gr; |
gr = (pkg_group_t*)malloc(sizeof(pkg_group_t)); |
INIT_LIST_HEAD(&gr->list); |
INIT_LIST_HEAD(&gr->packages); |
gr->name = strdup(xmlgroup->Value()); |
list_add_tail(&gr->list, &collection->groups); |
parse_group(gr, xmlgroup); |
}; |
}; |
return collection; |
} |
collection_t* load_collection_buffer(const char *buffer) |
{ |
TiXmlDocument doc; |
TiXmlElement *col; |
collection_t *collection = NULL; |
doc.Parse(buffer); |
col = doc.FirstChildElement(key_collection); |
if (col) |
{ |
collection = (collection_t*)malloc(sizeof(collection_t)); |
INIT_LIST_HEAD(&collection->groups); |
TiXmlElement* xmlgroup = col->FirstChildElement(); |
if (xmlgroup) |
{ |
pkg_group_t *gr; |
gr = (pkg_group_t*)malloc(sizeof(pkg_group_t)); |
INIT_LIST_HEAD(&gr->list); |
INIT_LIST_HEAD(&gr->packages); |
gr->name = strdup(xmlgroup->Value()); |
list_add_tail(&gr->list, &collection->groups); |
parse_group(gr, xmlgroup); |
}; |
}; |
return collection; |
} |
/contrib/other/kpm/collection.h |
---|
0,0 → 1,39 |
#ifndef __COLLECTION_H__ |
#ifdef __cplusplus |
extern "C" { |
#endif |
#include "list.h" |
typedef struct |
{ |
list_t groups; |
char *issue; |
}collection_t; |
typedef struct |
{ |
list_t list; |
list_t packages; |
char *name; |
}pkg_group_t; |
typedef struct package |
{ |
list_t list; |
int id; |
char *name; |
char *version; |
char *filename; |
char *description; |
}package_t; |
collection_t* load_collection_file(const char *name); |
collection_t* load_collection_buffer(const char *buffer); |
#ifdef __cplusplus |
} |
#endif |
#endif /* __COLLECTION_H__ */ |
/contrib/other/kpm/http.asm |
---|
0,0 → 1,236 |
include 'proc32.inc' |
format MS COFF |
public _http_init |
public _http_get@16 |
public _http_receive@4 |
public _http_free@4 |
section '.text' align 16 |
;void* __fastcall getprocaddr(export, name) |
align 4 |
getprocaddress: |
push esi |
push edi |
xor eax, eax |
test ecx, ecx ; If hlib = 0 then goto .end |
jz .end |
.next: |
cmp [ecx], dword 0 ; If end of export table then goto .end |
jz .end |
xor eax, eax |
mov esi, [ecx] |
mov edi, edx ; name |
.next_: |
lodsb |
scasb |
jne .fail |
or al, al |
jnz .next_ |
jmp .ok |
.fail: |
add ecx, 8 |
jmp .next |
.ok: |
mov eax, [ecx + 4] ; return address |
.end: |
pop edi |
pop esi |
ret |
;void fastcall dll_link(export, import) |
align 4 |
dll_link: |
push esi |
push ecx |
mov esi, edx |
test esi, esi |
jz .done |
.next: |
mov edx, [esi] |
test edx, edx |
jz .done |
mov ecx, [esp] |
call getprocaddress |
test eax, eax |
jz .done |
mov [esi], eax |
add esi, 4 |
jmp .next |
.done: |
pop ecx |
pop esi |
ret |
align 4 |
dll_load: |
push ebp |
push esi |
push edi |
mov ebp, [esp+16] |
.next_lib: |
mov edx, [ebp] |
test edx, edx |
jz .exit |
mov esi, [ebp+4] |
mov edi, s_libdir.fname |
@@: |
lodsb |
stosb |
test al, al |
jnz @b |
mov eax, 68 |
mov ebx, 19 |
mov ecx, s_libdir |
int 0x40 |
test eax, eax |
jz .fail |
mov ecx, eax |
call dll_link |
mov eax, [ecx] |
cmp dword[eax], 'lib_' |
jnz @f |
mov esi, [ecx+4] |
pushad |
mov eax, mem.Alloc |
mov ebx, mem.Free |
mov ecx, mem.ReAlloc |
mov edx, dll_load |
call esi |
popad |
@@: |
add ebp, 8 |
jmp .next_lib |
.exit: |
pop edi |
pop esi |
pop ebp |
xor eax, eax |
ret 4 |
.fail: |
pop edi |
pop esi |
pop ebx |
inc eax |
ret 4 |
align 4 |
_http_init: |
push @IMPORT |
call dll_load |
ret |
align 4 |
_http_get@16: |
jmp [HTTP_get] |
align 4 |
_http_receive@4: |
jmp [HTTP_receive] |
align 4 |
_http_free@4: |
jmp [HTTP_free] |
proc mem.Alloc, size |
push ebx ecx |
mov ecx, [size] |
mov eax, 68 |
mov ebx, 12 |
int 0x40 |
pop ecx ebx |
ret |
endp |
;----------------------------------------------------------------------------- |
proc mem.ReAlloc, mptr, size |
push ebx ecx edx |
mov ecx, [size] |
test ecx, ecx |
jz @f |
@@: |
mov edx, [mptr] |
test edx, edx |
jz @f |
@@: |
mov eax, 68 |
mov ebx, 20 |
int 0x40 |
test eax, eax |
jz @f |
@@: |
pop edx ecx ebx |
ret |
endp |
;----------------------------------------------------------------------------- |
proc mem.Free, mptr |
push ebx ecx |
mov ecx,[mptr] |
test ecx,ecx |
jz @f |
@@: |
mov eax, 68 |
mov ebx, 13 |
int 0x40 |
pop ecx ebx |
ret |
endp |
section '.data' align 16 |
; ------------------------- |
macro library [lname,fname] |
{ |
forward |
dd __#lname#_library_table__,__#lname#_library_name__ |
common |
dd 0 |
forward |
align 4 |
__#lname#_library_name__ db fname,0 |
} |
macro import lname,[name,sname] |
{ |
common |
align 4 |
__#lname#_library_table__: |
forward |
if used name |
name dd __#name#_import_name__ |
end if |
common |
dd 0 |
forward |
if used name |
align 4 |
__#name#_import_name__ db sname,0 |
end if |
} |
align 4 |
@IMPORT: |
library lib_http, 'http.obj' |
import lib_http, \ |
HTTP_get, 'get', \ |
HTTP_receive, 'receive', \ |
HTTP_free, 'free' |
s_libdir: |
db '/sys/lib/' |
.fname rb 32 |
/contrib/other/kpm/http.h |
---|
0,0 → 1,47 |
#ifndef __HTTP_H__ |
#define __HTTP_H__ |
#define FLAG_GOT_ALL_DATA (1 << 2) |
#define FLAG_STREAM (1 << 9) |
#define FLAG_REUSE_BUFFER (1 << 10) |
typedef struct |
{ |
int socket; // socket on which the actual transfer happens |
int flags; // flags, reflects status of the transfer using bitflags |
int write_ptr; // internal use only (where to write new data in buffer) |
int buffer_length; // internal use only (number of available bytes in buffer) |
int chunk_ptr; // internal use only (where the next chunk begins) |
int timestamp; // internal use only (when last data was received) |
int status; // HTTP status |
int header_length; // length of HTTP header |
void *content_ptr; // ptr to content |
int content_length; // total length of HTTP content |
int content_received; // number of currently received content bytes |
}http_t; |
int http_init(); |
int http_load(char *buf, const char *path); |
http_t* __attribute__ ((stdcall)) http_get(const char *url, http_t *conn, int flags, const char *header); |
int __attribute__ ((stdcall)) http_receive(http_t *conn); |
void __attribute__ ((stdcall)) http_free(http_t *conn); |
static inline int http_receive_with_retry(http_t *http, int retry_count) |
{ |
int err; |
do |
{ |
if(err = http_receive(http)) |
delay(1); |
}while(err && --retry_count); |
return err; |
} |
#endif /* __HTTP_H__ */ |
/contrib/other/kpm/kpm.c |
---|
0,0 → 1,181 |
#include <stdio.h> |
#include <string.h> |
#include <sys/stat.h> |
#include <sys/unistd.h> |
#include <fcntl.h> |
#include <kos32sys.h> |
#include "collection.h" |
#include "http.h" |
#define BUFFSIZE (64*1024) |
int http_load_mem(char *buf, const char *url) |
{ |
http_t *http; |
int offset = 0; |
int count; |
// asm volatile("int3"); |
http = http_get(url, NULL,FLAG_STREAM|FLAG_REUSE_BUFFER, NULL); |
if(http == NULL) |
goto err_get; |
do |
{ |
// delay(100); |
if(http_receive_with_retry(http, 500)==0) |
{ |
if(http->flags & 0xffff0000) |
goto err_http; |
count = http->content_received - offset; |
if(count == 0) |
continue; |
memcpy(buf+offset, http->content_ptr, count); |
offset = http->content_received; |
} |
else goto err_http; |
}while( (http->flags & FLAG_GOT_ALL_DATA) == 0); |
if(http->content_ptr) |
user_free(http->content_ptr); |
http_free(http); |
return offset; |
err_http: |
if(http->content_ptr) |
user_free(http->content_ptr); |
http_free(http); |
printf("HTTP receive failed\n"); |
return offset; |
err_get: |
printf("HTTP GET failed\n"); |
return offset; |
} |
int http_load_file(const char *path, const char *url) |
{ |
http_t *http; |
int received = 0; |
int offset = 0; |
int tail; |
char *buf; |
int fd; |
int i; |
buf = user_alloc(BUFFSIZE); |
for(i = 0; i < 16; i++) |
buf[i*4096] = 0; |
fd = open(path, O_CREAT|O_WRONLY); |
if(fd == -1) |
{ |
user_free(buf); |
return 0; |
}; |
http = http_get(url, NULL,FLAG_STREAM|FLAG_REUSE_BUFFER, NULL); |
if(http == NULL) |
goto err_get; |
do |
{ |
if(http_receive_with_retry(http, 500) == 0) |
{ |
int count; |
if(http->flags & 0xffff0000) |
break; |
count = http->content_received - received; |
if(count+offset <= BUFFSIZE) |
{ |
memcpy(buf+offset, http->content_ptr, count); |
offset+= count; |
+ |
+ else |
+ { |
+ tail = count+offset-BUFFSIZE; |
+ count = BUFFSIZE - offset; |
+ if(count) |
+ { |
+ memcpy(buf+offset, http->content_ptr, count); |
+ offset = 0; |
+ }; |
+ |
+ write(fd, buf, BUFFSIZE); |
+ |
+ if(tail) |
+ { |
+ memcpy(buf, http->content_ptr+count, tail); |
+ offset = tail; |
+ } |
+ } |
+ received = http->content_received; |
+ } |
+ else break; |
+ |
+ }while( (http->flags & FLAG_GOT_ALL_DATA) == 0); |
+ |
+ if(offset) |
+ { |
+ write(fd, buf, offset); |
+ } |
+ |
+// ftruncate(fd, received); |
+ close(fd); |
+ |
+ if(http->content_ptr) |
+ user_free(http->content_ptr); |
+ http_free(http); |
+ |
+ user_free(buf); |
+ |
+ return received; |
+ |
+err_get: |
+ printf("HTTP GET failed\n"); |
+ return received; |
+} |
+ |
+ |
+int main(int argc, char *argv[]) |
+{ |
+ int count; |
+ |
+ if(http_init()) |
+ goto err_init; |
+ |
+ count = http_load_file("/tmp0/1/packages.xml", "http://ftp.kolibrios.org/users/Serge/new/OS/packages.xml"); |
+ |
+ if(count) |
+ { |
+ collection_t *collection; |
+ pkg_group_t *gr; |
+ |
+ collection = load_collection_file("/tmp0/1/packages.xml"); |
+ |
+ list_for_each_entry(gr, &collection->groups, list) |
+ { |
+ package_t *pkg; |
+ |
+ list_for_each_entry(pkg, &gr->packages, list) |
+ { |
+ printf("package %s-%s\n", pkg->name, pkg->version); |
+ } |
+ }; |
+ } |
+ |
+ return 0; |
+ |
+err_init: |
+ printf("HTTP library initialization failed\n"); |
+ return -1; |
+} |
/contrib/other/kpm/list.h |
---|
0,0 → 1,253 |
#ifndef __LIST_H__ |
#define __LIST_H__ |
typedef struct _list list_t; |
struct _list |
{ |
list_t *next, *prev; |
}; |
#define LIST_HEAD_INIT(name) { &(name), &(name) } |
#define LIST_HEAD(name) \ |
list_t name = LIST_HEAD_INIT(name) |
static inline void INIT_LIST_HEAD(list_t *list) |
{ |
list->next = list; |
list->prev = list; |
} |
/* |
* Insert a new entry between two known consecutive entries. |
* |
* This is only for internal list manipulation where we know |
* the prev/next entries already! |
*/ |
static inline void __list_add(list_t *lnew, list_t *prev, list_t *next) |
{ |
next->prev = lnew; |
lnew->next = next; |
lnew->prev = prev; |
prev->next = lnew; |
} |
/** |
* list_add - add a new entry |
* @new: new entry to be added |
* @head: list head to add it after |
* |
* Insert a new entry after the specified head. |
* This is good for implementing stacks. |
*/ |
static inline void list_add(list_t *lnew, list_t *head) |
{ |
__list_add(lnew, head, head->next); |
} |
/** |
* list_add_tail - add a new entry |
* @new: new entry to be added |
* @head: list head to add it before |
* |
* Insert a new entry before the specified head. |
* This is useful for implementing queues. |
*/ |
static inline void list_add_tail(list_t *lnew, list_t *head) |
{ |
__list_add(lnew, head->prev, head); |
} |
/* |
* Delete a list entry by making the prev/next entries |
* point to each other. |
* |
* This is only for internal list manipulation where we know |
* the prev/next entries already! |
*/ |
static inline void __list_del(list_t * prev, list_t * next) |
{ |
next->prev = prev; |
prev->next = next; |
} |
/** |
* list_del - deletes entry from list. |
* @entry: the element to delete from the list. |
* Note: list_empty() on entry does not return true after this, the entry is |
* in an undefined state. |
*/ |
static inline void __list_del_entry(list_t *entry) |
{ |
__list_del(entry->prev, entry->next); |
} |
static inline void list_del(list_t *entry) |
{ |
__list_del(entry->prev, entry->next); |
entry->next = NULL; |
entry->prev = NULL; |
} |
/** |
* list_replace - replace old entry by new one |
* @old : the element to be replaced |
* @new : the new element to insert |
* |
* If @old was empty, it will be overwritten. |
*/ |
static inline void list_replace(list_t *old, list_t *lnew) |
{ |
lnew->next = old->next; |
lnew->next->prev = lnew; |
lnew->prev = old->prev; |
lnew->prev->next = lnew; |
} |
static inline void list_replace_init(list_t *old, list_t *lnew) |
{ |
list_replace(old, lnew); |
INIT_LIST_HEAD(old); |
} |
/** |
* list_del_init - deletes entry from list and reinitialize it. |
* @entry: the element to delete from the list. |
*/ |
static inline void list_del_init(list_t *entry) |
{ |
__list_del_entry(entry); |
INIT_LIST_HEAD(entry); |
} |
/** |
* list_move - delete from one list and add as another's head |
* @list: the entry to move |
* @head: the head that will precede our entry |
*/ |
static inline void list_move(list_t *list, list_t *head) |
{ |
__list_del_entry(list); |
list_add(list, head); |
} |
/** |
* list_move_tail - delete from one list and add as another's tail |
* @list: the entry to move |
* @head: the head that will follow our entry |
*/ |
static inline void list_move_tail(list_t *list, list_t *head) |
{ |
__list_del_entry(list); |
list_add_tail(list, head); |
} |
/** |
* list_is_last - tests whether @list is the last entry in list @head |
* @list: the entry to test |
* @head: the head of the list |
*/ |
static inline int list_is_last(const list_t *list, const list_t *head) |
{ |
return list->next == head; |
} |
/** |
* list_empty - tests whether a list is empty |
* @head: the list to test. |
*/ |
static inline int list_empty(const list_t *head) |
{ |
return head->next == head; |
} |
#define container_of(ptr, type, member) ({ \ |
const typeof( ((type *)0)->member ) *__mptr = (ptr); \ |
(type *)( (char *)__mptr - __builtin_offsetof(type,member) );}) |
/** |
* list_entry - get the struct for this entry |
* @ptr: the &struct list_head pointer. |
* @type: the type of the struct this is embedded in. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_entry(ptr, type, member) \ |
container_of(ptr, type, member) |
/** |
* list_first_entry - get the first element from a list |
* @ptr: the list head to take the element from. |
* @type: the type of the struct this is embedded in. |
* @member: the name of the list_struct within the struct. |
* |
* Note, that list is expected to be not empty. |
*/ |
#define list_first_entry(ptr, type, member) \ |
list_entry((ptr)->next, type, member) |
/** |
* list_for_each - iterate over a list |
* @pos: the &struct list_head to use as a loop cursor. |
* @head: the head for your list. |
*/ |
#define list_for_each(pos, head) \ |
for (pos = (head)->next; pos != (head); pos = pos->next) |
/** |
* list_for_each_prev - iterate over a list backwards |
* @pos: the &struct list_head to use as a loop cursor. |
* @head: the head for your list. |
*/ |
#define list_for_each_prev(pos, head) \ |
for (pos = (head)->prev; pos != (head); pos = pos->prev) |
/** |
* list_for_each_safe - iterate over a list safe against removal of list entry |
* @pos: the &struct list_head to use as a loop cursor. |
* @n: another &struct list_head to use as temporary storage |
* @head: the head for your list. |
*/ |
#define list_for_each_safe(pos, n, head) \ |
for (pos = (head)->next, n = pos->next; pos != (head); \ |
pos = n, n = pos->next) |
/** |
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry |
* @pos: the &struct list_head to use as a loop cursor. |
* @n: another &struct list_head to use as temporary storage |
* @head: the head for your list. |
*/ |
#define list_for_each_prev_safe(pos, n, head) \ |
for (pos = (head)->prev, n = pos->prev; \ |
pos != (head); \ |
pos = n, n = pos->prev) |
/** |
* list_for_each_entry - iterate over list of given type |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_for_each_entry(pos, head, member) \ |
for (pos = list_entry((head)->next, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = list_entry(pos->member.next, typeof(*pos), member)) |
/** |
* list_for_each_entry_reverse - iterate backwards over list of given type. |
* @pos: the type * to use as a loop cursor. |
* @head: the head for your list. |
* @member: the name of the list_struct within the struct. |
*/ |
#define list_for_each_entry_reverse(pos, head, member) \ |
for (pos = list_entry((head)->prev, typeof(*pos), member); \ |
&pos->member != (head); \ |
pos = list_entry(pos->member.prev, typeof(*pos), member)) |
#endif |
/contrib/other/kpm/proc32.inc |
---|
0,0 → 1,301 |
; Macroinstructions for defining and calling procedures |
macro stdcall proc,[arg] ; directly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call proc } |
macro invoke proc,[arg] ; indirectly call STDCALL procedure |
{ common |
if ~ arg eq |
reverse |
pushd arg |
common |
end if |
call [proc] } |
macro ccall proc,[arg] ; directly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call proc |
if size@ccall |
add esp,size@ccall |
end if } |
macro cinvoke proc,[arg] ; indirectly call CDECL procedure |
{ common |
size@ccall = 0 |
if ~ arg eq |
reverse |
pushd arg |
size@ccall = size@ccall+4 |
common |
end if |
call [proc] |
if size@ccall |
add esp,size@ccall |
end if } |
macro proc [args] ; define procedure |
{ common |
match name params, args> |
\{ define@proc name,<params \} } |
prologue@proc equ prologuedef |
macro prologuedef procname,flag,parmbytes,localbytes,reglist |
{ local loc |
loc = (localbytes+3) and (not 3) |
parmbase@proc equ ebp+8 |
localbase@proc equ ebp-loc |
if parmbytes | localbytes |
push ebp |
mov ebp,esp |
if localbytes |
sub esp,loc |
end if |
end if |
irps reg, reglist \{ push reg \} } |
epilogue@proc equ epiloguedef |
macro epiloguedef procname,flag,parmbytes,localbytes,reglist |
{ irps reg, reglist \{ reverse pop reg \} |
if parmbytes | localbytes |
leave |
end if |
if flag and 10000b |
retn |
else |
retn parmbytes |
end if } |
close@proc equ |
macro define@proc name,statement |
{ local params,flag,regs,parmbytes,localbytes,current |
if used name |
name: |
match =stdcall args, statement \{ params equ args |
flag = 11b \} |
match =stdcall, statement \{ params equ |
flag = 11b \} |
match =c args, statement \{ params equ args |
flag = 10001b \} |
match =c, statement \{ params equ |
flag = 10001b \} |
match =params, params \{ params equ statement |
flag = 0 \} |
match =uses reglist=,args, params \{ regs equ reglist |
params equ args \} |
match =regs =uses reglist, regs params \{ regs equ reglist |
params equ \} |
match =regs, regs \{ regs equ \} |
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \} |
virtual at parmbase@proc |
match =,args, params \{ defargs@proc args \} |
match =args@proc args, args@proc params \{ defargs@proc args \} |
parmbytes = $-(parmbase@proc) |
end virtual |
name # % = parmbytes/4 |
all@vars equ |
current = 0 |
macro locals |
\{ virtual at localbase@proc+current |
macro label def \\{ match . type,def> \\\{ deflocal@proc .,label,<type \\\} \\} |
struc db [val] \\{ \common deflocal@proc .,db,val \\} |
struc du [val] \\{ \common deflocal@proc .,du,val \\} |
struc dw [val] \\{ \common deflocal@proc .,dw,val \\} |
struc dp [val] \\{ \common deflocal@proc .,dp,val \\} |
struc dd [val] \\{ \common deflocal@proc .,dd,val \\} |
struc dt [val] \\{ \common deflocal@proc .,dt,val \\} |
struc dq [val] \\{ \common deflocal@proc .,dq,val \\} |
struc rb cnt \\{ deflocal@proc .,rb cnt, \\} |
struc rw cnt \\{ deflocal@proc .,rw cnt, \\} |
struc rp cnt \\{ deflocal@proc .,rp cnt, \\} |
struc rd cnt \\{ deflocal@proc .,rd cnt, \\} |
struc rt cnt \\{ deflocal@proc .,rt cnt, \\} |
struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \} |
macro endl |
\{ purge label |
restruc db,du,dw,dp,dd,dt,dq |
restruc rb,rw,rp,rd,rt,rq |
current = $-(localbase@proc) |
end virtual \} |
macro ret operand |
\{ match any, operand \\{ retn operand \\} |
match , operand \\{ match epilogue:reglist, epilogue@proc:<regs> \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \} |
macro finish@proc |
\{ localbytes = current |
match close:reglist, close@proc:<regs> \\{ close name,flag,parmbytes,localbytes,reglist \\} |
end if \} } |
macro defargs@proc [arg] |
{ common |
if ~ arg eq |
forward |
local ..arg,current@arg |
match argname:type, arg |
\{ current@arg equ argname |
label ..arg type |
argname equ ..arg |
if qqword eq type |
dd ?,?,?,?,?,?,?,? |
else if dqword eq type |
dd ?,?,?,? |
else if tbyte eq type |
dd ?,?,? |
else if qword eq type | pword eq type |
dd ?,? |
else |
dd ? |
end if \} |
match =current@arg,current@arg |
\{ current@arg equ arg |
arg equ ..arg |
..arg dd ? \} |
common |
args@proc equ current@arg |
forward |
restore current@arg |
common |
end if } |
macro deflocal@proc name,def,[val] { name def val } |
macro deflocal@proc name,def,[val] |
{ common |
match vars, all@vars \{ all@vars equ all@vars, \} |
all@vars equ all@vars name |
forward |
local ..var,..tmp |
..var def val |
match =?, val \{ ..tmp equ \} |
match any =?, val \{ ..tmp equ \} |
match any (=?), val \{ ..tmp equ \} |
match =label, def \{ ..tmp equ \} |
match tmp : value, ..tmp : val |
\{ tmp: end virtual |
initlocal@proc ..var,def value |
virtual at tmp\} |
common |
match first rest, ..var, \{ name equ first \} } |
struc label type { label . type } |
macro initlocal@proc name,def |
{ virtual at name |
def |
size@initlocal = $ - name |
end virtual |
position@initlocal = 0 |
while size@initlocal > position@initlocal |
virtual at name |
def |
if size@initlocal - position@initlocal < 2 |
current@initlocal = 1 |
load byte@initlocal byte from name+position@initlocal |
else if size@initlocal - position@initlocal < 4 |
current@initlocal = 2 |
load word@initlocal word from name+position@initlocal |
else |
current@initlocal = 4 |
load dword@initlocal dword from name+position@initlocal |
end if |
end virtual |
if current@initlocal = 1 |
mov byte [name+position@initlocal],byte@initlocal |
else if current@initlocal = 2 |
mov word [name+position@initlocal],word@initlocal |
else |
mov dword [name+position@initlocal],dword@initlocal |
end if |
position@initlocal = position@initlocal + current@initlocal |
end while } |
macro endp |
{ purge ret,locals,endl |
finish@proc |
purge finish@proc |
restore regs@proc |
match all,args@proc \{ restore all \} |
restore args@proc |
match all,all@vars \{ restore all \} } |
macro local [var] |
{ common |
locals |
forward done@local equ |
match varname[count]:vartype, var |
\{ match =BYTE, vartype \\{ varname rb count |
restore done@local \\} |
match =WORD, vartype \\{ varname rw count |
restore done@local \\} |
match =DWORD, vartype \\{ varname rd count |
restore done@local \\} |
match =PWORD, vartype \\{ varname rp count |
restore done@local \\} |
match =QWORD, vartype \\{ varname rq count |
restore done@local \\} |
match =TBYTE, vartype \\{ varname rt count |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
rq count*2 |
restore done@local \\} |
match =QQWORD, vartype \\{ label varname qqword |
rq count*4 |
restore done@local \\} |
match =XWORD, vartype \\{ label varname xword |
rq count*2 |
restore done@local \\} |
match =YWORD, vartype \\{ label varname yword |
rq count*4 |
restore done@local \\} |
match , done@local \\{ virtual |
varname vartype |
end virtual |
rb count*sizeof.\#vartype |
restore done@local \\} \} |
match :varname:vartype, done@local:var |
\{ match =BYTE, vartype \\{ varname db ? |
restore done@local \\} |
match =WORD, vartype \\{ varname dw ? |
restore done@local \\} |
match =DWORD, vartype \\{ varname dd ? |
restore done@local \\} |
match =PWORD, vartype \\{ varname dp ? |
restore done@local \\} |
match =QWORD, vartype \\{ varname dq ? |
restore done@local \\} |
match =TBYTE, vartype \\{ varname dt ? |
restore done@local \\} |
match =DQWORD, vartype \\{ label varname dqword |
dq ?,? |
restore done@local \\} |
match =QQWORD, vartype \\{ label varname qqword |
dq ?,?,?,? |
restore done@local \\} |
match =XWORD, vartype \\{ label varname xword |
dq ?,? |
restore done@local \\} |
match =YWORD, vartype \\{ label varname yword |
dq ?,?,?,? |
restore done@local \\} |
match , done@local \\{ varname vartype |
restore done@local \\} \} |
match ,done@local |
\{ var |
restore done@local \} |
common |
endl } |
/contrib/other/kpm/tinyxml/tinystr.cpp |
---|
0,0 → 1,115 |
/* |
www.sourceforge.net/projects/tinyxml |
Original file by Yves Berquin. |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
/* |
* THIS FILE WAS ALTERED BY Tyge Løvset, 7. April 2005. |
*/ |
#ifndef TIXML_USE_STL |
#include "tinystr.h" |
// Error value for find primitive |
const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1); |
// Null rep. |
TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } }; |
void TiXmlString::reserve (size_type cap) |
{ |
if (cap > capacity()) |
{ |
TiXmlString tmp; |
tmp.init(length(), cap); |
memcpy(tmp.start(), data(), length()); |
swap(tmp); |
} |
} |
TiXmlString& TiXmlString::assign(const char* str, size_type len) |
{ |
size_type cap = capacity(); |
if (len > cap || cap > 3*(len + 8)) |
{ |
TiXmlString tmp; |
tmp.init(len); |
memcpy(tmp.start(), str, len); |
swap(tmp); |
} |
else |
{ |
memmove(start(), str, len); |
set_size(len); |
} |
return *this; |
} |
TiXmlString& TiXmlString::append(const char* str, size_type len) |
{ |
size_type newsize = length() + len; |
if (newsize > capacity()) |
{ |
reserve (newsize + capacity()); |
} |
memmove(finish(), str, len); |
set_size(newsize); |
return *this; |
} |
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b) |
{ |
TiXmlString tmp; |
tmp.reserve(a.length() + b.length()); |
tmp += a; |
tmp += b; |
return tmp; |
} |
TiXmlString operator + (const TiXmlString & a, const char* b) |
{ |
TiXmlString tmp; |
TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) ); |
tmp.reserve(a.length() + b_len); |
tmp += a; |
tmp.append(b, b_len); |
return tmp; |
} |
TiXmlString operator + (const char* a, const TiXmlString & b) |
{ |
TiXmlString tmp; |
TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) ); |
tmp.reserve(a_len + b.length()); |
tmp.append(a, a_len); |
tmp += b; |
return tmp; |
} |
#endif // TIXML_USE_STL |
/contrib/other/kpm/tinyxml/tinystr.h |
---|
0,0 → 1,319 |
/* |
www.sourceforge.net/projects/tinyxml |
Original file by Yves Berquin. |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
/* |
* THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005. |
* |
* - completely rewritten. compact, clean, and fast implementation. |
* - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems) |
* - fixed reserve() to work as per specification. |
* - fixed buggy compares operator==(), operator<(), and operator>() |
* - fixed operator+=() to take a const ref argument, following spec. |
* - added "copy" constructor with length, and most compare operators. |
* - added swap(), clear(), size(), capacity(), operator+(). |
*/ |
#ifndef TIXML_USE_STL |
#ifndef TIXML_STRING_INCLUDED |
#define TIXML_STRING_INCLUDED |
#include <assert.h> |
#include <string.h> |
/* The support for explicit isn't that universal, and it isn't really |
required - it is used to check that the TiXmlString class isn't incorrectly |
used. Be nice to old compilers and macro it here: |
*/ |
#if defined(_MSC_VER) && (_MSC_VER >= 1200 ) |
// Microsoft visual studio, version 6 and higher. |
#define TIXML_EXPLICIT explicit |
#elif defined(__GNUC__) && (__GNUC__ >= 3 ) |
// GCC version 3 and higher.s |
#define TIXML_EXPLICIT explicit |
#else |
#define TIXML_EXPLICIT |
#endif |
/* |
TiXmlString is an emulation of a subset of the std::string template. |
Its purpose is to allow compiling TinyXML on compilers with no or poor STL support. |
Only the member functions relevant to the TinyXML project have been implemented. |
The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase |
a string and there's no more room, we allocate a buffer twice as big as we need. |
*/ |
class TiXmlString |
{ |
public : |
// The size type used |
typedef size_t size_type; |
// Error value for find primitive |
static const size_type npos; // = -1; |
// TiXmlString empty constructor |
TiXmlString () : rep_(&nullrep_) |
{ |
} |
// TiXmlString copy constructor |
TiXmlString ( const TiXmlString & copy) : rep_(0) |
{ |
init(copy.length()); |
memcpy(start(), copy.data(), length()); |
} |
// TiXmlString constructor, based on a string |
TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0) |
{ |
init( static_cast<size_type>( strlen(copy) )); |
memcpy(start(), copy, length()); |
} |
// TiXmlString constructor, based on a string |
TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0) |
{ |
init(len); |
memcpy(start(), str, len); |
} |
// TiXmlString destructor |
~TiXmlString () |
{ |
quit(); |
} |
// = operator |
TiXmlString& operator = (const char * copy) |
{ |
return assign( copy, (size_type)strlen(copy)); |
} |
// = operator |
TiXmlString& operator = (const TiXmlString & copy) |
{ |
return assign(copy.start(), copy.length()); |
} |
// += operator. Maps to append |
TiXmlString& operator += (const char * suffix) |
{ |
return append(suffix, static_cast<size_type>( strlen(suffix) )); |
} |
// += operator. Maps to append |
TiXmlString& operator += (char single) |
{ |
return append(&single, 1); |
} |
// += operator. Maps to append |
TiXmlString& operator += (const TiXmlString & suffix) |
{ |
return append(suffix.data(), suffix.length()); |
} |
// Convert a TiXmlString into a null-terminated char * |
const char * c_str () const { return rep_->str; } |
// Convert a TiXmlString into a char * (need not be null terminated). |
const char * data () const { return rep_->str; } |
// Return the length of a TiXmlString |
size_type length () const { return rep_->size; } |
// Alias for length() |
size_type size () const { return rep_->size; } |
// Checks if a TiXmlString is empty |
bool empty () const { return rep_->size == 0; } |
// Return capacity of string |
size_type capacity () const { return rep_->capacity; } |
// single char extraction |
const char& at (size_type index) const |
{ |
assert( index < length() ); |
return rep_->str[ index ]; |
} |
// [] operator |
char& operator [] (size_type index) const |
{ |
assert( index < length() ); |
return rep_->str[ index ]; |
} |
// find a char in a string. Return TiXmlString::npos if not found |
size_type find (char lookup) const |
{ |
return find(lookup, 0); |
} |
// find a char in a string from an offset. Return TiXmlString::npos if not found |
size_type find (char tofind, size_type offset) const |
{ |
if (offset >= length()) return npos; |
for (const char* p = c_str() + offset; *p != '\0'; ++p) |
{ |
if (*p == tofind) return static_cast< size_type >( p - c_str() ); |
} |
return npos; |
} |
void clear () |
{ |
//Lee: |
//The original was just too strange, though correct: |
// TiXmlString().swap(*this); |
//Instead use the quit & re-init: |
quit(); |
init(0,0); |
} |
/* Function to reserve a big amount of data when we know we'll need it. Be aware that this |
function DOES NOT clear the content of the TiXmlString if any exists. |
*/ |
void reserve (size_type cap); |
TiXmlString& assign (const char* str, size_type len); |
TiXmlString& append (const char* str, size_type len); |
void swap (TiXmlString& other) |
{ |
Rep* r = rep_; |
rep_ = other.rep_; |
other.rep_ = r; |
} |
private: |
void init(size_type sz) { init(sz, sz); } |
void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; } |
char* start() const { return rep_->str; } |
char* finish() const { return rep_->str + rep_->size; } |
struct Rep |
{ |
size_type size, capacity; |
char str[1]; |
}; |
void init(size_type sz, size_type cap) |
{ |
if (cap) |
{ |
// Lee: the original form: |
// rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap)); |
// doesn't work in some cases of new being overloaded. Switching |
// to the normal allocation, although use an 'int' for systems |
// that are overly picky about structure alignment. |
const size_type bytesNeeded = sizeof(Rep) + cap; |
const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int ); |
rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] ); |
rep_->str[ rep_->size = sz ] = '\0'; |
rep_->capacity = cap; |
} |
else |
{ |
rep_ = &nullrep_; |
} |
} |
void quit() |
{ |
if (rep_ != &nullrep_) |
{ |
// The rep_ is really an array of ints. (see the allocator, above). |
// Cast it back before delete, so the compiler won't incorrectly call destructors. |
delete [] ( reinterpret_cast<int*>( rep_ ) ); |
} |
} |
Rep * rep_; |
static Rep nullrep_; |
} ; |
inline bool operator == (const TiXmlString & a, const TiXmlString & b) |
{ |
return ( a.length() == b.length() ) // optimization on some platforms |
&& ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare |
} |
inline bool operator < (const TiXmlString & a, const TiXmlString & b) |
{ |
return strcmp(a.c_str(), b.c_str()) < 0; |
} |
inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); } |
inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; } |
inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); } |
inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); } |
inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; } |
inline bool operator == (const char* a, const TiXmlString & b) { return b == a; } |
inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); } |
inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); } |
TiXmlString operator + (const TiXmlString & a, const TiXmlString & b); |
TiXmlString operator + (const TiXmlString & a, const char* b); |
TiXmlString operator + (const char* a, const TiXmlString & b); |
/* |
TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString. |
Only the operators that we need for TinyXML have been developped. |
*/ |
class TiXmlOutStream : public TiXmlString |
{ |
public : |
// TiXmlOutStream << operator. |
TiXmlOutStream & operator << (const TiXmlString & in) |
{ |
*this += in; |
return *this; |
} |
// TiXmlOutStream << operator. |
TiXmlOutStream & operator << (const char * in) |
{ |
*this += in; |
return *this; |
} |
} ; |
#endif // TIXML_STRING_INCLUDED |
#endif // TIXML_USE_STL |
/contrib/other/kpm/tinyxml/tinyxml.cpp |
---|
0,0 → 1,1886 |
/* |
www.sourceforge.net/projects/tinyxml |
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
#ifdef TIXML_USE_STL |
#include <sstream> |
#include <iostream> |
#endif |
#include "tinyxml.h" |
bool TiXmlBase::condenseWhiteSpace = true; |
// Microsoft compiler security |
FILE* TiXmlFOpen( const char* filename, const char* mode ) |
{ |
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) |
FILE* fp = 0; |
errno_t err = fopen_s( &fp, filename, mode ); |
if ( !err && fp ) |
return fp; |
return 0; |
#else |
return fopen( filename, mode ); |
#endif |
} |
void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString ) |
{ |
int i=0; |
while( i<(int)str.length() ) |
{ |
unsigned char c = (unsigned char) str[i]; |
if ( c == '&' |
&& i < ( (int)str.length() - 2 ) |
&& str[i+1] == '#' |
&& str[i+2] == 'x' ) |
{ |
// Hexadecimal character reference. |
// Pass through unchanged. |
// © -- copyright symbol, for example. |
// |
// The -1 is a bug fix from Rob Laveaux. It keeps |
// an overflow from happening if there is no ';'. |
// There are actually 2 ways to exit this loop - |
// while fails (error case) and break (semicolon found). |
// However, there is no mechanism (currently) for |
// this function to return an error. |
while ( i<(int)str.length()-1 ) |
{ |
outString->append( str.c_str() + i, 1 ); |
++i; |
if ( str[i] == ';' ) |
break; |
} |
} |
else if ( c == '&' ) |
{ |
outString->append( entity[0].str, entity[0].strLength ); |
++i; |
} |
else if ( c == '<' ) |
{ |
outString->append( entity[1].str, entity[1].strLength ); |
++i; |
} |
else if ( c == '>' ) |
{ |
outString->append( entity[2].str, entity[2].strLength ); |
++i; |
} |
else if ( c == '\"' ) |
{ |
outString->append( entity[3].str, entity[3].strLength ); |
++i; |
} |
else if ( c == '\'' ) |
{ |
outString->append( entity[4].str, entity[4].strLength ); |
++i; |
} |
else if ( c < 32 ) |
{ |
// Easy pass at non-alpha/numeric/symbol |
// Below 32 is symbolic. |
char buf[ 32 ]; |
#if defined(TIXML_SNPRINTF) |
TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) ); |
#else |
sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) ); |
#endif |
//*ME: warning C4267: convert 'size_t' to 'int' |
//*ME: Int-Cast to make compiler happy ... |
outString->append( buf, (int)strlen( buf ) ); |
++i; |
} |
else |
{ |
//char realc = (char) c; |
//outString->append( &realc, 1 ); |
*outString += (char) c; // somewhat more efficient function call. |
++i; |
} |
} |
} |
TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase() |
{ |
parent = 0; |
type = _type; |
firstChild = 0; |
lastChild = 0; |
prev = 0; |
next = 0; |
} |
TiXmlNode::~TiXmlNode() |
{ |
TiXmlNode* node = firstChild; |
TiXmlNode* temp = 0; |
while ( node ) |
{ |
temp = node; |
node = node->next; |
delete temp; |
} |
} |
void TiXmlNode::CopyTo( TiXmlNode* target ) const |
{ |
target->SetValue (value.c_str() ); |
target->userData = userData; |
} |
void TiXmlNode::Clear() |
{ |
TiXmlNode* node = firstChild; |
TiXmlNode* temp = 0; |
while ( node ) |
{ |
temp = node; |
node = node->next; |
delete temp; |
} |
firstChild = 0; |
lastChild = 0; |
} |
TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node ) |
{ |
assert( node->parent == 0 || node->parent == this ); |
assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() ); |
if ( node->Type() == TiXmlNode::DOCUMENT ) |
{ |
delete node; |
if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
node->parent = this; |
node->prev = lastChild; |
node->next = 0; |
if ( lastChild ) |
lastChild->next = node; |
else |
firstChild = node; // it was an empty list. |
lastChild = node; |
return node; |
} |
TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis ) |
{ |
if ( addThis.Type() == TiXmlNode::DOCUMENT ) |
{ |
if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
TiXmlNode* node = addThis.Clone(); |
if ( !node ) |
return 0; |
return LinkEndChild( node ); |
} |
TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ) |
{ |
if ( !beforeThis || beforeThis->parent != this ) { |
return 0; |
} |
if ( addThis.Type() == TiXmlNode::DOCUMENT ) |
{ |
if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
TiXmlNode* node = addThis.Clone(); |
if ( !node ) |
return 0; |
node->parent = this; |
node->next = beforeThis; |
node->prev = beforeThis->prev; |
if ( beforeThis->prev ) |
{ |
beforeThis->prev->next = node; |
} |
else |
{ |
assert( firstChild == beforeThis ); |
firstChild = node; |
} |
beforeThis->prev = node; |
return node; |
} |
TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ) |
{ |
if ( !afterThis || afterThis->parent != this ) { |
return 0; |
} |
if ( addThis.Type() == TiXmlNode::DOCUMENT ) |
{ |
if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
TiXmlNode* node = addThis.Clone(); |
if ( !node ) |
return 0; |
node->parent = this; |
node->prev = afterThis; |
node->next = afterThis->next; |
if ( afterThis->next ) |
{ |
afterThis->next->prev = node; |
} |
else |
{ |
assert( lastChild == afterThis ); |
lastChild = node; |
} |
afterThis->next = node; |
return node; |
} |
TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ) |
{ |
if ( replaceThis->parent != this ) |
return 0; |
TiXmlNode* node = withThis.Clone(); |
if ( !node ) |
return 0; |
node->next = replaceThis->next; |
node->prev = replaceThis->prev; |
if ( replaceThis->next ) |
replaceThis->next->prev = node; |
else |
lastChild = node; |
if ( replaceThis->prev ) |
replaceThis->prev->next = node; |
else |
firstChild = node; |
delete replaceThis; |
node->parent = this; |
return node; |
} |
bool TiXmlNode::RemoveChild( TiXmlNode* removeThis ) |
{ |
if ( removeThis->parent != this ) |
{ |
assert( 0 ); |
return false; |
} |
if ( removeThis->next ) |
removeThis->next->prev = removeThis->prev; |
else |
lastChild = removeThis->prev; |
if ( removeThis->prev ) |
removeThis->prev->next = removeThis->next; |
else |
firstChild = removeThis->next; |
delete removeThis; |
return true; |
} |
const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = firstChild; node; node = node->next ) |
{ |
if ( strcmp( node->Value(), _value ) == 0 ) |
return node; |
} |
return 0; |
} |
const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = lastChild; node; node = node->prev ) |
{ |
if ( strcmp( node->Value(), _value ) == 0 ) |
return node; |
} |
return 0; |
} |
const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const |
{ |
if ( !previous ) |
{ |
return FirstChild(); |
} |
else |
{ |
assert( previous->parent == this ); |
return previous->NextSibling(); |
} |
} |
const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const |
{ |
if ( !previous ) |
{ |
return FirstChild( val ); |
} |
else |
{ |
assert( previous->parent == this ); |
return previous->NextSibling( val ); |
} |
} |
const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = next; node; node = node->next ) |
{ |
if ( strcmp( node->Value(), _value ) == 0 ) |
return node; |
} |
return 0; |
} |
const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = prev; node; node = node->prev ) |
{ |
if ( strcmp( node->Value(), _value ) == 0 ) |
return node; |
} |
return 0; |
} |
void TiXmlElement::RemoveAttribute( const char * name ) |
{ |
#ifdef TIXML_USE_STL |
TIXML_STRING str( name ); |
TiXmlAttribute* node = attributeSet.Find( str ); |
#else |
TiXmlAttribute* node = attributeSet.Find( name ); |
#endif |
if ( node ) |
{ |
attributeSet.Remove( node ); |
delete node; |
} |
} |
const TiXmlElement* TiXmlNode::FirstChildElement() const |
{ |
const TiXmlNode* node; |
for ( node = FirstChild(); |
node; |
node = node->NextSibling() ) |
{ |
if ( node->ToElement() ) |
return node->ToElement(); |
} |
return 0; |
} |
const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = FirstChild( _value ); |
node; |
node = node->NextSibling( _value ) ) |
{ |
if ( node->ToElement() ) |
return node->ToElement(); |
} |
return 0; |
} |
const TiXmlElement* TiXmlNode::NextSiblingElement() const |
{ |
const TiXmlNode* node; |
for ( node = NextSibling(); |
node; |
node = node->NextSibling() ) |
{ |
if ( node->ToElement() ) |
return node->ToElement(); |
} |
return 0; |
} |
const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const |
{ |
const TiXmlNode* node; |
for ( node = NextSibling( _value ); |
node; |
node = node->NextSibling( _value ) ) |
{ |
if ( node->ToElement() ) |
return node->ToElement(); |
} |
return 0; |
} |
const TiXmlDocument* TiXmlNode::GetDocument() const |
{ |
const TiXmlNode* node; |
for( node = this; node; node = node->parent ) |
{ |
if ( node->ToDocument() ) |
return node->ToDocument(); |
} |
return 0; |
} |
TiXmlElement::TiXmlElement (const char * _value) |
: TiXmlNode( TiXmlNode::ELEMENT ) |
{ |
firstChild = lastChild = 0; |
value = _value; |
} |
#ifdef TIXML_USE_STL |
TiXmlElement::TiXmlElement( const std::string& _value ) |
: TiXmlNode( TiXmlNode::ELEMENT ) |
{ |
firstChild = lastChild = 0; |
value = _value; |
} |
#endif |
TiXmlElement::TiXmlElement( const TiXmlElement& copy) |
: TiXmlNode( TiXmlNode::ELEMENT ) |
{ |
firstChild = lastChild = 0; |
copy.CopyTo( this ); |
} |
void TiXmlElement::operator=( const TiXmlElement& base ) |
{ |
ClearThis(); |
base.CopyTo( this ); |
} |
TiXmlElement::~TiXmlElement() |
{ |
ClearThis(); |
} |
void TiXmlElement::ClearThis() |
{ |
Clear(); |
while( attributeSet.First() ) |
{ |
TiXmlAttribute* node = attributeSet.First(); |
attributeSet.Remove( node ); |
delete node; |
} |
} |
const char* TiXmlElement::Attribute( const char* name ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( node ) |
return node->Value(); |
return 0; |
} |
#ifdef TIXML_USE_STL |
const std::string* TiXmlElement::Attribute( const std::string& name ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( node ) |
return &node->ValueStr(); |
return 0; |
} |
#endif |
const char* TiXmlElement::Attribute( const char* name, int* i ) const |
{ |
const char* s = Attribute( name ); |
if ( i ) |
{ |
if ( s ) { |
*i = atoi( s ); |
} |
else { |
*i = 0; |
} |
} |
return s; |
} |
#ifdef TIXML_USE_STL |
const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const |
{ |
const std::string* s = Attribute( name ); |
if ( i ) |
{ |
if ( s ) { |
*i = atoi( s->c_str() ); |
} |
else { |
*i = 0; |
} |
} |
return s; |
} |
#endif |
const char* TiXmlElement::Attribute( const char* name, double* d ) const |
{ |
const char* s = Attribute( name ); |
if ( d ) |
{ |
if ( s ) { |
*d = atof( s ); |
} |
else { |
*d = 0; |
} |
} |
return s; |
} |
#ifdef TIXML_USE_STL |
const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const |
{ |
const std::string* s = Attribute( name ); |
if ( d ) |
{ |
if ( s ) { |
*d = atof( s->c_str() ); |
} |
else { |
*d = 0; |
} |
} |
return s; |
} |
#endif |
int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
return node->QueryIntValue( ival ); |
} |
#ifdef TIXML_USE_STL |
int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
return node->QueryIntValue( ival ); |
} |
#endif |
int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
return node->QueryDoubleValue( dval ); |
} |
#ifdef TIXML_USE_STL |
int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
return node->QueryDoubleValue( dval ); |
} |
#endif |
void TiXmlElement::SetAttribute( const char * name, int val ) |
{ |
char buf[64]; |
#if defined(TIXML_SNPRINTF) |
TIXML_SNPRINTF( buf, sizeof(buf), "%d", val ); |
#else |
sprintf( buf, "%d", val ); |
#endif |
SetAttribute( name, buf ); |
} |
#ifdef TIXML_USE_STL |
void TiXmlElement::SetAttribute( const std::string& name, int val ) |
{ |
std::ostringstream oss; |
oss << val; |
SetAttribute( name, oss.str() ); |
} |
#endif |
void TiXmlElement::SetDoubleAttribute( const char * name, double val ) |
{ |
char buf[256]; |
#if defined(TIXML_SNPRINTF) |
TIXML_SNPRINTF( buf, sizeof(buf), "%f", val ); |
#else |
sprintf( buf, "%f", val ); |
#endif |
SetAttribute( name, buf ); |
} |
void TiXmlElement::SetAttribute( const char * cname, const char * cvalue ) |
{ |
#ifdef TIXML_USE_STL |
TIXML_STRING _name( cname ); |
TIXML_STRING _value( cvalue ); |
#else |
const char* _name = cname; |
const char* _value = cvalue; |
#endif |
TiXmlAttribute* node = attributeSet.Find( _name ); |
if ( node ) |
{ |
node->SetValue( _value ); |
return; |
} |
TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue ); |
if ( attrib ) |
{ |
attributeSet.Add( attrib ); |
} |
else |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
} |
} |
#ifdef TIXML_USE_STL |
void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value ) |
{ |
TiXmlAttribute* node = attributeSet.Find( name ); |
if ( node ) |
{ |
node->SetValue( _value ); |
return; |
} |
TiXmlAttribute* attrib = new TiXmlAttribute( name, _value ); |
if ( attrib ) |
{ |
attributeSet.Add( attrib ); |
} |
else |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
} |
} |
#endif |
void TiXmlElement::Print( FILE* cfile, int depth ) const |
{ |
int i; |
assert( cfile ); |
for ( i=0; i<depth; i++ ) { |
fprintf( cfile, " " ); |
} |
fprintf( cfile, "<%s", value.c_str() ); |
const TiXmlAttribute* attrib; |
for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() ) |
{ |
fprintf( cfile, " " ); |
attrib->Print( cfile, depth ); |
} |
// There are 3 different formatting approaches: |
// 1) An element without children is printed as a <foo /> node |
// 2) An element with only a text child is printed as <foo> text </foo> |
// 3) An element with children is printed on multiple lines. |
TiXmlNode* node; |
if ( !firstChild ) |
{ |
fprintf( cfile, " />" ); |
} |
else if ( firstChild == lastChild && firstChild->ToText() ) |
{ |
fprintf( cfile, ">" ); |
firstChild->Print( cfile, depth + 1 ); |
fprintf( cfile, "</%s>", value.c_str() ); |
} |
else |
{ |
fprintf( cfile, ">" ); |
for ( node = firstChild; node; node=node->NextSibling() ) |
{ |
if ( !node->ToText() ) |
{ |
fprintf( cfile, "\n" ); |
} |
node->Print( cfile, depth+1 ); |
} |
fprintf( cfile, "\n" ); |
for( i=0; i<depth; ++i ) { |
fprintf( cfile, " " ); |
} |
fprintf( cfile, "</%s>", value.c_str() ); |
} |
} |
void TiXmlElement::CopyTo( TiXmlElement* target ) const |
{ |
// superclass: |
TiXmlNode::CopyTo( target ); |
// Element class: |
// Clone the attributes, then clone the children. |
const TiXmlAttribute* attribute = 0; |
for( attribute = attributeSet.First(); |
attribute; |
attribute = attribute->Next() ) |
{ |
target->SetAttribute( attribute->Name(), attribute->Value() ); |
} |
TiXmlNode* node = 0; |
for ( node = firstChild; node; node = node->NextSibling() ) |
{ |
target->LinkEndChild( node->Clone() ); |
} |
} |
bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const |
{ |
if ( visitor->VisitEnter( *this, attributeSet.First() ) ) |
{ |
for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) |
{ |
if ( !node->Accept( visitor ) ) |
break; |
} |
} |
return visitor->VisitExit( *this ); |
} |
TiXmlNode* TiXmlElement::Clone() const |
{ |
TiXmlElement* clone = new TiXmlElement( Value() ); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
const char* TiXmlElement::GetText() const |
{ |
const TiXmlNode* child = this->FirstChild(); |
if ( child ) { |
const TiXmlText* childText = child->ToText(); |
if ( childText ) { |
return childText->Value(); |
} |
} |
return 0; |
} |
TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT ) |
{ |
tabsize = 4; |
useMicrosoftBOM = false; |
ClearError(); |
} |
TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) |
{ |
tabsize = 4; |
useMicrosoftBOM = false; |
value = documentName; |
ClearError(); |
} |
#ifdef TIXML_USE_STL |
TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT ) |
{ |
tabsize = 4; |
useMicrosoftBOM = false; |
value = documentName; |
ClearError(); |
} |
#endif |
TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT ) |
{ |
copy.CopyTo( this ); |
} |
void TiXmlDocument::operator=( const TiXmlDocument& copy ) |
{ |
Clear(); |
copy.CopyTo( this ); |
} |
bool TiXmlDocument::LoadFile( TiXmlEncoding encoding ) |
{ |
// See STL_STRING_BUG below. |
//StringToBuffer buf( value ); |
return LoadFile( Value(), encoding ); |
} |
bool TiXmlDocument::SaveFile() const |
{ |
// See STL_STRING_BUG below. |
// StringToBuffer buf( value ); |
// |
// if ( buf.buffer && SaveFile( buf.buffer ) ) |
// return true; |
// |
// return false; |
return SaveFile( Value() ); |
} |
bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding ) |
{ |
// There was a really terrifying little bug here. The code: |
// value = filename |
// in the STL case, cause the assignment method of the std::string to |
// be called. What is strange, is that the std::string had the same |
// address as it's c_str() method, and so bad things happen. Looks |
// like a bug in the Microsoft STL implementation. |
// Add an extra string to avoid the crash. |
TIXML_STRING filename( _filename ); |
value = filename; |
// reading in binary mode so that tinyxml can normalize the EOL |
FILE* file = TiXmlFOpen( value.c_str (), "rb" ); |
if ( file ) |
{ |
bool result = LoadFile( file, encoding ); |
fclose( file ); |
return result; |
} |
else |
{ |
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return false; |
} |
} |
bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding ) |
{ |
if ( !file ) |
{ |
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return false; |
} |
// Delete the existing data: |
Clear(); |
location.Clear(); |
// Get the file size, so we can pre-allocate the string. HUGE speed impact. |
long length = 0; |
fseek( file, 0, SEEK_END ); |
length = ftell( file ); |
fseek( file, 0, SEEK_SET ); |
// Strange case, but good to handle up front. |
if ( length <= 0 ) |
{ |
SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return false; |
} |
// If we have a file, assume it is all one big XML file, and read it in. |
// The document parser may decide the document ends sooner than the entire file, however. |
TIXML_STRING data; |
data.reserve( length ); |
// Subtle bug here. TinyXml did use fgets. But from the XML spec: |
// 2.11 End-of-Line Handling |
// <snip> |
// <quote> |
// ...the XML processor MUST behave as if it normalized all line breaks in external |
// parsed entities (including the document entity) on input, before parsing, by translating |
// both the two-character sequence #xD #xA and any #xD that is not followed by #xA to |
// a single #xA character. |
// </quote> |
// |
// It is not clear fgets does that, and certainly isn't clear it works cross platform. |
// Generally, you expect fgets to translate from the convention of the OS to the c/unix |
// convention, and not work generally. |
/* |
while( fgets( buf, sizeof(buf), file ) ) |
{ |
data += buf; |
} |
*/ |
char* buf = new char[ length+1 ]; |
buf[0] = 0; |
if ( fread( buf, length, 1, file ) != 1 ) { |
delete [] buf; |
SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return false; |
} |
const char* lastPos = buf; |
const char* p = buf; |
buf[length] = 0; |
while( *p ) { |
assert( p < (buf+length) ); |
if ( *p == 0xa ) { |
// Newline character. No special rules for this. Append all the characters |
// since the last string, and include the newline. |
data.append( lastPos, (p-lastPos+1) ); // append, include the newline |
++p; // move past the newline |
lastPos = p; // and point to the new buffer (may be 0) |
assert( p <= (buf+length) ); |
} |
else if ( *p == 0xd ) { |
// Carriage return. Append what we have so far, then |
// handle moving forward in the buffer. |
if ( (p-lastPos) > 0 ) { |
data.append( lastPos, p-lastPos ); // do not add the CR |
} |
data += (char)0xa; // a proper newline |
if ( *(p+1) == 0xa ) { |
// Carriage return - new line sequence |
p += 2; |
lastPos = p; |
assert( p <= (buf+length) ); |
} |
else { |
// it was followed by something else...that is presumably characters again. |
++p; |
lastPos = p; |
assert( p <= (buf+length) ); |
} |
} |
else { |
++p; |
} |
} |
// Handle any left over characters. |
if ( p-lastPos ) { |
data.append( lastPos, p-lastPos ); |
} |
delete [] buf; |
buf = 0; |
Parse( data.c_str(), 0, encoding ); |
if ( Error() ) |
return false; |
else |
return true; |
} |
bool TiXmlDocument::SaveFile( const char * filename ) const |
{ |
// The old c stuff lives on... |
FILE* fp = TiXmlFOpen( filename, "w" ); |
if ( fp ) |
{ |
bool result = SaveFile( fp ); |
fclose( fp ); |
return result; |
} |
return false; |
} |
bool TiXmlDocument::SaveFile( FILE* fp ) const |
{ |
if ( useMicrosoftBOM ) |
{ |
const unsigned char TIXML_UTF_LEAD_0 = 0xefU; |
const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; |
const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; |
fputc( TIXML_UTF_LEAD_0, fp ); |
fputc( TIXML_UTF_LEAD_1, fp ); |
fputc( TIXML_UTF_LEAD_2, fp ); |
} |
Print( fp, 0 ); |
return (ferror(fp) == 0); |
} |
void TiXmlDocument::CopyTo( TiXmlDocument* target ) const |
{ |
TiXmlNode::CopyTo( target ); |
target->error = error; |
target->errorId = errorId; |
target->errorDesc = errorDesc; |
target->tabsize = tabsize; |
target->errorLocation = errorLocation; |
target->useMicrosoftBOM = useMicrosoftBOM; |
TiXmlNode* node = 0; |
for ( node = firstChild; node; node = node->NextSibling() ) |
{ |
target->LinkEndChild( node->Clone() ); |
} |
} |
TiXmlNode* TiXmlDocument::Clone() const |
{ |
TiXmlDocument* clone = new TiXmlDocument(); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
void TiXmlDocument::Print( FILE* cfile, int depth ) const |
{ |
assert( cfile ); |
for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) |
{ |
node->Print( cfile, depth ); |
fprintf( cfile, "\n" ); |
} |
} |
bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const |
{ |
if ( visitor->VisitEnter( *this ) ) |
{ |
for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() ) |
{ |
if ( !node->Accept( visitor ) ) |
break; |
} |
} |
return visitor->VisitExit( *this ); |
} |
const TiXmlAttribute* TiXmlAttribute::Next() const |
{ |
// We are using knowledge of the sentinel. The sentinel |
// have a value or name. |
if ( next->value.empty() && next->name.empty() ) |
return 0; |
return next; |
} |
/* |
TiXmlAttribute* TiXmlAttribute::Next() |
{ |
// We are using knowledge of the sentinel. The sentinel |
// have a value or name. |
if ( next->value.empty() && next->name.empty() ) |
return 0; |
return next; |
} |
*/ |
const TiXmlAttribute* TiXmlAttribute::Previous() const |
{ |
// We are using knowledge of the sentinel. The sentinel |
// have a value or name. |
if ( prev->value.empty() && prev->name.empty() ) |
return 0; |
return prev; |
} |
/* |
TiXmlAttribute* TiXmlAttribute::Previous() |
{ |
// We are using knowledge of the sentinel. The sentinel |
// have a value or name. |
if ( prev->value.empty() && prev->name.empty() ) |
return 0; |
return prev; |
} |
*/ |
void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const |
{ |
TIXML_STRING n, v; |
EncodeString( name, &n ); |
EncodeString( value, &v ); |
if (value.find ('\"') == TIXML_STRING::npos) { |
if ( cfile ) { |
fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() ); |
} |
if ( str ) { |
(*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\""; |
} |
} |
else { |
if ( cfile ) { |
fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() ); |
} |
if ( str ) { |
(*str) += n; (*str) += "='"; (*str) += v; (*str) += "'"; |
} |
} |
} |
int TiXmlAttribute::QueryIntValue( int* ival ) const |
{ |
if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 ) |
return TIXML_SUCCESS; |
return TIXML_WRONG_TYPE; |
} |
int TiXmlAttribute::QueryDoubleValue( double* dval ) const |
{ |
if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 ) |
return TIXML_SUCCESS; |
return TIXML_WRONG_TYPE; |
} |
void TiXmlAttribute::SetIntValue( int _value ) |
{ |
char buf [64]; |
#if defined(TIXML_SNPRINTF) |
TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value); |
#else |
sprintf (buf, "%d", _value); |
#endif |
SetValue (buf); |
} |
void TiXmlAttribute::SetDoubleValue( double _value ) |
{ |
char buf [256]; |
#if defined(TIXML_SNPRINTF) |
TIXML_SNPRINTF( buf, sizeof(buf), "%f", _value); |
#else |
sprintf (buf, "%f", _value); |
#endif |
SetValue (buf); |
} |
int TiXmlAttribute::IntValue() const |
{ |
return atoi (value.c_str ()); |
} |
double TiXmlAttribute::DoubleValue() const |
{ |
return atof (value.c_str ()); |
} |
TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT ) |
{ |
copy.CopyTo( this ); |
} |
void TiXmlComment::operator=( const TiXmlComment& base ) |
{ |
Clear(); |
base.CopyTo( this ); |
} |
void TiXmlComment::Print( FILE* cfile, int depth ) const |
{ |
assert( cfile ); |
for ( int i=0; i<depth; i++ ) |
{ |
fprintf( cfile, " " ); |
} |
fprintf( cfile, "<!--%s-->", value.c_str() ); |
} |
void TiXmlComment::CopyTo( TiXmlComment* target ) const |
{ |
TiXmlNode::CopyTo( target ); |
} |
bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const |
{ |
return visitor->Visit( *this ); |
} |
TiXmlNode* TiXmlComment::Clone() const |
{ |
TiXmlComment* clone = new TiXmlComment(); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
void TiXmlText::Print( FILE* cfile, int depth ) const |
{ |
assert( cfile ); |
if ( cdata ) |
{ |
int i; |
fprintf( cfile, "\n" ); |
for ( i=0; i<depth; i++ ) { |
fprintf( cfile, " " ); |
} |
fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output |
} |
else |
{ |
TIXML_STRING buffer; |
EncodeString( value, &buffer ); |
fprintf( cfile, "%s", buffer.c_str() ); |
} |
} |
void TiXmlText::CopyTo( TiXmlText* target ) const |
{ |
TiXmlNode::CopyTo( target ); |
target->cdata = cdata; |
} |
bool TiXmlText::Accept( TiXmlVisitor* visitor ) const |
{ |
return visitor->Visit( *this ); |
} |
TiXmlNode* TiXmlText::Clone() const |
{ |
TiXmlText* clone = 0; |
clone = new TiXmlText( "" ); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
TiXmlDeclaration::TiXmlDeclaration( const char * _version, |
const char * _encoding, |
const char * _standalone ) |
: TiXmlNode( TiXmlNode::DECLARATION ) |
{ |
version = _version; |
encoding = _encoding; |
standalone = _standalone; |
} |
#ifdef TIXML_USE_STL |
TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, |
const std::string& _encoding, |
const std::string& _standalone ) |
: TiXmlNode( TiXmlNode::DECLARATION ) |
{ |
version = _version; |
encoding = _encoding; |
standalone = _standalone; |
} |
#endif |
TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) |
: TiXmlNode( TiXmlNode::DECLARATION ) |
{ |
copy.CopyTo( this ); |
} |
void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy ) |
{ |
Clear(); |
copy.CopyTo( this ); |
} |
void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const |
{ |
if ( cfile ) fprintf( cfile, "<?xml " ); |
if ( str ) (*str) += "<?xml "; |
if ( !version.empty() ) { |
if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ()); |
if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; } |
} |
if ( !encoding.empty() ) { |
if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ()); |
if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; } |
} |
if ( !standalone.empty() ) { |
if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ()); |
if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; } |
} |
if ( cfile ) fprintf( cfile, "?>" ); |
if ( str ) (*str) += "?>"; |
} |
void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const |
{ |
TiXmlNode::CopyTo( target ); |
target->version = version; |
target->encoding = encoding; |
target->standalone = standalone; |
} |
bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const |
{ |
return visitor->Visit( *this ); |
} |
TiXmlNode* TiXmlDeclaration::Clone() const |
{ |
TiXmlDeclaration* clone = new TiXmlDeclaration(); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
void TiXmlUnknown::Print( FILE* cfile, int depth ) const |
{ |
for ( int i=0; i<depth; i++ ) |
fprintf( cfile, " " ); |
fprintf( cfile, "<%s>", value.c_str() ); |
} |
void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const |
{ |
TiXmlNode::CopyTo( target ); |
} |
bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const |
{ |
return visitor->Visit( *this ); |
} |
TiXmlNode* TiXmlUnknown::Clone() const |
{ |
TiXmlUnknown* clone = new TiXmlUnknown(); |
if ( !clone ) |
return 0; |
CopyTo( clone ); |
return clone; |
} |
TiXmlAttributeSet::TiXmlAttributeSet() |
{ |
sentinel.next = &sentinel; |
sentinel.prev = &sentinel; |
} |
TiXmlAttributeSet::~TiXmlAttributeSet() |
{ |
assert( sentinel.next == &sentinel ); |
assert( sentinel.prev == &sentinel ); |
} |
void TiXmlAttributeSet::Add( TiXmlAttribute* addMe ) |
{ |
#ifdef TIXML_USE_STL |
assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set. |
#else |
assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set. |
#endif |
addMe->next = &sentinel; |
addMe->prev = sentinel.prev; |
sentinel.prev->next = addMe; |
sentinel.prev = addMe; |
} |
void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe ) |
{ |
TiXmlAttribute* node; |
for( node = sentinel.next; node != &sentinel; node = node->next ) |
{ |
if ( node == removeMe ) |
{ |
node->prev->next = node->next; |
node->next->prev = node->prev; |
node->next = 0; |
node->prev = 0; |
return; |
} |
} |
assert( 0 ); // we tried to remove a non-linked attribute. |
} |
#ifdef TIXML_USE_STL |
const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const |
{ |
for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
{ |
if ( node->name == name ) |
return node; |
} |
return 0; |
} |
/* |
TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) |
{ |
for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
{ |
if ( node->name == name ) |
return node; |
} |
return 0; |
} |
*/ |
#endif |
const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const |
{ |
for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
{ |
if ( strcmp( node->name.c_str(), name ) == 0 ) |
return node; |
} |
return 0; |
} |
/* |
TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) |
{ |
for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next ) |
{ |
if ( strcmp( node->name.c_str(), name ) == 0 ) |
return node; |
} |
return 0; |
} |
*/ |
#ifdef TIXML_USE_STL |
std::istream& operator>> (std::istream & in, TiXmlNode & base) |
{ |
TIXML_STRING tag; |
tag.reserve( 8 * 1000 ); |
base.StreamIn( &in, &tag ); |
base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING ); |
return in; |
} |
#endif |
#ifdef TIXML_USE_STL |
std::ostream& operator<< (std::ostream & out, const TiXmlNode & base) |
{ |
TiXmlPrinter printer; |
printer.SetStreamPrinting(); |
base.Accept( &printer ); |
out << printer.Str(); |
return out; |
} |
std::string& operator<< (std::string& out, const TiXmlNode& base ) |
{ |
TiXmlPrinter printer; |
printer.SetStreamPrinting(); |
base.Accept( &printer ); |
out.append( printer.Str() ); |
return out; |
} |
#endif |
TiXmlHandle TiXmlHandle::FirstChild() const |
{ |
if ( node ) |
{ |
TiXmlNode* child = node->FirstChild(); |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const |
{ |
if ( node ) |
{ |
TiXmlNode* child = node->FirstChild( value ); |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::FirstChildElement() const |
{ |
if ( node ) |
{ |
TiXmlElement* child = node->FirstChildElement(); |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const |
{ |
if ( node ) |
{ |
TiXmlElement* child = node->FirstChildElement( value ); |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::Child( int count ) const |
{ |
if ( node ) |
{ |
int i; |
TiXmlNode* child = node->FirstChild(); |
for ( i=0; |
child && i<count; |
child = child->NextSibling(), ++i ) |
{ |
// nothing |
} |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const |
{ |
if ( node ) |
{ |
int i; |
TiXmlNode* child = node->FirstChild( value ); |
for ( i=0; |
child && i<count; |
child = child->NextSibling( value ), ++i ) |
{ |
// nothing |
} |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::ChildElement( int count ) const |
{ |
if ( node ) |
{ |
int i; |
TiXmlElement* child = node->FirstChildElement(); |
for ( i=0; |
child && i<count; |
child = child->NextSiblingElement(), ++i ) |
{ |
// nothing |
} |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const |
{ |
if ( node ) |
{ |
int i; |
TiXmlElement* child = node->FirstChildElement( value ); |
for ( i=0; |
child && i<count; |
child = child->NextSiblingElement( value ), ++i ) |
{ |
// nothing |
} |
if ( child ) |
return TiXmlHandle( child ); |
} |
return TiXmlHandle( 0 ); |
} |
bool TiXmlPrinter::VisitEnter( const TiXmlDocument& ) |
{ |
return true; |
} |
bool TiXmlPrinter::VisitExit( const TiXmlDocument& ) |
{ |
return true; |
} |
bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ) |
{ |
DoIndent(); |
buffer += "<"; |
buffer += element.Value(); |
for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() ) |
{ |
buffer += " "; |
attrib->Print( 0, 0, &buffer ); |
} |
if ( !element.FirstChild() ) |
{ |
buffer += " />"; |
DoLineBreak(); |
} |
else |
{ |
buffer += ">"; |
if ( element.FirstChild()->ToText() |
&& element.LastChild() == element.FirstChild() |
&& element.FirstChild()->ToText()->CDATA() == false ) |
{ |
simpleTextPrint = true; |
// no DoLineBreak()! |
} |
else |
{ |
DoLineBreak(); |
} |
} |
++depth; |
return true; |
} |
bool TiXmlPrinter::VisitExit( const TiXmlElement& element ) |
{ |
--depth; |
if ( !element.FirstChild() ) |
{ |
// nothing. |
} |
else |
{ |
if ( simpleTextPrint ) |
{ |
simpleTextPrint = false; |
} |
else |
{ |
DoIndent(); |
} |
buffer += "</"; |
buffer += element.Value(); |
buffer += ">"; |
DoLineBreak(); |
} |
return true; |
} |
bool TiXmlPrinter::Visit( const TiXmlText& text ) |
{ |
if ( text.CDATA() ) |
{ |
DoIndent(); |
buffer += "<![CDATA["; |
buffer += text.Value(); |
buffer += "]]>"; |
DoLineBreak(); |
} |
else if ( simpleTextPrint ) |
{ |
TIXML_STRING str; |
TiXmlBase::EncodeString( text.ValueTStr(), &str ); |
buffer += str; |
} |
else |
{ |
DoIndent(); |
TIXML_STRING str; |
TiXmlBase::EncodeString( text.ValueTStr(), &str ); |
buffer += str; |
DoLineBreak(); |
} |
return true; |
} |
bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration ) |
{ |
DoIndent(); |
declaration.Print( 0, 0, &buffer ); |
DoLineBreak(); |
return true; |
} |
bool TiXmlPrinter::Visit( const TiXmlComment& comment ) |
{ |
DoIndent(); |
buffer += "<!--"; |
buffer += comment.Value(); |
buffer += "-->"; |
DoLineBreak(); |
return true; |
} |
bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown ) |
{ |
DoIndent(); |
buffer += "<"; |
buffer += unknown.Value(); |
buffer += ">"; |
DoLineBreak(); |
return true; |
} |
/contrib/other/kpm/tinyxml/tinyxml.h |
---|
0,0 → 1,1807 |
/* |
www.sourceforge.net/projects/tinyxml |
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
#ifndef TINYXML_INCLUDED |
#define TINYXML_INCLUDED |
#ifdef _MSC_VER |
#pragma warning( push ) |
#pragma warning( disable : 4530 ) |
#pragma warning( disable : 4786 ) |
#endif |
#include <ctype.h> |
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <assert.h> |
// Help out windows: |
#if defined( _DEBUG ) && !defined( DEBUG ) |
#define DEBUG |
#endif |
#ifdef TIXML_USE_STL |
#include <string> |
#include <iostream> |
#include <sstream> |
#define TIXML_STRING std::string |
#else |
#include "tinystr.h" |
#define TIXML_STRING TiXmlString |
#endif |
// Deprecated library function hell. Compilers want to use the |
// new safe versions. This probably doesn't fully address the problem, |
// but it gets closer. There are too many compilers for me to fully |
// test. If you get compilation troubles, undefine TIXML_SAFE |
#define TIXML_SAFE |
#ifdef TIXML_SAFE |
#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) |
// Microsoft visual studio, version 2005 and higher. |
#define TIXML_SNPRINTF _snprintf_s |
#define TIXML_SNSCANF _snscanf_s |
#define TIXML_SSCANF sscanf_s |
#elif defined(_MSC_VER) && (_MSC_VER >= 1200 ) |
// Microsoft visual studio, version 6 and higher. |
//#pragma message( "Using _sn* functions." ) |
#define TIXML_SNPRINTF _snprintf |
#define TIXML_SNSCANF _snscanf |
#define TIXML_SSCANF sscanf |
#elif defined(__GNUC__) && (__GNUC__ >= 3 ) |
// GCC version 3 and higher.s |
//#warning( "Using sn* functions." ) |
#define TIXML_SNPRINTF snprintf |
#define TIXML_SNSCANF snscanf |
#define TIXML_SSCANF sscanf |
#else |
#define TIXML_SSCANF sscanf |
#endif |
#endif |
class TiXmlDocument; |
class TiXmlElement; |
class TiXmlComment; |
class TiXmlUnknown; |
class TiXmlAttribute; |
class TiXmlText; |
class TiXmlDeclaration; |
class TiXmlParsingData; |
const int TIXML_MAJOR_VERSION = 2; |
const int TIXML_MINOR_VERSION = 5; |
const int TIXML_PATCH_VERSION = 3; |
/* Internal structure for tracking location of items |
in the XML file. |
*/ |
struct TiXmlCursor |
{ |
TiXmlCursor() { Clear(); } |
void Clear() { row = col = -1; } |
int row; // 0 based. |
int col; // 0 based. |
}; |
/** |
If you call the Accept() method, it requires being passed a TiXmlVisitor |
class to handle callbacks. For nodes that contain other nodes (Document, Element) |
you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves |
are simple called with Visit(). |
If you return 'true' from a Visit method, recursive parsing will continue. If you return |
false, <b>no children of this node or its sibilings</b> will be Visited. |
All flavors of Visit methods have a default implementation that returns 'true' (continue |
visiting). You need to only override methods that are interesting to you. |
Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting. |
You should never change the document from a callback. |
@sa TiXmlNode::Accept() |
*/ |
class TiXmlVisitor |
{ |
public: |
virtual ~TiXmlVisitor() {} |
/// Visit a document. |
virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; } |
/// Visit a document. |
virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; } |
/// Visit an element. |
virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; } |
/// Visit an element. |
virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; } |
/// Visit a declaration |
virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; } |
/// Visit a text node |
virtual bool Visit( const TiXmlText& /*text*/ ) { return true; } |
/// Visit a comment node |
virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; } |
/// Visit an unknow node |
virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; } |
}; |
// Only used by Attribute::Query functions |
enum |
{ |
TIXML_SUCCESS, |
TIXML_NO_ATTRIBUTE, |
TIXML_WRONG_TYPE |
}; |
// Used by the parsing routines. |
enum TiXmlEncoding |
{ |
TIXML_ENCODING_UNKNOWN, |
TIXML_ENCODING_UTF8, |
TIXML_ENCODING_LEGACY |
}; |
const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN; |
/** TiXmlBase is a base class for every class in TinyXml. |
It does little except to establish that TinyXml classes |
can be printed and provide some utility functions. |
In XML, the document and elements can contain |
other elements and other types of nodes. |
@verbatim |
A Document can contain: Element (container or leaf) |
Comment (leaf) |
Unknown (leaf) |
Declaration( leaf ) |
An Element can contain: Element (container or leaf) |
Text (leaf) |
Attributes (not on tree) |
Comment (leaf) |
Unknown (leaf) |
A Decleration contains: Attributes (not on tree) |
@endverbatim |
*/ |
class TiXmlBase |
{ |
friend class TiXmlNode; |
friend class TiXmlElement; |
friend class TiXmlDocument; |
public: |
TiXmlBase() : userData(0) {} |
virtual ~TiXmlBase() {} |
/** All TinyXml classes can print themselves to a filestream |
or the string class (TiXmlString in non-STL mode, std::string |
in STL mode.) Either or both cfile and str can be null. |
This is a formatted print, and will insert |
tabs and newlines. |
(For an unformatted stream, use the << operator.) |
*/ |
virtual void Print( FILE* cfile, int depth ) const = 0; |
/** The world does not agree on whether white space should be kept or |
not. In order to make everyone happy, these global, static functions |
are provided to set whether or not TinyXml will condense all white space |
into a single space or not. The default is to condense. Note changing this |
value is not thread safe. |
*/ |
static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; } |
/// Return the current white space setting. |
static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; } |
/** Return the position, in the original source file, of this node or attribute. |
The row and column are 1-based. (That is the first row and first column is |
1,1). If the returns values are 0 or less, then the parser does not have |
a row and column value. |
Generally, the row and column value will be set when the TiXmlDocument::Load(), |
TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set |
when the DOM was created from operator>>. |
The values reflect the initial load. Once the DOM is modified programmatically |
(by adding or changing nodes and attributes) the new values will NOT update to |
reflect changes in the document. |
There is a minor performance cost to computing the row and column. Computation |
can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value. |
@sa TiXmlDocument::SetTabSize() |
*/ |
int Row() const { return location.row + 1; } |
int Column() const { return location.col + 1; } ///< See Row() |
void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data. |
void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data. |
const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data. |
// Table that returs, for a given lead byte, the total number of bytes |
// in the UTF-8 sequence. |
static const int utf8ByteTable[256]; |
virtual const char* Parse( const char* p, |
TiXmlParsingData* data, |
TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0; |
/** Expands entities in a string. Note this should not contian the tag's '<', '>', etc, |
or they will be transformed into entities! |
*/ |
static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out ); |
enum |
{ |
TIXML_NO_ERROR = 0, |
TIXML_ERROR, |
TIXML_ERROR_OPENING_FILE, |
TIXML_ERROR_OUT_OF_MEMORY, |
TIXML_ERROR_PARSING_ELEMENT, |
TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, |
TIXML_ERROR_READING_ELEMENT_VALUE, |
TIXML_ERROR_READING_ATTRIBUTES, |
TIXML_ERROR_PARSING_EMPTY, |
TIXML_ERROR_READING_END_TAG, |
TIXML_ERROR_PARSING_UNKNOWN, |
TIXML_ERROR_PARSING_COMMENT, |
TIXML_ERROR_PARSING_DECLARATION, |
TIXML_ERROR_DOCUMENT_EMPTY, |
TIXML_ERROR_EMBEDDED_NULL, |
TIXML_ERROR_PARSING_CDATA, |
TIXML_ERROR_DOCUMENT_TOP_ONLY, |
TIXML_ERROR_STRING_COUNT |
}; |
protected: |
static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding ); |
inline static bool IsWhiteSpace( char c ) |
{ |
// FIXME: Explicit tests for '\n' and '\r' seem redundant here; |
// POSIX requires isspace() to match both of these characters as |
// white space anyway; is there any know implementation which |
// does not comply with this requirement? |
// |
return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' ); |
} |
inline static bool IsWhiteSpace( int c ) |
{ |
if ( c < 256 ) |
return IsWhiteSpace( (char) c ); |
return false; // Again, only truly correct for English/Latin...but usually works. |
} |
#ifdef TIXML_USE_STL |
static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ); |
static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag ); |
#endif |
/* Reads an XML name into the string provided. Returns |
a pointer just past the last character of the name, |
or 0 if the function has an error. |
*/ |
static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding ); |
/* Reads text. Returns a pointer past the given end tag. |
Wickedly complex options, but it keeps the (sensitive) code in one place. |
*/ |
static const char* ReadText( const char* in, // where to start |
TIXML_STRING* text, // the string read |
bool ignoreWhiteSpace, // whether to keep the white space |
const char* endTag, // what ends this text |
bool ignoreCase, // whether to ignore case in the end tag |
TiXmlEncoding encoding ); // the current encoding |
// If an entity has been found, transform it into a character. |
static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding ); |
// Get a character, while interpreting entities. |
// The length can be from 0 to 4 bytes. |
inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding ) |
{ |
assert( p ); |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
*length = utf8ByteTable[ *((const unsigned char*)p) ]; |
assert( *length >= 0 && *length < 5 ); |
} |
else |
{ |
*length = 1; |
} |
if ( *length == 1 ) |
{ |
if ( *p == '&' ) |
return GetEntity( p, _value, length, encoding ); |
*_value = *p; |
return p+1; |
} |
else if ( *length ) |
{ |
//strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe), |
// and the null terminator isn't needed |
for( int i=0; p[i] && i<*length; ++i ) { |
_value[i] = p[i]; |
} |
return p + (*length); |
} |
else |
{ |
// Not valid text. |
return 0; |
} |
} |
// Return true if the next characters in the stream are any of the endTag sequences. |
// Ignore case only works for english, and should only be relied on when comparing |
// to English words: StringEqual( p, "version", true ) is fine. |
static bool StringEqual( const char* p, |
const char* endTag, |
bool ignoreCase, |
TiXmlEncoding encoding ); |
static const char* errorString[ TIXML_ERROR_STRING_COUNT ]; |
TiXmlCursor location; |
/// Field containing a generic user pointer |
void* userData; |
// None of these methods are reliable for any language except English. |
// Good for approximation, not great for accuracy. |
static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding ); |
static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding ); |
inline static int ToLower( int v, TiXmlEncoding encoding ) |
{ |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
if ( v < 128 ) return tolower( v ); |
return v; |
} |
else |
{ |
return tolower( v ); |
} |
} |
static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ); |
private: |
TiXmlBase( const TiXmlBase& ); // not implemented. |
void operator=( const TiXmlBase& base ); // not allowed. |
struct Entity |
{ |
const char* str; |
unsigned int strLength; |
char chr; |
}; |
enum |
{ |
NUM_ENTITY = 5, |
MAX_ENTITY_LENGTH = 6 |
}; |
static Entity entity[ NUM_ENTITY ]; |
static bool condenseWhiteSpace; |
}; |
/** The parent class for everything in the Document Object Model. |
(Except for attributes). |
Nodes have siblings, a parent, and children. A node can be |
in a document, or stand on its own. The type of a TiXmlNode |
can be queried, and it can be cast to its more defined type. |
*/ |
class TiXmlNode : public TiXmlBase |
{ |
friend class TiXmlDocument; |
friend class TiXmlElement; |
public: |
#ifdef TIXML_USE_STL |
/** An input stream operator, for every class. Tolerant of newlines and |
formatting, but doesn't expect them. |
*/ |
friend std::istream& operator >> (std::istream& in, TiXmlNode& base); |
/** An output stream operator, for every class. Note that this outputs |
without any newlines or formatting, as opposed to Print(), which |
includes tabs and new lines. |
The operator<< and operator>> are not completely symmetric. Writing |
a node to a stream is very well defined. You'll get a nice stream |
of output, without any extra whitespace or newlines. |
But reading is not as well defined. (As it always is.) If you create |
a TiXmlElement (for example) and read that from an input stream, |
the text needs to define an element or junk will result. This is |
true of all input streams, but it's worth keeping in mind. |
A TiXmlDocument will read nodes until it reads a root element, and |
all the children of that root element. |
*/ |
friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base); |
/// Appends the XML node or attribute to a std::string. |
friend std::string& operator<< (std::string& out, const TiXmlNode& base ); |
#endif |
/** The types of XML nodes supported by TinyXml. (All the |
unsupported types are picked up by UNKNOWN.) |
*/ |
enum NodeType |
{ |
DOCUMENT, |
ELEMENT, |
COMMENT, |
UNKNOWN, |
TEXT, |
DECLARATION, |
TYPECOUNT |
}; |
virtual ~TiXmlNode(); |
/** The meaning of 'value' changes for the specific type of |
TiXmlNode. |
@verbatim |
Document: filename of the xml file |
Element: name of the element |
Comment: the comment text |
Unknown: the tag contents |
Text: the text string |
@endverbatim |
The subclasses will wrap this function. |
*/ |
const char *Value() const { return value.c_str (); } |
#ifdef TIXML_USE_STL |
/** Return Value() as a std::string. If you only use STL, |
this is more efficient than calling Value(). |
Only available in STL mode. |
*/ |
const std::string& ValueStr() const { return value; } |
#endif |
const TIXML_STRING& ValueTStr() const { return value; } |
/** Changes the value of the node. Defined as: |
@verbatim |
Document: filename of the xml file |
Element: name of the element |
Comment: the comment text |
Unknown: the tag contents |
Text: the text string |
@endverbatim |
*/ |
void SetValue(const char * _value) { value = _value;} |
#ifdef TIXML_USE_STL |
/// STL std::string form. |
void SetValue( const std::string& _value ) { value = _value; } |
#endif |
/// Delete all the children of this node. Does not affect 'this'. |
void Clear(); |
/// One step up the DOM. |
TiXmlNode* Parent() { return parent; } |
const TiXmlNode* Parent() const { return parent; } |
const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children. |
TiXmlNode* FirstChild() { return firstChild; } |
const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found. |
/// The first child of this node with the matching 'value'. Will be null if none found. |
TiXmlNode* FirstChild( const char * _value ) { |
// Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe) |
// call the method, cast the return back to non-const. |
return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value )); |
} |
const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children. |
TiXmlNode* LastChild() { return lastChild; } |
const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children. |
TiXmlNode* LastChild( const char * _value ) { |
return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value )); |
} |
#ifdef TIXML_USE_STL |
const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form. |
TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form. |
const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form. |
TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form. |
#endif |
/** An alternate way to walk the children of a node. |
One way to iterate over nodes is: |
@verbatim |
for( child = parent->FirstChild(); child; child = child->NextSibling() ) |
@endverbatim |
IterateChildren does the same thing with the syntax: |
@verbatim |
child = 0; |
while( child = parent->IterateChildren( child ) ) |
@endverbatim |
IterateChildren takes the previous child as input and finds |
the next one. If the previous child is null, it returns the |
first. IterateChildren will return null when done. |
*/ |
const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const; |
TiXmlNode* IterateChildren( const TiXmlNode* previous ) { |
return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) ); |
} |
/// This flavor of IterateChildren searches for children with a particular 'value' |
const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const; |
TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) { |
return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) ); |
} |
#ifdef TIXML_USE_STL |
const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. |
TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form. |
#endif |
/** Add a new node related to this. Adds a child past the LastChild. |
Returns a pointer to the new object or NULL if an error occured. |
*/ |
TiXmlNode* InsertEndChild( const TiXmlNode& addThis ); |
/** Add a new node related to this. Adds a child past the LastChild. |
NOTE: the node to be added is passed by pointer, and will be |
henceforth owned (and deleted) by tinyXml. This method is efficient |
and avoids an extra copy, but should be used with care as it |
uses a different memory model than the other insert functions. |
@sa InsertEndChild |
*/ |
TiXmlNode* LinkEndChild( TiXmlNode* addThis ); |
/** Add a new node related to this. Adds a child before the specified child. |
Returns a pointer to the new object or NULL if an error occured. |
*/ |
TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis ); |
/** Add a new node related to this. Adds a child after the specified child. |
Returns a pointer to the new object or NULL if an error occured. |
*/ |
TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis ); |
/** Replace a child of this node. |
Returns a pointer to the new object or NULL if an error occured. |
*/ |
TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis ); |
/// Delete a child of this node. |
bool RemoveChild( TiXmlNode* removeThis ); |
/// Navigate to a sibling node. |
const TiXmlNode* PreviousSibling() const { return prev; } |
TiXmlNode* PreviousSibling() { return prev; } |
/// Navigate to a sibling node. |
const TiXmlNode* PreviousSibling( const char * ) const; |
TiXmlNode* PreviousSibling( const char *_prev ) { |
return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) ); |
} |
#ifdef TIXML_USE_STL |
const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. |
TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form. |
const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form. |
TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form. |
#endif |
/// Navigate to a sibling node. |
const TiXmlNode* NextSibling() const { return next; } |
TiXmlNode* NextSibling() { return next; } |
/// Navigate to a sibling node with the given 'value'. |
const TiXmlNode* NextSibling( const char * ) const; |
TiXmlNode* NextSibling( const char* _next ) { |
return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) ); |
} |
/** Convenience function to get through elements. |
Calls NextSibling and ToElement. Will skip all non-Element |
nodes. Returns 0 if there is not another element. |
*/ |
const TiXmlElement* NextSiblingElement() const; |
TiXmlElement* NextSiblingElement() { |
return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() ); |
} |
/** Convenience function to get through elements. |
Calls NextSibling and ToElement. Will skip all non-Element |
nodes. Returns 0 if there is not another element. |
*/ |
const TiXmlElement* NextSiblingElement( const char * ) const; |
TiXmlElement* NextSiblingElement( const char *_next ) { |
return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) ); |
} |
#ifdef TIXML_USE_STL |
const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. |
TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form. |
#endif |
/// Convenience function to get through elements. |
const TiXmlElement* FirstChildElement() const; |
TiXmlElement* FirstChildElement() { |
return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() ); |
} |
/// Convenience function to get through elements. |
const TiXmlElement* FirstChildElement( const char * _value ) const; |
TiXmlElement* FirstChildElement( const char * _value ) { |
return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) ); |
} |
#ifdef TIXML_USE_STL |
const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. |
TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form. |
#endif |
/** Query the type (as an enumerated value, above) of this node. |
The possible types are: DOCUMENT, ELEMENT, COMMENT, |
UNKNOWN, TEXT, and DECLARATION. |
*/ |
int Type() const { return type; } |
/** Return a pointer to the Document this node lives in. |
Returns null if not in a document. |
*/ |
const TiXmlDocument* GetDocument() const; |
TiXmlDocument* GetDocument() { |
return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() ); |
} |
/// Returns true if this node has no children. |
bool NoChildren() const { return !firstChild; } |
virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type. |
/** Create an exact duplicate of this node and return it. The memory must be deleted |
by the caller. |
*/ |
virtual TiXmlNode* Clone() const = 0; |
/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the |
XML tree will be conditionally visited and the host will be called back |
via the TiXmlVisitor interface. |
This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse |
the XML for the callbacks, so the performance of TinyXML is unchanged by using this |
interface versus any other.) |
The interface has been based on ideas from: |
- http://www.saxproject.org/ |
- http://c2.com/cgi/wiki?HierarchicalVisitorPattern |
Which are both good references for "visiting". |
An example of using Accept(): |
@verbatim |
TiXmlPrinter printer; |
tinyxmlDoc.Accept( &printer ); |
const char* xmlcstr = printer.CStr(); |
@endverbatim |
*/ |
virtual bool Accept( TiXmlVisitor* visitor ) const = 0; |
protected: |
TiXmlNode( NodeType _type ); |
// Copy to the allocated object. Shared functionality between Clone, Copy constructor, |
// and the assignment operator. |
void CopyTo( TiXmlNode* target ) const; |
#ifdef TIXML_USE_STL |
// The real work of the input operator. |
virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0; |
#endif |
// Figure out what is at *p, and parse it. Returns null if it is not an xml node. |
TiXmlNode* Identify( const char* start, TiXmlEncoding encoding ); |
TiXmlNode* parent; |
NodeType type; |
TiXmlNode* firstChild; |
TiXmlNode* lastChild; |
TIXML_STRING value; |
TiXmlNode* prev; |
TiXmlNode* next; |
private: |
TiXmlNode( const TiXmlNode& ); // not implemented. |
void operator=( const TiXmlNode& base ); // not allowed. |
}; |
/** An attribute is a name-value pair. Elements have an arbitrary |
number of attributes, each with a unique name. |
@note The attributes are not TiXmlNodes, since they are not |
part of the tinyXML document object model. There are other |
suggested ways to look at this problem. |
*/ |
class TiXmlAttribute : public TiXmlBase |
{ |
friend class TiXmlAttributeSet; |
public: |
/// Construct an empty attribute. |
TiXmlAttribute() : TiXmlBase() |
{ |
document = 0; |
prev = next = 0; |
} |
#ifdef TIXML_USE_STL |
/// std::string constructor. |
TiXmlAttribute( const std::string& _name, const std::string& _value ) |
{ |
name = _name; |
value = _value; |
document = 0; |
prev = next = 0; |
} |
#endif |
/// Construct an attribute with a name and value. |
TiXmlAttribute( const char * _name, const char * _value ) |
{ |
name = _name; |
value = _value; |
document = 0; |
prev = next = 0; |
} |
const char* Name() const { return name.c_str(); } ///< Return the name of this attribute. |
const char* Value() const { return value.c_str(); } ///< Return the value of this attribute. |
#ifdef TIXML_USE_STL |
const std::string& ValueStr() const { return value; } ///< Return the value of this attribute. |
#endif |
int IntValue() const; ///< Return the value of this attribute, converted to an integer. |
double DoubleValue() const; ///< Return the value of this attribute, converted to a double. |
// Get the tinyxml string representation |
const TIXML_STRING& NameTStr() const { return name; } |
/** QueryIntValue examines the value string. It is an alternative to the |
IntValue() method with richer error checking. |
If the value is an integer, it is stored in 'value' and |
the call returns TIXML_SUCCESS. If it is not |
an integer, it returns TIXML_WRONG_TYPE. |
A specialized but useful call. Note that for success it returns 0, |
which is the opposite of almost all other TinyXml calls. |
*/ |
int QueryIntValue( int* _value ) const; |
/// QueryDoubleValue examines the value string. See QueryIntValue(). |
int QueryDoubleValue( double* _value ) const; |
void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute. |
void SetValue( const char* _value ) { value = _value; } ///< Set the value. |
void SetIntValue( int _value ); ///< Set the value from an integer. |
void SetDoubleValue( double _value ); ///< Set the value from a double. |
#ifdef TIXML_USE_STL |
/// STL std::string form. |
void SetName( const std::string& _name ) { name = _name; } |
/// STL std::string form. |
void SetValue( const std::string& _value ) { value = _value; } |
#endif |
/// Get the next sibling attribute in the DOM. Returns null at end. |
const TiXmlAttribute* Next() const; |
TiXmlAttribute* Next() { |
return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() ); |
} |
/// Get the previous sibling attribute in the DOM. Returns null at beginning. |
const TiXmlAttribute* Previous() const; |
TiXmlAttribute* Previous() { |
return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() ); |
} |
bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; } |
bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; } |
bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; } |
/* Attribute parsing starts: first letter of the name |
returns: the next char after the value end quote |
*/ |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
// Prints this Attribute to a FILE stream. |
virtual void Print( FILE* cfile, int depth ) const { |
Print( cfile, depth, 0 ); |
} |
void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; |
// [internal use] |
// Set the document pointer so the attribute can report errors. |
void SetDocument( TiXmlDocument* doc ) { document = doc; } |
private: |
TiXmlAttribute( const TiXmlAttribute& ); // not implemented. |
void operator=( const TiXmlAttribute& base ); // not allowed. |
TiXmlDocument* document; // A pointer back to a document, for error reporting. |
TIXML_STRING name; |
TIXML_STRING value; |
TiXmlAttribute* prev; |
TiXmlAttribute* next; |
}; |
/* A class used to manage a group of attributes. |
It is only used internally, both by the ELEMENT and the DECLARATION. |
The set can be changed transparent to the Element and Declaration |
classes that use it, but NOT transparent to the Attribute |
which has to implement a next() and previous() method. Which makes |
it a bit problematic and prevents the use of STL. |
This version is implemented with circular lists because: |
- I like circular lists |
- it demonstrates some independence from the (typical) doubly linked list. |
*/ |
class TiXmlAttributeSet |
{ |
public: |
TiXmlAttributeSet(); |
~TiXmlAttributeSet(); |
void Add( TiXmlAttribute* attribute ); |
void Remove( TiXmlAttribute* attribute ); |
const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } |
TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; } |
const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } |
TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; } |
const TiXmlAttribute* Find( const char* _name ) const; |
TiXmlAttribute* Find( const char* _name ) { |
return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); |
} |
#ifdef TIXML_USE_STL |
const TiXmlAttribute* Find( const std::string& _name ) const; |
TiXmlAttribute* Find( const std::string& _name ) { |
return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) ); |
} |
#endif |
private: |
//*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element), |
//*ME: this class must be also use a hidden/disabled copy-constructor !!! |
TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed |
void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute) |
TiXmlAttribute sentinel; |
}; |
/** The element is a container class. It has a value, the element name, |
and can contain other elements, text, comments, and unknowns. |
Elements also contain an arbitrary number of attributes. |
*/ |
class TiXmlElement : public TiXmlNode |
{ |
public: |
/// Construct an element. |
TiXmlElement (const char * in_value); |
#ifdef TIXML_USE_STL |
/// std::string constructor. |
TiXmlElement( const std::string& _value ); |
#endif |
TiXmlElement( const TiXmlElement& ); |
void operator=( const TiXmlElement& base ); |
virtual ~TiXmlElement(); |
/** Given an attribute name, Attribute() returns the value |
for the attribute of that name, or null if none exists. |
*/ |
const char* Attribute( const char* name ) const; |
/** Given an attribute name, Attribute() returns the value |
for the attribute of that name, or null if none exists. |
If the attribute exists and can be converted to an integer, |
the integer value will be put in the return 'i', if 'i' |
is non-null. |
*/ |
const char* Attribute( const char* name, int* i ) const; |
/** Given an attribute name, Attribute() returns the value |
for the attribute of that name, or null if none exists. |
If the attribute exists and can be converted to an double, |
the double value will be put in the return 'd', if 'd' |
is non-null. |
*/ |
const char* Attribute( const char* name, double* d ) const; |
/** QueryIntAttribute examines the attribute - it is an alternative to the |
Attribute() method with richer error checking. |
If the attribute is an integer, it is stored in 'value' and |
the call returns TIXML_SUCCESS. If it is not |
an integer, it returns TIXML_WRONG_TYPE. If the attribute |
does not exist, then TIXML_NO_ATTRIBUTE is returned. |
*/ |
int QueryIntAttribute( const char* name, int* _value ) const; |
/// QueryDoubleAttribute examines the attribute - see QueryIntAttribute(). |
int QueryDoubleAttribute( const char* name, double* _value ) const; |
/// QueryFloatAttribute examines the attribute - see QueryIntAttribute(). |
int QueryFloatAttribute( const char* name, float* _value ) const { |
double d; |
int result = QueryDoubleAttribute( name, &d ); |
if ( result == TIXML_SUCCESS ) { |
*_value = (float)d; |
} |
return result; |
} |
#ifdef TIXML_USE_STL |
/** Template form of the attribute query which will try to read the |
attribute into the specified type. Very easy, very powerful, but |
be careful to make sure to call this with the correct type. |
NOTE: This method doesn't work correctly for 'string' types. |
@return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE |
*/ |
template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
std::stringstream sstream( node->ValueStr() ); |
sstream >> *outValue; |
if ( !sstream.fail() ) |
return TIXML_SUCCESS; |
return TIXML_WRONG_TYPE; |
} |
/* |
This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string" |
but template specialization is hard to get working cross-compiler. Leaving the bug for now. |
// The above will fail for std::string because the space character is used as a seperator. |
// Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string |
template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const |
{ |
const TiXmlAttribute* node = attributeSet.Find( name ); |
if ( !node ) |
return TIXML_NO_ATTRIBUTE; |
*outValue = node->ValueStr(); |
return TIXML_SUCCESS; |
} |
*/ |
#endif |
/** Sets an attribute of name to a given value. The attribute |
will be created if it does not exist, or changed if it does. |
*/ |
void SetAttribute( const char* name, const char * _value ); |
#ifdef TIXML_USE_STL |
const std::string* Attribute( const std::string& name ) const; |
const std::string* Attribute( const std::string& name, int* i ) const; |
const std::string* Attribute( const std::string& name, double* d ) const; |
int QueryIntAttribute( const std::string& name, int* _value ) const; |
int QueryDoubleAttribute( const std::string& name, double* _value ) const; |
/// STL std::string form. |
void SetAttribute( const std::string& name, const std::string& _value ); |
///< STL std::string form. |
void SetAttribute( const std::string& name, int _value ); |
#endif |
/** Sets an attribute of name to a given value. The attribute |
will be created if it does not exist, or changed if it does. |
*/ |
void SetAttribute( const char * name, int value ); |
/** Sets an attribute of name to a given value. The attribute |
will be created if it does not exist, or changed if it does. |
*/ |
void SetDoubleAttribute( const char * name, double value ); |
/** Deletes an attribute with the given name. |
*/ |
void RemoveAttribute( const char * name ); |
#ifdef TIXML_USE_STL |
void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form. |
#endif |
const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element. |
TiXmlAttribute* FirstAttribute() { return attributeSet.First(); } |
const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element. |
TiXmlAttribute* LastAttribute() { return attributeSet.Last(); } |
/** Convenience function for easy access to the text inside an element. Although easy |
and concise, GetText() is limited compared to getting the TiXmlText child |
and accessing it directly. |
If the first child of 'this' is a TiXmlText, the GetText() |
returns the character string of the Text node, else null is returned. |
This is a convenient method for getting the text of simple contained text: |
@verbatim |
<foo>This is text</foo> |
const char* str = fooElement->GetText(); |
@endverbatim |
'str' will be a pointer to "This is text". |
Note that this function can be misleading. If the element foo was created from |
this XML: |
@verbatim |
<foo><b>This is text</b></foo> |
@endverbatim |
then the value of str would be null. The first child node isn't a text node, it is |
another element. From this XML: |
@verbatim |
<foo>This is <b>text</b></foo> |
@endverbatim |
GetText() will return "This is ". |
WARNING: GetText() accesses a child node - don't become confused with the |
similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are |
safe type casts on the referenced node. |
*/ |
const char* GetText() const; |
/// Creates a new Element and returns it - the returned element is a copy. |
virtual TiXmlNode* Clone() const; |
// Print the Element to a FILE stream. |
virtual void Print( FILE* cfile, int depth ) const; |
/* Attribtue parsing starts: next char past '<' |
returns: next char past '>' |
*/ |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* visitor ) const; |
protected: |
void CopyTo( TiXmlElement* target ) const; |
void ClearThis(); // like clear, but initializes 'this' object as well |
// Used to be public [internal use] |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
/* [internal use] |
Reads the "value" of the element -- another element, or text. |
This should terminate with the current end tag. |
*/ |
const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding ); |
private: |
TiXmlAttributeSet attributeSet; |
}; |
/** An XML comment. |
*/ |
class TiXmlComment : public TiXmlNode |
{ |
public: |
/// Constructs an empty comment. |
TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {} |
/// Construct a comment from text. |
TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) { |
SetValue( _value ); |
} |
TiXmlComment( const TiXmlComment& ); |
void operator=( const TiXmlComment& base ); |
virtual ~TiXmlComment() {} |
/// Returns a copy of this Comment. |
virtual TiXmlNode* Clone() const; |
// Write this Comment to a FILE stream. |
virtual void Print( FILE* cfile, int depth ) const; |
/* Attribtue parsing starts: at the ! of the !-- |
returns: next char past '>' |
*/ |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* visitor ) const; |
protected: |
void CopyTo( TiXmlComment* target ) const; |
// used to be public |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
// virtual void StreamOut( TIXML_OSTREAM * out ) const; |
private: |
}; |
/** XML text. A text node can have 2 ways to output the next. "normal" output |
and CDATA. It will default to the mode it was parsed from the XML file and |
you generally want to leave it alone, but you can change the output mode with |
SetCDATA() and query it with CDATA(). |
*/ |
class TiXmlText : public TiXmlNode |
{ |
friend class TiXmlElement; |
public: |
/** Constructor for text element. By default, it is treated as |
normal, encoded text. If you want it be output as a CDATA text |
element, set the parameter _cdata to 'true' |
*/ |
TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT) |
{ |
SetValue( initValue ); |
cdata = false; |
} |
virtual ~TiXmlText() {} |
#ifdef TIXML_USE_STL |
/// Constructor. |
TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT) |
{ |
SetValue( initValue ); |
cdata = false; |
} |
#endif |
TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); } |
void operator=( const TiXmlText& base ) { base.CopyTo( this ); } |
// Write this text object to a FILE stream. |
virtual void Print( FILE* cfile, int depth ) const; |
/// Queries whether this represents text using a CDATA section. |
bool CDATA() const { return cdata; } |
/// Turns on or off a CDATA representation of text. |
void SetCDATA( bool _cdata ) { cdata = _cdata; } |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* content ) const; |
protected : |
/// [internal use] Creates a new Element and returns it. |
virtual TiXmlNode* Clone() const; |
void CopyTo( TiXmlText* target ) const; |
bool Blank() const; // returns true if all white space and new lines |
// [internal use] |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
private: |
bool cdata; // true if this should be input and output as a CDATA style text element |
}; |
/** In correct XML the declaration is the first entry in the file. |
@verbatim |
<?xml version="1.0" standalone="yes"?> |
@endverbatim |
TinyXml will happily read or write files without a declaration, |
however. There are 3 possible attributes to the declaration: |
version, encoding, and standalone. |
Note: In this version of the code, the attributes are |
handled as special cases, not generic attributes, simply |
because there can only be at most 3 and they are always the same. |
*/ |
class TiXmlDeclaration : public TiXmlNode |
{ |
public: |
/// Construct an empty declaration. |
TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {} |
#ifdef TIXML_USE_STL |
/// Constructor. |
TiXmlDeclaration( const std::string& _version, |
const std::string& _encoding, |
const std::string& _standalone ); |
#endif |
/// Construct. |
TiXmlDeclaration( const char* _version, |
const char* _encoding, |
const char* _standalone ); |
TiXmlDeclaration( const TiXmlDeclaration& copy ); |
void operator=( const TiXmlDeclaration& copy ); |
virtual ~TiXmlDeclaration() {} |
/// Version. Will return an empty string if none was found. |
const char *Version() const { return version.c_str (); } |
/// Encoding. Will return an empty string if none was found. |
const char *Encoding() const { return encoding.c_str (); } |
/// Is this a standalone document? |
const char *Standalone() const { return standalone.c_str (); } |
/// Creates a copy of this Declaration and returns it. |
virtual TiXmlNode* Clone() const; |
// Print this declaration to a FILE stream. |
virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const; |
virtual void Print( FILE* cfile, int depth ) const { |
Print( cfile, depth, 0 ); |
} |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* visitor ) const; |
protected: |
void CopyTo( TiXmlDeclaration* target ) const; |
// used to be public |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
private: |
TIXML_STRING version; |
TIXML_STRING encoding; |
TIXML_STRING standalone; |
}; |
/** Any tag that tinyXml doesn't recognize is saved as an |
unknown. It is a tag of text, but should not be modified. |
It will be written back to the XML, unchanged, when the file |
is saved. |
DTD tags get thrown into TiXmlUnknowns. |
*/ |
class TiXmlUnknown : public TiXmlNode |
{ |
public: |
TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {} |
virtual ~TiXmlUnknown() {} |
TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); } |
void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); } |
/// Creates a copy of this Unknown and returns it. |
virtual TiXmlNode* Clone() const; |
// Print this Unknown to a FILE stream. |
virtual void Print( FILE* cfile, int depth ) const; |
virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ); |
virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* content ) const; |
protected: |
void CopyTo( TiXmlUnknown* target ) const; |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
private: |
}; |
/** Always the top level node. A document binds together all the |
XML pieces. It can be saved, loaded, and printed to the screen. |
The 'value' of a document node is the xml file name. |
*/ |
class TiXmlDocument : public TiXmlNode |
{ |
public: |
/// Create an empty document, that has no name. |
TiXmlDocument(); |
/// Create a document with a name. The name of the document is also the filename of the xml. |
TiXmlDocument( const char * documentName ); |
#ifdef TIXML_USE_STL |
/// Constructor. |
TiXmlDocument( const std::string& documentName ); |
#endif |
TiXmlDocument( const TiXmlDocument& copy ); |
void operator=( const TiXmlDocument& copy ); |
virtual ~TiXmlDocument() {} |
/** Load a file using the current document value. |
Returns true if successful. Will delete any existing |
document data before loading. |
*/ |
bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); |
/// Save a file using the current document value. Returns true if successful. |
bool SaveFile() const; |
/// Load a file using the given filename. Returns true if successful. |
bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); |
/// Save a file using the given filename. Returns true if successful. |
bool SaveFile( const char * filename ) const; |
/** Load a file using the given FILE*. Returns true if successful. Note that this method |
doesn't stream - the entire object pointed at by the FILE* |
will be interpreted as an XML file. TinyXML doesn't stream in XML from the current |
file location. Streaming may be added in the future. |
*/ |
bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); |
/// Save a file using the given FILE*. Returns true if successful. |
bool SaveFile( FILE* ) const; |
#ifdef TIXML_USE_STL |
bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version. |
{ |
// StringToBuffer f( filename ); |
// return ( f.buffer && LoadFile( f.buffer, encoding )); |
return LoadFile( filename.c_str(), encoding ); |
} |
bool SaveFile( const std::string& filename ) const ///< STL std::string version. |
{ |
// StringToBuffer f( filename ); |
// return ( f.buffer && SaveFile( f.buffer )); |
return SaveFile( filename.c_str() ); |
} |
#endif |
/** Parse the given null terminated block of xml data. Passing in an encoding to this |
method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml |
to use that encoding, regardless of what TinyXml might otherwise try to detect. |
*/ |
virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ); |
/** Get the root element -- the only top level element -- of the document. |
In well formed XML, there should only be one. TinyXml is tolerant of |
multiple elements at the document level. |
*/ |
const TiXmlElement* RootElement() const { return FirstChildElement(); } |
TiXmlElement* RootElement() { return FirstChildElement(); } |
/** If an error occurs, Error will be set to true. Also, |
- The ErrorId() will contain the integer identifier of the error (not generally useful) |
- The ErrorDesc() method will return the name of the error. (very useful) |
- The ErrorRow() and ErrorCol() will return the location of the error (if known) |
*/ |
bool Error() const { return error; } |
/// Contains a textual (english) description of the error if one occurs. |
const char * ErrorDesc() const { return errorDesc.c_str (); } |
/** Generally, you probably want the error string ( ErrorDesc() ). But if you |
prefer the ErrorId, this function will fetch it. |
*/ |
int ErrorId() const { return errorId; } |
/** Returns the location (if known) of the error. The first column is column 1, |
and the first row is row 1. A value of 0 means the row and column wasn't applicable |
(memory errors, for example, have no row/column) or the parser lost the error. (An |
error in the error reporting, in that case.) |
@sa SetTabSize, Row, Column |
*/ |
int ErrorRow() const { return errorLocation.row+1; } |
int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow() |
/** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol()) |
to report the correct values for row and column. It does not change the output |
or input in any way. |
By calling this method, with a tab size |
greater than 0, the row and column of each node and attribute is stored |
when the file is loaded. Very useful for tracking the DOM back in to |
the source file. |
The tab size is required for calculating the location of nodes. If not |
set, the default of 4 is used. The tabsize is set per document. Setting |
the tabsize to 0 disables row/column tracking. |
Note that row and column tracking is not supported when using operator>>. |
The tab size needs to be enabled before the parse or load. Correct usage: |
@verbatim |
TiXmlDocument doc; |
doc.SetTabSize( 8 ); |
doc.Load( "myfile.xml" ); |
@endverbatim |
@sa Row, Column |
*/ |
void SetTabSize( int _tabsize ) { tabsize = _tabsize; } |
int TabSize() const { return tabsize; } |
/** If you have handled the error, it can be reset with this call. The error |
state is automatically cleared if you Parse a new XML block. |
*/ |
void ClearError() { error = false; |
errorId = 0; |
errorDesc = ""; |
errorLocation.row = errorLocation.col = 0; |
//errorLocation.last = 0; |
} |
/** Write the document to standard out using formatted printing ("pretty print"). */ |
void Print() const { Print( stdout, 0 ); } |
/* Write the document to a string using formatted printing ("pretty print"). This |
will allocate a character array (new char[]) and return it as a pointer. The |
calling code pust call delete[] on the return char* to avoid a memory leak. |
*/ |
//char* PrintToMemory() const; |
/// Print this Document to a FILE stream. |
virtual void Print( FILE* cfile, int depth = 0 ) const; |
// [internal use] |
void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding ); |
virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type. |
/** Walk the XML tree visiting this node and all of its children. |
*/ |
virtual bool Accept( TiXmlVisitor* content ) const; |
protected : |
// [internal use] |
virtual TiXmlNode* Clone() const; |
#ifdef TIXML_USE_STL |
virtual void StreamIn( std::istream * in, TIXML_STRING * tag ); |
#endif |
private: |
void CopyTo( TiXmlDocument* target ) const; |
bool error; |
int errorId; |
TIXML_STRING errorDesc; |
int tabsize; |
TiXmlCursor errorLocation; |
bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write. |
}; |
/** |
A TiXmlHandle is a class that wraps a node pointer with null checks; this is |
an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml |
DOM structure. It is a separate utility class. |
Take an example: |
@verbatim |
<Document> |
<Element attributeA = "valueA"> |
<Child attributeB = "value1" /> |
<Child attributeB = "value2" /> |
</Element> |
<Document> |
@endverbatim |
Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very |
easy to write a *lot* of code that looks like: |
@verbatim |
TiXmlElement* root = document.FirstChildElement( "Document" ); |
if ( root ) |
{ |
TiXmlElement* element = root->FirstChildElement( "Element" ); |
if ( element ) |
{ |
TiXmlElement* child = element->FirstChildElement( "Child" ); |
if ( child ) |
{ |
TiXmlElement* child2 = child->NextSiblingElement( "Child" ); |
if ( child2 ) |
{ |
// Finally do something useful. |
@endverbatim |
And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity |
of such code. A TiXmlHandle checks for null pointers so it is perfectly safe |
and correct to use: |
@verbatim |
TiXmlHandle docHandle( &document ); |
TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement(); |
if ( child2 ) |
{ |
// do something useful |
@endverbatim |
Which is MUCH more concise and useful. |
It is also safe to copy handles - internally they are nothing more than node pointers. |
@verbatim |
TiXmlHandle handleCopy = handle; |
@endverbatim |
What they should not be used for is iteration: |
@verbatim |
int i=0; |
while ( true ) |
{ |
TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement(); |
if ( !child ) |
break; |
// do something |
++i; |
} |
@endverbatim |
It seems reasonable, but it is in fact two embedded while loops. The Child method is |
a linear walk to find the element, so this code would iterate much more than it needs |
to. Instead, prefer: |
@verbatim |
TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement(); |
for( child; child; child=child->NextSiblingElement() ) |
{ |
// do something |
} |
@endverbatim |
*/ |
class TiXmlHandle |
{ |
public: |
/// Create a handle from any node (at any depth of the tree.) This can be a null pointer. |
TiXmlHandle( TiXmlNode* _node ) { this->node = _node; } |
/// Copy constructor |
TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; } |
TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; } |
/// Return a handle to the first child node. |
TiXmlHandle FirstChild() const; |
/// Return a handle to the first child node with the given name. |
TiXmlHandle FirstChild( const char * value ) const; |
/// Return a handle to the first child element. |
TiXmlHandle FirstChildElement() const; |
/// Return a handle to the first child element with the given name. |
TiXmlHandle FirstChildElement( const char * value ) const; |
/** Return a handle to the "index" child with the given name. |
The first child is 0, the second 1, etc. |
*/ |
TiXmlHandle Child( const char* value, int index ) const; |
/** Return a handle to the "index" child. |
The first child is 0, the second 1, etc. |
*/ |
TiXmlHandle Child( int index ) const; |
/** Return a handle to the "index" child element with the given name. |
The first child element is 0, the second 1, etc. Note that only TiXmlElements |
are indexed: other types are not counted. |
*/ |
TiXmlHandle ChildElement( const char* value, int index ) const; |
/** Return a handle to the "index" child element. |
The first child element is 0, the second 1, etc. Note that only TiXmlElements |
are indexed: other types are not counted. |
*/ |
TiXmlHandle ChildElement( int index ) const; |
#ifdef TIXML_USE_STL |
TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); } |
TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); } |
TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); } |
TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); } |
#endif |
/** Return the handle as a TiXmlNode. This may return null. |
*/ |
TiXmlNode* ToNode() const { return node; } |
/** Return the handle as a TiXmlElement. This may return null. |
*/ |
TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); } |
/** Return the handle as a TiXmlText. This may return null. |
*/ |
TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); } |
/** Return the handle as a TiXmlUnknown. This may return null. |
*/ |
TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); } |
/** @deprecated use ToNode. |
Return the handle as a TiXmlNode. This may return null. |
*/ |
TiXmlNode* Node() const { return ToNode(); } |
/** @deprecated use ToElement. |
Return the handle as a TiXmlElement. This may return null. |
*/ |
TiXmlElement* Element() const { return ToElement(); } |
/** @deprecated use ToText() |
Return the handle as a TiXmlText. This may return null. |
*/ |
TiXmlText* Text() const { return ToText(); } |
/** @deprecated use ToUnknown() |
Return the handle as a TiXmlUnknown. This may return null. |
*/ |
TiXmlUnknown* Unknown() const { return ToUnknown(); } |
private: |
TiXmlNode* node; |
}; |
/** Print to memory functionality. The TiXmlPrinter is useful when you need to: |
-# Print to memory (especially in non-STL mode) |
-# Control formatting (line endings, etc.) |
When constructed, the TiXmlPrinter is in its default "pretty printing" mode. |
Before calling Accept() you can call methods to control the printing |
of the XML document. After TiXmlNode::Accept() is called, the printed document can |
be accessed via the CStr(), Str(), and Size() methods. |
TiXmlPrinter uses the Visitor API. |
@verbatim |
TiXmlPrinter printer; |
printer.SetIndent( "\t" ); |
doc.Accept( &printer ); |
fprintf( stdout, "%s", printer.CStr() ); |
@endverbatim |
*/ |
class TiXmlPrinter : public TiXmlVisitor |
{ |
public: |
TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ), |
buffer(), indent( " " ), lineBreak( "\n" ) {} |
virtual bool VisitEnter( const TiXmlDocument& doc ); |
virtual bool VisitExit( const TiXmlDocument& doc ); |
virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute ); |
virtual bool VisitExit( const TiXmlElement& element ); |
virtual bool Visit( const TiXmlDeclaration& declaration ); |
virtual bool Visit( const TiXmlText& text ); |
virtual bool Visit( const TiXmlComment& comment ); |
virtual bool Visit( const TiXmlUnknown& unknown ); |
/** Set the indent characters for printing. By default 4 spaces |
but tab (\t) is also useful, or null/empty string for no indentation. |
*/ |
void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; } |
/// Query the indention string. |
const char* Indent() { return indent.c_str(); } |
/** Set the line breaking string. By default set to newline (\n). |
Some operating systems prefer other characters, or can be |
set to the null/empty string for no indenation. |
*/ |
void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; } |
/// Query the current line breaking string. |
const char* LineBreak() { return lineBreak.c_str(); } |
/** Switch over to "stream printing" which is the most dense formatting without |
linebreaks. Common when the XML is needed for network transmission. |
*/ |
void SetStreamPrinting() { indent = ""; |
lineBreak = ""; |
} |
/// Return the result. |
const char* CStr() { return buffer.c_str(); } |
/// Return the length of the result string. |
size_t Size() { return buffer.size(); } |
#ifdef TIXML_USE_STL |
/// Return the result. |
const std::string& Str() { return buffer; } |
#endif |
private: |
void DoIndent() { |
for( int i=0; i<depth; ++i ) |
buffer += indent; |
} |
void DoLineBreak() { |
buffer += lineBreak; |
} |
int depth; |
bool simpleTextPrint; |
TIXML_STRING buffer; |
TIXML_STRING indent; |
TIXML_STRING lineBreak; |
}; |
#ifdef _MSC_VER |
#pragma warning( pop ) |
#endif |
#endif |
/contrib/other/kpm/tinyxml/tinyxmlerror.cpp |
---|
0,0 → 1,53 |
/* |
www.sourceforge.net/projects/tinyxml |
Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com) |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
#include "tinyxml.h" |
// The goal of the seperate error file is to make the first |
// step towards localization. tinyxml (currently) only supports |
// english error messages, but the could now be translated. |
// |
// It also cleans up the code a bit. |
// |
const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] = |
{ |
"No error", |
"Error", |
"Failed to open file", |
"Memory allocation failed.", |
"Error parsing Element.", |
"Failed to read Element name", |
"Error reading Element value.", |
"Error reading Attributes.", |
"Error: empty tag.", |
"Error reading end tag.", |
"Error parsing Unknown.", |
"Error parsing Comment.", |
"Error parsing Declaration.", |
"Error document empty.", |
"Error null (0) or unexpected EOF found in input stream.", |
"Error parsing CDATA.", |
"Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.", |
}; |
/contrib/other/kpm/tinyxml/tinyxmlparser.cpp |
---|
0,0 → 1,1635 |
/* |
www.sourceforge.net/projects/tinyxml |
Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com) |
This software is provided 'as-is', without any express or implied |
warranty. In no event will the authors be held liable for any |
damages arising from the use of this software. |
Permission is granted to anyone to use this software for any |
purpose, including commercial applications, and to alter it and |
redistribute it freely, subject to the following restrictions: |
1. The origin of this software must not be misrepresented; you must |
not claim that you wrote the original software. If you use this |
software in a product, an acknowledgment in the product documentation |
would be appreciated but is not required. |
2. Altered source versions must be plainly marked as such, and |
must not be misrepresented as being the original software. |
3. This notice may not be removed or altered from any source |
distribution. |
*/ |
#include "tinyxml.h" |
//#define DEBUG_PARSER |
#if defined( DEBUG_PARSER ) |
# if defined( DEBUG ) && defined( _MSC_VER ) |
# include <windows.h> |
# define TIXML_LOG OutputDebugString |
# else |
# define TIXML_LOG printf |
# endif |
#endif |
// Note tha "PutString" hardcodes the same list. This |
// is less flexible than it appears. Changing the entries |
// or order will break putstring. |
TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = |
{ |
{ "&", 5, '&' }, |
{ "<", 4, '<' }, |
{ ">", 4, '>' }, |
{ """, 6, '\"' }, |
{ "'", 6, '\'' } |
}; |
// Bunch of unicode info at: |
// http://www.unicode.org/faq/utf_bom.html |
// Including the basic of this table, which determines the #bytes in the |
// sequence from the lead byte. 1 placed for invalid sequences -- |
// although the result will be junk, pass it through as much as possible. |
// Beware of the non-characters in UTF-8: |
// ef bb bf (Microsoft "lead bytes") |
// ef bf be |
// ef bf bf |
const unsigned char TIXML_UTF_LEAD_0 = 0xefU; |
const unsigned char TIXML_UTF_LEAD_1 = 0xbbU; |
const unsigned char TIXML_UTF_LEAD_2 = 0xbfU; |
const int TiXmlBase::utf8ByteTable[256] = |
{ |
// 0 1 2 3 4 5 6 7 8 9 a b c d e f |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0 |
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0 |
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte |
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0 |
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte |
4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid |
}; |
void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length ) |
{ |
const unsigned long BYTE_MASK = 0xBF; |
const unsigned long BYTE_MARK = 0x80; |
const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; |
if (input < 0x80) |
*length = 1; |
else if ( input < 0x800 ) |
*length = 2; |
else if ( input < 0x10000 ) |
*length = 3; |
else if ( input < 0x200000 ) |
*length = 4; |
else |
{ *length = 0; return; } // This code won't covert this correctly anyway. |
output += *length; |
// Scary scary fall throughs. |
switch (*length) |
{ |
case 4: |
--output; |
*output = (char)((input | BYTE_MARK) & BYTE_MASK); |
input >>= 6; |
case 3: |
--output; |
*output = (char)((input | BYTE_MARK) & BYTE_MASK); |
input >>= 6; |
case 2: |
--output; |
*output = (char)((input | BYTE_MARK) & BYTE_MASK); |
input >>= 6; |
case 1: |
--output; |
*output = (char)(input | FIRST_BYTE_MARK[*length]); |
} |
} |
/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) |
{ |
// This will only work for low-ascii, everything else is assumed to be a valid |
// letter. I'm not sure this is the best approach, but it is quite tricky trying |
// to figure out alhabetical vs. not across encoding. So take a very |
// conservative approach. |
// if ( encoding == TIXML_ENCODING_UTF8 ) |
// { |
if ( anyByte < 127 ) |
return isalpha( anyByte ); |
else |
return 1; // What else to do? The unicode set is huge...get the english ones right. |
// } |
// else |
// { |
// return isalpha( anyByte ); |
// } |
} |
/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ ) |
{ |
// This will only work for low-ascii, everything else is assumed to be a valid |
// letter. I'm not sure this is the best approach, but it is quite tricky trying |
// to figure out alhabetical vs. not across encoding. So take a very |
// conservative approach. |
// if ( encoding == TIXML_ENCODING_UTF8 ) |
// { |
if ( anyByte < 127 ) |
return isalnum( anyByte ); |
else |
return 1; // What else to do? The unicode set is huge...get the english ones right. |
// } |
// else |
// { |
// return isalnum( anyByte ); |
// } |
} |
class TiXmlParsingData |
{ |
friend class TiXmlDocument; |
public: |
void Stamp( const char* now, TiXmlEncoding encoding ); |
const TiXmlCursor& Cursor() { return cursor; } |
private: |
// Only used by the document! |
TiXmlParsingData( const char* start, int _tabsize, int row, int col ) |
{ |
assert( start ); |
stamp = start; |
tabsize = _tabsize; |
cursor.row = row; |
cursor.col = col; |
} |
TiXmlCursor cursor; |
const char* stamp; |
int tabsize; |
}; |
void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding ) |
{ |
assert( now ); |
// Do nothing if the tabsize is 0. |
if ( tabsize < 1 ) |
{ |
return; |
} |
// Get the current row, column. |
int row = cursor.row; |
int col = cursor.col; |
const char* p = stamp; |
assert( p ); |
while ( p < now ) |
{ |
// Treat p as unsigned, so we have a happy compiler. |
const unsigned char* pU = (const unsigned char*)p; |
// Code contributed by Fletcher Dunn: (modified by lee) |
switch (*pU) { |
case 0: |
// We *should* never get here, but in case we do, don't |
// advance past the terminating null character, ever |
return; |
case '\r': |
// bump down to the next line |
++row; |
col = 0; |
// Eat the character |
++p; |
// Check for \r\n sequence, and treat this as a single character |
if (*p == '\n') { |
++p; |
} |
break; |
case '\n': |
// bump down to the next line |
++row; |
col = 0; |
// Eat the character |
++p; |
// Check for \n\r sequence, and treat this as a single |
// character. (Yes, this bizarre thing does occur still |
// on some arcane platforms...) |
if (*p == '\r') { |
++p; |
} |
break; |
case '\t': |
// Eat the character |
++p; |
// Skip to next tab stop |
col = (col / tabsize + 1) * tabsize; |
break; |
case TIXML_UTF_LEAD_0: |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
if ( *(p+1) && *(p+2) ) |
{ |
// In these cases, don't advance the column. These are |
// 0-width spaces. |
if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 ) |
p += 3; |
else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU ) |
p += 3; |
else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU ) |
p += 3; |
else |
{ p +=3; ++col; } // A normal character. |
} |
} |
else |
{ |
++p; |
++col; |
} |
break; |
default: |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
// Eat the 1 to 4 byte utf8 character. |
int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)]; |
if ( step == 0 ) |
step = 1; // Error case from bad encoding, but handle gracefully. |
p += step; |
// Just advance one column, of course. |
++col; |
} |
else |
{ |
++p; |
++col; |
} |
break; |
} |
} |
cursor.row = row; |
cursor.col = col; |
assert( cursor.row >= -1 ); |
assert( cursor.col >= -1 ); |
stamp = p; |
assert( stamp ); |
} |
const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding ) |
{ |
if ( !p || !*p ) |
{ |
return 0; |
} |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
while ( *p ) |
{ |
const unsigned char* pU = (const unsigned char*)p; |
// Skip the stupid Microsoft UTF-8 Byte order marks |
if ( *(pU+0)==TIXML_UTF_LEAD_0 |
&& *(pU+1)==TIXML_UTF_LEAD_1 |
&& *(pU+2)==TIXML_UTF_LEAD_2 ) |
{ |
p += 3; |
continue; |
} |
else if(*(pU+0)==TIXML_UTF_LEAD_0 |
&& *(pU+1)==0xbfU |
&& *(pU+2)==0xbeU ) |
{ |
p += 3; |
continue; |
} |
else if(*(pU+0)==TIXML_UTF_LEAD_0 |
&& *(pU+1)==0xbfU |
&& *(pU+2)==0xbfU ) |
{ |
p += 3; |
continue; |
} |
if ( IsWhiteSpace( *p ) ) |
++p; |
else |
break; |
} |
} |
else |
{ |
while ( *p && IsWhiteSpace( *p ) ) |
++p; |
} |
return p; |
} |
#ifdef TIXML_USE_STL |
/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag ) |
{ |
for( ;; ) |
{ |
if ( !in->good() ) return false; |
int c = in->peek(); |
// At this scope, we can't get to a document. So fail silently. |
if ( !IsWhiteSpace( c ) || c <= 0 ) |
return true; |
*tag += (char) in->get(); |
} |
} |
/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag ) |
{ |
//assert( character > 0 && character < 128 ); // else it won't work in utf-8 |
while ( in->good() ) |
{ |
int c = in->peek(); |
if ( c == character ) |
return true; |
if ( c <= 0 ) // Silent failure: can't get document at this scope |
return false; |
in->get(); |
*tag += (char) c; |
} |
return false; |
} |
#endif |
// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The |
// "assign" optimization removes over 10% of the execution time. |
// |
const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding ) |
{ |
// Oddly, not supported on some comilers, |
//name->clear(); |
// So use this: |
*name = ""; |
assert( p ); |
// Names start with letters or underscores. |
// Of course, in unicode, tinyxml has no idea what a letter *is*. The |
// algorithm is generous. |
// |
// After that, they can be letters, underscores, numbers, |
// hyphens, or colons. (Colons are valid ony for namespaces, |
// but tinyxml can't tell namespaces from names.) |
if ( p && *p |
&& ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) ) |
{ |
const char* start = p; |
while( p && *p |
&& ( IsAlphaNum( (unsigned char ) *p, encoding ) |
|| *p == '_' |
|| *p == '-' |
|| *p == '.' |
|| *p == ':' ) ) |
{ |
//(*name) += *p; // expensive |
++p; |
} |
if ( p-start > 0 ) { |
name->assign( start, p-start ); |
} |
return p; |
} |
return 0; |
} |
const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding ) |
{ |
// Presume an entity, and pull it out. |
TIXML_STRING ent; |
int i; |
*length = 0; |
if ( *(p+1) && *(p+1) == '#' && *(p+2) ) |
{ |
unsigned long ucs = 0; |
ptrdiff_t delta = 0; |
unsigned mult = 1; |
if ( *(p+2) == 'x' ) |
{ |
// Hexadecimal. |
if ( !*(p+3) ) return 0; |
const char* q = p+3; |
q = strchr( q, ';' ); |
if ( !q || !*q ) return 0; |
delta = q-p; |
--q; |
while ( *q != 'x' ) |
{ |
if ( *q >= '0' && *q <= '9' ) |
ucs += mult * (*q - '0'); |
else if ( *q >= 'a' && *q <= 'f' ) |
ucs += mult * (*q - 'a' + 10); |
else if ( *q >= 'A' && *q <= 'F' ) |
ucs += mult * (*q - 'A' + 10 ); |
else |
return 0; |
mult *= 16; |
--q; |
} |
} |
else |
{ |
// Decimal. |
if ( !*(p+2) ) return 0; |
const char* q = p+2; |
q = strchr( q, ';' ); |
if ( !q || !*q ) return 0; |
delta = q-p; |
--q; |
while ( *q != '#' ) |
{ |
if ( *q >= '0' && *q <= '9' ) |
ucs += mult * (*q - '0'); |
else |
return 0; |
mult *= 10; |
--q; |
} |
} |
if ( encoding == TIXML_ENCODING_UTF8 ) |
{ |
// convert the UCS to UTF-8 |
ConvertUTF32ToUTF8( ucs, value, length ); |
} |
else |
{ |
*value = (char)ucs; |
*length = 1; |
} |
return p + delta + 1; |
} |
// Now try to match it. |
for( i=0; i<NUM_ENTITY; ++i ) |
{ |
if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 ) |
{ |
assert( strlen( entity[i].str ) == entity[i].strLength ); |
*value = entity[i].chr; |
*length = 1; |
return ( p + entity[i].strLength ); |
} |
} |
// So it wasn't an entity, its unrecognized, or something like that. |
*value = *p; // Don't put back the last one, since we return it! |
//*length = 1; // Leave unrecognized entities - this doesn't really work. |
// Just writes strange XML. |
return p+1; |
} |
bool TiXmlBase::StringEqual( const char* p, |
const char* tag, |
bool ignoreCase, |
TiXmlEncoding encoding ) |
{ |
assert( p ); |
assert( tag ); |
if ( !p || !*p ) |
{ |
assert( 0 ); |
return false; |
} |
const char* q = p; |
if ( ignoreCase ) |
{ |
while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) ) |
{ |
++q; |
++tag; |
} |
if ( *tag == 0 ) |
return true; |
} |
else |
{ |
while ( *q && *tag && *q == *tag ) |
{ |
++q; |
++tag; |
} |
if ( *tag == 0 ) // Have we found the end of the tag, and everything equal? |
return true; |
} |
return false; |
} |
const char* TiXmlBase::ReadText( const char* p, |
TIXML_STRING * text, |
bool trimWhiteSpace, |
const char* endTag, |
bool caseInsensitive, |
TiXmlEncoding encoding ) |
{ |
*text = ""; |
if ( !trimWhiteSpace // certain tags always keep whitespace |
|| !condenseWhiteSpace ) // if true, whitespace is always kept |
{ |
// Keep all the white space. |
while ( p && *p |
&& !StringEqual( p, endTag, caseInsensitive, encoding ) |
) |
{ |
int len; |
char cArr[4] = { 0, 0, 0, 0 }; |
p = GetChar( p, cArr, &len, encoding ); |
text->append( cArr, len ); |
} |
} |
else |
{ |
bool whitespace = false; |
// Remove leading white space: |
p = SkipWhiteSpace( p, encoding ); |
while ( p && *p |
&& !StringEqual( p, endTag, caseInsensitive, encoding ) ) |
{ |
if ( *p == '\r' || *p == '\n' ) |
{ |
whitespace = true; |
++p; |
} |
else if ( IsWhiteSpace( *p ) ) |
{ |
whitespace = true; |
++p; |
} |
else |
{ |
// If we've found whitespace, add it before the |
// new character. Any whitespace just becomes a space. |
if ( whitespace ) |
{ |
(*text) += ' '; |
whitespace = false; |
} |
int len; |
char cArr[4] = { 0, 0, 0, 0 }; |
p = GetChar( p, cArr, &len, encoding ); |
if ( len == 1 ) |
(*text) += cArr[0]; // more efficient |
else |
text->append( cArr, len ); |
} |
} |
} |
if ( p ) |
p += strlen( endTag ); |
return p; |
} |
#ifdef TIXML_USE_STL |
void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag ) |
{ |
// The basic issue with a document is that we don't know what we're |
// streaming. Read something presumed to be a tag (and hope), then |
// identify it, and call the appropriate stream method on the tag. |
// |
// This "pre-streaming" will never read the closing ">" so the |
// sub-tag can orient itself. |
if ( !StreamTo( in, '<', tag ) ) |
{ |
SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
while ( in->good() ) |
{ |
int tagIndex = (int) tag->length(); |
while ( in->good() && in->peek() != '>' ) |
{ |
int c = in->get(); |
if ( c <= 0 ) |
{ |
SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
break; |
} |
(*tag) += (char) c; |
} |
if ( in->good() ) |
{ |
// We now have something we presume to be a node of |
// some sort. Identify it, and call the node to |
// continue streaming. |
TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING ); |
if ( node ) |
{ |
node->StreamIn( in, tag ); |
bool isElement = node->ToElement() != 0; |
delete node; |
node = 0; |
// If this is the root element, we're done. Parsing will be |
// done by the >> operator. |
if ( isElement ) |
{ |
return; |
} |
} |
else |
{ |
SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
} |
} |
// We should have returned sooner. |
SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN ); |
} |
#endif |
const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding ) |
{ |
ClearError(); |
// Parse away, at the document level. Since a document |
// contains nothing but other tags, most of what happens |
// here is skipping white space. |
if ( !p || !*p ) |
{ |
SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
// Note that, for a document, this needs to come |
// before the while space skip, so that parsing |
// starts from the pointer we are given. |
location.Clear(); |
if ( prevData ) |
{ |
location.row = prevData->cursor.row; |
location.col = prevData->cursor.col; |
} |
else |
{ |
location.row = 0; |
location.col = 0; |
} |
TiXmlParsingData data( p, TabSize(), location.row, location.col ); |
location = data.Cursor(); |
if ( encoding == TIXML_ENCODING_UNKNOWN ) |
{ |
// Check for the Microsoft UTF-8 lead bytes. |
const unsigned char* pU = (const unsigned char*)p; |
if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0 |
&& *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1 |
&& *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 ) |
{ |
encoding = TIXML_ENCODING_UTF8; |
useMicrosoftBOM = true; |
} |
} |
p = SkipWhiteSpace( p, encoding ); |
if ( !p ) |
{ |
SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return 0; |
} |
while ( p && *p ) |
{ |
TiXmlNode* node = Identify( p, encoding ); |
if ( node ) |
{ |
p = node->Parse( p, &data, encoding ); |
LinkEndChild( node ); |
} |
else |
{ |
break; |
} |
// Did we get encoding info? |
if ( encoding == TIXML_ENCODING_UNKNOWN |
&& node->ToDeclaration() ) |
{ |
TiXmlDeclaration* dec = node->ToDeclaration(); |
const char* enc = dec->Encoding(); |
assert( enc ); |
if ( *enc == 0 ) |
encoding = TIXML_ENCODING_UTF8; |
else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) ) |
encoding = TIXML_ENCODING_UTF8; |
else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) ) |
encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice |
else |
encoding = TIXML_ENCODING_LEGACY; |
} |
p = SkipWhiteSpace( p, encoding ); |
} |
// Was this empty? |
if ( !firstChild ) { |
SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding ); |
return 0; |
} |
// All is well. |
return p; |
} |
void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
// The first error in a chain is more accurate - don't set again! |
if ( error ) |
return; |
assert( err > 0 && err < TIXML_ERROR_STRING_COUNT ); |
error = true; |
errorId = err; |
errorDesc = errorString[ errorId ]; |
errorLocation.Clear(); |
if ( pError && data ) |
{ |
data->Stamp( pError, encoding ); |
errorLocation = data->Cursor(); |
} |
} |
TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding ) |
{ |
TiXmlNode* returnNode = 0; |
p = SkipWhiteSpace( p, encoding ); |
if( !p || !*p || *p != '<' ) |
{ |
return 0; |
} |
TiXmlDocument* doc = GetDocument(); |
p = SkipWhiteSpace( p, encoding ); |
if ( !p || !*p ) |
{ |
return 0; |
} |
// What is this thing? |
// - Elements start with a letter or underscore, but xml is reserved. |
// - Comments: <!-- |
// - Decleration: <?xml |
// - Everthing else is unknown to tinyxml. |
// |
const char* xmlHeader = { "<?xml" }; |
const char* commentHeader = { "<!--" }; |
const char* dtdHeader = { "<!" }; |
const char* cdataHeader = { "<![CDATA[" }; |
if ( StringEqual( p, xmlHeader, true, encoding ) ) |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing Declaration\n" ); |
#endif |
returnNode = new TiXmlDeclaration(); |
} |
else if ( StringEqual( p, commentHeader, false, encoding ) ) |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing Comment\n" ); |
#endif |
returnNode = new TiXmlComment(); |
} |
else if ( StringEqual( p, cdataHeader, false, encoding ) ) |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing CDATA\n" ); |
#endif |
TiXmlText* text = new TiXmlText( "" ); |
text->SetCDATA( true ); |
returnNode = text; |
} |
else if ( StringEqual( p, dtdHeader, false, encoding ) ) |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing Unknown(1)\n" ); |
#endif |
returnNode = new TiXmlUnknown(); |
} |
else if ( IsAlpha( *(p+1), encoding ) |
|| *(p+1) == '_' ) |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing Element\n" ); |
#endif |
returnNode = new TiXmlElement( "" ); |
} |
else |
{ |
#ifdef DEBUG_PARSER |
TIXML_LOG( "XML parsing Unknown(2)\n" ); |
#endif |
returnNode = new TiXmlUnknown(); |
} |
if ( returnNode ) |
{ |
// Set the parent, so it can report errors |
returnNode->parent = this; |
} |
else |
{ |
if ( doc ) |
doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN ); |
} |
return returnNode; |
} |
#ifdef TIXML_USE_STL |
void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag) |
{ |
// We're called with some amount of pre-parsing. That is, some of "this" |
// element is in "tag". Go ahead and stream to the closing ">" |
while( in->good() ) |
{ |
int c = in->get(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
(*tag) += (char) c ; |
if ( c == '>' ) |
break; |
} |
if ( tag->length() < 3 ) return; |
// Okay...if we are a "/>" tag, then we're done. We've read a complete tag. |
// If not, identify and stream. |
if ( tag->at( tag->length() - 1 ) == '>' |
&& tag->at( tag->length() - 2 ) == '/' ) |
{ |
// All good! |
return; |
} |
else if ( tag->at( tag->length() - 1 ) == '>' ) |
{ |
// There is more. Could be: |
// text |
// cdata text (which looks like another node) |
// closing tag |
// another node. |
for ( ;; ) |
{ |
StreamWhiteSpace( in, tag ); |
// Do we have text? |
if ( in->good() && in->peek() != '<' ) |
{ |
// Yep, text. |
TiXmlText text( "" ); |
text.StreamIn( in, tag ); |
// What follows text is a closing tag or another node. |
// Go around again and figure it out. |
continue; |
} |
// We now have either a closing tag...or another node. |
// We should be at a "<", regardless. |
if ( !in->good() ) return; |
assert( in->peek() == '<' ); |
int tagIndex = (int) tag->length(); |
bool closingTag = false; |
bool firstCharFound = false; |
for( ;; ) |
{ |
if ( !in->good() ) |
return; |
int c = in->peek(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
if ( c == '>' ) |
break; |
*tag += (char) c; |
in->get(); |
// Early out if we find the CDATA id. |
if ( c == '[' && tag->size() >= 9 ) |
{ |
size_t len = tag->size(); |
const char* start = tag->c_str() + len - 9; |
if ( strcmp( start, "<![CDATA[" ) == 0 ) { |
assert( !closingTag ); |
break; |
} |
} |
if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) ) |
{ |
firstCharFound = true; |
if ( c == '/' ) |
closingTag = true; |
} |
} |
// If it was a closing tag, then read in the closing '>' to clean up the input stream. |
// If it was not, the streaming will be done by the tag. |
if ( closingTag ) |
{ |
if ( !in->good() ) |
return; |
int c = in->get(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
assert( c == '>' ); |
*tag += (char) c; |
// We are done, once we've found our closing tag. |
return; |
} |
else |
{ |
// If not a closing tag, id it, and stream. |
const char* tagloc = tag->c_str() + tagIndex; |
TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING ); |
if ( !node ) |
return; |
node->StreamIn( in, tag ); |
delete node; |
node = 0; |
// No return: go around from the beginning: text, closing tag, or node. |
} |
} |
} |
} |
#endif |
const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
p = SkipWhiteSpace( p, encoding ); |
TiXmlDocument* document = GetDocument(); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding ); |
return 0; |
} |
if ( data ) |
{ |
data->Stamp( p, encoding ); |
location = data->Cursor(); |
} |
if ( *p != '<' ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding ); |
return 0; |
} |
p = SkipWhiteSpace( p+1, encoding ); |
// Read the name. |
const char* pErr = p; |
p = ReadName( p, &value, encoding ); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding ); |
return 0; |
} |
TIXML_STRING endTag ("</"); |
endTag += value; |
endTag += ">"; |
// Check for and read attributes. Also look for an empty |
// tag or an end tag. |
while ( p && *p ) |
{ |
pErr = p; |
p = SkipWhiteSpace( p, encoding ); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); |
return 0; |
} |
if ( *p == '/' ) |
{ |
++p; |
// Empty tag. |
if ( *p != '>' ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding ); |
return 0; |
} |
return (p+1); |
} |
else if ( *p == '>' ) |
{ |
// Done with attributes (if there were any.) |
// Read the value -- which can include other |
// elements -- read the end tag, and return. |
++p; |
p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens. |
if ( !p || !*p ) { |
// We were looking for the end tag, but found nothing. |
// Fix for [ 1663758 ] Failure to report error on bad XML |
if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); |
return 0; |
} |
// We should find the end tag now |
if ( StringEqual( p, endTag.c_str(), false, encoding ) ) |
{ |
p += endTag.length(); |
return p; |
} |
else |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding ); |
return 0; |
} |
} |
else |
{ |
// Try to read an attribute: |
TiXmlAttribute* attrib = new TiXmlAttribute(); |
if ( !attrib ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding ); |
return 0; |
} |
attrib->SetDocument( document ); |
pErr = p; |
p = attrib->Parse( p, data, encoding ); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding ); |
delete attrib; |
return 0; |
} |
// Handle the strange case of double attributes: |
#ifdef TIXML_USE_STL |
TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() ); |
#else |
TiXmlAttribute* node = attributeSet.Find( attrib->Name() ); |
#endif |
if ( node ) |
{ |
node->SetValue( attrib->Value() ); |
delete attrib; |
return 0; |
} |
attributeSet.Add( attrib ); |
} |
} |
return p; |
} |
const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
TiXmlDocument* document = GetDocument(); |
// Read in text and elements in any order. |
const char* pWithWhiteSpace = p; |
p = SkipWhiteSpace( p, encoding ); |
while ( p && *p ) |
{ |
if ( *p != '<' ) |
{ |
// Take what we have, make a text element. |
TiXmlText* textNode = new TiXmlText( "" ); |
if ( !textNode ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding ); |
return 0; |
} |
if ( TiXmlBase::IsWhiteSpaceCondensed() ) |
{ |
p = textNode->Parse( p, data, encoding ); |
} |
else |
{ |
// Special case: we want to keep the white space |
// so that leading spaces aren't removed. |
p = textNode->Parse( pWithWhiteSpace, data, encoding ); |
} |
if ( !textNode->Blank() ) |
LinkEndChild( textNode ); |
else |
delete textNode; |
} |
else |
{ |
// We hit a '<' |
// Have we hit a new element or an end tag? This could also be |
// a TiXmlText in the "CDATA" style. |
if ( StringEqual( p, "</", false, encoding ) ) |
{ |
return p; |
} |
else |
{ |
TiXmlNode* node = Identify( p, encoding ); |
if ( node ) |
{ |
p = node->Parse( p, data, encoding ); |
LinkEndChild( node ); |
} |
else |
{ |
return 0; |
} |
} |
} |
pWithWhiteSpace = p; |
p = SkipWhiteSpace( p, encoding ); |
} |
if ( !p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding ); |
} |
return p; |
} |
#ifdef TIXML_USE_STL |
void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag ) |
{ |
while ( in->good() ) |
{ |
int c = in->get(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
(*tag) += (char) c; |
if ( c == '>' ) |
{ |
// All is well. |
return; |
} |
} |
} |
#endif |
const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
TiXmlDocument* document = GetDocument(); |
p = SkipWhiteSpace( p, encoding ); |
if ( data ) |
{ |
data->Stamp( p, encoding ); |
location = data->Cursor(); |
} |
if ( !p || !*p || *p != '<' ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding ); |
return 0; |
} |
++p; |
value = ""; |
while ( p && *p && *p != '>' ) |
{ |
value += *p; |
++p; |
} |
if ( !p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding ); |
} |
if ( *p == '>' ) |
return p+1; |
return p; |
} |
#ifdef TIXML_USE_STL |
void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag ) |
{ |
while ( in->good() ) |
{ |
int c = in->get(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
(*tag) += (char) c; |
if ( c == '>' |
&& tag->at( tag->length() - 2 ) == '-' |
&& tag->at( tag->length() - 3 ) == '-' ) |
{ |
// All is well. |
return; |
} |
} |
} |
#endif |
const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
TiXmlDocument* document = GetDocument(); |
value = ""; |
p = SkipWhiteSpace( p, encoding ); |
if ( data ) |
{ |
data->Stamp( p, encoding ); |
location = data->Cursor(); |
} |
const char* startTag = "<!--"; |
const char* endTag = "-->"; |
if ( !StringEqual( p, startTag, false, encoding ) ) |
{ |
document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding ); |
return 0; |
} |
p += strlen( startTag ); |
// [ 1475201 ] TinyXML parses entities in comments |
// Oops - ReadText doesn't work, because we don't want to parse the entities. |
// p = ReadText( p, &value, false, endTag, false, encoding ); |
// |
// from the XML spec: |
/* |
[Definition: Comments may appear anywhere in a document outside other markup; in addition, |
they may appear within the document type declaration at places allowed by the grammar. |
They are not part of the document's character data; an XML processor MAY, but need not, |
make it possible for an application to retrieve the text of comments. For compatibility, |
the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity |
references MUST NOT be recognized within comments. |
An example of a comment: |
<!-- declarations for <head> & <body> --> |
*/ |
value = ""; |
// Keep all the white space. |
while ( p && *p && !StringEqual( p, endTag, false, encoding ) ) |
{ |
value.append( p, 1 ); |
++p; |
} |
if ( p ) |
p += strlen( endTag ); |
return p; |
} |
const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
p = SkipWhiteSpace( p, encoding ); |
if ( !p || !*p ) return 0; |
// int tabsize = 4; |
// if ( document ) |
// tabsize = document->TabSize(); |
if ( data ) |
{ |
data->Stamp( p, encoding ); |
location = data->Cursor(); |
} |
// Read the name, the '=' and the value. |
const char* pErr = p; |
p = ReadName( p, &name, encoding ); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding ); |
return 0; |
} |
p = SkipWhiteSpace( p, encoding ); |
if ( !p || !*p || *p != '=' ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); |
return 0; |
} |
++p; // skip '=' |
p = SkipWhiteSpace( p, encoding ); |
if ( !p || !*p ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); |
return 0; |
} |
const char* end; |
const char SINGLE_QUOTE = '\''; |
const char DOUBLE_QUOTE = '\"'; |
if ( *p == SINGLE_QUOTE ) |
{ |
++p; |
end = "\'"; // single quote in string |
p = ReadText( p, &value, false, end, false, encoding ); |
} |
else if ( *p == DOUBLE_QUOTE ) |
{ |
++p; |
end = "\""; // double quote in string |
p = ReadText( p, &value, false, end, false, encoding ); |
} |
else |
{ |
// All attribute values should be in single or double quotes. |
// But this is such a common error that the parser will try |
// its best, even without them. |
value = ""; |
while ( p && *p // existence |
&& !IsWhiteSpace( *p ) // whitespace |
&& *p != '/' && *p != '>' ) // tag end |
{ |
if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) { |
// [ 1451649 ] Attribute values with trailing quotes not handled correctly |
// We did not have an opening quote but seem to have a |
// closing one. Give up and throw an error. |
if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding ); |
return 0; |
} |
value += *p; |
++p; |
} |
} |
return p; |
} |
#ifdef TIXML_USE_STL |
void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag ) |
{ |
while ( in->good() ) |
{ |
int c = in->peek(); |
if ( !cdata && (c == '<' ) ) |
{ |
return; |
} |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
(*tag) += (char) c; |
in->get(); // "commits" the peek made above |
if ( cdata && c == '>' && tag->size() >= 3 ) { |
size_t len = tag->size(); |
if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) { |
// terminator of cdata. |
return; |
} |
} |
} |
} |
#endif |
const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding ) |
{ |
value = ""; |
TiXmlDocument* document = GetDocument(); |
if ( data ) |
{ |
data->Stamp( p, encoding ); |
location = data->Cursor(); |
} |
const char* const startTag = "<![CDATA["; |
const char* const endTag = "]]>"; |
if ( cdata || StringEqual( p, startTag, false, encoding ) ) |
{ |
cdata = true; |
if ( !StringEqual( p, startTag, false, encoding ) ) |
{ |
document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding ); |
return 0; |
} |
p += strlen( startTag ); |
// Keep all the white space, ignore the encoding, etc. |
while ( p && *p |
&& !StringEqual( p, endTag, false, encoding ) |
) |
{ |
value += *p; |
++p; |
} |
TIXML_STRING dummy; |
p = ReadText( p, &dummy, false, endTag, false, encoding ); |
return p; |
} |
else |
{ |
bool ignoreWhite = true; |
const char* end = "<"; |
p = ReadText( p, &value, ignoreWhite, end, false, encoding ); |
if ( p ) |
return p-1; // don't truncate the '<' |
return 0; |
} |
} |
#ifdef TIXML_USE_STL |
void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag ) |
{ |
while ( in->good() ) |
{ |
int c = in->get(); |
if ( c <= 0 ) |
{ |
TiXmlDocument* document = GetDocument(); |
if ( document ) |
document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN ); |
return; |
} |
(*tag) += (char) c; |
if ( c == '>' ) |
{ |
// All is well. |
return; |
} |
} |
} |
#endif |
const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding ) |
{ |
p = SkipWhiteSpace( p, _encoding ); |
// Find the beginning, find the end, and look for |
// the stuff in-between. |
TiXmlDocument* document = GetDocument(); |
if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) ) |
{ |
if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding ); |
return 0; |
} |
if ( data ) |
{ |
data->Stamp( p, _encoding ); |
location = data->Cursor(); |
} |
p += 5; |
version = ""; |
encoding = ""; |
standalone = ""; |
while ( p && *p ) |
{ |
if ( *p == '>' ) |
{ |
++p; |
return p; |
} |
p = SkipWhiteSpace( p, _encoding ); |
if ( StringEqual( p, "version", true, _encoding ) ) |
{ |
TiXmlAttribute attrib; |
p = attrib.Parse( p, data, _encoding ); |
version = attrib.Value(); |
} |
else if ( StringEqual( p, "encoding", true, _encoding ) ) |
{ |
TiXmlAttribute attrib; |
p = attrib.Parse( p, data, _encoding ); |
encoding = attrib.Value(); |
} |
else if ( StringEqual( p, "standalone", true, _encoding ) ) |
{ |
TiXmlAttribute attrib; |
p = attrib.Parse( p, data, _encoding ); |
standalone = attrib.Value(); |
} |
else |
{ |
// Read over whatever it is. |
while( p && *p && *p != '>' && !IsWhiteSpace( *p ) ) |
++p; |
} |
} |
return 0; |
} |
bool TiXmlText::Blank() const |
{ |
for ( unsigned i=0; i<value.length(); i++ ) |
if ( !IsWhiteSpace( value[i] ) ) |
return false; |
return true; |
} |