1 /* Copyright (C) 2021 Wildfire Games.
2 * This file is part of 0 A.D.
4 * 0 A.D. is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
9 * 0 A.D. is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.
19 Xeromyces - XMB reading library
23 XMB originated as a binary representation of XML, with some limitations
24 but much more efficiency (particularly for loading simple data
25 classes that don't need much initialisation).
27 Theoretical file structure:
30 char Header[4]; // because everyone has one; currently "XMB0"
33 int OffsetFromStartToElementNames;
36 int OffsetFromStartToAttributeNames;
37 int AttributeNameCount;
42 ZStr8 AttributeNames[];
47 0) int Length; // of entire struct, so it can be skipped over
51 8) int AttributeCount;
54 16) int ChildrenOffset; // == sizeof(Text)+sizeof(Attributes)
56 XMB_Attribute Attributes[];
67 int Length; // in bytes
68 char* Text; // null-terminated UTF8
72 20) int Length; // 0 if there's no text, else 4+sizeof(Text) in bytes including terminator
74 24) int LineNumber; // for e.g. debugging scripts
75 28) char* Text; // null-terminated UTF8
80 #ifndef INCLUDED_XEROXMB
81 #define INCLUDED_XEROXMB
86 #include <string_view>
92 class XMBAttributeList
;
99 XMBData() : m_Pointer(nullptr) {}
102 * Initialise from the contents of an XMBStorage.
103 * @param doc must remain allocated and unchanged while
104 * the XMBData is being used.
105 * @return indication of success; main cause for failure is attempting to
106 * load a partially valid XMB file (e.g. if the game was interrupted
107 * while writing it), which we detect by checking the magic string.
108 * It also fails when trying to load an XMB file with a different version.
110 bool Initialise(const XMBStorage
& doc
);
112 // Returns the root element
113 XMBElement
GetRoot() const;
115 // Returns internal ID for a given element/attribute string.
116 int GetElementID(const char* Name
) const;
117 int GetAttributeID(const char* Name
) const;
119 // Returns element/attribute string for a given internal ID.
120 const char* GetElementString(const int ID
) const;
121 const char* GetAttributeString(const int ID
) const;
123 std::string_view
GetElementStringView(const int ID
) const;
124 std::string_view
GetAttributeStringView(const int ID
) const;
127 const char* m_Pointer
;
129 int m_ElementNameCount
;
130 int m_AttributeNameCount
;
131 const char* m_ElementPointer
;
132 const char* m_AttributePointer
;
141 XMBElement(const char* offset
)
142 : m_Pointer(offset
) {}
144 int GetNodeName() const;
145 XMBElementList
GetChildNodes() const;
146 XMBAttributeList
GetAttributes() const;
147 CStr8
GetText() const;
148 // Returns the line number of the text within this element,
149 // or -1 if there is no text
150 int GetLineNumber() const;
153 // Pointer to the start of the node
154 const char* m_Pointer
;
160 XMBElementList(const char* offset
, size_t count
, const char* endoffset
)
161 : m_Size(count
), m_Pointer(offset
), m_CurItemID(0), m_CurPointer(offset
), m_EndPointer(endoffset
) {}
163 // Get first element in list with the given name.
164 // Performance is linear in the number of elements in the list.
165 XMBElement
GetFirstNamedItem(const int ElementName
) const;
167 // Linear in the number of elements in the list
168 XMBElement
operator[](size_t id
); // returns Children[id]
173 typedef ptrdiff_t difference_type
;
174 typedef XMBElement value_type
;
175 typedef XMBElement reference
; // Because we need to construct the object
176 typedef XMBElement pointer
; // Because we need to construct the object
177 typedef std::forward_iterator_tag iterator_category
;
179 iterator(size_t size
, const char* ptr
, const char* endptr
= NULL
)
180 : m_Size(size
), m_CurItemID(endptr
? size
: 0), m_CurPointer(endptr
? endptr
: ptr
) {}
181 XMBElement
operator*() const { return XMBElement(m_CurPointer
); }
182 XMBElement
operator->() const { return **this; }
183 iterator
& operator++();
185 bool operator==(const iterator
& rhs
) const
187 return m_Size
== rhs
.m_Size
&&
188 m_CurItemID
== rhs
.m_CurItemID
&&
189 m_CurPointer
== rhs
.m_CurPointer
;
191 bool operator!=(const iterator
& rhs
) const { return !(*this == rhs
); }
195 const char* m_CurPointer
;
197 iterator
begin() { return iterator(m_Size
, m_Pointer
); }
198 iterator
end() { return iterator(m_Size
, m_Pointer
, m_EndPointer
); }
200 size_t size() const { return m_Size
; }
201 bool empty() const { return m_Size
== 0; }
206 const char* m_Pointer
;
208 // For optimised sequential access:
210 const char* m_CurPointer
;
212 const char* m_EndPointer
;
219 XMBAttribute(int name
, const CStr8
& value
)
220 : Name(name
), Value(value
) {};
223 CStr8 Value
; // UTF-8 encoded
226 class XMBAttributeList
229 XMBAttributeList(const char* offset
, size_t count
, const char* endoffset
)
230 : m_Size(count
), m_Pointer(offset
), m_CurItemID(0), m_CurPointer(offset
), m_EndPointer(endoffset
) {}
232 // Get the attribute value directly
233 CStr8
GetNamedItem(const int AttributeName
) const;
235 // Linear in the number of elements in the list
236 XMBAttribute
operator[](size_t id
); // returns Children[id]
241 typedef ptrdiff_t difference_type
;
242 typedef XMBAttribute value_type
;
243 typedef XMBAttribute reference
; // Because we need to construct the object
244 typedef XMBAttribute pointer
; // Because we need to construct the object
245 typedef std::forward_iterator_tag iterator_category
;
247 iterator(size_t size
, const char* ptr
, const char* endptr
= NULL
)
248 : m_Size(size
), m_CurItemID(endptr
? size
: 0), m_CurPointer(endptr
? endptr
: ptr
) {}
249 XMBAttribute
operator*() const;
250 XMBAttribute
operator->() const { return **this; }
251 iterator
& operator++();
253 bool operator==(const iterator
& rhs
) const
255 return m_Size
== rhs
.m_Size
&&
256 m_CurItemID
== rhs
.m_CurItemID
&&
257 m_CurPointer
== rhs
.m_CurPointer
;
259 bool operator!=(const iterator
& rhs
) const { return !(*this == rhs
); }
263 const char* m_CurPointer
;
265 iterator
begin() const { return iterator(m_Size
, m_Pointer
); }
266 iterator
end() const { return iterator(m_Size
, m_Pointer
, m_EndPointer
); }
268 size_t size() const { return m_Size
; }
269 bool empty() const { return m_Size
== 0; }
274 // Pointer to start of attribute list
275 const char* m_Pointer
;
277 // For optimised sequential access:
279 const char* m_CurPointer
;
281 const char* m_EndPointer
;
284 #endif // INCLUDED_XEROXMB