From 0912df7cb5ad2f18cf75be132dead19fca10cf91 Mon Sep 17 00:00:00 2001 From: Abs62 Date: Thu, 22 Jan 2015 18:17:05 +0300 Subject: [PATCH] Add SLOB dictionaries support --- README.md | 2 +- decompress.cc | 21 +- decompress.hh | 3 +- goldendict.pro | 7 +- help/gdhelp_en.qch | Bin 680960 -> 680960 bytes help/gdhelp_ru.qch | Bin 789504 -> 790528 bytes icons/icon32_slob.png | Bin 0 -> 1625 bytes loaddictionaries.cc | 10 +- preferences.cc | 9 + preferences.ui | 11 +- resources.qrc | 1 + slob.cc | 1312 +++++++++++++++++++++++++++++++++++++++++ slob.hh | 24 + 13 files changed, 1391 insertions(+), 9 deletions(-) create mode 100644 icons/icon32_slob.png create mode 100644 slob.cc create mode 100644 slob.hh diff --git a/README.md b/README.md index 1c618d94..42b62302 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Alternatively, you might want to load `goldendict.pro` file from within Qt Creat ### Building with Zim dictionaries support -To add Zim format support you need at first install lzma-dev package: +To add Zim and Slob formats support you need at first install lzma-dev package: sudo apt-get liblzma-dev diff --git a/decompress.cc b/decompress.cc index 9ca0fff2..3a66ef1d 100644 --- a/decompress.cc +++ b/decompress.cc @@ -82,7 +82,8 @@ int res; #define BUFSIZE 0xFFFF -string decompressLzma2( const char * bufptr, unsigned length ) +string decompressLzma2( const char * bufptr, unsigned length, + bool raw_decoder ) { string str; lzma_ret res; @@ -92,9 +93,25 @@ char buf[BUFSIZE]; strm.next_in = reinterpret_cast< const uint8_t * >( bufptr ); strm.avail_in = length; + lzma_options_lzma opt; + lzma_filter filters[ 2 ]; + + if( raw_decoder ) + { + lzma_lzma_preset(&opt, LZMA_PRESET_DEFAULT); + + filters[ 0 ].id = LZMA_FILTER_LZMA2; + filters[ 0 ].options = &opt; + filters[ 1 ].id = LZMA_VLI_UNKNOWN; + } + while( 1 ) { - res = lzma_stream_decoder( &strm, UINT64_MAX, 0 ); + if( raw_decoder ) + res = lzma_raw_decoder( &strm, filters ); + else + res = lzma_stream_decoder( &strm, UINT64_MAX, 0 ); + if( res != LZMA_OK ) break; diff --git a/decompress.hh b/decompress.hh index f0d00c79..c5b6254b 100644 --- a/decompress.hh +++ b/decompress.hh @@ -14,7 +14,8 @@ string decompressBzip2( const char * bufptr, unsigned length ); #ifdef MAKE_ZIM_SUPPORT -string decompressLzma2( const char * bufptr, unsigned length ); +string decompressLzma2( const char * bufptr, unsigned length, + bool raw_decoder = false ); #endif diff --git a/goldendict.pro b/goldendict.pro index 44cede74..f1dc509d 100644 --- a/goldendict.pro +++ b/goldendict.pro @@ -293,7 +293,8 @@ HEADERS += folding.hh \ fulltextsearch.hh \ ftshelpers.hh \ dictserver.hh \ - helpwindow.hh + helpwindow.hh \ + slob.hh FORMS += groups.ui \ dictgroupwidget.ui \ @@ -311,6 +312,7 @@ FORMS += groups.ui \ dictheadwords.ui \ authentication.ui \ fulltextsearch.ui + SOURCES += folding.cc \ main.cc \ dictionary.cc \ @@ -414,7 +416,8 @@ SOURCES += folding.cc \ fulltextsearch.cc \ ftshelpers.cc \ dictserver.cc \ - helpwindow.cc + helpwindow.cc \ + slob.cc win32 { FORMS += texttospeechsource.ui diff --git a/help/gdhelp_en.qch b/help/gdhelp_en.qch index cc76900b4f3c2bcb62900344e00372ce99649913..29d245eaf4ff7daf3fbc3abbee6f4e542d08eb5b 100644 GIT binary patch delta 20881 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∋gAbrw3Pda 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 aSQ!`gU3!xS&u$8 z)!SJOra*b+ac<;zeS(BX*mnm49GonB7ZR4|Vhcx>o&qeLy7r(EF+Cmo!2q zfD5-_cjv&Hi4V#uQENUu2NgBP5><91#1@ArFCC`1fT*j+`4J zX|##7<-NIZkis0ctU!u3bgI=YWY;ed*p;hl#8spmcqjabp*pDtP4PWHGz$>!xD(Ar z8L>;_v=CDL5mF;W2X-MKq@P8YcTxYLM~UJ+j!zG49w<}f(wb64$wbMfLdX?tAvSf2 z8XZiD**t?-dECBsc`)(8CPLCkHEM4x{dQRp9x{2K*pwaWD)7BM$^q=i{HFX2dSkCb zn6Ui0YybTGocf8Ysqgm$HWfN6^`YK@cH@eVagUdR@rxE5ACXEwm6h`+e1YuU-k|SP+D7ivaRN(J-e&GIx;aP_@LzEGi9FzbHvgU?d4$Bg8e+Dq@HEntov% z{CQ93VJAY?y&wuuO)*2|2empj?H-^g4?jPeOFMthQSArOV73kj{&;EscmaV+0DlAk9{)qp zIWPb9AD2KscH=F zB{`^tvA0&&S(fp;rE-$)Acycbeu?L8b}mr&vfi_>Jk8;8aksbZYQ!08lUgK>d!V(Y>%3A<}l9oPnHf3 zL5V?X#>wx<&mQM+8lqBGq-QUmyYz|Lk4mPanLLBFeuGbm&~adIr3(yOTR_7`FMbk$ zcSc4=3dAWdnf*;#Eg9RVBt<-U4zqCfZ^m;g)#H5sB9yYW|U==xs;n&bH6j4Pq%jTAB!@#uk4l5jy@ zgkMysy4Cpy`3E0F@~+A6481D#|9Rr6p!)&|CUYz8LcDE;4@84pu$2Mci9hx*8R2Q1?d);-rbnB2o=`gc?9gy4av-Z-w90C~){jrH2h z>{5f2o>Vz2918?5)2v0S2vM_WfQ!a&a;?fcnmZyqDLi9(lKKH%lmy&$U=rh{{?S8< z31{wjas*XyD^npUUv6q9Q(;&6l95RRC1A!S;sodVD-vm#*h7qQd|a)jCHCijrl2!I z=KS>62gi!!hnrea^YpypzykueNCv24Ba0{GxlJ>?V*a?K9_84Xl(6{y+3_k|0Xhj zq>TS!(Xo^&gvEfi#ehN5Lni^il0c9FN&f*QgeJlT2^^4U0|3B8dFG^QOgU^xpznOp zm4zs`1WZ&WFq%lJ#B82}No}RKc7QRES4(52g_G^N%yqtO9E}gGcKkD52c{TkVpD$B4k>Uv((ndbw34srH(HIsRIY1A~ z(8rZc+K=zY&2%Ijzr~l zu)-e`A`e=VB#5C=C9+b}rh@TN)Gh4iPgS~yy3E`gnp+`jYSSl78>?Go6Dt?8OAY?( z!5lrN@TknO12Hfu4SCT7RSeGmnY>Yp4m0);fsg|i8a3`aDB?F+PY{JRtG5lFclC1PE+KoA7a<|MDibyGH&UwqcP1iX-`n3}l_S#(rw>fUvK` zj3~MeUWaj2UU!lIZRh%A#ssXCejfbFD);B4VbMeAw_a6x@*p`zV6T*-nXH@w@nZ(< z+Ty6?86wiD$xY}l=sR@YrikJuJv*H%*O53RVE_h81Jv0?+jYa?U58&9CmyBhZ3 zx&6cj`z$aG1xr?+T}SKUh<91voBB)u0w5HfAwA=ji<_5HgY z7yQ$8Yqt4RRvx(v;})NoYn%qc00KEK@D>>*D{simY-vV(;Rku1!l8~ew&6W1A@TRZ zPX@@rj5Y!P@!4(*x}U{kzRUUeLG=KCo;z_aCts4M_&2XaK-{CCdSL~5G{TatOz#mA zG^<^adwxEfndU+-hrB;-HfihZo8kIr@R!&3@W!7BIm^s(c`p~nf@3C5dy3y9LN1iU zPfuR2z%mBCuh^V_kf}JuDY2WcS@ptY1d>2On3Uw6*s1t70r#7Sdk%A|?m}0Orwyd3 z7Cj;4^Yr*^^Vh3{g)sQt_9FCu+%)xKr>3Sq3|veNr4;p2IygRf1dukHq&jAuy8C7Tu3j^JQ1q)t4;FuA+%XYX zhzS`|$z`aI818d4>Jrm7uxqb-3UyK;1AX^SiIpS4v}&+ntmEtN-&a!U;v%N#J=FbFns=FZ4R*MRONGO*<% z3ZB(G5+l=!Lc_Q7XlWj#KcJE!fl*x_OMEC z3egK6cuPT2=`5JgsTWxT1q{Oxw!k_H1etIg@@jLMVZ7Kjbw-VKg)|Nm;s-SHu&pa^B29tAY94m`Cc3ZTFM}s@)zfU;4qO5s8TL{XqQ=4M;+Mdt|Vkz$DDI zl5pALnNJrPP8^6JZLd9cW-{3E34xyeLqWZ!3Pk0{zgtRNT%co~K`cFCP~lNtlmSQa zpnwuAiqx#nqJref|+b)f^plrG?{*QvX%CIQL$k2`pG9&V}tLx&Sz}W7(O0? z#k{BFC+C_j7#818!(WULmS_S!i z$68V_kLXhN9u98u!)~=;qLi;8QzNe4x?Ht+0sdTCm`FKM1n3**Z&f2%^b-5-Q<`&1 zgbiis&n(1qphq1g{A7V1Ky#sd{JBnOz4<80liMnGju$|Z$)Ng$&C75OeikiZ_k+ijHwoQ&&5)$LvRl*Q%TYAvaQio}hDtLG9Qzb;@QzPgl439_OErN9iZ z#i0#xry9i4WA^b>_$Rhbv*24*{PxPRe(l42x3d~Xh zO>9G@&Vvkq*v@|^u1H>sqr>GW0qXsjyv-Exr%4id{}C}6k8{|`FwakYM(A8YyHc>p zY2?5;Ts5(Y1DBvIt}Kz4LUe}(_VR<+p3Q<5jr65)_*&@bvX(^(Ile;t{y#z+dbBM_ zPn#WK35z0Z2=JoZ&+#Mo)=jrVL1p-QXr#&GBM!MhY|u_YH`i>Hi0LVIQ!A9u*JW>~ zq-k7U-OGDzM(_N^1FqV^EP&grNy9$YhAD`^`zHjsuG+AgC3l8qb7>_}P=1Y8R!7#$ z>~ z2`DU9PF%;BSVW>o+-V%QJa+4mgz5YNK}FAKY4jCht;!IW&Glm>6Ue3mBVjUi`?MHkSv5SRj42N zB#DpllCt{igBr%`F2x3JP9xLi?jwixj}D=LYzof|-hSn>>=k?Ix@9;5uH6^0E1qf$|p~hV6w|Cl7kK1SeMXP!sc@73O z^)QMudNgWDDGq%mM1U;)`zcgBW}H8d-$5hgln#%NbRNQkf|X&~D7bCr=yIW`%()Ih zvBI_(LS3BLKg00bZm00<`rasktsk--6VW&i+9l4s6|j;Eh>FJy4q$KJs4p8tWir<|sr_(%pZ?on+-}f?|BWXQ4N>6lXV-e4ZgTNk{L67Lv zH<+X7OhuRUnD|G_F(8+prOoO0&ZQkm$j7Zei`V5TI@|BIuaor@d&N1q=6ZqbPQU0t zfICwS23(=N;m@|wm!UpHrlNurfG<=7;8t1srL3U65B2*#Rc0 zMn&-fiBsuJk8Y5=uBFEXb--5fV2XOBu(OUgwwT!T-g#qciZgyadPaF{Rey>nT4M)` z)(f1PfjxQb!gkb6>StOydhXT%I4aCx9&W+r1wbc$wg*;^%CoTjg7@Edh_tE1&j#$Y zo==4SWA9XJZt(6Q0bKKi#|k`-gK~^|@owc`n~}K6bi6TK#hB6k(ZDXJH)flWXV2u( z_+qdQyqkdNS}VuxQ`WhLdzHoqhH9@;7&2&0S%Zdsufjo*c|B@9XwYDW#esj0j7M19B3#}eU9S7(aM72_c%>ZsCYqk{3p6XmM2GTG$p^*5 zfd~N$`^$O(Nr^;_#5u3oAe!-~IU5@*EBFCM{u5je#h4#vztbBi!7+h}{Ps=t`(FX1 zv*zeLmW_YsjD8T{Ascj`V83gEHvq)&-`4+ZdLtLlVn4msk8dmWaO`8PkbIjXw+hyn z=}YSm5ionh@C=H$sCJLCPo&>u;;_)-4Q)bpU?c5E_TowMd`4j5#EvoKVnMFv z$9q}-FeQZSl-y`loEo_4%;L8^^^xy4nk~;hbv9tY;9!28c?%b6)PyArN2IDJ70<=+ z$x_dT`YO>wP%j4Ro|uy)7%J3Fc4JCF9dLEf70Q^goQQIsPuHanQ-RaBe^PEVh6gvCg9o)VaAS;=IrZAGkdY?t$&{Ky}>f~<%Gez0&%;?tFH zH^U-kmM@b>-Y-l$Ke*w<0vskOM@+V-XfTdJcP*jUCm*iL=;F`^}cp5D_rX`IsOjChF-2uJ4f? z{%GDE>~zU-Uwy7|xF6&!WrNZU7D#JdHUo0)9MS*fe~_e3f)+t42ka`&d3Mep@+!0w zZNqQy5YDv>N~i>z>39{|ao2tR*CnatuU)&-k-0`jPNq;gwv5C}AVrC-ND)Fwy}yIf zoe&Wt44H{z47e5TPPQzH$w}$sgnDc|(5_0^X$^bmY89W-uja&`Gw=Y`xL=McR2x^? zpkah1wZ^T$uQLoDT$m_PisAkHGE=(b`i3AEh8 z3TRakK$$`?exuod7Guxk=8 zM=R{1Kert}o6aAVrtb+upv`fGYSJesq06Q`?nuh7Xh^C+ZwZ1Vdyt1ML!5T1{-jtb z6}>#Ip%_aFKl_I!ednibYcFG+A-7XG{cIXfluA?99(H6B9?)v)X2BDip$mMc)b&ZQ zIwK8aqERM`ss2vI*#>2E~fvTDdokX<>D2o1ESf;D%xD7CMm)3jueoIDXSSHVx)%P zm^QwIkv#plT@Or*Cb*JhM`OHY>i1#`RiO3AgxYsm#fjDP-o&PXJ9GQ(2+)&u}K(0Gz4{{4M1`Eo@C zPVBeUZ(l|Z3mWdxqhM3d93{-A6|b~=p+h7_Tc{yKce5xd=JJ+)u)q{1vQyAWT7(Yy z{LW1&0n#h0tgNEMd6OzQjBNSNIyu?)zV1^FUv)t9zmiK3bne3*O7*p;4<6wSTd*Bq zFi)b4YC`3>sb6(Qn2%1CXJaRh7<&SO?j%HFXAn*{_j~8BGmC(h@eVQ{l1WlB&9)x8 z35?S`tdpnJFPV~dWj;b@ZW90TO&VQ+9CJ8Lk|#B5gv0KPfu}LA&sKErnQ#z-k9Ri7 zJtwPa1#fa94i)ugV`^0iME+S{YNIINUpRqaQF{^)cWS#_P9XSM^{vi^Eq923Y%j|+ zyQgc|yj=do2`TzqIK9i#Q*HN<5W%JI&WVL7*kOKhtlY&Fc(~j{LbyccE&8H{W5!?U z+g>@9CN~i%S)e;U=|Q-@$L;x?wq~84w4mh#6}>J{;wU~amF))gG;tC zgC~Q*VxWKn3K#(Z46^WCHt_abHVDfU;6mpOIvWiBpW|N6#E^Kj%9uNUAxO{M8~*xh zjzkDP`Nnx5B+sAh`W?Q59tc(bpo5RROZ(yeI?u;Vna+P{FOHrKm)9O#uaC&h`OFrA zC~P05o=yeeYbd)e^}G6iuzJ$g@V!T!O-JuDFn$nwx^{ZOc!Ru~PB^-=MeAJ_fm&x~ z)4cIoxDDNqzATfpXk)Z!jn(WumeTtK&@fj zTtw^LHnmP&b3_st90&I*KxiUr>J-}5`nV`VU}i-0WX6r9)`=!3`& zVH6+>SaJ2#MiQ=}{+pZvOYYd&;!4l=`(?%F3Oa9z*>2@2ZK%1J(*rLh&~?cpQoAtl z7t(i~(lT{F-=!ZMp9hXAxKN{_`S2Fp0yW^2v*+v%iZIZ3b^lsE0b(4kr4MB2W0D;j z%K+?N28D7@FQC7*0)eJPr3U*!JOk-Tv0wy(nBZ`i^1oM^(@}*=?YZSh5srE6r#bi< zwuRGi{cjuxPl9^@;s6c+LRs4n7pr@MIJJBLeo}9f8Qpt&mtDO#oDz>4GPI+qO!%>U z#izk(qHp%@bPrPtj}X=o8(Sm$K-F;=Vm2hRYONjSTVk1SBMavy*p1I`Bwp$QQnT25 zW_@0^SvqyKK+S~JIITY2Uk0@tSBbL+hu#~>#uG?(n44v2tPnwg(B%&bjSWgc+HkUP zMLH8R1sgJhW~&qR_eFjI^OeFR@&}BsWh9%+~H$tlQr?g z{H;q~cY<83*{Tr)TE(`YRtP%&A#I8zwvuX@Z~>(O-`GU`i7eaJhq|u=op38j>kkyi zi+L`A(s86vA1`Nyxib_SU^qPrB!J3%3S+t~I?q$tdN05k(bJYo;NyR0WF%KqE7S|S*l~=&F z!z7coges(D<*nsqe(*9)nBuQq zQW?HsF7I2U2p~B(a-g8SNdfs4m5$+M!J_^;%zz;f&zVz*?5e4ohjPPi9$I59XZE*Rt--w%J}5GvJ2<=lot;K(oTh#Kd|!`ms!xkh@shm55uvtnMZ zg)XVO@#b~!lNgjsU<%b7Uj^CeKfpfJyQ$>E^b~&H#{!}6% z?nEAn>so%|0B6pK0>iau7SrG#`zF$!n$ltu`B9WO|Cu+hL}~dsK4<|V@6_u)GoY_v zpE=G&^fET1?`UU(AQ(G_Yjo+n_RK5hk+<*@eR^V~qxkScrt-%LCU-1kqq9%a@FpKtOHXs@ zev!r^KBYQo6h%S}Y-3hIodz*y1+e!!Rj)?Bk(;<9$mwDT(H0?Wftb_Vnx$GzC@=qn zLHCn@l7XtP7GdlrSV=lZtL@{QUQ_^++!!|eFh%ESm1@G&jiA*uOXV{UuBD?-#d27C z+2nK>KC~B<=bQFZa%2K$DQ#W*c=W3)ZtGT(T+v}ORCUptcY%JU&{{Rt1(bz1u3c@^ zl0Vqw5&g1jw6E!Wx}l@>mMCX;o~}HF)HG+0Qep3jnce83@ z+SD^kJ=@dltU(vEagASFLqZO=yDayg(UeMk1?@37?i6a?Ziwz z0e@eu%{slFr`>HLrpyw3ZF=DJTGHKg4xPL=q0{We2-{U*xZpefpk%%`3=P=|6~$<; zi3KmViDSD&S~NzN+vY)oz^dWxN_5^eeSs=zr~ht*^J_=%&3=c zIhOjk-97c5jf0C1+2@5xtWDk1+)D533}NShas<+Hnz^9y^Z7;%*;!!V$~++a5Hr>+ zg>vA(Jm9Xik`!KE{qG@XEDxOUUL&1u*7u-{*Z-i12ZaeHy<4?wAWB00)Q{2B=H!qT z!002Sb6GVMh_YVt+NuV|tS~7Dk)@xk*cZShFFYbm-~;-brGzH=pmA1V+T4F4^$}2M5b~1NkVXur`6B&##oHYxL=|V1cSGk74&Nw5M z%E+8rT~EsQc4w->^knMlR~~1l-!Zp&+rpa{u|`taKeBj?TVGe{@@&N~F|H@U$fDL>)}q^w=Flm&t!pf9*?jyKLZ!Wi7Lja*23#)_@;N8$X?fDWX>7$scj7jo?L@bqmH;jFFD^&fF1Ha+?ItjJXxOkx29p74nVTQqcb( zZY!*`>#1rGZT?j?(V({UYRZ-<7V4KqOYj2o%j+m?1^1obly&_ zWeL9pBA(U!?3DED6R$T}t8Ct%Xa6LTt|-I>V5}%GDlW5NcRG5QL%r;ZjL-X=AqAHl z`(4ntDDDm+N>Zt1Eml-Y`(2#1|2_bVel4Sor!oAT#01JCysMK_yZ5`lMr{;2KotT( zmHye{3ugbjk?4H6Z4k3LtiiALA!*&JDNZl@5HsR4)vsfIup` z@!8g$;gEz8E~y1SV=q4O6rRHAErGZ=oo7+s5f80>X>g5Wi`k@nRy~YFfm2TR^}S9` zUp9lCN6i5P=YfzldAz`NG~f)(uEYV7i=*fPi)t57;-JmTbSKx&_rsWX(2KiNjT9zK zwMc}XzZBqj>U$D`wws0bU}u*jGvF@|st;U8CO1?2#??1YnXDa2wl) z_bu&^dt)5idTBXxsxpjQV>f`No6-)+EnJbcJKeo}1L-;K&_s=-gJBQz{IIKclPP_R zi$bRh+Vc8iLz42Wji@to@eo$A*2L}gis1DYNXIU*Ru-uV?%653E5_8NNl^}H5z|kc zS8$+Qq07CcaWShtFO1ASUm4xk_s@-fGKS{MR&@dabCgslUb>Ale=31tP~oXR#TYP{ z_iS+mB@;G~#bTFnxoXX++LHAw5YZ7+$%ZZf`I;I z=e?>QjhTpornu58#F+r&&Jt=A@=4k zCs?+Eyzyc4^tNK}{HxP4dx)OZ&SL2#XMklaJN!=onE10Ptc9zoiD0ZCjko7%}{ou?RIwW#XOnwqai-&sMNyyzXaRxbz{X@|4Jl? zMX$`F_?V~@#}&%`xrv^ye_P*k6L*T^B_~Ls3yOI&gl~eCAEj3Rd#(iX0swhwMghMD z0T%zp00;cB0ss_XJaew~wp>*I-~i9+*J;xOD=A1~1}WRJ0WkCA6lghxev{OTjkS^V zIMSyNVfN4^WzNJC2{kCgg_3@pW^>+;dGuOMZR=ieRQ^X{^)Wx zn$I-r_Zk=gGm@%PnowQ3bo)(1f*Rer`H<=QJ{F5tiFZ`_+nj{|#rd6bHfhlKp?`ul zR{F&D4ZKDo8em*{AvXe^Sy@R#m_Cp`i{30{YfeG(^y7p`m7UK|I`WjHIt80UajvIJ z1Juix&Y?@UQK(GI>2AFu7mE{|A-9>G(ZRL!lRd_4POVbS)~=ix{ual@Nsx;Q{VY<| z`)+AU>Plle6JwQrT!U>bV)H4~oBmb$*Z|`!fuE1OtC+W?e_iM1=tJPRw)L1*)O~S1 z9M0?Oyk+azy<|=3EhdKrS2`y?N;6AdWz(uFUf%VWyEUW&BrvH?uQdxf8pG0{FOhL> zZkU)#+>kiXdiUxWu>EnSV#UTp_or?q43^RY(I>wsY-&^wTSZ6cZc}A@!fD9?3HY z1PS!+tNnTh0t*yKh>=@5WC~@bRteQ=)%~}J7I^A^$j89oNo42SYw&$=!d5}s0(`qz z!kSwfbPj!W@Y0WneSq}+5r3P)3IN>I+N{#bL|7W~?5m~P)WA0O_ZzMoGA?It6@A8X z6Q@x8o=SI^76=uBK$JKlmZFb}b^)YmXlT^ri%L`%D(V5V8KB1Kh7$ahbO3kmB@cm0 zdYxNU*BH6a-X&%w+YiQ~yh@FR;*t|!6wuEwYE}MhX;tegx*3Adr~_`szbYmh?oFH3 z*AXr-ob<;uIWQ&{&z_kR79c4>s_#5;p73%r$(B|%-)j|I_i`=^d6wFZ;_e=E6`lvs zR^32)8Zd!h;PN<_xmpBataUP#_)1dDXX=rrP*w7ssk#yGtC+kKphU>R#%TXIF9%6V z`@vJ^0v$&YUA=vc4dO6|v)1g$)UWUXVjMF@=@ zS@aaPcMKV{RDj_lA_Yn=hCSFC%Vh{;ah5$Vf#m{8vPW7Xv7Kiknys^4=J~h(2HpTR zdpImlvG_+;jA$Wp`AD1P3@_{YL{wdB(1e=lTw<^#J%2}^(fs}O-Em3`#?Ndi)J>D+ zj#3kTY8f!=$9_@3CEn30RNk?|kq+%)$CxRfuC+g5%V*jA3%qxj8;00R4<}2o=y=KNJE(u~DNc=dx7^K&qB5kCth@IJlYr+W=?b}bBvWw6t zb{*IGAU#WjLlP+9-|vn>+xmw->^c*#$XWqds{$s*&4oqIMsUb!84@SzfSnc-J#gvq zxETsv3Zcl}q5GV##w1f69u0Rj6w+X2>%UNOrOMzviXaNo@t$dKYSRW^>G5bGnOUI< zsTDyYGe6cJ?YuKR@uSw>pU770Mn7NTiPQr8 z=aXzz^o*ww#^e6#p16qRh46@D?m^1lJDlJDBJ(2={W1h0kXLghXi8KkYGpG13j+3NI@^mWQP z*>Zx#iYGD&Km7at=&WH!kD$O}r4X*l6Vuh;&zL@K3X9+3t4Ual{x z2IaeDo1k!ltNw{zQ|`eFIA5&?Nh^DM`%{!Ar1xgikfHk!a>9s-N+_*ye;>Qj&t`u%;Psnvu` z0p5O{)-(9@d+X2;n1=7%`o!r2+%WWaU!tPs3?^JJ9U#jwNQA}Po@gZUawZeh|Y z2!qO`X@n^Ah(R6!XK8kbOZ5PE%3!0c)O`KR=WBBLC1psMv zFA{FLpCY;#U77Hfff3dm44i5l@=eA~eGyd1ti`Q{sK!N{Lpx^qF8)Gwa4UA%zoCrP z$xB@hBy@;(mnjj|UxYN;R}KhCvMlEwdRUdAhH^4!3n6oKzhb1vkRs?lwb@^&!b^>E*I)T>2MlCCzDRmVWo zqr>%h>>cI4kU43HbqIC>P9b|Xj#N~~kiCPoI-76sJXoSy-tDk+gJ?=TJ$u%UusTu| zM+2#(>jIboU%fP86#^qYQ4q+W1w!S_gkpA31s-?(lc9tZDgIdt!~Q1kVPKYT(qW^s zT&P$d(o-pbl!3O29hC+DLer+4eb{HUHIk#udU;Q&{3o}a{2q>wmy+ceMKfavV&pV zaB$tlcBh)?PbL(^rr@*uJTSzh1d`xh=Xr7sE4}Kw=Ik_XE2Z+7U>cMRxUqI0B zMgSxu%OsqpL0Dbbz&}`3aFw;Y&lP8BPgGY$#()2!SN#_GJDyzoeUiE%A4!>ekr7d& z3d42uOO#g_&w`Q+p9dF$ipDt7E477l+3I~97~2fOM0WKvzfK;dTpkgKXlP$C_is+w ztO&f4G9+HON8jz_1o$EIF)i=^q^=LY{nX`a@1P0|x{>zB@3Vh&`H+O|y8E9l(tCPG zM*&#qYi3p89Ss0_mTK+I|Homjy#sFdM%z6;Oi_(VO9@d z+f*3c!6hEX2q6%aALr5kSN#5Fr+WfR{P}l7V^R8pws^_Oi;iQ07L|^ z^j~WDlRoDJ=>%lM0S9FLx43{j_uqz(=6?nzb!7j!dTu*9xxs&&wY05~*XT*V6J;ui zF$z=)V?9iD?N(=RPXDFxB0!Xm1PDntf4{ZQPxc*!3alDF1kkZ~d z%gKDRIL*#%?yOva(52U{)2!t6vgh;BM@v(!$-*d4StA6_^ksL}%43ZEuAlK`=l^&c z_9?nL`W%+L-TpDsvBJ^+c{**Wo131EnA^?&y6X!7y^p-ri0Z4`^C^I-z4~Z{(KpoA zo~YZN*4RlB_-O2t(HWDbf6uztqO^T4gS52+AHZi46d8QY{pFF8BN0w%7u?V#oAuX^ zj3CVzb1Vcn&Y;ytA|*SfqgO?L)_Pubq#Ku?sb8&~MO|g+HPf!)m)oKcWwPPKKQ+hn z_IPLb7d=2uB4xVCe67zly(!wFm6{c2^;Xk&i?&CzRemZn5Y0qHub<&~%1PgSxcmWp z&bx#0xDft0?`qQY^LCQV8}_O?U$}#i^LN)G2jy>|`{n@NR zROg9LK1JVFfVWWd?2N?B+$$LQk`}bHv#K);NtAmGv_xJ=tPa70K@>`(s_xu6G{-?{ zdQ5zQlTR!+&?;2+mkMDxZ@mR~qllw5<6`ELH9ze6O0}jBbrbq$jJ20|y9!wh{y~nm zc3dj(E>8p5&oW^vYG>Fm8VNH|dCG6AE(QNe9aCn=CEBaD$tZbzB?jx$5X3$`5b0J8@HuL)3na7^Fn>q1m!Fvn ze!@dS+5xRADMQGjj1dEwR#V1G!YMpc%*%%k%eglJ-KM(Y%_KqG)$;6BJo1vmLmm^Hfb^uzIB@T7L38-ec*+|uX8(H z`d=J$Pq+RPdMVVoup8aIAK~U;92&in6Ww52eO$( zI)DHf6}>^y?pLG_CFD=eI|?P&jf*QhL1|9(x$e>-E6@4Dvg?ueSxHz0Qi6}tS_V>= zvO0v1rp3t9hof?7URffDl1Vmn=~z#9ka@&*8279-pEvxzC;oJP`1w;Q+%K20#iI)C zPl|3uRdarP$KiVeAZr9=k+AbXe)y7=?>mcLaQcVLeU55fxALG-HXHPNSocpIfVi7D4BxgeW;3rp(qDoyaezS@7-)y93uhm+_ z<#uXM{IBo<&d4vA;q|lfamG`eOWx?{`0iUqY4(a*T5%|U;6APkdRZ8&d^Sv)hUSG7 zC&AwlC}`w**FSRUXp@Ok39uV~AX#Za`DtS#?PEG1)j`aO?N=j3!9=7hJ3M>ZM_VI{ z;|aW%{vOqmR&A@QK?)2^PDT5KYM5rHoxrWBy6D993Nr=<|5kH{mNX&_b(TU{NB9#Q zzV%>MkM&)?226%(iU}iiugzcXt!R&Xoug z!Eo!CUI|88$xkbd+ayLkXfCQ)*jCS+!^lbki=uJefI(_rB>YE}m(bPcC_DKMII1eA zlv(TD@oO|&A%f!Ct_zg$)@Aw8=eMy0JjvU^8OR)o4Up4$WPsGo==lWvpcOxMtf&~x zj#3+qNy4e%N}PgS0?rM+47Ks#;GTq+_ab~7W}Qc;(35i2dIPC{CPlT$UV;rPiP`#e z(e5N(0K-ulL&l5MYy4F}*@O8Z%95*=Wju%%bTX*rEFk5Ici0mMOXixI;`Mi$ML=ex z`=jh{1n?OhtqkH9!;(LBr6RI3M7Y~RNk=DDLUp%UH-^J$qfr-FI96YJnVD8EHKg&?fyKe-k#r!xi5Gw}Oq_(sD^g?uNQqRMXD{ zjpejnWVaXT-gKZ0Wp`L&cm4_bivLF_u$7+-KhH=l(6i^`xqHUXovHf^FKwOGrcIm1 zvUTH0T^{>Hq|_>Ht$8yTxDv0*)vDWBIqgGd$XM_1a~ns^Lkzqfl=KkP#nh2m>(4V> zeNJ7$xSuJn&fmi*5Zd;zu^3!<{$*$-LdT=vro7hP-oCW;crIhFZ}=s%C(O|7DQ8e- z$D7Q^D~?c;h~iXZXGuk!p|7R2?}7`^KnfQg ze)&|8I2%?aHO)K$-ipsOG-X}$HN$tCVaHM8J1Ki>G}z0h*oD=t}(#{Ndb!Yvrj_x|DsWuD%_<#|UmhSHEECARKKAXLyWhF{XWR3hd)~P3^IWbd(&G^(EhYJZz1PWc zL|md7vDfrwDs(R8MHWQ%A7>CaaYeI>nh7cjyp7a9ToggqxX(h;ggD4_cV!yDIhW68 zOFdH95?B7u2ZfsBk$ZVy{9|NHVY2Cel;pu=;=A6O^PhTG&~cALmFG@-hI`i)#*bsy z86;9;!*(s@Ym1l)hmqGK-aU--&JC}ZG}mz+8_`r|lihpv&i4MQ-0@V~<}k-8MbP~q z$f0SK-E5fh`sou+BC5qTPXUb_cn)DpVSNVsOiKK)ON@y2aq#r;>IwMd3E>rGrsi<} zy0ces(0S8dz)5WozC~W-I{;tO4^acmB@K|<6|rLU;pJh?kllp`~QU0Bz#+oG1KTqs4M zvDz$B^aas;eVGLW$857TNjtbBxS!@t#@|r>km+{ULCCge8~B7%vwkdjH-$B3KAj@d zS@vs9?p}ZWpG@CMj2k-ht+rU*Eq9Qpe@4zQ4iuPMNlkl;{ozGSUJD>=V=N^%o*ZETgdcOUgbI*nlQ6k9Usv>7yRE zP+ksH*y9!&+A(4M}dZfT^Y@s|@> zgn@AsTQOO#sYpAqhAEyOul+0LyHjb}b`TjU_ z^7J46RK%z9#zRWWD9iXEJ8f#$cs-fa%1~N;THKuBWR<}V6)3ghdJ(c833Zf$=4M5T zwV`js4w>giC00)y#0WsF$!NgkScsLGn0T}~{Um$3YgD5#8HU`kl2m*Yg;&{av1f!S z*nRf6*6WkE|Ltw9Y{7WY^C-3u_zz;eaA)hnP5=yse(QYYyaEJv)v{tr^xt1gps;JQ zF6;(~Q^J0J=E%nKJtYcKOc!j{h3S0^FzUD``qG=O?`0Bk=wIb{UJ$N!*%G?a>j z%~0@!ABi~tZbCFUar$3lU%E_Nn3Ax8aoH-p)6r1g-%nd8le4N%SFR&F=YVDgX8@O| zFPXsX#D7DgQ`aWjuE!yi2ALa`ns0mVmE=33y?H?Mku^^S;*)s)-j7}P?UwYD&c7p; z3f7UM$Sf~b{1Ac@8}f!i*N1DE7+6lMLui79vQKZci+r$d{oc#$ufiQ9n5dZqoXO&) zut7%>BbXOFL1hAiQGUxGtD`>B4WVA*8_;nC5N z#c^COq3-XCx4R`4MJ~~*hK^F?FF!d^#Ju&T0|>=RCzB^ZFy*gKs+3P3@S@zPWcE1o zG)yWyy|J!Q72kDikm*FB3oO?Ft0AI4swHqKbPkUqWm7h>R_1o1{6qQo^m7eA@Ogqy z6{S9 zRNPdamu4QCy=s}C=@q{4vucgVWlkY~_bU(`(+6Lp#xJU&&b6#eOWs;vnM*r`Xhz*oIox+PM* z+}wP7zET#KZ-!eS9kBI-Om~i-E6@V1_)klvjoRgGwQ;}kDUtDswfnh)J7(kW!mLLl z7sXNocL$W0StQ_FDVR@6wtG37&&FW1OU>rwm8Fw61}<2ZLa#(ml2OjC-;E8i5xtL94zZ_qIjqiBI9&TwOkb?wvi zAN)_#M!N5qlY?Lzi+cBInWptQMBQkvdQeHa9wrN%#2zJLIq>HVYI1q9Gm`N44S1BX zXJ{RNC*+0Mv)O}G(~spZZ6cnX+OOPd30dczOOSk$XY6 zVKsjSR++nL1q(R)&P4R&?tIHfl5(t!Xks8DXGdo#L6^u@A(4HCR49Ydh;N8iumFX| zaXzu9-3W^+B4{27D$_Lf^`rF9e(rJUC<&QJ@~(W;%`jWM8!zO2QJf9p4@?tCj{>g( z5&rsZTz*4s2{0f**CDJ{SlOqvZDo^QLG$uCvodCHa(Vzy3tj(A^*?lb7Y^?3!BL-) z_-TfXHp_gtx$&kOk-QbLBN0uo;0k2hppF9|bUdalLJ%h^_!4El?UmkHsYLg)joLV3 zH(ACW-JnHQ>)T|pY1DzI4?uamcwhfa%Y$mm6kg~RW1$#OIOIRl_R z(fQGcg(%SooZGlwI5*w-NBA`lXLGr3RDLx{K^hY>GP+U!K%et_cU|44Tl~@q@r^pB z-bh8RvpLtvqFUrHhvU3tmeKFzBmtp5`X}^SkB_1X%FB2A@oyFpEGux&c*RkI!apbst3VXmY#U>f-@+zj}5yw96OmZD=N=p2~eN= zC@T(T@{Om`50j1O2|#-LZQJ3gHy^M`Ns!lW8$}lgU`D`wAg8&tyNymfZ^{X$Gl(X* zHvnsiqvsc@i&sQdbyJ4~MXE@d{Te^BOJyKoyc+Btn_!k9_yELhXF9?;2YUQrslc4T zl^h_64|Y%fgO}?U62FX-Kx>2DhuVZeOD+UnMma!HojXv6CSU)Bj{r0)^*}pdx-soS z)JHjm^C1%&T4cW>3@rn*97YfawJ0SoC!?H4l>Jagk)W1pF&hK3uRU+Z=cymhNI5sQ zBzNh=k7o??_(y#I*cR1w`t1@;9jR*s$sAl|i(WTWQw{3~)1qLp)C!4s2MF@8l_#Z$!c@tBItHXuwY8;Y|CA4o)0{1`XnPw9WOEw|P(492K`AjYA# zl#aA#Do1*~NF$Gj*&nkJ9V_3(sHzmR+-P~83!7W5AN`kw1e3@)B<97nL(IyQ%pWc$ zI6E~;WdDmRH7>iaRE6Qq;;pGl$O5*-uCQ~z*{Jb69K_3`<}MQymKxvm%w}($(R!s-X%#@-il8=KOyoHRz z__q4j_(h$+7yItgF>M9KtMht3#^L}=cDckKka>(zDnPq+1db^@S+x6@%BB>(0Nju2 zGd-2+dAb$a<5aHMr6gP{3TYeNDhVM<(E?xg#-O z8&BV_bUCNrr+8t>XJ-P=G)z{tC65fv0%6jh%<*W8>a98j{egX^4**-o9A&r+y%W`vK9AofX<-<(Asjc;Xml!sJ1eTY=G%0iK_7Qq>Y6fGe zZFP8W_8udJepp>JQ`ewQGl5(<(k5X$aAF0`Q_GJMcuBIW6$-X)YK(kBdsDmtt#nWt`LHR5M$nLFp%=<`a>z6uLuBK@s! zT_xZ=1al$cGy!Lw6DF>;WnXyGv_G;_JrMo#Ojvmt4|ulJ1`>jOpVie?FpW;^i-VfK zaX)*>AYbpuml&Bfn>6`uZEg1Va6wiL9$PCrJKVO09jMA@upXZlN3f+Hu3}m7RZ6%< z-?L=YtTt5yT@EIUNojuzZdtX{g@~0*Ds-}b?XfSLY6I)AuC#i8dRkq$mv<=f*rHOt zbtXp3N9t|JmuukZ;GE7V9T76ABA8+I=?V^ay>(eO>c6&*(h|Y*A+K!e~zr zYL=0V(63!&R9=PBxckZ2;nGZ(bhyIc%eB~yI)}mE2l?vP)3rS`(+t-)$OO+USWGK} zVS|3+iQZf7!dmAD|7^&fFt#kjq2k8u=e?i4_8T=miOsyShoD0wCO{nE4Bhqs)I8@N zJ{k0I(gt*uxDws~-SSo4;YK&I`6WAcJlH5_HtIf|g%%lAaK>2Ar&;?mh3bm@DrE1l z#Wx7~R^NkM3(=n2xjPFsskSDzWyG_pG$?I;XlLEoLMI zwa;N`2~F7OBkDhW11{QP%@8#xRRwK={vb-Cn*Rl1btIuG)co{EW54@?y1amF&@Dx0 zKDYXNxFc-1qj(b>!i4?dAUbn3-;pw=lgPCs&d?TBFYM7`kOG++jJ7cqxcxw!e2(J- zlUR_J$O=Gu_F~YaP0s)nMh_t)X-}v1OdiKJwgARppLbf`7q)w;5E`;?>=jLY>bU<{ zynwJZm#478r5AeRR;iqy9NOCQW{n^-eIor;R;K;PS6z3IFew7&gJJ@rypghu{ZJh) zeJh2$kVTQ0Z{hj^m;xD<7?6}#3F|O&@K}ul7inLw7tnx@@62;-lyW60#;) zpRwX8n&e@sCa#cw(_0O_lj4d|uFRZ72HJ3aXhTWA2*mo5^+S5=aD2Eif~9j8~qwKzYd*6Z9G(_h^}5We0MT?vGe9y-Iu`@ z0$@YG9Qms(li{$=H-5HxDSf(GU2-?}ZH)3&NIW64=wz>-=vfjDE*({oXkS?WWHrP3 zZ6~5NGn=SK7Ua(q=ryJ78voJyXPltumrL49>Tu$d*SR4-)5f;gNH5al5`=OZM8zxE zRg!~o7L6UaP)r=1qUgi;{0q~Kq;+6}8J>0J1O*B1dcufZR@l z#1R}J{4*eV1SrIR1|*L7vk=le1EK+9W2l-#R%bx5h;Bm=`&kexa7z2LB_wMWL=N1W zdszo>ngxj<&U!;GXF-k3qjdr&_JA=&)%k)lZt3M< z(w)o;$oL$Hn?37y4wN>NQyuXo0^TA4+qI%^HvxpR5umc~?Uaa{pzJ~?&cL_C%%iV* zrXcL|ATk6yh~hkmf|0}&#W$EyO2$K#vL|QkrEmu7rE7j=a@jpsf`b>f&UYLnTx?Df zNZdR~h=rsUQB<}#Y`Bn5pJ{AcpXvF{#LV0XV?n1kJ8lKBH;{XFUI(bRl% z3k8t}&;^~Mxii`I^iSTq0AXsZ4KI=KfnY9!JQ3U=Vap&IaJpAzsF=jSVYW}Fyp3@v zdCkv>gLG`s(|c;~Ml;b&@x_mD}7ilGy>KQ0ke76O+ zwaWnOlVhFOXD_XzEId&OSPf;**i8D)uw;nc39aW=wyk#!5&mCorlEEwgXX zOKy)K!>D!6e$?}n~IFg_gSNV^Ph)l{nycgqImNVZ5w)~+fwgp zv>4`<9!QPKVu;xp`5o?`_QwR?-(klmo+3Y4AQa$*Ei+-|e9oj~AXT5e>6^Aup#BfL za_EQB>Sdc;Huf7=)-lyQ|2jK)A?_lthPmeJ-H*&55ox<)l{(c!y<@d@R~CtF_6QaA z`*xBRPDo+@oXU!j(tSf%8GEaIFdhj>4mVZK*4Y~&G|g^0+PEKNifz~(I%dn~7j1Ld zVs2mtx;qkwIB~KZ0?a=aOkUb($cz#j+w|`w4{&(`KgbzLChwc~()9@E$I7(sN~Q*A ztHzGUyURK9e5C7D=W}Uvvvnw)#KRq$YtL8I%Fx>1U#lEtu~l6lUf~;< z0>xR;%vbJTt7kjlPu*Kr(jFQ17!xsHRhqgJtl%Q*xR%L-@p_3WMnG$nR@$9>sRRpQ z#vs+JfTv(g+`cua&2$~sdS?IN{xwT7*|(+-9n!BpAl=|wjp0X!C<`nzB>}75mVE88 zo(@olhh4zrO&mDYigVQ4188-`9P&$}$`P^gK^dK8ARby#L5ucE!z~R3`nz z4LOX-qLB&UPyHz2#H)mngLpaaHWQZkcR#3p))txLy5@Vyf+q=AO5Buoo%`h!7<*PU zLCm_%?h%YEDpZ-d`>ZfJk! z&1L+^Tawx0d7R444T;or_z-Lci~X(E;`Cn8na;tEGHdVa(k!3BOa>>`#cLqW1M?iM zWaN92;KCuK)5UTr6_IO*^Z{L>nkNG;-bzo^5^;A->VQbm-tA3IgT|L3mXc0MA3^D6b!Yk(oH{w zbNLL3Gn z@V4{kW*r94xWLdCWnsi?G}Yg475!Zo5j6VUhE+QK=r+-*QHU6+rAg)&lKJOv)2Ghq zgcpbk;=lGpyx$4KmU_HUfy$aTFKJ$8c%3w$|Et^L)6OsubfUvdtqW)NSNf*hY%4}N z$U%aqma+#^?V-V>G8O~twfd>2BrBNwV0;F~Q>A9y$YV^xYHX0xZGuOB)4e2_6yBSen+@=h!-(_{9drXlKzE$d*!?acp;)+aPb+RwR_=9Em$3Fl#Hy*?qFx`9YqUm*1Q(7w`Uq6 zomKiWcb3_DD~#8F?8@^3h{T^~(9(Xx6nwteWE`>Ven(XvZF9WTk=>zg$!iExTf!^EL|~7i-{P=6w5oGB;qS>|tS^W8?1|&E zpwDWDGl~ZN*$l3qD(ZY{i5M5h2D#nek|oHWgnPUuuO*hX3gnifhS$?!dKs%;i-kfZ zoL)wM#RB)hWYV*Sx+*L#GI`5}8K*%m^_tMmzE8@zgikb|%p)RBGwa$TxU`)JuQ(Hw zk%hi~EfL#!mZyL6uH)UN)6-_wD@5ij zjBe85_m2$kGF!)G4L&hb>4}%4&F!U{$~QQ(^wvkYNQTF;vBDx z_a-)8hSTCg)N;97_zVx#VfZc|U1M|J3-YUH=%h}ll->d73|fQyIg?zEml?9Zap8Ip zD?8JLNN=bfj*vm7mmt==AZ_sOV}zl#b+uxd?)#^e45LQh%6HDXHC35MI2m0(>Q}_P zZ^Y!TFSSi2cNM+!>gO|H##>_NW%Hd^Dh3b(_)NL~<1L35>?@Qa%D70H9Uzfwmj1sFNw+cZ_MP!kU9o{I`#6d0XN1 z9Q)afLN7Gha3V&KIkf6bya0bf)QR zN|WYQ(w$Vpv)%CL$VkGO-x#gEe4WS35zx>@m=K%IMWE1Va8>a$-m)}(glJEpaiBcr z7v_oHCRppSa=W)~noE0&eZb;zdP^)#Dv^hy=!mb^swGdAVPWi6>z0WG&3vjYboKCE+4Z%&@m8%!8?6z+}W7gwW(7?rM^}Q^G zmTeTIydm|hX1A^KjNpy;5Oj^HyVDLUBTbVgP5P2K9Ql*?!dYkQ zr+ZED^r;~uq$Uf6%5>e`Txtq8STTIW#$CSf(ZQPLFT3&3H^uPnOK~pZnAVavv&@X$ zXo5YKb6IyP{QW8O1ewBwx(@`8jajzQvhN54EEa0FTA)5L{pk0bczQgqigN}b=#klc z7~mQntV5P+-qP|qlm0Aix~s`$a#h}Pwq+1c>NwYQ$Uf#Rk9q9+_RfJxnev_qDJ7{;dK~V(K+}-pBqc z?U$+jK|r@$iXE|$dNlTzEaXl#az;#!6tHk}*WB9M$j0zHv=+hc;0oaeSYKVcU2QQ! zP$iZox4Toca0rk8nKn$nkBRsl60WCz0s`PBww>-qT$sBKy-5E=fOsYR?Pt~LW3@VL zA#PW+(ym{o6Ag3b-A)gfzYT3%rsx|<`6(OxWe@?Icq~z+6ft!Ee57;3<{}zngkTKR zQr}|RV03DCkrQjEKGbH+C;SHm^_EEH{<5M!>U_Gk1{lxNHTbYtpolYnzb%w1mVw%j z$Mn}&*ubThq5CY0b$yduCPNVO8JoU&fZl2>SVoTm=le0{ooPLc9_^t3#eC>^&bIvD zYg~)q%fj~FW8L7D&@q$%RItmDJ@_39UZaRMy43`8%kT61Kh5a?`HX}wC{y$ zS{i&bFczd=#fHU&Sx#nc$sVhVUIGJntQrVNaZd3AlVm({yA_bQQr5dnO`dRcs#!W_ zO=VF?>?4mE+P&q+jmI^T(=VMS%M->Eco($RaZJ$&=UZ0XlN!6RR(~Yes}euB3$<$qAxiITB(_~* zzMMV$m1{5$_tkrGPOy5fwxS!2=-*)SD986CmR4Dr;J#3N({ zvy8|YgaY{A$7)m*-tw!@$3%63ay4~&H}=$@OfykXubey6 z`^a13>a-%Ah=`aCo%vK#ZqRYuHigN4Hz=~xo}l%IA18hd*~tGxb`0cUes$|v)Dqz- zP4P~@*!ZJh7@gGC?4^?sd?aC=+{Kh0Yp?#%vHGM0IO_f`bpGGD4lx)}R!ra&^TWSF zfjd%hy$sa(I@y#SBD|P4rUnE7*rmHG?@mod&QZrDNv2n+V?|6WTJ)|bU#$@9g>J|n zd2lSfsom!LWeRCW{(56U$NWok(Iev{j*fVLw!fhp8p>D7cLbdX_1ssEQQVI~cHR6R z3nJK{A^eO&Ux%|f=iJS~t{sxv1MB0D>yapSB_0JB`o+nOJHRSkAO?#GM2(=-wkkt& zE%HLh+g8lwB^C8hSHo^RX(mfW#?hX;w3fL=g~8ZJTPawbh&*ze#d?@UQW1nYERubY zl)I`S>Y^)BzIA?6QH3N)Yhn8)Y*B1@>pQhKz*T-8x0AK8Qh)#~zQ};u7lm`CW^ziI zgYqt))R4n?vbsLBUG;T^V&tU0r;sg%04!nsmqx%6s9jZ5j`UW~A2F8zB|a$P09)PO z<9j@0cO8Z_Ze@H&h{*D$*l6$?(C5Pv+%bvubkm}(>8H&9zV1U>_+3N)YD4Mk+K2-CDO*yM9geYZ7w+ zQ_QOEaINQVTSKBcN#?yLXQq9PNkG4gG}+ytQcAb05B?BX!uH{oMk&ooi!^ctgwX3D ze2Ovqo(w|5yh|STX6`7)%9o# zf&nZZnP<{iY&f4}Tm$$1^$>XirHC?NP-QNIUx04{%5e zQ^TeiRMDj?t-R+Z1=wHL6uoP^{rM)&{-$Pij#l=x|E+D636JjMhFV&zBIn+royKAT z{mQ??;JbEH5-iL776sjO&)rO5efd_u;~ZcLBJ|k_>@YB*nh%Lm^rDRux_(+r6?e*I z?Flf*$hB!Jp8etgu3sC3)(@aA&BbKZPIjlI2vuYr2%}*d462zN)h#(K9#u!4q<=3m zozfDuyaS^njF5X}-+Ryf;mXRGlVWQPtf26)G1-riqJgc~(6M_^?-G_yHS@p!a2a>l z^?Y+eu=EEB?E9;>5-eB%&QUb^OXWf}x%V<|F@zzWfu7cYFMaqA7;yU4GZF#}2Aqf6 z1OqO^ZH58Y;kLkl+i+W9zFrXaz13Gf!%U_*=0X5;D&BA~>aOYq^1Gw`r zpb6Xs7|Ong#kU_uEBslaMxkL0Js}4U@+WG7%&{} z77Q2-cN+$bhr0sH9; tH2F)65T<|Zqth`V0Mhc<*&rI&7)<{^vyA7Z8V3ernlk%q$T~I#^?$t{(xw0a diff --git a/icons/icon32_slob.png b/icons/icon32_slob.png new file mode 100644 index 0000000000000000000000000000000000000000..984205ea66258f257f09548de9f71db7d6ad8af3 GIT binary patch literal 1625 zcmV-f2B!ImP)e zS$Y{DK>kN|S>;!F;a`x2mq8ZU1kl1TEXRgz$+8|Wr16l$hxiz>$?mF~MK_zI#)8H& zf)r68yIEcL)H&zgsuoq{|Jm%~hlm6~w0iG<)G}bMs;&eeB9)K+^2ZM^?d<(2NRzOD z#5{A{{@?@DyPpwno#F9he*DEZ5C0}2AF1lhiiiL^K1u)l=#zh$xEdDWg}GOz{a@2- zw<&-!olH15IwY{c#g?08w2yzFR;!cCt(V`q`sQDOk45Cf0s(M&*zcN91VKPR#9(B> zg|M~1L+7N8cb;CSOAwd~EL?HU;W9^-rtBT<({K0KZUl$GW#Dw7cilU;h=!N|F$SXo z1_%tDR-0Lp5CoRVc*wCbW-FuwjVz89*JDhLa!)Y1VextXFW( z)hQHAZjU1mu_uH35`*grZTs#NH;+oZ{yES*E1d9nZ?0B4ga)5(BQ zJtDG}FbWZ4P+)g|k6x$GWIUn1kq~djFOT~|R>#dI!@-d0IAJ5Mv9+_gYHC?9U?LG3 zwSZXhzv!z)%d1CJkix0Xc~A)K(wqwbET=$K@qRhaVzg23U%*)!j!H`a?%k>-AIC|@FjS26U5|nko3N#}_vl3u}00|74lB4xL zNA5k&IikpNGtQSc5-P)bmG;9P2z`s*4C zUw-;EtshRAB?+VcfJR*BvpaX0B{Rav^7z{)y!rMUG~znDm$tck=W|Y5rz>+Qx#8D6 zAgigN=rSMFtvUGp-`p(6MbQSo|HJRjo0puqU%r21Wif8WnCm8#e9Vh!xX52Ea(AUx z0IlOTVHlz6sWqzfI|G_qG3jiMDRxQ`!{+wJa^)1P`jYLk5=t0_Y-~1(>lM8BIOoY` z^Fsd>7K(Q1Xm4%7^{dszuW|v-75+hAr~{mnAQ+D)9A`5|wPG)@7B#HpbwS;Qn^`NNAv04QN(vxgDpz$Xl;K`QT4%#WUwi`WgcTI@SjRs;>BNQIcN+LXm=t zIaa+?R>I|A1yL3zEOqni9{362%j&l*(OSkVC0K!51XdLAy1oazM))GQt}uCC0G~>y4PubnyVxw7qNw^oI=S+@<6FRLPaa<#v&#*Q;4`4Ex z^6VsIP_=}CA+#0*)H^zz9xhX=bxRlpj0Ync@kKx=l;O=Cc{y&WwY@y)^&= zn9vAuHQx&`f}o_D8>kY6Wa5}7bDp2}nI&@?jmm{c=(hV*Di-HFm5L=;> > slobDictionaries = + Slob::makeDictionaries( allFiles, FsEncoding::encode( Config::getIndexDir() ), *this ); + + dictionaries.insert( dictionaries.end(), slobDictionaries.begin(), + slobDictionaries.end() ); + } #endif #ifndef NO_EPWING_SUPPORT { diff --git a/preferences.cc b/preferences.cc index fab02032..7e7763ad 100644 --- a/preferences.cc +++ b/preferences.cc @@ -294,12 +294,14 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ): ui.allowDSL->setChecked( !p.fts.disabledTypes.contains( "DSL", Qt::CaseInsensitive ) ); ui.allowMDict->setChecked( !p.fts.disabledTypes.contains( "MDICT", Qt::CaseInsensitive ) ); ui.allowSDict->setChecked( !p.fts.disabledTypes.contains( "SDICT", Qt::CaseInsensitive ) ); + ui.allowSlob->setChecked( !p.fts.disabledTypes.contains( "SLOB", Qt::CaseInsensitive ) ); ui.allowStardict->setChecked( !p.fts.disabledTypes.contains( "STARDICT", Qt::CaseInsensitive ) ); ui.allowXDXF->setChecked( !p.fts.disabledTypes.contains( "XDXF", Qt::CaseInsensitive ) ); ui.allowZim->setChecked( !p.fts.disabledTypes.contains( "ZIM", Qt::CaseInsensitive ) ); ui.allowEpwing->setChecked( !p.fts.disabledTypes.contains( "EPWING", Qt::CaseInsensitive ) ); #ifndef MAKE_ZIM_SUPPORT ui.allowZim->hide(); + ui.allowSlob->hide(); #endif #ifdef NO_EPWING_SUPPORT ui.allowEpwing->hide(); @@ -441,6 +443,13 @@ Config::Preferences Preferences::getPreferences() p.fts.disabledTypes += "SDICT"; } + if( !ui.allowSlob->isChecked() ) + { + if( !p.fts.disabledTypes.isEmpty() ) + p.fts.disabledTypes += ','; + p.fts.disabledTypes += "SLOB"; + } + if( !ui.allowStardict->isChecked() ) { if( !p.fts.disabledTypes.isEmpty() ) diff --git a/preferences.ui b/preferences.ui index 2e50ff58..e5591b7f 100644 --- a/preferences.ui +++ b/preferences.ui @@ -1240,13 +1240,20 @@ download page. - + SDict + + + + Slob + + + @@ -1268,7 +1275,7 @@ download page. - + diff --git a/resources.qrc b/resources.qrc index cc29474e..97e33451 100644 --- a/resources.qrc +++ b/resources.qrc @@ -78,5 +78,6 @@ icons/playsound_full.png icons/icon32_zim.png icons/icon32_epwing.png + icons/icon32_slob.png diff --git a/slob.cc b/slob.cc new file mode 100644 index 00000000..9e5a4262 --- /dev/null +++ b/slob.cc @@ -0,0 +1,1312 @@ +/* This file is (c) 2015 Abs62 + * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */ + +#ifdef MAKE_ZIM_SUPPORT + +#include "slob.hh" +#include "btreeidx.hh" +#include "fsencoding.hh" +#include "folding.hh" +#include "gddebug.hh" +#include "utf8.hh" +#include "decompress.hh" +#include "langcoder.hh" +#include "wstring.hh" +#include "wstring_qt.hh" +#include "ftshelpers.hh" +#include "htmlescape.hh" +#include "filetype.hh" +#include "tiff.hh" + +#ifdef _MSC_VER +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Slob { + +using std::string; +using std::map; +using std::vector; +using std::multimap; +using std::pair; +using std::set; +using gd::wstring; + +using BtreeIndexing::WordArticleLink; +using BtreeIndexing::IndexedWords; +using BtreeIndexing::IndexInfo; + +DEF_EX_STR( exNotSlobFile, "Not an Slob file", Dictionary::Ex ) +DEF_EX_STR( exCantReadFile, "Can't read file", Dictionary::Ex ) +DEF_EX_STR( exCantDecodeFile, "Can't decode file", Dictionary::Ex ) +DEF_EX_STR( exNoCodecFound, "No text codec found", Dictionary::Ex ) +DEF_EX( exUserAbort, "User abort", Dictionary::Ex ) + +#pragma pack( push, 1 ) + +enum +{ + Signature = 0x58424C53, // SLBX on little-endian, XBLS on big-endian + CurrentFormatVersion = 1 + BtreeIndexing::FormatVersion + Folding::Version +}; + +struct IdxHeader +{ + quint32 signature; // First comes the signature, SLBX + quint32 formatVersion; // File format version (CurrentFormatVersion) + quint32 indexBtreeMaxElements; // Two fields from IndexInfo + quint32 indexRootOffset; + quint32 resourceIndexBtreeMaxElements; // Two fields from IndexInfo + quint32 resourceIndexRootOffset; + quint32 wordCount; + quint32 articleCount; + quint32 langFrom; // Source language + quint32 langTo; // Target language +} +#ifndef _MSC_VER +__attribute__((packed)) +#endif +; + +#pragma pack( pop ) + +const char SLOB_MAGIC[ 8 ] = { 0x21, 0x2d, 0x31, 0x53, 0x4c, 0x4f, 0x42, 0x1f }; + +struct RefEntry +{ + QString key; + quint32 binIndex; + quint16 itemIndex; + QString fragment; +}; + +bool indexIsOldOrBad( string const & indexFile ) +{ + File::Class idx( indexFile, "rb" ); + + IdxHeader header; + + return idx.readRecords( &header, sizeof( header ), 1 ) != 1 || + header.signature != Signature || + header.formatVersion != CurrentFormatVersion; +} + + +class SlobFile +{ + enum Compressions + { UNKNOWN = 0, ZLIB, BZ2, LZMA2 }; + + QFile file; + QString fileName, dictionaryName; + Compressions compression; + QString encoding; + unsigned char uuid[ 16 ]; + QTextCodec *codec; + QMap< QString, QString > tags; + QVector< QString > contentTypes; + quint32 blobCount; + quint64 storeOffset, fileSize, refsOffset; + quint32 refsCount, itemsCount; + quint64 itemsOffset, itemsDataOffset; + quint32 currentItem; + string currentItemData; + + QString readTinyText(); + QString readText(); + QString readLargeText(); + QString readString( unsigned lenght ); + +public: + SlobFile() : + compression( UNKNOWN ) + , codec( 0 ) + , blobCount( 0 ) + , storeOffset( 0 ) + , fileSize( 0 ) + , refsOffset( 0 ) + , refsCount( 0 ) + , itemsCount( 0 ) + , itemsOffset( 0 ) + , itemsDataOffset( 0 ) + , currentItem( 0xFFFFFFFF ) + {} + + ~SlobFile(); + + Compressions getCompression() const + { return compression; } + + QString const & getEncoding() const + { return encoding; } + + QString const & getDictionaryName() const + { return dictionaryName; } + + quint32 blobsCount() const + { return blobCount; } + + quint64 dataOffset() const + { return storeOffset; } + + quint32 getRefsCount() const + { return refsCount; } + + QTextCodec * getCodec() const + { return codec; } + + QString getContentType( quint8 content_id ) const + { return content_id < contentTypes.size() ? contentTypes[ content_id ] : QString(); } + + QMap< QString, QString > const & getTags() const + { return tags; } + + void open( const QString & name ); + + void getRefEntry( quint32 ref_nom, RefEntry & entry ); + + quint8 getItem( RefEntry const & entry, string * data ); +}; + +SlobFile::~SlobFile() +{ + file.close(); +} + +QString SlobFile::readString( unsigned length ) +{ + QByteArray data = file.read( length ); + QString str; + + if( codec != 0 && !data.isEmpty() ) + str = codec->toUnicode( data ); + else + str = QString( data ); + + char term = 0; + int n = str.indexOf( term ); + if( n > 0 ) + str.resize( n ); + + return str; +} + +QString SlobFile::readTinyText() +{ + unsigned char len; + if( !file.getChar( ( char * )&len ) ) + { + QString error = fileName + ": " + file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); + } + return readString( len ); +} + +QString SlobFile::readText() +{ + quint16 len; + if( file.read( ( char * )&len, sizeof( len ) ) != sizeof( len ) ) + { + QString error = fileName + ": " + file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); + } + return readString( qFromBigEndian( len ) ); +} + +QString SlobFile::readLargeText() +{ + quint32 len; + if( file.read( ( char * )&len, sizeof( len ) ) != sizeof( len ) ) + { + QString error = fileName + ": " + file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); + } + return readString( qFromBigEndian( len ) ); +} + +void SlobFile::open( const QString & name ) +{ +QString error( name + ": " ); + + if( file.isOpen() ) + file.close(); + + fileName = name; + + file.setFileName( name ); + + { + QFileInfo fi( name ); + dictionaryName = fi.fileName(); + } + + for( ; ; ) + { + + if( !file.open( QFile::ReadOnly ) ) + break; + + char magic[ 8 ]; + if( file.read( magic, sizeof( magic ) ) != sizeof( magic ) ) + break; + + if( memcmp( magic, SLOB_MAGIC, sizeof( magic ) ) != 0 ) + throw exNotSlobFile( string( name.toUtf8().data() ) ); + + if( file.read( ( char * )uuid, sizeof( uuid ) ) != sizeof( uuid ) ) + break; + + // Read encoding + + encoding = readTinyText(); + + codec = QTextCodec::codecForName( encoding.toLatin1() ); + if( codec == 0 ) + { + error = QString( "for encoding \"") + encoding + "\""; + throw exNoCodecFound( string( error.toUtf8().data() ) ); + } + + // Read compression type + + QString compr = readTinyText(); + + if( compr.compare( "zlib", Qt::CaseInsensitive ) == 0 ) + compression = ZLIB; + else + if( compr.compare( "bz2", Qt::CaseInsensitive ) == 0 ) + compression = BZ2; + else + if( compr.compare( "lzma2", Qt::CaseInsensitive ) == 0 ) + compression = LZMA2; + + // Read tags + + unsigned char count; + if( !file.getChar( ( char * )&count ) ) + break; + + for( unsigned i = 0; i < count; i++ ) + { + QString key = readTinyText(); + QString value = readTinyText(); + tags[ key ] = value; + + if( key.compare( "label", Qt::CaseInsensitive ) == 0 + || key.compare( "name", Qt::CaseInsensitive ) == 0) + dictionaryName = value; + } + + // Read content types + + if( !file.getChar( ( char * )&count ) ) + break; + + for( unsigned i = 0; i < count; i++ ) + { + QString type = readText(); + contentTypes.append( type ); + } + + // Read data parameters + + quint32 cnt; + if( file.read( ( char * )&cnt, sizeof( cnt ) ) != sizeof( cnt ) ) + break; + blobCount = qFromBigEndian( cnt ); + + quint64 tmp; + if( file.read( ( char * )&tmp, sizeof( tmp ) ) != sizeof( tmp ) ) + break; + storeOffset = qFromBigEndian( tmp ); + + if( file.read( ( char * )&tmp, sizeof( tmp ) ) != sizeof( tmp ) ) + break; + fileSize = qFromBigEndian( tmp ); + + if( file.read( ( char * )&cnt, sizeof( cnt ) ) != sizeof( cnt ) ) + break; + refsCount = qFromBigEndian( cnt ); + + refsOffset = file.pos(); + + if( !file.seek( storeOffset ) ) + break; + + if( file.read( ( char * )&cnt, sizeof( cnt ) ) != sizeof( cnt ) ) + break; + itemsCount = qFromBigEndian( cnt ); + + itemsOffset = storeOffset + sizeof( itemsCount ); + itemsDataOffset = itemsOffset + itemsCount * sizeof( quint64 ); + + return; + } + error += file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); +} + +void SlobFile::getRefEntry( quint32 ref_nom, RefEntry & entry ) +{ + quint64 pos = refsOffset + ref_nom * sizeof( quint64 ); + quint64 offset, tmp; + + for( ; ; ) + { + if( !file.seek( pos ) || file.read( ( char * )&tmp, sizeof( tmp ) ) != sizeof( tmp ) ) + break; + offset = qFromBigEndian( tmp ) + refsOffset + refsCount * sizeof( quint64 ); + + if( !file.seek( offset ) ) + break; + + entry.key = readText(); + + quint32 index; + if( file.read( ( char * )&index, sizeof( index ) ) != sizeof( index ) ) + break; + entry.itemIndex = qFromBigEndian( index ); + + quint16 binIndex; + if( file.read( ( char * )&binIndex, sizeof( binIndex ) ) != sizeof( binIndex ) ) + break; + entry.binIndex = qFromBigEndian( binIndex ); + + entry.fragment = readTinyText(); + + return; + } + QString error = fileName + ": " + file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); +} + +quint8 SlobFile::getItem( RefEntry const & entry, string * data ) +{ + quint64 pos = itemsOffset + entry.itemIndex * sizeof( quint64 ); + quint64 offset, tmp; + + for( ; ; ) + { + // Read item data types + + if( !file.seek( pos ) || file.read( ( char * )&tmp, sizeof( tmp ) ) != sizeof( tmp ) ) + break; + + offset = qFromBigEndian( tmp ) + itemsDataOffset; + + if( !file.seek( offset ) ) + break; + + quint32 bins, bins_be; + if( file.read( ( char * )&bins_be, sizeof( bins_be ) ) != sizeof( bins_be ) ) + break; + bins = qFromBigEndian( bins_be ); + + if( entry.binIndex >= bins ) + return 0xFF; + + QVector< quint8 > ids; + ids.resize( bins ); + if( file.read( ( char * )ids.data(), bins ) != bins ) + break; + + quint8 id = ids[ entry.binIndex ]; + + if( id >= (unsigned)contentTypes.size() ) + return 0xFF; + + if( data != 0 ) + { + // Read item data + if( currentItem != entry.itemIndex ) + { + currentItemData.clear(); + quint32 length, length_be; + if( file.read( ( char * )&length_be, sizeof( length_be ) ) != sizeof( length_be ) ) + break; + length = qFromBigEndian( length_be ); + + QByteArray compressedData = file.read( length ); + + if( compression == ZLIB ) + currentItemData = decompressZlib( compressedData.data(), length ); + else + if( compression == ZLIB ) + currentItemData = decompressBzip2( compressedData.data(), length ); + else + currentItemData = decompressLzma2( compressedData.data(), length, true ); + + if( currentItemData.empty() ) + { + currentItem = 0xFFFFFFFF; + return 0xFF; + } + currentItem = entry.itemIndex; + } + + // Find bin data inside item + + const char * ptr = currentItemData.c_str(); + quint32 pos = entry.binIndex * sizeof( quint32 ); + + if( pos >= currentItemData.length() - sizeof( quint32 ) ) + return 0xFF; + + quint32 offset, offset_be; + memcpy( &offset_be, ptr + pos, sizeof( offset_be ) ); + offset = qFromBigEndian( offset_be ); + + pos = bins * sizeof( quint32 ) + offset; + + if( pos >= currentItemData.length() - sizeof( quint32 ) ) + return 0xFF; + + quint32 length, len_be; + memcpy( &len_be, ptr + pos, sizeof( len_be ) ); + length = qFromBigEndian( len_be ); + + *data = currentItemData.substr( pos + sizeof( len_be ), length ); + } + + return ids[ entry.binIndex ]; + } + QString error = fileName + ": " + file.errorString(); + throw exCantReadFile( string( error.toUtf8().data() ) ); +} + +// SlobDictionary + +class SlobDictionary: public BtreeIndexing::BtreeDictionary +{ + Mutex idxMutex; + Mutex slobMutex, idxResourceMutex; + File::Class idx; + BtreeIndex resourceIndex; + IdxHeader idxHeader; + string dictionaryName; + SlobFile sf; + + public: + + SlobDictionary( string const & id, string const & indexFile, + vector< string > const & dictionaryFiles ); + + ~SlobDictionary(); + + virtual string getName() throw() + { return dictionaryName; } + + virtual map< Dictionary::Property, string > getProperties() throw() + { return map< Dictionary::Property, string >(); } + + virtual unsigned long getArticleCount() throw() + { return idxHeader.articleCount; } + + virtual unsigned long getWordCount() throw() + { return idxHeader.wordCount; } + + inline virtual quint32 getLangFrom() const + { return idxHeader.langFrom; } + + inline virtual quint32 getLangTo() const + { return idxHeader.langTo; } + + virtual sptr< Dictionary::DataRequest > getArticle( wstring const &, + vector< wstring > const & alts, + wstring const & ) + throw( std::exception ); + + virtual sptr< Dictionary::DataRequest > getResource( string const & name ) + throw( std::exception ); + + virtual QString const& getDescription(); + + /// Loads the resource. + void loadResource( std::string &resourceName, string & data ); + + virtual sptr< Dictionary::DataRequest > getSearchResults( QString const & searchString, + int searchMode, bool matchCase, + int distanceBetweenWords, + int maxResults ); + virtual void getArticleText( uint32_t articleAddress, QString & headword, QString & text ); + + virtual void makeFTSIndex(QAtomicInt & isCancelled, bool firstIteration ); + + virtual void setFTSParameters( Config::FullTextSearch const & fts ) + { + can_FTS = fts.enabled + && !fts.disabledTypes.contains( "SLOB", Qt::CaseInsensitive ) + && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); + } + +protected: + + virtual void loadIcon() throw(); + +private: + + /// Loads the article. + void loadArticle( quint32 address, + string & articleText, + bool rawText = false ); + + quint32 readArticle( quint32 address, + string & articleText ); + + string convert( string const & in_data ); + + friend class SlobArticleRequest; + friend class SlobResourceRequest; +}; + +SlobDictionary::SlobDictionary( string const & id, + string const & indexFile, + vector< string > const & dictionaryFiles ): + BtreeDictionary( id, dictionaryFiles ), + idx( indexFile, "rb" ), + idxHeader( idx.read< IdxHeader >() ) +{ + // Open data file + + try + { + sf.open( FsEncoding::decode( dictionaryFiles[ 0 ].c_str() ) ); + } + catch( std::exception & e ) + { + gdWarning( "Slob dictionary initializing failed: %s, error: %s\n", + dictionaryFiles[ 0 ].c_str(), e.what() ); + } + + // Initialize the indexes + + openIndex( IndexInfo( idxHeader.indexBtreeMaxElements, + idxHeader.indexRootOffset ), + idx, idxMutex ); + + resourceIndex.openIndex( IndexInfo( idxHeader.resourceIndexBtreeMaxElements, + idxHeader.resourceIndexRootOffset ), + idx, idxResourceMutex ); + + // Read dictionary name + + dictionaryName = string( sf.getDictionaryName().toUtf8().constData() ); + if( dictionaryName.empty() ) + { + QString name = QDir::fromNativeSeparators( FsEncoding::decode( dictionaryFiles[ 0 ].c_str() ) ); + int n = name.lastIndexOf( '/' ); + dictionaryName = string( name.mid( n + 1 ).toUtf8().constData() ); + } + + // Full-text search parameters + + can_FTS = true; + + ftsIdxName = indexFile + "_FTS"; + + if( !Dictionary::needToRebuildIndex( dictionaryFiles, ftsIdxName ) + && !FtsHelpers::ftsIndexIsOldOrBad( ftsIdxName, this ) ) + FTS_index_completed.ref(); +} + +SlobDictionary::~SlobDictionary() +{ +} + +void SlobDictionary::loadIcon() throw() +{ + if ( dictionaryIconLoaded ) + return; + + QString fileName = + QDir::fromNativeSeparators( FsEncoding::decode( getDictionaryFilenames()[ 0 ].c_str() ) ); + + // Remove the extension + fileName.chop( 4 ); + + if( !loadIconFromFile( fileName ) ) + { + // Load failed -- use default icons + dictionaryNativeIcon = dictionaryIcon = QIcon(":/icons/icon32_slob.png"); + } + + dictionaryIconLoaded = true; +} + +QString const& SlobDictionary::getDescription() +{ + if( !dictionaryDescription.isEmpty() ) + return dictionaryDescription; + + QMap< QString, QString > const & tags = sf.getTags(); + + QMap< QString, QString >::const_iterator it; + for( it = tags.begin(); it != tags.end(); ++it ) + { + if( it != tags.begin() ) + dictionaryDescription += "\n\n"; + + dictionaryDescription += it.key() + ": " +it.value(); + } + + return dictionaryDescription; +} + +void SlobDictionary::loadArticle( quint32 address, + string & articleText, + bool rawText ) +{ + articleText.clear(); + + readArticle( address, articleText ); + + if( !articleText.empty() ) + { + if( rawText ) + return; + articleText = convert( articleText ); + } + else + articleText = string( QObject::tr( "Article decoding error" ).toUtf8().constData() ); + + // See Issue #271: A mechanism to clean-up invalid HTML cards. + string cleaner = """""""""""" + """""""""""" + "" + "" + ""; + + string prefix( "
"; +} + +string SlobDictionary::convert( const string & in ) +{ + QString text = QString::fromUtf8( in.c_str() ); + + // pattern of img and script + text.replace( QRegExp( "<\\s*(img|script)\\s*([^>]*)src=(\"[^\"]*)" ), + QString( "<\\1 \\2src=\\3bres://%1/").arg( getId().c_str() ) ); + + // pattern + text.replace( QRegExp( "<\\s*link\\s*([^>]*)href=\"" ), + QString( ", excluding any known protocols such as http://, mailto:, #(comment) + // these links will be translated into local definitions + QRegExp rxLink( "<\\s*a\\s+([^>]*)href=\"(?!(\\w+://|#|mailto:|tel:))(/|)([^\"]*)\"\\s*(title=\"[^\"]*\")?[^>]*>", + Qt::CaseSensitive, + QRegExp::RegExp2 ); + int pos = 0; + while( (pos = rxLink.indexIn( text, pos )) >= 0 ) + { + QStringList list = rxLink.capturedTexts(); + QString tag = list[3]; + if ( !list[4].isEmpty() ) + tag = list[4].split("\"")[1]; + + tag.remove( QRegExp(".*/") ). + remove( QRegExp( "\\.(s|)htm(l|)$", Qt::CaseInsensitive ) ). + replace( "_", "%20" ). + prepend( "" ); + + text.replace( pos, list[0].length(), tag ); + pos += tag.length() + 1; + } + + // Fix outstanding elements + text += "
"; + + return text.toUtf8().data(); +} + +void SlobDictionary::loadResource( std::string & resourceName, string & data ) +{ + vector< WordArticleLink > link; + string resData; + + link = resourceIndex.findArticles( Utf8::decode( resourceName ) ); + + if( link.empty() ) + return; + + readArticle( link[ 0 ].articleOffset, data ); +} + +quint32 SlobDictionary::readArticle( quint32 articleNumber, std::string & result ) +{ + RefEntry entry; + string data; + quint8 contentId; + + { + Mutex::Lock _( slobMutex ); + sf.getRefEntry( articleNumber, entry ); + contentId = sf.getItem( entry, &data ); + } + + if( contentId == 0xFF ) + return 0xFFFFFFFF; + + QString contentType = sf.getContentType( contentId ); + + if( contentType.contains( "text/html", Qt::CaseInsensitive ) + || contentType.contains( "text/plain", Qt::CaseInsensitive ) + || contentType.contains( "/css", Qt::CaseInsensitive ) + || contentType.contains( "/javascript", Qt::CaseInsensitive ) + || contentType.contains( "/json", Qt::CaseInsensitive )) + { + QTextCodec *codec = sf.getCodec(); + QString content = codec->toUnicode( data.c_str(), data.size() ); + result = string( content.toUtf8().data() ); + } + else + result = data; + + return contentId; +} + +void SlobDictionary::makeFTSIndex( QAtomicInt & isCancelled, bool firstIteration ) +{ + if( !( Dictionary::needToRebuildIndex( getDictionaryFilenames(), ftsIdxName ) + || FtsHelpers::ftsIndexIsOldOrBad( ftsIdxName, this ) ) ) + FTS_index_completed.ref(); + + if( haveFTSIndex() ) + return; + + if( ensureInitDone().size() ) + return; + + if( firstIteration && getArticleCount() > FTS::MaxDictionarySizeForFastSearch ) + return; + + gdDebug( "Slob: Building the full-text index for dictionary: %s\n", + getName().c_str() ); + + try + { + FtsHelpers::makeFTSIndex( this, isCancelled ); + FTS_index_completed.ref(); + } + catch( std::exception &ex ) + { + gdWarning( "Slob: Failed building full-text search index for \"%s\", reason: %s\n", getName().c_str(), ex.what() ); + QFile::remove( FsEncoding::decode( ftsIdxName.c_str() ) ); + } +} + +void SlobDictionary::getArticleText( uint32_t articleAddress, QString & headword, QString & text ) +{ + try + { + headword.clear(); + string articleText; + + loadArticle( articleAddress, articleText, true ); + + text = Html::unescape( QString::fromUtf8( articleText.data(), articleText.size() ) ); + } + catch( std::exception &ex ) + { + gdWarning( "Slob: Failed retrieving article from \"%s\", reason: %s\n", getName().c_str(), ex.what() ); + } +} + + +sptr< Dictionary::DataRequest > SlobDictionary::getSearchResults( QString const & searchString, + int searchMode, bool matchCase, + int distanceBetweenWords, + int maxResults ) +{ + return new FtsHelpers::FTSResultsRequest( *this, searchString, searchMode, matchCase, distanceBetweenWords, maxResults ); +} + + +/// SlobDictionary::getArticle() + +class SlobArticleRequest; + +class SlobArticleRequestRunnable: public QRunnable +{ + SlobArticleRequest & r; + QSemaphore & hasExited; + +public: + + SlobArticleRequestRunnable( SlobArticleRequest & r_, + QSemaphore & hasExited_ ): r( r_ ), + hasExited( hasExited_ ) + {} + + ~SlobArticleRequestRunnable() + { + hasExited.release(); + } + + virtual void run(); +}; + +class SlobArticleRequest: public Dictionary::DataRequest +{ + friend class SlobArticleRequestRunnable; + + wstring word; + vector< wstring > alts; + SlobDictionary & dict; + + QAtomicInt isCancelled; + QSemaphore hasExited; + +public: + + SlobArticleRequest( wstring const & word_, + vector< wstring > const & alts_, + SlobDictionary & dict_ ): + word( word_ ), alts( alts_ ), dict( dict_ ) + { + QThreadPool::globalInstance()->start( + new SlobArticleRequestRunnable( *this, hasExited ) ); + } + + void run(); // Run from another thread by DslArticleRequestRunnable + + virtual void cancel() + { + isCancelled.ref(); + } + + ~SlobArticleRequest() + { + isCancelled.ref(); + hasExited.acquire(); + } +}; + +void SlobArticleRequestRunnable::run() +{ + r.run(); +} + +void SlobArticleRequest::run() +{ + if ( isCancelled ) + { + finish(); + return; + } + + vector< WordArticleLink > chain = dict.findArticles( word ); + + for( unsigned x = 0; x < alts.size(); ++x ) + { + /// Make an additional query for each alt + + vector< WordArticleLink > altChain = dict.findArticles( alts[ x ] ); + + chain.insert( chain.end(), altChain.begin(), altChain.end() ); + } + + multimap< wstring, pair< string, string > > mainArticles, alternateArticles; + + set< quint32 > articlesIncluded; // Some synonims make it that the articles + // appear several times. We combat this + // by only allowing them to appear once. + + wstring wordCaseFolded = Folding::applySimpleCaseOnly( word ); + + for( unsigned x = 0; x < chain.size(); ++x ) + { + if ( isCancelled ) + { + finish(); + return; + } + + if ( articlesIncluded.find( chain[ x ].articleOffset ) != articlesIncluded.end() ) + continue; // We already have this article in the body. + + // Now grab that article + + string headword, articleText; + + headword = chain[ x ].word; + try + { + dict.loadArticle( chain[ x ].articleOffset, articleText ); + } + catch(...) + { + } + + // Ok. Now, does it go to main articles, or to alternate ones? We list + // main ones first, and alternates after. + + // We do the case-folded comparison here. + + wstring headwordStripped = + Folding::applySimpleCaseOnly( Utf8::decode( headword ) ); + + multimap< wstring, pair< string, string > > & mapToUse = + ( wordCaseFolded == headwordStripped ) ? + mainArticles : alternateArticles; + + mapToUse.insert( pair< wstring, pair< string, string > >( + Folding::applySimpleCaseOnly( Utf8::decode( headword ) ), + pair< string, string >( headword, articleText ) ) ); + + articlesIncluded.insert( chain[ x ].articleOffset ); + } + + if ( mainArticles.empty() && alternateArticles.empty() ) + { + // No such word + finish(); + return; + } + + string result; + + multimap< wstring, pair< string, string > >::const_iterator i; + + for( i = mainArticles.begin(); i != mainArticles.end(); ++i ) + { + result += "

