| /* |
| * 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 §ion_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() ); |
| } |
| |