1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "EntityAttributes.h"
21 
22 #include "Exceptions.h"
23 #include "Assets/EntityDefinition.h"
24 
25 namespace TrenchBroom {
26     namespace Model {
27         const String AttributeEscapeChars = "\"\n\\";
28 
29         namespace AttributeNames {
30             const AttributeName Classname         = "classname";
31             const AttributeName Origin            = "origin";
32             const AttributeName Wad               = "wad";
33             const AttributeName Textures          = "_tb_textures";
34             const AttributeName Mods              = "_tb_mod";
35             const AttributeName Spawnflags        = "spawnflags";
36             const AttributeName EntityDefinitions = "_tb_def";
37             const AttributeName Angle             = "angle";
38             const AttributeName Angles            = "angles";
39             const AttributeName Mangle            = "mangle";
40             const AttributeName Target            = "target";
41             const AttributeName Targetname        = "targetname";
42             const AttributeName Killtarget        = "killtarget";
43             const AttributeName GroupType         = "_tb_type";
44             const AttributeName LayerId           = "_tb_id";
45             const AttributeName LayerName         = "_tb_name";
46             const AttributeName Layer             = "_tb_layer";
47             const AttributeName GroupId           = "_tb_id";
48             const AttributeName GroupName         = "_tb_name";
49             const AttributeName Group             = "_tb_group";
50             const AttributeName Message           = "_tb_message";
51         }
52 
53         namespace AttributeValues {
54             const AttributeValue WorldspawnClassname = "worldspawn";
55             const AttributeValue NoClassname         = "undefined";
56             const AttributeValue LayerClassname      = "func_group";
57             const AttributeValue GroupClassname      = "func_group";
58             const AttributeValue GroupTypeLayer      = "_tb_layer";
59             const AttributeValue GroupTypeGroup      = "_tb_group";
60         }
61 
numberedAttributePrefix(const String & name)62         String numberedAttributePrefix(const String& name) {
63             size_t i = 0;
64             while (i < name.size() && name[i] < '0' && name[i] > '9')
65                 ++i;
66             if (i == name.size())
67                 return "";
68             for (size_t j = i; j < name.size(); ++j) {
69                 if (name[j] < '0' || name[j] > '9')
70                     return "";
71             }
72             return name.substr(0, i);
73         }
74 
isNumberedAttribute(const String & prefix,const AttributeName & name)75         bool isNumberedAttribute(const String& prefix, const AttributeName& name) {
76             if (name.size() < prefix.size())
77                 return false;
78             for (size_t i = 0; i < prefix.size(); ++i)
79                 if (name[i] != prefix[i])
80                     return false;
81             for (size_t i = prefix.size(); i < name.size(); ++i)
82                 if (name[i] < '0' || name[i] > '9')
83                     return false;
84             return true;
85         }
86 
87         const EntityAttribute::List EntityAttribute::EmptyList(0);
88 
EntityAttribute()89         EntityAttribute::EntityAttribute() :
90         m_definition(NULL) {}
91 
EntityAttribute(const AttributeName & name,const AttributeValue & value,const Assets::AttributeDefinition * definition)92         EntityAttribute::EntityAttribute(const AttributeName& name, const AttributeValue& value, const Assets::AttributeDefinition* definition) :
93         m_name(name),
94         m_value(value),
95         m_definition(definition) {}
96 
operator <(const EntityAttribute & rhs) const97         bool EntityAttribute::operator<(const EntityAttribute& rhs) const {
98             return compare(rhs) < 0;
99         }
100 
compare(const EntityAttribute & rhs) const101         int EntityAttribute::compare(const EntityAttribute& rhs) const {
102             const int nameCmp = m_name.compare(rhs.m_name);
103             if (nameCmp != 0)
104                 return nameCmp;
105             return m_value.compare(rhs.m_value);
106         }
107 
name() const108         const AttributeName& EntityAttribute::name() const {
109             return m_name;
110         }
111 
value() const112         const AttributeValue& EntityAttribute::value() const {
113             return m_value;
114         }
115 
definition() const116         const Assets::AttributeDefinition* EntityAttribute::definition() const {
117             return m_definition;
118         }
119 
setName(const AttributeName & name,const Assets::AttributeDefinition * definition)120         void EntityAttribute::setName(const AttributeName& name, const Assets::AttributeDefinition* definition) {
121             m_name = name;
122             m_definition = definition;
123         }
124 
setValue(const AttributeValue & value)125         void EntityAttribute::setValue(const AttributeValue& value) {
126             m_value = value;
127         }
128 
isLayer(const String & classname,const EntityAttribute::List & attributes)129         bool isLayer(const String& classname, const EntityAttribute::List& attributes) {
130             if (classname != Model::AttributeValues::LayerClassname)
131                 return false;
132             const AttributeValue& groupType = findAttribute(attributes, Model::AttributeNames::GroupType);
133             return groupType == Model::AttributeValues::GroupTypeLayer;
134         }
135 
isGroup(const String & classname,const EntityAttribute::List & attributes)136         bool isGroup(const String& classname, const EntityAttribute::List& attributes) {
137             if (classname != Model::AttributeValues::GroupClassname)
138                 return false;
139             const AttributeValue& groupType = findAttribute(attributes, Model::AttributeNames::GroupType);
140             return groupType == Model::AttributeValues::GroupTypeGroup;
141         }
142 
isWorldspawn(const String & classname,const EntityAttribute::List & attributes)143         bool isWorldspawn(const String& classname, const EntityAttribute::List& attributes) {
144             return classname == Model::AttributeValues::WorldspawnClassname;
145         }
146 
findAttribute(const EntityAttribute::List & attributes,const AttributeName & name,const AttributeValue & defaultValue)147         const AttributeValue& findAttribute(const EntityAttribute::List& attributes, const AttributeName& name, const AttributeValue& defaultValue) {
148             Model::EntityAttribute::List::const_iterator it, end;
149             for (it = attributes.begin(), end = attributes.end(); it != end; ++it) {
150                 if (name == it->name())
151                     return it->value();
152             }
153             return defaultValue;
154         }
155 
attributes() const156         const EntityAttribute::List& EntityAttributes::attributes() const {
157             return m_attributes;
158         }
159 
setAttributes(const EntityAttribute::List & attributes)160         void EntityAttributes::setAttributes(const EntityAttribute::List& attributes) {
161             m_attributes = attributes;
162             rebuildIndex();
163         }
164 
addOrUpdateAttribute(const AttributeName & name,const AttributeValue & value,const Assets::AttributeDefinition * definition)165         const EntityAttribute& EntityAttributes::addOrUpdateAttribute(const AttributeName& name, const AttributeValue& value, const Assets::AttributeDefinition* definition) {
166             EntityAttribute::List::iterator it = findAttribute(name);
167             if (it != m_attributes.end()) {
168                 assert(it->definition() == definition);
169                 it->setValue(value);
170                 return *it;
171             } else {
172                 m_attributes.push_back(EntityAttribute(name, value, definition));
173                 m_index.insert(name, --m_attributes.end());
174                 return m_attributes.back();
175             }
176         }
177 
renameAttribute(const AttributeName & name,const AttributeName & newName,const Assets::AttributeDefinition * newDefinition)178         void EntityAttributes::renameAttribute(const AttributeName& name, const AttributeName& newName, const Assets::AttributeDefinition* newDefinition) {
179             EntityAttribute::List::iterator it = findAttribute(name);
180             if (it == m_attributes.end())
181                 return;
182             m_index.remove(it->name(), it);
183             it->setName(newName, newDefinition);
184             m_index.insert(it->name(), it);
185         }
186 
removeAttribute(const AttributeName & name)187         void EntityAttributes::removeAttribute(const AttributeName& name) {
188             EntityAttribute::List::iterator it = findAttribute(name);
189             if (it == m_attributes.end())
190                 return;
191             m_index.remove(name, it);
192             m_attributes.erase(it);
193         }
194 
updateDefinitions(const Assets::EntityDefinition * entityDefinition)195         void EntityAttributes::updateDefinitions(const Assets::EntityDefinition* entityDefinition) {
196             EntityAttribute::List::iterator it, end;
197             for (it = m_attributes.begin(), end = m_attributes.end(); it != end; ++it) {
198                 EntityAttribute& attribute = *it;
199                 const AttributeName& name = attribute.name();
200                 const Assets::AttributeDefinition* attributeDefinition = Assets::EntityDefinition::safeGetAttributeDefinition(entityDefinition, name);
201                 attribute.setName(name, attributeDefinition);
202             }
203         }
204 
hasAttribute(const AttributeName & name) const205         bool EntityAttributes::hasAttribute(const AttributeName& name) const {
206             return findAttribute(name) != m_attributes.end();
207         }
208 
hasAttribute(const AttributeName & name,const AttributeValue & value) const209         bool EntityAttributes::hasAttribute(const AttributeName& name, const AttributeValue& value) const {
210             const EntityAttribute::List::const_iterator it = findAttribute(name);
211             if (it == m_attributes.end())
212                 return false;
213             return it->value() == value;
214         }
215 
hasAttributeWithPrefix(const AttributeName & prefix,const AttributeValue & value) const216         bool EntityAttributes::hasAttributeWithPrefix(const AttributeName& prefix, const AttributeValue& value) const {
217             return containsValue(m_index.queryPrefixMatches(prefix), value);
218         }
219 
hasNumberedAttribute(const AttributeName & prefix,const AttributeValue & value) const220         bool EntityAttributes::hasNumberedAttribute(const AttributeName& prefix, const AttributeValue& value) const {
221             return containsValue(m_index.queryNumberedMatches(prefix), value);
222         }
223 
snapshot(const AttributeName & name) const224         EntityAttributeSnapshot EntityAttributes::snapshot(const AttributeName& name) const {
225             const AttributeIndex::QueryResult matches = m_index.queryExactMatches(name);
226             if (matches.empty())
227                 return EntityAttributeSnapshot(name);
228 
229             assert(matches.size() == 1);
230             return EntityAttributeSnapshot(name, matches.front()->value());
231         }
232 
containsValue(const AttributeIndex::QueryResult & matches,const AttributeValue & value) const233         bool EntityAttributes::containsValue(const AttributeIndex::QueryResult& matches, const AttributeValue& value) const {
234             if (matches.empty())
235                 return false;
236 
237             AttributeIndex::QueryResult::const_iterator it, end;
238             for (it = matches.begin(), end = matches.end(); it != end; ++it) {
239                 const EntityAttribute::List::iterator attrIt = *it;
240                 const EntityAttribute& attribute = *attrIt;
241                 if (attribute.value() == value)
242                     return true;
243             }
244 
245             return false;
246         }
247 
attribute(const AttributeName & name) const248         const AttributeValue* EntityAttributes::attribute(const AttributeName& name) const {
249             EntityAttribute::List::const_iterator it = findAttribute(name);
250             if (it == m_attributes.end())
251                 return NULL;
252             return &it->value();
253         }
254 
safeAttribute(const AttributeName & name,const AttributeValue & defaultValue) const255         const AttributeValue& EntityAttributes::safeAttribute(const AttributeName& name, const AttributeValue& defaultValue) const {
256             const AttributeValue* value = attribute(name);
257             if (value == NULL)
258                 return defaultValue;
259             return *value;
260         }
261 
numberedAttributes(const String & prefix) const262         EntityAttribute::List EntityAttributes::numberedAttributes(const String& prefix) const {
263             EntityAttribute::List result;
264 
265             EntityAttribute::List::const_iterator it, end;
266             for (it = m_attributes.begin(), end = m_attributes.end(); it != end; ++it) {
267                 const EntityAttribute& attribute = *it;
268                 if (isNumberedAttribute(prefix, attribute.name()))
269                     result.push_back(attribute);
270             }
271 
272             return result;
273         }
274 
findAttribute(const AttributeName & name) const275         EntityAttribute::List::const_iterator EntityAttributes::findAttribute(const AttributeName& name) const {
276             const AttributeIndex::QueryResult matches = m_index.queryExactMatches(name);
277             if (matches.empty())
278                 return m_attributes.end();
279 
280             assert(matches.size() == 1);
281             return matches.front();
282         }
283 
findAttribute(const AttributeName & name)284         EntityAttribute::List::iterator EntityAttributes::findAttribute(const AttributeName& name) {
285             const AttributeIndex::QueryResult matches = m_index.queryExactMatches(name);
286             if (matches.empty())
287                 return m_attributes.end();
288 
289             assert(matches.size() == 1);
290             return matches.front();
291         }
292 
rebuildIndex()293         void EntityAttributes::rebuildIndex() {
294             m_index.clear();
295 
296             EntityAttribute::List::iterator it, end;
297             for (it = m_attributes.begin(), end = m_attributes.end(); it != end; ++it) {
298                 const EntityAttribute& attribute = *it;
299                 m_index.insert(attribute.name(), it);
300             }
301         }
302     }
303 }
304