Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
XMLConfig.cpp
Go to the documentation of this file.
1 /*
2 * Copyright (c) 2016-2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of NVIDIA CORPORATION nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <string>
30 #include <fstream>
31 #include <stdio.h>
32
33 #include <expat.h>
34
35 #include "XMLConfig.h"
36 #include "Dispatcher.h"
37 #include "UniquePointer.h"
38
39 namespace ArgusSamples
40 {
41
42 // XML version
43 static const char *VERSION = "1.0";
44
45 // element names
46 static const char *ELEMENT_DEVICE_INDEX = "deviceIndex";
47 static const char *ELEMENT_VERBOSE = "verbose";
48 static const char *ELEMENT_KPI = "kpi";
49 static const char *ELEMENT_EXPOSURE_TIME_RANGE = "exposureTimeRange";
50 static const char *ELEMENT_GAIN_RANGE = "gainRange";
51 static const char *ELEMENT_SENSOR_MODE_INDEX = "sensorModeIndex";
52 static const char *ELEMENT_FRAME_RATE = "frameRate";
53 static const char *ELEMENT_FOCUS_POSITION = "focusPosition";
54 static const char *ELEMENT_CAPTURE_YUV_FORMAT = "captureYuvFormat";
55 static const char *ELEMENT_AE_ANTIBANDING_MODE = "aeAntibandingMode";
56 static const char *ELEMENT_AE_LOCK = "aeLock";
57 static const char *ELEMENT_AWB_LOCK = "awbLock";
58 static const char *ELEMENT_AWB_MODE = "awbMode";
59 static const char *ELEMENT_EXPOSURE_COMPENSATION = "exposureCompensation";
60 static const char *ELEMENT_ISP_DIGITAL_GAIN_RANGE = "ispDigitalGainRange";
61 static const char *ELEMENT_DENOISE_MODE = "denoiseMode";
62 static const char *ELEMENT_STILL_FILE_TYPE = "stillFileType";
63 static const char *ELEMENT_VIDEO_FORMAT = "videoFormat";
64 static const char *ELEMENT_VIDEO_FILE_TYPE = "videoFileType";
65 static const char *ELEMENT_VIDEO_BIT_RATE = "videoBitRate";
66 static const char *ELEMENT_OUTPUT_SIZE = "outputSize";
67 static const char *ELEMENT_OUTPUT_PATH = "outputPath";
68 static const char *ELEMENT_DE_FOG_ENABLE = "deFogEnable";
69 static const char *ELEMENT_DE_FOG_AMOUNT = "deFogAmount";
70 static const char *ELEMENT_DE_FOG_QUALITY = "deFogQaulity";
71
72 static void XMLCALL xmlHandleData(void *parser, const char *s, int len)
73 {
74 XML_Parser p = (XML_Parser)parser;
75 std::string *data = reinterpret_cast<std::string*>(XML_GetUserData(p));
76
77 data->append(s, len);
78 }
79
80 static void XMLCALL xmlStartElement(void *parser, const char *name, const char **atts)
81 {
82 XML_Parser p = (XML_Parser)parser;
83
84 if (strcmp(name, "argusconfig") == 0)
85 {
86 const char **curAtt = atts;
87
88 while (*curAtt != NULL)
89 {
90 const char *attribute = curAtt[0];
91 const char *value = curAtt[1];
92
93 if (strcmp(attribute, "version") == 0)
94 {
95 if (strcmp(value, VERSION) != 0)
96 {
97 ORIGINATE_ERROR_FAIL("Unsupported version '%s' expected version '%s'",
98 value, VERSION);
99 }
100 }
101 else
102 ORIGINATE_ERROR_FAIL("Found unexpected attribute '%s'", attribute);
103 curAtt += 2;
104 }
105 }
106
107 XML_SetCharacterDataHandler(p, xmlHandleData);
108
109 return;
110
111 fail:
112 XML_StopParser(p, XML_FALSE);
113 }
114
115 /**
116 * Check if an element matches the value name, if this is the case set the value to 'dataStr'
117 * @param [in] elementName current element
118 * @param [in] dataStr data for that element
119 * @param [in] valueName value name
120 * @param [in] value value to update with dataStr if there is a match
121 * @param [out] match set if there was a match
122 */
123 template<typename T> static bool checkValue(const char *elementName, const char *dataStr,
124 const char *valueName, Value<T> &value, bool *match)
125 {
126 if (strcmp(elementName, valueName) == 0)
127 {
128 PROPAGATE_ERROR(value.setFromString(dataStr));
129 *match = true;
130 }
131
132 return true;
133 }
134
135 static void XMLCALL xmlEndElement(void *parser, const char *name)
136 {
137 Dispatcher &dispatcher = Dispatcher::getInstance();
138 XML_Parser p = (XML_Parser)parser;
139 std::string *data = reinterpret_cast<std::string*>(XML_GetUserData(p));
140
141 if (strcmp(name, ELEMENT_DEVICE_INDEX) == 0)
142 {
143 PROPAGATE_ERROR_FAIL(dispatcher.m_deviceIndex.setFromString(data->c_str()));
144 }
145 else if (strcmp(name, ELEMENT_VERBOSE) == 0)
146 {
147 PROPAGATE_ERROR_FAIL(dispatcher.m_verbose.setFromString(data->c_str()));
148 }
149 else if (strcmp(name, ELEMENT_KPI) == 0)
150 {
151 PROPAGATE_ERROR_FAIL(dispatcher.m_kpi.setFromString(data->c_str()));
152 }
153 else if (strcmp(name, ELEMENT_EXPOSURE_TIME_RANGE) == 0)
154 {
155 PROPAGATE_ERROR_FAIL(dispatcher.m_exposureTimeRange.setFromString(data->c_str()));
156 }
157 else if (strcmp(name, ELEMENT_GAIN_RANGE) == 0)
158 {
159 PROPAGATE_ERROR_FAIL(dispatcher.m_gainRange.setFromString(data->c_str()));
160 }
161 else if (strcmp(name, ELEMENT_SENSOR_MODE_INDEX) == 0)
162 {
163 PROPAGATE_ERROR_FAIL(dispatcher.m_sensorModeIndex.setFromString(data->c_str()));
164 }
165 else if (strcmp(name, ELEMENT_FRAME_RATE) == 0)
166 {
167 PROPAGATE_ERROR_FAIL(dispatcher.m_frameRate.setFromString(data->c_str()));
168 }
169 else if (strcmp(name, ELEMENT_FOCUS_POSITION) == 0)
170 {
171 PROPAGATE_ERROR_FAIL(dispatcher.m_focusPosition.setFromString(data->c_str()));
172 }
173 else if (strcmp(name, ELEMENT_CAPTURE_YUV_FORMAT) == 0)
174 {
175 PROPAGATE_ERROR_FAIL(dispatcher.m_captureYuvFormat.setFromString(data->c_str()));
176 }
177 else if (strcmp(name, ELEMENT_DENOISE_MODE) == 0)
178 {
179 PROPAGATE_ERROR_FAIL(dispatcher.m_denoiseMode.setFromString(data->c_str()));
180 }
181 else if (strcmp(name, ELEMENT_AE_ANTIBANDING_MODE) == 0)
182 {
183 PROPAGATE_ERROR_FAIL(dispatcher.m_aeAntibandingMode.setFromString(data->c_str()));
184 }
185 else if (strcmp(name, ELEMENT_AE_LOCK) == 0)
186 {
187 PROPAGATE_ERROR_FAIL(dispatcher.m_aeLock.setFromString(data->c_str()));
188 }
189 else if (strcmp(name, ELEMENT_AWB_LOCK) == 0)
190 {
191 PROPAGATE_ERROR_FAIL(dispatcher.m_awbLock.setFromString(data->c_str()));
192 }
193 else if (strcmp(name, ELEMENT_AWB_MODE) == 0)
194 {
195 PROPAGATE_ERROR_FAIL(dispatcher.m_awbMode.setFromString(data->c_str()));
196 }
197 else if (strcmp(name, ELEMENT_EXPOSURE_COMPENSATION) == 0)
198 {
199 PROPAGATE_ERROR_FAIL(dispatcher.m_exposureCompensation.setFromString(data->c_str()));
200 }
201 else if (strcmp(name, ELEMENT_ISP_DIGITAL_GAIN_RANGE) == 0)
202 {
203 PROPAGATE_ERROR_FAIL(dispatcher.m_ispDigitalGainRange.setFromString(data->c_str()));
204 }
205 else if (strcmp(name, ELEMENT_STILL_FILE_TYPE) == 0)
206 {
207 PROPAGATE_ERROR_FAIL(dispatcher.m_stillFileType.setFromString(data->c_str()));
208 }
209 else if (strcmp(name, ELEMENT_VIDEO_FORMAT) == 0)
210 {
211 PROPAGATE_ERROR_FAIL(dispatcher.m_videoFormat.setFromString(data->c_str()));
212 }
213 else if (strcmp(name, ELEMENT_VIDEO_FILE_TYPE) == 0)
214 {
215 PROPAGATE_ERROR_FAIL(dispatcher.m_videoFileType.setFromString(data->c_str()));
216 }
217 else if (strcmp(name, ELEMENT_VIDEO_BIT_RATE) == 0)
218 {
219 PROPAGATE_ERROR_FAIL(dispatcher.m_videoBitRate.setFromString(data->c_str()));
220 }
221 else if (strcmp(name, ELEMENT_OUTPUT_SIZE) == 0)
222 {
223 PROPAGATE_ERROR_FAIL(dispatcher.m_outputSize.setFromString(data->c_str()));
224 }
225 else if (strcmp(name, ELEMENT_OUTPUT_PATH) == 0)
226 {
227 PROPAGATE_ERROR_FAIL(dispatcher.m_outputPath.set(*data));
228 }
229 else if (strcmp(name, ELEMENT_DE_FOG_ENABLE) == 0)
230 {
231 PROPAGATE_ERROR_FAIL(dispatcher.m_deFogEnable.setFromString(data->c_str()));
232 }
233 else if (strcmp(name, ELEMENT_DE_FOG_AMOUNT) == 0)
234 {
235 PROPAGATE_ERROR_FAIL(dispatcher.m_deFogAmount.setFromString(data->c_str()));
236 }
237 else if (strcmp(name, ELEMENT_DE_FOG_QUALITY) == 0)
238 {
239 PROPAGATE_ERROR_FAIL(dispatcher.m_deFogQuality.setFromString(data->c_str()));
240 }
241 else if (strcmp(name, "argusconfig") == 0)
242 {
243 }
244 else
245 {
246 ORIGINATE_ERROR_FAIL("Unhandled element '%s'.", name);
247 }
248
249 XML_SetCharacterDataHandler(p, NULL);
250 data->clear();
251
252 return;
253
254 fail:
255 XML_StopParser(p, XML_FALSE);
256 }
257
258 bool loadConfig(const char *configFile)
259 {
260 if (configFile == NULL)
261 ORIGINATE_ERROR("'configFile' is NULL");
262
263 FILE *xmlFile;
264 bool success = true;
265 long ftellResult;
266 size_t fileSize;
267 UniquePointer<char> fileData;
268 XML_Parser parser = NULL;
269 std::string data;
270
271 // open the file
272 xmlFile = fopen(configFile, "rb");
273 if (xmlFile == NULL)
274 ORIGINATE_ERROR_FAIL("Failed to open file %s", configFile);
275
276 // get file size
277 if (fseek(xmlFile, 0, SEEK_END) != 0)
278 ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
279
280 ftellResult = ftell(xmlFile);
281 if (ftellResult == -1)
282 ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
283 if (ftellResult == 0)
284 ORIGINATE_ERROR_FAIL("Empty file %s", configFile);
285
286 fileSize = ftellResult;
287
288 if (fseek(xmlFile, 0, SEEK_SET) != 0)
289 ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
290
291 // allocate buffer
292 fileData.reset(new char[fileSize + 1]);
293 if (!fileData)
294 ORIGINATE_ERROR_FAIL("Out of memory");
295
296 // read from file to buffer
297 if (fread(fileData.get(), fileSize, 1, xmlFile) != 1)
298 ORIGINATE_ERROR_FAIL("Failed to read buffer file %s", configFile);
299 // terminate string
300 fileData.get()[fileSize] = 0;
301
302 // create XML parser
303 parser = XML_ParserCreate(NULL);
304 if (parser == NULL)
305 ORIGINATE_ERROR_FAIL("Failed to create parser");
306
307 XML_UseParserAsHandlerArg(parser);
308 // the user data is a string, the XML data handler appens to this, the end element handler
309 // then uses it to set the values
310 XML_SetUserData(parser, &data);
311 XML_SetElementHandler(parser, xmlStartElement, xmlEndElement);
312
313 // start parsing
314 if (XML_Parse(parser, fileData.get(), (int)fileSize, 1) == XML_STATUS_ERROR)
315 {
316 // on failure print the line and column number and the line in which the error occured
317 const XML_Size lineNumber = XML_GetCurrentLineNumber(parser);
318 const XML_Size columnNumber = XML_GetCurrentColumnNumber(parser);
319 const XML_Index byteIndex = XML_GetCurrentByteIndex(parser);
320
321 std::string line;
322
323 if ((byteIndex >= 0) && (static_cast<size_t>(byteIndex) < fileSize))
324 {
325 // find line start
326 size_t lineStart = static_cast<size_t>(byteIndex);
327 while ((lineStart > 0) && (fileData.get()[lineStart] != '\n'))
328 --lineStart;
329 // point after new line
330 if (fileData.get()[lineStart] == '\n')
331 ++lineStart;
332
333 // find line end
334 size_t lineEnd = static_cast<size_t>(lineStart);
335 while ((lineEnd < fileSize) && (fileData.get()[lineEnd] != '\n'))
336 ++lineEnd;
337
338 line.append(&fileData.get()[lineStart], lineEnd - lineStart);
339 }
340 else
341 {
342 line += "-";
343 }
344
345 ORIGINATE_ERROR_FAIL("%s at line %lu:%lu:\n%s",
346 XML_ErrorString(XML_GetErrorCode(parser)),
347 lineNumber, columnNumber, line.c_str());
348 }
349
350 goto succeeded;
351
352 fail:
353 success = false;
354
355 succeeded:
356 if (parser != 0)
357 XML_ParserFree(parser);
358 if (xmlFile != NULL)
359 fclose(xmlFile);
360
361 return success;
362 }
363
364 // write an string to XML
365 static void writeValue(std::ofstream &stream, const char *name, const std::string& string)
366 {
367 stream << " <" << name << ">" << string << "</" << name << ">" << std::endl;
368 }
369
370 // write an value to XML
371 template<typename T> static void writeValue(std::ofstream &stream, const char *name,
372 const Value<T> &value)
373 {
374 writeValue(stream, name, value.toString());
375 }
376
377 bool saveConfig(const char *configFile)
378 {
379 if (configFile == NULL)
380 ORIGINATE_ERROR("'configFile' is NULL");
381
382 Dispatcher &dispatcher = Dispatcher::getInstance();
383
384 // open the stream
385 std::ofstream stream(configFile, std::ofstream::out);
386 if (!stream.is_open())
387 ORIGINATE_ERROR("Failed to open file '%s' for saving.", configFile);
388
389 // header
390 stream << "<?xml version='1.0' encoding='utf-8'?>" << std::endl;
391 stream << "<argusconfig version='" << VERSION << "'>" << std::endl;
392
393 // write the value
394 writeValue(stream, ELEMENT_DEVICE_INDEX, dispatcher.m_deviceIndex);
395 writeValue(stream, ELEMENT_VERBOSE, dispatcher.m_verbose);
396 writeValue(stream, ELEMENT_KPI, dispatcher.m_kpi);
397 writeValue(stream, ELEMENT_EXPOSURE_TIME_RANGE, dispatcher.m_exposureTimeRange);
398 writeValue(stream, ELEMENT_GAIN_RANGE, dispatcher.m_gainRange);
399 writeValue(stream, ELEMENT_SENSOR_MODE_INDEX, dispatcher.m_sensorModeIndex);
400 writeValue(stream, ELEMENT_FRAME_RATE, dispatcher.m_frameRate);
401 writeValue(stream, ELEMENT_FOCUS_POSITION, dispatcher.m_focusPosition);
402 writeValue(stream, ELEMENT_CAPTURE_YUV_FORMAT, dispatcher.m_captureYuvFormat);
403 writeValue(stream, ELEMENT_DENOISE_MODE, dispatcher.m_denoiseMode);
404 writeValue(stream, ELEMENT_AE_ANTIBANDING_MODE, dispatcher.m_aeAntibandingMode);
405 writeValue(stream, ELEMENT_AE_LOCK, dispatcher.m_aeLock);
406 writeValue(stream, ELEMENT_AWB_LOCK, dispatcher.m_awbLock);
407 writeValue(stream, ELEMENT_AWB_MODE, dispatcher.m_awbMode);
408 writeValue(stream, ELEMENT_EXPOSURE_COMPENSATION, dispatcher.m_exposureCompensation);
409 writeValue(stream, ELEMENT_ISP_DIGITAL_GAIN_RANGE, dispatcher.m_ispDigitalGainRange);
410 writeValue(stream, ELEMENT_STILL_FILE_TYPE, dispatcher.m_stillFileType);
411 writeValue(stream, ELEMENT_VIDEO_FORMAT, dispatcher.m_videoFormat);
412 writeValue(stream, ELEMENT_VIDEO_FILE_TYPE, dispatcher.m_videoFileType);
413 writeValue(stream, ELEMENT_VIDEO_BIT_RATE, dispatcher.m_videoBitRate);
414 writeValue(stream, ELEMENT_OUTPUT_SIZE, dispatcher.m_outputSize);
415 writeValue(stream, ELEMENT_OUTPUT_PATH, dispatcher.m_outputPath.get());
416 writeValue(stream, ELEMENT_DE_FOG_ENABLE, dispatcher.m_deFogEnable);
417 writeValue(stream, ELEMENT_DE_FOG_AMOUNT, dispatcher.m_deFogAmount);
418 writeValue(stream, ELEMENT_DE_FOG_QUALITY, dispatcher.m_deFogQuality);
419
420 // footer
421 stream << "</argusconfig>" << std::endl;
422
423 stream.close();
424
425 return true;
426 }
427
428 }; // namespace ArgusSamples