ZED Open Capture  v0.6.0
Low level camera driver for the ZED stereo camera family
calibration.hpp
Go to the documentation of this file.
1 #ifndef CONF_MANAGER_HPP
2 #define CONF_MANAGER_HPP
3 
4 // Includes
5 #include <iostream>
6 #include <sstream>
7 #include <string>
8 #include <locale>
9 #include <sstream>
10 #include <vector>
11 #include <fstream>
12 #include <cstdio>
13 
14 #ifdef _WIN32
15 #include <windows.h>
16 #include <shlobj.h>
17 #include <urlmon.h>
18 #pragma comment(lib, "urlmon.lib")
19 #else
20 #include <unistd.h>
21 #include <sys/vfs.h>
22 #endif
23 
24 
25 
26 //https://github.com/brofield/simpleini
27 /*The MIT License (MIT)
28 
29 Copyright (c) 2006-2013 Brodie Thiesfield
30 
31 Permission is hereby granted, free of charge, to any person obtaining a copy of
32 this software and associated documentation files (the "Software"), to deal in
33 the Software without restriction, including without limitation the rights to
34 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
35 the Software, and to permit persons to whom the Software is furnished to do so,
36 subject to the following conditions:
37 
38 The above copyright notice and this permission notice shall be included in all
39 copies or substantial portions of the Software.
40 
41 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
43 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
44 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
45 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
46 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/
47 
48 #ifndef INCLUDED_SimpleIni_h
49 #define INCLUDED_SimpleIni_h
50 
51 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
52 #pragma once
53 #endif
54 
55 // Disable these warnings in MSVC:
56 // 4127 "conditional expression is constant" as the conversion classes trigger
57 // it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
58 // be optimized away in a release build.
59 // 4503 'insert' : decorated name length exceeded, name was truncated
60 // 4702 "unreachable code" as the MS STL header causes it in release mode.
61 // Again, the code causing the warning will be cleaned up by the compiler.
62 // 4786 "identifier truncated to 256 characters" as this is thrown hundreds
63 // of times VC6 as soon as STL is used.
64 #ifdef _MSC_VER
65 #pragma warning (push)
66 #pragma warning (disable: 4127 4503 4702 4786)
67 #endif
68 
69 #include <cstring>
70 #include <cstdlib>
71 #include <string>
72 #include <map>
73 #include <list>
74 #include <algorithm>
75 #include <stdio.h>
76 
77 #ifdef SI_SUPPORT_IOSTREAMS
78 #include <iostream>
79 #endif // SI_SUPPORT_IOSTREAMS
80 
81 #ifdef _DEBUG
82 #ifndef assert
83 #include <cassert>
84 #endif
85 #define SI_ASSERT(x) assert(x)
86 #else
87 #define SI_ASSERT(x)
88 #endif
89 
90 namespace sl_oc {
91 namespace tools {
92 
93 enum SI_Error {
94  SI_OK = 0,
95  SI_UPDATED = 1,
97 
98  // note: test for any error with (retval < 0)
99  SI_FAIL = -1,
100  SI_NOMEM = -2,
101  SI_FILE = -3
102 };
103 
104 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
105 
106 #ifdef _WIN32
107 #define SI_NEWLINE_A "\r\n"
108 #define SI_NEWLINE_W L"\r\n"
109 #else // !_WIN32
110 #define SI_NEWLINE_A "\n"
111 #define SI_NEWLINE_W L"\n"
112 #endif // _WIN32
113 
114 #if defined(SI_CONVERT_ICU)
115 #include <unicode/ustring.h>
116 #endif
117 
118 #if defined(_WIN32)
119 #define SI_HAS_WIDE_FILE
120 #define SI_WCHAR_T wchar_t
121 #elif defined(SI_CONVERT_ICU)
122 #define SI_HAS_WIDE_FILE
123 #define SI_WCHAR_T UChar
124 #endif
125 
126 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
128 public:
129  typedef SI_CHAR SI_CHAR_T;
130 
132  struct Entry {
133  const SI_CHAR * pItem;
134  const SI_CHAR * pComment;
135  int nOrder;
136 
137  Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
138  : pItem(a_pszItem)
139  , pComment(NULL)
140  , nOrder(a_nOrder) {
141  }
142 
143  Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
144  : pItem(a_pszItem)
145  , pComment(a_pszComment)
146  , nOrder(a_nOrder) {
147  }
148 
149  Entry(const Entry & rhs) {
150  operator=(rhs);
151  }
152 
153  Entry & operator=(const Entry & rhs) {
154  pItem = rhs.pItem;
155  pComment = rhs.pComment;
156  nOrder = rhs.nOrder;
157  return *this;
158  }
159 
160 #if defined(_MSC_VER) && _MSC_VER <= 1200
161 
163  bool operator<(const Entry & rhs) const {
164  return LoadOrder()(*this, rhs);
165  }
166 
167  bool operator>(const Entry & rhs) const {
168  return LoadOrder()(rhs, *this);
169  }
170 #endif
171 
173  struct KeyOrder : std::binary_function<Entry, Entry, bool> {
174 
175  bool operator()(const Entry & lhs, const Entry & rhs) const {
176  const static SI_STRLESS isLess = SI_STRLESS();
177  return isLess(lhs.pItem, rhs.pItem);
178  }
179  };
180 
182  struct LoadOrder : std::binary_function<Entry, Entry, bool> {
183 
184  bool operator()(const Entry & lhs, const Entry & rhs) const {
185  if (lhs.nOrder != rhs.nOrder) {
186  return lhs.nOrder < rhs.nOrder;
187  }
188  return KeyOrder()(lhs.pItem, rhs.pItem);
189  }
190  };
191  };
192 
194  typedef std::multimap<Entry, const SI_CHAR *, typename Entry::KeyOrder> TKeyVal;
195 
197  typedef std::map<Entry, TKeyVal, typename Entry::KeyOrder> TSection;
198 
202  typedef std::list<Entry> TNamesDepend;
203 
207  class OutputWriter {
208  public:
209 
211  }
212 
213  virtual ~OutputWriter() {
214  }
215  virtual void Write(const char * a_pBuf) = 0;
216  private:
217  OutputWriter(const OutputWriter &); // disable
218  OutputWriter & operator=(const OutputWriter &); // disable
219  };
220 
222  class FileWriter : public OutputWriter {
223  FILE * m_file;
224  public:
225 
226  FileWriter(FILE * a_file) : m_file(a_file) {
227  }
228 
229  void Write(const char * a_pBuf) {
230  fputs(a_pBuf, m_file);
231  }
232  private:
233  FileWriter(const FileWriter &); // disable
234  FileWriter & operator=(const FileWriter &); // disable
235  };
236 
238  class StringWriter : public OutputWriter {
239  std::string & m_string;
240  public:
241 
242  StringWriter(std::string & a_string) : m_string(a_string) {
243  }
244 
245  void Write(const char * a_pBuf) {
246  m_string.append(a_pBuf);
247  }
248  private:
249  StringWriter(const StringWriter &); // disable
250  StringWriter & operator=(const StringWriter &); // disable
251  };
252 
253 #ifdef SI_SUPPORT_IOSTREAMS
254 
256  class StreamWriter : public OutputWriter {
257  std::ostream & m_ostream;
258  public:
259 
260  StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) {
261  }
262 
263  void Write(const char * a_pBuf) {
264  m_ostream << a_pBuf;
265  }
266  private:
267  StreamWriter(const StreamWriter &); // disable
268  StreamWriter & operator=(const StreamWriter &); // disable
269  };
270 #endif // SI_SUPPORT_IOSTREAMS
271 
275  class Converter : private SI_CONVERTER {
276  public:
277 
278  Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
279  m_scratch.resize(1024);
280  }
281 
282  Converter(const Converter & rhs) {
283  operator=(rhs);
284  }
285 
286  Converter & operator=(const Converter & rhs) {
287  m_scratch = rhs.m_scratch;
288  return *this;
289  }
290 
291  bool ConvertToStore(const SI_CHAR * a_pszString) {
292  size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
293  if (uLen == (size_t) (-1)) {
294  return false;
295  }
296  while (uLen > m_scratch.size()) {
297  m_scratch.resize(m_scratch.size() * 2);
298  }
299  return SI_CONVERTER::ConvertToStore(
300  a_pszString,
301  const_cast<char*> (m_scratch.data()),
302  m_scratch.size());
303  }
304 
305  const char * Data() {
306  return m_scratch.data();
307  }
308  private:
309  std::string m_scratch;
310  };
311 
312 public:
313  /*-----------------------------------------------------------------------*/
314 
322  bool a_bIsUtf8 = false,
323  bool a_bMultiKey = false,
324  bool a_bMultiLine = false
325  );
326 
329 
331  void Reset();
332 
334  bool IsEmpty() const {
335  return m_data.empty();
336  }
337 
338  /*-----------------------------------------------------------------------*/
355  void SetUnicode(bool a_bIsUtf8 = true) {
356  if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
357  }
358 
360  bool IsUnicode() const {
361  return m_bStoreIsUtf8;
362  }
363 
382  void SetMultiKey(bool a_bAllowMultiKey = true) {
383  m_bAllowMultiKey = a_bAllowMultiKey;
384  }
385 
387  bool IsMultiKey() const {
388  return m_bAllowMultiKey;
389  }
390 
398  void SetMultiLine(bool a_bAllowMultiLine = true) {
399  m_bAllowMultiLine = a_bAllowMultiLine;
400  }
401 
403  bool IsMultiLine() const {
404  return m_bAllowMultiLine;
405  }
406 
413  void SetSpaces(bool a_bSpaces = true) {
414  m_bSpaces = a_bSpaces;
415  }
416 
418  bool UsingSpaces() const {
419  return m_bSpaces;
420  }
421 
422  /*-----------------------------------------------------------------------*/
435  const char * a_pszFile
436  );
437 
438 #ifdef SI_HAS_WIDE_FILE
446  const SI_WCHAR_T * a_pwszFile
447  );
448 #endif // SI_HAS_WIDE_FILE
449 
458  FILE * a_fpFile
459  );
460 
461 #ifdef SI_SUPPORT_IOSTREAMS
469  std::istream & a_istream
470  );
471 #endif // SI_SUPPORT_IOSTREAMS
472 
479  SI_Error LoadData(const std::string & a_strData) {
480  return LoadData(a_strData.c_str(), a_strData.size());
481  }
482 
491  const char * a_pData,
492  size_t a_uDataLen
493  );
494 
495  /*-----------------------------------------------------------------------*/
509  const char * a_pszFile,
510  bool a_bAddSignature = true
511  ) const;
512 
513 #ifdef SI_HAS_WIDE_FILE
525  const SI_WCHAR_T * a_pwszFile,
526  bool a_bAddSignature = true
527  ) const;
528 #endif // _WIN32
529 
543  FILE * a_pFile,
544  bool a_bAddSignature = false
545  ) const;
546 
579  OutputWriter & a_oOutput,
580  bool a_bAddSignature = false
581  ) const;
582 
583 #ifdef SI_SUPPORT_IOSTREAMS
584 
597  std::ostream & a_ostream,
598  bool a_bAddSignature = false
599  ) const {
600  StreamWriter writer(a_ostream);
601  return Save(writer, a_bAddSignature);
602  }
603 #endif // SI_SUPPORT_IOSTREAMS
604 
617  std::string & a_sBuffer,
618  bool a_bAddSignature = false
619  ) const {
620  StringWriter writer(a_sBuffer);
621  return Save(writer, a_bAddSignature);
622  }
623 
624  /*-----------------------------------------------------------------------*/
640  TNamesDepend & a_names
641  ) const;
642 
661  const SI_CHAR * a_pSection,
662  TNamesDepend & a_names
663  ) const;
664 
682  const SI_CHAR * a_pSection,
683  const SI_CHAR * a_pKey,
684  TNamesDepend & a_values
685  ) const;
686 
697  const SI_CHAR * a_pSection
698  ) const;
699 
715  const SI_CHAR * a_pSection
716  ) const;
717 
735  const SI_CHAR * GetValue(
736  const SI_CHAR * a_pSection,
737  const SI_CHAR * a_pKey,
738  const SI_CHAR * a_pDefault = NULL,
739  bool * a_pHasMultiple = NULL
740  ) const;
741 
756  const SI_CHAR * a_pSection,
757  const SI_CHAR * a_pKey,
758  long a_nDefault = 0,
759  bool * a_pHasMultiple = NULL
760  ) const;
761 
776  const SI_CHAR * a_pSection,
777  const SI_CHAR * a_pKey,
778  double a_nDefault = 0,
779  bool * a_pHasMultiple = NULL
780  ) const;
781 
801  const SI_CHAR * a_pSection,
802  const SI_CHAR * a_pKey,
803  bool a_bDefault = false,
804  bool * a_pHasMultiple = NULL
805  ) const;
806 
837  const SI_CHAR * a_pSection,
838  const SI_CHAR * a_pKey,
839  const SI_CHAR * a_pValue,
840  const SI_CHAR * a_pComment = NULL,
841  bool a_bForceReplace = false
842  ) {
843  return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
844  }
845 
870  const SI_CHAR * a_pSection,
871  const SI_CHAR * a_pKey,
872  long a_nValue,
873  const SI_CHAR * a_pComment = NULL,
874  bool a_bUseHex = false,
875  bool a_bForceReplace = false
876  );
877 
899  const SI_CHAR * a_pSection,
900  const SI_CHAR * a_pKey,
901  double a_nValue,
902  const SI_CHAR * a_pComment = NULL,
903  bool a_bForceReplace = false
904  );
905 
927  const SI_CHAR * a_pSection,
928  const SI_CHAR * a_pKey,
929  bool a_bValue,
930  const SI_CHAR * a_pComment = NULL,
931  bool a_bForceReplace = false
932  );
933 
952  bool Delete(
953  const SI_CHAR * a_pSection,
954  const SI_CHAR * a_pKey,
955  bool a_bRemoveEmpty = false
956  );
957 
979  const SI_CHAR * a_pSection,
980  const SI_CHAR * a_pKey,
981  const SI_CHAR * a_pValue,
982  bool a_bRemoveEmpty = false
983  );
984 
985  /*-----------------------------------------------------------------------*/
992  return Converter(m_bStoreIsUtf8);
993  }
994 
995  /*-----------------------------------------------------------------------*/
996 
997 private:
998  // copying is not permitted
999  CSimpleIniTempl(const CSimpleIniTempl &); // disabled
1000  CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled
1001 
1004  SI_Error FindFileComment(
1005  SI_CHAR *& a_pData,
1006  bool a_bCopyStrings
1007  );
1008 
1013  bool FindEntry(
1014  SI_CHAR *& a_pData,
1015  const SI_CHAR *& a_pSection,
1016  const SI_CHAR *& a_pKey,
1017  const SI_CHAR *& a_pVal,
1018  const SI_CHAR *& a_pComment
1019  ) const;
1020 
1043  SI_Error AddEntry(
1044  const SI_CHAR * a_pSection,
1045  const SI_CHAR * a_pKey,
1046  const SI_CHAR * a_pValue,
1047  const SI_CHAR * a_pComment,
1048  bool a_bForceReplace,
1049  bool a_bCopyStrings
1050  );
1051 
1053  inline bool IsSpace(SI_CHAR ch) const {
1054  return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
1055  }
1056 
1058  inline bool IsComment(SI_CHAR ch) const {
1059  return (ch == ';' || ch == '#');
1060  }
1061 
1063  inline void SkipNewLine(SI_CHAR *& a_pData) const {
1064  a_pData += (*a_pData == '\r' && *(a_pData + 1) == '\n') ? 2 : 1;
1065  }
1066 
1068  SI_Error CopyString(const SI_CHAR *& a_pString);
1069 
1071  void DeleteString(const SI_CHAR * a_pString);
1072 
1074  bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
1075  const static SI_STRLESS isLess = SI_STRLESS();
1076  return isLess(a_pLeft, a_pRight);
1077  }
1078 
1079  bool IsMultiLineTag(const SI_CHAR * a_pData) const;
1080  bool IsMultiLineData(const SI_CHAR * a_pData) const;
1081  bool LoadMultiLineText(
1082  SI_CHAR *& a_pData,
1083  const SI_CHAR *& a_pVal,
1084  const SI_CHAR * a_pTagName,
1085  bool a_bAllowBlankLinesInComment = false
1086  ) const;
1087  bool IsNewLineChar(SI_CHAR a_c) const;
1088 
1089  bool OutputMultiLineText(
1090  OutputWriter & a_oOutput,
1091  Converter & a_oConverter,
1092  const SI_CHAR * a_pText
1093  ) const;
1094 
1095 private:
1101  SI_CHAR * m_pData;
1102 
1107  size_t m_uDataLen;
1108 
1110  const SI_CHAR * m_pFileComment;
1111 
1113  TSection m_data;
1114 
1119  TNamesDepend m_strings;
1120 
1122  bool m_bStoreIsUtf8;
1123 
1125  bool m_bAllowMultiKey;
1126 
1128  bool m_bAllowMultiLine;
1129 
1131  bool m_bSpaces;
1132 
1136  int m_nOrder;
1137 };
1138 
1139 // ---------------------------------------------------------------------------
1140 // IMPLEMENTATION
1141 // ---------------------------------------------------------------------------
1142 
1143 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1145  bool a_bIsUtf8,
1146  bool a_bAllowMultiKey,
1147  bool a_bAllowMultiLine
1148  )
1149 : m_pData(0)
1150 , m_uDataLen(0)
1151 , m_pFileComment(NULL)
1152 , m_bStoreIsUtf8(a_bIsUtf8)
1153 , m_bAllowMultiKey(a_bAllowMultiKey)
1154 , m_bAllowMultiLine(a_bAllowMultiLine)
1155 , m_bSpaces(true)
1156 , m_nOrder(0) {
1157 }
1158 
1159 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1161  Reset();
1162 }
1163 
1164 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1165 void
1167  // remove all data
1168  delete[] m_pData;
1169  m_pData = NULL;
1170  m_uDataLen = 0;
1171  m_pFileComment = NULL;
1172  if (!m_data.empty()) {
1173  m_data.erase(m_data.begin(), m_data.end());
1174  }
1175 
1176  // remove all strings
1177  if (!m_strings.empty()) {
1178  typename TNamesDepend::iterator i = m_strings.begin();
1179  for (; i != m_strings.end(); ++i) {
1180  delete[] const_cast<SI_CHAR*> (i->pItem);
1181  }
1182  m_strings.erase(m_strings.begin(), m_strings.end());
1183  }
1184 }
1185 
1186 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1187 SI_Error
1189  const char * a_pszFile
1190  ) {
1191  FILE * fp = NULL;
1192 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1193  fopen_s(&fp, a_pszFile, "rb");
1194 #else // !__STDC_WANT_SECURE_LIB__
1195  fp = fopen(a_pszFile, "rb");
1196 #endif // __STDC_WANT_SECURE_LIB__
1197  if (!fp) {
1198  return SI_FILE;
1199  }
1200  SI_Error rc = LoadFile(fp);
1201  fclose(fp);
1202  return rc;
1203 }
1204 
1205 #ifdef SI_HAS_WIDE_FILE
1206 
1207 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1208 SI_Error
1210  const SI_WCHAR_T * a_pwszFile
1211  ) {
1212 #ifdef _WIN32
1213  FILE * fp = NULL;
1214 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1215  _wfopen_s(&fp, a_pwszFile, L"rb");
1216 #else // !__STDC_WANT_SECURE_LIB__
1217  fp = _wfopen(a_pwszFile, L"rb");
1218 #endif // __STDC_WANT_SECURE_LIB__
1219  if (!fp) return SI_FILE;
1220  SI_Error rc = LoadFile(fp);
1221  fclose(fp);
1222  return rc;
1223 #else // !_WIN32 (therefore SI_CONVERT_ICU)
1224  char szFile[256];
1225  u_austrncpy(szFile, a_pwszFile, sizeof (szFile));
1226  return LoadFile(szFile);
1227 #endif // _WIN32
1228 }
1229 #endif // SI_HAS_WIDE_FILE
1230 
1231 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1232 SI_Error
1234  FILE * a_fpFile
1235  ) {
1236  // load the raw file data
1237  int retval = fseek(a_fpFile, 0, SEEK_END);
1238  if (retval != 0) {
1239  return SI_FILE;
1240  }
1241  long lSize = ftell(a_fpFile);
1242  if (lSize < 0) {
1243  return SI_FILE;
1244  }
1245  if (lSize == 0) {
1246  return SI_OK;
1247  }
1248 
1249  // allocate and ensure NULL terminated
1250  char * pData = new(std::nothrow) char[lSize + 1];
1251  if (!pData) {
1252  return SI_NOMEM;
1253  }
1254  pData[lSize] = 0;
1255 
1256  // load data into buffer
1257  fseek(a_fpFile, 0, SEEK_SET);
1258  size_t uRead = fread(pData, sizeof (char), lSize, a_fpFile);
1259  if (uRead != (size_t) lSize) {
1260  delete[] pData;
1261  return SI_FILE;
1262  }
1263 
1264  // convert the raw data to unicode
1265  SI_Error rc = LoadData(pData, uRead);
1266  delete[] pData;
1267  return rc;
1268 }
1269 
1270 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1271 SI_Error
1273  const char * a_pData,
1274  size_t a_uDataLen
1275  ) {
1276  SI_CONVERTER converter(m_bStoreIsUtf8);
1277 
1278  if (a_uDataLen == 0) {
1279  return SI_OK;
1280  }
1281 
1282  // consume the UTF-8 BOM if it exists
1283  if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
1284  if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
1285  a_pData += 3;
1286  a_uDataLen -= 3;
1287  }
1288  }
1289 
1290  // determine the length of the converted data
1291  size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1292  if (uLen == (size_t) (-1)) {
1293  return SI_FAIL;
1294  }
1295 
1296  // allocate memory for the data, ensure that there is a NULL
1297  // terminator wherever the converted data ends
1298  SI_CHAR * pData = new(std::nothrow) SI_CHAR[uLen + 1];
1299  if (!pData) {
1300  return SI_NOMEM;
1301  }
1302  memset(pData, 0, sizeof (SI_CHAR)*(uLen + 1));
1303 
1304  // convert the data
1305  if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1306  delete[] pData;
1307  return SI_FAIL;
1308  }
1309 
1310  // parse it
1311  const static SI_CHAR empty = 0;
1312  SI_CHAR * pWork = pData;
1313  const SI_CHAR * pSection = &empty;
1314  const SI_CHAR * pItem = NULL;
1315  const SI_CHAR * pVal = NULL;
1316  const SI_CHAR * pComment = NULL;
1317 
1318  // We copy the strings if we are loading data into this class when we
1319  // already have stored some.
1320  bool bCopyStrings = (m_pData != NULL);
1321 
1322  // find a file comment if it exists, this is a comment that starts at the
1323  // beginning of the file and continues until the first blank line.
1324  SI_Error rc = FindFileComment(pWork, bCopyStrings);
1325  if (rc < 0) return rc;
1326 
1327  // add every entry in the file to the data table
1328  while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1329  rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
1330  if (rc < 0) return rc;
1331  }
1332 
1333  // store these strings if we didn't copy them
1334  if (bCopyStrings) {
1335  delete[] pData;
1336  } else {
1337  m_pData = pData;
1338  m_uDataLen = uLen + 1;
1339  }
1340 
1341  return SI_OK;
1342 }
1343 
1344 #ifdef SI_SUPPORT_IOSTREAMS
1345 
1346 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1347 SI_Error
1349  std::istream & a_istream
1350  ) {
1351  std::string strData;
1352  char szBuf[512];
1353  do {
1354  a_istream.get(szBuf, sizeof (szBuf), '\0');
1355  strData.append(szBuf);
1356  } while (a_istream.good());
1357  return LoadData(strData);
1358 }
1359 #endif // SI_SUPPORT_IOSTREAMS
1360 
1361 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1362 SI_Error
1364  SI_CHAR *& a_pData,
1365  bool a_bCopyStrings
1366  ) {
1367  // there can only be a single file comment
1368  if (m_pFileComment) {
1369  return SI_OK;
1370  }
1371 
1372  // Load the file comment as multi-line text, this will modify all of
1373  // the newline characters to be single \n chars
1374  if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
1375  return SI_OK;
1376  }
1377 
1378  // copy the string if necessary
1379  if (a_bCopyStrings) {
1380  SI_Error rc = CopyString(m_pFileComment);
1381  if (rc < 0) return rc;
1382  }
1383 
1384  return SI_OK;
1385 }
1386 
1387 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1388 bool
1389 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::FindEntry(
1390  SI_CHAR *& a_pData,
1391  const SI_CHAR *& a_pSection,
1392  const SI_CHAR *& a_pKey,
1393  const SI_CHAR *& a_pVal,
1394  const SI_CHAR *& a_pComment
1395  ) const {
1396  a_pComment = NULL;
1397 
1398  SI_CHAR * pTrail = NULL;
1399  while (*a_pData) {
1400  // skip spaces and empty lines
1401  while (*a_pData && IsSpace(*a_pData)) {
1402  ++a_pData;
1403  }
1404  if (!*a_pData) {
1405  break;
1406  }
1407 
1408  // skip processing of comment lines but keep a pointer to
1409  // the start of the comment.
1410  if (IsComment(*a_pData)) {
1411  LoadMultiLineText(a_pData, a_pComment, NULL, true);
1412  continue;
1413  }
1414 
1415  // process section names
1416  if (*a_pData == '[') {
1417  // skip leading spaces
1418  ++a_pData;
1419  while (*a_pData && IsSpace(*a_pData)) {
1420  ++a_pData;
1421  }
1422 
1423  // find the end of the section name (it may contain spaces)
1424  // and convert it to lowercase as necessary
1425  a_pSection = a_pData;
1426  while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
1427  ++a_pData;
1428  }
1429 
1430  // if it's an invalid line, just skip it
1431  if (*a_pData != ']') {
1432  continue;
1433  }
1434 
1435  // remove trailing spaces from the section
1436  pTrail = a_pData - 1;
1437  while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1438  --pTrail;
1439  }
1440  ++pTrail;
1441  *pTrail = 0;
1442 
1443  // skip to the end of the line
1444  ++a_pData; // safe as checked that it == ']' above
1445  while (*a_pData && !IsNewLineChar(*a_pData)) {
1446  ++a_pData;
1447  }
1448 
1449  a_pKey = NULL;
1450  a_pVal = NULL;
1451  return true;
1452  }
1453 
1454  // find the end of the key name (it may contain spaces)
1455  // and convert it to lowercase as necessary
1456  a_pKey = a_pData;
1457  while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
1458  ++a_pData;
1459  }
1460 
1461  // if it's an invalid line, just skip it
1462  if (*a_pData != '=') {
1463  continue;
1464  }
1465 
1466  // empty keys are invalid
1467  if (a_pKey == a_pData) {
1468  while (*a_pData && !IsNewLineChar(*a_pData)) {
1469  ++a_pData;
1470  }
1471  continue;
1472  }
1473 
1474  // remove trailing spaces from the key
1475  pTrail = a_pData - 1;
1476  while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1477  --pTrail;
1478  }
1479  ++pTrail;
1480  *pTrail = 0;
1481 
1482  // skip leading whitespace on the value
1483  ++a_pData; // safe as checked that it == '=' above
1484  while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1485  ++a_pData;
1486  }
1487 
1488  // find the end of the value which is the end of this line
1489  a_pVal = a_pData;
1490  while (*a_pData && !IsNewLineChar(*a_pData)) {
1491  ++a_pData;
1492  }
1493 
1494  // remove trailing spaces from the value
1495  pTrail = a_pData - 1;
1496  if (*a_pData) { // prepare for the next round
1497  SkipNewLine(a_pData);
1498  }
1499  while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1500  --pTrail;
1501  }
1502  ++pTrail;
1503  *pTrail = 0;
1504 
1505  // check for multi-line entries
1506  if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1507  // skip the "<<<" to get the tag that will end the multiline
1508  const SI_CHAR * pTagName = a_pVal + 3;
1509  return LoadMultiLineText(a_pData, a_pVal, pTagName);
1510  }
1511 
1512  // return the standard entry
1513  return true;
1514  }
1515 
1516  return false;
1517 }
1518 
1519 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1520 bool
1521 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::IsMultiLineTag(
1522  const SI_CHAR * a_pVal
1523  ) const {
1524  // check for the "<<<" prefix for a multi-line entry
1525  if (*a_pVal++ != '<') return false;
1526  if (*a_pVal++ != '<') return false;
1527  if (*a_pVal++ != '<') return false;
1528  return true;
1529 }
1530 
1531 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1532 bool
1533 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::IsMultiLineData(
1534  const SI_CHAR * a_pData
1535  ) const {
1536  // data is multi-line if it has any of the following features:
1537  // * whitespace prefix
1538  // * embedded newlines
1539  // * whitespace suffix
1540 
1541  // empty string
1542  if (!*a_pData) {
1543  return false;
1544  }
1545 
1546  // check for prefix
1547  if (IsSpace(*a_pData)) {
1548  return true;
1549  }
1550 
1551  // embedded newlines
1552  while (*a_pData) {
1553  if (IsNewLineChar(*a_pData)) {
1554  return true;
1555  }
1556  ++a_pData;
1557  }
1558 
1559  // check for suffix
1560  if (IsSpace(*--a_pData)) {
1561  return true;
1562  }
1563 
1564  return false;
1565 }
1566 
1567 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1568 bool
1569 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::IsNewLineChar(
1570  SI_CHAR a_c
1571  ) const {
1572  return (a_c == '\n' || a_c == '\r');
1573 }
1574 
1575 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1576 bool
1577 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::LoadMultiLineText(
1578  SI_CHAR *& a_pData,
1579  const SI_CHAR *& a_pVal,
1580  const SI_CHAR * a_pTagName,
1581  bool a_bAllowBlankLinesInComment
1582  ) const {
1583  // we modify this data to strip all newlines down to a single '\n'
1584  // character. This means that on Windows we need to strip out some
1585  // characters which will make the data shorter.
1586  // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
1587  // LINE1-LINE1\nLINE2-LINE2\0
1588  // The pDataLine entry is the pointer to the location in memory that
1589  // the current line needs to start to run following the existing one.
1590  // This may be the same as pCurrLine in which case no move is needed.
1591  SI_CHAR * pDataLine = a_pData;
1592  SI_CHAR * pCurrLine;
1593 
1594  // value starts at the current line
1595  a_pVal = a_pData;
1596 
1597  // find the end tag. This tag must start in column 1 and be
1598  // followed by a newline. No whitespace removal is done while
1599  // searching for this tag.
1600  SI_CHAR cEndOfLineChar = *a_pData;
1601  for (;;) {
1602  // if we are loading comments then we need a comment character as
1603  // the first character on every line
1604  if (!a_pTagName && !IsComment(*a_pData)) {
1605  // if we aren't allowing blank lines then we're done
1606  if (!a_bAllowBlankLinesInComment) {
1607  break;
1608  }
1609 
1610  // if we are allowing blank lines then we only include them
1611  // in this comment if another comment follows, so read ahead
1612  // to find out.
1613  SI_CHAR * pCurr = a_pData;
1614  int nNewLines = 0;
1615  while (IsSpace(*pCurr)) {
1616  if (IsNewLineChar(*pCurr)) {
1617  ++nNewLines;
1618  SkipNewLine(pCurr);
1619  } else {
1620  ++pCurr;
1621  }
1622  }
1623 
1624  // we have a comment, add the blank lines to the output
1625  // and continue processing from here
1626  if (IsComment(*pCurr)) {
1627  for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
1628  a_pData = pCurr;
1629  continue;
1630  }
1631 
1632  // the comment ends here
1633  break;
1634  }
1635 
1636  // find the end of this line
1637  pCurrLine = a_pData;
1638  while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1639 
1640  // move this line down to the location that it should be if necessary
1641  if (pDataLine < pCurrLine) {
1642  size_t nLen = (size_t) (a_pData - pCurrLine);
1643  memmove(pDataLine, pCurrLine, nLen * sizeof (SI_CHAR));
1644  pDataLine[nLen] = '\0';
1645  }
1646 
1647  // end the line with a NULL
1648  cEndOfLineChar = *a_pData;
1649  *a_pData = 0;
1650 
1651  // if are looking for a tag then do the check now. This is done before
1652  // checking for end of the data, so that if we have the tag at the end
1653  // of the data then the tag is removed correctly.
1654  if (a_pTagName &&
1655  (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine))) {
1656  break;
1657  }
1658 
1659  // if we are at the end of the data then we just automatically end
1660  // this entry and return the current data.
1661  if (!cEndOfLineChar) {
1662  return true;
1663  }
1664 
1665  // otherwise we need to process this newline to ensure that it consists
1666  // of just a single \n character.
1667  pDataLine += (a_pData - pCurrLine);
1668  *a_pData = cEndOfLineChar;
1669  SkipNewLine(a_pData);
1670  *pDataLine++ = '\n';
1671  }
1672 
1673  // if we didn't find a comment at all then return false
1674  if (a_pVal == a_pData) {
1675  a_pVal = NULL;
1676  return false;
1677  }
1678 
1679  // the data (which ends at the end of the last line) needs to be
1680  // null-terminated BEFORE before the newline character(s). If the
1681  // user wants a new line in the multi-line data then they need to
1682  // add an empty line before the tag.
1683  *--pDataLine = '\0';
1684 
1685  // if looking for a tag and if we aren't at the end of the data,
1686  // then move a_pData to the start of the next line.
1687  if (a_pTagName && cEndOfLineChar) {
1688  SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1689  *a_pData = cEndOfLineChar;
1690  SkipNewLine(a_pData);
1691  }
1692 
1693  return true;
1694 }
1695 
1696 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1697 SI_Error
1698 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::CopyString(
1699  const SI_CHAR *& a_pString
1700  ) {
1701  size_t uLen = 0;
1702  if (sizeof (SI_CHAR) == sizeof (char)) {
1703  uLen = strlen((const char *) a_pString);
1704  } else if (sizeof (SI_CHAR) == sizeof (wchar_t)) {
1705  uLen = wcslen((const wchar_t *)a_pString);
1706  } else {
1707  for (; a_pString[uLen]; ++uLen) /*loop*/;
1708  }
1709  ++uLen; // NULL character
1710  SI_CHAR * pCopy = new(std::nothrow) SI_CHAR[uLen];
1711  if (!pCopy) {
1712  return SI_NOMEM;
1713  }
1714  memcpy(pCopy, a_pString, sizeof (SI_CHAR) * uLen);
1715  m_strings.push_back(pCopy);
1716  a_pString = pCopy;
1717  return SI_OK;
1718 }
1719 
1720 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1721 SI_Error
1722 CSimpleIniTempl<SI_CHAR, SI_STRLESS, SI_CONVERTER>::AddEntry(
1723  const SI_CHAR * a_pSection,
1724  const SI_CHAR * a_pKey,
1725  const SI_CHAR * a_pValue,
1726  const SI_CHAR * a_pComment,
1727  bool a_bForceReplace,
1728  bool a_bCopyStrings
1729  ) {
1730  SI_Error rc;
1731  bool bInserted = false;
1732 
1733  SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1734 
1735  // if we are copying strings then make a copy of the comment now
1736  // because we will need it when we add the entry.
1737  if (a_bCopyStrings && a_pComment) {
1738  rc = CopyString(a_pComment);
1739  if (rc < 0) return rc;
1740  }
1741 
1742  // create the section entry if necessary
1743  typename TSection::iterator iSection = m_data.find(a_pSection);
1744  if (iSection == m_data.end()) {
1745  // if the section doesn't exist then we need a copy as the
1746  // string needs to last beyond the end of this function
1747  if (a_bCopyStrings) {
1748  rc = CopyString(a_pSection);
1749  if (rc < 0) return rc;
1750  }
1751 
1752  // only set the comment if this is a section only entry
1753  Entry oSection(a_pSection, ++m_nOrder);
1754  if (a_pComment && (!a_pKey || !a_pValue)) {
1755  oSection.pComment = a_pComment;
1756  }
1757 
1758  typename TSection::value_type oEntry(oSection, TKeyVal());
1759  typedef typename TSection::iterator SectionIterator;
1760  std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
1761  iSection = i.first;
1762  bInserted = true;
1763  }
1764  if (!a_pKey || !a_pValue) {
1765  // section only entries are specified with pItem and pVal as NULL
1766  return bInserted ? SI_INSERTED : SI_UPDATED;
1767  }
1768 
1769  // check for existence of the key
1770  TKeyVal & keyval = iSection->second;
1771  typename TKeyVal::iterator iKey = keyval.find(a_pKey);
1772 
1773  // remove all existing entries but save the load order and
1774  // comment of the first entry
1775  int nLoadOrder = ++m_nOrder;
1776  if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
1777  const SI_CHAR * pComment = NULL;
1778  while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
1779  if (iKey->first.nOrder < nLoadOrder) {
1780  nLoadOrder = iKey->first.nOrder;
1781  pComment = iKey->first.pComment;
1782  }
1783  ++iKey;
1784  }
1785  if (pComment) {
1786  DeleteString(a_pComment);
1787  a_pComment = pComment;
1788  CopyString(a_pComment);
1789  }
1790  Delete(a_pSection, a_pKey);
1791  iKey = keyval.end();
1792  }
1793 
1794  // make string copies if necessary
1795  bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
1796  if (a_bCopyStrings) {
1797  if (bForceCreateNewKey || iKey == keyval.end()) {
1798  // if the key doesn't exist then we need a copy as the
1799  // string needs to last beyond the end of this function
1800  // because we will be inserting the key next
1801  rc = CopyString(a_pKey);
1802  if (rc < 0) return rc;
1803  }
1804 
1805  // we always need a copy of the value
1806  rc = CopyString(a_pValue);
1807  if (rc < 0) return rc;
1808  }
1809 
1810  // create the key entry
1811  if (iKey == keyval.end() || bForceCreateNewKey) {
1812  Entry oKey(a_pKey, nLoadOrder);
1813  if (a_pComment) {
1814  oKey.pComment = a_pComment;
1815  }
1816  typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *> (NULL));
1817  iKey = keyval.insert(oEntry);
1818  bInserted = true;
1819  }
1820  iKey->second = a_pValue;
1821  return bInserted ? SI_INSERTED : SI_UPDATED;
1822 }
1823 
1824 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1825 const SI_CHAR *
1827  const SI_CHAR * a_pSection,
1828  const SI_CHAR * a_pKey,
1829  const SI_CHAR * a_pDefault,
1830  bool * a_pHasMultiple
1831  ) const {
1832  if (a_pHasMultiple) {
1833  *a_pHasMultiple = false;
1834  }
1835  if (!a_pSection || !a_pKey) {
1836  return a_pDefault;
1837  }
1838  typename TSection::const_iterator iSection = m_data.find(a_pSection);
1839  if (iSection == m_data.end()) {
1840  return a_pDefault;
1841  }
1842  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
1843  if (iKeyVal == iSection->second.end()) {
1844  return a_pDefault;
1845  }
1846 
1847  // check for multiple entries with the same key
1848  if (m_bAllowMultiKey && a_pHasMultiple) {
1849  typename TKeyVal::const_iterator iTemp = iKeyVal;
1850  if (++iTemp != iSection->second.end()) {
1851  if (!IsLess(a_pKey, iTemp->first.pItem)) {
1852  *a_pHasMultiple = true;
1853  }
1854  }
1855  }
1856 
1857  return iKeyVal->second;
1858 }
1859 
1860 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1861 long
1863  const SI_CHAR * a_pSection,
1864  const SI_CHAR * a_pKey,
1865  long a_nDefault,
1866  bool * a_pHasMultiple
1867  ) const {
1868  // return the default if we don't have a value
1869  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1870  if (!pszValue || !*pszValue) return a_nDefault;
1871 
1872  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
1873  char szValue[64] = {0};
1874  SI_CONVERTER c(m_bStoreIsUtf8);
1875  if (!c.ConvertToStore(pszValue, szValue, sizeof (szValue))) {
1876  return a_nDefault;
1877  }
1878 
1879  // handle the value as hex if prefaced with "0x"
1880  long nValue = a_nDefault;
1881  char * pszSuffix = szValue;
1882  if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
1883  if (!szValue[2]) return a_nDefault;
1884  nValue = strtol(&szValue[2], &pszSuffix, 16);
1885  } else {
1886  nValue = strtol(szValue, &pszSuffix, 10);
1887  }
1888 
1889  // any invalid strings will return the default value
1890  if (*pszSuffix) {
1891  return a_nDefault;
1892  }
1893 
1894  return nValue;
1895 }
1896 
1897 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1898 SI_Error
1900  const SI_CHAR * a_pSection,
1901  const SI_CHAR * a_pKey,
1902  long a_nValue,
1903  const SI_CHAR * a_pComment,
1904  bool a_bUseHex,
1905  bool a_bForceReplace
1906  ) {
1907  // use SetValue to create sections
1908  if (!a_pSection || !a_pKey) return SI_FAIL;
1909 
1910  // convert to an ASCII string
1911  char szInput[64];
1912 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1913  sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
1914 #else // !__STDC_WANT_SECURE_LIB__
1915  sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
1916 #endif // __STDC_WANT_SECURE_LIB__
1917 
1918  // convert to output text
1919  SI_CHAR szOutput[64];
1920  SI_CONVERTER c(m_bStoreIsUtf8);
1921  c.ConvertFromStore(szInput, strlen(szInput) + 1,
1922  szOutput, sizeof (szOutput) / sizeof (SI_CHAR));
1923 
1924  // actually add it
1925  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
1926 }
1927 
1928 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1929 double
1931  const SI_CHAR * a_pSection,
1932  const SI_CHAR * a_pKey,
1933  double a_nDefault,
1934  bool * a_pHasMultiple
1935  ) const {
1936  // return the default if we don't have a value
1937  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1938  if (!pszValue || !*pszValue) return a_nDefault;
1939 
1940  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
1941  char szValue[64] = {0};
1942  SI_CONVERTER c(m_bStoreIsUtf8);
1943  if (!c.ConvertToStore(pszValue, szValue, sizeof (szValue))) {
1944  return a_nDefault;
1945  }
1946 
1947  char * pszSuffix = NULL;
1948  double nValue = strtod(szValue, &pszSuffix);
1949 
1950  // any invalid strings will return the default value
1951  if (!pszSuffix || *pszSuffix) {
1952  return a_nDefault;
1953  }
1954 
1955  return nValue;
1956 }
1957 
1958 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1959 SI_Error
1961  const SI_CHAR * a_pSection,
1962  const SI_CHAR * a_pKey,
1963  double a_nValue,
1964  const SI_CHAR * a_pComment,
1965  bool a_bForceReplace
1966  ) {
1967  // use SetValue to create sections
1968  if (!a_pSection || !a_pKey) return SI_FAIL;
1969 
1970  // convert to an ASCII string
1971  char szInput[64];
1972 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1973  sprintf_s(szInput, "%f", a_nValue);
1974 #else // !__STDC_WANT_SECURE_LIB__
1975  sprintf(szInput, "%f", a_nValue);
1976 #endif // __STDC_WANT_SECURE_LIB__
1977 
1978  // convert to output text
1979  SI_CHAR szOutput[64];
1980  SI_CONVERTER c(m_bStoreIsUtf8);
1981  c.ConvertFromStore(szInput, strlen(szInput) + 1,
1982  szOutput, sizeof (szOutput) / sizeof (SI_CHAR));
1983 
1984  // actually add it
1985  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
1986 }
1987 
1988 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1989 bool
1991  const SI_CHAR * a_pSection,
1992  const SI_CHAR * a_pKey,
1993  bool a_bDefault,
1994  bool * a_pHasMultiple
1995  ) const {
1996  // return the default if we don't have a value
1997  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1998  if (!pszValue || !*pszValue) return a_bDefault;
1999 
2000  // we only look at the minimum number of characters
2001  switch (pszValue[0]) {
2002  case 't': case 'T': // true
2003  case 'y': case 'Y': // yes
2004  case '1': // 1 (one)
2005  return true;
2006 
2007  case 'f': case 'F': // false
2008  case 'n': case 'N': // no
2009  case '0': // 0 (zero)
2010  return false;
2011 
2012  case 'o': case 'O':
2013  if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on
2014  if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off
2015  break;
2016  }
2017 
2018  // no recognized value, return the default
2019  return a_bDefault;
2020 }
2021 
2022 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2023 SI_Error
2025  const SI_CHAR * a_pSection,
2026  const SI_CHAR * a_pKey,
2027  bool a_bValue,
2028  const SI_CHAR * a_pComment,
2029  bool a_bForceReplace
2030  ) {
2031  // use SetValue to create sections
2032  if (!a_pSection || !a_pKey) return SI_FAIL;
2033 
2034  // convert to an ASCII string
2035  const char * pszInput = a_bValue ? "true" : "false";
2036 
2037  // convert to output text
2038  SI_CHAR szOutput[64];
2039  SI_CONVERTER c(m_bStoreIsUtf8);
2040  c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
2041  szOutput, sizeof (szOutput) / sizeof (SI_CHAR));
2042 
2043  // actually add it
2044  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2045 }
2046 
2047 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2048 bool
2050  const SI_CHAR * a_pSection,
2051  const SI_CHAR * a_pKey,
2052  TNamesDepend & a_values
2053  ) const {
2054  a_values.clear();
2055 
2056  if (!a_pSection || !a_pKey) {
2057  return false;
2058  }
2059  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2060  if (iSection == m_data.end()) {
2061  return false;
2062  }
2063  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2064  if (iKeyVal == iSection->second.end()) {
2065  return false;
2066  }
2067 
2068  // insert all values for this key
2069  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2070  if (m_bAllowMultiKey) {
2071  ++iKeyVal;
2072  while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
2073  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2074  ++iKeyVal;
2075  }
2076  }
2077 
2078  return true;
2079 }
2080 
2081 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2082 int
2084  const SI_CHAR * a_pSection
2085  ) const {
2086  if (!a_pSection) {
2087  return -1;
2088  }
2089 
2090  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2091  if (iSection == m_data.end()) {
2092  return -1;
2093  }
2094  const TKeyVal & section = iSection->second;
2095 
2096  // if multi-key isn't permitted then the section size is
2097  // the number of keys that we have.
2098  if (!m_bAllowMultiKey || section.empty()) {
2099  return (int) section.size();
2100  }
2101 
2102  // otherwise we need to count them
2103  int nCount = 0;
2104  const SI_CHAR * pLastKey = NULL;
2105  typename TKeyVal::const_iterator iKeyVal = section.begin();
2106  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
2107  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2108  ++nCount;
2109  pLastKey = iKeyVal->first.pItem;
2110  }
2111  }
2112  return nCount;
2113 }
2114 
2115 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2118  const SI_CHAR * a_pSection
2119  ) const {
2120  if (a_pSection) {
2121  typename TSection::const_iterator i = m_data.find(a_pSection);
2122  if (i != m_data.end()) {
2123  return &(i->second);
2124  }
2125  }
2126  return 0;
2127 }
2128 
2129 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2130 void
2132  TNamesDepend & a_names
2133  ) const {
2134  a_names.clear();
2135  typename TSection::const_iterator i = m_data.begin();
2136  for (int n = 0; i != m_data.end(); ++i, ++n) {
2137  a_names.push_back(i->first);
2138  }
2139 }
2140 
2141 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2142 bool
2144  const SI_CHAR * a_pSection,
2145  TNamesDepend & a_names
2146  ) const {
2147  a_names.clear();
2148 
2149  if (!a_pSection) {
2150  return false;
2151  }
2152 
2153  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2154  if (iSection == m_data.end()) {
2155  return false;
2156  }
2157 
2158  const TKeyVal & section = iSection->second;
2159  const SI_CHAR * pLastKey = NULL;
2160  typename TKeyVal::const_iterator iKeyVal = section.begin();
2161  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
2162  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2163  a_names.push_back(iKeyVal->first);
2164  pLastKey = iKeyVal->first.pItem;
2165  }
2166  }
2167 
2168  return true;
2169 }
2170 
2171 #if 0
2172 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2173 SI_Error
2175  const char * a_pszFile,
2176  bool a_bAddSignature
2177  ) const {
2178  FILE * fp = NULL;
2179 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2180  fopen_s(&fp, a_pszFile, "wb");
2181 #else // !__STDC_WANT_SECURE_LIB__
2182  fp = fopen(a_pszFile, "wb");
2183 #endif // __STDC_WANT_SECURE_LIB__
2184  if (!fp) return SI_FILE;
2185  SI_Error rc = SaveFile(fp, a_bAddSignature);
2186  fclose(fp);
2187  return rc;
2188 }
2189 
2190 #ifdef SI_HAS_WIDE_FILE
2191 
2192 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2193 SI_Error
2195  const SI_WCHAR_T * a_pwszFile,
2196  bool a_bAddSignature
2197  ) const {
2198 #ifdef _WIN32
2199  FILE * fp = NULL;
2200 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2201  _wfopen_s(&fp, a_pwszFile, L"wb");
2202 #else // !__STDC_WANT_SECURE_LIB__
2203  fp = _wfopen(a_pwszFile, L"wb");
2204 #endif // __STDC_WANT_SECURE_LIB__
2205  if (!fp) return SI_FILE;
2206  SI_Error rc = SaveFile(fp, a_bAddSignature);
2207  fclose(fp);
2208  return rc;
2209 #else // !_WIN32 (therefore SI_CONVERT_ICU)
2210  char szFile[256];
2211  u_austrncpy(szFile, a_pwszFile, sizeof (szFile));
2212  return SaveFile(szFile, a_bAddSignature);
2213 #endif // _WIN32
2214 }
2215 #endif // SI_HAS_WIDE_FILE
2216 
2217 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2218 SI_Error
2220  FILE * a_pFile,
2221  bool a_bAddSignature
2222  ) const {
2223  FileWriter writer(a_pFile);
2224  return Save(writer, a_bAddSignature);
2225 }
2226 
2227 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2228 SI_Error
2230  OutputWriter & a_oOutput,
2231  bool a_bAddSignature
2232  ) const {
2233  Converter convert(m_bStoreIsUtf8);
2234 
2235  // add the UTF-8 signature if it is desired
2236  if (m_bStoreIsUtf8 && a_bAddSignature) {
2237  a_oOutput.Write(SI_UTF8_SIGNATURE);
2238  }
2239 
2240  // get all of the sections sorted in load order
2241  TNamesDepend oSections;
2242  GetAllSections(oSections);
2243 #if defined(_MSC_VER) && _MSC_VER <= 1200
2244  oSections.sort();
2245 #elif defined(__BORLANDC__)
2246  oSections.sort(Entry::LoadOrder());
2247 #else
2248  oSections.sort(typename Entry::LoadOrder());
2249 #endif
2250 
2251  // write the file comment if we have one
2252  bool bNeedNewLine = false;
2253  if (m_pFileComment) {
2254  if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2255  return SI_FAIL;
2256  }
2257  bNeedNewLine = true;
2258  }
2259 
2260  // iterate through our sections and output the data
2261  typename TNamesDepend::const_iterator iSection = oSections.begin();
2262  for (; iSection != oSections.end(); ++iSection) {
2263  // write out the comment if there is one
2264  if (iSection->pComment) {
2265  if (bNeedNewLine) {
2266  a_oOutput.Write(SI_NEWLINE_A);
2267  a_oOutput.Write(SI_NEWLINE_A);
2268  }
2269  if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2270  return SI_FAIL;
2271  }
2272  bNeedNewLine = false;
2273  }
2274 
2275  if (bNeedNewLine) {
2276  a_oOutput.Write(SI_NEWLINE_A);
2277  a_oOutput.Write(SI_NEWLINE_A);
2278  bNeedNewLine = false;
2279  }
2280 
2281  // write the section (unless there is no section name)
2282  if (*iSection->pItem) {
2283  if (!convert.ConvertToStore(iSection->pItem)) {
2284  return SI_FAIL;
2285  }
2286  a_oOutput.Write("[");
2287  a_oOutput.Write(convert.Data());
2288  a_oOutput.Write("]");
2289  a_oOutput.Write(SI_NEWLINE_A);
2290  }
2291 
2292  // get all of the keys sorted in load order
2293  TNamesDepend oKeys;
2294  GetAllKeys(iSection->pItem, oKeys);
2295 #if defined(_MSC_VER) && _MSC_VER <= 1200
2296  oKeys.sort();
2297 #elif defined(__BORLANDC__)
2298  oKeys.sort(Entry::LoadOrder());
2299 #else
2300  oKeys.sort(typename Entry::LoadOrder());
2301 #endif
2302 
2303  // write all keys and values
2304  typename TNamesDepend::const_iterator iKey = oKeys.begin();
2305  for (; iKey != oKeys.end(); ++iKey) {
2306  // get all values for this key
2307  TNamesDepend oValues;
2308  GetAllValues(iSection->pItem, iKey->pItem, oValues);
2309 
2310  typename TNamesDepend::const_iterator iValue = oValues.begin();
2311  for (; iValue != oValues.end(); ++iValue) {
2312  // write out the comment if there is one
2313  if (iValue->pComment) {
2314  a_oOutput.Write(SI_NEWLINE_A);
2315  if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2316  return SI_FAIL;
2317  }
2318  }
2319 
2320  // write the key
2321  if (!convert.ConvertToStore(iKey->pItem)) {
2322  return SI_FAIL;
2323  }
2324  a_oOutput.Write(convert.Data());
2325 
2326  // write the value
2327  if (!convert.ConvertToStore(iValue->pItem)) {
2328  return SI_FAIL;
2329  }
2330  a_oOutput.Write(m_bSpaces ? " = " : "=");
2331  if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2332  // multi-line data needs to be processed specially to ensure
2333  // that we use the correct newline format for the current system
2334  a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
2335  if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2336  return SI_FAIL;
2337  }
2338  a_oOutput.Write("END_OF_TEXT");
2339  } else {
2340  a_oOutput.Write(convert.Data());
2341  }
2342  a_oOutput.Write(SI_NEWLINE_A);
2343  }
2344  }
2345 
2346  bNeedNewLine = true;
2347  }
2348 
2349  return SI_OK;
2350 }
2351 
2352 #endif
2353 
2354 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2355 bool
2357  OutputWriter & a_oOutput,
2358  Converter & a_oConverter,
2359  const SI_CHAR * a_pText
2360  ) const {
2361  const SI_CHAR * pEndOfLine;
2362  SI_CHAR cEndOfLineChar = *a_pText;
2363  while (cEndOfLineChar) {
2364  // find the end of this line
2365  pEndOfLine = a_pText;
2366  for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/;
2367  cEndOfLineChar = *pEndOfLine;
2368 
2369  // temporarily null terminate, convert and output the line
2370  *const_cast<SI_CHAR*> (pEndOfLine) = 0;
2371  if (!a_oConverter.ConvertToStore(a_pText)) {
2372  return false;
2373  }
2374  *const_cast<SI_CHAR*> (pEndOfLine) = cEndOfLineChar;
2375  a_pText += (pEndOfLine - a_pText) + 1;
2376  a_oOutput.Write(a_oConverter.Data());
2377  a_oOutput.Write(SI_NEWLINE_A);
2378  }
2379  return true;
2380 }
2381 
2382 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2383 bool
2385  const SI_CHAR * a_pSection,
2386  const SI_CHAR * a_pKey,
2387  bool a_bRemoveEmpty
2388  ) {
2389  return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty);
2390 }
2391 
2392 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2393 bool
2395  const SI_CHAR * a_pSection,
2396  const SI_CHAR * a_pKey,
2397  const SI_CHAR * a_pValue,
2398  bool a_bRemoveEmpty
2399  ) {
2400  if (!a_pSection) {
2401  return false;
2402  }
2403 
2404  typename TSection::iterator iSection = m_data.find(a_pSection);
2405  if (iSection == m_data.end()) {
2406  return false;
2407  }
2408 
2409  // remove a single key if we have a keyname
2410  if (a_pKey) {
2411  typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2412  if (iKeyVal == iSection->second.end()) {
2413  return false;
2414  }
2415 
2416  const static SI_STRLESS isLess = SI_STRLESS();
2417 
2418  // remove any copied strings and then the key
2419  typename TKeyVal::iterator iDelete;
2420  bool bDeleted = false;
2421  do {
2422  iDelete = iKeyVal++;
2423 
2424  if (a_pValue == NULL ||
2425  (isLess(a_pValue, iDelete->second) == false &&
2426  isLess(iDelete->second, a_pValue) == false)) {
2427  DeleteString(iDelete->first.pItem);
2428  DeleteString(iDelete->second);
2429  iSection->second.erase(iDelete);
2430  bDeleted = true;
2431  }
2432  } while (iKeyVal != iSection->second.end()
2433  && !IsLess(a_pKey, iKeyVal->first.pItem));
2434 
2435  if (!bDeleted) {
2436  return false;
2437  }
2438 
2439  // done now if the section is not empty or we are not pruning away
2440  // the empty sections. Otherwise let it fall through into the section
2441  // deletion code
2442  if (!a_bRemoveEmpty || !iSection->second.empty()) {
2443  return true;
2444  }
2445  } else {
2446  // delete all copied strings from this section. The actual
2447  // entries will be removed when the section is removed.
2448  typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2449  for (; iKeyVal != iSection->second.end(); ++iKeyVal) {
2450  DeleteString(iKeyVal->first.pItem);
2451  DeleteString(iKeyVal->second);
2452  }
2453  }
2454 
2455  // delete the section itself
2456  DeleteString(iSection->first.pItem);
2457  m_data.erase(iSection);
2458 
2459  return true;
2460 }
2461 
2462 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2463 void
2465  const SI_CHAR * a_pString
2466  ) {
2467  // strings may exist either inside the data block, or they will be
2468  // individually allocated and stored in m_strings. We only physically
2469  // delete those stored in m_strings.
2470  if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2471  typename TNamesDepend::iterator i = m_strings.begin();
2472  for (; i != m_strings.end(); ++i) {
2473  if (a_pString == i->pItem) {
2474  delete[] const_cast<SI_CHAR*> (i->pItem);
2475  m_strings.erase(i);
2476  break;
2477  }
2478  }
2479  }
2480 }
2481 
2482 // ---------------------------------------------------------------------------
2483 // CONVERSION FUNCTIONS
2484 // ---------------------------------------------------------------------------
2485 
2486 // Defines the conversion classes for different libraries. Before including
2487 // SimpleIni.h, set the converter that you wish you use by defining one of the
2488 // following symbols.
2489 //
2490 // SI_CONVERT_GENERIC Use the Unicode reference conversion library in
2491 // the accompanying files ConvertUTF.h/c
2492 // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
2493 // ICU headers on include path and icuuc.lib
2494 // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
2495 
2496 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2497 #ifdef _WIN32
2498 #define SI_CONVERT_WIN32
2499 #else
2500 #define SI_CONVERT_GENERIC
2501 #endif
2502 #endif
2503 
2509 template<class SI_CHAR>
2511 
2512  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2513  long cmp;
2514  for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2515  cmp = (long) *pLeft - (long) *pRight;
2516  if (cmp != 0) {
2517  return cmp < 0;
2518  }
2519  }
2520  return *pRight != 0;
2521  }
2522 };
2523 
2530 template<class SI_CHAR>
2532 
2533  inline SI_CHAR locase(SI_CHAR ch) const {
2534  return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
2535  }
2536 
2537  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2538  long cmp;
2539  for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2540  cmp = (long) locase(*pLeft) - (long) locase(*pRight);
2541  if (cmp != 0) {
2542  return cmp < 0;
2543  }
2544  }
2545  return *pRight != 0;
2546  }
2547 };
2548 
2552 template<class SI_CHAR>
2554  bool m_bStoreIsUtf8;
2555 protected:
2556 
2558  }
2559 public:
2560 
2561  SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {
2562  }
2563 
2564  /* copy and assignment */
2565  SI_ConvertA(const SI_ConvertA & rhs) {
2566  operator=(rhs);
2567  }
2568 
2570  m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2571  return *this;
2572  }
2573 
2588  const char * a_pInputData,
2589  size_t a_uInputDataLen) {
2590  (void) a_pInputData;
2591  SI_ASSERT(a_uInputDataLen != (size_t) - 1);
2592 
2593  // ASCII/MBCS/UTF-8 needs no conversion
2594  return a_uInputDataLen;
2595  }
2596 
2611  const char * a_pInputData,
2612  size_t a_uInputDataLen,
2613  SI_CHAR * a_pOutputData,
2614  size_t a_uOutputDataSize) {
2615  // ASCII/MBCS/UTF-8 needs no conversion
2616  if (a_uInputDataLen > a_uOutputDataSize) {
2617  return false;
2618  }
2619  memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2620  return true;
2621  }
2622 
2633  size_t SizeToStore(
2634  const SI_CHAR * a_pInputData) {
2635  // ASCII/MBCS/UTF-8 needs no conversion
2636  return strlen((const char *) a_pInputData) + 1;
2637  }
2638 
2653  const SI_CHAR * a_pInputData,
2654  char * a_pOutputData,
2655  size_t a_uOutputDataSize) {
2656  // calc input string length (SI_CHAR type and size independent)
2657  size_t uInputLen = strlen((const char *) a_pInputData) + 1;
2658  if (uInputLen > a_uOutputDataSize) {
2659  return false;
2660  }
2661 
2662  // ascii/UTF-8 needs no conversion
2663  memcpy(a_pOutputData, a_pInputData, uInputLen);
2664  return true;
2665  }
2666 };
2667 
2668 
2669 // ---------------------------------------------------------------------------
2670 // SI_CONVERT_GENERIC
2671 // ---------------------------------------------------------------------------
2672 #ifdef SI_CONVERT_GENERIC
2673 
2674 #define SI_Case SI_GenericCase
2675 #define SI_NoCase SI_GenericNoCase
2676 
2677 #include <wchar.h>
2678 //#include "ConvertUTF.hpp"
2679 /*
2680  * Copyright 2001-2004 Unicode, Inc.
2681  *
2682  * Disclaimer
2683  *
2684  * This source code is provided as is by Unicode, Inc. No claims are
2685  * made as to fitness for any particular purpose. No warranties of any
2686  * kind are expressed or implied. The recipient agrees to determine
2687  * applicability of information provided. If this file has been
2688  * purchased on magnetic or optical media from Unicode, Inc., the
2689  * sole remedy for any claim will be exchange of defective media
2690  * within 90 days of receipt.
2691  *
2692  * Limitations on Rights to Redistribute This Code
2693  *
2694  * Unicode, Inc. hereby grants the right to freely use the information
2695  * supplied in this file in the creation of products supporting the
2696  * Unicode Standard, and to make copies of this file in any form
2697  * for internal or external distribution as long as this notice
2698  * remains attached.
2699  */
2700 
2701 /* ---------------------------------------------------------------------
2702 
2703  Conversions between UTF32, UTF-16, and UTF-8. Header file.
2704 
2705  Several funtions are included here, forming a complete set of
2706  conversions between the three formats. UTF-7 is not included
2707  here, but is handled in a separate source file.
2708 
2709  Each of these routines takes pointers to input buffers and output
2710  buffers. The input buffers are const.
2711 
2712  Each routine converts the text between *sourceStart and sourceEnd,
2713  putting the result into the buffer between *targetStart and
2714  targetEnd. Note: the end pointers are *after* the last item: e.g.
2715  *(sourceEnd - 1) is the last item.
2716 
2717  The return result indicates whether the conversion was successful,
2718  and if not, whether the problem was in the source or target buffers.
2719  (Only the first encountered problem is indicated.)
2720 
2721  After the conversion, *sourceStart and *targetStart are both
2722  updated to point to the end of last text successfully converted in
2723  the respective buffers.
2724 
2725  Input parameters:
2726  sourceStart - pointer to a pointer to the source buffer.
2727  The contents of this are modified on return so that
2728  it points at the next thing to be converted.
2729  targetStart - similarly, pointer to pointer to the target buffer.
2730  sourceEnd, targetEnd - respectively pointers to the ends of the
2731  two buffers, for overflow checking only.
2732 
2733  These conversion functions take a ConversionFlags argument. When this
2734  flag is set to strict, both irregular sequences and isolated surrogates
2735  will cause an error. When the flag is set to lenient, both irregular
2736  sequences and isolated surrogates are converted.
2737 
2738  Whether the flag is strict or lenient, all illegal sequences will cause
2739  an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
2740  or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
2741  must check for illegal sequences.
2742 
2743  When the flag is set to lenient, characters over 0x10FFFF are converted
2744  to the replacement character; otherwise (when the flag is set to strict)
2745  they constitute an error.
2746 
2747  Output parameters:
2748  The value "sourceIllegal" is returned from some routines if the input
2749  sequence is malformed. When "sourceIllegal" is returned, the source
2750  value will point to the illegal value that caused the problem. E.g.,
2751  in UTF-8 when a sequence is malformed, it points to the start of the
2752  malformed sequence.
2753 
2754  Author: Mark E. Davis, 1994.
2755  Rev History: Rick McGowan, fixes & updates May 2001.
2756  Fixes & updates, Sept 2001.
2757 
2758 ------------------------------------------------------------------------ */
2759 
2760 /* ---------------------------------------------------------------------
2761  The following 4 definitions are compiler-specific.
2762  The C standard does not guarantee that wchar_t has at least
2763  16 bits, so wchar_t is no less portable than unsigned short!
2764  All should be unsigned values to avoid sign extension during
2765  bit mask & shift operations.
2766 ------------------------------------------------------------------------ */
2767 
2768 typedef unsigned int UTF32; /* at least 32 bits */
2769 typedef unsigned short UTF16; /* at least 16 bits */
2770 typedef unsigned char UTF8; /* typically 8 bits */
2771 
2772 /* Some fundamental constants */
2773 #define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
2774 #define UNI_MAX_BMP (UTF32)0x0000FFFF
2775 #define UNI_MAX_UTF16 (UTF32)0x0010FFFF
2776 #define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
2777 #define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
2778 
2779 typedef enum {
2780  conversionOK, /* conversion successful */
2781  sourceExhausted, /* partial character in source, but hit end */
2782  targetExhausted, /* insuff. room in target for conversion */
2783  sourceIllegal /* source sequence is illegal/malformed */
2785 
2786 typedef enum {
2790 
2791 /* This is for C++ and does no harm in C */
2792 #ifdef __cplusplus
2793 extern "C" {
2794 #endif
2795 #if 0
2797  const UTF8** sourceStart, const UTF8* sourceEnd,
2798  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
2799 
2801  const UTF16** sourceStart, const UTF16* sourceEnd,
2802  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
2803 
2805  const UTF8** sourceStart, const UTF8* sourceEnd,
2806  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
2807 
2809  const UTF32** sourceStart, const UTF32* sourceEnd,
2810  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
2811 
2813  const UTF16** sourceStart, const UTF16* sourceEnd,
2814  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
2815 
2817  const UTF32** sourceStart, const UTF32* sourceEnd,
2818  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
2819 
2820  Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
2821 #endif
2822 
2823 
2824 #ifdef CVTUTF_DEBUG
2825 #include <stdio.h>
2826 #endif
2827 
2828  static const int halfShift = 10; /* used for shifting by 10 bits */
2829 
2830  static const UTF32 halfBase = 0x0010000UL;
2831  static const UTF32 halfMask = 0x3FFUL;
2832 
2833 #define UNI_SUR_HIGH_START (UTF32)0xD800
2834 #define UNI_SUR_HIGH_END (UTF32)0xDBFF
2835 #define UNI_SUR_LOW_START (UTF32)0xDC00
2836 #define UNI_SUR_LOW_END (UTF32)0xDFFF
2837 
2838  /* --------------------------------------------------------------------- */
2839 
2840 #if 1
2841 
2843  const UTF32** sourceStart, const UTF32* sourceEnd,
2844  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
2845  ConversionResult result = conversionOK;
2846  const UTF32* source = *sourceStart;
2847  UTF16* target = *targetStart;
2848  while (source < sourceEnd) {
2849  UTF32 ch;
2850  if (target >= targetEnd) {
2851  result = targetExhausted;
2852  break;
2853  }
2854  ch = *source++;
2855  if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
2856  /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
2857  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
2858  if (flags == strictConversion) {
2859  --source; /* return to the illegal value itself */
2860  result = sourceIllegal;
2861  break;
2862  } else {
2863  *target++ = UNI_REPLACEMENT_CHAR;
2864  }
2865  } else {
2866  *target++ = (UTF16) ch; /* normal case */
2867  }
2868  } else if (ch > UNI_MAX_LEGAL_UTF32) {
2869  if (flags == strictConversion) {
2870  result = sourceIllegal;
2871  } else {
2872  *target++ = UNI_REPLACEMENT_CHAR;
2873  }
2874  } else {
2875  /* target is a character in range 0xFFFF - 0x10FFFF. */
2876  if (target + 1 >= targetEnd) {
2877  --source; /* Back up source pointer! */
2878  result = targetExhausted;
2879  break;
2880  }
2881  ch -= halfBase;
2882  *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START);
2883  *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START);
2884  }
2885  }
2886  *sourceStart = source;
2887  *targetStart = target;
2888  return result;
2889  }
2890 
2891  /* --------------------------------------------------------------------- */
2892 
2894  const UTF16** sourceStart, const UTF16* sourceEnd,
2895  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
2896  ConversionResult result = conversionOK;
2897  const UTF16* source = *sourceStart;
2898  UTF32* target = *targetStart;
2899  UTF32 ch, ch2;
2900  while (source < sourceEnd) {
2901  const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
2902  ch = *source++;
2903  /* If we have a surrogate pair, convert to UTF32 first. */
2904  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
2905  /* If the 16 bits following the high surrogate are in the source buffer... */
2906  if (source < sourceEnd) {
2907  ch2 = *source;
2908  /* If it's a low surrogate, convert to UTF32. */
2909  if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
2910  ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
2911  + (ch2 - UNI_SUR_LOW_START) + halfBase;
2912  ++source;
2913  } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
2914  --source; /* return to the illegal value itself */
2915  result = sourceIllegal;
2916  break;
2917  }
2918  } else { /* We don't have the 16 bits following the high surrogate. */
2919  --source; /* return to the high surrogate */
2920  result = sourceExhausted;
2921  break;
2922  }
2923  } else if (flags == strictConversion) {
2924  /* UTF-16 surrogate values are illegal in UTF-32 */
2925  if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
2926  --source; /* return to the illegal value itself */
2927  result = sourceIllegal;
2928  break;
2929  }
2930  }
2931  if (target >= targetEnd) {
2932  source = oldSource; /* Back up source pointer! */
2933  result = targetExhausted;
2934  break;
2935  }
2936  *target++ = ch;
2937  }
2938  *sourceStart = source;
2939  *targetStart = target;
2940 #ifdef CVTUTF_DEBUG
2941  if (result == sourceIllegal) {
2942  fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
2943  fflush(stderr);
2944  }
2945 #endif
2946  return result;
2947  }
2948 
2949  /* --------------------------------------------------------------------- */
2950 
2951  /*
2952  * Index into the table below with the first byte of a UTF-8 sequence to
2953  * get the number of trailing bytes that are supposed to follow it.
2954  * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
2955  * left as-is for anyone who may want to do such conversion, which was
2956  * allowed in earlier algorithms.
2957  */
2958  static const char trailingBytesForUTF8[256] = {
2959  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2960  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2961  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2962  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2963  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2964  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2965  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2966  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
2967  };
2968 
2969  /*
2970  * Magic values subtracted from a buffer value during UTF8 conversion.
2971  * This table contains as many values as there might be trailing bytes
2972  * in a UTF-8 sequence.
2973  */
2974  static const UTF32 offsetsFromUTF8[6] = {0x00000000UL, 0x00003080UL, 0x000E2080UL,
2975  0x03C82080UL, 0xFA082080UL, 0x82082080UL};
2976 
2977  /*
2978  * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
2979  * into the first byte, depending on how many bytes follow. There are
2980  * as many entries in this table as there are UTF-8 sequence types.
2981  * (I.e., one byte sequence, two byte... etc.). Remember that sequencs
2982  * for *legal* UTF-8 will be 4 or fewer bytes total.
2983  */
2984  static const UTF8 firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC};
2985 
2986  /* --------------------------------------------------------------------- */
2987 
2988  /* The interface converts a whole buffer to avoid function-call overhead.
2989  * Constants have been gathered. Loops & conditionals have been removed as
2990  * much as possible for efficiency, in favor of drop-through switches.
2991  * (See "Note A" at the bottom of the file for equivalent code.)
2992  * If your compiler supports it, the "isLegalUTF8" call can be turned
2993  * into an inline function.
2994  */
2995 
2996  /* --------------------------------------------------------------------- */
2997 
2999  const UTF16** sourceStart, const UTF16* sourceEnd,
3000  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
3001  ConversionResult result = conversionOK;
3002  const UTF16* source = *sourceStart;
3003  UTF8* target = *targetStart;
3004  while (source < sourceEnd) {
3005  UTF32 ch;
3006  unsigned short bytesToWrite = 0;
3007  const UTF32 byteMask = 0xBF;
3008  const UTF32 byteMark = 0x80;
3009  const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
3010  ch = *source++;
3011  /* If we have a surrogate pair, convert to UTF32 first. */
3012  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
3013  /* If the 16 bits following the high surrogate are in the source buffer... */
3014  if (source < sourceEnd) {
3015  UTF32 ch2 = *source;
3016  /* If it's a low surrogate, convert to UTF32. */
3017  if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
3018  ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
3019  + (ch2 - UNI_SUR_LOW_START) + halfBase;
3020  ++source;
3021  } else if (flags == strictConversion) { /* it's an unpaired high surrogate */
3022  --source; /* return to the illegal value itself */
3023  result = sourceIllegal;
3024  break;
3025  }
3026  } else { /* We don't have the 16 bits following the high surrogate. */
3027  --source; /* return to the high surrogate */
3028  result = sourceExhausted;
3029  break;
3030  }
3031  } else if (flags == strictConversion) {
3032  /* UTF-16 surrogate values are illegal in UTF-32 */
3033  if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
3034  --source; /* return to the illegal value itself */
3035  result = sourceIllegal;
3036  break;
3037  }
3038  }
3039  /* Figure out how many bytes the result will require */
3040  if (ch < (UTF32) 0x80) {
3041  bytesToWrite = 1;
3042  } else if (ch < (UTF32) 0x800) {
3043  bytesToWrite = 2;
3044  } else if (ch < (UTF32) 0x10000) {
3045  bytesToWrite = 3;
3046  } else if (ch < (UTF32) 0x110000) {
3047  bytesToWrite = 4;
3048  } else {
3049  bytesToWrite = 3;
3050  ch = UNI_REPLACEMENT_CHAR;
3051  }
3052 
3053  target += bytesToWrite;
3054  if (target > targetEnd) {
3055  source = oldSource; /* Back up source pointer! */
3056  target -= bytesToWrite;
3057  result = targetExhausted;
3058  break;
3059  }
3060  switch (bytesToWrite) { /* note: everything falls through. */
3061  case 4: *--target = (UTF8) ((ch | byteMark) & byteMask);
3062  ch >>= 6;
3063  case 3: *--target = (UTF8) ((ch | byteMark) & byteMask);
3064  ch >>= 6;
3065  case 2: *--target = (UTF8) ((ch | byteMark) & byteMask);
3066  ch >>= 6;
3067  case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
3068  }
3069  target += bytesToWrite;
3070  }
3071  *sourceStart = source;
3072  *targetStart = target;
3073  return result;
3074  }
3075 
3076  /* --------------------------------------------------------------------- */
3077 
3078  /*
3079  * Utility routine to tell whether a sequence of bytes is legal UTF-8.
3080  * This must be called with the length pre-determined by the first byte.
3081  * If not calling this from ConvertUTF8to*, then the length can be set by:
3082  * length = trailingBytesForUTF8[*source]+1;
3083  * and the sequence is illegal right away if there aren't that many bytes
3084  * available.
3085  * If presented with a length > 4, this returns false. The Unicode
3086  * definition of UTF-8 goes up to 4-byte sequences.
3087  */
3088 
3089  static bool isLegalUTF8(const UTF8 *source, int length) {
3090  UTF8 a;
3091  const UTF8 *srcptr = source + length;
3092  switch (length) {
3093  default: return false;
3094  /* Everything else falls through when "true"... */
3095  case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
3096  case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
3097  case 2: if ((a = (*--srcptr)) > 0xBF) return false;
3098 
3099  switch (*source) {
3100  /* no fall-through in this inner switch */
3101  case 0xE0: if (a < 0xA0) return false;
3102  break;
3103  case 0xED: if (a > 0x9F) return false;
3104  break;
3105  case 0xF0: if (a < 0x90) return false;
3106  break;
3107  case 0xF4: if (a > 0x8F) return false;
3108  break;
3109  default: if (a < 0x80) return false;
3110  }
3111 
3112  case 1: if (*source >= 0x80 && *source < 0xC2) return false;
3113  }
3114  if (*source > 0xF4) return false;
3115  return true;
3116  }
3117 
3118  /* --------------------------------------------------------------------- */
3119 
3120  /*
3121  * Exported function to return whether a UTF-8 sequence is legal or not.
3122  * This is not used here; it's just exported.
3123  */
3124  bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
3125  int length = trailingBytesForUTF8[*source] + 1;
3126  if (source + length > sourceEnd) {
3127  return false;
3128  }
3129  return isLegalUTF8(source, length);
3130  }
3131 
3132  /* --------------------------------------------------------------------- */
3133 
3135  const UTF8** sourceStart, const UTF8* sourceEnd,
3136  UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
3137  ConversionResult result = conversionOK;
3138  const UTF8* source = *sourceStart;
3139  UTF16* target = *targetStart;
3140  while (source < sourceEnd) {
3141  UTF32 ch = 0;
3142  unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
3143  if (source + extraBytesToRead >= sourceEnd) {
3144  result = sourceExhausted;
3145  break;
3146  }
3147  /* Do this check whether lenient or strict */
3148  if (!isLegalUTF8(source, extraBytesToRead + 1)) {
3149  result = sourceIllegal;
3150  break;
3151  }
3152  /*
3153  * The cases all fall through. See "Note A" below.
3154  */
3155  switch (extraBytesToRead) {
3156  case 5: ch += *source++;
3157  ch <<= 6; /* remember, illegal UTF-8 */
3158  case 4: ch += *source++;
3159  ch <<= 6; /* remember, illegal UTF-8 */
3160  case 3: ch += *source++;
3161  ch <<= 6;
3162  case 2: ch += *source++;
3163  ch <<= 6;
3164  case 1: ch += *source++;
3165  ch <<= 6;
3166  case 0: ch += *source++;
3167  }
3168  ch -= offsetsFromUTF8[extraBytesToRead];
3169 
3170  if (target >= targetEnd) {
3171  source -= (extraBytesToRead + 1); /* Back up source pointer! */
3172  result = targetExhausted;
3173  break;
3174  }
3175  if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
3176  /* UTF-16 surrogate values are illegal in UTF-32 */
3177  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
3178  if (flags == strictConversion) {
3179  source -= (extraBytesToRead + 1); /* return to the illegal value itself */
3180  result = sourceIllegal;
3181  break;
3182  } else {
3183  *target++ = UNI_REPLACEMENT_CHAR;
3184  }
3185  } else {
3186  *target++ = (UTF16) ch; /* normal case */
3187  }
3188  } else if (ch > UNI_MAX_UTF16) {
3189  if (flags == strictConversion) {
3190  result = sourceIllegal;
3191  source -= (extraBytesToRead + 1); /* return to the start */
3192  break; /* Bail out; shouldn't continue */
3193  } else {
3194  *target++ = UNI_REPLACEMENT_CHAR;
3195  }
3196  } else {
3197  /* target is a character in range 0xFFFF - 0x10FFFF. */
3198  if (target + 1 >= targetEnd) {
3199  source -= (extraBytesToRead + 1); /* Back up source pointer! */
3200  result = targetExhausted;
3201  break;
3202  }
3203  ch -= halfBase;
3204  *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START);
3205  *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START);
3206  }
3207  }
3208  *sourceStart = source;
3209  *targetStart = target;
3210  return result;
3211  }
3212 
3213  /* --------------------------------------------------------------------- */
3214 
3216  const UTF32** sourceStart, const UTF32* sourceEnd,
3217  UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
3218  ConversionResult result = conversionOK;
3219  const UTF32* source = *sourceStart;
3220  UTF8* target = *targetStart;
3221  while (source < sourceEnd) {
3222  UTF32 ch;
3223  unsigned short bytesToWrite = 0;
3224  const UTF32 byteMask = 0xBF;
3225  const UTF32 byteMark = 0x80;
3226  ch = *source++;
3227  if (flags == strictConversion) {
3228  /* UTF-16 surrogate values are illegal in UTF-32 */
3229  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
3230  --source; /* return to the illegal value itself */
3231  result = sourceIllegal;
3232  break;
3233  }
3234  }
3235  /*
3236  * Figure out how many bytes the result will require. Turn any
3237  * illegally large UTF32 things (> Plane 17) into replacement chars.
3238  */
3239  if (ch < (UTF32) 0x80) {
3240  bytesToWrite = 1;
3241  } else if (ch < (UTF32) 0x800) {
3242  bytesToWrite = 2;
3243  } else if (ch < (UTF32) 0x10000) {
3244  bytesToWrite = 3;
3245  } else if (ch <= UNI_MAX_LEGAL_UTF32) {
3246  bytesToWrite = 4;
3247  } else {
3248  bytesToWrite = 3;
3249  ch = UNI_REPLACEMENT_CHAR;
3250  result = sourceIllegal;
3251  }
3252 
3253  target += bytesToWrite;
3254  if (target > targetEnd) {
3255  --source; /* Back up source pointer! */
3256  target -= bytesToWrite;
3257  result = targetExhausted;
3258  break;
3259  }
3260  switch (bytesToWrite) { /* note: everything falls through. */
3261  case 4: *--target = (UTF8) ((ch | byteMark) & byteMask);
3262  ch >>= 6;
3263  case 3: *--target = (UTF8) ((ch | byteMark) & byteMask);
3264  ch >>= 6;
3265  case 2: *--target = (UTF8) ((ch | byteMark) & byteMask);
3266  ch >>= 6;
3267  case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
3268  }
3269  target += bytesToWrite;
3270  }
3271  *sourceStart = source;
3272  *targetStart = target;
3273  return result;
3274  }
3275 
3276  /* --------------------------------------------------------------------- */
3277 
3279  const UTF8** sourceStart, const UTF8* sourceEnd,
3280  UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
3281  ConversionResult result = conversionOK;
3282  const UTF8* source = *sourceStart;
3283  UTF32* target = *targetStart;
3284  while (source < sourceEnd) {
3285  UTF32 ch = 0;
3286  unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
3287  if (source + extraBytesToRead >= sourceEnd) {
3288  result = sourceExhausted;
3289  break;
3290  }
3291  /* Do this check whether lenient or strict */
3292  if (!isLegalUTF8(source, extraBytesToRead + 1)) {
3293  result = sourceIllegal;
3294  break;
3295  }
3296  /*
3297  * The cases all fall through. See "Note A" below.
3298  */
3299  switch (extraBytesToRead) {
3300  case 5: ch += *source++;
3301  ch <<= 6;
3302  case 4: ch += *source++;
3303  ch <<= 6;
3304  case 3: ch += *source++;
3305  ch <<= 6;
3306  case 2: ch += *source++;
3307  ch <<= 6;
3308  case 1: ch += *source++;
3309  ch <<= 6;
3310  case 0: ch += *source++;
3311  }
3312  ch -= offsetsFromUTF8[extraBytesToRead];
3313 
3314  if (target >= targetEnd) {
3315  source -= (extraBytesToRead + 1); /* Back up the source pointer! */
3316  result = targetExhausted;
3317  break;
3318  }
3319  if (ch <= UNI_MAX_LEGAL_UTF32) {
3320  /*
3321  * UTF-16 surrogate values are illegal in UTF-32, and anything
3322  * over Plane 17 (> 0x10FFFF) is illegal.
3323  */
3324  if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
3325  if (flags == strictConversion) {
3326  source -= (extraBytesToRead + 1); /* return to the illegal value itself */
3327  result = sourceIllegal;
3328  break;
3329  } else {
3330  *target++ = UNI_REPLACEMENT_CHAR;
3331  }
3332  } else {
3333  *target++ = ch;
3334  }
3335  } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
3336  result = sourceIllegal;
3337  *target++ = UNI_REPLACEMENT_CHAR;
3338  }
3339  }
3340  *sourceStart = source;
3341  *targetStart = target;
3342  return result;
3343  }
3344 #endif
3345  /* ---------------------------------------------------------------------
3346 
3347  Note A.
3348  The fall-through switches in UTF-8 reading code save a
3349  temp variable, some decrements & conditionals. The switches
3350  are equivalent to the following loop:
3351  {
3352  int tmpBytesToRead = extraBytesToRead+1;
3353  do {
3354  ch += *source++;
3355  --tmpBytesToRead;
3356  if (tmpBytesToRead) ch <<= 6;
3357  } while (tmpBytesToRead > 0);
3358  }
3359  In UTF-8 writing code, the switches on "bytesToWrite" are
3360  similarly unrolled loops.
3361 
3362  --------------------------------------------------------------------- */
3363 
3364 #ifdef __cplusplus
3365 }
3366 #endif
3367 
3368 /* --------------------------------------------------------------------- */
3369 
3374 template<class SI_CHAR>
3376  bool m_bStoreIsUtf8;
3377 protected:
3378 
3380  }
3381 public:
3382 
3383  SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {
3384  }
3385 
3386  /* copy and assignment */
3387  SI_ConvertW(const SI_ConvertW & rhs) {
3388  operator=(rhs);
3389  }
3390 
3392  m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
3393  return *this;
3394  }
3395 
3410  const char * a_pInputData,
3411  size_t a_uInputDataLen) {
3412  SI_ASSERT(a_uInputDataLen != (size_t) - 1);
3413 
3414  if (m_bStoreIsUtf8) {
3415  // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
3416  // so we just return the same number of characters required as for
3417  // the source text.
3418  return a_uInputDataLen;
3419  }
3420 
3421 #if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
3422  // fall back processing for platforms that don't support a NULL dest to mbstowcs
3423  // worst case scenario is 1:1, this will be a sufficient buffer size
3424  (void) a_pInputData;
3425  return a_uInputDataLen;
3426 #else
3427  // get the actual required buffer size
3428  return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
3429 #endif
3430  }
3431 
3446  const char * a_pInputData,
3447  size_t a_uInputDataLen,
3448  SI_CHAR * a_pOutputData,
3449  size_t a_uOutputDataSize) {
3450  if (m_bStoreIsUtf8) {
3451  // This uses the Unicode reference implementation to do the
3452  // conversion from UTF-8 to wchar_t. The required files are
3453  // ConvertUTF.h and ConvertUTF.c which should be included in
3454  // the distribution but are publically available from unicode.org
3455  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
3456  ConversionResult retval;
3457  const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
3458  if (sizeof (wchar_t) == sizeof (UTF32)) {
3459  UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
3460  retval = ConvertUTF8toUTF32(
3461  &pUtf8, pUtf8 + a_uInputDataLen,
3462  &pUtf32, pUtf32 + a_uOutputDataSize,
3464  } else if (sizeof (wchar_t) == sizeof (UTF16)) {
3465  UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
3466  retval = ConvertUTF8toUTF16(
3467  &pUtf8, pUtf8 + a_uInputDataLen,
3468  &pUtf16, pUtf16 + a_uOutputDataSize,
3470  }
3471  return retval == conversionOK;
3472  }
3473 
3474  // convert to wchar_t
3475  size_t retval = mbstowcs(a_pOutputData,
3476  a_pInputData, a_uOutputDataSize);
3477  return retval != (size_t) (-1);
3478  }
3479 
3490  size_t SizeToStore(
3491  const SI_CHAR * a_pInputData) {
3492  if (m_bStoreIsUtf8) {
3493  // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
3494  size_t uLen = 0;
3495  while (a_pInputData[uLen]) {
3496  ++uLen;
3497  }
3498  return (6 * uLen) + 1;
3499  } else {
3500  size_t uLen = wcstombs(NULL, a_pInputData, 0);
3501  if (uLen == (size_t) (-1)) {
3502  return uLen;
3503  }
3504  return uLen + 1; // include NULL terminator
3505  }
3506  }
3507 
3522  const SI_CHAR * a_pInputData,
3523  char * a_pOutputData,
3524  size_t a_uOutputDataSize
3525  ) {
3526  if (m_bStoreIsUtf8) {
3527  // calc input string length (SI_CHAR type and size independent)
3528  size_t uInputLen = 0;
3529  while (a_pInputData[uInputLen]) {
3530  ++uInputLen;
3531  }
3532  ++uInputLen; // include the NULL char
3533 
3534  // This uses the Unicode reference implementation to do the
3535  // conversion from wchar_t to UTF-8. The required files are
3536  // ConvertUTF.h and ConvertUTF.c which should be included in
3537  // the distribution but are publically available from unicode.org
3538  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
3539  ConversionResult retval;
3540  UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
3541  if (sizeof (wchar_t) == sizeof (UTF32)) {
3542  const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
3543  retval = ConvertUTF32toUTF8(
3544  &pUtf32, pUtf32 + uInputLen,
3545  &pUtf8, pUtf8 + a_uOutputDataSize,
3547  } else if (sizeof (wchar_t) == sizeof (UTF16)) {
3548  const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
3549  retval = ConvertUTF16toUTF8(
3550  &pUtf16, pUtf16 + uInputLen,
3551  &pUtf8, pUtf8 + a_uOutputDataSize,
3553  }
3554  return retval == conversionOK;
3555  } else {
3556  size_t retval = wcstombs(a_pOutputData,
3557  a_pInputData, a_uOutputDataSize);
3558  return retval != (size_t) - 1;
3559  }
3560  }
3561 };
3562 
3563 #endif // SI_CONVERT_GENERIC
3564 
3565 
3566 // ---------------------------------------------------------------------------
3567 // SI_CONVERT_ICU
3568 // ---------------------------------------------------------------------------
3569 #ifdef SI_CONVERT_ICU
3570 
3571 #define SI_Case SI_GenericCase
3572 #define SI_NoCase SI_GenericNoCase
3573 
3574 #include <unicode/ucnv.h>
3575 
3579 template<class SI_CHAR>
3580 class SI_ConvertW {
3581  const char * m_pEncoding;
3582  UConverter * m_pConverter;
3583 protected:
3584 
3585  SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) {
3586  }
3587 public:
3588 
3589  SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3590  m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
3591  }
3592 
3593  /* copy and assignment */
3594  SI_ConvertW(const SI_ConvertW & rhs) {
3595  operator=(rhs);
3596  }
3597 
3599  m_pEncoding = rhs.m_pEncoding;
3600  m_pConverter = NULL;
3601  return *this;
3602  }
3603 
3605  if (m_pConverter) ucnv_close(m_pConverter);
3606  }
3607 
3622  const char * a_pInputData,
3623  size_t a_uInputDataLen) {
3624  SI_ASSERT(a_uInputDataLen != (size_t) - 1);
3625 
3626  UErrorCode nError;
3627 
3628  if (!m_pConverter) {
3629  nError = U_ZERO_ERROR;
3630  m_pConverter = ucnv_open(m_pEncoding, &nError);
3631  if (U_FAILURE(nError)) {
3632  return (size_t) - 1;
3633  }
3634  }
3635 
3636  nError = U_ZERO_ERROR;
3637  int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
3638  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3639  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3640  return (size_t) - 1;
3641  }
3642 
3643  return (size_t) nLen;
3644  }
3645 
3660  const char * a_pInputData,
3661  size_t a_uInputDataLen,
3662  UChar * a_pOutputData,
3663  size_t a_uOutputDataSize) {
3664  UErrorCode nError;
3665 
3666  if (!m_pConverter) {
3667  nError = U_ZERO_ERROR;
3668  m_pConverter = ucnv_open(m_pEncoding, &nError);
3669  if (U_FAILURE(nError)) {
3670  return false;
3671  }
3672  }
3673 
3674  nError = U_ZERO_ERROR;
3675  ucnv_toUChars(m_pConverter,
3676  a_pOutputData, (int32_t) a_uOutputDataSize,
3677  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3678  if (U_FAILURE(nError)) {
3679  return false;
3680  }
3681 
3682  return true;
3683  }
3684 
3695  size_t SizeToStore(
3696  const UChar * a_pInputData) {
3697  UErrorCode nError;
3698 
3699  if (!m_pConverter) {
3700  nError = U_ZERO_ERROR;
3701  m_pConverter = ucnv_open(m_pEncoding, &nError);
3702  if (U_FAILURE(nError)) {
3703  return (size_t) - 1;
3704  }
3705  }
3706 
3707  nError = U_ZERO_ERROR;
3708  int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
3709  a_pInputData, -1, &nError);
3710  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3711  return (size_t) - 1;
3712  }
3713 
3714  return (size_t) nLen + 1;
3715  }
3716 
3731  const UChar * a_pInputData,
3732  char * a_pOutputData,
3733  size_t a_uOutputDataSize) {
3734  UErrorCode nError;
3735 
3736  if (!m_pConverter) {
3737  nError = U_ZERO_ERROR;
3738  m_pConverter = ucnv_open(m_pEncoding, &nError);
3739  if (U_FAILURE(nError)) {
3740  return false;
3741  }
3742  }
3743 
3744  nError = U_ZERO_ERROR;
3745  ucnv_fromUChars(m_pConverter,
3746  a_pOutputData, (int32_t) a_uOutputDataSize,
3747  a_pInputData, -1, &nError);
3748  if (U_FAILURE(nError)) {
3749  return false;
3750  }
3751 
3752  return true;
3753  }
3754 };
3755 
3756 #endif // SI_CONVERT_ICU
3757 
3758 
3759 // ---------------------------------------------------------------------------
3760 // SI_CONVERT_WIN32
3761 // ---------------------------------------------------------------------------
3762 #ifdef SI_CONVERT_WIN32
3763 
3764 #define SI_Case SI_GenericCase
3765 
3766 // Windows CE doesn't have errno or MBCS libraries
3767 #ifdef _WIN32_WCE
3768 #ifndef SI_NO_MBCS
3769 #define SI_NO_MBCS
3770 #endif
3771 #endif
3772 
3773 #include <windows.h>
3774 #ifdef SI_NO_MBCS
3775 #define SI_NoCase SI_GenericNoCase
3776 #else // !SI_NO_MBCS
3785 #include <mbstring.h>
3786 
3787 template<class SI_CHAR>
3788 struct SI_NoCase {
3789 
3790  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
3791  if (sizeof (SI_CHAR) == sizeof (char)) {
3792  return _mbsicmp((const unsigned char *) pLeft,
3793  (const unsigned char *) pRight) < 0;
3794  }
3795  if (sizeof (SI_CHAR) == sizeof (wchar_t)) {
3796  return _wcsicmp((const wchar_t *)pLeft,
3797  (const wchar_t *)pRight) < 0;
3798  }
3799  return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
3800  }
3801 };
3802 #endif // SI_NO_MBCS
3803 
3810 template<class SI_CHAR>
3811 class SI_ConvertW {
3812  UINT m_uCodePage;
3813 protected:
3814 
3816  }
3817 public:
3818 
3819  SI_ConvertW(bool a_bStoreIsUtf8) {
3820  m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
3821  }
3822 
3823  /* copy and assignment */
3824  SI_ConvertW(const SI_ConvertW & rhs) {
3825  operator=(rhs);
3826  }
3827 
3829  m_uCodePage = rhs.m_uCodePage;
3830  return *this;
3831  }
3832 
3847  const char * a_pInputData,
3848  size_t a_uInputDataLen) {
3849  SI_ASSERT(a_uInputDataLen != (size_t) - 1);
3850 
3851  int retval = MultiByteToWideChar(
3852  m_uCodePage, 0,
3853  a_pInputData, (int) a_uInputDataLen,
3854  0, 0);
3855  return (size_t) (retval > 0 ? retval : -1);
3856  }
3857 
3872  const char * a_pInputData,
3873  size_t a_uInputDataLen,
3874  SI_CHAR * a_pOutputData,
3875  size_t a_uOutputDataSize) {
3876  int nSize = MultiByteToWideChar(
3877  m_uCodePage, 0,
3878  a_pInputData, (int) a_uInputDataLen,
3879  (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
3880  return (nSize > 0);
3881  }
3882 
3893  size_t SizeToStore(
3894  const SI_CHAR * a_pInputData) {
3895  int retval = WideCharToMultiByte(
3896  m_uCodePage, 0,
3897  (const wchar_t *) a_pInputData, -1,
3898  0, 0, 0, 0);
3899  return (size_t) (retval > 0 ? retval : -1);
3900  }
3901 
3916  const SI_CHAR * a_pInputData,
3917  char * a_pOutputData,
3918  size_t a_uOutputDataSize) {
3919  int retval = WideCharToMultiByte(
3920  m_uCodePage, 0,
3921  (const wchar_t *) a_pInputData, -1,
3922  a_pOutputData, (int) a_uOutputDataSize, 0, 0);
3923  return retval > 0;
3924  }
3925 };
3926 
3927 #endif // SI_CONVERT_WIN32
3928 
3929 
3930 // ---------------------------------------------------------------------------
3931 // TYPE DEFINITIONS
3932 // ---------------------------------------------------------------------------
3933 
3934 typedef CSimpleIniTempl<char,
3936 typedef CSimpleIniTempl<char,
3938 
3939 #if defined(SI_CONVERT_ICU)
3940 typedef CSimpleIniTempl<UChar,
3942 typedef CSimpleIniTempl<UChar,
3944 #else
3945 typedef CSimpleIniTempl<wchar_t,
3947 typedef CSimpleIniTempl<wchar_t,
3948 SI_Case<wchar_t>, SI_ConvertW<wchar_t> > CSimpleIniCaseW;
3949 #endif
3950 
3951 #ifdef _UNICODE
3952 #define CSimpleIni CSimpleIniW
3953 #define CSimpleIniCase CSimpleIniCaseW
3954 #define SI_NEWLINE SI_NEWLINE_W
3955 #else // !_UNICODE
3956 #define CSimpleIni CSimpleIniA
3957 #define CSimpleIniCase CSimpleIniCaseA
3958 #define SI_NEWLINE SI_NEWLINE_A
3959 #endif // _UNICODE
3960 
3961 #ifdef _MSC_VER
3962 #pragma warning (pop)
3963 #endif
3964 
3965 #endif // INCLUDED_SimpleIni_h
3966 
3967 
3969 //
3970 // Copyright (c) 2018, STEREOLABS.
3971 //
3972 // All rights reserved.
3973 //
3974 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
3975 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
3976 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
3977 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3978 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3979 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3980 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3981 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3982 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3983 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3984 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3985 //
3987 
3988 inline std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
3989  std::stringstream ss(s);
3990  std::string item;
3991  while (getline(ss, item, delim)) {
3992  elems.push_back(item);
3993  }
3994  return elems;
3995 }
3996 
3997 inline std::vector<std::string> split(const std::string &s, char delim) {
3998  std::vector<std::string> elems;
3999  split(s, delim, elems);
4000  return elems;
4001 }
4002 
4004 public:
4005 
4006  ConfManager(std::string filename) {
4007  filename_ = filename;
4008  ini_.SetUnicode();
4009  SI_Error rc = ini_.LoadFile(filename_.c_str());
4010  is_opened_ = !(rc < 0);
4011  }
4012 
4014  //if (is_opened_) ini_.SaveFile(filename_.c_str());
4015  }
4016 
4017  float getValue(std::string key, float default_value = -1) {
4018  if (is_opened_) {
4019  std::vector<std::string> elems;
4020  split(key, ':', elems);
4021 
4022  return atof(ini_.GetValue(elems.front().c_str(), elems.back().c_str(), std::to_string(default_value).c_str()));
4023  } else
4024  return -1.f;
4025  }
4026 
4027  void setValue(std::string key, float value) {
4028  if (is_opened_) {
4029  std::vector<std::string> elems;
4030  split(key, ':', elems);
4031 
4032  /*SI_Error rc = */ini_.SetValue(elems.front().c_str(), elems.back().c_str(), std::to_string(value).c_str());
4033  }
4034  }
4035 
4036  inline bool isOpened() {
4037  return is_opened_;
4038  }
4039 
4040 private:
4041  std::string filename_;
4042  bool is_opened_;
4043  CSimpleIniA ini_;
4044 };
4045 
4046 
4047 
4048 bool checkFile(std::string path) {
4049  std::ifstream f(path.c_str());
4050  return f.good();
4051 }
4052 
4053 static inline std::string getRootHiddenDir() {
4054 #ifdef WIN32
4055 
4056 #ifdef UNICODE
4057  wchar_t szPath[MAX_PATH];
4058 #else
4059  TCHAR szPath[MAX_PATH];
4060 #endif
4061 
4062  if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)))
4063  return "";
4064 
4065  char snfile_path[MAX_PATH];
4066 
4067 #ifndef UNICODE
4068 
4069  size_t newsize = strlen(szPath) + 1;
4070  wchar_t * wcstring = new wchar_t[newsize];
4071  // Convert char* string to a wchar_t* string.
4072  size_t convertedChars = 0;
4073  mbstowcs_s(&convertedChars, wcstring, newsize, szPath, _TRUNCATE);
4074  wcstombs(snfile_path, wcstring, MAX_PATH);
4075 #else
4076  wcstombs(snfile_path, szPath, MAX_PATH);
4077 #endif
4078 
4079  std::string filename(snfile_path);
4080  filename += "\\Stereolabs\\";
4081 
4082 #else //LINUX
4083  std::string homepath = getenv("HOME");
4084  std::string filename = homepath + "/zed/";
4085 #endif
4086 
4087  return filename;
4088 }
4089 
4090 /*return the path to the Sl ZED hidden dir*/
4091 static inline std::string getHiddenDir() {
4092  std::string filename = getRootHiddenDir();
4093 #ifdef WIN32
4094  filename += "settings\\";
4095 #else //LINUX
4096  filename += "settings/";
4097 #endif
4098  return filename;
4099 }
4100 
4101 bool downloadCalibrationFile(unsigned int serial_number, std::string &calibration_file) {
4102 #ifndef _WIN32
4103  std::string path = getHiddenDir();
4104  char specific_name[128];
4105  sprintf(specific_name, "SN%d.conf", serial_number);
4106  calibration_file = path + specific_name;
4107  if (!checkFile(calibration_file)) {
4108  std::string cmd;
4109  int res;
4110 
4111  // Create download folder
4112  cmd = "mkdir -p " + path;
4113  res = system(cmd.c_str());
4114 
4115  // Download the file
4116  std::string url("'https://calib.stereolabs.com/?SN=");
4117 
4118  cmd = "wget " + url + std::to_string(serial_number) + "' -O " + calibration_file;
4119  std::cout << cmd << std::endl;
4120  res = system(cmd.c_str());
4121 
4122  if( res == EXIT_FAILURE )
4123  {
4124  std::cerr << "Error downloading the calibration file" << std::endl;
4125  return false;
4126  }
4127 
4128  if (!checkFile(calibration_file)) {
4129  std::cerr << "Invalid calibration file" << std::endl;
4130  return false;
4131  }
4132  }
4133 #else
4134  std::string path = getHiddenDir();
4135  char specific_name[128];
4136  sprintf(specific_name, "SN%d.conf", serial_number);
4137  calibration_file = path + specific_name;
4138  if (!checkFile(calibration_file)) {
4139  TCHAR *settingFolder = new TCHAR[path.size() + 1];
4140  settingFolder[path.size()] = 0;
4141  std::copy(path.begin(), path.end(), settingFolder);
4142  SHCreateDirectoryEx(NULL, settingFolder, NULL); //recursive creation
4143 
4144  std::string url("https://calib.stereolabs.com/?SN=");
4145  url += std::to_string(serial_number);
4146  TCHAR *address = new TCHAR[url.size() + 1];
4147  address[url.size()] = 0;
4148  std::copy(url.begin(), url.end(), address);
4149  TCHAR *calibPath = new TCHAR[calibration_file.size() + 1];
4150  calibPath[calibration_file.size()] = 0;
4151  std::copy(calibration_file.begin(), calibration_file.end(), calibPath);
4152 
4153  HRESULT hr = URLDownloadToFile(NULL, address, calibPath, 0, NULL);
4154  if (hr != 0) {
4155  std::cout << "Fail to download calibration file" << std::endl;
4156  return false;
4157  }
4158 
4159  if (!checkFile(calibration_file)) {
4160  std::cout << "Invalid calibration file" << std::endl;
4161  return false;
4162  }
4163  }
4164 #endif
4165 
4166  return true;
4167 }
4168 
4169 // OpenCV includes
4170 #include <opencv2/opencv.hpp>
4171 
4172 bool initCalibration(std::string calibration_file, cv::Size2i image_size, cv::Mat &map_left_x, cv::Mat &map_left_y,
4173  cv::Mat &map_right_x, cv::Mat &map_right_y, cv::Mat &cameraMatrix_left, cv::Mat &cameraMatrix_right, double *baseline=nullptr) {
4174 
4175  if (!checkFile(calibration_file)) {
4176  std::cout << "Calibration file missing." << std::endl;
4177  return 0;
4178  }
4179 
4180  // Open camera configuration file
4181  ConfManager camerareader(calibration_file.c_str());
4182  if (!camerareader.isOpened())
4183  return 0;
4184 
4185  std::string resolution_str;
4186  switch ((int) image_size.width) {
4187  case 2208:
4188  resolution_str = "2k";
4189  break;
4190  case 1920:
4191  resolution_str = "fhd";
4192  break;
4193  case 1280:
4194  resolution_str = "hd";
4195  break;
4196  case 672:
4197  resolution_str = "vga";
4198  break;
4199  default:
4200  resolution_str = "hd";
4201  break;
4202  }
4203 
4204  // Get translations
4205  float T_[3];
4206  T_[0] = camerareader.getValue("stereo:baseline", 0.0f);
4207  T_[1] = camerareader.getValue("stereo:ty_" + resolution_str, 0.f);
4208  T_[2] = camerareader.getValue("stereo:tz_" + resolution_str, 0.f);
4209 
4210  if(baseline) *baseline=T_[0];
4211 
4212  // Get left parameters
4213  float left_cam_cx = camerareader.getValue("left_cam_" + resolution_str + ":cx", 0.0f);
4214  float left_cam_cy = camerareader.getValue("left_cam_" + resolution_str + ":cy", 0.0f);
4215  float left_cam_fx = camerareader.getValue("left_cam_" + resolution_str + ":fx", 0.0f);
4216  float left_cam_fy = camerareader.getValue("left_cam_" + resolution_str + ":fy", 0.0f);
4217  float left_cam_k1 = camerareader.getValue("left_cam_" + resolution_str + ":k1", 0.0f);
4218  float left_cam_k2 = camerareader.getValue("left_cam_" + resolution_str + ":k2", 0.0f);
4219  float left_cam_p1 = camerareader.getValue("left_cam_" + resolution_str + ":p1", 0.0f);
4220  float left_cam_p2 = camerareader.getValue("left_cam_" + resolution_str + ":p2", 0.0f);
4221  float left_cam_k3 = camerareader.getValue("left_cam_" + resolution_str + ":k3", 0.0f);
4222 
4223  // Get right parameters
4224  float right_cam_cx = camerareader.getValue("right_cam_" + resolution_str + ":cx", 0.0f);
4225  float right_cam_cy = camerareader.getValue("right_cam_" + resolution_str + ":cy", 0.0f);
4226  float right_cam_fx = camerareader.getValue("right_cam_" + resolution_str + ":fx", 0.0f);
4227  float right_cam_fy = camerareader.getValue("right_cam_" + resolution_str + ":fy", 0.0f);
4228  float right_cam_k1 = camerareader.getValue("right_cam_" + resolution_str + ":k1", 0.0f);
4229  float right_cam_k2 = camerareader.getValue("right_cam_" + resolution_str + ":k2", 0.0f);
4230  float right_cam_p1 = camerareader.getValue("right_cam_" + resolution_str + ":p1", 0.0f);
4231  float right_cam_p2 = camerareader.getValue("right_cam_" + resolution_str + ":p2", 0.0f);
4232  float right_cam_k3 = camerareader.getValue("right_cam_" + resolution_str + ":k3", 0.0f);
4233 
4234  // (Linux only) Safety check A: Wrong "." or "," reading in file conf.
4235 #ifndef _WIN32
4236  if (right_cam_k1 == 0 && left_cam_k1 == 0 && left_cam_k2 == 0 && right_cam_k2 == 0) {
4237  std::cout << "ZED File invalid" << std::endl;
4238 
4239  std::string cmd = "rm " + calibration_file;
4240  int res = system(cmd.c_str());
4241  if( res == EXIT_FAILURE )
4242  {
4243  exit(1);
4244  }
4245 
4246  exit(1);
4247  }
4248 #endif
4249 
4250  // Get rotations
4251  cv::Mat R_zed = (cv::Mat_<double>(1, 3) << camerareader.getValue("stereo:rx_" + resolution_str, 0.f), camerareader.getValue("stereo:cv_" + resolution_str, 0.f), camerareader.getValue("stereo:rz_" + resolution_str, 0.f));
4252  cv::Mat R;
4253 
4254  cv::Rodrigues(R_zed /*in*/, R /*out*/);
4255 
4256  cv::Mat distCoeffs_left, distCoeffs_right;
4257 
4258  // Left
4259  cameraMatrix_left = (cv::Mat_<double>(3, 3) << left_cam_fx, 0, left_cam_cx, 0, left_cam_fy, left_cam_cy, 0, 0, 1);
4260  distCoeffs_left = (cv::Mat_<double>(5, 1) << left_cam_k1, left_cam_k2, left_cam_p1, left_cam_p2, left_cam_k3);
4261 
4262  // Right
4263  cameraMatrix_right = (cv::Mat_<double>(3, 3) << right_cam_fx, 0, right_cam_cx, 0, right_cam_fy, right_cam_cy, 0, 0, 1);
4264  distCoeffs_right = (cv::Mat_<double>(5, 1) << right_cam_k1, right_cam_k2, right_cam_p1, right_cam_p2, right_cam_k3);
4265 
4266  // Stereo
4267  cv::Mat T = (cv::Mat_<double>(3, 1) << T_[0], T_[1], T_[2]);
4268  std::cout << " Camera Matrix L: \n" << cameraMatrix_left << std::endl << std::endl;
4269  std::cout << " Camera Matrix R: \n" << cameraMatrix_right << std::endl << std::endl;
4270 
4271  cv::Mat R1, R2, P1, P2, Q;
4272  cv::stereoRectify(cameraMatrix_left, distCoeffs_left, cameraMatrix_right, distCoeffs_right, image_size, R, T,
4273  R1, R2, P1, P2, Q, cv::CALIB_ZERO_DISPARITY, 0, image_size);
4274 
4275  //Precompute maps for cv::remap()
4276  initUndistortRectifyMap(cameraMatrix_left, distCoeffs_left, R1, P1, image_size, CV_32FC1, map_left_x, map_left_y);
4277  initUndistortRectifyMap(cameraMatrix_right, distCoeffs_right, R2, P2, image_size, CV_32FC1, map_right_x, map_right_y);
4278 
4279  cameraMatrix_left = P1;
4280  cameraMatrix_right = P2;
4281 
4282  return 1;
4283 }
4284 
4285 } // namespace oc_tools
4286 } // namespace sl_oc
4287 
4288 
4289 #endif // CONF_MANAGER_HPP
Converter & operator=(const Converter &rhs)
bool ConvertToStore(const SI_CHAR *a_pszString)
virtual void Write(const char *a_pBuf)=0
SI_Error LoadFile(const SI_WCHAR_T *a_pwszFile)
SI_Error LoadData(std::istream &a_istream)
SI_Error LoadData(const std::string &a_strData)
bool DeleteValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, bool a_bRemoveEmpty=false)
SI_Error SetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nValue, const SI_CHAR *a_pComment=NULL, bool a_bUseHex=false, bool a_bForceReplace=false)
void SetSpaces(bool a_bSpaces=true)
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
const SI_CHAR * GetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pDefault=NULL, bool *a_pHasMultiple=NULL) const
SI_Error SetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
void SetMultiLine(bool a_bAllowMultiLine=true)
bool GetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bDefault=false, bool *a_pHasMultiple=NULL) const
Converter GetConverter() const
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
int GetSectionSize(const SI_CHAR *a_pSection) const
SI_Error Save(OutputWriter &a_oOutput, bool a_bAddSignature=false) const
long GetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nDefault=0, bool *a_pHasMultiple=NULL) const
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
SI_Error SaveFile(FILE *a_pFile, bool a_bAddSignature=false) const
void GetAllSections(TNamesDepend &a_names) const
SI_Error LoadData(const char *a_pData, size_t a_uDataLen)
SI_Error SaveFile(const char *a_pszFile, bool a_bAddSignature=true) const
SI_Error LoadFile(const char *a_pszFile)
SI_Error SaveFile(const SI_WCHAR_T *a_pwszFile, bool a_bAddSignature=true) const
SI_Error LoadFile(FILE *a_fpFile)
void SetUnicode(bool a_bIsUtf8=true)
CSimpleIniTempl(bool a_bIsUtf8=false, bool a_bMultiKey=false, bool a_bMultiLine=false)
SI_Error SetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
SI_Error Save(std::ostream &a_ostream, bool a_bAddSignature=false) const
SI_Error Save(std::string &a_sBuffer, bool a_bAddSignature=false) const
double GetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nDefault=0, bool *a_pHasMultiple=NULL) const
std::list< Entry > TNamesDepend
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
SI_Error SetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
void SetMultiKey(bool a_bAllowMultiKey=true)
ConfManager(std::string filename)
float getValue(std::string key, float default_value=-1)
void setValue(std::string key, float value)
SI_ConvertA(bool a_bStoreIsUtf8)
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
SI_ConvertA(const SI_ConvertA &rhs)
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
SI_ConvertA & operator=(const SI_ConvertA &rhs)
size_t SizeToStore(const SI_CHAR *a_pInputData)
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
SI_ConvertW & operator=(const SI_ConvertW &rhs)
size_t SizeToStore(const UChar *a_pInputData)
SI_ConvertW(const SI_ConvertW &rhs)
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
size_t SizeToStore(const SI_CHAR *a_pInputData)
SI_ConvertW(bool a_bStoreIsUtf8)
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, UChar *a_pOutputData, size_t a_uOutputDataSize)
bool ConvertToStore(const UChar *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
unsigned char UTF8
bool initCalibration(std::string calibration_file, cv::Size2i image_size, cv::Mat &map_left_x, cv::Mat &map_left_y, cv::Mat &map_right_x, cv::Mat &map_right_y, cv::Mat &cameraMatrix_left, cv::Mat &cameraMatrix_right, double *baseline=nullptr)
ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
@ SI_NOMEM
Out of memory error.
@ SI_UPDATED
An existing value was updated.
Definition: calibration.hpp:95
@ SI_FAIL
Generic failure.
Definition: calibration.hpp:99
@ SI_OK
No error.
Definition: calibration.hpp:94
@ SI_FILE
File error (see errno for detail error)
@ SI_INSERTED
A new value was inserted.
Definition: calibration.hpp:96
bool checkFile(std::string path)
ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
CSimpleIniTempl< char, SI_Case< char >, SI_ConvertA< char > > CSimpleIniCaseA
bool downloadCalibrationFile(unsigned int serial_number, std::string &calibration_file)
CSimpleIniTempl< UChar, SI_Case< UChar >, SI_ConvertW< UChar > > CSimpleIniCaseW
CSimpleIniTempl< char, SI_NoCase< char >, SI_ConvertA< char > > CSimpleIniA
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
unsigned int UTF32
unsigned short UTF16
CSimpleIniTempl< UChar, SI_NoCase< UChar >, SI_ConvertW< UChar > > CSimpleIniW
bool operator()(const Entry &lhs, const Entry &rhs) const
bool operator()(const Entry &lhs, const Entry &rhs) const
Entry(const SI_CHAR *a_pszItem, const SI_CHAR *a_pszComment, int a_nOrder)
bool operator>(const Entry &rhs) const
Entry(const SI_CHAR *a_pszItem=NULL, int a_nOrder=0)
const SI_CHAR * pComment
int nOrder
Entry(const Entry &rhs)
bool operator<(const Entry &rhs) const
const SI_CHAR * pItem
Entry & operator=(const Entry &rhs)
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
SI_CHAR locase(SI_CHAR ch) const
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const