From: Mostyn Bramley-Moore Date: Tue, 29 Oct 2024 02:29:23 +0000 (+0100) Subject: 7zip reader: add SPARC filter support for non-LZMA compressors (#2399) X-Git-Tag: v3.8.0~124 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=974b59113d595c1b7babcfbc1f16341e49400aad;p=thirdparty%2Flibarchive.git 7zip reader: add SPARC filter support for non-LZMA compressors (#2399) These two new test archives contain a C hello world executable built like so on a ubuntu 24.04 machine: ``` #include int main(int argc, char *argv[]) { printf("hello, world\n"); return 0; } ``` `sparc64-linux-gnu-gcc hw.c -o hw-sparc64 -Wall` The two test archives that contain this executable were created like so, using the https://github.com/tehmul/p7zip-zstd fork of 7-Zip: `7z a -t7z -m0=zstd -mf=SPARC libarchive/test/test_read_format_7zip_zstd_sparc.7z hw-sparc64` `7z a -t7z -m0=lzma2 -mf=SPARC libarchive/test/test_read_format_7zip_lzma2_sparc.7z hw-sparc64` Two test files are required, because the 7zip reader code has two different paths, one for lzma and one for all other compressors. The test_read_format_7zip_lzma2_sparc test is expected to pass, because LZMA BCJ filters are implemented in liblzma. The test_read_format_7zip_zstd_sparc test is expected to fail in the first commit, because libarchive does not currently implement the SPARC BCJ filter. The second commit will make test_read_format_7zip_zstd_sparc pass. --- diff --git a/Makefile.am b/Makefile.am index c72ed70f7..8f175f68f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -806,6 +806,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_lzma2.7z.uu \ libarchive/test/test_read_format_7zip_lzma2_arm64.7z.uu \ libarchive/test/test_read_format_7zip_lzma2_arm.7z.uu \ + libarchive/test/test_read_format_7zip_lzma2_sparc.7z.uu \ libarchive/test/test_read_format_7zip_malformed.7z.uu \ libarchive/test/test_read_format_7zip_malformed2.7z.uu \ libarchive/test/test_read_format_7zip_packinfo_digests.7z.uu \ @@ -816,6 +817,7 @@ libarchive_test_EXTRA_DIST=\ libarchive/test/test_read_format_7zip_zstd_arm.7z.uu \ libarchive/test/test_read_format_7zip_zstd_bcj.7z.uu \ libarchive/test/test_read_format_7zip_zstd_nobcj.7z.uu \ + libarchive/test/test_read_format_7zip_zstd_sparc.7z.uu \ libarchive/test/test_read_format_7zip_zstd.7z.uu \ libarchive/test/test_read_format_ar.ar.uu \ libarchive/test/test_read_format_cab_1.cab.uu \ diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c index b4e34d68d..62e9a2b1c 100644 --- a/libarchive/archive_read_support_format_7zip.c +++ b/libarchive/archive_read_support_format_7zip.c @@ -435,6 +435,7 @@ static void arm_Init(struct _7zip *); static size_t arm_Convert(struct _7zip *, uint8_t *, size_t); static size_t arm64_Convert(struct _7zip *, uint8_t *, size_t); static ssize_t Bcj2_Decode(struct _7zip *, uint8_t *, size_t); +static size_t sparc_Convert(struct _7zip *, uint8_t *, size_t); int @@ -770,7 +771,7 @@ archive_read_format_7zip_read_header(struct archive_read *a, /* allocate for ",rdonly,hidden,system" */ fflags_text = malloc(22 * sizeof(*fflags_text)); if (fflags_text != NULL) { - ptr = fflags_text; + ptr = fflags_text; if (zip_entry->attr & FILE_ATTRIBUTE_READONLY) { strcpy(ptr, ",rdonly"); ptr = ptr + 7; @@ -1109,7 +1110,8 @@ init_decompression(struct archive_read *a, struct _7zip *zip, if (coder2->codec != _7Z_X86 && coder2->codec != _7Z_X86_BCJ2 && coder2->codec != _7Z_ARM && - coder2->codec != _7Z_ARM64) { + coder2->codec != _7Z_ARM64 && + coder2->codec != _7Z_SPARC) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Unsupported filter %lx for %lx", @@ -1708,6 +1710,8 @@ decompress(struct archive_read *a, struct _7zip *zip, *outbytes = arm_Convert(zip, buff, *outbytes); } else if (zip->codec2 == _7Z_ARM64) { *outbytes = arm64_Convert(zip, buff, *outbytes); + } else if (zip->codec2 == _7Z_SPARC) { + *outbytes = sparc_Convert(zip, buff, *outbytes); } } @@ -4007,6 +4011,64 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size) return i; } +static size_t +sparc_Convert(struct _7zip *zip, uint8_t *buf, size_t size) +{ + // This function was adapted from + // static size_t bcj_sparc(struct xz_dec_bcj *s, uint8_t *buf, size_t size) + // in https://git.tukaani.org/xz-embedded.git + + /* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * Copyright (C) The XZ Embedded authors and contributors + * + * Permission to use, copy, modify, and/or distribute this + * software for any purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + size_t i; + uint32_t instr; + + size &= ~(size_t)3; + + for (i = 0; i < size; i += 4) { + instr = (uint32_t)(buf[i] << 24) + | ((uint32_t)buf[i+1] << 16) + | ((uint32_t)buf[i+2] << 8) + | (uint32_t)buf[i+3]; + + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { + instr <<= 2; + instr -= zip->bcj_ip + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) + | 0x40000000 | (instr & 0x3FFFFF); + + buf[i] = (uint8_t)(instr >> 24); + buf[i+1] = (uint8_t)(instr >> 16); + buf[i+2] = (uint8_t)(instr >> 8); + buf[i+3] = (uint8_t)instr; + } + } + + zip->bcj_ip += (uint32_t)i; + + return i; +} + /* * Brought from LZMA SDK. * diff --git a/libarchive/test/test_read_format_7zip.c b/libarchive/test/test_read_format_7zip.c index bb47be668..e2eaf4889 100644 --- a/libarchive/test/test_read_format_7zip.c +++ b/libarchive/test/test_read_format_7zip.c @@ -1301,3 +1301,76 @@ DEFINE_TEST(test_read_format_7zip_extract_second) assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } + +static void +test_sparc_filter(const char *refname) +{ + struct archive *a; + struct archive_entry *ae; + size_t expected_entry_size = 1053016; + char *buff = malloc(expected_entry_size); + uint32_t computed_crc = 0; + uint32_t expected_crc = 0x6b5b364d; + + assert((a = archive_read_new()) != NULL); + + extract_reference_file(refname); + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt((AE_IFREG | 0775), archive_entry_mode(ae)); + assertEqualString("hw-sparc64", archive_entry_pathname(ae)); + assertEqualInt(expected_entry_size, archive_entry_size(ae)); + assertEqualInt(expected_entry_size, archive_read_data(a, buff, expected_entry_size)); + + computed_crc = crc32(computed_crc, buff, expected_entry_size); + assertEqualInt(computed_crc, expected_crc); + + assertEqualInt(1, archive_file_count(a)); + + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + + free(buff); +} + +DEFINE_TEST(test_read_format_7zip_lzma2_sparc) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_lzma(a)) { + skipping( + "7zip:lzma decoding is not supported on this platform"); + } else { + test_sparc_filter("test_read_format_7zip_lzma2_sparc.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_format_7zip_zstd_sparc) +{ + struct archive *a; + + assert((a = archive_read_new()) != NULL); + + if (ARCHIVE_OK != archive_read_support_filter_zstd(a)) { + skipping( + "7zip:zstd decoding is not supported on this platform"); + } else { + test_sparc_filter("test_read_format_7zip_zstd_sparc.7z"); + } + + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/libarchive/test/test_read_format_7zip_lzma2_sparc.7z.uu b/libarchive/test/test_read_format_7zip_lzma2_sparc.7z.uu new file mode 100644 index 000000000..2ebafa01b --- /dev/null +++ b/libarchive/test/test_read_format_7zip_lzma2_sparc.7z.uu @@ -0,0 +1,51 @@ +begin 664 test_read_format_7zip_lzma2_sparc.7z +M-WJ\KR<<``1(J^\JS`<```````!R`````````&XZ*<3P$5<'Q%T`/Y%%A&A$ +M5%3B6Q&;I4I!>'?U2E@?=@^5X!K6EVT<$4NCHF?DMTN)_D0A*']W)L'Z%[C!D#%Y!:S#"T[CWFG]LXC']WLL'!9\"+`GHW+D/-^/!QXPGPB*2!. +M&?09NH<7;YVN5R,.-)TZ,3Z02@1?D6E^K*PC3[:&6'/!,LVQ%I$W&4[9AN4H +M(CO]U]07P);P2!)3%9:,R>I3?`MRC-]B-0Q"VZZ/O5-9%`@K-K4V1BV(]-*\EV(]UK_[`!>/-93[9'TW>4C[PM_CL +MD/O':;6X+-;Z,AK??'U1&%LC>HO773Q5J_0Y9--2OI+3= +MQH_VD')4E65;)ZC;-27Z?WZ`QKO&#T#'A<1UYZ/ +MQR6=`OU_Q@1`D`""M0F.^4JB]:>K3E +M.L"=A%OKG9\4]`](:-9)`_U74PFQ?5]B:'LYYX"!(O`?Z)O;ZYGAX+NX/^TX +M0K75$*-U`.[W!@/&3>#LK>&,$^-7LYGR.NW.]OR5ZUID9$)KF83C3_(T`VC:+$#)> +M_J)O-N(.,D9*@##LJ#L6)@"0(SIS23[971FJOCGB:F-@KH8 +M^NW=UPME7UOPB-B1R-20(%:V"C(Z6^LP$9O9*_5KJD2/(NU"#J(66A;9L[:@ +M:DQ*AA6U(]38*!(>D&:^#<2X.9/]B0Z[ER1POL6BS5EKD4]@6C465`N[(]*, +M1]6:T99]16KXHV0E2G^R%J-\H(^K1V;-N5RH!KF8Z2U).4>YC.EJI#>:]WOP +MU+8[3UBF4]5WKQ5W619%/BB*5WQ*JCJ19!*@4K]%=/7W0`@Z6-E1HN>[U7CE +M]`%]W)W`!IA-F/W8K]60#\0E4_CUD38Q!:6P[F_!<$U'#-&1$:JM8!VZSK$G +M&%Q9ANEF4EB^Z7:L6>3E6P4(^ +M`YH,USJ&*2&?3ML,ADZAK_>3'O!:"CB($W22J.O\G$CE..,RWP:DJL#='-?Y +M*2W,E'ZN]S``7)5/K;EZA>=GJO:77RNU+S"3#]V\A^_.YDJTUN'\D&V.:+'M +MX;1P_8RY.GKK:U['95&:`LQT2+^G+9DJ.'SBT($]6)6X>4%8E6R>QI9F&#%( +MB*1]Q80;B^[*-X?J+PGIHY#5CZ1N,Q'MEK5W?+BE2'R6^D2A:W!POR\V79;) +MM,8D?C2](B[0)SW)<3]RNOH4SEX?06<'J[<&OJDWA_MH@C)87X.(@/:FHB[` +M,`9=MXE'=%I_EJ2UB:JTC;*.H\3]&GE^X"DQ2TM#53B$QR12B +MEY?G$IQ57"8+OXW?3YF.%:61.T?Z->H2PWS!2AZ1IJY=:(*.UB?-JHMJ2?(%&IW=*:VRA\'=*T'"ZH5?UCU_5-H\VD9?(PNF;GJ;Z +MIL_*^CQVY;0)8N:T3="V$US\M"[D)[YJ/YD;OG +M@D+M+#Q3%@?=[)`;XS$B,2A*D?),85#?5^10N\2#"DKDL,, +MA6NA6U>I0\:CP/E9,(`8^.8@7I94A`P5?74_%[NN#<4@18-TB>M\32JW*?&O +M&=[=TN=VPE\@Y$8\&Z>Q>PAZ_GSR?Q/=.LDV\='/S7*`N*V0>BB"5_9JF?=, +MB*\+@&D8[#W[^X*`ATPU[WRK">MUA3+YLZQ\?"F7!X.V0T9W4[?/_1+<+UZ? +M:=0+KHF`W(I%SP1C%MDQJ^M*Y^5@TE1[83"SIQ_<'R'=AR4E7C5"EJ0YCT8D +M4FI1(Y(H;#Y[A*;Y!Z7D=&&F^Z4ERQ>CQD$C;.GCY>JDTZPQ1?"4W0^D#T9` +M)+,/HN?5_Y'H#_@M<,VE(0@(X\G3W(#_S4C>D-7S/E`Z3DS#+M**S]YQ%*N@9RMHM#M?<:\,=^D +MA*_IR`W7;2OJK".[-`T'*-#209OXHBX0B%$P3#$5D+VE1/4$'J.D^9I[V+VH +M&WN#Y"AO'3Q`6"T60J[ZCT,*T1(=4I;!&6+F4G!]D75J$F5>:'%?M'DE8&I@ +MQ_L``00&``$)A\P`!PL!``(A(0$1!`,#"`4!``S06!'06!$`"`H!339;:P`` +M!0$9#P```````````````````!$7`&@`=P`M`',`<`!A`'(`8P`V`#0````9 +;!``````4"@$`@,:@07(HVP$5!@$`((#]@0`` +` +end diff --git a/libarchive/test/test_read_format_7zip_zstd_sparc.7z.uu b/libarchive/test/test_read_format_7zip_zstd_sparc.7z.uu new file mode 100644 index 000000000..ae94baa94 --- /dev/null +++ b/libarchive/test/test_read_format_7zip_zstd_sparc.7z.uu @@ -0,0 +1,59 @@ +begin 664 test_read_format_7zip_zstd_sparc.7z +M-WJ\KR<<``3"/F,50PD```````!R`````````&JZD5PHM2_]`$@!``!0*DT8 +M!````"X)```HM2_]H%@1$`#,%P#VY81(\-"H-?,C>D3."L@6'/;(Z"_OIG-< +M&K,3C)Y#S,RFL.J-K#=E?%`M<*T];K]*&Z!'F&=H'7BNL.%[O^W'36\1$@F5 +ML25C;RE39P!U`'$`MAH8R!8>B!DH;E@X$*JU?FFQ@'_(SU+1;*J;FIG9V2!V +MDB8GL-E)TFW5<'2+V0Q'MUAHX5$A^4D?7\5P\H?T8?KIK?2V@XK\%?S%>_3P +M+_T%-O!='.5[_3<`L!<7VI_!=5KKBLL%G+V.,&3U)2MV?$KV3YUF,P&H!Z]3 +M#V>,K8R]8FADM[*\G*')?"C+31ZP5*Q2I4*+"\LG*II-!0.;G<_,7C+EC>9U +MLY4PL-E9EMMN-;4=Q='5J?0(P;3R_P&0$#\BR-8$'!U_Z)J6?EI#$`1?6BST +MMRD5"0.0`B^;J_?<6%.@LVES/Y*3[@?I53>N%NP\GG1[@.PQZ"(R`BHM6XWT +MP""QZ$6.N7CIUL2C+?%H?4)2)QT-!Q'B@212\#C06.T0_+QU82-'+(*1\]/: +MXOUI.*YN[G"TU\$GFJC<#_:,1()6])MDFG01&0$%L9.&9C.6T,XS1G9U$1D! +MT:V*312=1RI;O";,ZF@XB,-+X!O!L[F!VN9DY*#9>P1ROQ?IHZ/-H=#O/6WN +M<+_7AX]>T]!8(UMLC@S]$:ZOTEI*#[V5AT*-U0/64G3$F^+YO2S/C^2D$XMB +M?'LG;J]N!MBLXMWA?@%KJ`$]!%%)0"-!"HJ:M`'``J$9*FX2X`!1J"\5929= +M4%!.O2K+_AF)^77`/:-'"SXW\6%YIU\F^,G;UASI9MI_Z9;A^(47[B^6XR"F +M)5>`7MKK@4\P`2F&4I)_/6!LZWDI8IMCY5@U4[/JEM;N?MIKQ5$9,RTVTNEX +MG;Z-F@\+0`!*3I@5-@FGL?SC,_@K$;VM_4S_7>XI!WD*?B^HQ%Q3$`@KC"+' +MCR'^M.NC^7L!=`08@Z(RCIUT3^?(6X6B),J1MP"Q/(MO/WYIR]X_$RA(U5#O +MI9_'^@"ZOZ5T"^S&29;WDF^K]`P(--U]F:3-Q0PHPW^EZQ +MW?\>+/@?<4/]3^'&-E#&\(W8=$S_.Z:5?V(;YW^WQ??G@Q"5*0"F\:)&\)23 +MQJP5#??[N\QK\8K/R8D['_38TJ)4>6XX00;0;J0:4<^0-42()$,8$.<$/@?X +M-]A*ERF\-K>$<>,XR9C?9*9``E`"3`']06$@RE)4>=$H\+#(34:E) +MD",,4H#T\=F=HR=6]0._W1W6:KVZ]5J;B#-, +MK*"WL$T4M_W`#V=)M/.JQW*U0FX4KVU',:S=LK94R%)MV.T^>F#(XK955_3J +M^*D\T>OF*`[.JXY5Y%9M=;_4MGM(+521.V%00V:9B$8,^2P'0"YZ*OD`5]6H(TEVB5\%O)=:1GMIJ"S;2^H&?:>9F=QQ3NW>@MW?> +M^%KPZ^JX-3*[Q^K`;;7AV*UL=>MV?ZM;YW'(P*(EP->J+N?:ZJF6$S?7N#>G +M#R\O-8LJM=2@8':3S$R)9D1)O@`:BLPA3[29$JKP*_AU`&01-J+U$-&TG7_$ +M(^5)BS^D!?DU($V:W.,/K>,;H4QGQNB'S)'Q_WG0"P0Q/3TM*_Z4E)V=%*&3 +M$G^6#@U5=.YK;2"L6WDT%&F!4*@A86:&1)*"@I0RK`%Q!08AA!2J,V5U$D"Q +M0"1L65R9H1$2B5,_MC8#:.`!CH&`8X3!\O=`W"N)K*++$/418+A*NBEL:!0- +M,:)]QOG,8+P[Q596>NE0>)@R]!R(D<5G>&C',BX,>MP+%Z#R`SF$D[#G!7A< +MK$WSC0;<'+!<;C>MS((#J%_WY_.':K+X#YNUOTE,2LZQXPR@:%Z3182?V20/ +M+NM&7>9T6=#7T")Z!S_,?U3.=0$&+.I9E/_!AE_UK+482*C309H.X/.8NO]A +MXS8<5[@W$$8#R)4[!)]8`,6A8+/B5R_Z#S*;UL5;*7WFT%MR,=B$;I/+E`Q6 +M_$;&CT5P[0*I/&R8BXFXS^O2%G$)?#T`,ALPS[61>02@ +M'N%$.9)8Z>E!GJ^`S_M-"-`BV-U9ISY8-0`0P#D<3DRRJ`!_)1-9IO1-6?,V +M8Y4>V5$$UZ,>%_=48D5U8P**U_GCO*:GEK+\.MTVVX0N@!?.U[,7P']+9YF, +M!4!6JSA;``\O7`'\G\B+C!7`R\U=`?RD"*%K.8`=D:(J%9K16'"C!,`J=AAM +M+),P?%7]6?!PW78<:++M.^&QC09HV6)V`$PH]VCY4ZEXX*\!;Z;?A!>^,`": +M`+(=Z:&T/^K,^OX$SNV[PRW3ANQZ\U6;MG#C$F-JD*'0YZ/]?57+NMG:&/+4 +M,%:\T9IL$9.A]`EQ"-108&:J,A1P*/4^H5U/W))T+V:-`C!8I"#M_T1/D[T" +M`,*+WPN,7"HVPM``,,ZTX&^E