• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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