📄 lib.cpp
字号:
std::string cache_dir=std::string(g_get_user_cache_dir())+G_DIR_SEPARATOR_S+"sdcv"; if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_EXISTS)) { if (g_mkdir(cache_dir.c_str(), 0700)==-1) return res; } else if (!g_file_test(cache_dir.c_str(), G_FILE_TEST_IS_DIR)) return res; gchar *base=g_path_get_basename(url.c_str()); res.push_back(cache_dir+G_DIR_SEPARATOR_S+base+".oft"); g_free(base); return res;}bool offset_index::save_cache(const std::string& url){ strlist_t vars=get_cache_variant(url); for (strlist_t::const_iterator it=vars.begin(); it!=vars.end(); ++it) { FILE *out=fopen(it->c_str(), "wb"); if (!out) continue; if (fwrite(CACHE_MAGIC, 1, strlen(CACHE_MAGIC), out)!=strlen(CACHE_MAGIC)) continue; if (fwrite(&wordoffset[0], sizeof(wordoffset[0]), wordoffset.size(), out)!=wordoffset.size()) continue; fclose(out); printf("save to cache %s\n", url.c_str()); return true; } return false;}bool offset_index::load(const std::string& url, gulong wc, gulong fsize){ wordcount=wc; gulong npages=(wc-1)/ENTR_PER_PAGE+2; wordoffset.resize(npages); if (!load_cache(url)) {//map file will close after finish of block MapFile map_file; if (!map_file.open(url.c_str(), fsize)) return false; const gchar *idxdatabuffer=map_file.begin(); const gchar *p1 = idxdatabuffer; gulong index_size; guint32 j=0; for (guint32 i=0; i<wc; i++) { index_size=strlen(p1) +1 + 2*sizeof(guint32); if (i % ENTR_PER_PAGE==0) { wordoffset[j]=p1-idxdatabuffer; ++j; } p1 += index_size; } wordoffset[j]=p1-idxdatabuffer; if (!save_cache(url)) fprintf(stderr, "cache update failed\n"); } if (!(idxfile = fopen(url.c_str(), "rb"))) { wordoffset.resize(0); return false; } first.assign(0, read_first_on_page_key(0)); last.assign(wordoffset.size()-2, read_first_on_page_key(wordoffset.size()-2)); middle.assign((wordoffset.size()-2)/2, read_first_on_page_key((wordoffset.size()-2)/2)); real_last.assign(wc-1, get_key(wc-1)); return true;}inline gulong offset_index::load_page(glong page_idx){ gulong nentr=ENTR_PER_PAGE; if (page_idx==glong(wordoffset.size()-2)) if ((nentr=wordcount%ENTR_PER_PAGE)==0) nentr=ENTR_PER_PAGE; if (page_idx!=page.idx) { page_data.resize(wordoffset[page_idx+1]-wordoffset[page_idx]); fseek(idxfile, wordoffset[page_idx], SEEK_SET); fread(&page_data[0], 1, page_data.size(), idxfile); page.fill(&page_data[0], nentr, page_idx); } return nentr;}const gchar *offset_index::get_key(glong idx){ load_page(idx/ENTR_PER_PAGE); glong idx_in_page=idx%ENTR_PER_PAGE; wordentry_offset=page.entries[idx_in_page].off; wordentry_size=page.entries[idx_in_page].size; return page.entries[idx_in_page].keystr;}void offset_index::get_data(glong idx){ get_key(idx);}const gchar *offset_index::get_key_and_data(glong idx){ return get_key(idx);}bool offset_index::lookup(const char *str, glong &idx){ bool bFound=false; glong iFrom; glong iTo=wordoffset.size()-2; gint cmpint; glong iThisIndex; if (stardict_strcmp(str, first.keystr.c_str())<0) { idx = 0; return false; } else if (stardict_strcmp(str, real_last.keystr.c_str()) >0) { idx = INVALID_INDEX; return false; } else { iFrom=0; iThisIndex=0; while (iFrom<=iTo) { iThisIndex=(iFrom+iTo)/2; cmpint = stardict_strcmp(str, get_first_on_page_key(iThisIndex)); if (cmpint>0) iFrom=iThisIndex+1; else if (cmpint<0) iTo=iThisIndex-1; else { bFound=true; break; } } if (!bFound) idx = iTo; //prev else idx = iThisIndex; } if (!bFound) { gulong netr=load_page(idx); iFrom=1; // Needn't search the first word anymore. iTo=netr-1; iThisIndex=0; while (iFrom<=iTo) { iThisIndex=(iFrom+iTo)/2; cmpint = stardict_strcmp(str, page.entries[iThisIndex].keystr); if (cmpint>0) iFrom=iThisIndex+1; else if (cmpint<0) iTo=iThisIndex-1; else { bFound=true; break; } } idx*=ENTR_PER_PAGE; if (!bFound) idx += iFrom; //next else idx += iThisIndex; } else { idx*=ENTR_PER_PAGE; } return bFound;}wordlist_index::~wordlist_index(){ g_free(idxdatabuf);}bool wordlist_index::load(const std::string& url, gulong wc, gulong fsize){ gzFile in = gzopen(url.c_str(), "rb"); if (in == NULL) return false; idxdatabuf = (gchar *)g_malloc(fsize); gulong len = gzread(in, idxdatabuf, fsize); gzclose(in); if (len != fsize) return false; wordlist.resize(wc+1); gchar *p1 = idxdatabuf; guint32 i; for (i=0; i<wc; i++) { wordlist[i] = p1; p1 += strlen(p1) +1 + 2*sizeof(guint32); } wordlist[wc] = p1; return true;}const gchar *wordlist_index::get_key(glong idx){ return wordlist[idx];}void wordlist_index::get_data(glong idx){ gchar *p1 = wordlist[idx]+strlen(wordlist[idx])+sizeof(gchar); wordentry_offset = g_ntohl(*reinterpret_cast<guint32 *>(p1)); p1 += sizeof(guint32); wordentry_size = g_ntohl(*reinterpret_cast<guint32 *>(p1));}const gchar *wordlist_index::get_key_and_data(glong idx){ get_data(idx); return get_key(idx);}bool wordlist_index::lookup(const char *str, glong &idx){ bool bFound=false; glong iTo=wordlist.size()-2; if (stardict_strcmp(str, get_key(0))<0) { idx = 0; } else if (stardict_strcmp(str, get_key(iTo)) >0) { idx = INVALID_INDEX; } else { glong iThisIndex=0; glong iFrom=0; gint cmpint; while (iFrom<=iTo) { iThisIndex=(iFrom+iTo)/2; cmpint = stardict_strcmp(str, get_key(iThisIndex)); if (cmpint>0) iFrom=iThisIndex+1; else if (cmpint<0) iTo=iThisIndex-1; else { bFound=true; break; } } if (!bFound) idx = iFrom; //next else idx = iThisIndex; } return bFound;}//===================================================================bool Dict::load(const std::string& ifofilename){ gulong idxfilesize; if (!load_ifofile(ifofilename, idxfilesize)) return false; std::string fullfilename(ifofilename); fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "dict.dz"); if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { dictdzfile.reset(new dictData); if (!dictdzfile->open(fullfilename, 0)) { //g_print("open file %s failed!\n",fullfilename); return false; } } else { fullfilename.erase(fullfilename.length()-sizeof(".dz")+1, sizeof(".dz")-1); dictfile = fopen(fullfilename.c_str(),"rb"); if (!dictfile) { //g_print("open file %s failed!\n",fullfilename); return false; } } fullfilename=ifofilename; fullfilename.replace(fullfilename.length()-sizeof("ifo")+1, sizeof("ifo")-1, "idx.gz"); if (g_file_test(fullfilename.c_str(), G_FILE_TEST_EXISTS)) { idx_file.reset(new wordlist_index); } else { fullfilename.erase(fullfilename.length()-sizeof(".gz")+1, sizeof(".gz")-1); idx_file.reset(new offset_index); } if (!idx_file->load(fullfilename, wordcount, idxfilesize)) return false; //g_print("bookname: %s , wordcount %lu\n", bookname.c_str(), narticles()); return true;}bool Dict::load_ifofile(const std::string& ifofilename, gulong &idxfilesize){ DictInfo dict_info; if (!dict_info.load_from_ifo_file(ifofilename, false)) return false; if (dict_info.wordcount==0) return false; ifo_file_name=dict_info.ifo_file_name; wordcount=dict_info.wordcount; bookname=dict_info.bookname; idxfilesize=dict_info.index_file_size; sametypesequence=dict_info.sametypesequence; return true;}bool Dict::LookupWithRule(GPatternSpec *pspec, glong *aIndex, int iBuffLen){ int iIndexCount=0; for(guint32 i=0; i<narticles() && iIndexCount<iBuffLen-1; i++) if (g_pattern_match_string(pspec, get_key(i))) aIndex[iIndexCount++]=i; aIndex[iIndexCount]= -1; // -1 is the end. return (iIndexCount>0);}//===================================================================Libs::Libs(progress_func_t f){ progress_func=f; iMaxFuzzyDistance = MAX_FUZZY_DISTANCE; //need to read from cfg.}Libs::~Libs(){ for (std::vector<Dict *>::iterator p=oLib.begin(); p!=oLib.end(); ++p) delete *p;}void Libs::load_dict(const std::string& url){ Dict *lib=new Dict; if (lib->load(url)) oLib.push_back(lib); else delete lib;}class DictLoader {public: DictLoader(Libs& lib_): lib(lib_) {} void operator()(const std::string& url, bool disable) { if (!disable) lib.load_dict(url); }private: Libs& lib;};void Libs::load(const strlist_t& dicts_dirs, const strlist_t& order_list, const strlist_t& disable_list){ for_each_file(dicts_dirs, ".ifo", order_list, disable_list, DictLoader(*this));}class DictReLoader {public: DictReLoader(std::vector<Dict *> &p, std::vector<Dict *> &f, Libs& lib_) : prev(p), future(f), lib(lib_) { } void operator()(const std::string& url, bool disable) { if (!disable) { Dict *dict=find(url); if (dict) future.push_back(dict); else lib.load_dict(url); } }private: std::vector<Dict *> &prev; std::vector<Dict *> &future; Libs& lib; Dict *find(const std::string& url) { std::vector<Dict *>::iterator it; for (it=prev.begin(); it!=prev.end(); ++it) if ((*it)->ifofilename()==url) break; if (it!=prev.end()) { Dict *res=*it; prev.erase(it); return res; } return NULL; }};void Libs::reload(const strlist_t& dicts_dirs, const strlist_t& order_list, const strlist_t& disable_list){ std::vector<Dict *> prev(oLib); oLib.clear(); for_each_file(dicts_dirs, ".ifo", order_list, disable_list, DictReLoader(prev, oLib, *this)); for (std::vector<Dict *>::iterator it=prev.begin(); it!=prev.end(); ++it) delete *it;} const gchar *Libs::poGetCurrentWord(glong * iCurrent){ const gchar *poCurrentWord = NULL; const gchar *word; for (std::vector<Dict *>::size_type iLib=0; iLib<oLib.size(); iLib++) { if (iCurrent[iLib]==INVALID_INDEX) continue; if ( iCurrent[iLib]>=narticles(iLib) || iCurrent[iLib]<0) continue; if ( poCurrentWord == NULL ) { poCurrentWord = poGetWord(iCurrent[iLib],iLib); } else { word = poGetWord(iCurrent[iLib],iLib); if (stardict_strcmp(poCurrentWord, word) > 0 ) poCurrentWord = word; } } return poCurrentWord;}const gchar *Libs::poGetNextWord(const gchar *sWord, glong *iCurrent){ // the input can be: // (word,iCurrent),read word,write iNext to iCurrent,and return next word. used by TopWin::NextCallback(); // (NULL,iCurrent),read iCurrent,write iNext to iCurrent,and return next word. used by AppCore::ListWords(); const gchar *poCurrentWord = NULL; std::vector<Dict *>::size_type iCurrentLib=0; const gchar *word; for (std::vector<Dict *>::size_type iLib=0;iLib<oLib.size();iLib++) { if (sWord) oLib[iLib]->Lookup(sWord, iCurrent[iLib]); if (iCurrent[iLib]==INVALID_INDEX) continue; if (iCurrent[iLib]>=narticles(iLib) || iCurrent[iLib]<0) continue; if (poCurrentWord == NULL ) { poCurrentWord = poGetWord(iCurrent[iLib],iLib); iCurrentLib = iLib; } else { word = poGetWord(iCurrent[iLib],iLib); if (stardict_strcmp(poCurrentWord, word) > 0 ) { poCurrentWord = word; iCurrentLib = iLib; } } } if (poCurrentWord) { iCurrent[iCurrentLib]++; for (std::vector<Dict *>::size_type iLib=0;iLib<oLib.size();iLib++) { if (iLib == iCurrentLib) continue; if (iCurrent[iLib]==INVALID_INDEX) continue; if ( iCurrent[iLib]>=narticles(iLib) || iCurrent[iLib]<0) continue; if (strcmp(poCurrentWord, poGetWord(iCurrent[iLib],iLib)) == 0 ) iCurrent[iLib]++; } poCurrentWord = poGetCurrentWord(iCurrent); } return poCurrentWord;}const gchar *Libs::poGetPreWord(glong * iCurrent){ // used by TopWin::PreviousCallback(); the iCurrent is cached by AppCore::TopWinWordChange(); const gchar *poCurrentWord = NULL; std::vector<Dict *>::size_type iCurrentLib=0; const gchar *word; for (std::vector<Dict *>::size_type iLib=0;iLib<oLib.size();iLib++) { if (iCurrent[iLib]==INVALID_INDEX) iCurrent[iLib]=narticles(iLib); else { if ( iCurrent[iLib]>narticles(iLib) || iCurrent[iLib]<=0) continue; } if ( poCurrentWord == NULL ) { poCurrentWord = poGetWord(iCurrent[iLib]-1,iLib); iCurrentLib = iLib; } else { word = poGetWord(iCurrent[iLib]-1,iLib); if (stardict_strcmp(poCurrentWord, word) < 0 ) { poCurrentWord = word; iCurrentLib = iLib; } } } if (poCurrentWord) { iCurrent[iCurrentLib]--; for (std::vector<Dict *>::size_type iLib=0;iLib<oLib.size();iLib++) { if (iLib == iCurrentLib) continue; if (iCurrent[iLib]>narticles(iLib) || iCurrent[iLib]<=0) continue; if (strcmp(poCurrentWord, poGetWord(iCurrent[iLib]-1,iLib)) == 0) { iCurrent[iLib]--; } else { if (iCurrent[iLib]==narticles(iLib)) iCurrent[iLib]=INVALID_INDEX; } } } return poCurrentWord;}bool Libs::LookupSimilarWord(const gchar* sWord, glong & iWordIndex, int iLib){ glong iIndex; bool bFound=false; gchar *casestr; if (!bFound) { // to lower case. casestr = g_utf8_strdown(sWord, -1); if (strcmp(casestr, sWord)) { if(oLib[iLib]->Lookup(casestr, iIndex)) bFound=true; } g_free(casestr); // to upper case. if (!bFound) { casestr = g_utf8_strup(sWord, -1); if (strcmp(casestr, sWord)) { if(oLib[iLib]->Lookup(casestr, iIndex)) bFound=true; } g_free(casestr); } // Upper the first character and lower others. if (!bFound) { gchar *nextchar = g_utf8_next_char(sWord); gchar *firstchar = g_utf8_strup(sWord, nextchar - sWord); nextchar = g_utf8_strdown(nextchar, -1); casestr = g_strdup_printf("%s%s", firstchar, nextchar); g_free(firstchar); g_free(nextchar); if (strcmp(casestr, sWord)) { if(oLib[iLib]->Lookup(casestr, iIndex))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -