static const char * get_key_value(const char * line_beg, char ** key, char ** value) { const char * key_beg; const char * equal_sign; const char * key_end; const char * val_beg; const char * val_end; int strLen = 0; while(TRUE) { const size_t n1 = strcspn(line_beg, "\r\n"); const size_t n2 = strspn(line_beg, " \t"); const char* const line_end = line_beg + n1; if(*line_end == '\0') { // EOF reached if(n1 != n2) // Last line is not terminated with new line char. return NULL; } // new line char found if(n1 == n2) { // empty line if(n1 == 0) // TODO: Why need to add this line? return NULL; line_beg = skip_new_line(line_end); continue; } key_beg = line_beg + n2; // first non-blank char equal_sign = key_beg; while(*equal_sign != '=' && equal_sign < line_end) ++equal_sign; if(*equal_sign != '=') { // '=' not found. line_beg = skip_new_line(line_end); continue; } key_end = equal_sign; while(key_beg < key_end && (*(key_end-1) == ' ' || *(key_end-1) == '\t')) --key_end; strLen = key_end - key_beg; (*key) = malloc(strLen + 1); strncpy(*key, key_beg, strLen); (*key)[strLen] = 0; val_beg = equal_sign+1; val_end = line_end; while(val_beg < line_end && (*val_beg == ' ' || *val_beg == '\t')) ++val_beg; while(val_beg < val_end && (*(val_end-1) == ' ' || *(val_end-1) == '\t')) --val_end; strLen = val_end-val_beg; (*value) = malloc(strLen + 1); strncpy(*value, val_beg, strLen); (*value)[strLen] = 0; line_beg = skip_new_line(line_end); return line_beg; } }
/* extract key - value pair having the following format: * key=value<new line> * Empty lines and lines containing only spaces and tabs are skipped. * Leading and trailing blanks, as well as blanks around the equal sign are discarded. * * Parameters: * p1 - beginning of the string. * * Return value: * NULL if key - value pair was not found * != NULL otherwise. It is a pointer to the beginning of the next string. */ const char* DictInfo::get_key_value(const char *line_beg, std::string& key, std::string& value) { key.clear(); value.clear(); while(true) { const size_t n1 = strcspn(line_beg, "\r\n"); const size_t n2 = strspn(line_beg, " \t"); const char* const line_end = line_beg + n1; if(*line_end == '\0') { // EOF reached if(n1 != n2) g_warning("%s: line %d: Last line is not terminated with new line char.", ifo_file_name.c_str(), lineno); return NULL; } // new line char found g_assert(*line_end == '\r' || *line_end == '\n'); if(n1 == n2) { // empty line line_beg = skip_new_line(line_end); ++lineno; continue; } const char* const key_beg = line_beg + n2; // first non-blank char const char *equal_sign = key_beg; while(*equal_sign != '=' && equal_sign < line_end) ++equal_sign; if(*equal_sign != '=') { g_warning("%s: line %d: '=' not found.", ifo_file_name.c_str(), lineno); line_beg = skip_new_line(line_end); ++lineno; continue; } const char *key_end=equal_sign; while(key_beg < key_end && (*(key_end-1) == ' ' || *(key_end-1) == '\t')) --key_end; key.assign(key_beg, key_end-key_beg); const char *val_beg = equal_sign+1; const char *val_end = line_end; while(val_beg < line_end && (*val_beg == ' ' || *val_beg == '\t')) ++val_beg; while(val_beg < val_end && (*(val_end-1) == ' ' || *(val_end-1) == '\t')) --val_end; value.assign(val_beg, val_end-val_beg); line_beg = skip_new_line(line_end); // no ++lineno; here return line_beg; } }
/* replace new lines with "<br>" sequence */ static void encode_description(const char *p, long len, std::string &description) { description.clear(); const char *p1 = p; while(p1 - p < len) { if(*p1 == '\r' || *p1 == '\n') { description += "<br>"; p1 = skip_new_line(p1); } else { description += *p1; ++p1; } } }
bool DictInfo::load_from_ifo_file(const std::string& ifofilename, DictInfoType infotype) { clear(); ifo_file_name=ifofilename; set_infotype(infotype); glib::CharStr buffer; glib::Error error; if (!g_file_get_contents(ifo_file_name.c_str(), get_addr(buffer), NULL, get_addr(error))) { g_critical("Load %s failed. Error: %s.", ifo_file_name.c_str(), error->message); return false; } const gchar *p1 = get_impl(buffer); if(g_str_has_prefix(p1, UTF8_BOM)) p1 += 3; if(!g_utf8_validate(p1, -1, NULL)) { g_critical("Load %s failed: Invalid UTF-8 encoded text.", ifo_file_name.c_str()); return false; } lineno = 1; const gchar *magic_data = NULL; if(infotype == DictInfoType_NormDict) magic_data = NORM_DICT_MAGIC_DATA; else if(infotype == DictInfoType_TreeDict) magic_data = TREE_DICT_MAGIC_DATA; else if(infotype == DictInfoType_ResDb) magic_data = RES_DB_MAGIC_DATA; else return false; if (!g_str_has_prefix(p1, magic_data)) { g_critical("Load %s failed: Incorrect magic data.", ifo_file_name.c_str()); if(g_str_has_prefix(p1, NORM_DICT_MAGIC_DATA)) g_message("File '%s' is an index-based dictionary.", ifo_file_name.c_str()); else if(g_str_has_prefix(p1, TREE_DICT_MAGIC_DATA)) g_message("File '%s' is a tree dictionary.", ifo_file_name.c_str()); else if(g_str_has_prefix(p1, RES_DB_MAGIC_DATA)) g_message("File '%s' is a resource database.", ifo_file_name.c_str()); else g_message("File '%s' is not a StarDict dictionary or it's broken.", ifo_file_name.c_str()); return false; } p1 += strlen(magic_data); p1 = skip_new_line(p1); if(!p1) { g_critical("Load %s failed: Incorrect magic data.", ifo_file_name.c_str()); return false; } std::string key, value; while(true) { ++lineno; p1 = get_key_value(p1, key, value); if(!p1) break; // version must the first option if(!is_version()) { if(key != "version") { g_critical("Load %s failed: \"version\" must be the first option.", ifo_file_name.c_str()); return false; } } if(key == "version") { if(!check_option_duplicate(f_version, "version")) continue; set_version(value); if(infotype == DictInfoType_NormDict) { if(version != "2.4.2" && version != "3.0.0") { g_critical("Load %s failed: Unknown version.", ifo_file_name.c_str()); return false; } } else if(infotype == DictInfoType_TreeDict) { if(version != "2.4.2") { g_critical("Load %s failed: Unknown version.", ifo_file_name.c_str()); return false; } } else if(infotype == DictInfoType_ResDb) { if(version != "3.0.0") { g_critical("Load %s failed: Unknown version.", ifo_file_name.c_str()); return false; } } } else if(key == "idxoffsetbits") { if(!check_option_duplicate(f_idxoffsetbits, "idxoffsetbits")) continue; if(value != "32") { // TODO g_critical("Load %s failed: idxoffsetbits != 32 not supported presently.", ifo_file_name.c_str()); return false; } } else if(key == "wordcount" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_wordcount, "wordcount")) continue; set_wordcount(atol(value.c_str())); } else if(key == "filecount" && infotype == DictInfoType_ResDb) { if(!check_option_duplicate(f_filecount, "filecount")) continue; set_filecount(atol(value.c_str())); } else if(key == "synwordcount" && infotype == DictInfoType_NormDict) { if(!check_option_duplicate(f_synwordcount, "synwordcount")) continue; set_synwordcount(atol(value.c_str())); } else if(key == "tdxfilesize" && infotype == DictInfoType_TreeDict) { if(!check_option_duplicate(f_index_file_size, "tdxfilesize")) continue; set_index_file_size(atol(value.c_str())); } else if(key == "idxfilesize" && infotype == DictInfoType_NormDict) { if(!check_option_duplicate(f_index_file_size, "idxfilesize")) continue; set_index_file_size(atol(value.c_str())); } else if(key == "ridxfilesize" && infotype == DictInfoType_ResDb) { if(!check_option_duplicate(f_index_file_size, "ridxfilesize")) continue; set_index_file_size(atol(value.c_str())); } else if(key == "dicttype" && infotype == DictInfoType_NormDict) { if(!check_option_duplicate(f_dicttype, "dicttype")) continue; set_dicttype(value); } else if(key == "bookname" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_bookname, "bookname")) continue; set_bookname(value); } else if(key == "author" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_author, "author")) continue; set_author(value); } else if(key == "email" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_email, "email")) continue; set_email(value); } else if(key == "website" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_website, "website")) continue; set_website(value); } else if(key == "date" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_date, "date")) continue; set_date(value); } else if(key == "description" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_description, "description")) continue; std::string temp; decode_description(value.c_str(), value.length(), temp); set_description(temp); } else if(key == "sametypesequence" && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { if(!check_option_duplicate(f_sametypesequence, "sametypesequence")) continue; set_sametypesequence(value); } else { g_message("Load %s warning: unknown option %s.", ifo_file_name.c_str(), key.c_str()); } } // check required options if((!is_wordcount() || wordcount == 0) && ((infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict))) { g_critical("Load %s failed: wordcount not specified or 0.", ifo_file_name.c_str()); return false; } if((!is_filecount() || filecount == 0) && infotype == DictInfoType_ResDb) { g_critical("Load %s failed: filecount not specified or 0.", ifo_file_name.c_str()); return false; } if((!is_bookname() || bookname.empty()) && (infotype == DictInfoType_NormDict || infotype == DictInfoType_TreeDict)) { g_critical("Load %s failed: bookname not specified.", ifo_file_name.c_str()); return false; } if(!is_index_file_size() || index_file_size == 0) { const char* kkey; if(infotype == DictInfoType_NormDict) kkey = "idxfilesize"; else if(infotype == DictInfoType_TreeDict) kkey = "tdxfilesize"; else if(infotype == DictInfoType_ResDb) kkey = "ridxfilesize"; else kkey = ""; g_critical("Load %s failed: %s not specified or 0.", ifo_file_name.c_str(), kkey); return false; } return true; }