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. 21 static int isspace(int ch) { 22 return (ch == ' ' || ch == '\t'); 23 } 24 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 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 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