1 /*
2  * Copyright (c) 2011-2015, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 #include "ArrayParameter.h"
31 #include <sstream> // for istringstream
32 #include "Tokenizer.h"
33 #include "ParameterType.h"
34 #include "ParameterAccessContext.h"
35 #include "ConfigurationAccessContext.h"
36 #include "ParameterBlackboard.h"
37 #include "Utility.h"
38 #include <assert.h>
39 
40 #define base CParameter
41 
42 using std::string;
43 
CArrayParameter(const string & strName,const CTypeElement * pTypeElement)44 CArrayParameter::CArrayParameter(const string& strName, const CTypeElement* pTypeElement) : base(strName, pTypeElement)
45 {
46 }
47 
getFootPrint() const48 uint32_t CArrayParameter::getFootPrint() const
49 {
50     return getSize() * getArrayLength();
51 }
52 
53 // Array length
getArrayLength() const54 uint32_t CArrayParameter::getArrayLength() const
55 {
56     return getTypeElement()->getArrayLength();
57 }
58 
59 // Element properties
showProperties(string & strResult) const60 void CArrayParameter::showProperties(string& strResult) const
61 {
62     base::showProperties(strResult);
63 
64     // Array length
65     strResult += "Array length: ";
66     strResult += CUtility::toString(getArrayLength());
67     strResult += "\n";
68 }
69 
70 // XML configuration settings parsing
serializeXmlSettings(CXmlElement & xmlConfigurationSettingsElementContent,CConfigurationAccessContext & configurationAccessContext) const71 bool CArrayParameter::serializeXmlSettings(CXmlElement& xmlConfigurationSettingsElementContent, CConfigurationAccessContext& configurationAccessContext) const
72 {
73     // Check for value space
74     handleValueSpaceAttribute(xmlConfigurationSettingsElementContent, configurationAccessContext);
75 
76     // Handle access
77     if (!configurationAccessContext.serializeOut()) {
78 
79         // Actually set values to blackboard
80         if (!setValues(0, configurationAccessContext.getBaseOffset(), xmlConfigurationSettingsElementContent.getTextContent(), configurationAccessContext)) {
81 
82             return false;
83         }
84     } else {
85 
86         // Get string value
87         string strValue;
88 
89         // Whole array requested
90         getValues(configurationAccessContext.getBaseOffset(), strValue, configurationAccessContext);
91 
92         // Populate value into xml text node
93         xmlConfigurationSettingsElementContent.setTextContent(strValue);
94     }
95 
96     // Done
97     return true;
98 }
99 
100 // User set/get
accessValue(CPathNavigator & pathNavigator,string & strValue,bool bSet,CParameterAccessContext & parameterAccessContext) const101 bool CArrayParameter::accessValue(CPathNavigator& pathNavigator, string& strValue, bool bSet, CParameterAccessContext& parameterAccessContext) const
102 {
103     uint32_t uiIndex;
104 
105     if (!getIndex(pathNavigator, uiIndex, parameterAccessContext)) {
106 
107         return false;
108     }
109 
110     if (bSet) {
111         // Set
112         if (uiIndex == (uint32_t)-1) {
113 
114             // No index provided, start with 0
115             uiIndex = 0;
116         }
117 
118         // Actually set values
119         if (!setValues(uiIndex, parameterAccessContext.getBaseOffset(), strValue, parameterAccessContext)) {
120 
121             return false;
122         }
123 
124         // Synchronize
125         if (!sync(parameterAccessContext)) {
126 
127             appendParameterPathToError(parameterAccessContext);
128             return false;
129         }
130     } else {
131         // Get
132         if (uiIndex == (uint32_t)-1) {
133 
134             // Whole array requested
135             getValues(parameterAccessContext.getBaseOffset(), strValue, parameterAccessContext);
136 
137         } else {
138             // Scalar requested
139             doGetValue(strValue, getOffset() + uiIndex * getSize(), parameterAccessContext);
140         }
141     }
142 
143     return true;
144 }
145 
146 // Boolean
accessAsBooleanArray(std::vector<bool> & abValues,bool bSet,CParameterAccessContext & parameterAccessContext) const147 bool CArrayParameter::accessAsBooleanArray(std::vector<bool>& abValues, bool bSet, CParameterAccessContext& parameterAccessContext) const
148 {
149     return accessValues(abValues, bSet, parameterAccessContext);
150 }
151 
152 // Integer
accessAsIntegerArray(std::vector<uint32_t> & auiValues,bool bSet,CParameterAccessContext & parameterAccessContext) const153 bool CArrayParameter::accessAsIntegerArray(std::vector<uint32_t>& auiValues, bool bSet, CParameterAccessContext& parameterAccessContext) const
154 {
155     return accessValues(auiValues, bSet, parameterAccessContext);
156 }
157 
158 // Signed Integer Access
accessAsSignedIntegerArray(std::vector<int32_t> & aiValues,bool bSet,CParameterAccessContext & parameterAccessContext) const159 bool CArrayParameter::accessAsSignedIntegerArray(std::vector<int32_t>& aiValues, bool bSet, CParameterAccessContext& parameterAccessContext) const
160 {
161     return accessValues(aiValues, bSet, parameterAccessContext);
162 }
163 
164 // Double Access
accessAsDoubleArray(std::vector<double> & adValues,bool bSet,CParameterAccessContext & parameterAccessContext) const165 bool CArrayParameter::accessAsDoubleArray(std::vector<double>& adValues, bool bSet, CParameterAccessContext& parameterAccessContext) const
166 {
167     return accessValues(adValues, bSet, parameterAccessContext);
168 }
169 
170 // String Access
accessAsStringArray(std::vector<string> & astrValues,bool bSet,CParameterAccessContext & parameterAccessContext) const171 bool CArrayParameter::accessAsStringArray(std::vector<string>& astrValues, bool bSet, CParameterAccessContext& parameterAccessContext) const
172 {
173     return accessValues(astrValues, bSet, parameterAccessContext);
174 }
175 
176 // Dump
logValue(string & strValue,CErrorContext & errorContext) const177 void CArrayParameter::logValue(string& strValue, CErrorContext& errorContext) const
178 {
179     // Parameter context
180     CParameterAccessContext& parameterAccessContext = static_cast<CParameterAccessContext&>(errorContext);
181 
182     // Dump values
183     getValues(0, strValue, parameterAccessContext);
184 }
185 
186 // Used for simulation and virtual subsystems
setDefaultValues(CParameterAccessContext & parameterAccessContext) const187 void CArrayParameter::setDefaultValues(CParameterAccessContext& parameterAccessContext) const
188 {
189     // Get default value from type
190     uint32_t uiDefaultValue = static_cast<const CParameterType*>(getTypeElement())->getDefaultValue();
191 
192     // Write blackboard
193     CParameterBlackboard* pBlackboard = parameterAccessContext.getParameterBlackboard();
194 
195     // Process
196     uint32_t uiValueIndex;
197     uint32_t uiSize = getSize();
198     uint32_t uiOffset = getOffset();
199     bool bSubsystemIsBigEndian = parameterAccessContext.isBigEndianSubsystem();
200     uint32_t uiArrayLength = getArrayLength();
201 
202     for (uiValueIndex = 0; uiValueIndex < uiArrayLength; uiValueIndex++) {
203 
204         // Beware this code works on little endian architectures only!
205         pBlackboard->writeInteger(&uiDefaultValue, uiSize, uiOffset, bSubsystemIsBigEndian);
206 
207         uiOffset += uiSize;
208     }
209 }
210 
211 // Index from path
getIndex(CPathNavigator & pathNavigator,uint32_t & uiIndex,CParameterAccessContext & parameterAccessContext) const212 bool CArrayParameter::getIndex(CPathNavigator& pathNavigator, uint32_t& uiIndex, CParameterAccessContext& parameterAccessContext) const
213 {
214     uiIndex = (uint32_t)-1;
215 
216     string* pStrChildName = pathNavigator.next();
217 
218     if (pStrChildName) {
219 
220         // Check index is numeric
221 	std::istringstream iss(*pStrChildName);
222 
223         iss >> uiIndex;
224 
225         if (!iss) {
226 
227             parameterAccessContext.setError("Expected numerical expression as last item in " + pathNavigator.getCurrentPath());
228 
229             return false;
230         }
231 
232         if (uiIndex >= getArrayLength()) {
233 	    std::ostringstream oss;
234 
235             oss << "Provided index out of range (max is " << getArrayLength() - 1 << ")";
236 
237             parameterAccessContext.setError(oss.str());
238 
239             return false;
240         }
241 
242         // Check no other item provided in path
243         pStrChildName = pathNavigator.next();
244 
245         if (pStrChildName) {
246 
247             // Should be leaf element
248             parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
249 
250             return false;
251         }
252     }
253 
254     return true;
255 }
256 
257 // Common set value processing
setValues(uint32_t uiStartIndex,uint32_t uiBaseOffset,const string & strValue,CParameterAccessContext & parameterAccessContext) const258 bool CArrayParameter::setValues(uint32_t uiStartIndex, uint32_t uiBaseOffset, const string& strValue, CParameterAccessContext& parameterAccessContext) const
259 {
260     // Deal with value(s)
261     Tokenizer tok(strValue, Tokenizer::defaultDelimiters + ",");
262 
263     std::vector<string> astrValues = tok.split();
264     size_t uiNbValues = astrValues.size();
265 
266     // Check number of provided values
267     if (uiNbValues + uiStartIndex > getArrayLength()) {
268 
269         // Out of bounds
270         parameterAccessContext.setError("Too many values provided");
271 
272         return false;
273     }
274 
275     // Process
276     uint32_t uiValueIndex;
277     uint32_t uiSize = getSize();
278     uint32_t uiOffset = getOffset() + uiStartIndex * uiSize - uiBaseOffset;
279 
280     for (uiValueIndex = 0; uiValueIndex < uiNbValues; uiValueIndex++) {
281 
282         if (!doSetValue(astrValues[uiValueIndex], uiOffset, parameterAccessContext)) {
283 
284             // Append parameter path to error
285             parameterAccessContext.appendToError(" " + getPath() + "/" +
286                                                  CUtility::toString(uiValueIndex + uiStartIndex));
287 
288             return false;
289         }
290 
291         uiOffset += uiSize;
292     }
293     return true;
294 }
295 
296 // Common get value processing
getValues(uint32_t uiBaseOffset,string & strValues,CParameterAccessContext & parameterAccessContext) const297 void CArrayParameter::getValues(uint32_t uiBaseOffset, string& strValues, CParameterAccessContext& parameterAccessContext) const
298 {
299     uint32_t uiValueIndex;
300     uint32_t uiSize = getSize();
301     uint32_t uiOffset = getOffset() - uiBaseOffset;
302     uint32_t uiArrayLength = getArrayLength();
303 
304     strValues.clear();
305 
306     bool bFirst = true;
307 
308     for (uiValueIndex = 0; uiValueIndex < uiArrayLength; uiValueIndex++) {
309         string strReadValue;
310 
311         doGetValue(strReadValue, uiOffset, parameterAccessContext);
312 
313         if (!bFirst) {
314 
315             strValues += " ";
316         } else {
317 
318             bFirst = false;
319         }
320 
321         strValues += strReadValue;
322 
323         uiOffset += uiSize;
324     }
325 }
326 
327 // Generic Access
328 template <typename type>
accessValues(std::vector<type> & values,bool bSet,CParameterAccessContext & parameterAccessContext) const329 bool CArrayParameter::accessValues(std::vector<type>& values, bool bSet, CParameterAccessContext& parameterAccessContext) const
330 {
331     if (bSet) {
332 
333         // Set Value
334         if (!setValues(values, parameterAccessContext)) {
335 
336             appendParameterPathToError(parameterAccessContext);
337             return false;
338         }
339         if (!sync(parameterAccessContext)) {
340 
341             appendParameterPathToError(parameterAccessContext);
342             return false;
343         }
344     } else {
345         // Get Value
346         if (!getValues(values, parameterAccessContext)) {
347 
348             appendParameterPathToError(parameterAccessContext);
349             return false;
350         }
351     }
352     return true;
353 }
354 
355 template <typename type>
setValues(const std::vector<type> & values,CParameterAccessContext & parameterAccessContext) const356 bool CArrayParameter::setValues(const std::vector<type>& values, CParameterAccessContext& parameterAccessContext) const
357 {
358     uint32_t uiNbValues = getArrayLength();
359     uint32_t uiValueIndex;
360     uint32_t uiSize = getSize();
361     uint32_t uiOffset = getOffset();
362 
363     assert(values.size() == uiNbValues);
364 
365     // Process
366     for (uiValueIndex = 0; uiValueIndex < uiNbValues; uiValueIndex++) {
367 
368         if (!doSet(values[uiValueIndex], uiOffset, parameterAccessContext)) {
369 
370             return false;
371         }
372 
373         uiOffset += uiSize;
374     }
375 
376    return true;
377 }
378 
379 template <typename type>
getValues(std::vector<type> & values,CParameterAccessContext & parameterAccessContext) const380 bool CArrayParameter::getValues(std::vector<type>& values, CParameterAccessContext& parameterAccessContext) const
381 {
382     uint32_t uiNbValues = getArrayLength();
383     uint32_t uiValueIndex;
384     uint32_t uiSize = getSize();
385     uint32_t uiOffset = getOffset();
386 
387     values.clear();
388 
389     for (uiValueIndex = 0; uiValueIndex < uiNbValues; uiValueIndex++) {
390         type readValue;
391 
392         if (!doGet(readValue, uiOffset, parameterAccessContext)) {
393 
394             return false;
395         }
396 
397         values.push_back(readValue);
398 
399         uiOffset += uiSize;
400     }
401     return true;
402 }
403 
404 template <typename type>
doSet(type value,uint32_t uiOffset,CParameterAccessContext & parameterAccessContext) const405 bool CArrayParameter::doSet(type value, uint32_t uiOffset, CParameterAccessContext& parameterAccessContext) const
406 {
407     uint32_t uiData;
408 
409     if (!static_cast<const CParameterType*>(getTypeElement())->toBlackboard(value, uiData, parameterAccessContext)) {
410 
411         return false;
412     }
413     // Write blackboard
414     CParameterBlackboard* pBlackboard = parameterAccessContext.getParameterBlackboard();
415 
416     // Beware this code works on little endian architectures only!
417     pBlackboard->writeInteger(&uiData, getSize(), uiOffset, parameterAccessContext.isBigEndianSubsystem());
418 
419     return true;
420 }
421 
422 template <typename type>
doGet(type & value,uint32_t uiOffset,CParameterAccessContext & parameterAccessContext) const423 bool CArrayParameter::doGet(type& value, uint32_t uiOffset, CParameterAccessContext& parameterAccessContext) const
424 {
425     uint32_t uiData = 0;
426 
427     // Read blackboard
428     const CParameterBlackboard* pBlackboard = parameterAccessContext.getParameterBlackboard();
429 
430     // Beware this code works on little endian architectures only!
431     pBlackboard->readInteger(&uiData, getSize(), uiOffset, parameterAccessContext.isBigEndianSubsystem());
432 
433     return static_cast<const CParameterType*>(getTypeElement())->fromBlackboard(value, uiData, parameterAccessContext);
434 }
435 
436