From a5a49657dc17609a05dca59a8521fd71d14fe76e Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Fri, 1 Dec 2023 16:48:44 +0300 Subject: [PATCH] tdf#158442: fix opening hybrid PDFs on Windows Commit 046e9545956d8ad1d69345d6b4a4c0a33714d179 (Try to revert to use of file_iterator from boost on Windows, 2023-10-31) had introduced a problem that pdfparse::PDFReader::read couldn't create file_iterator for files already opened with write access: mmap_file_iterator ctor on Windows used single FILE_SHARE_READ as dwSharedMode parameter for CreateFileA WinAPI; and that failed, when the file was already opened using GENERIC_WRITE in dwDesiredAccess - which happens when opening stream in TypeDetection::impl_detectTypeFlatAndDeep. Fix this by patching boosts' mmap_file_iterator constructor to use FILE_SHARE_READ | FILE_SHARE_WRITE, like we do in osl_openFile. But there was a pre-existing problem of using char-based CreateFileA API, which disallows opening any files with names not representable in current Windows codepage. Such hybrid PDF files would still fail creation of the file_iterator, and open as PDF. Fix that by further patching boost to have wstring-based constructors for file_iterator and mmap_file_iterator on Windows, which would call CreateFileW. Change-Id: Ib190bc090636159ade390b3dd120957d06d7b89b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160218 Tested-by: Jenkins Reviewed-by: Mike Kaganski --- external/boost/UnpackedTarball_boost.mk | 2 + .../boost.file_iterator.sharing_win.patch | 158 ++++++++++++++++++ filter/CppunitTest_filter_textfilterdetect.mk | 4 + filter/qa/unit/data/hybrid_calc_абв_αβγ.pdf | Bin 0 -> 10420 bytes .../qa/unit/data/hybrid_impress_абв_αβγ.pdf | Bin 0 -> 21055 bytes filter/qa/unit/data/hybrid_writer_абв_αβγ.pdf | Bin 0 -> 10732 bytes filter/qa/unit/textfilterdetect.cxx | 41 ++++- include/o3tl/char16_t2wchar_t.hxx | 1 + sdext/source/pdfimport/filterdet.cxx | 5 +- sdext/source/pdfimport/inc/pdfparse.hxx | 5 +- sdext/source/pdfimport/pdfparse/pdfparse.cxx | 11 +- sdext/source/pdfimport/test/pdfunzip.cxx | 3 +- sdext/source/pdfimport/wrapper/wrapper.cxx | 3 +- 13 files changed, 216 insertions(+), 17 deletions(-) create mode 100644 external/boost/boost.file_iterator.sharing_win.patch create mode 100644 filter/qa/unit/data/hybrid_calc_абв_αβγ.pdf create mode 100644 filter/qa/unit/data/hybrid_impress_абв_αβγ.pdf create mode 100644 filter/qa/unit/data/hybrid_writer_абв_αβγ.pdf diff --git a/external/boost/UnpackedTarball_boost.mk b/external/boost/UnpackedTarball_boost.mk index acdc5d331c76..d8bd131ac8df 100644 --- a/external/boost/UnpackedTarball_boost.mk +++ b/external/boost/UnpackedTarball_boost.mk @@ -35,6 +35,8 @@ boost_patches += boost-ios.patch.0 # violations": boost_patches += 0001-Avoid-boost-phoenix-placeholders-uarg1.10-ODR-violat.patch.2 +boost_patches += boost.file_iterator.sharing_win.patch + $(eval $(call gb_UnpackedTarball_UnpackedTarball,boost)) $(eval $(call gb_UnpackedTarball_set_tarball,boost,$(BOOST_TARBALL))) diff --git a/external/boost/boost.file_iterator.sharing_win.patch b/external/boost/boost.file_iterator.sharing_win.patch new file mode 100644 index 000000000000..b3b8bea3f3ff --- /dev/null +++ b/external/boost/boost.file_iterator.sharing_win.patch @@ -0,0 +1,158 @@ +--- foo/misc/boost/boost/spirit/home/classic/iterator/impl/file_iterator.ipp.orig ++++ foo/misc/boost/boost/spirit/home/classic/iterator/impl/file_iterator.ipp +@@ -181,67 +181,28 @@ public: + {} + + explicit mmap_file_iterator(std::string const& fileName) +- : m_filesize(0), m_curChar(0) +- { +- HANDLE hFile = ::CreateFileA( ++ : mmap_file_iterator(::CreateFileA( + fileName.c_str(), + GENERIC_READ, +- FILE_SHARE_READ, ++ FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL +- ); +- +- if (hFile == INVALID_HANDLE_VALUE) +- return; +- +- // Store the size of the file, it's used to construct +- // the end iterator +- m_filesize = ::GetFileSize(hFile, NULL); ++ )) ++ {} + +- HANDLE hMap = ::CreateFileMapping( +- hFile, ++ explicit mmap_file_iterator(std::wstring const& fileName) ++ : mmap_file_iterator(::CreateFileW( ++ fileName.c_str(), ++ GENERIC_READ, ++ FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, +- PAGE_READONLY, +- 0, 0, ++ OPEN_EXISTING, ++ FILE_FLAG_SEQUENTIAL_SCAN, + NULL +- ); +- +- if (hMap == NULL) +- { +- ::CloseHandle(hFile); +- return; +- } +- +- LPVOID pMem = ::MapViewOfFile( +- hMap, +- FILE_MAP_READ, +- 0, 0, 0 +- ); +- +- if (pMem == NULL) +- { +- ::CloseHandle(hMap); +- ::CloseHandle(hFile); +- return; +- } +- +- // We hold both the file handle and the memory pointer. +- // We can close the hMap handle now because Windows holds internally +- // a reference to it since there is a view mapped. +- ::CloseHandle(hMap); +- +- // It seems like we can close the file handle as well (because +- // a reference is hold by the filemap object). +- ::CloseHandle(hFile); +- +- // Store the handles inside the shared_ptr (with the custom destructors) +- m_mem.reset(static_cast(pMem), ::UnmapViewOfFile); +- +- // Start of the file +- m_curChar = m_mem.get(); +- } ++ )) ++ {} + + mmap_file_iterator(const mmap_file_iterator& iter) + { *this = iter; } +@@ -290,6 +251,59 @@ private: + boost::shared_ptr m_mem; + std::size_t m_filesize; + CharT* m_curChar; ++ ++ explicit mmap_file_iterator(HANDLE hFile) ++ : m_filesize(0), m_curChar(0) ++ { ++ if (hFile == INVALID_HANDLE_VALUE) ++ return; ++ ++ // Store the size of the file, it's used to construct ++ // the end iterator ++ m_filesize = ::GetFileSize(hFile, NULL); ++ ++ HANDLE hMap = ::CreateFileMapping( ++ hFile, ++ NULL, ++ PAGE_READONLY, ++ 0, 0, ++ NULL ++ ); ++ ++ if (hMap == NULL) ++ { ++ ::CloseHandle(hFile); ++ return; ++ } ++ ++ LPVOID pMem = ::MapViewOfFile( ++ hMap, ++ FILE_MAP_READ, ++ 0, 0, 0 ++ ); ++ ++ if (pMem == NULL) ++ { ++ ::CloseHandle(hMap); ++ ::CloseHandle(hFile); ++ return; ++ } ++ ++ // We hold both the file handle and the memory pointer. ++ // We can close the hMap handle now because Windows holds internally ++ // a reference to it since there is a view mapped. ++ ::CloseHandle(hMap); ++ ++ // It seems like we can close the file handle as well (because ++ // a reference is hold by the filemap object). ++ ::CloseHandle(hFile); ++ ++ // Store the handles inside the shared_ptr (with the custom destructors) ++ m_mem.reset(static_cast(pMem), ::UnmapViewOfFile); ++ ++ // Start of the file ++ m_curChar = m_mem.get(); ++ } + }; + + #endif // BOOST_SPIRIT_FILEITERATOR_WINDOWS +--- foo/misc/boost/boost/spirit/home/classic/iterator/file_iterator.hpp.orig ++++ foo/misc/boost/boost/spirit/home/classic/iterator/file_iterator.hpp +@@ -170,6 +170,12 @@ public: + : base_t(adapted_t(fileName)) + {} + ++#ifdef BOOST_SPIRIT_FILEITERATOR_WINDOWS ++ file_iterator(std::wstring const& fileName) ++ : base_t(adapted_t(fileName)) ++ {} ++#endif ++ + file_iterator(const base_t& iter) + : base_t(iter) + {} diff --git a/filter/CppunitTest_filter_textfilterdetect.mk b/filter/CppunitTest_filter_textfilterdetect.mk index be2697a17406..e931a5741a1d 100644 --- a/filter/CppunitTest_filter_textfilterdetect.mk +++ b/filter/CppunitTest_filter_textfilterdetect.mk @@ -42,4 +42,8 @@ $(eval $(call gb_CppunitTest_use_rdb,filter_textfilterdetect,services)) $(eval $(call gb_CppunitTest_use_configuration,filter_textfilterdetect)) +$(eval $(call gb_CppunitTest_use_custom_headers,filter_textfilterdetect, \ + officecfg/registry \ +)) + # vim: set noet sw=4 ts=4: diff --git a/filter/qa/unit/data/hybrid_calc_абв_αβγ.pdf b/filter/qa/unit/data/hybrid_calc_абв_αβγ.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b104113a52387d56fc7ae8c17c6043b3171f4bcd GIT binary patch literal 10420 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 L+}sLUij@BYsiV@- literal 0 HcmV?d00001 diff --git a/filter/qa/unit/data/hybrid_impress_абв_αβγ.pdf b/filter/qa/unit/data/hybrid_impress_абв_αβγ.pdf new file mode 100644 index 0000000000000000000000000000000000000000..78e7136211f475a08c07d7563e69ba8df3e2d78b GIT binary patch literal 21055 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 Gqw+sZJuOuL literal 0 HcmV?d00001 diff --git a/filter/qa/unit/data/hybrid_writer_абв_αβγ.pdf b/filter/qa/unit/data/hybrid_writer_абв_αβγ.pdf new file mode 100644 index 0000000000000000000000000000000000000000..00cf3de44c5ce15d47bd39f561458a4e86e0eb90 GIT binary patch literal 10732 zcmdT~c|26z|3?X9DUs}ktc95|m>DI>*s_m3OAW@BbrySNjfj*|C|e{H*|SE7$QqKh zP(ox071i%vJ)YE4&-eHJ{r5Xwcka38ezx;DpL6bUK5r3yteO-;8U+!leFRf33 z$U@;zcN=HOp+hijf|~=`5h@3?;9zP_E@T1`rsjet6R-qZcRRx2!w?dgNWi;7d~P5+ zkw)T^-QJS>pJ;1oOB;ABQr_%0g6qROk?=x&c!_K;QU+ywACBlLf&-MtUPGSan#YN> zIS?Z%s+v>GZy*FWyT7CXHP8SEs28lrqrjINP3XUkg8 z&Iy0i-NynBJj!9@q>*qW28n{hQD~Gb6fKL8Mx!w(c_a#jk&{7N!BhZS0BIyB=u_Ml zgXMwezkIx*+K^17*pgLU2(A#AAq?woOK}DGfDS+rpenE{4p7iu+|~|ky!)pZBO-x- zb9V>XH#!48LlKDYaPT=w@gmWB>&?C=_%R-jxJJ zY&aPTSnyXY>T7M=&Q3)|PetWt9%O3$ScXZAii!%nfF>$eCszV!z!vo|K)LjWYU!bKJw5$K908jCE=)kp74PO`Pau({iFWpFacyoP z@Li$r4}}rh`;WkAX^G-3<<2R!a_7uwVT*~oM`~i?Objw|rc-*x^VE=|F~v!!Etm$O+vyk*dC+82ubo7rzFx`G_{j&Q0oMp&p zz*R@TIa@!QBi%L0l#zK#xx|5@zOr7F41wVF-dUtbE~Hz*h*Skw{0BoBxjSW z1C2(r(!_V$JQ?K+Z{k0%$nC<3#;Lyeq%>MCkkj-$ZPoe+PnzBAIDAntR@+msa^Tz7 zb$0fzwo7R^*8`lp^7?(LoI5)D?KXR zXg1|8AH&h2`eUKTyv1YE+3&rNJ~JD(e)@Hm6C}$H?`a~JmRlwyJ#lGY>j|mO!Zv~Qcbt<5y~RRW7GINM)f;1y1Q&~jhXH&1 zNIY*x&i1dlzb(Oa;f4Jr6laRtdf-eL2Q{f&vSD{Z7m4 zA3mffo;?wB#ssHy?{UZEQrVJweScAIZmzRW1ur+3;-zP&#o{lvi8P|Me_xP*3@)uKfb2$IAPHLTfn40?};*~n&>^rl#i;BdRMxh zwX{uzPv4IC(&&XB!%Q4*>F+3o96sy4{5Ac?ydE^GX!hCRgG!YT4rzb(uz#~HqU%&D zhRqM+rc>X~Nqf}Pt*Y%MoR4q#zWv`>=K9XeTu+GOhti&C6LBFS>sO`dX=KP%l9HL7)w+gZOO=Q99(8|}{JdY3Y zN!>xsc5_@pc{L5`?JU-5Vpdk35OlLx55iBMpz02q?}j($&CoyJxj>(MdS}rRmJ53& zJA#9$g;=M8RSc!p-sO7h%TT}A4r85La-D8UXin!#Ec1*ZiS0(WmbtI%q)fBzT#+`k z#?775(w_-@c=3^xQjNB3CI8;?Q)^Tcnrq11_3)>cA5MKcS}=V~cUj{?_(;a-apCH- z>pi1QH_m(U2Y2)>oRQ?Uw3f}_@G{7rL%c%IF&^+}ft<^Z5a$v|$=Oclq&0KMH-K(c zb1kN(<1(V(R5pHI(^7xfFuv_-NpvPb_nwAB-mS{+g6+X;G$zk)vR9-`H9L%ze1Wm` zBk`vdm);0QhmA6ng}>)?duAx@uO+(w+FKfNkM=LhO5KUGr;ad+!>$FDtYS=J2UNMj2 z9NcXkJDen{89HM8_RGScz{78!T2mhKNAQORXq>D|kM9Y-rPk7wa7IfZ^1+B*_g+J@ zH=eh5=^2(BSuL`w8CPG{4+!gG5Q|MA`Y-2n7)5EaMZ$Mj zK2|3@K3Wnv$0t(zP0-{m$x()9wst7#e4Y7=f{&lBr`e52aJK!MYh-Ps|7!pn@^3*2+Ob=$f;%$64}FV;Gq zV+`MUN3pd)r|!#PhxXPd!7D9_$CN7B6xjBYapguVRBZcQ4Tk+^Iy2}4iq&?Ub|r+a z3a%w!`?H78G8pUCghHHE6SGKc*?3NKhE7_#w&(K83blr9+Er=?Vr*$_NR+bu-q+OG zFLHzrlpf#i*MRS+$~D%XICzAG*Yge+l;15^xm~(L8aDFqpyk`z>l6oR*n_untTc%J zv35mn9z%6oJKCE!v`I?##uPC*TFo=m=>?8OJ_|SJi+03^VoM*rXg*bf|;+5+SFj)B_jj0;F;HtZ8MZGKg8(p6Km%g0l37<{(;&29f;dvZM1;Ll4Z7ScK z&_Z|OjSW3kD`SPr6EEa$gBvYjHAL5&;VE@pIUifXSa*x0q-0E*$}A!s)rFIzu*^uF z&(m6>0;%D&%-WxW>vuZDD_qV+8tq_edz}1WhbT>%9nbQ7v`9dKnPYUl`Aad$3%q(= zoedsW6_5#)y#hDH(2?vVC*D z^K)CPv${E?TWMe_rd<$kN6+krYQGiZc~3CynII$Eea-{-&P+xqQU)%RFtSNaNot2h zU%OvRMU%oY#Z){$4}VKU4}2MA2%l>%Wu`pl=6zZe_VN4$kBk1CA|0&L+{04h{ilt` zj)>7Os>oRIP0C2o%tXIEf3<%%yG4ChAY^PRXQz3j)>m~Q-F%}*B8}kzAE(z_2Ly^F zgXs%6q?v^)FP_-2_V3F>Y^tDLp&J#yo#^zpHdy;iI8Oc2` zR^B7%PVMsa+DT%5#@Bt<_!bAoi?{@KmmYM_HbH%5H5y(%k)8Aq*tgNqN8d2vO{N1j zxpM!ukAr~Ub+WGuVdJYlYoT>y1u|}o%5b)Zc_8Q*AQ1y?v!RH+!p^R5~4{=<;&E& za%HFW>=gNUvixyE)!?j<4&|=X*r%LC!?vrUthdc1*bJ&J>}#?(dH&5nmd~K*RBHR4 zzNfBE=Tjyu@r{G=udi0!rx}bGkMx`xuj_Kk6K!NH?=gvA)KNGQ5a)IDgU=1V)TZ%< zZZXVQkxFL5K~J^tPq`ThgWUuxUUY^q0% zqGk^w$!x4QrH`}b3pI`l?z={N^Bj{Z5`r}a-?r{zD@%tvmIEOpB3LOz{zB+&D z4i)c1z(G@g1aGxn#>(V6 zQnv;kHWf)Z?S1K!0p==`Ikoj z%n>nEfM#n%Cg4?zTP_)DLp%0YW-jE)TpyI<>GToFy)p9K*bX8&}m{hK1O<|d{8m8H@i zjPx!E70My6Pw1!5b2xlc8YP{Q7#GpXSLYMeFyg$S^=#u)wDPKRcLrlT>rBpBG%f{0 zQ0hH>EJr*KK5TpSjY>^fEju{Sm9;P_I6r5=ItM-RuE&sNpQ590?E{F&L7Rl!Q*>c0 z&)LiNBtq7kXSh=T=}fJ->#Md2GW;csr{2@>SeS(CxeoaJ zpx^RfQ063}C=c%$ggz-4dKcI4Rn(`bjXZM_ms2ECj9RD&s@}eTmwi6#>?++ER`QbJ z^c%V^Hif8DwPWW*W~f9v=eF0EnK}LPr8iJ0|_FjtmQ=RI=OXsCkC*v!dPw3Qt#PT>lzOudet;ZeFC$hTBq}qn3IQ7tP zIlKwaBT6mj$ukY_gx6SO#`I1g8Y7b5+eDtuB!3+2EnkW0?Y8u1G8q$7Veq@au4Lo< zLMNby>f@9}X$5`nX(bxFl^|1kC)Kq}?s39wD50^s|PNxnh@39jTyxQMDt3CpPJMAbDHiX=V)+)ZKbp zH*@nW_^#X^Y^Z!5_<_5qS4mvR3U^RjB+l%Jo~8YS*`S529{sG7psjY!s4Z*MtZ(h1 zlEXsBb0=93zTF;n@ycmFr`GE#p?-%AmdY<$UU|4A)j&`nK)FzzI{8A~X7Jngi}ZH< zcb3DZ+@A9mG^N{$Ii(-*6qSm;!ti|5DCZ{s)57;+w*GE+#s{q0fa+8qIyUVXnMZ@m2nZ6Sgh-7jk%R2U*_!CjCT$GUJfL(`;oLetG*N zh5N`Fm89M`6)!ux+miSa1s_Z?rnl|r=<<2Cw`yAfhP&)^-FBHpqJH$tq_md`F$*Gf z>rAn>HSGM-!ZqU4L9WD@S$Q?@9q-ODjPSYC1b0!M2dt+j`=@?>dG|g2T;e$WgNXLP zkl~BxbA(vbuKSf8Pb3Ouf9Ch#gPG>`k34V+uB2GKk1vZeJ84YS(;VxWUZYZ++WcT5 zqB-?!5y~_7Igg2>4Ch2&YQl-roEa>PA0|$BnRbhgd9~Z#K2T6J@x($yu1_c(VOrJiLgtJ5xovgg3*HvuUrtD6DC0u%?Qhhpz3p?I z8SM_AXR~Udnskl1Wp><2 zGpO1q*JNNe%_Vc?Z3*A~>5DyH^y_Oee7i4OJvyE_O&c-U_H^mOWaCqJZ`_5_r)GJ* zLJ5}9ajb?|!@RzziM4Snzqldk(WjJT(j%E1O^F1eL|04QDt*<}Hs={3iRc#D(jj|@ zmOWBk#tPo+L$D%q5cy1st%Z3eBbfx>>+j1eHorBq@KG@*g@>GHi=4fyL1MNe1o55S zU7c~Tt~X!a)!5jyS2p9uQ+p))UFIv7IZUspZD$vWV0aT}E?b_My5m4XeZl&nQmrQy z)e+LRRNmEmgXLxp7iT{wKDs$oOJ`@67JX_4@3AN8iR~*mCC&huxiDuqaG=YJ&nk7+ zFLl{2M2DPB^T5<$oqaTuYR)egcNoD|efr&elv@1*BZtXMnIXipptvHBU|Od--*wJy zSuiLYFwyD{B2s-0jo1(GH^|eXRi#;0h$U18bIs|PZ7;jK zH|;EoCndho?!uwl!{d)N5qCL929AV%Wh|w`zr(&QY{Rg%^%rCH&UGnVm4BVuskYa= zsgg(6ri`n!0RQSksTQ z@b)q+viA4Q_zik%(RC^D&zaiQ3m*>tG;=c5fzPDLdtgA{Z_zPml)Y|n2N^m{G^utK zdo+-J@b$t+W?zeG5q`d=fotzdE}a@F3a9bTqkU%gVu*Tr#jHnq!eg%nN!#og7poU0 zpElQuzqg~tDrzD*2$)wu{wzKvDvCol1XJ4&Q8eiuaiJ|$VuDwxL3Gp^-$_yEQgVt2J(SGN!Q-!-g z)e*_bSE7zD-tW%);+lFb>ehX1xzzTNtO~M+l6^K++V&STR?KfIwx0+Uzn4qb@T^+A z-?nI~HNCbYDkLDsy>M?+`S?tCPc*Oe83X^&9k)wHAtRjZJOhd}l${3o)s8Pa1{QaM zvoFW<)n`@USaFtlbM|d!bRJs>3vdC4j^G6*Q;Zxbt~PFXCl?Zoyjhj@aC11XudB`s z;RgRpVb;{Z;;5*oovEm3sOSNyR5yb9Jb)X6zP6F-w{PEoD)4*e{Y5>X)~bnBHu4#m ztwR7Bs2-&*>$yUdQi1CKyHc~GkDrPQkuGI zu)i}Lz>)2}IAynb=q}Y&Oju*7Ovdc(qn?F#de}1PQdeF=Us2cXYAl15j`bVwk%%wc zhCK7WgY!MhwRR2%`Y!a{{sW_hH21xt>q>1#oAMV!_*RmvvN|0jgtJsHjn?}Nnn==K z(N$#=$ze&)IIgg>|A7J}Q21M4YZrM?il(aQz<|O7?V-*Vh77AmY6f{VkuS#tufNhT zpDLD@Yo^7^&Y~KJg5^0{EcriU0(JZ1t-G>q#@zCJ={q@%aqrV?TKrE@{VA3%jgTdDBWv138Blal@ficYUpQ^&uF& zi7V@pl0fu`YzL#4nueX~&l$;|qiQoh`775}DlpOZqv!zDe@jIEto;Yy_u2E~IqWxb zek3OUw^Ay9Bjrb;^3PI!?$g3=q-;%G{#g#VBK#;4z!?1Mn;(hHKTG-9niIc~vNf^! zXE|Vw@khD#8#zBGI{z#QOm+S!UB8j^kHqJnh5c+63(Y^B^m8KgyQIxr-qtK1nA`bL zGyq9|FB?E&bTf!IIk)DEz%1a85)LfNKw^F)C-^JZ*3+n;^?B3&oLTynbL$ok{0{sm zdcbGp$Jy1dd|N+0;0EtUG2-}XySK^sr*G2_#%``Zf2lU5Y`SUd>H#jvKZ+pF9~NkR zE!rI*87uHd02ZCtjUoOGLT3X$0pc^zvT~Te;W!&0ioXyehE9G202w2P*#hbSF&A3^ zB~TDrL?C$(Y+-7L)Kt~f;BZ;sLdn44@)+O(@HHEERp5>QE)_Uj2CM@#^0EM(>|rR( z`2Wm_C6H{Pn`-3%kyzjYRfBav{KoZH9cbQA`>&>fG$0>n9uhEbQzm!^%tit4Hs#36 zf3JgW@@U`!x{CsM!1n+-To!1T{fh>q-EafYeR(;c%c^Qn0HUP^-2nCgh?Ol4Mr^@w zZQzSk@MOG;yTb;=iS!-Z1cB+|T>)ehAY&_}W~1Tz8;eb^{Fj6A9Z~}zhyaT=H0l6Y zF_mMkqFRk&;xW}gl-JU=CA<62J(YL2O`422t~>RvNlu# z9mN887jdkD3|t0@kbxr*vIvA6;s6{e28WADY%$k|NU(>%p$K^hAnC6Hm6wx4%0ca+ zn{Dzaz{y~Nx^1>$kVwFlKexeUt|8>c zVaR_b0fB4)f=|VfV0(&0aRnyoQCTz+jg&zjRZ%+%$H>U2sbJ9ZSOgX+uPTqhU?4DM wJ3A+EGT>c+pa<}jB&fxIjcEJ63_vz;eZY2tNZtq}1RQ~cLqtSW_0%B$1GB8;i~s-t literal 0 HcmV?d00001 diff --git a/filter/qa/unit/textfilterdetect.cxx b/filter/qa/unit/textfilterdetect.cxx index e8de97a8df61..c88de0e8790d 100644 --- a/filter/qa/unit/textfilterdetect.cxx +++ b/filter/qa/unit/textfilterdetect.cxx @@ -16,7 +16,9 @@ #include #include +#include #include +#include #include #include #include @@ -31,6 +33,11 @@ using namespace com::sun::star; namespace { +bool supportsService(const uno::Reference& x, const OUString& s) +{ + return uno::Reference(x, uno::UNO_QUERY_THROW)->supportsService(s); +} + /// Test class for PlainTextFilterDetect. class TextFilterDetectTest : public UnoApiTest { @@ -63,10 +70,6 @@ CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testTdf114428) CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testEmptyFile) { - auto supportsService = [](const uno::Reference& x, const OUString& s) { - return uno::Reference(x, uno::UNO_QUERY_THROW)->supportsService(s); - }; - // Given an empty file, with a pptx extension // When loading the file loadFromURL(u"empty.pptx"); @@ -172,6 +175,36 @@ CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testEmptyFile) CPPUNIT_ASSERT_EQUAL(u"Writer template’s first line"_ustr, xParagraph->getString()); } } + +CPPUNIT_TEST_FIXTURE(TextFilterDetectTest, testHybridPDFFile) +{ + // Make sure that file locking is ON + { + std::shared_ptr xChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Common::Misc::UseDocumentSystemFileLocking::set(true, xChanges); + xChanges->commit(); + } + + // Given a hybrid PDF file + + // Created in Writer + loadFromURL(u"hybrid_writer_абв_αβγ.pdf"); + // Make sure it opens in Writer. + // Without the accompanying fix in place, this test would have failed on Windows, as it was + // opened in Draw instead. + CPPUNIT_ASSERT(supportsService(mxComponent, "com.sun.star.text.TextDocument")); + + // Created in Calc + loadFromURL(u"hybrid_calc_абв_αβγ.pdf"); + // Make sure it opens in Calc. + CPPUNIT_ASSERT(supportsService(mxComponent, "com.sun.star.sheet.SpreadsheetDocument")); + + // Created in Impress + loadFromURL(u"hybrid_impress_абв_αβγ.pdf"); + // Make sure it opens in Impress. + CPPUNIT_ASSERT(supportsService(mxComponent, "com.sun.star.presentation.PresentationDocument")); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/include/o3tl/char16_t2wchar_t.hxx b/include/o3tl/char16_t2wchar_t.hxx index fcbbaf079ce3..c2640f627109 100644 --- a/include/o3tl/char16_t2wchar_t.hxx +++ b/include/o3tl/char16_t2wchar_t.hxx @@ -41,6 +41,7 @@ inline char16_t* toU(wchar_t* p) { return reinterpret_cast(p); } inline char16_t const* toU(wchar_t const* p) { return reinterpret_cast(p); } inline std::u16string_view toU(std::wstring_view v) { return { toU(v.data()), v.size() }; } +inline std::wstring_view toW(std::u16string_view v) { return { toW(v.data()), v.size() }; } #endif } diff --git a/sdext/source/pdfimport/filterdet.cxx b/sdext/source/pdfimport/filterdet.cxx index e8d2e11d30ba..d9fdcc03c6ab 100644 --- a/sdext/source/pdfimport/filterdet.cxx +++ b/sdext/source/pdfimport/filterdet.cxx @@ -555,7 +555,6 @@ uno::Reference< io::XStream > getAdditionalStream( const OUString& bool bMayUseUI ) { uno::Reference< io::XStream > xEmbed; - OString aPDFFile; OUString aSysUPath; if( osl_getSystemPathFromFileURL( rInPDFFileURL.pData, &aSysUPath.pData ) != osl_File_E_None ) return xEmbed; @@ -563,9 +562,7 @@ uno::Reference< io::XStream > getAdditionalStream( const OUString& if (!detectHasAdditionalStreams(aSysUPath)) return xEmbed; - aPDFFile = OUStringToOString( aSysUPath, osl_getThreadTextEncoding() ); - - std::unique_ptr pEntry( pdfparse::PDFReader::read( aPDFFile.getStr() )); + std::unique_ptr pEntry(pdfparse::PDFReader::read(aSysUPath)); if( pEntry ) { pdfparse::PDFFile* pPDFFile = dynamic_cast(pEntry.get()); diff --git a/sdext/source/pdfimport/inc/pdfparse.hxx b/sdext/source/pdfimport/inc/pdfparse.hxx index 7891419471d3..542a9ed4b1a5 100644 --- a/sdext/source/pdfimport/inc/pdfparse.hxx +++ b/sdext/source/pdfimport/inc/pdfparse.hxx @@ -292,10 +292,7 @@ struct PDFReader { PDFReader() = delete; - static std::unique_ptr read( const char* pFileName ); -#ifdef _WIN32 - static std::unique_ptr read( const char* pBuffer, unsigned int nLen ); -#endif + static std::unique_ptr read(std::u16string_view aFileName); }; } // namespace diff --git a/sdext/source/pdfimport/pdfparse/pdfparse.cxx b/sdext/source/pdfimport/pdfparse/pdfparse.cxx index cdd3ac13ff35..8b3da7eb39d7 100644 --- a/sdext/source/pdfimport/pdfparse/pdfparse.cxx +++ b/sdext/source/pdfimport/pdfparse/pdfparse.cxx @@ -36,7 +36,9 @@ #include +#include #include +#include #include #include #include @@ -558,9 +560,14 @@ public: } -std::unique_ptr PDFReader::read( const char* pFileName ) +std::unique_ptr PDFReader::read(std::u16string_view aFileName) { - file_iterator<> file_start( pFileName ); +#ifdef _WIN32 + file_iterator<> file_start(std::wstring(o3tl::toW(aFileName))); +#else + file_iterator<> file_start( + std::string(OUStringToOString(aFileName, osl_getThreadTextEncoding()))); +#endif if( ! file_start ) return nullptr; file_iterator<> file_end = file_start.make_end(); diff --git a/sdext/source/pdfimport/test/pdfunzip.cxx b/sdext/source/pdfimport/test/pdfunzip.cxx index b9bf3a62f14f..6db3b740d668 100644 --- a/sdext/source/pdfimport/test/pdfunzip.cxx +++ b/sdext/source/pdfimport/test/pdfunzip.cxx @@ -224,7 +224,8 @@ typedef int(*PDFFileHdl)(const char*, const char*, PDFFile*); static int handleFile( const char* pInFile, const char* pOutFile, const char* pPassword, PDFFileHdl pHdl ) { int nRet = 0; - std::unique_ptr pEntry = pdfparse::PDFReader::read( pInFile ); + std::unique_ptr pEntry + = pdfparse::PDFReader::read(OStringToOUString(pInFile, osl_getThreadTextEncoding())); if( pEntry ) { PDFFile* pPDFFile = dynamic_cast(pEntry.get()); diff --git a/sdext/source/pdfimport/wrapper/wrapper.cxx b/sdext/source/pdfimport/wrapper/wrapper.cxx index ad25f85ebc09..ade4dc5edb6b 100644 --- a/sdext/source/pdfimport/wrapper/wrapper.cxx +++ b/sdext/source/pdfimport/wrapper/wrapper.cxx @@ -911,9 +911,8 @@ static bool checkEncryption( std::u16string_view i_rPa ) { bool bSuccess = false; - OString aPDFFile = OUStringToOString( i_rPath, osl_getThreadTextEncoding() ); - std::unique_ptr pEntry( pdfparse::PDFReader::read( aPDFFile.getStr() )); + std::unique_ptr pEntry(pdfparse::PDFReader::read(i_rPath)); if( pEntry ) { pdfparse::PDFFile* pPDFFile = dynamic_cast(pEntry.get());