summaryrefslogtreecommitdiff
path: root/indra/llxml/llxmlnode.h
blob: e2019a8e60ed4d4fe2897e50ba4043a4dca397bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
/** 
 * @file llxmlnode.h
 * @brief LLXMLNode definition
 *
 * $LicenseInfo:firstyear=2000&license=viewergpl$
 * 
 * Copyright (c) 2000-2007, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */

#ifndef LL_LLXMLNODE_H
#define LL_LLXMLNODE_H

#define XML_STATIC
#ifdef LL_STANDALONE
#include <expat.h>
#else
#include "expat/expat.h"
#endif
#include <map>

#include "indra_constants.h"
#include "llmemory.h"
#include "llthread.h"
#include "llstring.h"
#include "llstringtable.h"



struct CompareAttributes
{
	bool operator()(const LLStringTableEntry* const lhs, const LLStringTableEntry* const rhs) const
	{	
		if (lhs == NULL)
			return TRUE;
		if (rhs == NULL)
			return FALSE;

		return strcmp(lhs->mString, rhs->mString) < 0;
	}
};


// Defines a simple node hierarchy for reading and writing task objects

class LLXMLNode;
typedef LLPointer<LLXMLNode> LLXMLNodePtr;
typedef std::multimap<LLString, LLXMLNodePtr > LLXMLNodeList;
typedef std::multimap<const LLStringTableEntry *, LLXMLNodePtr > LLXMLChildList;
typedef std::map<const LLStringTableEntry *, LLXMLNodePtr, CompareAttributes> LLXMLAttribList;

struct LLXMLChildren
{
	LLXMLChildList map;			// Map of children names->pointers
	LLXMLNodePtr head;			// Head of the double-linked list
	LLXMLNodePtr tail;			// Tail of the double-linked list
};

class LLXMLNode : public LLThreadSafeRefCount
{
public:
	enum ValueType
	{
		TYPE_CONTAINER,		// A node which contains nodes
		TYPE_UNKNOWN,		// A node loaded from file without a specified type
		TYPE_BOOLEAN,		// "true" or "false"
		TYPE_INTEGER,		// any integer type: U8, U32, S32, U64, etc.
		TYPE_FLOAT,			// any floating point type: F32, F64
		TYPE_STRING,		// a string
		TYPE_UUID,			// a UUID
		TYPE_NODEREF,		// the ID of another node in the hierarchy to reference
	};

	enum Encoding
	{
		ENCODING_DEFAULT = 0,
		ENCODING_DECIMAL,
		ENCODING_HEX,
		// ENCODING_BASE32, // Not implemented yet
	};

protected:
	~LLXMLNode();

public:
	LLXMLNode();
	LLXMLNode(const LLString& name, BOOL is_attribute);
	LLXMLNode(LLStringTableEntry* name, BOOL is_attribute);

	BOOL isNull();

	BOOL deleteChild(LLXMLNode* child);
    void addChild(LLXMLNodePtr new_parent); 
    void setParent(LLXMLNodePtr new_parent); // reparent if necessary

    // Serialization
	static bool parseFile(
		LLString filename,
		LLXMLNodePtr& node, 
		LLXMLNode* defaults_tree);
	static bool parseBuffer(
		U8* buffer,
		U32 length,
		LLXMLNodePtr& node, 
		LLXMLNode* defaults);
	static bool parseStream(
		std::istream& str,
		LLXMLNodePtr& node, 
		LLXMLNode* defaults);
	static bool updateNode(
	LLXMLNodePtr& node,
	LLXMLNodePtr& update_node);
	static void writeHeaderToFile(FILE *fOut);
    void writeToFile(FILE *fOut, LLString indent = LLString());
    void writeToOstream(std::ostream& output_stream, const LLString& indent = LLString());

    // Utility
    void findName(const LLString& name, LLXMLNodeList &results);
    void findName(LLStringTableEntry* name, LLXMLNodeList &results);
    void findID(const LLString& id, LLXMLNodeList &results);


