blob: 4783f60c93504d380aa781cee06dda29072b8ef3 [file] [log] [blame]
/*
* Copyright (c) 2017, 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 "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.
*/
#pragma once
#include "ini_parser.h"
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include <string.h>
template <class PRODUCT>
void ini_parser<PRODUCT>::update_section(u_int8_t translation_map_bits, ini_section_t *orig, const ini_section_t &update, bool is_string)
{
if (*orig == update) {
return;
}
ini_section_t::const_iterator update_iter = update.begin();
ini_section_t::iterator orig_iter;
while (update_iter != update.end() ) {
orig_iter = find(translation_map_bits, update_iter, *orig, is_string);
if (orig_iter == orig->end() ) {
if (g_debug) DBG("Appending key %s value %s\n", update_iter->first.c_str(), update_iter->second.c_str());
orig->insert(orig->end(), *update_iter); // append entry from the update section
} else {
if (g_debug) DBG("Replacing Key %s value %s with key %s value %s\n"
, orig_iter->first.c_str()
, orig_iter->second.c_str()
, update_iter->first.c_str()
, update_iter->second.c_str());
*orig_iter = *update_iter; // replace the original entry with the entry from the update section
}
update_iter++;
}
}
template <class PRODUCT>
ini_section_t::iterator ini_parser<PRODUCT>::find(
u_int8_t translation_map_bits,
ini_section_t::const_iterator &lside,
ini_section_t &ini_section,
bool is_string) const
{
//u_int8_t translation_map_bits = 1;
typename PRODUCT::ADDRESS laddress,raddress;
typename PRODUCT::REG lvalue, rvalue;
int lstart, lend, rstart, rend;
if (!is_string) {
get_resolved_address_data(translation_map_bits, lside, &laddress, &lvalue, &lstart, &lend);
}
ini_section_t::iterator rside = ini_section.begin();
while (rside != ini_section.end() ) {
if (is_string) {
if (lside->first == rside->first) {
break;
}
} else {
get_resolved_address_data(translation_map_bits, rside, &raddress, &rvalue, &rstart, &rend);
if (laddress == raddress && lstart == rstart && lend == rend ) {
break;
}
}
rside++;
}
return rside;
}
//bool ini_parser::get_value (const ini_section_t &ini_section,
//const string &key,
//u_int64_t *value,
//bool must_be) const
bool get_value (const ini_section_t &ini_section,
const string &key,
u_int64_t *value,
bool must_be)
{
ini_section_t::const_iterator iter = ini_section.begin();
while( ini_section.end() != iter ) {
if( iter->first == key ) {
char *end_ptr;
*value = STRTOULL(iter->second.c_str(), &end_ptr, 0);
if(*end_ptr != 0) {
ERR("Key %s: Failed converting value %s\n", key.c_str(), iter->second.c_str());
EXIT (-1);
}
return true;
}
iter++;
}
if(must_be) {
ERR("Could not find key %s\n", key.c_str());
EXIT (-1);
}
return false;
}
//bool ini_parser::get_string(const ini_section_t &ini_section,
//const string &key,
//void *str,
//u_int32_t max_length,
//bool must_be) const
bool get_string(const ini_section_t &ini_section,
const string &key,
void *str,
u_int32_t max_length,
bool must_be)
{
ini_section_t::const_iterator iter = ini_section.begin();
while( ini_section.end() != iter ) {
if( iter->first == key ) {
if (iter->second.size() > max_length ) {
ERR("Key %s: length %lu exceeded maximal length of %u\n", key.c_str(), (unsigned long)iter->second.size(), max_length);
EXIT (-1);
}
iter->second.copy((char*)str, max_length);
return true;
}
iter++;
}
if(must_be) {
ERR("Could not find key %s\n", key.c_str());
EXIT (-1);
}
return false;
}
template <class PRODUCT>
void ini_parser<PRODUCT>::get_resolved_address_data (
u_int8_t translation_map_bits,
ini_section_t::const_iterator sec_iter,
typename PRODUCT::ADDRESS *address,
typename PRODUCT::REG *value,
bool word_addresses)
{
int start, end;
get_resolved_address_data(translation_map_bits, sec_iter, address, value, &start, &end, word_addresses);
}
template <class PRODUCT>
void ini_parser<PRODUCT>::get_resolved_address_data (
u_int8_t translation_map_bits,
ini_section_t::const_iterator sec_iter,
typename PRODUCT::ADDRESS *address,
typename PRODUCT::REG *value,
int *start,
int *end,
bool word_addresses
)
{
char *end_ptr;
if(g_debug) DBG( "Dumping address %s value %s\n", sec_iter->first.c_str(),sec_iter->second.c_str());
*address = ( typename PRODUCT::ADDRESS)strtoul(sec_iter->first.c_str(), &end_ptr, 0);
if (0 != *end_ptr) // it was a pathname
{
if(g_debug) DBG("Converting %s to ", sec_iter->first.c_str());
u_int32_t temp_address;
bool found = false;
if (!found && (translation_map_bits & TRANSLATION_MAP_REGTREE))
{
found = g_reg_tree_t_map.get_from_translation_map(sec_iter->first.c_str(), &temp_address, start, end);
}
if (!found && (translation_map_bits & TRANSLATION_MAP_FW))
{
found = g_fw_t_map.get_from_translation_map(sec_iter->first.c_str(), &temp_address, start, end);
}
if (!found && (translation_map_bits & TRANSLATION_MAP_UCODE))
{
found = g_ucode_t_map.get_from_translation_map(sec_iter->first.c_str(), &temp_address, start, end);
}
// bool found = ::g_t_map.get_from_translation_map(sec_iter->first.c_str(), &temp_address, start, end);
*address = ( typename PRODUCT::ADDRESS)temp_address;
if (!found) {
ERR("Could not find %s in translation map. Make sure that it is in the REG_TREE section in your INI file\n",
sec_iter->first.c_str());
EXIT (-1);
}
if (word_addresses) {
if (*address & 0x1) {
ERR("%s was converted to 0x%04x, which is not dword aligned\n",
sec_iter->first.c_str(),
*address );
EXIT (-1);
}
*address = *address / 2;
}
}
else
{
*start = 0;
*end = sizeof ( typename PRODUCT::REG) * 8 - 1;
}
*value = ( typename PRODUCT::REG)strtoul(sec_iter->second.c_str(), &end_ptr, 0);
if(g_debug) DBG( "Address %0#4x value %0#4x start %d end %d\n", *address, *value, *start, *end);
}
//void ini_parser::get_resolved_data (ini_section_t::const_iterator sec_iter,
// IMAGE *value) const
void get_resolved_data (ini_section_t::const_iterator sec_iter,
IMAGE *value)
{
char *end_ptr;
*value = strtoul(sec_iter->second.c_str(), &end_ptr, 0);
if(g_debug) DBG( "Image %0#4x\n", *value);
}
template <class PRODUCT>
ini_parser<PRODUCT>::ini_parser ()
{
this ->hadProductionSeciton = false;
//nothing to do
}
template <class PRODUCT>
bool ini_parser<PRODUCT>::init (const char *filename, u_int32_t option)
{
FILE *stream;
printf("%s\n", filename);
stream = fopen( filename, "r" );
if( stream == NULL )
{
// char cwd[1024];
// if (getcwd(cwd, sizeof(cwd)) != NULL)
// fprintf(stdout, "Current working dir: %s\n", cwd);
printf("%s\n", strerror(errno));
ERR( "Failed opening file %s \n", filename );
EXIT (-1);
}
else
{
int reg_tree_section_index = 0;
bool skip_section = false;
char buffer [1100];
char a1 [1000];
char a2 [256];
char a3 [256];
char a4 [256];
int ch;
int num;
u_int8_t translation_map_bits = TRANSLATION_MAP_NONE;
do
{
ch = get_clean_line (stream, buffer, sizeof buffer);
num = sscanf(buffer, "%999s %256s %256s %256s", a1, a2, a3, a4);
switch (num)
{
case 1:
{
INFO( "Section [%s]\n", a1 );
string section = a1;
if (section == "production")
{
if (hadProductionSeciton == true)
{
ERR( "Only one PRODUCTION Section is allowed in one burn command ! \n");
EXIT (-1);
}
hadProductionSeciton = true;
}
if (option == 1)
{
if (section == "radio_tx_conf")
{
section += "2";
}
if (section == "radio_rx_conf")
{
section += "2";
}
}
skip_section = false;
if (section == "fw_symbols")
{
translation_map_bits = TRANSLATION_MAP_FW;
}
else if (section == "ucode_symbols")
{
translation_map_bits = TRANSLATION_MAP_UCODE;
}
else if (section == "reg_tree")
{
translation_map_bits = TRANSLATION_MAP_REGTREE;
// if [REG_TREE] section appear more then once then do not process
// its key, values
reg_tree_section_index++;
if (reg_tree_section_index > 1)
{
skip_section = true;
}
}
if (section != "reg_tree")
{
if(g_debug) DBG("Adding ini section\n");
ini_section_t *sec = new ini_section_t;
pair <string, ini_section_t*> p (section, sec);
current_ini_section = ini_file.insert(p);
}
break;
}
case 2:
{
if(g_debug) DBG( "Address %s Value %s\n", a1, a2 );
key_value_t entry (a1, a2);
pair <ini_section_t::iterator, bool> ret;
ini_section_t *sec = this->current_ini_section->second;
sec->push_back(entry);
break;
}
case 3:
{
if(g_debug) DBG( "Address %s[%s] Value %s\n", a1, a3, a2 );
string temp = a1;
temp += '#';
temp.append(a3);
key_value_t entry (temp, a2);
pair <ini_section_t::iterator, bool> ret;
ini_section_t *sec = this->current_ini_section->second;
sec->push_back(entry);
break;
}
case 4:
{
if (!skip_section)
{
bool bInsert = false;
if(g_debug) DBG ("path %s address %s start %s end %s\n", a1, a2, a3, a4);
if (translation_map_bits == TRANSLATION_MAP_REGTREE)
{
bInsert = g_reg_tree_t_map.add_to_translation_map(a1, a2, a3, a4);
}
else if (translation_map_bits == TRANSLATION_MAP_FW)
{
bInsert = g_fw_t_map.add_to_translation_map(a1, a2, a3, a4);
}
else if (translation_map_bits == TRANSLATION_MAP_UCODE)
{
bInsert = g_ucode_t_map.add_to_translation_map(a1, a2, a3, a4);
}
// if( !g_t_map.add_to_translation_map(a1, a2, a3, a4) )
if (!bInsert)
{
ERR("Failed adding to translation map: path %s address %s start %s end %s\n", a1, a2, a3, a4);
EXIT (-1);
};
}
break;
}
default : if(g_debug) DBG( "empty line or comment line\n" );break;
}
} while (EOF != ch);
fclose(stream);
}
return true;
}
template <class PRODUCT>
int ini_parser<PRODUCT>::get_clean_line (FILE *stream, char *buffer, const int buffer_size) const
{
int i;
int ch=0;
bool alpha_detected = false;
bool section_detected = false;
for (i = 0; i < buffer_size; i++)
{
ch = getc(stream);
if( ch >= 'A' && ch <= 'Z' )
{
ch = ch - 'A' + 'a'; // change to lower case
}
alpha_detected = alpha_detected | (ch >= 'a' && ch <= 'z') ;
if (EOF == ch || '\n' == ch)
{
buffer[i] = '\0';
break;
}
else if ('[' == ch && !alpha_detected)
{
section_detected = true;
buffer[i] = ' ';
}
else if (']' == ch && section_detected)
{
buffer[i] = ' ';
}
else if ( '=' == ch)
{
buffer[i] = ' ';
}
else if ('#' == ch || ';' == ch)
{
buffer[i] = '\0';
} else
{
buffer[i] = (char)ch;
}
}
return ch;
}
template <class PRODUCT>
bool ini_parser<PRODUCT>::get_section(const string &section_name, u_int8_t translation_map_bits, ini_file_t::iterator *iter1, bool is_string, bool must_be)
{
//unused param
(void)must_be;
ini_file_t::iterator iter = ini_file.begin();
*iter1 = ini_file.end();
while (iter != ini_file.end() ) {
if (iter->first == section_name ) {
if (*iter1 == ini_file.end()){
*iter1 = iter;
}else{
this->update_section(translation_map_bits, (*iter1)->second, *(iter->second), is_string);
}
}
iter++;
}
//
// adding this lines cause the application stop running if the section must_be and did not find
// in other words, this function always return true
// if you decide to remove these lines, you should handle the return code in the caller function
//
/*if (must_be && *iter1 == ini_file.end()) {
ERR("Could not find mandatory section %s\n", section_name.c_str() );
EXIT (-1);
}*/
return (*iter1 != ini_file.end() );
}