/* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of The Linux Foundation nor * the names of its contributors may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "ConfFileParser.h" #include #include #include #include #include #include #include //declaration of functions only specific to this file static char parse_line ( group_table *key_file, const char *line, char **cur_grp ); static char parse_load_frm_fhandler ( group_table *key_file, FILE *fp ); static char line_is_grp ( group_table *key_file, const char *str, char **cur_grp ); static void free_grp_list ( group *a ); static void free_key_list ( key_value_pair_list *a ); static char line_is_key_value_pair ( group_table *key_file, const char *str, const char *cur_grp ); static char line_is_comment ( const char *str ); static char grp_exist ( const group_table *key_file, const char *new_grp ); static char add_grp ( group_table *key_file, const char *new_grp ); static group *alloc_group ( void ); static key_value_pair_list *alloc_key_value_pair ( void ); static char add_key_value_pair ( group_table *key_file, const char *cur_grp, const char *key, const char *val ); //Definitions void free_strs ( char **str_array ) { char **str_array_cpy = str_array; if(str_array != NULL) { while(*str_array != NULL) { free(*str_array); str_array++; } } free(str_array_cpy); } //ToDo: Come up with code hashing //function unsigned int get_hash_code ( const char *str ) { unsigned len = strlen(str); unsigned int i; unsigned int hash_code = 0; for(i = 0; len > 0; len--, i++) { hash_code += (int)((str[i] * pow(2, len))) % INT_MAX; hash_code %= INT_MAX; } return hash_code; } static key_value_pair_list *alloc_key_value_pair ( void ) { key_value_pair_list *key_list = NULL; key_list = (key_value_pair_list *)malloc( sizeof(key_value_pair_list)); if(key_list != NULL) { key_list->key = NULL; key_list->next = NULL; key_list->value = NULL; } return key_list; } static group * alloc_group ( void ) { group *grp = NULL; unsigned int i; grp = (group *)malloc(sizeof(group)); if(grp != NULL) { grp->grp_name = NULL; grp->grp_next = NULL; grp->num_of_keys = 0; grp->keys_hash_size = MAX_UNIQ_KEYS; grp->list = (key_value_pair_list **)malloc (sizeof(key_value_pair_list *) * grp->keys_hash_size); if(grp->list == NULL) { ALOGE("Could not alloc group\n"); free(grp); grp = NULL; }else { for(i = 0; i < grp->keys_hash_size; i++) { grp->list[i] = NULL; } } } return grp; } group_table *get_key_file ( ) { group_table *t = NULL; unsigned int i; t = (group_table *)malloc(sizeof(group_table)); if (t != NULL) { t->grps_hash_size = MAX_UNIQ_GRPS; t->num_of_grps = 0; t->grps_hash = (group **)malloc(sizeof(group *) * t->grps_hash_size); if (t->grps_hash == NULL) { free(t); return NULL; } for(i = 0; i < t->grps_hash_size; i++) { t->grps_hash[i] = NULL; } } return t; } void free_key_file( group_table *key_file ) { unsigned int i; if(key_file != NULL) { if(key_file->grps_hash != NULL) { for(i = 0; i < key_file->grps_hash_size; i++) { free_grp_list(key_file->grps_hash[i]); } } free(key_file->grps_hash); free(key_file); } } static void free_grp_list ( group *a ) { group *next; unsigned int i; while(a != NULL) { next = a->grp_next; if(a->list != NULL) { for(i = 0; i < a->keys_hash_size; i++) { free_key_list(a->list[i]); } } free(a->grp_name); free(a->list); free(a); a = next; } } static void free_key_list ( key_value_pair_list *a ) { key_value_pair_list *next; while(a != NULL) { next = a->next; free(a->key); free(a->value); free(a); a = next; } } //return all the groups //present in the file char **get_grps ( const group_table *key_file ) { char **grps = NULL; unsigned int i = 0; unsigned int j = 0; unsigned int grp_len; group *grp_list; if((key_file == NULL) || (key_file->grps_hash == NULL) || (key_file->grps_hash_size == 0) || (key_file->num_of_grps == 0)) { return grps; } grps = (char **)calloc((key_file->num_of_grps + 1), sizeof(char *)); if(grps == NULL) { return grps; } for(i = 0; i < key_file->grps_hash_size; i++) { grp_list = key_file->grps_hash[i]; while(grp_list != NULL) { grp_len = strlen(grp_list->grp_name); grps[j] = (char *)malloc(sizeof(char) * (grp_len + 1)); if(grps[j] == NULL) { free_strs(grps); grps = NULL; return grps; } memcpy(grps[j], grp_list->grp_name, (grp_len + 1)); grp_list = grp_list->grp_next; j++; } } grps[j] = NULL; return grps; } //returns the list of keys //associated with group name char **get_keys ( const group_table *key_file, const char *grp_name ) { unsigned int grp_hash_code; unsigned int grp_index; unsigned int num_of_keys; unsigned int i; unsigned int j = 0; unsigned int key_len; group *grp; key_value_pair_list *key_val_list; char **keys = NULL; if((key_file == NULL) || (grp_name == NULL) || (key_file->num_of_grps == 0) || (key_file->grps_hash_size == 0) || (key_file->grps_hash == NULL) || (!strcmp(grp_name, ""))) { return keys; } grp_hash_code = get_hash_code(grp_name); grp_index = (grp_hash_code % key_file->grps_hash_size); grp = key_file->grps_hash[grp_index]; while(grp != NULL) { if(!strcmp(grp_name, grp->grp_name)) { if((grp->num_of_keys == 0) || (grp->keys_hash_size == 0) || (grp->list == 0)) { return keys; } keys = (char **)calloc((grp->num_of_keys + 1), sizeof(char *)); if(keys == NULL) { return keys; } for(i = 0; i < grp->keys_hash_size; i++) { key_val_list = grp->list[i]; while(key_val_list != NULL) { key_len = strlen(key_val_list->key); keys[j] = (char *)malloc(sizeof(char) * (key_len + 1)); if(keys[j] == NULL) { free_strs(keys); keys = NULL; return keys; } memcpy(keys[j], key_val_list->key, (key_len + 1)); j++; key_val_list = key_val_list->next; } } keys[j] = NULL; return keys; } grp = grp->grp_next; } return keys; } char *get_value ( const group_table *key_file, const char *grp_name, const char *key ) { unsigned int grp_hash_code; unsigned int key_hash_code; unsigned int grp_index; unsigned int key_index; unsigned val_len; char *val = NULL; group *grp; key_value_pair_list *list; if((key_file == NULL) || (grp_name == NULL) || (key == NULL) || (key_file->grps_hash == NULL) || (key_file->grps_hash_size == 0) || !strcmp(grp_name, "") ||(!strcmp(key, ""))) { return NULL; } grp_hash_code = get_hash_code(grp_name); key_hash_code = get_hash_code(key); grp_index = (grp_hash_code % key_file->grps_hash_size); grp = key_file->grps_hash[grp_index]; while(grp != NULL) { if(!strcmp(grp_name, grp->grp_name) && grp->keys_hash_size && grp->list) { key_index = (key_hash_code % grp->keys_hash_size); list = grp->list[key_index]; while((list != NULL) && (strcmp(list->key, key))) { list = list->next; } if(list != NULL) { val_len = strlen(list->value); val = (char *)malloc(sizeof(char) * (val_len + 1)); if(val != NULL) { memcpy(val, list->value, val_len); val[val_len] = '\0'; } } return val; } grp = grp->grp_next; } return val; } //open the file, //read, parse and load //returns PARSE_SUCCESS if successfully //loaded else PARSE_FAILED char parse_load_file ( group_table *key_file, const char *file ) { FILE *fp; char ret = FALSE; if((file == NULL) || !strcmp(file, "")) { ALOGE("File name is null or empty \n"); return ret; } fp = fopen(file, "r"); if(fp == NULL) { ALOGE("could not open file for read\n"); return ret; } ret = parse_load_frm_fhandler(key_file, fp); fclose(fp); return ret; } //Read block of data from file handler //extract each line, check kind of line(comment, //group, key value pair) static char parse_load_frm_fhandler ( group_table *key_file, FILE *fp ) { char buf[MAX_LINE_LEN]; char ret = TRUE; char *line = NULL; void *new_line; char *cur_grp = NULL; unsigned line_len = 0; unsigned line_allocated = 0; unsigned int bytes_read = 0; unsigned int i; bool has_carriage_rtn = false; while((bytes_read = fread(buf, 1, MAX_LINE_LEN, fp))) { for(i = 0; i < bytes_read; i++) { if(line_len == line_allocated) { line_allocated += 25; new_line = realloc(line, line_allocated); if(new_line == NULL) { ret = FALSE; ALOGE("memory allocation failed for line\n"); break; } line = (char *)new_line; } if((buf[i] == '\n')) { has_carriage_rtn = false; line[line_len] = '\0'; ret = parse_line(key_file, line, &cur_grp); line_len = 0; if(ret == FALSE) { ALOGE("could not parse the line, line not proper\n"); break; } }else if(buf[i] == '\r') { ALOGE("File has carriage return\n"); has_carriage_rtn = true; }else if(has_carriage_rtn) { ALOGE("File format is not proper, no line character\ after carraige return\n"); ret = FALSE; break; }else { line[line_len] = buf[i]; line_len++; } } if (!ret) { break; } } free(line); free(cur_grp); return ret; } //checks whether a line is //comment or grp or key pair value //and accordingly adds to list static char parse_line ( group_table *key_file, const char *line, char **cur_grp ) { const char *line_begin; char *grp_name; unsigned int len; if((line == NULL) || (key_file == NULL)) { ALOGE("key file or line is null\n"); return FALSE; } for(line_begin = line; isspace(*line_begin); line_begin++); if(line_is_comment(line_begin)) { ALOGE("line is comment\n"); return TRUE; }else if(line_is_grp(key_file, line_begin, cur_grp)) { ALOGE("line is grp\n"); return TRUE; }else if(line_is_key_value_pair(key_file, line_begin, *cur_grp)) { ALOGE("line is key value pair\n"); return TRUE; }else { ALOGE("line is neither comment, grp nor key value pair\n"); return FALSE; } } static char line_is_comment ( const char *str ) { if(str == NULL) { return FALSE; }else if(((*str) == '#') || ((*str) == '\0') || ((*str) == '\n')) { return TRUE; }else { ALOGE("line is not comment\n"); return FALSE; } } //return true if a group //name already exist //else false static char grp_exist ( const group_table *key_file, const char *new_grp ) { unsigned hash_code; unsigned int index; group *grp; if((key_file == NULL) || (new_grp == NULL) || (!key_file->grps_hash_size)) { return FALSE; }else { hash_code = get_hash_code(new_grp); index = hash_code % key_file->grps_hash_size; grp = key_file->grps_hash[index]; while(grp != NULL) { if (!strcmp(grp->grp_name, new_grp)) return TRUE; grp = grp->grp_next; } return FALSE; } } //Add a group to group //table if it does not exist static char add_grp ( group_table *key_file, const char *new_grp ) { unsigned int hash_code; unsigned int index; unsigned int grp_name_len; group *grp; if(!grp_exist(key_file, new_grp)) { if((key_file == NULL) || (new_grp == NULL) || !key_file->grps_hash_size) { return FALSE; } hash_code = get_hash_code(new_grp); ALOGE("group hash code is: %u\n", hash_code); index = hash_code % key_file->grps_hash_size; ALOGE("group index is: %u\n", index); grp = alloc_group(); if(grp == NULL) { return FALSE; } grp_name_len = strlen(new_grp); grp->grp_name = (char *)malloc( sizeof(char) * (grp_name_len + 1)); if(grp->grp_name == NULL) { ALOGE("could not alloc memory for group name\n"); ALOGE("Add group failed\n"); free_grp_list(grp); return FALSE; }else { memcpy(grp->grp_name, new_grp, (grp_name_len + 1)); } grp->grp_next = key_file->grps_hash[index]; key_file->grps_hash[index] = grp; key_file->num_of_grps++; return TRUE; }else { return FALSE; } } //checks validity of a group //a valid group is //inside [] group name must be //alphanumeric //Example: [grpName] static char line_is_grp ( group_table *key_file, const char *str, char **cur_grp ) { const char *g_start; const char *g_end; char *new_grp; unsigned int grp_len; if ((str == NULL) || (key_file == NULL)) { ALOGE("str is null or key file is null\n"); return FALSE; } //checks start mark char ']' if(((*str) != '[')) { ALOGE("start mark is not '['\n"); return FALSE; }else { str++; g_start = str; } //checks the end char '[' while((*str != '\0') && ((*str) != ']')) { str++; } //if end mark group not found if ((*str) != ']') { ALOGE("grp end mark is not '['\n"); return FALSE; }else { g_end = (str - 1); } str++; //if end mark found checks the rest chars as well //rest chars should be space while(((*str) == ' ') || ((*str) == '\t')) { str++; } if(*str) { ALOGE("after ']' there are some character\n"); return FALSE; } str = g_start; while((*g_start != '\0') && (g_start != g_end) && isalnum(*g_start)) { g_start++; } if((g_start == g_end) && isalnum(*g_start)) { //look up if already exist //return false else insert the grp in grp table grp_len = (g_end - str + 1); new_grp = (char *)malloc(sizeof(char) * (grp_len + 1)); if (new_grp == NULL) { ALOGE("could not alloc memory for new group\n"); return FALSE; } memcpy(new_grp, str, grp_len); new_grp[grp_len] = '\0'; if(add_grp(key_file, new_grp)) { free(*cur_grp); *cur_grp = new_grp; return TRUE; }else { ALOGE("could not add group to group table\n"); return FALSE; } }else { return FALSE; } } static char key_exist ( const group_table *key_file, const char *cur_grp, const char *key ) { unsigned int grp_hash_code; unsigned int key_hash_code; unsigned int grp_index; unsigned int key_index; group *grp = NULL; key_value_pair_list *list = NULL; if((key_file != NULL) && (cur_grp != NULL) && (key != NULL) && ((key_file->grps_hash != NULL)) && (strcmp(key, ""))) { grp_hash_code = get_hash_code(cur_grp); grp_index = (grp_hash_code % key_file->grps_hash_size); grp = key_file->grps_hash[grp_index]; key_hash_code = get_hash_code(key); while((grp != NULL)) { if(!strcmp(cur_grp, grp->grp_name)) { key_index = (key_hash_code % grp->keys_hash_size); if(grp->list) list = grp->list[key_index]; while((list != NULL) && strcmp(key, list->key)) { list = list->next; } if(list != NULL){ return TRUE; }else{ return FALSE; } } grp = grp->grp_next; } if(!grp) { return TRUE; }else { return FALSE; } }else { return FALSE; } } //checks validity of key //a valid key must start in //a seperate line and key must //be alphanumeric and before '=' //there must not be any space //Example: key=value static char line_is_key_value_pair ( group_table *key_file, const char *str, const char *cur_grp ) { char *equal_start; char *key; char *val; unsigned key_len; unsigned val_len; if((str == NULL) || (cur_grp == NULL) || !strcmp(cur_grp, "") || (key_file == NULL)) { ALOGE("line is null or cur group or key file is null or empty\n"); return FALSE; } equal_start = strchr(str, '='); key_len = (equal_start - str); if((equal_start == NULL) || (equal_start == str)) { ALOGE("line does not have '=' character or no key\n"); return FALSE; } while((str != equal_start) && isalnum(*str)) str++; if((str == equal_start)) { key = (char *)malloc(sizeof(char) * (key_len + 1)); if(key == NULL) { ALOGE("could not alloc memory for new key\n"); return FALSE; } equal_start++; val_len = strlen(equal_start); val = (char *)malloc(sizeof(char) * (val_len + 1)); if(val == NULL) { ALOGE("could not alloc memory for value\n"); return FALSE; } memcpy(key, (str - key_len), key_len); memcpy(val, equal_start, val_len); key[key_len] = '\0'; val[val_len] = '\0'; ALOGE("Grp: %s, key: %s, value: %s\n", cur_grp, key, val); return add_key_value_pair(key_file, cur_grp, key, val); }else { ALOGE("key name doesnot have alpha numeric char\n"); return FALSE; } } static char add_key_value_pair ( group_table *key_file, const char *cur_grp, const char *key, const char *val ) { unsigned int grp_hash_code; unsigned int key_hash_code; unsigned int grp_index; unsigned int key_index; unsigned key_len, val_len; group *grp = NULL; key_value_pair_list *list = NULL; if((key_file != NULL) && (cur_grp != NULL) && (key != NULL) && ((key_file->grps_hash != NULL)) && (strcmp(key, ""))) { grp_hash_code = get_hash_code(cur_grp); ALOGE("grp hash code is %u\n", grp_hash_code); grp_index = (grp_hash_code % key_file->grps_hash_size); ALOGE("grp index is %u\n", grp_index); grp = key_file->grps_hash[grp_index]; key_hash_code = get_hash_code(key); while((grp != NULL)) { if(!strcmp(cur_grp, grp->grp_name)) { key_index = (key_hash_code % grp->keys_hash_size); if(grp->list) { list = grp->list[key_index]; }else { ALOGE("group list is null\n"); return FALSE; } while((list != NULL) && strcmp(key, list->key)) { list = list->next; } if(list != NULL) { ALOGE("group already contains the key\n"); return FALSE; }else{ list = alloc_key_value_pair(); if(list == NULL) { ALOGE("add key value failed as could not alloc memory for key\ val pair\n"); return FALSE; } key_len = strlen(key); list->key = (char *)malloc(sizeof(char) * (key_len + 1)); if(list->key == NULL) { ALOGE("could not alloc memory for key\n"); free(list); return FALSE; } val_len = strlen(val); list->value = (char *)malloc(sizeof(char) * (val_len + 1)); if(!list->value) { free(list->key); free(list); return FALSE; } memcpy(list->key, key, key_len); memcpy(list->value, val, val_len); list->key[key_len] = '\0'; list->value[val_len] = '\0'; list->next = grp->list[key_index]; grp->list[key_index] = list; grp->num_of_keys++; return TRUE; } } grp = grp->grp_next; } ALOGE("group does not exist\n"); return FALSE; }else { return FALSE; } }