1 /* Copyright 2016-2021 Dimitrij Mijoski
2  *
3  * This file is part of Nuspell.
4  *
5  * Nuspell is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Nuspell 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
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Nuspell.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "dictionary.hxx"
20 #include "utils.hxx"
21 
22 #include <fstream>
23 #include <iostream>
24 #include <stdexcept>
25 
26 using namespace std;
27 
28 namespace nuspell {
29 inline namespace v5 {
30 
Dictionary(std::istream & aff,std::istream & dic)31 Dictionary::Dictionary(std::istream& aff, std::istream& dic)
32 {
33 	if (!parse_aff_dic(aff, dic))
34 		throw Dictionary_Loading_Error("error parsing");
35 }
36 
37 Dictionary::Dictionary() = default;
38 
39 /**
40  * @brief Create a dictionary from opened files as iostreams
41  *
42  * Prefer using load_from_path(). Use this if you have a specific use case,
43  * like when .aff and .dic are in-memory buffers istringstream.
44  *
45  * @param aff The iostream of the .aff file
46  * @param dic The iostream of the .dic file
47  * @return Dictionary object
48  * @throws Dictionary_Loading_Error on error
49  */
load_from_aff_dic(std::istream & aff,std::istream & dic)50 auto Dictionary::load_from_aff_dic(std::istream& aff, std::istream& dic)
51     -> Dictionary
52 {
53 	return Dictionary(aff, dic);
54 }
55 
56 /**
57  * @brief Create a dictionary from files
58  * @param file_path_without_extension path *without* extensions (without .dic or
59  * .aff)
60  * @return Dictionary object
61  * @throws Dictionary_Loading_Error on error
62  */
load_from_path(const std::string & file_path_without_extension)63 auto Dictionary::load_from_path(const std::string& file_path_without_extension)
64     -> Dictionary
65 {
66 	auto path = file_path_without_extension;
67 	path += ".aff";
68 	std::ifstream aff_file(path);
69 	if (aff_file.fail()) {
70 		auto err = "Aff file " + path + " not found";
71 		throw Dictionary_Loading_Error(err);
72 	}
73 	path.replace(path.size() - 3, 3, "dic");
74 	std::ifstream dic_file(path);
75 	if (dic_file.fail()) {
76 		auto err = "Dic file " + path + " not found";
77 		throw Dictionary_Loading_Error(err);
78 	}
79 	return load_from_aff_dic(aff_file, dic_file);
80 }
81 
82 /**
83  * @brief Checks if a given word is correct
84  * @param word any word
85  * @return true if correct, false otherwise
86  */
spell(std::string_view word) const87 auto Dictionary::spell(std::string_view word) const -> bool
88 {
89 	auto ok_enc = validate_utf8(word);
90 	if (unlikely(word.size() > 360))
91 		return false;
92 	if (unlikely(!ok_enc))
93 		return false;
94 	auto word_buf = string(word);
95 	return spell_priv(word_buf);
96 }
97 
98 /**
99  * @brief Suggests correct words for a given incorrect word
100  * @param[in] word incorrect word
101  * @param[out] out this object will be populated with the suggestions
102  */
suggest(std::string_view word,std::vector<std::string> & out) const103 auto Dictionary::suggest(std::string_view word,
104                          std::vector<std::string>& out) const -> void
105 {
106 	out.clear();
107 	auto ok_enc = validate_utf8(word);
108 	if (unlikely(word.size() > 360))
109 		return;
110 	if (unlikely(!ok_enc))
111 		return;
112 	suggest_priv(word, out);
113 }
114 } // namespace v5
115 } // namespace nuspell
116