xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq/common/rkaiq_ini.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 /**
2  * Copyright (c) 2016 rxi
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20  * SOFTWARE.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <ctype.h>
27 
28 #include "rkaiq_ini.h"
29 
30 struct ini_t {
31   char *data;
32   char *end;
33 };
34 
35 
36 /* Case insensitive string compare */
strcmpci(const char * a,const char * b)37 static int strcmpci(const char *a, const char *b) {
38   for (;;) {
39     int d = tolower(*a) - tolower(*b);
40     if (d != 0 || !*a) {
41       return d;
42     }
43     a++, b++;
44   }
45 }
46 
47 /* Returns the next string in the split data */
next(ini_t * ini,char * p)48 static char* next(ini_t *ini, char *p) {
49   p += strlen(p);
50   while (p < ini->end && *p == '\0') {
51     p++;
52   }
53   return p;
54 }
55 
trim_back(ini_t * ini,char * p)56 static void trim_back(ini_t *ini, char *p) {
57   while (p >= ini->data && (*p == ' ' || *p == '\t' || *p == '\r')) {
58     *p-- = '\0';
59   }
60 }
61 
discard_line(ini_t * ini,char * p)62 static char* discard_line(ini_t *ini, char *p) {
63   while (p < ini->end && *p != '\n') {
64     *p++ = '\0';
65   }
66   return p;
67 }
68 
69 
unescape_quoted_value(ini_t * ini,char * p)70 static char *unescape_quoted_value(ini_t *ini, char *p) {
71   /* Use `q` as write-head and `p` as read-head, `p` is always ahead of `q`
72    * as escape sequences are always larger than their resultant data */
73   char *q = p;
74   p++;
75   while (p < ini->end && *p != '"' && *p != '\r' && *p != '\n') {
76     if (*p == '\\') {
77       /* Handle escaped char */
78       p++;
79       switch (*p) {
80         default   : *q = *p;    break;
81         case 'r'  : *q = '\r';  break;
82         case 'n'  : *q = '\n';  break;
83         case 't'  : *q = '\t';  break;
84         case '\r' :
85         case '\n' :
86         case '\0' : goto end;
87       }
88 
89     } else {
90       /* Handle normal char */
91       *q = *p;
92     }
93     q++, p++;
94   }
95 end:
96   return q;
97 }
98 
99 
100 /* Splits data in place into strings containing section-headers, keys and
101  * values using one or more '\0' as a delimiter. Unescapes quoted values */
split_data(ini_t * ini)102 static void split_data(ini_t *ini) {
103   char *value_start, *line_start;
104   char *p = ini->data;
105 
106   while (p < ini->end) {
107     switch (*p) {
108       case '\r':
109       case '\n':
110       case '\t':
111       case ' ':
112         *p = '\0';
113         p++;
114         break;
115       case '\0':
116         p++;
117         break;
118 
119       case '[':
120         p += strcspn(p, "]\n");
121         *p = '\0';
122         break;
123 
124       case ';':
125         p = discard_line(ini, p);
126         break;
127 
128       default:
129         line_start = p;
130         p += strcspn(p, "=\n");
131 
132         /* Is line missing a '='? */
133         if (*p != '=') {
134           p = discard_line(ini, line_start);
135           break;
136         }
137         trim_back(ini, p - 1);
138 
139         /* Replace '=' and whitespace after it with '\0' */
140         do {
141           *p++ = '\0';
142         } while (*p == ' ' || *p == '\r' || *p == '\t');
143 
144         /* Is a value after '=' missing? */
145         if (*p == '\n' || *p == '\0') {
146           p = discard_line(ini, line_start);
147           break;
148         }
149 
150         if (*p == '"') {
151           /* Handle quoted string value */
152           value_start = p;
153           p = unescape_quoted_value(ini, p);
154 
155           /* Was the string empty? */
156           if (p == value_start) {
157             p = discard_line(ini, line_start);
158             break;
159           }
160 
161           /* Discard the rest of the line after the string value */
162           p = discard_line(ini, p);
163 
164         } else {
165           /* Handle normal value */
166           p += strcspn(p, "\n");
167           trim_back(ini, p - 1);
168         }
169         break;
170     }
171   }
172 }
173 
174 
175 
rkaiq_ini_load(const char * filename)176 ini_t* rkaiq_ini_load(const char *filename) {
177   ini_t *ini = NULL;
178   FILE *fp = NULL;
179   int n, sz;
180 
181   /* Init ini struct */
182   ini = (ini_t*)malloc(sizeof(*ini));
183   if (!ini) {
184     goto fail;
185   }
186   memset(ini, 0, sizeof(*ini));
187 
188   /* Open file */
189   fp = fopen(filename, "rb");
190   if (!fp) {
191     goto fail;
192   }
193 
194   /* Get file size */
195   fseek(fp, 0, SEEK_END);
196   sz = ftell(fp);
197   rewind(fp);
198 
199   /* Load file content into memory, null terminate, init end var */
200   ini->data = (char*)malloc(sz + 1);
201   ini->data[sz] = '\0';
202   ini->end = ini->data  + sz;
203   n = fread(ini->data, 1, sz, fp);
204   if (n != sz) {
205     goto fail;
206   }
207 
208   /* Prepare data */
209   split_data(ini);
210 
211   /* Clean up and return */
212   fclose(fp);
213   return ini;
214 
215 fail:
216   if (fp) fclose(fp);
217   if (ini) rkaiq_ini_free(ini);
218   return NULL;
219 }
220 
221 
rkaiq_ini_free(ini_t * ini)222 void rkaiq_ini_free(ini_t *ini) {
223   free(ini->data);
224   free(ini);
225 }
226 
227 
rkaiq_ini_get(ini_t * ini,const char * section,const char * key)228 const char* rkaiq_ini_get(ini_t *ini, const char *section, const char *key) {
229   char *current_section = "";
230   char *val;
231   char *p = ini->data;
232 
233   if (*p == '\0') {
234     p = next(ini, p);
235   }
236 
237   while (p < ini->end) {
238     if (*p == '[') {
239       /* Handle section */
240       current_section = p + 1;
241 
242     } else {
243       /* Handle key */
244       val = next(ini, p);
245       if (!section || !strcmpci(section, current_section)) {
246         if (!strcmpci(p, key)) {
247           return val;
248         }
249       }
250       p = val;
251     }
252 
253     p = next(ini, p);
254   }
255 
256   return NULL;
257 }
258 
259 
rkaiq_ini_sget(ini_t * ini,const char * section,const char * key,const char * scanfmt,void * dst)260 int rkaiq_ini_sget(
261   ini_t *ini, const char *section, const char *key,
262   const char *scanfmt, void *dst
263 ) {
264   const char *val = rkaiq_ini_get(ini, section, key);
265   if (!val) {
266     return 0;
267   }
268   if (scanfmt) {
269     sscanf(val, scanfmt, dst);
270   } else {
271     *((const char**) dst) = val;
272   }
273   return 1;
274 }
275