1 // Copyright 2014 The Android Open Source Project
2 //
3 // This software is licensed under the terms of the GNU General Public
4 // License version 2, as published by the Free Software Foundation, and
5 // may be copied, distributed, and modified under those terms.
6 //
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License for more details.
11
12 #include "android/utils/property_file.h"
13
14 #include "android/utils/system.h"
15
16 #include <string.h>
17 #include <stdlib.h>
18
19 // Return true iff |ch| is whitespace. Don't use isspace() to avoid
20 // locale-related results and associated issues.
isspace(int ch)21 static int isspace(int ch) {
22 return (ch == ' ' || ch == '\t');
23 }
24
propertyFileIterator_init(PropertyFileIterator * iter,const void * propFile,size_t propFileLen)25 void propertyFileIterator_init(PropertyFileIterator* iter,
26 const void* propFile,
27 size_t propFileLen) {
28 iter->name[0] = '\0';
29 iter->value[0] = '\0';
30 iter->p = propFile;
31 iter->end = iter->p + propFileLen;
32 }
33
34
propertyFileIterator_next(PropertyFileIterator * iter)35 bool propertyFileIterator_next(PropertyFileIterator* iter) {
36 const char* p = iter->p;
37 const char* end = iter->end;
38 while (p < end) {
39 // Get end of line, and compute next line position.
40 const char* line = p;
41 const char* lineEnd = (const char*)memchr(p, '\n', end - p);
42 if (!lineEnd) {
43 lineEnd = end;
44 p = end;
45 } else {
46 p = lineEnd + 1;
47 }
48
49 // Remove trailing \r before the \n, if any.
50 if (lineEnd > line && lineEnd[-1] == '\r')
51 lineEnd--;
52
53 // Skip leading whitespace.
54 while (line < lineEnd && isspace(line[0]))
55 line++;
56
57 // Skip empty lines, and those that begin with '#' for comments.
58 if (lineEnd == line || line[0] == '#')
59 continue;
60
61 const char* name = line;
62 const char* nameEnd =
63 (const char*)memchr(name, '=', lineEnd - name);
64 if (!nameEnd) {
65 // Skipping lines without a =
66 continue;
67 }
68 const char* value = nameEnd + 1;
69 while (nameEnd > name && isspace(nameEnd[-1]))
70 nameEnd--;
71
72 size_t nameLen = nameEnd - name;
73 if (nameLen == 0 || nameLen >= MAX_PROPERTY_NAME_LEN) {
74 // Skip lines without names, or with names too long.
75 continue;
76 }
77
78 memcpy(iter->name, name, nameLen);
79 iter->name[nameLen] = '\0';
80
81 // Truncate value's length.
82 size_t valueLen = (lineEnd - value);
83 if (valueLen >= MAX_PROPERTY_VALUE_LEN)
84 valueLen = (MAX_PROPERTY_VALUE_LEN - 1);
85
86 memcpy(iter->value, value, valueLen);
87 iter->value[valueLen] = '\0';
88
89 iter->p = p;
90 return true;
91 }
92 iter->p = p;
93 return false;
94 }
95
propertyFile_getValue(const char * propFile,size_t propFileLen,const char * propName)96 char* propertyFile_getValue(const char* propFile,
97 size_t propFileLen,
98 const char* propName) {
99 size_t propNameLen = strlen(propName);
100 if (propNameLen >= MAX_PROPERTY_NAME_LEN)
101 return NULL;
102
103 char* ret = NULL;
104 PropertyFileIterator iter[1];
105 propertyFileIterator_init(iter, propFile, propFileLen);
106 while (propertyFileIterator_next(iter)) {
107 if (!strcmp(iter->name, propName)) {
108 free(ret);
109 ret = ASTRDUP(iter->value);
110 }
111 }
112 return ret;
113 }
114