"; + result += i->second.first; + result += "

"; + result += i->second.second; + } + + for( i = alternateArticles.begin(); i != alternateArticles.end(); ++i ) + { + result += "

"; + result += i->second.first; + result += "

"; + result += i->second.second; + } + + Mutex::Lock _( dataMutex ); + + data.resize( result.size() ); + + memcpy( &data.front(), result.data(), result.size() ); + + hasAnyData = true; + + finish(); +} + +sptr< Dictionary::DataRequest > SlobDictionary::getArticle( wstring const & word, + vector< wstring > const & alts, + wstring const & ) + throw( std::exception ) +{ + return new SlobArticleRequest( word, alts, *this ); +} + +//// SlobDictionary::getResource() + +class SlobResourceRequest; + +class SlobResourceRequestRunnable: public QRunnable +{ + SlobResourceRequest & r; + QSemaphore & hasExited; + +public: + + SlobResourceRequestRunnable( SlobResourceRequest & r_, + QSemaphore & hasExited_ ): r( r_ ), + hasExited( hasExited_ ) + {} + + ~SlobResourceRequestRunnable() + { + hasExited.release(); + } + + virtual void run(); +}; + +class SlobResourceRequest: public Dictionary::DataRequest +{ + friend class SlobResourceRequestRunnable; + + SlobDictionary & dict; + + string resourceName; + + QAtomicInt isCancelled; + QSemaphore hasExited; + +public: + + SlobResourceRequest( SlobDictionary & dict_, + string const & resourceName_ ): + dict( dict_ ), + resourceName( resourceName_ ) + { + QThreadPool::globalInstance()->start( + new SlobResourceRequestRunnable( *this, hasExited ) ); + } + + void run(); // Run from another thread by ZimResourceRequestRunnable + + virtual void cancel() + { + isCancelled.ref(); + } + + ~SlobResourceRequest() + { + isCancelled.ref(); + hasExited.acquire(); + } +}; + +void SlobResourceRequestRunnable::run() +{ + r.run(); +} + +void SlobResourceRequest::run() +{ + // Some runnables linger enough that they are cancelled before they start + if ( isCancelled ) + { + finish(); + return; + } + + try + { + string resource; + dict.loadResource( resourceName, resource ); + if( resource.empty() ) + throw File::Ex(); + + if( Filetype::isNameOfCSS( resourceName ) ) + { + QString css = QString::fromUtf8( resource.data(), resource.size() ); + dict.isolateCSS( css, ".slobdict" ); + QByteArray bytes = css.toUtf8(); + data.resize( bytes.size() ); + memcpy( &data.front(), bytes.constData(), bytes.size() ); + } + else + if ( Filetype::isNameOfTiff( resourceName ) ) + { + // Convert it + + dataMutex.lock(); + + QImage img = QImage::fromData( reinterpret_cast< const uchar * >( resource.data() ), resource.size() ); + +#ifdef MAKE_EXTRA_TIFF_HANDLER + if( img.isNull() ) + GdTiff::tiffToQImage( &data.front(), data.size(), img ); +#endif + + dataMutex.unlock(); + + if ( !img.isNull() ) + { + // Managed to load -- now store it back as BMP + + QByteArray ba; + QBuffer buffer( &ba ); + buffer.open( QIODevice::WriteOnly ); + img.save( &buffer, "BMP" ); + + Mutex::Lock _( dataMutex ); + + data.resize( buffer.size() ); + + memcpy( &data.front(), buffer.data(), data.size() ); + } + } + else + { + Mutex::Lock _( dataMutex ); + data.resize( resource.size() ); + memcpy( &data.front(), resource.data(), data.size() ); + } + + hasAnyData = true; + } + catch( std::exception &ex ) + { + gdWarning( "SLOB: Failed loading resource \"%s\" from \"%s\", reason: %s\n", + resourceName.c_str(), dict.getName().c_str(), ex.what() ); + // Resource not loaded -- we don't set the hasAnyData flag then + } + + finish(); +} + +sptr< Dictionary::DataRequest > SlobDictionary::getResource( string const & name ) + throw( std::exception ) +{ + return new SlobResourceRequest( *this, name ); +} + + +vector< sptr< Dictionary::Class > > makeDictionaries( + vector< string > const & fileNames, + string const & indicesDir, + Dictionary::Initializing & initializing ) + throw( std::exception ) +{ + vector< sptr< Dictionary::Class > > dictionaries; + + for( vector< string >::const_iterator i = fileNames.begin(); i != fileNames.end(); + ++i ) + { + // Skip files with the extensions different to .slob to speed up the + // scanning + + QString firstName = QDir::fromNativeSeparators( FsEncoding::decode( i->c_str() ) ); + if( !firstName.endsWith( ".slob") ) + continue; + + // Got the file -- check if we need to rebuid the index + + vector< string > dictFiles( 1, *i ); + + string dictId = Dictionary::makeDictionaryId( dictFiles ); + + string indexFile = indicesDir + dictId; + + try + { + if ( Dictionary::needToRebuildIndex( dictFiles, indexFile ) || + indexIsOldOrBad( indexFile ) ) + { + SlobFile sf; + + sf.open( firstName ); + + initializing.indexingDictionary( sf.getDictionaryName().toUtf8().constData() ); + + File::Class idx( indexFile, "wb" ); + IdxHeader idxHeader; + memset( &idxHeader, 0, sizeof( idxHeader ) ); + + // We write a dummy header first. At the end of the process the header + // will be rewritten with the right values. + + idx.write( idxHeader ); + + RefEntry refEntry; + quint32 entries = sf.getRefsCount(); + + IndexedWords indexedWords, indexedResources; + + set< quint64 > articlesPos; + quint32 articleCount = 0, wordCount = 0; + + for( quint32 i = 0; i < entries; i++ ) + { + sf.getRefEntry( i, refEntry ); + + quint8 type = sf.getItem( refEntry, 0 ); + + QString contentType = sf.getContentType( type ); + + if( contentType.startsWith( "text/html", Qt::CaseInsensitive ) + || contentType.startsWith( "text/plain", Qt::CaseInsensitive ) ) + { + //Article + indexedWords.addWord( gd::toWString( refEntry.key ), i ); + + wordCount += 1; + + quint64 pos = ( ( (quint64)refEntry.itemIndex ) << 32 ) + refEntry.binIndex; + if( articlesPos.find( pos ) == articlesPos.end() ) + { + articleCount += 1; + articlesPos.insert( pos ); + } + } + else + { + indexedResources.addSingleWord( gd::toWString( refEntry.key ), i ); + } + } + + // Build index + + { + IndexInfo idxInfo = BtreeIndexing::buildIndex( indexedWords, idx ); + + idxHeader.indexBtreeMaxElements = idxInfo.btreeMaxElements; + idxHeader.indexRootOffset = idxInfo.rootOffset; + + indexedWords.clear(); // Release memory -- no need for this data + } + + { + IndexInfo idxInfo = BtreeIndexing::buildIndex( indexedResources, idx ); + + idxHeader.resourceIndexBtreeMaxElements = idxInfo.btreeMaxElements; + idxHeader.resourceIndexRootOffset = idxInfo.rootOffset; + + indexedResources.clear(); // Release memory -- no need for this data + } + + idxHeader.signature = Signature; + idxHeader.formatVersion = CurrentFormatVersion; + + idxHeader.articleCount = articleCount; + idxHeader.wordCount = wordCount; + + QPair langs = + LangCoder::findIdsForFilename( QString::fromStdString( dictFiles[ 0 ] ) ); + + idxHeader.langFrom = langs.first; + idxHeader.langTo = langs.second; + + idx.rewind(); + + idx.write( &idxHeader, sizeof( idxHeader ) ); + + } + dictionaries.push_back( new SlobDictionary( dictId, + indexFile, + dictFiles ) ); + } + catch( std::exception & e ) + { + gdWarning( "Slob dictionary initializing failed: %s, error: %s\n", + i->c_str(), e.what() ); + continue; + } + catch( ... ) + { + qWarning( "Slob dictionary initializing failed\n" ); + continue; + } + } + return dictionaries; +} + +} // namespace Slob + +#endif diff --git a/slob.hh b/slob.hh new file mode 100644 index 00000000..9fdbde94 --- /dev/null +++ b/slob.hh @@ -0,0 +1,24 @@ +#ifndef __SLOB_HH_INCLUDED__ +#define __SLOB_HH_INCLUDED__ + +#ifdef MAKE_ZIM_SUPPORT + +#include "dictionary.hh" + +/// Support for the Slob dictionaries. +namespace Slob { + +using std::vector; +using std::string; + +vector< sptr< Dictionary::Class > > makeDictionaries( + vector< string > const & fileNames, + string const & indicesDir, + Dictionary::Initializing & ) + throw( std::exception ); + +} + +#endif + +#endif // __SLOB_HH_INCLUDED__