    virtual LLXMLNodePtr createChild(const LLString& name, BOOL is_attribute);
    virtual LLXMLNodePtr createChild(LLStringTableEntry* name, BOOL is_attribute);


    // Getters
    U32 getBoolValue(U32 expected_length, BOOL *array);
    U32 getByteValue(U32 expected_length, U8 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getIntValue(U32 expected_length, S32 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getUnsignedValue(U32 expected_length, U32 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getLongValue(U32 expected_length, U64 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getFloatValue(U32 expected_length, F32 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getDoubleValue(U32 expected_length, F64 *array, Encoding encoding = ENCODING_DEFAULT);
    U32 getStringValue(U32 expected_length, LLString *array);
    U32 getUUIDValue(U32 expected_length, LLUUID *array);
    U32 getNodeRefValue(U32 expected_length, LLXMLNode **array);

	BOOL hasAttribute(const LLString& name );

	BOOL getAttributeBOOL(const LLString& name, BOOL& value );
	BOOL getAttributeU8(const LLString& name, U8& value );
	BOOL getAttributeS8(const LLString& name, S8& value );
	BOOL getAttributeU16(const LLString& name, U16& value );
	BOOL getAttributeS16(const LLString& name, S16& value );
	BOOL getAttributeU32(const LLString& name, U32& value );
	BOOL getAttributeS32(const LLString& name, S32& value );
	BOOL getAttributeF32(const LLString& name, F32& value );
	BOOL getAttributeF64(const LLString& name, F64& value );
	BOOL getAttributeColor(const LLString& name, LLColor4& value );
	BOOL getAttributeColor4(const LLString& name, LLColor4& value );
	BOOL getAttributeColor4U(const LLString& name, LLColor4U& value );
	BOOL getAttributeVector3(const LLString& name, LLVector3& value );
	BOOL getAttributeVector3d(const LLString& name, LLVector3d& value );
	BOOL getAttributeQuat(const LLString& name, LLQuaternion& value );
	BOOL getAttributeUUID(const LLString& name, LLUUID& value );
	BOOL getAttributeString(const LLString& name, LLString& value );

    const ValueType& getType() const { return mType; }
    U32 getLength() const { return mLength; }
    U32 getPrecision() const { return mPrecision; }
    const LLString& getValue() const { return mValue; }
	LLString getTextContents() const;
    const LLStringTableEntry* getName() const { return mName; }
	BOOL hasName(const char* name) const { return mName == gStringTable.checkStringEntry(name); }
	BOOL hasName(LLString name) const { return mName == gStringTable.checkStringEntry(name.c_str()); }
    const LLString& getID() const { return mID; }

    U32 getChildCount() const;
    // getChild returns a Null LLXMLNode (not a NULL pointer) if there is no such child.
    // This child has no value so any getTYPEValue() calls on it will return 0.
    bool getChild(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
    bool getChild(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
    void getChildren(const LLString& name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;
    void getChildren(const LLStringTableEntry* name, LLXMLNodeList &children, BOOL use_default_if_missing = TRUE) const;

	bool getAttribute(const LLString& name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);
	bool getAttribute(const LLStringTableEntry* name, LLXMLNodePtr& node, BOOL use_default_if_missing = TRUE);

	// The following skip over attributes
	LLXMLNodePtr getFirstChild();
	LLXMLNodePtr getNextSibling();

    LLXMLNodePtr getRoot();

	// Setters

	bool setAttributeString(const LLString& attr, const LLString& value);
	
	void setBoolValue(const BOOL value)	{ setBoolValue(1, &value); }
	void setByteValue(const U8 value, Encoding encoding = ENCODING_DEFAULT) { setByteValue(1, &value, encoding); }
	void setIntValue(const S32 value, Encoding encoding = ENCODING_DEFAULT) { setIntValue(1, &value, encoding); }
	void setUnsignedValue(const U32 value, Encoding encoding = ENCODING_DEFAULT) { setUnsignedValue(1, &value, encoding); }
	void setLongValue(const U64 value, Encoding encoding = ENCODING_DEFAULT) { setLongValue(1, &value, encoding); }
	void setFloatValue(const F32 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setFloatValue(1, &value, encoding); }
	void setDoubleValue(const F64 value, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0) { setDoubleValue(1, &value, encoding); }
	void setStringValue(const LLString value) { setStringValue(1, &value); }
	void setUUIDValue(const LLUUID value) { setUUIDValue(1, &value); }
	void setNodeRefValue(const LLXMLNode *value) { setNodeRefValue(1, &value); }

	void setBoolValue(U32 length, const BOOL *array);
	void setByteValue(U32 length, const U8 *array, Encoding encoding = ENCODING_DEFAULT);
	void setIntValue(U32 length, const S32 *array, Encoding encoding = ENCODING_DEFAULT);
	void setUnsignedValue(U32 length, const U32* array, Encoding encoding = ENCODING_DEFAULT);
	void setLongValue(U32 length, const U64 *array, Encoding encoding = ENCODING_DEFAULT);
	void setFloatValue(U32 length, const F32 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
	void setDoubleValue(U32 length, const F64 *array, Encoding encoding = ENCODING_DEFAULT, U32 precision = 0);
	void setStringValue(U32 length, const LLString *array);
	void setUUIDValue(U32 length, const LLUUID *array);
	void setNodeRefValue(U32 length, const LLXMLNode **array);
	void setValue(const LLString& value);
	void setName(const LLString& name);
	void setName(LLStringTableEntry* name);

	// Escapes " (quot) ' (apos) & (amp) < (lt) > (gt)
	// TomY TODO: Make this private
	static LLString escapeXML(const LLString& xml);

	// Set the default node corresponding to this default node
	void setDefault(LLXMLNode *default_node);

	// Find the node within defaults_list which corresponds to this node
	void findDefault(LLXMLNode *defaults_list);

	void updateDefault();

	// Delete any child nodes that aren't among the tree's children, recursive
	void scrubToTree(LLXMLNode *tree);

	BOOL deleteChildren(const LLString& name);
	BOOL deleteChildren(LLStringTableEntry* name);
	void setAttributes(ValueType type, U32 precision, Encoding encoding, U32 length);
	void appendValue(const LLString& value);

	// Unit Testing
	void createUnitTest(S32 max_num_children);
	BOOL performUnitTest(LLString &error_buffer);

protected:
	BOOL removeChild(LLXMLNode* child);

public:
	LLString mID;				// The ID attribute of this node

	XML_Parser *mParser;		// Temporary pointer while loading

	BOOL mIsAttribute;			// Flag is only used for output formatting
	U32 mVersionMajor;			// Version of this tag to use
	U32 mVersionMinor;
	U32 mLength;				// If the length is nonzero, then only return arrays of this length
	U32 mPrecision;				// The number of BITS per array item
	ValueType mType;			// The value type
	Encoding mEncoding;			// The value encoding

	LLXMLNode* mParent;				// The parent node
	LLXMLChildren* mChildren;		// The child nodes
	LLXMLAttribList mAttributes;		// The attribute nodes
	LLXMLNodePtr mPrev;				// Double-linked list previous node
	LLXMLNodePtr mNext;				// Double-linked list next node

	static BOOL sStripEscapedStrings;
	static BOOL sStripWhitespaceValues;
	
protected:
	LLStringTableEntry *mName;		// The name of this node
	LLString mValue;			// The value of this node (use getters/setters only)

	LLXMLNodePtr mDefault;		// Mirror node in the default tree

	static const char *skipWhitespace(const char *str);
	static const char *skipNonWhitespace(const char *str);
	static const char *parseInteger(const char *str, U64 *dest, BOOL *is_negative, U32 precision, Encoding encoding);
	static const char *parseFloat(const char *str, F64 *dest, U32 precision, Encoding encoding);

	BOOL isFullyDefault();
};

#endif // LL_LLXMLNODE