From 4800e6999914bdf89f3ac2cb6985eb9c3be8423a Mon Sep 17 00:00:00 2001 From: Ollie Tulloch Date: Wed, 22 May 2024 22:08:20 +0100 Subject: [PATCH 1/2] Initial commit of handling excel files with incorrect file extensions --- lib/ndr_import/file/excel.rb | 46 ++++++++++++++---- test/file/excel_test.rb | 31 ++++++++++++ .../sample_xlsx_with_dat_extension.dat | Bin 0 -> 26835 bytes 3 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 test/resources/sample_xlsx_with_dat_extension.dat diff --git a/lib/ndr_import/file/excel.rb b/lib/ndr_import/file/excel.rb index cd76555..94a9ca6 100644 --- a/lib/ndr_import/file/excel.rb +++ b/lib/ndr_import/file/excel.rb @@ -20,7 +20,10 @@ class Excel < Base def tables return enum_for(:tables) unless block_given? - workbook = load_workbook(@filename) + # Create a new file using the given format as the extension, if a format is provided + path = @format.present? ? create_file_with_correct_extension : @filename + + workbook = load_workbook(path) workbook.sheets.each do |sheet_name| yield sheet_name, excel_rows(workbook, sheet_name) end @@ -91,11 +94,7 @@ def load_workbook(path) when '.xls' Roo::Excel.new(SafeFile.safepath_to_string(path)) when '.xlsm', '.xlsx' - if @options['file_password'] - Roo::Excelx.new(StringIO.new(decrypted_file_string(path, @options['file_password']))) - else - Roo::Excelx.new(SafeFile.safepath_to_string(path)) - end + load_xlsm_xlsx(path) else raise "Received file path with unexpected extension #{SafeFile.extname(path)}" end @@ -107,13 +106,42 @@ def load_workbook(path) # so we create a duplicate file in xlsx extension raise e.message unless /(.*)\.xls$/.match(path) + load_workbook create_amended_xlsx_from(path) + rescue RuntimeError, ::Zip::Error => e + raise ["Unable to read the file '#{path}'", e.message].join('; ') + ensure + SafeFile.delete(path) if @remove_updated_extension_file + end + + def load_xlsm_xlsx(path) + if @options['file_password'] + Roo::Excelx.new(StringIO.new(decrypted_file_string(path, @options['file_password']))) + else + Roo::Excelx.new(SafeFile.safepath_to_string(path)) + end + end + + def create_amended_xlsx_from(path) new_file_name = SafeFile.basename(path).gsub(/(.*)\.xls$/, '\1_amend.xlsx') new_file_path = SafeFile.dirname(path).join(new_file_name) copy_file(path, new_file_path) - load_workbook(new_file_path) - rescue RuntimeError, ::Zip::Error => e - raise ["Unable to read the file '#{path}'", e.message].join('; ') + new_file_path + end + + def create_file_with_correct_extension + # We shouldn't attempt to change one excel format to another + return @filename if %w[.xls .xlsx .xlsm].include? SafeFile.extname(@filename).downcase + + new_file_name = SafeFile.basename(@filename).sub(/\..+\z/, ".#{@format}") + new_file_path = SafeFile.dirname(@filename).join(new_file_name) + return @filename if ::File.exist?(new_file_path) + + copy_file(@filename, new_file_path) + # Flag the newly made file for deletion once we've finished with it + @remove_updated_extension_file = true + + new_file_path end # Note that this method can produce insecure calls. All callers must protect diff --git a/test/file/excel_test.rb b/test/file/excel_test.rb index 92836b6..3c49642 100644 --- a/test/file/excel_test.rb +++ b/test/file/excel_test.rb @@ -129,6 +129,37 @@ def setup SafeFile.delete @permanent_test_files.join('txt_file_xls_extension_amend.xlsx') end + + test 'should use format provided to read excel file with incorrect file extension' do + file_path = @permanent_test_files.join('sample_xlsx_with_dat_extension.dat') + handler = NdrImport::File::Excel.new(file_path, 'xlsx') + handler.tables.each do |tablename, sheet| + assert_equal 'Sheet1', tablename + assert_instance_of Enumerator, sheet + assert_equal %w[1A 1B], sheet.first + end + end + + test 'should read xlsx file when an xls format provided incorrectly' do + file_path = @permanent_test_files.join('sample_xlsx_with_dat_extension.dat') + handler = NdrImport::File::Excel.new(file_path, 'xls') + handler.tables.each do |tablename, sheet| + assert_equal 'Sheet1', tablename + assert_instance_of Enumerator, sheet + assert_equal %w[1A 1B], sheet.first + end + + # Existing logic doesn't remove the _amend.xlsx file + SafeFile.delete @permanent_test_files.join('sample_xlsx_with_dat_extension_amend.xlsx') + end + + test 'should fail to load if format provided is not an excel extension' do + file_path = @permanent_test_files.join('sample_xlsx_with_dat_extension.dat') + handler = NdrImport::File::Excel.new(file_path, 'cabbage') + exception = assert_raises(RuntimeError) { handler.tables.to_a } + + assert_match(/Received file path with unexpected extension \.cabbage/, exception.message) + end end end end diff --git a/test/resources/sample_xlsx_with_dat_extension.dat b/test/resources/sample_xlsx_with_dat_extension.dat new file mode 100644 index 0000000000000000000000000000000000000000..d046e72ea0956b59787b5e8f359bade4725c44b3 GIT binary patch literal 26835 zcmeFYcR*9i);GLE=)DO7Qltn-Q;J9p2vS6fpdcV1QbUyAg1< zr56Dy38)Ani6TS@$+z*`a?1Ul``mNS``7z!O)`6C_RLyq&nmw)gNXr@oE@M9r~v>t z4yfoQX?Q>YppP5?*Z^uWYb|dte6>1gjUFzi0Iil@YXclGa;a1na@aL_2yP?X6e;X%^uN_0bz z@crSM{e|Y?GRK~fijyof_k%7iW^-z+Xkg}EL0bsf<@v9LlPbO?S(1J2!`V@{MFw>nzz zIXAcq#;cQ?j?2_+*-OQ;BQzNz46YiOU|N|P3^jsye;Fo{(bCY9_jHL29e7T?-_8qqP0%Y z>AT334~&|y=08FX&){00yqN47fiBoGuI_|LeHwcic|3a<@j+g=CVoJ3hKunwdZbn zzt=ZVR4rgDH$V+Rc*y*sKtbNV?l-)>-4C7I-<1ghdOA?k{_noZQ%Br-Ptgx-MYczd zh5C#qp4Q2+9mt=N3IQA>d|Yqv80@Dt=Do}}Ebz~`MxS@5b4#>f^NY)|KF$;CkrpOL zM5wnGH#s+WU^jlCt8N z$37bIjF%`4O};F7qZuTo==4KuVjQ|IXI$M#JHEIW>00zKjkL??InRTn`QWEL!YL?> zlV62sKQW6bUpD5;W#BUoV!srt?XYr|3g< zG5n9)g2szDqc6=*o#H&rdQL*Rb!1jPM`uF#O6qteGbw3)oT85|*yq^bp!(qOmd?~; z?;d5i|LrG+u_>ePE}PoX5xx&8y}hxjI&s83k%JPArqFKVDp;^s5E6Uw^8o1B?ZYHvG2W`;N(%OiQB z9^RLc+>-K5V%-Wrf*rtjlV8nGu-9Kch z5^hP*5e^J5teD-p3(d-1xt^EXBk<}5x8uvqqL;VFg$rTR&ChUo-4ZV=e2R8>yx1+B z8C!eejy6BEaA_?!%6#V2*x1&5Y^>SI;$H5sYCh+v!{*)cAuA#n_5ShgFCX_WEe7BE z8u(%V%vb@Mgd2JasM$R_};T>p>OE-##RP8>kL2s8$=-sfVaeI1` z*N0^9a`voH z6n?KSS7KX99xHsDf86mM{g<8Aj5B1yM~tE$;_k>til=nfR|G9J$17gZz7e6Jo|4_f zrG23=TS7wij=iMJxBJ3aufFqlkEq7uUYRTljq=n!n7ZH;Dl#BXV-n$D65=BN__$_h zh3wl`4}y-Wp181n`(9kGx#2OINM63n3g?WRvT6KdE#<<4qX{L(Nms&;rqkNWN5=o4 zGjFJ@Tz+#gwv?hqq`C6P(5mchbaz>%*-oV8-E6O=Wt!7f&TmYjM zc5=>i+H%9|vUT$?>kHzenT5(p2?b8O@y;_Yeov;{rg$=?%u6A&dG$&J9jEq&_Vs0k z7nlt{yp?rFq8NuR6lshDZVW}w_Ag=60=gA5Y7%=3U=T}$%} z`)pzHQJl8atNNp`<;QdYgX7gP@>2K(owIi&y;cwcV$*EPh7ktdpH0L*MsHu!i;gHN z<7&&hQ4*WkVKLGf`kf$t>pS7)%U%~zCe+#B?X^|(u6c$K0xG&vvpiG<`*ASDH0EvG zdFuyW4rZH3ti$sm_+ZwFABF9CXK2m zcPnb$bywnw{ieSybdi_l*ln-m^`!V?%bViP>emvQRu|YtRgqmAX;euS?Rpp4zrRMx z#q%ype=P5h$_UTCRms|Wpf9^)EPcZ1o%%pbNAvtypL6q>Pe&ELJ@s$$*6lm(myFg% zpVp5(x5o<;=v!F`y})Z51Q%;s6^i;|HrX?2pr6P1NIQ#WA^&ur)A~2AbDKA7LzwE% zehY5bVzd!vCwJys*}tPCZ#&2q<&gJEJ;^c?Ykl>+x=@H2OS%tlsld2H&)IeQxclmv zDr5vHih~o;Vec9CrLza5O~r04PXyEX+3I}3Mh4zlnT**S6F%v%lty*$@zG76_mNw^ zjpw%I`XHioy`jmhqVHT3BU=4GKa@9MK5!OPt!^`FO6zPF=dr)hLSN@!Y&Iw#Y%}l7 zzSoe0_MG>koPQqsBmUz+sdGE^u8hZ+3L^D0OG*3>k#*0Qu=#>W5;Dg2@(|}zhD*iK zmb%4zZ`&JYg9qsp7lmG3H8$jG7J0L1-9sk-xhFqeF2>08Sl>8x*!qQNnq%*-UKffa zx8OH9@?G#zPe(hqtB6BpDWAc8Uz(5S`xQh&){#9W~$vuN$Lc~iOgnUB8tZ8sSx>CV`@ zL|%uHOIGz(+Zi)_AzBqm=nWNXaIUbegL#vr~ zOD1;qXl24V5s&Fy%Y-657d}OT<&~(R1PY3k`#vY1&UMSyoR+VuF{#!baon`4nDMW% zxeLv8u6cCCo#&n)>ERJ(H^n+fdBK8{RIT!ln`@ITMOWF*Ys+x+6+p6ML+Q~}M)feQ zljxov_PVg}d4)F(!S8pb%O~z{)zJ?pIi%~H-ALaHJW+L)PVwOB^KR7#uc1qA4Ll!* zx8f`D3BHAo21s%i+rEGzwYwJYZD#2p3Y`|yEC}aG%xKhjY_ttzqvI3rJ*k^obXB*J zO*hVv=zL2^jS4OS4{M?$^XG~kgvBI9PqNI^Z%`H+ZHo94 zKM*)ia6H@h_+I-}N7YVfC~1we*2Yw-iq-|^E?-l+IC{s4V|m=lU1j>w;Ir@V&c|)wPb#9OUDyf7z^T4)%b5eaNW-)>jYBtO>?_(8wOcDMZJA@V4qLLHBJ9n z&7`vm{~N20t9DqO`iHyhvvW00m{6md1jG9(Ic5o*`hf$_d+T|v^%S&s{Ns8?#b7ZH zyB;#xy!XC@!~$gP&_*JgbEnZu_S}oSPeXbfXTq6^XN^y6M!44+<=M-pitIbyS;L-% zq1Z3JWv#K(`zlqV>3%xLHEKC)Yjl~`86o9nF?0^`-2;8D=QX`lEAtsnH+2eZsHFS5 zJy$Bkyko^oOOtQW)vqpM);$QA(_-34&HdR(j63u@<^9r?8ME}$6svDU`H*P#qe-@E z6Da$!>P#=wz>UMO?~kE@Bogxc3m6#kgMkCX-$DcbU=OFCF~QR`!-V-$%+Xs>M5=;) z9sRfIU=*x%{CP}zPtoWzNrR-Tp-175<_^B|S|+7EkCEEGk*xDXx5_p#zPOv)H~qNV z)`b?!3h@*pyiRMwQ&@6LjLd!Q?~shVidnT?UxzMHNmK3Cv5W8b6exA^Wf@>1EjKe2yw z_5RgrlvfT@+ZnNdx2nEA_QsKlh-c@qV-i=7Cj}SQ-SfWkVwKPeDT@GQ(Pn10vFQ@a?O zYP)jn``HEGYqo*k!5qyW7sd?#*o3>;O zu93kd(M{BI!r~mw=(+pk^#bz3qh;0IwHw#CpZPqR{lau-r*rFbITx!;o3MJ`LG%7% z&bN&xUN8B|&59&kW#8Y|5H&1pG1NpIv}Ip2#k8%R9Lr*)-J?yi&9LiSrE+MjgkZ^O zawJ?=Li0|4aD-Ylm3}JFGWIOz;4^HsuWS@3L+Ce3zDEw!neg(0dQRUvS)Y2-ebq?o zBUNmaIpXz_LRpY#R(f7H+`h3jOfc~aOSO5$*D96^ap|)MMRMll){~(Zhoe-hpWq-> z59$Uo=ZskfqqSjf9XBlK^_^_RFEhU~lANTl5uTMTEPw3~ntSBfyH*9SToRF0(i?# zJ1!(JsM5Ax$`O*9)SU58^4-iwo@)E_~`F<`i*~ksh**o~% z)HE@&^1b|N;j&BZ}GXf$c|1pBVshLxor>0I7oO*g{ z;~sZ_*gsn$eC^;4Bgt5B+{2jFHNjR7zy+-J1V6v<^`nBX8e%0^SvUVcpBR@^9PkxqM2@oKMk!z5v zlWT)_D&!ac@x&ESR&XE)q}vyy-X7$^3kU{V|M{l>DO=zdT?1DPs7Ja^UQWJn2Z2NV z2d#-S+{5W-!!KX|rukPr|EJ=iUHPTmDgXe={Xp|2|IfN_rax^6gk$8Nb^e9`p!Nl{ z2c!S269e_(NFD$*opA{84gA}D5Xc(<@OMIhIu8I^-Zz7N;V!QJ0WfCFsL0dpo6oTIgJL_Yu=Etgze--v}C74$h-o+#)AL#l%m_ zE1Xe0tE8-@eO^abPyd41KhuHnp=8$`}zk4U%Y%ZJ~25pJ@a;U4vkq^egEO(+NX8g z*Kgb3cXshV_73?vzvK%P0)&j597;}g$QOhx=#X(1a*E@pDOoiyQQ7;j3CiB4 zWI9wmP1$`ErL5_?I&mdJH{gZ6lecn?4Nwi0rXG^`0}7E01O}& zBGpwT4x*kMJkuN#Z6*%aefy9#F#93hPK55IL`!;*^Gjzh{SVJ{zglg6{Dj)DnB4#V zmDtHvI$jq_b*-~;LLNm0w@NSY-?y)?8?PvQ&|2FtIe+ZZ-L~3SFX{E@UaaS5Nw#ix z8WRnO)V3r5>(wbc-M+jbLlZU*t4;1TH0#Y}ZyG0fJFO(M;-kgtzWeT~^J70$dAmQp zP@do(Quu8B%--FBt2s-TpVy^|BuO|1XMC^RB2tZ*sDB~>Q84T?V%$t544X4f0)BAc zqauidwRYP^ZCoVa&X)`l@M043BXi$~U<}q@+1EiTO%Qmnk$UZT8tjqXk zV9fOf-gxo$-Ou}eMTp~J%)CMRqaJN+Oud~kE%k)ymgLV%{Cz&9@`1LzjrfEopK$nT zx|iPSBDVMh6RcWVVPo%p1+A2|%|w98DW+*Vycr3g?Oe-2$dLe=1sM{MQUd%@;NhxI zdh+Nyco&f7_{O4Zc%hzepXO}xdW$DKoW|sTNO|y>j0a?TXN^;a4?=B*=uNL3ow_)} zEw@@C4_OD-Lox9PYD^jHLS$>PBLPAtmV3I2cp~hLR#zu2 zL5{y`i`f!UAgRCrK}t9+@5{tzY2jrZ`0wQI4-iGB1#wCbH`Z!+hG?z>2Mqs$L8gBp z2zs27GHsb8Ptcgv-Y4jw>K3BlnX2K9Ow+7M>jnx9Fi8N z$@^~h#2s@h1M->7|HU-wVF%@^r_rcrSS{5i1CGDTmKjb+Jq2`45Rfv zaEvh%Ld#;x-#V>u5x#4l6&qtx-*|8K+PpEv^wJ4eM_oq&epTWi=NznWD|YFqs*KuF zgt|IG7@HRv#<-Dt6yMXyK%jW6P}OI5)Dlr<7u!iY+_-GVhzRNKkmF;kA4f`59W?5X zJ4~u7Bdrf2t85l+biM3>1FC;PGnY&cQ`9*nYJAXg*EuCBBFloD60MQ1RPBK)^bL_7 zc?$1WjugOKKXdD##8y5jT}Lsg@}NrAIkWik{DMP6gV3AmA`-?H%^1=Tt;VL)IvN01`JJsGOTp4!@Q8fmb_2u_uD`pT>P`Y(U&QcA}mHqA3DU+b_1PVPrw1wC`(#Jg#`F~7cNy22pnwimFMfhWcN2`7aeRCUP1r}_;Z+rfl$ z5?KyHh%t$NATf)ei+C>r@MDuVmbO*h^YGHx5fUIS27QHu7p;f!;EvQ(5G zXj|p<5k2fcBKjE#VAI%4L=r(9N7d&&n~W}3T;ePbK+Qcv+jaBDFH)uxhnD+-xKCu`_KolbrFbFT8NzA4 zPSHdKiFxWU7DNM#+no>eQVFUO%hPGv%`*Y>hAQSsI|5AOGI-tZTYG#8BLq%_3kkS? zAIQTdZDcNhrn;lC_2|fsceGqG=%jAA@J#}pzh@A%<9AS?H!fJYMgqEnqESEeHIAK# zTHfDB9mDSsnK(CmmfSdqEY|yZ)%egiuV&x6vCKi));8&FwS8YSM=`(bl-;^c4SWH0 z^tYmikN|38I|Z~1rKS%5t?1S554!owMRfAUCHy&_=@nyW}XvZ;pf3x{g&h^U+ zFKOZ6i+b9Zyk=R2?JomCcK=cWHh-6Z_fH8>tEyFsb>TW1fHlf&bT~}r^98`}4|1Nt z5?iaktt8$|tVlV?LFei)qCU`Q91H5rqj6IX>LmftPkY{X6^0De2Yb|cYisKFIb(`A zcGBn0KRtt`DIQzRy2P$m`oU0W=)}UfoRV;OAnFgqsq@VkQw{8)sY;Z+qm58s<20x{ zcxTw{k)9PL+ct8&fZxkySN}i0SLjgKS;WbY*YHX>Eu9%vi%K_T_0nZy_N#7zlrx(3 zoau^I=ie!w8Tc@v7rhRVH+tdRn69+4&?3&#bsaK{l*f^PWREaD{E1hC%gKof*(!E) zYw0^J^~JFr$E@epP0km0rPx__m*8Iw6OVeC&^$@{I=zTy>3PF?_9UPhiOwM=+v8?d z?E0$65h@s&1a)CV4-=!S9XmmSbHMm^$MI_H8a8|V%pyl^6LuhH#jX+WyrOMg;b&Z9 zFl%aI{YHnU+E3MWdYS*+HT=hcy`tu2yn;+*hZJ`EG(Orrc1wYunV{Yj0Z;3-6+B;i zew<)kVw9$TEcJDjq_}s@qBcC;B1#y*3y$ot93&Hh&PspaE+nP~AE4UDITvH)0Pn-&Q;r(Q(@BE1jwHzh&Ck)DUs$*tpdQy&nL<=7o1U$jpZ5;P^kUwK%uqI0u53=)?F4 zT(x*J^c#njpkB`_s-DYBvmg6ARB%gO?Y=wn`f0{fgi9{inQOStSeG#cDej#S!zqvQ z&z`E6bB{Mpywij1g&wqH`1e@8qX;~QMkqrbKzSo#h<8H4NRINSaeV{u&o3Sa)r{W) zG&GH%n)zu^?d-;))^w-9;Lj5@*Vjg=#0%Z6zT%(tS9UN=*{mk?wxYRF#oPGHth7Y$d|yppH#F`Y*Y!#)zDAk35^0|9a&^EmU2IVYN`1GF43dGZ z#kllVD54v~w-2-iZCPtNYO(2&-a+sH41+XJwtH;dyni|kI`zF{yz3+OR7I1uCXYQ?+X(_-21!EpN%TRasyy>;0;Zl{Jp2JMuW@D#_9k-tu4%IL`w zOY2t`p7iokwO+B~SV9!r1Wol9MLmY^g*||aOy@(sr#Ir5x^4{@pbcz<`iX4Q(hf6U zibKQ{HqYF|CetFa*mhFbYaebpX1RL4fABcPV#MUq5czecUe6FB&Bp#Yq$NJ2bd5VE z9_2hT+uFC6Jm4K`SFe-b0d2}2R40$wi5l(T!$Z*-pKE1$N9gbtTG8l?t=liR94TmEJ|kh)}3jcHdrJw4|!RnUta-3=gl6 zbrK1?Fj(IP`uBtWlERDO=Fx6|~wsHA=EYlhlku{kSH5#G^8i^>-Ao7A(`p?ub8t8%cc&0!1 zR7!ojm~aZ>rcn0&^-9xWtopd}-eU;~8~!+t!Vs!JvuwITtyIRN$-RIDO- zF)*e_mA-O+Rrb*lfd~j?xNq3N>PfOP>%fG+>Kb`3g&}BKUihlOrpi*fv`MGYvz^W5xlu9`odgV&0KXrA(P%|~yc4Z7E<}7ivBOV;k9!pw zKM(gQM_i*6dewcMD_l*(Vciv4{`&|2`uoO3PsTDc%txA0RL~FhrB>2>W}A6T$3q+f41l+N@!TUdV8<5!lta`weEWp z;L<4Mc0UjRrhNXpX%)6Z1%y%x;mx#tsQkHH4bir1M0v<-1i$|HQ>@FKh3z*=3k1c- za&nf|9L~y~4VG~UB5|u}sYd$3X&Su7|AvcyCk4I`oco1w4Bj3`cC~JvdexX3aeG|5 zw$Va|+q0YgZgsRd)xE9=CV>y(s-5WK7@~qP=tkt$NB}F6t@x8E-cCEs=y@C7y~Is1 zFwncWYkFr!5r^ODmpKtFSSs>r)~bA%E>?)j6A0$)UE(-Vi2I01?lF#0SH~NBnK-23({+>AbDK{_Lex{v6tD-?>V_)x zv4n?G`4k{+8fH}ah=TYiG=uq@w)3)@l-by?`xmk#deK!Z@LByQfh zB-d6dkfW`mq@iZ8uQFh_Ef2DQzW^?VHz2H@U6chQzhYf5iDK$ago^>hVO+)mgEEZB znuhwO4=$CUyPa$Bu|wwuDo@r009M=P1Y$>{WYAMRT_TK|P)Ya{~Z^}2qGs) zz=zauB{flF92{qt5P`_JV5x1(`^{0E>p|+p*~Q=x(0tyxeepb{ma{(jooL7@Eg&H8 z{|F5*YB*8S-Nv;SV{`J9swF1s9xU1^!+)rJfyU8PRg5^sW}?lZ`Wq%kh{yUY_G#A&)ma!eHDEWN(Y@OWm0%4T za934>!t->9ARSi>irzqOAjYWiWTFf~`1Fq`T?#_o!rjl;mH~ef@E3@L3W785?T2G0 z2CD)vYSNflq)3%K_B^`Ob2aOD@iopwQDp*#Bj8osMcL1yfdd27R20~GOvjT#f;!eb zhqI?MF6&XCI_H>_*`?f8r16&m6sIooPRbL2q$?!-p%f$mYrf4D!UIDwZ z5)I8SdmU33-m;EwC6A~{bC z8`l*hxnr^ozD)vrp!8{MJ|588ihx#C4~0Jf!@UQKsL?`<9f3Rs#OOamhX1sO?=Iho z7IlSjXK=OJ^=W4G5Csxmo~aJL%WsYy%H-U|i$#%j-W(Ub_6P|0E9U$C7*rC4h^$Sd z8D(bj6vrP}=w*QsP|!T@UTU%=`grWQx@vo2`4m)}OCn1?$1 z!^9pw+`Ms|zU9rt!)!UGMctfK#$oE08ydWJ1d*V;ZE-{f34nmOb!8hs^;iUhI6Wf{ zg=OU@!ZfJ2V5^e9YK7p`Jy-hq~wm zF7oQR9*27j%1exQMqZu$k<#?;=`ngtxUwDo!WL}J6emL@(;@+bYlj)T%5TId8CEdv z5QY)L4nwtn)8nj6e3)=cGv0k=C=fdmE0yj|voTiRw^L1R&rtLZDp`I)#KE}jGvs9c zqhltNjXi1(`Uz<7-nWHQ@@wytyBGQNg;Musg>`LY-^#Yg7d!wX$LHjH)NcS}EmjNd zRg2x)DZ{^CNstoiofGZJgv>AE#W)yWq|rTm~nswF6|O!h$q9D8fHnr$U@@*h(}03d_Huu z0rhRylLVkJBmh$a{N~ZsN*O5_T4kJRt^&kr)ETke>PW=PX{4ma@Rwrpl@6vtAfVF| z#N&Cb-uonglLQ>mpqlp}0Uy826G=cn_}>JwGY|W*-#`L7aVXqnAhcnG7`EBDMX)1W z0r-FS?6K&SU^uAKL3iU?8oOh9uY%K^t!*D>{Nl41u1o^{6Waf0wi#jF8G#WKHgBey zM((O!)p5D&$m{hva>$o@m2VsJ_J5@E-*EU+#)Hrd8{h0$0kc<#&KA^MKBGfdV|rw_ zEi2{vI~H_1JG0AOW}O@_YJmn#st6_}P@63N3#su1;e5YLb#NljU1@G~_NKyzQ?Tji ziyAg{0cZ3@^N(c#-}0jQDZ|(|_!*H5W$SrNZ4#(bH@+jITQXH%{t1>|USBHZ@gljH zU`s`P$r?G8R#wY6;ZdsY&YHkZI8J3{unz@6Uc#H@&pzDhP+D+R=c~aM$2=ZuV=6$( z;76Exs~F$nW4go`ooSjO{f|dyj$mNJkudG@kJqF|LpkUz(NUh+iDjr(<{TY zVaw1qrb>s-kzGfz8o=duvJA^j4ctYek-8FHtDssp+fMIzlM3cmo_{8)qqF=~Ma+^N{riZJ8sX-cu&xq77=Zp{F!5(TYHLds^mSg zjpIt{d2`k9&s2*_0Jt0Um&^$zvM|wtiObd}sO63s5EYD4i9W@f^-5tnIs4`q?~V0y z#?ZTZNW~YV4r7}yyDk<26mR(;_t zVEwOo{Y)@?6&l4bkCelG@9&5z)KukTohgiVE%zMPduphRPSp;$E8Fs%zMNX%ZlngE zCw9K8lf^rXA93=VF}@L#DE(@qms@ft%dB6qQ8(SVwpM~`o-J0r-Go#jCy_lNZl zzMQhgLacqzH%J9c!h+dKP;3X|Tf`P-F$Tvf#daBY0z9$-V!%KN2!_{BM5%Q?nK6HYkVOl$8Fe-*_dqJ0KWVd znH`OtiFHg`SFFW`W@ob8Nad|jz4!3ry@wYg#D#$GBY531*? zVQW4(*ugh2we0-UZHAbD8Zy{N0(M8h{Bt&#T4LGMBF6Buk$@$2E-<)1)T}>@^xjJz z)HS@}_QOuJB#z4gZO8oLgamp?;oLg$s2S@@FGfcCT=$Z{=ZUomhq5gTV7>D%oBQ`% zK-0$kB|d=I;~t{6&uy$9y)a&e2zs3nnu8{@S>$&-Sfn=ywj{~wjgY8!un zoxXbo3uc6+zY$cdyRkF9O}<%Eqj2ljSVGL}`|nrh%+>mSxF$payxs(%xtIe+bx{(~ zfs`WwuMdq{vK#;QS$rPx$KhV9+@Zp&m7qpfFsS{H;Fiam!_by`rvOBO$#EoLD-YZm z`KGABfMQyQ90P%*119W9vN$?VYlbM^0xB3=f!)yZ7VQgFYs^_Ke9(D&c761Sw1EGH zuTb)9>~^Y$=GUrBp$_2P=UHKBF=%f7+-ms48wtl(6f9|CM+R$Q@ondQQ}711fsIXe zOh4GlJ~fi}i$`iipri(05igJF*X7iRgE$|wwN?G-r-wk~VHh{TbTX_P9m+bfx#tp7 zmz}8m?Zw1$^5z-2Am)}<~o+9ryl1B01F>mGhCq}hs0 z?A(_qRB6H%6CVDBz=QVW>D{rih-zagw$j8j=JsmT=Sq3^-Q7X}jZ07>obQ>3&ZxquB+VN>zNDwJ1Tz_Jo6^E$?f0_;tr* zr^2_C8Ud$(G~ptynj^JI%ZGp<6*XFcsUna~bpCKZ4FCVDdvKdc)d**`p@H!3tJ%W2 z#EZN(Pp4;oS-zkYx9jGnU7gmTAq#~@+rI&m2-tLe(BC)4cVg*`z@rKkp!)oo8U=#I zab13F0^->NdlJBB6?7A|E}?O3DS}`utj>fjx5FkPvg~AfTV#W)E#Dq}I$vy^h)bWG zidS4Tef6}IyhPQ63e4%yIOc6jAfADVy}B);)lUripVv@9aTa}5J|Kd>$IpmJeP@VP zyCtXAUl`xbc%Y0%zRXg)pnG*fi2;Z;p0#GEREnw*bG9)jik+>15F%!H#nU|@W7gy7DR(x9P}zD3UvO+uy*%I1k-0wCl7GiHaFgYpNPcmI_A~4vntI4!F!`rc7GvT{L4cLKJZFsgbvak(<67%m$5NWbAN%!BqYfd z`h5RNBY~g^!Za}DaR}4?gIh@IwRv`*omeF>_Dvt#X4Sv{89BY_*B`V6cw@M&;Ji*u)bVkhgPRd2s z4jL>mJ3uk^Lv6adJ9WxxeMYakP`cjHZx83L9>15o)t5MR9=PRAIGzh0Tg|5gGalj9 zAQ_;IiAIW;GNFkVqkVK(Dd-(h3eH-~$ zu;4M8G+?xDNxV%0!)2*H#5bJ+CTs0P>v#ie!S=VN&EbBQP54 zV>6=d`opB->eLjTMDsHS>v=ky%ylYUQ6EcEJVm|-?*9FoG5%vJps85Yoi;gz$_A&= z?HO^*5_?}^g@cGgf@O=|sL$>t;0kXzS-A4jf6B}s2;mWpM4n`MF)H5{1qy>N<$L$e zVHQ@M1=~kt#FkIE-ttHtLN9RZ3x`}CQt8O?di~ia^|iimF8JT|XYlhIVf|tJe9875;o?{rXo zT2!gSr=iY7Ryy5I9UZl74`<(J zS|(|zduQ)Fo@kQ-*BfJ}6OPlmz82q%{fOoq=ww4A7~-X{#5ougA+%B)@83y|RKW4~ zHFu%~B5)sPRIQ&?rpa^Dhl#XKV4hEXx9(5ASi>n79@?%L)gk_NBbPbD7XOU087>;@ z9M5x=!15Sg!7u^(W9bZABx~zgy;Q_q$wHoyrQU&}a5b}i{(jWs%|?VNLGCoRF_zbv*f&vAU0H#?hua*OW|b5AqU7`yOU*b7tfPMa zG~@sj?A|dZB6Zye@dUWphypVJqsu7l`63if9^9D1R}o{NV1_^njJV^#-O1mO@0(@x z0OJRqg(|~8FOTDlLB2#)%ddQhu5A^gO^N#2W&icy^Xhg!W7TgT`zyE>Me|DZZMjzj z+e)0K00SSEn4J?@^Q$(_Yx?3MzN&*mn``+|$3Rs62Z8;EEK_!*VDih2?=q5A!*ItZ zn2stfS2B%aLq@5TmfI!zz9O`GMwk-lFDb_OJ15C}R#RxJQx0gpx_e4;o@%H)&UxU2 zN?bl;#(yh;<*<|RFp&gwRkCmsPQUrKs%T~1^x?iH(iW*@)Fi{1mCyk@?b~q!`6*}U z8$^Ro0ge;Wm{up7Bd9%Z!VM%=x#cmSv1RTzk^J~bOoj5mhh1$OS3SuO-u{Ue5&n|(}$}W<~jAX_i!JUw>n_U{*@x(Eq zcRz37q=zsTz0?9Jbp|om^rozwr!B_u3Sx{;I2sGx6vyUf;TCxgEp@=bu_k;c8pZ;` zh1!X7d?$*|DI$HiRo#Cv$u%9@x9M)5Tmu!1)p7Xzz+?}fb3$E0X3xvJxE{5X;z(C-7DA6 zAL5HlIO^Mbj4?q3d7cEkIy?yT=g5QF4Om&~k`47`p6n%_w_^zqAOVwS!j-Bh5RHbB z;2vSrXTmvK8OF6212B3-#MPHJ%I{cH2a9F(Vz?}H9DSnA1tK(*QGbvv|DU4}8jgR4 zX;2?_dF(ZQ z&Xmq{e}a#+ZJ!LIA9Qhef;azEjyzvtXM^w*d>*OaW@D!99+J_5;Bq2PSCgGu9WK+m z&Xgi=Oh<5O#EuYHcXlt~J#mQyOKgR_C)>(0cV(L3+Foczm)#Mh;*1C`v6CPwWQ-GN z$7ctllbNk-=liSd)KlQMFDfc_=3dIU-=v}1P;SAGTlWpO@P zI4!VR2^w_}BLoi;1Z{;sHlP}i5_yB*enlN%0@0uV*dc@94*XX|{Lmsl1M1U}O(2l{ zA1!!E7I@_)n8DL8NwJCug>(uxeOH=_fRpP2naBLI4 zXnLhj{Wz{0OK7Ptx_waerWC#>6Yn2<{?Q2AGwV;g<~%_ZaTxGVoPSu&T&u=0#lUWO zI`nWe^&VIc^^f@=2WjSnK;;CW=$lQf)glWv<{;8q4fK%EVYh%Lb|bQ8pNscVOZi>e2;O$WpC zmVn~50b}HFyfN`M=|4j+x}}_&!RwP#%4?O#gz3$E^U>LnUs2`d)Jv6KR4)I0|H?G@#su=4WuX- zDc6#K+jGezK;&l{jp+^;hj5^h3z)UolsRGXoACQd@soY?M4AA`k6#{|0Lg;q$9c`+g&a#oOP6qd2 zZ^I@6APr&x*(ED>>1!@-w_gsOekq*x7g0dj8QvzwGO}ZdzWOb+WQY74G2>^-g9#my zM}@b-c%G`OMTF?2>u|P2d`a2f4-D*T?RwYu2mnOGsSc0S{`UR-uOtlnt>BJv_8U_m z+=jpqKzg%og}1-)&i79RX`2~aHCMMcqIKqWFDBN9tJqi?>ySG#GckMPukN5~SCwPp zR`L3k1erR#4?N@cP!)j3RB4cgBORNgkHh$=i6plis z_>P5Tx^{QFnd_6~N#oceX6YET z42R`{$QGD56FjXiw}hV~ic4t=q8;Oe;?0E4Z77#}9}DLz+(Gf8My-2Lcw={d!o(=# zzq|(z0#PNx(2C=?r&MJ=f_6y)LzW~jbyZuCID;K|Siw&acAC@iW6>usD|;qb=VfCF zC|A|uH;567pf2}>fOzslZaC9lRHLMJf{7c|a|N@URUFmVBg6RP^&Cgp*z+?%VRq?} zeQqxQu?E#&R0H~Z0bFMNG$F^VmzpX; z)kOH4zm)m82?pnlVSjPV*`2;|$3Y%S|7#NZ$9Y~*S^k$V0V>>x8%h5$)h4>jLv-47 z0C%}2M-G+hI<6EO6m^liIBJ{?y>PUzW=**+wcN$H@okM>u5cW0&$3Fn&$BaE1)+6^ z2Z3C0GY1rHpuM`Y17;lFr~&+cs^%vDk?XivJbYy$s1)yPa0#u3c&F=Kuzv5IDr|O! z??$hD$ML2lr3B7J};Pq#)j9 zg`brHdc{V}b?-?p*_vmeThVM{-~YElqq}>Ttlbt`Da_bl7n9#>zcKcH^ZwNJ%vt-l znr$v$`tNk|!ymw*^SActz1hA$CfDuf)&H{X!rL$Xa_$R!>mSV47p$mvzEq?9QR=eO zmXeR_+b;)hp1bAARrL^tzl;~{^WWc0e^lSO$9T~XFV8fzGm`r9m}r1)@+fU?Nw{1)cNFnHkdj$SyQHGf!s&no;>>x$^Y7_*Z)!90~|^N zx8j!nJ{zIWJzThJ!J?q~lm$#?rd%=^d=ZH>3h|6vI1nc80eCwvcB*8|(K z@*ge(mjc_rNZ$p@G)Lrt&2he}{9Dcsxqoc-y()fWy4pE@{_HZL(|?=SHEj>Cn$}pD z*JQl>XOEn=_AA}%@m%KpE%k@A z>jf(&2TVUQT|0Zl@kP2z=HIY-Ey+7|>zQ&%*UP7u9iPZ>Z}o1=*aN~2vhsh(4ggH+ z8R`%F{{c?)E}Zuo*x-0C0Pd0O=lORLI9Rdeb#0jSexaCS*W*+^@-5_$;@kCmZT?s9 z?%A1~zLrhX+gy`++nvgGwXp=S1A91Bj62i+44LnndDiUzFeSF;l>49VdkXJ3fbE!E zhQx~CZxeqwF8z^wcvtT8PQB#a8!miVZN1`H^STqtJGO0X(wyKaH|NAd6}NyFXV&(f z@=&~YZ5J?3jNzZsaduRXLm_U?_dJc3&; zXMQ{?Q7Id;r*Fm1(*_K)82;ZxJqcasWJ$go@DzZD z-Y$I`mi_FY@}D{zn>~uNWkW=38%vj7v|PmLCl~q?ZqW+8ozHi$9{cLxqP|3gdDFeytC&3+7c#Nlvi1?~s^2BIrl?--#iYRCssAF{ z&F7XJ&(Zu)+zSTGlnD`Wc z$GQk0CqCe*SEFeUks#(-#fak^49+abm^0=6#P^MoHL%${UeCR=!Azf;XZwuzo6Rc3T0TUhIbBK zF8NSZx%Gto)0f5RrmFtS*8-<&p=p_sNf&sYHTIid5U~egVYvq;z#G*7)LSW#4Oj}y zAV_yqpld`ukRMs&V>a-i)HsgkM>hxkly-zkVw@OfwxerCKja&sSp<0O9`L|-j3d9% zO+Y_Q8)3p*hzaOtYoi;0ewZl20Da);+#n~wj}}GOihkTALaT=;-0K*JPeM$=eUu== zluf{s1>too>cN8OPC>1b5k@dDtWQ8P1Xe+#Yey|qk+th2BWZ^gu>sz!z$5~?1%;d8 MD6kFi1AI&w0Qh%!K>z>% literal 0 HcmV?d00001 From 5d6d8c014563ef351919b68123460b56ce2c3f60 Mon Sep 17 00:00:00 2001 From: Ollie Tulloch Date: Wed, 22 May 2024 23:12:06 +0100 Subject: [PATCH 2/2] Changelog update --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e09537..65208ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## [Unreleased] ======= -* no unreleased changes * + +### Added +* Handling excel files with incorrect file extension ## 11.2.0 / 2024-04-10 ### Added