1 //
2 // Copyright (c) 2008-2017 the Urho3D project.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a copy
5 // of this software and associated documentation files (the "Software"), to deal
6 // in the Software without restriction, including without limitation the rights
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 // copies of the Software, and to permit persons to whom the Software is
9 // furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 // THE SOFTWARE.
21 //
22 
23 #include "../Precompiled.h"
24 
25 #include "../Core/Context.h"
26 #include "../IO/Deserializer.h"
27 #include "../IO/Log.h"
28 #include "../Resource/PListFile.h"
29 #include "../Resource/XMLFile.h"
30 
31 #include <stdio.h>
32 
33 #include "../DebugNew.h"
34 
35 namespace Urho3D
36 {
37 
38 static PListValue EMPTY_VALUE;
39 static PListValueMap EMPTY_VALUEMAP;
40 static PListValueVector EMPTY_VALUEVECTOR;
41 
PListValue()42 PListValue::PListValue() :
43     type_(PLVT_NONE)
44 {
45 }
46 
PListValue(int value)47 PListValue::PListValue(int value) :
48     type_(PLVT_NONE)
49 {
50     SetInt(value);
51 }
52 
PListValue(bool value)53 PListValue::PListValue(bool value) :
54     type_(PLVT_NONE)
55 {
56     SetBool(value);
57 }
58 
PListValue(float value)59 PListValue::PListValue(float value) :
60     type_(PLVT_NONE)
61 {
62     SetFloat(value);
63 }
64 
PListValue(const String & value)65 PListValue::PListValue(const String& value) :
66     type_(PLVT_NONE)
67 {
68     SetString(value);
69 }
70 
PListValue(PListValueMap & valueMap)71 PListValue::PListValue(PListValueMap& valueMap) :
72     type_(PLVT_NONE)
73 {
74     SetValueMap(valueMap);
75 }
76 
PListValue(PListValueVector & valueVector)77 PListValue::PListValue(PListValueVector& valueVector) :
78     type_(PLVT_NONE)
79 {
80     SetValueVector(valueVector);
81 }
82 
PListValue(const PListValue & value)83 PListValue::PListValue(const PListValue& value) :
84     type_(PLVT_NONE)
85 {
86     *this = value;
87 }
88 
~PListValue()89 PListValue::~PListValue()
90 {
91     Reset();
92 }
93 
operator =(const PListValue & rhs)94 PListValue& PListValue::operator =(const PListValue& rhs)
95 {
96     switch (rhs.type_)
97     {
98     case PLVT_NONE:
99         Reset();
100         break;
101     case PLVT_INT:
102         SetInt(rhs.int_);
103         break;
104     case PLVT_BOOL:
105         SetBool(rhs.bool_);
106         break;
107     case PLVT_FLOAT:
108         SetFloat(rhs.float_);
109         break;
110     case PLVT_STRING:
111         SetString(*rhs.string_);
112         break;
113     case PLVT_VALUEMAP:
114         SetValueMap(*rhs.valueMap_);
115         break;
116     case PLVT_VALUEVECTOR:
117         SetValueVector(*rhs.valueVector_);
118         break;
119     }
120 
121     return *this;
122 }
123 
SetInt(int value)124 void PListValue::SetInt(int value)
125 {
126     if (type_ != PLVT_INT)
127     {
128         Reset();
129         type_ = PLVT_INT;
130     }
131 
132     int_ = value;
133 }
134 
SetBool(bool value)135 void PListValue::SetBool(bool value)
136 {
137     if (type_ != PLVT_BOOL)
138     {
139         Reset();
140         type_ = PLVT_BOOL;
141     }
142 
143     bool_ = value;
144 }
145 
SetFloat(float value)146 void PListValue::SetFloat(float value)
147 {
148     if (type_ != PLVT_FLOAT)
149     {
150         Reset();
151         type_ = PLVT_FLOAT;
152     }
153     float_ = value;
154 }
155 
SetString(const String & value)156 void PListValue::SetString(const String& value)
157 {
158     if (type_ != PLVT_STRING)
159     {
160         Reset();
161         type_ = PLVT_STRING;
162         string_ = new String();
163     }
164 
165     *string_ = value;
166 }
167 
SetValueMap(const PListValueMap & valueMap)168 void PListValue::SetValueMap(const PListValueMap& valueMap)
169 {
170     if (type_ != PLVT_VALUEMAP)
171     {
172         Reset();
173         type_ = PLVT_VALUEMAP;
174         valueMap_ = new PListValueMap();
175     }
176 
177     *valueMap_ = valueMap;
178 }
179 
SetValueVector(const PListValueVector & valueVector)180 void PListValue::SetValueVector(const PListValueVector& valueVector)
181 {
182     if (type_ != PLVT_VALUEVECTOR)
183     {
184         Reset();
185         type_ = PLVT_VALUEVECTOR;
186         valueVector_ = new PListValueVector();
187     }
188 
189     *valueVector_ = valueVector;
190 }
191 
GetInt() const192 int PListValue::GetInt() const
193 {
194     return type_ == PLVT_INT ? int_ : 0;
195 }
196 
GetBool() const197 bool PListValue::GetBool() const
198 {
199     return type_ == PLVT_BOOL ? bool_ : false;
200 }
201 
GetFloat() const202 float PListValue::GetFloat() const
203 {
204     return type_ == PLVT_FLOAT ? float_ : 0.0f;
205 }
206 
GetString() const207 const String& PListValue::GetString() const
208 {
209     return type_ == PLVT_STRING ? *string_ : String::EMPTY;
210 }
211 
GetIntRect() const212 IntRect PListValue::GetIntRect() const
213 {
214     if (type_ != PLVT_STRING)
215         return IntRect::ZERO;
216 
217     int x, y, w, h;
218     sscanf(string_->CString(), "{{%d,%d},{%d,%d}}", &x, &y, &w, &h);
219     return IntRect(x, y, x + w, y + h);
220 }
221 
GetIntVector2() const222 IntVector2 PListValue::GetIntVector2() const
223 {
224     if (type_ != PLVT_STRING)
225         return IntVector2::ZERO;
226 
227     int x, y;
228     sscanf(string_->CString(), "{%d,%d}", &x, &y);
229     return IntVector2(x, y);
230 }
231 
GetIntVector3() const232 IntVector3 PListValue::GetIntVector3() const
233 {
234     if (type_ != PLVT_STRING)
235         return IntVector3::ZERO;
236 
237     int x, y, z;
238     sscanf(string_->CString(), "{%d,%d,%d}", &x, &y, &z);
239     return IntVector3(x, y, z);
240 }
241 
GetValueMap() const242 const PListValueMap& PListValue::GetValueMap() const
243 {
244     return type_ == PLVT_VALUEMAP ? *valueMap_ : EMPTY_VALUEMAP;
245 }
246 
GetValueVector() const247 const PListValueVector& PListValue::GetValueVector() const
248 {
249     return type_ == PLVT_VALUEVECTOR ? *valueVector_ : EMPTY_VALUEVECTOR;
250 }
251 
ConvertToValueMap()252 PListValueMap& PListValue::ConvertToValueMap()
253 {
254     if (type_ != PLVT_VALUEMAP)
255     {
256         Reset();
257         type_ = PLVT_VALUEMAP;
258         valueMap_ = new PListValueMap();
259     }
260 
261     return *valueMap_;
262 }
263 
ConvertToValueVector()264 PListValueVector& PListValue::ConvertToValueVector()
265 {
266     if (type_ != PLVT_VALUEVECTOR)
267     {
268         Reset();
269         type_ = PLVT_VALUEVECTOR;
270         valueVector_ = new PListValueVector();
271     }
272 
273     return *valueVector_;
274 }
275 
Reset()276 void PListValue::Reset()
277 {
278     if (type_ == PLVT_NONE)
279         return;
280 
281     switch (type_)
282     {
283     case PLVT_STRING:
284         delete string_;
285         break;
286     case PLVT_VALUEMAP:
287         delete valueMap_;
288         break;
289     case PLVT_VALUEVECTOR:
290         delete valueVector_;
291         break;
292     default:
293         break;
294     }
295 
296     type_ = PLVT_NONE;
297 }
298 
PListFile(Context * context)299 PListFile::PListFile(Context* context) :
300     Resource(context)
301 {
302 }
303 
~PListFile()304 PListFile::~PListFile()
305 {
306 }
307 
RegisterObject(Context * context)308 void PListFile::RegisterObject(Context* context)
309 {
310     context->RegisterFactory<PListFile>();
311 }
312 
BeginLoad(Deserializer & source)313 bool PListFile::BeginLoad(Deserializer& source)
314 {
315     if (GetName().Empty())
316         SetName(source.GetName());
317 
318     XMLFile xmlFile(context_);
319     if (!xmlFile.Load(source))
320     {
321         URHO3D_LOGERROR("Could not load property list");
322         return false;
323     }
324 
325     XMLElement plistElem = xmlFile.GetRoot("plist");
326     if (!plistElem)
327     {
328         URHO3D_LOGERROR("Invalid property list file");
329         return false;
330     }
331 
332     root_.Clear();
333 
334     XMLElement dictElem = plistElem.GetChild("dict");
335     if (!LoadDict(root_, dictElem))
336         return false;
337 
338     SetMemoryUse(source.GetSize());
339 
340     return true;
341 }
342 
LoadDict(PListValueMap & dict,const XMLElement & dictElem)343 bool PListFile::LoadDict(PListValueMap& dict, const XMLElement& dictElem)
344 {
345     if (!dictElem)
346         return false;
347 
348     XMLElement keyElem = dictElem.GetChild("key");
349     XMLElement valueElem = keyElem.GetNext();
350     while (keyElem && valueElem)
351     {
352         String key = keyElem.GetValue();
353         valueElem = keyElem.GetNext();
354 
355         PListValue value;
356         if (!LoadValue(value, valueElem))
357             return false;
358 
359         dict[key] = value;
360 
361         keyElem = valueElem.GetNext("key");
362         valueElem = keyElem.GetNext();
363     }
364 
365     return true;
366 }
367 
LoadArray(PListValueVector & array,const XMLElement & arrayElem)368 bool PListFile::LoadArray(PListValueVector& array, const XMLElement& arrayElem)
369 {
370     if (!arrayElem)
371         return false;
372 
373     for (XMLElement valueElem = arrayElem.GetChild(); valueElem; valueElem = valueElem.GetNext())
374     {
375         PListValue value;
376 
377         if (!LoadValue(value, valueElem))
378             return false;
379 
380         array.Push(value);
381     }
382 
383     return true;
384 }
385 
LoadValue(PListValue & value,const XMLElement & valueElem)386 bool PListFile::LoadValue(PListValue& value, const XMLElement& valueElem)
387 {
388     String valueType = valueElem.GetName();
389 
390     if (valueType == "string")
391         value.SetString(valueElem.GetValue());
392     else if (valueType == "real")
393         value.SetFloat(ToFloat(valueElem.GetValue()));
394     else if (valueType == "integer")
395         value.SetInt(ToInt(valueElem.GetValue()));
396     else if (valueType == "true")
397         value.SetBool(true);
398     else if (valueType == "false")
399         value.SetBool(false);
400     else if (valueType == "dict")
401     {
402         if (!LoadDict(value.ConvertToValueMap(), valueElem))
403             return false;
404     }
405     else if (valueType == "array")
406     {
407         if (!LoadArray(value.ConvertToValueVector(), valueElem))
408             return false;
409     }
410     else
411     {
412         URHO3D_LOGERROR("Supported value type");
413         return false;
414     }
415 
416     return true;
417 }
418 
419 
420 }
421