1 2 // This file is part of hhpcomp, a free HTML Help Project (*.hhp) compiler. 3 // Copyright (C) 2015 Benedikt Freisen 4 // 5 // This library is free software; you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 2.1 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library; if not, write to the Free Software 17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 19 20 #include <iostream> 21 #include <fstream> 22 #include <stdexcept> 23 24 #include <stdlib.h> 25 26 #include "hhp_reader.h" 27 #include "utils.h" 28 29 using namespace std; 30 31 string hhp_section::get_name() 32 { 33 return name; 34 } 35 36 void hhp_section::set_name(string name) 37 { 38 this->name = name; 39 } 40 41 hhp_pair::hhp_pair(string key, bool has_default_value, string default_value) 42 { 43 this->key = key; 44 this->has_default_value = has_default_value; 45 this->default_value = default_value; 46 value_has_been_set = false; 47 } 48 49 void hhp_pair::set_value(string value) 50 { 51 this->value = value; 52 value_has_been_set = true; 53 } 54 55 string hhp_pair::get_value() 56 { 57 if (value_has_been_set) 58 return value; 59 else 60 { 61 if (has_default_value) 62 return default_value; 63 else 64 throw domain_error("pair '" + key + "' does not have a default value"); 65 } 66 } 67 68 string hhp_pair::get_key() 69 { 70 return key; 71 } 72 73 void hhp_key_value_section::process_line(string line) 74 { 75 int pos_equals_sign = line.find_first_of('='); 76 if (pos_equals_sign == string::npos) 77 throw runtime_error("key-value pair does not contain an equals sign"); 78 string key = to_upper(line.substr(0, pos_equals_sign)); 79 string value = line.substr(pos_equals_sign + 1); 80 if (key.length() == 0) 81 throw runtime_error("key has length zero"); 82 83 entries.find(key)->second->set_value(value); 84 } 85 86 void hhp_key_value_section::add_entry(hhp_pair* entry) 87 { 88 string upper_case_key = to_upper(entry->get_key()); 89 if (entries.count(upper_case_key) != 0) 90 throw logic_error("trying to redundantly add key '" + upper_case_key + "'"); 91 entries.insert(pair<string, hhp_pair*>(upper_case_key, entry)); 92 } 93 94 hhp_options_section::hhp_options_section() 95 { 96 set_name("OPTIONS"); 97 98 add_entry(binary_TOC = new hhp_pair("Binary TOC", true, "No")); 99 add_entry(binary_index = new hhp_pair("Binary Index", true, "Yes")); 100 add_entry(compiled_file = new hhp_pair("Compiled File", false)); 101 add_entry(contents_file = new hhp_pair("Contents File", true, "")); 102 add_entry(index_file = new hhp_pair("Index File", true, "")); 103 add_entry(autoindex = new hhp_pair("AutoIndex", true, "No")); 104 add_entry(defaultwindow = new hhp_pair("DefaultWindow", true, ""));//? 105 add_entry(default_topic = new hhp_pair("Default Topic", true, "Index.htm"));//? 106 add_entry(defaultfont = new hhp_pair("DefaultFont", true, "")); 107 add_entry(language = new hhp_pair("Language", true, "0x409 English (US)"));//? 108 add_entry(title = new hhp_pair("Title", true, ""));//? 109 add_entry(createchifile = new hhp_pair("CreateCHIFile", true, "No")); 110 add_entry(compatibility = new hhp_pair("Compatibility", true, "1.1")); 111 add_entry(errorlogfile = new hhp_pair("ErrorLogFile", true, "Compiler.log"));//? 112 add_entry(full_text_search = new hhp_pair("Full-text search", true, "Yes"));//? 113 add_entry(display_compile_progress = new hhp_pair("Display compile progress", true, "Yes"));//? 114 add_entry(display_compile_note = new hhp_pair("Display compile note", true, "Yes"));//? 115 add_entry(flat = new hhp_pair("Flat", true, "No")); 116 add_entry(full_text_search_stop_list_file = new hhp_pair("Full text search stop list file", true, "")); 117 } 118 119 hhp_options_section::~hhp_options_section() 120 { 121 delete binary_TOC; 122 delete binary_index; 123 delete compiled_file; 124 delete contents_file; 125 delete index_file; 126 delete autoindex; 127 delete defaultwindow; 128 delete default_topic; 129 delete defaultfont; 130 delete language; 131 delete title; 132 delete createchifile; 133 delete compatibility; 134 delete errorlogfile; 135 delete full_text_search; 136 delete display_compile_progress; 137 delete display_compile_note; 138 delete flat; 139 delete full_text_search_stop_list_file; 140 } 141 142 hhp_files_section::hhp_files_section() 143 { 144 set_name("FILES"); 145 } 146 147 void hhp_files_section::process_line(string line) 148 { 149 filenames.push_back(line); 150 } 151 152 hhp_reader::hhp_reader(string filename) 153 { 154 this->filename = filename; 155 156 options = new hhp_options_section(); 157 add_section(options); 158 files = new hhp_files_section(); 159 add_section(files); 160 161 read(); 162 compute_unique_file_pathes_set(); 163 } 164 165 hhp_reader::~hhp_reader() 166 { 167 delete options; 168 delete files; 169 } 170 171 void hhp_reader::add_section(hhp_section* section) 172 { 173 string upper_case_name = to_upper(section->get_name()); 174 if (sections.count(upper_case_name) != 0) 175 throw logic_error("trying to redundantly add section '" + upper_case_name + "'"); 176 sections.insert(pair<string, hhp_section*>(upper_case_name, section)); 177 } 178 179 void hhp_reader::read() 180 { 181 ifstream hhp_file; 182 hhp_file.open(filename.c_str()); 183 184 string line; 185 int line_number = 0; 186 hhp_section* section = NULL; 187 while (hhp_file.good()) 188 { 189 getline(hhp_file, line); 190 line_number++; 191 if (line[line.length() - 1] == '\015') // delete CR character if present 192 line = line.substr(0, line.length() - 1); 193 if (line[0] == '[' && line[line.length() - 1] == ']') 194 { 195 string name = to_upper(line.substr(1, line.length() - 2)); 196 if (sections.count(name)) 197 { 198 section = sections.find(name)->second; 199 clog << section->get_name() << endl; 200 } 201 else 202 { 203 clog << "unknown section: " << name << endl; 204 } 205 } 206 else if (line[0] != ';' && !line.empty()) 207 { 208 if (section) 209 section->process_line(line); 210 } 211 } 212 213 hhp_file.close(); 214 } 215 216 void hhp_reader::compute_unique_file_pathes_set() 217 { 218 for (list<string>::iterator it = files->filenames.begin(); it != files->filenames.end(); ++it) 219 { 220 unique_file_pathes.insert(replace_backslashes(real_path(it->c_str()))); 221 } 222 } 223 224 string hhp_reader::get_title_string() 225 { 226 return options->title->get_value(); 227 } 228 229 string hhp_reader::get_contents_file_string() 230 { 231 return options->contents_file->get_value(); 232 } 233 234 string hhp_reader::get_index_file_string() 235 { 236 return options->index_file->get_value(); 237 } 238 239 string hhp_reader::get_default_topic_string() 240 { 241 return options->default_topic->get_value(); 242 } 243 244 unsigned int hhp_reader::get_language_code() 245 { 246 return strtoul(options->language->get_value().c_str(), NULL, 0); 247 } 248 249 string hhp_reader::get_compiled_file_string() 250 { 251 return options->compiled_file->get_value(); 252 } 253 254 set<string>::iterator hhp_reader::get_file_pathes_iterator_begin() 255 { 256 return unique_file_pathes.begin(); 257 } 258 259 set<string>::iterator hhp_reader::get_file_pathes_iterator_end() 260 { 261 return unique_file_pathes.end(); 262 } 263