blob: 912d40dae61181f344cab0d9f724a5fde02a525f [file] [log] [blame]
/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <math.h>
#include <utils/Log.h>
//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 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;
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;
}
}
//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
)
{
const char *equal_start;
char *key = NULL;
char *val = NULL;
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");
if(key){
free(key);
key = NULL;
}
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 = 0;
unsigned val_len = 0;
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");
goto err;
}
while((list != NULL) && strcmp(key, list->key)) {
list = list->next;
}
if(list != NULL) {
ALOGE("group already contains the key\n");
goto err;
}else{
list = alloc_key_value_pair();
if(list == NULL) {
ALOGE("add key value failed as could not alloc memory for key\
val pair\n");
goto err;
}
if(key) {
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);
goto err;
}
if(val) {
val_len = strlen(val);
}
list->value = (char *)malloc(sizeof(char) *
(val_len + 1));
if(!list->value) {
free(list->key);
free(list);
goto err;
}
memcpy(list->key, key, key_len);
memcpy(list->value, val, val_len);
if (key) free((char*)key);
if (val) free((char*)val);
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");
goto err;
}
err:
if (key) free((char*)key);
if (val) free((char*)val);
return FALSE;
}