Argus Camera Sample
Argus Camera Sample
 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