diff options
Diffstat (limited to 'funcs.cpp')
| -rw-r--r-- | funcs.cpp | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/funcs.cpp b/funcs.cpp new file mode 100644 index 0000000..a8e1b25 --- /dev/null +++ b/funcs.cpp @@ -0,0 +1,257 @@ +#include "transcode.h" + +string random_anum_string(int len) +{ + string alphan("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); + + random_device rand; + mt19937 rgen(rand()); + + shuffle(alphan.begin(), alphan.end(), rgen); + + return alphan.substr(0, len); +} + +bool to_bool(const wstring& s) +{ + return s != "0"; +} + +void uniq(vector <wstring>& vec) +{ + sort(vec.begin(), vec.end()); + vec.erase(unique(vec.begin(), vec.end()), vec.end()); +} + +inline wstring& wtrim(wstring& s, const wchar_t* t = L" \t\n\r\f\v") +{ + s.erase(s.find_last_not_of(t) + 1); + s.erase(0, s.find_first_not_of(t)); + return s; +} + +void read_config_file(const char* configfile, + map<wstring, wstring>& config_options) +{ + wifstream config(configfile); + if (!config.is_open()) return; + + wstring line; + while(getline(config, line)) + { + wistringstream config_line(line); + wstring key; + if(getline(config_line, key, L'=')) { + wtrim(key); + wstring value; + if(getline(config_line, value)) { + wtrim(value); + config_options.insert({key, value}); + } + } + } + + config.close(); +} + +void write_config_file(const char* configfile, + map<wstring, wstring>& config_options) +{ + wofstream config(configfile); + + for (auto const& config_option: config_options) { + config << config_option.first << " = " + << config_option.second << endl; + } + + config.close(); +} + +void replace_chars(wstring& str, const wstring& a, // from + const wstring& b) // to +{ + size_t pos = 0; + while ((pos = str.find(a, pos)) != wstring::npos) { + str.replace(pos, a.length(), b); + pos += b.length(); + } +} + +// Replace problematic ASCII characters such as +// the 'Ohm' sign using our hexadecimal codes map +void str_ascii_to_utf(wstring& str) +{ + wstring char_old, char_new; + for (auto const& char_pair: ascii_utf) { + char_old = char_pair.first; + char_new = char_pair.second; + size_t pos = 0; + while ((pos = str.find(char_old, pos)) != wstring::npos) { + str.replace(pos, 1, char_new); + pos++; + } + } +} + +wstring convert_node_text(const wstring& text, + vector<wstring>& font_chars, + vector<wstring>& utf_chars, + bool do_greek) +{ + wstring str_out = text; + + size_t char_max = utf_chars.size(); + if (font_chars.size() < utf_chars.size()) + char_max = font_chars.size(); + + for (size_t i = 0; i < char_max; i++) { + if (font_chars[i].length() > 0) { + wstringstream fchstream(font_chars[i]); + wstring font_char; + + while(getline(fchstream, font_char, L' ')) + replace_chars(str_out, font_char, utf_chars[i]); + } + } + + if (do_greek && greek_precomp.size() <= greek_comb.size()) { + for (size_t i = 0; i < greek_comb.size(); i++) { + replace_chars(str_out, greek_comb[i], greek_precomp[i]); + } + } + + return str_out; +} + +void get_default_pfont(wstring& default_pfont, const char* styles_xmlfile) +{ + xml_document styles_xmldoc; + if (!styles_xmldoc.load_file(styles_xmlfile)) return; + + xpath_node_set style_xns = styles_xmldoc.select_nodes(L"//w:style[@w:styleId='Normal' or @w:styleId='Standard']/w:rPr/w:rFonts"); + + for (auto style_xn: style_xns) { + if (default_pfont.length() > 0) break; + xml_node style_node = style_xn.node(); + default_pfont = style_node.attribute(L"w:ascii").value(); + } +} + + +void update_default_pfont(const char * styles_xmlfile, wstring& targ_font, + const vector<wstring>& doc_fonts) +{ + xml_document styles_xmldoc; + if (!styles_xmldoc.load_file(styles_xmlfile)) return; + + for(const wstring& fstr: doc_fonts) { + // change the font attributes to the target + xpath_node_set xpf_ns = styles_xmldoc.select_nodes(L"//w:rFonts"); + for (auto xpf_n: xpf_ns) { + xml_node font_node = xpf_n.node(); + for (auto& attr: font_node.attributes()) + if (attr.value() == fstr) attr.set_value(targ_font.c_str()); + } + } + + ofstream xmlos(styles_xmlfile); + styles_xmldoc.save(xmlos); +} + +void detect_fonts(const char* xmlfile, vector<wstring>& doc_fonts, + vector<wstring>& doc_encs) +{ + xml_document xmldoc; + if (!xmldoc.load_file(xmlfile)) return; + + xpath_node_set xpf_ns = xmldoc.select_nodes(L"//w:rFonts"); + + // Find which font tags and encodings are in the document + for (auto xpf_n: xpf_ns) { + xml_node font_node = xpf_n.node(); + + for (const auto& attr: font_node.attributes()) { + doc_encs.push_back(attr.name()); + doc_fonts.push_back(attr.value()); + } + } + + // we only want the unique values + uniq(doc_encs); + uniq(doc_fonts); +} + +void process_xml(const char * xmlfile, wstring& targ_font, + const vector<wstring>& doc_fonts, const vector<wstring>& doc_encs, + map<wstring, vector<wstring>>& char_map, + vector<wstring>& utf_chars, const wstring& default_font, bool do_greek) +{ + xml_document xmldoc; + if (!xmldoc.load_file(xmlfile)) return; + + for(const wstring& fstr: doc_fonts) { + if (!char_map.count(fstr)) continue; + vector<wstring> font_chars = char_map.find(fstr)->second; + + cout << "Doing conversion for font " << fstr << endl; + + // we need to build the XPath query string out of the MS Word + // w:rFonts attributes identified, such as w:ascii, w:cs, etc. + // e.g. //w:p/w:r[w:rPr/w:rFonts[@w:ascii='Font' or @w:cs='Font']]/w:t + size_t enc_ct = doc_encs.size(); + wstring xpt_str = L"//w:r[w:rPr/w:rFonts[@"; + if (enc_ct > 1) { + for (size_t enc_it = 0; enc_it < enc_ct - 1; enc_it++) + xpt_str += doc_encs[enc_it] + L"='" + fstr + L"' or @"; + } + xpt_str += doc_encs[enc_ct - 1] + L"='" + fstr + L"']]/w:t"; + + // Get the set of nodes matching XPath query + xpath_query xpt(xpt_str.c_str()); + xpath_node_set xpt_ns = xpt.evaluate_node_set(xmldoc); + + // Do the actual conversion per node + for (auto xpt_match: xpt_ns) { + xml_node xpt_n = xpt_match.node(); + xml_text xpt_xmltxt = xpt_n.text(); + wstring txt = xpt_xmltxt.get(); + str_ascii_to_utf(txt); + wstring txt_new = convert_node_text(txt.c_str(), + font_chars, utf_chars, do_greek); + xpt_xmltxt.set(txt_new.c_str()); + } + + // now change the font attributes to the target + xpath_node_set xpf_ns = xmldoc.select_nodes(L"//w:rFonts"); + for (auto xpf_n: xpf_ns) { + xml_node font_node = xpf_n.node(); + for (auto& attr: font_node.attributes()) + if (attr.value() == fstr) attr.set_value(targ_font.c_str()); + } + } + + // this handles text segments without a set font + // i.e. in the default style determined in get_default_font + if (char_map.count(default_font)) { + xpath_node_set xpt_dfont_ns = xmldoc.select_nodes(L"//w:r[w:rPr and not(w:rPr/w:rFonts[@w:ascii or @w:hAnsi or @w:cs])]/w:t"); + vector<wstring> default_font_chars = char_map.find(default_font)->second; + + cout << "Converting default paragraph font " + << default_font << endl; + + for (auto xpt_dfont_match: xpt_dfont_ns) { + xml_node xpt_dfont_n = xpt_dfont_match.node(); + xml_text xpt_dfont_xmltxt = xpt_dfont_n.text(); + + wstring txt = xpt_dfont_xmltxt.get(); + str_ascii_to_utf(txt); + wstring txt_new = convert_node_text(txt.c_str(), + default_font_chars, utf_chars, do_greek); + + xpt_dfont_xmltxt.set(txt_new.c_str()); + } + } + + ofstream xmlos(xmlfile); + xmldoc.save(xmlos); +} |
