From 14953c19e7f35fe4d8e63c94bb5a0613576a3fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Sun, 26 Jun 2016 23:59:58 +0200 Subject: [PATCH 1/2] Add support for .svgz files to svgload --- libvips/foreign/svgload.c | 77 ++++++++++++++++++++++++++++++---- test/images/vips-profile.svgz | Bin 0 -> 24962 bytes test/test_foreign.py | 4 ++ 3 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 test/images/vips-profile.svgz diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 9bae681a..3861963d 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -54,6 +54,16 @@ #include #include +/* Old librsvg versions don't include librsvg-features.h by default, + * while newer versions deprecate direct inclusion. + */ +#ifndef LIBRSVG_FEATURES_H +#include +#endif + +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) +#include +#endif typedef struct _VipsForeignLoadSvg { VipsForeignLoad parent_object; @@ -315,6 +325,9 @@ vips_foreign_load_svg_file_header( VipsForeignLoad *load ) static const char *vips_foreign_svg_suffs[] = { ".svg", +#if LIBRSVG_CHECK_FEATURE(SVGZ) + ".svgz", +#endif NULL }; @@ -364,13 +377,66 @@ typedef VipsForeignLoadSvgClass VipsForeignLoadSvgBufferClass; G_DEFINE_TYPE( VipsForeignLoadSvgBuffer, vips_foreign_load_svg_buffer, vips_foreign_load_svg_get_type() ); +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) +static void * +vips_zalloc( void *opaque, unsigned items, unsigned size ) +{ + return( g_malloc0_n( items, size ) ); +} + +static void +vips_zfree( void *opaque, void *ptr ) +{ + return( g_free( ptr ) ); +} +#endif + static gboolean vips_foreign_load_svg_is_a_buffer( const void *buf, size_t len ) { - char *str = (char *) buf; + unsigned char *str = (unsigned char *) buf; int i; +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) + /* Check for SVGZ gzip signature and inflate. + * Minimum gzip size is 18 bytes, starting with 1F 8B. + */ + if( len >= 18 && str[0] == 0x1f && str[1] == 0x8b ) { + z_stream zs; + size_t opos = 0; + unsigned char obuf[224]; + + zs.zalloc = (alloc_func) vips_zalloc; + zs.zfree = (free_func) vips_zfree; + zs.opaque = Z_NULL; + zs.next_in = str; + zs.avail_in = len; + + if( inflateInit2(&zs, 15 | 32) != Z_OK ) { + vips_error( "svgload", + "%s", _( "Zlib init failed" ) ); + return( -1 ); + } + + do { + zs.avail_out = sizeof(obuf) - opos; + zs.next_out = obuf + opos; + if( inflate(&zs, Z_NO_FLUSH) < Z_OK ) { + vips_error( "svgload", + "%s", _( "Zlib inflate failed" ) ); + return( -1 ); + } + opos = sizeof(obuf) - zs.avail_out; + } while( opos < sizeof(obuf) && zs.avail_out == 0 ); + + inflateEnd(&zs); + + str = obuf; + len = opos; + } +#endif + /* SVG documents are very freeform. They normally look like: * * @@ -390,15 +456,10 @@ vips_foreign_load_svg_is_a_buffer( const void *buf, size_t len ) return( 0 ); for( i = 0; i < 24; i++ ) if( !isascii( str[i] ) ) - return( 0 ); + return( 0 ); for( i = 0; i < 200 && i < len - 5; i++ ) { - char txt[5]; - - /* 5, since we include the \0 at the end. - */ - vips_strncpy( txt, buf + i, 5 ); - if( strcasecmp( txt, "FSBTS=w6yWt_kN1B%or9-6QyB9xxEqnLw z&dfPyX7&PQED8+x0|)P*!s`XkiGAe$(N}}xB%3^v-S9__%(R*9@4u!h+}E~&Voa#y zXOcvLA1$@0u)Fw?zbrC~iLI2li--&BMkVxdzl+k?=3KJOzX~k4^t2LzR1`9uTO)K! zriZ<}y{4=+U?sRYApAlYHL6;dJ?$v7F7ui~wJr;v!=6z-*fLUs^>c_dipbiT{{(J< zG&u^!bbQw~>FkvJ>uKy)%E2G=P|O%nKM3T~q!jJE(d$e)SuI)V<}g;`3QK4h%HI4@f{dctk7n+Y5Q8;h|%ewuoy z&Un-}!d&TQRk$2ozUnW*s--AfUD>6uhda>f(dBoD;s}jOS6}~b-a;6A|IoVP7?Q-; zUe)trwBAs5`@}Se05d1wnyE$gMZatoa}t5E)nb%DgmPa{_s29sUG=gW_ypHE+i)Ad&Bm|*EdeqAEr zHPPWDV{x9k5SBWm{=A$mAY&cJ65Wn^#?--1Osi=?fc8nFzde*F4?*wM_Gh%A{0ZCv zo?LYw*^f8O9{*wHkmsY2^1%ouZFXn}D+_q343r)qR_dW)Ru{clNND1hpg==QB_!YC z2kdv5P{ZZT;X3`V=RIs?fEUU8%jiF=+?E%oKwLQ7S0ZL)EX z2Sl!e2ctzwxU)R^XV(li1(1_l(i_oRr1|bB)IrLU4!7%=E1ZYo?9xP6 zF;8eV>_v;#6ACG=Mg&?s;#W)qWE(5j@^nnrlmpIn%37W(b>5dSnTAI>BF7g!6{#bh zVN}H!^R??$0q}J3q-r!@(ErrZhQ4VRW9<7&iu-c;IMO6$iSk4IxpYqMn%D0)zAJrJ zLG3)tHqFOg_HBv}+8GZzECuEzPuciBE=r=@c%gO|Kb+s2Dk1IaFYM=cWeTBQ%++tF z!nb{^xI()~#Yy}2S6=sP@H@Bg$Q#&uULK7S&kG`$ZTL*SO%Hu9Y}wHxCG`&wHm1ns1u<-N)RD=(YG>uT0ArHkQOS9u++b>#g?7n7^w^SpN-vQNoSwNho| z*BXZvjJ8G{$)!x^Bp7uwRQ!>in77Fkb~lLDh2&t#7Gc{j?|B{a#(Vt+>#>R}jHy>y z?(hX9-^1hh$H^V!yw$>&G-*nZuAjezD`X)KNy)N&kAc1{x;O84zuQrploG5iJ;G5j zWUZ3dQ!PnS*HHQ?68UpsrqVt?Aq|cW^4D?`_8!CcTIn|}8ZlfFB+UM@ZJf|{Uk1$< zcY+R!xstq(y8`feYC>!y;eGMaT-)EP1TBd26Bup=>8AJI%-HxCll+`Nv)31$n^802 zwwHkrBV+UPP%xkjF)8Dt?4Cnmv86u1M%zbr_g<$p`*tiJz9v=s$z6NPyIXtk;-ddk zXqO8|U$Uksx|a`3QI=~t#^=doW%p!Zd&#B<9S##RX3~atIzbIbv-vC|J9&hB-L9!{ z@|p~e5s=?MfA+wVQJ!Ec)=Su$E-6U!AWScR7b13Yg7Hz7(p75Wm zhPL_kE$Zvfg_Voem^H;OoVj`KKWTXdw{umk-NJ_oEi#hT*5r~XR_cY>qscRLemws0 zVPSO&c}@tQAujD^P({9{8#`Q6L5&eHq8v?HX`J19+d>49jS_3{tkcVY+NJitUyZJs zaR0rakBhk;6Y>~ILWbLBpmyzZAIzx6t7ueMfqD$>Ei)A+q6L;R&N6x|FeDBkIY^|t zuCL_oa;nJ;j$%(&_CSP?vG$FVR(e9y8lqLuCSyq4!%$ycykNoXTK~>y?Hoq!O!xAh zQf*HF-m7Q2$|^72Fkdu4gqM@rq&!YirdE1VXoq*EfL%>RSQf?8rvFw z{VVb5aODkYJ_z}i+SA2xUIf$I_a7A)LM(DzpaiMsFL&DBIQ=_ zZBIP3zG4!GInQ35Ra7ClNed_4lr#Ni-_BBKvaP@ZTlxBT=EhNUD?Q`(-X(qc_TCF2 zRkNb~VLMMR!}srcYLfTm!}F|i$-P?=4AJCR)7u;dgEmWtiz ze5quNL>sjy0V#ULWG>27 zPa#U%%nQ3BisxEPlYig{lPwiQzI2ME1@0RZd@Wc|5ygMOjVLYRN!_fBIcvr?X_GDz znt*qnqF(q(R(1@J5ix#gU^&9GQHDgnGjy3skL=!vHeVFRaDTl@XEm>t)?$%*<}y+W zACfzg-52?p#~3bV=^YxjJlzXe%Yp{-Xn(!+so$6A7eQK<3Qgqdf*sL3mBK31N{V3-jM=`41lNR%y~p_#QK+6gl~Yfw13mqy@NpUEK576@ zR&d*kb!^I^l0`=Vn=1V8JXH;)e3pa!3!IMQbL2Nsn(I|?I}*j1w-}JX*EA!?GIR4a zL#wLkVT&P6D8|Fe(u$;hq4c7OF5UBIjVfxRf-ZyECaiESICCz#@ANqWAz35CH+k4a z*I3IK5fASUzg?GF&lV>|y-;F_wfDH&^W-{? zQA4u&w%1rxMpSOUpK(gN=5kWx^9uj6>)Q~Cw2w@R=p0tjwdTzywI?wWhhM0%x$gy#A$;(ta5`AIMb&Zp(KP78e}peB&-_YpXZYB(mTGKUrZJk{ zYqe2$4o0rO=cQ-J`q0#a;P0Aoi1qPrEsB=_9aSj_At{T+S-N!Uhc9QjBw`_yGc;;J zZ%a0~49CnCP`^_V&tU7H)|yB4=8!26!Jwws?0&v2MOc&G!r**-;5Aa=D9BuV13_0k zrFUp>9PuxH%lJ}F!`S$38nOqA-p|6A$Xe8379U5u!)QMoax5X7_-T`CkcuH?#kDE$G<1e!?iu*gEIAe6w;mhwoxken_=j0LZ&>9<1rroDYn=d8I z9Cb@M-std(VefaTH2DSRFGB;obDQY}k1Fbrvuh%^@T7B5e>z5@FIddW6qHvv87>_u z(FDGGQTGK)`DcfZk4A;2#Ebpn+VXn)(!jr}^qrMs_1#gL8CLZ1)s{<8A?F6YthIn5 z)_GxjnOSs%v(_IGFNve5X5!3@q@?5eS`+Yzom*(Mn`lB~4YZ)_^Ca&|ozCHNp7x6i zqjvaWk<6k^4DEI>oVZ2aSC|bvAXsIwU{zmD)UAC>_9s4w`!Yr?Y){vi?wO$Bp7D0Y zwZDUFxQ-|}l!NJ7AKg7iOtm+Sti*!o5Zx=94%2vQ4VBF*r38V~$Bp58UYrBA>y2j< zZyp8ikVU;1wQ#MaYid;Co7!!|SF$++F~%SJeAmO+5sy4)pfTc2-{eT_5v!OFvRUMZ z%2;+KhK#?d#vRkAh}$bHGQAr5YZ7LcR=Dl*`E$ds6Ro#D7j0ckuq&DizUj0O)(s@8 zCmtByoPBA-a3lP7Z|czgbY3?d?~7@lgqS;v#Ac?K;ml*=zA$(?g}`baHV3&Mf$D3ZKuCxHk!Bw*=tLirV^pU=J~)P$=kX$^yC10LKdoC_QwnDYb)g6JqTV(&c`lo{qFtIO{dE9^UCCJZ*$o7URKFAn~wp;@fNLF=MbE}+kg*z0N)njXk3H=PGh;F z-`AC$Sp$(A`BrY{k0oTOA2WNbRwbD3Lm-^O`fgDZNz9mHpGdzeVI}I@(-+H8#PBG&nx(ra4=#oJ^a{Sa9y~ z7Cu6W1jF;=uZq@f=Gvly&ztJ)`s~NKLryQtM*CSq`UebyX{z=&;fs)c-!jm?HniPp zB+TY`$E+n>t8zJN|R@%q2$E@v`==G=K8btfY)9N@5(Zg(N2| zt7gT|qw2)ZKWm4(r|e&MyMEe`DnfC9Bre?ChEgAWd!sZ;uC`lQhKV7Docr9a+UU_8X1(b;N1l_&m{FW^($Z8! zv=3x4?0AdGRFor~Pon6lsU}u7crRKmk@^PQ9WEq}I+ut&EXzpa1vU7cH~EuOx{54F zDfR2(0uJw*HI?0JC7;FvJ#(o}l(~n;s@H!HYgiT3FXg{x-z_~?zdY|^s+KWJmTld-{-guG(OfTUtOg(mtY4@o{)unTw&iJ^QXUv>)$o71C5$l|-d;7_97rzG{_Q>DKR{Odxrc!nz*#-KPe^Vp zN=}<1GkG1_yoW$X(M_VhRVtGnisK(SeYdzu-4({e2o<@ulAa4k6xl}4p%?$e>QMHB znJ-+^l?Q)asWVb^vXf)9JTBgHql+B?b3Q4A$#DUnvdN#yn^{I@{PrR8|JQJZL}>3sk#ecYLIO8Jg1uQRQ2hIHeT3 z_26q>K%ZV%h*4R5m?|rt<7)~0lebd7Y^1gm>{p9Qcdn9O^PQ!iA?ee3cf?QS2xtyN&UsjUP?9ceKSFxBiFd-IH`mC3Z1Vzo!Pvn z^z1)k$&ogUBaF&Fs~fLmquo}h*aFhZ+bYsZg_sZ0U&Uf+UlU4IUU>{7 zmlcm+{+#3D>u9^=r(t~z9KgI&t=AJ$-LncyVqA`&31`$zmY&0U1>+hEP8 zU|0h>i(uA+Cq0PX%0_T&-?nPlSjo!^N%J3wu1+b})tF8}g&wu;Q`91<`5(oirJrJ> z9!4u8W)F;@cG6|mn*GLEDRz*UpD}Y$ypO6=x49t(3r{m&qbcSG#W_sPi*8?_P3S_< zEf9l7OFQ=LjyoG=i)ozgbr&u~x&lz|0_-!^vZ>j-XYLrG7#!JRhkGfee6n$E!*87# zme(GqAi7jcxbW(KUbW&W6xRA@H0kD%_ig-vzV&vwlGQW%bbAw_(Q~iKDnL5SO>`L? z^zaxSB=AsnGLXxmtv@<>f2rWP+_cmjA+TEzoL|uKV7z9h=0uMs-L`tMyj0_C-19^{ z)xMyQR?&dt?&RqVb62!iD-^un^OsC;5_0 z^i#L;1*^T}hB*Xnm^DpJ%zj6=60=h3OP+<8DoaYep1d;d6m%R(%O3V~rJH``bWv=) zfzwUw@`;%THlF^ct2!juN4AO;BmS}5{j=R@C|icU_3}!|9BkYRAJJ4n8XBocVrp`t zO=#^eSGHVkg*GTt+Pjxx7w=!FlF^hBrI?I-zKkI%$&~q0=|MvK7sXnDN2P-dkufQr zqoQT5hp1j3yt!Y(&;A(4`g@Gf;z=6U|4XYq6f-@K zY3XVB#TyZur@vm+PI5{ofiSR?Os)V(Sq;hhd+UCkUNax41nTx7IUJIhZ;#vHhm1;Q_!yw#fA4na8tyU*QQ>&!99_lF`IQ}YWgd(q6&}hm#h$pw?ic)tloTY-9C-= zSN!mVheDDDPORBW`%1Lw`MC{>GTF0O4Y&?y_!9$yy!_t!a$>L>a&gmCtE*%vrQ7To zriTGr9)7RsC0{?`|TVSnyZz1l@|6qqHw?FXXpU22|c-leXREU`6Eh~Ouc z*H#WtkG%!l9BB*MGyxsv;m_9rPJ1y~s0#RZJ|%u>aJS)n_g8>l)hPHz4saq~{Bkc$ zf8x>B_bx^x{k@hAL1O*3ObUMXYzTN*m{kt4!Yg*qVG zFPYVufaf`M&1hzIhe{a}>knS@Ib*Kaa)VPVI|Z*(g0d5gJ*vbDsdh80+=v5uAd%wO zkUMKP;uV*!;4AlK2a=3)3u1jWM=bj;K?mo8He*|tflIIdsNsCYTV&?p7Ih zmMkFp4&NtWJ{NDk!$^NXrxP5rh_aFjR+n=9h6IUv^C{P&Ub0~Xi5@@0t~TJD5eOg) z4`mGq(u+v~9gr514L9h|k1M6X$BK>aiD$9Tpps!uJReAK)$klN=+JYx9jnHzp2N@R zQ};Yii}nu&TO82v*j6td?f0>UQtM)kU ztq8kQ@6wP?(iC?;o6R$oDKa=0c&}7eEd(G4BpRl=0gRi7x=k9~po>qAwRDi?CF5|$ zvNj_QXkn44&N$G$lOTBCO&vKfgUj89?$nAj=p80M7U5gNA`zf|_cf4)w7l>1Tm%oT z{&RLh(@7A)OY<$Pu9FsBtj9+@-;i;n$$UpJ3{viuSfF{=yrdk7-HS%!ftGtat`c*I zOGeCBeXOlha?Mg#O0iwm>=}Ld^C5@b5PODw!NW3c~4!%J8@5sDrn#19{Cq1j#Ic*(5&~8vkpZDXg%hBC2 z|Lw$jj99+&$UhoXhL}FTQ?~O@I}I5B==0I% zIc^OSQO{ZB?-@xxp0byX7n@P)dxP@6dVwflqss3qU!_ooN?x%>k6cqK#B&Cz)g`@; zvMhss8l+31U%JO12kr632lvEv%$u6T1v#G122zWD=^7#bqav@)ap0$Ix|ApAZt)ux zo*VHhC5ZcQ-wws{<>=qY>6IEDACA_9gU%*LL#kJO7AAc>*xh6DmLs;eFCR<&|(378o21n2TA64yZ8bC-Vv_Vdozw!Z|&Acl)a->t9=@~QJoO`Hi@s0 z)Y>9s)#~tOuVHm4=vJWvhZH7YVOGkgTq0#>BHZ3G)?ml~m1B+@r@-c|kN4qUcGOp# z4`<~91sZb}S)3bY-gaH*ZepdKZ`+8-T$-?(Yc5#LWeqS*RUN0ftonD7E}QICu}sEK7^T)CErWF@EzolWVfAk-@>lUjY+qC zA|?s8vuIPbu?QbVC)7R0Bgy)FvsQ2<_9YpXgqyi;g`S5?VmSzV=!wGl{jVM0{=U1} zlM9|?>TJx#+7$*KE@|itfBJH`tgMY!zSz`NlG zxgQZ^^aq=n3BzdFqiR2oH{=q#@?uww+k=C;=Epp}(HRDIjHy;KE_)1#oSlh~gBLRw zdfBYj3_x6Sw5Hvx21|IYBv$d{mIh1uaOTIC{C4hM8GsmVxXE`FnEH>o?QXGmosaCP zxu#5Lup`MCc%@VtE%RWG(C?VJYi@GM=HA?-_1BBM_{N(5m5XwL5NQOOZ#fzr3on76;>bE=2JDZy zYvYs7j8{!ie=u4OZoZS0{7oU>a$?WWZ|8z5;aypc^4p>B;p6#PbxI<3P{0#$(G!W9 zO5flKVSy>-ne3NwGg#9iI;Hbm(+72fRurrb+Bc6U`HKj>4XNlsk9$@@Ysmwi)s`2j zv3)oh(hKk{W6#Iz@Tycibf6Pqv+ccdewj`AqtpO>s#ReA-9FAbh*Gagdg0=EkLA(! z7lYAWeJ`W#*&c5`IC|e6o_gHEEfHU}YN0ke+*Ba4Y!>rBmjQyKW=vk`YfV;MB*lcn zrqC`J&o#smy>?s?exF`_%O9fvqV2#DeQQn3vA#GpLeq_N*tJk>fUeT27j0F`s~H*h z^>Dg(ID%TWjVRYeu()-2U3VD0l^we~MuwQvOt1C&n}}63B}kj+eq(;$P!{NyXG^vO?T*6Y!^-(ui2ix zQncofcfupi`eIw4!`cFh%BS_izd_?R8pKhGmYc^=v)3)>`zVSd=XjHgI&r#_Fjbqf zg+(OaZ+R?;p%iU_@TcJ++sIGK6KslO>k6%8{af;^kW3tHv>Bl~AeO`#(sPNyX&W@z zX`*FmN(=P>e8hwr3#;EsR6%&6DgJ3vmeZ=q3ah@Gefod2R}7k_2`A(E#>I=X&5=#To~86;W0+tBD=#-5kGXpEPI3 zh5n@c2QVk06}|rSniMTnxX>@lInu%Y>-3zxEP9QV56SZ?+NORf__t zrhit-E6=z|cQ~$9Z}iK9e>ST*gFz5)#e&WPAZBZWg0iv>a;xN49)S%z>J_e2@G+YO z^ij?6+1HBI@gD&N4F4eNk$?Lf`C6n$+VN;ujj-?3H$Sb2IZf<{4n}&$ZD8ZqIMy=idLEY{Gc9bW2uVuykWgBdDm9}$-R}s634ZhYlwybaL1k?%;WHp~PW6nxE zAlG-ZS|Q52<&3W0l$=F-fyL&ggwt3T)X5|9QpVqsMdO8ML9jli?eM7rPk+|}Y|rO8 zSJaRHLBJk=UvIa9Hs(k}E6tPA2>a^o4}w_%Cp@B?l12U#z1FYjidZ<(!2Y98@=FF8cjrr`%Z)ky1P4qO*ASP@Hy#Z% zKYXcqXrtnOJXE`n>h|&tcI;|)&5pXn3Op*W$!nP}?yw2&@2nKJS9|&Oa)I9&W>it7(+vDX=&E7MjsXdg00pFPe(SwKMr;YiV z{J=3FL+qe{Hjdul%_ZE}y#62Bzm{Dkc4rB_gQTBnj?`gw8l1~n%wr8U_8^HGJ}ym8k39Yw+S~{j z&0YPtwHQ0piFe?=Id|LdrV`@WS?>|G5jNxF%yU!)wI$ol0zBoF> z1z#haG^hg=3d{e`VM!sgPBkvMhQ=trc|vM~d@dYwOpX5H@W z6PI}AaX|pi5$7|g_5S7)5$Y%P6hJPU2Vc9h>U*Bau@c>cQ7PM)q0Z-P`~Y?I@dz)o zmo%wHj2o|=o9&M2LXwm7Y5y9(D^>^e4Et+?Mny%moto}HHvW)MkZ;;vAq)H$DQE4| zeuP!FeEJJzItXn^q9i)`exQ7L;TMXkTrys+(Lj-O=VY+3KSpB0>Ai*LK4{9awfMv# zkBHD9)KUiALe3{D`0FYIAD8sS^iP$dBKS^QgVh9EgPSP2Tk!}KajX>N@3sbi&ekm% z99S~aeioJ1wXjvh*Np0Wi}inODTj7?daPIZ7c8A=xw7woPeP8&beqbrf9%Y~Rehx7 zM+x)wf3iRb^kgx>5TKuY7j+Wo0zIlo zckcVm3;H;r@h?o-k_gXhR289M03Uvt$+al&+1opfHdWMV_W$jkiL``PRW;XfikWoi zHPY@kL8^%L?Po+I?KAYb`6kuwYb(FYTf`-dHU<*CtiJR!HxC$`(`%Iex6qu~(cJCG z&3;g8%Pd$@p&?;;c=$RbKK4?F2dxI+QR2cJ7P7WNXRJyV39`0wCnS$}S?pX}X)LOo zmj?rDEUurmtr_wSC#T0&=(~ghEu_o(#CL)cH&3A{KJE-B2eV2Q;^#!-Y3o2zP+KJ~ zEN!}R9I#x^DQ3G8Az~cW8mP*)AsI8Aj$ez7SscrYOQVzL2kDmq7gv5 z(PhUN)mn{6ssE+>3WP8@MW*Xsqz0Lz$Ma60&Evz!gasIBz@_`q|Rx(UWXBPt4Si64*trN86Ci*9Lri>s)eO!*8*^ws~Y-_|9v( z{c1T`npG$Wl7ciA5PrF8*%5G#Hqhf67VkV;ZG1eG-XJ{@y#f9J`dw}E+ehzj#FW>l z?K(R9i(YNKW;q_3Sdg2fu~I-RrtW&&c+rvRsZFVy&f%Vdm%j%%eMa_tXJ(G1C$FuY zy-m!;y0dkglp*8Sqb-*!hPbiKSdO^FMez0RNKC0=TfxqYLBt!b; zrtvhKG;Xg+m^P0-^tJ^n?3lSo|4lOw87ti5sb)iV<1n5#Us?3;4^<3nCpfoPLR(DCxN3R~j**^My&MQ45U%_CXXTAMzk z)1G5hF+(4ZuT-Ry&A~jt7I2`}kd4;fwF^>(lcT@z;p&Iw+~`<|(c=YzV}5&Ju7S|N z)@Rx5uBF}V7Hsa~fW9aJ8=Gt@&0R34+x zgv~R@!&~YJl>W)gDz)xeff5_o8^@6(M) z$33qn2?g6~hWCQ&9+0i_@{^b<`KGuD4suFUmiOCy@QEj2!5^&A@LoIei@~f zKTu7fqf%EY)wqA{Y&r}`>e?)WFqWqGmMrH&lxrqc{On4N_yCb`11P;{1W>}!kM}=| zt$ht?u(ct{PcmfY=HBRpe8nM!3aLWsvG_s7E!QvK?Z(pEIK*Ks=%GOxn zXLbQau-~h$c3K12FS@F!*3lFg#2sZOB=%4uW9|L{N=BKZpW~gd|LNzcX3&8-J)e0d zgE)-V`$cldx^NB(pH-9UZxY7E1Y#SjYnM8>l1FK_Dv6tx>LTJ89=g8Ezr$Jdos69 zhgeK|YFrrb1HlkG#T(2sV)c^y09Y1Y)s(uL`FuibgsRL5m;LB2ftGoTVbx__1Fgg3 zM3H5)=O`UlJZ1pJehJ|!J@0`@Hdu)C?TLNe3cRy;&F$In_Oe$2-{Z|iS??Ki%pv5Y z^*x*f`e907sQE5_R;`(u2aNJv{QkC!65T(v5E84~R2E+GIJW>wjCCdBFMC6zgQd8= zSAq=q%CI07f$0)pU3C1xkOE)sWn}3Fj;`W{B)4ORI(Ktygk~RbUXtUJ$g1JONwFhP zJq2>~1B9D)1QM+|49j@y@|N73e&q@0=x1+{=lnJ?Ji(+mF<@O;v+I~3sk?cowhXkT z?xm+U_mJ{RRuVy9=upZ|%3EHOtTU%1A=!d&cBkcM{mbJ@Lb`?5Jm(e{;G_>=z}Moi zSDwNEDTd85^7ACtka%kmH#Pdl7H;Sy?K|j7TZxf*8Ke?bKW{nMlv!D#tJxuLdf}d_ zuFsO4QsdPE0BBo_PXRHKac+xIpCWN@QRr*;Yafs zf=%Mq50qt3O?b9KS7jFc3_~NG*s?%fEGyrW3 z^DUnI-qj}t(59?wi%=d~28ml0p)2uko0U_?XM*iM9eA6zpsJOVbe5t_K!)crd0%*;6AbKF(SGOj1Uht$STJLJBfHJ8SUks(q8h&}g__ zOA$0L!Y2O{rx10Ae0m$ZW~tIwz2TrW%ZX?R{R);tN769hIO^RquX_5;RWX}@w1B$Y zmpTUJs#}^D=X>cK zfe`mLV~9z*G_bt^Q@w>yl2Op34x}mmKQR^dhaHUjq=7a^pGF^JiZbs_u!k#{zB|`p zM*!>MlgDbth^=AK9A?mVThyAd1@%Z3Up~4 zSUT>nHKjs=S!XAgzz6;SW`g*8`Q;&9X~@mQeYj>1<*6Xc@_-o2FFcmP6q#OE`31;< z;b25`sOU@}X?nlXXFI7*4Erq@MuJAig%`2#+DZHQi&{C!Z<g!IAoI?Q7P>by!G54PgmuBlKkWZMc7GZQ0r2%_vZPA)gW1@`DAtGW3P*6WW2K zX;alZ|R0J{p1DOl6N2958HVlj2hUo9fPu0k_DE)_3ZR{E9(^yAWOU=+y`- z1BZ7O?XJ3H^b!nBXjE&bs-Ik=7p#mz zz~BlUzB;7@-D{k^fCxBn-Rxpn6c5gv%)4WZZs(8`LU#&ZMCvnRNVQH^<;%6?LE@|^pu9^x@-T_GVJEl0 z^)Gi`>7$;io1LOsn|@Y?3rH0?h7^dEbEtaHQU#`F2B2&A5x2p{AzU;0UaL|JiX5Q! zo=dx|TEStRwHvuKM#QB@rRgV{*}?}POb5HNvifZ|{0)-Uh3idS5DRc6zlSsV4d4D6 zg;i#^2IpUR6K!OFB4eY94Bo}z|KGiVJDf`(^jOLMc+WF36Xbf>;0)TC5mt!J5nOa? zYqUt} zy86d0YOb94J$*bfWh}NUH(4k$3}_T$z(1o__Sez@nAT}_Yq>$Z)~V~IVE>QcHts)A zi-KbQJX0p>^w|MI&MQ-?|2r422JW-oSH}>bB>Epb=JG4Y#(RIL0JMJ)w`&&3gR(D- zQG3IjV5cfeb(hUf0y*1Cz1#lWKo3yM=9!^>8k~g2m=E z>dpAyDB!Zw9j8E-;lUGBWrutBC}k#AwjWfl=1lP>TAlKFB;;a-_{9PP_H8hMr_lMK z>wCBVf>EaUIZ>1b14gj_?+e;n8F2(`RCLOI^XeWvbQ$|369thTI_sN~g)+;>A4nrT z{0l!nS;GdS!Bwg9SBF~hxEB0jh80nuxY|*jMwJpk&zysyq{l39!DL^x77oArBYO{V zrPRC$TJs}k&H4_oNaP;ruUltS8k@5Tl-$<{o^UTvqyoW!U4eD243$Y^cMq#CCaYJ{ zf}H4C^3>NUG(iUh{7AsEMTXpc_;=K`9uexQh_93r?EH3@dVJo z<7{!406{Pq^sF*w00ksv@g3nGV!8_9U(vwi&^C|qZ|n5r*aq9JqKB1>>V;Oe`}>pY z*Aaa@#}S$m=Wz@e>!32ClASQ5`j84-ns0d|LK1OfRmD8eW&ZEA&T=&%zIAgVM3rue za#%41vhIfmOp4rZ?^s54Xu4#3fl(sU?@qyZ<3dIF3bpJ#zc19nW=PL)dMj= z>rff1>)?Qq+1XH6214$^MJW&|bg>OqX!mxRaTt?H7)S7JZ+-nu9a5;5j)gHRB$uUv z2W5sNKv7Jl-&9Kv$V@~5{iaFp!B8^hinPlCLDLCnqlM3nzx)lvV%xXCO^3!PN4*v) zM{T%qDwZ!9Hqe7uhyA>r;7i@UeLkJZDbmkl*Pc0j``~FPI^##3d4NtwrX-nU<6wtvmEI znBCxIN85RP)nSb+7W)P=VGB>?_3L*)Oo%Azy}a~S*r%G$hdxW*GWp(e+E0ghKxHf~S&760In)t!>*^?s8WqR{RAt;mRRKolZjfjMYr0RP6wufP zWV?`QUkY=${k*H2=iHB$T!s6b@X(S4HJ;O@)OHLEsIXe>8z-rsh}fu)DTBtF9LdP< zpC3!Jy6^4HGYDiekOExn7Y*5^koU&&&K*mOk=gyk(fR%tFP4>Kw&IVIMYuZklHBj7La3H+1NR?;e zIfGPapV&j>P8IKSqScR)z~US;s`R1|DA((>32x47VEvXMP@%B{&SE$F8Ct~$)MY|! zjEc*|Xs8uR{Mk##2UjtVL z)<2+=HZAvvH~x0*>vdFO#S621Bi6$^bhuJ!UR4e)kvt3ItqM zr8^c>N9DYE{%zcpx&TSNmx6K&-DPTJ{5>$K6F?cP^x={Kcio+hce23fxb_1-1)V$v zK1H65K)d`u3+K8Nun`^3P^0jHbpT_{d50zi1$(4F{82aa%@r-X>9XJQavkRDTJ4Cm zOA=Ga56TrSwU-Ix6r0M2zKi;l`Q{#XkbJ?&SQB&464Yd@s=$2ZBn=Qm5kPz#t$;64 zssd!6Z-~P~C<9&&WOT&!nQlM3aGO{(xh_+AjRM5*9CdFL+4eb_s8Ra7s6YlUaLGLR zM1^p8nr1wIW=5a{xFm8+%E8dSewv+xkO9bFRp25+>t(sz@U1ng=V9_QahBEkOy6jM z`SAScGG)Zn0(5Ib15k2qPa~8zn-5$uC!tosX_n2zhmh|KhNi+I@0bO}YmS)SN5z%Q=HDw~??u42>QVTe9henJ-xxgL;$X~J1oubd#@*ekzgoaU%7VLO>fD9X) zuG4*-%_p|RZWMT!cLzh=$8qLN!(|Zi6&1Wi>HDH&EdyyUe)Ka^A;WVMi%IgY>Mxq3 z{u}5TC4eoFPc#`uB6wZ$i7xP$K2juTgXS;?pY2UmCR#2mw~y5R}>eG1-4mH8`1G}!8 zCwG6^jZS9m82(V|uDvc;DPcR|?AbArtmwP!&{3e!U31wj`_;7Fpk*{+8UJK#+`Z~K z@^YlTz+GcLa5K?X(AYdCxYog9v0iyOy6(PcR1h-fxs>?Oln~tLWO`9eyJ^7e|A^Or z^xt{A7&gRJwJQkqI(&sbu{y-}2->e=1yOPqIkjWy>dV`%Gk7w#=98ZdS#4GP6+aTd z9o5@A7Wk76SeQEVLmYwgeQyo13=q;XpmC7MA;W|C|=H zU%Iv-?LHe$Ke)gCKsw*-4D@A#f8$%`^*@wg{E~!IBsA(t_L$EfiG7=-_t;f+v5Gtf z)ee-{!_kTEZ2N!h-GP>3=nTjSx#`2wIl?6N%96RaB{%{t^I0r}Mf1LVHz67qrgZSn z0mKZ&uM*>z6tHc6n;^XC@L(|lYU$v7#NNofBkA`Dgamer+c*m0njRC-Dq&C`Eo_&g~09H9E1*fB8d^xel5{9g{RU`2s@ z)|8-10!T!GYOWe(H}yTspu8O5-8#daHnGQQM+rh)o%Yj8vEiZ-$FabDjW z%V}X$T&0+!R}G|yqH~BI)S*Rag5oI@=7)_)z=@t4?FqME4&VSceng<}{4f_ePJ?+( z-_1Tz1^=s#?=u=It6{4l_vxR7Orto0bl_0}yHamAdeHqU&veV2OGOCFnoDt+&lh93 zYF>KN)5*3PQZlDUkQnY9WgF(CA_C^RJ&0hQaVx>e?UO8it^*ahmb=3WVQQyE-S@xS zSm?=A8d8C4lup3Jb-!tY2#`R|4-3SieRJ_ccB0lhC-dw2Hj74ltc}91|3vihCrxy& zalkg3cGQx^_j?|OUCiP5ME{u_njzrQOEgwp{j^82tN#mEqGZs^@=Cp<+#c#Xun>6l zirOzW>JlW;`N8;&t;=};7nrI#I?wi+QjxTINeOV5(WrjI`5>@w);Y{;KDT)egN|$& z;Qi@ngOequ3>6#r+H&b+YYU_&2AU2-s^>0lbC2BU`KFO|^4#Bv3`Vg1S}SZqqk4CK z$j{l`CepzMy&ND!h0!p(E!FoSC>ps9VF!9iU3pAUEf3fD><1IvCT`UTE&vTS1hqqF zj2$JgaDCcePj&qza$n%-JD)cEZv-6~yjibFnNZgw(*F~an-}KufVN(S^$keuHx|V& z)bYT3kKi`)zwbPd`H_FU=|SH+C=v|tO{d692k0bEaUdZVOV6KsV67hRot1_u%wHhM z5q_q9y+WIsLCVFHLIo1@KgLwp-b?$GsUq9LojwDbB^avEjs0^oA;J_#1N!y-cet2q zd!m8Wjh}$JD^ei3TDb1l3`;10LQxQ=FShqu+iH~lGg`cR=D6vt0(igC&TwWW#R6}5 z+rDdrQ@HAVV6&wvVDD4|)@Ii3%P#m=xkb-4h4T+e)G-Ut8R~f8bC)(@6uOYN_eDsh z)D+tYe-|p_Lf&iYg1rOMPYSAt%&NhgpTK3`K*lNa`GeA)c;t@b9LqX+KM5e(3wyUt z9}W7BifT15p$)WL3^cn=KNLvG5h=(|go?&srJo&jwXt@aBkXW|3l!mjz+FTp z$oBjVNPmR4_w@B%l;DTGYkDb*YwUmU>M}eR!Fx@hO!kvGeFSySfwO7S$^FI<;DO9G zzMF(Hsd0146{Leg@brHzTzNcH?-w?MvCF>i>&TvD3zNp4hD3JRNtUsfDTB($T9iok zt+Gb;Wh~)mm!eP@dzS1=w%@(u``3Nl`@Ziv?>Wyo_ngOkZXfV{6uh=g2#G$pkuM|X zs1DIo9j~-!CBWD16+%%k4TvBeTDyNY&flFXmhArx8rjaV^fOuYKbXC}i8KQ7##7vW z^PF_dJ>|R)Zsgch<2`ZUezs*da(eh?lAMwX)A3Jz3+(fLYkQM@g4597VQ3z4N3J@{eBPHhf5@dsmtc6--1W4KaOZc zCDcTHye6i%s&ui!129^YPwJa}jA!*pU}+TDMv>go?REnmI;}<+|9;2+EDOgf8b>XO zWxBm`?)~!XU`dBkQ44hg{m;g4ZHa$R^A4617{x6~xG%y0al{(#u8q^OrTJ@;4QHPsDHcUeBG zuiPzwp~;h#HEycSj{Al%egwLqii2ck@fCyfjg{qJ1r}5do7^3udM1woa4xNCw|TvC zF|U$rBi)Bw3~LIL#cvY(Q|1>XKZz|RZ6r(UsJG2Gc*8Ab5a1HA5K-l0Tj>3aDf)b# z`$bvT;Cm+ar#qhrVd{lrJ?~8Ez5?`1A0a<^QgYNheJb+#o z=biWh(d;18U_QB6KLs>Q`-2oQT>p+Q?>a~;<$ zD1P2$cUOoJqd`W<2T80#QNJcWCWKxuSig)z*@F~KH3H~d+JhI8IMZ|Qw*h?F%f&}@ zQSVv}&H+_73)IMRC?pEOJ|va)t}j^S?XA|78ufZ}-4HvBagU2>1*H(+5Bh8fYmZ z>_PubRd=QYgBXEy34X`y}GX}1#r^q z)7e#B!E&^tGU8|FBe zawLmum+vyi#Uwz7grj8t8w!g>#2h@;sxFqkHePZa03ipaN2M-iM1Z7W)TR4Uto-_m zBw3K{d1%|I(m#f*Mca1%&k9va&z!}CgvHNiAG|4uH0=r^#xIpy`7eO6!n7OND^F?w zCR^Q2!RkPtOK>#jb!1#SiZJQUTC$p&Vszc>+^40<=YzOqXwZ4HY8}dDfRM zQ<7`$;c&7E-wDwhjZv3dh{2-UQPI>=u*10dg4}6G@7*46D06v1+{>=9s%y?dtYDOs zGpe*H{gq8Fyh=<1#` zegw$Xd?&BJbSYTDZfHD$Z7$P9$u7Q}_8t8QU=8GTIWGgI3&rp(Knvqf7=R9NUh+bn znv>djgMZVz=Dhb@pq@#V9s|5V*pv|eVgKnoB>X#uTq#E#dR18E(!;@KA7Dt!gY!UY z(5E+wMp?=S#3jHvSY(s{(J`a8GR3wa1p=x4&RBo^v}_sK0VZ_p@$B3L|9E`c=Oq?X zv0`_fY%AwJQKy;tMlL*&Wthz%vbB*-9^UkK(!{Qu)^(Y~DH^VLUVOlc+SJQb+F zJ2~yrywP+3SS+#cwNW<`eZPXl2Vp}Z%8Vaet}(+SpU0}D*sZ~aO`l{>5xX+w=afJ9 z?9X^Sa5LG@orbNiYw_a1)wQ(mo=1L}X4|5Ae4?m9Gvx2DfBdSuWJXTwW&d}Yws7?1 z0+kSHJB4`I>H%p5&(s9OPub?8!wC)+{=Lw&|HsT%m~Oas*E4PR9H|~+)xmCE>Jsjs z{HqvH$Z=C*aZbGjG%rAgU$x~gJ*S%Nl|6qNhXdB)%k=BKN&@!cvre7?%DGZlLC{`> zJfjNdP-S*uHUp4nftf_Lzvu1&eFiWw4R48W0Dw364$yjPm>$az@1lOVMU0n2I^PZ3 zMxFDQU9r@wAjY4giV2~M%cvZ6v`K4t{~qTVK3B?J1L9tjL7xKmXCj4 zKtlrLY5%pd(zt{@*#x@0%_@i%z=0lKC88GTyu){1{QR5+z|BH9n_08*6?F>~XnbV} zX@lA9ow8p^7!pO#O*X%4A>Uq2u1`kcZ(pL~pgv+;kzL!Jdhja@^RgxL&+h(FaQ^Y^ z=E~O)xp}eEi;$Ad`l^ zlICU$Q8aH)`}=a8OfJpiC!aKx+qVeI<24-w^tb)*=rIXGKxy=iwmEAligBNS(h$td zk7=(^rtTVx0c52DQO=(2aB*P&!od!Iv5m~~7o^Q&qJ-vJUmT1Et4Hbi%s(eHU0I8aVx|7itYYwxkWT(y!n07oIMYYiV#Ym!wFqO{SkO z9v$77Nu-hd9;$mZ)YWRPYhs~*`7@FtYw)+fVI(*w*TOB^tm)x(0~@bE@o6Tu-VE=R z%0tgEBjeP5!Lu?>r*UM==j_}tcPF2i6hT)r&7IF4rYyJrIt;?CCF6&GY3ARTwP&H- zcIE#UaKka=3MWG8(5$@Tv=_4U9HImYDa8g$tHZcE#-Pe#REkQF8iAH>j- zp=A{(t$+`Z5NM_EiEX_{CAaR5`$sl2i$-;X4x`B<|E&&g>fj8QV(@%ZF-zlSj)MQD zpp5Jev;D${3%6wg=YN*GH)Nx1wD64>6j+y}&(j%%9=fY^urC;H$K@DGA$Ah?B;fU-W6XnLm0V#eGCL_{d|}Diw3An^2r!cwW1^zD+LjtI*xd_-5BWJ#>dgO> zg?4ibiV=i(+}rq5RLtC@TcpaV5^NXN(L1|uG->qk6bDQCW(6EZ%5apSz&IaeZHb2;d zq>xkGYrjl0mpjkEA5howwRG}CnhN-f%>ItKij}YNL=y>h)hZw)?#T8xr5=9bkm;tI z$v8KJDn!Y?lZs8ci7_$!LSGS{N!*mupXjBw6tu+y0uUh@_!Qp|`xJ7KX;O@wWhsB| z;2Lg3e%W35nv$x|C4Ge+0p0}m`Y*l_GVQ*1;-v&;ybF6Tw;mOU2yA;V&PFN_I99|& z!ZB6p)4j?jj-vw2fT;Z~7oLxk+RHi!*zexp1Si!kL8euz>KUHU6|yzZ^a_~t>6<*I z+2^VhN`>k0$kgO-L^T~D(0tK3a`m~LytiNPwUmcNyeA#>jc$J@vUP;_RkbpIB@#Yp zXwaNFa@Kq&MBVu|!$D)7-_(o037VR_JS3X(jW;dhQfycW&H8L6^f;}U+9{K0M+A#O z$4P+!3u%tA;Chq`(>xZQjAOIK0S_)BSC9yY1%*4nub+?4UXo@H2{niH`XN}jkf=S8 z9*7B?aj`}!mV4}EJcHd-@3y)OOeuSeLUqEAxqH(tnEcZIl7Q8yOe;D^B1jF7e_euZW zS9$!)Q2=4(j}5zj!d zNm2)FuZk2O0G)HMqh|I9kWasP5EA=q((@_NO7D!35(3ofgcX^4;6RZurp#MOoL$FP z0bCz;G_j|`$-t9`l9>Ysj9GdP&0%18%7&JDQ!LlER&o6;f8-rntX7<|Qg|`2KilxB zF*t#5Q*|+H2^espS7mGf=Ld(#&=K^*jf)r;w>AM!0$2SKR=^L!@hD?Sz_>a*e+9&t zQ{T7$du%(__Y#^pBwYHSF%t?H^ECEL!GBXX&Zlzw-g$Ef*k&^K6JQ!EBzqUrQ!M-& z?#K>~6a-JCoK!_T$L0%}Sl@nB@VWph37Rz|Y_~nDM-80gU^iqSL6~^vW)}t%N}N`L z@~K=~pPTpQUWr187P#p?R2V?P5@T1+;<>_)n?Nmu;)SInAuH}LI|njYNi&Rv2l8i$ z+6{ch0T$reRN2!l0S0_%nUoGtsYM%^XmFoJKYhT2aUuQlFF{Lf9?7Q|0!msTYrcsB zg4`K@X(xlm)=5|5umEtVPWWMW?v1~7pO`^Y4ZM0sl;9?{26%pw!0YcK4!}=0T~ZCi zEg|i{>p_V^YWEG^QI!-U$7$w!9iHA!IHCrhKn-FJwmE_gtcVg0DxQHG^*1aRb5MdR zza^?{@BdQ-2o|06UNIE`YH30UDV6XfpIViZO?JH>35!*SBI;lfJe%e=LKT>Z#0(^z z0y6;>C`N#*C_&{c#2+|Yho^d{N+J+|)Wg4ifk3qC*k3y%?m1ca5{#4qZ7lGZZS&Dl z7?@0yQTD*bRk*(sXTW-cj#>Ex8{$R}{(*u3AePPcxs`5=9*wR58grpD5_$nNF?6*Z zZ$H9YeKC6|F0JnehR1{OH3e|RBuZZh@ZSVzWF%?a-{5g z#=)+TBXvNKH^J!GFuM8*1Ar%i-yL=Eumw;Z|E9e@h)Hd<(x%wyEN+_;{0q)lRu>cs zJf7?bV@1c+G{|koJ-VReQ~Eelg@Kxt0Q`_AM-te4nQ?J>MUtqzn_?MoSf*iHWtd}h?K*y{h3aeZ*Jpsx5Wm=BQwUt|HW zLJ39zO#AGg0pH;v`86mJ;k9FSFFotRi|VzJ3po`p{k|V% zjP9NM#I8p!ejezisQgd_T>Tfkjw9yk1QN6Gyd3UkQ z)O0_Z zA|`HfuZD&;($GR4QE!k`###^iB&N1iTR}c{ne{L`L)IMK6P>2;=1JIU0Z$jrR;Hn9 z9oTqw;VUYOO8bSx2f^jCOC(eoK}jVutq8R%Rkt8sdB0?g$#(vnhspR=PSf2j!ivpNWrCVg2Lpj+beO4<5(0^R^@Af&;-d3wz zxmz}qwtEAuUlYisBWR9ULRcq4l()3L8VoG`B=>Fdm*{E1b~4)rjyg1jpHEZeR164QoP5b0IYDY0r5@ zY2EbHF1F%*zTqh88ek!5o`=AmdYCO1L93pHKl^M)ru;s-Iro7_2{cY5Q3)FjZ6%i!P+F_SfH#?sny35TgQ&NhtF{l|c zs1+x2TW9Gxv^I-Nn5XBfOmx0h5}M}5dVBqgYrSnKjpd~}f+t4risM?V=pbIS&QHZk z&E1)t$rHMsTl>L%pQFdm{L(i&prXp~kcM$;)f!fVo5lyrSwjs0=84id(~N=}qzF7| zxlq9v{J>@aq8DOCvBU%2R``>J!(z;yYrAP8%#JQ&VWceUC-9|S^WvY6(j`>8EElUI zIQO%CA8=~q6nLXHWS?`^Jc*d3Ag@bcozsBh6yYRrtHT?=A|bm)O71}mdn9n24tDMJ zMd(4z{iu(}Lq3WI6OXKa#bRj&QR;bS`2k3aE$l>3kda$at~h&3KZXsl5*K z?&Ro{CIku#cd#}s&B)B6918oL1-k3eFUGZX$-s15ZN2xd-v=^n$J#1NEzr{-dYkc5#+}7-dWvOuOLW2hHLHK!2VB) zt6bJxOm%-`5#@M{;Xb z3h!PQgN=8RkxqB`WH&}OHv>BuUni*><-@Wr7b2WgvezXL7L(jrd*pJrs*}m6JyS{8 za?k#(T}%{>&K`=p)ksm{dGczdEMK>XH<(Uwc<&iIL)WuCX#X|4tfS8~e!&6P*0p7B z2cNQ~9o?ttw=H?P4(rznR&#c!JuJWbtcChbdnt6??IUHSmU>=|^ZLtWe8wzgyjFK0u$aJ#-)`~!^u}LQn0cWhj@>9qVn#e1ih5bf zsR`*8o#?su^|vWPVfWA3^7^=mOK^Sx<(T&K<$o$BrIk$cAH*u^|7qXv`b1yRfYahB zrC^9Mogf4VSw@UhGyU$Dq(Il(QLuzzcc(&_lddMBTg-62YcIt PV?Ma4Mbe!dGLruTrKw~H literal 0 HcmV?d00001 diff --git a/test/test_foreign.py b/test/test_foreign.py index a4e904df..be4cc7db 100755 --- a/test/test_foreign.py +++ b/test/test_foreign.py @@ -50,6 +50,7 @@ class TestForeign(unittest.TestCase): self.pdf_file = "images/ISO_12233-reschart.pdf" self.cmyk_pdf_file = "images/cmyktest.pdf" self.svg_file = "images/vips-profile.svg" + self.svgz_file = "images/vips-profile.svgz" self.colour = Vips.Image.jpegload(self.jpeg_file) self.mono = self.colour.extract_band(1) @@ -499,6 +500,9 @@ class TestForeign(unittest.TestCase): self.file_loader("svgload", self.svg_file, svg_valid) self.buffer_loader("svgload_buffer", self.svg_file, svg_valid) + self.file_loader("svgload", self.svgz_file, svg_valid) + self.buffer_loader("svgload_buffer", self.svgz_file, svg_valid) + im = Vips.Image.new_from_file(self.svg_file) x = Vips.Image.new_from_file(self.svg_file, scale = 2) self.assertLess(abs(im.width * 2 - x.width), 2) From 5ab0001ec68a5f61396aecd8d2d7a619b1dbe1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Bu=CC=88nemann?= Date: Mon, 27 Jun 2016 03:03:45 +0200 Subject: [PATCH 2/2] Add configure check for zlib with inflateInit2 and replace old unused and poorly named FIND_ZIP. The new code prefers pkgconfig and only falls back to manual detection if needed. This also prioritizes detected zlib flags and includes to be preferred over the ones that are added by pkgconfig for libpng, tifflib etc. which would otherwise have caused the system default zlib to be used. --- configure.ac | 38 ++++++++---- libvips/foreign/svgload.c | 6 +- m4/zip.m4 | 117 ----------------------------------- m4/zlib.m4 | 124 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 132 deletions(-) delete mode 100644 m4/zip.m4 create mode 100644 m4/zlib.m4 diff --git a/configure.ac b/configure.ac index 7adf1160..92517f82 100644 --- a/configure.ac +++ b/configure.ac @@ -626,6 +626,29 @@ if test x"$with_rsvg" != x"no"; then ) fi +# zlib +# some platforms, like macosx, are missing the .pc files for zlib, so +# we fall back to FIND_ZLIB +AC_ARG_WITH([zlib], + AS_HELP_STRING([--without-zlib], [build without zlib (default: test)])) + +if test x"$with_zlib" != "xno"; then + PKG_CHECK_MODULES(ZLIB, zlib >= 0.4, + [AC_DEFINE(HAVE_ZLIB,1,[define if you have zlib installed.]) + with_zlib=yes + PACKAGES_USED="$PACKAGES_USED zlib" + ], + [FIND_ZLIB( + [with_zlib="yes (found by search)" + ], + [AC_MSG_WARN([zlib not found; disabling SVGZ buffer support]) + with_zlib=no + ] + ) + ] + ) +fi + # OpenSlide AC_ARG_WITH([openslide], AS_HELP_STRING([--without-openslide], @@ -786,15 +809,6 @@ fi AM_CONDITIONAL(ENABLE_PYVIPS8, test x"$enable_pyvips8" = x"yes") -# hmm, these don't have .pc files on ubuntu 5.10, how odd -FIND_ZIP( - [with_zip=yes - ], - [AC_MSG_WARN([libz not found; disabling ZIP support]) - with_zip=no - ] -) - # look for TIFF with pkg-config ... fall back to our tester # pkgconfig support for libtiff starts with libtiff-4 AC_ARG_WITH([tiff], @@ -943,14 +957,14 @@ fi # Gather all up for VIPS_CFLAGS, VIPS_INCLUDES, VIPS_LIBS # sort includes to get longer, more specific dirs first # helps, for example, selecting graphicsmagick over imagemagick -VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS +VIPS_CFLAGS=`for i in $VIPS_CFLAGS $GTHREAD_CFLAGS $REQUIRED_CFLAGS $ZLIB_CFLAGS $PANGOFT2_CFLAGS $GSF_CFLAGS $FFTW_CFLAGS $MAGICK_CFLAGS $PNG_CFLAGS $EXIF_CFLAGS $MATIO_CFLAGS $CFITSIO_CFLAGS $LIBWEBP_CFLAGS $GIFLIB_INCLUDES $RSVG_CFLAGS $POPPLER_CFLAGS $OPENEXR_CFLAGS $OPENSLIDE_CFLAGS $ORC_CFLAGS $TIFF_CFLAGS $LCMS_CFLAGS do echo $i done | sort -ru` VIPS_CFLAGS=`echo $VIPS_CFLAGS` VIPS_CFLAGS="$VIPS_DEBUG_FLAGS $VIPS_CFLAGS" -VIPS_INCLUDES="$PNG_INCLUDES $TIFF_INCLUDES $ZIP_INCLUDES $JPEG_INCLUDES" -VIPS_LIBS="$MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $ZIP_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $MATIO_LIBS $EXIF_LIBS -lm" +VIPS_INCLUDES="$ZLIB_INCLUDES $PNG_INCLUDES $TIFF_INCLUDES $JPEG_INCLUDES" +VIPS_LIBS="$ZLIB_LIBS $MAGICK_LIBS $PNG_LIBS $TIFF_LIBS $JPEG_LIBS $GTHREAD_LIBS $REQUIRED_LIBS $PANGOFT2_LIBS $GSF_LIBS $FFTW_LIBS $ORC_LIBS $LCMS_LIBS $GIFLIB_LIBS $RSVG_LIBS $POPPLER_LIBS $OPENEXR_LIBS $OPENSLIDE_LIBS $CFITSIO_LIBS $LIBWEBP_LIBS $MATIO_LIBS $EXIF_LIBS -lm" AC_SUBST(VIPS_LIBDIR) diff --git a/libvips/foreign/svgload.c b/libvips/foreign/svgload.c index 3861963d..a0d1606a 100644 --- a/libvips/foreign/svgload.c +++ b/libvips/foreign/svgload.c @@ -61,7 +61,7 @@ #include #endif -#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) #include #endif @@ -377,7 +377,7 @@ typedef VipsForeignLoadSvgClass VipsForeignLoadSvgBufferClass; G_DEFINE_TYPE( VipsForeignLoadSvgBuffer, vips_foreign_load_svg_buffer, vips_foreign_load_svg_get_type() ); -#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) static void * vips_zalloc( void *opaque, unsigned items, unsigned size ) { @@ -398,7 +398,7 @@ vips_foreign_load_svg_is_a_buffer( const void *buf, size_t len ) int i; -#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZIP) +#if LIBRSVG_CHECK_FEATURE(SVGZ) && defined(HAVE_ZLIB) /* Check for SVGZ gzip signature and inflate. * Minimum gzip size is 18 bytes, starting with 1F 8B. */ diff --git a/m4/zip.m4 b/m4/zip.m4 deleted file mode 100644 index d956a738..00000000 --- a/m4/zip.m4 +++ /dev/null @@ -1,117 +0,0 @@ -dnl From FIND_MOTIF and ACX_PTHREAD, without much understanding -dnl -dnl FIND_ZIP[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]] -dnl ------------------------------------------------ -dnl -dnl Find ZIP libraries and headers -dnl -dnl Put includes stuff in ZIP_INCLUDES -dnl Put link stuff in ZIP_LIBS -dnl Define HAVE_ZIP if found -dnl -AC_DEFUN([FIND_ZIP], [ -AC_REQUIRE([AC_PATH_XTRA]) - -ZIP_INCLUDES="" -ZIP_LIBS="" - -AC_ARG_WITH(zip, - AS_HELP_STRING([--without-zip], [build without libx (default: test)])) -# Treat --without-zip like --without-zip-includes --without-zip-libraries. -if test "$with_zip" = "no"; then - ZIP_INCLUDES=no - ZIP_LIBS=no -fi - -AC_ARG_WITH(zip-includes, - AS_HELP_STRING([--with-zip-includes=DIR], [libz includes are in DIR]), - ZIP_INCLUDES="-I$withval") -AC_ARG_WITH(zip-libraries, - AS_HELP_STRING([--with-zip-libraries=DIR], [libz libraries are in DIR]), - ZIP_LIBS="-L$withval -lz") - -AC_MSG_CHECKING(for ZIP) - -# Look for zlib.h -if test "$ZIP_INCLUDES" = ""; then - # Check the standard search path - AC_TRY_COMPILE([#include ],[int a;],[ - ZIP_INCLUDES="" - ], [ - # zlib.h is not in the standard search path, try - # $prefix - zip_save_INCLUDES="$INCLUDES" - - INCLUDES="-I${prefix}/include $INCLUDES" - - AC_TRY_COMPILE([#include ],[int a;],[ - ZIP_INCLUDES="-I${prefix}/include" - ], [ - ZIP_INCLUDES="no" - ]) - - INCLUDES=$zip_save_INCLUDES - ]) -fi - -# Now for the libraries -if test "$ZIP_LIBS" = ""; then - zip_save_LIBS="$LIBS" - zip_save_INCLUDES="$INCLUDES" - - LIBS="-lz $LIBS" - INCLUDES="$ZIP_INCLUDES $INCLUDES" - - # Try the standard search path first - AC_TRY_LINK([#include ],[zlibVersion()], [ - ZIP_LIBS="-lz" - ], [ - # libz is not in the standard search path, try $prefix - - LIBS="-L${prefix}/lib $LIBS" - - AC_TRY_LINK([#include ],[zlibVersion()], [ - ZIP_LIBS="-L${prefix}/lib -lz" - ], [ - ZIP_LIBS=no - ]) - ]) - - LIBS="$zip_save_LIBS" - INCLUDES="$zip_save_INCLUDES" -fi - -AC_SUBST(ZIP_LIBS) -AC_SUBST(ZIP_INCLUDES) - -# Print a helpful message -zip_libraries_result="$ZIP_LIBS" -zip_includes_result="$ZIP_INCLUDES" - -if test x"$zip_libraries_result" = x""; then - zip_libraries_result="in default path" -fi -if test x"$zip_includes_result" = x""; then - zip_includes_result="in default path" -fi - -if test "$zip_libraries_result" = "no"; then - zip_libraries_result="(none)" -fi -if test "$zip_includes_result" = "no"; then - zip_includes_result="(none)" -fi - -AC_MSG_RESULT([libraries $zip_libraries_result, headers $zip_includes_result]) - -# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: -if test "$ZIP_INCLUDES" != "no" && test "$ZIP_LIBS" != "no"; then - AC_DEFINE(HAVE_ZIP,1,[Define if you have libz libraries and header files.]) - $1 -else - ZIP_LIBS="" - ZIP_INCLUDES="" - $2 -fi - -])dnl diff --git a/m4/zlib.m4 b/m4/zlib.m4 new file mode 100644 index 00000000..eaeb1c39 --- /dev/null +++ b/m4/zlib.m4 @@ -0,0 +1,124 @@ +dnl From FIND_MOTIF and ACX_PTHREAD, without much understanding +dnl +dnl FIND_ZLIB[ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]] +dnl ------------------------------------------------ +dnl +dnl Find zlib libraries and headers ... useful for platforms which are missing +dnl the zlib .pc file +dnl +dnl Put compile stuff in ZLIB_INCLUDES +dnl Put link stuff in ZLIB_LIBS +dnl Define HAVE_ZLIB if found +dnl +AC_DEFUN([FIND_ZLIB], [ +AC_REQUIRE([AC_PATH_XTRA]) + +ZLIB_INCLUDES="" +ZLIB_LIBS="" + +AC_ARG_WITH(zlib, + AS_HELP_STRING([--without-zlib], [build without zlib (default: test)])) +# Treat --without-zlib like --without-zlib-includes --without-zlib-libraries. +if test "$with_zlib" = "no"; then + ZLIB_INCLUDES=no + ZLIB_LIBS=no +fi + +AC_ARG_WITH(zlib-includes, + AS_HELP_STRING([--with-zlib-includes=DIR], [libz includes are in DIR]), + ZLIB_INCLUDES="-I$withval") +AC_ARG_WITH(zlib-libraries, + AS_HELP_STRING([--with-zlib-libraries=DIR], [libz libraries are in DIR]), + ZLIB_LIBS="-L$withval -lz") + +AC_MSG_CHECKING(for ZLIB) + +# Look for zlib.h +if test "$ZLIB_INCLUDES" = ""; then + # Check the standard search path + AC_TRY_COMPILE([#include + #include ],[int a;],[ + ZLIB_INCLUDES="" + ], [ + # zlib.h is not in the standard search path, try + # $prefix + zlib_save_INCLUDES="$INCLUDES" + + INCLUDES="-I${prefix}/include $INCLUDES" + + AC_TRY_COMPILE([#include + #include ],[int a;],[ + ZLIB_INCLUDES="-I${prefix}/include" + ], [ + ZLIB_INCLUDES="no" + ]) + + INCLUDES=$zlib_save_INCLUDES + ]) +fi + +# Now for the libraries +if test "$ZLIB_LIBS" = ""; then + zlib_save_LIBS="$LIBS" + zlib_save_INCLUDES="$INCLUDES" + + LIBS="-lz $LIBS" + INCLUDES="$ZLIB_INCLUDES $INCLUDES" + + # Try the standard search path first + AC_TRY_LINK([#include + #include + ],[z_stream zs;inflateInit2(&zs, 15 | 32)], [ + ZLIB_LIBS="-lz" + ], [ + # libz is not in the standard search path, try $prefix + + LIBS="-L${prefix}/lib $LIBS" + + AC_TRY_LINK([#include + #include + ],[z_stream zs;inflateInit2(&zs, 15 | 32)], [ + ZLIB_LIBS="-L${prefix}/lib -lz" + ], [ + ZLIB_LIBS=no + ]) + ]) + + LIBS="$zlib_save_LIBS" + INCLUDES="$zlib_save_INCLUDES" +fi + +AC_SUBST(ZLIB_LIBS) +AC_SUBST(ZLIB_INCLUDES) + +# Print a helpful message +zlib_libraries_result="$ZLIB_LIBS" +zlib_includes_result="$ZLIB_INCLUDES" + +if test x"$zlib_libraries_result" = x""; then + zlib_libraries_result="in default path" +fi +if test x"$zlib_includes_result" = x""; then + zlib_includes_result="in default path" +fi + +if test "$zlib_libraries_result" = "no"; then + zlib_libraries_result="(none)" +fi +if test "$zlib_includes_result" = "no"; then + zlib_includes_result="(none)" +fi + +AC_MSG_RESULT([libraries $zlib_libraries_result, headers $zlib_includes_result]) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test "$ZLIB_INCLUDES" != "no" && test "$ZLIB_LIBS" != "no"; then + AC_DEFINE(HAVE_ZLIB,1,[Define if you have zlib libraries and header files.]) + $1 +else + ZLIB_INCLUDES="" + ZLIB_LIBS="" + $2 +fi + +])dnl