pax_global_header00006660000000000000000000000064147732474030014525gustar00rootroot0000000000000052 comment=6d41cf624eb42ca5be5d874308d1e94d523fbec3 zpaqfranz-62.2/000077500000000000000000000000001477324740300134725ustar00rootroot00000000000000zpaqfranz-62.2/AUTOTEST/000077500000000000000000000000001477324740300147425ustar00rootroot00000000000000zpaqfranz-62.2/AUTOTEST/README.txt000066400000000000000000001262411477324740300164460ustar00rootroot00000000000000zpaqfranz has an internal self-testing mechanism, aimed at 'strange' systems, i.e. with CPUs operating differently from Intel, such as Apple M1, M2, PowerPC, sparc, ARM, BIG endians and so on. The command autotest -to extracts a binary file, contained within the source, a (Windows-created) .zpaq archive for check whether the PAQL code (during extraction) is well processed. It is essentially an interoperability test between Windows (taken as a known good-working model) and the "weird" host system. It is packed with 256 "shuffled" pieces of the Iliade https://www.rodoni.ch/busoni/bibliotechina/nuovifiles/iliade_h/testo.htm Cantami, o Diva, del Pelìde Achille l'ira funesta che infiniti addusse lutti agli Achei, molte anzi tempo all'Orco generose travolse alme d'eroi... From version 55.16, instead of using deduplicated pseudorandom files, I preferred plaintext, in order to dispel any doubts about the contents of the binary archive: the theoretical coverage is minor, but it does not matter. The resulting archive (sha256.zpaq), compressed by -m5 on Windows, with every filenames == SHA-256(content), is mime64-encoded and "splitted" into 4 strings, becoming (inside the source code) char extract_test1[]={"N2tT... char extract_test2[]={"W1hY... char extract_test3[]={"+Au5... char extract_test4[]={"sFPj... It is quickly possible to double-check this way (just in case...) zpaqfranz autotest -to somewhere zpaqfranz x somewhere/sha256.zpaq -to extracted The sha256.zpaq should be this one SHA-256: D90223FAEE2878D7854B9438864B4856A3C1F920C34EFB8C136A8949B54E5400 [ 158.239] sha256.zpaq With these files inside SHA-256: 00D478184C1851145A712B8054D04789DA164CDEE61EDB2240F124E0AC3501AA [ 37.000] 00D478184C1851145A712B8054D04789DA164CDEE61EDB2240F124E0AC3501AA SHA-256: 010CE956B14903A000536ACEB4B12CF503B3D84E15985A5F6C5648DC772D8B54 [ 37.000] 010CE956B14903A000536ACEB4B12CF503B3D84E15985A5F6C5648DC772D8B54 SHA-256: 032EA211A2F1CA5F977A46BF3211FB9DF3DCBC29D13D6B1764EB4B2637819A6E [ 37.000] 032EA211A2F1CA5F977A46BF3211FB9DF3DCBC29D13D6B1764EB4B2637819A6E SHA-256: 0344D52DF32E001AC79B9EADEB75CD515A2325481B4A3EF5BD876B9A64915068 [ 37.000] 0344D52DF32E001AC79B9EADEB75CD515A2325481B4A3EF5BD876B9A64915068 SHA-256: 078E164828817CAC9D7FF1CAE2F88C695C1059D495B17832522264E0CD8CAE86 [ 37.000] 078E164828817CAC9D7FF1CAE2F88C695C1059D495B17832522264E0CD8CAE86 SHA-256: 0829C6BEA1EAEEB1303950F741079730134340B484F383F354882D81EBDCC350 [ 37.000] 0829C6BEA1EAEEB1303950F741079730134340B484F383F354882D81EBDCC350 SHA-256: 08BE3D4900A6CC3E9BD4159A91EE2D86E130503A0995F21BA99DC3060F285687 [ 37.000] 08BE3D4900A6CC3E9BD4159A91EE2D86E130503A0995F21BA99DC3060F285687 SHA-256: 0960E3A414FFC2FB928425C42E51992717C809A5FF4CF2F03F922D620E3A0C12 [ 37.000] 0960E3A414FFC2FB928425C42E51992717C809A5FF4CF2F03F922D620E3A0C12 SHA-256: 0A179201C68752B062168579F5F2423FE0B76B7CEE519674DF018C3559FEA0DE [ 37.000] 0A179201C68752B062168579F5F2423FE0B76B7CEE519674DF018C3559FEA0DE SHA-256: 0A404D353DDE54CE863A235689D13F1F3FAEAABDFB0733B5E48787BF8B1ABAA0 [ 37.000] 0A404D353DDE54CE863A235689D13F1F3FAEAABDFB0733B5E48787BF8B1ABAA0 SHA-256: 0A710AA592664A6A01C98338C46AE4F9364067CD43A224A77D4B47D02126C6D4 [ 37.000] 0A710AA592664A6A01C98338C46AE4F9364067CD43A224A77D4B47D02126C6D4 SHA-256: 0B430875FEABCD1B1E20F0D4A25B6B080F16485ADEEE27A740A8CF4CE6EB5DFF [ 37.000] 0B430875FEABCD1B1E20F0D4A25B6B080F16485ADEEE27A740A8CF4CE6EB5DFF SHA-256: 0B7C69CDFDBF4D41A65EE9FCC9C290DA947C0FDDCDE7C0D8CAB20870150A97A9 [ 37.000] 0B7C69CDFDBF4D41A65EE9FCC9C290DA947C0FDDCDE7C0D8CAB20870150A97A9 SHA-256: 0DC92BFBA489354B5BF53F8AADD17C9C4659524747F467FD85ADE369834B6379 [ 37.000] 0DC92BFBA489354B5BF53F8AADD17C9C4659524747F467FD85ADE369834B6379 SHA-256: 0E082AFA0578C194400693A23B477BA8A9B309A5AF60E2BE54D8695D8BC08112 [ 37.000] 0E082AFA0578C194400693A23B477BA8A9B309A5AF60E2BE54D8695D8BC08112 SHA-256: 0E505B858ED58BA66402789B512D136BBA22F16DF9CD22CACCABF122AA0B6962 [ 37.000] 0E505B858ED58BA66402789B512D136BBA22F16DF9CD22CACCABF122AA0B6962 SHA-256: 0F5E547E80F985B3F3C13EF0658D3D3C376387FB0B67A9545F0DF09F012C8EE4 [ 37.000] 0F5E547E80F985B3F3C13EF0658D3D3C376387FB0B67A9545F0DF09F012C8EE4 SHA-256: 108AAB75EE08118321A705601435EDCAC957120B70A0E2FF6AF292F1BC32B159 [ 37.000] 108AAB75EE08118321A705601435EDCAC957120B70A0E2FF6AF292F1BC32B159 SHA-256: 10CCE2C6F78285C608158A5A0EFF34BF004E528E42FC646B485F5BA683403C13 [ 37.000] 10CCE2C6F78285C608158A5A0EFF34BF004E528E42FC646B485F5BA683403C13 SHA-256: 10DEBF94E56498EB24725F471DE3CA7C0839A388DE130CDE923D20F10FF5366B [ 37.000] 10DEBF94E56498EB24725F471DE3CA7C0839A388DE130CDE923D20F10FF5366B SHA-256: 13355FF10342D3521A87570D377CFA94151697E335AEC6FDA898FE5EDB38EB60 [ 37.000] 13355FF10342D3521A87570D377CFA94151697E335AEC6FDA898FE5EDB38EB60 SHA-256: 15C367F88C3A0550E10253DD69F76B7876D02FF72DEB028EEEBEFB5FD41C2B29 [ 37.000] 15C367F88C3A0550E10253DD69F76B7876D02FF72DEB028EEEBEFB5FD41C2B29 SHA-256: 165120A494D7B6E6E9E3D5AC33AD00B0E5BA9362BBFF062CC2F8297D007D3790 [ 37.000] 165120A494D7B6E6E9E3D5AC33AD00B0E5BA9362BBFF062CC2F8297D007D3790 SHA-256: 16C8EDAEA5AB72A5BECF00E3395908ABB727E2C005C34AACA9EC5A89E1F839BB [ 37.000] 16C8EDAEA5AB72A5BECF00E3395908ABB727E2C005C34AACA9EC5A89E1F839BB SHA-256: 1812B7923D633AA2C688A6FB2E2B9B56C61BE416C7CEFDD5C11C64D62655855F [ 37.000] 1812B7923D633AA2C688A6FB2E2B9B56C61BE416C7CEFDD5C11C64D62655855F SHA-256: 1B9E31E11D96A5EF19F71E5E005EF89C8343C9E49F053FD1E27B8B48FD107B13 [ 37.000] 1B9E31E11D96A5EF19F71E5E005EF89C8343C9E49F053FD1E27B8B48FD107B13 SHA-256: 1BD84476ADFCEBD6459DC7FF6C4E8591A0196A461B7A16849E4825E8323A2C84 [ 37.000] 1BD84476ADFCEBD6459DC7FF6C4E8591A0196A461B7A16849E4825E8323A2C84 SHA-256: 1D1155709A45EBA6FE76DA1BDE8130D4DA0B6621D9D17411E8D9F41490AF0ADD [ 37.000] 1D1155709A45EBA6FE76DA1BDE8130D4DA0B6621D9D17411E8D9F41490AF0ADD SHA-256: 1DF209DB3D40B3988B75122DCD45FD1D84DC87D4A21415DB1CB7E894D4755213 [ 37.000] 1DF209DB3D40B3988B75122DCD45FD1D84DC87D4A21415DB1CB7E894D4755213 SHA-256: 1FC14CD3E1D394DB285B7113EFA5765455516C72C6B2ADD2710ABF810EBB5591 [ 37.000] 1FC14CD3E1D394DB285B7113EFA5765455516C72C6B2ADD2710ABF810EBB5591 SHA-256: 1FD808BD5631008B0F4B10FB3050A017A9D6AFA03EC2F99186E8D1980E458153 [ 37.000] 1FD808BD5631008B0F4B10FB3050A017A9D6AFA03EC2F99186E8D1980E458153 SHA-256: 210B63FA532B0CA36974F2E4208591CB84ABA9C599E8178A6FC5E5260E19353F [ 37.000] 210B63FA532B0CA36974F2E4208591CB84ABA9C599E8178A6FC5E5260E19353F SHA-256: 21B095AF58EE64FF3E75CAE759BF8D854E85830152ABDB50BF8E177DE2C38BB5 [ 37.000] 21B095AF58EE64FF3E75CAE759BF8D854E85830152ABDB50BF8E177DE2C38BB5 SHA-256: 234CAB0BD56614D8891934E71891B0FBFE1781350EB25EBCE0ED9FA398EF8A5F [ 37.000] 234CAB0BD56614D8891934E71891B0FBFE1781350EB25EBCE0ED9FA398EF8A5F SHA-256: 24A966A5D474A7A850688563489FEF0DAEC981CB4F3CBB7E1767ABBEEDBE722E [ 37.000] 24A966A5D474A7A850688563489FEF0DAEC981CB4F3CBB7E1767ABBEEDBE722E SHA-256: 252B1DB9F19113AEE3575B805B4B6BA768B4FC93EDB05A8E6EC61650FDF39D2B [ 37.000] 252B1DB9F19113AEE3575B805B4B6BA768B4FC93EDB05A8E6EC61650FDF39D2B SHA-256: 25D8AEE1BDE16464F72E0A7BBA0550F0BD843D1FF1BA817D8877739A6FB0CDDA [ 37.000] 25D8AEE1BDE16464F72E0A7BBA0550F0BD843D1FF1BA817D8877739A6FB0CDDA SHA-256: 26BFB864EEC92283547953EB66009274DE9E25C89C15C11571543925AEB06CFC [ 37.000] 26BFB864EEC92283547953EB66009274DE9E25C89C15C11571543925AEB06CFC SHA-256: 26FD9CBE82F02D2F1D40EC7D61F64992475005B071555FF0F7891BC90ED07DFF [ 37.000] 26FD9CBE82F02D2F1D40EC7D61F64992475005B071555FF0F7891BC90ED07DFF SHA-256: 27074DA8B7C6D97E09092CA36C801AB00E00DFE89A2DBFE3D0F9064C7B538AA9 [ 37.000] 27074DA8B7C6D97E09092CA36C801AB00E00DFE89A2DBFE3D0F9064C7B538AA9 SHA-256: 2756249F7862D948B8DADD7D6B94F2EABF616AE9BDD4FBB4E5D74B4F216988DF [ 37.000] 2756249F7862D948B8DADD7D6B94F2EABF616AE9BDD4FBB4E5D74B4F216988DF SHA-256: 27C54140CF47AA5B7D469FCABBBFEEA666D23C427A636C869350FCEA46C892B0 [ 37.000] 27C54140CF47AA5B7D469FCABBBFEEA666D23C427A636C869350FCEA46C892B0 SHA-256: 28A1435A0ECC1A521150DDECE1E1F213B42CBC2FF754824A8A0177DE2A4319C4 [ 37.000] 28A1435A0ECC1A521150DDECE1E1F213B42CBC2FF754824A8A0177DE2A4319C4 SHA-256: 2D8294F94A7B49E8A1CEEC70A9E204DAC69016ED681B07099370BBEB3D82352A [ 37.000] 2D8294F94A7B49E8A1CEEC70A9E204DAC69016ED681B07099370BBEB3D82352A SHA-256: 2F70BDF9416D3C0A2D00DC9526F8A95E0DF437B862B3DC8EE10418E58D73FADE [ 37.000] 2F70BDF9416D3C0A2D00DC9526F8A95E0DF437B862B3DC8EE10418E58D73FADE SHA-256: 3089FB37D22A22682CAA80F56B73DD7843A0C2567AB7373295F60340A8DE1038 [ 37.000] 3089FB37D22A22682CAA80F56B73DD7843A0C2567AB7373295F60340A8DE1038 SHA-256: 30C5E6037FCCC63994DB761FAF3D4E7ED5BABFC3D62F9C560058791437C6EFE4 [ 37.000] 30C5E6037FCCC63994DB761FAF3D4E7ED5BABFC3D62F9C560058791437C6EFE4 SHA-256: 31528C0C41EEA6E4234D1939DAC42BC389B6A9B1B2E4AA92918D30B7DF1587F2 [ 37.000] 31528C0C41EEA6E4234D1939DAC42BC389B6A9B1B2E4AA92918D30B7DF1587F2 SHA-256: 341F785E400CABD0688623FF248496BDA776D979FD184A07EC2A17CB1F9D44D1 [ 37.000] 341F785E400CABD0688623FF248496BDA776D979FD184A07EC2A17CB1F9D44D1 SHA-256: 3464F4CD9F1DE1E989FA8F07CB614A6324AF9121AE908A60137606CBE3866350 [ 37.000] 3464F4CD9F1DE1E989FA8F07CB614A6324AF9121AE908A60137606CBE3866350 SHA-256: 36BBB282BD737FFE945AF89A7108B70E626A980E8EA7B9A28F595AFE1908576A [ 37.000] 36BBB282BD737FFE945AF89A7108B70E626A980E8EA7B9A28F595AFE1908576A SHA-256: 37C94F56F8193D38C53846C05ED64C325E3CE31B83FD579F6FE4424D80AE2990 [ 37.000] 37C94F56F8193D38C53846C05ED64C325E3CE31B83FD579F6FE4424D80AE2990 SHA-256: 389CD2ACD8D2615C24233B16B6743B7CCFAF647D9071E3C6085F9407AE21EDA2 [ 37.000] 389CD2ACD8D2615C24233B16B6743B7CCFAF647D9071E3C6085F9407AE21EDA2 SHA-256: 3900A9A0227F16E20D73349CC5C35071AA7F074FF126F50D6D688DC68390F19D [ 37.000] 3900A9A0227F16E20D73349CC5C35071AA7F074FF126F50D6D688DC68390F19D SHA-256: 39343E6C33FD0F90C17A97148F94EE829F0E4B1CB2BAD01193A1CFE220AAFE52 [ 37.000] 39343E6C33FD0F90C17A97148F94EE829F0E4B1CB2BAD01193A1CFE220AAFE52 SHA-256: 39C3B48B173EA632FA8D5F024E3073E84F5027C4E7830DF3844CBDADD564C2B5 [ 37.000] 39C3B48B173EA632FA8D5F024E3073E84F5027C4E7830DF3844CBDADD564C2B5 SHA-256: 3B195045FE2AD01D640130A57775C456F9535946DEE65F5D960C6D3DD31F9E2A [ 37.000] 3B195045FE2AD01D640130A57775C456F9535946DEE65F5D960C6D3DD31F9E2A SHA-256: 3B7F9DFDAC53BEF07CF14030DFB0196AB8245B079B7BFB1DBBAA453677D0EAC1 [ 37.000] 3B7F9DFDAC53BEF07CF14030DFB0196AB8245B079B7BFB1DBBAA453677D0EAC1 SHA-256: 3BD4034DE33995B16866BD38101DD3E74CE7422CF4CA264C33C91D162A8F7B70 [ 37.000] 3BD4034DE33995B16866BD38101DD3E74CE7422CF4CA264C33C91D162A8F7B70 SHA-256: 3BE3FD05735B114206ABAC244D2990BC031DE034968848C27E58441DB0157FB8 [ 37.000] 3BE3FD05735B114206ABAC244D2990BC031DE034968848C27E58441DB0157FB8 SHA-256: 3BE556B87E0F6B64576646F8D1915DE5166F850730711A48A546589CA7A116F9 [ 37.000] 3BE556B87E0F6B64576646F8D1915DE5166F850730711A48A546589CA7A116F9 SHA-256: 3D4E6466502B9E393D833C61FE220D63A503855D5C2AEF061DEBAD645307E6C2 [ 37.000] 3D4E6466502B9E393D833C61FE220D63A503855D5C2AEF061DEBAD645307E6C2 SHA-256: 3D94BB464584A7AFFEC863D45FBE635E26E2E1936C76A280960D9FD51C85EB4D [ 37.000] 3D94BB464584A7AFFEC863D45FBE635E26E2E1936C76A280960D9FD51C85EB4D SHA-256: 3D98E7FC5B59489DE3FC5C2B39FAC5CAAD25F22E2FFD9DBF07C938029651FE80 [ 37.000] 3D98E7FC5B59489DE3FC5C2B39FAC5CAAD25F22E2FFD9DBF07C938029651FE80 SHA-256: 3E4A8132599AED13297DB87E69861257AF0253F050EF9A791907A9F7760E1E09 [ 37.000] 3E4A8132599AED13297DB87E69861257AF0253F050EF9A791907A9F7760E1E09 SHA-256: 3F3AFC1BC3DAD1A75AB79497BA4A7D795BC208DCF9CF8C3CCE01E75022D25C53 [ 37.000] 3F3AFC1BC3DAD1A75AB79497BA4A7D795BC208DCF9CF8C3CCE01E75022D25C53 SHA-256: 3FA10C9DF65691A1686059CCF4EAB20BF5E4EBD360A6663CDF88AE80D24593D2 [ 37.000] 3FA10C9DF65691A1686059CCF4EAB20BF5E4EBD360A6663CDF88AE80D24593D2 SHA-256: 446F672B5C291D11EE997A3BD6B0479C23179F28FB5D0D284CC35875727BDE73 [ 37.000] 446F672B5C291D11EE997A3BD6B0479C23179F28FB5D0D284CC35875727BDE73 SHA-256: 447E42ADEB6C7EBCD3ED68DCB8B7C91729227B3482CCF2392EC8ECB41C702E8B [ 37.000] 447E42ADEB6C7EBCD3ED68DCB8B7C91729227B3482CCF2392EC8ECB41C702E8B SHA-256: 45441B49D27BB4D48D26253901488318700DDA5E64E7475D46CC69529A6E1B5D [ 37.000] 45441B49D27BB4D48D26253901488318700DDA5E64E7475D46CC69529A6E1B5D SHA-256: 45DF6FD68BF0B4AB153492FB7492BC7CC518EEB4D77999F6838667D0CBB612E0 [ 37.000] 45DF6FD68BF0B4AB153492FB7492BC7CC518EEB4D77999F6838667D0CBB612E0 SHA-256: 462DA79124E977C9AFE38D773DE68178A14044B666C6CE3F58632DF2B64FE303 [ 37.000] 462DA79124E977C9AFE38D773DE68178A14044B666C6CE3F58632DF2B64FE303 SHA-256: 4639FAE9FEB3AC00269AF6CFB8FDDA191C3FFD51E7958B2C36123856E4652DAA [ 37.000] 4639FAE9FEB3AC00269AF6CFB8FDDA191C3FFD51E7958B2C36123856E4652DAA SHA-256: 474E4473A1BA757D56456B70C1B45A09E5EEDA080882C527FAD642774D769891 [ 37.000] 474E4473A1BA757D56456B70C1B45A09E5EEDA080882C527FAD642774D769891 SHA-256: 475EE529339349676C3C54CF7AB24B35D06163AED1888D23D8655F28AD6CA77C [ 37.000] 475EE529339349676C3C54CF7AB24B35D06163AED1888D23D8655F28AD6CA77C SHA-256: 47C6CD8953A795F630BC41CF3FAEF03742129CA779404C9E7384B73049EC710B [ 37.000] 47C6CD8953A795F630BC41CF3FAEF03742129CA779404C9E7384B73049EC710B SHA-256: 49BE9B32041ABAC22FFAA72A1DC14EF0E3EC5AC2BF2CB6A7276C1EA245FDEDFB [ 37.000] 49BE9B32041ABAC22FFAA72A1DC14EF0E3EC5AC2BF2CB6A7276C1EA245FDEDFB SHA-256: 4A9812764E2B1C34A22D298DA9BAB0032DB90C951BD890D903BE260A1842A0DF [ 37.000] 4A9812764E2B1C34A22D298DA9BAB0032DB90C951BD890D903BE260A1842A0DF SHA-256: 4BFDDC3ABF535FFFFE0597F3888C98836ABC39D263D965B56965309C1E97517A [ 37.000] 4BFDDC3ABF535FFFFE0597F3888C98836ABC39D263D965B56965309C1E97517A SHA-256: 4C39512F3778F92125BC22AE35CF128542B417B08FAE57BB9FA2B08BD53FB604 [ 37.000] 4C39512F3778F92125BC22AE35CF128542B417B08FAE57BB9FA2B08BD53FB604 SHA-256: 4D54FCF77DBBA3143F67EDDB073C598D161E8E4EBFA6F1296D3EFF7FB14DA9C5 [ 37.000] 4D54FCF77DBBA3143F67EDDB073C598D161E8E4EBFA6F1296D3EFF7FB14DA9C5 SHA-256: 50D7BF4E0E45BE449F054B756AE0D5BF615219AE40D46C63A5BEBC33AF525A73 [ 37.000] 50D7BF4E0E45BE449F054B756AE0D5BF615219AE40D46C63A5BEBC33AF525A73 SHA-256: 519E27584C601906882D7CEC1BA6DBF7FE156A940A9DC39F6CDBECF43D5A1FDC [ 37.000] 519E27584C601906882D7CEC1BA6DBF7FE156A940A9DC39F6CDBECF43D5A1FDC SHA-256: 526911B84F03A0C25B4D5FC23DD45DA5AD54CF20581006AC97B270AE943ADCF3 [ 37.000] 526911B84F03A0C25B4D5FC23DD45DA5AD54CF20581006AC97B270AE943ADCF3 SHA-256: 529CAAC78E5277E4D142F8261E53E6570C92ACA496F7A5DC8CF4DB674CFF9447 [ 37.000] 529CAAC78E5277E4D142F8261E53E6570C92ACA496F7A5DC8CF4DB674CFF9447 SHA-256: 544C881F08F27C926F3AFFC81C0CA4AACDCB8A0B748B8B5D685BE690CFEF8D5A [ 37.000] 544C881F08F27C926F3AFFC81C0CA4AACDCB8A0B748B8B5D685BE690CFEF8D5A SHA-256: 548F141A26913632C46AA174A36CFBD40AB0D6A968E83054AF35A3B5CEFAE1BA [ 37.000] 548F141A26913632C46AA174A36CFBD40AB0D6A968E83054AF35A3B5CEFAE1BA SHA-256: 55D7218CA360C0967A8D3C012FDBFB1EDE923BB6DC87244C2F6BC2944D449AD3 [ 37.000] 55D7218CA360C0967A8D3C012FDBFB1EDE923BB6DC87244C2F6BC2944D449AD3 SHA-256: 55E4CF5A088772EB94C4E6DDF0DB5381171F37E5B82ED363056CE22B426B13CB [ 37.000] 55E4CF5A088772EB94C4E6DDF0DB5381171F37E5B82ED363056CE22B426B13CB SHA-256: 5655700594E3E8057480DF1DB7395339FADEAD7600DE9FE1E704D3B37FDF3483 [ 37.000] 5655700594E3E8057480DF1DB7395339FADEAD7600DE9FE1E704D3B37FDF3483 SHA-256: 568860708726F8F86A8C64118DD81E1977A1068D501FA2C108D29F0E680D321E [ 37.000] 568860708726F8F86A8C64118DD81E1977A1068D501FA2C108D29F0E680D321E SHA-256: 56FB8A04E25A63192E9E540BC9FC4FD8DD50789EFC58337B0A7F8526FE2F95FA [ 37.000] 56FB8A04E25A63192E9E540BC9FC4FD8DD50789EFC58337B0A7F8526FE2F95FA SHA-256: 57A53D9564669D01DCE99B44A012CCD503D5727868C7B6DC5E3976AEF7397351 [ 37.000] 57A53D9564669D01DCE99B44A012CCD503D5727868C7B6DC5E3976AEF7397351 SHA-256: 57E24ECBA9F66747653EB16B09A4E252F6DDC4C1677C9A8547A283DF9A5CEB47 [ 37.000] 57E24ECBA9F66747653EB16B09A4E252F6DDC4C1677C9A8547A283DF9A5CEB47 SHA-256: 585FF005A50313F25EDA6A7E8BF31BCB61543C13E4156233C38A9CFBF98A91B1 [ 37.000] 585FF005A50313F25EDA6A7E8BF31BCB61543C13E4156233C38A9CFBF98A91B1 SHA-256: 5869F14D80E849BFCC43130983B64A9622FA1426E5CB4AD870E173AC5E2C881C [ 37.000] 5869F14D80E849BFCC43130983B64A9622FA1426E5CB4AD870E173AC5E2C881C SHA-256: 591F77D4E0D9A290D5928491661F6BC57FBB6F5D2D22C3CC21A2D82DBC0CB789 [ 37.000] 591F77D4E0D9A290D5928491661F6BC57FBB6F5D2D22C3CC21A2D82DBC0CB789 SHA-256: 5A0E32FD143AD117EBE107823C0168BC04228AAF21703009C077A41B0FBF457D [ 37.000] 5A0E32FD143AD117EBE107823C0168BC04228AAF21703009C077A41B0FBF457D SHA-256: 5A55CA569AA57411613844F1E908E7356C03136ECED223512CC34998968E1201 [ 37.000] 5A55CA569AA57411613844F1E908E7356C03136ECED223512CC34998968E1201 SHA-256: 5AE15A0204325884D4C9FDAF524E6A39019EEA61D177C2749A485C15960C51D2 [ 37.000] 5AE15A0204325884D4C9FDAF524E6A39019EEA61D177C2749A485C15960C51D2 SHA-256: 5CF9EF180B74B15F6B12C23F6EEE683FF2E21188844D364907BFB61D96108528 [ 37.000] 5CF9EF180B74B15F6B12C23F6EEE683FF2E21188844D364907BFB61D96108528 SHA-256: 5D631323E6C1CF993EB0722A5CECFC7B13E7FA34A60970841F39502543B9A553 [ 37.000] 5D631323E6C1CF993EB0722A5CECFC7B13E7FA34A60970841F39502543B9A553 SHA-256: 5DC3470EBC48F08A5F09D48306CAFDBA04A91FEE69983E066D261AB51C9862CE [ 37.000] 5DC3470EBC48F08A5F09D48306CAFDBA04A91FEE69983E066D261AB51C9862CE SHA-256: 5DE49182F8A1D29C04201C681FC04980B53A06FE25319BCF874AEA24397323F8 [ 37.000] 5DE49182F8A1D29C04201C681FC04980B53A06FE25319BCF874AEA24397323F8 SHA-256: 5E9ACB1D0E299FBE610A7BD551B4AB624F058B1AB1FDF0B05C75BCC963E8EEED [ 37.000] 5E9ACB1D0E299FBE610A7BD551B4AB624F058B1AB1FDF0B05C75BCC963E8EEED SHA-256: 5FB79AF55A64980E27C8EBEDDA7A65D53091B8558EDC01AEFEC34716420B26B5 [ 37.000] 5FB79AF55A64980E27C8EBEDDA7A65D53091B8558EDC01AEFEC34716420B26B5 SHA-256: 61A20B5037DEEC703B9E0420437B9227D53E2CF10165CEF6A881A95988F3FD50 [ 37.000] 61A20B5037DEEC703B9E0420437B9227D53E2CF10165CEF6A881A95988F3FD50 SHA-256: 62237E28DA9E8348BF4FD60816014DE340272EE3AF71D29AA846B2F17070FC60 [ 37.000] 62237E28DA9E8348BF4FD60816014DE340272EE3AF71D29AA846B2F17070FC60 SHA-256: 632D576C07DC4F0387CE451E4C9485F561CA374BC2CC6B4B3544A546DED2679A [ 37.000] 632D576C07DC4F0387CE451E4C9485F561CA374BC2CC6B4B3544A546DED2679A SHA-256: 64C51FDE6036CFEACF8793B20EC596CB420A2CB91487101E4048DE120EC9FFE9 [ 37.000] 64C51FDE6036CFEACF8793B20EC596CB420A2CB91487101E4048DE120EC9FFE9 SHA-256: 65300EB7090569287D264479CB84ACC2091867391F6151EC7CC17041DC4DBD9D [ 37.000] 65300EB7090569287D264479CB84ACC2091867391F6151EC7CC17041DC4DBD9D SHA-256: 659690FAA0059BD9487FC7081F057699774737F071C7081EB541A3B7329A4F47 [ 37.000] 659690FAA0059BD9487FC7081F057699774737F071C7081EB541A3B7329A4F47 SHA-256: 65FDC24F04EFDE97623AD9A3B1EEBF4B1AE5C92BA1B7006C18690B6DF3192070 [ 37.000] 65FDC24F04EFDE97623AD9A3B1EEBF4B1AE5C92BA1B7006C18690B6DF3192070 SHA-256: 6662229A32542A195E82D016C2CAA47C73733D13F395C7AB12DF838F19A7245B [ 37.000] 6662229A32542A195E82D016C2CAA47C73733D13F395C7AB12DF838F19A7245B SHA-256: 66A92DF3DFE7ECC7429FF033CF5BFBAE8F3B9D019403BA8BA0835B0F2CCEF98C [ 37.000] 66A92DF3DFE7ECC7429FF033CF5BFBAE8F3B9D019403BA8BA0835B0F2CCEF98C SHA-256: 67827811F2CB17E03415DE6E46EC2FE7561A7E07790FE1E97807C0F778760BCE [ 37.000] 67827811F2CB17E03415DE6E46EC2FE7561A7E07790FE1E97807C0F778760BCE SHA-256: 6AAAE32CBA8AA049FEAFE093E9EC9C4617534A7F37A4F90B81F6F27003C43C03 [ 37.000] 6AAAE32CBA8AA049FEAFE093E9EC9C4617534A7F37A4F90B81F6F27003C43C03 SHA-256: 6B7273DD6F79E6F3D4353989FB07983B5F47DFEF3946909BD7DA990C74708002 [ 37.000] 6B7273DD6F79E6F3D4353989FB07983B5F47DFEF3946909BD7DA990C74708002 SHA-256: 6DEDFAB01FE0573D34AF4546FFDC27341C985111473F6EB047731B3465AFCDCA [ 37.000] 6DEDFAB01FE0573D34AF4546FFDC27341C985111473F6EB047731B3465AFCDCA SHA-256: 706FED95A8978923F550C6C802F617A47C94CF7FA015353D59F01525D0109F7C [ 37.000] 706FED95A8978923F550C6C802F617A47C94CF7FA015353D59F01525D0109F7C SHA-256: 714D71D28B1ADE8FDEA1DBC297EE155FCF5318A97B0E561650C7B781778217BC [ 37.000] 714D71D28B1ADE8FDEA1DBC297EE155FCF5318A97B0E561650C7B781778217BC SHA-256: 7297DAF3C58DDDDEFCEF35296A90DD1DBFF8817682420F6B4E43BB2E1F02F153 [ 37.000] 7297DAF3C58DDDDEFCEF35296A90DD1DBFF8817682420F6B4E43BB2E1F02F153 SHA-256: 72DAF5A9F35AEB68EE403C1E711ED408E2BF19D1D42DAD6BE68EDEDFA30E8F82 [ 37.000] 72DAF5A9F35AEB68EE403C1E711ED408E2BF19D1D42DAD6BE68EDEDFA30E8F82 SHA-256: 744BABE76DE3DCB47E6EB868387591A543011514C842F8C1CA701E0247D9973A [ 37.000] 744BABE76DE3DCB47E6EB868387591A543011514C842F8C1CA701E0247D9973A SHA-256: 752571BDBB1D25A5AF56C96144E67BDCD8FDBA1CB2DA988C7727D5B4B71F1CC1 [ 37.000] 752571BDBB1D25A5AF56C96144E67BDCD8FDBA1CB2DA988C7727D5B4B71F1CC1 SHA-256: 77161315B7C3E9510C66514B7D6B144381B5F738411E5F5885E7906BF65ADF8A [ 37.000] 77161315B7C3E9510C66514B7D6B144381B5F738411E5F5885E7906BF65ADF8A SHA-256: 78A1EA5E4AF17BDC4E322D1EB9753633C27C6B8846FA25CEF93A12532208F6A0 [ 37.000] 78A1EA5E4AF17BDC4E322D1EB9753633C27C6B8846FA25CEF93A12532208F6A0 SHA-256: 7DBACBF41154D95C4D694AAA3579C0159DFB409FE0CA3529596554AC2C4EA256 [ 37.000] 7DBACBF41154D95C4D694AAA3579C0159DFB409FE0CA3529596554AC2C4EA256 SHA-256: 7F028BAA27EA9043E3E263913A53CC5E4059A4F8F4D0E06932552FAA777A42CC [ 37.000] 7F028BAA27EA9043E3E263913A53CC5E4059A4F8F4D0E06932552FAA777A42CC SHA-256: 7F94A6F0857C988EB107EF6A65559DC7B37A4D9BCBBBB94564244D61B8AB4B77 [ 37.000] 7F94A6F0857C988EB107EF6A65559DC7B37A4D9BCBBBB94564244D61B8AB4B77 SHA-256: 7FB17B349C66A0CD28A6A796BF262ADD149A70DF496E15177D5315CBA2EDF9A5 [ 37.000] 7FB17B349C66A0CD28A6A796BF262ADD149A70DF496E15177D5315CBA2EDF9A5 SHA-256: 80BCC74AA133D46752E346EC74AA050227B247DC79624065719294D49D284AE9 [ 37.000] 80BCC74AA133D46752E346EC74AA050227B247DC79624065719294D49D284AE9 SHA-256: 816BF2C6564FBD09FF2A2DE8B54684F19664F9D9274D87966C46FA768F0FB101 [ 37.000] 816BF2C6564FBD09FF2A2DE8B54684F19664F9D9274D87966C46FA768F0FB101 SHA-256: 81858D5E5EFC2A41A99EBC871AC25FE622B4E2601F7896FCF7DC7CB7844946BB [ 37.000] 81858D5E5EFC2A41A99EBC871AC25FE622B4E2601F7896FCF7DC7CB7844946BB SHA-256: 82041513A6416E9105FB4BE6DDEC0A301B200E3D0A051DAB56DF599E7D058C33 [ 37.000] 82041513A6416E9105FB4BE6DDEC0A301B200E3D0A051DAB56DF599E7D058C33 SHA-256: 83634D72BF480913A52F55DD7312273A4889E238BB31105FD6FF9292B9575E53 [ 37.000] 83634D72BF480913A52F55DD7312273A4889E238BB31105FD6FF9292B9575E53 SHA-256: 85DA854914FC7AECB458C9887FE9E3E8EADB5D9A51729FD4023E12A2A62BA84B [ 37.000] 85DA854914FC7AECB458C9887FE9E3E8EADB5D9A51729FD4023E12A2A62BA84B SHA-256: 87432D9300A3D974061765BD5E46C21DBD773B7531CA1F58313FFF475D0D55F7 [ 37.000] 87432D9300A3D974061765BD5E46C21DBD773B7531CA1F58313FFF475D0D55F7 SHA-256: 885537E91B77DA9E298B0827ED72951592BB0E6D48FBED9D079D7354335365CF [ 37.000] 885537E91B77DA9E298B0827ED72951592BB0E6D48FBED9D079D7354335365CF SHA-256: 885F1E5C7D3D223B10DCB8A986D7F2E443E05AF2EB7B39A815F16BE6AF8A55AC [ 37.000] 885F1E5C7D3D223B10DCB8A986D7F2E443E05AF2EB7B39A815F16BE6AF8A55AC SHA-256: 8869B76663373A64CE35E531AA3BF3248F8919C99BFE72D8925A4761BD292981 [ 37.000] 8869B76663373A64CE35E531AA3BF3248F8919C99BFE72D8925A4761BD292981 SHA-256: 889A86F182D19AACA016F89E8F8A12508FEDF87A387D0A2F4314CB240C205AB2 [ 37.000] 889A86F182D19AACA016F89E8F8A12508FEDF87A387D0A2F4314CB240C205AB2 SHA-256: 89FDFCB3293555F11F9B1F8D3F7F7039AB49C5772131DE80FD50BD26575F8FDA [ 37.000] 89FDFCB3293555F11F9B1F8D3F7F7039AB49C5772131DE80FD50BD26575F8FDA SHA-256: 8A20C46725F9E78C8DAAE2D749018CE4122C55976CFEE975800B8EB945AE64D3 [ 37.000] 8A20C46725F9E78C8DAAE2D749018CE4122C55976CFEE975800B8EB945AE64D3 SHA-256: 8DD92BF97911C490E4AB5CCEB75DC9D3FAF32933EC8B480C2369F8CDF570187F [ 37.000] 8DD92BF97911C490E4AB5CCEB75DC9D3FAF32933EC8B480C2369F8CDF570187F SHA-256: 8DE9D087F2067E5127162F010A0E2053A597DDE796545C7A2C0E52B047E06351 [ 37.000] 8DE9D087F2067E5127162F010A0E2053A597DDE796545C7A2C0E52B047E06351 SHA-256: 8E330005B0A7F402F2C6C9ACDB2B029875422B30FCE6F8C08186612E6C3512F8 [ 37.000] 8E330005B0A7F402F2C6C9ACDB2B029875422B30FCE6F8C08186612E6C3512F8 SHA-256: 8F9F0F05E638D6D1A1E7BCAE7EA837C8113FEB54790F36F1EB3870933DD0A407 [ 37.000] 8F9F0F05E638D6D1A1E7BCAE7EA837C8113FEB54790F36F1EB3870933DD0A407 SHA-256: 8FC82F03F95CE9FFF6A2E781415E0A903B0DEFF790C1F36FDDBE6F3D56FCD6F5 [ 37.000] 8FC82F03F95CE9FFF6A2E781415E0A903B0DEFF790C1F36FDDBE6F3D56FCD6F5 SHA-256: 8FD5B0F4F0F3CF882D70723C1432ABCA933A94E2A847BE7EA9314E61F552A195 [ 37.000] 8FD5B0F4F0F3CF882D70723C1432ABCA933A94E2A847BE7EA9314E61F552A195 SHA-256: 914671B460546BAF8D841BD9703176C02150590717D56124EF8B4BE9AA3E1CF7 [ 37.000] 914671B460546BAF8D841BD9703176C02150590717D56124EF8B4BE9AA3E1CF7 SHA-256: 92244AB4F4AF52B7C3E5F256A924A5D1C9ED323B52CC3F14A23AEA503FA3BBC7 [ 37.000] 92244AB4F4AF52B7C3E5F256A924A5D1C9ED323B52CC3F14A23AEA503FA3BBC7 SHA-256: 92F7BDEE518157ECD18968BE6E4AC17B2666FBB2A47789EFD84F05F21691200E [ 37.000] 92F7BDEE518157ECD18968BE6E4AC17B2666FBB2A47789EFD84F05F21691200E SHA-256: 934123B3BF2CE4BE47AE36BBDE8F9D23D77EAEAFA2A8B2ACD61D7AE8F577DED4 [ 37.000] 934123B3BF2CE4BE47AE36BBDE8F9D23D77EAEAFA2A8B2ACD61D7AE8F577DED4 SHA-256: 93BED1842035886A3BA8BF295E35B9D9F6CD10CC3711D1DD82E851A2BD3CCE58 [ 37.000] 93BED1842035886A3BA8BF295E35B9D9F6CD10CC3711D1DD82E851A2BD3CCE58 SHA-256: 93E35FD1D23278E82F57DE9C3281C9CA22622F60D8A7EDC59A4CACFF7149D009 [ 37.000] 93E35FD1D23278E82F57DE9C3281C9CA22622F60D8A7EDC59A4CACFF7149D009 SHA-256: 9444E16862B2A46EB999A2E23109002F2DD63AC9F8BD3830CDADFBE414ABC38B [ 37.000] 9444E16862B2A46EB999A2E23109002F2DD63AC9F8BD3830CDADFBE414ABC38B SHA-256: 952F5E3F51D123B7F18CE5999C7261404C2BD99CCFEE31FCD7C71579F27F51F8 [ 37.000] 952F5E3F51D123B7F18CE5999C7261404C2BD99CCFEE31FCD7C71579F27F51F8 SHA-256: 95AEFF7C413D4180BF1D19893F66E13DBE212DCD341349230921F8E91ECB7575 [ 37.000] 95AEFF7C413D4180BF1D19893F66E13DBE212DCD341349230921F8E91ECB7575 SHA-256: 9B92039B3A8800234BF0A30D5B76C3DF717D5BC3875F9765214711851425A899 [ 37.000] 9B92039B3A8800234BF0A30D5B76C3DF717D5BC3875F9765214711851425A899 SHA-256: 9C0BF94D6AEFCF1A145E52770998E29C56E341923FFB81C5ED8723FA18F59B52 [ 37.000] 9C0BF94D6AEFCF1A145E52770998E29C56E341923FFB81C5ED8723FA18F59B52 SHA-256: 9F01E7BC4C2296127E12A99EB2D632EB7336B7F8FD3FB338B380C607427D8268 [ 37.000] 9F01E7BC4C2296127E12A99EB2D632EB7336B7F8FD3FB338B380C607427D8268 SHA-256: A0F57829AFA6C0CEA1BABA37FF73DC9CE114B5D0D15A5A010D12C4F9F83C7AD3 [ 37.000] A0F57829AFA6C0CEA1BABA37FF73DC9CE114B5D0D15A5A010D12C4F9F83C7AD3 SHA-256: A1245F01239FA30E0D833AB8078065BFF8DE3F5DD79803A334C8872E7FFC6306 [ 37.000] A1245F01239FA30E0D833AB8078065BFF8DE3F5DD79803A334C8872E7FFC6306 SHA-256: A3D6E0C3733A036E06528F3762E89AECE4298D0602A3CF1BC8747951D3FE466F [ 37.000] A3D6E0C3733A036E06528F3762E89AECE4298D0602A3CF1BC8747951D3FE466F SHA-256: A48845D5582B2D884F159DFCE86B4664E584E1D3CE5ED203A710D88DB0C855B6 [ 37.000] A48845D5582B2D884F159DFCE86B4664E584E1D3CE5ED203A710D88DB0C855B6 SHA-256: A4B2756FA53988A9663BE419189AC5F39FCB1D4E88FCA6573FD62F69075DDD45 [ 37.000] A4B2756FA53988A9663BE419189AC5F39FCB1D4E88FCA6573FD62F69075DDD45 SHA-256: A4F387B0878F07F4D893180CBE03682B799E915E8C0B47A0A8CDDD580B273E67 [ 37.000] A4F387B0878F07F4D893180CBE03682B799E915E8C0B47A0A8CDDD580B273E67 SHA-256: A5F6F944B998606D0AA018081B05DF7128C0CE3564DE525AD97A762DA5BEB235 [ 37.000] A5F6F944B998606D0AA018081B05DF7128C0CE3564DE525AD97A762DA5BEB235 SHA-256: A6A354D4D57412DC2D322991A6384274A1AC875B264A0BE35066918656899C20 [ 37.000] A6A354D4D57412DC2D322991A6384274A1AC875B264A0BE35066918656899C20 SHA-256: A748FA178ED7A3797150AA1FD6171B62F870D77AA12C1A93CA995982F737C348 [ 37.000] A748FA178ED7A3797150AA1FD6171B62F870D77AA12C1A93CA995982F737C348 SHA-256: A7FCF9987603F0744E163C71A97723A83BD8DED7D29DEC9CAA5A905FE5AE4EA6 [ 37.000] A7FCF9987603F0744E163C71A97723A83BD8DED7D29DEC9CAA5A905FE5AE4EA6 SHA-256: A82EAF353C17B6C91221752985C6E193FE44A4F798E8C757D0058970A378CDC1 [ 37.000] A82EAF353C17B6C91221752985C6E193FE44A4F798E8C757D0058970A378CDC1 SHA-256: A86AE1B47BF3F390D361CC4D97E4544695664BD5B77607AE9A987F847F205BAC [ 37.000] A86AE1B47BF3F390D361CC4D97E4544695664BD5B77607AE9A987F847F205BAC SHA-256: A871EF3DE9F21D0192F34B624C414C73A4368FF1F6AD1A5297337FC68380ACE4 [ 37.000] A871EF3DE9F21D0192F34B624C414C73A4368FF1F6AD1A5297337FC68380ACE4 SHA-256: A9056DDF0D40648EFA52BFBBBC32E752E5059106F87E86F58DC2DF0B6B93FE15 [ 37.000] A9056DDF0D40648EFA52BFBBBC32E752E5059106F87E86F58DC2DF0B6B93FE15 SHA-256: AA463359197B0BE43B1A101EC200220230BC688FA6941DDB726456B1F0422804 [ 37.000] AA463359197B0BE43B1A101EC200220230BC688FA6941DDB726456B1F0422804 SHA-256: ABED942532E2E32FF3A1296CBE307C651AF4C906D9980DC740615516F457AF4A [ 37.000] ABED942532E2E32FF3A1296CBE307C651AF4C906D9980DC740615516F457AF4A SHA-256: ADDD5910D7071C29AB1507F4971E673CF2D30FABF403793AC5B85B36DE94F975 [ 37.000] ADDD5910D7071C29AB1507F4971E673CF2D30FABF403793AC5B85B36DE94F975 SHA-256: ADF51921DA80A6BBE7B30D8CC7CB94174E3E7EBAEF8DAD44389C35882A0220BE [ 37.000] ADF51921DA80A6BBE7B30D8CC7CB94174E3E7EBAEF8DAD44389C35882A0220BE SHA-256: AF230BB829E24655DD3654736A4F08025CEC27A2015DC80847481F72DF5465F4 [ 37.000] AF230BB829E24655DD3654736A4F08025CEC27A2015DC80847481F72DF5465F4 SHA-256: B15C62466B0AB8C4DB14A8D80DA6808EEF720F7F09AEB66663A61A1BA0533EC3 [ 37.000] B15C62466B0AB8C4DB14A8D80DA6808EEF720F7F09AEB66663A61A1BA0533EC3 SHA-256: B1F23843C8F238C08D4AEFCD64FED8C26525F826CEDBE5D15DA0C88F8C74F92A [ 37.000] B1F23843C8F238C08D4AEFCD64FED8C26525F826CEDBE5D15DA0C88F8C74F92A SHA-256: B40B640D8D750FB3E19CDF3A86D51D7065497DF0C043B4F7778681DFE4AB7FDF [ 37.000] B40B640D8D750FB3E19CDF3A86D51D7065497DF0C043B4F7778681DFE4AB7FDF SHA-256: B4F0CE880294117909FAD195C1132004CEA587E68592C7249EA7913DC4041D14 [ 37.000] B4F0CE880294117909FAD195C1132004CEA587E68592C7249EA7913DC4041D14 SHA-256: B587496E5038553959A20FD1286808608EC0F79C993E07C245845FF7C8C83626 [ 37.000] B587496E5038553959A20FD1286808608EC0F79C993E07C245845FF7C8C83626 SHA-256: B667B42A317718CB5294547E6A8DFA2C461EAFCE5D81409B8BD766228241FCAE [ 37.000] B667B42A317718CB5294547E6A8DFA2C461EAFCE5D81409B8BD766228241FCAE SHA-256: B82AB78154C96B5B5BF682604FB8C256C20A3D894C6199DF7A277304D0C390FD [ 37.000] B82AB78154C96B5B5BF682604FB8C256C20A3D894C6199DF7A277304D0C390FD SHA-256: B872FD54019BE3BCCF40D3C2E0805DF8832BABF5FA79A6ABCBD6224DB73B3AA8 [ 37.000] B872FD54019BE3BCCF40D3C2E0805DF8832BABF5FA79A6ABCBD6224DB73B3AA8 SHA-256: B8CC07752DF266ED084D4C58991CD1D7C486B7256C5ABBE30195954C5393AB22 [ 37.000] B8CC07752DF266ED084D4C58991CD1D7C486B7256C5ABBE30195954C5393AB22 SHA-256: BB8E03BA705D39FF477686157CEE4689BC4F2FF0F8AFA9B6EC22E7B76009C766 [ 37.000] BB8E03BA705D39FF477686157CEE4689BC4F2FF0F8AFA9B6EC22E7B76009C766 SHA-256: BBAB47571909E31E3E49F1B90FEB935375FCB58C0E58C28A788FF2158107BDD5 [ 37.000] BBAB47571909E31E3E49F1B90FEB935375FCB58C0E58C28A788FF2158107BDD5 SHA-256: BF24DAE09EC91C18E808C9871F8C1736C432F97034B329AC15411CFA2316B51D [ 37.000] BF24DAE09EC91C18E808C9871F8C1736C432F97034B329AC15411CFA2316B51D SHA-256: C0060FC19C32E45CE256244FF499738B9C0FE8BF4C13D38758AB109A712E7D99 [ 37.000] C0060FC19C32E45CE256244FF499738B9C0FE8BF4C13D38758AB109A712E7D99 SHA-256: C0C9527F6A605DB0CEB46C8D791FE313ADB74C183FB24E3919953C65F4A3153B [ 37.000] C0C9527F6A605DB0CEB46C8D791FE313ADB74C183FB24E3919953C65F4A3153B SHA-256: C0D4AB0D2F0D81E31015BB76F6B0E8C66E06DE52A976C4F81FAB103F39C4B803 [ 37.000] C0D4AB0D2F0D81E31015BB76F6B0E8C66E06DE52A976C4F81FAB103F39C4B803 SHA-256: C13A2143351DC5344A1E0DC1D397B8EACFC3E768C2CB35325B08EC7312ECEFDA [ 37.000] C13A2143351DC5344A1E0DC1D397B8EACFC3E768C2CB35325B08EC7312ECEFDA SHA-256: C380DDE9106121E656CF93D643E4CF4AFC9519C6C48543BE9BD764CC264EF23A [ 37.000] C380DDE9106121E656CF93D643E4CF4AFC9519C6C48543BE9BD764CC264EF23A SHA-256: C5A1F211BD2846572B77F47BDA91CE5BBEB1518AA58B4B9EBD71A8E390549F52 [ 37.000] C5A1F211BD2846572B77F47BDA91CE5BBEB1518AA58B4B9EBD71A8E390549F52 SHA-256: C5E23D66F360B83F58ADAFEA97175AB3CE772A3BE3A2DA54E7632DC262FEC745 [ 37.000] C5E23D66F360B83F58ADAFEA97175AB3CE772A3BE3A2DA54E7632DC262FEC745 SHA-256: C8A2570459BA91EF1BDCD43EF0894D192611F52067089939D1B0A35EEA6FB467 [ 37.000] C8A2570459BA91EF1BDCD43EF0894D192611F52067089939D1B0A35EEA6FB467 SHA-256: C8DC131BC15B7ECB331FD11FB7B1893134DFCF27A8FB38B2751D65CA60FE6D5C [ 37.000] C8DC131BC15B7ECB331FD11FB7B1893134DFCF27A8FB38B2751D65CA60FE6D5C SHA-256: C9BF9A57CB0CC14E1D8DC5CBE7D648666C11A24DCEE0EC755B50FA0C8E5112A6 [ 37.000] C9BF9A57CB0CC14E1D8DC5CBE7D648666C11A24DCEE0EC755B50FA0C8E5112A6 SHA-256: CA45B6A7A32709EAC16B758A4D9224B24C05D7A3A55EBC60CA3590C0E1FC2AD0 [ 37.000] CA45B6A7A32709EAC16B758A4D9224B24C05D7A3A55EBC60CA3590C0E1FC2AD0 SHA-256: CC98269F1547CAC14F6E18D907CA3020084B2B43EED33C027EA7C4E0CADFC632 [ 37.000] CC98269F1547CAC14F6E18D907CA3020084B2B43EED33C027EA7C4E0CADFC632 SHA-256: CDD0AA1D9AA5CCA4F1DC1DE5436659181FFF2E647166F9BF1AC6F18801431B8D [ 37.000] CDD0AA1D9AA5CCA4F1DC1DE5436659181FFF2E647166F9BF1AC6F18801431B8D SHA-256: D0F51667E9EDF939CAAD49A55993C24AC4996B9AFE38B4B68B7F06B243307278 [ 37.000] D0F51667E9EDF939CAAD49A55993C24AC4996B9AFE38B4B68B7F06B243307278 SHA-256: D15199382345ED1D1505662582522E3FABE974567FFFF1B1AFE03C7AAC578D9F [ 37.000] D15199382345ED1D1505662582522E3FABE974567FFFF1B1AFE03C7AAC578D9F SHA-256: D2FB130705BDE5240BB48844CC0D6AC5B37ADC6353E3057CF44A7304EFCD2CF7 [ 37.000] D2FB130705BDE5240BB48844CC0D6AC5B37ADC6353E3057CF44A7304EFCD2CF7 SHA-256: D424E0F8DEC9C4BA53D9824105B5A40F23F4C369A55EA9E63368F1ADA2642431 [ 37.000] D424E0F8DEC9C4BA53D9824105B5A40F23F4C369A55EA9E63368F1ADA2642431 SHA-256: D62F41ACA203C670D46A85010CE8B0FC4996DD8C7FCB0DF4CE2D2DE0BC1D0AA1 [ 37.000] D62F41ACA203C670D46A85010CE8B0FC4996DD8C7FCB0DF4CE2D2DE0BC1D0AA1 SHA-256: D75FB5E2F418E684E72F60771A479B1A1E1A0A42BE0E3379CA1DCEA753A8755B [ 37.000] D75FB5E2F418E684E72F60771A479B1A1E1A0A42BE0E3379CA1DCEA753A8755B SHA-256: D762DB5943A11BDD85D0697FC990C36AD98AA781C027416C999185C9DE9666E6 [ 37.000] D762DB5943A11BDD85D0697FC990C36AD98AA781C027416C999185C9DE9666E6 SHA-256: D81E6568DDDA59E0D3C8638F7E854E97748526E55F5E9AB5EE4114008058027D [ 37.000] D81E6568DDDA59E0D3C8638F7E854E97748526E55F5E9AB5EE4114008058027D SHA-256: D85D097158BA15C9C1246B8DE51A9D7DD3276C46108DF1C945FB43E2068D749C [ 37.000] D85D097158BA15C9C1246B8DE51A9D7DD3276C46108DF1C945FB43E2068D749C SHA-256: D8FD9797588F78F9462B866A8E2253ABAFBE231819C695E0CE2A168293F2D77C [ 37.000] D8FD9797588F78F9462B866A8E2253ABAFBE231819C695E0CE2A168293F2D77C SHA-256: D91BD71E5311E75B07FEFAE4E9D1ECB07905C8CD922D614273C1ADF5DA980B6A [ 37.000] D91BD71E5311E75B07FEFAE4E9D1ECB07905C8CD922D614273C1ADF5DA980B6A SHA-256: D95B7207AA116672A69633377E9007D21C1E67CF34BC215B590B91B4E7253CD1 [ 37.000] D95B7207AA116672A69633377E9007D21C1E67CF34BC215B590B91B4E7253CD1 SHA-256: DB1710EB7117F11B40DC669CC9E2346BD9312134294F692EE285971A213B7D36 [ 37.000] DB1710EB7117F11B40DC669CC9E2346BD9312134294F692EE285971A213B7D36 SHA-256: DB483F559D0CB9C7CCDAE01560050E0B8F8C64D2C36422BCDC8FA5DB583BBFF7 [ 37.000] DB483F559D0CB9C7CCDAE01560050E0B8F8C64D2C36422BCDC8FA5DB583BBFF7 SHA-256: DBE16FA616F8FD925855D1F76E90E05CF9FD379C85F5B132530D3B827F785460 [ 37.000] DBE16FA616F8FD925855D1F76E90E05CF9FD379C85F5B132530D3B827F785460 SHA-256: DC0DE21802BC89D3C39E82A26C3CED1487F56448ACC5255D54723891F4E44E8C [ 37.000] DC0DE21802BC89D3C39E82A26C3CED1487F56448ACC5255D54723891F4E44E8C SHA-256: DC4B3997FECBCB014212E627CDD65799A52EE7A96D8C3C3E5ADB784CC8826247 [ 37.000] DC4B3997FECBCB014212E627CDD65799A52EE7A96D8C3C3E5ADB784CC8826247 SHA-256: DC62148AC754739D5F1864B600CDBD36178712A61DA050443A8C58D6CD130F4C [ 37.000] DC62148AC754739D5F1864B600CDBD36178712A61DA050443A8C58D6CD130F4C SHA-256: DD2B293A54DE03F9DBD26504F3B5D77AC3BB917707CAA4E64D8D05D143DDB2F3 [ 37.000] DD2B293A54DE03F9DBD26504F3B5D77AC3BB917707CAA4E64D8D05D143DDB2F3 SHA-256: DD4D6B2C054230472B7B051999EEE80ABABF768CC3B9B4CB8695BD3F2A5537F8 [ 37.000] DD4D6B2C054230472B7B051999EEE80ABABF768CC3B9B4CB8695BD3F2A5537F8 SHA-256: DE029F18D92F6686ACF9228A1A4C2008585D56C6C7F3E0396414D52DCA2F4198 [ 37.000] DE029F18D92F6686ACF9228A1A4C2008585D56C6C7F3E0396414D52DCA2F4198 SHA-256: DF0B4CC2CFD2DC2E581B617DF9D63434CB7D3AF9952D8BB5F8EE4892609DA372 [ 37.000] DF0B4CC2CFD2DC2E581B617DF9D63434CB7D3AF9952D8BB5F8EE4892609DA372 SHA-256: DFF6560BCB4F4859925DBD3F2901730390643935F14BCEA9C063E3D198066DE8 [ 37.000] DFF6560BCB4F4859925DBD3F2901730390643935F14BCEA9C063E3D198066DE8 SHA-256: E34E6815F63AAFD8310235374723E00C8004363067CA22670FC90D3342AE3DCA [ 37.000] E34E6815F63AAFD8310235374723E00C8004363067CA22670FC90D3342AE3DCA SHA-256: E3A0ADE5348623E173F8E773321B7154CBF6F28EF0AF0930D650D09E63F41264 [ 37.000] E3A0ADE5348623E173F8E773321B7154CBF6F28EF0AF0930D650D09E63F41264 SHA-256: E3D797919BFAEDD334F332658AC09FEAED07FEABBB39D2F01B97FF18C70950CB [ 37.000] E3D797919BFAEDD334F332658AC09FEAED07FEABBB39D2F01B97FF18C70950CB SHA-256: E470CEACA5FA7F4463329471E95270B555CFAB56202687404CFC23E84E3C3707 [ 37.000] E470CEACA5FA7F4463329471E95270B555CFAB56202687404CFC23E84E3C3707 SHA-256: E81276941FB243AEFFC9447B4A57E3FFF8F4E218EAE62D337A8602E67ADF849E [ 37.000] E81276941FB243AEFFC9447B4A57E3FFF8F4E218EAE62D337A8602E67ADF849E SHA-256: E82738BD0D9105A81628EF0E2A6DEAA4FEC0B2F2828E45E8D8E87D736E549771 [ 37.000] E82738BD0D9105A81628EF0E2A6DEAA4FEC0B2F2828E45E8D8E87D736E549771 SHA-256: E90A9D5D5C1B195FC88FB6B222534C150F6D2DC5C4496E40F79AF80B784436C2 [ 37.000] E90A9D5D5C1B195FC88FB6B222534C150F6D2DC5C4496E40F79AF80B784436C2 SHA-256: E9F28C520987B842258F4D1F0ECD3004F991BB145FD8C011A4330A3E326FBBC9 [ 37.000] E9F28C520987B842258F4D1F0ECD3004F991BB145FD8C011A4330A3E326FBBC9 SHA-256: EB1E222D6B1B8EF70705FACB4F120CC8B1D1816A4AD058B4FE0492D91A132C30 [ 37.000] EB1E222D6B1B8EF70705FACB4F120CC8B1D1816A4AD058B4FE0492D91A132C30 SHA-256: EB4676576D04D2F10B4CE72288FA6E5DF5B1F6274604F521B9CDE01E5E0ACF15 [ 37.000] EB4676576D04D2F10B4CE72288FA6E5DF5B1F6274604F521B9CDE01E5E0ACF15 SHA-256: EBE41D6D35E597FFBE8F7C17929A9A27350F34538FAB8B5A8F75A961EF5373AF [ 37.000] EBE41D6D35E597FFBE8F7C17929A9A27350F34538FAB8B5A8F75A961EF5373AF SHA-256: ED169E0BF884A9A7DF1CD23B164CCBAAA4C3DFC0B0E962DF69836E3541915167 [ 37.000] ED169E0BF884A9A7DF1CD23B164CCBAAA4C3DFC0B0E962DF69836E3541915167 SHA-256: ED762370C31777D251DD92F4CC43D5D9468CFDF237465F68A1F18C1859A17E24 [ 37.000] ED762370C31777D251DD92F4CC43D5D9468CFDF237465F68A1F18C1859A17E24 SHA-256: F20E17924F71F116A87A28648433A61543C06F51ED06EFF4CFB1407D8FDE9EA5 [ 37.000] F20E17924F71F116A87A28648433A61543C06F51ED06EFF4CFB1407D8FDE9EA5 SHA-256: F30A039BEA38C80014B9CE80F54533FC314D279B73E689046602CD87E9BA4CED [ 37.000] F30A039BEA38C80014B9CE80F54533FC314D279B73E689046602CD87E9BA4CED SHA-256: F326C6AB37993AF0E23316711BCC5CBC5C2D47D7D3519AA5F2ADAE04DDE71945 [ 37.000] F326C6AB37993AF0E23316711BCC5CBC5C2D47D7D3519AA5F2ADAE04DDE71945 SHA-256: F33D356CCDA7C72B4FAC2BED2837E2D8D7FD116191C4D950BDA431011CCA0F76 [ 37.000] F33D356CCDA7C72B4FAC2BED2837E2D8D7FD116191C4D950BDA431011CCA0F76 SHA-256: F3825855F1485C6EB7A0DDA19FC097793B9FEADB813CD10EDD8A45B58D65BD97 [ 37.000] F3825855F1485C6EB7A0DDA19FC097793B9FEADB813CD10EDD8A45B58D65BD97 SHA-256: F39C5C8EC37EACC3E95FA51217E8A021B9975F7ED3459D6CE2DBA94BC8AC71B8 [ 37.000] F39C5C8EC37EACC3E95FA51217E8A021B9975F7ED3459D6CE2DBA94BC8AC71B8 SHA-256: F48C3742202FE05AD86E4F112279E87D7545C39A0FDCA1F5600E5C7BCEAF327A [ 37.000] F48C3742202FE05AD86E4F112279E87D7545C39A0FDCA1F5600E5C7BCEAF327A SHA-256: F589883E201672661A78D6FF21C4B3B749AF5853FC59BFFD940035069A68DD1D [ 37.000] F589883E201672661A78D6FF21C4B3B749AF5853FC59BFFD940035069A68DD1D SHA-256: F6706FA113237E866DE7B7E4D79BE98F21C46A93D2B8A98AE0316C2A10C3AE0E [ 37.000] F6706FA113237E866DE7B7E4D79BE98F21C46A93D2B8A98AE0316C2A10C3AE0E SHA-256: F88D8CCC7B844F640EA58D67BA8213BC657AD5C08C97B741CAE8B1BD1B8FF205 [ 37.000] F88D8CCC7B844F640EA58D67BA8213BC657AD5C08C97B741CAE8B1BD1B8FF205 SHA-256: FB4AF47721D4449692F3D1339BCBEC8578A7FE53BA01AD3B1335764BFFEB60A0 [ 37.000] FB4AF47721D4449692F3D1339BCBEC8578A7FE53BA01AD3B1335764BFFEB60A0 SHA-256: FB732127DB2B907DCEF4E87D8979146A43FA7AD915DD7587A8A890455F51FCC1 [ 37.000] FB732127DB2B907DCEF4E87D8979146A43FA7AD915DD7587A8A890455F51FCC1 SHA-256: FCA14D3C0B8CED91ACE33CCD96A13079E054311094D0B151BCB75622D768BADC [ 37.000] FCA14D3C0B8CED91ACE33CCD96A13079E054311094D0B151BCB75622D768BADC SHA-256: FCCE109C8360963EB18975B94BDBE434BE1A49D3F53BDD768A99093B3EB838D2 [ 37.000] FCCE109C8360963EB18975B94BDBE434BE1A49D3F53BDD768A99093B3EB838D2 zpaqfranz-62.2/AUTOTEST/encoded-20220920104108.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zpaqfranz-62.2/AUTOTEST/sha256.7z000066400000000000000000004770231477324740300162510ustar00rootroot000000000000007z'}5}%`?]6J"MxؐH?eXt>|GG-?7anHnYޖtkD Z6[SiͶvYyN tCyAӼPr°}pU-y5$⢬(jЭכ/s)k^ZU!HլELbskci6xɈPqxɿ!ꪐ QhJz&]M[6jM{CaGk$篼c2DŽeVyN*wxs"VJ,= =kQ%#Ѓ'@R:ں}kBEIM]{38+lA,.GN+ J3gH\b# Ywx@..XM- gb^N.V5 /y\ ,9,0pTdwauLvU]ߎn?UZHj^$U8o-r]`1CtӤ ߧP ŨGrR)T]fo 6J#N/4L3M`S7P[{M1a ?.!(E&D O7}T[Le43K1 o)!lcڢ\h`mB|_5+m[ CqXU+V8׆{m:ZiJ(J2Qcb#R}|NmŹq=k}W!|~ejX n<9Q̳OnM0'܊+8p0 lBۼ hʇ`ϣJ1- 0 R&{xn_|gpidYqP7 AHnFѾM{2b'_C]2mz奆/?$edS U U ۠$xV \`rl7I -0\*t.C.A֥|aRRiNBWҊc``JLXn;ycݺkJKKXrA* w/diY<``)#6lYA:[YXnMÔϗ3CKL z^J޻2l-}+iH,-^{W0$F 4Ƀ܏Lo睊Jvh9m * 4ͼ[lgn&NzVIAj3TgF2\7utY@&czWMFvfSVˮL58G9wؠȟ1Ȅ()*D8q AZD^9ߌ3p񤪇':OSP&sc }X$1~Ik=ZqapCWW1!q]t2/X5@CΆc ,bR cF!s:^|ꇡ6 l <Ngh˻NM[Swi޽kRwߏDrߞuG%!VO@ֶ;3~U= r -bM'\1vdA͌) 5pVA|j&dr.?.GfjHC X%,=s)AvXuX Ѭtl52/Nx޷*)eaE_ⅨReKIpHz8&wX꿱 xz.>dG347aJO^ 6ZA樌_|` V~KYThtf2O}Ϳr y'T>ey =tE~Wr9Z\GeGU2 V_3@)a6-"CcPM BZSpqN{C=]o %uIO E9ZSk$ΘJPVYQJњ¯C璸10\V~}Ӱ.%: ( }p4|\7^[ !>3=E+Wb˦r}pDVVb|FV'(JAQP ,)\udb85IzwͮňѦ֊W^Cp*ܝ…bJI:S!jsuR *l;Z/*5?_<2=Ǜ,8JF<vl,uAϻa9U=j:*liջXOZvJS=2PBlkvB>?{8Gp!w <4h>-[~"()h r7"+SCwQ1{Jz$k=kZ/15\G|q R&s-yӐ?_Dm%M΍]jy8)*53\W:9W # 9h/Xw߈^ >v|iϞѸhF NWqFdϊf{5] AϠn3Fk,.(h=^sOqgXFk]*WyAJRՆxƌ\ߥu:x`uM~UO/@Q}A1CEHl\*Ow;P'r/,=]->s?hמHۋ';QèDD>,"`ߟC zޞj\I\BOqtjWvoElhoc`b壭Y׻`9CVR_ƾ)W,wAH C@ZQG}g،|z^` |wl.s5*L/Ox8ƾ dOؤ773 d!S=TٻמfG.~\د%cbQtV[J9CO }(G{;uSX-@OmpzyMj&>,n'#yI@z01g2QgAdg.5et5tޤv*>V/U_]  c@+/g~M=rsyt8Qj~juW$p`2Xc] K%*b) X~gs$a >x=hbbWtZu{qvtN$uN/64([N9}wM,OC&PQɲ߶PcI/Kq?&9oIV:ᶎ~8JᲶE뇞w-x@E-Z6u|"Lݸ `mvx=}$H|]PΠa8EcTyı$-N([P uVP=3 Ծ%voFF(q}*6,i[+lZpg(uי>6&֟ΰyBu)$~x@n$P&2do#Jf}scffy^N_x%SKz^eb4UgR;l#IW"X'4I[0OL@`ٚ䳓7IM(dr:|ZA7ɯH#-#`T{=-K&r/*dHHXgZ7C/{ m垇nh?֢ț+rR`@qJջǼe͖:_݉?Q='u+Vm@X "/A"R.&Xơ}F={H5IVa"6Vq8gKl ؗY%Tw0k ?^ӹRRYC4!`1:;zŇ=u{~~[7!ua^2ObjkGq59E{|EPZ!4 FWapkOoaG]\8jdBBUsmhgPl*~礉9evEPlՋyhؐ~>FJ͵xb DjJ|]zh,0| Ϭlc27E.UU7<(HQ"7 Avy:ۨCcy{Bp|_8Ph⾯/F. *x<\vB5 3ފ: kjmJ;ZFa'fxNNx51 D=84;x Wp 9}qp і+=u"Z>l{&xvafU @pA|tfv  (G%xn4>Ћm+Ņ2GcXT+*׃{"a:l JS&MrnMZ>965=i݅'L?ƯqLFn;^;U^f> iO9&ln˰U w56ld]elc.u˙EaT2˳ A0ƞ $]e43N>VX0@|=XlFaC>cXj;Mo7ec 0xM)_hXީ2.l%dvJ_Jtrc&2AYÌ*v'A5 v&.W7d&ϬD:CC>ƒ`E5 Xpt~kţW/X5d#cՔ^;ϼ\]r @ERǢ*f}r\߹S m@{ k)Jka؝Z9'K8hVhE*)8Q%~MgпEbBt*[ -'vE8{ ' #ڙQuGK HļSn5S_esnHs@䩶puf7X S:}H*zgkPg4G{0wT2ݘ] 5I4-fbNdVs> Nh'C ZK̔cyu.3iX6ӈ^oc̵{!1;^x9{`(zwbq]L1C%Mi eQ\1-[n`WhsolIaʦc*ME輆Lj/%% NN2Fy!q͜/9|P܀*ݘSF98AK,fU)W z9djH:m}ȰyDxO}`QqΌ3W߰ΛBǢqhT2>|/iPF aTC:"9a,zx^ +Xd@._Gr?ҝdN1z~ N2CZPW-&TU ABWzJ>] %'[zUbHmu`z;9i?r%w&^{.>d5d@#̪47Fɏ_cu|.;K¤zp99-Tra?$^Y1Tk/4wĿ<ŷ,jmVx{\.d)r8 Dj~M}o c81k昚~HPį94^@/~ ox"$قv (\uoQI޹z6B 蹴ڰLD*PAT$1m8+pN@RL871SL%.PM@Gd; KUi SFZ_r+ͳ۞4!&-av< RZ% R]\ӌDR4)9K|ŮG:IX3"b@~׉=`@rF\7`pRtݝcO'>t0-(YFW[uvf)}O;~06%x0#w d߇UDŽ8ɏIߜZMwv)2Ƅ8oͧH2N ]SbZ'lT>^魟$%NMB((IWj3Z?P￶F[$ i|xm`z2YY)aV1>ȵlD 6|cs(pgsS?wT}Z!l%.vz<[\FoT ܿx-u},czCuq @SȚ}I©LKw96~I/϶$*үF9n9=)UI9L هXLzVFĵs eAZ X~J)_sSuX̍5=o\g/'"[fKàq%549&.gIK\ԔD|=b2B/ EFP|rfRi>tq۟3=17l>;ZM2*^6.IO<7L9ǵo.CYvzJfZǯ2b|#b:9N;Yzd+89g# hFnI7BX r.Eˬ5.PD}F3.2s{~fidE\%IVp\WҰ5[h󭣱 ɿj<)\e( uRS߬6fMLxHWA'ºD}d*տE^:i:F;bc0$)+Y(`=4&"Pe`KbhUq jInz\nh&!`{S/*3 Vg)TDAY1adSOJLzҳ}TH?߫s*^Sq!ȗ\v~EIɪV#nd̈́t$xdznvjA'OL-x |lCZH*g6*zq97@p{VE)BieVRjÀg#3@W5/ksn;ae9imVO"g+Y2FT# ZR':ub[l(Y/'BAPSڐ~O:I;g ؾ T\9>P;Qϑ&W!|SSUͲɅI6w({LoI7}B-JْςN<ՙdM?EY>zBytsO[5a0SAw? ih ܲ2l 9MM)wLUQYUhgo&>m-n?L\~pڠ/M]=&>_{uc?~I?lN1nӬ2 N?#UzWWQ:_0%A_-R؃Ⱥ{6*05ѹgU,ykEKXC|)˽D)>ht)%k}F3brCi}ˀmHNar'x+O=XI%lHexhԡPDI1Z诔@mI HSSX 9Dۙzf+6Ql.%3&@HԐr,ߛ}K@j0kѶ_}:"%oCO~3 R^R4Gh︾:*d|e7=⪛[A,\Ywi/]G݈ZIL •4֢bX-+LIzRunU[4]JBq#7V{qD);ðxi3 " <"Hn)TS:By"(ncѕB-Yu`tE?=2aX>_&W ΫJ&6<ifKtS](6W\E V ΀򉭑e1zT&i~PWzn&$/=I:Bsuv>@0a]YtW3ӥ %z @9i 9E}Pg\jHV2 c cR_{=ӗ엠JS8f$ ܣY2;J_b.uwbwXͨ5H<{֛}Oñ>' ?Ŝ>K!ndžA:~$Ap;qmO2DB>ū1)w<cJ% "t'DHqwtԟq;U0; # 9%Xve&m|@\-!Q [t_c hL[6(Qp71kC]420fUnw"0hN3~p!}@sN%Kzhnj؂-5xz?bX97 4%O%_h*@F=*nQoD5R.7|J!h: (NF"ϮykcFޕFhŁ8x~zS%]Wꩯo#N)SKTy GJOǠ(.sJ"V,9=kyDDgEF4!XYͺl +Gž0Ul 3suodUA4KtWA"]c7{:+o۽dǏ'DgRdxdjvA5VxHO!"~_X H?%7s ^g qZeYz!hbe}GL/꟠?_3`8q$¥7oVYEJP"T*JhzrsAz*)B>'eHJl\lx~gfj vw 3x88NW$<^' 7ܽDWUf4/ٚԣ\zrS(E/OAH^}R~{"b>[[S ѭuiG%@(4]*;nvJϘmStab4͕V'i㐖4r Yrb>2DLu< 'e]U+ \҂, ﭳ7J0"@x/C0*c[>uN;rahgy7f]IkSs0t\!{{GfahsRc"aL&g!7O&5[*|.{c[/ְ=XhzYީ%'+r+8yaz:{P"*Ȫ),YQ$Jr_uERsLooĝjE?fOMY<9f{jѺOGTdȅ*VY.RZ,iڦ\1hrgm󴶓-&^[p:ЋIeHJdeQw}9"0gθM$KU{M /p7}M-a/XMxJm}07Fvs(H Wm."Υ_$d.hJ!nKl>p7Hvݺ8ߧma^Q/ݾ \i=-פּf:хt`@̞Ad#qZk oԡP3q̨n^%W.Գĕ %:KlvvvŠʸB~'#{;O-l'vI w@H"mjB?*1Бl/3 [`lyfoL]IWM=g# U:݊bP1XĴܴC?DsUD˄zys/Xr B睜*ԁ~p[w6<+Y%3U}ا7{!N[hieboH7#u5;;s"JH19^V_3BЩT4q(h#87ڃt/N+ xflfpbsUڲJ-B> =vRmVØ=3XK[YA-+J샮S L ~l\J5p|Qa[!P:z_ ŭ]s&*s7j8kE6@!CBJ3; Qdk&:IkN2u2=XΪ)I\v,'}kSUq|Eߚ /C :{!OrğRhy@Ao/ Qjɞk\G5ZՈƗbŒBm c 2P*CjU<ٜ:mjM_%aUDQM%$g\%ۮ4vg7OE1?41zG+)@1;q޲5  {߰dͭ`VpdQlb=Jf)jZə #J";.׾J[%iʰ a wf\2N血: 16P xI:ʧhm2tܽb@I֘r>8$_PsRwm$VTn@m%1-Zq!vS-[Vu%=7r /OaÙq K#MQ!6LꞄiUz؆bF5CQ%<5Rg7'h̪yl)qzWՓw E03I:lpd,Hl°h-t8nr<k}7A0VT kcW&`N͔Ե0e瞟"%TI5D:s3Qejp†ӑF2cBiB=Z&>yÓ9by)7T;ؤA:簗uE*j;hg&g;9)"(;&a}FIMEoāJSCbRKڶ'Vͱaw)$YN  IpQőcD::bbMM#Y%-"T`Q ( (s}+CO^[RQ8\Hd׸ W18^g5E dA}e1L:j0;ݣ9Q 6l{ISMRQ}RsQ7;/fH6"!oa^}J2qJswsދfEw|gfT3XFS+>g6g3ir:X/kQ+o<[;k$=%<)r4 |YX5^;ȪU3)C=%f^Q׳vY\QkM.EQSowHnLgYʯ˪lXIm^V"9% =-?@pp}#iͳzuu&""*>vjApPSC77p D'!@z~#nO`DDҍA2s ,fM[:+kzf7m*5:AQr`ۭ_Z> l-x6(ŀN#Huk 2ys 9!N=7"*'ŷe>'ua?뺉l<(o=fұz>"eN?$kQ3LFu [Ў$FŽ!'^,^ Q1l)XՀ01Ѱ hydْVpg;J5z`T]:%SxqNݢYj-UkocSMJ9@O bR4r~tS^i1ٯeU]L,^I4V|uD(=gfx\mC dψ):&mۈ%q/E/©┇)DCe ql5U` pWLn1wXMhu|#1M l-vIb0Bx5*ƿT7?9N&MМR $a0UQ`jʔSe`"4MLZ%M~~{u\\R2(4ɪLd% & QjN<*k~7]%?l0SYE)ŵ#;ٕWGڍ%? n4`d #>DiK3߮*!3W`%D#frB;JE""9_t!xS9<ɜ #OLqۯ:u.|.~ ! t^@ '?QǦ `/!paLE҄AjKoXR%T,EyӅ|+\:'ϧI^xB ,=,DU*ٹU7Y$+7CQ2o9fڽS-7 9߫Kpx)dt{d|[`Dm2#lOQ` j}e q勭˖O(GKYZ+[/LMBC!M=YamnˊR][+>W : ⇞^˙`Md)̍xc,͍U\7Uye:J5_NI<,l\6ܸ͐Шި o_K,Lb㟶:JBRöK7I]DOcf&DHbs"/(*.#sV[U-e[^T~P~¬%_U"<;?!ttWWvUp!\b'^=j8#/h1l4[a9?NdB[^vRK8^"uƌ4*J;!h GvEiE᳣kz EN o{U~+]l]©F'E DL^C&,!wKzt] TyºXrG&$׍z2&JOs7kzȆMUM]S_Vz\œp8rCb@94'΢Dlb..)g`q+̕ =UF=a/l/?_#1RbLM߯Z&j›rOڴ PA~T>df T q[bd67@_&i.k* 5SVTm<Jx@l!!* b,mÈƃ%PXsMeD"kqk3 F]ni o,>"])ȗI @-\uwpʈ}u}n M SNA0xDz =g%B`7gEcI o3gjVL{ie+Pk5\KaC%ABs&wӠ&Ǖ]qcpWaY Km3d {$*E^ʻ4~skǑtX#r:Ai|վSS^p~<@%*ၹ̍VŖvٟVZ 1Ո1SwO˹]PFl樮R4|0 qbIVmxM6uaHMZ =CDT |&}EziD$_D5 b} w3ߪxwKjV5E=o|h#JYrh_'囗Ǥ>TIiqMqhClg00bSPR4KT5yseE2K6RzN 7ũΛ>e3e=kcaɥt<ⷫm8Q׬8vSAc'rqQc`W.F`$7Ś*D3Q_|5eHݓ" _A`5f)7bCT9ơQxV-]̏`^vt_9 ܩ5?f(}!K ~OxpbQ(F"Q #L܃*JG7Bp,7&R#Qv_Ӱ3`鼚3"|I$Sklu"g-&u"qbBh??kg_3C+ݧ`KPBUA<>.:~u9JayP%UQpL cH-Sy@[ n=~HBDǼщm_ǃ}4bm&dqcX|><[S3,~NG hqSzi~kk@e jf%ⱍ|ACwn\y 7T],n%uˇ9WH+8TR~{D{6?JI%E pw-![ 5^'I-yHGUpTFB?(1WZC%67ݤS[YH$tYsr/ zt/#Y湔MC;"ᰳce ~(&':n擒Bќ4kDl;BJA [ nY\jHP+nnH$>^1K\p49 ]p-L?BܫrXȻ _ Ke>3HOsyҦvOR¹m|Iŝ;n290evM ZK\PIuz\2GLVplBO!)MdO`ۜwqGTSyJDŽ/_ɍk̰EEu҉Y݉lL~MG62E2P;_igajMĕlD\k48еv"Dl؄vb }C!O;\ô`q?m.aFG%YtxT"xybW<QZF|M EL&^ ]ɘ,c d2Sc~k+d|c: 6  +bB%in=#Fxf=opcPUoIƾCe,"NՈ-) j$bq' x󬆮6Zg2ff7!4 &: >Y-k1Oķ.@Ưg) 2'![F"פ.9-<0 :gTkvۓgh8jA5@Qbce^;*Q>rlDO2'JԑRu LYG d"d߀4I]ЀJ"ހLTQ^!Pd2j2 ȹD_W5 ]eAګ$M8lN9.P>r 1]NY&Zt!S^|rqDB UZn,r-(MeDŢ.l2M .rnyeuzLLxxe瓧9*.+S&q>! 9M~ӀQYeyg禆[^qbOŽ1ڏT|gꏉ HWHh`֊&vЧ⾱K8 gO'W-=ܒDz f/X F-~''/5cA{df,S_n{k4X k6OqG5@IJ7-$2,foч.d[R]W_ϻEdnQow:Pf3&Eǵyly$AuoST<9> WuLE d8tQ_j~2*#g"lG,r#g^*u# %Mh6t "h8ubcA\ 8(qLx| _+7W1QeOΚ S #rmY*>2fu{,蚺aA P׈ۼ K?V 8[BUȮ/3r<gε2ť1%7wr8Сp}+ӹ ]A.{N紧r_,hzJԯ`}Eэ-K_UDfY*wKݶB cớEƭP]|:!NV1x>^(Q1+y?V״SnHD2>..F t̿ZC^f<Xi LβA#_0&%O\R liXJˀo 8/QUmBWl`!5] 9%cXmWp [&Gm#kS7c;得\&hPU `'){F2dWT %Y )-TЧ9BJ2xmOg&ҝq4,qp0ܐS~A0.\흊˟4gMqeMlgpMADp, Fl:x o䶴 屷zF6X1olT̍I9lJTzaȠ7;4Ch`-;ES:x8/1_ *Z¢4vs#fv G1Î́mo?xjV^8d %8K&VڗYTEVl%Dr=F'^Pr !V g(-ZK6P)Ny mS\ԁcX K٦rzεZ sc"ʕsnnE9`P7D2OZI-5VWH9^&+.#_@{R.Cz Ϋm]v%\b1:H5=Ls=BUKMH)w z 5]O;m`p0l]xQ2taHkkJlgSyK/!+ż,TZ3gȆ`dh(X6g1u5&`Lx>'[G6;tիԙȷ @UHiT]t1>5,G荱$%y`Yxv.#EW.b&TpKCv1v@H@jQ00X1R&a94WTr" ۛ:M_PIi,N.$5ҹZl fd z©fK߼T"wNJieL^ K,%NXNؠ @WKq9Wdp7FdJ 4g-x Ǔ,?gEl8叴>3ࠆE6ж0u 5dA{G S20JÂ58V ~GMRb'AuBgn.Q!G=qM g>7l;B9ޅ9^i­RM7N0 מ'R.~[g+ iݢ=$G6<]gc!CbpݕBlf [<=\ R*;0 CT$~Km}O^g峓5蒄C&;{I6X7 "a{g votHw;zýv01!#z"Cl:AS`fM6f\ Ĭ̞?TM=:SY񶶉6 Չf4)œaTh羮^ s M5! qлY$S1rL?ܘQ^s :p&ØndIk>ooU%iWx|I>8TE1B5q>I?P)-9G'PHoxE!]ZpU"DǨ-^f__ʓ[ZQd`Za z@`7Vk/p|x,Eŷh؛l13ToPW\R<W~"9H0 Br_|h4 5烑Cp~<~8D%0י(.'pbF>3,^(|I8/`wR2fI@ՑA۽DZɨL}{y ] G!6H5ndѡhbOsFj)I3&Ue$9ׇqe" aO[9w>:t[`Usq _+O›FC<'V4抍BIR)5lJO4%bfp`}gEE\k'\S{ó>@?/&p,eN.tfiYHٵO=`)-ҖpX'Aʘmzc+B/COhO⯾x%I 9/ui9ElIfd/-5- Z5.8*ߏkd1[Yb mܞVoQ&/8_y$5.݆Wz!\ *g4OHMR4OyFsa`NYTʈNc ?̜XV!ڳ%xa(u2' wl4$Mf{aE:> ]^P1hsTQUR?08wl[ilUYxA!#>r=6qxk>W׫ NEe:%)}h c]ais/EismfƁ,g,r"hYۧ\vxR{ a>`Iu_1#8a2zZ4U  PPg F93خS0&*A X WqDY}k86)2PUgR4#@Ϻ<i'e SQiFj\sn!(g0`ɋ-Q[bO@F1x \u>t *cE_JԶ8*oq0չ"]]n>Gk&Glp4?l.G0g DM,I9;Mr XW%bJ 0::Xj/3V wz>;ŠGFo%k!;K;V[-:8L˫^s_̺j[>8Tf] `C⁁KO/t\VQ C+zzwsw;.WʊH٣? ΂i-0$[e**!sS*J8%aЬHw wtu͸=QSg'i+ ӪS܋RRJ2wl-p !(N=P˼€yTVOFejL7T `(ꉤ%C{P'v4H]wC|CmsIs*ݕHKFƗW0xm%rKOK-mu@[w>hڞ@hZOe0wؠZPh6Rpvm_td7#G)~# >Y*0A'MLW2K{ރCj27Yj'tK~)љRqaOJgPO}ge3;';nDYxZؿ 6s_ R #5qMm 7ЄǼ4lV&&g3NWW;2ꫬ@yi@:./טF̈́P!a2ƒ_W9"2kRFޠ&MtBwX8BzC QtGxFa5BM*Btβ}o $',R,})jqAvndOM 5]<>n:_vհ1?)G#m\**OJqXt,:_}fHzĥҿ{.&!$`ïrZ1r@ӥb*Lw߲h+KbH#h ?./!Rb b7^zj%j⡡9C?S&W ;cd-(h `8;?Ѕr} &`{tuhv}Ym*ĔX8TYfm1h8hDF/_O}aP>xy֠5m@>$ܰ[Rj鮤NAei] OYk~ d ]$̆6E{` MUJxo47uv.ۇ,@HABG0!h zmq^R:jAo5{k% X{Y}BG gdPNqEL„)^FCD ډST2Vw؉:W۾-|\S&J.9Ol8pOGAB5rD1, 5dxٖ8z{v喸U9CcUT'cgB$B'Uӌo;741qLΉ9gT1e(_XVl5'Dθyܭh!ϸG@H1+3!GYDoT[<7|7.ti[mn1W 7U}@^#}AD]'x:/x-mrY5)EØ$ـ?ȧ> 6K%;D7lb<60҈5nzȮ"יynBL-#9F j'= $ksJ5ވ2c(i'<2$d8j+Y+ @;*Gf4GtQLgFN>i)o)@\2l-=%Y}wy7/M"F"\z 'ϋyN&Wr /&6ܱ_ QN :TR8ɶ}@IR4_DE4Yd;.ItBMcm$I׳ZDS1伿x=Ss@.2n?:qj3mn{Æ(ܖJW fKenmGOLЖن|Μ! ohy^Gas>fq׬nhZJDN"tC_m=[s~!N(1/HJo]\dyWTB3nĠl1Qf&&drƒSEbAf<"SAn{[Kǵ "tsEHLpڞGZG.yTr&C}'0~f7F/7;!z69r\]$qZ&^=Dٺ\tj@ees NPw&ΰՊ.`)?j$Af4'd12n,)p=IVX0NaB~2'f&&x]Q}u ,y\`<5Wwxv8~t)CPX@![Wrn7 }S x3Re'fXic9sj=l@ϫKoeM%7hIo_u[>9n)гoIEx~D>cpHXʴ0ly/jN b˄#w'(}-lBzqyB>h;|U>v|KtS1T\|QAph$w$ ~5k6̘G-zwRٌNYI1Yu&^v\oᩫm#X~bTJ62~ҼW8Rj9)bnV(؞́:1szo?[/LK/~TVk% 0P%"\ڎƥ=v3#RR«hS5}7k)4J$@kofB|Wzxqb|K y0[p7s(iް(h"C_f8?N$FyXCKufm|Uܑ a;&9?aӝ)S%ڏ; yW[(FXEE#Fs6`B28nd9QzXFw=Tyu%]L}5V!J_/أG* u#"J*fS:DBx:']4fQ}^M,<\[Ix-)!sT+Q=\ ^#>Yç;3ƫ5d{FU}ZA̪>Z)HҐHӄ/s(]VRteI!u'ltYIr(Clzc%F)N=& .+e+(̄N6ZR*8|—yCy`|N=LyvWj'h$OjQ G63HM}Ī~cZOޖԮ{<" sa=R Zq*unC <메(R8xC$̓VˇDŒ1XY@H mi&SϿHIώ]\ӟ9P-Ζ;%o,)j%?N$']Ɣqm&"M ryZ4pU- ^+`jq҆ WܑDk"ny !]YjG/BzYвQ Ԟh1sbd9,CuQf2߼>XsH/Գ?Y($Ƽ7'IX$Og^ZM;_ҩrorSeL;" җn1'_F+C5$`x!lkt1QݫzwàY.i]֜w lCǜKOee7EKquM,~5`u4o_8&Sd/L 6] V\)oQQ 8aol&րw}=W4s” zod(k<ŽFfntϳ&rOٸn?8'^>+Up$4lQfIw5>'* B "1ԯ R(yj/}& ݮF8yD~Opݑ]08T^/|k/F 'PUb5qZdN{T%DJp'VL U])NIUWWs{tbȶJwJ PLٻgU `bZqHMGOn7S)3] 2+0l6J08G#`xk[q)jkMM4L_ArpXEKUg+-4נf vEduE9Y{FeцU[OI1u|o/ac+fJV \Yf&(Dk?m%jOgcUedIRڧ^S3Q% NиU\ n;SgtXMt=yہB|dM {pEVڟ`Q},zD92$1b!;R)<2W2%@j%ԬiQJSb snY'K-748Kf B:usWY&|7d ^ڥBynB`|Ӧ˫cLsBvJkUlƄVm Fq4RK~b5:Z^QB˘*VkGA!7ԯNrۂ9?=oe x:%!1K敊_NK4b|R%` \)g;}:Je BeNk<7-#b|} gEp&I78mZގA:2k:V;ehuG||+^b O_Cωrt%"|ؠ QjgO;t>0 Ş 3$#(H ;oyƉbܜOcሪr^4"%@ %uzk|U6ɳ2 2/_/L, /;Wq{V_9Ȩ@m b2'%k9.`5ӟ͈ULoƜ~Mstm`HSf/7gv'E GSNBRT񠻊`~?,< aQ3]eo\< SEwgO wb.5̣~> *esyx9ah%S+бʦ"CAѹ:0 Ty81Sk+fx &pf5P[4ElD^sumj;Q-O:aUﶒ*JR@&\nPŢ ͦT};"<_%m\8d0χ5*a9ǟ"r sĕ;KeER{cbWW#H|m [j0$q1qcΊb$Iq [fnjݚQi/4f[Ο啝2Q/ $Ez o fKS,y(ML'wTO\n[eoDa AcrDG۴EB/ qr.JׇXZʯgkXWe$:ݱ81+(̨0w9n&moy7l +JD|*:G#؊Xks1۴6}B yCoj!:p`MzwuۢF6QCt-]v:E$ez/'~jĈh}6F~^PAAH.ok4otCST//~ݯv60&"Uw<3( ;nX܆Y7S4PKS"E/*!!E<.9pQ[Uqx߂1{qF,O^1K!0Cd\x> 7#RhH65 C0{'f7JŽ;Lǹ=cpyS%#֬cPrE?d6&,;Mʞ ,'F`%* X]6gV#_3ȬUf,M~e>:`h?ƊPBG~urXNxMA[IY!3i* z*Ңs͒&M)j  hwDKaP-v5d:69@!<K 0y䯵 & ԙ"!PY7Q+75Y9Jlxm-0sy{䔿=VDMeI s!?5N9(4hĮIeO[0Uu"ݤgk 1.+ C\t:H q+36p"j-Q%=턘ZDkK'lij`lmj╶n=HS>Db!kCϙ: NHI}٤Xy[[=~r4ŰlGsIsWhNPQf[kJҠуz#i@N Z;Gsiq7X b|̽?j;>EZs/s/![_4դ{\Ki|'mgmW~nJ#[P/E6֚ľUATϞ0Yi$2{<mXjǵ$H'˕xA @=!>#lQ, S?v.eXFu 8R\=9E_%0h.s$ÎTp #L D Pڝ=%7yknO.l vܧFhX{@XLWnE KE,uH7d!e,AaǙ_0R}xG2QWE^gZ.ь"0:[Tqw?lAQt9:8jIc_:Sq:fIE3 S9o%l e!'O573f 辸fL~Hn- /!tа:Usʎf( !1h 7ˆwNxjg*ouUMM VBnK\r`塯v@ $C'tRmn/#O/Qر(ɳوyJ{ O,,%%fY/R׋nuZQdGI<_ ge.rȰawCȫ1c's& %|S{^5Ya?kzBwӊS[$/y2_V3*ܸO `y|VC;5d%!I;>P</mȥuikɳPk/Jh\#1๰gTBTHq02w9$) aj~^Ao9܊7_n׏OՆARң{djh8}ޣe2/! ﯗP{]0} ֞dj9PM.hֹ~4(^(,]*%ޜ@g=)Hm]4ީ 3\>#bELW q${F,xB_\"yjxRep)3gt5@49# H&S$&q^EH`d?/p"7d#Befvv1'{")SM#]YG$ -uP7T҈[f͙d B<4$j0o06Sc(ǭ\1ìɬf<`x{ ^Hf1a43VEQőlff|%zz0|6鉹( '4+{ Rwl".( NM饨. $yr0nQI"M6\wpKW,_Otx'W;J3VyQPIG^hxK$E?v[B Ŀ*UJ:Cvz#$fxvԜvdz\ٴrhHP3gL<\|%V5:Vi4 ر?ӵ+Y}SBj֨crh#tJscוR036BTⵚKцmSq]ꕂy W6~/끠䔖qٞ:$0veLxarSN&A>?mFvm>"cSeg3C3 nZK> s5P"u+PF7'n^9Z"UV-G5V8z m/Y9mբ Plj睚Жvr|V ! &/ݬJMo`-d(/>YW49>klcǴJ- n*AnO-+ ?qT1c,u1[Z=lEpu3$ ?U+yDyVl3|i}E+bB` ΁'+R 1UقU5\$%g(OۊDŃxͪ ]tl4 ZIwjMyb!j Fx*[7(;^Q ڙՕ K7 ذ vȉCWT"LGڭF!DjQh|< :QH)et`WOI_W ׍;7'*YD@-Dw<=M:Z)!D# wzrf, V8rdY3wQ:wM5$q`/X\xfY8u ֨UGTYcW⟤_w 0[hV"_uUhIוSn/>d^ ˩ {˂3c92§Y W}U$]cY veqQ(gN]T-p0'$%pf ܭ ̥iU"<*Shð A~,x\h Σȡ+\ɸ8A-+`Tݣ+00H$`Q=Z5$iAF}/v ɡ;P>DQA$<*T`*bt&\t/$("~ТjK>f+/Z\Ř~ 6UT2 4_wU#ڠ Vɕ#8 $<)cG \pxʦ{`{N>4=wUTr|Y D*Wn-5!ei` jC+:\6ZDqI)Қ3ofv C?[_%J^5};hy|U뀙((r] {̧_powxzurUK#_eiysY(630] 6yM)s>"R޵I[D9Bx<5N?_<%kīP}n+MW4bY)F ;^Q.$çfjs׈u#O!S/t}$krp#wLy.e$ 9OX"+R D$0EBOӊ:[rc&҉1%oA\iZ,s*YUo/ϗ-!yz8o<1d>U t\&9 TRbosgc2"iQxzHwv=nKwe4KRkzd)8I^P?jK(ItMkq Jc[`N3nf')NO qgR9YV1#9Q`pKE&j 3A 8(}H+pwUd,g['l8(K|ѪW89 &/P By"ق3Rʕ0cLfHC&dM4"6NDe"$-Jtȸ a\:+~/b$~=r?-ƀkv k%7. "HgIH⏄JHZn{(_'ҋH'Sh q6'j+=XSrO;2z+0;iJ)UoÐkxk me!řkK3׹Vp>B(E ZlQS dxѭr2x1E Q"Gi=hnv+9X:yqɄ}Q3ӛ1Iu^ȅa=b#'IhJPoZ+)^P?3 ѶFXJt;-Zz&~ P]u%PoiK8jE"ɩG6j 1B:ɶuaeoNHؕ|ď PkD.x1#yIg()+ґnv %[/Z͌M1h{w-+3`/ؼl1dSfM:~% `Ǯ wag-V{P-hIA )?+*Q:qb㴠 M!7S Jth>\tj 7U+}\?,0%(xqˡ11~׻$aN}SOD`SW IvZ@sV\5q`F,ڄu]s%aL0` ݨUJm]}_h,?rA8vlMZ4h 6uğ&ZPs'9h+IjsWSS4kPeuFzySD8cO8S=ĀDڔT p|:g+|uޙ!$;V1a&N4dSse96`̳ϧDmHM^G! eՌ1`0umA$LӇ?<[Nɡ؆d^p G1}=Clg5X4N285(v^ӃbDkf;y:_6eiWlHۧX z3+y|ELE#9'9 tg1I;H˷NDt$f[̯L3cM_Oڍ ŽX>E<ON0VD7apf|SZC"9%l&QQ&GKV2OSxhhuSa#9e7B6ޜB-6Ԓ\1H8[j؏H.ْܺӐ"5leU =dT@`4i͝QUVo3X9}O4v!ar, |RC]-Dx\t:AZ8T'\!M-ՐHхG& ~kڮ4ר(Lqԗ P—U<`/ *\yTd5V!J/E"%[8M:RUh{r e6#T"[_9@z$b)@&dCcϼ B^TӋ捝B࠿j+hWe"|$pHwv/rH_Fy?8n7eEUj<A 3J9͢2,,C`y(RZY1K/-E낇 ]P%@$[pBk-C$p%\j8HUr#?={\HsHzL\P,2#Y'vR9@PT~~_MGš&nKBVc[ RïM||c@mFNQ{E1SYޱRDB2 wc&^*hHw#ՂBQGl}y܈FO/D*?[z dz+j*% wC1uzCѳic-1M]nAL^+`:-R4mo;u>>;q9 b[ERJ$.kOTZ 6 dv,i4<[1tM9)LUGDZl10i~8JP8@m,@KXGrhG3/a! LPO4#ʯWWXԋ Q,/T=K W=U;;l/M엧I:BާIH6 ( | b~ +V8:M ՠT>Ӿxy6wxkDҩ8'LTJ4.%~Kg!̃lNp=]LDkZ|N$wmX&:p_>mc"r!7{{K-,5Np 7q"5D 0?Ѻm'ޔriHx߿ |R>JffAVS&RmiV0kAE{&R9sSF!3څ8}plҹvo#Jrʛ:Q "|As[yDt}6h8a+x8Ś#u|Rx\c%Ɗ63`.:{H8pXj^S{>q2\ˮn<|UY#Hσc+"/Ƶ͠ˀ{KT3^=+ IsJׅ  Rh]8hwe"020#ȨR(tkЕYhԐ˄s)aNI4+DyBqѤ|3a%(Lѝ|qTU>+g\Hgu S [9ƈ/iS %n+x I??ͫU_x74TaIUCcH!w̷|~9ѐ]1/D6YYuF]Lba^uxĸ]36`/\9G.(Ps^ְB1-bܨ*Fwgm\^Iy֦H4OddF`ڴI|z;尦(^_w:VG[-/Xvvh",,PqxG5BGrq*_'MlL+$FcZig2ںuo k1jw:宧)wh`ڮn^|HX ,&jҀߕKܿX۞vg< ERGHb%/?VWrbᯕɝgHK;'ARݸ'yB-dԾu>cs52X* ei5~\/g$?2:L?QV|vt_~Y3Bxne,D3:OYsaD_{lkXuޒv;8V/%H+;]-ph7CwuZliт8>K{3I\O9#,HQXh ؘI%Q [JgO%KafFh/1(5IJ<:XHvګ&2#Y;?`O;թa0١?%m!KYѝގ i GA Af[57v֒B ;0'Gʭbf1bͲ̑BN>8 R$mѦ81B~_JkY8/\UNS"X@Cz "vfy~j ^~՗{ .*[2єULvr!vܗvdb>,2> kZj6 "uN*1|˪zTl{ Ol"qwv]7άy7P}hɺ|)8PLUHWqh{EL5tP2s!6 `@w+A<¯+~ʌϖL-gx[_ah\pR` 9G$|ȐbbqqFH!.WGFvRúeeb0\ X9oJ)Rh5||`,P'cbh&؆V1NAgV=@LqlEac}RvC4Uu*[J0暥nI4D2w7s>fΧZLqaU3O!;$ XoA@ 9N7DN4'{R?X8)6kX6u'5@G&Y9xA8@,派DBBfH7R`?D=J1 p`^,L A&L#B9DoaT;(X )RH N.|=GX]#S4S~#H>%wɠ^U-%6;KKYif`UMˠZ:@;qfB!OXDŢGi8[v`>?{FZ\qaFv3\8o\@ј)1!xc]dQg~DYIkhQ\'>e'Rw4sJ/d\ 8Z<|\ί5E,Rw?/zLDR慥`SEv2V iBU `x%L+݆TQɩ8g^fbȐUQF;(sNF !í<:Pvt W)В!0LWtǍiKO?~e Xw-e SgYo6jpG&jdVP-l":$QMV=mՉf}@ xo`R,A4qɎة [^Y)֔*8 l+rIƳA~''Mlo$쩎 rר=GERM*vBOǚ]jK7` L0g)tQ՜& +5ǎ\[<{W֚o8mi7f&!|Cmⶪ3O?[;%էQ.ݩN)8|`B+j- ϯE];rOMwNJceZ%?wԎXFIϨKx =VAZ]f*{k|l۲ϳ+OT3yNm~7~I$uOסis LuoŒjfΦ\bΝgFSRӖHvфo,9vm8.,ě@svz@Jí OQ &ozGHVъK7)r#¶dI[Gg}٤&P; [Q. t{ mwD^IP>JՌPSp6٬ݐu otaYxtj]J<ٞE.ށ` 6ERn:^Ovr"%Z4gCvmʆwwr̼rqQ`EJmLp8 /T:WbIlOmhЦS{[Eb1F[t!|vM ”-d66X+7ò CATOSh OُZd?|e#T/*g7xR>E4\܁.o+d. MXU6֪񣡅QlDԄ@haDE7q6t0OkW};;ЉjLFhER=IJ4&1X=OXxfAgZ9Y;()~/LX:CR\Xl0sg^O(=EbJ예ܺ]+6Qw7\R)%*M/UWz\y墛#P,K`q5FWo ^4Yc߈╄c(L *ҭP pZE߾τi+Ds T)EC 0C_X_W"V74h6R/dn(n2-OgZ^ w E[d:z3ͫNY/tX t5&|t}xk5c*׳6= .=zK&w3lhΒt? fʀd-Wmjۥ}U k(m=,o,t̐.0L?8e[sV WK aHpnuY["KK`+'WlY1> 49j  M,Rs(jjOd$߀j>;mdbK5EfOH<`}˻*,3m_YZJ z078RbmGt,XxҽGWgqRfkPL\M&*jϭ޷DК6[mqӍ7fp7կa?/L>(En1Hd'QF*&8r^Ygmi I0 M1#LrR(/bj3~f7Bߪ+7P b~J+$q I?#ѿTd\A8mN-:ZǨ$}(~Z߶iWWrd0Av+ɕݸ8Q_.4f4qjl"Em=` IĿO 呲 jQY&c7h3-zwO1H "(}&sc <e[%uJ D+ t4H-nZQ|6& { JF*@֏6{i|&_ҿC |8+ѹ`yRhnOZX;1FI/X%fjƃ~At,h)1br71(!v:x>iJ9 _]܎1$,2 Kcƭ@=@̞*4/Ouė+@RBFg,|* 5!`EQ@/W{ٱ ~>N=xG$h#{K-K7G5A[;Ĝ.ధ0tOc؃Z PY 7YViJcC[ݳռUɍ@Y~9=HI 0l%c[UƬv W'<**]IZcnre0暘+VN[T8s4hl6 4`7MQ7{[/Klx:Xd1%8U&YI Ϳ1̭ລt0TtE"k`RRa`=rBI4dJ $_}Lczb`*2_{C.NÀ} *pLJWu+OAftf/#Prt\ m:Ny^zXR8>9$3L˼F~qtf }[5I^h$&X`<gA ֦o?KU*`i ?z4?n )a7DE@2!i.T"h%[fv?.EK Μ$-2&;%#8GG? Y ű׮\EŌ1-[Q,)q!WdPI🕐)R5F^h.4jtm"ύMIn䍉1o4 xO͜/)χ$8aD$XCNG0# \tл?s!Ep <Tlw.yA wfV '&ٯG9 ΖF_ 7nz1Q^#"8-Y̥Jg$wx ~şѷ BIJGl'VHօAÓ+܆3-3<L/^U7Jx<| qYfhU=f-dYrn_r̘^1Ykoj)ѓܣ3$B@m~5/G7: qx"@E(EZY`S>*S,.Iֵ9SFx=mȰ>ݼf%0H܏ˈ< ,l;(E(ghQY9݊b؅T;̇KOYmɄV0~]7hF֪pCXQ?js{l Rs:u$+#*DI Y7>MǶJ)=!P)E\ĐcCTkUDD;QiM,֛ OcJNFsdjbq,;tN6fySα"$˦齭cvn(}$i8!|v,u6-zďV㷁ڝY,?qTsvG;a:7&0eXer Aȟo]A>ku(tVZ2t󸴛Y֫,$%f{%7(Pߓhsi?y"i(Oy5[W(0;&0o]?mm"=`),8Y𱇬x[&`Mbǻ.uG5P,`O{};Uv͑2;4yyƝKS%]GżC"ڜ9kh;[Bn55/߯t/S/vO|sqɅ๢CJTolv2N넰U4K" !dpi& !!Ii˧t>wR(u bmꏇ6װLX۔Γb V/RzQ"ŗ0ltN{  OT7U+e*[MhcL.h۱Y#žxT'<>h7XYPrOq;L'߆ppTͬ&X%y5g3Q #/!BTz&V=Yl$nỦ{RVR۵jiNVmK8#;%Y̏s J+緿hI (5,jƼDקҿ472"ܲOL[Hj[5G[n-|MpEo*pTLB>ÆNl'TV5U[e˶ڏ4t @PAkcU~b>Ssx ]S$u*$)_|nuG3z-L;ɓf5wq[ لbٛt]AE=2B_5c  H\s\~c_g6oE4D" uI.WqI̊hƉxzw"+icRaT Wm7[J/^BU{"n} 0ɽ% `EW;:(Ayw{s OWXAܣ̨ثu.?{)%ëV3!*5S*,fwܛc[i}+m#@hU;Kk5cD}ɴJY[cuAFZ$ؿ)U |z'oj+ w ^8q8οfmqPv_Hvu XgPD^7ed &3L`mv&Y^py g{O _k(1֚r}iJv i/RI`kd5\2<\6UEAl+qX0 {|H[S&@ha-FQAkR 2{o nu}~M"KqL"uJ6j{?#;+ם&ӑ *g !ec+Jʟވ[MWJ)ZHI_ vW,^EC>Z~pNW(3y/7^YʢdlU'>R8Whj v9#nFG6Bs'RWa P#?[)S|b|GËL]qVe/7rMGWO:u;9pQѶĞPw 1?9 = z,@/݋0w׭SW> %A'VZgY2FpVW*h|e\,YW f{u{pkT%.p':[֔ǟ:nſ9@[m߇.bcHF]Ys/R:R+gKb?OF{sxG3ݶnV mDBsAĕ"1"|_5>(͈I+iHzRIH~/.Ԙ݋ab׉BJtyQ4x\i#65rWpj&eN<'=tD/υxwlT(~#}lj2cTcA+& $Doi.AHgQL86(g1D#z& R{e%V?~ؘubQ{1f/ǡ0=/]m>$.!XyjH>c;BwV -SsM$@ď#^CGP'^]̙bPC\P޳X?9jVDgK70)ZJaGrhs+=zңl}o=7崖iGMn듃Q C_%:kT? y?u3̀].ʭ7DA~<-'Pzd |ju'6Us ~7Oix_й0]~5 irdA((Hd6#Xz(Tcjy)d{'[&-l7y,o0"vY5J DA%Ut> C~むN;[=wXm$MY2++/QHIzΩ%JO. sTܵH \ZioLgt?G| cJ-ƴǤ@KBn0?>b0ަ߁6}2]TO;ޱ :T*Cg7Ƈ<9i.o@B@c";U\Ȯ' !!e:ݸf8a?!P?ʁ5b#(QKBxE.%&TDž š%mo<1F˄-w탿b7Ur22}0zh;ht {xG}-ͯJ 4QdԿ~FPZRا02&0D)+Q x7 1p}7pK>~,v]_ėU+r a(N1ksY?W1- i27hf{6P8mPA+==*O9XP+S_ZJu@Q^ׅ&Ӭ2˾ײÉ#wMn.h˼)6'ʀ2l*l,-jzpzV|&=<󱮋 |!R]`܉;%؎ Ww|&cH{!4nn;)̂ON-Goiea& վ0r*@=l7<>9jsb;KEwE.ɴN@6ߙI^~n ?)"}_G U쭞D=ηVBڢ0|9,H (;g`wCVBf̛W҉Mk H'i,r.Ȫ7^ZU+~wC 8d԰\3FʰlmjR&Į 0?(;iHH~6P[ح{uz<.CkS&ƋEY*?5twK<9Fw*a6yu`@V]*l)=gǢY v!R^|C?ip̊+94T$بRm  P-<\)u-S7$p4w4@nW]5\P`-W{7R[>u˿*AA#R⑓^jtF @'5mRc׀il~'Lhr]2.e̡w%-w'jl4/yϵ])q"([T-5(ݨbzLg\ؚAwHۋ3ߓA6hm6>VIpF kJYX`']fTtzp$_\B3[_@+HN@0J߈ ݫ}U+5&C+]P  _M#QsIcڗ.A} %3rCRAi綵K J.}'=8 A8.hд շUuEEۉ+"~{CQ'a9ͻZ>ɺKvY4^}Σ97ZLO&oQATk-,WI-ڝoGiuk`j+#yoUAͪ1FkjGGB9 E2;%,tmo7iʹ󎡝|h.Z^O:aIE.wh ?$A*Nh?%*X5+uj9&9t>MCܾSsYB/ A<{sh}*Jko jM{ $ɢZ DӁsr\V^#et5Mr%D8[㜚 f4иj߃aF. =4C!ԒY[L)gLߧNsC+ 'L/ c?z{Ta-M鑜|w / Y<,6-o1t0SڳG]u'rde^J2ijh >!H'%nemǛ5׉{+P5ڇo MH+8HkԊ ;1Rw–#ԉua9.{TzTΫH)XvO#v$'5o(%2oΡe"c#xt_r3^}M%E&*o  eBMZg<9o~E".qY I )̨I~p.@{ۛaYh_@2W^OMD.ݻ/b6 ܒ*Ɏ/}b`OY@R  oi'6CT, g/HSOM fDMѓCr1aHxujw8iYO$RtF%/ p2B[&g+'S>䁴.c,@U%Y&_?"Ȳק,s:OR? )1K&$?09`6h*Da"7C,gB 㵣c"\ Zgq^%^G}TxɒaxP3;\' ~; \=b34c^,XnYOg PUCTæ+M(mIy_3p^i={0 G` @@t>f E`E:uYe/gLȞwv;r=Vo^eDވc1́_(x(7 f=QefHGۦB5~MIg7}Ak8ͷv}0s"ݺkbb>rI:؈^$K%;Pw';ߘ~Z/9-W\ZK [ CzLkutCY4}Q蒇rS- Q3Wb{oLyn$\K8*K.E-KTM ;xH5#a\> v'LS`˧UȽP)pZ^owH(̓^صzz$M'YM&4r*&"5" +,9g]S]v6c}> 5.xF(hLZODm !_{L-Y.etxѲ+\lE֘j~=^vF1Q/~dcLr>0G]GQ:pXfzSY̞jdI AI[ M8"sN  U8P\iFX BQWk-6E]A_I'FUE xfmL:}|3+$TȈrv!M{&]hEk~ P>4p~p%څ,ABaEY]>B#z@vEQT2C1v,,5`}Nu_e Xw2a>XL$9 Gp3x"}~ā~';yH*i^gmink8`x f8e!rS8Dt@GK cZ_."N!zcFqT^OS%LYJ/#ԥ["u(;$dϚMcEBA6>BTBJɻ5[b''wTS}FgJƛ@ŞH$bB}pRnʯJU.&?'_@j S[⸬)vn=m -):Jˆ.6T" Yb!>m6媸98+&? #sLbS7 I8G_s(Ws ?߀ţC2+N!_8QzEw*_ڪOGʗX+ K^arK ȎM}¼ 22ʙAc]0[eoyxJq,'9'Y\_a3׻ҎeK)= Q`j2a[s[#1iD >kOHvA57#PkhO(臵ybZ,jӾfm.=TxEJ2X5־ 6%30A:қ⑊+c}U\ukg? I| 'lˎ30|'\67l"ؿN%8T0Qe(*{Sҹiˮmb_[t"cRx kVvdB1sl^:0twe_S P*~ޮ!O;Z$P.ḟSGԣ SeQ~D|-vr.UY41TL/-%=/ۉ-;wx/*H(0,:!զT<۰>l 6ehqp D@3=AYY#,3vk(h" lxK[D_~g{zHi}4I1|դy@j|ўxK )Al$#~\|ErfR\kyot[X?{] p{d׏1|S21^i˒)u"4fbI~!3] S~[2A 'V yˬ @@F%:|}ZdtZ$R^9Fs4Q {G^ ; G@z3xsAȕ@/NmHǯm]';B[.y%t "U[ evaeG.f'ijcW fZ4"7qgt?kz/i'abĂ*(WHt}xzuCXRz=VY1N}1Tef,.r@B O%9*k6ص3OMvI7H5܄޾`ޟw)hHL6[oىnY !΅x\s&sW0a ~0 %pJ6i7ny]: JCsn%[ػkӬ<{z`j8r:W' PBs2v*m- *MʕEzK E#CȶX!k=RΙP'#>4h0rsn >~SM\e!;3EyBd{@&Udr77-;é4z43J!uGU,{[R4y Ekxj[?RUw(1NRROz*R 7)'# M9da/uBOʼnByS(]X 6aQB h8V52NŕXZ4h~@"ddFs,Cva1H!ӰUD5 餅%qo%0<5J=NYI1͐.GiUQ*ȠOY?fxHL/2G#|ѸZƚ2 5Q!_v+0z1 2ǓEFƎS<'$.?'*7Ib@-tbW$[g,JHN q]y s=.1BP[`0{Rm4E&foSZirm#ưv ̍j^ ?_Cv IXJw"[QB }QH318=#h9MhzvfG KU xR"λUŃ&!>g@B<4(hK"7PdrGO]كb?e3ӓ'HOjj2~rGV '6GޝŘy^y#3P;;\E~/DQh_ \{i鐦k4d. m  F6SaR(Z[({SO+ O͔ЯU9 -\ ^ kH*c5ə!z;ϲh 13{_ɩ`g5pJ.B ?-}~}Tb*tmqf س]V]"1ǪDnB,[i}yQ;ΐu=Rg{N#B9bZOTo;rk_P8å);ݺ*a@}EY}9iiv5(=߸ 1qb`,m+)Cy^E@ky̔o [m;N|jx'JPM<6F,Ld}&GzBqձb_@ʇQJeuP{3j [2v$uc%<;xqG1K.VgWuwxjtQ`Qw=LʨྕL.` UXSm*$h L߉bsjfc}YJiL]I ċg$ĭ0#\^tY GB.O"g?p嶕0'9 ףp9 .P%8ێ#ZTk/4pĦ瓐ZPufaHYf:D9 o盕ꨮ(qQ5uKك3Ή#Z̚'*maᑲ+e!3h.^?d/[|3߈Ы#B>6s S]Z0$:TQKwC*pYP]|` ,Wؘ¼J@Mmދ&_dTs8.빺˄8Ck=+M63}F'xDS}:+@qDö$J|1|9QZ2g4 TK5e%37 TR%H|ͣI-%IrMǡ Vx3 p:т`=3KmnyJVDŽ *.Eb oኈ:/Yj#B9՘)W)gh4I9`DkH g1B[(S2) pA{MY 4G6">̱/1:;~hx-gbb5<Z7bi1M7_"Dϰ Ceh>,PN}9c ^ WоYbBf3ӷ/Dja }o}FeO![K.bGIݠxshzS\5QS>h3q]Sp8O8Pn%W ˧'z鹿WƛO ^(z7$wEp>,Kj0jC1J&:w]pf|CY]֣g$C7&n/>~SB Q,eqe,!9DAd%FaFەP;8 ҰB;(Dm.SE:|ʷWdBL\ ~<>Ӿʊ!?X1m$ MTgw*> !3FO|+m_r)ZE t`el]?<{ {\(KRE2aE27N?\@޲f9>4(MJ,$o$ SmX0cxq%#9{nQUԧ=0?g]a| 8q g dIk2 bl{1~63TiC4  *ۢP5z0>4@./m }ݡB~R!+QnZ 4Oܫ'{MUY;<$>hjmLCӡb&=eFLye"3tu5FH-9\W!'ʢq/4"H͞J2u<KvB_Ģa.8iGrz~Q Ѫ6J)F7{bcL_Y(`RsV6i"/I`&6n薙B^Tq),ZFpf]}vZ?Pv -<Ճـl,TYC{,I"g~K뮚,\YqC^,^okC"\C!RKeI3CL$hVfClzZj-qC=ڭ/}Fm\=D XǾY]2yxP(ROeFdj_[˲Ny”B]JohPyGN#.u<;tQS#T.%q}fukŨ)GJ[CO}\XB\[5S(QM8BQ33hj.@P$0N=:K.@Mx9}9x .u:8Zs@_Eq?xݴW:@WqkvA-w5gP"+c>R"hS}!X=,- EFzYC ۉjFWI$g+EI)fvEɼ)g1żdF6l:ҙO>"s'qe-_N8kX`U%Dvcl=,#J}0 vk̽ ;WolI.ä~魒ncfG g4MZe@22VOej63S/&kj"jO$8ғӂPzl).)#OJbg!M , Ak}ʳrt_dK<CE#|.UkAyG$2=iukv== aߦ Bx+Ako> Yl&! SS|bOg{݄/U^$fa)ԺN*髝<<:c] u٤%4`\ND|BnVyEx-,pRޓA$КY wjhؾ%~Ϛ+|b=a@.gV) 2IxZa%U9S9m'lYKIL<3jwqNSmA Eyx̧JnaCãQ쒡V/[eVEpF:GrNݽ_\aK\q4cIt;> |D飂ڤaR-\Ǜ5[d`WrD9Co9Pf-VrOxKa5Yr 9>jB~rdXsB#wCtw$iAQ@ %W(mwz1$[g (UF*#~ &c!ѢD'}t@wgkEwD~0gH $r#ڿw$CCSWMrK.ry*ӆi#f-.<*p@.5$dB.-1xӎbxs<œ=֘fLhTCJ/Bq[4tsgSl\`chĻ8K\vAt2O n:n\ilGQ..$9d%:RA Ep2x:jv_մƙ+.$"y`wE3sHC,k5̤ž=Jw) BhlRuG^ v#AdY_b"'v&嵏CϽ-(=< 7+a96eya2̽-h`ZK!mU qeĢ>'_A==UP'7ߤH}胹% o2 ~ qB5Yi ӝTe&ą8'.f'0)2L. Fv@` 0o[9X+EZ9U~~'EU"ǜm..ae|`񭞔^R(KD 17uqjjk8gΌvX07vd fiS#v ɸܷ.$A@v\iTxN.fOTuI1tv{n_&ڦpi=_ rYm3ե?͖ .:3n=k8**-SJl+ ?Iݴ `h=ztTHbN02gotЈ{5F>`r/n `AxJ0u᳴+0E 3)$6 2 9ݟPuQdJE/fךa)C2P_!Tߺ~z;X{]Ol@9/3F7τ/Ql'F<3 uR#uz,5%Zh[k^|c&ו: G XLTC]g4W3@t=4i;x. hW/S&_UeM+!E r_mOM@Q ^bY!q$޷ 5#ҿ3Oz}FD*hpmp)r ,e$n95u'2XRZ2"|h|eQ(,!΍K(Aoc4 z |B2ȖWdi#i T*|6A1d*ŋZg#jyoZCX}̶j4PnI4uEf^_P?2) 7 pF}3B/ MW=7Ҁa]==|>h'j)f6Ų[ H@#{GrENnqs5cb#'2oژwO3}(tky1WPoBɚ(s7ju]1{_qmV0hEn\"w/2>͐..ι-E; $ p|ru8)` QS%?uS4Ap U Vq`_Ohn]$`fk+sCy'9gk ҇Τ^0ڟZLeUELG?f SVko~6%q f-KS H2G:@kGڜS!Jkv=Ri@|+́:R9n0u}D)>tMd T)؄4~E:~M2-W APUjճT^qH3*#Z*bZ}:ѿs{A70 0/ګPXׂ'LMt\+bԍeRtu'37VpR= rCF푨Lq^ |Z!Oj5ztMH[T ʲIwQ6{͐Ei@l1P>+Z*`fi4ʫSs %ex"QJh/ vdd|߇V&Zbϻ" ;8qTU]dztYoWEr{L)Blre ~E3;ᆴ)` PUԿ\D83I @[ˈ^o_%H.`uW$wJ:V 1uTSc AA}VOR ' D@z'OHΩATIpmߔ)#ݥҫc\lrXm6}`ax%4Y\,/޾/ 5 S.Xb=HZyhaڍd"'G#rTk2{jոPRE.[r8֛aPE7_>)sĴ3,߬g-[CYKfWp@SvQl\'UJ)Cc\ JD4Q%}"-j[wnBͭem.8}QTQejONBg܎f6EO*rK0 ~cVo]۶?;G۰AI:}gG&SMK~6.'ʮ8 ^uX[B<14X-[S,r.1L-~_#،AwN(v@M~{=(5#&5O}q%Ÿ :T+qZvC[׿E]ƪ 8w.O۠f--!l<$KFDVE.$lĎ.+}.8c F[؄|3!Սԫl`>ߐ^|#e$)ns§~So^Ly혝rhFgH#rQ爠ln|[v.Θ0;Ã`ÀĖ/xJič+U5beS^M<ڢLl.ItrĸN7/+uƲXqN&eXpѣU!wmh1}G ٳ:1`n ?{mRLbҢXU6D!Y|3P޸sҩiŵݎٕ$ߴMp<F nkEgb7C DKI??0AHYur.Jfן컎x`*,J9HyXg0 kVK]uE7 _r~?$ ˑ\ktk,.jYKcoiB~Q؍7i%e7uq]Xw8Wᮮ&r.$h)Pc;lאܖf~X2S׳iQh,n-$?*B ׷IԼ ?\&saն9мt {Y@QV7|'Co:-EӦoK _ɀP#ށPίBQbM#˾'𸏋qʣ0tn6UЄyc>r4;|a,?3+LѿՄs]`h Mt,u6J WruM1o_QJVtOYF!עL3vfxѧuP+1|2"bK-jq#澯8\wWO c?=ʫGLz{safBCcsU4Ƭ+ͭ.O?ћ(~d-wHR& Iv^A\1Z cϏ'S7S ɨLZ7] CF׿#!*`ܯz6&Gn 5*iOUx1ӑ/0*+|8)>puqJIz˷M9ЫI~xC"g_6宼uۇ:hSjHq'2\ȧf! 9ƛ@fVyj݌S jAMD :UtU=HR[bEc9zU.H(~Q]DQ;߱>>ݛKԪOZSN> TL?Jf]XRYj=%P]BN⒬nin8vw puW0:}"c?|gc,KBy'm8j# $j)>D NL}%nE2'k,76!ȣ,|oM^.q^ CBH7Еٕ̍Oi˜6)Aᆐ/=؆<ҷn8:שW~J\c<ls_7JG4G}W|W'?0# ck٠.wg52 ]ߢz[5[[Y%jМ@ͳ_H^^Kb{߈4tW񆏫)x^'- L[]PJ$ߌ@.', u.|I5oT9@{k@ly夭;^8w+<iV- :JTKC5_Af,)H.Y/7Yt)́ᦅFd6;e_#♶Ib}ҭh`;S=<k! O6]&(ܼl q{\5o,[|p̶%y?AaQ>;EB-ƪ//݌G}UmkK 6[tQQpV˳/ө() jPsk6IraSC!Cw)Tep]gFb(*tۓ5PGNl88k6ruCFUEʭr^vhԍnDt+3* eSJP.;k/CNM"28 :^p/]o'/wF8\=k̊U}{i=WZ/cኽ|[IJMѣHPPŧ2mh pt)IYXzRmR u .Ѕ k,4ם#Il&Ozį$" $~HSQP YyZNjgr=$5 pۛ1TJ7K>qAQA(A86 *ݲK٢IbN$WdTw7b)vb$bG^?1kK3!9o[ ma þ{jW#x?ʀD,4aSH!l6܊k4yM `= ;Br\gjR"T5sֱnm k%ZO1GH?8/,+Hݔ,*$E6bHzWGfo8W@0SXhSAV22u{Knw3UCrrSS5S&\%C0&iӰ}f;"]\Z]a칤B"E|qu5 z?8=_pG_^<8dk4+tQ˾! =:u'Un8'xDCJ)(ٜsz1CN_#U|v%lYeDӀC-tGn 7$=ULDNӸoX;:$>`OK2w8rcyMtDuh3w[t7_/zŢ4Or(QT7}cͅ3 xUihu^`9Ċ UnqU_2Waw;+P#oC@ [CB%Pa^)ֱn귂&1rkCD>;p7gpB*^m ԺlOjvF<>&)~)b.ыęWo0(ׄ{iՕ1*B#QhrVôIAC·AV|wW9hÚwG`W/u͜X8r)ƏuKQrTR UHa@vDр;Y6xH%+bcZ$qROՆERωEÁVFT(fͪb񝐯,bh81w!J5P"RLIMҶ R\"3%(( F =<(wZ S7`FPouvB@C6Lu" ۇx Gp$![sLosiNbjHRFwbߧ]9y+qc[U<b+"|b c.㹬8,7[E5WRq;IwH# B^Y/q]qb#Eĕ}9!-ҟ\:{\g+6c,#0mښ J/F8-[ƌtJn:Zx3 zD(Q`mzk499nV`) 'ߧ⩹ɾo8n.pY&LOoTQeӁ"0a>̆D^ѩWKݴ ~H!' b@?{4<.ם-N>tEYWfJ&9.^g%=2EKLͱQZ7 r ǹ},=<ݶKw~юU5 hc FgШP-&p0j'QZU ZF9<v# e9Wx )2-n)I{!]TA(U.5sgRnuMԙTUh*(8א46 'ĩocSJx<UɃEJE6o79oS^sA=u#5GLXؖ퀿6H8֘Rt;\{5#i!ML^oJƩlnW]~bK:.揷|rm<Y6]/Z&15 qR"%=n;>lf뱓Ll Jo`+q5u+ C) Ջ7ɓ3wS;;s|fiR];˻ȝ{ C[Z."o #hjjvm_efN3hS,)[Q1T+ii1|9A]S#ct GdoH@b|m㗇-<4Ggfvw3z͂uHX +cj?E%8@l2KL V_y 25>Q> T;ϗ%{w wb:1Q'GBC[C^ u.݋|qS5ԼHJM{e$_̷K_\2JGۍ6h2駏cdm+sPr?ڸ+IENA䚵0)pa5{bQ-;"pcf6_*]òkkL cod{ajP=F{yHz*/i~A8Ou[q]-RFOk2{[\:4Jz5z0>a^- _Fnk@wH? ;r>ƞ1IA-)j`Ȫ3hd-t<> L2kbTI !<^YO,DY#g"ȻbQy>==Av~cuXhg\ˡʤ/\7H@[D2d4%E$:s _RCKb`bBh*iG$;Y{@I3w!:-"HsiZ/Q ܉Ul|x.EG#KܟhU (-a X4BXa4/%"\ &4- _dƀ$v6*9s+'2fu]O+Xɍ'm Wh x͡όl$GRbP_a̮?gH^jB÷ڿxt̗VeR/ s[Vc5 fd7Ѡ(*38p$͖4C?m?WТS6+2/ƫ /\]d}2%;V:,#s:~# Yo(6DNc­Lɞ贕x-̓Ӵa܇GhB&6ke ӷ(T$%߈2DJ.5`HVUäp z\^lB5V"J~d" *ڿE͌vO ޱppTH78̹arEOFc7!fl:IZ@L ;q˫pD-h LƄX5KeřOy%KawL^n/CSɂ"Uj@n[Jgٸz rz!< T'yƛDseg?*]ނ%ⓙ<(.qꄻM?5YDߓ̋\,׭OH?I*; !{`4%G+b#DZHGﰻW>Wao <wNܛHNtn}-Xj]-H4^B\iÇoL߭nxuq^<[2V Z9SO}i6W*i OUL)Gu,z8Im'ʢmwbJポ>KÖ9hANȼnk#'-J;!K c#? mCD!Z[1wRvt8+xeh&رYX5Wd Kb 3s+}E]VY lhSO!kxOexI& .Q).Q33G`d@o; Eʔgq+d3xb5P>%Nq!Rv nք?9E$zz::$sRtkLm͎|- ռS+Z] 'f"hNbu)о'jbgۖ\`j^G J0*C ,:``C0?̨6W" 3dzs{{H5 J cœ7udzg,Z9K,˞y17'Zy凘j/UGk@e0I-CIJIO2;@M]%[ZWQDv}&PIfiK/@@`QwC[@'<>C`U'^_"Z&VESvߩN=4Fo&5?$5v8F }zoh8J,^)>Un$QmЭN%7?NV {G Md79:m²#IOgH#/ydgF/wT}FED'5^K(U'$JxûO ' C\q]In HCO[SJe9$}`y95O-]z$@-~I%,Z QmNusΛx VN)U|{agZoOFlo]fެu=/Rey9fB 'ؼ''4‚yw[{!q g!Taú$5$P52olhhm$  tUtGm$!PRxI-i޶<yycS1!l 9`Xɢq\ؗg@?L*5 &Q\ r]\tuagbP7Y +цsC45gX xف?e26 A ,fXM&;~9Iy۷[}z800zP-zd/C"yweA|,2DCwBWQ{ 'uǜvaDe44вzԘcnBOMZy7˟6BѦ7XR>[OyGB;+tPa1l 5{-dm+&@$*%଀̠?|ohbX~񀿡FxG]V`+mh")iwgOCv: }_sZVj\)|܃Μ߸ƒDf.]wj9c\h&3m. hܡ )hmu1wB5NAGNPVQeBo{9逦D׳"_ErQTRY8d!g456Q=)`(|ItyHYli:0I/lEAWGAI )(*Xd $Rc65ElOJGV䡨kP< Q sqCBtX C>~.p6AwE5[ɕ. T~QR,yO;I'H%=WGЫY 3D3{{┶-}"X&zms&]kQb_;\ ; ѴT=Ѝ:sqR 儢Sgn] 9^N嘨*IWX`2+7SD ^'M`Lc>wS"@ [d'F7j<ۨjKw|Lg$TۋA 囗"cdgkLDwJCR8SF)cǚ+c HWB`bn$f Et] bEү \A#T"(} c;sU<ڔE7w^MJ~lHKE>]>54lL^7PoY>ۯI/ R1!ϒ{ZH>L'*!jlIn}ӿH NO!T_Anh> SiXD\￈M:!El6ٲ61` fײQnޤO<@qN9W\Rd*ETssJ_x1Y%=]ϴĄOqy]FZ&>_r 4N`&Ic5aqᔕ"e!''' ʁ/\ FyK5)]ٽ`)N|#y{S'܉$ا2V2u jTCq~ y?s?&Vzrx5ƫ1Fd'N9?X3 5 .ŠȃbUTKE4eð.-oL:_.pC"MCFM" wڡ@ګT+5ڗ?ԭ8EԜBЏN)7 3Mi*Px0;%-O㓠-C(4`B=aO&#2?Itnٯb 30r0.yRl(#qnׄpʢ@$BGS}*/=qR< yJC\ Ӽl9|}\D^]yK7j~\Vx|o$h ىj> uUާyV(Ck<)wTY*,XL\¬>&'&4gKa_TOa:I<u9,]#H83uJ~=@\ս%.q_|k08!PfC>p7zxzo'ڂQC,<-&ʧ|oiE}=2ƫP|ss3]ՐKFE/C.Fik_v;PAUwzȭz@hlkKKR&uyQ eZu@hZ=q 8[XO:X$ȚR很}hٙitFݪjҍ05 Ȳ+?|^7RY:Vck۴iD~ik G&P{)wf Q3\|?T,i#]ȉfQ^G"r,S̔0,$(` PyD(3rwD"90\E(@EyG3x CӳJ0EڬP[ػڄu2-&BceHY-S)߶ X/҈|2(bT@a1t7؇PdM{FTA>ĕ(:t مb08^/]k <-N UeC%C笲J׈qdmPRiHzԼHzH(t/ ,)'өw4QRA*|Mor]"1Nu4rr+Ƭ , X| ר9::pA\nb tvK`P6hduvMNP%w{˭3-+l F!`_ AAC9Ӟr#In#  1(##xZ7AUXV2|҃uf1*>:[0&'#O1_mp|̿9jN]V,E#ka HhKȞ }yuۋosۻKx#\l4b,A{ʽwv(xsD64=b_9KAp{ʎ āՙLN q @U꥟ifX]4 [t-:N@(d-{p;#vsS)9GCM͊`;C0~$S7y-6GTyUhfؘc5xe'>J>D4%evMq. { Rr+8L9*jd/`&JSBx$xk0k 0,@xyXyKm(K&'3d /Ih?^ʲ%Ō0Sz3vb; "BˬIwѝEEyjuIJ] svヾ+Bvd_~-_Isa=[ 0WmF."@АE9E7wW>K]UaS;<[ٺ_˜f! bMYp<`@WD41c qEErnH@>t=8U0n/ᷩ /ZP\4I&b_-#sn r؜H?dEbvdxf(VU#=h-G^K 清cnFҾ'v-F`H'otUze R곋1/ډ|ҵ΂CBLXGͰ(\F hϤJp(zBmEcOp܄֭Kv4bO{+ᄴrL#O̴VOT]1afRQ&Ecs`WQX_rHG" fQ$lo`+x,w-.ZC҄ؠRf.,_|; zũ+? ]u@ p,9W荂aG3(atdo lSPJ~hj7$@0v6CПV%W-b7p69d\GeK9Ǯx?#̍f'!-+9Vq?O*fY2lݳw} +1pǠBxGPp.pv~B~ Ea RXY |m}Z_ӢlC&or$mG2M+GXE^ݹ7T#g|m*?s˵Y^>3oYd( '3ܒ gw(OL.SXŵ7tGѻ~7[>WA9;|}ʍrG Gc_'V3fe)S[&"7x V\gghE礽CcK E9*ØiI$s@ %ֈ6 .38·buat&:kTDAvuz!+`]9Iw -+a偽ϔ`)}L^|fpjͽ%n$^=w67&;0z,|.N3Ćl9q*7ȴuDE&ӂ7$ڏ F9 3#4#*К\Vb׶9o?lOf5o)XNqׯf4ʞ\*\Vl<~ ⥋ XO*mEtO>h}COPy!CIwCJͭ%ICřte`Fq!a8xO?SMj5E}KL7pCcr!Fw56׭]VDba&8훗֗$ Պ1faEM `C^-A}]5`_ye0q_7^:CKB1q(is܄ESr֖s#y}h8#9@%0dvcBܽcaN1|ug /ПGtTFp zrZ[0g|5ng&CEz,r 3(|9(>_ƔūG¸Ahe0ͦПoy\).NCg%ι?X;\uYY*)؈+. IӚǘ9#S5vG#)_'^ PdEG ΄sXy}dc?x-" #z)_"&tx&eG@bZcΩ}nYԔ4dgG \!Tx"袽]ycN!A/_"Q<?aڅ4T,Gù'w-O53}ĘLb6gI1ZY2 rɼ=_<v59k], yH[ġZ@#qr(fIsGy(OM_)8Wpp4{LKCԍwb bCswN[ u 5d9)K~Mzj"_6#⢱V V13Y *L,~jU/X"ɈQJ{y> BWx;YwؓNUwL|+϶ 9c3ܠ&A:iVK]%_z lc*sز o7X ]W_P0ֱrDјMwoV,EV^'04)#{H.Y16]ʶVnF8`ji8a*7& ?/BȮ6 <(YHk.?=5-kӿdLo^DH~ m?8q`(q* e:3V+M-2/aCLFnE6*F{%ʠ:4R%=ʧ_z/斟4tM|&IŌ|ѱ_!o/Sˆ+i1C9Iˡ #ĶΔx)͇#+X1֥  x}i&? P /{],~RE%.nEH֚d>Piɉ7FHAY<`f;\jvR}妐'gm=dG'ԧZ Hb|u! [ƬMKhhl?W>p{?T(Lv[?6w*n16treqA}G-Q`6.ft/Y v+Rvq 3]P~y+V9Q2[(0?AgA7wΓ(sޜXu#8&g@EW4'F/ ya aI G+n>?N-R)߰fΘo\{!s§?jQ~.EBF{v:_qՓۇV/Av4`XGNDo#J[G<''^Zt79 fp% b'ߒ /oBBk7J YP(RQ s̪! Մ9j[6K4Xf".'eR^LH7kcD$$'"Eah%)B)M",!%w)R杬rC'ьh@MI^uؗOɀQ%` (Ou?gZPQZp唞/YjS55&w=*T}9W?o[WgCBtxh_Prݑv9L(ծɾ|8SFs\f$*]"ArOLp|6[x-Ɔ {/gLWniy֐c;'L;s1Ӫ_7y~ӥu.kzP=xlն0^w)k%H[*k fcyپJF<+3M4>k^ι<+LGwuzkA,Fy@9G~}]H>|BDO65i L'.q’3f{BO}qKmX9NkP+y,dӷj4d6rQ\#țHJ/qRw4.{4^Se'-fضAKpj[BEsvj]S%kk0zv2]sɱ\x! sfʦ(g(cO~ROvU],^)0zEM%ߨ" (aWT)`6.5zBELPӊƬqYAFB̄m/AQٸ(D:޴TXž $ICCZAdS)./\@A:tR>E1#0 TAp:]|Rj?-}78Ǩϔ./k2RYOD|lX;+BG.ei4XvzxSv=q7.-wNBm xEŎ5e"Ɠ=6/RVѳ7ֆ2,ijc7. +,Xceu7~$*ޱ,sLK*54~G 2FRq3?Q_mHd3j=BѠ7hP:77 )|?I=G(xr1AUH3\/F|k& ".R65ڝȞhKZԐxxE> qƅP2!~A #\r׸aXXVM\4kp:ӢNW]i9:Mc]&x)9FX(jƄߕuf/F06jRɱTՠr!62Lj]>s1'P9i72zcf6ᮭ6:"zE3$a]pmYd:]V hiKkM%綟M^37^IoXʴ<>i9$X^-H"TRj,0MOv }V|bR7K&~+|kdR&#@LU|;j%)pRPXxx-OJJ4a?us/:L8=,) O PNtuMstn#QiOuuLgx\YS0%ޖJM!]Cݮgphiٯk5iT[C` B,+1vL_3k2=E=/yr 6*Ҧ w)Qȕ_ls@9Ҿe ,5~oB4vPL8$Ә[| l Q"6qifQrr%['# %t ;ֶ(t VE7$@8YӃبq= OA }d`%֍a?݌I|˦{Јn>O|ַ,fc;L9=3s@u~UrfH-FojWs#2Nc&]D`)R$K˪:\1eNaŷOu6"A| psF7c "Ty-StdZ%q޿!|¥-\vɟEz"b̼Bg0}UPw_I@%,P:4ZKt)) lm"CoB⵶ƳMxSi=0~"W*vQ? c"΂b C`,%φA[`yƻ݊DQU(I+]VW H,鬎M+Ӝہw5|2fXv z5?ԉ"i(:bqxd΢VȄ$mV>8Nly4QhI*:yƲ*& ֦ kVvw]nSj5zr*ouWS,MOwbc@'q5]bS̽phl TADF~%.GYO;uʇGᇟ-M?}pk3ĦN+C%=6+W юMlڪ 5J7R9®!~] Ԙ2StL= WK{b#RSڍRcSJd) 퇗\몄Ooy' Vި+mps`ZzToT~cIp:f'PwZ *8i@2GpoYe-av֕FI.!fCWNH/ww*iz>c;E ջ,7P?fߥA- |/0Қ FMvPXMc`mC.Rp- KAk he?T-&htT˛U.Gk4gVE"^&룖!Jg2UHI"iASL]0\A:eRK6JiRũ;:>%\?Z<ztY߽ t,aHM4/ty[u`\Yi4<{~:UHZğKu)V(pmI/Gy! Fam.#c$;XjWs {m,?v"bG% t![hf .Hvtgx ?j4\QO_$ !a֨U 9?_2'l;z4r4$ Hf9 oT[ȲEuG2ݿ|"@tPD[RaCI-F}CFԼbHX}6̹P3rKyvځ [a#qଇ$k.g>1kG n<I)[eOw'\zmAbM][)Ч(OҬ 1AK`ާ6bէb7yH9lty;F`(vSs )Y8( t7Wm!\{2N @"Ũ Z+z-^D<" e;N!Fos}#w  S,wm7xUU v?uTql "P%u47*WD; rZ:킪Ἒ}6:.'No!͹mMn‡.w@ ހ@톈<|\`ŘC O.W/?r+`@U}$zcMX%RS3?/T"J%X3 R88jF+1nI`\T|>C>yk:΋SK%)  `_5s~Ꝉ.GָK]~#ΈL 2p=y5meƭ{ =zdVh ކ S *w 7v3l$ REg$P5>ߒ0; kj.G],$f҅>p?Rқ>#e9kp]ǪOqm\J @ @.5u ⢟pPMQgȯ@Qَ$mD:Jwf>vH*7Hf-ʄDlB tعm۷ H,-Zi)ظ:T[{?ƴ 7`λKӡ3Bo*IMݝY.hl:t#x)DO{1Xo@s#6< DqLŻ)pܨqX帇`OM0BP:{E[f盕.udR:8 GEꟊWr.r| fd/d\EڄX[Ţ6sW1GqzzqJ&0m\1xOsZX[|\=AYNm?{r$ޏf-vSp[xWݒPf>W{/v\s$EXIq,Z:Rc3VO_ƿPd+Xs?F|O}M9=Hv}'3N[ĥK9jLVT$(ufw cĐ]N{HY5!+ IX_ToWPfL3n&-6?ZOG]4m \vF,= 3!}>O{&"L o}qy9>I0&G4=A'NsZX:,FP&_h,VkqkW[X&K\w~rMap_@ѝffX.z@+Nzz"L"QTo>z1L,!v#"3z^-Bɦ3g֒cpAjV6261stx"_dI2&B^q+c;Msk'K*G^55즄밦?gFE[kȇH>%o]W(UOGe .jMgpF%ī?FKZ f(o/|ҁ<}?+]7 ࡺ:0- ׶c \V; T" ΰWC.{|^~\% fU-B ؇D’EKv~>ؗr g!ഺt0EksKT^/B=a(reRD=,4GOh!^ers6ԼWDPCOgꎊ83NL'zPҲV~w'U?w.TѼ `#ai~sm!Y&pNx K6`-?>j]0$ g:LJqv|}^}xPdb48$ Ok~Sq9, &`#<[IDRUBb`CoH> 58Hd9\y}2S˃3T7#]][,EbP̒Íxߵzs7pP2}[ZM)LȀM1wV$rYI giY-ޢma oP9> ώ7۝ wKU;r~.,!$pRɩ.&?4J]–+Tfq2 O4&h3nV; [n }}")/yگ=QSKv' T#U=%l`+]c%jG9%/}9j繧QrbaW SB32B `7{#&,_S_-L 9=.W8 brɢLhZX6pڗр5z5p#'}xx"QH'9pD 5>BͻoիUDɴ9:|PV?rh<#4xK&]yY2ˇ1`Ap5$`t ~4B Io7鑮B$6+@x5L0mD޲|Y~l<0^efXT7)ꍿW찪rH9vM4xnbhV{f<0 Do4ѽtt _*,$C _ɶnTuھH |3|42cǿZO&_ZR_k՟x4GH=.'CAh)hρWxv&WWT9>F5VGQlp\8s}FfQJG1F ʋzeq)OfkS}]#Kp%9 ºz$eJBLpr;HYHy ,A\pKְA bRoqR碏 gçT˦8duroh 5xl%oF2Ľ頾<*ř _g@6Gs*a'TpI|hj#Snc MO>o \w[s5`!_AI}ػ]/xꍦ9O\nRz@beP8.+BmܯNm:[+OI0kVN]TN/3m5HyPLt;i 5.nrYk5'j?cfQm.[42ӡ ʽwؔL> 0{Q Ai^B gPQZi?ۻn^plQ * HtIZqГpOn|XWoNm99P)f[`82H45:roLib`:K53cM!,՟(5;H9}՘=Z {󋾵a=_֌DC4éBU,HZu',@;=AKSU;a7JAh\ZSߍ%Hh$za{2sf;ŲMr6qjMLZ[e$cK6Tk &;P쀤8ce8uJM{l5)þ9fQɹM3Hλ?31d lu\L߸C#BmLKiij~ͅcB[}e&|-!¿ pI^=w g2\4GɵWq#d̅/+Ht9wЋ@̛:XX@4 ӪiEJw&x<[㿺-y"m#0IKŐ~-n'0t@jh6$ByMYnIcnvlF"MǃcQu|\3x@tV33}^b K7f38Pn6"*Nck90SX%N?E8NWeO[oE; sp]uOI{bfHGgLp_$!ZsWna._=DJ#,ex X :G!GȺ H hOEyt/Tb9nͮ ȨfX̻{zR9LkTQ Yv!iU..)Z;ËI^:4ÂY ն'^$w>U uxSXw2E_N|G35/8ZU]M(q;(b!۷T3G] LKu)3bD|0 WI.Sƺ9"gN|!T[/# HN \mg0;X/cPj nw# jFvGw0ZiU^s7I0bv*&䞋 G)Ă(ѧP z!6*ӿVWh  ESkR3$:ҙ5~r0\($`}j`~iKvy{>Ĕ V*;mVaV3,Ggbr8:d<)weȕR\rlܬ0Toc jD@d̕3m+NPU@1qh{tbOۂ9c0 |*3pğ'mփ(6)zXvusp\EȐ dΣ,.E$='K`oA<{cr~jkv4pZo,' 'u1`pŎ_boφg_7PZ+L3W5W+Y"ƦDam yϒ_ML=u9zoFshc)F{&az#e0BxiG{abO\[T9ɎxVtMVS!`-cBNb@tCoP_ĒtVQrNw"/#Qod W]E}6ʭEVf^B~l{j뎪#+ $t?Z}Z).Eq 1YXP=+[s(BW.L' RQzxB<,NHŌ,|w_cۮg"!`C~Fmpnՙ!"]'5/LO_ rc߽H_ I!x1` ces MY:O} C/b[FNS?J;}c1-#H85.)iuK5kUEd*3RsJ?u+bVbOWSS&10ۣ*T1ӘDN[oF*\ 1Vr-*|Eqn"Ixĵm TlʉBǰ Bh"T䩓ljjr~l+l@Um{n4eD=e½Lݐ8ۢkLT/ \=3⹯b13w}>܇~ZJ-]W)Q\w)1O8R;DAͺ?O6߆K~WHoZ&:`xuOkoA34v/ ?N _6N S9կ6;2x Vq4 'F>1ohfeT;S)tcS~w qwwYJje^ kE>bE`' h6TW)VE(vaSyF^/*6ympՎ|} /:zjLEA 'bxc&Ưoaf[eݚ( Od?m8&%/Ҏ&aeÝ#pO#w? &޷sF@~ΝI_T7$$HLڍAIl̞=D+Zҧ:?xR2'鑦oC\l,Z_`gu$a_ d(r%&єRe|F{3Y*QB!B\Uio҅47ΒVGGu5گ1A2hFC@ϴISG/&뮄٠dV쪼ԡC};}.lQ-_lř%jÜ29Ai#n}W2(8=f|^ u>$d-eOC;CzN 2rь';Mf4Xuw#0eO0 -_ * G"kڀ7q4ബbjrYURBl\͹]pA.TCz[CF eUe"\ѽ\6X⧪,`n)N fEלM6cRo4JT`ڕh%T:Ϊ7e&b6+w{F7l^I'$zdSPKt!.,s~R"Ǽ記<18&HD9أn!ԼcIs[ [ W}϶`Tm1rL][a%\o̹镙f VhL+FTZ~\` &k3JxQ(Kq.kYr B'bt#0D'(HOjLܟHI<-n | 0teo;Rnwz.zPz_&dHj]\#li61it%T9Ƥe1nȀ`#|;9E$|7T!{R̺;1%Y`zK{bl T&rR+BwB9 進Pb%iͩN!М5`g Y<:>o_@ ݀C!B$~7uiRȊx#~s > |^R'?1<Ah쨔5ΠTTyX^쳸mE ǾLʶO@N;P,pՍXm}p糍>rpsTdLi;Ⱥ{0-F\wD1/#>r P~[+*I\_恼ilQĬgZY4!-91,jp[F7œN0Km KwF%"rqpj=:Wa$ہȷ4ՖJ~]hQU/ Q qjWLCY[@KMtf 02XKyrYDPO=E4Eoõ6{u*׀ޅ#FYBkXiSwx*ILD{NB$*h9@w}F5͕ ru2rnawf{t!kNL-V;yy+T!bhߌ+TSUPX%圍,i@2#fv) HP,ClvTֳIh%ٕ3|A@ӫPO\bC'wu :^w ֲz'*S6p0>λj\&6w)H@{+blb>el[>-Ql>i$%{#-1-s5=,{wi OZo{:& uIrޡ<,$ՑWA0zD 0ОRa3l3ȁT|=nQz泊r'}8mQX֬,U )FQB.+y "lr(^U+w3=xb^f @kT G>d\y:k6,Ӈv7ǞqE`_(dԢuL,^L-aˁN=2.hP{aQÓn fp *ٮ{%AG2ۂTgiCKv#B͓puf7c !YuۋՈ%K!ߤ }a~سFxa[휅VTоk"jxBG2үn M.o7 ֋驌^['"`F7[yWT}ԝ2}X>XYZk3= aVk^+MR5;o[fdYo'**V0BT g3ԕ> eJtzBa,CA$'^¾ *BqWO <({/ς?YL _%-:$kq[0 mE +zשeZRPKN? ɜ okNR["v W cjԳσ?.j![RpL#1vc$>ENx`%iHsLjk9yY66oeKʁJcp8qUs!t[&MνGLj${}_kuKyPq8anDi[TOӻ7Fr`?he}Ѝ|Ibp~\3& K?.&)fPɫ쌭ygcaWBZ"3a: M_OMQH_-Kma v?ɪv/7JaC| ={r=d\fTLޗT,& pu?GqxݵՌՏT3A~[.޷zF z66/ jS4FrwX.L4cJ~ȭ/^P#b,#1#p٥H=1ōj91]R%;wW<@>&4~b,u:{li$E3hQNVяi(*pAaf!p殠bP/dJI#䒂+H3'(۫}Ux_4o0KA_%H܋u/gqX\ :(ty''9ͫt456}Ġ^2D史>v]In?)RygG~6d=$S.]/,AQCYɛ!F!k_|4gƢ' -% e^Df(*NIȴ`7jIy 9"~Æ1-[\.uC+b~~$uQE<ͬRs6vIEI8 )fvd9bDxi]ƕ.?>uLVb /5<4mtaoпf/wg_ҩg| hc'!,6uDMg) 4/#@V(evJgh U0JnPqiX0i,ۮEc$zjLP xe((gG,H~;/Z,{N7G&Hw,y9gasViOl~^C(Iav0~ùUH8;h2aA; NoF), ¡ e獥>p((&VV]{ A=aET u EnCݺIaX-ۑ2f<@+)%}ޙf,XǮ<+ɶc`/ٖ)pLڦ_[zoo'0E:o-:¿5She?)IRb/"+(ǼS42׸M`F)d~v qE ~&+Véb2'xCjްCwߒyLt^ٙfaMeƅ\ea]`Na,3׎sB .N^-T{Ea&s` a-3 OnTߊȠ?; Y);yJ-˴$e*늢#"lrFZ_S8)X&Ŕ#65X7ja}'D:(G~s&nX>m t!NV';9J]Bt jx;Vx g6T 苔c:t,Yk0oe$jOn3a "88L>7QyCjp\8Hߴ>ɞTMik) fhT;>rёӰ 2u:@-`Eagc5.Qkq l%%eJub6>ELFZ>XbLϧQ%ffw9N;S jkēvLWɁqJCԵc|۾d 2i&Q"]_yL!LHq8p!jdYe8!'j4LP,%P1GH f>t] q -ȡVuk>;.sVX-O/wF"|A `1ڏ:?<2gI(},'@ȈˠS|H4&('._?fk@qLA^@ʥϬMxеwMȒpx\]H`ZYj.z'H V ?`1^nݖx ;9}Mo8UD7hg]BTǡsfy]mF>G"҄Meoxų_1yRC9+{'YKf$yJd8#9ąrPq'?$g;K hR*=ųcc?^>*P,O{#eS~J=GSTU1U]=IXfwhQ r\T^>:貶ubZۺQ՗v݀[נlPl\3FZT=0ps,cAT8_1  ;G-c9#́GSA MaiH5\1R08c+UVڶN#7!"z͚|K[ݾhsI/FL]," ¨֜sN⟞͢mӯW)0Bl _myE Yrs[0ՋGkKF<ΩItS0Ī*1O7a( ԵV aaѸzW_uĻ!r.2-1kRy{!s/_HyЏۘZp4* {VNB++Ið4xpN2i6?@8ET.ܥiQU{/92sT=AkQ@g_~VW ٻѧH$QԽuzXGz 8ߑt3uMs)Rnl00Lm<,x-3l‚f7}x/:e8yմ%~GHnKӘޖLm*F]g5 EJT6W#K.gĝo:Nba>PgOWc2NhLT:/F-F`>VYoH% zM+{r  FR]{K-iNu D2-tԪ@hk#{_fv92&#3xzb;n@&R#f?S3t05Dܷmj]{FvDIc"M`NEi^/£$,1iٍ"RsxTs teKKl I$я596g.XHo٤5^8Z6w6tyq2߂UGpSRlwZwAYn€ aJ<.} kzAOS*˸ ŷ7%U!qRt:[NS*N(~\&KN@'UIw-:XrdjbZ@N,KS &SۗiJ˹9F="^U^tAn\^1Ŏ\aNE_W\LZ(4msD1c%QDPiJV`f7ku$yphd#OȇֺN`JlXcOaBe"-Պ 9Pz0omTZy2"b1}-#x3Jvs4j_Okڏ2@Z»Ϭ(_ ]|[qѿh8uD"S vSUY7Ȫ_ꞔi3e8PQ!2H.O1z0h8U xo ĞL kl@d'^ )S|p+rhatD+7Tz߲Z|8(ҡnCb?k#2zkf$0%ܒ5!X\'Ms OEW]EO@vcyDO?5/~øΗ=% L}B4lC 2wa:!Z8"*1O;UY[_D'v-[&4#5ע@i0Q_TRe 7#kAVMs*8Toވuo1xC~+8GI69'5(l'`KCQap3(s4ƘY .<1[3J-7R%|ynP! U#5Whvvgkgxg(3"|ݒIt?`Vͦ#>vxKw,ܿuyՖ*~#-ڿj,7S#t\KAJ7{J&l_}js}&q0H 8+n20YRn=&myLP-ɝc}ȹse'4o-+,erƭ &@X=dqi7Q ,4@4ACD#Ջ:Ϗ " 5}1Ny R.aV{j*?`q#eRZB.tƩ 2" y;/s t,%+\ĥ9vm|f yFש)9戸{ N\ T aE5Bu׿%!S`3'n@/֤sК*N8dr!K>TUS}o8\q-ӏov"ApSh"X,Ze`t\HN׿G"W=g#ko2 <;(uPNzbʡY>*0* ]R]px 8ŗq&TQ gJ8<<քBPfM+*l@Oqz{;r)O EpKƳ@ | ](R橖kwCbW11^nUQNuSsMm.MUW޽cUbz3m3HT(ٲN+3mʠJs4sٿn0 OhV {)ۆ*/ bɈ}[&ۮN1&'3vԽ ?1] duFgFPtMLcyEc McܸBtEtW[xpn)Fb;R>g%_YGAޗx,*Jh]^R~-V<<8y&LRk "w*ZM1\,K]/x=@e,iU:EhBS1`;09 嶐iNG=is/5YCc[$q^ dQ6B416jjLJu#=uB,e$4^gb'RI;Vj- >P=l,k-uWv^k%EJG F1"\/ $19J򑆁rp{8/Nh=ǰ1O {ɸ(B7ŇaF܎Soz~ ld 翏`!|pw6ɸhX$&Xɳ$T)S1Ľ4wmG:5|⏦gZܨR82cQ{Mo_J-*MӮ+?u1bw+lB.V>]] ɬ_xW }AY8 ;"]-N4:{ Kmnl9hH{z@skQKޫl K]v kj[}Q{tp SNꑿdym[dA݀c <ڔ¿sxfZ[MǞV W^.dB`l9Қ"sP {?/6\V6P΁G;t;WQ5f,_ ClB7V?Q:_UȶʨE,CH}nYU2˸y(m9~f ('̍U{(9SC>{=:'32KdfzmksY)nzU [GpS|xs& o_?3< lr sLGQ^GUyC󤭾9dN$`DC氲gŶզ\). m=;gT^ )|r"Ҿ;i3}hԸBbs2d5ib| j_ Y ɻVũ 337.q~LqX%$@lm[x:j[|Cܞ6_sotq21ڻ Pey/\$jc8Bo)aDrN'8bZbF;KvZWE!@D?=xaekDNuF`X!2נ0X.oꑷ3w ԾX1{g$\Jfk:]&աAЊµvrcic0= w[j*'$s)]fKUaW [:9Q4a“cLDEye2h:>[03v?@UE+sag;͠*uT2@fol\r׸`'|_~MjڳӛI[JLZfYC>B:jB)"G, #BѝDbIݜϰª]p+ jn?w_4lbXB_IE5W=suR.\@F5R6g+{Z3;<"<턾Dԩ-AZ㫛LZ'Ĉt*\tU!N5=Wm6g]ԩx~3UU|5VWcd5($ۂC tv>r!_cdlDƿ||C乐%M3\%loH i> j4=Y2GN z =GX{eK>mʔ{UXWݘX_y7gTe)^NJ9NΕg+dZUYiP &1K#_ }<7RaؕljKJN>/d cW sf?65f=@㗴[h;ڶ0xfEPae Ol HyK`,Űxlu{,5LaV%,M S[ ;Œ#K/ńOVnẛUFsfFr7nF92#Dd0ν4.JS%*YL9e7Uy*%\C&ZL~"SQ=~ܠ@7(`f'ԃs_ێnh1V[_jY*-ΙJFuEnYGb$,2z[1?Svo0H``1~+i6_1JsHX m|3@V`gl[8(YG:.g F%LyQ&ɂ`2| GrI^{Yp|_9tқt쐤4{QCex/.hկP v6 fM+vj8LyQⳋuk[$%dVr=o:S k2tG,V`F1A֏ϕ!썉c.bݳb ,S&#Y -p1]7K͝,E]3I6ԩ޴.Y'횣fQ3B8LZLbKMչKMf~< qpJCs < +X!- Eu򧜍T(q镨Q&!8,:ސ%|gŊ9br,0OXt!HXA0x2#J^TѢA>jHGs` /Aט3A3wC:ZH?*:vu8]қ$'؛FZx8:̖ 3G6Th@o~TŦ~;}{y>B!?yO>+O+[YRE*F@_^Q5Q6A) dkJayrrPeJa0Qzk((+pȖAHZ^//ẏ9xGK{F$@tVi"R,keDx !nvh a,`Szվ a[ [zB?Iٳog or,'͛]7*$?|/O-zab;舋+>mJ/v ŷ֢}=_v]mb)YxB:ǂ,F&")?7 9B}B]a~ <<2>ۭC ä!#t}8/d{y?ikP@MV/c{4R# wa'Gř7b1n0ٜE& B*R/Qi\LVϙ/ZN>th]`H\vHܯqkM{a޿?U'o֎1P{uKIlfIm>J,8]W`$! 2ze FcL4‚zNOց;.NϰOьH&roibC HhdteOoIO@5&o Ҭ[ρH-edpX='dzʨl,RT:R 吻X1PH!!.Ct45<.(D{Fmo"31>%;ks+ex¶Ŷ9 نK3'+<9 %#V -K' xң_X~[om*o&C$ [WI+%~G|WJ{ܚ|W%^yW+=ȓWF np򛹟Upݩ8FUDQ E@SJOLLjMAiEP~RAt&02Bg$jlx1M2IE fK5P:(z Z  ]/[]Pːc'k A|DDumfc0`#)z/rG}{8l_7dsf>C.2|X-p^7Hv]H9ᵓi_n.0ΰ .=JKF06r}a_ p$S‘ۿ'ƿ<&_IcIqaе=82<=QxQ7>2jۀkwp\waXKi(TpRxpRk;)(5?$%`KW$R}}4cdI<tRvlC-zq0I{e?RAnPCȥ*:PjJ=8ZG ʏcg N|KDF B>'˞տ&5.Z->7HP#'{SQZ$Zk)”~}V9ҵ-̙fe{#t)#B+Jp |( ٲy@6C5"ںhPq.tL)v'첕k4MT-MӤSVi)җHFYsQߜRb1PV7#{78X>Q4̙2n)z2''vՙ[o3C- #mVwDH '/&IBoHU.S +i9 YijnS 6욢CxE(w.ۧ}F_Wi{Ċb (:u($\8b}-7PʍԎ<z΀0LOf8=',Z %y?ّ|63\UݢU ^kiN&놲_kb УTVws?BMd Q%#g@N4čb%MIX/?$5VTFD귮 ,V(oR3~^i Xŕsk C 9bK'˜@߾ 92i0?N*^ g@dAk |7 6sQeU];)ڌ>$; _kb0eٳ? 1g#a s} xS fUEL;w;V?qZ ojO(፼Ph`w59CH0es{F]q"V IXSF&w1$x47s SNg^.ݮH yGJʠ3W B^P =SJj;MDHZռiw]c9;l-Eq|`U FGq񹇶<ɪnAQ`8c=T:9qTD>Pfqf){g XʔAC˔ɪ::wU{O%,%]?u^&U#"-4P+%Ph%Ƙ{6_~1CfteLn)S?b  ũ6&w_ǸmBy7-'#gQy$9N2[8xtp6޹s#|$J ]D9'I\hP2DVaWU|3'fr̞aR萆̽F$*xP̣Ƿ4yEUAhbq?a6۩!^MC'LבB9ڿh¤sdݘD< ] mGo$/v# ǝ\x{im_`γUɇ̆!D°S'=6 Q$JsH:ЧdYP8=9M6[ WZ.5i ?r v 7&nd@^|攽Hޠbi(sDKEDz)p|'aMFHN~{- FHEHw_u/R="GG 42`ȋl!#_lKhęGe<.iYE`on1fD*qքfSwERB+r V\:F,8#*{VMfw@!nߦ~G2~c&pO^y#K7#˹Jad)DGò@+SL|3\TG2HeJAȝ`P3-vp̉A?G5v?7+ |ohFz C/ $D( Pìp,ѓ=N>y<}o}]pHxRp>c Fno6)sjY>dL~lJLt3.RY\G,wHMke1&gjP>bBmjl%̜;$@'Aۑ [{Ai5f׮['I0#zgz+wFZ%[Fz =7v[>`s?HF˘_E#e$V/l^iO\ Fb'vwak9WluPŒ\%nIX%S'2B 짥Q)foOFM>ӊaVAtWHm/ħlwB=M{Ly඙ˤU:'#55j23nhՎ?hPM_) &k^ٜ:TlK TOAeЊ vq !H{;m_bFeY @] t`=jvmøGbxkhS= n:Q|"VNNN[Ug^^ڐ) !U '?q0ZZwx( -tOdDS[wݬ;E9=8E` Wi!*<deÖӖ4:]o·AlTgj҅X5//3c!O* iYq9:zؒ,+T?]ҹ4V[;z?]96ϕ34B{q8}VbO(xi̹-_-e՛VY.lV#ZMT/4#x:I%D *s-G5,͉4&#nN}.u3x^dk@NwբrpC%4wSEqvk`H0p؉MeUuu ӼN ރO[Q獅)Y ņ6ߜLlϥ%Cg uHȄdQ݇%)G7dɕdTKjyR:7Aaf! rRɰ?5>XGM1Okj%Fgo[ To]ط"՛DԧCӻɨ93jJBvY2t*"0aN =14f M;^sDӵ2L6$YM@ΰJ2` ᚇ܆ZG5 m<3)%QW3$=|O+ &Kt uY*C=x0Q0Dgf}¡UC5v:d{qMl~݌=CoQIJϲQl@{CTaU{UG 1}#ᤷ345Ȯ깘Ao ,Sq%:"9I.[ZIR kA뷑-fGQ4!!C%\&0`#Oi 2;g~)"ՉMy^ߨ{i~rpz 4ƟUY|FpK}$p?94~ aHh`Y"?%dOˀyU2@`ɰ'P KNҖ3QrEgk0~&I 5MvĜ%/BQHQjm0K yêXl(n0jl(iinb~-~y.f/[\v3_It(5\uvi*ޓ5>v ( [OR7 A]MO7ƙ(ԙWUsS?$z,=ˏ<8,Qҹ84mT PV/ U\ípfXXrmyޕ+fȿiLa2=H}KKp[*@՛UJs<-א/lֈ"4h5[ yTkAka'=2lx3%CU&4!terűpԉw:17:l*,Rh+p@%A9R `VɷU \%7I7W$,PhG[Q#SGŜwk[ a6t0+.K;Gǹ #VtNdAf;*prwMG=?^,lAp5`lMQo ͇B>,jQMazT*GJdA9My}c,y T ք̎G>=Ey]/x&62)C rr z, "jG$Q*z~3e0?O2ͨ4`mULȒg 97"zhRWkN3  ]A7iBIΜ9󈪥־ ,V`wSހTay;rx fПr  5:JդeQP &!zٙx%UhyhG׀)C6agpX]2)khL seˀF[GYEaAue{Jhf wb3_)2{(YFTo.nXzBu}A1qTlM1#=pB SYe>U齵׭gnBvgG(a,QDNJ2)ԡՁ*,Ga7zx,Gm<s^KguCJVw_Q7UjT&4;5"5j&N{,*;!ݽk9qarH (7.% / ْ7U1㜮LJV?:]A"rs酓:fGzh=,b)"ϰqr>uS_s)bZWlKf ]-<Ҩ<)BѩE &x9$x0AxP+q\lαeQiUEfC$_vzC0~}v4b,_d8(e{<iwH,)%+*~?Z$ $3Wjr^~4ͦ"Pr9ܻ)d8<'q,9(;`&i/ ƖC`!n= O*_sx>,OĠcmE1w#+N*[KzJTpZΆ1E P zDj:D*К4(E߯dm41y%~Bw1`j(lj!ggl%{׻bC:rC>N[՝:Y<-=N 0:zT~O<\JBXNs݅煓-kUnghu {mS g}APo![% wP+X1, I "m]8GxTT2:J2-TS$T)zf5@$m}) L {~"-t"o/x:B՟(δ<#^ 0ͧƈw=z8/wjW:{SS1Zpf;a^o>AwB!;<*|7wF^w{t1lx%i|nж_5߷H/.|}ïxTqz`n|2Kuɺxm`oU{j xX '^dKA 'ZsȮ>P1`= yoxb5Mp554|RFt*Pv{N?Kkf!O&sR (iU46!Ή#>m]iITmӑ[vmvՕ5<ί`q8yT%,8o\7 OrD7ʥ 5*2 b@mFAiQyA×]ݣ@W膥5,'{(*7bD\YGXZ>KƵ=Թ7s6!Xl/Ŏ'䞖;;P53 LU6?.fLKTP ,1W 8Kj"ix]V!`az6\ gTӅu%Ug0Oջ^ (-ȸK`+Zl4EIcPƪԙm/*ʢFtnn͎$>FLu!Ix]eBf>&?MnI~ÜEx݆ҀJB5 ezxaOƘZ5fn^}h7<|.KExBvtHˉ*„̤icN3OL8b7zWba;FhNu ܠ-EZBͭ=)k ,,E7Ym2f^p,L_xJj |DDß :oJ,k9Dl.+DO\Vʥm`"k^1-R.Hċ6m',?=/{Gy = j 2 %b*LjXLCNX,"!FH ˗(>ǀ>>"~Zl䪊"*7qx;[v'qRdoyEmsW!4d9}vwsBF9=)9̃ BuWf;Ȕa1j$- UKJ[Sx.)ጃ 'L7^v!U-],k hM&Beq ]ċwC`>i(Tl(桳P^K 僽^U,B2֤Ç/6[aJFnF%"J b5fZ}:|#D (گ3QLj7` 5h̞N1^S,1t[HSebmG3"cB+̋WN2+;ܙ鮔ʼnj^?2nc "t{j_4q^dnҳ\4,B72f6 p}|ƶHf}ӳBDA?',u*u$9̂շkGË<+"~Fܢ pX ܥ>MVeS׾ffx09[~k+rOh N!Z5xWY8ى+(7nћST3g\0)ov ʌx[4y)'n^X^~*~&W`n<;=>'=p jEidM8D f㥻wK"q6MY1ʖ+2 T *Z]E:ߋ Z#RPލN߶~.?#@ZDW?Hѯ5oS%dӼϪW`M(ƦsvPIW9@űz܅$ Ck~2+W+]N6@|q( #'9U0EK׌ 7w>܄JaX%Q\?3TkN9 -ϛi a(m=ԀgQGܪ3yXR&r)I5>5cR~NugRF W4sR~nRvgg>OwS{?he `-(-o28$L}/G^P5-C@kպxB%8 ׮|a5{g9-9NUZ;ɵ|-"  MЇ`Vy~%v5s֨8Nf&n7>JrtvQ*\-xwы8Oo+ﰺz~2f$R:}aIO"Õ8"`H\7 +Mx[6! ܇)v=-?wڱ(IRB(wFXBc{nc|)sY=?/y4גm0bMhC-NBd-/D!G%PFR͑X5|e:ʯ$d;7t'b8Ez]J5m оN~NZJLfl43:DtW?9xO0y5ٲM+@6fzhU,v:RtvD)F8}+"?HpJhIu렽mS4P~Dqx5yQXZUfQkŲ~oQxS θoj<'p‗1Vp{6c{>P=GшZaU.X/$uJ;9=ךNf;Fp[U?]-c$} +7czMߪᢩ+K,\is,fx^eI+|YB_VqҳIyс]Q}X+6ŻTn|ӛLdF !fB9US<%tenJb)* ij1d+q\^}4RV&&Q-g t&bFx8* ^ jXa!8T }^LƱ "9:DrG/@N|.1fI`"}ԂWkIg$\2#ȔR 7bvVI`dI'g&*Bw{T@ZZ 7Gc ciax55/d~2.fGӜ ˋQl¯|7ladY1u\22N4$)Sک4Nԁ=IjLF ku[w]u{ )'Dג&raº;39M+g#:7v's"e34g6>:'0Yqr nQ+Sy*N"*\Y(0;#4$ǰX3E4i*'lgjo\gz="|:iDAXk k,1Qtm/ z;A2_381 Ť(q/x+6 v]P|9u.6\X Y$C3~>_sϕ5DA<`7 V{:b/k-*(jwdi"MױHop5Λ-ʌo$fWαvSlՋa53o}IHͩogLaIKJm91ǎv>sT+k+ZT;c / _=g$":$mpč|ϢfLx eǾ;LPg7!=ZʭǫAkR!MFF;?ܦAr\6ηeՕ%~ ha .0܅Qޕ9?Z<|k]f-+)n{a]]E2bUdHUyJk CLUJCna-{;&Wy =\:8phlSp0$b uC:2jUC<8R9t2&Eh>_Qaz(򤲚;DH) oe7q.1@ɗF[_|H}%y:@7snz&61Lsm|ӣ}L4/_Vxlk[8g[rK~ZMMIp{)igY[ҍG $R76$/ٱ_Xa++@ȷ hBb% ĩJ3?eaE@O`갷 `}y`8(FǚFDneʅhy͵a`vyȍň~!5K:穋;?/LKNGr<ȡՂ][=1.N崝KH.# Z2/p $Jrظ,!Oy?DܿƸ+uh[XngMq^MX>MBO?=h³U34hH Cz36:p^6 Vgb;YL.%j;l|Sn(5E]$lSTԛ*C)~鞌*LJS%Dd7~H@Akl-&({W v^r:^*Rx#7;ⵣA (ָR5Cw>@ }1EYj(1)Y+ᚭFB4,_quuDDx3 /: +?[FJDNiF+T h֘ ={(ҕW&KYɶ{3w/XFKdA;C]b˜_S8x?1sp֨)f8IJɘpP|=aBi:b.= C8h16B;CNS*1 {O5L%j3*3}-ܔb9>y&g6Kc5OsX@!P.π3YҩJhR i-Z-ӃcR>8?++^OwBd7:lNfWTJoL|0nhyuW ky񩻍۩<Ӻ2s҃,P޼M BvmXv}=5QƟ{U5]:3,ƅi4-U"qΧɀfZ0ЂVR\ ?3oO5mmRWrW̜ <O'4aPX'd_ld7Ii8sW|c;YV%5֘̓}I36y9izپ{BO z iQG2 %.;/K YP΂լW (ʜ& _[= 6Az'Ij*.5so_P홐j m{w+u=1Ty0conRze#i9F0qFGs_S;PiXLCbb@ 1|XC,EԞa G`j|ipriÀdu{`l뽋%hgsma)z/YKu6>h́ǻ9,8/X`5qbߪ/b|tsmd| I|]eSX]@b;VQ~OӓK#mAx9>,BDbA S/'=rCgUԩ.+Gaw#*|B)J p#P1(T?hKFZ+*ZD%-?v# EDlj*n9J}|DN\Fu93ӤRH.t֨ TpAK8lۉ@@Y)8 6$J\tC$W T*vv[3$Xi{UexvζP|1imxR0d&zJ9\ޣ;$ʖ%/<5ۧ|yd;J}u+B>ZWg\V#f1 $dX}W_Xe.;hʦl'g#W NxIJ,#vV"ܐs@GhNuv2U<;=\}Z&SJetN r`: 6瘠M`,k{3S7S18:J%kbɤ5#) 'PW_&=^{5'R1W-zܶf1UgL!^gmyYfRJf58;\-$ ^mv~.L&\%@Blo dTQR\5-lTg1n+Skɡ‡p.'׶ȟL:F^p/՞s=Rbq[^Jodf±yqv|p[%=uk*=Sr\bE5TfѬD1i +)6-ͤIZ1BFuYSj6l8s/1Nk s(4v@ ` XsI;+i\y_ӱ7J/6l9ԟ2+P:U<){j{6*Cg{CpA>r,&b*67C&W`MC@r=HIufذ>S _/VDͿX18F -V,'%|M~F]F;qcTe>(>#K$[QN(Tʄ`Emȼt?DT"KR H^&8D]/s6a\eLS_&t( ;ӥp[YL]<&5 )UӺ|k>&,Pop+O4{T >HiP+Ns z¨K8ڧ4Ǧ*U j80wN R5#$Һ)RTؿq}s5Y F U-#g|zUZֆN '}Z).{GJ W +EDMԬͧMuf8CTw+9G[$' aA/9&]h~2oM!g{%pr;\χdž[$dSyL,<  ~54z70=i*9W)6?x||甅Θ'Nw$y?V!( >_=#9PCTYhe?T33z_‘^f}v̒sZgE-vl"Ry6w$wH2 ɦj"&T1/'y0]CK\v"bYjá>{s+ݛ#S':>ϓLea*T2n&+vbay#^RVY aB2k;5ʎM~nҝ%r7Y_ vmikeUǷ5l/Rrp9čA͠ui'Zl@4*@N *rvzD׷ö́^%*MP{Ч\o{YGY (@'B&c>=CsiՙbGTaAWgP Z'0{uyͿwjƪB@Њ/:6;\ZbV͢y[kZa<,m T f <]]!샐A@?~8ʬIQ}_ ^H:h%`# Zt-^!׮ },6ܮNʟ3ӱ=a ^ZmZ6fbTvbҢ$d|b8H2 [~(%: iJ4dE,V{r5-{Dz'۫ibDk=V{PF+QgO !g#\-`*8nv4p\ׂ _hAkf$NRF:3 N8KK[cfMP"slb]pTثnN #Wɑ@ǟhb.1/+ ~C}lu8CGqA(4C tN8?FQe W ;*W6Š pL{ه(Q\|ĭGhnIL2πo+1U9{]OsDbMfGϴeR9ގ v*M8s`fE .| ExrW0~J=8A5R}N-Ohׯ# .M־MCT*n*eb0cqR%R#[p&3"uXB@kY{@уPzh>yI_D #GEJ/s"ØͷGixQ#@wpCmn9ܗ/ .{+>6\jLO[)9Z`<⬴AR-ɺ*&=C|Gcœ sM[cD Q3OTInP6vZTѨ(tOY9Oѱ|qW LFƵHi:s86lNfץ.K_s7s$G0ttSFgРY]'s { UQc&u3qJ>9X@J\:h-EA C z5\+i5UY)ov88kR"a"yXI@e|4b#x*Xr8VǓ.AqǁuG+F  _'jqٓ74ʱV΢YacC&Tgqs2: -gGF5Ϳ;!sC)]fUYVh9xALLT !d =HCu nSW0+VHr$x=$ BcXoY>4 9pCtIi8lJ+ l$ y96\M!&W"`X !WкDFIBXOn3+[ 2wt*傚1q22o q @,0N;B;%*o]hS#zkVvb‡a}2DU(U26©- T/dv6TW #p'VΓՂ `Y11CoS .#abLK|ThBʐdM\ !)0q'Zw1HDMKCcQe[Ϟ/?1ʇ5<:;˟Tڰ*.O]:N@Gk) Dn-I|ݦހQ}-QvO0nM=B~msO㡁]Hz&u̘äztl6W=mog@해i ,3 ʐ=|6lF4v `(TL Xm t[ +Bi~3\l# m](+ndL.jLhn 6P/( _gvlviG$M>;^D os͂〠?dy)֎X- o@Xn,hist ݼ]^`3^SpųZ<ʬjý~xBeօa*pgoH仈G̤m[nի^kc:^䎬7xf׼g4 ?h k.h}ۦf髰\{ڬ[72s ;'6k/Vf")7NV@wS@s1aě-z$J5 Ez(iʦp`i9Z@%0ƐJ"f=|yNW j~dnٺΡ1c5qlo* 25`Ķ%H;WԚ@cs?CKxDOh!bV-(sB,r茛4[)}ԮiU>W6"UyqghE#&$84)4HyT󸵊>`d`7J,L6Ȍ ^:2)'UC*,d%7?&N!>fgACWL3 t?%$[hG/yV;!H-fءyֲ(ex͟G](NB*y=sZ?HZK'rzw! aPpAu= #5יy /:OX4 h `;/y]6Ω:7>&s.zqxEK=tv?>uw 5"%T"]ҖCgw{BObI#ݏ+[˄&cja>vV?s!>˅~T*cXBO.0ԪhZ.?q-^-E8OA+S١2Sv/hʊ+֭I-E<[YpGuT jOk%_'GޱN˥ĄĿUNI.h>BRϻp2]Hdy:Hm{ :ѫ|P Q{wxу]ib1ic1#>}!'>~4-Y-$/[ag7PVw) `Hp/봵{Q¼:Nrr9fPI{ܣ+-3Q"fT^K8)JQI?)rd{]B^K".t]UWi?5e#ɪ:'BR6 fx$y1:2ՎsD2 ZǒUu~D'? Ԍa4^MVjLXLvE;|F3- XpxlTT9, ؐlp>@;ԡ0BR~@ezGjK(VeIFyCWd\ltfi_4 a x˵01G,͙2~"ATהF0 B`^3ߠ Xc|[+OSp:6/ݓ}@uȕe-HefЏ?#IlSʤ[]d %U/u:C4bvnZR+ᑼ0"0g(SWȽ"i1ahlTN1:C*+O,l=W"]CxDP[CzO|±J .)&e/Fv@*Qܟ>nZV@r 9o){AsmζKX8ڞXwҒLO?ڎƝv$̺.xhb S1l8xMPO}u&a%]]ӌK_f7 !:]-uD%Z>uͷtÅ4[0J(&K!,m7q:`HCrV;؀`1ݏsltg6T-śPfحx1̌ 9#r|΄)6Џ(y6SIoGUk;^Uǣ<,`mKFտ%\"rJp@\bWp{ho&h9VrC5FL0ddoQ$JҎľEGnm62ȵv=FC:z\c_Tϼͷ#,h%wk4Q8n+"@Ĝ&s  'yN{ŠD3Cv/n'&gDfF79sBp?%mʋS+H"jHߧUPPotH~Fcëɠq Vd瑃&;>S a$F>TXKtn5_grԮnDl!+X %Q'qȂ/`eՁy`֘X)-8jS@E(#?`L_.yn?]l.36O@A{gm`; lek{>7Iu%3,VZ;`{̓}\K{ƫY7r5Uԓ&f/~W5sRFD!8^^{7f,Uս΀-YN1Pbz*lia&ᗓ.&$eHv^ swUj)oY IM,ޜRfB#rg-]9q6A.E7s^q阻>?yt3mDX6äiOo4o$24o}R5,W1+;fwǞZfCWCvRl*4Y\󑀑 󥡂qGki^S F'oΒ{wȀ`%{ǚJ ^edʘ]GH ?i'xD +%m@λ״{l+6pe` i+2}\;ӵ¡wTPSKOb{Oŋ>be)D29r ֵP蕷@Y叞Mony)>(9X2+泆Ot^T*(YU_ y 3Đ#n1\V3343A ,֛+г.]nؘ &~^mі(waօumܨ@]Qg)SiC'8wXf1/ .OPtkGO\M&ے 7KcP.ga!FisJgL&,ދ͖c;r5P$Au'?Tm "0E6F,ĸc) %ѡ_w2 [VDt*Íí=|[P/܇Jt H~Mb/|l캜4m%e24 62NBqXji1 oK AaCwMҌ.-!\fyExÚZKdז EB ⌮})>̿W^ F&Ȕ.kL2./]= DSIT_n)"Rx嚊';5 wbKԧ71^*"g/&.,&?\˲sѕAhK!jkLe㱨eH Pac=VդsɡwdUʽpkT_î[?rZHԈ5Hk\CV[|dPN &wyU S֦C ƏIXL(}EDHyLa&h VyBΧšOLR0A  |3+L% IEoNjZ[,:W1'Ul],I(>̳TJf<\Di\\=$>n[y5AJ" қE@y2F5~8_-2D7!:<|t }]B῝\UpfJ$dO!+z;Xyd$ILW#cX@4n SXx(+uXKe+Hi5Տ,)oR7}!m,ι;$mO6$5ǵyЗc\|X;Ľ:prInȮDuy2NU(w,'_8{Z3.ڮ xRi.a:ykuf:M hwdۺin*]#/>Y%vQs (>sHS?pc0s 돔v^GMn3̗:`z< IĦ²IMRbݒApeؔK>fo@uZg# ^.>~+HԂݦ-Љ2.Yez_\$G)%sGUsq cU˜eI&+D&R~xk:N)@m|٣ CW+J7u cB "p#u-{f}:vjK\0#!+Iv8HFmHC^L/RH[/t@pW'a9VYmr^놼FYVV λ0qX^ֱg8I Ex1W-#A6Dy!DYv2ZIp ;$y BAOaV& 5qbѺB'MQrXZ_~o]sKOp>˜܏.~;G{nٻ{Y ; _%8oi`sbs*@/A9'6)0\.c H2Ҧ[֦V*<. 1(L{d]'HB7wI_kZ@m2>i.xn|+ S0?!!x7 `~{+0)gU}`+I~9йBc١ nj#РJJ:sL|Dj Kx/2RS;;8:p_W>I]pxF(CE-L3w wsFUsv#WAU c=~zڝM%Dsq`^rSkw@ܹXDl#/$G {s4Cl'.yZƅJ}gMZ` q1-9!"&Mv/~~#u?Fz1$e듣e6Rt=#0mC58!y9[hzt fɂ\Ha&6I1T":>z-Y M!xN8k|D?Yr YpŖɣ˶c:;@z*yѬk6m1^i oEkQo\Wfx\+[RG9/Mhᾎ(ǘG h2 Sgd*BcEo)4ֈq=^vwL5D9Pk]uBҕ1*C>VAqW6}D>|q>!Gц$|FƱEybX.ͲpT3zezBChZm ^@*% އ JT*@Q h>>xΊZۮ17G$n5̩O0{9?KВ{C㮊\p mB6M޻`75#wwb6eQ^/ ꍾo&Z~DAϳɹ )ru${\5ð2,0jDʃY*3CG~b"ɿVϟfhD aͬm<$ScBӑ`mڋcd_Mp!1T/*sS'Z%=:OJ$X<#kmi{hT,:31r4ٯ$:u> (=^v)[(P?;}v & QоFax g3aRϮOWWgۖ)=d$/%Ǝ3k8mOWĞ/ŁL&s(P`OKF 'XyukQ./C̘sͣap V!f0LoB榣>:Rf2|<({ozA@*~\|Q% kUzCI xWfǫHcސj[h? dp+ Ƽ;L_%J&1q-V[+r[[+؝][\ `D-vZ5c?N#RR|tJ})YQ"N]˻YZt<ڃI;a+jic0z&&N"vVK"+Ìr~; !qߌ4/-gR@T $nۀ_8Q7 10QsJe*eǦ'B}#>!akLSLrU{ޑD[x}kO?[3)tr5RIYt\kEy#}Lo`_'Yտ }3{P~ U|K͝yxa*ň]esX?%D@-N̊ b5/f + ByǢDHX}~Ÿ;)qnHdR3v7LL5 yN+.ՋIpqgmЍ~3u 8+E .B.W-! f'qfd2 2ᄓ BzXmU6㳙s6[PEw9wtTFgכgZ*ٗb wfvk^Đ3lwt/-O½p:׈Q8h ˵r8 DKAu,U>Dw\>'eG{YY#ڐOտD }u꡸ @r4, q阿a<]wMAg!mT|XRyAU !!{<0Ӿxv} 8]о3gIpx;h|'87p;HظzYH_5#[8eFb@4 xr7:錌5Kā\ؖā61…Zm { ^;XrXT1q% "h4 [$#K~>yfؐՍ Bsmo3hM:i;iV#)24Q!QՕ|gOM)-B &6E Q  #] B 1zpaqfranz-62.2/AUTOTEST/sha256.zpaq000066400000000000000000004650371477324740300166660ustar00rootroot000000000000007kSt1ӌ(zPQjDC20220920104036c00000000018 jDC z]m~oHJ7kSt1ӌ(zPQ         hXrEߏA/ _Fp?_4_JF;p_4_4_JF; p; p; p; p; p; p; ;p_ Fp_ 4Bfw)ߗ(@Mj6T.J?= mNDx#mU~dGZMx]^ R]+v;89 !=S_`V_Ɯ}k 'SuUշ٢wl4^ ᔽPSp@eC,ú7˯Ru+|čNx8$ܷ47AQIlnI̶ySEn|- ;)Yk'&-GG4hBLILE@@=XQyU_I؝ϤJ>גgB2@ʰI{QI[P[;H$xNm@|Ͽ05˵,R}F*$ڦ%fԭV86K(YZ P\pAu!ڴ8̼꼿ՈٮY]^S;c_f'tqRo$)`Bh[`(k,BRpy&^Ys =[~DŽrՅmވM@-}3^#8C6S4M#Z2ܬ _rMk<AiVB0s)@ZD(6'-~i`Sڱw@(A71PjUy5BZ[ʲ<3n.uI0#B~Y6uD\ @7|8s#xbRs+Nln23HZ[NZ%pY4@/9^ޜO~Q*~wZ%50Zis/W,\ qwDnЯzjņjOAb.xl(]Zn~ZQ[o2DW~k,A'| ~uTKc@KURN гv:z 3J#ܗ'OaGȖ@1{!kT閾G  M -i<ʲP"O(gٙw󾬁lmiٷc@fō S K?)oẅbdM`">]̇ nrwS5_u+:c] O T5zA e QqeyG$>ٮyeZ (@: &}4Iś2[O^к5Bpz{OcMHGkl؈կO 4zIg}UѪXi{$.%~g\L>Z\6i,òl "(Bw2HB٪>ʛip,&b@c.[/!-8 u$R5N;KAB22p+yo 2$^TnXur8n͋n-BPI"lHC.zz@/a5#J+@~mm@i@|sma׀g L|+&У͋n )ok ,^NBŻ 7BܬE0 ZFc3l=5Ăߧ1#[Ij n<]?< 橈۬Z9UƱ|FoM[YZ/ֱ+JSُky,w+dsb@ZKv;b{G?ANNAPH9hn\OsBo^HFUkmkF*7䰉(@s^Cmf\QIS1%P NTJj=q,^u'Ym GugWAxk(?WY3^!UFoh;R_UFy{ޅN p6%|yYg+ q(ha&?%5 :l6l=X,½j7*Ǟ~;N 5KᕦaF8Vjw\2Ű!$\ԳN^6T],4@ڻ]2ʵ]ڝHci\p-<<%-REOqGd_cev0)'K\cWQQ0"v22 m0NWL >ɀcF_W 'HI0馉_dad%!iG& 5O{^N06JO"Z)5|Dy\o yIKi͛,0[zek9cAΞNaC9=L+cGƵ9#ޟK2`N)^#/&u\VȔa!?ѢeEjΞi]}Ǫeabmri*=0AOn'XUKzŝ6R+[004A:g? bAtCqPtxH/Cٯ_9HL䶜۳~aO6*.mn:UfzkvF:I_ y<6Եځxя-cm\eĸ͏jSߠd AK7dݢH:?`e]k5J(C֙pL~}O +Ђ@![ۥKM,r΃3;g R-W9 lj8L`{*B?dy`>UЮN;KѦް]xKܡco d(_MedY+=/0ȧ)Sk'>^Iv!m?%ծrm 3qk^D*.nĺ36\ݶZlFvg-'l8̑JotECk{8JG1rN{Q)'%r9Ҡ4s9-Qv@Axw|X-_B=*ˉQ~/ƙS5ǥT,g D 憎~ i -LԔɦari^I1^ߘZPZsHjAk,HzV1%ew^mDk+]4 :uMd\H'XCtdru5%emVۉ0<@_)!>n&x̢n 8Gl1d} 5pJع 'e6Ef\(@է{9~B+JޓztMG 0 UǢmTBBtœ+ҥB]Z>-7cX}}E$n5uAqw:xD$:IgMyCqm0␟TAˍ@<>gN)X)WubUߌ]8IT7x{'cV=$W?6mV(Mi'c` `jO(@Xg+t bؽ*Li΀|1NBGZK  +2-,Q#:JzUk \m.SbOǎмd$mLM ˸&>0pˎaf.D]CoN;S+qU(0rxѹ!Lt{:C[p*ė t6O/:-Gld9O 8!, ח6LKeV$Q/4G^T5J0)hQ}^9Z }McqmyfZͅ>3r´ACrl#5*anŽ/Fʗmzjri;l\LjȹQjȹ؇ЏO7z{j,f Y*z4.x!f;u= (g]do;o4Xv+5LfSZaΑROіr,s qt E'<6A4 8Hhf> Jao]9^/!⴬6JTX ^3 P=s ]b!nVGN⤬òý0FDЦӸn"$_ICΑ!Ϝuшct{n!ŝFg)?A"xQs-<S|~1hQ\6%'GG7`$4g^cxfMk9L 0z,SYn\CNs&l`ѫD\a#20P`Lj4p pHG],S" }CaK[h|96׏&dz߄˝ׄ-`\ľ'%ϥ6VP͡{2dZ't)":O 5>(@xָ?CWP@2,QOVƋDVI1Aif'U $=fkҭXnj^(ID;F=x) NixB+*u=CbIf'y|? NpΜ RxnʇFnk'h۩wQH!pQF#H6"5Ev\GUԿ4W1nƞ_۞Ɓ9xXf#r-"Y.TL AfA 91gl:|J}-ҡkض Nۥp*s[Wmc's!տvyVfH4,p8}6h鮈5pq7oDjwo*2,B|-n`}k`ȬJkR.2';Rd Swp%b>UtNIJR45ҜvxYg2&@B \x3KɏHg]>zyxT^|NxpDhגXܗz{-NT"_ F8C%h) 7M hs&0sk\& X= ndžSv-k~E!rCLVЂ̳M9 5jNnAFL%Ksfegǧ u@F'xSPfI`"Qۀ{Ԗ{.d *4R 5pTm,k%xJI:{!Y$OyH*;lwE6k-ty($3V]<<T-xܬoAjc)R}ga(B#pl5wq(C4zAJ?ݘrdи۬VUb' :b3;v7i􈙭ٵPh`]P(.b]\6ߡ8e;jZ7of46rݎ2%`\ّPc\ ?}qmNG`a}W7AVëT==Ym,_w$ϛ,Oěz(L@tFD 7Y#ddrߏ/S6O4.+̀zgf(VRK#5M7 w3H$Ա||Ny1YH0@5\p!_KU*ly[Ҟ|Lz?;!ʾ$˷L]T%Vw-dOӁ7 㗑T 1`h̞_OKJ=޴4 uR{-H2C$(LOTmIʕ&T\Y3RdaE=l9F jUD]Gg7M-tL]C6L2v빠)~S;2KW+N \3e P\!bNfAcqE8[ӱ xfX[v2oPUKiЪ\R_ؙB*[)҈otqS FW??"PoU0a/67R]r># )3Yn2>JeeR,ԉZBvVA=18XAoH]Uh玠0S3; {02ҟCbL2seA*t47TxqUp.ʊV]x1Հ2%@8 3Ӝq-ugl㨵O6 %c6B43$ !Z~sF}W+z-NnƟ)^7-+Kd1GoǽضV9V-Q a я5Dk{K 5GƇ仅eu"Z7L k8,g'Y\G&C<k'iC:vΌ+n ՒLXROhi|c) KcB9/U fѲkf4p*h@QX5ߛ A!*Kɔrg-! N*7O%$]˧AXVji4>V)Ki RlrIޜxk/d8hyԧ2|6WɁADC!E4Sc (u*R2'QUc\Q7ɒg.xeܕI/ʍҁp NPOo>6VOcWf9ȗpwk#JsSۀXҝ9EFuS,,ZЛ&9a0ή%փNdiʝD9kl0*vMS46= –}/ _-.XrX@fyؾ4q>LJ-c%2BOMǺw2؍G\ '9ŗ (*Q+nn= ]aivVy%94yb&1Y3oNVbm&Tv9Y+G  ع>rS&YBY+ʁzP6ȓкly[aH?vxRMoQ*Mnɡ:I(~S&"q&tyO-2ٰmd+$p tY_ MPEZB)$,G󚱘ռ0|,#bRR96̀)bܺ;VxE};+JO tQÆxPQWk;lv׈K'Xq!┉$^ 1׏}G*k^*RW%Y?46"$+x.O!YI'߉]H[85gXs N$ aoA܇~K]`9 cAPB+M b=ڑs|8XD7QZ"Lks|p^`Xvg B%>ڈՔ:%W3*0GIYbMDHm+-i i3b\հ6n[RZ 4 ,Es j MĀА.wOrΕ_̅c[<kǣTR?Oji\PoW -LN> Ij'4+h L`ZC;~r 1_2e"M C)KInI1| _iqUe7,dl+97d63DY&rew[H\sғEYpeXd)(n8ۋaY90YsLvQA٠n{T볁(d$pv-(6s `T2AM峽*vȷP8Mu+ޠ)󦿗"8+Rg 9-3{ j#He{˔^ 8|a'X> ~W *`qTH/?o*wJy6Ӝ +Y؈imEIZ8WkJїHPS-:Nɧh/|2AA 0{1?{<9͉DCf\Pnys%)iX28']Q)s?镖m*>7&G:/%uhwNu݁8x"\m <#dwFVniRBfvތO|Wi|K}~DQp$T>|ТQo'&e?L_6ںI_#F~&|n`9 k<EPn> vg)bX6$ YzLTu(l~hx89T29CLi/ \D5]0âI 8I"Ӹ?\ii=~/!/b x=E3._; ;šKnѾj|u+{gW1eF(w,la{գj3BY ag] /A^ٞy:gKruMˌ0'DWh'-L."D&$,"x gKOZӵU1⢉IV58'2W!TLsڻ.l1UONbk{;X) wȻϸlxo=däo5IAN ȁ2fp!C6VB/q&4EG? jSfXM;ym\IZ".R:r#֨9b]2,$kqmcAZD%UmswaІ?y†҄ղmyP@@ctM=Rv$9AV/GDgSzB3 s/$)BOD "*Y[^q/;trfoRDdꙕvUtllҠL.ZRB [u&WoBy)έ 07皮B 2+:#|P[}p_^qzw]tWO42XM!MO͝2ȭ3 ,drL,sx؛>;Gڨ˦kQzw\.H`yO2x)M#%~ڗ'.kJݏC} rMi@Dn5m0PLp^K=h (aRJo!Mz+(r7 ?cPi"POŷ(ohL?gO.||讄; ò+Δm`yJK\ =#ljtlvW? pָ"-W}0c*1]o[Bq$g*T&`?^hIբS>&ȎbRbX7:j[PQ #Is@ _Г'և6MO5TLmf&| LӉozu{(Bb#ﰙeerrʯ!NTM&$ғ`Lߧ=@?0U6Qna^R @_0Wl afQsg>̈g.%1 q[>o,` on Eډ?>@! 2H`y_\W8ScBu,^|g #͖Jm:{V1N#ͧܫCpϢ&AͅwIL_^RAL nmy~;%6X \1SA"G HD*՞5 h\kWu^MFБD]U;9!+ҕJ0˱ك[X٪|f$%M5$a9FXV>q--YjcژzZT!= j@՛ Z%l0\!F ÚuIxB{*'+bg^0.:8CX mja,Y8ii&KlD4ؚOS/rcQO*qa3Sc@Oi!2b`ziaAFY Gi|9SPA3ϩ#^]uj ds3u,&dҳ"h'$Ҧ( 4 s|ܜdF&}>j#z6I?|yBnO_xZO]#^h~s#w ŇiWr:2!ew"edZ?SHey@67i KwCg$sL^R_\ho\RX-zo{ elԳb1G O;pB}8T M#B:B ijzl7_PPDa 0{w@ƹ?eZ-j 4N)Jez/'/u'c+;Z~oh6@ ۦ+LYr-0bK} [5c9޹33X@u{iU5|wlhKz_9w\7Mz6^h6(ܮIqF_4^6|:5z$hyznءtmߨY9?q-]SI3bj͍!ؠюhdۀy8M2oU.}rP>s||Z$epNׄ*29}wYGcQN ,bP+L-7T+fUy\bf9隽FrIT5o!px‹fzo=pر>9399[}S7 k9%ԗP2B>) }`x$G Qk](9Շ d.t'@㏸cF17BHJk\($*2 lfxڪLo*`yjd۹i( u?fuN.Ws Gbu@+M7 ;2Wٹ0X3z)Q}VGwﱶ~s>k"딙"P~ټPrN"ȩLGv)}LCHg>ԙR٬_}ٙ4F%e*{2#;zkY7 {=7aI"a{.nuL σNNJ%l42TT)pT?o$*s?v_ph/k=^gp!|{潩LS4v /\K*-<1d}ە讝շe2g Nɭ|HSa0Yp!5odq۹Ckf@/Vړ?bg-(|MEяO-+#z%^OEB ?06!&NdIB9]tL#sr}_b%*9-K±zX51GlB!⍪jQUw%LrwF! \`ቜ%6hMb,wo<WUv)brpRC_'~AJJ d.xs4*l_KBP&!e ~kB 9;>yKꗵ:N~ߤ%8Pfu@Xsy\v/?NK4 X4q-{Zb+RK$9)+Sd|ZxK~wPzr890.Ā68%vLh5w(SAY.HJF9(r0PZ+)5B Fq)3IH\|J!!^=#`L/Y>u0C{jRMЇ)^Xv9ŝgɬεj5g9`ڶH:ddW"t5s?c﷐*h{9TUf>tY% Kp~"cUemϴ /ĵC^-t:@C(CM`[~Cn1KzF\sh94/g)A C CX`)d;Hgd|541  '. G_}EyԁUd5h ıOlF1wS+| E`!#ٻ##Yjc~ j\b x,A&I<@gT,tFN . `A)XCՃ]N73x((`{~Q[+P@ZFL_ʐUHnxICE)ˮq/Ovj '2vcKj3Ĺ̼p>;QkL02 J$ef^;Ҕܱzgb3EEcnrtbp#+ӓE4/,`Aҳ3ʸ>z>Esj/|4. hۊ0bv`i1F{ž^H+g>3| qiIeNvixXaTĪR?q~SR!$Wٓ C=v} D*eAջGVQ1/Z[@)IM _̞TxC yi`|OMT7 .HeK,DB !9"]7RHPi*3G2\H-QWm&m^pȉ bTDvJh C9.* |c7%0^F,2fޏ+BXmC-rzǁR{9H.?1[❜';@'*V2;=iؘf׉B:1#ɡ1&ŨX rTg *M]32̉i2Hg&L*8SYU,yYOxE:FDq$mN^__*@B;.*If;4MXhY}@ܜAo(MQ1/q3sL)&,*dܺ75 rAG[`2x$,g >"S*v-t1x??+bU2Q\G [1Bꭋ +.ۊf/WpZ 1:;eŬs?_,1!fcӨȂ% +cMg@; ߋcdˇt:2 [VCTQo/7]hBz`.M8pBNbVh^]$ƨ|c@mƱXu((Fȷ;2ؼC\ѓHi DVc8|[Kh@zks\-;MI; #"ʖAMʵ¯o'rO`T[n?P|~mvT<25O%%xDvMIzM Ox=p_Õ9`+P`;lbw3gvoM&j/(wԓ=$"SFNTMC,"@fYvP,5PS{9š&3%pLPEl2"=dTAq*X=[!SЖ}EӯTC@VF-4QSe;W%/6Ÿ~.N*Y!*[icx2 :.V=pAv]RݤaFw ۼz̥ uoxebĽ} m5C%aSOhg(YjHYM$ xdbK嘺QW2,ͷgzxm^aZPyB`=l$irbz@М{2bV{gJ '57J eO,~%]ְtΕT z۠{$  Q֝]w Hn \{U){{[4z C4'Q# Qlj]  $BqEhAEjVn䡅ҴEaؓ1R(x"FZ)UaHt!V?}jYF9)5ײ :2EZZ1R΁sC i|(b0.ia^Hzm>+wx"?<)%܅@~ Ky+d@W?||@sjYٞ;ݠ,L6҆I̞jXN Uh*cM){z8`'O%RAӇK9Yt$O IwMh1<{0Lme@bHj5oHp>R2 3Xت$QI|mQoh@]&ׯ"H=9UŲ^2+, k&5G/j Ujҏ0ABڭj 2\KLWp<1/WNՅHB^JuaERӅH|c9êBA3<WDegEOxn%t(p=j"[́">(q`GHCt؜V{ܤN_ay T\a0D3pF4wXp<5fa9g6T} 7P9)k4D^}z e85V1=Ch5IAH{!h*1"+-'wÜr͒i;i RcJE\D@d\>\-US0O uV%m_ IJ<'-I޸ïu(-wGT.F / wkq0ۓv罼? æ_%r1ہYL<%XՍi[JpL1\RӄX)qڙ "LR8//D 8-kD:UUSN>Y2f'$VK՝x=*nhEcf=6*Ghx!*_ dki'F YC=H+)eF?'2NGB:'@MNj2Bz"l@/˪X\rR_r4z˚*Kxy3w YMs.i/E. Kmَ9p~=迿IY>;p &)M9A[%@kVJiƂB7,iWE2]? ͂!gg%?YGJˇu2'K{J4| , dS ͜)?]cJ̨ |fWh"/U~|Wi?A-¹ܵb1zoQW#7*}'V;ۗxzXO0g%S灢SU#wݼFH<=\;&?`lo٧G5f^1|(h1O#ot%7aQmh8uXӊVJziVأϡ 20t5N16:&ɝ7xϻ2,1K&aF{qX]`k qSk'RedOM/9FJ_0@ 'DZGdLS"ZP(ǫ}J*rYzMfT&,bz[`iA]Uϗmu+xvSfo% iG" #JhN)+T IX'y1$|?YxW} *p LqkCdԌU *mv34͟ݏmq)iN]H?f瑬%p",3M8fNmK˟F{hb1A YT(/؛;p;SbjumaQ *:{[7()+Kn <0CY)$[н[R;ȉB;s]?XiFB0 8ם$ӂLAM_G C v۫ 5=a )yK!tD Zj+ۈ8=\M6(hf!Vfߩp5Y1gL`tK~ęX]<z@ 4KVV==[ x&&6xI~|+;xX4X14^?bw]N M~'q-0iH޻,eݮCUn&0B,_y&96pUHNZK`&d͏4X1{TJǘe࠿B.ݣ,8,IjL t{NJ z̐Gاa V9wi D4>&EXRIy9IO9abybZv zqmwu7n5.ӂe.q%.یM!m AX:62#ӶN5 4̩>`pjDdaJ X򥼂Ծ̃A/rЕ}pi8A䇡_yqiȥ sc\ڇɗ99Bc(^,bSe^*qhSM)\qmhMe{Q- ]qW&/Ċ)o=ğӱyӏ+Ri[LeoW$=>M!4M?5U\q֐h%0D6 y[{8cx;ΛQ6D 1Yknec'.`NhB^Wms:h31\X\I'[G#-B J(GJrhx{)sލQC7Ξ{nәT  ~,8a:?P^ө"7Q;pjb =Nm+~[mީ=N0**XkcufjpD)`L :z[06=17`\ʼ.9Ô'RC h+E/Uδ$H[RFa"٠EG6zز] $ O Ie8g‰@]fkћj}ON[8m65B"䘉 tdFZ OnH" ׸PDvEo.B Y ™~"[SY"XfC3CNcI(J|4=Gu\5lSɦGTOceT,6') K1+[ c"T{JC(D_n%:{%=R:˗^]DK2Ҩ g @dZ";{">pew{ gl1Z0TP@?b?Mb}U-| ӡNymtm_&=%_ ~\莻^'܄YBK9"$2BdJp3XB%7C{cAևYnВBN=O_FzhhvcbީP^ mg HL| Uڜ#pݴ =0ߞ7P4+B x9)zu%ٯyRE#_4u)~ ײ i._⹓\u&AF Sq1,3e]tI)i][UOerd6'긒C&E_%Æ v+7vdIr@zL֖l1sϖLO{U(i|3q_aP$j _+-{D|wAOVȣƇtz 1^(xy)֓!Qztl#PYßr^ V?TP #1k]_NjTD[*l f|/i nGM ^8pRϻA`{fX]b*[ݝ^ɄͶ@DNv-Y]'8fI9 [z1l Y[=$**OTحVc<@ T5L{Lu0X(޸+N 8,hһU5AJE#pqۛa1=aV 9VtŬxs4:dB3Ccl/j 5ql+װ0OLLIJ5Xdp$aCU/Fl0>vqY+eD6mHAhBpgJGFB|m~<~L an1~Vn>,˟pd  LXH7He.}TƉX"0 Ķ 䫈FfA}`ۜF:|mBkf֯dL+THZ#o^c?n(䴍hW tCF-ur%=-e PezK.r#t=@'NfrL`MHwջ OYi /$K3 -I C^8ֺfBJBF{LyYrpdhBP`a2,i])\} JL؏k r!Bi]3;)7c="mNib&|hK>5b^H!PP\G=$A gۑ)FedHs%mrEkhNKM-Z ඈEjs(;{vɆT-%vPYmV 탋~L̈:C q7/(HQ AMkrwO]TMbUFr1s8-/lp6 .ftUľ=UA~CC<[W7옶vίM ,c#wJ:rpnIk "vbP 4/=Fdg(⧓t#][&S3ֵ;zM* bhJX ;xh|Wm;qTr j#r.#JAנ$Y\6kQ}@Akg7}e2Yaj(V $R }@>Wv ~5_.DM!DR2^؅O'J*/^1_Z_ LB}dMI,0QLGI&dN\h=*+[ Pֆ qeq{T ]JiҰM/!c5waNoKps{ZE]*},]kd0KMTtz@_}?[Rf?]-2gG(=z΂mO N|AF"+v[JȞe>{ B =n~ٺG6@̘?pezEw?ӷ4F>uRlgy`P9g`:pc@:p* OF1O$C?yX[~F˙NqvٽwZ0Q(AN'TGCպղ񉁲0rvt^`#\`(ʞHQ\}UdZ}.yZe U: rI˄hA[1{o:k96*L:rP衇j$~8`[4lch0y܉'DTor]f tncb̭n@A#n, JIsdwPٖE6&dh>pe*3A7xt4* zh8mYzNЖb'>CʡgcN8*rBÉ-U IOL VYD>:@Qb%ǜe'ϳZ>,j>9 oriPAqy-[$UZ* $1%ˣ26 rHaYoxؘ!B:h9f_q=RNEs*E(tfM; M@8͚V]Mֆ& E'/&}mb<1_@ -A\ >4_8ś̄M@i6g(Ū swg͐8qT]$]==ɏ =ȋK aWxtJ1tK{^IҡoHW@Fzv,vحsśU7@=bEGB\2?O~*u>◉j1Scb97KI >m({>1d5m^~OsUnw\rn^~}|iO:AIKM)pH_$(zLg({cg+c{/WFNry4r,Fkꦭ ֎x99D"p~o4;G=#LvG$pz B6[ LičZ'$P z.A`Ha453-@"1_UƊ9z֨w:;4S;K" Eu+bԭ@sg>X\^|y5:ې6禩Fmݿ64# RiVoEB=+_>gQ6J[ݼP]Prl(N6!Gz (\a M4vF:!5vxRߞV,@6q}05_l &ܖ2 8zZ~'R>tf8YqιQR_ A&@dh($_>7`*s(?Ƙ'*+J8qϚQO$#bNϯmPLɧ/2_R"n#FF|!X ) ݶ35ї4ORwޑHZ?p*9| /MZf4Vd9d*/jZ mC.];U 7`M~A)6hOSHv5k,E^P[utN֌WϏ8O}ܖ61SxDjB`K\x`k$9]lyZs6$n:S2HȺs޿;i}}~4݂.)ejCgQy!3lHkd479!}h ;PDОYo_4#[ ~Vq!Bz֝{bT>{Fey=,%*g8&Z;s,.Jhi؀CGtξ߆I9kЗ |N%3:SxsgO]]9t1D:F1ЁǕijN¹3BgPDfO*șif+-Tg?M>VsJdq?ƴt>d 3 <7\hd;rv瀂/*-9 E}}odSI/ Ǭ&(}BdzHלXw vǓ#è ^|A>f6 PY-]wJ||S+oX- Ŭ+4S_Vf *:jAﯳ;Vp+,~Ɔx5\oE2uK{+}nߖ"5R|E4FWn[/-8ߦ3-0=]^% {'{Hw@*א ^pFS#PsFNׁO1ō 71VDIsWBA(!1zh(O%zi2WD]\̜Kˌ/G7vWhAXGu&'O{RL=(_NҀ~pB=6\u ɻ^0kҦy8֫-r-tl2G7 63@WH+﷤Cx2ʹ\yN/^4{*Cg4lGټIY{#u*d 8S|x? B"ykũu'+Fƒ&Z08Rƺf`c:j=L? m ?g7 64:cM;iԇʿ_ ĵ*&F4YFs θo<-VY_g/v%n¹ b9sv1320ҪFvH؄ 0+Klo5=wK=|U鵦O }=tWs1mǤ BUHZNqòm{̮(z@%μo.t.c?*0E/v c]=E! ML0+fm>Z tSj\K 0=<0Nob{(-Ԩhj:;LS`d%>P|,;=*Tyuig =C*'DV\[25(h]$&OBi'zʘT]&}_TНLk Lfr;Vj6/M5]'"LBNQ8&m2TNSAhfuYoyy]$ F II9/h*ρk\ ^8n+Bb-b`fpfevКle4J?k۪cܗV35A9QFA10L"ib.G'Qq#& #ڗgL4 ޤ}h}T\^Nah^3o\Iϑsr("@k@frP+M WWwTdM55e'j۞t<"$\`ŞV:}r uC#]Jۦ`EENI;!9,*3s^[/;<'^G.7T3BUϐљ&3<\ Xn(F&YsOn# o8{ۓ8:\˞[O{` UȗOl K2QY%fN*~\2U;mH(\xw!+$6$]=6P1D,8eP9mZb,P3V 8aO HK1)i|\4HIW57 PD,^&nVO=BmO{c(UN!,9)Y,l|Kn0xDt=bȺP"#@yӻYp54Z *a,h|GKbS)S3vՁdLQ1"I_(\!HU*Z]I(m_pa9}Ӌ 'N![P4V#7sQ)5{NyNkn<r^PV+/ôş,w>3 Sh{Wv%E!K3Yad#IO[[>K qveK'V34OLc`麞]FȿETk=J̹ڲr`LGd1ân8ݱ%dBh8RTJgIi3o*h@#dzB!铝l)21 w-/mt4"4 FkXbXa\BMHѕ% ݌4F/aBjB֌s  Q$V2F`;~ꇯ.2{VpTC `lDg1v+p/1?ZZhK~𓕇Eݝ0yԖ C|l7J(^4lCq; Xm"T!DLR^S˿U5끒ur5.-D#g [6df/N&FׯH]Jm? WuLOc8TgM'UIx;lQq p/vXυ6vMXo`py8@ѐ33H7i&x1Y3*.ucL+0s~ AP9_۾1sbO Tc3_70fͻ fM§ptb] V aa#@O#>aKAz{y#U qrrD|`<2#rz.n_{F<~7Y7\szS?6=U2s}v47Mkf[dkeERuR]L|~Y9Snt΁"g-}X]qS5 dA h-}NqI/vZe/ϋ<_ `CMqd0O eJ)ehu J|tb\ @B]p> ݅b#UJ?Պ |CvWtAY%t?c 5u'S!8YЁf[2|9G+2pn:awl/%V.@*O MeseuMJ>cZfL՘XƷV' \zh OA =瑩V&2:o Fd)^H9+Z9eBau XWO<N&$|E>e@),BZf+^+ z(nB/!AhNFԙt?4S! yϟcti+u? srGEL.({)m\.#S]g&A(kk,CYkAE ;KNauMpCZJujZ4RH8=ىBi㻇\{?} ZbӃ7ۑ8;z F44bVǏWE#ߦhF1ՄqKnBluN%r:=F* 8%,z2?c&8GZ2.Z }eNcVPf?Vċ<:-ƃ.ʫDZAxrVعEhSvT}ﺓݘE 3P t o|tdh胐h ܽbVz9}mlj1lj-a7'r_ ZbDYipa[swF8D!wVΨymua_,90bG:K AA vZv33T ]?7/`UlYUeG<"fl; }O G? ~`G ?v"p8b@K}n~47!<:ś?`DVZ>`CHPɮ%!]'idZHl.ɑӧZ :l(aɤzlb{oxΩ(%._xlc pS!vttF~:;!+l$j˂T}uņHhxqrn~%\H 6 +/-okYq~I\o!l8{YV1O[|'avLadBpWcιD4 ϫՊA s*<9_\ ACX2\?W3ўA'9~45|N v$;D@R|씶=ŵ[ IAxxm-fJH'H3 #YH9ۍ~^P»7KTJFlVY&jqvk;o(]OU *KŇ-}ӃfW+Wx&[5ى[|֟s <>8fl[;XΡnD5YX)b=+XY\k!zo )??0C{êieW7߰ߋOːC%[plG5I0}eÏ\5*`Pݯ#UfEƊڗLͶeA3PE1Suy{@9DL틖AU@:3n$ܒdAvP-fzIʲ֛S^} M\I_nbb:,jT˱ϑaX7GuqZ0YmxS+ +5l Ak\;5b k]iuZ߭o:0&Wy`mW1&΅>h4|A])3;󘥆ċNS \הU[ްdW2yZ fY7h)Q\JvPe>"Q(xTl@ Q`Bn{tuHy󩋟 b7mDB=BO&<%׭EW[㘭W}Ӂkse'IORdsޝ7rwjSMpۉ( p? }0f*IRks䓤PBk ǸW_@B#|A8~QdsƮhYc.̌3SEk ~Lf4 eCQ@y.tRy-4$AU%*.StL J𦻯|V4ևҕL #HJWc G$(Njl\ *?h%?:L1ZbbZԉ/?X6?V *Ns(E:Eqnd}5rEu+93ơy!Uo ; P L}{7s  Sϧ"<]-dNu :LuO"0@StB5c.%&ܞL$-EoP-].uќԢo{˽@ڳ#HڠQ1]t뻞N׺ M^QExI5s?.pq"d~(S.i`Vz$o BѕC{Nuֆ}aY`|~LQt=Ak Rو mdsF`"1ښ-f\Ix(?gvψeZc怍{b-_fshCXY _]ETC{`V9sԃ_(\Y+G9xΘUSYpf R;l1 X•ZMEjf5JS^ yEf?(D֍<7]#rb!Eak9w,mȑKB DmoR[9hj`!Yg6 zjċ|43ۥj &jYȊҊ%I oELCPc !O7[)ߍJނc}S?5ME6ƒ}iq չ.b |#%iV8琓V0Q#fXȴM%O ̷Ȍ}:~9{9jq҉~DMܛ5"6ӢrĞa %1#Z4S?AJǩˡuL-쥵T1yCIHRX%ӛU26yauJ%ίv[gqjP\@iv=g6oA:Xus~پTKi Ը`r.<ù[%d ҡKEuVq݊$>s+si,k㥏q!y]+!v2I-D'2RD>⨻[ D85rdRpt"5~ތkeBG'A K/=TTrQ,EgixUV lڊjUb6!CS4Ԍ2TQ#&^eF 7DxB-:ȷ2n>Ҧy~ig`TWG̠ ,[ʮՕeO k}K0_hO@]1h4Zԏq'/nL ~BZ5@2Jabcb#bcA?)~q@FY Fέu% u2ZاL>ռ Gm Oق^qퟛ/sA٠`˅@FaHZǨjcƼ:a;$推 t$hDžٗMd2:>J0k@H7ԡ#vMn,'">ŇNz~QD]G(ҭ|bMh(C%nAm4Jga`BB)s d髈^HD"ؼpZls!N’6,c rA0l|dY>/w3^zr٦o^dk7S2M`vL7q$MWCufjTEe[>Q+PۘSf i9͕4E.B{sis1ҁbvTLvIﳰZKõJz߇˟ *:rS3S'o,~8O)E}ių28+1SaX'!?*#aVQi k|$*.rb^gg>N_?; QXyCߘbwJTis[Gn{{~8 L!-D_& 95>@j^>b/ TUd D1"xڽ8 j=-(. nZBdB ?2amfyU;Qx E+ۡwad=nJ΁&ĸDф!^@RVKHtߌg{ P8bȜs9sAkg#H ]7e&($*I>Vʛ; 9W". }w#K+~4 'q\ZQWg=4w rKvi,U@^aYVj/O>BnBfuCxQT3DN?\P{B010mO<ߠύxi]So;'"Nm9c5JQqѝ:tL[qcpO'G(QQrL xԳoY9Ȱkl/ bDz zkH i,8w`jiWA66i\7Aq@Hf L+BQ}*"މնN-);_~߻D±>~0ÌҫE. 6źN$Z-OF 8)O9Tɧ;Z]k<(pCM"'qq{h,l.9ʭT;u?#YO>tp HaJ g߽aV]@;$NUy;MS:yR޾ke4lG`މDBxxO90y.A]88Bv ` aL]leu He*58YYUNrFF4b" ƿ9P>Lrb ڋA>+1Mb}I?N͗|? Hkb (P0.l%· ')=6SHigk4L6wcǛ%^)Z0qЊ{vBmږ`RdȰ3G;~D|K[kGw`/R+M/,(n%gyfO3^;vxȴ uF3l〶N(,%w֢ӹ"A@qW0voy0ſ+bedO䳝8N#au]6č3 SvtK.g&dX}Na' ^>jD ]W& nݮQĀT))UB&ˍݾf; wd9fO%<1}!uMNhN:Ft?+Ц2XalY^HD|y 6,Ȁؐ6UWZ.`J)k 9L%F)LO~TyڪdmJu螥m!C'-RȫJCɄa֯R&o+ lE~DѶV;8O99Gv-JN&Dd^xBl?EO+Dj^2fGU`&ۘje˄Ёu;{`P1خsj|™ f6En^/j'{U8Ӧ]1E,mZ'1A& *Xqn 6d Vҁpwi"PC ]%aa ui\u&Z6P; an*.>D?eUkhώU^yφfSQ\O[}G4)0;c׻s$SF1=WfPBg󴫬v+`ʂD/]v&&r" xfӭƑg_%YqU p7<ͬ;j$Cmfk$G7`Ֆs٫]7sG(њ\ykpAgH,)dupzPo(8k'b2/K. RCD#B{(:9c;`4ü4˓n#=< JZr ̣7Eu0f`,,DX9$cB*M믣џN)"{ɫ* V vI!DC&.iqi0*oe 9LNpkZ%5@U?>QCnR֦O$B.V4(g w/At5QqUQ:`MΑ.VGjKckRG^`'ШȜp+,f{4  k&G vk%YFRc BF펼ϞCڟSYCzgaP_Uv޾JbJ "빷ZǺXju K0OO[ܴ'J53& ,qKV[)MΠm"mum@/ ayk5(J/C%āE0I TH0XN0.#CE*z9&oFF{&GAYw(j0MNe8O9$Jy[#RKB~Tjf2($>GWQ1#.A3){=aur{–a׎˕<Ġ|A_uCnD6`!6Q 6^w|7W |R:̟,$O(?VP]jǪ@'R+۴x׼8?~؏ ) 0ɆQ^tk}`ũ.}'Of$CTYt.[SȎ2NH[,ݎb6" RpEuAj3Ur%Uxxq}I^#T|u lb`#ֳ e/'*]E2#mYs' As_v|UeE&ԧ;H 'F%Ia  X9>JR=i.DӇ{?eVﭡ\/F7"J ^x٫ A^K=2fD;$rX^ J7J`wUB1"x33}S^UQ=w_z+?A2+p8MCj%ōB-\Dްۦqv-pq{Q ]p89e┵}6_SUmђRH [JɓulxBe(X#i\긡^,W"`bpLiug9lAn܄W&0&qǂ`g#Z1̴Rգ~Wjg3[Vsb>+ɽp2IJ<#L˗#цed0LG!Gdè Jo)c$˺( WPI7-n9g{ՋN.$*Vo+nz݌2\a`EQqǍ=QKot\^/@6:xH-#ÑYrn GDObu)oKUXD]ݚ4SY@zM`Q,O-P֥V"nI&Cl҂2cPC|2ې_""nz"B-FNźwCӍ [7yCC/*n@8eM]O4,O:|.aVD%pg2% vSl=FhÇer*v:4Xz(>r$|05h^n:۹W 5]}sa8V8&/ôAcrԱkv֛Ȋk6Kz"~zK/*஌ܘڟ7Gn?@&;)ǛYPa+T? [lɦ*Holo_%z]ppU@Ku @%bOKOH 62.dd2,1[,?a^pLq zҧP'[ʼ.+JR0~ 2`Zv~D]8T O$k Tha*y;UcXl,ᵡY"l! t{ 5Ŗ?PG0qAFf܆]8PшIUCKpN0K~1L݄\ex+'85^^Ԝz@Ɣ8 3LAqN~.HLꪻiJ3|a=XOfB :$&{$lT\$|@'~վB c'y7\3 n ? Tkcx80Ǵ84xHρ]шAyŲ{9 an]w`,»c)%[w*T_^`eäOJ|ag1 O(@*@\%Dw3 .<vxuT[^uEP&XVU~ؕi_􏝍ˌ#HV;2jh5닆k?<:(8e.W[ߚi]t B6"瘌ET^k!(ZjE4*^h;EÎv<"T-v)cDZCƼ8$SFӲg0j9h&p@Oe#G;^[qQ*%`̍]OG`Iuا 3ZPϼY M}Ѽ.$tj[d[ȊlKYS\9a~cAG1 28ѽrHQƔJ8WiigQ`9"NXmrhL8JXOl-|识;-m2FtC+GV8yZNAe:-蝮R}δs~& q\׿Y'IM[#V+{Ҝ_Zo:.RݹIʴ{@yFs# ǎ4/`kȺNU|: gѱi]^t Yyԙ̸(qrVP\TNNjr^8x.:c蚱ַ]6u1 K3? i?j ƣ8ޑlH<֋Xgí*:/^/)3mW4V]5SЏhl X'R'P]rbm.l-|펡^ƚI?2"rgY";ЧСmt>tZe˻횆@K0ZQ5q%"i۶NqUB-ݺ? o|j_j".zWLPlOL *}Fp0®yktѣ&7JH/5<2&$m݄e6WS{y$Dxb>#; !=(pT"1:jRR+`١'+z%X&344zoQ߰ `.ġ8 <یrM_Z_}vcPMHNtv bO3^XLfr1>ZUxiucAfQTج f+j^v-!Ium"ц&;턑naK{Q^SՐpth|lk䷵m"^k? {mg@J:*0j@!XbMG6gh-PգU6Gz f-V.# +'5 bW*3„Ô%y ydF.޹H; ˎ6 QYO?qEu~pH4%jQ'jMm\ FކRŸh&fKt=iHpX/uBT?%;P_P'r%Z];-*Z'Ɠ>Qʔ I,9_=MC#̵˭ ?Jq\sJnws;6#\^8@SvlyLbrE2W|]:;J;40F¸ 贁$${2خ"bXsBq- |=KWg%FNVȬh4V(hMmtytJ+/D+yg`oזFkD%`O6rn QuEh&9b@Cf6֋VȾH-JCD9H̽dݚI;J^wi]VѤX܃S6*Gan+6Y=֐M(eA( O9&{us,IUoXyutLc%ֵB\s(vJl{YuqUGڙpXL>gӛu 6tuajڳrDQ}M>Ф[㖓lW*%_ ڴP߹5:Pچ XZ"[]p&QHRvD `s0=j]alwXU8LxyIR5Zol~-7EB h.ݕoW/ dC{Mi6Zj?܂%uFzoMT8Z:|8D1n-M9uY/^}fcUHBP! *e7~K};Lb;DWk;%[S3fFccǼ_9$鯴1DSxjT/xq1deԜjZ\Y>GAV?)^XEkTLjߤcJ'۝!9<6f|î>CL,| >tNV9J)LGrs2FHZl4'/}DC9,):'aHRs;i.=߾G1:g|)pY,6 Z0vSWxߪ#{${``$K>W "jj0@x5+#E1J6>3|4%"82 6}츨-txS$>.aޓL90O"~VM.l) ^Dz-'z.*le@ٙinp,t}Z#eTS1 fLi)$KI ]0\k }wy݁Em}+-q/}TE԰v&ζ@`ئNɟPbD ;5jcM8BAiDZR}vF+HGڴ^~/3 %ES-g PEצGH@ 2w7YA{uJneO{T׌lZ i]gqRshpVF؂#"_(gzAZSi<³R}Xp$}ϫ%CrEmFiQ@-7.O)2oŒs1WdC&+3xI#y-kybwWC:S?2?Cp?"|v,Ÿ{$3LL@pjK&OM;ZE\hG 9]m2E' zHv$9-RaVГj^[_gؚF/e}2 H pW 24BaJ(`p}r `i%ZwH`f8PYC#sdu@Ι8a )*Uӳ'kE:LKvg:iܕ7aX՝mNp%߹@AVyKsJĪ1y$)e؜)ufʲgewwO?\ j< Np3w**i\+,RT@Q0)e\><^i(Do@5( >q & ʺU2!8|XUp'NPce׎u*j#oJ\ui峎Q…Mݭzae CEbdW}?n0Qjt-k)RCߣ4A.%;xocӁYXm, B{kkaPNAl(p7k FVT8%y-PudkkOwK3V #>WF16$J@BV'`iVQUƄ~ Gjh&qXu[N4KDüjȁq铐3ǴLwtpM"^yWJ8y&;-(e?m{όYgͯĹsJh aYoByaP;QU31?5 0QMwZXÿ_bvK\*?t c%/Ko&5cFTe}ߡ#@a[4;5Z#c},##-lcJ5e(e_~?M.%Qrybxl+[po2" R܁mK!3 lQt6b h;hז^hP衱_A?dylӪ_}d>Urq:=⦋^/_2woq@:cwd6j:],DŽ}2a[fSuҖb<O䶆:h3Ї-o,22BNGJY^'fq t Ry`2dΰ5o Eè^GULe]v;yG +g`-j@P }L!mY$v3hb3e F {o ^(>؆]7 ~?*I*xw5¢}7^P}扲Q4gxQC}p k%Zϫ];yEu9s/`{$l!TNybV)73X\T_QǤ5JF*Y>=uN>[T1G2a*qs>` Cr^L*' g$9"r QPcT2]~ۘnu.7 &P%^gd7qP +rˀ<m EPcVµn7xɟh4$OZSi}U%:dGQ? l{s jM~'c7|:Ro/D ߳@ŷhyP_j S^ I5r J Ѿ$ r%FH?fd+FXpk eW yM1vt`p!c sngwɔN7}8fnfqu ×qJx'F/y¸(zw>"T! M썘Tɵ)ȑ/z1h@F3Ƙk6Kq˹/S6{nV gsYBnQۏ,]πGvTx]e(tTb'^xTXb]:S^Uތ^ }$N4 s 26ĬviØ&^Ơ.'CO՚ٔL79=u\'ώn]' Api'rX53qan<{_&& 0B!˚8^^ nb8 46LJV~]wv *t豾(y$O^#{jᝠ(U>xU.\N6Co,$ ,.#!~D^*b' ɥyx䒳y_"w~Ti-з#2 { nh ?jd`XѻjVrh?3'^ʓ+504i4QgL6rtCn9 kCWt.|O|Tzۂ/M;=z"Y .'cgkG* 5^rzDX[ocS!/hV.rVFk⬏h ~rD:I3_1v[Y\R- QbfA{!ҳ!g/ksφlE=`I <Ǔ~<Xr3*ؤK3e3Be+Hci.ז4wˀ4pL KRq)O5@K|uV_0'g磗åxFpa =۟Q_Y jZQ6c  @4>d+ SRvWܘI 4K<;2M|^bx<]Ir8H7?gH+?~Rʺ?)&7ϗfA,n! a fq#ZT0hsFtVxe] oGzn{QM1Ht*ilazЈG /\1*1PJ-O ؗZHURdW!$4XnkC?i^݁<0ztZ^K]d8|nKt_R* Q i[KB|LYF#>l#oDwUI0opLHV)f{*֦ׅKp]=pjqUmIT {|cs/I, =la9c!ƋD/IQg6^Y[j?e[˓Bce-恔Ow+^yK?cj+A E(ަ//@Efa}NLte ixss/TLQJÀ8`K43(=1,Ҿ6WpQ"q }jMޯŞZ(mjmVb+1*贕f%7Ix .=1cgqy`;xKK[*,V"Z@$^Y]e? ڢR#Of>o'BOcŲ-Fd}z$3]Wn6ҡ-.9Enq)Ō  IT>vśeI&{޶àM++ovKq/*k47mcEpJU]F]"ڶL}nqk\.􁑨l+\+X8Mwu7bHyC0re"}{Ĭ>wIU-gh#y{>^op=3hìEź2iw5ǮV'd-)qS Í^u8+,Lj\C>arWg(\@8#GkL [EpsnX\Mq/y gl+ҙjCh}KL \0ײ{h}Xb7%jp-޼BD-f˨^$jQRR.T;QwS[d^y7җui?; Y\&tQ)ôSf$qN. 6hG W `Ѯw/e'dܡFJ6nM`oʏ=k/]6ae3);Vs$ZeYPÖӸTX@>HmAdz"e:Kn8=6(Cѽ ǂ moMHCtwdS6);ŋ5R}CM~G5F}6n&q/Y%bE7ύ8&9:6?'7׏a:o*C:gwҺ.Nx{nյh`^p̾g/<>^1KS5|U;+Tv\<+YQA"}9؇Y' /}1#nN'xmr+a;Y딲vykd=0OaXpe *d {?~:pt)p(rx Op:ɒCVX3v#_iW?j*76>cImu:j IX++yfJ8NgG@`TYaqNtDɖHsRdgkI>Za-H7=ļ,Gј.ւW?Vfh*tc2&,X+'pJ~+5lͼW]V"ǛO5mh9%~4WpNhmt5*ַ->tۨx @t)O֑sq&EqQY3#fⷎ/ αNX+w˞zv7|*RrBr@Eߴ}Tք ]SD78L Иlͳctkw'˧Ϫys*iM&xd#ZGA,pLnW ?LI>y+3[aqqym8í={V3F?̹jD,jT24Cvj Di:,ԑf؉:ro]'3Sהn,? 0YHA`,ԜB+8Vq5s:p4<"&YVm1QB-Uxe/27@3{reikȝ9*? !̚lZ19Ny!`?*P.BmJP1oP UI1YZ!|`"/1տ=n݂ayGf8:&ͩ"qOJ+@b$B:-/N$>9OBٟubE|&=o(` hdYAE1*"$SPG5WajM,C {m] )(8g(o pRnL+,r?<`bU[_>zm^]S <f_F'|b$`2 \~jZNA{#we8\I l Q}-?%hs-6#FWO<EmAtth,<TӹmB)gS`A{XϺR!K^|tS`\?]јװZY&&!$zC (SC8QR]l4m栣O-D=I(!\vՐ7/{RYc4rf< .ܖ?뢅YWk&&:xJUa+>f轹v rv#يQe?X`>x }}Va;0NEx=1sR*{ޟ,LEl01)*m9Ď8[x`f/ČOmEN?l602折H.fmh!SbUrDw&a- N2IԆ4exڀ`({JAu.r'['i"ZLi!=)|;ik'i|;b eD&^AfӰAs^1HU22^iNv\=wʱijTXH&[iVJ]6}õLysܑ`iMT޲,Nr +{n:f7JE.B>ѾNCA[Q4ƨWSזpІͫO@wt# E#ی2Z[N$Uk91tʻkmӞvDƵ2|E_7*n8a& ht <;#Fyg[QbyjxyZhR9;1!sA*@4N\FݩX8>()6;K@-ѱǟC<.§II]ֽ)\|*䚾!+[{X̙"%+\L<@QLc8lye|GZYV I#\^>>J?%/{NY綯PY·g'E0֐ULRL?‶Pԓ79[Dr~*b xpsufy[*[Liy^WX U=ʕU.ՖrN7Ds x)IvF|9\a- ˔C_1(`_t*׎nt= gLU(e@sO~ϡU ¾)7=F*tfKLR+Q=:IuPX؎u2ތ)n(8pA[tw2`2gպVZ8^ ^4NzL.⯚RNPM},8NH6q8/Yj Iyvl W,~npWh0{˹D|v @u%Ia *؏?;6=,SbeZ$hYo hD5<3 Gl4;bJ,>s@t²]H.ޣ3jrTOEFL\L%+WJEx[}i܏P âd6P6ty\i*ú+ 袦cjӊ yX)~`3砤Ṕ^t4߆-[x uD0`4@^3e& xqxІvw:@iCQ(DtFZ״OgiZsTKA $MvV^V)Fc$o `F#ic+ȟWufwT+} rv=[.7GUUҙVx)Sf*YBg2zcA@?SYS0XL!7y$ SR͜wm0+^6F+v*k7_r.4`sV \+vheNej# @[g |̪~`;f{1N,)>EJ_ҽMT8$)*$2D2ُU51BN? N$ٸF_j~Uzȷ{MjQAzW,vrG^+B] `gޖ $vEAcv IkT_), K1݊ f 1)32 .1 drC9m_ S#MTWjW3KUE:؝ûW0 |qNXR]],zDpxƥҳ,h5EN7d~]0n% H ꉃ}.B&/Zn_!y cKX[˂I\wu Dz=sF;IAd fg>jpRc0bK7rf+v+t꿕Z% BAyDZ u|rq{NaMh38 `gw=8պSm y99}ˍdx<-q,',ֿ`h~SD5D1*uz֫IJw~{Tt8U0Eϔ %F-3fQ'E>|e"&lhG%H+Psz:޵^D O(Y`3w}6ZX0puxirZnȄ * DaʿI֘2iBv71 Rbg|3r~_ok֎Y6DOz4LzrL >+mH V^2-՗3xQԠsD vO}A $|r>Y kƜOp9 *W=\ f#1#_S{ /fjWvYd௒԰j#ʙ K}+%tNӸkIMwn k}dG{)J(J#I$ 8t`Dz ;|7#M.9$UjHV+±9! xGEżv0jv="|/+mKU.#=.}ښ f$SdJ?o,b82I0,f")uFq8Ek05L=m8lމ/{2XxKb-ej7qLtT:ZhW4$ғ2qV 'Y?uNDEz4X,"SG `bQ C:)kl5.ݵ3H*/ZID%8ýEI$FLP)&!Ӧ#v_QM`E930; ݛy$c7d'`-. 2$b6=/=.e`r Ռ+޳e'9LoO >锿[옔MFLB6 M:{Oxž]~4dn:.r{"AN0elVpN/"T:fa4GE7to}XB͖;:csҍx@Q1l_k0ͼA}ٮ)VV^VTU4n+$ :Z}\(ܲϝ PxY~XIh%jhtXa *1O"|0uaYz HvZ-Bk=ge8fS%gAT#M.З pЁSŔnoΜl1)i!r&2SZF/㱽{ v vń5.,g{e5 B_!}w-)3#hPbvWD0g3x^b#edu]h[0Q&\߉{ ~KN~R}Sd>ѕx˵Ɯfk4v?6N?z{b|:rsE^޾`.XG=nhr/Wi=C'kI c.Sf-Lxjo[U$ q.s*,T͐6TO`[{^d .h{m_zv u4ڡ$HrJN-vM8dKM"u>uAKm:39XTeQ LG˦5fArI[%\q`W ~VURk,#Ig !qn @YZ@ȥ&z.ߗQ If0pTS?Jk6ΛތqW$!* ~k8;.vH(xofG5_YQ>LO(kP-:hqw^T뎝V-b9]Z$+PjF4 l! R"op4fˆ&ttqĹM~h*LӋxE$0݄% \߇.G7,9H2B28kÐy Ϊt#C-A 6iZHsw- pzSD 2otOSGmz*?J}㋶?%]KCM7YUnַ^\A*ZlW,c{ZK`BP%qۅj *IwdT[UasIh(@jWmqm?6ގ]Z+/űԯ?{@oA]E5[ra?* 3ogT~GZFP<D xcQhw%)nmDmLnCMR|QYJeѳoZ^W[൉6PpSۃ^0#a޸ d<?vZGJvi]>`ص(XXHw(xIW],ߡF/5fcwYьڨ 7FEܶ"Qh ^o#AHѤa6䏚mON70יւ<ߨ |~Ie-#Qc6)KR;O^06RA>#;_!nBv)E']eb"Uj^VlPHlwtc)9#^qQxH5mٌj i҉L!olq[> ҁMji]ĿŚصQ(sɱOyBoqtTztf%&3[ퟦ X";oX`MGGLOkB~~djhe/-X'8TK06+Hk&v0l>J?,< ϑ5z' ` z'Եd%W`t25o Hwqly@Q)޴[uUo8h!(aӹbE'QKd{&X\m3ڲdE*0kQ,,*?t_)u 1u WO7 QͽUf_Ջ@]݋tNt% AIPj-LQ)L |!)ys~=02Fb?ΚgU0)J\ I{5,4O1Sgj@ÇHyaIMVȞba>l۶G|{J/@):v[ķ}t\B '(b6-ن;ax*UBih}H]jJ<;H,9$dPn"|FUuW~|lzO5eKVCQiWw}Gc PV 骹FqP}az/1 fArA 70! )+ұ䜆mΣK :<*S16j7BD0i}KtPй|8kL]yµ |+mߩџ;ߍul8\>[[m Ɩ2=>Ұwt #U$fӣXU&~P}xɢ[ z־uN-n=-@ '58Ӝ"IzmVLAD>>ǁFt*E5yTT#(s姯1m1Q's dy ]XN(_r`LPKPqw{˸zvC5RKȥEYJG_z[&0ӌ3V'ܩNBmkQ1>B&Mg0 aX*󷈿]apka-4ew@}?' lWˤn@$$AO5 fuĠe=+EI2 JaЭtL`E^#(ܑn82yjP1% O&6uj2#Jh*l&*3߁5+U&}6Iώ)!2M}o~ye$p2yUUI|FTE5q>ۛ}=~v6Ji-Db|ӂ@Qe8t|}+s |ڛo)l)1tLW\ o&=gqB`2>I(8-gDm xfx ,='vbJ(N441Z5;!jS碾z k#X e43@Z f1MĠkk .YE |NIe_w]kjY3 b >UwfD7;IZjxdL>:ҢoNNo9Tx( ^[d+;VNRgSD˺u`}!\+05e~tvBwn uƐR!a 7웙4Y|m]Jk˲^XbB>;;{Zd2j6]L>JoUgkDHZs {E wZFZO>@Ťu`A,%ުhGƓpoBgk!;3o!2wt2_uvE(M&)i5QxcwB<SŲ 2*#Q6|&è rnɼ+ԢBAqj8B/,Fz2nvR}>BK̐Acgue^aEGᑬ'#d 3IK܁FafuzHh"t9$#1wcvת \;'}ZBIi~!x)2ރ :'uۅT+30xtH⯮l )(Ntz'RH~Kˉ~d YQ- (!-I]=4R jv[XTz ͪR R`qꖸ|nL76zngobݷ](^9 +GXV4wI]OLXk4jc6f]-7B^rYrLn1A+pP]EԸaBH6 q $A=()^@SrtEsmb1awاBC9 G@+5 :!(Ux89 j]U ]Ц mMS kv:͟kZ'WRυd\'@ЪjdhbzL|6z$^ Va\-q8.*+ŻbN|,hZO^('Ѓ^-yk\phJJ<{_0?EY?/6紝6p1C%~Uȼhuq+*Cyt%βnR8q6G7.^p#0*)l) ʍWB";6F/ir2HA{xz(fvnmd81(*xe&N}]xٞuLMm. )uȰz~xֺEGx7VGtEA=hïadd^\VBWڂ`)Yv&hsp@@D.-yls *Q/wnt|c.<鶓ATGQi&#^Nܭ^7--8Z` 9HY?P`TSYgh>exQ>ettUj:wFo W&"y 迼 Xs=8 y_+$Ė9uAme,MqikNgLeS}z* 'ege/=FW;WռR D-Tl;!Drl/p'lZYQo5SSO+ p\BWKafIO O_# JӠ";"؊=Vs$C!$-FL]sa|"vϧ$1Z =JşvC,Jꮌ4Yq6=Mg'W W*+`*nP2[?2$AiHW FJ+ܛźd)G[EBsFF|`yEд6yD3wF'\d, Lmh{귗\FͰ}>s/H%M_nctķ8 ޥŗ Sp@$Z9C򯈺4g$E [,QDq6V *sҞ"γqĐd)_O 9 Ry7bY_"kHn&JRaP7Lݑ=9RB(RTov?zmbmUkuy1݂!U- qtT:b\gtwh(睒V6@=:\+}c#24jԉeeo9&͒9FWgDo5i:膂{2H7i|; F & mlA?z bׁA4 ܵML;hOrT(!{}f?kӓgMr0ctz8o/swB+\Σ%slz%]Z9KomKAXjTijil볠+J(G79.~܅p8{ʸ1Pp2~[jF^?~{tM.vLX1& GNaGFOǞ A{7&< cU\Y6\G|ʥ&O np;eJ2b9|c'?DHZپk :72/wFH96F0)w*6u#86ihx@UmW DC`)x^oh_jxSǂ,%M•1:<!12NV릎M%r2r2q@k8\}&=]tޮ1?SWR-]_Z/k 4zTY220rCLM`ݪ(C"|r8qR)P]Wtr܃L-GgۋI␄!}"jt3N d ~7ke҅^jѕޑS\۞>~b8tP.a`B$MC%^F6V rgjɉ &zԽArvGnRɴ! k> MU{N"%63B᝕١ F&ˑc3A 8J2s/-# jO>?rP&?]|_,As{դo6H1g!p7ոab.j\lF }a~fuز3["=1SU1JOLo$:]pX؜l}Tjژӄ4JCD SHRbmu3]q׋_N`FK6pCLk:I,;3b#[!otfsђ%`1_b^rb|-}͕SPҫ~EqgYWo7O(' %DG7]e}U9 DPrmFu(Hѣ0jpB)тnUn|hy/WѰےH~䝚UQPzč'R.gWʜkt4&a9Eig1{(ͻp#y3_a75- '%{HnSҙ2 i7P[S9QMC6(ŭF 9Fip ZN/L3vXm6}Yճ }钷[ycN9E)NUFΌdjRF]B:YNXeU^B32z8*ϖ|EU1d冼X՛N.TK)Mu4o_Z6ctVs. !heSTx"ZA@=q`C%!(lZNV;loAe(Ң/o'^[UNmx釕(c{zCFQE(''޸4L4E?#N>fHԴi[K2D9:rEAXUmo4ٔD+iT'*8}9 #Itlff`ų3P4BC|1MMq]=ґfV׷k?JRP%"$S*wrhUШb1% 407) Tn D1 p1tpL}QxF+kWZý=e@[r;? b.!&UdSD`ߧsӗ;g['> 73^Q!yBy>C"XL>*&Ř@bI[u-b9 iNp.j:+5[{b\#ǔꨱVB̄˷KP)Ǐ4%@qNьc[gQ֪g+(x!\8 +{h nSE3ܶk׷'vVFov|;jY4L ob CU+nEk֠_ %G_o<} /'}z.N ɥZC[Ƚ1$+`Ⱦ bab sĔLi`}hJ]$IV&Ӻs(rU /6=;¶vJ z#RSK_XL{yvWڢ|byV_oݡߙ$^އ *U(+NAğ%/z ǔ9* yH1=24_\$E9am?˕X3){cez MjUrdУu1|4FOj¿Ϳ=Y݌ ?B٦J̔S@z5܊ qx-({|L><kIx9h~#k{95SaqW5؂vtZI؜WU^,8:Q<P· "H#ZWʊt/FəKfaG\hbGX>Qc5F"&ӝ{f+=_0k#$g\O'2mHvdV/Cу==1 qK9~%R0"r YLǧ cqy[QW4/:$4 2oڳ%-UD`0A ߻x J,6e{Gn[.uNwg?鲱ɄQXyP "r3޲|Ӝ;JNI(UJGއ6\% V~`ؗG5x1q?V0Ew{q!jR th`өr\~RG|/%Wc5!b{ [*F4i֡v+ֶ6a@Үq?Zh/htIt)i{RT,"sя3}h@ B(N~]^Fˮ.L̸Nˢt=t58-/G:vxyjG,K^FMfܢ=\[TA}aZp1lB4HQJվ#jR:kB[>;ѢEmjnD6BKGsVϚ+0mr9b!>q%ï:@I@BBb߽ݿL!MG#M d_3 u2v# ]Ct990mdT.o8_ qB`cA?*\P hHRr}K~ܘ*|Sk9owcOdKІfuljX6J{IS㦲Fͳ_Iؼx1|4# #yDs;Fhذ"ρvi;Jx/#u󧟛OzsXc"NΈ^ŽjMϝ֫ed;!=@ mb:QU6jUC, I;^/"\smITC' __R Q9 ֫'nn#>%#Au]zM/h|sۖ@1ݝWr -S'ZkRre ~ajҺ[?C>; (fO^{5 T[g(MUuʱ<Š0l_%ֱ[u5>ޔ#>^ }P SY|ĢbGNI.p8dSiht ~_N~oZУhZT1&Г&FMFŹaW )0d6ag9ڟ`jvL (d_bq5g4鶜gi1&@҄`~\a+9rA&W',&2Ql"[\B-&ޯukk(Y^>w)! Q ^^@h(M`-9;uQ s4ydEeʉe&[U(QA흸IGxBnY%ȺRѣ> O< '3U~I[FG:=#+8@Ի兝2be`Yר>-Q͌ :̸5G I̚ Q[CpI%(?,s"C $QsZf-5Brk= vlhA|5mS_)%62 f:@K$cg꼪7$m[J+>&%_B[=~ή.HTX'\fAF#:Мn%z\DXoF2&Ƨ*5Q 0C~iլN;z_ w~(>t/?h@v* h_3T&1;dq;weQy`ƒId_ps t'@scd 4nԘ9dbjq@VKN 3tA~t1C"uV/BY AMt vVF OT^q΅{{NYk#Q,3-Q/wOX*[;C@ NH< =+5s$%"yqvs2%l|dNmv?>r}YvPeOq,E8HfL-5:,CӢFL57’z?БCwZho[@i'  LDV7RlH7 C薭q${cX֯W.abi{M*p>Du>~6֭]$3vH lExJl0ӬƔ¸@-CA&""ǬMyNjRmPlbBNڭa;W ̓H4>7C:7  <`+JDfsvTF 1bHaGČXݼ6x,x I7` -D9JA7]GTm_45h3NKig 7 X9J4q\:Cd(sX'U _Yg6sN4rl2U dQ!PðmguZodyN8{ޣ^Ei梹̏xM *hz\*L'">{m=Nj,[V#2&xkA"$_-uEb~HDS" [_q@6ؕd|v5igR9[>9@ AyVS؈S =b߳QP`JLNmP`D6|:ÜS\@.ԔcT݄@Qbyc$߈-_ʛ7z#v,E{w}!h,I#Pi@Ьmj>,"44}M(78t-cQ"VK8,^'e>\6Ag渋:|҉EF#X<$$$LYQ|1 &(E4p;VmŬO PsW cVYvXOvq7\"jZX+ nK#%Q-fnZx1K_X0MI/ :X ^'_}W"ĸ8=Ap\_z1יj@1D3nҏ6ߡP48?[ivmf99|lXv?wR~F rה &c!ޜ~)u_*~ I8~:K:'$SC;A$rTLmk;q#-!l%^(Me?8v-*冢H(Fkyͺ VdِbWDȐ &{$Tz=*"yIۚE![U hNnR jf?O[FHb+Q)T pV@i-*Ux&_dˠ;_X)Զn[f5{I4Yp2fh@]P<?<ɣCT[ IBJܕH l^#?ۧ2_;Њ.K%1U!#uujuڔFg_cq?4Eq'e6$OНŸCzTHZ:>e';܋1U'duo>If PB7PTG{ցwLG/N,(|fxZڊ(ډUvUɤ[̻:_ f2RKiX'} !}D6-IUYo²n+l^?wd4/5;ܶqJ@>QW8 LKR)'[A)&!23A)sͯQJ=s%)Ŝ)(Mޮ۔r"eR yMa~,G 3q ɲJ]6˘uIZp8tı 0d{wL芤8Og[lE`D vZ* ]2T!#-9@"vizʅFR*7xCȏ3j5t]?Sj0#LAue·&?TU.~*-ХY?nn(NaMa٭` B#gVˣZtcږ,:{t3ZRm#;;PJ$ŖW5ό+E}8ɈBNm) $A=-l]sZXOm0 v$2و&_ޜgp U8Xڙ !c@-rkZ(Փ |eER&gj4LWIۣ\?E3 i2 )J/Pі<,*!0࡝X ߝ~Yvhꕿ3`zcfq Ow$v ED@Y7Ii*+\):9Ap R6අoX$LOB>z{(D ~[{%}ZTsC%mZ0oOc’zd2Y3k"Yo'dqόsw;G}QȚ1Na4I7 }n2uHރf0G;/vˤԢW}ĭ? EPs)M']Fѩ dw-e?tmAM5."/]8dѓU`= konZnoBli#ڮIJ ਰԥ%@mROƒ {#\}XK;6[_%Gp Qs8 `jrP|V7'dGȷ[ X{r 27"fzb7Z/{b7 D5 Lʼn@1L$g(ћ2=LrKig\$p[p0g/<7H{LeSA/بs@ҧ!tYko'Z{*V8; 㹚$ds̓ ,3b1Zw5(l]fVMjv6PF3cF'ylҫ/ʯjSם)) /YSN M OJW0i;s=r-Va rfQ(6yLԯ|;BsC6yz\QS$>t2j[?u QV钗^ .}&I2. y@ p<8{{1mk,UxxW\?gx覛}]]nVPf.)!t9mnŗ"L:DR>Z]ΡF y|~h"Dx$ؓ`"h *f>|,Ld[x*Rug7ׯ@V~JuG +!}7_w0*=Z$va¼@ga#A\1!_ xs㛑 8sD\S):y(Ћ6 @a0IPu4@*qLsHPkprQIsAg8 [й wŠԺ2R4 TQ?7d{k H*)s/^0-VTڐyP ]v} &Լu%oAt0t {戴;Ùs'6Xq0cH H:RIl1a;Ű\2 _Lߺ:U23#!M52 w;N@T9qXD M͵mc_ήDa%{Y|fz\w+G 8`@&,?6ʥ'= m+Hrg ߏ#out.)SyTOWhP3BG0GjMXɇ}BT\Iī'YYO1ڤ$jq tQN}XٙZ,PiKisat{[yW HZvg_Tt,D_̓mT:mH6H>$D6f˲|*5#d\^M 45B}b S]Վ"$«Cl,܃3wUSg=j9zyN'w<"TX2=*gdɹw f7{/KѺ Xz@Pjǰ{jH5uKJ.]Jطh8L')OMY)"hC{en+X.,1j ]hvcy'X[P2 ^O*Q5X aelhWÚ^ ٭Fob W a uR"O(Vnjbx0+8rMqE2 " "P)n3oA ˆZA@\Cc Y`8E(6G.I GHJm%&d_SǙUB @pZV7U_|}%VϨe1bԏZb]@)@ŌURC=wȉ_ l@-s;>i)Q_70Oe&YڥeN8@ ϽLK *N5/*4`{8phtYOx< {֤Ē yRJ:LkV3zu?" Q nFc%フ9ǎSO(Ug@yUs2,Rz-K!/r*J+ ZufM 98eC!+UZhɚcMMs4CgG`x%{29@ 2Z`-&LcO:VhD3YNx6|2n< c2h\W :wRʈ%}>q >KlWx@ s%fܪ$RiB1ҙBodJa6%ȣWV'h84*D1Y а_V5_qv VԱ{\/:7fil򩾕_P`~Nz΄uDLϗ}>ѮL<>9hw a 25f$zP.a\BT8>*v Kx_G"L7Gf1._`_;R{igm zAO틞߉"͓̘IXyx`bR̷] 4 8@,zt} -՛=ē+"8BTB{%Va"D ِBsGpjCYɎhlwqպΟ!]9bݰ*18F`\> z%H$7bά7E;f>oTK5纒9=NyCz#dyYIjw_t iįKfNxv~d7ì4q>bdg ڛkJ(icbq ~- cF/>wSG,঑d=omCpQFD6%]dMWϯS hӚYj癚$-">)̳=NgkI4dB6&5kc=f~<&ӗ EKi{SyG:JV/Q`6>w$x! i-ax> :%W w"qa)F~l}Xo*F̖~ݟ? .]v<ғ&uԊ`j|iDIZF^!awƳ)2qfX??)PJ\$ȓ߲41-.+UkN^,`$xT=k*%zγ cS% 2wH}~B!/?9k / (?3H:6f0TJ&q$I?Yw活c\ >0_;vB/| 42hXa :DZ{ Ŭ67tg,F~{ 1Ob|XZ46ND]<\]@0?O.Q_ȚC$žOY@I 5)/b)g34+(kmWil\q;i-֭g܂ P?̔8&>%ˈsH>*8iG3*] $lq3:yy~V\d])O@G0ƳlL5@ڀF&Ȓ13*Pd^bvT#ӨLm3 ͩKd: \F|}Rc :<'J\kQZKdKoe3Ai C[yꂿZMR*HۯwI1]jOUID-ޚ5l0J%x'6}TNpzK!jp!kQϏ8Z&7E˗=>]ysXk: O͔jZ|hBk)$!t:ه1fy!¾+r3Ȩ?,yO[u }95ј'+mA$Y=K }ĪFA2 jH=mѨ]t0,u? !3ShQx/ a(~_N%\RF95ޢTĄLjmtmgjdEl=cX`#TٶWr<z1 E,8TT[_6*?9s6HkWq(J~%m`m]Z<ldAg{y#[i3-{9_Aʀd\v[; GUQS]Q(r4*%.pW3-6&=bk&G ~vܸUc'fs=*L ^qFY 8T0+tFNI®=WC#G'@1OD*<C,I%{`ߡIpni |KLVyc _F%Pl}K!=pdjiSZ6Omd8?۪uu k֌k?[iNĮ(;7^H0ַouvМiٚ  hrVn #`qQX!7r 5<}&W)N<TCD61J -SLulOR2æ3݊o·3O:!AWa V'EIhRqd05i$r':czGVL%a}Q9KE%6l~T{:8ZAl;' `? ȧU:$wjqAy'4ٽ&0ҷET~RRCS87 \aёl8k-ٿmkSOX1D1e;j%P5.0.<\Sȃ & M$4 Pվ)Wҧi9bw3B_cѨ ѹ^ cyKh懝v3# /e?=QA u=I8׻ 7hٓ˻FJ2kIM^&{G~2nq@HV7 o滪Xԅ+p*2LvHlG Qe;ʬ.Ҝ+h 3zM"x{'v% zrJLdotڴQ#]t0&n߉̇(%ag3Nօ\gpJv,N"5e;oo:4{q JH9ye^3?XKH3(pi~;`t&}}\X.uyAL)79߱"6`jEUSOnXGBWl@9L|-K0LEU ofiUOK@Q&RU(O얎t &IԁnFێHe[ L6ӆ0*))F̿C}޷ngTznLcھ7\w1_o"[櫛jrVP!," ڬܶ@8{RI~1;vkfAb!hҖ^-qܰ,GErjSѢⶑYNv Ҿ< ?dDBB؄k5J`7n=56^p!y;?3h BL`9-v k j+28ǒD!6LJQegRO|9~˯=R d6}q,H0|:3Ppjw8t<g- dޡjC(C/{+Jk0!RB_=19Uj OP!HbBa!GN`!8]p~C'!4j y׷v)èx^Lb{eS,t;riGc%c\or9f޼lEHlH$v;}#D+$XdexGxlY.t#u*IkmXgluvwLM[f=/qT/<\]4_ j1 YFAZ]O#:%A01trx+iժ } 5q(mDiHgV LgwXqe2r9 A"177ĝG9K n͚: U<ϰFp#A !Ws3$uDkHyML-{!^#4- QVZ3-a宎wבް|rnݯCSrO]+E/9΃Ǩ]QJ9_Tɠxr\T盃mm!/"sVq8aԪYe-)SU`k;μm QWtÑmq;3މ_lINǾeS7v߱":CW̻8A(6mm}ד@ -^NfN/n{qeK;ssN[y%,P5m7tY(Ii)6ޏoq24a7-L}oC$V3xsiZ0:_4O!w%!v!ۛmwjy7M/ {<πF#? m\^ )_?@a6jbliwHAE1U<\Br>S(A~ %iJxc@& ׫xܥdf|bH65bJ۷ʖ &}Ľr;o<ܟPm7V͙pzjx9ʌ:ҩGLhu\>̞эczR;UH,M Ȋ67N8KE=(}Hrś^fTUJ32KHoZwAxԲ`&&d5QtIW8PvvKdY5!UBW~)6915mxy1}EC4#4@mPgM^GX Uf\ k'yg fK{Jk1f`%4#Dm@4B >ƚrWט3RAO~i |y߆o(U5HL{ K7b1p(A& l>]_ Ϙ׉Ak^ĈC)$F#eո7l>g]6 աn9(kS}R]^ef5z+;LRDg*~L…5Æ5>_k>&Ck5 =B=Ǻ1tp*#X$- AH$9Y$KUH7ՑVv4֎~oUVH J|6] d l~3z Ը}-4[P]VX#HI 1,%v@{kx+sH@OTFneXUIWoOހMst:4m S[ gJ8w$5OhJ\\YWa!cI4Y2GĽAl"xxJ+M՗$xF?nmrc 6-R ѽP:H~J8>ix|ө oC1i*8Հ^,@t( ::(..vt>h}I-BXSRÁ=`د]XN_ _ob8)-ʽuzÝ[橍ThOnNS&7i,̫q *jquY=SتX| Y6z֒ck&"}AA/R.DܷBH[UOSv%u쳭- )+5< J=Ol/o_{6PHU샲uCFy>@U0gmZ~"8cZe؅xJwpCnGRw5x;F/uv(ޗvL&`3C* 3KjђAo\z~{6BB E]>A8W?a!Gg.^Bdt߫-nֽ!k{uNvN5V0#=#4,Ub;?בaop :B̀siwk:OT/T<E:0v+h$wз:6+p_轩Ң3(([|/("|E FQEKYhoA?-H?HtPDA/e-|H`mD{ݞAwVbD?,D!Ԧ[JnB==J  q桮u+QQ7'Qb6U쫡b߈qqI$dnm'pIE;՘ݒNf`v zN>P  MCh 1/x C+n(&p|8Թ\pQxǞCzfh;0`t8 k I =+T 5lK oc4uvVa^} \~%@ʬM xf\2PȢyH=^.71 ;2}# cie\Fˇ$9*c}n+|YZVi7"8^eΞtGEO߮^*rQ~ְaL RG:fE5 M K.i¦Susr@,\{߀.U>dx3ǍKh/iz+^w axOf2PV<޸0. W=*Kwd3mdS]'xN0g)κ;;.Pٰ@{?tf3 Df)JQ]}*x(?)&[OY|#i=2ʲKkl6y1&,Gљ)1$r.oc]ܛȖSneNa#P1=qo?Ke7ȍ p_Lҕx$9ոn5ݣJ&\^bM vFZK<2 rD 9ۉN(V!A![θjz}h;H(f RT;?Qveh]R/k8Ή,GЋ[mbb0ҷO`;xϾ-5wiFw']s:z0>-5 J8(&=S V2h)(ި%Xqu|zu,$-l&pwF i@]/MS(("rm]4HTNiNn/<"_/oj*6QQk&^^-iV)R;RSҒ(?S)zI ^QJMq4j =%Ket>㺗"_GbB|}օ\ 6y\v dpCH6z"cT3I`e?9O6 ՏKHd =?Q:υFu&2+,@W^ 01j<tpE3#rEzaIKEˇpwW^n~IJBqA_(΁De 뾮Q-&B#Qԋ@ݓɃJj0-OD}|+uu:I62~JyA.Vs.7(Qc͚tYɼ-CSrVBLB+)o*5ٱтeTvg+]dN:[IJ:RAOe3Xd挢0NgԿ.x \vpn/0Ezngm ΆfǑˆjY@n0՜mBp0%zeV%X=;<ʙ!AU \ZNvk.rT5㜵OpKl= 䫣qMZhąWS$!@NΒk U=Y< -1Ii8`"%alkC\E[ָL~<ܿ]$tzF7И 1pǼ'CZ!'ZHv54aS5v/:2R8[C `zin7\<sJ׻_2`gf7sa !'QXx]]Ϻ"PU1$ŸvPH~\oyQȯ\(mN֎5Q7h=H g4c#:3۩{iѺu½ 7y<^8%8ky(NrgԚ1w:mu+ ii:D O3^ -rf(r;0lφ$_rV"{ Ӻ۲:*[<Ȯ޿1IuK DV_utsae[ms= Yml>ʜiTn/[uh4o}ސv>3W$PO_pT"`O }&m8X0)56O:咔-8'ŕpЗ̓\e/wJ" @Hv߭E`ivmMOϤx<;.̲Yjl6%SbUZ?upI27 V.I68MN 8l\&^nN`U^  Ϡ k!05T OUb,@][ ܹ}`_i a QyD")]O9nqzG=šK8 .l ›t@T*&ZRɲPqwZbv[Ӏ|n$ssޡC>!~kCÔO4Msp/T--!xol7~/K]l`L >v=kF#:'=^\p`. >'>iI=sÀmM@f⢊b33 \κE _uTX4fqhH QT:"hP=Hr曙F ђ3_gy?tL=IHnܦשZ^7bg))fJ];㐔s[g<)]ue$)HP>t(OҏW>ԑ,:\Q`EbTN$ H2 cL {\_zuGEtʥK8  bP6PA^/i&3jk] l )@/Fd,8Fo>5Ȁk Ќ9R7ن8p,'10 r@kO aG>/,i Kʍk;Kw6KH]SOk,}@ti mE&Tv_ r?.=rcǶY)b`E(f!A̍Z?,Vm󾲫7Ԙz,ʎvР X/PcG] 5O_ EiOQC0ԸlZnh@>l'ⓛM5=].^;+j34|tv̔8I13veK1sמ>v$@Ic\ufDAꊬ T#[El+$ݫ;I2HUFy51"u-ppuN#8oCg# &!viW F՛E,<TQXlx-m$EåﰽIbHˆ#uw+@tR烗-nDϒmyiӛ}OsGdk))`b bX>;t^ 80Bd_{Q,T _t'v[}3,I@"z*DDw3N ЗT4N,}O 2VϜOcaz|qL]ɰ{pSR~X@ .kKmq lO$f,߃uR~ U.+]hGt,E'eNuf=gNJ='GZ+vOOzM1 h.B;Av=OF:3q2ܖFQPh泇h\{b 1_Ri<^y}=O{:viL({ r7H[Lzm$xx9㟆O@I|{UDRCI^!DztS:[Pl& U}?8!G#V*$XM '$_Da 1 #VWTU_a4r*oB&cG1fu<+95+SHMqF{Ζ|*YGJfMW;X9WMRIO<[2 iY-?\\{Kx}675]-o-:xiƲP'Uљ @WQ+ psJN}ռsmզ_E*>2y5)%\ !ku-Xm6!!컗NG}M  ĕQiUe`)w[ <׵jM T舥_؇I>yc,Jc02h)UN\jv/Lm>:؇HM%ϒ4`bS[s3;& ވxQE^W16xlGR*ղ62a?s,$6A K1'c;,gcUV}Wh/G1YvHY7_A4 B`Ѷ!۱');}\pY87p? 4[6I=]U99PCP_u8BO3}Bqs_2},Ǖ<7!\ejkQ?%5l3~H4rN8@l&J3#K+h*Oiy3Q4 <h^5*bZr~ C6@8pE,sޓ+7/ tS;cVV\.]ZG*ޑ_ w6mOd }E~ڷ>:ufp^ Y_~Q^%4HQ4[;xH_rC \LݗqΆ;aWצs_ ":MXN>/w6O`0{ 97wk=!h=  A^,K$؉&H-hTli|WΘRNa;Xrأ\bFր9ƃ:^nG(ުZ݀rC֍^o |b Un:3޽ߙN4nkJDeW > :!+TF)V^_zOn8ǐ HsT^xNNUG5VPt3&`n$_UV "35m?@ku&t1jÅL.u4_Sj+,Ԙ ; mw5gZ|0M%RAzT>spo }%p/M}2`e7B]H4:kh5- 4ʲP ҔxL1c";Et9h"&O iz9m5ca+&M[`yH.5D1@خ4C>wDx4"R/#Hv{b-ˣRZ~4$|%1_/#>U.V)SxQ))}t9Ts['H@1' W32t1749Emd:AۭNRYٟ1E6tox[=]7$;wl?Gh&U3pT?5+3ZeI$|6?MI9+w6IRU|6Q`ESY2r}v{=m1i:I `RRl/[#쮤q=j)?+@ ֎l pے"i7NCoG6l, 1 pliɒ|U{ٖIq7z Yk脴Sna&2%1j{'#>/3WVW&c/h7OoΡTTanG~y)Q%"}o'0.Ph̜ %B7U]=IVHsS -8w[ߣ-8P[O}~:ELYnI7o#s_Ň0UI\{]B{[[\~f+VlÄZ(&4,!NxI@ &Љt% IZ' kFASwb3躒J$o-Lf95lVz?տgGȾ`945qĘm*h@BEoSK |/e[8žMq1l}KLDlA"(je޾"9FEMGQ̳hJ忄L W{Oik@E%UnJkAD]U7fߨba»@ڐG w?Mr oDQSkw!+?LK(:bg-}~ي~֎xJ>xTI0*ϧtk򕱝·Ղ*W:P!]X6ÅgAXg?tR4m-Ň%0 |j沆 +,7g+g'N;GC,rb 5 څ]5;[.A/2m$Lp0{g|uZ 2ud`jC1$DJ^ܰe‚kg;撘o)tb-kREF󻳫QނwPUMS>z3^ ь`ShZ.@|Q`Lz$ki8\78b܃3Aa{nEJ^m \HI X+0sEcKi)nr)\ s8СMqjl^.W ˫n@뇺*!C\z0Ju!$nj6 xhVJOl4- xvP$yfwZ? $:/ݵd :̞X]ۑSuV!"υGy#5H'GYםxù 7f85Å-Hh72튜HTH⑶B]Ɯo2TdbnpJ M67bYHN _Ȕmw+ٍ~3J^RB@NI#Ynz#6Ej.TE.#N~ uOosX?3=/Y3֛3g;2(5L|*OJ{fBObQOsW3p)Fe XWEDpH)t> 'y$~H^(b ^Pv92&eZUьZ%GqŒ4i)Hȉ.c(h.H!9:%0ɺ{) 5Sy3٤KR:+eoGG6o!M?50w)mn$ d1iOkn}GKlI䐢PN=RV {Iy42 tQt;+U_wVeT1P Oq/]/σKO2גvo)l 2 cwˠ!w=swS!od಴D}ӵ:w#$aepiŹ4b딉t25̨qpVq&~.Qg4o.咍YĪ%!yi (gV*t!xmdEn+ @}ܳCNa&sȬI?.jGfo'ԏ/3fV;A˥6e]pe:h Iz CI."8iYǢ:ȜߟW(jW Hꇿ /L9ބ0n[#cNjec$` 7{2f/D36QAXL-8>2Q_"7jQM9t'~xo\t7B.iȕXO `ۙ`n*[r@xji ̙'ukO"Q?VY/k|kAy=f'."w4ba d^Gjbu/.?' ld1i,M[b_=zSWGf&5;wȓzKT/B}EB8'&v9CKe68Q]G1T+yY2%eu& O`$#Y [[ p~4S+$&ai9)/:^V|qfKSX%h\3:uOT] &Z(H8B7U>,M Fʠ'nH[ `Nz e[~5_PىW:gM5>|=ccnϦCOl7uuܺiCVīmg6SlL/V^Cxy&GKʽd$Y&l gURa9wɎ_%@Dض@|KL"~&YK/tl0vJgmjV^R[JU1}[ILUզ*"<%7Xrt:sH?h(mpL`%P$)D\~dq)}=sBWFYQB.};tzu{aT-^iBRq^_VN>ߞ%BtA׬n9l#"|txmtM|ixLjrÈgrf]6~D?fǵ]K| 9sX A4I^nH=:bb 9H=e9:lPXԏe;{Oo~V}yY"|͇F6Xi4i_ @zԨ\LWu]aB{T~I'5+'^A7 ϑ,K4limpZNEie&#Hkn:[tʄ4 G-\]^TFHbj, );+3 o`XU1,x!Ntb#T<'nˡՀ]ttyݏoⲴcQKJ*ZUCGrȡ\4dm}r{_ϑ lmrQ }Vo9d\rhW7I{Na]$b;1ld 7=v\jL7B`w|,| f!$hI=?=$-)Fgc=9v{#gə.c$uϥ\}BӖ8Bx5 ѐ`&۝yo.±PujQA>̷P[ B(;S׶q8!^6U0:Q^@=]oP0r8nJ22NzzcKY>&UQȞWw:Qbu$dIKYaOkn݉KXdD+Z?zYxhZKCZu"i 4fwFWdVz9E1ieufy}^WvsDdCb`fzYsg/;N_97rwЄcێvTv^4k3&ݔb& KqKoګa()8ɺBEf/l0۫~LmҬ m68ŇP\GB𷖝T9gF!mz`694VM9HϞC ܂d Y pH-LdRGWG-,+Npyʓsrsb9ګԝr\U5A(@ƐSg}E uƵ`(A~;T0#焰ނ%ޟ0K(E0weMO;7-%PVqiQRTDD (~Kؕz]6&>H/ dԛ< NV~LB]ĵW.yI >,r(sbu{+JMaidΛR/82)\ B1=,ܙ4_ 6|{3+ BB{ʩAuH ^&>M&LL w@#V0U`MQYuVAU/d1mp _#'d!x\puCw6ZMEtPbV % Ue& 7ܽ8M :F},*37# 2sEX-sN%i5 pbs!dc&\W2n1r6暸ohgXѮYoAZuۼ:ʯ]W\B(ʥPLJ,D+TD᪪Z8xEޣ6c Q?! |WqkqaXzXz(lKV IbP0+Yuߒ̆O9e8Sfx6$Xnw@*OjpjWg~]&;%mk. {`S0:#g1*ԍyxs%SoRQ (Ʊ2sl8šM#CLu@tR*u ]x~wO;hj2|%E-dD2a,L#]>lcYSQf\b;=ELc2ѓb7c7v;J~GƲ::GeR+)Ykdzu6%LA& 3e kہG6(}w"DBCԇөU4_vn@OSWʻ: RyrPGf 9H|{|؎KϦ@|8RóџQ8 dJxu Yf~DžĒc"YY{,D4brfNR1q"5%w J6}&$XFw;Qs6; _JDfYO6h ?1,JQ䱣?FC6iOKI'*_r*yЄ7 KCU=5mbbܔk<ȼh|!9#.U3Th1QHz|EK9-?{t\նoLw\YGbvub9EɾԂ*x΁xE;*k2'c68Ⴁ +h7J$4+6ʑЩ\ }Unce.*1Cdd)by'ĆJY#`b&4.S001W߀ԲaGp3k< 58P X3Rvd|7 jrLvWް?WNuՠ=\^BnHvV^6wFS3Ȅa!EYsӻ&q 㣖W oGXUΖs͡:iv+DlbIM &.ijjw` ()F̚ FO$%\ ;X"4l(d}`CI o) \9W"zR ܚU9MۮQxO  +ie!C0Э(D^ 7{؉x`!́ Y_sҕF1Η펗թ| {dKouVgF;٤~A 1F& )vKd!]>C弳YT`Çn?BgDVBēzpkg+kU!W:~=ifr"~ 2t !k}w䦥٬v5iLDʆoZmnq(dd"xMC8} oOLuZ+3;R% RlR62Wɖ%[?+AOi=gfuJ;ٰ l_$wqkwoH+6^Fg.{dԨ:`۫pTS2T^o3Ek{ /x?l0J>Yn(F f\VECPH45܀{7bSw7Ѫe 8RY<[d)z<ޛ)Wm=t9R{,H̨;OLBڄV72I9%Un%T +&ot0l8@IZM̓-7SlC*aPδ{਷~d;_BW(V3m{+{ݓ6ً =dSW(L ܾ+ uVp )=[#9|d5֪Z_{)H\^Tu# Mqoَ*FJ\k%Fw<Ƚ_ /ܾLeYvH0D3 +QHg^.Ƈ?F #UOozq׺̳%u bC0+ö'h}Er(Z-a O;+~s`im]D9)l)j (XYȌzng 9P?esw#h'{`"w`w~epQR9Pd`Wjt\p?-C]qt*^tζTZ4+!g$ 7Ys[.ɌTyrsړ{\X;dܹs%KSY/~yG+ŞKNPHhj~T3sw`$1Z}0ѩo[.UK>Q2ÐpsAVg2/) I3vIX)'ʁ_JFon>S]wxv}qO4@mLҹ=>YO s`Jj㺵TOXMp>iem;oW;nk XdC"9 6BK.xqҁN ӫL[tWQJV5`i߃DBn43=FN6ƺWY;`ԦyGD w+8;?z1!5O_1yexW1[onzVsǯÝdN5k5~¿"(.* W-H$gvG=aVKDmn,Zn*Wk$wYR98|閵e@P:2|цʇC2+ZB'٥Mոvj؎*zFkO< Wi $"Л/=bst_I7BE) `f9}#cfc~X9B.äPXۓCò?UcǷRlw P42E_NdH-.AYH0Kk}}+hsĜgI#=}j+Pޮ;tEpLBx~VQd+!5B+ uC5p&XFscnkVGSؗb:ݢLy\3BO{Bbg԰x~>VaHc}n ^ɭ3{ݒUUUƓ\Z5wc9hMzxV~Ie?V<Ԃ JW6$@dH3؄`Zw}Kb D,^704ڔ@!l* cq+ F&)fvs 9[f`WqZt{n\ӻB{pTod(LzsBM-UQG%gv폄䪘@I[9 2u3ȱ^Wn¿֣2&2ZonpšO%C<&m ح,w*M@96)9ۅuuU[- Wm'yqfrj4ѶgX@wK(?eEt=*<@P {\So6~GDWK?i*J3j$%0\03?+ǚXW;u+95,? ֣#%熐;kd]D1O!,m,Č+b9kC3@MlJE]I+: I3t|)5HiEn#g#r;0?ǖaZcBЙBcWC9*0TM 1YMFHۗ}ves*xr]Y 8}L /g/V[( Y?Tde1s6F8ǃF47" qrEi[useĭp!c۠R-K%Li5M<(fw {wsnr@mx"۞_'Ce-ny!%v RlR]sФ@8'2`&ݰqS2/'Lz,ŕ7h}Onמ)>T4%4Ćznx$#-nT<nKKKѓr+̻R/}=2GU x1)`cǂk_iЇF J<S{=g\A:1Y5ka(Es6CjLT+Vh qe")ԗm{7:Y >Jn6c[ gdӫV-t\(cC[tS ,B?LR܆lgA;E \,tam.m zv%E'1vK@1%j5x5Z|M+d .ߡ3yɴ4ߢu{ md_j~fvkg#xA@ȾG$72,x&.j1 iZR ɣ5H)^"Rc%<u򌾹_PvNwť'Uj6ItƮuYQM=% ._h 0Ƽ]*AZ4V  NX٪ ޣ뉐f)ona;8$sK$-R*d zPT޷>?L~OF+K!|VRBy/GN$il^䏈A @oa{m!<׉7a_I 'A4\$bo^i6N1TG-C >8%y.I,}.~g`XmjN;y1pZd'`e`&;pb)bŅ(AĽ ѳ[)-%z .'C{ ?sų #T]a_WQLQfGQ(>RȈj⭴{ \׎Mtef9;_ل\ rR0dzMxGFCHz Ggiġڽ:܅/b/~r5y/~ohs7 ٚum܇{1OO}KP2u]'iIl|4أ=d3˕Es$-ˌi6;􎄻ߕ!B4&zG!2 `bl_~RuȡS6뀣E6=M,_yĜI/.bXkٓCt/;X]}Ys>.5l[ڕKWldۀE3sQ.|?:vIWRJh{~M$t݁T2̉oZVe^M*7z2Vbx/Mi{oLϵ Zp`4!KOI/KJ#c뤣2*$Ԛ l$]8זZG&8}o;+|6;)qbv1ڢzl!lcobo9Q;Ƈؖ>2Cdbm^9f`8i9Y[` P<CוwU>頉xBD6Z-Ο8W28",y/HG^ /`t/p z}zvsE߀wa0KŚ'~lwW쾄q9Fo+ =U;8,&?u,e+ _pn{R,j-!ETHdBs:$m&sôt$o4u=ĭBSRe(O܎J" 8ۊrK֣/so݆keFxMmtV^!e-"燏J|1%Yc긺aLokEKC#\܎Z2<8=7JB[d%%o;GYQ,G /ݗZEZ;Z' Jlzцn4  s(I;B](B- 5_efmAtF"(!Qx.:laW~v,t~X;J쎚3~tvDW* q/`,PVM=Y*ӽ/?{jZ=p{=')0( X_ ;G-^r} 8:R r?U@ʄ Pm03a&|b雫frΘO-IAϑf; o/2Y!j L m*yh ƨ䣿 JЖA:yd#ŒX mVCw.mdskA=h-a7xīj%F%IF#{6b1qgLT,fnE_?$9lVVS~CPYufܧ~\1@ԩ%K?@??̇jrėϠ|ܨ@0%XQkMhOhޏi6_86Y<5ujf$cagcBrtq*H-'mw'x:|‰Ӣn |0N(o吩^ΰA[@´*WVm;}:kxq!FVFDٓ_t0șїx'i/i"˟pg$1;i<w"ඌZѕgoRlG?/Li}dzl#&+C^(;~qwUV"Fh&?TgFmE0/ gܭ8 G>.ψ/60!PRأPr2 6)b%x# p!fnA-Sɯ-WgЯ;xh5K-X/b~`V ;w~Ij ]G3bNڔ Z,ϩʸ  ]H/T0mgzyHd&tHAhݛ?3) &lZxF=Ù2Cvˠ6b~TLQNe쒿]SYP[ԏ/@w'as8dc\Gmׯ YҥEw|~[_ ,VMJ.oR عE~D/(*S MIhtXeC?gAm: AKi!X2Љ%習Y(Ulo =$BФfXz (2a oƤ+뀮JZY(ujry|-L[.S^aDQ4e"'& g~(:_­;nSPUoMOƽW8S /IJYmʣ- B|u=)eOH!-]FN[/?Ne pmwޑcB}Ǹ%arl.hnVg(瘪(w=:?Ъ,{UGq%끞hY"rIFvh$P!Q7XhII\+T Pr PHun d%Md改WZ *d5W#?fU+NLXu&:.Q, ;l\k~G'Q a}\Xe%]^O$<9J2a5jX vTˣ'ܸYf68o|#˟HY5i6%/菤zK蹋I hx!ҵb#WхN3} vl;r JiN~7-jaŽj1 z@7yEAHԋrY"1 %Ƅ;fF^ш@DŽķj9lvvX29u]i3Bg\6+Ŕ9"=+0^b*#x*TӾ|=#m/]lw*rx%% ĿK |ka*F&wCvJР_R/ +:3ߘi䤹$1P3ѕrpڄLQh?zHhQQCгPVhQ"=ZgU!/k.B?,J4疨M2X8O^-ĉ-cu/$So̔8W=Lz{Z晋gGGc\ld)5f~úgHrpߗ$eՔ?U5vrڛYlN9p^+Ї8OG ވ=3YރKۇoS٭a'!5TZak/v;#oLAH86gkf$1: bwm]Ic%F2E$]2gkH=1ZqN_ʳ<9B ǐ-oTS1ryB?=B>;_?pv/>EW p[ oi;K;w6bWrȷ$J5'H]Ȋ^?'7pzm̷:ĵclqP`@Iy֩Z[furW/:8UOA?\y=O=JkG7۷pޘC)>嘴Ⱥ:Dۣ%_guL 蹽~PTև$ItĜX:(g¶j:Lb_ЀzVa?KÜa"ނdDDXw֓[:ٌd&J whQZ>?bz仧aeo9 l6;C0QA\ ;[ez!b ,J^i:@s3$Xb|H [%p<;☸pՀȡb:$Ⰼq7[|!SgFmSEv@Dg "oo$ Iydp3"J,y5^*FP)Q ΂ײZ]Gb[fUl,c' twKp=Am֫1r}OwHNF˯ƣE(No-jxID4l/@߬ٗ#yc`Oani&uքApqPW7P;W%0@̇K}0ua8JbqTb6X-򱗿udžmŌb}6ZE{2l'%UQ6NMpwK@RY| _wAz6ցR Ubt|[s AKqt^x&g$9k] s6es.^/.`3'9brBN`c$,04jsey^K!'Kɨ@fgJI'rڨsaKy.ZA6QR9#LwU W;G̪pG> L܈'$el+͐\("RJw%iYTu$-)}TqRT}ӤUR\4Oy+{,]Q숐)/#;hfӑWּZsZzTClڻ'ό3?P:B{C-]IE:d?r ůWdmkuĒͷAW7mMxڅ-,0$9;1شnD=v}Fގ@4/u_}B-kb7-V&nH1#xBiRP(L)ϖGR&v[֯(\3&> '@ˈCr+ؤڲ42n$#s Qkɻs "U8Nj?*UV2du;GŲde8dOϙVi')K!tsrxPn$38m|%!f2&]fCluojo#4x4_a x7*WH&\T12Nr,QD Rb0Wi>BXJOjÜVڙ(K6=ӪuۮqCR*`Xi& A6J?Y{)iU#PH w|ѱ,{V}/y4sqUFcbl'u⨐vi#(G(}.yGzjVP")a?L^'46]Ɖ$LM?+[.Q㧝hqVaŶhhx,fS,w>HX.K0*uy$Xi}@8bD<JNJ~S=,hL|=]D"<L&;2V2hHMVaCR%6G`lHhziϞr}+m=*EYZs'CdvN -7[ 9 θ2k(\2p숐UԿD|8Z#RYzM̽8 } =&xoI_x$c ~-5韼y%Soz}p,5ڬZ1P&%D}Kz@owk"ҕ90Yԗ=z{ >{~hHf2YNfS"\@*5'6*5:!0)X:;Co̸PS:п+uJ{#"Mܘr]nϤp9<8m,嵰0 #.W+߶ ̐W>jv=+$;J䤧=UӴ[6/Egpy3о$B.RL+5{"!=0wQ -vF .gŨ`똧WVw<&%͐cҠ̙CENGQ}J>C~tvi7=*Zgň<'Jq8u}Ś}E3A"/tD9pX7M;VߣA`kKX`ҐdEq$ {4HBHX`FnTөq6Z3t.ݕOExP7Z{k |CTFIJ#R~Day/ʣ;,75ЮԴo" 7C}Z~+HK嬽@y{Sl"WBNgЈ&sJ#"= \Ӣp)&D7LtxpZpϮY+z# ~` u‡6$$y]Қ牃"Kߘ ?7GtSxN $wX[i+7FVLj&ߜ0~g(G -+J6p_k<ػY&c;Ssz?EKW ̈:wzw;r2TwMWٮC͗Ude!FDXlM- I7޷ Z%*85GP$8ErG,;r/; ‚9hй{a5W3$`(&wmHd%'Ӹ6&6D)M@,0(h7VZ /ml TG4{0ʎ!hy(BƚK;R[Q!ee[ųD2AgHSe74a~@T8@N;Gr a%gAv=gÓzUH8'!ntW:g0XEдx1EEq5ۜ+Db3s-28< EπYI\rYM'{1 Ma|p Th*8} g"9W~BTф#.gd~WDъH$nCW{܄y/$25pzx qb0*È~/nk)SzB ˼TMs/ h]''8 /`r2GLA"2g7&=1PwebKI&W/d.`9GټTqí}7qbg*E/trDVx #&8Q}5N/W- USxU8$j w` ]WO @lKWcKTWyAhOS?FQl5l8C5>7کMIp< Jp 4|՗XN,~QdVjGR "Z #2mIf_7H3#U`oC1X*2 E&J5jU!:lȶ  n3`@x'zLd@P!~ 0ԱЦT;f4(s2"7ۥװpt$Vn=nء yħ%3L(>?#fֳxREDNZ07آӇ(--6.dr˼n+bRb Ã{NBwEx g=y}{iJUbtsSo %߃H+]8 *,^™ KZEUqGGSni/"s ˆm'LY?U!ձ^Vd;cxgDBF# B6+h^ 8!1,7ME$źΒ%hRn&_$T0E'0HΚcz<2_'RCObݔ|aRdس^$ Fo$y>I|co*l)ߒk =m|PzbggolBǴdlEYBo\V^AI+D7^gMn"v7qWLJl:M.Bm;0(9iQ2$C^ϊod?2V8y#mM{a"APfki`MǝP1܊L2[іg>őgL‰ Hf!63LC}`K@D޳!ϋ uhFI7']((;q lY1Sދ~߿)8؅6j#A"P93pNFV?˽q5-I OJ#<iO5*]XR|6*Ͳp(p`͜Rws45_3oNݻHN+x5M6#|?^ #e6x:en}XH02튓\#m4nLSΝ_t8 H&n[2+#dy,$*eY<67?˲T@%]Z(jP54cBt+6˃ ,  tVs=;9-/܀̚86V✨V6VZtIJUn+ءnWR>aȖϜdQ3W|)`5 g+eӓV[& jŷƛ>>W `aȈ^u}n^kVXO8Jz ysPWݫ'n]C8a 㤼3k>}Űf눐Zn5f(f*ac(! FGnxkOa5zӼ`,9<FMo EHkGf[@<& 'ۧv'KHc]`aѰV\!2)<쪥,_\c=6TgYo'W$T!XL 'h25D(ƍY Q7ˁ @JBO)Qe^bz̓@$8dTG4K#/0S|BO9J!ikdʋ,O`oN-T\P2 Rtjla `h >H<::k$f^jChRPݓrp q*LLehEOu\HWw/;jCA2O3>_v5d/FiG9cs bgJfWFoVRK?ɠHaPu)ɈdWHO CrB;Q/:D$S37$̠joyHcdn#jstX] oY\O^htt,Qʈ4K &Q~ RϨunȹp{4lH7k^%JiS.ֿy:dYzka.18_?"bV!Y5ZvInڹ='CE Uu [P`3𘠇qވz_MD5f[V(򭈐CJR~FrcSYŲC,.?xHL>/]ZC7y#k|~C. 0R@5ModVI}45&aI&՜ $ pŎ,"] h}p ڸDa8h(]pl.SVHȋG.ƫ"LhDAH?;qN]_i1"Ixi'y`>.x'l=Z[ʈVYD$eC0;Ll#:RD:EOHMD{S²M"R1,CLD[ʴ *Ϭe?/9D[)+8WS5=<)l3(@gN1B3Oh<'`~DgZFCmLJkCN<$"` p{ laOxm)C$ /Ÿtt[g5 Hh)SAiF,}i5AEUuyK)ml6?*"JP1`8# £mQ3;e|} Űf$"@i~D sp|)/降/$ʯ5<| tn2H5%[^qO:!-aySQ}hqM0-$ָx '_GfP3k_kߐH Kl&FmEI:SGӐnC/&M S {kB;̙r`B0!շM)bҺ:Yۅ ٛIw_-7kSt1ӌ(zPQ hXr8jDC20220920104036i000000000116093 jDC,./  77778˂PGX/3G7B/7BP7BPCXG7? BPG7/=C/8B/BPB7BP?BPHB7BPG7?/9'4B7C7GXXAPC/E` 9?A7PX7/+C/&B/BP7BP? BPG7?/"C/B`9 A7BPCX7/78t Ba2 "!"!"""!" ;234sD$4c#3tTQF&'h@ ԕ Ba2  "!!"#"ޚP%'hf&(Ff&&h&fnd`&>&oF(H&&&H(f((&FhF&&H(hhHhH&(fF(ƆHFHf'&'ȦH4M    \nhrfrph&&FhF&&h&G((Hf&&HfF'F&hȨFF('Ȇ&'&TtMh}L NQ NPPэQPPΐMNP LMMNP ΌL MPPh!1") Ӆr90C67E2]ZB#3d#TSTT$33SctCss33C3C#DCc43c4SC#CS$D444S[f`bjda*!Ɂ )" ʉ)*!±) ɩ1 !1Udblhrlfnj.B6999A98Fר148q960E3A414FFC2FB928425C42E51992717C809A5FF4CF2F03F922D620E3A0C12uJ NLMΐLЌMNDEH(F(DŽ   \ \pbnlpr׃    &~38D33B952D3CA4E IL5o710AA592664A6A01C98338C46AE4F9364067CD43A224A77D4B47D02126C6DyUlnhfp *E828A843]@E'D3sScT$4D#S$cCD$S#d#ccCSDTTT$stC3dD3TdS$TCdd[~810739681224BDB$OƆfhHQ7E_s3d3DdD$dDCDdSSTc443$CCs3cDD4DTt3C3$$sSs#&b`bhnfpfjrj!mL ML`DC92BFBA489354B5BF53F8AADD17C9C4659524747F467FDB-tflrpfhlfnz&''HFH&F (B>G&(g(&&g&HfFF('(Gh&'&HF&Gh'ƴSFh(Ȩ&fhHF(N@dSc3c#Kkj`jpjpjpllh`dnprjbdbflddblrddbdd`lrlzs/Gh&&(FGGcTSTCsScS#4c433SdcSC4C434sc3sc$#dsSCScCdc#3STdfR#D#3CT#43C!* z )* )" ʩ )12 2ɑ11M |blhprdjbdDك LPNLQQ}=P̐ N͐ NL NPML  MQ Nѐ  NQP PLo≠j8C03214_㣯!*2ʡ))1!*  !*"*ʑ!112Ublhdnndrlt%+9A752FB]?3355FF10342D3521A87570D377CFA94151697E335AEC6FDA898FE5EDB38EB6Y#Ubdb`pnfhr`nt%9763DF0]?5C367F88C3A0550E10253DD69F76B7876D02FF72DEB028EEEBEFB5FD41C2B2Ƀ*8F8540C016448671q5!Dx !" "!!!##!#" 9q͸bxD226D4Aa)" *  *2)ɩɁ )  ) )1™2MT!8m @ I##t#3Cd33$3ddc$$S$##Tc3d#TD;f(ATldljjpjjTsj ]N NM΍P-Nx7"""#!"##"!!#!ӎO 883ccdDPz7" ""!"##!"  "" !PPQ M )#css@JGSSsDSS$dcTtcC#DT3CDC#dc#CCsCSCcDCdDDdܨCTnhb5/F209DB3D40B3988B75122DCD45FD1D84DC87D4A21415DB1CB7E894D47552/Ȩ&'GhF uMh,-}LP LQ L NMLLQP͍M MMMMЍ̐LM LN LPMMNLoMP "")2RK #"11 ! 2 )1ɉ)!)M Fy9318644]j123=_L ͌QP͌PЌM L NMN̐MPPPMNNN NPMQ LQLL͌j@ "!8QMNь`rjjplhfnjnjrppjhpjpf`bjdj`pbnndfpjzo(hhƦH&Gfrlhfh!AM6C3$#DTccCC3CSt#c$dTs3SS$$SS$4TSDc4Sd񩹹 ) t=`ǃ    ȸ"eyB7F5198jdbrbrbbffjnjp`jhlnlphrf`jpllblj`frdTZ>09A630B6D3DF33<6  pzЏ'(F(ƆƆF&FHTFf((F('f&'HfH6و QM̐QPPM/>x7569053!2±)*ʑɩ)ɑ!*)ɑ *2?"!#Ql 8Rׄ   ܸCи"dy6874342ǃ      vyB8A9713F(B14AqpO(&fư=zz! ""# !#!""#!!!#"7cC3DCtSCTS=I৯ 2 !1 2** ! ±ə1* ɑrb)2qEPʱ!©Q@PC3SS44T#SCDT4TSc$3#D#3$4$cdtSC#CX'f&&gȵmmHff&ƕ122T>G&(&F&'(fh&(H(h&&Ʀ'F&'gFHHhGfF4+! !*21ETpjlrj ߌn`rhblf`d``rjdlprj`hfnpldfpb`hbpjpnfd ""<!1!  1!"  ɩ1 !*mgCTC3DTt3##$$K&mh&H iFG}MPM ̍АLN ЍMQ MMQP QP L MN ͐Ml?!! YD5*40C25C66B@bjdp`hblhdfhbrfrhdfprlrbdhrdrbpf`nbjpndB"333s34C33W>CRCctSSD3$Dcc#3cd$CCc#DtscCscDCsS4$s3$cCDCCʐQ QMLPLPL\]hBD442ΔR_gCcD3DcCTSccs3$dCd3#Cd#Td3scc3$T4cc#ȯF(fƈ AIߣ-01?6BBB282BD737FFE945AF89A7108B70E626A980E8EA7B9A28F595AFE1908576OLь  L*#˃rx𷛡#!""!##"""^~2CEC3ED9C7188B4!<#&S3D$4DC$cS3$C#33#c#dsC3#t34dddCsCsS43dScCsT$SDd RMH+)QO}@׃k7F9DFDAC53BEF07CF14030DFBR?!!!#"! "!~MPMM,/&gư=z7"!"!#  lfhfhF'C&gdž ય +1"  !Ɂ!*ɱ)!1RM$Sc3$WK.mHfFPX}>KMM M͍ QLNL QQMN MLL NP M NPMPLk^MLM ьL,0GHHFiYZ}LGDSdCccS##S43C333dcD   f|>B69F2BA0FD7356\Khf(kBkrhhlhjphnplfhjlfjdldbrflnldp`rl`rjbpjhT"~16BB9AA47720603H,OFhȆƦ,|! "#"##"!#"Ӿ&f'((&VDC#CscWSD3#STD3#sC$sSdc#Ssd#S3cSSdtsctscSScD  ؈ XXf4d4#44CDtS$tCs#DtCtS#4$C4d3d3434TStS##C$S3$'G((&FfhƆfF5 " !2ɉ 2) 2))" "2 *!ə!(ȆHfgg&&(GjXGCccds##T3$CSTs4#Dd#Cs3$3sc$c$TCC$C344SsSs#s#DTt#"bljrr`jdn\1IY_vSD#DT$d3tS$4D4SDdC4$#t3s###s#4C#34d$3#S4S4$D3t#S#sir EYj5441B49D2RRUhpdldjfr`bhppfbpn``jlhnhnjhllrjdrlbjL3>"!""W'&(Ʊ0߈llp`hbjfhrdnhrdnjbphnnrrrlpfplln`lbdL3>?!#!Y<9PL a| QMN MQPNQ  QT'FffhƨfFHFȆƨh4!)!qznrnr' e&((ǨHh&hF&'fHLj((&'fhȈ&&GHfh&FfƦƦFȶq?"!#" Ql8i}< M LPPM Q M PMMLNQMQQ  P̍Q эMlS#" !!"YD4 LNL%vZ_VSTT#333Ccsc343TC3dt$$C#4SCcc3TDC$3CcSSc$Dd3ts#oh&'H(ghFF3S#DSC$u)mf'f&&fFh&fʧP=#ӌϏƆ&F(Uă" QDŽNPQЌ Me蟌QPЍLP P MLLPMА̐MЍ̍PLQ MQQoN r_pbpj]Dc߂rpbdnlhdbfhdddrpr``fdr`rjbpr`r`fdl`bphd`dbCT$4$Dd$tc#CK=͆ffFhrs}LLQLQLM΍ PΌML QMPMM LPLQMM̍iWdCt4S$!I#1.C39512F3778F92125BC22AE35CF128542B417B08FAE57BB9FA2BRK1qCDc#TTtCjbhf݇]CTCc4dtsC$$4C3cdsSDD$s33TCcSSDS$ddc#cC4Sddtc$CC3#fSd$Cc3$4cd!V$Cd#FȈFF MMP QMLLLNP ͐LPPLQLMjfFƆȆ&GG11"±6*brdnjphl`br`lppdnblnbjlrh`rfrlhfjbT  Վ)>tdlrbbph`$     Uޚ3d4$Cdׄ      ئ3#TS43cs$C#ʽ >_FC3cc$s3#cc4dd433D4D4$#tC##TCdc5 ՘f|~A3CFFF60A8DB63AO̍E>& (&&H&'ffFf&((&hfH&H&(g&h&hFf((F7'|nldnnnb``jDYw3C4ctc i}LWCt#34c3csC43#cD$d$Sd%f#$dC4s#CC3$cd#4$CCCDCDdH   24"" g9"+2 )ʡ)!"2!1)‘)"*Rͯr"st33S$TKcljjn``jrhfp`jnhp`bnfrjffrnl``rbn`hffnfhpDSь MLQN/N8%!@!a_css#cccc3dCCDSsscCTc$3C$EG<P"cuQx5B938A1x7DCF84B]j}]N MLMLLLQNQ PQ NNP ̍LЍNQQNi'$S4#cCdss3T㊠ Ix🛠"! !!"׬! #["1I[`kBdhrllnhnljfbl`rhdjdlhblFI ""!>_LP L*bK&&ȊrkpxcCpj``jj`fbfdjlnpfblbjhz}hbjldfffprrprbDӅMPLQMQ,/F(=!1!)¡2 ʱ1 ) "¹) )q򑹩 2ʱe ɉRl& 0DŽ    &Ɂ1¹ɱɹqephlhl$F PDŽ    XnFSs#H"" "7g3d3tc`׃    &.378698E2BAB7V'x6090D88h]`5/E15A0204325884D4C9FDAF524E6A39019EEA61D177C2749A485C15960C51},jhhfndlpf`ddx32B3F45Bf  H"ճ12)!Ɂ2!ʱ3tScdt#cc3#"Tbld`߈lfbfdflbrrf`nddjnbfnfhl`rn`phbfrj`djhfrjd2CT$SDCDcTCDSWK F߆fhn`hp`pj`rhpf`l`hrblrrpf`lldlbjbrpldT[>FB2DCF4F909F88\QP P5Ug_ XJWc4C#T3ccT$S3#4dsCT$C3sԡiƧ#s3CT#TtVnjh60B9DtzE9ACB1D0E299FBE610A7BD551B4AB624F05V>1FDF0B05C75BCC963E8EEEٞ_QLMѐQMNMM,*!x񠋑MNQMM MLNwMM Q LNNM NLLPQ M l[1Unjlrp`dljfbj!gL MRgz61A20B5037DV  JN͐ QNΌM Lȫ) e4P>&MFfH((gGȈƈ'&hFFh&&H&'(FH(hȶ"" "S K~>ܙ!!1*)ʱʖ  !*"q͊) ¹) !rEsjpjj,Fx#"!!#!!! !"#"{܄rf`dpbhrTQ3MMN `HJЯfH&&GHƆ&Q!#!"!"^|bbfjpdbjpbdyyE7BA3604K1} Ԥ&? B7kSt1ӌ(zPQ hXr8jDC20220920104036i000000000216133 jDC-+./  77778˂PGX/3G7B/7BP7BPCXG7? BPG7/=C/8B/BPB7BP?BPHB7BPG7?/9'4B7C7GXXAPC/E` 9?A7PX7/+C/&B/BP7BP? BPG7?/"C/B`9 A7BPCX7/78\gPL&&((&G(h'&'f&&ʸV$TC4#t3#DcDspUrbnpdd`  L 3u=ѐ  MQQ΍LQNЌPLQPLPQPPP P M LL Lo=b#4T3csC4$S$ (f(@ ɩ)‘! !1ɩ !2™1  Unfnjlldrdnt:F302CE3*j_#Cd4CdTtS44tC#cd333dT#d$Tc4#CC3##3S#c$34Td3$`hpnjh *21FEDA6FB`npdnpbbdbn`fhbjlhldnjlbn`nnr`brnp`n`nnpnl`zof(h'FE  Z\𿠠!  "! !##!!ޚPhG&FF&NPSDCd4$$>OFf&hff&'H&gFƈȨh&&&G(('fF4  ¹1kThnjllr`b`jnffhhjhldnfhbrpjbbbhnfl`hnnfbfhljzA!"""! @N QP=? QQNMN ŇQM ̐MMP͐эQLLL QMLLL L Lэi>MЍ̌ LLQLDhHM` !! "*1"* !ɹ)*12 ʹ) #!#!!!U'C3cd8F PDŽ    Ԙ4~5B901553044362E8Cs3dD55:DAF5A9F35AEB68EE403C1E711ED408E2BF19D1D42DAD6BE68EF{830E8F8yߌQ MP LL)#pr !!""!!#"F!!8N MQ~52571BDBB1D25A5AF56C96144E67BDCD8FDBA1CB2DA988C7727D5B4B71F1CC1J̌PP\/dpjdvxz!"!# "#4#34STSSC3dCQ12oSTSDds#D4DS4##CS$sS3c333$s3d#Ccc$S3Td3#S3##cdS(&F&h&NT#S4d$dB # 2!ʩ!ɡ !21* ɩɱ ) Uhlfbrrjf M&F}< PPMQP LLLNLPPM LMN LMΌLMQPM̐jį&fFh(g(H op_CdcSs3S$sSdddSSSC4t#4sDC#4$$$$CScC#CCCd#$D#t:33tc#T43sdC$$Tjjr`hpl bnfhrll`dplnrldldbhrn`hrlbjbnnjfbjdrjz('h(H(&(H=u=P~80BCC74AA133D46752E346EQC]`j`ddndhnnrldh`ljnbrdrhhrdphrzA!#88ML k4c>&'FHfȦƆH&H&HG(&Ɔ((G憆&f(H(F5d##CsC4T㊅ r_SCTSTSd4$DS$4s4$ScTd###DS$cctcc4dtC4t3$tCCCc#XG$#3433#$4#$Ӌ^ ͍Qh}L MLML MMQN LP QL L L LLM QP QMNN L ЌjͯHfF&&&F(Geff&'F j}\/2F55DD7312273A4889E238BB31105FD6FF9292B9575E?U`rdf`prrhffpt:93868BBjǃ   Јf.?! !"SFeGF&FȄ34@tsC3#C34CsCcscS#DTSDc3$C$Dts3#tS33cT33cddDsSCCTScPEHFFF&f&&&cDd##d>f('F((H&GG榈F&&&GFHȆH(&ffffƦfȨ7|hdb``h\1ZL/F1E5C7D3D223B10DCB8A986D7F2E443E05AF2EB7B39A815F16BE6AF8A55A#Unrd`lhffbnj!QN [5@u_f#tccc33s3dC3T4SST34#d4#Cc3#dTt#C#SDsc#D$#P(hH&&&f(N0s#tSs5Y\5o9A86F182D19AACA016F89E8F8A12508FEDF87A387D0A2F4314CB240C205AB-~5BF9E89618D48FA(?oGƐx#"!# !"#!"##"n? "7;5033C8AA}lO ͍LQN QPP ML PMPMM΍͐QQQM  NPMMP jįfHf&hHP""RAwCD##ds3DSD$T34T$tSC4C4cd4#33S4#D3$3cc3DdTsscn  ݸ" 1y|5oE9D087F2067E5127162F010A0E2053A597DDE796545C7A2C0E52B047E0635LL  N MM*̓!q?x𿢙!##!!"!!"#!"#|!* 2)qjddlb !111)!! ) *) ™‰1*Ɂ11)ə!" QMP ±5jC82F03F95CE9FFF6A2E781415E0A903B0DEFF790C1F36FDDBR1"1rM! 2"REy7B70522" ׈j`h`fppdn`ndfbhfdrffrhdphnnrfbhlbjjNT2!¹1ӥ,3S3D$#$B+0yrbhlnbhl`jhlpphbrn`fbnl`dbj`jr`nbnjlbdhphrfbT{l~27C9C5799FB8686*A2E44053]9zn2244AB4F4AF52NЦ/5F256A924A5D1C9ED323B52CC3F14A23AEA503FA3BBC9Gc3CTc3#3cccfy802D081F5?F7BDEE518157ECD18968BE6E4AC17B2666FBB2A47789EFD84F05F21691200E57#C4c4dSC3$ 8v}< M̌ЌPPMPьQQ MQPQQLLM MPQ QMo=  yBBBE2BAg*" *5c$SS4S#Ccd3D344sCCD#SS$#D434TT 2* !!"rEjj`j$ }=[LQ ̌ NQ QQЌ NPP NMPMNPАM M kߌ L NQЌQP΍+&w#$cdSdxDŽ     fG䨢kT`d`r&x>&Fƨhƨ&(FfF(g&''gF&fHF('ghȨh&hf&&Hƨ&FJL QLL QPnC$s#T#T-f&f&F((&'gƦ(fHH&Fhh&f&Gf&G&('hHF5?'D$ScDTc`RTc##cC}  )Q $憦HF&ƈHfH'wCdtS3T@}3#dCCdTd4dCSST#ssS$3TcS4C#3cd$3TSDs#3ccT#T7#CSCD44D"%DZj}\\hddrlbdnbdO}dlfdnfflnpfffpfp`l`nhdnpdlL?! WOHf&H2h=OOQ LNQPQPPP̍ PPQL P  QLMPML QQMk'*A203B4445FD1AF90q:">1#CSc#3#r\gf&HƦFhƨ&f&hffFhfƦ&hddfnllr`np\Y" I1?3D6E0C3733A036E06528F3762E89AECE4298D0602A3CF1BC8747951D3FE466l~2707A0C25A286198"sc4$d?@@@@IY]*±))!*)" !!©M~6307516653F83D4hm LP#l!׃    Ѩ&%drf`rdpbpl`T*49E26943] oF387B0878F07F4D893180CBE03682B799E915E8C0B47A0A8CDDD580B273E6 ļ!"AScdcCC#ccC#SCdt#33T4ScCCTT#SDstc#CT#T$$3#jpnbhppDуgcdcSS#)(lfjhhjnhbddfddrrblfphdnhbpnjdlh`fj`llrbpljlprrdd b834D8F60nhpbnpnfnrnbj`blbnbldpn`nnbdbrfrrjrpdnfnfhTs# ļTnpjp`8h('ftof&&(Ff&gFH&h(g((&(ƨ&(4)1)rhpbddB#Sd4S33s#d3##sS#S3dS3cTDCDctS3tSsCSs4s3D$H˯&&ffh'HHz!!!"!##!v~E7E75E219D6A463 2 tBB_vSd4CTc$C#c4C#d#C3DC3t3D3ccdcdDT#s33sc4d34Tgd4SC#S4CST#˼ƹ g0?9056DDF0D40648EFA52BFBBBC32E752E5059106F87E86F58DC2DF0B6B93FE1ٞ*ACBE4F74881EADA0q$lnd`f581?A463359197B0BE43B1A101EC200220230BC688FA6941DDB726456B1F042280--ȨȨH&Hk tMh}LPQL͌LLьLPL͐P ͐MMLP QN ѐTѫ1 2MWc$SdSSC3S ^CDFDDTCts3$$SscDsSds33d$C4c$dD3s34T#S#4cCTCcTCc3$D3c4#S3#+8&0ׄ    &"Nu63tStC3Ӌ^NЍcQTXq?F230BB829E24655DD3654736A4F08025CEC27A2015DC80847481F72DF5465F閟 PPQL L/^x72AEA89yE*B15C6246RDuphbhpp`lp`pnd`n`rllllflbb`jff\X\pfdnnnbblnhllUpll`{F_f$3C33c$33CDTd4DdCcTD3$cS#Sc#c3TD$TTCSC3c3tCc#c(1311J[rlfp\2!Zj}\ M LQLL QM M M  ͌ N QMЍl?" "UWTCDTcɎ׃    vf)"ʩZM ̍#i}LO MMQ NMLNMN Q  NMPNL͐ M MΌj((&GH&'HMgs#D3D,|?667B42A317718CB5294547E6A8DFA2C461EAFCE5D81409B8BD766228241FCAٟ*EB02E9BA47ACA381q:ŏǃ    փߍ N L PL*Ƒ! ZHH_v#cDTC#T4#44dDC43$SSCd3##$dTctd$4$Dd##CC$t3#46CCC#ST$cT3S#(B&&F(#}=M M  P NNNQ  ЍLPMP LLNMN PLLlSƛ*4?B8E03BA705D39FF477686157CEE4689BC4F2FF0F8AFA9B6EC22E7B76009C76[LMP L*HegF(V`ׄ    vA܈b,"#q?F24DAE09EC91C18E808C9871F8C1736C432F97034B329AC15411CFA2316B51 MQL N΍-7ލь ьdTVz!""##!"!# "ٖ~DB04B75735593CCKEFȨfkBc hk߆rjdnll`j`hlpnrbfbfnhbpfdhfrbrrjfljhfbjfdӲЈb/OgF-\z" !"#"!#!"!"!# !!.g`djrr`jnfhr\1Z!I~1/13A2143351DC5344A1E0DC1D397B8EACFC3E768C2CB35325B08EC7312ECE$|jdfhhnpT1HN Mbfp`rb`lbdbljlrflhfhhrjbrlhpjhfrnlhpAƶUp`djdb`phj2""LVc$#D$CcSs##tscDs#D3TT#$T$ST#D#S$DtS4SCc$ۖƆfȈHF'Cc#Cci0׃   ëp *1)*Nū1r|&   ʉ)2"")2ɡ!ɑ1ə! )* 1YGTcdd$dSC#Sc#w@*ɡ6>߈bfbbjnffbbbnbprfbfhdnpfpdnjbljl`ljl;- ʩӥh#DcT4S$$B crrjn`bhbpjnlhplllbbdh`njjj``pjbbdd;3 ƣtNh9:}LOMMMЌ LNQPM N Q L MLPMMАˢ3Sc4$D$Jo&FƆFFf(ƆF7343h#?C98269F1547CAC14F6E18D907CA3020084B2B43EED33C027EA7C4E0CADFC63i*D8A9AEF7CA8028C0q:""!󁧏!" !  1!!*ɉ122)12 1QͭB#Dc#C33W+©)"Bz|~z?""" "!! !!#!Ud`rppndddb ^LАLcə)"!)1 *ʹ1222 2* !1Ubdffnpjd`tzE4922CBEB&Ԃ#!!!!" !!#"!"{j`rhfnpTQ6^ QЌ$󃨏h :4BA53D9824105B5A40F23F4C369A55EA9E63368F1ADA264243b4dC$ST3#sCspfb>1  ! ©*12B?""!!"#"""##DStTScD3D#0"FQQRsSc$TS$cDSdCSt#cdssDs#SD##TS43s3C4TtS3sSS㚧G3dCC4tCcLx9BADE63FH&f&(&F&h('fh&('('fF&f('''f((ƦH5e'TD3ts3T3TSbfnjp)>qJ_!"" )!±1)©)ʹ)1) )*QMH F[Xn\,o5D097158BA15C9C1246B8DE51A9D7DD3276C46108DF1C945FB43E2068D74996UplbrnhbhlbhblbtI%Y&S@S_bDssSctcCc##ccS$#S3$d$T$33dSS3T$c#3c$Ctcې2UPQ*Ɖ!).4>&''F&f&&Fƨ(((hH&fg(GF&Fff(&Ȩ((F5&G&H&'F(FHzz ""!!!!"̯"!Yuьiǃ  Hf F?m&XTT_B3cTSC3$3t34DTScSS#c3dCC$34cC###4D4cTC$T3#$d9r3 1!)" 2eˋʱQ$T}=[QQMQL NM QэMQLL͐QMNQP̌L ь̍ N k͍Q ѐ, x!"!" "#""ӬO%FF&*[Gd()VoukB Bt|7kSt1ӌ(zPQ hXr8jDC20220920104036i00000000034910 jDC./  77778˂PGX/3G7B/7BP7BPCXG7? BPG7/=C/8B/BPB7BP?BPHB7BPG7?/9'4B7C7GXXAPC/E` 9?A7PX7/+C/&B/BP7BP? BPG7?/"C/B`9 A7BPCX7/78t Ba2 !!!!"!""" "!;Rc3Sc#cD3Cq&H&(@*+`Pkldbhpnjhnfrjbplhl``flbnpnbdlb`j`hhfpjplbf`hzkB k“в?"!""!"! """""!ޜ ɉ)))0ddtc#C׃     f-" 88 N L\}rSD#4Sc4dSz32"!)!2!! 2ɩ!1)*ɑ! ?#!!!Z'c4DcW_  5R!"͍ML̐ MNN\ }<   ք_PM QQ Q)r##4dc4D#$'&fFf(fffF&F&fHH&&gȦ&fƈ&FƆlj``djj`pnL+OfHhF0b}=MMNLQP ̌M NLQQP̍QQLLP΍Q LN ̐Po=ݘ3*F3D8CB5DB>&f(h((ƈffF&&(FFf(HFFfhHfhfhF5M M   QPLN fF&&'kB+ 0cpbdnlrhbdhfrhhnhjnfphdbpldffnpl`dlnphrzkB#!""88JMNQ P-zPEfG('&'(]+ !* 1*1))!)¹!)ɹ1iflrlfrnnrftzA47A2F8A]?90A9D5D5C1B195FC88FB6B222534C150F6D2DC5C4496E40F79AF80B784436CI !QDC$3c@Z_c$3T#s#C##ScDCcS4D4Cc#$CScD3D334S4#cc$$4#|dfdnldhrhjL" # 4>&O(HFFF(F(hH(FfhG(('&&Gƨ&G('&(fFfh&hnbdrjbpl\1Tjnnfhnb׃   ԘX>8D2598F945CF1AXG#$3c4(>z""##"  ! " #$_̐ьPN эPN(''fF>(&F&('(fHfF(ƆfhH(((fhhF(F&gƦh&&'&F53#C#S4TC3#dSS21B{ knldfn`fbnnndjbrdhhfjrhlpdfnhljlpbbpbpjrbndTF~4E91C3CC5EF8F74h"*89F8423EB"d`bnrdhnbbblpndplhphfflbjhf`ljb`lhbh`nprL##!!U&C#Cd$d r}< LLPQ  L PPQ M̌L ML N MQPPQo=244#CC#4tSTD3T#dQ))z` ə 2)!!! 1 " *!"*ɡM~6A6B1A24EB675F9A&f&F. !" 1 *")!!1"ɉ!ʩ"  1Qm@D"##!AL NMQ N͐MM QPL1* "‰")"" !"1Mjfrplh`llpTQ|*253A6FE1]o9C5C8EC37EACC3E95FA51217E8A021B9975F7ED3459D6CE2DBA94BC8AC71B9=  Jp󆌊jfjbixy}LG34sC###cTSDcSDc##s<jhjfr`bjl``jnfdn\Vpdj`djjpTQ|LА"!4>&'gH&F&&H&fFhF&'Ȩfh&GȈ(f&'(4+ !" 2k "Gln`lbbfdfnpllnnhnrrp.ܳ ʙ! *  *qPEh&Ȩ&f&VG3T#T@_C344t#CCcdCSTCds##3#4dSsDT33s#tC3T##D#cd$S󫡩1 *"kN)q/௏  2!ɱɑ1!*© 1D !#"! ׬""Wd,"#"!!?732127DB2B907DCEF4E87D8979146A43FA7AD915DD7587A8A890455F51FCC1J  LPPD%('f&>g((hfFg('&hhffh(&(f&f&&&F(&FhHFFG(H6N Lΐ+ NL P,M0` *™ɱ)ɹʡ"** !1"" Ɂə)™!rM2ɑ1!1> 00000026 ARCHIVE;HIDDEN;SYSTEM; ``` ### Refactored help _The "no command" is now this (a bit tighter). Of course Windows and Non-Windows are different_ ![ryzen cpu](http://www.francocorbelli.it/nocommand.jpg) _The "help on help" (can be asked by zpaqfranz /? zpaqfranz h zpaqfranz -h etc) is *more concise, but more readable*_ ![ryzen cpu](http://www.francocorbelli.it/command.jpg) ### Commands "kind of C: backup" g/q refined a bit Default exclusions are: - c:\windows - RECYCLE BIN - %TEMP% - ADS - .zfs - pagefile.sys - swapfile.sys - System Volume Information - WindowsApps (maybe) _Switches_ **-frugal** _Exclude program files and program files x86_ **-forcewindows** _Takes C:\WINDOWS, $RECYCLE.BIN, %TEMP%, ADS and .zfs_ **-all** _All EXCEPT pagefile, swapfile, system volume information, WindowsApps_ ### Starting of reparsepoint support _Windows have a LOT of strange files (for example in WindowsApps folder), work in progress..._ ### 20-07-2022: 55.4 ### Command q (paQQa) on Windows: archive ("fake backup") of drive C _The new command archive (a large part) of the C: drive, excluding, by default, the swap files, system volume information, and the Windows folder **Admin rights are required, and the C:\FRANZSNAP FOLDER MUST NOT EXISTS EVERY KIND OF PRE-EXISTING VSS WILL BE DELETED**_ _Usage is quite easy_ ``` zpaqfranz q z:\pippo.zpaq ``` _the -forcewindows add the c:\windows folder, the %TEMP% and ADS Almost all add() switches are enabled, with the exception of -to_ ``` zpaqfranz q z:\pippo.zpaq -only *.cpp -key migthypassword ``` **This is NOT a bare-metal restorable backup but a (blazingly fast) snapshotted/versioned archiving of precious data** _On my PC updating the "backup" (aka: new version) takes less than 2 minutes for ~200GB C: drive_ _Note: some special folders cannot be accessed/archived at all (Windows's Defender, CSC etc.), because Windows does not like. I am working on it_ ### 16-07-2022: 55.2 ### Command r (robocopy) MAYBE works with -longpath on Windows (caution using r) ### Some minor fixes in help ### Source code in "Unix" text format (no CR/LF) for easy ancient make compatibility --- ### 15-07-2022: 55.2 ### Some fixes on ETA computations ### A little bit better handling of verify on legacy 7.15 archives ### -verbose shows individual % of files bigger than 100.000.000 (10%) or 1.000.000.000 (1%) _One of the problems with zpaq is that, while updating a large, little changed file, there is no response: the program seems to hang This is evident, in particular, for virtual machine disks, hundreds of GBs each, in which perhaps only a few MB need to be added to the archive. In this case you get zero feedback maybe for an hour, then 5 seconds of ETA, then all is done. So now, using the -verbose switch, you get a progress indicator on big files (nothing on smaller one to reduce console output time)_ ### -touch switch on command a add() _Converting a legacy 7.15 archive to zpaqfranz (aka: saving CRC-32s and hashes for every file) IN PLACE (=without extracting/repack etc) is not trivial and potentially, it is a dangerous thing to do. As a workaround I implemented the -touch switch that, during the add phase, "fakely" change the timestamp of the files. Therefore IF you own the original files, you can switch from 7.15 to zpaqfranz in two steps Suppose you have a **z:\1.zpaq** file, created by zpaq 7.15, containing years of backups WITHOUT **CRC-32**. Now you want to use zpaqfranz to get better testing features. The data folder is **c:\nz** and is available_ ``` zpaqfranz a z:\1.zpaq c:\nz\ -touch ``` _This will force to add ANYTHING from **c:\nz** into **z:\1.zpaq**. Lenghty, but litte space needed. Then_ ``` zpaqfranz a z:\1.zpaq c:\nz\ ``` _This time **without -touch**. Add, again, everything, BUT now with "true" timestamps. Yes, I know, it is rather weird, but the complexity (on the source code) is minimal. It is actually possible to carry out this operation WITHOUT having the data archive available, and in a much faster way. However, as it is normally a one-off operation, it is enough for me_ --- ### 09-07-2022: 55.1 This new release introduce... new features # As all new code should be deeply tested, before production use ### Compile on OpenBSD 6.6+ and OmniOS (open Solaris Unix) r151042 _Not very common, but I like Unix more than Linux_ ### (Windows) sfx module updated _Now, if no -to is specified, it asks from console where to extract the data_ ### General behaviour _Show less infos during execution. It is a working in progress Switches to REDUCE output are -noeta, -pakka and -summary Switches to INCREASE output are -verbose and -debug Advancing by 1s in progress infos_ ### The "dir" command, by default, show dates in European format _Instead of 2022-12-25 => 25/12/2022 It does NOT use "local" translator, because it's way too hard to support many platforms -utc turn off local time (just like 7.15)_ ### -flagflat use mime64 encoded filenames _In some cases there were problems with reserved words on NTFS filesystems_ ### On Windows more extensive support for -longpath (filenames longer than 255 chars) ### On Windows -fixcase and -fixreserved _Handle case collisions (ex. pippo.txt and PIPPO.txt) and reserved filenames (ex lpt1)_ ### Disabled some computation. Use -stat to re-activate _Some checks can be slow for huge archives (reserved filenames, collisions etc)_ ### The -all switch, for turning on multi-thread computation, is now -ssd _In zpaqfranz 55- -all can means "all versions" or "all core". On 55+ (zpaqfranz's extensions) for multithread read/write use -ssd_ ### command d _It is now possible to use different hashes zpaqfranz d c:\dropbox\ -ssd -blake3_ ### command dir _It is possible now to use different hashes to find duplicates zpaqfranz dir c:\dropbox\ /s -checksum -blake3_ ### Main changes command a (add) _-debug -zero Add files but zero-filled (debugging)_ _If you want to send me some kind of strange archive, for debug, without privacy issues_ _-debug -zero -kill Add 0-byte long file (debugging)_ _Store empty files, very small archive, to test and debug filesystem issues_ _-verify Verify hashes against filesystem_ _-verify -ssd Verify hashes against filesystem MULTITHREAD (do NOT use on spinning drives)_ ### Command i (information) _Is now about 30% faster_ _-stat to calc statistics on files, like case collisions (slow)_ ### On Windows: new command rd() _Delete hard-to-erase folders on Windows -force Remove folder if not-zero files present -kill wet-run -space do not check writeability (example delete folder from a 0 bytes free drive)_ # And now... the main thing! ### command w Chunked-extraction _Extract/test in chunks, on disk or 'ramdisk' (RAM) **The output -to folder MUST (should) BE EMPTY** The w command essentially works like the x (extract) command but in chunks It can extract the data into RAM, and to simply check (hash) it, or even write it in order_ **PRELIMINARY NOTE AGAIN: the -to folder MUST BE EMPTY (no advanced checks-and-balance as zpaq)** There are various scenarios 1) **Extracting on spinning drive (HDD)** zpaq's extraction method is not very fit for spinning drive, because can make a lot of seeks while writing data to disk. This can slow down the process. On media with lower latency (SSD, NVMe, ramdisk) the slowdown is much less noticeable. Basically zpaq "loves" SSD and isn't very HDD friendly. If the largest file in the archive is smaller than the free RAM on your computer, you can use the -ramdisk switch Extract to a spinning drive (Windows) zpaqfranz w z:\1.zpaq -to p:\muz7\ -ramdisk -longpath In this example the archive 1.zpaq will be extracted in RAM, then written on p:\muz7 folder (suppose an HDD drive) at the max speed possible (no seeks at all) 2) **Checking the hashes without write on disk AND MULTITHREAD AND MULTIPART and whatever** The p (paranoid) command can verify the hash checksum of the files into the archive WITHOUT writing to disk, but it is limited to a SINGLE CORE computation, without multipart archive support The w command (if the largest file in the archive is smaller than free RAM) does not have such limitations zpaqfranz w z:\1.zpaq -ramdisk -test -checksum -ssd -frugal -verbose will test (-test, no write on drive) the archive 1.zpaq, into RAM (-ramdisk), testing hashes (-checksum), in multithread way (-ssd), using as little memory as possible (-frugal) and in -verbose mode 3) **Paranoid no-limit check, for huge archives (where the largest uncompressed file is bigger than free RAM)** zpaqfranz w z:\1.zpaq -to z:\muz7\ -paranoid -verify -verbose -longpath will extract everything from 1.zpaq into z:\muz7, with longpath support (example for Windows), then do a -paranoid -verify At the end into z:\muz7\zfranz the BAD files will be present. If everything is ok this folder should be empty 4) **Paranoid test-everything, when the biggest uncompressed file is smaller then RAM and using a SSD/NVMe/ramdisk as output (z:\)** zpaqfranz w z:\1.zpaq -to z:\kajo -ramdisk -paranoid -verify -checksum -longpath -ssd Recap of switches + : **-maxsize X** Limit chunks to X bytes + : **-ramdisk** Use 'RAMDISK', only if uncompressed size of the biggest file (+10%) is smaller than current free RAM (-25%) + : **-frugal** Consume as litte RAM as possible (default: get 75% of free RAM) + : **-ssd** Multithread writing from ramdisk to disk / Multithread hash computation (ex -all) + : **-test** Do not write on media + : **-verbose** Show useful infos (default: rather brief) + : **-checksum** Do CRC-32 / hashes test in w command (by default: NO) + : **-verify** Do a 'check-against-filesystem' + : **-paranoid** Extract "real" to filesystem, then delete if hash OK (need -verify) ### Yes, I understand, the w command can seems incomprehensible. In fact it is developed to avoid the limitations of zpaq in the management of very large archives with huge files (for example virtual machine disks) kept on spinning HDD or handling archives containing a very large number (millions) of relatively small files (such as for example the versioned backup of a file server full of DOC, EML, JPG etc), to be checked on a high-powered machine (with many cores, lots of RAM and SSD), without wearing the media. As is known, writing large amounts of data reduces the lifespan of SSDs and NVMes (HDDs too, but to a lesser extent). And remember: the **p** command is monothread AND cannot handle archive bigger than RAM. To make a "quick check" of the "spiegone" try yourself: compare the execution time on a "small" archive (=uncompressed size smaller than your RAM, say 5/10GB for example) zpaqfranz p **p:\1.zpaq** against zpaqfranz w **p:\1.zpaq** -test -checksum -ramdisk -ssd -verbose ### One last thing: 55.1 is developed and tested on Windows. More developing for BSD/Linux from 55.2+. And remember: the embedded help (and examples) are just about always updated ``` 20-12-2021: 54.10 media full check franzomips -checksum in test 04-11-2021: 54.9 -nilsimsa -nodedup -desc -tar -orderby -desc -flagappend (robocopy) -minsize (s command) 06-10-2021: 54.8 New purgesync command, exec_warn, support for "strange things", .ppt with .xls, fix, changed -kill to -zero in extract 25-09-2021: 54.7 Support (maybe!) for ReFS-deduplicated VHDX, verify now supports multithread (-all) 18-09-2021: 54.6 Refactoring, some fixes 08-09-2021: 52.3 SFX module (for Windows) now support encrypted archives 07-09-2021: 52.2 SFX module for Win32 too, LZ4-compressed 06-09-2021: 54.1 SFX module for Win64, some fixes 31-08-2021: 52.21 Some fixes, less RAM usage, Solaris port 21-08-2021: 52.19 -paranoid in test 20-08-2021: 52.18 -sha3 (SHA3-256) -md5 (MD5) 17-08-2021: 52.17 New switch for add() - freeze outputfolder -maxsize something zpaqfranz a z:\1.zpaq c:\nz\ -freeze y:\archived -maxsize 2000000000 If the archive (z:\1.zpaq) is bigger than the -maxsize limit (2GB), it will be MOVED (before the execution) to the -freeze folder (the y:\archived directory, so **y:\archived\1.zpaq**, **y:\archived\1_000001.zpaq**, **y:\archived\1_000002.zpaq** ...) **without** overwrite. HW acceleration for BLAKE3 on Windows 64 zpaqfranz use 1 of 4 implementations (if supported), SSE2 SSE41, AVX2, AVX512 for the BLAKE3 hasher. it is not a very tested version, I use it mainly to compare performance with the Rust version Fast check zpaqfranz b -blake3 -sha1 On SW implementation (zpaqfranz <=52.16) BLAKE3 run slower then SHA-1 (about 2/3) You can see here zpaqfranz v52.17-experimental **with HW BLAKE3**, compiled Aug 17 2021 Usage: zpaqfranz command archive[.zpaq] files|directory... -switches... 12-08-2021: 52.16 zfslist, zfspurge, zfsadd 06-08-2021: 52.14 in add() ``` -exec_ok something.bat (launch a script with archivename as parameter) -copy somewhere (write a second copy of the archive into somewhere) Add 2nd copy to USB drive (U): a "z:\f_???.zpaq" c:\nz\ -copy u:\usb Launch pippo.bat after OK: a "z:\g_???.zpaq" c:\nz\ -exec_ok u:\pippo.bat ``` 03-08-2021: 52.13 New hasher -whirlpool new commands zfs 31-07-2021: 52.12 In the command a (add) it is now possible to use -blake3 as file integrity checker 30-07-2021: 52.11 The CPU cooker: in the b command (benchmark) now -all (multithread) and -tX (limit to X thread) 29-07-2021 Very rough benchmark command for hashes-checksums test. By default runs 5 seconds each on 390.62 (-7) KB To be developed in future (in fact it is a BLAKE3 mock up test) YES I KNOW, THOSE ARE REALLY CRUDE BENCHMARKS! zpaqfranz b zpaqfranz -? b 25-07-2021: 52.9 A little more faster in -sha256 (2%) TWO TIME faster in multithreaded -sha1. Up to 6.7 GB/s on my test PC Implemented, just for fun, the -wyhash running on memory mapped files (not so fast, of course) 21-07-2021: 52.8 Support for storing XXHASH64 as default, plus a fix for XXH3 on "strange" compilers 19-07-2021: 52.5 Support for storing SHA-256 for each file. New switches zpaqfranz a z:\1.zpaq c:\nz -xxhash (the default) zpaqfranz a z:\1.zpaq c:\nz -sha1 zpaqfranz a z:\1.zpaq c:\nz -sha256 zpaqfranz a z:\1.zpaq c:\nz -crc32 zpaqfranz a z:\1.zpaq c:\nz -nochecksum (like 7.15) 11-07-2021: 52.1 New switch -filelist zpaqfranz a z:\1.zpaq c:\nz -filelist zpaqfranz x z:\1.zpaq -filelist New behavior: store by default XXH3 and CRC-32 of every file (to be completed) New switches -checksum and -summary in list zpaqfranz l z:\1.zpaq -checksum (show CRC and hash if any) zpaqfranz l z:\1.zpaq -checksum -summary (compact output) 02-07-2021: 51.43 n command (decimation) 26-06-2021: 51.41 help refactoring (splitted map) 20-06-2021: 51.36 help refactoring 16-06-2021: 51.33 commands r (robocopy) and d (deduplication) 06-06-2021: 51.31 -715 Works just about like v7.15 22-05-2021: 51.23 First "working" stage of -utf, -fix255, fixeml 18-05-2021: 51.22 A lot of work, experimental extraction of too long filename (and many more) 05-04-2021: 51.10 New branch: single source code (zpaqfranz.cpp), to make it easier to package for FreeBSD and later Linux 03-04-2021: 50.22 With sha1 ... -all runs hash in multithread (DO NOT USE ON MAGNETIC DISKS!) With sha1 ... -verify compute XXH3 of the entire tree 01-04-2021: 50.21 Use XXH3 (128 bit version) instead of xxhash64 Refined -noeta -pakka in sha1() 29-03-2021: 50.19 New "hidden" command kill Fixed a bug extracting files with -force over existing (but different) ones 26-03-2021: 50.18 Fixed some aesthetic detail 22-03-2021: 50.17 Fixed the "magical" help parser +Added -minsize X and -maxsize Y on the add(), list() and sha1() functions zpaqfranz a z:\1.zpaq c:\nz -maxsize 1000000 +Added exec_on something / exec_error something execute (system()) a file after successfull (all OK) or NOT (errors/warnings) Typically this is for sending an error e-mail alert message Something like (with smtp-cli) smtp-cli --missing-modules-ok -verbose -server=mail.mysmtp.com --port 587 -4 -user=log@mysmtp.com -pass=mygoodpassword -from=log@mysmtp.com -to log@mysmtp.com -subject "CHECK-ZPAQ" -body-plain="Something wrong" -attach=/tmp/checkoutput.txt ``` zpaqfranz-62.2/COPYING000066400000000000000000000231211477324740300145240ustar00rootroot00000000000000zpaqfranz ========= ** As usual, this software is provided "as is", without any warranty ** __ _____ __ __ _ __ _ / _|_ __ __ _ _ __ ____ |_ / '_ \ / _` |/ _` | |_| '__/ _` | '_ \|_ / / /| |_) | (_| | (_| | _| | | (_| | | | |/ / /___| .__/ \__,_|\__, |_| |_| \__,_|_| |_/___| |_| |_| This is zpaqfranz, a patched but (maybe) compatible fork of ZPAQ version 7.15 (http://mattmahoney.net/dc/zpaq.html) Portions of software by other authors, mentioned later, are included. As far as I know this is allowed by the licenses. **** I apologize if I have unintentionally violated any rule **** **** Please report and I will fix as soon as possible **** _ _____ _____ ______ _ _ _____ ______ _____ | | |_ _/ ____| ____| \ | |/ ____| ____|/ ____| | | | || | | |__ | \| | (___ | |__ | (___ | | | || | | __| | . ` |\___ \| __| \___ \ | |____ _| || |____| |____| |\ |____) | |____ ____) | |______|_____\_____|______|_| \_|_____/|______|_____/ Credits and copyrights and licenses and links and internal bookmarks 0 [Public domain] zpaq http://mattmahoney.net/dc/zpaq.html 1 [Public domain] zpaq.AES from libtomcrypt by Tom St Denis /// LICENSE_START.1 LICENSE_END.1 2 [Public domain] zpaq.salsa20 by D. J. Bernstein /// LICENSE_START.2 LICENSE_END.2 3 [Public domain] unzpaq206.cpp by Matt Mahoney /// LICENSE_START.3 LICENSE_END.3 4 [Public domain] zpaq.Include mod by data man and reg2s patch from encode.su forum 5 [Public domain] Sha1Opt.asm and 7zAsm.asm by Igor Pavlov /// LICENSE_START.5 LICENSE_END.5 6 [MIT license] zpaq.Code from libdivsufsort 2.0 (C) Yuta Mori, 2003-2008 /// LICENSE_START.6 LICENSE_END.6 7 [MIT License] Embedded Artistry (memory-aligned malloc) https://github.com/embeddedartistry /// LICENSE_START.7 LICENSE_END.7 8 [MIT License] Nilsimsa implementation by Sepehr Laal https://github.com/3p3r/nilsimsa-lite/blob/master/nilsimsa.c /// LICENSE_START.8 LICENSE_END.8 9 [MIT License] zsfx by ... me https://github.com/fcorbelli/zsfx 10 [zlib license] Crc32.h Copyright (c) 2011-2019 Stephan Brumme https://create.stephan-brumme.com/crc32/ /// LICENSE_START.10 LICENSE_END.10 11 [zlib license] part of hash-library (MD5, SHA-3) by Stephan Brumme https://github.com/stbrumme/hash-library /// LICENSE_START.11 LICENSE_END.11 12 [zlib license] crc32c.c Copyright (C) Mark Adler https://github.com/madler/brotli/blob/master/crc32c.c /// LICENSE_START.12 LICENSE_END.12 13 [The Unlicense] wyhash (experimental) WangYi https://github.com/wangyi-fudan/wyhash /// LICENSE_START.13 LICENSE_END.13 14 [BSD 2-Clause license] xxHash Copyright (C) 2012-2020 Yann Collet https://github.com/memcached/memcached/blob/master/xxhash.h /// LICENSE_START.14 LICENSE_END.14 15 [CC0 1.0 / Apache License 2.0] BLAKE3 hasher https://github.com/BLAKE3-team/BLAKE3 /// LICENSE_START.15 LICENSE_END.15 16 [Public domain] Whirlpool by Paulo Barreto and Vincent Rijmen https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html /// LICENSE_START.16 LICENSE_END.16 17 [almost-unrestricted] Twofish implementation,(c) 2002 by Niels Ferguson https://github.com/wernerd/ZRTPCPP/blob/master/cryptcommon/twofish.c **** This is part of currently not released zpaqfranz (future zpaq-over-IP) 18 [Apache License 2.0] HighWay64 hasher https://github.com/google/highwayhash /// LICENSE_START.18 LICENSE_END.18 19 [Public domain] The files in this directory are released to the Public Domain. *** NOTE: PDC is used only on Windows *** /// LICENSE_START.19 LICENSE_END.19 20 [Public domain] CPU accelerated SHA code taken from SHA-Intrinsics /// LICENSE_START.20 LICENSE_END.20 21 [Public domain] zpaqd v7.15 - ZPAQ compression development tool - Aug. 17, 2016. /// LICENSE_START.21 LICENSE_END.21 22 [BSD 2-Clause license] LZ4 Copyright (C) 2011-2023, Yann Collet https://github.com/lz4/lz4 /// LICENSE_START.22 LICENSE_END.22 23 [MIT License] https://github.com/codewithnick/ascii-art /// LICENSE_START.23 LICENSE_END.23 _____ _____ ______ ______ _______ _____ _ _ _____ _____ / ____| __ \| ____| ____|__ __|_ _| \ | |/ ____|/ ____| | | __| |__) | |__ | |__ | | | | | \| | | __| (___ | | |_ | _ /| __| | __| | | | | | . ` | | |_ |\___ \ | |__| | | \ \| |____| |____ | | _| |_| |\ | |__| |____) | \_____|_| \_\______|______| |_| |_____|_| \_|\_____|_____/ 0 ****** It is worth mentioning that the initial developer, ****** the one who has the most credit is ****** Dr. Matt Mahoney http://mattmahoney.net ****** If you like zpaq technology, HE is the one to thank 1 Thanks to JFLarvoire for usefun (yes, usefun) informations https://github.com/JFLarvoire/SysToolsLib/blob/master/C/MsvcLibX/src/readlink.c 2 Thanks to Bulat Ziganshin for contribution on Slicing-by-16 for crc32 3 Thanks to SeDD user of the encode.ru forum for SFX debugging 4 Thanks to Aki user of forums.debian.net for some Debian's packager help 5 Thanks to https://github.com/dertuxmalwieder for testing on various Unixes and OpenBSD port 6 Thanks to Felix Palmen for great help on FreeBSD "packaging" 7 Thanks to https://github.com/omar-polo for a merged-unmerged-hardcoded NOJIT fix 8 Thanks to https://github.com/Piqlet for non-x86 help 9 Thanks to https://github.com/osmano807 for non-x86 help 10 Thanks to Stephen Kitt for supporting Debian "packaging" 11 Thanks to Niels Ferguson for the Twofish implementation 12 Thanks to Newcastle University for some winsock related issues, Master Degree, Game Engineering 13 Thanks to https://github.com/akumiszcza for OneDrive issue 14 Thanks to https://github.com/ratay for help help fix, longpath 15 Thanks to https://github.com/graphixillusion for "lost" -vss 16 Thanks to https://discuss.haiku-os.org/u/PulkoMandy for Haiku help 17 Thanks to https://github.com/Bill-Gray for PDCursesMod 18 Thanks to https://github.com/justinormont for the proposed Homebrew install formula for macOS and x64 Linux 19 Thanks to https://github.com/alebcay for coding the Homebrew install formula for macOS and x64 Linux 20 Thanks to https://github.com/ZhongRuoyu for __linux__ instead of older #defines 21 Thanks to Coody user of encode.su for unexistent folder bug 22 Thanks to https://github.com/ruptotus for "hidden" overloaded fwrite() function bug, and -dryrun on robocopy fix 23 Thanks to Karl Wagner for typo fixing and various suggestions 24 Thanks to https://github.com/Erol-2022 for Windows 7 console-bug fixing 25 Thanks to Martin Pluskal for OpenSUSE package 26 Thanks to Petr Pisar for Fedora Package 27 Thanks to Davide Moretti for good ideas 28 Thanks to https://github.com/DetourNetworkUK for Mac PowerPC strnlen bug 29 Thanks to Lone_Wolf (bbs.archlinux.org) for reviewing PKGBUILD on arch 30 Thanks to Scimmia (bbs.archlinux.org) for reviewing PKGBUILD on arch 31 Thanks to Loqs (bbs.archlinux.org) for reviewing PKGBUILD on arch 32 Thanks to https://github.com/tansy for Slackware older compilers 33 Thanks to https://github.com/janko-js for idea on quick collision-detector 34 Thanks to https://github.com/havocesp for very useful ideas 35 Thanks to https://github.com/luckman212 for a refactoring-induced bug detection 36 Thanks to whiskytechfred user of the encode.su forum for truncate-touching 37 Thanks to Takayuki Matsuoka for LZ4 streaming API example : line-by-line logfile 38 Thanks to whiskytechfred user of the encode.ru forum for vss filename fix 39 Thanks to https://github.com/sergeevabc for suggestions on hash command 40 Thanks to https://github.com/gitboogey for ideas on -test and -verify with vss 41 Thanks to https://github.com/bastiple for -D_FORTIFY_SOURCE=3 42 Thanks to https://github.com/sheckandar for Synology 7.1 issue 43 Thanks to https://github.com/adamantida for improved similarity with zpaq for archives with only deletions 44 Thanks to https://github.com/kskarlatos for giving me an idea to improve stdin support 45 Thanks to https://github.com/codewithnick for change his license to a Fedora-friendly one 46 Thanks to https://github.com/mirogeorg for various suggestions 47 Thanks to https://github.com/brad0 for OpenBSD fix zpaqfranz-62.2/LICENSE000066400000000000000000000020661477324740300145030ustar00rootroot00000000000000MIT License Copyright (c) 2022-2023 Franco Corbelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zpaqfranz-62.2/Makefile000066400000000000000000000015341477324740300151350ustar00rootroot00000000000000### generic Makefile. Look at BINDIR for the prefix (/usr/bin instead of /usr/local/bin) ### Generally, but not always, /usr/local/bin is for "BSD-style" systems, while /usr/bin is for older Linux systems ### In reality, each platform has its own custom:cannot know "a priori" ### Usually a straight ### make install clean ### is good enough CXX?= cc INSTALL?= install RM?= rm PROG= zpaqfranz SOURCE= zpaqfranz.cpp CPPFLAGS+= -Dunix CXXFLAGS+= -O3 -pthread LDLIBS= -lm BINDIR= /usr/local/bin BSD_INSTALL_PROGRAM?= ${INSTALL} -m 0755 all: build build: ${PROG} install: ${PROG} ${BSD_INSTALL_PROGRAM} -d ${DESTDIR}${BINDIR} ${BSD_INSTALL_PROGRAM} $^ ${DESTDIR}${BINDIR} ${PROG}: ${SOURCE} ${CXX} ${CPPFLAGS} ${CXXFLAGS} ${LDFLAGS} $^ ${LDLIBS} -o $@ clean: ${RM} -f ${PROG} zpaqfranz-62.2/NONWINDOWS/000077500000000000000000000000001477324740300151775ustar00rootroot00000000000000zpaqfranz-62.2/NONWINDOWS/Makefile000066400000000000000000000007161477324740300166430ustar00rootroot00000000000000CXX?= c++ INSTALL?= install RM?= rm PROG= zpaqfranz CXXFLAGS+= -O3 -std=c++11 -Dunix LDADD= -pthread -lm BINDIR= /usr/local/bin BSD_INSTALL_PROGRAM?= install -m 0555 all: build build: ${PROG} install: ${PROG} ${BSD_INSTALL_PROGRAM} ${PROG} ${DESTDIR}${BINDIR} ${PROG}: ${OBJECTS} ${CXX} ${CXXFLAGS} zpaqfranz.cpp -o ${PROG} ${LDADD} clean: ${RM} -f ${PROG}zpaqfranz-62.2/NONWINDOWS/README.md000066400000000000000000000006541477324740300164630ustar00rootroot00000000000000Please go to https://github.com/fcorbelli/zpaqfranz-stuff/tree/main/NONWINDOWS Moved the unnecessary material to the zpaqfranz-stuff github repository (smaller git) ### The Makefile is somewhat "universal" for *nix, beware of prefix BINDIR=/usr/local/bin, sometimes must be /usr/bin ### There are too many non-Windows systems to make a makefile that works everywhere, in the source there are examples for various targets zpaqfranz-62.2/README.md000066400000000000000000000525051477324740300147600ustar00rootroot00000000000000# zpaqfranz: advanced multiversioned archiver, with HW acceleration and SFX (on Windows) ### Swiss army knife for backup and disaster recovery, like 7z or RAR on steroids, with deduplicated "snapshots" (versions). Conceptually similar to the Mac time machine, but much more efficiently. zpaq 7.15 fork. | Platform | OS package | Version | Video| | ---------- | ----- | ---------- | ------- | | [Windows 32/64bit (sourceforge)](https://sourceforge.net/projects/zpaqfranz/files) | |![Badge](https://img.shields.io/github/v/release/fcorbelli/zpaqfranz)| | | [Windows 32 (direct)](http://www.francocorbelli.it/zpaqfranz/win32) | `zpaqfranz32 upgrade -force` |latest| | | [Windows 64 (direct)](http://www.francocorbelli.it/zpaqfranz/win64) | `zpaqfranz upgrade -force` |latest| | | [Windows 64 (HW accelerated)](http://www.francocorbelli.it/zpaqfranz/win64hw) | `zpaqfranzhw -force` |latest| | | [OpenBSD](http://www.francocorbelli.it/zpaqfranz/openbsd) |`pkg_add zpaqfranz` |![Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fopenbsd.app%2F%3Fsearch%3Dzpaqfranz%26format%3Djson%26current%3Don&query=%24..FULLPKGNAME&label=openbsd)| | | [FreeBSD](http://www.francocorbelli.it/zpaqfranz/freebsd) |`pkg install zpaqfranz` |60.3a | | | [MacOS](http://www.francocorbelli.it/zpaqfranz/mac) |`brew install zpaqfranz` |![Badge](https://img.shields.io/homebrew/v/zpaqfranz)| | | [OpenSUSE](http://www.francocorbelli.it/zpaqfranz/opensuse) |`sudo zypper install zpaqfranz`| | | | [Debian 13+ (Ubuntu etc) ](https://packages.debian.org/trixie/utils/zpaqfranz) | `apt-get install zpaqfranz` |60.7| | | [Debian (Ubuntu etc) .deb](http://www.francocorbelli.it/zpaqfranz/debian) | `sudo apt install zpaqfranz` |59.8j / 60.7|[Desktop](http://www.francocorbelli.it/zpaqfranz/video/debian-deb.mp4) | | [Linux generic (32/64)](http://www.francocorbelli.it/zpaqfranz/linux) | |60.7u| | | [Arch](http://www.francocorbelli.it/zpaqfranz/arch) | [AUR user repository (latest)](https://aur.archlinux.org/packages/zpaqfranz-git)|58.10i|[Terminal](http://www.francocorbelli.it/zpaqfranz/video/arch.mp4) | [Solaris 11-64](http://www.francocorbelli.it/zpaqfranz/solaris) | |60.7u| | | [OmniOS 64](http://www.francocorbelli.it/zpaqfranz/omnios) | |60.7u| | | [NAS (Intel, Synology...)](http://www.francocorbelli.it/zpaqfranz/nas) | |60.7u| | | [NAS (armv8, QNAP...)](http://www.francocorbelli.it/zpaqfranz/qnap) | |60.7u| | | [NAS (arm Cortex-C57,QNAP TS433...)](http://www.francocorbelli.it/zpaqfranz/57c) | |60.7u| | | [Haiku](http://www.francocorbelli.it/zpaqfranz/haiku) | |60.7u| | | [ESXi](http://www.francocorbelli.it/zpaqfranz/esxi) | |60.7u| | [Freeware GUI for Windows](https://github.com/fcorbelli/zpaqfranz/wiki/PAKKA-Windows-32-bit-extractor) | |[latest](http://www.francocorbelli.it/pakka/build/latest/pakka_latest.zip) | | | [![ZpaqTreeView](https://github.com/fcorbelli/zpaqfranz/assets/77727889/2e155fa7-0565-416b-8bdd-b99c16ae896d)](https://github.com/EpicGazel/ZpaqTreeView) | Third Party Python software | | [![Freeware GUI for Windows](https://github.com/fcorbelli/zpaqfranz/assets/77727889/e8243e14-b299-4224-b998-8c96a8e425d5)](https://github.com/fcorbelli/zpaqfranz/wiki/PAKKA-Windows-32-bit-extractor) [![Wiki](https://github-production-user-asset-6210df.s3.amazonaws.com/77727889/267342908-7d4c5bb9-6ea2-4735-9226-4d8112c5d65d.jpg)](https://github.com/fcorbelli/zpaqfranz/wiki) [![Help](https://github-production-user-asset-6210df.s3.amazonaws.com/77727889/267348388-d539932d-55c6-454a-a27b-054a10ae5f35.jpg)](https://github.com/fcorbelli/zpaqfranz/wiki/HELP-integrated) [![Sourceforge](https://github-production-user-asset-6210df.s3.amazonaws.com/77727889/267350249-91c18ca6-8c74-4585-96f4-3c72fd2c6725.jpg)](https://github.com/EpicGazel/ZpaqTreeView) ## Classic archivers (tar, 7z, RAR etc) are obsolete, when used for repeated backups (daily etc), compared to the ZPAQ technology, that maintain "snapshots" (versions) of the data. [This is even more true in the case of ASCII dumps of databases (e.g. MySQL/MariaDB)](https://github.com/fcorbelli/zpaqfranz/wiki/Real-world:-SQL-dumps-(MySQL-MariaDB-Postgres-backup)) Let's see. Archiving a folder multiple times (5), simulating a daily run Monday-to-Friday, with 7z https://user-images.githubusercontent.com/77727889/215149589-0f2d9f91-ea5a-4f60-b587-f2a506148fe9.mp4 Same, but with zpaqfranz https://user-images.githubusercontent.com/77727889/215148702-edb8e5bb-8f4e-42bb-9637-6ee98742318a.mp4 _As you can see, the .7z "daily" 5x backups takes ~ 5x the space of the .zpaq_ ![compare](https://user-images.githubusercontent.com/77727889/215150599-83032cc6-06b0-432d-ba3b-b410698e3631.jpg) ## Seeing is believing ("real world") I thought it's best to show the difference for a more realistic example. Physical (small fileserver) Xeon machine with 8 cores, 64GB RAM and NVMe disks, plus Solaris-based NAS, 1Gb ethernet Rsync update from filesystem to filesystem (real speed) https://user-images.githubusercontent.com/77727889/215152167-c6ce107a-6345-4060-b7a7-33ad30b269ee.mp4 Rsync update to Solaris NAS (real speed) https://user-images.githubusercontent.com/77727889/215152259-2baa7001-d838-40de-b56c-6fe3feff9f1b.mp4 Backup update from file system with zpaqfranz (real speed) https://user-images.githubusercontent.com/77727889/215146670-1a11cd5d-6f00-4544-b797-9ca288ae12b1.mp4 Backup upgrade via zfsbackup (real speed) https://user-images.githubusercontent.com/77727889/215147310-cc760f20-08b8-4088-9d8a-f58f00eac211.mp4 # What? At every run only data changed since the last execution will be added, creating a new version (the "snapshot"). It is then possible to restore the data @ the single version, just like snapshots by zfs or virtual machines, but a single-file level. - Keeps a forever-to-ever copy (even thousands of versions), conceptually similar to Mac's time machine, but much more efficiently. - Ideal for virtual machine disk storage (ex backup of vmdk), virtual disks (VHDx) and even TrueCrypt containers. - Easily handles millions of files and tens of TBs of data. - Allows rsync (or zfs replica) copies to the cloud with minimal data transfer and encryption. - Multiple possibilities of data verification, fast, advanced and even paranoid. - Some optimizations for modern hardware (aka: SSD, NVMe, multithread). - By default triple-check with "chunked" SHA-1, XXHASH64 and CRC-32 (!). ``` For even higher level of paranoia, it is possible to use others hash algorithms, as ``` - MD5 - SHA-1 of the full-file (NIST FIPS 180-4) - XXH3-128 - BLAKE3 128 - SHA-2-256 (NIST FIPS 180-4) - SHA-3-256 (NIST FIPS 202) - WHIRLPOOL (ISO/IEC 10118-3) - HIGHWAY (64,128,256) ...And much more. **No complex (and fragile) repository folders, with hundreds of "whatever", just only a single file!** ## Windows client? Minimum size (without software) VSS backups _It is often important to copy the %desktop% folder, Thunderbird's data, %download% and generally the data folders of a Windows system, leaving out the programs_ Real speed (encrypted) update of C: without software (-frugal) https://user-images.githubusercontent.com/77727889/215269540-8e2c8641-0d3a-4f67-a243-ab617834c5de.mp4 ## Are you a really paranoid Windows user (like me)? You can get sector-level copies of C:, too. _In this case the space used is obviously larger, as is the execution time, but even the "most difficult" folders are also taken. Deliberately the bitmap of occupied clusters is ignored: if you are paranoid, be all the way down!_ _It is just like a dd. You can't (for now) restore with zpaqfranz. You have to extract to a temporary folder and then use other software (e.g., 7z, OSFMount) to extract the files directly from the image_ Accelerated speed (encrypted) every-sector update of a 256GB C: @ ~150MB/s https://user-images.githubusercontent.com/77727889/215271199-94400833-f973-41d2-a018-3f2277a648a9.mp4 ### To date, there is no software, free or paid, that matches this characteristics _AFAIK of course_ 10+ years of developing (2009-now). **Who did that?** One of the world's leading scientists in compression. [No, not me, but this guy](http://mattmahoney.net/) [ZPAQ - Wikipedia](https://en.wikipedia.org/wiki/ZPAQ) **When?** From 2009 to 2016. **Where?** On a Russian compression forum, one of the most famous, but obviously super-niche **Why is it not known as 7z or RAR, despite being enormously superior?** Because lack of users who ... try it! **Who are you?** A user (and a developer) who has proposed and made various improvements that have been implemented over the years. When the author left the project, I made my fork to make the functions I need as a data storage manager. **Why is it no longer developed? Why should I use your fork?** Because Dr. Mahoney is now retired and no longer supports it (he... run!) **Why should I trust? It will be one of 1000 other programs that silently fail and give problems** As the Russians (and Italians) say, trust me, but check. **Archiving data requires safety. How can I be sure that I can then extract them without problems?** It is precisely the portion of the program that I have evolved, implementing a barrage of controls up to the paranoid level, and more. Let's say there are verification mechanisms which you have probably never seen. Do you want to use SHA-2/SHA-3 to be very confident? You can. Accelerated speed of real world testing of archive >1GB/s https://user-images.githubusercontent.com/77727889/215271989-5a77e1f1-8fba-422b-9e25-24c3f4640eb2.mp4 **ZPAQ (zpaqfranz) allows you to NEVER delete the data that is stored and will be available forever (in reality typically you starts from scratch every 1,000 or 2,000 versions, for speed reasons, on HDD. 10K+ on SSD), and restore the files present to each archived version, even if a month or three years ago.** Real-speed updating (on QNAP NAS) of a small server (300GB); ~7GB of Thunderbird mbox become ~6MB (!) in ~4 minutes. https://user-images.githubusercontent.com/77727889/215268613-e07e385c-0880-4534-ae35-0db8925cee6b.mp4 In this "real world" example (a ~500.000 files / ~500GB file server of a mid-sized enterprise), you will see 1042 "snapshots", stored in 877GB. ``` root@f-server:/copia1/copiepaq/spaz2020 # zpaqfranz i fserver_condivisioni.zpaq zpaqfranz v51.27-experimental snapshot archiver, compiled May 26 2021 fserver_condivisioni.zpaq: 1042 versions, 1.538.727 files, 15.716.105 fragments, 877.457.003.477 bytes (817.20 GB) Long filenames (>255) 4.526 Version(s) enumerator ------------------------------------------------------------------------- < Ver > < date > < time > < added > < bytes added > ------------------------------------------------------------------------- 00000001 2018-01-09 16:56:02 +00308608 -00000000 -> 229.882.913.501 00000002 2018-01-09 18:06:28 +00007039 -00000340 -> 47.356.864 00000003 2018-01-10 15:06:25 +00007731 -00000159 -> 7.314.709 00000004 2018-01-10 15:17:44 +00007006 -00000000 -> 612.584 00000005 2018-01-10 15:47:03 +00007005 -00000000 -> 611.980 00000006 2018-01-10 18:03:08 +00008135 -00000829 -> 2.698.417.427 (...) 00000011 2018-01-10 19:20:30 +00007007 -00000000 -> 613.273 00000012 2018-01-11 07:00:36 +00007008 -00000000 -> 613.877 (...) 00000146 2018-03-27 17:08:39 +00001105 -00000541 -> 164.399.767 00000147 2018-03-28 17:08:28 +00000422 -00000134 -> 277.237.055 00000148 2018-03-29 17:12:02 +00011953 -00011515 -> 826.218.948 (...) 00001039 2021-05-02 17:17:42 +00030599 -00031135 -> 12.657.155.316 00001040 2021-05-03 17:14:03 +00000960 -00000095 -> 398.358.496 00001041 2021-05-04 17:13:40 +00000605 -00000004 -> 95.909.988 00001042 2021-05-05 17:15:13 +00000579 -00000008 -> 82.487.415 54.799 seconds (all OK) ``` Do you want to restore @ 2018-03-28? ``` 00000147 2018-03-28 17:08:28 +00000422 -00000134 -> 277.237.055 ``` Version 147 => ``` zpaqfranz x ... -until 147 ``` Do you want 2021-03-05? Version 984 => ``` zpaqfranz x ... -until 984 ``` Another real world example: 4900 versions, from mid-2017 ``` zpaqfranz v51.10-experimental journaling archiver, compiled Apr 5 2021 franz:use comment old_aserver.zpaq: 4904 versions, 385.830 files, 3.515.679 fragments, 199.406.200.193 bytes (185.71 GB) Version comments enumerator ------------ 00000001 2017-08-16 19:26:15 +00090863 -00000000 -> 79.321.339.869 00000002 2017-08-17 13:29:25 +00000026 -00000000 -> 629.055 00000003 2017-08-17 13:30:41 +00000005 -00000000 -> 18.103 00000004 2017-08-17 14:34:12 +00000005 -00000000 -> 18.149 00000005 2017-08-17 15:28:42 +00000008 -00000000 -> 99.062 00000006 2017-08-17 19:30:03 +00000008 -00000000 -> 1.013.616 00000007 2017-08-18 19:33:14 +00000021 -00000001 -> 2.556.335 00000008 2017-08-19 19:29:23 +00000025 -00000000 -> 1.377.082 00000009 2017-08-20 19:29:56 +00000002 -00000000 -> 24.153 00000010 2017-08-21 19:34:35 +00000031 -00000000 -> 2.554.582 (...) 00004890 2021-02-16 16:40:51 +00000190 -00000005 -> 99.051.540 00004891 2021-02-16 19:30:17 +00000065 -00000006 -> 16.467.364 00004892 2021-02-17 19:34:04 +00000381 -00000257 -> 95.354.305 (...) 00004900 2021-02-25 19:35:47 +00000755 -00000611 -> 132.241.557 00004901 2021-02-26 19:57:16 +00000406 -00000253 -> 122.669.868 00004902 2021-02-27 20:33:45 +00000029 -00000002 -> 12.677.932 00004903 2021-02-28 20:34:00 +00000027 -00000001 -> 6.978.088 00004904 2021-03-01 20:33:52 +00000174 -00000019 -> 77.113.147 ``` until 2021 (4 years later) This is a ~200GB server ``` (...) - 2019-09-23 10:14:44 2.943.578.106 0666 /tank/mboxstorico/inviata_spazzatura__2017_2018 - 2021-02-18 10:16:25 4.119.172 0666 /tank/mboxstorico/inviata_spazzatura__2017_2018.msf - 2019-10-25 15:39:15 1.574.715.392 0666 /tank/mboxstorico/nstmp - 2020-11-28 20:33:22 2.038.165 0666 /tank/mboxstorico/nstmp.msf - 2021-02-25 17:48:11 8.802 0644 /tank/mboxstorico/sha1.txt 214.379.664.412 (199.66 GB) of 214.379.664.412 (199.66 GB) in 154.975 files shown ``` so for 4900 versions you need 200GB*4900 = ~980TB with something like tar, 7z, RAR etc (yes, 980 terabytes), versus ~200GB (yes, 200GB) with zpaq. Same things for virtual machines (vmdks) ## Why you say uniqueness? We got (hb) hashbackup, borg, restic, bupstash etc ## Because other software (sometimes very, very good) runs on complex "repositories", very fragile and way too hard to manage (at least for my tastes). It may happen that you have to worry about backing up ... the backup, because maybe some files were lost during a transfer, corrupted etc. _If it's simple, maybe it will work_ ## Too good to be true? ## Obviously this is not "magic", it is simply the "chaining" of a block deduplicator with a compressor and an archiver. There are faster compressors. There are better compressors. There are faster archivers. There are more efficient deduplicators. But what I have never found is a combination of these that is so simple to use and reliable, with excellent handling of non-Latin filenames (Chinese, Russian etc). This is the key: you don't have to use complex "pipe" of tar | srep | zstd | something hoping that everything will runs file, but a single ~4MB executable, with 7z-like commands. You don't even have to install a complex program with many dependencies that will have to read a folder (the repository) with maybe thousands of files, hoping that they are all fully functional. There are also many great features for backup, I mention only the greatest. **The ZPAQ file is "in addition", it is never modified** So rsync --append will copy only the portion actually added, for example on ssh tunnel to a remote server, or local NAS (QNAP etc) with tiny times. TRANSLATION You can pay ~$4 a month for 1TB cloud-storage-space to store just about everything You don't have to copy or synchronize let's say 700GB of tar.gz,7z or whatever, but only (say) the 2GB added in the last copy, the first 698GB are untouched. This opens up the concrete possibility of using VDSL connections (upload ~ 2/4MB /s) to backup even virtual servers of hundreds of gigabytes in a few minutes. In this (accelerated) video the rsync transfer of 2 remote backups: "standard" .zpaq archive (file level) AND zfsbackup (bit-level) for a small real-world server 1 day-update of work https://user-images.githubusercontent.com/77727889/215267855-22bf875c-90ee-47d1-8f8f-c2d0fa2ab201.mp4 **Bonus: for a developer it's just like a "super-git-versioning"** In the makefile just put at top a zpaq-save-everything and you will keep all the versions of your software, even with libraries, SQL dump etc. A single archive keeps everything, forever, with just one command (or two, for verify) **Defects?** Some. The main one is that the listing of files is not very fast, when there are many versions (thousands), due to the structure of the archiver-file-format. *I could get rid of it, but at the cost of breaking the backward compatibility of the file format, so I don't want to. On 52+ there is a workaround (-filelist)* It is not the fastest tool out there, with real world performance of 80-200MB/s (depending on the case and HW of course). *Not a big deal for me (I have very powerful HW, and/or run nightly cron-tasks)* Extraction can require a number of seeks (due to various deduplicated blocks), which can slow down extraction on magnetic disks (but not on SSDs). *If you have plenty of RAM now it is possible to bypass with the w command* No other significant ones come to mind, except that it is known and used by few **Very hard to use?** It is a tool for power users and administrators, who are used to the command line. A text-based GUI is being developed to make data selection and complex extraction easier (!). In this example we want to extract all the .cpp files as .bak from the 1.zpaq archive. This is something you typically cannot do with other archives such as tar, 7z, rar etc. ### With a "sort of" WYSIWYG 'composer' First **f** key (find) and entering .cpp Then **s** (search) every .cpp substring Then **r** (replace) with .bak Then **t** (to) for the z:\example folder Finally **x** to run the extraction https://user-images.githubusercontent.com/77727889/226925740-d62b92ae-4eee-43ac-94a9-e1a6dae684c1.mp4 **I do not trust you, but I am becoming curious. So?** On **FreeBSD** [you can try to build the port (of paq, inside archivers)](https://www.freshports.org/archivers/paq) but it is very, very, very old (v 6.57 of 2014) You can get a "not too old" zpaqfranz with a `pkg install zpaqfranz` On **OpenBSD** `pkg_add zpaqfranz` is usually rather updated On **Debian** [there is a zpaq 7.15 package](https://packages.debian.org/zpaq), and starting with Debian 13 [zpaqfranz is available too](https://packages.debian.org/zpaqfranz). You can download the original version (7.15 of 2016) directly from the author's website, and compile it, or get the same from github. In this case be careful, because the source is divided into 3 source files, but nothing difficult for the compilation. **OK, let's assume I want to try out zpaqfranz. How?** From branch 51 all source code is merged in one zpaqfranz.cpp aiming to make it as easy as possible to compile on "strange" systems (NAS, vSphere etc). Updating, compilation and Makefile are now trivial. # How to build My main development platforms are INTEL Windows (non-Intel Windows (arm) currently unsupported) and FreeBSD. I rarely use Linux or MacOS or whatever (for compiling), so fixing may be needed. As explained the program is single file, be careful to link the pthread library. You need it for ESXi too, even if it doesn't work. Don't be afraid, zpaqfranz knows! ### [Almost "universal" (minimal) Makefile](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-Makefile) ### [Quicker and dirtier!](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-quicker%E2%80%90and%E2%80%90dirtier) ### [DEFINEs at compile-time](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-How-to-Build) ### [TARGET EXAMPLES](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-Target-examples) ### [HIDDEN GEMS](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-Hidden-gems) ### [STRANGE THINGS](https://github.com/fcorbelli/zpaqfranz/wiki/Quickstart-Strange-Things) ### [Integrated HELP](https://github.com/fcorbelli/zpaqfranz/wiki/HELP-integrated) ### [Wiki commands](https://github.com/fcorbelli/zpaqfranz/wiki/Command) zpaqfranz-62.2/TODO.md000066400000000000000000000015061477324740300145630ustar00rootroot00000000000000### This is the todo list @ 2023-10-03 in no particular order - [ ] *Hard* Debian package. Ready, but I get an "overloaded" DD - [ ] *Hard* Fedora package. Almost ready, lost contact with Fedora maintainer - [ ] *Mid* Update FreeBSD package. Not really a priority - [ ] *Hard* Implement the zpaq-over-TCP. Not easy, but all "pieces" already done - [ ] *Low* Complete and fix the wiki. I do not like very much english :) - [ ] *Mid* XOR-ing SHA-1 to VFILE. Requires a lot of work to fix SHA-1 collisions - [ ] *Hard* New file format without SHA-1. Backward compatibility will be broken. Not sure - [ ] *Low* "Automagically" define. In the source, but need more tests - [ ] *Low* Better low-memory extractor. For ESXi servers - [ ] *Low* Better proxmox backup. "Smarter hunter" of image's dataset - [ ] *???* Inspect -stdin with -fragment zpaqfranz-62.2/WINDOWS/000077500000000000000000000000001477324740300146245ustar00rootroot00000000000000zpaqfranz-62.2/WINDOWS/README.md000066400000000000000000000002401477324740300160770ustar00rootroot00000000000000Please go to https://github.com/fcorbelli/zpaqfranz-stuff/tree/main/WINDOWS Moved unnecessary material to the github repository zpaqfranz-stuff (smaller git) zpaqfranz-62.2/ZPIPE/000077500000000000000000000000001477324740300143615ustar00rootroot00000000000000zpaqfranz-62.2/ZPIPE/README.md000066400000000000000000000002371477324740300156420ustar00rootroot00000000000000please go to https://github.com/fcorbelli/zpaqfranz-stuff/tree/main/ZPIPE Moved unnecessary material to the github repository zpaqfranz-stuff (smaller git) zpaqfranz-62.2/ZSFX/000077500000000000000000000000001477324740300142645ustar00rootroot00000000000000zpaqfranz-62.2/ZSFX/LICENSE000066400000000000000000000020671477324740300152760ustar00rootroot00000000000000MIT License Copyright (c) 2022-2023 Franco Corbelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zpaqfranz-62.2/ZSFX/README.md000066400000000000000000000016431477324740300155470ustar00rootroot00000000000000# Those are the Windows 32/64 SFX modules for zpaqfranz ### Released by Franco Corbelli, with MIT License **zsfx.cpp** use two files: **libzpaq.cpp** and **libzpaq.h**, with compatible licenses (MIT and public domain) ### libzpaq.cpp use libdivsufsort.c for divsufsort 2.00, included within (C) 2003-2008 Yuta Mori, all rights reserved. It is released under the **MIT license** as described in the comments at the beginning of that section. Some of the code for AES is from libtomcrypt 1.17 by Tom St. Denis and is **public domain**. The Salsa20/8 code for Scrypt is by D. Bernstein and is **public domain**. All of the remaining software is provided as-is, with no warranty by Matt Mahoney, who release this software into the **public domain**. ### libzpaq.h is provided as-is, with no warranty, by Matt Mahoney, who release this software into the **public domain** This applies worldwide. zpaqfranz-62.2/ZSFX/libzpaq.cpp000066400000000000000000007144471477324740300164530ustar00rootroot00000000000000/* libzpaq.cpp - LIBZPAQ Version 7.15 implementation - Aug. 17, 2016. libdivsufsort.c for divsufsort 2.00, included within, is (C) 2003-2008 Yuta Mori, all rights reserved. It is released under the MIT license as described in the comments at the beginning of that section. Some of the code for AES is from libtomcrypt 1.17 by Tom St. Denis and is public domain. The Salsa20/8 code for Scrypt is by D. Bernstein and is public domain. All of the remaining software is provided as-is, with no warranty. I, Matt Mahoney, release this software into the public domain. This applies worldwide. In some countries this may not be legally possible; if so: I grant anyone the right to use this software for any purpose, without any conditions, unless such conditions are required by law. LIBZPAQ is a C++ library for compression and decompression of data conforming to the ZPAQ level 2 standard. See http://mattmahoney.net/zpaq/ See libzpaq.h for additional documentation. */ #include "libzpaq.h" #include #include #include namespace libzpaq { // Read 16 bit little-endian number int toU16(const char* p) { return (p[0]&255)+256*(p[1]&255); } // Default read() and write() int Reader::read(char* buf, int n) { int i=0, c; while (i=0) buf[i++]=c; return i; } void Writer::write(const char* buf, int n) { for (int i=0; i 0 bytes of executable memory and update // p to point to it and newsize = n. Free any previously // allocated memory first. If newsize is 0 then free only. // Call error in case of failure. If NOJIT, ignore newsize // and set p=0, n=0 without allocating memory. void allocx(U8* &p, int &n, int newsize) { #ifdef NOJIT p=0; n=0; #else if (p || n) { if (p) #ifdef unix munmap(p, n); #else // Windows VirtualFree(p, 0, MEM_RELEASE); #endif p=0; n=0; } if (newsize>0) { #ifdef unix p=(U8*)mmap(0, newsize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANON, -1, 0); if ((void*)p==MAP_FAILED) p=0; #else p=(U8*)VirtualAlloc(0, newsize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE); #endif if (p) n=newsize; else { n=0; error("allocx failed"); } } #endif } //////////////////////////// SHA1 //////////////////////////// // SHA1 code, see http://en.wikipedia.org/wiki/SHA-1 // Start a new hash void SHA1::init() { len=0; h[0]=0x67452301; h[1]=0xEFCDAB89; h[2]=0x98BADCFE; h[3]=0x10325476; h[4]=0xC3D2E1F0; memset(w, 0, sizeof(w)); } // Return old result and start a new hash const char* SHA1::result() { // pad and append length const U64 s=len; put(0x80); while ((len&511)!=448) put(0); put(s>>56); put(s>>48); put(s>>40); put(s>>32); put(s>>24); put(s>>16); put(s>>8); put(s); // copy h to hbuf for (int i=0; i<5; ++i) { hbuf[4*i]=h[i]>>24; hbuf[4*i+1]=h[i]>>16; hbuf[4*i+2]=h[i]>>8; hbuf[4*i+3]=h[i]; } // return hash prior to clearing state init(); return hbuf; } // Hash buf[0..n-1] void SHA1::write(const char* buf, int64_t n) { const unsigned char* p=(const unsigned char*) buf; for (; n>0 && (U32(len)&511)!=0; --n) put(*p++); for (; n>=64; n-=64) { for (int i=0; i<16; ++i) w[i]=p[0]<<24|p[1]<<16|p[2]<<8|p[3], p+=4; len+=512; process(); } for (; n>0; --n) put(*p++); } // Hash 1 block of 64 bytes void SHA1::process() { U32 a=h[0], b=h[1], c=h[2], d=h[3], e=h[4]; static const U32 k[4]={0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; #define f(a,b,c,d,e,i) \ if (i>=16) \ w[(i)&15]^=w[(i-3)&15]^w[(i-8)&15]^w[(i-14)&15], \ w[(i)&15]=w[(i)&15]<<1|w[(i)&15]>>31; \ e+=(a<<5|a>>27)+k[(i)/20]+w[(i)&15] \ +((i)%40>=20 ? b^c^d : i>=40 ? (b&c)|(d&(b|c)) : d^(b&(c^d))); \ b=b<<30|b>>2; #define r(i) f(a,b,c,d,e,i) f(e,a,b,c,d,i+1) f(d,e,a,b,c,i+2) \ f(c,d,e,a,b,i+3) f(b,c,d,e,a,i+4) r(0) r(5) r(10) r(15) r(20) r(25) r(30) r(35) r(40) r(45) r(50) r(55) r(60) r(65) r(70) r(75) #undef f #undef r h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; h[4]+=e; } //////////////////////////// SHA256 ////////////////////////// void SHA256::init() { len0=len1=0; s[0]=0x6a09e667; s[1]=0xbb67ae85; s[2]=0x3c6ef372; s[3]=0xa54ff53a; s[4]=0x510e527f; s[5]=0x9b05688c; s[6]=0x1f83d9ab; s[7]=0x5be0cd19; memset(w, 0, sizeof(w)); } void SHA256::process() { #define ror(a,b) ((a)>>(b)|(a<<(32-(b)))) #define m(i) \ w[(i)&15]+=w[(i-7)&15] \ +(ror(w[(i-15)&15],7)^ror(w[(i-15)&15],18)^(w[(i-15)&15]>>3)) \ +(ror(w[(i-2)&15],17)^ror(w[(i-2)&15],19)^(w[(i-2)&15]>>10)) #define r(a,b,c,d,e,f,g,h,i) { \ unsigned t1=ror(e,14)^e; \ t1=ror(t1,5)^e; \ h+=ror(t1,6)+((e&f)^(~e&g))+k[i]+w[(i)&15]; } \ d+=h; \ {unsigned t1=ror(a,9)^a; \ t1=ror(t1,11)^a; \ h+=ror(t1,2)+((a&b)^(c&(a^b))); } #define mr(a,b,c,d,e,f,g,h,i) m(i); r(a,b,c,d,e,f,g,h,i); #define r8(i) \ r(a,b,c,d,e,f,g,h,i); \ r(h,a,b,c,d,e,f,g,i+1); \ r(g,h,a,b,c,d,e,f,i+2); \ r(f,g,h,a,b,c,d,e,i+3); \ r(e,f,g,h,a,b,c,d,i+4); \ r(d,e,f,g,h,a,b,c,i+5); \ r(c,d,e,f,g,h,a,b,i+6); \ r(b,c,d,e,f,g,h,a,i+7); #define mr8(i) \ mr(a,b,c,d,e,f,g,h,i); \ mr(h,a,b,c,d,e,f,g,i+1); \ mr(g,h,a,b,c,d,e,f,i+2); \ mr(f,g,h,a,b,c,d,e,i+3); \ mr(e,f,g,h,a,b,c,d,i+4); \ mr(d,e,f,g,h,a,b,c,i+5); \ mr(c,d,e,f,g,h,a,b,i+6); \ mr(b,c,d,e,f,g,h,a,i+7); static const unsigned k[64]={ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; unsigned a=s[0]; unsigned b=s[1]; unsigned c=s[2]; unsigned d=s[3]; unsigned e=s[4]; unsigned f=s[5]; unsigned g=s[6]; unsigned h=s[7]; r8(0); r8(8); mr8(16); mr8(24); mr8(32); mr8(40); mr8(48); mr8(56); s[0]+=a; s[1]+=b; s[2]+=c; s[3]+=d; s[4]+=e; s[5]+=f; s[6]+=g; s[7]+=h; #undef mr8 #undef r8 #undef mr #undef r #undef m #undef ror } // Return old result and start a new hash const char* SHA256::result() { // pad and append length const unsigned s1=len1, s0=len0; put(0x80); while ((len0&511)!=448) put(0); put(s1>>24); put(s1>>16); put(s1>>8); put(s1); put(s0>>24); put(s0>>16); put(s0>>8); put(s0); // copy s to hbuf for (int i=0; i<8; ++i) { hbuf[4*i]=s[i]>>24; hbuf[4*i+1]=s[i]>>16; hbuf[4*i+2]=s[i]>>8; hbuf[4*i+3]=s[i]; } // return hash prior to clearing state init(); return hbuf; } //////////////////////////// AES ///////////////////////////// // Some AES code is derived from libtomcrypt 1.17 (public domain). #define Te4_0 0x000000FF & Te4 #define Te4_1 0x0000FF00 & Te4 #define Te4_2 0x00FF0000 & Te4 #define Te4_3 0xFF000000 & Te4 // Extract byte n of x static inline unsigned byte(unsigned x, unsigned n) {return (x>>(8*n))&255;} // x = y[0..3] MSB first static inline void LOAD32H(U32& x, const char* y) { const unsigned char* u=(const unsigned char*)y; x=u[0]<<24|u[1]<<16|u[2]<<8|u[3]; } // y[0..3] = x MSB first static inline void STORE32H(U32& x, unsigned char* y) { y[0]=x>>24; y[1]=x>>16; y[2]=x>>8; y[3]=x; } #define setup_mix(temp) \ ((Te4_3[byte(temp, 2)]) ^ (Te4_2[byte(temp, 1)]) ^ \ (Te4_1[byte(temp, 0)]) ^ (Te4_0[byte(temp, 3)])) // Initialize encryption tables and round key. keylen is 16, 24, or 32. AES_CTR::AES_CTR(const char* key, int keylen, const char* iv) { assert(key != NULL); assert(keylen==16 || keylen==24 || keylen==32); // Initialize IV (default 0) iv0=iv1=0; if (iv) { LOAD32H(iv0, iv); LOAD32H(iv1, iv+4); } // Initialize encryption tables for (int i=0; i<256; ++i) { unsigned s1= "\x63\x7c\x77\x7b\xf2\x6b\x6f\xc5\x30\x01\x67\x2b\xfe\xd7\xab\x76" "\xca\x82\xc9\x7d\xfa\x59\x47\xf0\xad\xd4\xa2\xaf\x9c\xa4\x72\xc0" "\xb7\xfd\x93\x26\x36\x3f\xf7\xcc\x34\xa5\xe5\xf1\x71\xd8\x31\x15" "\x04\xc7\x23\xc3\x18\x96\x05\x9a\x07\x12\x80\xe2\xeb\x27\xb2\x75" "\x09\x83\x2c\x1a\x1b\x6e\x5a\xa0\x52\x3b\xd6\xb3\x29\xe3\x2f\x84" "\x53\xd1\x00\xed\x20\xfc\xb1\x5b\x6a\xcb\xbe\x39\x4a\x4c\x58\xcf" "\xd0\xef\xaa\xfb\x43\x4d\x33\x85\x45\xf9\x02\x7f\x50\x3c\x9f\xa8" "\x51\xa3\x40\x8f\x92\x9d\x38\xf5\xbc\xb6\xda\x21\x10\xff\xf3\xd2" "\xcd\x0c\x13\xec\x5f\x97\x44\x17\xc4\xa7\x7e\x3d\x64\x5d\x19\x73" "\x60\x81\x4f\xdc\x22\x2a\x90\x88\x46\xee\xb8\x14\xde\x5e\x0b\xdb" "\xe0\x32\x3a\x0a\x49\x06\x24\x5c\xc2\xd3\xac\x62\x91\x95\xe4\x79" "\xe7\xc8\x37\x6d\x8d\xd5\x4e\xa9\x6c\x56\xf4\xea\x65\x7a\xae\x08" "\xba\x78\x25\x2e\x1c\xa6\xb4\xc6\xe8\xdd\x74\x1f\x4b\xbd\x8b\x8a" "\x70\x3e\xb5\x66\x48\x03\xf6\x0e\x61\x35\x57\xb9\x86\xc1\x1d\x9e" "\xe1\xf8\x98\x11\x69\xd9\x8e\x94\x9b\x1e\x87\xe9\xce\x55\x28\xdf" "\x8c\xa1\x89\x0d\xbf\xe6\x42\x68\x41\x99\x2d\x0f\xb0\x54\xbb\x16" [i]&255; unsigned s2=s1<<1; if (s2>=0x100) s2^=0x11b; unsigned s3=s1^s2; Te0[i]=s2<<24|s1<<16|s1<<8|s3; Te1[i]=s3<<24|s2<<16|s1<<8|s1; Te2[i]=s1<<24|s3<<16|s2<<8|s1; Te3[i]=s1<<24|s1<<16|s3<<8|s2; Te4[i]=s1<<24|s1<<16|s1<<8|s1; } // setup the forward key Nr = 10 + ((keylen/8)-2)*2; // 10, 12, or 14 rounds int i = 0; U32* rk = &ek[0]; U32 temp; static const U32 rcon[10] = { 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL}; // round constants LOAD32H(rk[0], key ); LOAD32H(rk[1], key + 4); LOAD32H(rk[2], key + 8); LOAD32H(rk[3], key + 12); if (keylen == 16) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { break; } rk += 4; } } else if (keylen == 24) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); for (;;) { temp = rk[5]; rk[ 6] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { break; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } else if (keylen == 32) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); LOAD32H(rk[6], key + 24); LOAD32H(rk[7], key + 28); for (;;) { temp = rk[7]; rk[ 8] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { break; } temp = rk[11]; rk[12] = rk[ 4] ^ setup_mix(temp<<24|temp>>8); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } } // Encrypt to ct[16] void AES_CTR::encrypt(U32 s0, U32 s1, U32 s2, U32 s3, unsigned char* ct) { int r = Nr >> 1; U32 *rk = &ek[0]; U32 t0=0, t1=0, t2=0, t3=0; s0 ^= rk[0]; s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; for (;;) { t0 = Te0[byte(s0, 3)] ^ Te1[byte(s1, 2)] ^ Te2[byte(s2, 1)] ^ Te3[byte(s3, 0)] ^ rk[4]; t1 = Te0[byte(s1, 3)] ^ Te1[byte(s2, 2)] ^ Te2[byte(s3, 1)] ^ Te3[byte(s0, 0)] ^ rk[5]; t2 = Te0[byte(s2, 3)] ^ Te1[byte(s3, 2)] ^ Te2[byte(s0, 1)] ^ Te3[byte(s1, 0)] ^ rk[6]; t3 = Te0[byte(s3, 3)] ^ Te1[byte(s0, 2)] ^ Te2[byte(s1, 1)] ^ Te3[byte(s2, 0)] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[byte(t0, 3)] ^ Te1[byte(t1, 2)] ^ Te2[byte(t2, 1)] ^ Te3[byte(t3, 0)] ^ rk[0]; s1 = Te0[byte(t1, 3)] ^ Te1[byte(t2, 2)] ^ Te2[byte(t3, 1)] ^ Te3[byte(t0, 0)] ^ rk[1]; s2 = Te0[byte(t2, 3)] ^ Te1[byte(t3, 2)] ^ Te2[byte(t0, 1)] ^ Te3[byte(t1, 0)] ^ rk[2]; s3 = Te0[byte(t3, 3)] ^ Te1[byte(t0, 2)] ^ Te2[byte(t1, 1)] ^ Te3[byte(t2, 0)] ^ rk[3]; } // apply last round and map cipher state to byte array block: s0 = (Te4_3[byte(t0, 3)]) ^ (Te4_2[byte(t1, 2)]) ^ (Te4_1[byte(t2, 1)]) ^ (Te4_0[byte(t3, 0)]) ^ rk[0]; STORE32H(s0, ct); s1 = (Te4_3[byte(t1, 3)]) ^ (Te4_2[byte(t2, 2)]) ^ (Te4_1[byte(t3, 1)]) ^ (Te4_0[byte(t0, 0)]) ^ rk[1]; STORE32H(s1, ct+4); s2 = (Te4_3[byte(t2, 3)]) ^ (Te4_2[byte(t3, 2)]) ^ (Te4_1[byte(t0, 1)]) ^ (Te4_0[byte(t1, 0)]) ^ rk[2]; STORE32H(s2, ct+8); s3 = (Te4_3[byte(t3, 3)]) ^ (Te4_2[byte(t0, 2)]) ^ (Te4_1[byte(t1, 1)]) ^ (Te4_0[byte(t2, 0)]) ^ rk[3]; STORE32H(s3, ct+12); } // Encrypt or decrypt slice buf[0..n-1] at offset by XOR with AES(i) where // i is the 128 bit big-endian distance from the start in 16 byte blocks. void AES_CTR::encrypt(char* buf, int n, U64 offset) { for (U64 i=offset/16; i<=(offset+n)/16; ++i) { unsigned char ct[16]; encrypt(iv0, iv1, i>>32, i, ct); for (int j=0; j<16; ++j) { const int k=i*16-offset+j; if (k>=0 && k0) c=1; libzpaq::SHA256 sha256; char b[32]; for (int i=1; i*32<=dkLen; ++i) { for (int j=0; j=0; j-=8) sha256.put(i>>j); memcpy(b, sha256.result(), 32); for (int j=0; j>(32-b))) x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); #undef R } for (int i=0; i<16; ++i) b[i]+=x[i]; } // BlockMix_{Salsa20/8, r} on b[0..128*r-1] static void blockmix(U32* b, int r) { assert(r<=8); U32 x[16]; U32 y[256]; memcpy(x, b+32*r-16, 64); for (int i=0; i<2*r; ++i) { for (int j=0; j<16; ++j) x[j]^=b[i*16+j]; salsa8(x); memcpy(&y[i*16], x, 64); } for (int i=0; i x(32*r), v(32*r*n); for (int i=0; i>(i%4*8); } // Strengthen password pw[0..pwlen-1] and salt[0..saltlen-1] // to produce key buf[0..buflen-1]. Uses O(n*r*p) time and 128*r*n bytes // of memory. n must be a power of 2 and r <= 8. void scrypt(const char* pw, int pwlen, const char* salt, int saltlen, int n, int r, int p, char* buf, int buflen) { assert(r<=8); assert(n>0 && (n&(n-1))==0); // power of 2? libzpaq::Array b(p*r*128); pbkdf2(pw, pwlen, salt, saltlen, 1, &b[0], p*r*128); for (int i=0; i=1 && (buf[0]=='z' || buf[0]=='7')) buf[0]^=0x80; } //////////////////////////// Component /////////////////////// // A Component is a context model, indirect context model, match model, // fixed weight mixer, adaptive 2 input mixer without or with current // partial byte as context, adaptive m input mixer (without or with), // or SSE (without or with). const int compsize[256]={0,2,3,2,3,4,6,6,3,5}; void Component::init() { limit=cxt=a=b=c=0; cm.resize(0); ht.resize(0); a16.resize(0); } ////////////////////////// StateTable //////////////////////// // sns[i*4] -> next state if 0, next state if 1, n0, n1 static const U8 sns[1024]={ 1, 2, 0, 0, 3, 5, 1, 0, 4, 6, 0, 1, 7, 9, 2, 0, 8, 11, 1, 1, 8, 11, 1, 1, 10, 12, 0, 2, 13, 15, 3, 0, 14, 17, 2, 1, 14, 17, 2, 1, 16, 19, 1, 2, 16, 19, 1, 2, 18, 20, 0, 3, 21, 23, 4, 0, 22, 25, 3, 1, 22, 25, 3, 1, 24, 27, 2, 2, 24, 27, 2, 2, 26, 29, 1, 3, 26, 29, 1, 3, 28, 30, 0, 4, 31, 33, 5, 0, 32, 35, 4, 1, 32, 35, 4, 1, 34, 37, 3, 2, 34, 37, 3, 2, 36, 39, 2, 3, 36, 39, 2, 3, 38, 41, 1, 4, 38, 41, 1, 4, 40, 42, 0, 5, 43, 33, 6, 0, 44, 47, 5, 1, 44, 47, 5, 1, 46, 49, 4, 2, 46, 49, 4, 2, 48, 51, 3, 3, 48, 51, 3, 3, 50, 53, 2, 4, 50, 53, 2, 4, 52, 55, 1, 5, 52, 55, 1, 5, 40, 56, 0, 6, 57, 45, 7, 0, 58, 47, 6, 1, 58, 47, 6, 1, 60, 63, 5, 2, 60, 63, 5, 2, 62, 65, 4, 3, 62, 65, 4, 3, 64, 67, 3, 4, 64, 67, 3, 4, 66, 69, 2, 5, 66, 69, 2, 5, 52, 71, 1, 6, 52, 71, 1, 6, 54, 72, 0, 7, 73, 59, 8, 0, 74, 61, 7, 1, 74, 61, 7, 1, 76, 63, 6, 2, 76, 63, 6, 2, 78, 81, 5, 3, 78, 81, 5, 3, 80, 83, 4, 4, 80, 83, 4, 4, 82, 85, 3, 5, 82, 85, 3, 5, 66, 87, 2, 6, 66, 87, 2, 6, 68, 89, 1, 7, 68, 89, 1, 7, 70, 90, 0, 8, 91, 59, 9, 0, 92, 77, 8, 1, 92, 77, 8, 1, 94, 79, 7, 2, 94, 79, 7, 2, 96, 81, 6, 3, 96, 81, 6, 3, 98, 101, 5, 4, 98, 101, 5, 4, 100, 103, 4, 5, 100, 103, 4, 5, 82, 105, 3, 6, 82, 105, 3, 6, 84, 107, 2, 7, 84, 107, 2, 7, 86, 109, 1, 8, 86, 109, 1, 8, 70, 110, 0, 9, 111, 59, 10, 0, 112, 77, 9, 1, 112, 77, 9, 1, 114, 97, 8, 2, 114, 97, 8, 2, 116, 99, 7, 3, 116, 99, 7, 3, 62, 101, 6, 4, 62, 101, 6, 4, 80, 83, 5, 5, 80, 83, 5, 5, 100, 67, 4, 6, 100, 67, 4, 6, 102, 119, 3, 7, 102, 119, 3, 7, 104, 121, 2, 8, 104, 121, 2, 8, 86, 123, 1, 9, 86, 123, 1, 9, 70, 124, 0, 10, 125, 59, 11, 0, 126, 77, 10, 1, 126, 77, 10, 1, 128, 97, 9, 2, 128, 97, 9, 2, 60, 63, 8, 3, 60, 63, 8, 3, 66, 69, 3, 8, 66, 69, 3, 8, 104, 131, 2, 9, 104, 131, 2, 9, 86, 133, 1, 10, 86, 133, 1, 10, 70, 134, 0, 11, 135, 59, 12, 0, 136, 77, 11, 1, 136, 77, 11, 1, 138, 97, 10, 2, 138, 97, 10, 2, 104, 141, 2, 10, 104, 141, 2, 10, 86, 143, 1, 11, 86, 143, 1, 11, 70, 144, 0, 12, 145, 59, 13, 0, 146, 77, 12, 1, 146, 77, 12, 1, 148, 97, 11, 2, 148, 97, 11, 2, 104, 151, 2, 11, 104, 151, 2, 11, 86, 153, 1, 12, 86, 153, 1, 12, 70, 154, 0, 13, 155, 59, 14, 0, 156, 77, 13, 1, 156, 77, 13, 1, 158, 97, 12, 2, 158, 97, 12, 2, 104, 161, 2, 12, 104, 161, 2, 12, 86, 163, 1, 13, 86, 163, 1, 13, 70, 164, 0, 14, 165, 59, 15, 0, 166, 77, 14, 1, 166, 77, 14, 1, 168, 97, 13, 2, 168, 97, 13, 2, 104, 171, 2, 13, 104, 171, 2, 13, 86, 173, 1, 14, 86, 173, 1, 14, 70, 174, 0, 15, 175, 59, 16, 0, 176, 77, 15, 1, 176, 77, 15, 1, 178, 97, 14, 2, 178, 97, 14, 2, 104, 181, 2, 14, 104, 181, 2, 14, 86, 183, 1, 15, 86, 183, 1, 15, 70, 184, 0, 16, 185, 59, 17, 0, 186, 77, 16, 1, 186, 77, 16, 1, 74, 97, 15, 2, 74, 97, 15, 2, 104, 89, 2, 15, 104, 89, 2, 15, 86, 187, 1, 16, 86, 187, 1, 16, 70, 188, 0, 17, 189, 59, 18, 0, 190, 77, 17, 1, 86, 191, 1, 17, 70, 192, 0, 18, 193, 59, 19, 0, 194, 77, 18, 1, 86, 195, 1, 18, 70, 196, 0, 19, 193, 59, 20, 0, 197, 77, 19, 1, 86, 198, 1, 19, 70, 196, 0, 20, 199, 77, 20, 1, 86, 200, 1, 20, 201, 77, 21, 1, 86, 202, 1, 21, 203, 77, 22, 1, 86, 204, 1, 22, 205, 77, 23, 1, 86, 206, 1, 23, 207, 77, 24, 1, 86, 208, 1, 24, 209, 77, 25, 1, 86, 210, 1, 25, 211, 77, 26, 1, 86, 212, 1, 26, 213, 77, 27, 1, 86, 214, 1, 27, 215, 77, 28, 1, 86, 216, 1, 28, 217, 77, 29, 1, 86, 218, 1, 29, 219, 77, 30, 1, 86, 220, 1, 30, 221, 77, 31, 1, 86, 222, 1, 31, 223, 77, 32, 1, 86, 224, 1, 32, 225, 77, 33, 1, 86, 226, 1, 33, 227, 77, 34, 1, 86, 228, 1, 34, 229, 77, 35, 1, 86, 230, 1, 35, 231, 77, 36, 1, 86, 232, 1, 36, 233, 77, 37, 1, 86, 234, 1, 37, 235, 77, 38, 1, 86, 236, 1, 38, 237, 77, 39, 1, 86, 238, 1, 39, 239, 77, 40, 1, 86, 240, 1, 40, 241, 77, 41, 1, 86, 242, 1, 41, 243, 77, 42, 1, 86, 244, 1, 42, 245, 77, 43, 1, 86, 246, 1, 43, 247, 77, 44, 1, 86, 248, 1, 44, 249, 77, 45, 1, 86, 250, 1, 45, 251, 77, 46, 1, 86, 252, 1, 46, 253, 77, 47, 1, 86, 254, 1, 47, 253, 77, 48, 1, 86, 254, 1, 48, 0, 0, 0, 0 }; // Initialize next state table ns[state*4] -> next if 0, next if 1, n0, n1 StateTable::StateTable() { memcpy(ns, sns, sizeof(ns)); } /////////////////////////// ZPAQL ////////////////////////// // Write header to out2, return true if HCOMP/PCOMP section is present. // If pp is true, then write only the postprocessor code. bool ZPAQL::write(Writer* out2, bool pp) { if (header.size()<=6) return false; assert(header[0]+256*header[1]==cend-2+hend-hbegin); assert(cend>=7); assert(hbegin>=cend); assert(hend>=hbegin); assert(out2); if (!pp) { // if not a postprocessor then write COMP for (int i=0; iput(header[i]); } else { // write PCOMP size only out2->put((hend-hbegin)&255); out2->put((hend-hbegin)>>8); } for (int i=hbegin; iput(header[i]); return true; } // Read header from in2 int ZPAQL::read(Reader* in2) { // Get header size and allocate int hsize=in2->get(); hsize+=in2->get()*256; header.resize(hsize+300); cend=hbegin=hend=0; header[cend++]=hsize&255; header[cend++]=hsize>>8; while (cend<7) header[cend++]=in2->get(); // hh hm ph pm n // Read COMP int n=header[cend-1]; for (int i=0; iget(); // component type if (type<0 || type>255) error("unexpected end of file"); header[cend++]=type; // component type int size=compsize[type]; if (size<1) error("Invalid component type"); if (cend+size>hsize) error("COMP overflows header"); for (int j=1; jget(); } if ((header[cend++]=in2->get())!=0) error("missing COMP END"); // Insert a guard gap and read HCOMP hbegin=hend=cend+128; if (hend>hsize+129) error("missing HCOMP"); while (hendget(); if (op==-1) error("unexpected end of file"); header[hend++]=op; } if ((header[hend++]=in2->get())!=0) error("missing HCOMP END"); assert(cend>=7 && cendhbegin && hend6); assert(output==0); assert(sha1==0); init(header[2], header[3]); // hh, hm } // Initialize machine state as PCOMP void ZPAQL::initp() { assert(header.isize()>6); init(header[4], header[5]); // ph, pm } // Flush pending output void ZPAQL::flush() { if (output) output->write(&outbuf[0], bufptr); if (sha1) sha1->write(&outbuf[0], bufptr); bufptr=0; } // pow(2, x) static double pow2(int x) { double r=1; for (; x>0; x--) r+=r; return r; } // Return memory requirement in bytes double ZPAQL::memory() { double mem=pow2(header[2]+2)+pow2(header[3]) // hh hm +pow2(header[4]+2)+pow2(header[5]) // ph pm +header.size(); int cp=7; // start of comp list for (int i=0; i0); assert(cend>=7); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend0); if (hbits>32) error("H too big"); if (mbits>32) error("M too big"); h.resize(1, hbits); m.resize(1, mbits); r.resize(256); a=b=c=d=pc=f=0; } // Run program on input by interpreting header void ZPAQL::run0(U32 input) { assert(cend>6); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend0); assert(h.size()>0); assert(header[0]+256*header[1]==cend+hend-hbegin-2); pc=hbegin; a=input; while (execute()) ; } // Execute one instruction, return 0 after HALT else 1 int ZPAQL::execute() { switch(header[pc++]) { case 0: err(); break; // ERROR case 1: ++a; break; // A++ case 2: --a; break; // A-- case 3: a = ~a; break; // A! case 4: a = 0; break; // A=0 case 7: a = r[header[pc++]]; break; // A=R N case 8: swap(b); break; // B<>A case 9: ++b; break; // B++ case 10: --b; break; // B-- case 11: b = ~b; break; // B! case 12: b = 0; break; // B=0 case 15: b = r[header[pc++]]; break; // B=R N case 16: swap(c); break; // C<>A case 17: ++c; break; // C++ case 18: --c; break; // C-- case 19: c = ~c; break; // C! case 20: c = 0; break; // C=0 case 23: c = r[header[pc++]]; break; // C=R N case 24: swap(d); break; // D<>A case 25: ++d; break; // D++ case 26: --d; break; // D-- case 27: d = ~d; break; // D! case 28: d = 0; break; // D=0 case 31: d = r[header[pc++]]; break; // D=R N case 32: swap(m(b)); break; // *B<>A case 33: ++m(b); break; // *B++ case 34: --m(b); break; // *B-- case 35: m(b) = ~m(b); break; // *B! case 36: m(b) = 0; break; // *B=0 case 39: if (f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JT N case 40: swap(m(c)); break; // *C<>A case 41: ++m(c); break; // *C++ case 42: --m(c); break; // *C-- case 43: m(c) = ~m(c); break; // *C! case 44: m(c) = 0; break; // *C=0 case 47: if (!f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JF N case 48: swap(h(d)); break; // *D<>A case 49: ++h(d); break; // *D++ case 50: --h(d); break; // *D-- case 51: h(d) = ~h(d); break; // *D! case 52: h(d) = 0; break; // *D=0 case 55: r[header[pc++]] = a; break; // R=A N case 56: return 0 ; // HALT case 57: outc(a&255); break; // OUT case 59: a = (a+m(b)+512)*773; break; // HASH case 60: h(d) = (h(d)+a+512)*773; break; // HASHD case 63: pc+=((header[pc]+128)&255)-127; break; // JMP N case 64: break; // A=A case 65: a = b; break; // A=B case 66: a = c; break; // A=C case 67: a = d; break; // A=D case 68: a = m(b); break; // A=*B case 69: a = m(c); break; // A=*C case 70: a = h(d); break; // A=*D case 71: a = header[pc++]; break; // A= N case 72: b = a; break; // B=A case 73: break; // B=B case 74: b = c; break; // B=C case 75: b = d; break; // B=D case 76: b = m(b); break; // B=*B case 77: b = m(c); break; // B=*C case 78: b = h(d); break; // B=*D case 79: b = header[pc++]; break; // B= N case 80: c = a; break; // C=A case 81: c = b; break; // C=B case 82: break; // C=C case 83: c = d; break; // C=D case 84: c = m(b); break; // C=*B case 85: c = m(c); break; // C=*C case 86: c = h(d); break; // C=*D case 87: c = header[pc++]; break; // C= N case 88: d = a; break; // D=A case 89: d = b; break; // D=B case 90: d = c; break; // D=C case 91: break; // D=D case 92: d = m(b); break; // D=*B case 93: d = m(c); break; // D=*C case 94: d = h(d); break; // D=*D case 95: d = header[pc++]; break; // D= N case 96: m(b) = a; break; // *B=A case 97: m(b) = b; break; // *B=B case 98: m(b) = c; break; // *B=C case 99: m(b) = d; break; // *B=D case 100: break; // *B=*B case 101: m(b) = m(c); break; // *B=*C case 102: m(b) = h(d); break; // *B=*D case 103: m(b) = header[pc++]; break; // *B= N case 104: m(c) = a; break; // *C=A case 105: m(c) = b; break; // *C=B case 106: m(c) = c; break; // *C=C case 107: m(c) = d; break; // *C=D case 108: m(c) = m(b); break; // *C=*B case 109: break; // *C=*C case 110: m(c) = h(d); break; // *C=*D case 111: m(c) = header[pc++]; break; // *C= N case 112: h(d) = a; break; // *D=A case 113: h(d) = b; break; // *D=B case 114: h(d) = c; break; // *D=C case 115: h(d) = d; break; // *D=D case 116: h(d) = m(b); break; // *D=*B case 117: h(d) = m(c); break; // *D=*C case 118: break; // *D=*D case 119: h(d) = header[pc++]; break; // *D= N case 128: a += a; break; // A+=A case 129: a += b; break; // A+=B case 130: a += c; break; // A+=C case 131: a += d; break; // A+=D case 132: a += m(b); break; // A+=*B case 133: a += m(c); break; // A+=*C case 134: a += h(d); break; // A+=*D case 135: a += header[pc++]; break; // A+= N case 136: a -= a; break; // A-=A case 137: a -= b; break; // A-=B case 138: a -= c; break; // A-=C case 139: a -= d; break; // A-=D case 140: a -= m(b); break; // A-=*B case 141: a -= m(c); break; // A-=*C case 142: a -= h(d); break; // A-=*D case 143: a -= header[pc++]; break; // A-= N case 144: a *= a; break; // A*=A case 145: a *= b; break; // A*=B case 146: a *= c; break; // A*=C case 147: a *= d; break; // A*=D case 148: a *= m(b); break; // A*=*B case 149: a *= m(c); break; // A*=*C case 150: a *= h(d); break; // A*=*D case 151: a *= header[pc++]; break; // A*= N case 152: div(a); break; // A/=A case 153: div(b); break; // A/=B case 154: div(c); break; // A/=C case 155: div(d); break; // A/=D case 156: div(m(b)); break; // A/=*B case 157: div(m(c)); break; // A/=*C case 158: div(h(d)); break; // A/=*D case 159: div(header[pc++]); break; // A/= N case 160: mod(a); break; // A%=A case 161: mod(b); break; // A%=B case 162: mod(c); break; // A%=C case 163: mod(d); break; // A%=D case 164: mod(m(b)); break; // A%=*B case 165: mod(m(c)); break; // A%=*C case 166: mod(h(d)); break; // A%=*D case 167: mod(header[pc++]); break; // A%= N case 168: a &= a; break; // A&=A case 169: a &= b; break; // A&=B case 170: a &= c; break; // A&=C case 171: a &= d; break; // A&=D case 172: a &= m(b); break; // A&=*B case 173: a &= m(c); break; // A&=*C case 174: a &= h(d); break; // A&=*D case 175: a &= header[pc++]; break; // A&= N case 176: a &= ~ a; break; // A&~A case 177: a &= ~ b; break; // A&~B case 178: a &= ~ c; break; // A&~C case 179: a &= ~ d; break; // A&~D case 180: a &= ~ m(b); break; // A&~*B case 181: a &= ~ m(c); break; // A&~*C case 182: a &= ~ h(d); break; // A&~*D case 183: a &= ~ header[pc++]; break; // A&~ N case 184: a |= a; break; // A|=A case 185: a |= b; break; // A|=B case 186: a |= c; break; // A|=C case 187: a |= d; break; // A|=D case 188: a |= m(b); break; // A|=*B case 189: a |= m(c); break; // A|=*C case 190: a |= h(d); break; // A|=*D case 191: a |= header[pc++]; break; // A|= N case 192: a ^= a; break; // A^=A case 193: a ^= b; break; // A^=B case 194: a ^= c; break; // A^=C case 195: a ^= d; break; // A^=D case 196: a ^= m(b); break; // A^=*B case 197: a ^= m(c); break; // A^=*C case 198: a ^= h(d); break; // A^=*D case 199: a ^= header[pc++]; break; // A^= N case 200: a <<= (a&31); break; // A<<=A case 201: a <<= (b&31); break; // A<<=B case 202: a <<= (c&31); break; // A<<=C case 203: a <<= (d&31); break; // A<<=D case 204: a <<= (m(b)&31); break; // A<<=*B case 205: a <<= (m(c)&31); break; // A<<=*C case 206: a <<= (h(d)&31); break; // A<<=*D case 207: a <<= (header[pc++]&31); break; // A<<= N case 208: a >>= (a&31); break; // A>>=A case 209: a >>= (b&31); break; // A>>=B case 210: a >>= (c&31); break; // A>>=C case 211: a >>= (d&31); break; // A>>=D case 212: a >>= (m(b)&31); break; // A>>=*B case 213: a >>= (m(c)&31); break; // A>>=*C case 214: a >>= (h(d)&31); break; // A>>=*D case 215: a >>= (header[pc++]&31); break; // A>>= N case 216: f = 1; break; // A==A case 217: f = (a == b); break; // A==B case 218: f = (a == c); break; // A==C case 219: f = (a == d); break; // A==D case 220: f = (a == U32(m(b))); break; // A==*B case 221: f = (a == U32(m(c))); break; // A==*C case 222: f = (a == h(d)); break; // A==*D case 223: f = (a == U32(header[pc++])); break; // A== N case 224: f = 0; break; // AA case 233: f = (a > b); break; // A>B case 234: f = (a > c); break; // A>C case 235: f = (a > d); break; // A>D case 236: f = (a > U32(m(b))); break; // A>*B case 237: f = (a > U32(m(c))); break; // A>*C case 238: f = (a > h(d)); break; // A>*D case 239: f = (a > U32(header[pc++])); break; // A> N case 255: if((pc=hbegin+header[pc]+256*header[pc+1])>=hend)err();break;//LJ default: err(); } return 1; } // Print illegal instruction error message and exit void ZPAQL::err() { error("ZPAQL execution error"); } ///////////////////////// Predictor ///////////////////////// // sdt2k[i]=2048/i; static const int sdt2k[256]={ 0, 2048, 1024, 682, 512, 409, 341, 292, 256, 227, 204, 186, 170, 157, 146, 136, 128, 120, 113, 107, 102, 97, 93, 89, 85, 81, 78, 75, 73, 70, 68, 66, 64, 62, 60, 58, 56, 55, 53, 52, 51, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 40, 39, 38, 37, 37, 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; // sdt[i]=(1<<17)/(i*2+3)*2; static const int sdt[1024]={ 87380, 52428, 37448, 29126, 23830, 20164, 17476, 15420, 13796, 12482, 11396, 10484, 9708, 9038, 8456, 7942, 7488, 7084, 6720, 6392, 6096, 5824, 5576, 5348, 5140, 4946, 4766, 4598, 4442, 4296, 4160, 4032, 3912, 3798, 3692, 3590, 3494, 3404, 3318, 3236, 3158, 3084, 3012, 2944, 2880, 2818, 2758, 2702, 2646, 2594, 2544, 2496, 2448, 2404, 2360, 2318, 2278, 2240, 2202, 2166, 2130, 2096, 2064, 2032, 2000, 1970, 1940, 1912, 1884, 1858, 1832, 1806, 1782, 1758, 1736, 1712, 1690, 1668, 1648, 1628, 1608, 1588, 1568, 1550, 1532, 1514, 1496, 1480, 1464, 1448, 1432, 1416, 1400, 1386, 1372, 1358, 1344, 1330, 1316, 1304, 1290, 1278, 1266, 1254, 1242, 1230, 1218, 1208, 1196, 1186, 1174, 1164, 1154, 1144, 1134, 1124, 1114, 1106, 1096, 1086, 1078, 1068, 1060, 1052, 1044, 1036, 1028, 1020, 1012, 1004, 996, 988, 980, 974, 966, 960, 952, 946, 938, 932, 926, 918, 912, 906, 900, 894, 888, 882, 876, 870, 864, 858, 852, 848, 842, 836, 832, 826, 820, 816, 810, 806, 800, 796, 790, 786, 782, 776, 772, 768, 764, 758, 754, 750, 746, 742, 738, 734, 730, 726, 722, 718, 714, 710, 706, 702, 698, 694, 690, 688, 684, 680, 676, 672, 670, 666, 662, 660, 656, 652, 650, 646, 644, 640, 636, 634, 630, 628, 624, 622, 618, 616, 612, 610, 608, 604, 602, 598, 596, 594, 590, 588, 586, 582, 580, 578, 576, 572, 570, 568, 566, 562, 560, 558, 556, 554, 550, 548, 546, 544, 542, 540, 538, 536, 532, 530, 528, 526, 524, 522, 520, 518, 516, 514, 512, 510, 508, 506, 504, 502, 500, 498, 496, 494, 492, 490, 488, 488, 486, 484, 482, 480, 478, 476, 474, 474, 472, 470, 468, 466, 464, 462, 462, 460, 458, 456, 454, 454, 452, 450, 448, 448, 446, 444, 442, 442, 440, 438, 436, 436, 434, 432, 430, 430, 428, 426, 426, 424, 422, 422, 420, 418, 418, 416, 414, 414, 412, 410, 410, 408, 406, 406, 404, 402, 402, 400, 400, 398, 396, 396, 394, 394, 392, 390, 390, 388, 388, 386, 386, 384, 382, 382, 380, 380, 378, 378, 376, 376, 374, 372, 372, 370, 370, 368, 368, 366, 366, 364, 364, 362, 362, 360, 360, 358, 358, 356, 356, 354, 354, 352, 352, 350, 350, 348, 348, 348, 346, 346, 344, 344, 342, 342, 340, 340, 340, 338, 338, 336, 336, 334, 334, 332, 332, 332, 330, 330, 328, 328, 328, 326, 326, 324, 324, 324, 322, 322, 320, 320, 320, 318, 318, 316, 316, 316, 314, 314, 312, 312, 312, 310, 310, 310, 308, 308, 308, 306, 306, 304, 304, 304, 302, 302, 302, 300, 300, 300, 298, 298, 298, 296, 296, 296, 294, 294, 294, 292, 292, 292, 290, 290, 290, 288, 288, 288, 286, 286, 286, 284, 284, 284, 284, 282, 282, 282, 280, 280, 280, 278, 278, 278, 276, 276, 276, 276, 274, 274, 274, 272, 272, 272, 272, 270, 270, 270, 268, 268, 268, 268, 266, 266, 266, 266, 264, 264, 264, 262, 262, 262, 262, 260, 260, 260, 260, 258, 258, 258, 258, 256, 256, 256, 256, 254, 254, 254, 254, 252, 252, 252, 252, 250, 250, 250, 250, 248, 248, 248, 248, 248, 246, 246, 246, 246, 244, 244, 244, 244, 242, 242, 242, 242, 242, 240, 240, 240, 240, 238, 238, 238, 238, 238, 236, 236, 236, 236, 234, 234, 234, 234, 234, 232, 232, 232, 232, 232, 230, 230, 230, 230, 230, 228, 228, 228, 228, 228, 226, 226, 226, 226, 226, 224, 224, 224, 224, 224, 222, 222, 222, 222, 222, 220, 220, 220, 220, 220, 220, 218, 218, 218, 218, 218, 216, 216, 216, 216, 216, 216, 214, 214, 214, 214, 214, 212, 212, 212, 212, 212, 212, 210, 210, 210, 210, 210, 210, 208, 208, 208, 208, 208, 208, 206, 206, 206, 206, 206, 206, 204, 204, 204, 204, 204, 204, 204, 202, 202, 202, 202, 202, 202, 200, 200, 200, 200, 200, 200, 198, 198, 198, 198, 198, 198, 198, 196, 196, 196, 196, 196, 196, 196, 194, 194, 194, 194, 194, 194, 194, 192, 192, 192, 192, 192, 192, 192, 190, 190, 190, 190, 190, 190, 190, 188, 188, 188, 188, 188, 188, 188, 186, 186, 186, 186, 186, 186, 186, 186, 184, 184, 184, 184, 184, 184, 184, 182, 182, 182, 182, 182, 182, 182, 182, 180, 180, 180, 180, 180, 180, 180, 180, 178, 178, 178, 178, 178, 178, 178, 178, 176, 176, 176, 176, 176, 176, 176, 176, 176, 174, 174, 174, 174, 174, 174, 174, 174, 172, 172, 172, 172, 172, 172, 172, 172, 172, 170, 170, 170, 170, 170, 170, 170, 170, 170, 168, 168, 168, 168, 168, 168, 168, 168, 168, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 164, 164, 164, 164, 164, 164, 164, 164, 164, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126 }; // ssquasht[i]=int(32768.0/(1+exp((i-2048)*(-1.0/64)))); // Middle 1344 of 4096 entries only. static const U16 ssquasht[1344]={ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, 37, 38, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, 45, 46, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 90, 91, 93, 94, 96, 97, 99, 100, 102, 103, 105, 107, 108, 110, 112, 114, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 144, 146, 148, 151, 153, 155, 158, 160, 163, 165, 168, 171, 173, 176, 179, 182, 184, 187, 190, 193, 196, 199, 202, 206, 209, 212, 215, 219, 222, 226, 229, 233, 237, 240, 244, 248, 252, 256, 260, 264, 268, 272, 276, 281, 285, 289, 294, 299, 303, 308, 313, 318, 323, 328, 333, 338, 343, 349, 354, 360, 365, 371, 377, 382, 388, 394, 401, 407, 413, 420, 426, 433, 440, 446, 453, 460, 467, 475, 482, 490, 497, 505, 513, 521, 529, 537, 545, 554, 562, 571, 580, 589, 598, 607, 617, 626, 636, 646, 656, 666, 676, 686, 697, 708, 719, 730, 741, 752, 764, 776, 788, 800, 812, 825, 837, 850, 863, 876, 890, 903, 917, 931, 946, 960, 975, 990, 1005, 1020, 1036, 1051, 1067, 1084, 1100, 1117, 1134, 1151, 1169, 1186, 1204, 1223, 1241, 1260, 1279, 1298, 1318, 1338, 1358, 1379, 1399, 1421, 1442, 1464, 1486, 1508, 1531, 1554, 1577, 1600, 1624, 1649, 1673, 1698, 1724, 1749, 1775, 1802, 1829, 1856, 1883, 1911, 1940, 1968, 1998, 2027, 2057, 2087, 2118, 2149, 2181, 2213, 2245, 2278, 2312, 2345, 2380, 2414, 2450, 2485, 2521, 2558, 2595, 2633, 2671, 2709, 2748, 2788, 2828, 2869, 2910, 2952, 2994, 3037, 3080, 3124, 3168, 3213, 3259, 3305, 3352, 3399, 3447, 3496, 3545, 3594, 3645, 3696, 3747, 3799, 3852, 3906, 3960, 4014, 4070, 4126, 4182, 4240, 4298, 4356, 4416, 4476, 4537, 4598, 4660, 4723, 4786, 4851, 4916, 4981, 5048, 5115, 5183, 5251, 5320, 5390, 5461, 5533, 5605, 5678, 5752, 5826, 5901, 5977, 6054, 6131, 6210, 6289, 6369, 6449, 6530, 6613, 6695, 6779, 6863, 6949, 7035, 7121, 7209, 7297, 7386, 7476, 7566, 7658, 7750, 7842, 7936, 8030, 8126, 8221, 8318, 8415, 8513, 8612, 8712, 8812, 8913, 9015, 9117, 9221, 9324, 9429, 9534, 9640, 9747, 9854, 9962, 10071, 10180, 10290, 10401, 10512, 10624, 10737, 10850, 10963, 11078, 11192, 11308, 11424, 11540, 11658, 11775, 11893, 12012, 12131, 12251, 12371, 12491, 12612, 12734, 12856, 12978, 13101, 13224, 13347, 13471, 13595, 13719, 13844, 13969, 14095, 14220, 14346, 14472, 14599, 14725, 14852, 14979, 15106, 15233, 15361, 15488, 15616, 15744, 15872, 16000, 16128, 16256, 16384, 16511, 16639, 16767, 16895, 17023, 17151, 17279, 17406, 17534, 17661, 17788, 17915, 18042, 18168, 18295, 18421, 18547, 18672, 18798, 18923, 19048, 19172, 19296, 19420, 19543, 19666, 19789, 19911, 20033, 20155, 20276, 20396, 20516, 20636, 20755, 20874, 20992, 21109, 21227, 21343, 21459, 21575, 21689, 21804, 21917, 22030, 22143, 22255, 22366, 22477, 22587, 22696, 22805, 22913, 23020, 23127, 23233, 23338, 23443, 23546, 23650, 23752, 23854, 23955, 24055, 24155, 24254, 24352, 24449, 24546, 24641, 24737, 24831, 24925, 25017, 25109, 25201, 25291, 25381, 25470, 25558, 25646, 25732, 25818, 25904, 25988, 26072, 26154, 26237, 26318, 26398, 26478, 26557, 26636, 26713, 26790, 26866, 26941, 27015, 27089, 27162, 27234, 27306, 27377, 27447, 27516, 27584, 27652, 27719, 27786, 27851, 27916, 27981, 28044, 28107, 28169, 28230, 28291, 28351, 28411, 28469, 28527, 28585, 28641, 28697, 28753, 28807, 28861, 28915, 28968, 29020, 29071, 29122, 29173, 29222, 29271, 29320, 29368, 29415, 29462, 29508, 29554, 29599, 29643, 29687, 29730, 29773, 29815, 29857, 29898, 29939, 29979, 30019, 30058, 30096, 30134, 30172, 30209, 30246, 30282, 30317, 30353, 30387, 30422, 30455, 30489, 30522, 30554, 30586, 30618, 30649, 30680, 30710, 30740, 30769, 30799, 30827, 30856, 30884, 30911, 30938, 30965, 30992, 31018, 31043, 31069, 31094, 31118, 31143, 31167, 31190, 31213, 31236, 31259, 31281, 31303, 31325, 31346, 31368, 31388, 31409, 31429, 31449, 31469, 31488, 31507, 31526, 31544, 31563, 31581, 31598, 31616, 31633, 31650, 31667, 31683, 31700, 31716, 31731, 31747, 31762, 31777, 31792, 31807, 31821, 31836, 31850, 31864, 31877, 31891, 31904, 31917, 31930, 31942, 31955, 31967, 31979, 31991, 32003, 32015, 32026, 32037, 32048, 32059, 32070, 32081, 32091, 32101, 32111, 32121, 32131, 32141, 32150, 32160, 32169, 32178, 32187, 32196, 32205, 32213, 32222, 32230, 32238, 32246, 32254, 32262, 32270, 32277, 32285, 32292, 32300, 32307, 32314, 32321, 32327, 32334, 32341, 32347, 32354, 32360, 32366, 32373, 32379, 32385, 32390, 32396, 32402, 32407, 32413, 32418, 32424, 32429, 32434, 32439, 32444, 32449, 32454, 32459, 32464, 32468, 32473, 32478, 32482, 32486, 32491, 32495, 32499, 32503, 32507, 32511, 32515, 32519, 32523, 32527, 32530, 32534, 32538, 32541, 32545, 32548, 32552, 32555, 32558, 32561, 32565, 32568, 32571, 32574, 32577, 32580, 32583, 32585, 32588, 32591, 32594, 32596, 32599, 32602, 32604, 32607, 32609, 32612, 32614, 32616, 32619, 32621, 32623, 32626, 32628, 32630, 32632, 32634, 32636, 32638, 32640, 32642, 32644, 32646, 32648, 32650, 32652, 32653, 32655, 32657, 32659, 32660, 32662, 32664, 32665, 32667, 32668, 32670, 32671, 32673, 32674, 32676, 32677, 32679, 32680, 32681, 32683, 32684, 32685, 32686, 32688, 32689, 32690, 32691, 32693, 32694, 32695, 32696, 32697, 32698, 32699, 32700, 32701, 32702, 32703, 32704, 32705, 32706, 32707, 32708, 32709, 32710, 32711, 32712, 32713, 32713, 32714, 32715, 32716, 32717, 32718, 32718, 32719, 32720, 32721, 32721, 32722, 32723, 32723, 32724, 32725, 32725, 32726, 32727, 32727, 32728, 32729, 32729, 32730, 32730, 32731, 32731, 32732, 32733, 32733, 32734, 32734, 32735, 32735, 32736, 32736, 32737, 32737, 32738, 32738, 32739, 32739, 32739, 32740, 32740, 32741, 32741, 32742, 32742, 32742, 32743, 32743, 32744, 32744, 32744, 32745, 32745, 32745, 32746, 32746, 32746, 32747, 32747, 32747, 32748, 32748, 32748, 32749, 32749, 32749, 32749, 32750, 32750, 32750, 32750, 32751, 32751, 32751, 32752, 32752, 32752, 32752, 32752, 32753, 32753, 32753, 32753, 32754, 32754, 32754, 32754, 32754, 32755, 32755, 32755, 32755, 32755, 32756, 32756, 32756, 32756, 32756, 32757, 32757, 32757, 32757, 32757, 32757, 32757, 32758, 32758, 32758, 32758, 32758, 32758, 32759, 32759, 32759, 32759, 32759, 32759, 32759, 32759, 32760, 32760, 32760, 32760, 32760, 32760, 32760, 32760, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32767, 32767, 32767, 32767, 32767, 32767 }; // stdt[i]=count of -i or i in botton or top of stretcht[] static const U8 stdt[712]={ 64, 128, 128, 128, 128, 128, 127, 128, 127, 128, 127, 127, 127, 127, 126, 126, 126, 126, 126, 125, 125, 124, 125, 124, 123, 123, 123, 123, 122, 122, 121, 121, 120, 120, 119, 119, 118, 118, 118, 116, 117, 115, 116, 114, 114, 113, 113, 112, 112, 111, 110, 110, 109, 108, 108, 107, 106, 106, 105, 104, 104, 102, 103, 101, 101, 100, 99, 98, 98, 97, 96, 96, 94, 94, 94, 92, 92, 91, 90, 89, 89, 88, 87, 86, 86, 84, 84, 84, 82, 82, 81, 80, 79, 79, 78, 77, 76, 76, 75, 74, 73, 73, 72, 71, 70, 70, 69, 68, 67, 67, 66, 65, 65, 64, 63, 62, 62, 61, 61, 59, 59, 59, 57, 58, 56, 56, 55, 54, 54, 53, 52, 52, 51, 51, 50, 49, 49, 48, 48, 47, 47, 45, 46, 44, 45, 43, 43, 43, 42, 41, 41, 40, 40, 40, 39, 38, 38, 37, 37, 36, 36, 36, 35, 34, 34, 34, 33, 32, 33, 32, 31, 31, 30, 31, 29, 30, 28, 29, 28, 28, 27, 27, 27, 26, 26, 25, 26, 24, 25, 24, 24, 23, 23, 23, 23, 22, 22, 21, 22, 21, 20, 21, 20, 19, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 14, 13, 13, 13, 12, 13, 12, 12, 12, 11, 12, 11, 11, 11, 11, 11, 10, 11, 10, 10, 10, 10, 9, 10, 9, 9, 9, 9, 9, 8, 9, 8, 9, 8, 8, 8, 7, 8, 8, 7, 7, 8, 7, 7, 7, 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 6, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 4, 5, 4, 4, 5, 4, 4, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; Predictor::Predictor(ZPAQL& zr): c8(1), hmap4(1), z(zr) { assert(sizeof(U8)==1); assert(sizeof(U16)==2); assert(sizeof(U32)==4); assert(sizeof(U64)==8); assert(sizeof(short)==2); assert(sizeof(int)==4); pcode=0; pcode_size=0; initTables=false; } Predictor::~Predictor() { allocx(pcode, pcode_size, 0); // free executable memory } // Initialize the predictor with a new model in z void Predictor::init() { // Clear old JIT code if any allocx(pcode, pcode_size, 0); // Initialize context hash function z.inith(); // Initialize model independent tables if (!initTables && isModeled()) { initTables=true; memcpy(dt2k, sdt2k, sizeof(dt2k)); memcpy(dt, sdt, sizeof(dt)); // ssquasht[i]=int(32768.0/(1+exp((i-2048)*(-1.0/64)))); // Copy middle 1344 of 4096 entries. memset(squasht, 0, 1376*2); memcpy(squasht+1376, ssquasht, 1344*2); for (int i=2720; i<4096; ++i) squasht[i]=32767; // sstretcht[i]=int(log((i+0.5)/(32767.5-i))*64+0.5+100000)-100000; int k=16384; for (int i=0; i<712; ++i) for (int j=stdt[i]; j>0; --j) stretcht[k++]=i; assert(k==32768); for (int i=0; i<16384; ++i) stretcht[i]=-stretcht[32767-i]; #ifndef NDEBUG // Verify floating point math for squash() and stretch() U32 sqsum=0, stsum=0; for (int i=32767; i>=0; --i) stsum=stsum*3+stretch(i); for (int i=4095; i>=0; --i) sqsum=sqsum*3+squash(i-2048); assert(stsum==3887533746u); assert(sqsum==2278286169u); #endif } // Initialize predictions for (int i=0; i<256; ++i) h[i]=p[i]=0; // Initialize components for (int i=0; i<256; ++i) // clear old model comp[i].init(); int n=z.header[6]; // hsize[0..1] hh hm ph pm n (comp)[n] END 0[128] (hcomp) END const U8* cp=&z.header[7]; // start of component list for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); Component& cr=comp[i]; switch(cp[0]) { case CONS: // c p[i]=(cp[1]-128)*4; break; case CM: // sizebits limit if (cp[1]>32) error("max size for CM is 32"); cr.cm.resize(1, cp[1]); // packed CM (22 bits) + CMCOUNT (10 bits) cr.limit=cp[2]*4; for (size_t j=0; j26) error("max size for ICM is 26"); cr.limit=1023; cr.cm.resize(256); cr.ht.resize(64, cp[1]); for (size_t j=0; j32 || cp[2]>32) error("max size for MATCH is 32 32"); cr.cm.resize(1, cp[1]); // index cr.ht.resize(1, cp[2]); // buf cr.ht(0)=1; break; case AVG: // j k wt if (cp[1]>=i) error("AVG j >= i"); if (cp[2]>=i) error("AVG k >= i"); break; case MIX2: // sizebits j k rate mask if (cp[1]>32) error("max size for MIX2 is 32"); if (cp[3]>=i) error("MIX2 k >= i"); if (cp[2]>=i) error("MIX2 j >= i"); cr.c=(size_t(1)<32) error("max size for MIX is 32"); if (cp[2]>=i) error("MIX j >= i"); if (cp[3]<1 || cp[3]>i-cp[2]) error("MIX m not in 1..i-j"); int m=cp[3]; // number of inputs assert(m>=1); cr.c=(size_t(1)<32) error("max size for ISSE is 32"); if (cp[2]>=i) error("ISSE j >= i"); cr.ht.resize(64, cp[1]); cr.cm.resize(512); for (int j=0; j<256; ++j) { cr.cm[j*2]=1<<15; cr.cm[j*2+1]=clamp512k(stretch(st.cminit(j)>>8)*1024); } break; case SSE: // sizebits j start limit if (cp[1]>32) error("max size for SSE is 32"); if (cp[2]>=i) error("SSE j >= i"); if (cp[3]>cp[4]*4) error("SSE start > limit*4"); cr.cm.resize(32, cp[1]); cr.limit=cp[4]*4; for (size_t j=0; j0); cp+=compsize[*cp]; assert(cp>=&z.header[7] && cp<&z.header[z.cend]); } } // Return next bit prediction using interpreted COMP code int Predictor::predict0() { assert(initTables); assert(c8>=1 && c8<=255); // Predict next bit int n=z.header[6]; assert(n>0 && n<=255); const U8* cp=&z.header[7]; assert(cp[-1]==n); for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); Component& cr=comp[i]; switch(cp[0]) { case CONS: // c break; case CM: // sizebits limit cr.cxt=h[i]^hmap4; p[i]=stretch(cr.cm(cr.cxt)>>17); break; case ICM: // sizebits assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; p[i]=stretch(cr.cm(cr.cxt)>>8); break; case MATCH: // sizebits bufbits: a=len, b=offset, c=bit, cxt=bitpos, // ht=buf, limit=pos assert(cr.cm.size()==(size_t(1)<>(7-cr.cxt))&1; // predicted bit p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767); } break; case AVG: // j k wt p[i]=(p[cp[1]]*cp[3]+p[cp[2]]*(256-cp[3]))>>8; break; case MIX2: { // sizebits j k rate mask // c=size cm=wt[size] cxt=input cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1)); assert(cr.cxt=0 && w<65536); p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16; assert(p[i]>=-2048 && p[i]<2048); } break; case MIX: { // sizebits j m rate mask // c=size cm=wt[size][m] cxt=index of wt in cm int m=cp[3]; assert(m>=1 && m<=i); cr.cxt=h[i]+(c8&cp[5]); cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights assert(cr.cxt<=cr.cm.size()-m); int* wt=(int*)&cr.cm[cr.cxt]; p[i]=0; for (int j=0; j>8)*p[cp[2]+j]; p[i]=clamp2k(p[i]>>8); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; // bit history int *wt=(int*)&cr.cm[cr.cxt*2]; p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16); } break; case SSE: { // sizebits j start limit cr.cxt=(h[i]+c8)*32; int pq=p[cp[2]]+992; if (pq<0) pq=0; if (pq>1983) pq=1983; int wt=pq&63; pq>>=6; assert(pq>=0 && pq<=30); cr.cxt+=pq; p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt)+(cr.cm(cr.cxt+1)>>10)*wt)>>13); cr.cxt+=wt>>5; } break; default: error("component predict not implemented"); } cp+=compsize[cp[0]]; assert(cp<&z.header[z.cend]); assert(p[i]>=-2048 && p[i]<2048); } assert(cp[0]==NONE); return squash(p[n-1]); } // Update model with decoded bit y (0...1) void Predictor::update0(int y) { assert(initTables); assert(y==0 || y==1); assert(c8>=1 && c8<=255); assert(hmap4>=1 && hmap4<=511); // Update components const U8* cp=&z.header[7]; int n=z.header[6]; assert(n>=1 && n<=255); assert(cp[-1]==n); for (int i=0; i>8))>>2; } break; case MATCH: // sizebits bufbits: // a=len, b=offset, c=bit, cm=index, cxt=bitpos // ht=buf, limit=pos { assert(cr.a<=255); assert(cr.c==0 || cr.c==1); assert(cr.cxt<8); assert(cr.cm.size()==(size_t(1)<>5; int w=cr.a16[cr.cxt]; w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13; if (w<0) w=0; if (w>65535) w=65535; cr.a16[cr.cxt]=w; } break; case MIX: { // sizebits j m rate mask // cm=wt[size][m], cxt=input int m=cp[3]; assert(m>0 && m<=i); assert(cr.cm.size()==m*cr.c); assert(cr.cxt+m<=cr.cm.size()); int err=(y*32767-squash(p[i]))*cp[4]>>4; int* wt=(int*)&cr.cm[cr.cxt]; for (int j=0; j>13)); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert(cr.cxt==cr.ht[cr.c+(hmap4&15)]); int err=y*32767-squash(p[i]); int *wt=(int*)&cr.cm[cr.cxt*2]; wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13)); wt[1]=clamp512k(wt[1]+((err+16)>>5)); cr.ht[cr.c+(hmap4&15)]=st.next(cr.cxt, y); } break; case SSE: // sizebits j start limit train(cr, y); break; default: assert(0); } cp+=compsize[cp[0]]; assert(cp>=&z.header[7] && cp<&z.header[z.cend] && cp<&z.header[z.header.isize()-8]); } assert(cp[0]==NONE); // Save bit y in c8, hmap4 c8+=c8+y; if (c8>=256) { z.run(c8-256); hmap4=1; c8=1; for (int i=0; i=16 && c8<32) hmap4=(hmap4&0xf)<<5|y<<4|1; else hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf); } // Find cxt row in hash table ht. ht has rows of 16 indexed by the // low sizebits of cxt with element 0 having the next higher 8 bits for // collision detection. If not found after 3 adjacent tries, replace the // row with lowest element 1 as priority. Return index of row. size_t Predictor::find(Array& ht, int sizebits, U32 cxt) { assert(initTables); assert(ht.size()==size_t(16)<>sizebits&255; size_t h0=(cxt*16)&(ht.size()-16); if (ht[h0]==chk) return h0; size_t h1=h0^16; if (ht[h1]==chk) return h1; size_t h2=h0^32; if (ht[h2]==chk) return h2; if (ht[h0+1]<=ht[h1+1] && ht[h0+1]<=ht[h2+1]) return memset(&ht[h0], 0, 16), ht[h0]=chk, h0; else if (ht[h1+1]=0 && p<65536); assert(high>low && low>0); if (currhigh) error("archive corrupted"); assert(curr>=low && curr<=high); U32 mid=low+U32(((high-low)*U64(U32(p)))>>16); // split range assert(high>mid && mid>=low); int y; if (curr<=mid) y=1, high=mid; // pick half else y=0, low=mid+1; while ((high^low)<0x1000000) { // shift out identical leading bytes high=high<<8|255; low=low<<8; low+=(low==0); int c=get(); if (c<0) error("unexpected end of file"); curr=curr<<8|c; } return y; } // Decompress 1 byte or -1 at end of input int Decoder::decompress() { if (pr.isModeled()) { // n>0 components? if (curr==0) { // segment initialization for (int i=0; i<4; ++i) curr=curr<<8|get(); } if (decode(0)) { if (curr!=0) error("decoding end of stream"); return -1; } else { int c=1; while (c<256) { // get 8 bits int p=pr.predict()*2+1; c+=c+decode(p); pr.update(c&1); } return c-256; } } else { if (curr==0) { for (int i=0; i<4; ++i) curr=curr<<8|get(); if (curr==0) return -1; } --curr; return get(); } } // Find end of compressed data and return next byte int Decoder::skip() { int c=-1; if (pr.isModeled()) { while (curr==0) // at start? curr=get(); while (curr && (c=get())>=0) // find 4 zeros curr=curr<<8|c; while ((c=get())==0) ; // might be more than 4 return c; } else { if (curr==0) // at start? for (int i=0; i<4 && (c=get())>=0; ++i) curr=curr<<8|c; while (curr>0) { while (curr>0) { --curr; if (get()<0) return error("skipped to EOF"), -1; } for (int i=0; i<4 && (c=get())>=0; ++i) curr=curr<<8|c; } if (c>=0) c=get(); return c; } } ////////////////////// PostProcessor ////////////////////// // Copy ph, pm from block header void PostProcessor::init(int h, int m) { state=hsize=0; ph=h; pm=m; z.clear(); } // (PASS=0 | PROG=1 psize[0..1] pcomp[0..psize-1]) data... EOB=-1 // Return state: 1=PASS, 2..4=loading PROG, 5=PROG loaded int PostProcessor::write(int c) { assert(c>=-1 && c<=255); switch (state) { case 0: // initial state if (c<0) error("Unexpected EOS"); state=c+1; // 1=PASS, 2=PROG if (state>2) error("unknown post processing type"); if (state==1) z.clear(); break; case 1: // PASS z.outc(c); break; case 2: // PROG if (c<0) error("Unexpected EOS"); hsize=c; // low byte of size state=3; break; case 3: // PROG psize[0] if (c<0) error("Unexpected EOS"); hsize+=c*256; // high byte of psize if (hsize<1) error("Empty PCOMP"); z.header.resize(hsize+300); z.cend=8; z.hbegin=z.hend=z.cend+128; z.header[4]=ph; z.header[5]=pm; state=4; break; case 4: // PROG psize[0..1] pcomp[0...] if (c<0) error("Unexpected EOS"); assert(z.hend>8; z.initp(); state=5; } break; case 5: // PROG ... data z.run(c); if (c<0) z.flush(); break; } return state; } /////////////////////// Decompresser ///////////////////// // Find the start of a block and return true if found. Set memptr // to memory used. bool Decompresser::findBlock(double* memptr) { assert(state==BLOCK); // Find start of block U32 h1=0x3D49B113, h2=0x29EB7F93, h3=0x2614BE13, h4=0x3828EB13; // Rolling hashes initialized to hash of first 13 bytes int c; while ((c=dec.get())!=-1) { h1=h1*12+c; h2=h2*20+c; h3=h3*28+c; h4=h4*44+c; if (h1==0xB16B88F1 && h2==0xFF5376F1 && h3==0x72AC5BF1 && h4==0x2F909AF1) break; // hash of 16 byte string } if (c==-1) return false; // Read header if ((c=dec.get())!=1 && c!=2) error("unsupported ZPAQ level"); if (dec.get()!=1) error("unsupported ZPAQL type"); z.read(&dec); if (c==1 && z.header.isize()>6 && z.header[6]==0) error("ZPAQ level 1 requires at least 1 component"); if (memptr) *memptr=z.memory(); state=FILENAME; decode_state=FIRSTSEG; return true; } // Read the start of a segment (1) or end of block code (255). // If a segment is found, write the filename and return true, else false. bool Decompresser::findFilename(Writer* filename) { assert(state==FILENAME); int c=dec.get(); if (c==1) { // segment found while (true) { c=dec.get(); if (c==-1) error("unexpected EOF"); if (c==0) { state=COMMENT; return true; } if (filename) filename->put(c); } } else if (c==255) { // end of block found state=BLOCK; return false; } else error("missing segment or end of block"); return false; } // Read the comment from the segment header void Decompresser::readComment(Writer* comment) { assert(state==COMMENT); state=DATA; while (true) { int c=dec.get(); if (c==-1) error("unexpected EOF"); if (c==0) break; if (comment) comment->put(c); } if (dec.get()!=0) error("missing reserved byte"); } // Decompress n bytes, or all if n < 0. Return false if done bool Decompresser::decompress(int n) { assert(state==DATA); if (decode_state==SKIP) error("decompression after skipped segment"); assert(decode_state!=SKIP); // Initialize models to start decompressing block if (decode_state==FIRSTSEG) { dec.init(); assert(z.header.size()>5); pp.init(z.header[4], z.header[5]); decode_state=SEG; } // Decompress and load PCOMP into postprocessor while ((pp.getState()&3)!=1) pp.write(dec.decompress()); // Decompress n bytes, or all if n < 0 while (n) { int c=dec.decompress(); pp.write(c); if (c==-1) { state=SEGEND; return false; } if (n>0) --n; } return true; } // Read end of block. If a SHA1 checksum is present, write 1 and the // 20 byte checksum into sha1string, else write 0 in first byte. // If sha1string is 0 then discard it. void Decompresser::readSegmentEnd(char* sha1string) { assert(state==DATA || state==SEGEND); // Skip remaining data if any and get next byte int c=0; if (state==DATA) { c=dec.skip(); decode_state=SKIP; } else if (state==SEGEND) c=dec.get(); state=FILENAME; // Read checksum if (c==254) { if (sha1string) sha1string[0]=0; // no checksum } else if (c==253) { if (sha1string) sha1string[0]=1; for (int i=1; i<=20; ++i) { c=dec.get(); if (sha1string) sha1string[i]=c; } } else error("missing end of segment marker"); } /////////////////////////// decompress() ////////////////////// void decompress(Reader* in, Writer* out) { Decompresser d; d.setInput(in); d.setOutput(out); while (d.findBlock()) { // don't calculate memory while (d.findFilename()) { // discard filename d.readComment(); // discard comment d.decompress(); // to end of segment d.readSegmentEnd(); // discard sha1string } } } /////////////////////////// Encoder /////////////////////////// //////////////////////////// Compiler ///////////////////////// // Component names const char* compname[256]= {"","const","cm","icm","match","avg","mix2","mix","isse","sse",0}; // Opcodes const char* opcodelist[272]={ "error","a++", "a--", "a!", "a=0", "", "", "a=r", "b<>a", "b++", "b--", "b!", "b=0", "", "", "b=r", "c<>a", "c++", "c--", "c!", "c=0", "", "", "c=r", "d<>a", "d++", "d--", "d!", "d=0", "", "", "d=r", "*b<>a","*b++", "*b--", "*b!", "*b=0", "", "", "jt", "*c<>a","*c++", "*c--", "*c!", "*c=0", "", "", "jf", "*d<>a","*d++", "*d--", "*d!", "*d=0", "", "", "r=a", "halt", "out", "", "hash", "hashd","", "", "jmp", "a=a", "a=b", "a=c", "a=d", "a=*b", "a=*c", "a=*d", "a=", "b=a", "b=b", "b=c", "b=d", "b=*b", "b=*c", "b=*d", "b=", "c=a", "c=b", "c=c", "c=d", "c=*b", "c=*c", "c=*d", "c=", "d=a", "d=b", "d=c", "d=d", "d=*b", "d=*c", "d=*d", "d=", "*b=a", "*b=b", "*b=c", "*b=d", "*b=*b","*b=*c","*b=*d","*b=", "*c=a", "*c=b", "*c=c", "*c=d", "*c=*b","*c=*c","*c=*d","*c=", "*d=a", "*d=b", "*d=c", "*d=d", "*d=*b","*d=*c","*d=*d","*d=", "", "", "", "", "", "", "", "", "a+=a", "a+=b", "a+=c", "a+=d", "a+=*b","a+=*c","a+=*d","a+=", "a-=a", "a-=b", "a-=c", "a-=d", "a-=*b","a-=*c","a-=*d","a-=", "a*=a", "a*=b", "a*=c", "a*=d", "a*=*b","a*=*c","a*=*d","a*=", "a/=a", "a/=b", "a/=c", "a/=d", "a/=*b","a/=*c","a/=*d","a/=", "a%=a", "a%=b", "a%=c", "a%=d", "a%=*b","a%=*c","a%=*d","a%=", "a&=a", "a&=b", "a&=c", "a&=d", "a&=*b","a&=*c","a&=*d","a&=", "a&~a", "a&~b", "a&~c", "a&~d", "a&~*b","a&~*c","a&~*d","a&~", "a|=a", "a|=b", "a|=c", "a|=d", "a|=*b","a|=*c","a|=*d","a|=", "a^=a", "a^=b", "a^=c", "a^=d", "a^=*b","a^=*c","a^=*d","a^=", "a<<=a","a<<=b","a<<=c","a<<=d","a<<=*b","a<<=*c","a<<=*d","a<<=", "a>>=a","a>>=b","a>>=c","a>>=d","a>>=*b","a>>=*c","a>>=*d","a>>=", "a==a", "a==b", "a==c", "a==d", "a==*b","a==*c","a==*d","a==", "aa", "a>b", "a>c", "a>d", "a>*b", "a>*c", "a>*d", "a>", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "lj", "post", "pcomp","end", "if", "ifnot","else", "endif","do", "while","until","forever","ifl","ifnotl","elsel",";", 0}; // Advance in to start of next token. Tokens are delimited by white // space. Comments inclosed in ((nested) parenthsis) are skipped. void Compiler::next() { assert(in); for (; *in; ++in) { if (*in=='\n') ++line; if (*in=='(') state+=1+(state<0); else if (state>0 && *in==')') --state; else if (state<0 && *in<=' ') state=0; else if (state==0 && *in>' ') {state=-1; break;} } if (!*in) error("unexpected end of config"); } // convert to lower case int tolower(int c) {return (c>='A' && c<='Z') ? c+'a'-'A' : c;} // return true if in==word up to white space or '(', case insensitive bool Compiler::matchToken(const char* word) { const char* a=in; for (; (*a>' ' && *a!='(' && *word); ++a, ++word) if (tolower(*a)!=tolower(*word)) return false; return !*word && (*a<=' ' || *a=='('); } // Print error message and exit void Compiler::syntaxError(const char* msg, const char* expected) { Array sbuf(128); // error message to report char* s=&sbuf[0]; strcat(s, "Config line "); for (int i=strlen(s), r=1000000; r; r/=10) // append line number if (line/r) s[i++]='0'+line/r%10; strcat(s, " at "); for (int i=strlen(s); i<40 && *in>' '; ++i) // append token found s[i]=*in++; strcat(s, ": "); strncat(s, msg, 40); // append message if (expected) { strcat(s, ", expected: "); strncat(s, expected, 20); // append expected token if any } error(s); } // Read a token, which must be in the NULL terminated list or else // exit with an error. If found, return its index. int Compiler::rtoken(const char* list[]) { assert(in); assert(list); next(); for (int i=0; list[i]; ++i) if (matchToken(list[i])) return i; syntaxError("unexpected"); assert(0); return -1; // not reached } // Read a token which must be the specified value s void Compiler::rtoken(const char* s) { assert(s); next(); if (!matchToken(s)) syntaxError("expected", s); } // Read a number in (low...high) or exit with an error // For numbers like $N+M, return arg[N-1]+M int Compiler::rtoken(int low, int high) { next(); int r=0; if (in[0]=='$' && in[1]>='1' && in[1]<='9') { if (in[2]=='+') r=atoi(in+3); if (args) r+=args[in[1]-'1']; } else if (in[0]=='-' || (in[0]>='0' && in[0]<='9')) r=atoi(in); else syntaxError("expected a number"); if (rhigh) syntaxError("number too high"); return r; } // Compile HCOMP or PCOMP code. Exit on error. Return // code for end token (POST, PCOMP, END) int Compiler::compile_comp(ZPAQL& z) { int op=0; const int comp_begin=z.hend; while (true) { op=rtoken(opcodelist); if (op==POST || op==PCOMP || op==END) break; int operand=-1; // 0...255 if 2 bytes int operand2=-1; // 0...255 if 3 bytes if (op==IF) { op=JF; operand=0; // set later if_stack.push(z.hend+1); // save jump target location } else if (op==IFNOT) { op=JT; operand=0; if_stack.push(z.hend+1); // save jump target location } else if (op==IFL || op==IFNOTL) { // long if if (op==IFL) z.header[z.hend++]=(JT); if (op==IFNOTL) z.header[z.hend++]=(JF); z.header[z.hend++]=(3); op=LJ; operand=operand2=0; if_stack.push(z.hend+1); } else if (op==ELSE || op==ELSEL) { if (op==ELSE) op=JMP, operand=0; if (op==ELSEL) op=LJ, operand=operand2=0; int a=if_stack.pop(); // conditional jump target location assert(a>comp_begin && a=0); if (j>127) syntaxError("IF too big, try IFL, IFNOTL"); z.header[a]=j; } else { // IFL, IFNOTL int j=z.hend-comp_begin+2+(op==LJ); assert(j>=0); z.header[a]=j&255; z.header[a+1]=(j>>8)&255; } if_stack.push(z.hend+1); // save JMP target location } else if (op==ENDIF) { int a=if_stack.pop(); // jump target address assert(a>comp_begin && a=0); if (z.header[a-1]!=LJ) { assert(z.header[a-1]==JT || z.header[a-1]==JF || z.header[a-1]==JMP); if (j>127) syntaxError("IF too big, try IFL, IFNOTL, ELSEL\n"); z.header[a]=j; } else { assert(a+1>8)&255; } } else if (op==DO) { do_stack.push(z.hend); } else if (op==WHILE || op==UNTIL || op==FOREVER) { int a=do_stack.pop(); assert(a>=comp_begin && a=-127) { // backward short jump if (op==WHILE) op=JT; if (op==UNTIL) op=JF; if (op==FOREVER) op=JMP; operand=j&255; } else { // backward long jump j=a-comp_begin; assert(j>=0 && j>8; } } else if ((op&7)==7) { // 2 byte operand, read N if (op==LJ) { operand=rtoken(0, 65535); operand2=operand>>8; operand&=255; } else if (op==JT || op==JF || op==JMP) { operand=rtoken(-128, 127); operand&=255; } else operand=rtoken(0, 255); } if (op>=0 && op<=255) z.header[z.hend++]=(op); if (operand>=0) z.header[z.hend++]=(operand); if (operand2>=0) z.header[z.hend++]=(operand2); if (z.hend>=z.header.isize()-130 || z.hend-z.hbegin+z.cend-2>65535) syntaxError("program too big"); } z.header[z.hend++]=(0); // END return op; } // Compile a configuration file. Store COMP/HCOMP section in hcomp. // If there is a PCOMP section, store it in pcomp and store the PCOMP // command in pcomp_cmd. Replace "$1..$9+n" with args[0..8]+n Compiler::Compiler(const char* in_, int* args_, ZPAQL& hz_, ZPAQL& pz_, Writer* out2_): in(in_), args(args_), hz(hz_), pz(pz_), out2(out2_), if_stack(1000), do_stack(1000) { line=1; state=0; hz.clear(); pz.clear(); hz.header.resize(68000); // Compile the COMP section of header rtoken("comp"); hz.header[2]=rtoken(0, 255); // hh hz.header[3]=rtoken(0, 255); // hm hz.header[4]=rtoken(0, 255); // ph hz.header[5]=rtoken(0, 255); // pm const int n=hz.header[6]=rtoken(0, 255); // n hz.cend=7; for (int i=0; i10) syntaxError("invalid component"); for (int j=1; j>8; // Compile POST 0 END if (op==POST) { rtoken(0, 0); rtoken("end"); } // Compile PCOMP pcomp_cmd ; program... END else if (op==PCOMP) { pz.header.resize(68000); pz.header[4]=hz.header[4]; // ph pz.header[5]=hz.header[5]; // pm pz.cend=8; pz.hbegin=pz.hend=pz.cend+128; // get pcomp_cmd ending with ";" (case sensitive) next(); while (*in && *in!=';') { if (out2) out2->put(*in); ++in; } if (*in) ++in; // Compile PCOMP op=compile_comp(pz); int len=pz.cend-2+pz.hend-pz.hbegin; // insert header size assert(len>=0); pz.header[0]=len&255; pz.header[1]=len>>8; if (op!=END) syntaxError("expected END"); } else if (op!=END) syntaxError("expected END or POST 0 END or PCOMP cmd ; ... END"); } //////////////////////// ZPAQL::assemble() //////////////////// #ifndef NOJIT /* assemble(); Assembles the ZPAQL code in hcomp[0..hlen-1] and stores x86-32 or x86-64 code in rcode[0..rcode_size-1]. Execution begins at rcode[0]. It will not write beyond the end of rcode, but in any case it returns the number of bytes that would have been written. It returns 0 in case of error. The assembled code implements int run() and returns 0 if successful, 1 if the ZPAQL code executes an invalid instruction or jumps out of bounds, or 2 if OUT throws bad_alloc, or 3 for other OUT exceptions. A ZPAQL virtual machine has the following state. All values are unsigned and initially 0: a, b, c, d: 32 bit registers (pointed to by their respective parameters) f: 1 bit flag register (pointed to) r[0..255]: 32 bit registers m[0..msize-1]: 8 bit registers, where msize is a power of 2 h[0..hsize-1]: 32 bit registers, where hsize is a power of 2 out: pointer to a Writer sha1: pointer to a SHA1 Generally a ZPAQL machine is used to compute contexts which are placed in h. A second machine might post-process, and write its output to out and sha1. In either case, a machine is called with its input in a, representing a single byte (0..255) or (for a postprocessor) EOF (0xffffffff). Execution returs after a ZPAQL halt instruction. ZPAQL instructions are 1 byte unless the last 3 bits are 1. In this case, a second operand byte follows. Opcode 255 is the only 3 byte instruction. They are organized: 00dddxxx = unary opcode xxx on destination ddd (ddd < 111) 00111xxx = special instruction xxx 01dddsss = assignment: ddd = sss (ddd < 111) 1xxxxsss = operation xxxx from sss to a The meaning of sss and ddd are as follows: 000 = a (accumulator) 001 = b 010 = c 011 = d 100 = *b (means m[b mod msize]) 101 = *c (means m[c mod msize]) 110 = *d (means h[d mod hsize]) 111 = n (constant 0..255 in second byte of instruction) For example, 01001110 assigns *d to b. The other instructions xxx are as follows: Group 00dddxxx where ddd < 111 and xxx is: 000 = ddd<>a, swap with a (except 00000000 is an error, and swap with *b or *c leaves the high bits of a unchanged) 001 = ddd++, increment 010 = ddd--, decrement 011 = ddd!, not (invert all bits) 100 = ddd=0, clear (set all bits of ddd to 0) 101 = not used (error) 110 = not used 111 = ddd=r n, assign from r[n] to ddd, n=0..255 in next opcode byte Except: 00100111 = jt n, jump if f is true (n = -128..127, relative to next opcode) 00101111 = jf n, jump if f is false (n = -128..127) 00110111 = r=a n, assign r[n] = a (n = 0..255) Group 00111xxx where xxx is: 000 = halt (return) 001 = output a 010 = not used 011 = hash: a = (a + *b + 512) * 773 100 = hashd: *d = (*d + a + 512) * 773 101 = not used 110 = not used 111 = unconditional jump (n = -128 to 127, relative to next opcode) Group 1xxxxsss where xxxx is: 0000 = a += sss (add, subtract, multiply, divide sss to a) 0001 = a -= sss 0010 = a *= sss 0011 = a /= sss (unsigned, except set a = 0 if sss is 0) 0100 = a %= sss (remainder, except set a = 0 if sss is 0) 0101 = a &= sss (bitwise AND) 0110 = a &= ~sss (bitwise AND with complement of sss) 0111 = a |= sss (bitwise OR) 1000 = a ^= sss (bitwise XOR) 1001 = a <<= (sss % 32) (left shift by low 5 bits of sss) 1010 = a >>= (sss % 32) (unsigned, zero bits shifted in) 1011 = a == sss (compare, set f = true if equal or false otherwise) 1100 = a < sss (unsigned compare, result in f) 1101 = a > sss (unsigned compare) 1110 = not used 1111 = not used except 11111111 is a 3 byte jump to the absolute address in the next 2 bytes in little-endian (LSB first) order. assemble() translates ZPAQL to 32 bit x86 code to be executed by run(). Registers are mapped as follows: eax = source sss from *b, *c, *d or sometimes n ecx = pointer to destination *b, *c, *d, or spare edx = a ebx = f (1 for true, 0 for false) esp = stack pointer ebp = d esi = b edi = c run() saves non-volatile registers (ebp, esi, edi, ebx) on the stack, loads a, b, c, d, f, and executes the translated instructions. A halt instruction saves a, b, c, d, f, pops the saved registers and returns. Invalid instructions or jumps outside of the range of the ZPAQL code call libzpaq::error(). In 64 bit mode, the following additional registers are used: r12 = h r14 = r r15 = m */ // Called by out static int flush1(ZPAQL* z) { try { z->flush(); return 0; } catch(std::bad_alloc& x) { return 2; } catch(...) { return 3; } } // return true if op is an undefined ZPAQL instruction static bool iserr(int op) { return op==0 || (op>=120 && op<=127) || (op>=240 && op<=254) || op==58 || (op<64 && (op%8==5 || op%8==6)); } // Return length of ZPAQL instruction at hcomp[0]. Assume 0 padding at end. // A run of identical ++ or -- is counted as 1 instruction. static int oplen(const U8* hcomp) { if (*hcomp==255) return 3; if (*hcomp%8==7) return 2; if (*hcomp<51 && (*hcomp%8-1)/2==0) { // ++ or -- opcode int i; for (i=1; i<127 && hcomp[i]==hcomp[0]; ++i); return i; } return 1; } // Write k bytes of x to rcode[o++] MSB first static void put(U8* rcode, int n, int& o, U32 x, int k) { while (k-->0) { if (o>(k*8))&255; ++o; } } // Write 4 bytes of x to rcode[o++] LSB first static void put4lsb(U8* rcode, int n, int& o, U32 x) { for (int k=0; k<4; ++k) { if (o>(k*8))&255; ++o; } } // Write a 1-4 byte x86 opcode without or with an 4 byte operand // to rcode[o...] #define put1(x) put(rcode, rcode_size, o, (x), 1) #define put2(x) put(rcode, rcode_size, o, (x), 2) #define put3(x) put(rcode, rcode_size, o, (x), 3) #define put4(x) put(rcode, rcode_size, o, (x), 4) #define put5(x,y) put4(x), put1(y) #define put6(x,y) put4(x), put2(y) #define put4r(x) put4lsb(rcode, rcode_size, o, x) #define puta(x) t=U32(size_t(x)), put4r(t) #define put1a(x,y) put1(x), puta(y) #define put2a(x,y) put2(x), puta(y) #define put3a(x,y) put3(x), puta(y) #define put4a(x,y) put4(x), puta(y) #define put5a(x,y,z) put4(x), put1(y), puta(z) #define put2l(x,y) put2(x), t=U32(size_t(y)), put4r(t), \ t=U32(size_t(y)>>(S*4)), put4r(t) // Assemble ZPAQL in in the HCOMP section of header to rcode, // but do not write beyond rcode_size. Return the number of // bytes output or that would have been output. // Execution starts at rcode[0] and returns 1 if successful or 0 // in case of a ZPAQL execution error. int ZPAQL::assemble() { // x86? (not foolproof) const int S=sizeof(char*); // 4 = x86, 8 = x86-64 U32 t=0x12345678; if (*(char*)&t!=0x78 || (S!=4 && S!=8)) error("JIT supported only for x86-32 and x86-64"); const U8* hcomp=&header[hbegin]; const int hlen=hend-hbegin+2; const int msize=m.size(); const int hsize=h.size(); static const int regcode[8]={2,6,7,5}; // a,b,c,d.. -> edx,esi,edi,ebp,eax.. Array it(hlen); // hcomp -> rcode locations int done=0; // number of instructions assembled (0..hlen) int o=5; // rcode output index, reserve space for jmp // Code for the halt instruction (restore registers and return) const int halt=o; if (S==8) { put2l(0x48b9, &a); // mov rcx, a put2(0x8911); // mov [rcx], edx put2l(0x48b9, &b); // mov rcx, b put2(0x8931); // mov [rcx], esi put2l(0x48b9, &c); // mov rcx, c put2(0x8939); // mov [rcx], edi put2l(0x48b9, &d); // mov rcx, d put2(0x8929); // mov [rcx], ebp put2l(0x48b9, &f); // mov rcx, f put2(0x8919); // mov [rcx], ebx put4(0x4883c408); // add rsp, 8 put2(0x415f); // pop r15 put2(0x415e); // pop r14 put2(0x415d); // pop r13 put2(0x415c); // pop r12 } else { put2a(0x8915, &a); // mov [a], edx put2a(0x8935, &b); // mov [b], esi put2a(0x893d, &c); // mov [c], edi put2a(0x892d, &d); // mov [d], ebp put2a(0x891d, &f); // mov [f], ebx put3(0x83c40c); // add esp, 12 } put1(0x5b); // pop ebx put1(0x5f); // pop edi put1(0x5e); // pop esi put1(0x5d); // pop ebp put1(0xc3); // ret // Code for the out instruction. // Store a=edx at outbuf[bufptr++]. If full, call flush1(). const int outlabel=o; if (S==8) { put2l(0x48b8, &outbuf[0]);// mov rax, outbuf.p put2l(0x49ba, &bufptr); // mov r10, &bufptr put3(0x418b0a); // mov rcx, [r10] put3(0x881408); // mov [rax+rcx], dl put2(0xffc1); // inc rcx put3(0x41890a); // mov [r10], ecx put2a(0x81f9, outbuf.size()); // cmp rcx, outbuf.size() put2(0x7403); // jz L1 put2(0x31c0); // xor eax, eax put1(0xc3); // ret put1(0x55); // L1: push rbp ; call flush1(this) put1(0x57); // push rdi put1(0x56); // push rsi put1(0x52); // push rdx put1(0x51); // push rcx put3(0x4889e5); // mov rbp, rsp put4(0x4883c570); // add rbp, 112 #if defined(unix) && !defined(__CYGWIN__) put2l(0x48bf, this); // mov rdi, this #else // Windows put2l(0x48b9, this); // mov rcx, this #endif put2l(0x49bb, &flush1); // mov r11, &flush1 put3(0x41ffd3); // call r11 put1(0x59); // pop rcx put1(0x5a); // pop rdx put1(0x5e); // pop rsi put1(0x5f); // pop rdi put1(0x5d); // pop rbp } else { put1a(0xb8, &outbuf[0]); // mov eax, outbuf.p put2a(0x8b0d, &bufptr); // mov ecx, [bufptr] put3(0x881408); // mov [eax+ecx], dl put2(0xffc1); // inc ecx put2a(0x890d, &bufptr); // mov [bufptr], ecx put2a(0x81f9, outbuf.size()); // cmp ecx, outbuf.size() put2(0x7403); // jz L1 put2(0x31c0); // xor eax, eax put1(0xc3); // ret put3(0x83ec0c); // L1: sub esp, 12 put4(0x89542404); // mov [esp+4], edx put3a(0xc70424, this); // mov [esp], this put1a(0xb8, &flush1); // mov eax, &flush1 put2(0xffd0); // call eax put4(0x8b542404); // mov edx, [esp+4] put3(0x83c40c); // add esp, 12 } put1(0xc3); // ret // Set it[i]=1 for each ZPAQL instruction reachable from the previous // instruction + 2 if reachable by a jump (or 3 if both). it[0]=2; assert(hlen>0 && hcomp[hlen-1]==0); // ends with error do { done=0; const int NONE=0x80000000; for (int i=0; i>24);// jt,jf,jmp if (op==63) next1=NONE; // jmp if ((next2<0 || next2>=hlen) && next2!=NONE) next2=hlen-1; // error if (next1>=0 && next1=0 && next20); // Set it[i] bits 2-3 to 4, 8, or 12 if a comparison // (==, <, > respectively) does not need to save the result in f, // or if a conditional jump (jt, jf) does not need to read f. // This is true if a comparison is followed directly by a jt/jf, // the jt/jf is not a jump target, the byte before is not a jump // target (for a 2 byte comparison), and for the comparison instruction // if both paths after the jt/jf lead to another comparison or error // before another jt/jf. At most hlen steps are traced because after // that it must be an infinite loop. for (int i=0; i=216 && op1<240 && (op2==39 || op2==47) && it[i2]==1 && (i2==i+1 || it[i+1]==0)) { int code=(op1-208)/8*4; // 4,8,12 is ==,<,> it[i2]+=code; // OK to test CF, ZF instead of f for (int j=0; j<2 && code; ++j) { // trace each path from i2 int k=i2+2; // branch not taken if (j==1) k=i2+2+(hcomp[i2+1]<<24>>24); // branch taken for (int l=0; l=hlen) break; // out of bounds, pass const int op=hcomp[k]; if (op==39 || op==47) code=0; // jt,jf, fail else if (op>=216 && op<240) break; // ==,<,>, pass else if (iserr(op)) break; // error, pass else if (op==255) k=hcomp[k+1]+256*hcomp[k+2]; // lj else if (op==63) k=k+2+(hcomp[k+1]<<24>>24); // jmp else if (op==56) k=0; // halt else k=k+1+(op%8==7); // ordinary instruction } } it[i]+=code; // if > 0 then OK to not save flags in f (bl) } } // Start of run(): Save x86 and load ZPAQL registers const int start=o; assert(start>=16); put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi put1(0x53); // push ebx/rbx if (S==8) { put2(0x4154); // push r12 put2(0x4155); // push r13 put2(0x4156); // push r14 put2(0x4157); // push r15 put4(0x4883ec08); // sub rsp, 8 put2l(0x48b8, &a); // mov rax, a put2(0x8b10); // mov edx, [rax] put2l(0x48b8, &b); // mov rax, b put2(0x8b30); // mov esi, [rax] put2l(0x48b8, &c); // mov rax, c put2(0x8b38); // mov edi, [rax] put2l(0x48b8, &d); // mov rax, d put2(0x8b28); // mov ebp, [rax] put2l(0x48b8, &f); // mov rax, f put2(0x8b18); // mov ebx, [rax] put2l(0x49bc, &h[0]); // mov r12, h put2l(0x49bd, &outbuf[0]); // mov r13, outbuf.p put2l(0x49be, &r[0]); // mov r14, r put2l(0x49bf, &m[0]); // mov r15, m } else { put3(0x83ec0c); // sub esp, 12 put2a(0x8b15, &a); // mov edx, [a] put2a(0x8b35, &b); // mov esi, [b] put2a(0x8b3d, &c); // mov edi, [c] put2a(0x8b2d, &d); // mov ebp, [d] put2a(0x8b1d, &f); // mov ebx, [f] } // Assemble in multiple passes until every byte of hcomp has a translation for (int istart=0; istarti); assert(i>=0 && i=16) { if (i>istart) { int a=code-o; if (a>-120 && a<120) put2(0xeb00+((a-2)&255)); // jmp short o else put1a(0xe9, a-5); // jmp near o } break; } // Else assemble the instruction at hcomp[i] to rcode[o] else { assert(i>=0 && i0 && it[i]<16); assert(o>=16); it[i]=o; ++done; const int op=hcomp[i]; const int arg=hcomp[i+1]+((op==255)?256*hcomp[i+2]:0); const int ddd=op/8%8; const int sss=op%8; // error instruction: return 1 if (iserr(op)) { put1a(0xb8, 1); // mov eax, 1 put1a(0xe9, halt-o-4); // jmp near halt continue; } // Load source *b, *c, *d, or hash (*b) into eax except: // {a,b,c,d}=*d, a{+,-,*,&,|,^,=,==,>,>}=*d: load address to eax // {a,b,c,d}={*b,*c}: load source into ddd if (op==59 || (op>=64 && op<240 && op%8>=4 && op%8<7)) { put2(0x89c0+8*regcode[sss-3+(op==59)]); // mov eax, {esi,edi,ebp} const int sz=(sss==6?hsize:msize)-1; if (sz>=128) put1a(0x25, sz); // and eax, dword msize-1 else put3(0x83e000+sz); // and eax, byte msize-1 const int move=(op>=64 && op<112); // = or else ddd is eax if (sss<6) { // ddd={a,b,c,d,*b,*c} if (S==8) put5(0x410fb604+8*move*regcode[ddd],0x07); // movzx ddd, byte [r15+rax] else put3a(0x0fb680+8*move*regcode[ddd], &m[0]); // movzx ddd, byte [m+eax] } else if ((0x06587000>>(op/8))&1) {// {*b,*c,*d,a/,a%,a&~,a<<,a>>}=*d if (S==8) put4(0x418b0484); // mov eax, [r12+rax*4] else put3a(0x8b0485, &h[0]); // mov eax, [h+eax*4] } } // Load destination address *b, *c, *d or hashd (*d) into ecx if ((op>=32 && op<56 && op%8<5) || (op>=96 && op<120) || op==60) { put2(0x89c1+8*regcode[op/8%8-3-(op==60)]);// mov ecx,{esi,edi,ebp} const int sz=(ddd==6||op==60?hsize:msize)-1; if (sz>=128) put2a(0x81e1, sz); // and ecx, dword sz else put3(0x83e100+sz); // and ecx, byte sz if (op/8%8==6 || op==60) { // *d if (S==8) put4(0x498d0c8c); // lea rcx, [r12+rcx*4] else put3a(0x8d0c8d, &h[0]); // lea ecx, [ecx*4+h] } else { // *b, *c if (S==8) put4(0x498d0c0f); // lea rcx, [r15+rcx] else put2a(0x8d89, &m[0]); // lea ecx, [ecx+h] } } // Translate by opcode switch((op/8)&31) { case 0: // ddd = a case 1: // ddd = b case 2: // ddd = c case 3: // ddd = d switch(sss) { case 0: // ddd<>a (swap) put2(0x87d0+regcode[ddd]); // xchg edx, ddd break; case 1: // ddd++ put3(0x83c000+256*regcode[ddd]+inc); // add ddd, inc break; case 2: // ddd-- put3(0x83e800+256*regcode[ddd]+inc); // sub ddd, inc break; case 3: // ddd! put2(0xf7d0+regcode[ddd]); // not ddd break; case 4: // ddd=0 put2(0x31c0+9*regcode[ddd]); // xor ddd,ddd break; case 7: // ddd=r n if (S==8) put3a(0x418b86+8*regcode[ddd], arg*4); // mov ddd, [r14+n*4] else put2a(0x8b05+8*regcode[ddd], (&r[arg]));//mov ddd, [r+n] break; } break; case 4: // ddd = *b case 5: // ddd = *c switch(sss) { case 0: // ddd<>a (swap) put2(0x8611); // xchg dl, [ecx] break; case 1: // ddd++ put3(0x800100+inc); // add byte [ecx], inc break; case 2: // ddd-- put3(0x802900+inc); // sub byte [ecx], inc break; case 3: // ddd! put2(0xf611); // not byte [ecx] break; case 4: // ddd=0 put2(0x31c0); // xor eax, eax put2(0x8801); // mov [ecx], al break; case 7: // jt, jf { assert(code>=0 && code<16); static const unsigned char jtab[2][4]={{5,4,2,7},{4,5,3,6}}; // jnz,je,jb,ja, jz,jne,jae,jbe if (code<4) put2(0x84db); // test bl, bl if (arg>=128 && arg-257-i>=0 && o-it[arg-257-i]<120) put2(0x7000+256*jtab[op==47][code/4]); // jx short 0 else put2a(0x0f80+jtab[op==47][code/4], 0); // jx near 0 break; } } break; case 6: // ddd = *d switch(sss) { case 0: // ddd<>a (swap) put2(0x8711); // xchg edx, [ecx] break; case 1: // ddd++ put3(0x830100+inc); // add dword [ecx], inc break; case 2: // ddd-- put3(0x832900+inc); // sub dword [ecx], inc break; case 3: // ddd! put2(0xf711); // not dword [ecx] break; case 4: // ddd=0 put2(0x31c0); // xor eax, eax put2(0x8901); // mov [ecx], eax break; case 7: // ddd=r n if (S==8) put3a(0x418996, arg*4); // mov [r14+n*4], edx else put2a(0x8915, &r[arg]); // mov [r+n], edx break; } break; case 7: // special switch(op) { case 56: // halt put2(0x31c0); // xor eax, eax ; return 0 put1a(0xe9, halt-o-4); // jmp near halt break; case 57: // out put1a(0xe8, outlabel-o-4);// call outlabel put3(0x83f800); // cmp eax, 0 ; returned error code put2(0x7405); // je L1: put1a(0xe9, halt-o-4); // jmp near halt ; L1: break; case 59: // hash: a = (a + *b + 512) * 773 put3a(0x8d8410, 512); // lea edx, [eax+edx+512] put2a(0x69d0, 773); // imul edx, eax, 773 break; case 60: // hashd: *d = (*d + a + 512) * 773 put2(0x8b01); // mov eax, [ecx] put3a(0x8d8410, 512); // lea eax, [eax+edx+512] put2a(0x69c0, 773); // imul eax, eax, 773 put2(0x8901); // mov [ecx], eax break; case 63: // jmp put1a(0xe9, 0); // jmp near 0 (fill in target later) break; } break; case 8: // a= case 9: // b= case 10: // c= case 11: // d= if (sss==7) // n put1a(0xb8+regcode[ddd], arg); // mov ddd, n else if (sss==6) { // *d if (S==8) put4(0x418b0484+(regcode[ddd]<<11)); // mov ddd, [r12+rax*4] else put3a(0x8b0485+(regcode[ddd]<<11),&h[0]);// mov ddd, [h+eax*4] } else if (sss<4) // a, b, c, d put2(0x89c0+regcode[ddd]+8*regcode[sss]);// mov ddd,sss break; case 12: // *b= case 13: // *c= if (sss==7) put3(0xc60100+arg); // mov byte [ecx], n else if (sss==0) put2(0x8811); // mov byte [ecx], dl else { if (sss<4) put2(0x89c0+8*regcode[sss]);// mov eax, sss put2(0x8801); // mov byte [ecx], al } break; case 14: // *d= if (sss<7) put2(0x8901+8*regcode[sss]); // mov [ecx], sss else put2a(0xc701, arg); // mov dword [ecx], n break; case 15: break; // not used case 16: // a+= if (sss==6) { if (S==8) put4(0x41031484); // add edx, [r12+rax*4] else put3a(0x031485, &h[0]); // add edx, [h+eax*4] } else if (sss<7) put2(0x01c2+8*regcode[sss]);// add edx, sss else if (arg>=128) put2a(0x81c2, arg); // add edx, n else put3(0x83c200+arg); // add edx, byte n break; case 17: // a-= if (sss==6) { if (S==8) put4(0x412b1484); // sub edx, [r12+rax*4] else put3a(0x2b1485, &h[0]); // sub edx, [h+eax*4] } else if (sss<7) put2(0x29c2+8*regcode[sss]);// sub edx, sss else if (arg>=128) put2a(0x81ea, arg); // sub edx, n else put3(0x83ea00+arg); // sub edx, byte n break; case 18: // a*= if (sss==6) { if (S==8) put5(0x410faf14,0x84); // imul edx, [r12+rax*4] else put4a(0x0faf1485, &h[0]); // imul edx, [h+eax*4] } else if (sss<7) put3(0x0fafd0+regcode[sss]);// imul edx, sss else if (arg>=128) put2a(0x69d2, arg); // imul edx, n else put3(0x6bd200+arg); // imul edx, byte n break; case 19: // a/= case 20: // a%= if (sss<7) put2(0x89c1+8*regcode[sss]); // mov ecx, sss else put1a(0xb9, arg); // mov ecx, n put2(0x85c9); // test ecx, ecx put3(0x0f44d1); // cmovz edx, ecx put2(0x7408-2*(op/8==20)); // jz (over rest) put2(0x89d0); // mov eax, edx put2(0x31d2); // xor edx, edx put2(0xf7f1); // div ecx if (op/8==19) put2(0x89c2); // mov edx, eax break; case 21: // a&= if (sss==6) { if (S==8) put4(0x41231484); // and edx, [r12+rax*4] else put3a(0x231485, &h[0]); // and edx, [h+eax*4] } else if (sss<7) put2(0x21c2+8*regcode[sss]);// and edx, sss else if (arg>=128) put2a(0x81e2, arg); // and edx, n else put3(0x83e200+arg); // and edx, byte n break; case 22: // a&~ if (sss==7) { if (arg<128) put3(0x83e200+(~arg&255));// and edx, byte ~n else put2a(0x81e2, ~arg); // and edx, ~n } else { if (sss<4) put2(0x89c0+8*regcode[sss]);// mov eax, sss put2(0xf7d0); // not eax put2(0x21c2); // and edx, eax } break; case 23: // a|= if (sss==6) { if (S==8) put4(0x410b1484); // or edx, [r12+rax*4] else put3a(0x0b1485, &h[0]); // or edx, [h+eax*4] } else if (sss<7) put2(0x09c2+8*regcode[sss]);// or edx, sss else if (arg>=128) put2a(0x81ca, arg); // or edx, n else put3(0x83ca00+arg); // or edx, byte n break; case 24: // a^= if (sss==6) { if (S==8) put4(0x41331484); // xor edx, [r12+rax*4] else put3a(0x331485, &h[0]); // xor edx, [h+eax*4] } else if (sss<7) put2(0x31c2+8*regcode[sss]);// xor edx, sss else if (arg>=128) put2a(0x81f2, arg); // xor edx, byte n else put3(0x83f200+arg); // xor edx, n break; case 25: // a<<= case 26: // a>>= if (sss==7) // sss = n put3(0xc1e200+8*256*(op/8==26)+arg); // shl/shr n else { put2(0x89c1+8*regcode[sss]); // mov ecx, sss put2(0xd3e2+8*(op/8==26)); // shl/shr edx, cl } break; case 27: // a== case 28: // a< case 29: // a> if (sss==6) { if (S==8) put4(0x413b1484); // cmp edx, [r12+rax*4] else put3a(0x3b1485, &h[0]); // cmp edx, [h+eax*4] } else if (sss==7) // sss = n put2a(0x81fa, arg); // cmp edx, dword n else put2(0x39c2+8*regcode[sss]); // cmp edx, sss if (code<4) { if (op/8==27) put3(0x0f94c3); // setz bl if (op/8==28) put3(0x0f92c3); // setc bl if (op/8==29) put3(0x0f97c3); // seta bl } break; case 30: // not used case 31: // 255 = lj if (op==255) put1a(0xe9, 0); // jmp near break; } } } } // Finish first pass const int rsize=o; if (o>rcode_size) return rsize; // Fill in jump addresses (second pass) for (int i=0; i=128) target-=256; target+=i+2; } if (target<0 || target>=hlen) target=hlen-1; // runtime ZPAQL error o=it[i]; assert(o>=16 && o skip test assert(o>=16 && o=0x72 && op<0x78) || op==0xeb) { // jx, jmp short --target; if (target<-128 || target>127) error("Cannot code x86 short jump"); assert(o=0x82 && op<0x88) || op==0xe9) // jx, jmp near { target-=4; puta(target); } else assert(false); // not a x86 jump } } // Jump to start o=0; put1a(0xe9, start-5); // jmp near start return rsize; } //////////////////////// Predictor::assemble_p() ///////////////////// // Assemble the ZPAQL code in the HCOMP section of z.header to pcomp and // return the number of bytes of x86 or x86-64 code written, or that would // be written if pcomp were large enough. The code for predict() begins // at pr.pcomp[0] and update() at pr.pcomp[5], both as jmp instructions. // The assembled code is equivalent to int predict(Predictor*) // and void update(Predictor*, int y); The Preditor address is placed in // edi/rdi. The update bit y is placed in ebp/rbp. int Predictor::assemble_p() { Predictor& pr=*this; U8* rcode=pr.pcode; // x86 output array int rcode_size=pcode_size; // output size int o=0; // output index in pcode const int S=sizeof(char*); // 4 or 8 U8* hcomp=&pr.z.header[0]; // The code to translate #define off(x) ((char*)&(pr.x)-(char*)&pr) #define offc(x) ((char*)&(pr.comp[i].x)-(char*)&pr) // test for little-endian (probably x86) U32 t=0x12345678; if (*(char*)&t!=0x78 || (S!=4 && S!=8)) error("JIT supported only for x86-32 and x86-64"); // Initialize for predict(). Put predictor address in edi/rdi put1a(0xe9, 5); // jmp predict put1a(0, 0x90909000); // reserve space for jmp update put1(0x53); // push ebx/rbx put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi if (S==4) put4(0x8b7c2414); // mov edi,[esp+0x14] ; pr else { #if !defined(unix) || defined(__CYGWIN__) put3(0x4889cf); // mov rdi, rcx (1st arg in Win64) #endif } // Code predict() for each component const int n=hcomp[6]; // number of components U8* cp=hcomp+7; for (int i=0; i=pr.z.cend) error("comp too big"); if (cp[0]<1 || cp[0]>9) error("invalid component"); assert(compsize[cp[0]]>0 && compsize[cp[0]]<8); switch (cp[0]) { case CONS: // c break; case CM: // sizebits limit // Component& cr=comp[i]; // cr.cxt=h[i]^hmap4; // p[i]=stretch(cr.cm(cr.cxt)>>17); put2a(0x8b87, off(h[i])); // mov eax, [edi+&h[i]] put2a(0x3387, off(hmap4)); // xor eax, [edi+&hmap4] put1a(0x25, (1<rsi) put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] put3(0x8b0486); // mov eax, [esi+eax*4] put3(0xc1e811); // shr eax, 17 put4a(0x0fbf8447, off(stretcht)); // movsx eax,word[edi+eax*2+..] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; case ISSE: // sizebits j -- c=hi, cxt=bh // assert((hmap4&15)>0); // if (c8==1 || (c8&0xf0)==16) // cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); // cr.cxt=cr.ht[cr.c+(hmap4&15)]; // bit history // int *wt=(int*)&cr.cm[cr.cxt*2]; // p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16); case ICM: // sizebits // assert((hmap4&15)>0); // if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); // cr.cxt=cr.ht[cr.c+(hmap4&15)]; // p[i]=stretch(cr.cm(cr.cxt)>>8); // // Find cxt row in hash table ht. ht has rows of 16 indexed by the low // sizebits of cxt with element 0 having the next higher 8 bits for // collision detection. If not found after 3 adjacent tries, replace // row with lowest element 1 as priority. Return index of row. // // size_t Predictor::find(Array& ht, int sizebits, U32 cxt) { // assert(ht.size()==size_t(16)<>sizebits&255; // size_t h0=(cxt*16)&(ht.size()-16); // if (ht[h0]==chk) return h0; // size_t h1=h0^16; // if (ht[h1]==chk) return h1; // size_t h2=h0^32; // if (ht[h2]==chk) return h2; // if (ht[h0+1]<=ht[h1+1] && ht[h0+1]<=ht[h2+1]) // return memset(&ht[h0], 0, 16), ht[h0]=chk, h0; // else if (ht[h1+1]>(7-cr.cxt))&1; // predicted bit // p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767); // } if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(ht)); // mov esi, [edi+&ht] // If match length (a) is 0 then p[i]=0 put2a(0x8b87, offc(a)); // mov eax, [edi+&a] put2(0x85c0); // test eax, eax put2(0x7449); // jz L2 ; p[i]=0 // Else put predicted bit in c put1a(0xb9, 7); // mov ecx, 7 put2a(0x2b8f, offc(cxt)); // sub ecx, [edi+&cxt] put2a(0x8b87, offc(limit)); // mov eax, [edi+&limit] put2a(0x2b87, offc(b)); // sub eax, [edi+&b] put1a(0x25, (1<>8; put2a(0x8b87, off(p[cp[1]])); // mov eax, [edi+&p[j]] put2a(0x2b87, off(p[cp[2]])); // sub eax, [edi+&p[k]] put2a(0x69c0, cp[3]); // imul eax, wt put3(0xc1f808); // sar eax, 8 put2a(0x0387, off(p[cp[2]])); // add eax, [edi+&p[k]] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; case MIX2: // sizebits j k rate mask // c=size cm=wt[size] cxt=input // cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1)); // assert(cr.cxt=0 && w<65536); // p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16; // assert(p[i]>=-2048 && p[i]<2048); put2(0x8b07); // mov eax, [edi] ; c8 put1a(0x25, cp[5]); // and eax, mask put2a(0x0387, off(h[i])); // add eax, [edi+&h[i]] put1a(0x25, (1<=1 && m<=i); // cr.cxt=h[i]+(c8&cp[5]); // cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights // assert(cr.cxt<=cr.cm.size()-m); // int* wt=(int*)&cr.cm[cr.cxt]; // p[i]=0; // for (int j=0; j>8)*p[cp[2]+j]; // p[i]=clamp2k(p[i]>>8); put2(0x8b07); // mov eax, [edi] ; c8 put1a(0x25, cp[5]); // and eax, mask put2a(0x0387, off(h[i])); // add eax, [edi+&h[i]] put1a(0x25, (1<3) put4a(0xf30f6f96, k*4+16);//movdqu xmm2, [esi+k*4+16] put5(0x660f72e1,0x08); // psrad xmm1, 8 if (tail>3) put5(0x660f72e2,0x08); // psrad xmm2, 8 put4(0x660f6bca); // packssdw xmm1, xmm2 put4a(0xf30f6f9f, off(p[cp[2]+k])); // movdqu xmm3, [edi+&p[j+k]] if (tail>3) put4a(0xf30f6fa7,off(p[cp[2]+k+4]));//movdqu xmm4, [edi+&p[j+k+4]] put4(0x660f6bdc); // packssdw, xmm3, xmm4 if (tail>0 && tail<8) { // last loop, mask extra weights put4(0x660f76ed); // pcmpeqd xmm5, xmm5 ; -1 put5(0x660f73dd, 16-tail*2); // psrldq xmm5, 16-tail*2 put4(0x660fdbcd); // pand xmm1, xmm5 } if (k==0) { // first loop, initialize sum in xmm0 put4(0xf30f6fc1); // movdqu xmm0, xmm1 put4(0x660ff5c3); // pmaddwd xmm0, xmm3 } else { // accumulate sum in xmm0 put4(0x660ff5cb); // pmaddwd xmm1, xmm3 put4(0x660ffec1); // paddd xmm0, xmm1 } } // Add up the 4 elements of xmm0 = p[i] in the first element put4(0xf30f6fc8); // movdqu xmm1, xmm0 put5(0x660f73d9,0x08); // psrldq xmm1, 8 put4(0x660ffec1); // paddd xmm0, xmm1 put4(0xf30f6fc8); // movdqu xmm1, xmm0 put5(0x660f73d9,0x04); // psrldq xmm1, 4 put4(0x660ffec1); // paddd xmm0, xmm1 put4(0x660f7ec0); // movd eax, xmm0 ; p[i] put3(0xc1f808); // sar eax, 8 put1a(0x3d, 2047); // cmp eax, 2047 put2(0x7e05); // jle L1 put1a(0xb8, 2047); // mov eax, 2047 put1a(0x3d, -2048); // L1: cmp eax, -2048 put2(0x7d05); // jge, L2 put1a(0xb8, -2048); // mov eax, -2048 put2a(0x8987, off(p[i])); // L2: mov [edi+&p[i]], eax break; case SSE: // sizebits j start limit // cr.cxt=(h[i]+c8)*32; // int pq=p[cp[2]]+992; // if (pq<0) pq=0; // if (pq>1983) pq=1983; // int wt=pq&63; // pq>>=6; // assert(pq>=0 && pq<=30); // cr.cxt+=pq; // p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt) // p0 // +(cr.cm(cr.cxt+1)>>10)*wt)>>13); // p1 // // p = p0*(64-wt)+p1*wt = (p1-p0)*wt + p0*64 // cr.cxt+=wt>>5; put2a(0x8b8f, off(h[i])); // mov ecx, [edi+&h[i]] put2(0x030f); // add ecx, [edi] ; c0 put2a(0x81e1, (1<>5 put2a(0x898f, offc(cxt)); // mov [edi+cxt], ecx ; cxt saved put3(0xc1e80a); // shr eax, 10 ; p0 = cm[cxt]>>10 put3(0xc1eb0a); // shr ebx, 10 ; p1 = cm[cxt+1]>>10 put2(0x29c3); // sub ebx, eax, ; p1-p0 put3(0x0fafda); // imul ebx, edx ; (p1-p0)*wt put3(0xc1e006); // shr eax, 6 put2(0x01d8); // add eax, ebx ; p in 0..2^28-1 put3(0xc1e80d); // shr eax, 13 ; p in 0..32767 put4a(0x0fbf8447, off(stretcht)); // movsx eax, word [edi+eax*2+...] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; default: error("invalid ZPAQ component"); } } // return squash(p[n-1]) put2a(0x8b87, off(p[n-1])); // mov eax, [edi+...] put1a(0x05, 0x800); // add eax, 2048 put4a(0x0fbf8447, off(squasht[0])); // movsx eax, word [edi+eax*2+...] put1(0x5f); // pop edi put1(0x5e); // pop esi put1(0x5d); // pop ebp put1(0x5b); // pop ebx put1(0xc3); // ret // Initialize for update() Put predictor address in edi/rdi // and bit y=0..1 in ebp int save_o=o; o=5; put1a(0xe9, save_o-10); // jmp update o=save_o; put1(0x53); // push ebx/rbx put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi if (S==4) { put4(0x8b7c2414); // mov edi,[esp+0x14] ; (1st arg = pr) put4(0x8b6c2418); // mov ebp,[esp+0x18] ; (2nd arg = y) } else { #if defined(unix) && !defined(__CYGWIN__) // (1st arg already in rdi) put3(0x4889f5); // mov rbp, rsi (2nd arg in Linux-64) #else put3(0x4889cf); // mov rdi, rcx (1st arg in Win64) put3(0x4889d5); // mov rbp, rdx (2nd arg) #endif } // Code update() for each component cp=hcomp+7; for (int i=0; i=1 && cp[0]<=9); assert(compsize[cp[0]]>0 && compsize[cp[0]]<8); switch (cp[0]) { case CONS: // c break; case SSE: // sizebits j start limit case CM: // sizebits limit // train(cr, y); // // reduce prediction error in cr.cm // void train(Component& cr, int y) { // assert(y==0 || y==1); // U32& pn=cr.cm(cr.cxt); // U32 count=pn&0x3ff; // int error=y*32767-(cr.cm(cr.cxt)>>17); // pn+=(error*dt[count]&-1024)+(countrsi) put2a(0x8bb7, offc(cm)); // mov esi,[edi+cm] ; cm put2a(0x8b87, offc(cxt)); // mov eax,[edi+cxt] ; cxt put1a(0x25, pr.comp[i].cm.size()-1); // and eax, size-1 if (S==8) put1(0x48); // rex.w put3(0x8d3486); // lea esi,[esi+eax*4] ; &cm[cxt] put2(0x8b06); // mov eax,[esi] ; cm[cxt] put2(0x89c2); // mov edx, eax ; cm[cxt] put3(0xc1e811); // shr eax, 17 ; cm[cxt]>>17 put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 ; y*32768 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax ; error put2a(0x81e2, 0x3ff); // and edx, 1023 ; count put3a(0x8b8497, off(dt)); // mov eax,[edi+edx*4+dt] ; dt[count] put3(0x0fafc8); // imul ecx, eax ; error*dt[count] put2a(0x81e1, 0xfffffc00); // and ecx, -1024 put2a(0x81fa, cp[2+2*(cp[0]==SSE)]*4); // cmp edx, limit*4 put2(0x110e); // adc [esi], ecx ; pn+=... break; case ICM: // sizebits: cxt=bh, ht[c][0..15]=bh row // cr.ht[cr.c+(hmap4&15)]=st.next(cr.ht[cr.c+(hmap4&15)], y); // U32& pn=cr.cm(cr.cxt); // pn+=int(y*32767-(pn>>8))>>2; case ISSE: // sizebits j -- c=hi, cxt=bh // assert(cr.cxt==cr.ht[cr.c+(hmap4&15)]); // int err=y*32767-squash(p[i]); // int *wt=(int*)&cr.cm[cr.cxt*2]; // wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13)); // wt[1]=clamp512k(wt[1]+((err+16)>>5)); // cr.ht[cr.c+(hmap4&15)]=st.next(cr.cxt, y); // update bit history bh to next(bh,y=ebp) in ht[c+(hmap4&15)] put3(0x8b4700+off(hmap4)); // mov eax, [edi+&hmap4] put3(0x83e00f); // and eax, 15 put2a(0x0387, offc(c)); // add eax [edi+&c] ; cxt if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(ht)); // mov esi, [edi+&ht] put4(0x0fb61406); // movzx edx, byte [esi+eax] ; bh put4(0x8d5c9500); // lea ebx, [ebp+edx*4] ; index to st put4a(0x0fb69c1f, off(st)); // movzx ebx,byte[edi+ebx+st]; next bh put3(0x881c06); // mov [esi+eax], bl ; save next bh if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] // ICM: update cm[cxt=edx=bit history] to reduce prediction error // esi = &cm if (cp[0]==ICM) { if (S==8) put1(0x48); // rex.w put3(0x8d3496); // lea esi, [esi+edx*4] ; &cm[bh] put2(0x8b06); // mov eax, [esi] ; pn put3(0xc1e808); // shr eax, 8 ; pn>>8 put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put3(0xc1f902); // sar ecx, 2 put2(0x010e); // add [esi], ecx } // ISSE: update weights. edx=cxt=bit history (0..255), esi=cm[512] else { put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht)); // movzx eax, word [edi+eax*2+..] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax ; err put2a(0x8b87, off(p[cp[2]]));// mov eax, [edi+&p[j]] put3(0x0fafc1); // imul eax, ecx put1a(0x05, (1<<12)); // add eax, 4096 put3(0xc1f80d); // sar eax, 13 put3(0x0304d6); // add eax, [esi+edx*8] ; wt[0] put1a(0x3d, (1<<19)-1); // cmp eax, (1<<19)-1 put2(0x7e05); // jle L1 put1a(0xb8, (1<<19)-1); // mov eax, (1<<19)-1 put1a(0x3d, 0xfff80000); // cmp eax, -1<<19 put2(0x7d05); // jge L2 put1a(0xb8, 0xfff80000); // mov eax, -1<<19 put3(0x8904d6); // L2: mov [esi+edx*8], eax put3(0x83c110); // add ecx, 16 ; err put3(0xc1f905); // sar ecx, 5 put4(0x034cd604); // add ecx, [esi+edx*8+4] ; wt[1] put2a(0x81f9, (1<<19)-1); // cmp ecx, (1<<19)-1 put2(0x7e05); // jle L3 put1a(0xb9, (1<<19)-1); // mov ecx, (1<<19)-1 put2a(0x81f9, 0xfff80000); // cmp ecx, -1<<19 put2(0x7d05); // jge L4 put1a(0xb9, 0xfff80000); // mov ecx, -1<<19 put4(0x894cd604); // L4: mov [esi+edx*8+4], ecx } break; case MATCH: // sizebits bufbits: // a=len, b=offset, c=bit, cm=index, cxt=bitpos // ht=buf, limit=pos // assert(cr.a<=255); // assert(cr.c==0 || cr.c==1); // assert(cr.cxt<8); // assert(cr.cm.size()==(size_t(1)<>5; // int w=cr.a16[cr.cxt]; // w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13; // if (w<0) w=0; // if (w>65535) w=65535; // cr.a16[cr.cxt]=w; // set ecx=err put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht));//movzx eax, word [edi+eax*2+&squasht] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put2a(0x69c9, cp[4]); // imul ecx, rate put3(0xc1f905); // sar ecx, 5 ; err // Update w put2a(0x8b87, offc(cxt)); // mov eax, [edi+&cxt] if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(a16)); // mov esi, [edi+&a16] if (S==8) put1(0x48); // rex.w put3(0x8d3446); // lea esi, [esi+eax*2] ; &w put2a(0x8b87, off(p[cp[2]])); // mov eax, [edi+&p[j]] put2a(0x2b87, off(p[cp[3]])); // sub eax, [edi+&p[k]] ; p[j]-p[k] put3(0x0fafc1); // imul eax, ecx ; * err put1a(0x05, 1<<12); // add eax, 4096 put3(0xc1f80d); // sar eax, 13 put3(0x0fb716); // movzx edx, word [esi] ; w put2(0x01d0); // add eax, edx put1a(0xba, 0xffff); // mov edx, 65535 put2(0x39d0); // cmp eax, edx put3(0x0f4fc2); // cmovg eax, edx put2(0x31d2); // xor edx, edx put2(0x39d0); // cmp eax, edx put3(0x0f4cc2); // cmovl eax, edx put3(0x668906); // mov word [esi], ax break; case MIX: // sizebits j m rate mask // cm=wt[size][m], cxt=input // int m=cp[3]; // assert(m>0 && m<=i); // assert(cr.cm.size()==m*cr.c); // assert(cr.cxt+m<=cr.cm.size()); // int err=(y*32767-squash(p[i]))*cp[4]>>4; // int* wt=(int*)&cr.cm[cr.cxt]; // for (int j=0; j>13)); // set ecx=err put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht));//movzx eax, word [edi+eax*2+&squasht] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put2a(0x69c9, cp[4]); // imul ecx, rate put3(0xc1f904); // sar ecx, 4 ; err // set esi=wt put2a(0x8b87, offc(cxt)); // mov eax, [edi+&cxt] ; cxt if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] if (S==8) put1(0x48); // rex.w put3(0x8d3486); // lea esi, [esi+eax*4] ; wt for (int k=0; kpcode_size) { allocx(pcode, pcode_size, n); n=assemble_p(); } if (!pcode || n<15 || pcode_size<15) error("run JIT failed"); } assert(pcode && pcode[0]); return ((int(*)(Predictor*))&pcode[10])(this); #endif } // Update the model with bit y = 0..1 // Use the JIT code starting at pcode[5]. void Predictor::update(int y) { #ifdef NOJIT update0(y); #else assert(pcode && pcode[5]); ((void(*)(Predictor*, int))&pcode[5])(this, y); // Save bit y in c8, hmap4 (not implemented in JIT) c8+=c8+y; if (c8>=256) { z.run(c8-256); hmap4=1; c8=1; for (int i=0; i=16 && c8<32) hmap4=(hmap4&0xf)<<5|y<<4|1; else hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf); #endif } // Execute the ZPAQL code with input byte or -1 for EOF. // Use JIT code at rcode if available, or else create it. void ZPAQL::run(U32 input) { #ifdef NOJIT run0(input); #else if (!rcode) { allocx(rcode, rcode_size, (hend*10+4096)&-4096); int n=assemble(); if (n>rcode_size) { allocx(rcode, rcode_size, n); n=assemble(); } if (!rcode || n<10 || rcode_size<10) error("run JIT failed"); } a=input; const U32 rc=((int(*)())(&rcode[0]))(); if (rc==0) return; else if (rc==1) libzpaq::error("Bad ZPAQL opcode"); else if (rc==2) libzpaq::error("Out of memory"); else if (rc==3) libzpaq::error("Write error"); else libzpaq::error("ZPAQL execution error"); #endif } ////////////////////////// divsufsort /////////////////////////////// /* * divsufsort.c for libdivsufsort-lite * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /*- Constants -*/ #define INLINE __inline #if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) # undef ALPHABET_SIZE #endif #if !defined(ALPHABET_SIZE) # define ALPHABET_SIZE (256) #endif #define BUCKET_A_SIZE (ALPHABET_SIZE) #define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) #if defined(SS_INSERTIONSORT_THRESHOLD) # if SS_INSERTIONSORT_THRESHOLD < 1 # undef SS_INSERTIONSORT_THRESHOLD # define SS_INSERTIONSORT_THRESHOLD (1) # endif #else # define SS_INSERTIONSORT_THRESHOLD (8) #endif #if defined(SS_BLOCKSIZE) # if SS_BLOCKSIZE < 0 # undef SS_BLOCKSIZE # define SS_BLOCKSIZE (0) # elif 32768 <= SS_BLOCKSIZE # undef SS_BLOCKSIZE # define SS_BLOCKSIZE (32767) # endif #else # define SS_BLOCKSIZE (1024) #endif /* minstacksize = log(SS_BLOCKSIZE) / log(3) * 2 */ #if SS_BLOCKSIZE == 0 # define SS_MISORT_STACKSIZE (96) #elif SS_BLOCKSIZE <= 4096 # define SS_MISORT_STACKSIZE (16) #else # define SS_MISORT_STACKSIZE (24) #endif #define SS_SMERGE_STACKSIZE (32) #define TR_INSERTIONSORT_THRESHOLD (8) #define TR_STACKSIZE (64) /*- Macros -*/ #ifndef SWAP # define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) #endif /* SWAP */ #ifndef MIN # define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) #endif /* MIN */ #ifndef MAX # define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) #endif /* MAX */ #define STACK_PUSH(_a, _b, _c, _d)\ do {\ assert(ssize < STACK_SIZE);\ stack[ssize].a = (_a), stack[ssize].b = (_b),\ stack[ssize].c = (_c), stack[ssize++].d = (_d);\ } while(0) #define STACK_PUSH5(_a, _b, _c, _d, _e)\ do {\ assert(ssize < STACK_SIZE);\ stack[ssize].a = (_a), stack[ssize].b = (_b),\ stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ } while(0) #define STACK_POP(_a, _b, _c, _d)\ do {\ assert(0 <= ssize);\ if(ssize == 0) { return; }\ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ } while(0) #define STACK_POP5(_a, _b, _c, _d, _e)\ do {\ assert(0 <= ssize);\ if(ssize == 0) { return; }\ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ } while(0) #define BUCKET_A(_c0) bucket_A[(_c0)] #if ALPHABET_SIZE == 256 #define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) #define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) #else #define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) #define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) #endif /*- Private Functions -*/ static const int lg_table[256]= { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; #if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) static INLINE int ss_ilg(int n) { #if SS_BLOCKSIZE == 0 return (n & 0xffff0000) ? ((n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]); #elif SS_BLOCKSIZE < 256 return lg_table[n]; #else return (n & 0xff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]; #endif } #endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ #if SS_BLOCKSIZE != 0 static const int sqq_table[256] = { 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 }; static INLINE int ss_isqrt(int x) { int y, e; if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } e = (x & 0xffff0000) ? ((x & 0xff000000) ? 24 + lg_table[(x >> 24) & 0xff] : 16 + lg_table[(x >> 16) & 0xff]) : ((x & 0x0000ff00) ? 8 + lg_table[(x >> 8) & 0xff] : 0 + lg_table[(x >> 0) & 0xff]); if(e >= 16) { y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); if(e >= 24) { y = (y + 1 + x / y) >> 1; } y = (y + 1 + x / y) >> 1; } else if(e >= 8) { y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; } else { return sqq_table[x] >> 4; } return (x < (y * y)) ? y - 1 : y; } #endif /* SS_BLOCKSIZE != 0 */ /*---------------------------------------------------------------------------*/ /* Compares two suffixes. */ static INLINE int ss_compare(const unsigned char *T, const int *p1, const int *p2, int depth) { const unsigned char *U1, *U2, *U1n, *U2n; for(U1 = T + depth + *p1, U2 = T + depth + *p2, U1n = T + *(p1 + 1) + 2, U2n = T + *(p2 + 1) + 2; (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); ++U1, ++U2) { } return U1 < U1n ? (U2 < U2n ? *U1 - *U2 : 1) : (U2 < U2n ? -1 : 0); } /*---------------------------------------------------------------------------*/ #if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) /* Insertionsort for small size groups */ static void ss_insertionsort(const unsigned char *T, const int *PA, int *first, int *last, int depth) { int *i, *j; int t; int r; for(i = last - 2; first <= i; --i) { for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); if(last <= j) { break; } } if(r == 0) { *j = ~*j; } *(j - 1) = t; } } #endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ /*---------------------------------------------------------------------------*/ #if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) static INLINE void ss_fixdown(const unsigned char *Td, const int *PA, int *SA, int i, int size) { int j, k; int v; int c, d, e; for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { d = Td[PA[SA[k = j++]]]; if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } if(d <= c) { break; } } SA[i] = v; } /* Simple top-down heapsort. */ static void ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) { int i, m; int t; m = size; if((size % 2) == 0) { m--; if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } } for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } for(i = m - 1; 0 < i; --i) { t = SA[0], SA[0] = SA[i]; ss_fixdown(Td, PA, SA, 0, i); SA[i] = t; } } /*---------------------------------------------------------------------------*/ /* Returns the median of three elements. */ static INLINE int * ss_median3(const unsigned char *Td, const int *PA, int *v1, int *v2, int *v3) { int *t; if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } if(Td[PA[*v2]] > Td[PA[*v3]]) { if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } else { return v3; } } return v2; } /* Returns the median of five elements. */ static INLINE int * ss_median5(const unsigned char *Td, const int *PA, int *v1, int *v2, int *v3, int *v4, int *v5) { int *t; if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } return v3; } /* Returns the pivot element. */ static INLINE int * ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { int *middle; int t; t = last - first; middle = first + t / 2; if(t <= 512) { if(t <= 32) { return ss_median3(Td, PA, first, middle, last - 1); } else { t >>= 2; return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); } } t >>= 3; first = ss_median3(Td, PA, first, first + t, first + (t << 1)); middle = ss_median3(Td, PA, middle - t, middle, middle + t); last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); return ss_median3(Td, PA, first, middle, last); } /*---------------------------------------------------------------------------*/ /* Binary partition for substrings. */ static INLINE int * ss_partition(const int *PA, int *first, int *last, int depth) { int *a, *b; int t; for(a = first - 1, b = last;;) { for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } if(b <= a) { break; } t = ~*b; *b = *a; *a = t; } if(first < a) { *first = ~*first; } return a; } /* Multikey introsort for medium size groups. */ static void ss_mintrosort(const unsigned char *T, const int *PA, int *first, int *last, int depth) { #define STACK_SIZE SS_MISORT_STACKSIZE struct { int *a, *b, c; int d; } stack[STACK_SIZE]; const unsigned char *Td; int *a, *b, *c, *d, *e, *f; int s, t; int ssize; int limit; int v, x = 0; for(ssize = 0, limit = ss_ilg(last - first);;) { if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { #if 1 < SS_INSERTIONSORT_THRESHOLD if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } #endif STACK_POP(first, last, depth, limit); continue; } Td = T + depth; if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } if(limit < 0) { for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { if((x = Td[PA[*a]]) != v) { if(1 < (a - first)) { break; } v = x; first = a; } } if(Td[PA[*first] - 1] < v) { first = ss_partition(PA, first, a, depth); } if((a - first) <= (last - a)) { if(1 < (a - first)) { STACK_PUSH(a, last, depth, -1); last = a, depth += 1, limit = ss_ilg(a - first); } else { first = a, limit = -1; } } else { if(1 < (last - a)) { STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); first = a, limit = -1; } else { last = a, depth += 1, limit = ss_ilg(a - first); } } continue; } /* choose pivot */ a = ss_pivot(Td, PA, first, last); v = Td[PA[*a]]; SWAP(*first, *a); /* partition */ for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } if(((a = b) < last) && (x < v)) { for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } } for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } if((b < (d = c)) && (x > v)) { for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } for(; b < c;) { SWAP(*b, *c); for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } if(a <= d) { c = b - 1; if((s = a - first) > (t = b - a)) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } if((s = d - c) > (t = last - d - 1)) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } a = first + (b - a), c = last - (d - c); b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); if((a - first) <= (last - c)) { if((last - c) <= (c - b)) { STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); STACK_PUSH(c, last, depth, limit); last = a; } else if((a - first) <= (c - b)) { STACK_PUSH(c, last, depth, limit); STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); last = a; } else { STACK_PUSH(c, last, depth, limit); STACK_PUSH(first, a, depth, limit); first = b, last = c, depth += 1, limit = ss_ilg(c - b); } } else { if((a - first) <= (c - b)) { STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); STACK_PUSH(first, a, depth, limit); first = c; } else if((last - c) <= (c - b)) { STACK_PUSH(first, a, depth, limit); STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); first = c; } else { STACK_PUSH(first, a, depth, limit); STACK_PUSH(c, last, depth, limit); first = b, last = c, depth += 1, limit = ss_ilg(c - b); } } } else { limit += 1; if(Td[PA[*first] - 1] < v) { first = ss_partition(PA, first, last, depth); limit = ss_ilg(last - first); } depth += 1; } } #undef STACK_SIZE } #endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ /*---------------------------------------------------------------------------*/ #if SS_BLOCKSIZE != 0 static INLINE void ss_blockswap(int *a, int *b, int n) { int t; for(; 0 < n; --n, ++a, ++b) { t = *a, *a = *b, *b = t; } } static INLINE void ss_rotate(int *first, int *middle, int *last) { int *a, *b, t; int l, r; l = middle - first, r = last - middle; for(; (0 < l) && (0 < r);) { if(l == r) { ss_blockswap(first, middle, l); break; } if(l < r) { a = last - 1, b = middle - 1; t = *a; do { *a-- = *b, *b-- = *a; if(b < first) { *a = t; last = a; if((r -= l + 1) <= l) { break; } a -= 1, b = middle - 1; t = *a; } } while(1); } else { a = first, b = middle; t = *a; do { *a++ = *b, *b++ = *a; if(last <= b) { *a = t; first = a + 1; if((l -= r + 1) <= r) { break; } a += 1, b = middle; t = *a; } } while(1); } } } /*---------------------------------------------------------------------------*/ static void ss_inplacemerge(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int depth) { const int *p; int *a, *b; int len, half; int q, r; int x; for(;;) { if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } else { x = 0; p = PA + *(last - 1); } for(a = first, len = middle - first, half = len >> 1, r = -1; 0 < len; len = half, half >>= 1) { b = a + half; q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); if(q < 0) { a = b + 1; half -= (len & 1) ^ 1; } else { r = q; } } if(a < middle) { if(r == 0) { *a = ~*a; } ss_rotate(a, middle, last); last -= middle - a; middle = a; if(first == middle) { break; } } --last; if(x != 0) { while(*--last < 0) { } } if(middle == last) { break; } } } /*---------------------------------------------------------------------------*/ /* Merge-forward with internal buffer. */ static void ss_mergeforward(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int depth) { int *a, *b, *c, *bufend; int t; int r; bufend = buf + (middle - first) - 1; ss_blockswap(buf, first, middle - first); for(t = *(a = first), b = buf, c = middle;;) { r = ss_compare(T, PA + *b, PA + *c, depth); if(r < 0) { do { *a++ = *b; if(bufend <= b) { *bufend = t; return; } *b++ = *a; } while(*b < 0); } else if(r > 0) { do { *a++ = *c, *c++ = *a; if(last <= c) { while(b < bufend) { *a++ = *b, *b++ = *a; } *a = *b, *b = t; return; } } while(*c < 0); } else { *c = ~*c; do { *a++ = *b; if(bufend <= b) { *bufend = t; return; } *b++ = *a; } while(*b < 0); do { *a++ = *c, *c++ = *a; if(last <= c) { while(b < bufend) { *a++ = *b, *b++ = *a; } *a = *b, *b = t; return; } } while(*c < 0); } } } /* Merge-backward with internal buffer. */ static void ss_mergebackward(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int depth) { const int *p1, *p2; int *a, *b, *c, *bufend; int t; int r; int x; bufend = buf + (last - middle) - 1; ss_blockswap(buf, middle, last - middle); x = 0; if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } else { p1 = PA + *bufend; } if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } else { p2 = PA + *(middle - 1); } for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { r = ss_compare(T, p1, p2, depth); if(0 < r) { if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } *a-- = *b; if(b <= buf) { *buf = t; break; } *b-- = *a; if(*b < 0) { p1 = PA + ~*b; x |= 1; } else { p1 = PA + *b; } } else if(r < 0) { if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } *a-- = *c, *c-- = *a; if(c < first) { while(buf < b) { *a-- = *b, *b-- = *a; } *a = *b, *b = t; break; } if(*c < 0) { p2 = PA + ~*c; x |= 2; } else { p2 = PA + *c; } } else { if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } *a-- = ~*b; if(b <= buf) { *buf = t; break; } *b-- = *a; if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } *a-- = *c, *c-- = *a; if(c < first) { while(buf < b) { *a-- = *b, *b-- = *a; } *a = *b, *b = t; break; } if(*b < 0) { p1 = PA + ~*b; x |= 1; } else { p1 = PA + *b; } if(*c < 0) { p2 = PA + ~*c; x |= 2; } else { p2 = PA + *c; } } } } /* D&C based merge. */ static void ss_swapmerge(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int bufsize, int depth) { #define STACK_SIZE SS_SMERGE_STACKSIZE #define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) #define MERGE_CHECK(a, b, c)\ do {\ if(((c) & 1) ||\ (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ *(a) = ~*(a);\ }\ if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ *(b) = ~*(b);\ }\ } while(0) struct { int *a, *b, *c; int d; } stack[STACK_SIZE]; int *l, *r, *lm, *rm; int m, len, half; int ssize; int check, next; for(check = 0, ssize = 0;;) { if((last - middle) <= bufsize) { if((first < middle) && (middle < last)) { ss_mergebackward(T, PA, first, middle, last, buf, depth); } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); continue; } if((middle - first) <= bufsize) { if(first < middle) { ss_mergeforward(T, PA, first, middle, last, buf, depth); } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); continue; } for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; 0 < len; len = half, half >>= 1) { if(ss_compare(T, PA + GETIDX(*(middle + m + half)), PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { m += half + 1; half -= (len & 1) ^ 1; } } if(0 < m) { lm = middle - m, rm = middle + m; ss_blockswap(lm, middle, m); l = r = middle, next = 0; if(rm < last) { if(*rm < 0) { *rm = ~*rm; if(first < lm) { for(; *--l < 0;) { } next |= 4; } next |= 1; } else if(first < lm) { for(; *r < 0; ++r) { } next |= 2; } } if((l - first) <= (last - r)) { STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); middle = lm, last = l, check = (check & 3) | (next & 4); } else { if((next & 2) && (r == middle)) { next ^= 6; } STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); first = r, middle = rm, check = (next & 3) | (check & 4); } } else { if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { *middle = ~*middle; } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); } } #undef STACK_SIZE } #endif /* SS_BLOCKSIZE != 0 */ /*---------------------------------------------------------------------------*/ /* Substring sort */ static void sssort(const unsigned char *T, const int *PA, int *first, int *last, int *buf, int bufsize, int depth, int n, int lastsuffix) { int *a; #if SS_BLOCKSIZE != 0 int *b, *middle, *curbuf; int j, k, curbufsize, limit; #endif int i; if(lastsuffix != 0) { ++first; } #if SS_BLOCKSIZE == 0 ss_mintrosort(T, PA, first, last, depth); #else if((bufsize < SS_BLOCKSIZE) && (bufsize < (last - first)) && (bufsize < (limit = ss_isqrt(last - first)))) { if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } buf = middle = last - limit, bufsize = limit; } else { middle = last, limit = 0; } for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); #endif curbufsize = last - (a + SS_BLOCKSIZE); curbuf = a + SS_BLOCKSIZE; if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); } } #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, a, middle, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, a, middle, depth); #endif for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { if(i & 1) { ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); a -= k; } } if(limit != 0) { #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, middle, last, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, middle, last, depth); #endif ss_inplacemerge(T, PA, first, middle, last, depth); } #endif if(lastsuffix != 0) { /* Insert last type B* suffix. */ int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; for(a = first, i = *(first - 1); (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); ++a) { *(a - 1) = *a; } *(a - 1) = i; } } /*---------------------------------------------------------------------------*/ static INLINE int tr_ilg(int n) { return (n & 0xffff0000) ? ((n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]); } /*---------------------------------------------------------------------------*/ /* Simple insertionsort for small size groups. */ static void tr_insertionsort(const int *ISAd, int *first, int *last) { int *a, *b; int t, r; for(a = first + 1; a < last; ++a) { for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); if(b < first) { break; } } if(r == 0) { *b = ~*b; } *(b + 1) = t; } } /*---------------------------------------------------------------------------*/ static INLINE void tr_fixdown(const int *ISAd, int *SA, int i, int size) { int j, k; int v; int c, d, e; for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { d = ISAd[SA[k = j++]]; if(d < (e = ISAd[SA[j]])) { k = j; d = e; } if(d <= c) { break; } } SA[i] = v; } /* Simple top-down heapsort. */ static void tr_heapsort(const int *ISAd, int *SA, int size) { int i, m; int t; m = size; if((size % 2) == 0) { m--; if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } } for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } for(i = m - 1; 0 < i; --i) { t = SA[0], SA[0] = SA[i]; tr_fixdown(ISAd, SA, 0, i); SA[i] = t; } } /*---------------------------------------------------------------------------*/ /* Returns the median of three elements. */ static INLINE int * tr_median3(const int *ISAd, int *v1, int *v2, int *v3) { int *t; if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } if(ISAd[*v2] > ISAd[*v3]) { if(ISAd[*v1] > ISAd[*v3]) { return v1; } else { return v3; } } return v2; } /* Returns the median of five elements. */ static INLINE int * tr_median5(const int *ISAd, int *v1, int *v2, int *v3, int *v4, int *v5) { int *t; if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } if(ISAd[*v3] > ISAd[*v4]) { return v4; } return v3; } /* Returns the pivot element. */ static INLINE int * tr_pivot(const int *ISAd, int *first, int *last) { int *middle; int t; t = last - first; middle = first + t / 2; if(t <= 512) { if(t <= 32) { return tr_median3(ISAd, first, middle, last - 1); } else { t >>= 2; return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); } } t >>= 3; first = tr_median3(ISAd, first, first + t, first + (t << 1)); middle = tr_median3(ISAd, middle - t, middle, middle + t); last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); return tr_median3(ISAd, first, middle, last); } /*---------------------------------------------------------------------------*/ typedef struct _trbudget_t trbudget_t; struct _trbudget_t { int chance; int remain; int incval; int count; }; static INLINE void trbudget_init(trbudget_t *budget, int chance, int incval) { budget->chance = chance; budget->remain = budget->incval = incval; } static INLINE int trbudget_check(trbudget_t *budget, int size) { if(size <= budget->remain) { budget->remain -= size; return 1; } if(budget->chance == 0) { budget->count += size; return 0; } budget->remain += budget->incval - size; budget->chance -= 1; return 1; } /*---------------------------------------------------------------------------*/ static INLINE void tr_partition(const int *ISAd, int *first, int *middle, int *last, int **pa, int **pb, int v) { int *a, *b, *c, *d, *e, *f; int t, s; int x = 0; for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } if(((a = b) < last) && (x < v)) { for(; (++b < last) && ((x = ISAd[*b]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } } for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } if((b < (d = c)) && (x > v)) { for(; (b < --c) && ((x = ISAd[*c]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } for(; b < c;) { SWAP(*b, *c); for(; (++b < c) && ((x = ISAd[*b]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } for(; (b < --c) && ((x = ISAd[*c]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } if(a <= d) { c = b - 1; if((s = a - first) > (t = b - a)) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } if((s = d - c) > (t = last - d - 1)) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } first += (b - a), last -= (d - c); } *pa = first, *pb = last; } static void tr_copy(int *ISA, const int *SA, int *first, int *a, int *b, int *last, int depth) { /* sort suffixes of middle partition by using sorted order of suffixes of left and right partition. */ int *c, *d, *e; int s, v; v = b - SA - 1; for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; ISA[s] = d - SA; } } for(c = last - 1, e = d + 1, d = b; e < d; --c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; ISA[s] = d - SA; } } } static void tr_partialcopy(int *ISA, const int *SA, int *first, int *a, int *b, int *last, int depth) { int *c, *d, *e; int s, v; int rank, lastrank, newrank = -1; v = b - SA - 1; lastrank = -1; for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; rank = ISA[s + depth]; if(lastrank != rank) { lastrank = rank; newrank = d - SA; } ISA[s] = newrank; } } lastrank = -1; for(e = d; first <= e; --e) { rank = ISA[*e]; if(lastrank != rank) { lastrank = rank; newrank = e - SA; } if(newrank != rank) { ISA[*e] = newrank; } } lastrank = -1; for(c = last - 1, e = d + 1, d = b; e < d; --c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; rank = ISA[s + depth]; if(lastrank != rank) { lastrank = rank; newrank = d - SA; } ISA[s] = newrank; } } } static void tr_introsort(int *ISA, const int *ISAd, int *SA, int *first, int *last, trbudget_t *budget) { #define STACK_SIZE TR_STACKSIZE struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE]; int *a, *b, *c; int t; int v, x = 0; int incr = ISAd - ISA; int limit, next; int ssize, trlink = -1; for(ssize = 0, limit = tr_ilg(last - first);;) { if(limit < 0) { if(limit == -1) { /* tandem repeat partition */ tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); /* update ranks */ if(a < last) { for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } } if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } /* push */ if(1 < (b - a)) { STACK_PUSH5(NULL, a, b, 0, 0); STACK_PUSH5(ISAd - incr, first, last, -2, trlink); trlink = ssize - 2; } if((a - first) <= (last - b)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); last = a, limit = tr_ilg(a - first); } else if(1 < (last - b)) { first = b, limit = tr_ilg(last - b); } else { STACK_POP5(ISAd, first, last, limit, trlink); } } else { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); first = b, limit = tr_ilg(last - b); } else if(1 < (a - first)) { last = a, limit = tr_ilg(a - first); } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } else if(limit == -2) { /* tandem repeat copy */ a = stack[--ssize].b, b = stack[ssize].c; if(stack[ssize].d == 0) { tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); } else { if(0 <= trlink) { stack[trlink].d = -1; } tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); } STACK_POP5(ISAd, first, last, limit, trlink); } else { /* sorted partition */ if(0 <= *first) { a = first; do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); first = a; } if(first < last) { a = first; do { *a = ~*a; } while(*++a < 0); next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } /* push */ if(trbudget_check(budget, a - first)) { if((a - first) <= (last - a)) { STACK_PUSH5(ISAd, a, last, -3, trlink); ISAd += incr, last = a, limit = next; } else { if(1 < (last - a)) { STACK_PUSH5(ISAd + incr, first, a, next, trlink); first = a, limit = -3; } else { ISAd += incr, last = a, limit = next; } } } else { if(0 <= trlink) { stack[trlink].d = -1; } if(1 < (last - a)) { first = a, limit = -3; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } else { STACK_POP5(ISAd, first, last, limit, trlink); } } continue; } if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { tr_insertionsort(ISAd, first, last); limit = -3; continue; } if(limit-- == 0) { tr_heapsort(ISAd, first, last - first); for(a = last - 1; first < a; a = b) { for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } } limit = -3; continue; } /* choose pivot */ a = tr_pivot(ISAd, first, last); SWAP(*first, *a); v = ISAd[*first]; /* partition */ tr_partition(ISAd, first, first + 1, last, &a, &b, v); if((last - first) != (b - a)) { next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; /* update ranks */ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } /* push */ if((1 < (b - a)) && (trbudget_check(budget, b - a))) { if((a - first) <= (last - b)) { if((last - b) <= (b - a)) { if(1 < (a - first)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); STACK_PUSH5(ISAd, b, last, limit, trlink); last = a; } else if(1 < (last - b)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); first = b; } else { ISAd += incr, first = a, last = b, limit = next; } } else if((a - first) <= (b - a)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, limit, trlink); STACK_PUSH5(ISAd + incr, a, b, next, trlink); last = a; } else { STACK_PUSH5(ISAd, b, last, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { STACK_PUSH5(ISAd, b, last, limit, trlink); STACK_PUSH5(ISAd, first, a, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { if((a - first) <= (b - a)) { if(1 < (last - b)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); STACK_PUSH5(ISAd, first, a, limit, trlink); first = b; } else if(1 < (a - first)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); last = a; } else { ISAd += incr, first = a, last = b, limit = next; } } else if((last - b) <= (b - a)) { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, limit, trlink); STACK_PUSH5(ISAd + incr, a, b, next, trlink); first = b; } else { STACK_PUSH5(ISAd, first, a, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { STACK_PUSH5(ISAd, first, a, limit, trlink); STACK_PUSH5(ISAd, b, last, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } } else { if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } if((a - first) <= (last - b)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, limit, trlink); last = a; } else if(1 < (last - b)) { first = b; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } else { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, limit, trlink); first = b; } else if(1 < (a - first)) { last = a; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } } else { if(trbudget_check(budget, last - first)) { limit = tr_ilg(last - first), ISAd += incr; } else { if(0 <= trlink) { stack[trlink].d = -1; } STACK_POP5(ISAd, first, last, limit, trlink); } } } #undef STACK_SIZE } /*---------------------------------------------------------------------------*/ /* Tandem repeat sort */ static void trsort(int *ISA, int *SA, int n, int depth) { int *ISAd; int *first, *last; trbudget_t budget; int t, skip, unsorted; trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); /* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { first = SA; skip = 0; unsorted = 0; do { if((t = *first) < 0) { first -= t; skip += t; } else { if(skip != 0) { *(first + skip) = skip; skip = 0; } last = SA + ISA[t] + 1; if(1 < (last - first)) { budget.count = 0; tr_introsort(ISA, ISAd, SA, first, last, &budget); if(budget.count != 0) { unsorted += budget.count; } else { skip = first - last; } } else if((last - first) == 1) { skip = -1; } first = last; } } while(first < (SA + n)); if(skip != 0) { *(first + skip) = skip; } if(unsorted == 0) { break; } } } /*---------------------------------------------------------------------------*/ /* Sorts suffixes of type B*. */ static int sort_typeBstar(const unsigned char *T, int *SA, int *bucket_A, int *bucket_B, int n) { int *PAb, *ISAb, *buf; #ifdef _OPENMP int *curbuf; int l; #endif int i, j, k, t, m, bufsize; int c0, c1; #ifdef _OPENMP int d0, d1; int tmp; #endif /* Initialize bucket arrays. */ for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } /* Count the number of occurrences of the first one or two characters of each type A, B and B* suffix. Moreover, store the beginning position of all type B* suffixes into the array SA. */ for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { /* type A suffix. */ do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); if(0 <= i) { /* type B* suffix. */ ++BUCKET_BSTAR(c0, c1); SA[--m] = i; /* type B suffix. */ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { ++BUCKET_B(c0, c1); } } } m = n - m; /* note: A type B* suffix is lexicographically smaller than a type B suffix that begins with the same first two characters. */ /* Calculate the index of start/end point of each bucket. */ for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { t = i + BUCKET_A(c0); BUCKET_A(c0) = i + j; /* start point */ i = t + BUCKET_B(c0, c0); for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { j += BUCKET_BSTAR(c0, c1); BUCKET_BSTAR(c0, c1) = j; /* end point */ i += BUCKET_B(c0, c1); } } if(0 < m) { /* Sort the type B* suffixes by their first two characters. */ PAb = SA + n - m; ISAb = SA + m; for(i = m - 2; 0 <= i; --i) { t = PAb[i], c0 = T[t], c1 = T[t + 1]; SA[--BUCKET_BSTAR(c0, c1)] = i; } t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; SA[--BUCKET_BSTAR(c0, c1)] = m - 1; /* Sort the type B* substrings using sssort. */ #ifdef _OPENMP tmp = omp_get_max_threads(); buf = SA + m, bufsize = (n - (2 * m)) / tmp; c0 = ALPHABET_SIZE - 2, c1 = ALPHABET_SIZE - 1, j = m; #pragma omp parallel default(shared) private(curbuf, k, l, d0, d1, tmp) { tmp = omp_get_thread_num(); curbuf = buf + tmp * bufsize; k = 0; for(;;) { #pragma omp critical(sssort_lock) { if(0 < (l = j)) { d0 = c0, d1 = c1; do { k = BUCKET_BSTAR(d0, d1); if(--d1 <= d0) { d1 = ALPHABET_SIZE - 1; if(--d0 < 0) { break; } } } while(((l - k) <= 1) && (0 < (l = k))); c0 = d0, c1 = d1, j = k; } } if(l == 0) { break; } sssort(T, PAb, SA + k, SA + l, curbuf, bufsize, 2, n, *(SA + k) == (m - 1)); } } #else buf = SA + m, bufsize = n - (2 * m); for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { i = BUCKET_BSTAR(c0, c1); if(1 < (j - i)) { sssort(T, PAb, SA + i, SA + j, buf, bufsize, 2, n, *(SA + i) == (m - 1)); } } } #endif /* Compute ranks of type B* substrings. */ for(i = m - 1; 0 <= i; --i) { if(0 <= SA[i]) { j = i; do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); SA[i + 1] = i - j; if(i <= 0) { break; } } j = i; do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); ISAb[SA[i]] = j; } /* Construct the inverse suffix array of type B* suffixes using trsort. */ trsort(ISAb, SA, m, 1); /* Set the sorted order of tyoe B* suffixes. */ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } if(0 <= i) { t = i; for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; } } /* Calculate the index of start/end point of each bucket. */ BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { i = BUCKET_A(c0 + 1) - 1; for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { t = i - BUCKET_B(c0, c1); BUCKET_B(c0, c1) = i; /* end point */ /* Move all type B* suffixes to the correct position. */ for(i = t, j = BUCKET_BSTAR(c0, c1); j <= k; --i, --k) { SA[i] = SA[k]; } } BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ BUCKET_B(c0, c0) = i; /* end point */ } } return m; } /* Constructs the suffix array by using the sorted order of type B* suffixes. */ static void construct_SA(const unsigned char *T, int *SA, int *bucket_A, int *bucket_B, int n, int m) { int *i, *j, *k; int s; int c0, c1, c2; if(0 < m) { /* Construct the sorted order of type B suffixes by using the sorted order of type B* suffixes. */ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { /* Scan the suffix array from right to left. */ for(i = SA + BUCKET_BSTAR(c1, c1 + 1), j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; i <= j; --j) { if(0 < (s = *j)) { assert(T[s] == c1); assert(((s + 1) < n) && (T[s] <= T[s + 1])); assert(T[s - 1] <= T[s]); *j = ~s; c0 = T[--s]; if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); *k-- = s; } else { assert(((s == 0) && (T[s] == c1)) || (s < 0)); *j = ~s; } } } } /* Construct the suffix array by using the sorted order of type B suffixes. */ k = SA + BUCKET_A(c2 = T[n - 1]); *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); /* Scan the suffix array from left to right. */ for(i = SA, j = SA + n; i < j; ++i) { if(0 < (s = *i)) { assert(T[s - 1] >= T[s]); c0 = T[--s]; if((s == 0) || (T[s - 1] < c0)) { s = ~s; } if(c0 != c2) { BUCKET_A(c2) = k - SA; k = SA + BUCKET_A(c2 = c0); } assert(i < k); *k++ = s; } else { assert(s < 0); *i = ~s; } } } /* Constructs the burrows-wheeler transformed string directly by using the sorted order of type B* suffixes. */ static int construct_BWT(const unsigned char *T, int *SA, int *bucket_A, int *bucket_B, int n, int m) { int *i, *j, *k, *orig; int s; int c0, c1, c2; if(0 < m) { /* Construct the sorted order of type B suffixes by using the sorted order of type B* suffixes. */ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { /* Scan the suffix array from right to left. */ for(i = SA + BUCKET_BSTAR(c1, c1 + 1), j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; i <= j; --j) { if(0 < (s = *j)) { assert(T[s] == c1); assert(((s + 1) < n) && (T[s] <= T[s + 1])); assert(T[s - 1] <= T[s]); c0 = T[--s]; *j = ~((int)c0); if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); *k-- = s; } else if(s != 0) { *j = ~s; #ifndef NDEBUG } else { assert(T[s] == c1); #endif } } } } /* Construct the BWTed string by using the sorted order of type B suffixes. */ k = SA + BUCKET_A(c2 = T[n - 1]); *k++ = (T[n - 2] < c2) ? ~((int)T[n - 2]) : (n - 1); /* Scan the suffix array from left to right. */ for(i = SA, j = SA + n, orig = SA; i < j; ++i) { if(0 < (s = *i)) { assert(T[s - 1] >= T[s]); c0 = T[--s]; *i = c0; if((0 < s) && (T[s - 1] < c0)) { s = ~((int)T[s - 1]); } if(c0 != c2) { BUCKET_A(c2) = k - SA; k = SA + BUCKET_A(c2 = c0); } assert(i < k); *k++ = s; } else if(s != 0) { *i = ~s; } else { orig = i; } } return orig - SA; } /*---------------------------------------------------------------------------*/ /*- Function -*/ int divsufsort(const unsigned char *T, int *SA, int n) { int *bucket_A, *bucket_B; int m; int err = 0; /* Check arguments. */ if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } else if(n == 0) { return 0; } else if(n == 1) { SA[0] = 0; return 0; } else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); /* Suffixsort. */ if((bucket_A != NULL) && (bucket_B != NULL)) { m = sort_typeBstar(T, SA, bucket_A, bucket_B, n); construct_SA(T, SA, bucket_A, bucket_B, n, m); } else { err = -2; } free(bucket_B); free(bucket_A); return err; } int divbwt(const unsigned char *T, unsigned char *U, int *A, int n) { int *B; int *bucket_A, *bucket_B; int m, pidx, i; /* Check arguments. */ if((T == NULL) || (U == NULL) || (n < 0)) { return -1; } else if(n <= 1) { if(n == 1) { U[0] = T[0]; } return n; } if((B = A) == NULL) { B = (int *)malloc((size_t)(n + 1) * sizeof(int)); } bucket_A = (int *)malloc(BUCKET_A_SIZE * sizeof(int)); bucket_B = (int *)malloc(BUCKET_B_SIZE * sizeof(int)); /* Burrows-Wheeler Transform. */ if((B != NULL) && (bucket_A != NULL) && (bucket_B != NULL)) { m = sort_typeBstar(T, B, bucket_A, bucket_B, n); pidx = construct_BWT(T, B, bucket_A, bucket_B, n, m); /* Copy to output string. */ U[0] = T[n - 1]; for(i = 0; i < pidx; ++i) { U[i + 1] = (unsigned char)B[i]; } for(i += 1; i < n; ++i) { U[i] = (unsigned char)B[i]; } pidx += 1; } else { pidx = -2; } free(bucket_B); free(bucket_A); if(A == NULL) { free(B); } return pidx; } // End divsufsort.c /////////////////////////////// add /////////////////////////////////// // E8E9 transform of buf[0..n-1] to improve compression of .exe and .dll. // Patterns (E8|E9 xx xx xx 00|FF) at offset i replace the 3 middle // bytes with x+i mod 2^24, LSB first, reading backward. void e8e9(unsigned char* buf, int n) { for (int i=n-5; i>=0; --i) { if (((buf[i]&254)==0xe8) && ((buf[i+4]+1)&254)==0) { unsigned a=(buf[i+1]|buf[i+2]<<8|buf[i+3]<<16)+i; buf[i+1]=a; buf[i+2]=a>>8; buf[i+3]=a>>16; } } } // Encode inbuf to buf using LZ77. args are as follows: // args[0] is log2 buffer size in MB. // args[1] is level (1=var. length, 2=byte aligned lz77, 3=bwt) + 4 if E8E9. // args[2] is the lz77 minimum match length and context order. // args[3] is the lz77 higher context order to search first, or else 0. // args[4] is the log2 hash bucket size (number of searches). // args[5] is the log2 hash table size. If 21+args[0] then use a suffix array. // args[6] is the secondary context look ahead // sap is pointer to external suffix array of inbuf or 0. If supplied and // args[0]=5..7 then it is assumed that E8E9 was already applied to // both the input and sap and the input buffer is not modified. class LZBuffer: public libzpaq::Reader { libzpaq::Array ht;// hash table, confirm in low bits, or SA+ISA const unsigned char* in; // input pointer const int checkbits; // hash confirmation size or lg(ISA size) const int level; // 1=var length LZ77, 2=byte aligned LZ77, 3=BWT const unsigned htsize; // size of hash table const unsigned n; // input length unsigned i; // current location in in (0 <= i < n) const unsigned minMatch; // minimum match length const unsigned minMatch2; // second context order or 0 if not used const unsigned maxMatch; // longest match length allowed const unsigned maxLiteral; // longest literal length allowed const unsigned lookahead; // second context look ahead unsigned h1, h2; // low, high order context hashes of in[i..] const unsigned bucket; // number of matches to search per hash - 1 const unsigned shift1, shift2; // how far to shift h1, h2 per hash const int minMatchBoth; // max(minMatch, minMatch2) const unsigned rb; // number of level 1 r bits in match code unsigned bits; // pending output bits (level 1) unsigned nbits; // number of bits in bits unsigned rpos, wpos; // read, write pointers unsigned idx; // BWT index const unsigned* sa; // suffix array for BWT or LZ77-SA unsigned* isa; // inverse suffix array for LZ77-SA enum {BUFSIZE=1<<14}; // output buffer size unsigned char buf[BUFSIZE]; // output buffer void write_literal(unsigned i, unsigned& lit); void write_match(unsigned len, unsigned off); void fill(); // encode to buf // write k bits of x void putb(unsigned x, int k) { x&=(1<7) { assert(wpos>=8, nbits-=8; } } // write last byte void flush() { assert(wpos0) buf[wpos++]=bits; bits=nbits=0; } // write 1 byte void put(int c) { assert(wpos 00) = match 4*n+ll at offset (q<=65536) r=16, x>>=16; if (x>=256) r+=8, x>>=8; if (x>=16) r+=4, x>>=4; assert(x>=0 && x<16); return "\x00\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x04\x04\x04\x04"[x]+r; } // return number of 1 bits in x int nbits(unsigned x) { int r; for (r=0; x; x>>=1) r+=x&1; return r; } // Read n bytes of compressed output into p and return number of // bytes read in 0..n. 0 signals EOF (overrides Reader). int LZBuffer::read(char* p, int n) { if (rpos==wpos) fill(); int nr=n; if (nr>int(wpos-rpos)) nr=wpos-rpos; if (nr) memcpy(p, buf+rpos, nr); rpos+=nr; assert(rpos<=wpos); if (rpos==wpos) rpos=wpos=0; return nr; } LZBuffer::LZBuffer(StringBuffer& inbuf, int args[], const unsigned* sap): ht((args[1]&3)==3 ? (inbuf.size()+1)*!sap // for BWT suffix array : args[5]-args[0]<21 ? 1u<0 ? (args[5]-1)/minMatch+1 : 1), shift2(minMatch2>0 ? (args[5]-1)/minMatch2+1 : 0), minMatchBoth(MAX(minMatch, minMatch2+lookahead)+4), rb(args[0]>4 ? args[0]-4 : 0), bits(0), nbits(0), rpos(0), wpos(0), idx(0), sa(0), isa(0) { assert(args[0]>=0); assert(n<=(1u<<20<=1 && args[1]<=7 && args[1]!=4); assert(level>=1 && level<=3); if ((minMatch<4 && level==1) || (minMatch<1 && level==2)) error("match length $3 too small"); // e8e9 transform if (args[1]>4 && !sap) e8e9(inbuf.data(), n); // build suffix array if not supplied if (args[5]-args[0]>=21 || level==3) { // LZ77-SA or BWT if (sap) sa=sap; else { assert(ht.size()>=n); assert(ht.size()>0); sa=&ht[0]; if (n>0) divsufsort((const unsigned char*)in, (int*)sa, n); } if (level<3) { assert(ht.size()>=(n*(sap==0))+(1u<<17<0 ? in[n-1] : 255); else if (i>n) put(idx&255), idx>>=8; else if (sa[i-1]==0) idx=i, put(255); else put(in[sa[i-1]-1]); } return; } // LZ77: scan the input unsigned lit=0; // number of output literals pending const unsigned mask=(1<0 && in[p+l1-1]==in[i+l1-1]; --l1); int score=int(l-l1)*8-lg(i-p)-4*(lit==0 && l1>0)-11; for (unsigned a=0; abscore) blen=l, bp=p, blit=l1, bscore=score; if (l255) break; } } } if (bscore<=0 || blen0) { for (unsigned k=0; k<=bucket; ++k) { unsigned p=ht[h2^k]; if (p && (p&mask)==(in[i+3]&mask)) { p>>=checkbits; if (p=minMatch2+lookahead) { int l1; // length back from lookahead for (l1=lookahead; l1>0 && in[p+l1-1]==in[i+l1-1]; --l1); assert(l1>=0 && l1<=int(lookahead)); int score=int(l-l1)*8-lg(i-p)-8*(lit==0 && l1>0)-11; if (score>bscore) blen=l, bp=p, blit=l1, bscore=score; } } } if (blen>=128) break; } } // Search the lower order context if (!minMatch2 || blen>=checkbits; if (p0)-11; if (score>bscore) blen=l, bp=p, blit=0, bscore=score; } } if (blen>=128) break; } } } // If match is long enough, then output any pending literals first, // and then the match. blen is the length of the match. assert(i>=bp); const unsigned off=i-bp; // offset if (off>0 && bscore>0 && blen-blit>=minMatch+(level==2)*((off>=(1<<16))+(off>=(1<<24)))) { lit+=blit; write_literal(i+blit, lit); write_match(blen-blit, off); } // Otherwise add to literal length else { blen=1; ++lit; } // Update index, advance blen bytes if (isa) i+=blen; else { while (blen--) { if (i+minMatchBoth>19)&bucket; const unsigned p=(i<=maxLiteral) write_literal(i, lit); } // Write pending literals at end of input assert(i<=n); if (i==n) { write_literal(n, lit); flush(); } } // Write literal sequence in[i-lit..i-1], set lit=0 void LZBuffer::write_literal(unsigned i, unsigned& lit) { assert(lit>=0); assert(i>=0 && i<=n); assert(i>=lit); if (level==1) { if (lit<1) return; int ll=lg(lit); assert(ll>=1 && ll<=24); putb(0, 2); --ll; while (--ll>=0) { putb(1, 1); putb((lit>>ll)&1, 1); } putb(0, 1); while (lit) putb(in[i-lit--], 8); } else { assert(level==2); while (lit>0) { unsigned lit1=lit; if (lit1>64) lit1=64; put(lit1-1); for (unsigned j=i-lit; j=minMatch && len<=maxMatch); assert(off>0); assert(len>=4); assert(rb>=0 && rb<=8); int ll=lg(len)-1; assert(ll>=2); off+=(1<=0 && lo<=23); putb((lo+8)>>3, 2);// mm putb(lo&7, 3); // mmm while (--ll>=2) { // n putb(1, 1); putb((len>>ll)&1, 1); } putb(0, 1); putb(len&3, 2); // ll putb(off, rb); // r putb(off>>rb, lo); // q } // x[2]:len[6] off[x-1] else { assert(level==2); assert(minMatch>=1 && minMatch<=64); --off; while (len>0) { // Split long matches to len1=minMatch..minMatch+63 const unsigned len1=len>minMatch*2+63 ? minMatch+63 : len>minMatch+63 ? len-minMatch : len; assert(wpos=minMatch && len1>8); put(off); } else if (off<(1<<24)) { put(128+len1-minMatch); put(off>>16); put(off>>8); put(off); } else { put(192+len1-minMatch); put(off>>24); put(off>>16); put(off>>8); put(off); } len-=len1; } } } } // end namespace libzpaq zpaqfranz-62.2/ZSFX/libzpaq.h000066400000000000000000001703431477324740300161070ustar00rootroot00000000000000/* libzpaq.h - LIBZPAQ Version 7.12 header - Apr. 19, 2016. This software is provided as-is, with no warranty. I, Matt Mahoney, release this software into the public domain. This applies worldwide. In some countries this may not be legally possible; if so: I grant anyone the right to use this software for any purpose, without any conditions, unless such conditions are required by law. LIBZPAQ is a C++ library providing data compression and decompression services using the ZPAQ level 2 format as described in http://mattmahoney.net/zpaq/ An application wishing to use these services should #include "libzpaq.h" and link to libzpaq.cpp (and advapi32.lib in Windows/VC++). libzpaq recognizes the following options: -DDEBUG Turn on assertion checks (slower). -DNOJIT Don't assume x86-32 or x86-64 with SSE2 (slower). -Dunix Without -DNOJIT, assume Unix (Linux, Mac) rather than Windows. The application must provide an error handling function and derived implementations of two abstract classes, Reader and Writer, specifying the input and output byte streams. For example, to compress from stdin to stdout (assuming binary I/O as in Linux): #include "libzpaq.h" #include #include void libzpaq::error(const char* msg) { // print message and exit fprintf(stderr, "Oops: %s\n", msg); exit(1); } class In: public libzpaq::Reader { public: int get() {return getchar();} // returns byte 0..255 or -1 at EOF } in; class Out: public libzpaq::Writer { public: void put(int c) {putchar(c);} // writes 1 byte 0..255 } out; int main() { libzpaq::compress(&in, &out, "1"); // "0".."5" = faster..better } Or to decompress: libzpaq::decompress(&in, &out); The function error() will be called with an English language message in case of an unrecoverable error such as badly formatted compressed input data or running out of memory. error() should not return. In a multi-threaded application where ZPAQ blocks are being decompressed in separate threads, error() should exit the thread, but other threads may continue. Blocks are independent and libzpaq is thread safe. Reader and Writer provide default implementations of read() and write() for block I/O. You may override these with your own versions, which might be faster. The default is to call get() or put() the appropriate number of times. For example: // Read n bytes into buf[0..n-1] or to EOF, whichever is first. // Return the number of bytes actually read. int In::read(char* buf, int n) {return fread(buf, 1, n, stdin);} // Write buf[0..n-1] void Out::write(char* buf, int n) {fwrite(buf, 1, n, stdout);} By default, compress() divides the input into blocks with one segment each. The segment filename field is empty. The comment field of each block is the uncompressed size as a decimal string. The checksum is saved. To override: compress(&in, &out, "1", "filename", "comment", false); If the filename is not NULL then it is saved in the first block only. If the comment is not NULL then a space and the comment are appended to the decimal size in the first block only. The comment would normally be the date and attributes like "20141231235959 w32", or "jDC\x01" for a journaling archive as described in the ZPAQ specification. The method string has the general form of a concatenation of single character commands each possibly followed by a list of decimal numeric arguments separated by commas or periods: {012345xciawmst}[N1[{.,}N2]...]... For example "1" or "14,128,0" or "x6.3ci1m". Only the first command can be a digit 0..5. If it is, then it selects a compression level and the other commands are ignored. Otherwise, if it is "x" then the arguments and remaining commands describe the compression method. Any other letter as the first command is interpreted the same as "x". Higher compression levels are slower but compress better. "1" is good for most purposes. "0" does not compress. "2" compresses slower but decompression is just as fast as 1. "3", "4", and "5" also decompress slower. The numeric arguments are as follows: N1: 0..11 = block size of at most 2^N1 MiB - 4096 bytes (default 4). N2: 0..255 = estimated ease of compression (default 128). N3: 0..3 = data type. 1 = text, 2 = exe, 3 = both (default 0). For example, "14" or "54" divide the input in 16 MB blocks which are compressed independently. N2 and N3 are hints to the compressor based on analysis of the input data. N2 is 0 if the data is random or 255 if the data is easily compressed (for example, all zero bytes). Most compression methods will simply store random data with no compression. The default is "14,128,0". If the first command is "x" then the string describes the exact compression method. The arguments to "x" describe the pre/post processing (LZ77, BWT, E8E9), and remaining commands describe the context model, if any, of the transformed data. The arguments to "x" are: N1: 0..11 = block size as before. N2: 0..7: 0=none, 1=packed LZ77, 2=LZ77, 3=BWT, 4..7 = 0..3 + E8E9. N3: 4..63: LZ77 min match. N4: LZ77 secondary match to try first or 0 to skip. N5: LZ77 log search depth. N6: LZ77 log hash table size, or N1+21 to use a suffix array. N7: LZ77 lookahead. N2 selects the basic transform applied before context modeling. N2 = 0 does not transform the input. N2 = 1 selects LZ77 encoding of literals strings and matches using bit-packed codes. It is normally not used with a context model. N2 = 2 selects byte aligned LZ77, which compresses worse by itself but better than 1 when a context model is used. It uses single bytes to encode either a literal of length 1..64 or a match of length N3..N3+63 with a 2, 3, or 4 byte offset. N2 = 3 selects a Burrows-Wheeler transform, in which the input is sorted by right-context. This does not compress by itself but makes the data more compressible using a low order, adaptive context model. BWT requires 4 times the block size in additional memory for both compression and decompression. N2 = 4..7 are the same as 0..3 except that a E8E9 transform is first applied to improve the compression of x86 code usually found .exe and .dll files. It scans the input block backward for 5 byte strings of the form {E8|E9 xx xx xx 00|FF} and adds the offset from the start of the block to the middle 3 bytes interpreted as a little-endian (LSB first) number (mod 2^24). E8 and E9 are the CALL and JMP instructions, followed by a 32 bit relative offset. N3..N7 apply only to LZ77. For either type, it searches for matches by hashing the next N4 bytes, and then the next N3 bytes, and looking up each of the hashes at 2^N5 locations in a table with 2^N6 entries. Of those, it picks the longest match, or closest in case of a tie. If no match is at least N3, then a literal is encoded instead. If N5 is 0 then only one hash is computed, which is faster but does not compress as well. Typical good values for fast compression are "x4.1.5.0.3.22" which means 16 MiB blocks, packed LZ77, mininum match length 5, no secondary match, search depth 2^3 = 8, and 2^22 = 4M hash table (using 16 MiB memory). The hash table requires 4 x 2^N6 bytes of memory. If N6 = N1+21, then matches are found using a suffix array and inverse suffix array using 2.25 x 2^N6 bytes (4.5 x block size). This finds better matches but takes longer to compute the suffix array (SA). The matches are found by searching forward and backward in the SA 2^N5 in each direction up to the first earlier match, and picking the longer of the two. Good values are "x4.1.4.0.8.25". The secondary match N4 has no effect. N7 is the lookahead. It looks for matches of length at least N4+N7 when using a hash table or N3+N7 for a SA, but allows the first N7 bytes not to match and be coded as literals if this results in a significantly longer match. Values higher than 1 are rarely effective. The default is 0. All subsequent commands after "x" describe a context model. A model consists of a set of components that output a bit prediction, taking a context and possibly earlier predictions as input. The final prediction is arithmetic coded. The component types are: c = CM or ICM (context model or indirect context model). i = ISSE chain (indirect secondary symbol estimator). a = MATCH. w = word model (ICM-ISSE chain with whole word contexts). m = MIX. s = SSE (secondary symbol estimator). t = MIX2 (2 input MIX). For example, "x4.3ci1" describes a BWT followed by an order 0 CM and order 1 ISSE, which is used for level 3 text compression. The parameters to "c" (default all 0) are as follows: N1: 0 = ICM, 1..256 CM with faster..slower adaptation, +1000 halves memory. N2: 1..255 = offset mod N2, 1000..1255 = offset to last N2-1000 byte. N3: 0..255 = order 0 context mask, 256..511 mixes LZ77 parse state. N4...: 0..255 order 1... context masks. 1000... skips N4-1000 bytes. Most components use no more memory than the block size, depending on the number of context bits, but it is possible to select less memory and lose compression. A CM inputs a context hash and outputs a prediction from a table. The table entry is then updated by adjusting in the direction of the actual bit. The adjustment is 1/count, where the maximum count is 4 x N1. Larger values are best for stationary data. Smaller values adapt faster to changing data. If N1 is 0 then c selects an ICM. An ICM maps a context to a bit history (8 bit state), and then to slow adapting prediction. It is generally better than a CM on most nonstationary data. The context for a CM or ICM is a hash of all selected contexts: a cyclic counter (N2 = 1..255), the distance from the last occurrence of some byte value (N2 = 1000..1255), and the masked history of the last 64K bytes ANDED with N3, N4... For example, "c0.0.255.255.255" is an order 3 ICM. "C0.1010.255" is an order 1 context hashed together with the column number in a text file (distance to the last linefeed, ASCII 10). "c256.0.255.1511.255" is a stationary grayscale 512 byte wide image model using the two previous neighboring pixels as context. "c0.0.511.255" is an order 1 model for LZ77, which helps compress literal strings. The LZ77 state context applies only to byte aligned LZ77 (type 2 or 6). The parameters to "i" (ISSE chain) are the initial context length and subsequent increments for a chain connected to an existing earlier component. For example, "ci1.1.2" specifies an ICM (order 0) followed by a chain of 3 ISSE with orders 1, 2, and 4. An ISSE maps a context to a bit history like an ISSE, but uses the history to select a pair of weights to mix the input prediction with a constant 1, thus performing the mapping q' := w1 x q + w2 in the logistic domain (q = log p/(1-p)). The mixer is then updated by adjusting the weights to improve the prediction. High order ISSE chains (like "x4.0ci1.1.1.1.2") and BWT followed by a low order chain (like "x4.3ci1") both provide excellent general purpose compression. A MATCH ("a") keeps a rotating history buffer and a hash table to look up the previous occurrence of the current context hash and predicts whatever bit came next. The parameters are: N1 = hash multiplier, default 24. N2 = halve buffer size, default 0 = same size as input block. N3 = halve hash table size, default 0 = block size / 4. For example, "x4.0m24.1.1" selects a 16 MiB block size, 8 MiB match buffer size, and 2M hash table size (using 8 MiB at 4 bytes per entry). The hash is computed as hash := hash x N1 + next_byte + 1 (mod hash table size). Thus, N1 = 12 selects a higher order context, and N1 = 48 selects a lower order. A word model ('w") is an ICM-ISSE chain of length N1 (orders 0..N1-1) in which the contexts are whole words. A word is defined as the set of characters in the range N2..N2+N3-1 after ANDing with N4. The context is hashed using multiplier N5. Memory is halved by N6. The default is "w1.65.26.223.20.0" which is a chain of length 1 (ICM only), where words are in range 65 ('A') to 65+26-1 ('Z') after ANDing with 223 (which converts to upper case). The hash multiplier is 20, which has the effect of shifting the high 2 bits out of the hash. The memory usage of each component is the same as the block size. A MIX ("m") performs the weighted average of all previous component predictions. The weights are then adjusted to improve the prediction by favoring the most accurate components. N1 selects the number of context bits (not hashed) to select a set of weights. N2 is the learning rate (around 16..32 works well). The default is "m8.24" which selects the previously modeled bits of the current byte as context. When N1 is not a multiple of 8, it selects the most significant bits of the oldest byte. A SSE ("s") adjusts the previous prediction like an ISSE, but uses a direct lookup table of the quantized and interpolated input prediction and a direct (not hashed) N1-bit context. The adjustment is 1/count where the count is allowed to range from N2 to 4 x N3. The default is "s8.32.255". A MIX2 ("t") is a MIX but mixing only the last 2 components. The default is "t8.24" where the meaning is the same as "m". For example, a good model for text is "x6.0ci1.1.1.1.2aw2mm16tst" which selects 2^6 = 64 MiB blocks, no preprocessing, an order 0 ICM, an ISSE chain with orders 1, 2, 3, 4, 6, a MATCH, an order 0-1 word ICM-ISSE chain, two mixers with 0 and 1 byte contexts, whose outputs are mixed by a MIX2. The MIX2 output is adjusted by a SSE, and finally the SSE input and outputs are mixed again for the final bit prediction. COMPRESSBLOCK CompressBlock() takes the same arguments as compress() except that the input is a StringBuffer instead of a Reader. The output is always a single block, regardless of the N1 (block size) argument in the method. void compressBlock(StringBuffer* in, Writer* out, const char* method, const char* filename=0, const char* comment=0, bool compute_sha1=false); A StringBuffer is both a Reader and a Writer, but also allows random memory access. It provides convenient and efficient storage when the input size is unknown. class StringBuffer: public libzpaq::Reader, public libzpaq::Writer { public: StringBuffer(size_t n=0); // initial allocation after first use ~StringBuffer(); int get(); // read 1 byte or EOF from memory int read(char* buf, int n); // read n bytes void put(int c); // write 1 byte to memory void write(const char* buf, int n); // write n bytes const char* c_str() const; // read-only access to written data unsigned char* data(); // read-write access size_t size() const; // number of bytes written size_t remaining() const; // number of bytes to read until EOF void setLimit(size_t n); // set maximum write size void reset(); // discard contents and free memory void resize(size_t n); // truncate to n bytes void swap(StringBuffer& s); // exchange contents efficiently }; The constructor sets the inital allocation size after the first write to n or 128, whichever is larger. Initially, no memory is allocated. The allocated size is always n x (2^k - 1), for example 128 x (1, 3, 7, 15, 31...). put() and write() append 1 or n bytes, allocating memory as needed. buf can be NULL and the StringBuffer will be enlarged by n. get() and read() read 1 or up to n bytes. get() returns EOF if you attempt to read past the end of written data. read() returns less than n if it reaches EOF first, or 0 at EOF. size() is the number of bytes written, which does not change when data is read. remaining() is the number of bytes left to read before EOF. c_str() provides read-only access to the data. It is not NUL terminated. data() provides read-write access. Either may return NULL if size() is 0. write(), put(), reset(), swap(), and the destructor may invalidate saved pointers. setLimit() sets a maximum size. It will call error() if you try to write past it. The default is -1 or no limit. reset() sets the size to 0 and frees memory. resize() sets the size to n by moving the write pointer, but does not allocate or free memory. Moving the pointer forward does not overwrite the previous contents in between. The write pointer can be moved past the end of allocated memory, and the next put() or write() will allocate as needed. If the write pointer is moved back before the read pointer, then remaining() is set to 0. swap() swaps 2 StringBuffers efficiently, but does not change their initial allocations. DECOMPRESSER decompress() will decompress any valid ZPAQ stream, which may contain multiple blocks with multiple segments each. It will ignore filenames, comments, and checksums. You need the Decompresser class if you want to do something other than decompress all of the data serially to a single file. To decompress individual blocks and segments and retrieve the filenames, comments, data, and hashes of each segment (in exactly this order): libzpaq::Decompresser d; // to decompress libzpaq::SHA1 sha1; // to verify output hashes double memory; // bytes required to decompress Out filename, comment; char sha1out[21]; d.setInput(&in); while (d.findBlock(&memory)) { // default is NULL while (d.findFilename(&filename)) { // default is NULL d.readComment(&comment); // default is NULL d.setOutput(&out); // if omitted or NULL, discard output d.setSHA1(&sha1); // optional while (d.decompress(1000)); // bytes to decode, default is all d.readSegmentEnd(sha1out); // {0} or {1,hash[20]} if (sha1out[0]==1 && memcmp(sha1.result(), sha1out+1, 20)) error("checksum error"); } } findBlock() scans the input for the next ZPAQ block and returns true if found. It optionally sets memory to the approximate number of bytes that it will allocate at the first call to decompress(). findFilename() finds the next segment and returns false if there are no more in the current block. It optionally writes the saved filename. readComment() optionally writes the comment. It must be called after reading the filename and before decompressing. setSHA1() specifies an SHA1 object for computing a hash of the segment. It may be omitted if you do not want to compute a hash. decompress() decodes the requested number of bytes, postprocesses them, and writes them to out. For the 3 built in compression levels, this is the same as the number of bytes output, but it may be different if postprocessing was used. It returns true until there is no more data to decompress in the current segment. The default (-1) is to decompress the whole segment. readSegmentEnd() skips any remaining data not yet decompressed in the segment and writes 21 bytes, either a 0 if no hash was saved, or a 1 followed by the 20 byte saved hash. If any data is skipped, then all data in the remaining segments in the current block must also be skipped. SHA1 The SHA1 object computes SHA-1 cryptographic hashes. It is safe to assume that two inputs with the same hash are identical. For example: libzpaq::SHA1 sha1; int ch; while ((ch=getchar())!=EOF) sha1.put(ch); printf("Size is %1.0f or %1.0f bytes\n", sha1.size(), double(sha1.usize())); size() returns the number of bytes read as a double, and usize() as a 64 bit integer. result() returns a pointer to the 20 byte hash and resets the size to 0. The hash (not just the pointer) should be copied before the next call to result() if you want to save it. You can also call sha1.write(buffer, n) to hash n bytes of char* buffer. COMPRESSOR A Compressor object allows greater control over the compressed data. In particular you can specify the compression algorithm in ZPAQL to specify methods not possible using compress() or compressBlock(). You can create blocks with multiple segments specifying different files, or compress streams of unlimited size to a single block when the input size is not known. libzpaq::Compressor c; for (int i=0; i 128) or 0 (c < 128). CM s t context model with 2^s contexts, learning rate 1/4t. ICM s indirect context model with 2^(s+6) contexts. MATCH s b match model with 2^s context hashes and 2^b history. AVG j k wt average components j and k with weight wt/256 for j. MIX2 s j k r x average j and k with 2^s contexts, rate r, mask x. MIX s j m r x average j..j+m-1 with 2^s contexts, rate r, mask x. ISSE s j adjust prediction j using 2^(s+6) indirect contexts. SSE s j t1 t2 adjust j using 2^s direct contexts, rate 1/t1..1/4t2. A CONST predicts a 1 with probability 1/(1+exp((128-c)/16)), i.e numbers near 0 or 255 are the most confident. A CM maps a context to a prediction and a count. It is updated by adjusting the prediction to reduce the error by 1/count and incrementing the count up to 4t. A ICM maps a s+10 bit context hash to a bit history (8 bit state) representing a bounded count of zeros and ones previously seen in the context and which bit was last. The bit history is mapped to a prediction, which is updated by reducing the error by 1/1024. The initial prediction is estimated from the counts represented by each bit history. A MATCH looks up a context hash and predicts whatever bit came next following the previous occurrence in the history buffer. The strength of the prediction depends on the match length. AVG, MIX2, and MIX perform weighted averaging of predictions in the logistic domain (log(p/(1-p))). AVG uses a fixed weight. MIX2 and MIX adjust the weights (selected by context) to reduce prediction error by a rate that increases with r. The mask is AND-ed with the current partially coded byte to compute that context. Normally it is 255. A MIX takes a contiguous range of m components as input. ISSE adjusts a prediction using a bit history (as with an ICM) to select a pair of weights for a 2 input MIX. It mixes the input prediction with a constant 1 in the logistic domain. SSE adjusts a logistic prediction by quantizing it to 32 levels and selecting a new prediction from a table indexed by context, interpolating between the nearest two steps. The nearest prediction error is reduced by 1/count where count increments from t1 to 4*t2. Contexts are computed and stored in an array H of 32 bit unsigned integers by the HCOMP program written in ZPAQL. The program is called after encoding a whole byte. To form a complete context, these values are combined with the previous 0 to 7 bits of the current parital byte. The method depends on the component type as follows: CM: H[i] XOR hmap4(c). ICM, ISSE: hash table lookup of (H[i]*16+c) on nibble boundaries. MIX2, MIX: H[i] + (c AND x). SSE: H[i] + c. where c is the previous bits with a leading 1 bit (1, 1x, 1xx, ..., 1xxxxxxx where x is a previously coded bit). hmap4(c) maps c to a 9 bit value to reduce cache misses. The first nibble is mapped as before and the second nibble with 1xxxx in the high 5 bits. For example, after 6 bits, where c = 1xxxxxx, hmap4(c) = 1xxxx01xx with the bits in the same order. There are two ZPAQL virtual machines, HCOMP to compute contexts and PCOMP to post-process the decoded output. Each has the following state: PC: 16 bit program counter. A, B, C, D, R0...R255: 32 bit unsigned registers. F: 1 bit condition register. H: array of 2^h 32 bit unsigned values (output for HCOMP). M: array of 2^m 8 bit unsigned values. All values are initialized to 0 at the beginning of a block and retain their values between calls. There are two machines. HCOMP is called after coding each byte with the value of that byte in A. PCOMP, if present, is called once for each decoded byte with that byte in A, and once more at the end of each segment with 2^32 - 1 in A. Normally, A is an accumulator. It is the destination of all binary operations except assignment. The low m bits of B and C index M. The low h bits of D indexes H. We write *B, *C, *D to refer to the elements they point to. The instruction set is as follows, where X is A, B, C, D, *B, *C, *D except as indicated. X may also be a constant 0...255, written with a leading space if it appears on the right side of an operator, e.g. "*B= 255". Instructions taking a numeric argument are 2 bytes, otherwise 1. Arithmetic is modulo 2^32. X<>A Swap X with A (X cannot be A). X++ Add 1. X-- Subtract 1. X! Complement bits of X. X=0 Clear X (1 byte instruction). X=X Assignment to left hand side. A+=X Add to A A-=X Subtract from A A*=X Multipy A/=X Divide. If X is 0 then A=0. A%=X Mod. If X is 0 then A=0. A&=X Clear bits of A that are 0 in X. A&~X Clear bits of A that are 1 in X. A|=X Set bits of A that are 1 in X. A^=X Complement bits of A that are set in X. A<<=X Shift A left by (X mod 32) bits. A>>=X Shift right (zero fill) A by (X mod 32) bits. A==X Set F=1 if equal else F=0. AX Set F=1 if greater else F=0. X=R N Set A,B,C,D to RN (R0...R255). R=A N Set R0...R255 to A. JMP N Jump N=-128...127 bytes from next instruction. JT N Jump N=-128...127 if F is 1. JF N Jump N=-128...127 if F is 0. LJ N Long jump to location 0...65535 (only 3 byte instruction). OUT Output A (PCOMP only). HASH A=(A+*B+512)*773. HASHD *D=(*D+A+512)*773. HALT Return at end of program. ERROR Fail if executed. Rather than using jump instructions, the following constructs are allowed and translated appropriately. IF ... ENDIF Execute if F is 1. IFNOT ... ENDIF Execute if F is 0. IF ... ELSE ... ENDIF Execute first part if F is 1 else second part. IFNOT ... ELSE ... ENDIF Execute first part if F is 0 else second part. DO ... WHILE Loop while F is 1. DO ... UNTIL Loop while F is 0. DO ... FOREVER Loop unconditionally. Forward jumps (IF, IFNOT, ELSE) will not compile if beyond 127 instructions. In that case, use the long form (IFL, IFNOTL, ELSEL). DO loops automatically use long jumps if needed. IF and DO loops may intersect. For example, DO ... IF ... FOREVER ENDIF is equivalent to a while-loop. A config argument without a postprocessor has the following syntax: COMP hh hm ph pm n i COMP args... HCOMP zpaql... END (or POST 0 END for backward compatibility) With a postprocessor: COMP hh hm ph pm n i COMP args... HCOMP zpaql... PCOMP command args... ; zpaql... END In HCOMP, H and M have sizes 2^hh and 2^hm respectively. In PCOMP, H and M have sizes 2^ph and 2^pm respectively. There are n components, which must be numbered i = 0 to n-1. If a postprocessor is used, then "command args..." is written to the Writer* passed as the 4'th argument, but otherwise ignored. A typical use in a development environment might be to call an external program that will be passed two additional arguments on the command line, the input and output file names respectively. You can pass up to 9 signed numeric arguments in args[]. In any place that a number "N" is allowed, you can write "$M" or "$M+N" (like "$1" or $9+25") and value args[M-1]+N will be substituted. ZPAQL allows (nested) comments in parenthesis. It is not case sensitive. If there are input errors, then error() will report the error. If the string contains newlines, it will report the line number of the error. ZPAQL is compiled internally into a byte code, and then to native x86 32 or 64 bit code (unless compiled with -DNOJIT, in which case the byte code is interpreted). You can also specify the algorithm directly in byte code, although this is less convenient because it requires two steps: c.startBlock(hcomp); // COMP and HCOMP at start of block c.postProcess(pcomp, 0); // PCOMP right before compress() in first segment This is necessary because the COMP and HCOMP sections are stored in the block header, but the PCOMP section is compressed in the first segment after the filename and comment but before any data. To retrive compiled byte code in suitable format after startBlock(): c.hcomp(&out); // writes COMP and HCOMP sections c.pcomp(&out); // writes PCOMP section if any Or during decompression: d.hcomp(&out); // valid after findBlock() d.pcomp(&out); // valid after decompress(0) in first segment Both versions of pcomp() write nothing and return false if there is no PCOMP section. The output of hcomp() and pcomp() may be passed to the input of startBlock() and postProcess(). These are strings in which the first 2 bytes encode the length of the rest of the string, least significant byte first. Alternatively, postProcess() allows the length to be omitted and passed separately as the second argument. In the case of decompression, the HCOMP and PCOMP strings are read from the archive. The preprocessor command (from "PCOMP cmd ;") is not saved in the compressed data. ARRAY The libzpaq::Array template class is convenient for creating arrays aligned on 64 byte addresses. It calls error("Out of memory") if needed. It is used as follows: libzpaq::Array a(n); // array a[0]..a[n-1] of type T, zeroed a.resize(n); // change size and zero contents a[i] // i'th element a(i) // a[i%n], valid only if n is a power of 2 a.size() // n (as a size_t) a.isize() // n (as a signed int) T should be a simple type without constructors or destructors. Arrays cannot be copied or assigned. You can also specify the size: Array a(n, e); // n << e a.resize(n, e); // n << e which is equivalent to n << e except that it calls error("Array too big") rather than overflow if n << e would require more than 32 bits. If compiled with -DDEBUG, then bounds are checked at run time. ENCRYPTION There is a class libzpaq::SHA256 with put(), result(), size(), and usize() as in SHA1. result() returns a 32 byte SHA-256 hash. It is used by scrypt. The libzpaq::AES_CTR class allows encryption in CTR mode with 128, 192, or 256 bit keys. The public members are: class AES_CTR { public: AES_CTR(const char* key, int keylen, char* iv=0); void encrypt(U32 s0, U32 s1, U32 s2, U32 s3, unsigned char* ct); void encrypt(char* buf, int n, U64 offset); }; The constructor initializes with a 16, 24, or 32 byte key. The length is given by keylen. iv can be an 8 byte string or NULL. If not NULL then iv0, iv1 are initialized with iv[0..7] in big-endian order, else 0. encrypt(s0, s1, s2, s3, ct) encrypts a plaintext block divided into 4 32-bit words MSB first. The first byte of plaintext is the high 8 bits of s0. The output is to ct[16]. encrypt(buf, n, offset) encrypts or decrypts an n byte slice of a string starting at offset. The i'th 16 byte block is encrypted by XOR with the result (in ct) of encrypt(iv0, iv1, i>>32, i&0xffffffff, ct) starting with i = 0. For example: AES_CTR a("a 128 bit key!!!", 16); char buf[500]; // some data a.encrypt(buf, 100, 0); // encrypt first 100 bytes a.encrypt(buf, 400, 100); // encrypt next 400 bytes a.encrypt(buf, 500, 0); // decrypt in one step libzpaq::stretchKey(char* out, const char* in, const char* salt); Generate a 32 byte key out[0..31] from key[0..31] and salt[0..31] using scrypt(key, salt, N=16384, r=8, p=1). key[0..31] should be the SHA-256 hash of the password. With these parameters, the function uses 0.1 to 0.3 seconds and 16 MiB memory. Scrypt is defined in http://www.tarsnap.com/scrypt/scrypt.pdf void random(char* buf, int n); Puts n cryptographic random bytes in buf[0..n-1], where the first byte is never '7' or 'z' (start of a ZPAQ archive). For a pure random string, discard the first byte. Other classes and functions defined here are for internal use. Use at your own risk. */ ////////////////////////////////////////////////////////////// #ifndef LIBZPAQ_H #define LIBZPAQ_H #ifndef DEBUG #define NDEBUG 1 #endif #include #include #include #include #include namespace libzpaq { // 1, 2, 4, 8 byte unsigned integers typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; // Tables for parsing ZPAQL source code extern const char* compname[256]; // list of ZPAQL component types extern const int compsize[256]; // number of bytes to encode a component extern const char* opcodelist[272]; // list of ZPAQL instructions // Callback for error handling extern void error(const char* msg); // Virtual base classes for input and output // get() and put() must be overridden to read or write 1 byte. // read() and write() may be overridden to read or write n bytes more // efficiently than calling get() or put() n times. class Reader { public: virtual int get() = 0; // should return 0..255, or -1 at EOF virtual int read(char* buf, int n); // read to buf[n], return no. read virtual ~Reader() {} }; class Writer { public: virtual void put(int c) = 0; // should output low 8 bits of c virtual void write(const char* buf, int n); // write buf[n] virtual ~Writer() {} }; // Read 16 bit little-endian number int toU16(const char* p); // An Array of T is cleared and aligned on a 64 byte address // with no constructors called. No copy or assignment. // Array a(n, ex=0); - creates n< class Array { T *data; // user location of [0] on a 64 byte boundary size_t n; // user size int offset; // distance back in bytes to start of actual allocation void operator=(const Array&); // no assignment Array(const Array&); // no copy public: Array(size_t sz=0, int ex=0): data(0), n(0), offset(0) { resize(sz, ex);} // [0..sz-1] = 0 void resize(size_t sz, int ex=0); // change size, erase content to zeros ~Array() {resize(0);} // free memory size_t size() const {return n;} // get size int isize() const {return int(n);} // get size as an int T& operator[](size_t i) {assert(n>0 && i0 && (n&(n-1))==0); return data[i&(n-1)];} }; // Change size to sz< void Array::resize(size_t sz, int ex) { assert(size_t(-1)>0); // unsigned type? while (ex>0) { if (sz>sz*2) error("Array too big"); sz*=2, --ex; } if (n>0) { assert(offset>0 && offset<=64); assert((char*)data-offset); ::free((char*)data-offset); } n=0; offset=0; if (sz==0) return; n=sz; const size_t nb=128+n*sizeof(T); // test for overflow if (nb<=128 || (nb-128)/sizeof(T)!=n) n=0, error("Array too big"); data=(T*)::calloc(nb, 1); if (!data) n=0, error("Out of memory"); offset=64-(((char*)data-(char*)0)&63); assert(offset>0 && offset<=64); data=(T*)((char*)data+offset); } //////////////////////////// SHA1 //////////////////////////// // For computing SHA-1 checksums class SHA1 { public: void put(int c) { // hash 1 byte U32& r=w[U32(len)>>5&15]; r=(r<<8)|(c&255); len+=8; if ((U32(len)&511)==0) process(); } void write(const char* buf, int64_t n); // hash buf[0..n-1] double size() const {return len/8;} // size in bytes uint64_t usize() const {return len/8;} // size in bytes const char* result(); // get hash and reset SHA1() {init();} private: void init(); // reset, but don't clear hbuf U64 len; // length in bits U32 h[5]; // hash state U32 w[16]; // input buffer char hbuf[20]; // result void process(); // hash 1 block }; //////////////////////////// SHA256 ////////////////////////// // For computing SHA-256 checksums // http://en.wikipedia.org/wiki/SHA-2 class SHA256 { public: void put(int c) { // hash 1 byte unsigned& r=w[len0>>5&15]; r=(r<<8)|(c&255); if (!(len0+=8)) ++len1; if ((len0&511)==0) process(); } double size() const {return len0/8+len1*536870912.0;} // size in bytes uint64_t usize() const {return len0/8+(U64(len1)<<29);} //size in bytes const char* result(); // get hash and reset SHA256() {init();} private: void init(); // reset, but don't clear hbuf unsigned len0, len1; // length in bits (low, high) unsigned s[8]; // hash state unsigned w[16]; // input buffer char hbuf[32]; // result void process(); // hash 1 block }; //////////////////////////// AES ///////////////////////////// // For encrypting with AES in CTR mode. // The i'th 16 byte block is encrypted by XOR with AES(i) // (i is big endian or MSB first, starting with 0). class AES_CTR { U32 Te0[256], Te1[256], Te2[256], Te3[256], Te4[256]; // encryption tables U32 ek[60]; // round key int Nr; // number of rounds (10, 12, 14 for AES 128, 192, 256) U32 iv0, iv1; // first 8 bytes in CTR mode public: AES_CTR(const char* key, int keylen, const char* iv=0); // Schedule: keylen is 16, 24, or 32, iv is 8 bytes or NULL void encrypt(U32 s0, U32 s1, U32 s2, U32 s3, unsigned char* ct); void encrypt(char* buf, int n, U64 offset); // encrypt n bytes of buf }; //////////////////////////// stretchKey ////////////////////// // Strengthen password pw[0..pwlen-1] and salt[0..saltlen-1] // to produce key buf[0..buflen-1]. Uses O(n*r*p) time and 128*r*n bytes // of memory. n must be a power of 2 and r <= 8. void scrypt(const char* pw, int pwlen, const char* salt, int saltlen, int n, int r, int p, char* buf, int buflen); // Generate a strong key out[0..31] key[0..31] and salt[0..31]. // Calls scrypt(key, 32, salt, 32, 16384, 8, 1, out, 32); void stretchKey(char* out, const char* key, const char* salt); //////////////////////////// random ////////////////////////// // Fill buf[0..n-1] with n cryptographic random bytes. The first // byte is never '7' or 'z'. void random(char* buf, int n); //////////////////////////// ZPAQL /////////////////////////// // Symbolic constants, instruction size, and names typedef enum {NONE,CONS,CM,ICM,MATCH,AVG,MIX2,MIX,ISSE,SSE} CompType; extern const int compsize[256]; class Decoder; // forward // A ZPAQL machine COMP+HCOMP or PCOMP. class ZPAQL { public: ZPAQL(); ~ZPAQL(); void clear(); // Free memory, erase program, reset machine state void inith(); // Initialize as HCOMP to run void initp(); // Initialize as PCOMP to run double memory(); // Return memory requirement in bytes void run(U32 input); // Execute with input int read(Reader* in2); // Read header bool write(Writer* out2, bool pp); // If pp write PCOMP else HCOMP header int step(U32 input, int mode); // Trace execution (defined externally) Writer* output; // Destination for OUT instruction, or 0 to suppress SHA1* sha1; // Points to checksum computer U32 H(int i) {return h(i);} // get element of h void flush(); // write outbuf[0..bufptr-1] to output and sha1 void outc(int ch) { // output byte ch (0..255) or -1 at EOS if (ch<0 || (outbuf[bufptr]=ch, ++bufptr==outbuf.isize())) flush(); } // ZPAQ1 block header Array header; // hsize[2] hh hm ph pm n COMP (guard) HCOMP (guard) int cend; // COMP in header[7...cend-1] int hbegin, hend; // HCOMP/PCOMP in header[hbegin...hend-1] private: // Machine state for executing HCOMP Array m; // memory array M for HCOMP Array h; // hash array H for HCOMP Array r; // 256 element register array Array outbuf; // output buffer int bufptr; // number of bytes in outbuf U32 a, b, c, d; // machine registers int f; // condition flag int pc; // program counter int rcode_size; // length of rcode U8* rcode; // JIT code for run() // Support code int assemble(); // put JIT code in rcode void init(int hbits, int mbits); // initialize H and M sizes int execute(); // interpret 1 instruction, return 0 after HALT, else 1 void run0(U32 input); // default run() if not JIT void div(U32 x) {if (x) a/=x; else a=0;} void mod(U32 x) {if (x) a%=x; else a=0;} void swap(U32& x) {a^=x; x^=a; a^=x;} void swap(U8& x) {a^=x; x^=a; a^=x;} void err(); // exit with run time error }; ///////////////////////// Component ////////////////////////// // A Component is a context model, indirect context model, match model, // fixed weight mixer, adaptive 2 input mixer without or with current // partial byte as context, adaptive m input mixer (without or with), // or SSE (without or with). struct Component { size_t limit; // max count for cm size_t cxt; // saved context size_t a, b, c; // multi-purpose variables Array cm; // cm[cxt] -> p in bits 31..10, n in 9..0; MATCH index Array ht; // ICM/ISSE hash table[0..size1][0..15] and MATCH buf Array a16; // MIX weights void init(); // initialize to all 0 Component() {init();} }; ////////////////////////// StateTable //////////////////////// // Next state table class StateTable { public: U8 ns[1024]; // state*4 -> next state if 0, if 1, n0, n1 int next(int state, int y) { // next state for bit y assert(state>=0 && state<256); assert(y>=0 && y<4); return ns[state*4+y]; } int cminit(int state) { // initial probability of 1 * 2^23 assert(state>=0 && state<256); return ((ns[state*4+3]*2+1)<<22)/(ns[state*4+2]+ns[state*4+3]+1); } StateTable(); }; ///////////////////////// Predictor ////////////////////////// // A predictor guesses the next bit class Predictor { public: Predictor(ZPAQL&); ~Predictor(); void init(); // build model int predict(); // probability that next bit is a 1 (0..4095) void update(int y); // train on bit y (0..1) int stat(int); // Defined externally bool isModeled() { // n>0 components? assert(z.header.isize()>6); return z.header[6]!=0; } private: // Predictor state int c8; // last 0...7 bits. int hmap4; // c8 split into nibbles int p[256]; // predictions U32 h[256]; // unrolled copy of z.h ZPAQL& z; // VM to compute context hashes, includes H, n Component comp[256]; // the model, includes P bool initTables; // are tables initialized? // Modeling support functions int predict0(); // default void update0(int y); // default int dt2k[256]; // division table for match: dt2k[i] = 2^12/i int dt[1024]; // division table for cm: dt[i] = 2^16/(i+1.5) U16 squasht[4096]; // squash() lookup table short stretcht[32768];// stretch() lookup table StateTable st; // next, cminit functions U8* pcode; // JIT code for predict() and update() int pcode_size; // length of pcode // reduce prediction error in cr.cm void train(Component& cr, int y) { assert(y==0 || y==1); U32& pn=cr.cm(cr.cxt); U32 count=pn&0x3ff; int error=y*32767-(cr.cm(cr.cxt)>>17); pn+=(error*dt[count]&-1024)+(count floor(32768/(1+exp(-x/64))) int squash(int x) { assert(initTables); assert(x>=-2048 && x<=2047); return squasht[x+2048]; } // x -> round(64*log((x+0.5)/(32767.5-x))), approx inverse of squash int stretch(int x) { assert(initTables); assert(x>=0 && x<=32767); return stretcht[x]; } // bound x to a 12 bit signed int int clamp2k(int x) { if (x<-2048) return -2048; else if (x>2047) return 2047; else return x; } // bound x to a 20 bit signed int int clamp512k(int x) { if (x<-(1<<19)) return -(1<<19); else if (x>=(1<<19)) return (1<<19)-1; else return x; } // Get cxt in ht, creating a new row if needed size_t find(Array& ht, int sizebits, U32 cxt); // Put JIT code in pcode int assemble_p(); }; //////////////////////////// Decoder ///////////////////////// // Decoder decompresses using an arithmetic code class Decoder: public Reader { public: Reader* in; // destination Decoder(ZPAQL& z); int decompress(); // return a byte or EOF int skip(); // skip to the end of the segment, return next byte void init(); // initialize at start of block int stat(int x) {return pr.stat(x);} int get() { // return 1 byte of buffered input or EOF if (rpos==wpos) { rpos=0; wpos=in ? in->read(&buf[0], BUFSIZE) : 0; assert(wpos<=BUFSIZE); } return rpos buf; // input buffer of size BUFSIZE bytes int decode(int p); // return decoded bit (0..1) with prob. p (0..65535) }; /////////////////////////// PostProcessor //////////////////// class PostProcessor { int state; // input parse state: 0=INIT, 1=PASS, 2..4=loading, 5=POST int hsize; // header size int ph, pm; // sizes of H and M in z public: ZPAQL z; // holds PCOMP PostProcessor(): state(0), hsize(0), ph(0), pm(0) {} void init(int h, int m); // ph, pm sizes of H and M int write(int c); // Input a byte, return state int getState() const {return state;} void setOutput(Writer* out) {z.output=out;} void setSHA1(SHA1* sha1ptr) {z.sha1=sha1ptr;} }; //////////////////////// Decompresser //////////////////////// // For decompression and listing archive contents class Decompresser { public: Decompresser(): z(), dec(z), pp(), state(BLOCK), decode_state(FIRSTSEG) {} void setInput(Reader* in) {dec.in=in;} bool findBlock(double* memptr = 0); void hcomp(Writer* out2) {z.write(out2, false);} bool findFilename(Writer* = 0); void readComment(Writer* = 0); void setOutput(Writer* out) {pp.setOutput(out);} void setSHA1(SHA1* sha1ptr) {pp.setSHA1(sha1ptr);} bool decompress(int n = -1); // n bytes, -1=all, return true until done bool pcomp(Writer* out2) {return pp.z.write(out2, true);} void readSegmentEnd(char* sha1string = 0); int stat(int x) {return dec.stat(x);} int buffered() {return dec.buffered();} private: ZPAQL z; Decoder dec; PostProcessor pp; enum {BLOCK, FILENAME, COMMENT, DATA, SEGEND} state; // expected next enum {FIRSTSEG, SEG, SKIP} decode_state; // which segment in block? }; /////////////////////////// decompress() ///////////////////// void decompress(Reader* in, Writer* out); //////////////////////////// Encoder ///////////////////////// // Encoder compresses using an arithmetic code class Encoder { public: Encoder(ZPAQL& z): out(0), low(1), high(0xFFFFFFFF), pr(z) {} void init(); void compress(int c); // c is 0..255 or EOF int stat(int x) {return pr.stat(x);} Writer* out; // destination private: U32 low, high; // range Predictor pr; // to get p Array buf; // unmodeled input void encode(int y, int p); // encode bit y (0..1) with prob. p (0..65535) }; //////////////////////////// Compiler //////////////////////// // Input ZPAQL source code with args and store the compiled code // in hz and pz and write pcomp_cmd to out2. class Compiler { public: Compiler(const char* in, int* args, ZPAQL& hz, ZPAQL& pz, Writer* out2); private: const char* in; // ZPAQL source code int* args; // Array of up to 9 args, default NULL = all 0 ZPAQL& hz; // Output of COMP and HCOMP sections ZPAQL& pz; // Output of PCOMP section Writer* out2; // Output ... of "PCOMP ... ;" int line; // Input line number for reporting errors int state; // parse state: 0=space -1=word >0 (nest level) // Symbolic constants typedef enum {NONE,CONS,CM,ICM,MATCH,AVG,MIX2,MIX,ISSE,SSE, JT=39,JF=47,JMP=63,LJ=255, POST=256,PCOMP,END,IF,IFNOT,ELSE,ENDIF,DO, WHILE,UNTIL,FOREVER,IFL,IFNOTL,ELSEL,SEMICOLON} CompType; void syntaxError(const char* msg, const char* expected=0); // error() void next(); // advance in to next token bool matchToken(const char* tok);// in==token? int rtoken(int low, int high); // return token which must be in range int rtoken(const char* list[]); // return token by position in list void rtoken(const char* s); // return token which must be s int compile_comp(ZPAQL& z); // compile either HCOMP or PCOMP // Stack of n elements class Stack { libzpaq::Array s; size_t top; public: Stack(int n): s(n), top(0) {} void push(const U16& x) { if (top>=s.size()) error("IF or DO nested too deep"); s[top++]=x; } U16 pop() { if (top<=0) error("unmatched IF or DO"); return s[--top]; } }; Stack if_stack, do_stack; }; //////////////////////// Compressor ////////////////////////// class Compressor { public: Compressor(): enc(z), in(0), state(INIT), verify(false) {} void setOutput(Writer* out) {enc.out=out;} void writeTag(); void startBlock(int level); // level=1,2,3 void startBlock(const char* hcomp); // ZPAQL byte code void startBlock(const char* config, // ZPAQL source code int* args, // NULL or int[9] arguments Writer* pcomp_cmd = 0); // retrieve preprocessor command void setVerify(bool v) {verify = v;} // check postprocessing? void hcomp(Writer* out2) {z.write(out2, false);} bool pcomp(Writer* out2) {return pz.write(out2, true);} void startSegment(const char* filename = 0, const char* comment = 0); void setInput(Reader* i) {in=i;} void postProcess(const char* pcomp = 0, int len = 0); // byte code bool compress(int n = -1); // n bytes, -1=all, return true until done void endSegment(const char* sha1string = 0); char* endSegmentChecksum(int64_t* size = 0, bool dosha1=true); int64_t getSize() {return sha1.usize();} const char* getChecksum() {return sha1.result();} void endBlock(); int stat(int x) {return enc.stat(x);} private: ZPAQL z, pz; // model and test postprocessor Encoder enc; // arithmetic encoder containing predictor Reader* in; // input source SHA1 sha1; // to test pz output char sha1result[20]; // sha1 output enum {INIT, BLOCK1, SEG1, BLOCK2, SEG2} state; bool verify; // if true then test by postprocessing }; /////////////////////////// StringBuffer ///////////////////// // For (de)compressing to/from a string. Writing appends bytes // which can be later read. class StringBuffer: public libzpaq::Reader, public libzpaq::Writer { unsigned char* p; // allocated memory, not NUL terminated, may be NULL size_t al; // number of bytes allocated, 0 iff p is NULL size_t wpos; // index of next byte to write, wpos <= al size_t rpos; // index of next byte to read, rpos < wpos or return EOF. size_t limit; // max size, default = -1 const size_t init; // initial size on first use after reset // Increase capacity to a without changing size void reserve(size_t a) { assert(!al==!p); if (a<=al) return; unsigned char* q=0; if (a>0) q=(unsigned char*)(p ? realloc(p, a) : malloc(a)); if (a>0 && !q) error("Out of memory"); p=q; al=a; } // Enlarge al to make room to write at least n bytes. void lengthen(size_t n) { assert(wpos<=al); if (wpos+n>limit || wpos+n=a) a=a*2+init; reserve(a); } // No assignment or copy void operator=(const StringBuffer&); StringBuffer(const StringBuffer&); public: // Direct access to data unsigned char* data() {assert(p || wpos==0); return p;} // Allocate no memory initially StringBuffer(size_t n=0): p(0), al(0), wpos(0), rpos(0), limit(size_t(-1)), init(n>128?n:128) {} // Set output limit void setLimit(size_t n) {limit=n;} // Free memory ~StringBuffer() {if (p) free(p);} // Return number of bytes written. size_t size() const {return wpos;} // Return number of bytes left to read size_t remaining() const {return wpos-rpos;} // Reset size to 0 and free memory. void reset() { if (p) free(p); p=0; al=rpos=wpos=0; } // Write a single byte. void put(int c) { // write 1 byte lengthen(1); assert(p); assert(wposwpos) n=wpos-rpos; if (n>0 && buf) memcpy(buf, p+rpos, n); rpos+=n; return n; } // Return the entire string as a read-only array. const char* c_str() const {return (const char*)p;} // Truncate the string to size i. void resize(size_t i) { wpos=i; if (rpos>wpos) rpos=wpos; } // Swap efficiently (init is not swapped) void swap(StringBuffer& s) { std::swap(p, s.p); std::swap(al, s.al); std::swap(wpos, s.wpos); std::swap(rpos, s.rpos); std::swap(limit, s.limit); } }; /////////////////////////// compress() /////////////////////// // Compress in to out in multiple blocks. Default method is "14,128,0" // Default filename is "". Comment is appended to input size. // dosha1 means save the SHA-1 checksum. void compress(Reader* in, Writer* out, const char* method, const char* filename=0, const char* comment=0, bool dosha1=true); // Same as compress() but output is 1 block, ignoring block size parameter. void compressBlock(StringBuffer* in, Writer* out, const char* method, const char* filename=0, const char* comment=0, bool dosha1=true); } // namespace libzpaq #endif // LIBZPAQ_H zpaqfranz-62.2/ZSFX/o3.bat000066400000000000000000000001711477324740300152740ustar00rootroot00000000000000@echo off del .\zsfx.exe g++ -Os zsfx.cpp libzpaq.cpp -o zsfx -static -fno-rtti -Wl,--gc-sections strip zsfx.exe zpaqfranz-62.2/ZSFX/o32.bat000066400000000000000000000003011477324740300153510ustar00rootroot00000000000000@echo off del .\zpaqfranz32.exe rem attenzione a -flto c:\mingw32\bin\g++ -m32 -Os zsfx.cpp libzpaq.cpp -o zsfx32 -pthread -static -fno-rtti -Wl,--gc-sections -flto strip zsfx32.exe zpaqfranz-62.2/ZSFX/zsfx.cpp000066400000000000000000002322371477324740300157730ustar00rootroot00000000000000/* zsfx Windows 32/64 self extracting for ZPAQ archives, with multithread support and everything, just like zpaq 7.15 Embedded in zpaqfranz for Windows Written by Franco Corbelli https://github.com/fcorbelli ======================================================= Those are the Windows 32/64 SFX modules for zpaqfranz Released by Franco Corbelli, with MIT License zsfx.cpp use two files: libzpaq.cpp and libzpaq.h, with compatible licenses (MIT and public domain) libzpaq.cpp use libdivsufsort.c for divsufsort 2.00, included within (C) 2003-2008 Yuta Mori, all rights reserved. It is released under the MIT license as described in the comments at the beginning of that section. Some of the code for AES is from libtomcrypt 1.17 by Tom St. Denis and is public domain. The Salsa20/8 code for Scrypt is by D. Bernstein and is public domain. All of the remaining software is provided as-is, with no warranty by Matt Mahoney, who release this software into the public domain. libzpaq.h is provided as-is, with no warranty, by Matt Mahoney, who release this software into the public domain This applies worldwide. ======================================================= Lots of improvements to do Targets Windows 64 (g++ 7.3.0) g++ -O3 zsfx.cpp libzpaq.cpp -o zsfx -static (more aggressive) 10.3.0 beware of -flto g++ -Os zsfx.cpp libzpaq.cpp -o zsfx -static -fno-rtti -Wl,--gc-sections -fdata-sections -flto Windows 32 (g++ 7.3.0) c:\mingw32\bin\g++ -m32 -O3 zsfx.cpp libzpaq.cpp -o zsfx32 -pthread -static (more aggressive) 10.3.0 -flto c:\mingw32\bin\g++ -m32 -Os zsfx.cpp libzpaq.cpp -o zsfx32 -pthread -static -fno-rtti -Wl,--gc-sections -flto */ #define ZSFX_VERSION "55.1" #define _FILE_OFFSET_BITS 64 // In Linux make sizeof(off_t) == 8 #define UNICODE // For Windows #include "libzpaq.h" #include #include #include #include #include #include #include #include #include using std::string; using std::vector; using std::map; using libzpaq::StringBuffer; // Global variables string g_franzo_start; string g_franzo_end; int64_t g_global_start=0; // set to mtime() at start of main() int64_t g_startzpaq=0; // where the data begin #define DEBUGX // define to see a lot of things string extractfilename(const string& i_string) { size_t i = i_string.rfind('/', i_string.length()); if (i != string::npos) return(i_string.substr(i+1, i_string.length() - i)); return(i_string); } string extractfilepath(const string& i_string) { size_t i = i_string.rfind('/', i_string.length()); if (i != string::npos) return(i_string.substr(0, i+1)); return(""); } string prendinomefileebasta(const string& s) { string nomefile=extractfilename(s); size_t i = nomefile.rfind('.', nomefile.length()); if (i != string::npos) return(nomefile.substr(0,i)); return(nomefile); } inline char * migliaia(uint64_t n) { static char retbuf[30]; char *p = &retbuf[sizeof(retbuf)-1]; unsigned int i = 0; *p = '\0'; do { if(i%3 == 0 && i != 0) *--p = '.'; *--p = '0' + n % 10; n /= 10; i++; } while(n != 0); return p; } // Handle errors in libzpaq and elsewhere void libzpaq::error(const char* msg) { if (strstr(msg, "ut of memory")) throw std::bad_alloc(); printf("%s\n",msg); exit(0); } using libzpaq::error; typedef DWORD ThreadReturn; typedef HANDLE ThreadID; void run(ThreadID& tid, ThreadReturn(*f)(void*), void* arg) { tid=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, arg, 0, NULL); if (tid==NULL) error("CreateThread failed"); } void join(ThreadID& tid) { WaitForSingleObject(tid, INFINITE); } typedef HANDLE Mutex; void init_mutex(Mutex& m) { m=CreateMutex(NULL, FALSE, NULL); } void lock(Mutex& m) { WaitForSingleObject(m, INFINITE); } void release(Mutex& m) { ReleaseMutex(m); } void destroy_mutex(Mutex& m) { CloseHandle(m); } // In Windows, convert 16-bit wide string to UTF-8 and \ to / string wtou(const wchar_t* s) { assert(sizeof(wchar_t)==2); // Not true in Linux assert((wchar_t)(-1)==65535); string r; if (!s) return r; for (; *s; ++s) { if (*s=='\\') r+='/'; else if (*s<128) r+=*s; else if (*s<2048) r+=192+*s/64, r+=128+*s%64; else r+=224+*s/4096, r+=128+*s/64%64, r+=128+*s%64; } return r; } // In Windows, convert UTF-8 string to wide string ignoring // invalid UTF-8 or >64K. Convert "/" to slash (default "\"). std::wstring utow(const char* ss, char slash='\\') { assert(sizeof(wchar_t)==2); assert((wchar_t)(-1)==65535); std::wstring r; if (!ss) return r; const unsigned char* s=(const unsigned char*)ss; for (; s && *s; ++s) { if (s[0]=='/') r+=slash; else if (s[0]<128) r+=s[0]; else if (s[0]>=192 && s[0]<224 && s[1]>=128 && s[1]<192) r+=(s[0]-192)*64+s[1]-128, ++s; else if (s[0]>=224 && s[0]<240 && s[1]>=128 && s[1]<192 && s[2]>=128 && s[2]<192) r+=(s[0]-224)*4096+(s[1]-128)*64+s[2]-128, s+=2; } return r; } bool fileexists(const string& i_filename) { HANDLE myhandle; WIN32_FIND_DATA findfiledata; std::wstring wpattern=utow(i_filename.c_str()); myhandle=FindFirstFile(wpattern.c_str(),&findfiledata); if (myhandle!=INVALID_HANDLE_VALUE) { FindClose(myhandle); return true; } return false; } // Print a UTF-8 string to f (stdout, stderr) so it displays properly void printUTF8(const char* s, FILE* f=stdout) { assert(f); assert(s); const HANDLE h=(HANDLE)_get_osfhandle(_fileno(f)); DWORD ft=GetFileType(h); if (ft==FILE_TYPE_CHAR) { fflush(f); std::wstring w=utow(s, '/'); // Windows console: convert to UTF-16 DWORD n=0; WriteConsole(h, w.c_str(), w.size(), &n, 0); } else // stdout redirected to file fprintf(f, "%s", s); } // Return relative time in milliseconds int64_t mtime() { int64_t t=GetTickCount(); if (t1) r/=size; return r; } // Write nobj objects of size size from ptr to fp. Return number written. size_t fwrite(const void* ptr, size_t size, size_t nobj, FP fp) { DWORD r=0; WriteFile(fp, ptr, size*nobj, &r, NULL); if (size>1) r/=size; return r; } // Move file pointer by offset. origin is SEEK_SET (from start), SEEK_CUR, // (from current position), or SEEK_END (from end). int fseeko(FP fp, int64_t offset, int origin) { if (origin==SEEK_SET) origin=FILE_BEGIN; else if (origin==SEEK_CUR) origin=FILE_CURRENT; else if (origin==SEEK_END) origin=FILE_END; LONG h=uint64_t(offset)>>32; SetFilePointer(fp, offset&0xffffffffull, &h, origin); return GetLastError()!=NO_ERROR; } // Get file position int64_t ftello(FP fp) { LONG h=0; DWORD r=SetFilePointer(fp, 0, &h, FILE_CURRENT); return r+(uint64_t(h)<<32); } // Return true if a file or directory (UTF-8 without trailing /) exists. bool exists(string filename) { int len=filename.size(); if (len<1) return false; if (filename[len-1]=='/') filename=filename.substr(0, len-1); return GetFileAttributes(utow(filename.c_str()).c_str()) !=INVALID_FILE_ATTRIBUTES; } // Print last error message void printerr(const char* filename) { fflush(stdout); int err=GetLastError(); printUTF8(filename, stderr); if (err==ERROR_FILE_NOT_FOUND) fprintf(stderr, ": file not found\n"); else if (err==ERROR_PATH_NOT_FOUND) fprintf(stderr, ": path not found\n"); else if (err==ERROR_ACCESS_DENIED) fprintf(stderr, ": access denied\n"); else if (err==ERROR_SHARING_VIOLATION) fprintf(stderr, ": sharing violation\n"); else if (err==ERROR_BAD_PATHNAME) fprintf(stderr, ": bad pathname\n"); else if (err==ERROR_INVALID_NAME) fprintf(stderr, ": invalid name\n"); else if (err==ERROR_NETNAME_DELETED) fprintf(stderr, ": network name no longer available\n"); else fprintf(stderr, ": Windows error %d\n", err); } // Close fp if open. Set date and attributes unless 0 void close(const char* filename, int64_t date, int64_t attr, FP fp=FPNULL) { assert(filename); const bool ads=strstr(filename, ":$DATA")!=0; // alternate data stream? if (date>0 && !ads) { if (fp==FPNULL) fp=CreateFile(utow(filename).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fp!=FPNULL) { SYSTEMTIME st; st.wYear=date/10000000000LL%10000; st.wMonth=date/100000000%100; st.wDayOfWeek=0; // ignored st.wDay=date/1000000%100; st.wHour=date/10000%100; st.wMinute=date/100%100; st.wSecond=date%100; st.wMilliseconds=0; FILETIME ft; SystemTimeToFileTime(&st, &ft); SetFileTime(fp, NULL, NULL, &ft); } } if (fp!=FPNULL) CloseHandle(fp); if ((attr&255)=='w' && !ads) SetFileAttributes(utow(filename).c_str(), attr>>8); } // Print file open error and throw exception void ioerr(const char* msg) { printerr(msg); exit(0); } // Create directories as needed. For example if path="/tmp/foo/bar" // then create directories /, /tmp, and /tmp/foo unless they exist. // Set date and attributes if not 0. void makepath(string path, int64_t date=0, int64_t attr=0) { for (unsigned i=0; i=0); assert(n>=0); string r; for (; x || n>0; x/=10, --n) r=string(1, '0'+x%10)+r; return r; } // Replace * and ? in fn with part or digits of part string subpart(string fn, int part) { for (int j=fn.size()-1; j>=0; --j) { if (fn[j]=='?') fn[j]='0'+part%10, part/=10; else if (fn[j]=='*') fn=fn.substr(0, j)+itos(part)+fn.substr(j+1), part=0; } return fn; } // Base of InputArchive and OutputArchive class ArchiveBase { protected: libzpaq::AES_CTR* aes; // NULL if not encrypted FP fp; // currently open file or FPNULL public: ArchiveBase(): aes(0), fp(FPNULL) {} ~ArchiveBase() { if (aes) delete aes; if (fp!=FPNULL) fclose(fp); } bool isopen() {return fp!=FPNULL;} }; // An InputArchive supports encrypted reading class InputArchive: public ArchiveBase, public libzpaq::Reader { vector sz; // part sizes int64_t off; // current offset string fn; // filename, possibly multi-part with wildcards public: // Open filename. If password then decrypt input. InputArchive(const char* filename, const char* password=0); // Read and return 1 byte or -1 (EOF) int get() { error("get() not implemented"); return -1; } // Read up to len bytes into obuf at current offset. Return 0..len bytes // actually read. 0 indicates EOF. int read(char* obuf, int len) { int nr=fread(obuf, 1, len, fp); if (nr==0) { seek(0, SEEK_CUR); nr=fread(obuf, 1, len, fp); } if (nr==0) return 0; if (aes) aes->encrypt(obuf, nr, off); off+=nr; return nr; } // Like fseeko() void seek(int64_t p, int whence); // Like ftello() int64_t tell() { return off; } #if defined(DEBUG) int64_t tello() { return ftello(fp); } #endif }; // Like fseeko. If p is out of range then close file. void InputArchive::seek(int64_t p, int whence) { if (!isopen()) return; // Compute new offset if (whence==SEEK_SET) off=p; else if (whence==SEEK_CUR) off+=p; else if (whence==SEEK_END) { off=p; for (unsigned i=0; i1); int64_t sum=0; unsigned i; for (i=0;; ++i) { sum+=sz[i]; if (sum>off || i+1>=sz.size()) break; } const string next=subpart(fn, i+1); fclose(fp); fp=fopen(next.c_str(), RB); if (fp==FPNULL) ioerr(next.c_str()); fseeko(fp, off-sum+g_startzpaq, SEEK_END); } // Open for input. Decrypt with password and using the salt in the // first 32 bytes. If filename has wildcards then assume multi-part // and read their concatenation. InputArchive::InputArchive(const char* filename, const char* password): off(0), fn(filename) { assert(filename); // Get file sizes const string part0=subpart(filename, 0); for (unsigned i=1; ; ++i) { const string parti=subpart(filename, i); if (i>1 && parti==part0) break; fp=fopen(parti.c_str(), RB); if (fp==FPNULL) break; fseeko(fp, 0, SEEK_END); sz.push_back(ftello(fp)); fclose(fp); } // Open first part const string part1=subpart(filename, 1); fp=fopen(part1.c_str(), RB); if (!isopen()) ioerr(part1.c_str()); assert(fp!=FPNULL); seek(0,SEEK_SET); /// go to right position // Get encryption salt if (password) { #if defined(DEBUG) printf("Prendo il sale\n"); printf("Z1 tello %ld\n",ftello(fp)); #endif char salt[32], key[32]; if (fread(salt, 1, 32, fp)!=32) error("cannot read salt"); #if defined(DEBUG) printf("Sale "); for (int i=0;i<32;i++) printf("%02X",(unsigned char)salt[i]); printf("\n"); #endif libzpaq::stretchKey(key, password, salt); aes=new libzpaq::AES_CTR(key, 32, salt); off=32; #if defined(DEBUG) printf("Off vale ora %d\n",off); #endif } } ///////////////////////// System info ///////////////////////////////// // Guess number of cores. In 32 bit mode, max is 2. int numberOfProcessors() { int rc=0; // result // In Windows return %NUMBER_OF_PROCESSORS% const char* p=getenv("NUMBER_OF_PROCESSORS"); if (p) rc=atoi(p); if (rc<1) rc=1; if (sizeof(char*)==4 && rc>2) rc=2; return rc; } ////////////////////////////// misc /////////////////////////////////// // For libzpaq output to a string less than 64K chars struct StringWriter: public libzpaq::Writer { string s; void put(int c) { if (s.size()>=65535) error("string too long"); s+=char(c); } }; // In Windows convert upper case to lower case. inline int tolowerW(int c) { if (c>='A' && c<='Z') return c-'A'+'a'; return c; } // Return true if strings a == b or a+"/" is a prefix of b // or a ends in "/" and is a prefix of b. // Match ? in a to any char in b. // Match * in a to any string in b. // In Windows, not case sensitive. bool ispath(const char* a, const char* b) { for (; *a; ++a, ++b) { const int ca=tolowerW(*a); const int cb=tolowerW(*b); if (ca=='*') { while (true) { if (ispath(a+1, b)) return true; if (!*b) return false; ++b; } } else if (ca=='?') { if (*b==0) return false; } else if (ca==cb && ca=='/' && a[1]==0) return true; else if (ca!=cb) return false; } return *b==0 || *b=='/'; } // Read 4 byte little-endian int and advance s unsigned btoi(const char* &s) { s+=4; return (s[-4]&255)|((s[-3]&255)<<8)|((s[-2]&255)<<16)|((s[-1]&255)<<24); } // Read 8 byte little-endian int and advance s int64_t btol(const char* &s) { uint64_t r=btoi(s); return r+(uint64_t(btoi(s))<<32); } /////////////////////////////// Jidac ///////////////////////////////// // A Jidac object represents an archive contents: a list of file // fragments with hash, size, and archive offset, and a list of // files with date, attributes, and list of fragment pointers. // Methods add to, extract from, compare, and list the archive. // enum for version static const int64_t DEFAULT_VERSION=99999999999999LL; // unless -until // fragment hash table entry struct HT { unsigned char sha1[20]; // fragment hash int usize; // uncompressed size, -1 if unknown, -2 if not init HT(const char* s=0, int u=-2) { if (s) memcpy(sha1, s, 20); else memset(sha1, 0, 20); usize=u; } }; // filename entry struct DT { int64_t date; // decimal YYYYMMDDHHMMSS (UT) or 0 if deleted int64_t size; // size or -1 if unknown int64_t attr; // first 8 attribute bytes int64_t data; // sort key or frags written. -1 = do not write vector ptr; // fragment list DT(): date(0), size(0), attr(0), data(0) {} }; typedef map DTMap; // list of blocks to extract struct Block { int64_t offset; // location in archive int64_t usize; // uncompressed size, -1 if unknown (streaming) int64_t bsize; // compressed size vector files; // list of files pointing here unsigned start; // index in ht of first fragment unsigned size; // number of fragments to decompress unsigned frags; // number of fragments in block unsigned extracted; // number of fragments decompressed OK enum {READY, WORKING, GOOD, BAD} state; Block(unsigned s, int64_t o): offset(o), usize(-1), bsize(0), start(s), size(0), frags(0), extracted(0), state(READY) {} }; // Version info struct VER { int64_t date; // Date of C block, 0 if streaming int64_t lastdate; // Latest date of any block int64_t offset; // start of transaction C block int64_t data_offset; // start of first D block int64_t csize; // size of compressed data, -1 = no index int updates; // file updates int deletes; // file deletions unsigned firstFragment;// first fragment ID VER() {memset(this, 0, sizeof(*this));} }; // Windows API functions not in Windows XP to be dynamically loaded typedef HANDLE (WINAPI* FindFirstStreamW_t) (LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD); FindFirstStreamW_t findFirstStreamW=0; typedef BOOL (WINAPI* FindNextStreamW_t)(HANDLE, LPVOID); FindNextStreamW_t findNextStreamW=0; /// we want the fullpath too! string getmyname() { wchar_t buffer[MAX_PATH]; GetModuleFileName(NULL,buffer,MAX_PATH); return (wtou(buffer)); } // Do everything class Jidac { public: int doCommand(int argc, char** argv); friend ThreadReturn decompressThread(void* arg); friend ThreadReturn testThread(void* arg); friend struct ExtractJob; string archive; // archive name private: string exename; string myname; string myoutput; // Command line arguments char command; // command 'a', 'x', or 'l' vector files; // filename args int all; // -all option bool force; // -force option char password_string[32]; // hash of -key argument const char* password; // points to password_string or NULL bool noattributes; // -noattributes option vector notfiles; // list of prefixes to exclude string nottype; // -not =... vector onlyfiles; // list of prefixes to include int summary; // summary option if > 0, detailed if -1 int threads; // default is number of cores vector tofiles; // -to option int64_t date; // now as decimal YYYYMMDDHHMMSS (UT) int64_t version; // version number or 14 digit date // Archive state int64_t dhsize; // total size of D blocks according to H blocks int64_t dcsize; // total size of D blocks according to C blocks vector ht; // list of fragments DTMap dt; // set of files in archive vector block; // list of data blocks to extract vector ver; // version info // Commands int extract(); // extract, return 1 if error else 0 int sfx(string i_thecommands); // make a sfx void usage(); // help string findcommand(int64_t& o_offset); void getpasswordifempty(); // Support functions string rename(string name); // rename from -to int64_t read_archive(const char* arc, int *errors=0); // read arc bool isselected(const char* filename, bool rn=false);// files, -only, -not bool equal(DTMap::const_iterator p, const char* filename); }; /// no buffer overflow protection etc etc string getline(string i_default) { size_t maxline = 255+1; char* line = (char*)malloc(maxline); // sfx module, keep it small char* p_line = line; int c; if (line==NULL) error("744: allocating memory"); if (i_default!="") printf("%s",i_default.c_str()); while((unsigned)(p_line-line)1 && b[1]==':') { // remove : from drive letter if (nb>2 && b[2]!='/') b[1]='/'; else b=b[0]+b.substr(2), --nb; } if (nb>0 && b[0]=='/') b=b.substr(1); if (na>0 && a[na-1]=='/') a=a.substr(0, na-1); return a+"/"+b; } // Rename name using tofiles[] string Jidac::rename(string name) { if (files.size()==0 && tofiles.size()>0) // append prefix tofiles[0] name=append_path(tofiles[0], name); else { // replace prefix files[i] with tofiles[i] const int n=name.size(); for (unsigned i=0; i kind %d\n",i_filename.c_str(),err); exit(0); } char s[4]={0}; if (g_startzpaq) fseek(inFile,g_startzpaq,SEEK_SET); const int nr=fread(s,1,4,inFile); /// for (int i=0;i<4;i++) /// printf("%d %c %d\n",i,s[i],s[i]); fclose(inFile); if (nr>0 && memcmp(s, "7kSt", 4) && (memcmp(s, "zPQ", 3) || s[3]<1)) return true; return false; } void explode(string i_string,char i_delimiter,vector& array) { ///printf("1\n"); // printf("Delimiter %c\n",i_delimiter); // printf("2\n"); //printf("String %s\n",i_string.c_str()); unsigned int i=0; while(i=i_string.size()) break; } } void Jidac::getpasswordifempty() { if (password==NULL) if (check_if_password(archive)) { printf("Archive seems encrypted (or corrupted)"); string spassword=getpassword(); if (spassword!="") { libzpaq::SHA256 sha256; for (unsigned int i=0;i argp(100); if (!autoextract) if (!flagbuilder) { string comandi=findcommand(g_startzpaq); printf("Extracting from EXE with parameters: x %s\n",comandi.c_str()); //printf("Extracting from EXE\n"); ///printf("Start %ld\n",startzpaq); if (g_startzpaq==0) { printf("860:Something is WRONG\n"); exit(0); } /* printf("ARGC prima vale %d\n",argc); for (int i=0;i array_command; explode(comandi,' ',array_command); argc=array_command.size(); #if defined(DEBUG) for (unsigned int i=0;itm_year+1900)*10000000000LL+(t->tm_mon+1)*100000000LL +t->tm_mday*1000000+t->tm_hour*10000+t->tm_min*100+t->tm_sec; string thecommands=""; /// compile a string from all argv (to be stored) if (!autoextract) if (flagbuilder) for (int i=1; i>\n",spassword.c_str()); if (spassword!="") { libzpaq::SHA256 sha256; for (unsigned int i=0;i-1) usage(); ++i; } else { // positive version or date while (++i=19000000LL && version<=29991231LL) version=version*100+23; if (version>=1900000000LL && version<=2999123123LL) version=version*100+59; if (version>=190000000000LL && version<=299912312359LL) version=version*100+59; if (version>9999999) { if (version<19000101000000LL || version>29991231235959LL) { fflush(stdout); fprintf(stderr, "Version date %1.0f must be 19000101000000 to 29991231235959\n", double(version)); exit(1); } date=version; } } else { printf("Unknown option ignored: %s\n", argv[i]); ///usage(); } } // Set threads if (threads<1) threads=numberOfProcessors(); // Test date if (now==-1 || date<19000000000000LL || date>30000000000000LL) error("date is incorrect, use -until YYYY-MM-DD HH:MM:SS to set"); // Adjust negative version if (version<0) { Jidac jidac(*this); jidac.version=DEFAULT_VERSION; jidac.read_archive(archive.c_str()); version+=jidac.ver.size()-1; printf("Version %1.0f\n", version+.0); } // Execute command else if (autoextract) { command='x'; getpasswordifempty(); return extract(); } if (g_startzpaq>0) { /// Houston, the magic is into startzpaq archive=myname; getpasswordifempty(); return extract(); } else if (command=='x') { string rimpiazza="dummy.zpaq"; myreplace(thecommands,archive,rimpiazza); rimpiazza="dummy.exe"; myreplace(thecommands,myoutput,rimpiazza); return sfx(thecommands); } else usage(); return 0; } /////////////////////////// read_archive ////////////////////////////// // Read arc up to -date into ht, dt, ver. Return place to // append. If errors is not NULL then set it to number of errors found. int64_t Jidac::read_archive(const char* arc, int *errors) { if (errors) *errors=0; dcsize=dhsize=0; assert(ver.size()==1); unsigned files=0; // count // Open archive InputArchive in(arc, password); if (!in.isopen()) { if (command!='a') { fflush(stdout); printUTF8(arc, stderr); fprintf(stderr, " not found.\n"); if (errors) ++*errors; } return 0; } printUTF8(arc); if (version==DEFAULT_VERSION) printf(": "); else printf(" -until %1.0f: ", version+0.0); fflush(stdout); in.seek(0,SEEK_SET); // note: the magic is here printf("\n"); if (password) { #if defined(DEBUG) printf("HOUston abbiamo una password!\n"); #endif in.seek(32,SEEK_SET); } #if defined(DEBUG) printf("K0 Inizio a decodificare da %ld\n",in.tell()); printf("K0 tello %ld\n",in.tello()); #endif // Test password char s[4]={0}; int nr=in.read(s, 4); #if defined(DEBUG) printf("\nPrendo 4 byte firma\n"); for (int i=0;i<4;i++) printf("%d %02X %c\n",i,(unsigned char)s[i],s[i]); #endif if (nr>0 && memcmp(s, "7kSt", 4) && (memcmp(s, "zPQ", 3) || s[3]<1)) error("Password kaputt"); in.seek(-nr, SEEK_CUR); #if defined(DEBUG) printf("K2 Inizio a decodificare da %ld\n",in.tell()); printf("K2 tello %ld\n",in.tello()); #endif // Scan archive contents string lastfile=archive; // last named file in streaming format if (lastfile.size()>5 && lastfile.substr(lastfile.size()-5)==".zpaq") lastfile=lastfile.substr(0, lastfile.size()-5); // drop .zpaq int64_t block_offset=32*(password!=0); // start of last block of any type int64_t data_offset=block_offset; // start of last block of d fragments bool found_data=false; // exit if nothing found bool first=true; // first segment in archive? StringBuffer os(32832); // decompressed block const bool renamed=command=='l' || command=='a'; // Detect archive format and read the filenames, fragment sizes, // and hashes. In JIDAC format, these are in the index blocks, allowing // data to be skipped. Otherwise the whole archive is scanned to get // this information from the segment headers and trailers. #if defined(DEBUG) printf("K3 Inizio a decodificare da %ld\n",in.tell()); printf("K3 tello %ld\n",in.tello()); #endif bool done=false; while (!done) { libzpaq::Decompresser d; try { d.setInput(&in); double mem=0; while (d.findBlock(&mem)) { #if defined(DEBUG) printf("Trovato un blocco\n"); #endif found_data=true; // Read the segments in the current block StringWriter filename, comment; int segs=0; // segments in block bool skip=false; // skip decompression? while (d.findFilename(&filename)) { if (filename.s.size()) { for (unsigned i=0; i[cdhi] // and comment ends with " jDC\x01". Skip d (data) blocks. if (comment.s.size()>=4 && comment.s.substr(comment.s.size()-4)=="jDC\x01") { if (filename.s.size()!=28 || filename.s.substr(0, 3)!="jDC") error("bad journaling block name"); if (skip) error("mixed journaling and streaming block"); // Read uncompressed size from comment int64_t usize=0; unsigned i; for (i=0; i0xffffffff) error("journaling block too big"); } // Read the date and number in the filename int64_t fdate=0, num=0; for (i=3; i<17 && isdigit(filename.s[i]); ++i) fdate=fdate*10+filename.s[i]-'0'; if (i!=17 || fdate<19000000000000LL || fdate>=30000000000000LL) error("bad date"); for (i=18; i<28 && isdigit(filename.s[i]); ++i) num=num*10+filename.s[i]-'0'; if (i!=28 || num>0xffffffff) error("bad fragment"); // Decompress the block. os.resize(0); os.setLimit(usize); d.setOutput(&os); libzpaq::SHA1 sha1; d.setSHA1(&sha1); if (strchr("chi", filename.s[17])) { if (mem>1.5e9) error("index block requires too much memory"); d.decompress(); char sha1result[21]={0}; d.readSegmentEnd(sha1result); if ((int64_t)os.size()!=usize) error("bad block size"); if (usize!=int64_t(sha1.usize())) error("bad checksum size"); if (sha1result[0] && memcmp(sha1result+1, sha1.result(), 20)) error("bad checksum"); } else d.readSegmentEnd(); // Transaction header (type c). // If in the future then stop here, else read 8 byte data size // from input and jump over it. if (filename.s[17]=='c') { if (os.size()<8) error("c block too small"); data_offset=in.tell()+1-d.buffered(); const char* s=os.c_str(); int64_t jmp=btol(s); if (jmp<0) printf("Incomplete transaction ignored\n"); if (jmp<0 || (version<19000000000000LL && int64_t(ver.size())>version) || (version>=19000000000000LL && version0); if (fdate>ver.back().lastdate) ver.back().lastdate=fdate; if (os.size()%24!=4) error("bad h block size"); const unsigned n=(os.size()-4)/24; if (num<1 || num+n>0xffffffff) error("bad h fragment"); const char* s=os.c_str(); const unsigned bsize=btoi(s); dhsize+=bsize; assert(ver.size()>0); if (int64_t(ht.size())>num) { fflush(stdout); fprintf(stderr, "Unordered fragment tables: expected >= %d found %1.0f\n", int(ht.size()), double(num)); } for (unsigned i=0; i0); unsigned f=btoi(s); if (f>0x7fffffff) error("fragment too big"); block.back().usize+=(ht[num+i].usize=f)+4u; } data_offset+=bsize; } // Index (type i) // Contents is: 0[8] filename 0 (deletion) // or: date[8] filename 0 na[4] attr[na] ni[4] ptr[ni][4] // Read into DT else if (filename.s[17]=='i') { assert(ver.size()>0); if (fdate>ver.back().lastdate) ver.back().lastdate=fdate; const char* s=os.c_str(); const char* const end=s+os.size(); while (s+9<=end) { DT dtr; dtr.date=btol(s); // date if (dtr.date) ++ver.back().updates; else ++ver.back().deletes; const int64_t len=strlen(s); if (len>65535) error("filename too long"); string fn=s; // filename renamed if (all) fn=append_path(itos(ver.size()-1, all), fn); const bool issel=isselected(fn.c_str(), renamed); s+=len+1; // skip filename if (s>end) error("filename too long"); if (dtr.date) { ++files; if (s+4>end) error("missing attr"); unsigned na=btoi(s); // attr bytes if (s+na>end || na>65535) error("attr too long"); for (unsigned i=0; iend) error("missing ptr"); unsigned ni=btoi(s); // ptr list size if (ni>(end-s)/4u) error("ptr list too long"); if (issel) dtr.ptr.resize(ni); for (unsigned i=0; i0 || first) { ++files; dtr.date=date; dtr.attr=0; dtr.ptr.resize(0); ++ver.back().updates; } dtr.ptr.push_back(ht.size()); } assert(ver.size()>0); if (segs==0 || block.size()==0) block.push_back(Block(ht.size(), block_offset)); assert(block.size()>0); ht.push_back(HT(sha1result+1, -1)); } // end else streaming ++segs; filename.s=""; first=false; } // end while findFilename if (!done) block_offset=in.tell()-d.buffered(); } // end while findBlock done=true; } // end try catch (std::exception& e) { in.seek(-d.buffered(), SEEK_CUR); fflush(stdout); fprintf(stderr, "Skipping block at %1.0f: %s\n", double(block_offset), e.what()); if (errors) ++*errors; } endblock:; } // end while !done #if defined(DEBUG) if (!found_data) printf("no found data\n"); #endif if (in.tell()>32*(password!=0) && !found_data) error("archive contains no data"); printf("%d versions, %u files, %s bytes\n", int(ver.size()-1), files, migliaia(block_offset)); // Calculate file sizes for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) { for (unsigned i=0; isecond.ptr.size(); ++i) { unsigned j=p->second.ptr[i]; if (j>0 && jsecond.size>=0) { if (ht[j].usize>=0) p->second.size+=ht[j].usize; else p->second.size=-1; // unknown size } } } return block_offset; } //////////////////////////////// add ////////////////////////////////// // Append n bytes of x to sb in LSB order inline void puti(libzpaq::StringBuffer& sb, uint64_t x, int n) { for (; n>0; --n) sb.put(x&255), x>>=8; } void print_progress(int64_t ts, int64_t td) { if (td>ts) td=ts; if (td>=1000000) printf("%5.2f%%\r", td*100.0/(ts+0.5)); } /////////////////////////////// extract /////////////////////////////// // Return true if the internal file p // and external file contents are equal or neither exists. // If filename is 0 then return true if it is possible to compare. bool Jidac::equal(DTMap::const_iterator p, const char* filename) { // test if all fragment sizes and hashes exist if (filename==0) { static const char zero[20]={0}; for (unsigned i=0; isecond.ptr.size(); ++i) { unsigned j=p->second.ptr[i]; if (j<1 || j>=ht.size() || ht[j].usize<0 || !memcmp(ht[j].sha1, zero, 20)) return false; } return true; } // internal or neither file exists if (p->second.date==0) return !exists(filename); // directories always match if (p->first!="" && p->first[p->first.size()-1]=='/') return exists(filename); // compare sizes FP in=fopen(filename, RB); if (in==FPNULL) return false; fseeko(in, 0, SEEK_END); if (ftello(in)!=p->second.size) return fclose(in), false; // compare hashes fseeko(in, 0, SEEK_SET); libzpaq::SHA1 sha1; const int BUFSIZE=4096; char buf[BUFSIZE]; for (unsigned i=0; isecond.ptr.size(); ++i) { unsigned f=p->second.ptr[i]; if (f<1 || f>=ht.size() || ht[f].usize<0) return fclose(in), false; for (int j=0; jBUFSIZE) n=BUFSIZE; int r=fread(buf, 1, n, in); if (r!=n) return fclose(in), false; sha1.write(buf, n); j+=n; } if (memcmp(sha1.result(), ht[f].sha1, 20)!=0) return fclose(in), false; } if (fread(buf, 1, BUFSIZE, in)!=0) return fclose(in), false; fclose(in); return true; } // An extract job is a set of blocks with at least one file pointing to them. // Blocks are extracted in separate threads, set READY -> WORKING. // A block is extracted to memory up to the last fragment that has a file // pointing to it. Then the checksums are verified. Then for each file // pointing to the block, each of the fragments that it points to within // the block are written in order. struct ExtractJob { // list of jobs Mutex mutex; // protects state Mutex write_mutex; // protects writing to disk int job; // number of jobs started Jidac& jd; // what to extract FP outf; // currently open output file DTMap::iterator lastdt; // currently open output file name double maxMemory; // largest memory used by any block (test mode) int64_t total_size; // bytes to extract int64_t total_done; // bytes extracted so far ExtractJob(Jidac& j): job(0), jd(j), outf(FPNULL), lastdt(j.dt.end()), maxMemory(0), total_size(0), total_done(0) { init_mutex(mutex); init_mutex(write_mutex); } ~ExtractJob() { destroy_mutex(mutex); destroy_mutex(write_mutex); } }; // Decompress blocks in a job until none are READY ThreadReturn decompressThread(void* arg) { ExtractJob& job=*(ExtractJob*)arg; int jobNumber=0; // Get job number lock(job.mutex); jobNumber=++job.job; release(job.mutex); // Open archive for reading InputArchive in(job.jd.archive.c_str(), job.jd.password); if (!in.isopen()) return 0; StringBuffer out; // Look for next READY job. int next=0; // current job while (true) { lock(job.mutex); for (unsigned i=0; i<=job.jd.block.size(); ++i) { unsigned k=i+next; if (k>=job.jd.block.size()) k-=job.jd.block.size(); if (i==job.jd.block.size()) { // no more jobs? release(job.mutex); return 0; } Block& b=job.jd.block[k]; if (b.state==Block::READY && b.size>0 && b.usize>=0) { b.state=Block::WORKING; release(job.mutex); next=k; break; } } Block& b=job.jd.block[next]; // Get uncompressed size of block unsigned output_size=0; // minimum size to decompress assert(b.start>0); for (unsigned j=0; j=0); output_size+=job.jd.ht[b.start+j].usize; } // Decompress double mem=0; // how much memory used to decompress try { assert(b.start>0); assert(b.start0); assert(b.start+b.size<=job.jd.ht.size()); in.seek(b.offset, SEEK_SET); libzpaq::Decompresser d; d.setInput(&in); out.resize(0); assert(b.usize>=0); assert(b.usize<=0xffffffffu); out.setLimit(b.usize); d.setOutput(&out); if (!d.findBlock(&mem)) error("archive block not found"); if (mem>job.maxMemory) job.maxMemory=mem; while (d.findFilename()) { d.readComment(); while (out.size()=output_size) break; d.readSegmentEnd(); } if (out.size()0 && j=0); assert(job.jd.ht[j].usize<=0x7fffffff); if (q+job.jd.ht[j].usize>out.size()) error("Incomplete decompression"); char sha1result[20]; sha1.write(out.c_str()+q, job.jd.ht[j].usize); memcpy(sha1result, sha1.result(), 20); q+=job.jd.ht[j].usize; if (memcmp(sha1result, job.jd.ht[j].sha1, 20)) { lock(job.mutex); fflush(stdout); fprintf(stderr, "Job %d: fragment %u size %d checksum failed\n", jobNumber, j, job.jd.ht[j].usize); release(job.mutex); error("bad checksum"); } ++b.extracted; } } // If out of memory, let another thread try catch (std::bad_alloc& e) { lock(job.mutex); fflush(stdout); fprintf(stderr, "Job %d killed: %s\n", jobNumber, e.what()); b.state=Block::READY; b.extracted=0; out.resize(0); release(job.mutex); return 0; } // Other errors: assume bad input catch (std::exception& e) { lock(job.mutex); fflush(stdout); fprintf(stderr, "Job %d: skipping [%u..%u] at %1.0f: %s\n", jobNumber, b.start+b.extracted, b.start+b.size-1, b.offset+0.0, e.what()); release(job.mutex); continue; } // Write the files in dt that point to this block lock(job.write_mutex); for (unsigned ip=0; ipsecond.date==0 || p->second.data<0 || p->second.data>=int64_t(p->second.ptr.size())) continue; // don't write // Look for pointers to this block const vector& ptr=p->second.ptr; int64_t offset=0; // write offset for (unsigned j=0; j=b.start+b.extracted) { offset+=job.jd.ht[ptr[j]].usize; continue; } // Close last opened file if different if (p!=job.lastdt) { if (job.outf!=FPNULL) { assert(job.lastdt!=job.jd.dt.end()); assert(job.lastdt->second.date); assert(job.lastdt->second.data second.ptr.size())); fclose(job.outf); job.outf=FPNULL; } job.lastdt=job.jd.dt.end(); } // Open file for output if (job.lastdt==job.jd.dt.end()) { string filename=job.jd.rename(p->first); assert(job.outf==FPNULL); if (p->second.data==0) { makepath(filename); if (job.jd.summary<=0) { lock(job.mutex); print_progress(job.total_size, job.total_done); release(job.mutex); } { job.outf=fopen(filename.c_str(), WB); if (job.outf==FPNULL) { lock(job.mutex); printerr(filename.c_str()); release(job.mutex); } else if ((p->second.attr&0x200ff)==0x20000+'w') { // sparse? DWORD br=0; if (!DeviceIoControl(job.outf, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &br, NULL)) // set sparse attribute printerr(filename.c_str()); } } } else job.outf=fopen(filename.c_str(), RBPLUS); // update existing file if (job.outf==FPNULL) break; // skip errors job.lastdt=p; assert(job.outf!=FPNULL); } assert(job.lastdt==p); // Find block offset of fragment uint64_t q=0; // fragment offset from start of block for (unsigned k=b.start; k0); assert(k=0); q+=job.jd.ht[k].usize; } assert(q+job.jd.ht[ptr[j]].usize<=out.size()); // Combine consecutive fragments into a single write assert(offset>=0); ++p->second.data; uint64_t usize=job.jd.ht[ptr[j]].usize; assert(usize<=0x7fffffff); assert(b.start+b.size<=job.jd.ht.size()); while (j+1=0 && usize+job.jd.ht[ptr[j+1]].usize<=0x7fffffff) { ++p->second.data; assert(p->second.data<=int64_t(ptr.size())); assert(job.jd.ht[ptr[j+1]].usize>=0); usize+=job.jd.ht[ptr[++j]].usize; } assert(usize<=0x7fffffff); assert(q+usize<=out.size()); // Write the merged fragment unless they are all zeros and it // does not include the last fragment. uint64_t nz=q; // first nonzero byte in fragments to be written while (nzsecond.data==int64_t(ptr.size())) { assert(p->second.date); assert(job.lastdt!=job.jd.dt.end()); assert(job.outf!=FPNULL); { assert(job.outf!=FPNULL); string fn=job.jd.rename(p->first); int64_t attr=p->second.attr; int64_t date=p->second.date; if ((p->second.attr&0x1ff)=='w'+256) attr=0; // read-only? if (p->second.data!=int64_t(p->second.ptr.size())) date=attr=0; // not last frag close(fn.c_str(), date, attr, job.outf); job.outf=FPNULL; } job.lastdt=job.jd.dt.end(); } } // end for j } // end for ip // Last file release(job.write_mutex); } // end while true // Last block return 0; } // Streaming output destination struct OutputFile: public libzpaq::Writer { FP f; void put(int c) { char ch=c; if (f!=FPNULL) fwrite(&ch, 1, 1, f); } void write(const char* buf, int n) {if (f!=FPNULL) fwrite(buf, 1, n, f);} OutputFile(FP out=FPNULL): f(out) {} }; // Extract files from archive. If force is true then overwrite // existing files and set the dates and attributes of exising directories. // Otherwise create only new files and directories. Return 1 if error else 0. bool yesorno(int i_ok) { int n = getch(); return (n==i_ok); ///printf("%d %c\n", n, n); } // This is just equal to ZPAQ 7.15, so can works with zpaqfranz too int Jidac::extract() { /// using SFX module, without -to, ask what to do if (tofiles.size()==0) { string where=getline("Path to extract into (empty=default) :"); if (where!="") tofiles.push_back(where); } // Read archive const int64_t sz=read_archive(archive.c_str()); if (sz<1) error("archive not found"); // test blocks for (unsigned i=0; i=ht.size()) error("block start too high"); if (i>0 && block[i].start0 && block[i].start==block[i-1].start) error("empty block"); if (i>0 && block[i].offset0 && block[i-1].offset+block[i-1].bsize>block[i].offset) error("overlapping blocks"); } // Label files to extract with data=0. // Skip existing output files. If force then skip only if equal // and set date and attributes. ExtractJob job(*this); int total_files=0, skipped=0; bool flagask=true; for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) { p->second.data=-1; // skip if (p->second.date && p->first!="") { const string fn=rename(p->first); const bool isdir=p->first[p->first.size()-1]=='/'; if (!force && exists(fn)) if (flagask) { printf("Overwrite ALL already existing files (y/n)?\n"); force=yesorno('y'); flagask=false; #if defined (DEBUG) if (force) printf("FORZA\n"); else printf("mantieni\n"); #endif } if (force && !isdir && equal(p, fn.c_str())) { if (summary<=0) { // identical printf("= "); printUTF8(fn.c_str()); printf("\n"); } close(fn.c_str(), p->second.date, p->second.attr); ++skipped; } else if (!force && exists(fn)) { // exists, skip if (summary<=0) { printf("? "); printUTF8(fn.c_str()); printf("\n"); } ++skipped; } else if (isdir) // update directories later p->second.data=0; else if (block.size()>0) { // files to decompress p->second.data=0; unsigned lo=0, hi=block.size()-1; // block indexes for binary search for (unsigned i=0; p->second.data>=0 && isecond.ptr.size(); ++i) { unsigned j=p->second.ptr[i]; // fragment index if (j==0 || j>=ht.size() || ht[j].usize<-1) { fflush(stdout); printUTF8(p->first.c_str(), stderr); fprintf(stderr, ": bad frag IDs, skipping...\n"); p->second.data=-1; // skip continue; } assert(j>0 && j=block.size() || j=block[lo+1].start)) { lo=0; // find block with fragment j by binary search hi=block.size()-1; while (lolo); assert(mid<=hi); if (j=0 && lo=block[lo].start); assert(lo+1==block.size() || jsecond.size; } } // end if selected } // end for if (!force && skipped>0) printf("%d ?existing files skipped.\n", skipped); if (force && skipped>0) printf("%d =identical files skipped.\n", skipped); // Decompress archive in parallel printf("Extracting %s bytes in %d files -threads %d\n", migliaia(job.total_size), total_files, threads); vector tid(threads); for (unsigned i=0; i0) { Block& b=block[i]; try { in.seek(b.offset, SEEK_SET); libzpaq::Decompresser d; d.setInput(&in); if (!d.findBlock()) error("block not found"); StringWriter filename; for (unsigned j=0; jsecond.ptr.size()>0 && b.files[k]->second.ptr[0]==b.start+j && b.files[k]->second.date>0 && b.files[k]->second.data==0) break; } if (kfirst); dtptr=b.files[k]; lock(job.mutex); if (summary<=0) { printf("2> "); printUTF8(outname.c_str()); printf("\n"); } { makepath(outname); outf=fopen(outname.c_str(), WB); if (outf==FPNULL) printerr(outname.c_str()); } release(job.mutex); } else { // end of file if (outf!=FPNULL) fclose(outf); outf=FPNULL; dtptr=dt.end(); } } // Decompress segment libzpaq::SHA1 sha1; d.setSHA1(&sha1); OutputFile o(outf); d.setOutput(&o); d.decompress(); // Verify checksum char sha1result[21]; d.readSegmentEnd(sha1result); if (sha1result[0]==1) { if (memcmp(sha1result+1, sha1.result(), 20)!=0) error("checksum failed"); } else if (sha1result[0]!=0) error("unknown checksum type"); ++b.extracted; if (dtptr!=dt.end()) ++dtptr->second.data; filename.s=""; ++segments; } } catch(std::exception& e) { lock(job.mutex); printf("Skipping block: %s\n", e.what()); release(job.mutex); } } } if (outf!=FPNULL) fclose(outf); } if (segments>0) printf("%u streaming segments extracted\n", segments); // Wait for threads to finish for (unsigned i=0; isecond.data>=0 && p->second.date && p->first!="") { string s=rename(p->first); if (p->first[p->first.size()-1]=='/') makepath(s, p->second.date, p->second.attr); else if ((p->second.attr&0x1ff)=='w'+256) // read-only? close(s.c_str(), 0, p->second.attr); } } } // Report failed extractions unsigned extracted=0, errors=0; for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) { string fn=rename(p->first); if (p->second.data>=0 && p->second.date && fn!="" && fn[fn.size()-1]!='/') { ++extracted; if (p->second.ptr.size()!=unsigned(p->second.data)) { fflush(stdout); if (++errors==1) fprintf(stderr, "\nFailed (extracted/total fragments, file):\n"); fprintf(stderr, "%u/%u ", int(p->second.data), int(p->second.ptr.size())); printUTF8(fn.c_str(), stderr); fprintf(stderr, "\n"); } } } if (errors>0) { fflush(stdout); fprintf(stderr, "\nExtracted %u of %u files OK (%u errors)" " using %1.3f MB x %d threads\n", extracted-errors, extracted, errors, job.maxMemory/1000000, int(tid.size())); } return errors>0; } /////////////////////////////// main ////////////////////////////////// /// N: no argc or argv, we'll work on it /// Convert argv to UTF-8 and replace \ with / int main() { int argc=0; LPWSTR* argw=CommandLineToArgvW(GetCommandLine(), &argc); vector args(argc); libzpaq::Array argp(argc); for (int i=0; i autoextracting\n"); jidac.archive=zpaqname; } errorcode=jidac.doCommand(argc, argv); } catch (std::exception& e) { fflush(stdout); fprintf(stderr, "zsfx error: %s\n", e.what()); errorcode=2; } fflush(stdout); fprintf(stderr, "%1.3f seconds %s\n", (mtime()-g_global_start)/1000.0, errorcode>1 ? "(with errors)" : errorcode>0 ? "(with warnings)" : "(all OK)"); return errorcode; } bool Jidac::isselected(const char* filename, bool rn) { bool matched=true; if (files.size()>0) { matched=false; for (unsigned i=0; i0) { matched=false; for (unsigned i=0; i= i_needle_len && (p = (unsigned char*)memchr(p,needle_first,plen-i_needle_len + 1))) { if (!memcmp(p,i_needle,i_needle_len)) return (unsigned char *)p; p++; plen=i_haystack_len-(p-i_haystack); } return NULL; } /* The most powerful encryption ever! */ string ahahencrypt(string i_string) { ///return i_string; string risultato=""; for (unsigned int i=0;i kind %d\n",myname.c_str(),err); return ""; } size_t readSize; /// Assumption: the SFX module is smaller then 3MB size_t const blockSize = 3000000; unsigned char *buffer=(unsigned char*)malloc(blockSize); if (buffer==NULL) { printf("2281: cannot allocate memory\n"); exit(0); } string comando =""; readSize = fread(buffer, 1, blockSize, inFile); bool flagbuilder=(myname=="zsfx.exe")||(myname=="zsfx32.exe"); if (flagbuilder) if (readSize==blockSize) { printf("2290: SFX module seems huge!\n"); exit(0); } if (readSize<=0) { printf("2296: very strange readsize\n"); exit(0); } unsigned char* startblock=memmem(buffer,readSize,g_franzo_start.c_str(),g_franzo_start.size()); if (startblock!=NULL) { /// OK start again from 0, it's a small size after all... unsigned char* endblock=memmem(buffer,readSize,g_franzo_end.c_str(),g_franzo_end.size()); if (endblock!=NULL) { startblock=startblock+g_franzo_start.size()+1; o_offset=(int64_t) (endblock+g_franzo_end.size()+1-&buffer[0])-1; endblock--; if (endblock>startblock) while (startblock++!=endblock) comando+=(char)*startblock; } else { printf("2316: cannot find endblock\n"); exit(0); } } else { printf("\n2317: Maybe this is a renamed %s.exe executable without any .zpaq data?\n",exename.c_str()); exit(0); } fclose(inFile); free(buffer); #if defined(DEBUG) printf("|||%s|||\n",comando.c_str()); #endif string ahahaencrypted=ahahencrypt(comando); return ahahaencrypted; } int Jidac::sfx(string i_thecommands) { bool flagbuilder=(myname=="zsfx.exe")||(myname=="zsfx32.exe"); if (!flagbuilder) { printf("2351: I need to extract\n"); return 1; } myname=getmyname(); // this is the FULL name now printf("Command line : %s\n",i_thecommands.c_str()); if (flagbuilder) if (!fileexists(archive)) { printf("2456: archive does not exists "); printUTF8(archive.c_str()); printf("\n"); return 2; } printf("My name : "); printUTF8(myname.c_str()); printf("\nArchive name : "); printUTF8(archive.c_str()); printf("\nOutput name : "); printUTF8(myoutput.c_str()); printf("\n"); if (myoutput=="") myoutput=archive; string outfile =prendinomefileebasta(myoutput); string percorso =extractfilepath(myoutput); outfile=percorso+outfile+".exe"; if (fileexists(outfile)) { printf("2334: output file exists, abort %s\n",outfile.c_str()); exit(0); } printf("Working on : %s\n",outfile.c_str()); /// Take care of non-latin stuff std::wstring widename=utow(outfile.c_str()); FILE* outFile=_wfopen(widename.c_str(), L"wb" ); if (outFile==NULL) { printf("2017 :CANNOT OPEN outfile %s\n",outfile.c_str()); return 2; } size_t const blockSize = 65536; unsigned char buffer[blockSize]; FILE* inFile = freadopen(myname.c_str()); if (inFile==NULL) { int err=GetLastError(); printf("\n2028: ERR <%s> kind %d\n",myname.c_str(),err); return 2; } size_t readSize; while ((readSize = fread(buffer, 1, blockSize, inFile)) > 0) fwrite(buffer,1,readSize,outFile); fclose(inFile); /// yes, one byte at time. Why? Because some "too smart" compilers can substitute too much /// please note: the strings is already inverted for (unsigned int i=0;i on archive kind %d\n",archive.c_str(),err); return 2; } while ((readSize = fread(buffer, 1, blockSize, inFile)) > 0) fwrite(buffer,1,readSize,outFile); fclose(outFile); /// Just debug stuff printf("SFX written on: %s\n",outfile.c_str()); printf("\n"); int64_t sfxsize =prendidimensionefile(myname.c_str()); int64_t zpaqsize=prendidimensionefile(archive.c_str()); int64_t sfxtotal=prendidimensionefile(outfile.c_str()); printf("SFX module : %19s\n",migliaia(sfxsize)); printf("Block1 : %19s\n",migliaia(g_franzo_start.size())); printf("Command : %19s\n",migliaia(i_thecommands.size())); printf("Block2 : %19s\n",migliaia(g_franzo_end.size())); printf("Start : %s\n",migliaia(sfxsize+g_franzo_start.size()+i_thecommands.size()+g_franzo_end.size())); printf("ZPAQ archive : %19s\n",migliaia(zpaqsize)); printf("Expected : %19s\n",migliaia(sfxsize+zpaqsize+g_franzo_start.size()+g_franzo_end.size()+i_thecommands.size())); printf("Written : %19s\n",migliaia(sfxtotal)); return 0; } zpaqfranz-62.2/ZSFX/zsfx.zpaq000066400000000000000000003267721477324740300161740ustar00rootroot000000000000007kSt1ӌ(zPQ         hXrEߏA/ _Fp?_4_JF;p_4_4_JF; p; p; p; p; p; p; ;p_ Fp_ 4B[3ttc聊* wWrSA,=?:1AQC 8i% :meO7F,k&@rj-i nBIu ,0}p ZT 8+HrhA!~qfX?{. _"\."kwQ_aGǃLneeOfTbF\}Eն!jEz<9|vu$@gt1UسPdTzl}BvJ~Gc4H+]݉;8,w=)8s^(d\21mjVqk4:]i[B2RsS^rTE@V.HlQ|@SCxH'GpG Q_#[Ct2_]Gdyw.̲ V>="W MG )fi吤, [9OJM5ͽ3||Sb ]1„l}@$(7Mq-Z̷nʺXiSh: 3$MI4F:e"~M kg.[ E (VB1܍mp+M3z:e7KY֥;ę ua@\k;Vy SHAw?e[X#DiWOUrQaÓ8O*Hi8'3{ xZX7q+ }-#RWcUq5{^8p-򒡩B3-5eͻ{iilkdvo 3Oc #HMMJXL%d:nHJTd |rve=1GE^~|MA Q7kK%X`?ÈT*N=?G 8rzrK7p0c'  ^LAot-!hc Z}nW2p@n6c3 _Frh%k+$vCЌ0O{K6)Xg Nq~ӽc)챒ң2n*3xpe`趲70GM#&<$\ RjqE1%WNa3 I3)-3uۀD^(~&(`iM% P{n:uT**jZwWykI]e/e V<7q(DUSO.w2pl Y$M|cH7p3t,|=ieªrC8>zL61:Jv#Ir˔G4rCdQM"^q+v뫃b)ӫ(ZGuJ W$-N;;3$PC AN_bL0MqʽdiӋ`En}d.6eeUb4+ᕁ66>,+rt8s=;HOw /#T@p*A TƐp޷ -[fߢ)_w+c D%"4+>>;`B$f0`<=z=ң0swL6qtFg_ٚz|t5O%g=2!S:2e+0(Owֵ/ONO&!_aHmғ+˻ϯDZϣ 4=FF>RzɋN+f6(R%ӱ:S%?ef |G+|2`?+ِwV9SOޖBt.T=WgDOy4ɳ.t$W+isQax,jxh{K%-}xȩv_j(yx0v:Cc/9GAƒѥ0NU9!n f49ށ W܎O*dC^ s|vC͍%u;ʜ5k^>|E |W$5#Jj)FT_QW{-vLsx byn/\k-a{ $xWR!F]7hIz{?K~~$L'd659ޓ&JFH%Z硗MEsYp`s0N\u=o茇z*U+?EE[֠|Rn<Ȯ-+7# 8Vt/;յ5]9ntE$3R 7[pCE^m/c1زYrXX9آM#%UA%"D2XMO_+I|.l;eE#`4 iCax-_ffvLӬ,wdr+(|0 ~\Rm$0t(ȧ܀/ cp]>\#u0:>#&(T0PղAEXO;_yolc93xt|)`#[NqC]yd>Yil!*q I!3O<ڥZQDYg-љ.xf&M4144pWJ]y }}9)%cLuV9ۯY>w\HrR]/,L֒`Tڕ>ᄮ_Dnp̪2CX&[5D>U!dn8ɗur`,ᬞwW5ʳuEE#ٲG|Q=-fU>РM>xb_I%ʇDRyͶ 9J08E")7o/16f3 ;!oD^@uu3 s-M ;zpw nΊS.+V=4fyPR)F2nEv0793H-]yxSH3f=|2(f$m`xMKE@{-@`p,YIYQAw~!Ў;~M;QŠƒeOJʸx|lW862q蕼l3WZ}t~.O<{)NY?Gx}2Q3`f@$eͳRdbl͛>2<նZ1ăM!,N+Y(]>^ds 2;0E)4AJV\= jTtOi(<5JXG=BWN wɜ)n`\/7c ;*ކl+wϑ&.M6FUM" ,| )ؚE #XZZ'B´$KO+QW/y߰6#,MS5Av د!ANP!)O41hj_vI]/O}inOF fIi"k |F4,t-|p2跘iĻB'½O}Q pg>>nfHqh1;-nFէ};Q?y&1Vژx6H}̝&9_zC@0:x[M/eyʈxCHԆ/юoL1H9隒qEM4vH֌&5n@ nBB"X5ٔXԇ=C5m "s1pOTj>l{>17B+cn'Z$E~$Z+G31p\M?1X )@8ӵCսGZ}Azdt*jxHO3Έū%n+ c-%t\E3TigQb ú}](r)xKpF ^߾u޽M lV,9d͐ bm vMq&Uo3!w.N# Yc4<,6') ]XNF!%$sD,ɘɴp Zw jCOaKqƨv, B+@a+Qr*l$"RXEk5ڽHl%웴{Xz C>V,3#2ݳP&)vZdahL1ܓzH_"y`%UtLjXg:T)3.zQUJ؅y-^׬~C?ݎbѽc8F7V3Ɨ$ OZ@)㟱7EWn?dUH$苏 7Ӱ:z[-TwXNI.;ϰJpYAj㏴ djifZkx9qjڝJCiѶ^uolZa.4[ߛGܦ_(b>V h[:FO=ՠ.7"М6XᲥ9]S?辙 ]݊y;yPڌz@)4 #o mJ}u9)!LU7!;Wr^ę0L" R (*P #i`~DHwV#f~l-D3n{UbaL'> S{m2W=&OwC Vo z_q!`ɥ ~=582y2fx4V8*~-p&w)oFtwfA)IJc{8䍀vf09&H <<$5AzKDϣ2̶j>U`A5kYH:o]![ϥ E.Zf7|X &ڄO^?a7؀ \ T;wY훫k(Ӯ1,cVC9M;fjdHeޣ& g"EjF;݈ss>=bÖgƏDvPӋ:6AIC i% tSLZt*[#Hq)LƟЅb;Yz5вuMӮ VuGjQuFRU5C o1E25&(+k|]^}ˏ?ߏ>:݄j,̋4|pд~4-ڷc';$sz] ,f BJaݫL-.aqqW)z"WhK5"עwוXŗhmkQ+[H9^=.ײ-<̑Q钽#8Ikڌ FaY+;<-2dlʿlU o, z^ g CJ)>:tgW[Uvd3Ίc OPdu. {Ee;sR{ ~}y1I7}4l(0I.j0 pEˆ|Bi! lVT:#-&LɭEzWgI?͈t|ܛG- _,"3B鼬.&[O马gi4[˼j+2{bYkOĩJ3d}`D;lCEL;OTtf #.%_Oj]%v6K*'o@'wZ$z^D+B>6cg9!.VJCUR*"3zjX: Mb2ytܗgr4D߲Yd@'{E|`Y5!Xe"3l &KOH{mMJn`+\;346d9o=$* gBm+qϣM°;BH G%GWG 1CR Bb?VXy@]g/{QkӸjdm{ՎJ ) 8!r}P|Tgv-MPgGe t# CJp@ 'Dt7RAui1 [ ZiZcoDێv3d݁K$GO*]^LVz >H]<5J99ERW?UZy G׺cPi2~eD͚R/o$Z"?6w덷E?1\e@ĹGWA!oV3b91m=}DgBT~ a4aflt07r[0b0m^hM~ɿXg"n2uMJ[!,dnS7a@p4nF@ "\>[BZEHH ow_XqQ+>g/ ;!bfC !U\Ttoc?>a #u`-+Xi,j C?Pum' TZtr@BŢJ}Km1*j)N)F )fȱSY֘`~~'XZZɸO@لN4yZ8"~k +H1iqFtȁIP%Q [).=%y򶁝2d{|YżЉŏUh/1Qe:_;5y1&Zc9fJGph{S tH9IP) Ǎ psD{7ngH=>0TgS)ҋI.`/nLKP5y_ $?BEG6~+v}T ϴё%Ob 0~殭^NU 5yz"W fRs쒕L$k9,?S;D {:^\8\ 1ꞻlKf$LEQ8wYmc˨F4ʤd}0Km ]?SG{xoY[ݧnC%dD?g Ygx6P x "+jvQ/pS(0ɝՍa.?F yM_e $l3l(<.|LW&R̓0=>xa RvQ*uMT'%6D|lnHYUי*/Rz"HUD񉹏x>OȗiNb&'ۍ` A 'u K,,Xk0KTzOJdOIiɯ c%9dc<(hPyFsҨ3t"njx,7xA6"1+N zi tR@)F(>kj4eVWg?iqPIc{bu .m R2y Q㕒 [ФϷljչ߆>rB2Wgc7^i hja"۳%x_ӣyHVh-KeQxKzDW{OY2tcYoƿK#=@g{bҒMs^J\me.0ۃGN¨} x'BmXVsC?#:y }3~0x<*Vl$f! jsnV x[ǔA} 7gv ɸ'$UmE P=2ezYcYg^:'Ne{'Β l=AFv8vҪޡIO=PL[z5l@z_&~NmR,4) Sz8ǖKrr R{5as00qjM3V 7K;fϒ5y8/SvSxV:$HIGčތ_Hl?1csV܆$^(kwȼ}/{j8e'ID4" V&|8ж ܫz\rp&atL`c5 ag(s.@E2/}t5$kˍB`zyl&8+BDΜt9'=ayE,D&2ƨÁ;P[Yo6k3L#8$FGz-FȬg҈"O1LR쭭~E r0+vZTݵ7VK\BwSۼb 4hN$3I[]_ ;u7!Twjuh} Nыg.={yE mB3T Jq a/wI_8/,q%Iԃq\kHӁMhau8ߎ"bM5E9q!,cݙTܽ^=~}9_,F{9WD6}ӷHۨtKWQ~H\,$O'Y)s@̔CI_M/+H}hf4JGBatA4ЙM(~I#~P*c 㷩:=җ/ZbX_x "|DQ -18)S>HvMݘ]>s6kz^kuzVʃ bʲp&gۂV6J&E\ɒI^_2F{cW1S #Y_% 鞍 B-?!wOu UsY1kRL%]-mCWT^Ih R]qWp %ˑf)4ǹTP)D| @XR b9GceMhM!=z1*DA=V\y/2,$G!xYMBR-eYs"ٙ@:?a뵔+ʕXz}5P@ˤivūTorʛbk+tA0@,cۦT~{>K|S ;;_*ިs|Pv75ӟҩm58͇T){}*6ly, U _aMm[ɟ@HJ:b[7+я&O0^Z*gsziXJ \#!Oȳ5i2*[ LrĖa+$"t0S K^℉>,f-\u/A8cC\JJG2neUK@ܤ75~!l <+#Zf!A?@|y(i*I}EՂsNސ]}@7隮ٵ}+ƽj}`l@^RmOD]55ՕDfG̣/U[iփ"Ob ٧4΄SR\!Hw! ۔9-a3n/T=z *w,88\3R1xGP%`UBhru f'?l^G?%hg#ͻ{ vzY["L+]ӕ=c'd{tIIJ4"13GMf1e=r+DpS/?ԉ qUpv.b`EMETMZX` ,Kԏɑɲ O;/䏛JbMNVJJU?{^ϑ<=Ca˸*Aʀ]Z+@];X}]-JrouA7&妶/0 Sz`Z#Ջtw}v}=@"o\;b=fqym)>%Si}w׿o"Qܖ0HlUў-G:M. ̦tJ.۵fx~Y) ]S8ң%S 57-ܽv(/,\%(irCI* $Xiֵ-=ȤU@/1MN0TѻL R/4@Kº+͢* whM=yv$=nf/ wWz"^hֱ #WGZ,Äood5«n,ʞi>֩xRW+̦45ekTJ։Ec\]mnlڬ1cv; L<7{#\%L Z.AN]TڣdC^t爷LrI ^uhg(\w@w#rYŔomAse< )z}x4`b%ISҰ;t"m`}0B&~Q" [Wkr z-y-&,1;y })CqnHlNr7zyMd#s%ӫA|!Tv4z[YU@L{LmsTaeE>E C+R+z۟=Vuuj37Nqa/^s @QXx2"9{ uR<|͍>Z=T;Ps,yʗ!꫻!YšLס6+#"dI B`p8 D_◍J7C1Yieh}ӆKFӿ`_-{". g@7$+J5@C<:30 40tƐ@}e7ep[Yڧ5Q=̊UH n Ѐvhc@hDK5Qؼd.~֣%tOXZkۇ6!D|Favԫl)xoGȅ_QH! ]kC-(bE#rbdۛE}ҘRݞt67&}_((2{s1Sc҇ g׊>Mͳ$n0LenP_'bWaz"ϫ XU۽HЊLwd߿ o6"U4 CTJ{{'A 7 D,k@ hԩ=9)끿4)K3-e XFR iɲc@o6qؖ:($Q=\Q};}`bG߸ŨzU`bf6ӊM#<p*4 8,xMb>Yo:0nQ#<-%⬸%4NUC)Éݾx^?lo`%hez=9[nTSظ~kQm]^xhD5'p 0ov|+|0iʌu'ۈ_L̫YH\-#|;-xueu<e4 @bΆ^cx0kRK55 Z0@/>V2㤢YkӷjVf?O 9/fC3va}z#J"jSݭVAwH&WΎ/:ZQG9hg!Ft9>];܃"FqYQ *:98l:ifw8dp,?bnF r;?{?ط#VaOE3QAg@zVCZu9,NCڅa én}sC*P3׉X M 2 8Xu\ը8 o'ꌯK( ȋX˴pDU ?jիK$̀ɘɚ}Y1c{](H0CL]di.^DlHoAf7e~F=A\)[j>8@\|>DG:5 2èR4!]co?3ҔBzT4碭zEwG--libxIla\?Oo< ԍ DZIqo j.f;6ځT(5I9rD50fdّW0JO#$,)&Q )9 ]!os!bZ;\@r@biH/Ը5O{aV X)yƼ@lhRfش$''XI)d[45B-V_YeFp&oe(R<('\^#*g23/:ly Pz2Ttdefm ~0r^;DDk kwYÙ.]= J1گ9x5ҁђоQ@\gv#~K0%Oյ%,_l#Pg cbϗKfOfYWO\sM".ukJ8XHfX툩po]}*cb)Ԍ8蘫w=F>`jgMPӵK<,E6`zxMQx\F /W(Jui2&L<3 ˆOޜ xhTl [e۲d&.?Q ^Daxe|2@\ ˂nWI-*1E}O1$S&xlNm9rǕ71adP!D̄~e e&Vo46җa%g7_v*+eCAB`7&jٞuBϘuD.yʭ;g]hiIf<(YkrJaҍ"LvtMg̾uHdJ@#s&IԵ2 /d4VMT.v3"zp7LD{X߹c?Neaju-OBX蒅y,:A_9}l'yw"+43f\?$X8 \JhM6EZ |܉Aͨht3YeKnM QO ƨ\_R$Jv<3r:$/ެIRO9L5`ݦжȅ[m~mʓ'S<<^#8 a㛉U=+`yuAbHdUۻ$l=Zqwk(InG0" M:^ hXANE>fr dԦVYSRi-ǰ6=cnػzrL"]-BY~/?{aDpl}Wt@g7^σ<1-G÷l{'y}i&Җn\a"!XU#ⱖ_[ۀY#2m,Qp7]t46_z~1o|tOnNTb-Π-2axq-I@eisfS3xOW~ 4Cv'ʉE(ʋdf҃~E܊g3 ͭwi99pimHv2 0W.^특27ەש 3u'?\:jw{FdB1LEw#Z11Gv7{uoL xKfId2 N+,n a!Pu4!f%3d%4Zק`,[JBm-goG8xSQPEDX~ĔF9}k| $4/lP7B$f:s)^":n­&AbKt`揻3%yqxrǩQZs1NURFcNw=6m-xY3f$[v{)b_1l M>hIџydAY:Z9ӵEW?/.'_M3":kin@Pa3ZxL*k)C_8BՏKBQ^P0jb;bjY6GVm~,h99?9h"t]DŽFa2sG=SH s40h. ^%]Zip@SnQWgX(?FSzI. 3䎶R ֻmU,qm*9L?W9\Ş5j8썅ֹJ@Ѝ m=A}0>b2f9ɮBz =FX5@J诲}ez "?eG bYa`8xwX^0B)AP8m8\|(ٳS&o#z1P#Vט30w`x/Wo;BZmGio5+CxO\2zР $ a]_:#8K*2kiFϔDfExܘdj"N/ ;˝vO/y@"+cyAW);; b&!+vKγIePr!X[50Ynn&V6_h mHi TXi:@/*1y#N=1yU*+DCT_Bع7:s!>sɌSGk8Cn> ),&awaujDMP8h|-6iL4a`ZA׈ C-nMsk^<TQ/ eVZV̕}Vi:=,غ>OC3UϽY9Nҽk N4ҙj*$C])zVY,ayk ;rp~gƜjsݟ+C k–ܐ r/wJDWDؓM#* zH~axC#CgҸ䮐H%awWߜܛ~✬"Jr aWCg Xj"( |nC8O:G^u3<|!H]WtgdӺMoUB$i`\v(:IG,YzArUL"C7LL+_!ZI&1%"G s0K,+00[_brtp$$8'obh5c lOQ]'i=2#qha?\盏e!XN Myohk'臩f%B;@V D,:`k}kUZuCw.ICI$g2Os#Y6~%iIqW7ئ7dĨc)IVYdXj_xrڻYCn>,{ϧm塒%]0)G ~B($4#`sä׉:fꏄ:VI$u9؍'7a;lx7)nS+xm5'N٥3k(c@WWt,<{妥E:?~ Z}SӓDI|'d-02km`og,(Ykڏ"\]G9Gl &&b{#Le7?b1=b!x VBi#Hol*?~q4TrǦZth>&72<3b9MA\Q&/vϴ~*/On7`i7;s]H\' iv|n tiJtC3:If=Lp?˪:ٶ* ;LM`=G*g-E9͎ `1EӴA PMi<s5Pt.B.UEz3NO;DچOקzbM-nvjYˤ."ا2K]E*kC35]IٶS+QF時[ÒK-Ӡ;pt܎_Djң_i(rtզOp 3 _ˉ]3z.y W~ ~W$'X;|g2Yb [LB.(bu^YC\岎Psx`5}ݤX7R;&-7xW4o 810zyU֯r]GVH~&16rEO"g 4 #>rdܷmΑ, 1g 52)!K(.KF;[zhK-;Ҿ4Ķ-"~QOZ nG Yz9ca_ )ƿi}) ~]GeEoZ hY@_vO/ [B%9\ u8&Da5:P:Y%KSa`|!97utb?F1*C_&kk"cf$Ȓ$#_{zi(6,L5nuGthRm(~i%YwCjXPCf~ðU NHX[c`b~A0Ja x\OXLomW Q }SfTK&cs3YZmhmZc".LB3;KI!5j]otX Wjj"L rApVA{GYo g}fD/UIm-yb6^Q#" 9!@f0;cF{'/ \L;iF82Df77V9!0WO<͸R3(0CҺ pI.aK{IPHq{O|p2r4ֵ4~GE(T)pCpȼCo!̾b&Ȫ͖rG.'̴[OB/81hf(lP$Eb`^35H('  ?Z$CO^RL]<Dg7 *%sz7ei]]PtSpתA(2Z`ETJwjyMԯf[~/rIe;h \PǵSÿ#9疇iN̸-,I0R@ /^׿jwFΰ^#ndH޽ۭ:(ǽa^4*c1SܲcbZzv>F 6 Ut5Tj&--ShTbby(KU)ܴbQu/| hʴCEK7Y?>C皺֬WhokGB@tѧ Ҽt\COTqp+wX31,OkXRIȼCVpufy;_1hsDδxh;y@rԜ@{'>{q3_/MDZ}Q[-񰚬~=mbvC,|w9vskk1&KdqLhK*^OωI}`[F1`ѫ1 Kj+W|Z*7ߪ/SʮG-EeY!9|qse往4ti19}&޾x1&Oώ5 :YF)i,!k- ŸUo*!Za'F! c i[ZWCg ŘXU1R"7 vS$ƺ՘Wx ְFira|[9bscO/<<ki19:،a)+ZSA7ܐ5fIr<"Hגjbm6+Y-R\ zX[_{DR3̏|>‰kɧA xŹI"'{z pS6  \)J/>\uf48ّQ ֹ#^%LGy7[Kǫ[w5Ng@4RbW@ve*t>ujA Oo[9IrzsS#T,#kgE4e(+ŧWg R[{v<3ytcrO$)fMFD$Yd\{*̘ځ]O+#iɀni!@Ʀ,bQ)3"|*8RIEv*~XoRE"ވ sJׂKyΗκ<'AᘹBmŁt`4dorMFoJ]`]=cdq>hiT㹕6}L\+ hpθ'CX3 VcR_k']*՟?)X|-F%NRR fdPoe3=ǣ2$5mMoo4;zJvr]Xր.ΎZ6kr˱`NWd 5Y 呿Eʈ0Ma|wIB< .gn g5AmVynan$uftYCeI(갊Tͭ hOeQ0. COyڗ~fTO CڏŒA $)|TksHV\\Y Jka{LАvB֦ n4'ԚVnsJ*ڣ5&F €JNlMx(w U˄n30C\b)lMMI}eR61VMnðTe]2c.hU?97[$9nn,!&4,1cu:V*N'e6],iztf<6zw/tγ3Q0!- }\Wϙ-9tYy3@5\I;dҽr2T+J^⎮Zo0$eͦqr@)̈{_0_|j]qzkwV㯉ao/h:~R3fvTQ:wHVdlsh^${<wUa$ATa\ɯ9'WH |@FA*Zl8ioW{wK Sݹ0P~`0\>Xe`/HP0lFu2X( 8i57 'G+-M:>;ċ:݂KĴMտ HMPng)6'M1/iD%ZdLm{FZIJOk4,L6C9V.5v_KbEC P*is9*]g'3\U%1KzYc=0ߜvZ6N4R,XqZ%2 >(іgIR5y) X791qxcЈov%Je;Y%9'=⦷R[I[kN+QDϠ%; w<6 8xs^yLu5JU(2X^EA"zv^Lau/We n怃?>@}wI4i% W":dpSruP@ ;YF?OS/%/h@W.=%&PJ"4 AAZ"֪[rJ]P%@˒.]Y$~j(f.c^+RKcP#_o;p^,5fprm+-'/+Gu'gck sfw395'0vzt?F̣k7zo%4> @Fϯ*m{ ϗa$؉yש1h¬!ڰF$X_27McwΡ8y(rQZA ,.݊NEGM%\ 0ܳwʠEnlWX81J/~YDy;7: dс'Ƿ6OE阌bޞ\&;Ot`KpB@kvr)@̆\+ƜV5TJ~Qn #4X Vo1 |rF~i'Bm a7V%xmkXNòD`E9Wjb1,Q=>YIӍ aJ:܈EOa;CZ*+kl mag B?SeNП,.ek%Ζ89[g_3T,aOO}>\9N0\>弥i' Wv.3iN|xPM}G/<H_ƤXh"gvu|;kGg:53haq$O;`ht0+@F_E?tD tVv뼲z{̰wq27OC8vr O%ĢCYt@2jgDy_nZ .c~%J}˸Jx (v4hiVtFrmj1gYFzdDЮ@oO,ڧ*|w N=祔m_*}`F7F#dA*R!ۥJ͎ _[ jxj_ Sh|V; 䞧⎽?i-!'$]JY&p1EVlsdNs\ uhZ۩p>;dB=?d%~&M&)ʾv$0%HT:惬; q^zyZX'{{Y֛0vItc岾qBj |npWN)G޲'x"Y4yR?MB>e /[M$ #VfuK;Yn1ٳ9<PҗH3/?7-;]# Ͷ{"Jʱy8 8u]!3pP<y1o<cXo*؈j.h6*"(ǖitx` C[D9?w{IZsp ' 2[YjT M0^S(5kso[ $`ف?=)AXx4홱*򻉠 WT/v_(-oZŀ>`j Z>hEڑR>"?ͫe0/ ~&ş-6LF$ǔTB_ɽE=y  [/tDv.ж_+(@t[i9SZv5fʟD@ƼD ySeL3ݛ&RءI.HIP7e0Tz UxϙrȰ Kj;CCk=0. ^)xM [Q ujohGOel"xVTԦpdW ˔aeRua:7Nzj˭ah?*kngL7DgZƕ+ʛQZw3^k]=)al_Q =oR?5wS#d{G>1;ġBJtᔣ24*806UϿiO!ځEx~"At~6k7͖w (.y 꾨;e\zi7az@ 6R(#Wy)95jsRt{%et]Dn5&j_aclָwp?J& r3t<1cvw pW lGh,EtmE쁎*n Mk+욠xd]{~ʡQiߒT^R#s1B_;Xk)OKM`H,3c [ m9\*}dJj~twg}Ю0%*v3Ailմ{4 SdE}@Z@Kٰ< Ű&Yj($TZ#GS)ak;pElJKk]Z dAͲzF㎎F8M?-#_/yUnb}SwvϬj}[΁G9t=DJDVJ ='$ 2^:.C0(,7v|8M>tsգWtV=~^쥰 m[2BA6׼zhc0+Gkģσ?aC5G+:{Je"TgdxCf )1ĦX a{fD@Q) _pk|D9JoT6R3$ʛХ NT " 7=6j|auW T,OOo s?7OƼ>SywMwWɦĨA;XVCk]䃀-%3jmDͰ6(iu%`y3LfGTR)B$D-lUA^ mL q zJcojxM>siM 8rU_8jm9,(S-嬀E?}#?S^C3閯{\@kTa ImP WT@nQ3;Œx#W] Eh#*0SgUNn+i/RB%Æ:( )ַU5R N(s}kO6iuČYcIa"kx~$ m">cr$.vFfZЈ<Ί.8+pLv05d.J(S3o6ɘU>G=϶ aX,mcf;6y݄~Ri/E/sHӲ ;!Ȩ(! Z@:rBPc P7e)l :Ր+Q[`ͪIVo!. Cժ,cy%Րx Jn4cbjHn $KtZu}mNTn['x#jJ$xnRSyNcJnyّ᧘f; VlF/fMG_~>vgZ =#]'ҠpMB\`u~YRl #֞*͖vBP5Ԙz}$l<6F32Wrg*\]u]~dZ(_J Kf[qN"d9/ ~kI=Am:,&~`+^DQ2sl+"Vl-xOX*462e[3h1pv3L\=<,eAbxtv#-M7` SH$=ܻ|LN:"]4ʀM sXt'J4_|G^3[" 0eV1mztEMSA] v҇I,#pӯike=CmACɫcm;&X $w'jv< A{ppGJzEL[2*qs}콈 fmgY5c-R զ2q7 <)dMA(9`: j]0'?kMZEl[fn':vn;&8+*مߎw+%E,suT'M17 H齮zc_Mu9M8jg}FXz M4[1ivHK*2E~"QΥDl#b1 .խB2Cr oNd.ᙹh͍R踼/<GS%]~ We>m8Pk'dW6iG ܉%)!u`f/\=segQp>!zY!3'f c#Y X#{AQbjOzyj]Lع6G~Əm#k'?&%կzR;=@]AH!4o==_~e`ا_6O4#k-(62LEɼZk--0g UV{yeHd*YkKqgJ҆&|9"8C!ئ|6"n@?Bݠf_M}5? Fmnt {}72I֦d~{5&PEa=M]#[PJŽm [ {Nlΐv; &ѶOW/Ba&?Q%$x^X-:r !%|m5K{? (07o u]n=EmFqَW(Xpܣ*2t U_ 4*a:+|IW ]EEX7FN}Կn'ta)S7$j[&w+KN *p"w+UǴ]@zHMdV䯁i(g:$ksJ5#PIc~L+Pk{Xd*8 r<|g;ӓPkNi{g6-6\4cQ rΩ;mfbE=$/% h |i)ɚTME7J۟JHϫ)2@^œDrޢSQӓ7F 2@(iQ-c'`+J XRhB f>"׬V,THփ:O_ jk%sb4tY ̀hp\E@$ &_qUdl#4Y cLD"z( 1نgZ N/$;a;Ź޼n}e6B]*2F1>fKY#$Kx«)'9YϷZ: AWE[얦̣*a#bA08]iײ8Jt4#-"J6uLW״nǻ2X\P{^-Q m2HV7'7.?SUd kuh[1f^OM*wi2h~j*J9ۯVFsԎubgR8K^MFSOAe@6@(u,rJp9G zDUB#ӵ?UM\RbVIwCkm"wG?(c& bUS9 >z`%M"TOh/{Y"*y1 \N3yӹ(X*ꡣ|UF[;Y@#v ]kIW4A4hcgՃ-ѓfIBj=P/4 M5kלnZ5smKQDov s5*bc-om(Mp/€8V -(DkKHiR/}ĖM+/yD'R .l+IɄ~LxT$NbeTK#N,߷r8ņrn5#*%M-K bUZeEjIR<@<]n26)ovĿY8qLª888sǬ/&JUlP~ѽ\/ІMݚgYB)БVK.K&z9}G3M?{tOL^*(9t\%.ٞ03U W= @hHR=&n).ЬN'q#+IZ׬$8@mo;}*M`u!ugwIBjİ\{9lWCS!z"l%ufs~~yI6/d 6_"!zNdp-H;j hžh-tbgK M+U=M*rU͗[#>.uv`*o3 Qi\2Sd!mÒ"Ql:vάiгy;ac{o'zL}mnk}c Î h6ž[+[[qex-2Eb8pAӉ;4ih ͌VJӅ[Pvdh$﴿ٯ*U`;\ltr@斾hz7vkYpá9xD*ښyLc{*6.H°#LDK@-q+y ~H|tv~f66mmEJ4}ϳ|x65 9Xi3@n\NE=үLO Xk-@҇o6 ::uKXR4GHpzy(;{WAr?D{WHi@Oe=a7LM-)@2N!eSv˽/&mXweW~jf, 0(A\Xa[IDLdn>~ 1z2r19 V7ZLQ>I'iaþ;T_ؖ7vNZ@MYIC ~Ő)ks±X{+UH0B*c*ni5B}@BO4W1N:H$8,PBmiƕ/F&b4Hiͤ$*%!:4j~Jh:tSK+3s\"pHql?Y(}:a5ˌUVugQpca4JKlKwXՍ_iuilb!Lq(q9ۜDJϔ j 9Ch Y.!ׄN{ `T ~zPqn sD>l2at LsJ)ϳC* hKsLͽ9"hf?g!;gTk/Ov q..[eF$$QB898*H,MmgLw6kf؎Boqi8;"(K0cr| GTtFZDJSY"Eh~6^LTs_{ 2e^]ȗ3=q43inD3O[$-az@c{\݄ŹD6 BUkV6Ј2afK0ͦ$S1)u{z%}o"H 1O0(SfSpFD歨"Jmhy:Nꋿ/5$tk~U41NmJg vyik5g3QЫ ;>q_l/aR'y:G׈aߵ^T~Нn@X8 =!M;'#ga88aO%UWu4 .gRN:o7̱7V`a-;C BifvG5n~yH?A{/ok#w(z`DAtKH0%՗ƻ{p[%FP*Hb7LyƌQ!c ad!s-d C\#F wޡnSzfo_*CLR:|Í u-rVƧxg&S7U0L e9m73(#]8yltx伀; u`F2i]-of"8x{ᅫsl޸#|VNupWoU `}@>V^i5:rDxHh'CunT\-s`m uY\eܛ;Į .ۋh*WeA^X3T SD B r =lB[,~ab')9_G}pL5|5CPRwYa?qʮma C6eH|a+'s#dkR;drIhuIx-WsfViCGuP )KS8aٿ%>ӥG*1\@G?ƃh DD*:?'/ǭ,M%,f5f}Xi8SU7{"1V[hR Y7FODXv; V }}]a1DG oMc#wGЗd|O::95)'~qT yt[If܋x9yVTS)~#0(CzSUZ:!J;ḣsDžcW3kB3f-b \Fʦ^ٺ4mȵХXfFras;HqSyetk<hJ.ׄ dJ?W<3U7hE^_e#|kݬՆswu+NItsK[J bF556-$M8)si7 (Ժc?5D"] $M*Dij ;e(.3d{CtHp hmM1OO7{_I?8o>#Mgr҄ P A*$TpL]w1uw ULG Dފ!w|{XzapUcw=PK#W0_ ͊jW_9f$sJVF?s?},$ @p;RMK# __3GZUf1\{(RȘvOlCuB2s~ N snSt} j.ZwK{44zOm57+*1lT|ƀL _EJlۖmMQGə7}C9G+]TIU háB,t4db_tĨjI-ꃔ7n\gc@כu6on"fbn#Q4~*DMټ*.ƱT_FI9] 0(ؖ1D L,r!S*E^heژ/%¶4˒_Sq1L Lr͉}?Ոµ$S>X2,xR?'H&Fn pܗڴx" ?Qz0z;jF6Q LQoՎܟڽV^Fކ_Ծ sfglkCZk"_e~ȱ)'=zM4OB gWBUGKCTonQhK=0@uMqCy5dFfv$~אpQZAlX)Ss7e ŜT#bMwl 2(_ ɢM IIވF.W-4[|8tȝlz~jfKqCt*]:6zIu&.d]2tnʵUgƽN/=-:$ '+8[U)~+N+HH~C鿤[gIƊf\kZBfZ!O:W^yk>(hю9OҒ &X,593F34;fUz1 *b:., ^ n+z CԵi4#[n݊DI!=amJD)mXaV\8NFC OکG&bC Zq%YRy"x6m<(!)J2O@tO'πRETv[ g#L 5_=DkkT.13uWR \7@tڪzj: TH[B-Q0 t ؾoHQ;_Ԉy+6s2|wusy%𙹴[-b%Yҽ Y'Ay6/Wl:Zd196H!VD`ڔHK+(j~ޗsAfȳhr 9qP^J;u&q˜jg\|I4bb]%C'MkxS7תь̍~-uHG#q'Q{֞6 ?\{nfUn~aG@DDqMtCL }7KNzQ]}jl͵aŻS0L3?S'񻹍5 ??, o ob%~j3f>f[zuuFp5r'$d*o.ip}. ^dirt5e,\ e%b(qyC#^']=CTkS CRF1TB;^b+|>?V 6O'CI{E@{A1~E9bJ *rm~̄Z]A\4!ff C-IN,KI#XEA^~_}wZn]VW֝TzLA}LRIl*Wʮ@{JV9dH&TQ:ۙJQBXZ˳ËrLd bRHf Y +:f:_Ul ɍoݐ[ 6դ<$]Aѕl_I'߾ ^/ qGu,JXu E|G[2f=BRM*#kUKY SpW U0üfZv4R;ʇB ٷM%X*ok@BBӻbܡȔ %C(V ϱp5I㎼Eٖ5EVeL) e~w-!;x:ɰ:zi#/\y &Ző̚BU W/ M>x3PK`Iw+"}"*5܊yk\#\'JN~R$͐8BN}9Γb£3"ߌ3S^ +DU| ^tf jsͱ=EssF:+,`+SrnAp ?18y\OV-%<ɸ++4=GՖܰ $ՕL?9" i#e EX5-¾sYke.IXI s-:Vڍ aZ/@jH-8?Ncɽ)S*82QhQZf`+4He'a$}*/WԢKX'ے锋JaH?eP9̇f݆ }2J ?X%s\FZ.m,lZGxυ#<GVBY,BV=Ldς]ex2&ʑ/c˨nDKt-ޖ^׺,ٴEjoژFQ^j-3ga{0ds=3`|(IL 1E+kwDu^2`ݒnf}R2G(cBdJ u}\g#ړQzV#oUCSUgJ;IR%wcHk ֚A0-go:՘^1a1N}t3F,,c]WK1ga^G2v6MqٛsH%snBBE -EEtGjF/1IÌ&nG|bID(T@pa Ӹ$^~N>csS޲)hF-OKc!ް(.XNqi腑=̇{/|o$$@Y]`> \H@׼Cz썹tAy=xb"7)g~Ŏљ_r+^ng)IQ( q)ns@ٜ^hs/%Րk5df0W0֓]_wzNM3EA}0\PfBs+72 C,m4mRks @mj|FBj]Iz1qW,lJqs{.ل޳A۱d U._Q"Ra'{t՗)+˫9,c4;tJ$0\u@;hzBtX [g ^0 pFp-k,;Kg|5Y<'O򰡨 Hi~-ɩUېڿūϤeGTSStNJ`lq1,zN;',gffPio L@uPDfljׁ[:QBlwTndM1E$ѳ=WSrjND@bYc]*^toHyŰnH2(ddM=bT`fBUdJfIAsQYzd*^z";K ~ Wͥzm-Atwjf0 Dܟ<ԟ'/^a4d F|{a V|:z~,jX3:؉o5SEsvվB&bC:}h 7ȸ_G#]n`Ł<:6`sw֟Ie?0 qCX:/_TVъفn [(3>0p {GB%vu/Z/Ya]b~sK| D^6Aз|5,dSz" s8{RZl4eZV9@ܗv䥙mNSeAAf)Oe?0_IUvf e~9Lߎ]q~<e'C26Mk6̓e 7ʬmcjٵ^ ɝfXLXgVĚD?=Z|VVQTGy=)7tk#os)HxRwВ}uJj~XVQ$ޛWs{ ~TX5(Yz`q(i\Av}T)vJ5'uR}$` f'u1x17>Q:'?)_Lٮ9fTcаyW Γ KӒ.]VdR%bɺ {[6f7f G\xdR?ɖ9VD>~e rYZPqZ1wI!Wasd$Oҷ$Ǖ CN3NN_Tn,:f4GC)+ cœ] :*iɺO mM:*9\O7z4*oLTe^&ZԒD(H[C͸Y0 E{B>oT-FBuӋHZu~10ṩ:e5nVחL\\m@H=WȻo8%{ i6H'i6@'?˙RG?JJU:' )zr]$~EQq&@?DXθ;1g1JlJB)U5c椚:-б_4+NnPdžgM{X ԃt=u5cR<0UeVjTZCw7rt۽xtl™*IbPeǏpyrJ "Gƒ"8fi W?u W2K.fQ"z PtO8=,lt׻3tC[g'0jP3_͐4>ҚVݚjv !\~ ~gkǰ(Wt]')E^"l"d\jO&) $Cc"|O4KŵJrBL_D1EYivMn;Ec ٨>>#P %Ujj0XopV0*_fr2|d9*_ r丠bxe"it63֌M_b@NQ<}EBl#8nUۄIJCZZcᾰ4aZp=aDO<}w8(v$o<Խ2"(!4ӵӌc@ g[ ~5! " '^*yC ;6Ra Zc Fk8)޽[- v:4Z&$:IC࣒Q87jqb覿r@tu!43%0쮠 n@mTa&Eʫ43X(vТv1ڧn#zqJdbDO'LFbR,Vy|B}K5\gq?TgT's=݉8|W'vN8nPIzX % 2gp`$Zddp?k֔ceA@o@Gr:S65} Կ&|TA'/|4Uֻ1/iGʺgiȏHCE&QD 2S:8/aܰ^QL믾6pHn/[!~x1ͽ[}RaobpOSfG^d\][(}WL/vR rg Tbxm1I LQvc]w+uHnMq_"{ ]b̪r'ڮ*7N?7َD)n 74>Ϯ"V$)t$<Ҏp3Hq$7#yW0?$T|~)4'M^-)"AQN$}Eh3̭r%FBu/@!,+Rrf:]+u$q\pZ@f2/ csz?wu9g.Qi$z^<\jS(Y%.hA%q"Q lB;cO"]{LNo(T XT_@?u7Z J$G=!5;͐O`ȏu{} hP탃GQ֬Uza +uj[ fٚnbL]I輮dff{ԧ4f"IF 32|Wd9*B3S C~z:5<Ɖ>ST_EeE呇@gNX*$ncghjw)TIhP'F>}ɵn&&NYiHDLΠ O?`cTMHo\9{#0=XJq{\d[3BfXw-(=0? e!Z%y4/kU*R %MPAz*@#wb>TA>j6cuZъc.Ii?{B`M-1j-ŭ y8%3 Ƈ%>+o9V=epٚn>޵ QSPZ[R۱'ۭVE]tB!R/#@Q6a<$"fw\ZgOMpc@MϾsڦe]BpyY'Ag,ٗKL_}VX7e^?w&"q UOH#-⩅J>*ګs$8~1%yrL|ov"\|ZqYZѢm<: JVw˯}(N,u" [EO;{6%f$2l5=>R ֕xhaW6QoL בj CܚKf;2kP}iḓ&DO/x/Rx=UHx%iBu g6HSAR r"I !n ϑ03Vw@^)YZ>0m=,/l#CCNLkZPB4e@N )T], ޯ[ڱnFG0oS=^?Ubʢ,ۻR}ЏbE'nx߉#9Tﻮv,x{)""AMGgaۯdRm U^s<ȃ˃E)<]@Нa]6* 2K0.?rUSag"`wIEᇄMi-C4!9X\aD~ev5} %\<X vZ<@2nsILb5\`lHTMˁn`K+/wC;TmOpђHO:%(c},N_V-.M$aJӣ-טrD97[`+łyM\K:|^]Z<. J1O}s-Ǹ*E$]uw@\}*e[qpXz -ֺgOŨ{J&2D]@~N/ؼvVqO"Q6zA;AhD"ݸ/a$wu 1AfF|6Xo[0Cͨ .vWNNBB835QZ7ܽl҂|>$@J(*i۴Ao2_i M ,7zӊqbQM drkLuЗw1ou^6L=4 JNAzMg,3ޤv[V+Ӌl_akuGOQ-m/İ#Xx"f˜T8t} 1gEG9 YVTCuV5Dt4u!z. 0ݰ*a[Y Z泌]^ O9>5!Ru'K5ѐ.P>.aۃ93^W+Ud@8Pt%9>Zô[t Cz-z:, 33,z d)}@%8|kI;eiQy2[)+PY]L!-"~|fiw|;Y"0ܚJcKw %()Sj0g͆Z2e¨D6mJ%I6A|>u`~nuEaVR&?*@bu\<# +ˌgIŚ}0' f]OgeWKˀ=_|Z?1BlO}vfd'J=mf(Ko◈iańW{O0JT:n.c&mdFps/JRr n"Q/9GrD~&C yۯc1d6iqxؽF$2SNG`A(A&{r-zp8ȘҕlF>'dT{rE`2Pn&h_dуZ-$ m*n澵Q77:y;"Pj1xUE;n=ęBCi ׺硆& L5Һo|B:;+U΋BO*t7^ Uø1Hț}2mZ`Ik^ Ta*iV^\!/\2q #*^wdN$QfՑ^cqH^Q%vş1hӣ66bG?ӧ9kv s,1^Y^NRǟ":d2Ar4Ơ*_T4ˀz3}Dah0w1$:ťpdcQ">!*r.кn8.ToI1 [:І0.Ԫnp >hI[AdqXC0GW̍7 Ne+!.LbH +E|Loz1@͝^$i[qypxLjpޙ۲&@:WV>/u2Wy~AC5! Mf̙/5?_bIxNG`XEٹW6=% sٝY0%`VZGqK/U *LH e;+E*elI{kK ɫRJd |kf 6W6 ;Κ[A1 *֘}/`7q c%밗Sɰ5u4H5*a*̭ ;7Ur "[vP9ihۯ;(IƻY;$}m9]R ~XQ84~T8YH~}?̯Qȸ/Gu 4z,ǁ+J '>*}'8g~% f;UN70-_X*H[USGPh67 riy g Nd4HܤT \O1[bF4puu$?W,ntctY5p'.Y`YCf\g[z*쏝>?מi۫H\X|CUv,W"fHU*4{c͠ƕ^|X+sm4/"OB~dDl- i{P3@]bBH|vX')^QFS(Yc[ӶM*d%~,v5{*mTUw}?pl5#!8l@;R{YҐ1vn{1OQC(Lf r~ bPkQWm_|W0bG8L"/qCYHϊw7-1Np+:'ؒY1-BcҺY,Fnxs;/;gJ1>9e] xIq|Z1퓈Bn Dr LWH+2hQ2'y7>뢝t<쇌Ҙ4瀁&3d݃nlY*]+argkNtvlGћy$dcnC:);7h{)ˋϯ@& {a2vv5'֫ 9<+%^qtgyd,3/e$A#&f$k\w !w B4w,zb8$+-dT er%L-_,NM`jQ?*qM*䖰D.JtE֡)ނp3JA: -&TCsvOteERrʆqȥ`ib`Åv^5h/.fӜi [;E!AlQ_ޠqh!:>֕&-ҋ>ҀNE@lEia1uk`3Kr2La?P`?IsĬJYω!}"ߵ$62N^0+}`)$^0{,j+QI9]E++)i у6;5LB~p -M"\+=k FE>ǝˆKU_@Cz!ݠ@D|Y4DQnu}:W0L_t3)5hSꉓt$F>pAr&?萢/u-Q[ &z5^MMc¯|3 "ǿ$^A&==ta~H8/MݠQR:㹆  0' Ш0t4+b SJUYf TP84*4@]bn3EZE`~[6Q2TD+ h9S9>Qd廌>ˈЇCu\,蛱̡[UT8t:Q_NʠAQN0.Y5~Qз2-*",#m]k O F}/Ҁ TfY׍]!-$,̡van`ձ)T83Ow4f.( !?KY|CraREƎ.bS.C MJs96<᥯I1hG'2n 3B+W5:l`{@_f.\3[ u 8 gLxP˛6)F*)>t|M#ܰu~8F5pr%מRt叢*@"u@F&)谭,U˗Ne~ӛ94}er} R5Wb`R#gٷӢ#`i2?pMA'XA,a.^%_g3O?!V&c2vg6_DTJ~hku-51G>3`OzJe}"q7ѩh5].cEZޥ :\w+ߜH3τPx\imɟjH`]({.Qz1Qbsq QހU Eap^u ʣv|Tʼ#)5A"cDb,]d8{>෰J?cl0p~4Z$7uCcQtb!9P;lb2Td*! O85Ń5mIŨe&q{ ֧kɀMf` ZR j=ՖR h~4U7,bssgkwJ4.84 /K ȀbA|k~*rQϒ68yY,DzOt~q믁8~_̓{7GVBJv89&Ż]`!К|"ZMT_@F(q$rʔ),1K\C[rcG7Za0E㒘&E`8;\׊cķ̓ MkX\UgUnx,STN+, qi:ʐ !LpU}H;2SIHFMgGfGKp w^"7ִmndTv i!( _g bs榼4;4.7U>l:s+[9 Lp}<53Ё0)40>t'Ԉ24 5 q6"o[FƷ&K%v:fEX:KC9u8.#'"[%AG\EӸ΂3+^} uwpޔ*s\ҮyW龌0Voag jm?tZ! @5]5&k`0ą,WZ|e?Q#`|Qś>ɧ#إnZ-U$,پLn[ .kX5XOv^I.旈]kV I^3& mI1#;=~%HY_ktCpH|r8Ơ^ Y;i x!f  5s@!Lh^7%U3Kd^I0$5q΅.( -ͧ^MSKhs 2w(lM8O۬ gC c{ˇ/2P wӥ|++gԍquQk`vo$L<6-^a˯!$ jGE I+;nI`8vdpZ U.D8ɿǐ9b¶ushԿp9As$hlC]>#) i5,J?[ꡝ7z #eݭRqS>+ v9.fu O=Vmo3j  ,Gu:ҞOASmla( ֡js&2s=}&QS/Z'o a:!zA%N1 #\vaօื+7hݙ.h]QK h~ď?ig(ec ׫dp"&ah /,HIQ'ZR$( hLkV=j7s+&ikRqt֟Y5\oEV[0Ö -䉸-ܫ8 WxA42 E=T1^<`26e'xBhRYۛ|y l=60V<&|,gfU]e mʢO[NDJxB%~aAq;1૯7emDb5>$$[OXN;NNSO,x*ǝz|^{Ԏhpẃk E^ilD$# R,y4<" B#;R"T}?Sy(88Ad¼mGC2 ;;c'gnLCVj,|nKiz[K/JYݣ|XOL ݎ<$z9$ިH^/m%qX0#dAt.l6@@;0& WvQ}p*.ɔHj){pCk.Ÿ]j)'Xt*A( izX^]=MEF睍{b B^zX*CFbF7OU쯹nc?5a-B=l4 A2%`s|qѰzYߴ_(JM VQ}w Vz$s0㟊9hXIeʃN7f9mBjO6MRDx)0vQ'ihndB})=rx2uЍݕ-!&T* y,o8JN)&1DP ũ/(?:é :eTM^"s%WJe{hⴤF,C!0AqT =:䇉5 gq)6~Wf? ^_D\JT'1%xܓR2Ō' r ?Z9KRs|nɯ ҮY'Qӧƅn:;_QT2["lE)\U%B/D]!&uh@xq]壁ijz 3(}#CLZMXԚ]WVZlﲼKd|_" =t#])Y/#nN2TIaSwX^j  #"FPSe%޵"+:*<; ֊0_YТ<; e #vn>7iB`f ilMwퟏF[:_ AoAk&0^ݴ"QtP5ToH3]̚yF|.,NDջR[ȗ;Dlr/xyA7~sM5[debV3_/٤9OK~RH| P&6ɽ@VpiV&4H3R(:öNrxUwA{ۓR}Yq+Gs#kRU-mh@L68H,?>3a_Lʙo8 {X(%zҏWOA<~7B$e]Zwi(bZQ]1 [mv2Y{]]kKA ^ CFV;$ـesBg8 AcpPev6)4Z5=wHMM!!8Xaܳ4G zU .myb: }c Pͦ'=6̷^6e iDl,NacJna33 *6l]*i*AG'irG+j zP F@遹ݬHšG01fT[~PفgX& vvǼN&V\M'jMɩ:'[$nj6]z!c͇C Qts鳿Ur}?pͅx1PbR7nWoޡ*wv%;G@MZGbnV_RH'opkD8S{9G'y{ i\'Rz'ٞN'VH^B; suP Z-5G!|곕 \cޟgKWRD)$qI;0+*W|rdh4O7o򛢈"]}{J$۱4ZK h>p7|*@u䃯kJRK8 Tж#mmpeX07NSQO޸*B8oPi;Rʰ2kFK1ec#Q.=9 9+% ʔTM8L^{leuF#V(_]|8o$VY';B=hE'a5X~ DGȿ|f !P֛l;d`~2h '^ClLs(R~[ʢyͿIu>i)́erpWגFM1?2]#RRnp•lMa݌"%[cۇzxg| aOֶɘ3: +oIAP§O=ݍ-lhRk cԓKB?fнexA]i4FST,m|eGbT.v7 tJ2x=?╭D\҄^1%%1?V91 hL5ѴAŴts!÷P%<[irsC9uZ-3ٚ=:r28f(]lq{䅟mЫȁ1Xqx1Y,ͳ`!mS( <J?^ cf”G?ױxK$5Sر4BOގ6j]Y ;ظbjw5_~ȥU׺!2~u.aaή uAv]A%k"8 `s"+r`h? [Y6k-1w-Iax6/Lw2 V-}̵Їt:Єmgz ;*D>^zGGHݹ wum39җ+͆Hq;SƔJb^2W`@\Zc9(rhX:]Cue$E*;hЗU#FГ~6Alb՘IuEan5\"x/:s&V#_GxS[l,*5#ϙuWeLmyKTaFPSi\#56n/T֞'hVMwFcyܫ}0Im%'\xK]JЖ̽*wQayZXUpiPmnz[|:L)6HmlqJ>.=]GITEUopt:Me}g$z2.BiacVKQRxwVN}<b$Xs/Yw̄Y)OKbc'͒o+-TzQr H&$$L$Y@NIßCu_?ҙ*>h+b $Yd=>u̢_`Vhm |x b}\2LdU4h*0zID>dcgu*g$MI)x-] %BgE0$@`"3AgV܍/ Z21Cym*a71lKP.A?>fZ wI|svqT#-[F}NT罿 tt毯7J ЮK-,d27uV,hZe޼vk/EEZIPƥ rU邃6~UM"Wж[i}xVq61zX$oKM9 p&'N-f[Z:$IFV%mDfNsshC8޷6]8BCZT}/jy~d 2KFZ=ö9`-ΰⴡܪ$adO6u ERɡ B]g'802>5ܬ#KH p֘J]P}' ѣ4?Xi0('5FDӏ7㧊,. 17 7`J;vՋdߔLz RCLdD2xʧeg؄ת"5 3救sӼ,İTץAE)kzS^Lr]ZS#m3'f ^.j("NG K}5 h"rt"|/;~Žgy5B#R/ؑЏ~xQxri()8k )Y ;FAü.(=W녳G6J^֜e]ī6fʜBD2YwR- )SȻx ,ř!^+g?Y m %dw流߈!(+{!ERSm*:vC?ŇhsỵŒfs9dELOn,=/)"l`3WT5r}{z4 T^;GKncp69WxRp| :;d}@WȲ*P'^b{fFxsb zapW|0"BGXB1fZ;'!4\[6}['pAOյ+4 -_ȏܽ=sOyD2@tPaQAd^Q!,d\[ -dt!J=;gEPp7mE q/`(9$U[@^d0+ŏo)ƢM)W.C!ifGZBC&SP:HtG=,J^D>Nzygfo 1LQST(6#@ǑD&,4OmisZ(jG]>r`:N/-)eU4*xIT(K(!`|w4]Ah?[&,djz.UĂ3-^LI 3I{VzFekINkO $y79^xJIXsJ s>>05<˄ 3;]ogE fix8n"EÅqX..YyNQ4DzYf!zn{DdnȎ%ٚ}jwPjdVOZ]Δ"ehl- )d,~c))㤠a&CĆf{Ξ#) f[v3!H@TrtH)~ڿW=3#KUy ^RAg^HaRӸsw4JvSf2&_x0;?,'5;f jfRZ .3!E_ov8®fϢ^@B ҴAG Keʃ81:rDjl\iU${O\8GoV M(fHkβߗCR LYexT#dss%0^<~].l+5(s/_i}Y&p/K']]# (8,K&˷4DGLԠccDj!+M c@Q,6֦`HDnc$;XI܍8QPKD:N=ěwpBOLnOaQ܄6wWIMrҬ\hԷ5rjCi5V`͕M$-KxiC*`crMBr8ZZ`1k"L0lpԛUPSU}o"dd&S +\4^nc/b%[$ڍs0F/9},.T-I}{?/LMK o/\DkSVÆ:Lr÷Y0eﲁWH}x9b|͋Vs +Uƹ.O:H3Bȏ+ط"$}!fHl/wNsp`Ƅ"ocPr% 6AxI+ߨЗ[]9IZ8ү仰%W]&Ls#"D؜ &z ,ٕ[TcEz/' z%5S\Nl977KoVhԛ*"#.h 7{#86bx)k*FYv}y T*mzeS1*>o`eٔVfp+z.AbwT.[v߃%npHCv'z|\&rm$`{õw@)μ,jA! :?؈{=-_"[ G^OnDAC=\Lp -#]WNu`;›<("O< Q/O\@T(5;gᵊQ,/_3j *ݷvjb޹ ]& O}e1' k"y3bJfAR ;w,D1;kx9迦%SHk*; Sð4At#Q Y2~nÉfPlkUdN+ZZD.w .JIkeOo.v$.n35hSLY^vn.u@-9PdgJ&%Sb#tٮMdMx |B)MEk$F>1*=o _>x6࠮f3K*:I$>;&ZElպUB!bĊddiI 5 0e:LY+.q+zO\МAti;[>mTwKB4Ք[SĬ Jy):y yфŠR5kb%? /|pTi5u'=z@(^`![Q`JFCkq9LbـfVVlgʴsQ+ǤP{Cf^]҅!H z$_s죣C@zF|qUK|QNTZ]#c%b5ķ^>8/&rVؗkgqxJ/G7F $Vc.TõEp ]FЎ ew+͚*,6wsP/YhX$yFWgPIc'fgYJ*vJv!-q\CꟅh9络& dxYaez 5u^xxƦ . c:qM\.ԜyaW9j ivZ2|j|#=?IyVv4F,8Zh̍oСT)=çAl^H G̀hNޔ yݠemU7Fi@N/e@Q}X,faڨfW:}<+T+L/N-.v -W4etpxI}?@,;B5k`f oc6~g3\AsGיH\9gO88EAjX7 a҆JNW`au 4=MU{ xQ+||#lO ܾh 7 YS%{rzr\r=|=DHM!/jkOZ-Pga%P;!$xS.[DwRM =n !l]˫fSzd;w, ؝I.xIUa^-qzJ"+z[Qna h 82Mu7h^xRn3z$gmFpZmw"˂N+$O,u\P5ؘMZ̗F9dK_w/NOtR'%Z]5\Kf,揦i'2Ym7MF,,'^]2$(W"xHfD{Za#bx;t=AE ^ks}00Nzf6-pc5P*R%lK( t{G;U&ViAG.Li,gn=uq!,&]ʗ!9;bnZ=lŏ`eN`7z x{wj|JNEé5H)A-v-IOT(0UslIׄ$9>.&Jm(l1]0[x^tHYZbPU''OOS._uxk5C"ƝKWySFnv73>vz"9' Fg3+Ev6t%gn/vMOiZE"ؾjЅq'3D GlUhEVA| wxʞM;쫷?w?mԅOONv3Ћr{3wtiѤFX#<^ì6b?rO!b? Rv'X2] σS@R릈jPz60?_4œY=dU0!y״^ȼlztbp?Y`Qk>Z7";%&7+9iά?+Aoո{i!*eF6To4塠eT1'!u|{!!WDmPQW/pn`MSխe@oPHF= i|#E ėsN\-u3{V>sYQ,1d,;}%5|$ivgWRHT[k׀w$:[=GMąE(M;jlo\Dd ^N`pȬH 5N)4Wy;Ek@_]) IΟ]rWfÿwYŵ'y$лczBM&-ew,(jDQHt%,n|q0bvkKTw23wh_xd$1!= Feњ)K).ȕ乄Js`ڣ] 7Y!߆ [W(,9 ,k#*4^'0_(j o^N@` )gj@32n?ØY ;q{ C֬@n7c,"v/;Gu)6Ojo<]93}e ;I֎a.y~bv05TLa<_<-t!_QJ*?Gf_>OSscoPM !/䣉ʼn4;25pC5oᕀ? q7z!p5эP<'MrAa' ` š7Iڳy,ҳv9p d3z&N[aLrIiUNJה@,[ϲ]^1"l?0[qG{,i6?yſU ?rh [I@ *:S+&d*Tm$|%MBڤ 4"(rQӀTcܫ|Ĕ1/ϼ1D/dʘ7_h *8 B:>\y\}DH0;@'rgq2F pʓ:22h6 qL67sQK&hY]lCpfQ%w |;< p`dg윺 Xir\81z:&Tכ2'6 Hq^nכnMB z@_ El3BkFU›hce)$窖~<|&+]HE#Ͽ˘X *ÈT`8H#I[9]97 ?9<0ϕ_OvXɆPvJN(y1*?~z-!@`tl-q&]H:żAבADEo\G,OI2gMghQOqC?V n:]!_f$"Mҍ`rmq\ddHUGܲIbz;yAgjV_>XUqhXߒ^iMu(2rj!\JRZf#Jq[h ERW8$}V=vO4_gr/3:sL܏u7 a 8\Qn=%/=tXYA=%aC|}0%ijSn+"N! TW-4ؾs|… Y1z ā-p_pmȯRd$-_iJ]c w u_-Nt`#̚WUp붱%Y#_)$)HVꊕo!x/YsS[/|~ >ہDa4]1\] 4/sg5:i ( y:(!8Nzȑ=E=:vBF#}dEK?\l2`<44.T^^tY.%* lZ$P*fye2s ?v^C otrqi%YN@2?oh5A6HvNS}qU7gjqW=3(3BX}r{,{9|?i:eQy*'гM{xH9KǪv0@T21|wF#yyd`7&o.6991pŻ.8ad&}~9r!#kHg6-KI 1lR_ӎ^12 BOzJC} z 3N qh:UzN) F6 I).,\\b%NɄ?)rEmw*V0T)ҺUEJ×3/>hi wTTpެ[ dևϽCHq;do+_mՅRahfo"J_ݐ-k~MZl{"0yDrLrxr,]O\qHi54*Q">/(DŽ{g߶%,Q*'{ eUz&Sp⏾yaQ@xx(x :ɖ#4f~h=,4c|)%PBpPyz23Zz|[J]k3g#u$RB?-ߢAZ=V`r`=Lr !1D1/y΂w4 F !q~$HF-K#m/; +iMhx(8&,h;6ݠtbe+ BNer󓀣%?RM~X5#ǰ\@KN bEL6-mzB!p^EdAD AC0Q2s!1:YBtړҵ@-Vc طb6hN4:;j/Ɔ )rn> ڕJK)i'"QZr}t^+ԒyTC7=֡p*-eGoESAVa&WDb!ۢ-:%1Xvn֖ =6hlo."WzJ+\0{r[!cE/m0| 4R3ql wL@raɀpiL9#;1SxE|U"uփ!ڕ^XOv]A;Fg[9"C4z/=U?}|3E?u!dgKk4_h߂3^Z_*.e/dagFЅD$I%_}E-E11]%\VM'Ean]K Rk-725dr³glSaۺGAQ%/T}i{yB1IҏUEahogu:C6[?/S[\r1κ/v)Ȃ7AtC9EhG/@`J[@Hz%|TBnRF'ʎw b?ف|p"8‰~;#tbA؆8j[>{Ohut`!J?}NPxh Oa u yd48!k[HT~,袳9ΫGޟԳQjEx47ir:࿠sz9?Hrp2,b{$v*6CY,CO5ER?__Av.~ S .ot{jjZfN0ȓ`4L={jLВYh\#Nz&NI }Gk,]ۙɘAvOijU:?D௷߶S!H)6JtW/ aDƉOW5XCOBsA.ù^9+ٵn{6|{.ORel5~ʓ<,9\T!m\﹪´gJ̷Y|\:߶I8]";#@y/e.Yr zW#ćݶ ?Sq\СOZ ,*kWvҩydqq/)"ŅԨF/iTO=p*?QV>6`e5GLd1g5r!k9Eip@5=f<$-MpW[ȖF(i\D?=6%j1K\Ț2{*|]V:f4>ϧr{QGd_#nP_=w:~PS?>o])0J uo ZoRCcXgR3_vi0廞x՛:KvWܠzqϏL]LJ\ ~xyAnAl 9$̑Y䝃hkgR ҈{ ?,7xE~6*S-)I FٗigX*6,է!$PN*)М,Gsµ /pZ1Gi4ߍ!@l:B7D8^;>Уn)vtJW2reӧ3!Ѡb;44vY<ő+ކtr;1A =5o?1GqVePڼ">󮣛T0&e8PR@DG+޺s=A;iy陏fc[b\{6Z&V3K @Qoe(QaR~TvLC$7sFvV~!fՇL,Ԃ,΂IJ)5&x,3Cub0-u؈(eX2!7]i`MXNZ4_?2#W,>N\8βRʁkO;^uA/(4]L_>/n@f&Ӂ/ݝQ|n<7%jcKI:+ ~}y!kX:,jw]m٥r}%$:]Bc{hVu4tisgE#}C!۶dħ`^8N{ сϮ<uS)Fe*>imxI]G2ۀ&)܋]wxI-b?prl'tnzp~#ue%ݷ3D, j\sI0~TJ)uG{r[wIx8̬"]6%>!ubXJb3=HV9{YXmR?'ZDwҨpB IJx,0&sm B ww2$9gVN{k(-TUW:aNbNpN7CC>3*G@4s ]9Sﱝ`Pf-;)#t1qE&9zd@>LxCzXGi=gsz{Oge6!dv Uj;%YjNuYek5;Hշp߆^>jrA E/{ 0Nauj3|m2oiW,AOC\h-g>n\%>g. zv[Øcn4tiV+*λtiXAvR_C8RaT86, cfp}vt{%%9, l?PP&Unm̑jiU ۦdmk*NjhEo$V5/KEtr-Fv7+ $An -HBG*sʝ;7ִxAssv ~(30%q"*|Zeu3Kj 7j-P|J\M[n)t☑ZCgIN\^5;Qy7-,p)dx5xX -Z?yLs:<Фrq V|q}~YqD\)U&Q T \B5rs )N8't.$LUyya%pXdVmҦsuz\?dcd|SOe[ ai~x6٨QHUN9g`'Z1t<- pz ɶoM7N|2-$̍QLx6fowO ~vO؅v>FMOxb*JAv-ζw?gXG-[8,7,a:QkZE#Ay2ְ' [=o950CDB;"O'?<.QQP]e J CPFWO㤙Zih:)$>XCWGO<.l?Ԁ49>mLW m ̲~yY MkJد#@G`UswMG&mys ?_Uwi17q` \=,Q(G=r DE9>CjnH /\ӽK#:8rv)$7aD:<+[)!6qJHtdqǧ9-Ét|Ͼˮfߜ~1N_nse2iRE8HOJ$eۇ "[} h-+%L_VpM9X_4edna5 컓iCUE|swc *Sd*I2bkiru5Wcߦ>qQ*p N<=|/xcLU^|'JޚN7#R7(oI_PyUஙvtV(ĸmCF]uJVVa]n%NwќfyCDkG k8=NQBoFWvh7}BpO`y cN fYeӓ|djezk\) R^Er[O-W{do/4~ԙ*1{_E 2r/.?*r]~;`LQ=NﵛmBuIGLcVQa۝ݫ@)Uźi:cszCB <-Q8gh=nr9O!h'5iHP9Z1Ognpf֓[v'zD<,FBi<oM+D{Vf,QT@=|jzEPk|]mDcr\Knf|0]Rl H-pDL#z`f;h}Ѓ*ދe9(:~xu8B+S"NwCy|%?/w1HBϓk(ruuNoGwE$нyV)>2*==rE'%)CoٹG!6e.& DTZA{}r 3'šT|# bOXNXIIH"&b|\LjAE9yTjJBQr3<7NyFS%N$lG֖FVf#͠v aY6&Phn2X&A&CdĘR^d,;Ӓ #쎯M:NTj ;ʍiѼDv >7}iS+'O'vTM¤z-2I@hm-GC:wkG0iikC> m7Wt6e}Ǧ: aG0c,>;ڊ:jKВ<4 w56_WpK$tyM(DY^A_Hn_3޺JL'ܙ0? DnPI*n7u N3[$CEXc3ы1jCglO\lqG]^Y[6<:H78fz/y9':uhUOQi`D?;i&ɁY*2$b,HC"Tou~{'*0܃'D2׸T ;Cչh)! h6Y&>3e(,OkDwПzZxCUgZ۱}U]Ѡ+#X6Z ,56j=ouwHjux{CS_ΣnSOh qDkX5zcA+j'8ռ4o8,K;dbCCU7ك+0N\! e5Xb"փFŧ4%**@J:PXrucH̲V8WOW:իᓉ?vM9z2Pw1N76y k*X$3BA/2? n%Ka;,ٶ<3h7cM ABe#HǦETQDک>opO   S+nmLÛyVf>~.`\ɏxU~ZEҙlĬO+wX u"B ǻASYLKጹC -yJWOº00y>@kiJuع,?; y nѰY.d/E_cUI֦Eoz :^5 gu~)XzΉإۅ<+GlRCU9:T/9~cdE@ lvslf+ gY `a$̄[w0C kg > jn"%ٜfK;>^j}gdJƞ `cΗ:D s8_/ i/3H5t*`boFFě|J):jpɈ*T2aOLu~pr`]lŌ׳tsL5r þ| mϢbO#֋'xo5+3W!WR٪:;'6 Yw|e0*9F IK\,_4.CV4:|nSgW"H˻qov"d#5`H>qXrJ`HفJ jfPe玸kDžD ^{b^i丏An gF%"TɿkEDcZEh/w%ؤ-ܺMz 9v_ę4E7rGVa} ygR9ZppvJ!C]KF7t%m{ń_^cP2gKŎrIi>y@w| E*)>EDK0(Lɘ<ԗ]>j!]㪨踾j $8pϕNNMǰ'tJ ռ(H?>u)^6Ѽ0<0XYlMj;x8YZ;3Tw!{# t %rH 0~?6]DaDM˞.]S;(]0Ƹd>MOI!Q4fH]E=%ǡ 8(O]6GFzß$Rh6־ڇAjkNM|bZV |%yK dvMЬG(vHKJb/tmH3v3UQ |֜*Cj#i_Tc,YzkiU-%226yFb{$v5|[''"Ӥ޷6 '~Sl mUǽJvPgxVK񪇲9OV$K58am c . NC`kml.W:jj6QD#z3M0w|bQa톾3]z׈P peG c$鷟mF^C7T Oΰ ^oBdQ- ^Fw(ҤݮR&Cfr8.u{ahOF"_0qur\G5oܕ: |~Rr ίd1LQc:'zn4`S +qWY˓}bz1F[^v*EgB$ʺ݋P&jG#6LU6lm(2P9J`KOX=RSߝT$G ÜB`R9,d&5&5#j4/5tiߗxAtܩǚqkQAOڹLwn{ag>jhbLAE4=uYߏ i",1 }%)둷{s~+)$;suiei'bMqi}^[#\_p iW1q%@wZkj_lV+rb'QOo'?Axexr`X^L xn&M7@$-.q N9G|$FOo>#~|HV[xx5pX.hdaQ6=Q t&#P IL&B3!~Xo1vKϟTG,Wo[xdŠ eOi݄)}+kXWRH FҊ6gY+b*,tK8\Fhf@@^Wz?_ X=x11$e,y|S#.520 0/虏zQU<,ODP1^}Fb|-w1Zޓxk5.u'!<am-.k) Pxri?*Y޵g1 o8b+2%gbcl^NtJÞ03Ffxը݆?Pʦ\l]nM:x?FSD bmZȹAp"'?߂ukޗD&/p5Sc0$LKՋ{Zw3w@2=}wE Af`ԝGa0 ei 01hv'6Ƞ1T8ؾ=+k F$?SL'\{w+.[CW,P!d#8zlŘuMkZu$ R&oT ^KUͨ%T bJf#()&4ERt3I6` S-8QWə+u1|y.y/ʆUO)i<1|7GdVy57܋n ]s %N62=ؼ \7b=sт[:L(' \a8:,E.ڔ3ӐPd a}Oϵd6)JA@ C"ಱ,\hXUmqS<~7;5ꨜ6*&;o\}G&۝:O=RǾ˅o37d:+^7܅.fiiVHucqf*ԖO>Z}kqsl*J}@ZNr]?QOw_•D[h(/vՐ+v{(&gTTUc kƜF%!D1|p޹`vt$(҈&⊄J0p.*rQ%u(0|Lɳyrt*fo 5Ce_$E0l!U9.4b36HXv,d8| 7,Pg>pA'7`ۼܺfYVp#0uXיG2Q^=G1la [5AbdEm1aS/E lQ&F)ݨg%`H6y ԱEdSۮHU]2,y(0_lG<\EC3jfb~ľ<2g'rڃmA>˜^Nض˩[?MP6=vKxŧ.u4JgJ?off+f+.ĭ#C yJz T @$NA0 Lmۉ-gM$Ե>J!~L$l_|Kq\W^6_f?RaA P TV=9I+[ {$sʓ =p BNN~De9ȎL͊zjMe\k=)b^ؒ ]s𪖖8uaw=Vԏ* jr *z%-T |BN LuQzeIi}O %{;H mZ置͊dUPVEc 欏?bɷax{ « j,چUҋ/*ݬ39F/Z*Vh1'X!/;Z;gr2BAPIO26tc'YOb}8b )bؾsw h\FOI:E'ޅI1죴na[~JK<;7Gܭ=V\S4~LSsyDasaCih`67+_[>]ʚ>X#D_4!P)ݠ9"gA|o/ˮǍTU.?1lKaž $?Q~hE*E!U; OfzS=NN'F~fYV&#|f Ƹix|tP#V4M3ͼL&>ɉ G) {c|tV;l ٺuivWS܄ (IDeENUqR5VLĺESZSkQkdiR81Y8A +4'߂ŭrϜa:"gfʅZ w(锪i*&TIC$#h.4VTaaN.tG8BGU*Y OR 7sՀ~8 *ћv!?/?YYs\xzɇ'xߧN2 |t"/9䞡UbM'\kq HWZvD* jE*PXf5 Q#o/ws[^o6fğ/D-&Wbi5_8!FS4BhCJx޼Jk6vK?6ۋ7H$'䀂GiKaJ/y0FӐ8~h?kpn˺a)u1s_$ y$pwCҴvk:7[{xFmZxU=o x#A k 'h$9b]:p{6?8T:(OmUExW_ qcx!G" ISR&ާ(&7)]9T+q25AaB H@ϓ -c ^f}|QAQט*` vgЦ+AP ,K=N>ށ][JO(Ͷl1if14m?Ku0M;cDn4 +?ش[Қ*]#Zfl{B2%k.yXa65-": ߳T}O9$G}ximt1;Ȯq{m:VK-J+{,!Wo*, eZ9m6`^5T<'~? Z".4Zij}7b ռyt'㦃ܺO͎f)yΉ<ˀ͜K'1]-nYlz>GEn8;;{_eq=>)eR}6"8{WGY& Y玣߫ &3Ef+Nջ ^}k~V9Sb B)pר;*((ŭOVn@mҐ@wU#m;3 kJ`JVhA@`6Vwe0BTzGͬz8'zHϕ}gB^sJ}~\y6 gklJupAsP봥e5RΉFMr,7T&{bj2/P'P' 3 @Gc/);EcB<], P@ʊϴ1,Y94'ln_v-5ML"w /.-E.dzHKU"6䩋4qA;79Jb`]Cu#E[e@8f;;v] LXrn\l*yLn\E7U'Z+)S-fLkĺz0&W%yʹ[v".('ꛗ ʚ6;24YϙQJJ^ϺOI La ΐYtV i(E$ ' rdߊ !I?$MͲkMB?؁4cӦ1\5kF2ِZJ[=UGm,mݘ},\?t59(S[nqgd?0rKdٓw@x!o@4ɗLHSx<.pH+疆b,Y#䍯J7 xS T0W V$Qwhhu;Q"tGU?u=qQ~krnk Tb,ZPD3f4|l=9H+=R߅GO\8S[2[o>No#hg6=W&N\̗H8?;[y+Nrd" ''E nuv=-p.rcx%\9AcSU` 4z5Z=j3,0<Ճ|n, _uPqN$ե9jQj&^bmPF_`qX(T)kjOq{3}-uBG߰D3vM RncK'354FSǏOnڥ'5Zla(r2}{,9y|1XӴ_>CQ􃇮HEE8#De W +u)Rގn [?Xwd~Aj¾}'f* Y\%Ϙ>fgR1Ag y0$˯WQ7 mbW.Rs;vAa9\2 A<{pW $ R3NR\wB0i[!ʼWkrOCHDן*Ǚ<GKoR:֝6oHA=Ħ KPPaE$/ݪkE#A(CӚz =OvWEN'& ৈ6q+yܣ.P4j_#E_Vp)*ojpX~\aۆTKjn9 CH~=*X -?7Xm:'YFE2AY \xĶsgv:zۯ/)h tKt@&\Y6M0 ĪZuꔔfZL(1ru2]a$~%"RGԚ%IV@)6GLPu4`p&2٤O}bӛTIʆSD|B^a ̐h|):Po52UNlWӃq-˄E~:S T]Q}>;`k Q Ǝs? ؃H.F'̷̊K04Pt{E&{-US餛]t7}pU _$u,OF:ڄoݡ1iu.eihn  шV# )6/KBfk tW CZ#K0D}FU'B9ϵhqJ?u9H{v$8ʅs(Z{CRߋmE[ךxwO-гqrS;EZMv7$%U.SGAQC-X,0kZLuZSA:]\]gqԃ|}Yy^]؟녨:V^*筇<0lI$(9V9|x2lYsLbXiڀpLDB6RǗa(e"<=?[ ѷMLb[{,J~M'Zؖ[b@Qr??AnR),Q̥n6NQyvӜvT RN+Eghk=M5QI]^^c|҅F/3ˁHdc39'Td yZ@ cimT;D91I3AՅJ+1v"PBT |P9=aȅe"Ifrҋũ)"?AMhb .kXoTpP؆+O ="٠iwTY-b[rB@a``SCk  ֬r@mJtRSk OV-Âs?Cr~?v!I6A;Cr(!f(!U|8ګgU֭S:U()3=s^caƲ)@hZ/V r!]s zaH>c]'`3r//B_&,0pmy;-RG̈́{+EO~` w-".#_2fPZ@B|u.r"$0PB4J@ʪ/ynJVGчo"##O&ԾDKfsSfi 9Z/MN$>fgv6R( we2h)']Bw#m*TJKt~nvbRg7<-ekPR1: ˎ^>ZpZK, t}wNRl]DH >1; cp& %/80E\oǵ~DRWxuaK'? ȣEZ!"%sar4CQ ~v%H k-VAVsF&E6%gGyMz+˘#_ٖh]I1!k* +AQLی@05}{gj ߥFYK/XF$b^m:ȥO!~WC\4ZBPuxb>"$Lu2 Lؖ֜ExĢ-TH0cIIF)|(y>AXP !m`Q&# jimc7_;#UZY O ܤ۽=s:iؽi)-4+=FhD(9{F8EBEϋM{=0M,SyQ0ּRR -WJpr>hj'Ien|V9efA^t.Dt{"KMd@ 0n0>$ZǼݩCM&)Kym^hP%+7,9쫽@cϐ 0O=cK |/ɡ`w|t@0b\ yGStP[Eq=[D8J2_('CUʴqYA^,7g`)E(nd֤D,PkOҨˠ<%/Q"G*Ə>uʘN+6睚؈,a4A2'-g,ݱDvXUt.2зؠܟ^evu%6W?`3xSgsѩsn:r2Zb:qupcQف5&WQ b:n0s`M2Z0́sr_eZNJ8JX?(!G?cvg"lwȋ?I tD epCA7&e,VHꅣ9JR4i?f.!1ivms?uIwp2#d0|{:t^f>| O #!K|+ yNNVuy(65D1}.T}Nq'9iӶ\!ʒx?v>n;nKH|pO87iKzANPOD#_n&ũJ+t|@nok9ZaHH;[:=.+PraۑuR%Qh|f 0r!?]vI&q2ߞնTOYfd~/OdyJ3 \eT+~EXՌdQ@^a͎ g)al&{9q,ZӋ)esoa#x;tAGն>_?@ %uOm$΢Z?Bz[7cF:!xGgt(@A99Rݍxb@s~FqPʔ K!eJTyjk(AHPXlR :*Y] y?pܴB cstwBh(;u !/7Ej{\k%.)xdqi6-՚Up/3؊H QsWsHbC?eώ^#;YSsX>y?E+ûR" ,`/ \( Z^VԍcL%; Qi\\,G9d2iԕ~=GLřާj ^>D#&2`7=8w olV`IL@;Q6 ꊋ\Ge 1~@hnR/vP3 K1j((}Rȟm>.j=U-gˬ SN)PPeؐD|s_pg4N`s[gNA?7-8uThI})NU(h7\)_B%GQ:TQ W5'<} 0ʣ\wg*.'L~bh}mwS ӝ{21}%8PcTiGva:Tz"߷ap ~(!j *=L8|-6EMR+y5`%E5 ͤ.ȹ3P7%첼a A#'{0){Bv@YCHATPyPA$zѲ>l~9oTw7E^ƖÀB>dY0`8CPģ1UG-k ҇l83H!|!V#;N\cP+u_xܲ MzKa9#k8`jR!9(&,Q}qJ/gKYb[rc0juni\ Дȫ8CY/ɀXl[Zw\8JzQN8{Wqqa8)Y'rovR ܈ɹ.dmD 15-X RC-r؁-v ^hX)k 3P> -2) PA]ЙWjuLn2e.ϮDf>]K4&}^oz*Ts3p-e#41e־qq@glW {ڧ;4Mg@;ί[oׅik!J unJe_7 (I0bKbe1jSkԇLXUnWa6wڲX-5i0.L_^Sh G+F+){j(_NĤQ޳v#--et&E~z hlj5)M7oFBI沖i+Ls`>]dȿP(<:[oeXʺe# ÀYX'daŠ~U#0LRE}$=BH*)b@au[}9B&$BElݙ9 8ШpAӒ`(c &n-<vk<ƪ_y2f댬?eMb-y˪ >ʬÓ3D#rp [)G2jZ]˭◴e*Bۖ97yN^0Xvwž_c)v?^[_e/YVGY)Ļ9b- i5XV4 zZ ̯@AM8USC!49av*lt&Sٳgن;1KIyME,ϐx)˩K*utN2"w76٥N|?S>_@".y͓U\ @rqw]ܼ2q9Mú=p9u%Tϼ LUy/,0sU "KS@;1Z;4b$:pӪ0YSy+evNC G^¿Qj[E:r?)N+*v'- <;Wl{ތCsGlzR8 \ 4-Xi(/{dqu,֒h'氹wr`"234eG4> & x9 1ɑ Ap6±H0 3<2p7o2sO$`sŖ3QʅYVo;G9!]ף3/A\h'qx^qΌEji"E(Xa,vʹGK3-E,T,j [CbŃGxitfI!eE/>g+KT|G)4Dn Fw8x'y_*]DO dQϦ.zn94'UAk>Y+ҔM4lrn pu 6j6$} $kFghVTŻ\/|{+;(8"CãoO51B4x~H;^ˈ-/Jחz# vm(|$?qÍ@؃^Pޔ䨻(x礎^T\v<ӅDqY?Ca1ۖ֯0[CK껁9`V6tli"{]jC(VʵWJ2eן=ɒ.H"AvKJ#B38wj! ~&Ű 씡#$ruĞ(CV1psnTgy M;vTaQ,Bm"!<**WC`=_ l6TKpd)\2X+"&rH>FȲA6˟1᫩~>#ЦF)."ZF1{͖ Wlc~8N]>D-!v,;wDeK[ z6 B^rd.fD[24!|:[imA:6yv2AW[&5<y)xǃE|D?f: "?E& [*j6+K Rs+^ftz$U {Iȩ~oyAP H| OcTtEW.:;#Y5jg.5lV*Ai~yni1HR \ҕkzqy#"-fw[Qh<Ūdt- HD}9"Ju>YϷ *]#f>5q$*i\q$eU l?D)Eq?ð?׾#cQ%`6R6[m_k3'eOh#R{M{mva$C-J2wEGdAVL#Oite-B+L >yxZqPm jjy'QgA6 ~,|ߴdy$܀ J "h 'u6׏I ZfJM3J{$*d]bXւ*/&۝ $f(:g"lZxZxh2i e'eeiю0%Wi"+=aՁdhd?vJŞpy/C3O [,:`D/{jH$97]I}>hf2Oжgc!VP҄9Fl˰Ik GX=F{v}b:e;j џDOJq7_]/7{ LC2C5eRNN|"GoMш* LUyV@8YVz.Yvw AvQ0 kpa @jFmD;@Ir8m69"3#S|?5'\ h o(yO}]X/^9Ag'k8% HrtSAH4S ㋰JO<_# "S7BٳZIH~&(24Esti7JU8gk%zv1B칩ErdMSZkZ21Bk˕2=:8L@qU/^4 STG:+q  U1 P0hj,MLR9mݽnC4*DDJ_x"eι}c}L:.an`HuD9osKX̞{S:P/ !Ҧ`2\׷cWcLlq⇟HIМ t} !Z.#8mOz v)6:ɺ^ 'Lay0cQ}{l/_g9qy NhV].`J+O*]|vU^& x`B ]Y&z&E:԰. I;xj-p# $ePi:9̅`.r{36@nj9_ cB^BhL̇-Er 2+5?6,IeOto|nHWBք2S50Hlo௟x˝npX}Ͳ\st cc Z-/Aeq"GzrܲJ^jw3 菩0S]&Q!qr}UOm0‚6}9w1oQ 1☌(H#:hbi,ڢ|ï(m{lČa sbJYZ_P05aHѶ9|LK(^b4KZ^htFlEW$vAšt3N W?|ӉxE-R<Vy]M=ĎSY(Ϟ67_{O 5`K:Rf]Q:Q:*oUrtb!_Uo[Vpj{1(~-L'c(u.)jSKE4| wI_"pjgQ%fބ3p"A,GG: pm=Tb\d)!`Ma8q,X ,nƇGXאRm ;RUj?#6JD+nNҐ2Fz&mpy'"$/C!1le-@wXoK~BqVdIlc֫X+:hs? t.y3=6WV+V$v O؝:vGP/sfRg3p8c&܀[YJ Jt/Ŵ8A9x%(B='AE|)uc%  g*s"nd_|P2kՕ<} w@lok!ٴecFK]A tJ :B.=GdžI_$4wN$?[aHǒ*LTgnns'=8t&¯di[g>_`: {Q3hP3!N/a(9P\P |l߾,@ ,Ӑe^8\[֥b)j#ktwu-`a@N:վ̼)L;*c#%0ri4_ e:֎ʄ %W?IZ=U\G9`O&Rge w@\@xJШqa B/  3aㇴDpt8((LVI=<[}RMQ&}!b'ML =/TjJqj"+;##^WP %jڏ~Ѵb,jQviw0%no7'k||lޡ'Zs=߈UlܡQNq3yɱ<S x39<Fx@;Q1*⇎VG.zHAwah {*#຿檸u$!hd7&SO ?Nl菓sH"t󐧉zpaqfranz-62.2/ZSFX/zsfx32.zpaq000066400000000000000000002415351477324740300163320ustar00rootroot000000000000007kSt1ӌ(zPQ         hXrEߏA/ _Fp?_4_JF;p_4_4_JF; p; p; p; p; p; p; ;p_ Fp_ 4B[3ttc聊* wWrS$Ö9xgo#v%n.;+4F׿-Z庳 ;BģW97Ho.7to'r8:VfΥuwi%I?y(̈u;١jr/ɻvK:v͸g]UA(@=yM!]n 0_L}Bt'us Ga^Jj/ݔﵲox1R~Z*)Ÿ]Cū#R t!|ZCZ]QHuŝx.q^;g^[!Yr X,߽ؾFlIlH8vғ,ԃ%'nf?.IMd&8̼ǰ=> ` ]0is<8L]B)`f%=Vf`ý*|0z&hŔIlvZaLڝP₁_U,!%P"L俰( l#f*dcey822B\t\^YQl2Ʃ0(KMI&> "Ă y"R$iZ_:1aT* G(TxE8C5R1Y^ 8ܨDt5S1 Ȟg2]bo!`ìL '3qxFㄊܜ\lܠ$R2%c0 rUX 4c%Q HAeŴkѡi&CCMd Ie;H^_ @0"c( j"8mGl Ke/|bwU0G,>ہj\W,2"™dJ4=:,FZ~rT"[ A}  oy4;Y"$# `&0kjRz8mZU֌z!PhPU>!A2W;g'Q0re?)-#K~p5'迕Q { t084H:hX'M L1A\n+ndW$E0HXGeA= [T8Lչkty|#83{ x 2Ѩ&?2i?;ymꛏ32DP.]vl!rQXW =[FJN +C(cNxйst մe6r#1,o[yN9MȔs:ǀzU&Ó],̊Yj髥 :J9T* XۣX[p&)YL{ZY]>O9<Lbb8u`m-u)Ir}x:dĻ/8-keI!AVp8g[^A+BerW5KdLatfibh B!8Hپ#)'*Ao!"ޗg'w :6U| Nθ{30tƏԟz{8Ƒee{%od;딃,;H셲v;L1USegE,: I}58v hAUE0!Ip)jBKdI@蜼&'sqB$9 w5b$8?|q$Em_[~\h":u|.e"Q\k]\(>c/Vn2p9/ ó*AɒL".g˖f-E_Gsqf4FrOt@7Π/܎{vL5o\ˮx~3+,‡fW+RPT)p<9~:M!Ie#0@l{Yi8J"\о4gjٳ"Ibr:ui^P~\w~q85F&? Z$CUNJ>=cv|0%sVO w`^>7 YC~ؔ OVIo`E D@x-Ap~SшP A{W!JhCiua=!Q;BFN>]Xbd\C?H +(2 6%wQ?'"oy[)`k=VG[IUߎ=6Ī^X3VAF7V.2 gN?KPkD3Hא: e`V\@A:sc ?aJvz5\5S.C5W6A@XiY۫UJ!!9 Cn%"j4:҇.f[FGy,В0z"AV5N>s ҙ嚘3p'HުMRgR3wY(YTˬ̎ 61$$X3 G顝`||2s~~-0*sZr~![-|ˮcy&leNd}JDC݈uNxr.cZ^#Wo:3Zd7:c0 :7m)F4l|rO Wd"UՇ+T]2n6KC|hsO2ѯ-b9pt1I|LQ9^S23iĶM ʆWjY41 'C貽HvIK ꓦAP 0 NtR]ב~rb\iUcb1 kƘdlc 6CT3O>J(B,a Š0rVދ;fXϩh٩ƫB 8͖b?]X|mR .LKcCo=ҿP-=ɷחMμ+,SfS趭qv,hZCx ۩ vukj< §z\;lGWCxQ/ϓkzާXo\N=كࠠ6AtHs%#{![c)Թ{3rA[Z߄Z2)k圐DK%O]# y-KXyhǫĂ Y qBh4"<pyKk ؘtzx.ݕޣT +qKt7~E- ~kXA\̸7ɇPIW!2Ei 5%J p< ȤG Ґ;h~\f}")KA{DQf90C=JQOeY.Eq8kF0H0"hn)ntՊM+2ώy=nW7f訙&6ٸYmq̪Y=t Ժ3&;Tf<+֖ܪƸDb)!HiO0W\ߢuH$Gu7L!xIdgǠhN143*LA$ ,\}=j<U:]|ZA).oͮ3ٞSd\&zm \X%ƚCJsjB"侅s\.KJU_k3j 7jXnCL"[5vEkp(ۧRDzP= Vωۃ'6<ܵi2V0(GeSt,aQE;!g3UF{J3a;K Tm|bE9)'jܾ!lsTnWث/cM/ۀ2~ $\`4jgTQj:[]GW&Hid6܁wfǃECGYn`xYdMI50>x H JDnիhAC$=ڊ6VӑJN\ߢ)q`ăF!go}Jka=T?x6b}SM *.y4A`0m:9PPs[7u#-%f2w| 5 dp2NfyƧ#TG2i4܄QQQW3&ݿcs uܳR|f{4k;SFQWXƟh򻽑 3nխG&eZNfRF>QltL[G:p\[V3+ZHy=qشK؀iFY&;&EmxZyfՊDePcY#X5Q-L6R y ;Wao$?tCKe7mupn;jX_Ba31;ngt`OgvӮu?[9nz1[P#,2I'8&N$+Sa3509bF a`>7AF(*:1z4݉|6Ʃ\gpNX {|9_mQTϜ8|ȅu OR/Ab"}~#\*%2ø ZS_|Kzo8nX[9ru5/,6|fI[Mff`d|ƉU8}(/@Syà'K0w坞PWteVa& D_؈܌޶xa^PD|cUQDM6s/ϓ|mX51tzK3,2ULIVd@N3Dauτ]'FU:}WC5_ҒeaF a+X4==CW_ 2ƥ^nxTmj, i CnKƚ qcmr Ҫ_}t[I0|{.{˃{7 > JO=Y 8 J4B-sr:h"ӑ͟rJ\6@PRQ { $ƈDm 㵨2&():Ty˔!3Ƃ(u :Vq"H](c/ aQP?, n*HЃ;c7WO$^v18r.=b c&.V2;/E[@fF'V#klP׎&&5ݨ/xydqօ5~Y-4NSK'iƲ)')B;o aЮ#VwEK6YɡGkaQ0dHpWS{!b y?? kJ],=O\"Ȟ._+讠F!*9]Rm{]HWΤnC(ˈ){eEA2*読mgjq Ӓbpt{V}wSz3=3 Fc ߽ a 7JJ6Ӊp0ݫV豹dX9R vt,q>ݸT2v$@F ^O<X Ail/d8lz[9Qu(t: oS5>Zf1ڌF gxF gFf^|PB027n;UnZL@Uo"9w/.oNDq! _Q#xW-e?d5G#mlLx$x%3&yThtl=fZ j/x?}p`'1ϽVѽ衠63OBQ,E ^+rc\EV(*xu #MS̚Lĕrä-_2B~OQ4ixs(7Sȯzm4;G+Un؇Jpy^s0ޞLsmO v)}睔 3wGt87鴘K 3 潮⛔; <qfiB â8|tAm/WXM*3n  }X_ tOP&vgúwh*.s:-9tw8IXM(K|#fb`vgqAYD=Kޚ'Tӧy.2?5vtTG%O0+Uҵ4#bKYk~ ݠWO[4_MT쉕x44jfO.UG.:{S5Or1>k~SO~G._K,_"Մ B({X6 _Lc{ .=Tz>(d$kxb"8+qVES%!g'nL?l އ5i/|fc]g\AR IQi@i[/ CO->k t"\xFW_00efeQWdsPE#ś7y5'¢;^JQo s.tiN" ;OQ]< @AYZ,P]L{30ÍW}QbneI*uWYbd2 |b дגTR @ 4eZuMYcVW] QB f!PipJ l~iq-D!clsn|d'*tȷ18#At/maVzXvhAz(|!hg}KX+к4/ˌ(XD/F֗'+"Nce8s#ZêBn>*>A l={LX@JMd A镁h,'E=*T<_2'p7S 8~(6D%{EbCoTQ8`ـ1at#VnBD% 059n ġ3 Q o7]D$i޽ 6PD"aN3qtݮF]@NUjk_tſ)<6`;s+ oN7Vܷ{5Ɨ7.bF=Ӕގ)r V>[ '=P9=K^CA> Y$bG^qI,,1|225 ;]e":d+ v`fԻ?6 ZTU} hVr@ks. +b4k'c'j.N Ky0yI٤j/':7;wA8bT*b\XYMۥQoR%]) tIa{ vq&X{T:ˎ^&υ(2@ȶT%=ݼN2 >]Mf>Rf/u#Q[+Y[3"*kI# /]Uzd }?iW_?hS2ݞcVM{KHy{ICQ/ajNǸyRη=5ߘ0/ёt#8MP\W,V)ʶU2-}?pr;Ҩ@ybшc ۨ1JNR&BxP*QbC gM+&:`;W[JzVèpn΋ZW*Vc d$2U*p.MTjT3Hq\2C5Dt"T&GgfLQ$'@%r{ daY U%F5.yՑ MwpJ Oy xR=7XDN*Ԓ ~@N ?r6/S5r?p8ol}"#wTnߌ2½#ڑr+x\3& bThqiͪ ϻTnYyAYv9RxOaGN:^o2R;NI/ -zY a L]M<ź:Ua$y-h}W.X=d_*b e12я _ee,Xȳ+5d}nB0w =/w+d rQF}DX'TJj\ >:@Ao0Z m;'C`/,>F(ё/JsLNH$zw%,MmiP%6s$O+HyHfѾ;ʾڡϞ5.6AY+e8 .Xs AHsAz_]&sٮ\}0&vQ:s`T DdX7m" oS!BEv :a wۇ$s_ P O4qt~,8Ø/q;\s+ &[t{ Q7$%.*t :ͣ$M=I^ _~}R}6wN׋{6u>HCC@3/iZZ,{=Oۚ}ȷy@LEy{XjZ<@~|h oɎ4Ag(7iˈ`h鯡P(jPH VjGir *_[P(ZXY3u;(G1o,k ܞS8ҌVHnYge"Lx˂fZL;NTX[l&б;D8 t1&kpUoN2W;؈c2ļѹmS(a0eE|"3*. |_O*܅8!|-/v΁#s}e_w)N%>yM/  (EH+dtНeډ[‰[#1dY῭ z *dyۄ+뾆C,X'HRrj'/<0.O:-1溁_ps:9oS;&G=~fRHE><w6Blp="bf/ U.u~Q<"fvC(f%򌫬ڻ)`L%٬#-,b".lsҷ׬u FecʓE L""nWoBfy5̥yYbPo/$ϒ)ICne*_(Fr4Mp* B9*QM8죢=(2vܹ^}X;-~z25'ɤ4 _3 % qg`ZZ6 Tn DAֽr5>'TG%д~ e{1&+b($-O_,`q @PbyʦqV⁆_x2QA!Ob^"%5NBy NR]$rx¹e]}PƓĆ7?TXYb ZYsbeYC M?qSQUSqk|+N)v$nsTR+7eի[x.IrC]lMadfI`ӝ@g4F?fgx,&$e8"5.>;rU]dB+3-6hn7'8LqSл+ܱ>*5gsIW',?)%H|T}w'#[%0Dfn^H]~V"q +c׌#DmaWM;B'!^d8ҷ_3kq87["\03P2 y>w9ЧЍ'o4 BdthVZϯ"B$k=is \^`a|F+GKV{nAQ*ts@hLeԈzZS{ʯLWsH ͱV@չ*}a LtJ!DNDE<< ԮLvc34A1[q0 ۇbY9-W(JVA=>}^q7;Rb kF)Ϫr.0lJ@YU7iUMpyH'ZrJ^Pam=i`ʅyߐc=i3]_WkO(nKuzc" 8a7~k73y+POIAJ?;yTPL_Ȝ^"Gtq֖.u&tw9GAHQ<Υ|ȩEC[h)Xd\@@ + "H"QsYT`Wv;2ȐƧ#x ډ䶂!&#g7D)ʲעюڢWȾ-kph Q+2Axvttxh8z/gbm)eL6 a)9bQr~RKJzLRmZ`1d:*RSHs4ASԙ>|!Dʕ)Y2~X WD9;НvF# `}HPNG`ft{'MT{k9f] 7Ha4G?ksפG3Go"L{:G3ELXZpv淴" 3p_t(fĝpG.Eu!J-д#k]U<tu)U[)<|XYl/Y!1Qj"UU;X<=;#$ky"=#Pm9CT 1KkCH*x(F2%3/ 88LBMCP‚މj3N§ #B3A!$%B=宎QdhWY* =|4jMs3hN}ʴ844@<`Jr%3RY\2D ,i-\TӺ&XrP1dYp<Vɋp2hӌ6aB g뛇;RG΂oPZ U=pvlƫ=ޝh_D']PWdζh,ksNo66`  fTc\>~1VYr$H] C+ wc!սˮACj>_ `# OQ. l|_u, Y:nwkz w2_/EĭRCx*U^w_;qX֧u< 2HS f1Mu]$mO0`L#"l?M#E'S V&YW: H-!@5->;r ,j!B(g6?RD)I ;?d 7ƨ2] {I>!1N4\d+@%<cENcFqqy!$ Vh a Tny~L) A$E_iufðh8)}ZI`uڣ?Y]v XjDIRmOx̮¤ⷭge{whOq|1 S5Fu5o2FԎ'p 5,o6JMp 8O՝IGBu¤u|ݛ+0JY9癵 P~Xt0l=ע5VxQA:H,}K篻"~˙^O33ӥ֟]STm-/:@u1QpCx˄տ(R`A܂IqFfJvBcDIב28j@Vu> s ^y`NW-^@-do04"o/AM}+  +h,ӕپYQicܷ26ϣT+[[Zo9H>=И! dnM'ġ6:LV?3_D)FKe$C.+Xkz6N [.zC3Al'E󩤧![uKLseQs#$W^ 14>'+ gILA4r+M)|05,Q<$owIQNQPԣC4=Uch ɷj:L $T>1m03(jYBKD(|CŒ@ "%)7{10+sW\kk_Ӂ 0u֩&4F?$.%vS]Y4S% g2)D-E 7E/եϣ2ʉghl,=\R\ m; ?B۱X9ynj;#vsI?C۳jmGޭD 8.Gfv/!fA3pc{|po\pI5&(fC|O$,8V~pWX / ;c;vpjRJsw >4v,*SRCYon'swlW uޤR=Smw旅9[ßZ<}0o?KtjOuczIOZŸ38ScHY'>WxգƵؽ-v7'͢#Y^.dkT8vkZI(F%%_tN>!͒HL6{hvmzs̚]"Bg캗X'sUsטh>qzlisiYo1Ranٕn rmxBmr9m 3╆@ZqAVvow"PEk9\165N]?+eY 0D*qG<6'PڕZ#at^۾t{<)<8ejӳG6k&5yX9Ayϩc4e}JlIB0bv򟐐d V}󓩌0w'7:㷆>-c$90IL\W4cx?ŋXRzHǯ,䜲d&gJ揼WL]DQqh9}JVCD>!]!zTZYbӼ[KmV5;`18#3lh./ /awy]Os!'HuR _p?@1k~ʲd~ uG0ZOX@,=%Ya]I;ۆanD$-f$y~SzSF8ng|EH58G{7c4\_Xج:x?O50{ʭr*њFs#$CN*&y;*6Mz`-#|m*9GAZdX_N㢺1ਟY&Jlj:uq~O IpiEf3 .ۏ$a[ a]28{ V _hX FPp AYYʮMm?) ' k70P/h°y'•m\e= lmWfB̂vXK2fCXGz˘Je{>}5C m \LTİXs ] ~Ea1:Zt /zuƋz.zG`>jL ̶̌+q2)g.7A/Q3q͠ 5Pq I}FxKO] E L&6#B=Z JK~N gos42`U<M`'fv p4IȣՎ7x!r í (дO޶%Fb S-esAj&.wbQz!wE;`.,7Y|Ǯt988 %H>b ?;}Y&i#G:(k dV9v*NTyZ? ~ IgTU| fce2ٻ1֙On`[D!eNb*Xx &ud9fSE*%|%ٰ"=Q/V>C35Mk6ٿm+hʑ_ꑦ|y Ta6 : җy>T܈ew<]-mo;](fGɋ@%tϝ ?aߠ 2L!3=whw1d̰``S~ 7`;hJ>$ɲؤˤqRȋ9lY_wĩX[Iea#$y6ot{jzAܜњێg(eˈ:or<#^S U!=>S> $fqYI0E;`ɉ# c=yS<86h"jՇk6m7:pq$U 0|-T@p29F*8h^Sb~#bjzUgǗrXh%Ǣ)䑡="lrIaX|aOբs0QOWZDIR ($;ϸcG ~>2̥ru@77iV6`c }̐&R%VXβi$tv _SGV#MDyL M f6xX`ˑBWQlU |" `h:э8 jJu a4r gjD )g4!/KU^*/RLoGp $B37$zuK$,Zl =CU^CkQ rҢFag9|znEsQMm{[eFǠBன>n`1m}*;œ t*}H`?x=Fru6@ZֿQ+8y~ u}N2(c\W*d=nJPn.on2ȑ(b1X:1iT@u_?Q?U⇳.=3ZSrwsԥwOgDRWJ HO04кѪ" pvl@HT{m~V^N90mI-;/cS {5B˱hXGt LWҾv9!cѵ] ^P`p8`0ЂG0nNĜcqMU\?NK`"Îgigt\dX#{jY&\}6x[,y_s]G a}9$qۯobٲ}q _ aR0kY 5Gi vEtjoIsF]Jre7Av &_ڔ ȬGb5`Xmf-?5|qw7cx=GG_ۢz=5)4[/0,ܶ8*hXGW}$_$TA ֩3+JҔ 㪴PU29 јar$̎C:j' {a!0GK_S%{e7}8`jzoc /QkeDo蕩}x=D` \á 5 Dt8 v/o$&0"u,6?g;X1׼NJl@ѽѝYǙ44slp(>kT\]tr/l8R$@ٶ$Ǽ;,f}qǽBISʊDHgl3F%z=3DIbe[9,m<'KO.q38UŮ|_$e=?n¾QMVYz)Yŷp=x<@$Sϋ!C3>"poI8@V.hUG_l F[{&j9ʌJ}ȢQTBX]"K}.'7ӛv<<2,ܮPcunX[wp%@LC^`wb a&'"~ z:4ͷN()r쳶KX $A"/AfF͒f" kQ֔jLR"j#r~b*GKCaP>laF  N @4NE~irEE;OgT 3/+IFzӏy?7=)u"ש `?jw%j"ƩZ;Im{{UU_5+f6QiN bޒ1Hd@m(gK+^ׯjztcг5+X3ʗnhP&ŘuLm_w)֐8H1ᡱ/ùW ;)' o~b1NW9,/UvIR9߼tJ5LRUP;v>Uן1]ZhAr6Ztm(lyv~H>is.}Nf2j2ΨC%z;U8#ejS;Md]=Ì'j?x <@غ#u#ҊKlwIiu >OzUJ+=U,?^#~V7(pq3:uo)ۈu~9;T,1Gn?Iqrnq-Y8"5<]2Bl`)-,; !­1?q>=hۋe+uᾜ}oꨶ([y+icIL82c+Nר f^0p ^J\˜+;d@ ]~OӆF~YH\2kWnqy !Ϗt9WXa"/1*O%/#Z/GcWu1^;c?_z-3<%DP尦(8K6Mf :*G}8lw6 aLk]62Z/~lR+r-x gRق*ScOLmn8"Qj:{hȆT*c:YBƚ-4eEnpO`vu`< TV[vnzQ i'2]^Qð66 ywjU*ĂP1,ImqK4˅2kbo[m.枿{y51d.JSП+K>,Y |o,)Bڐ9ټ 600?iT~cнHp"KBtnj/{"޿ 13k4 fB+Һd4@ˀ;A*y>2 A6\\@E,W+&5;7LFF;'Erҩ2lg-e"̘+lٲzXܘ% d,uhKa.=DM`ڴ=nK~+ D*X*sWF~LRvsFy:H.D?C-oAf Huۂe ÎqN p4[(RZ>%Z@i lJ4Y?to #̙V$Q2 FcHy04&ÔJk:\'7$Ύ&-giAS.8>\:˵ @\zӲ>c љp 7OH9ѿ8mԩt:sO>nB] R.vLeq\[d etWڕ[=˭R\TH!_z*עͶn['ޚ栞(̪ BʒX"Yԏ55WˢsRĠQpX m7" єih~A@rp+('gvU!DCT͹,M{G.^rʢC2Sq/pT5LK]QWSDrǚqC+ڡ7Y#\Q?寏Eu7s,↍NXuqqRcoe ˀِZ2Clߎ=:F rp2G͕e 9dn3l=C~!`[>xweņO2J6%+-ጅ_☂u/)+i8+,gۂ^%"2J+ƍyx;9*[b`@{/M: sZf)nށ,̰UdJ$+·@4 7;-3ݛVu{);v;BQ<i AҰdrxOv  ?iF(R*D915~oj6 <|:oKdUG-XE zojg*%qӒ>T4յzc6+jONķrt8-={_8& YH ҢӜ.g~5"4аJ?j'gi X)eA/d畝J ;;e^w#{+7g1uø'}'.  DRڈG.U!bL fgI/cE/#K9;ee@,enD_3!澑k=Ÿ?zx_̔;RZut&gV` !)MSDPNpr)OwGʁ5- jDū|_qo֒07Yl'W&ډd B^Of(;t(bPIHwx ?r ؒRs J %0n+RP<:)6Sa<i:,5x56tؒU?V] imj£U|*$P>_$-=}-N˚w~iY|EEx2 }Ԟ)a?[}^zj% '6rt!ۓuy?bD& /?ӡ0Y ;_3mZE4:)!=b7ܾໟB7a\YDݐ[6"-TH88#9>'ܚM6g~"M.i1)cLsyPjpJnǑ}c N<0!A`ws,[ T^G 3 JAk _Iix2zC'`+D|xX 0,- Z SI)s؊ƆkP(vBn9r&DDl;DHVvlD]3Ӌ5#&Rdzo^UgmDj63=qN ،-D]6`ެP~h[s lz9cr>x1&]Bc[Iwq 9Bh&MG5F/'zt7^f__!Ҕ\ePAxRXgﬗi{\p80a.eaw9֪֮|Xr+bǽ׍U7*A" Ix&)ݏ, y1uFd:0.,Է $2D!rӶA;vuLلh;UqY0U,Rq?mlF6hDŽDR%8`|1ao0Ci<qN槼!(,/\⶧Zkh|'#B*F|b-|3c4}n97HFg^t;=-I 37n\o a^9UR mp|3Q+X6s6dus-B >PT~ n]_7ryGyS;;_:Cf0PY+FR7-$f,"ͽ %i0/W[ 5cE/+&uzlh vLߦ}^· Nz4? Yۋ8 R ={0}@9+,6G^G+Oi['rlᛗMغRr blz K_l{?vL@6pF|&# tNDNp>˺cj\z!Tů?֚'lՃ84+S{It`vs/]ߕkWJf9R:Qޘ6De9[Eݻ[1&x-9u!=wsٷDeԍ#?8Ov[CtEق̄qXgv9`Cl}D+TeZ-ϩDU՟3ӅH5<"gzr^fs6qCbNugCc1 Ε؆&F 3\;!7?=#d*m k”dQ :֤OR&tN'> U$@N2*\ΡX5#[رUg.k6RZD4,I\4a0Qe1YRUO}ל"Kxm/(!}qs`7t,F;NJ:Mٯ^ĖG:T=|r+c -A.i=mkp Ef'ӷg.ê >hH<U\S629'sQi|05f>oFǒDX #?^1?;ܾopmd\B6ѻ|f\>(oQFZ0^#ŃCLK#w-@Xy:~Y–T˳ PD| Qf E,Lܓɼe?o,G .y0`.U*QP2oh|3I40"["z':!RkMI(FT~ O6),r[Dl`ۦ;~L3^C䭖}QIш[-ѬKv!R]K,d8D%Q"q Z!쪃 eCIN{31ZHWƮPR>`~) իT! ñ_. ~RxRLT d83Oi%3^mw+q7W.gq_[?=kY8k1o+b&t+^#w_A޵SwPK8tvAu $]+^9}X P\1W{ ܹL{<bM.Rx{7ؠ6AZIEϋ",:qt=]]Z!i[Q+5|o@"(QؔP2+H4%b8|<4o(Xk2UXA"^5f{y|tizt9`q1}WEQ^~TCZnt:ϖg[g~ ۸6.y;Z .6Z125bU ̤|C( `\6v.Mq`ܫqPY HcڠS1ඬ007l^|RLedB­ɕϽ=IeI%!vJ ب%9šd:5;6%e b{bɕ!31)=F]K&1E` 4ZuCQ;NY;Rߺ3/4+~Nxbxʣ)3DpWy4Q8D=<]ٻL뿷!_|zdԋ5866~#,mHZ^onw8+4{kj7jg݆z?V;@)' 麯:Sl0r"axE,sS׷c0"έÿ<Ց[(XN_@*PRm@da]ib+~H&Qm%C sxs2ZGSt&M ;p_N%*9VҁI+ۀʭMm(UameJKR7)ÿ{F%;R]MWcPs}BskfxR0$'X3}lX14>V靎t<2mۉеMߎH'2Bt20u50X'b@9Bc"c׶0DYh-@ JNe `llnH94W|nCpBils:7MҶҷw>n$ .å2I$Dl:l*ԤYd|d=k-mO}&dJ|@\gpUފh%Y-qByĹj']G(e(|jIN&/?NR !$ p`hH;wIWgP.rxs_D0/В,?, zwK|1-:Rd$߻;3Mxt/*Nxq ٲms`$(\D|GKaͻ0-͡_C]F)oI8U<<sB^o{9dhφFǘ`*B8Hz2:te-H8 L!+*So{"UZdSIe"F274X[̲M?",$Ya-^՘ VA ިٲ*!@Eݔ\ L3Dr"Ƕh4r^cܙk{R4[Gx&@>HRT<.cj /eY-?AF_=, Nxmz^P2`3^] O(,WK7ӁI όΡKsCv)>.\b>FiyD)!/2&π^ #y0k:ڿ  Xdf<%$Ҋ1HJo&Ql^&uN+P:9TjEinH\CLGu#/$аGǥUR*Ѽl"!01CMF_%WS3YJ&?HN3S~t΁* aV܍=$%1La^jϩY/tZfX0!\-}L¢noB zC}QN o< `HZ@19OG50NIa"3^~Ʉu$?u {ˈs#[2 6:[O >D̑oq0K>LH xn.#o)މP-a&>ƗQSmHb-í$BmѣZ2f|JοAg6/Â/d6x{vJKc%xM$ ]uQB^]ܶ"L^Tۢ|!JOЈ $"k&^J}sB-!'C; fP.grnD/7 >gj> S-VG[tY.if?"j8o##@Fem4^%>\(! P(m. 3|pEb= ;E̶ nmmB2Ue$ӴujwfT7mܷxxЗ㛬GSTh `#ZDOMa| V}VRWO`Apl: hyA0)]P$)hFgecR70N9@+eDFҌ+U{ق6Ҏwz]ZcMI#jI1P&sX GrTWH)z; >awdapd f5ȯ0D5x#LfkKG &e}B]u\2A?, ⳳuբOQvlπ&Z!Si[];`~cs*9st:D v 1 +>ACwK^yFDmlIR! %Fl+*1)r9$  }2M C~(wv@1HLY(b"7w?[;atE{7j%%ʷ>2pVp]9OPn*ڍ!CXxiq&Y `kQ"Y]Jhg2$2<I3JvN|e J6|P9/5IجO _K£6%*f2#FTC  &HծnK1ֲ!e}E*.@niIEʄeYwN5%}(<Ls7XqP}x!i *"|ap%p'F'5=L9e3sUF̴NTٶLOhdQ23Dļ座rA:|:u Z76\{ <$°FƢҔ/;ęS=o|zx=B]S)uNF~{G9oykyCwZӸ~[sl eQ*5f!E2 lC[]KRavA`N{$Htd^ac5K۹`A,7 ԼTR4^X]hS)x:4%*Rk( <4]Mjl-a#ƛv[0o8c1Ux/9gߦy͡bl;WK[vuk=av~xYqTe:+358`C;}`!VleNXޣ?Eٟgclr8iu6-$5/ūNeE1o o{N27E@qDM(K u'U ?B"e/l~/ {܈0ҷqLud\rK[>^'''W1ϵw? Vgőߣ#^"sGr2x-4n!#((OKC寳_"^J1 uc;|OhB<7 k\!&q6H,2|nTb yRp BwG&灴.'Xi0Xf6RѾWC@EE2SĠҋUKAW  []OIcPr)].X쎠Y#30=ٓjMD%2kNqQUJflDB>9I9X1JJdy6be =⥅)1Q@Ѧa(ET$u@]CB%x ȀYJ`Oq ‘ %QUt~sDq1YBV{%˝KŠl&ZIF(箱%5ScDNq* JG~bք`鷱U E%٧Vb͎*M?lMưۻ"TݎtmxygB~K'=4O IVm|kat[yG朌>*!M516oځRȝրns |pHnbTÑVfedH[t?c{g`ڑnNFc{pτKUf48Aڰ [J$+]H;`firEU*SunS&.(Ve C%ݟ :טXNT>ͼ֝]U33ATw`OC{~Vp}ҍh7V]yi7BW b؈{^MEEJMʧ4?zW/RNr!z Fnd3}$;>Y1w0 hTCݯz;{||^o3UОR|1JMfEev0jOI0l|ޕ&).~ɱ4zm`)PY,U倇3a:{7 =fǔc2akowY*&Eugmp1#?R'Pz>;A`!j߇&mClQtއ3gےQǐjy1hC(ڣH}2.S9iR%\LDH͠%) |Ǭ4<']34l,="{zw}5nY-]966eM""w(^a6~12c:,|{:2LcA*pS04?O*H;x._?}-Z#VB˒FX"3 :yH@_Z\'Uh续4CK1o^xRu.ĩN|3!m©*A!R&m`t68t+|5)i7M(-esz44q0Ķ#lsܱHHS %VG>= ,-9ʯ4|#0!kQ!iZmϢJd/ٙNאUVT>}MkZygIWr_/(c৸GA10@Vӏnr]IU=d]U7u1OI " Jat"iD[B q |`D E]NKsdy'GB`xra3 VeI4$m-i Mp;ࡈH8JwXh)4~,UK(\Q%W# _e ؊jӼ-"߼b:ΰ8Ҥ>lU%E)ϩN}{Q=\"*_{_jB7J[~u% 'H>M,gLR〨PoC,uEV6[Y! d^Q?jQ.H@BӲ,B,s5lKzrʌM{% 3$:9erSlJ<3>2-Rؿ+nd0W Uuf&Ҩ.Dֲ !v>=dD])Bjh`HatgN.x؂!hxbƬIE+{> .疖p/] N暪dJwa{9tE7HY33;I'p* c "Ks(z|51{im ͺ(iR._Ŧ {wc sLp u [b ~%zpm0kC\lo- NRUI B]gIDwK? ۝e:@J [p J}Ɇ)@31[G׉ٲ jg o3`REe!S`?#BNn5,!ľ"*Ew+RDs.+G ]u Y-zź 8Y+ԭʘzo#2i"<'h<&Ѭj*$\&ynA 1]\ r Cw"RAU/z|'ɽtOJ@FR?r5-tڦT_l^igar9}VoFzcI>}iLGW~͊\`$FM3w;F. E#!o4s(&xsIKV mvUCX[yMJB&5_:T? < \4nUP+*SP<6Iגc)XDɏBUt`gQszd e3uimZ=q&,EaiUĆ+sn"]-l~`)Tąl\p,h;9Uy @9K*-Y|nn(+EzvyL=4|]sRԢ'ZO8*ē}Jm2ɤX&r:S)ANP 'MCoO{ =@EA` ]1eGި7JJq5^݉ߧlIYP3X"ym9S>Gȗ,[x +ې`0lCs;x:q)2ٽRס&Gs"UT+~^l0^R`JX>$ yIJdz B=OUzڨ̜F֥^žaZsV~H*wrpD~u H'XXYRm=@A,J9E:r_.zGQJ7N m=W e0An91=EhݗV45+7EDh?%LTM|ƍ=ޞ^}SFiǣj6:sVboicmҢ阷\g{b`墙8},Qzr[+Hp3Tɛ!# NL.3uӅ mS@Y殑c|:$`링YBy ϝPLitۦmmR[ Hp*Bqi:3?@hEH\qڮ'݅\&l-`8S;ۍUl`-*!mh>㮂A6%"^ϧ֠Únz~Ϭ0M4>o LSM]X#` BV-olq9bSMK@=F9L8H=W:vp2֏o8)*f'Ʉ)mV%ߤ0C[Ӎxv{ ht/T|#AsTn NC*Y.e&Q&D!˂ ŽNӎ^w`T>Gg%{Ȩ d>ƫ fq>sldGómǖ,Ա a[ ?#(1Sp?0܄ 0%s澄qt 5X\$rZ4ff[YۼclX`SRwV|`[:ŌǗeٶ9 AL@hv(7\ˊOzk^T#GqLInl"~XS \L1J̕^ꑱo}OB*VY:ڬuy_Z8~j9syt~Opw69C"H1c^KB0&׊+IPbGI@]4 p6q!%!ͷq_hxzT`8W3~121.d9HDZG$>;*wYAӄEn"˚Vc V<DHj(\$lTaBBJEڔ'kڇNXn`jW36d~$WwW`łB?=@FΎT1of_ i"ƍL[{Kvax!k.U:SҨS T:vR]t sLz|Usv)akDGR$ܓ=^s of:$摋Sd' gebVY+%;xNmRU}@T1s+n*dX?`q"\(*BcqO՚M+t$ ,h BO)]5yyY r'4 aW%7P7.Dѻ!zڵLP#'}KxW_7 :||x~P7%@i9\8rngiNakeJ [x 9~ub 4GCng/ n2A=iNzNCzZ:5(1N[?$M!撓jJ{O:w63:oŽM/MZB[R&+~n@ȡ5EY3rr+~{O.xm60f5a^r36Yz$!O`q1INn#رOpb>"iЃS&_Uo%?P/W~[+~]*#c<[Um]- 7%9m2()X-f8˃tIO&{20jOL]*vm"mHW..`{`}8`2C&xo?)e];E>.ěqM\خ!δ=J{?TyVErL"aVYS"@s&Bd`'Av'L&aXʁArOha7sΎ7ˈ_G ;10\I|SUH/7 -riT`(5}HgӍY{i_~ùP^+`[L3aaS 6JFppwj 7)p-mMEEܬЋ!3/ސxhfGwq]Zc,SpI21u  oۖϪ:b9]rx? J)b[}2hP3Cא29ߜmX00u)0'Ǒ Ao]mr Y[ܜ pvpGV6=#C)Ȣ)TG+ƣv@E"0m8 V9h{Mdxsh RLOPe""! 9*}New?-? z~c;$ieZB;~~I_p*K"^SӒApm0O}vxPo1:EGYG}WHv;Hu :Zş)i!1]Y49H`hbP4@,y>*a@.yϏ8g3H|2A Ť$L^1 &e!VH(( g}wQLE7z?SU.Iz8$|_JloۄoC :D=rc~)]e^.E\"8.Q D0XX#Cljkj 6 wCٴ0ҖizMfN-`\@Z!-fycKz/5f* dWe/8zXA QĠԜ `Ks6 3ɕ\n1A3ba~ߛqBl8j5|鎊)5I9('61$1%a W"2+5muys@ TkZJBV(FL|\] F%\-}E.LbȜpWGyHP," v7l"Gkr)AZ66:Y_G 6IED:yʪ$n'g:.McƛRp%\<^N+@;i1G->k1`OXE2ߡ%ZzfǞ(rB2^xPm&I^ i$wWgZ(:2ݟ\(=1_:>4"& sl%P/ Oλ0ܕi5*s[uнRXb`'Kb( ]U5 *vuQtK'"r[{* dû*>IʻjX7Qw@}:i#325fzpZX8>{(d:Qcx҂׉"=-h)v6# wR{ԏKw層/0JP@n2h7dQXOV4n,Y s&f:#<7nH wҪ_W6 =9^OXsn4i^tHtT1H.f[mXn*=3G-Bcl`|1ćq$WuQUK o[b(){ ]}a*/ .lMgI~7[;_)x;?oƶ@[F ]a_CaD&V6̱u]b̋ajn{ٳ' H="MGO[!xkn).I $,hV!."(Z ?})Wv1UBNB< uv;Db,}d,lg,k7> =8[zQV!*h=ӎ/ RNzG?7[ѡ$(zO㰡go}XW΂`yL\\R#,_2 YX$XK$]5nbl9h3)Y2gv : ,hخ"٤7D =eDBZQy4KYem_>,Zibґdv;tΐzkc]N!\ڻf(e#1-TN uϤ3mbelD+X^v)ѡ#|Pa!$a2,>*8ԥ#SI W)?ޒ w- ې{%U׫ 4߇$G&On`3~PހoA.yK~h$wYMO32׺{R(V E@aEOcd#%W/4|M[K0@ńª|Q? X3uJa//WP,SV{o}XcV>HY"^ |9HpXSl,Ȩr_گ+Utӥ'!lB)%5`(Uo^`ɠQu roSĈ=kCẈPJB܎w$N냂&>!VRedTTyf;?( 9B˟aJ_VXZz[1%8ͦt(RQ(V(&ey?"䱘ih c`L ]g2؍8huIjHN"{< FQZ+IrZ+Z^kL c1TL#x`iT,jᖄ7RhM2o.d_}>h7GB JJ$8)ʊ}s,0lQ]>[n-Ң*S5O1`âJ6ށIU ~^7.eg0?U&%B,vwe(pz_ւ5vV5,?B'ASȡ蘅2W"I̭\ʤF) '*%q5ɟn&:3֮n%٨ߌ^= s\ 36늿JQl\%[,L5uv i4(B^2m([`QaڀLΌ!WIZ# ~GiVgLCߒRwT͖G=i:6UE`oឤYsa0IS/la[_K@iͽح~we⮷ x&^8`V{ >rKZKPg%d[{v=5Ea)hy('w~6|xQ>ٌS-?Z=OӽrX!,`rc#pMl+=B}!u~DΜGW >4qjOM @<{C#֓Yb[;BWYT}Q.'(~-7'qN"Wb w 2ƮhCg,!6 zj:ZZt1V]#>vwu~'w.icEDGxvzi):l\]h8'Ccġ0Ri=RnuS'Vt%dqXl ̸創^lc 2!i/"FiYH&q&-F{h(T58j+ NN@O2܀Q\1Shr|8FȦ¼r7{eb>Ƞ,8 Շ2p{z\1t(4ECrSe|nViQLңkOͺYrlih%\މg/8UI 6$ѐ_kAI ;(uTIg&Slj-KEp|Q/W_z")n&<~muLMfّ!A]Xnhuh%IK8LÖ2r$ \Hg17@ԙ'=&ןb ڛw/-'HݚeqmNa)ph:Q,#^\ v<~G-DI8oYcb()jJD{38DڃK΁7qX~LB^B68Tw;W}alΩ Oq&[`,a:9JT@nƂ0Q/%bΌe7.cgM[0E5x2h0t}|4CҾkr0@+>|pb># \hCBV {U.B7!dۨd>t_)2 &!Ӥ4|o2)C4(V $o 6(vUa7wd|^QiΝdn4,pɊcE=10󭺠!+*ފ=ٔ9 z}f`[ܦOg.EhVǒ#0ɤTŮm_+;=-C&SeK,A'զ>뭫lD"V>ik-t)D# AG)aF]b,hS3P2nhhqgad`o/iwq>Wx6r8)M׆~bVMuD/SU〒쨇0c%dG -;_ü퀰~iCԻT:I@P1eNdܭeF-u!2<7\uW^ɣICRp=\<·ǂѻ 5lƂs@]a^Ǘr}^c+:Gi]T<*|=2F%6KE∾A;(R<>E ]tJb:hLQLa}q08vӸ R? t0m0j藝dR)kM|o0cp`s I ]݀yC5%oW= -gFY kV#IYHbVPBd}^\_wsN).vZz LNGP:n]H1UШ3 !XR.1HJCn8psS' u$`佚op1n4k, O xkPtCE}9R%=(|z6=6o(EWh|B[{BQj!AH"/$#TBƏG[/lܽ zL3$z^/"(Ŏ|ۅ^ ㍧iԤg SԢJ}ҵW6ɮL'[g8FDwlmPxVIO*e[Inj#N vVCUtS2+ht7YwU>T9+2x.++F2ˊB3q" kЛfjpv %|Wxτ?`h@at 7uH,,zv !wFq,& ,RHQu&6.)3OQNk"n3LZ8k!=GW:_fqo)W!wOG{cR~N5e%>MFxpkTT9F$"p_B"uyrǹ, a'kU,hSs aVcĚ=C5R}ذۍ?c,Sc-V>&Zݟslh| A%.A674ϢDWoeW8Q.amw =.'soNvѣ6[.@"#Xdzª_S ki%kg{g:J8L;#Zo@=u''#t<Zv׭GѡX luZ %J v~LN'KOx*¦8 ᖡe=k+*[z#S ڂ}Gd9gkIo$ j@]G -7sgwFHqdq:V7޶ycBB.:ˈ@%ddqIhnHJin }h0,{x@4ЈV'i[I 9˥I9fu+vKM0A_lɢ)oj'sn(]sm:ssFiT!Y&jEN%*)Ua ums Ւ8m7Xר~Z[(ۼ*j,t0o> -?lV4{qxLv" ؛AX{R-atC#$\Kzع`ϱg6)ʪ*}D6n/n˛p ƬlpyD)yX0argCOvl^.AbvLvA`lz1A1 b?EboemSdR'8S"NIm NotTn6+zGQ ;՘> ¸9dXkȨJSX˨ڇȾjgE_3CCBwŧe֞`fϪD("ڠV} ;u0  >n`~!@Fw R&bG["Bi 5 冏C ѦYAba"{)"}`zs_ e,]KHCy Pεyc1*oDgeL%-&1ĺע2#5uhIuձ/ 7f{%g=}v-JDu,#Vc_DZpjp5SwF(cg.i||}>1a,ǢBFSvJo:P;k'sܡLA%[itۢYA4GQ }( m^)h켛+%m*j6x wI+#t{pwk9#!=IÑ(Ό=u\iTPQX-W)?h] /'8bp[e2MmCDfu{,?R j3ZǴIabSmZG1U .dw'RY7ݷ0nǁ/P$E^:/U-g-9?Oc&t<r3dA .Ɗ [`)eUW#g'"w5N,$n׳\B#SH|46,HsD]^mBZNb8ʱgEg+v O3qVd^)g !!o;hF+-w_"uĶgLufӃ`V`F7>+ BKα]_%TCJ׭}0($o`@:˒Eݍw@hNWYp!GLoalq{|]xVpnEmOƱakJRg:aov%ϺpD'#{j@8AtK0}C\G4mfk=.S88y.Yl)c1\+*1 |P_%I-2B+VzfXB#:LpexѹQMETS'$EpgRBLn'o#L~Ce<(<Zusf`N@e2U"vW*HIƿ+ ֲjR{dE@1Z!g#y9+ #`FbE@隙‡{꾹΀axٔU-Rt;9Xӷ:daz/f\?\#dp mJcӛ0—A#餥_fu$QI4A6_Q0|)L^K !q3U+fa>|aDfYS@*-aM [OS Gh~nxLF 5S(;\Y?мPX" (kVݗ"-- Ku@t58ګS}H:ݿ픥a"Clf~:ENX#?bxË9ȟZ;nSi;,x.xБO)*2gΊtI2"Dhy2IQ @RJ%^ֵ/ZȒWt`lk ^qtD|tpm y9\1Ԙ> iEFge IF 2oQè4Aɧz rš`J1p\7|=lY;WD¼L1:"c>uES$,@<ÌO'z4,Yԫ'iw{D: v~(g?LRׁ0)Ha@(`V[j:q7ܬhXL"{O-ڻ8(u9^+;&΅*+*Pxm1jTnc55s8,'; jBB]==]Aؗ{.oDFz8##۷17 ǜxkNIC(AphB<ݒBW |93Y}^YY&rV:1PgwCd?jxQe棐ݺEA xdp!'ttS{DD#, %p< 0HH,쓴  5_9Hg;Bf#01d~3ENg__B{`Wf#٣?X\Xrte;>B8t, 3vs1={z,< UcvnVsjv c y0@>!`6 'W$G&PbZA?AѷsZ>TE SU@ ,w69iU!]~0~x&_f8$n6r|Y͇=;=!Ù0Zʰwxya_bhy8HEp g.K_W+plN< F!t8:18r UcRMk2v0=Ъ:2FmE^#H#s6TqyL*gI q5ĸW;fJ"< D\!0n ʵ&*3GI9K5_=1ѭO!0D]P} c[Ҍ_Kp Vk QkNLa|~Ø4+lfv7UCu4TpIխWq"O1ڳ# &upcpwcŨ2Dxꋻ}d79@{ab <7LPVJkeOevVQñwvhœp3p"f:˳X`OGa%" ;/"kK3juWWmmrdPF{IOAmąekW8TAH̥"gl/p*X_tu IbKG'$9SCu)!8'JP{+AZRK:bmjݐcl~qՠwcHϽ$w;hXt- x:ѷN |"eUA0z1VfFc塃po (윇g{Xs7UҭG=Iљ.$5~@ `l#5h)Sl8L\2b`MsQz9 )7 Ap2$]S%^:biN[J=/Ksķ݊2uN7u)|C7^Ӌ{aѧ2]HyV09#΂qt_9N l>.PcB3?>M&jK`j1+!F U˴$rl@gH/tBi&yeezsIʹT> ;kEVX+]m_zKr9=ZOE `.-<#Fn ŻXO-I;%Qp&xb9EVg !钰á_(XOf4wWy`as!AA 6>??8k@6vQDDIwMeOn5 K=݈3>ET#z5V_?{Ar7\qSx8yڋ>?+V9 kFIp~JyHb1yS$? Car1o7 []^!XHM$Oݖ!KbEh';nʕ1L(3 (; *Lt}3ApsJNc2-"34Ƙc.;WނwSe"2*R .3}K[B ?} r ʡosݼ9 oPC"c+|ZVD $vdz }!j)cJHU딂OߔmR7|+K _/etN \Ł1^E:Ԉ DrP*LlkPs@`Gik= 1" n(R"_7 qf'@*u70NQvy>->&TXo4yѓPv824'Ѭ~<Ԛ[!KFY!gLK3R3@b58e/?)@99A$J}p͉5D3A>S&fq=LThb`7 cVc#MzH?"2RL4Z֒ˏyVOh^GeB(a?rr;k DlgZ=LK? '=LH߁)9&K/3!/ݱ@]36G'!o6Nnb 7[36KH)# sHWDЌ5+x苚=)K#3-VIƠCsckYq=)vw "kys]`1S>bha&.m1W^@u7/lܳtMgZ3v20NT #XUp&.(1C2smSd;F{ǚK+{M/֜hMR{+-6&K l径*@M9g&s3B4"-+Gx1U#o/_HzŴޏ'IJ|t`>M }mmYdԱz2X&(xD}bOT9YVKv(Ħsmo7ۆxV`c˗|Tm]7inY@?~CES-U)xT[4frI1g QB&Ӗo8EK vU@2S8'7ZXKWt]ߊ =X.[_P-݊I g&rIč#f- {AeƗqp7MaC>a3gr!wϭyIBaV8=Cwip^Pb;Ua۾zh0έ?e}‹?|q>/pq DDVɯWYKt/&08 >M\$r@Hz䕿G@?W-}@6kzE>]'bS Ų\}wMŸk6!2 { ?nEKy[ax8fuif-FYF Ov4*h[{ʟ*H=K{]^,Ωkv x,s *h`g(oz}1~bb3\Rf URž*MDO6êٲI֬9RB8kaqؽF*AVA=XQ݂[¯s/MU0jhay-Þyum)]u7z8 ܆;.yFˊ}ov|*e(ҿ!2&w& n+I(C] ]< %uHNW -mڎ'!\_vp d`mqE a>|"VwThLr ;SyS!lˑ.Bocݱ3 wۀđ\Ջ1(16]19;b\Ԙ0½A L?bꮵ>@musS`1~Jv)' S;j)t I~2d†wr!kqox9 V?Z۟IbAQNBgD4UVgE&:a31fƔvmZ/)_>?ij/dY`~{"UvHHs\ѧ,&6*7 {z-M!ky#Q-}wV)?0pˆ#:89@uy e_߻.RhxƤg;NP%1QC2:Si 8!<;)rE-qM!t[Zdoz쒔'Pk}: IbCWgf::.xS`Po8m1`n7S7[mkdJ','daGRKvO@wd)rCb()ïtܟ}i1R8)IU88h/Uwȯ=Ml_]*Ж~5SaBUN6 !,]a@,I|^yթ\[-e0Bm6߉Bv-,/97vաӳ聁݃:^ĔZqtjPW$БKӈ5L"@ 〮YjD2b>߻2}pЭl-=z-N쏫52QҴ;zZ@/jd;aD #keP_Fk9& pMnQpTQakbp R#5!@RGlVp1ĶǗGB;oF?SЪ;l"BR lL Dn|ά> ߋQ2`,TD##-Ĝm52.Iktu?sq\VlWBrx/$H~Fjoa _A ya`+DrȐFFD<> уrV-c4?R#QrbDXd>hw45# D8RyD~*CP.~όDk96`Ꜹ"=a3c(n4xϿy=W h+G9|vvɽ{ Š",D%EIȍq,F tW v"cF0lU iz\\CUhE\([^}t~g"ǭH"ʌ}OZlb3NqOč$@'Uԭ'"6{8C%DH vIqņ-a.)f녃XsW ga9$3#xy$-mI&hՕ(96u_DKPN4Tb+W3 7}}bI17c:s_t+tPd(Й~?e@*k PxV'`zifγ8i 7i&ʏtvjLJ$(]^)ό3W6A2w@C0J%eS"s3}v|T~|Oi>ÞD~393/SNuWNseFȡ2Bki[*(D{hL;igg qlDRZ&}lswx04[')T!h(@.ʵ*Cek/vY:oEމWO+n#Y*n&'/WgއYeJhOl:0Q ǩH?JUV<xI$Knm&G_YJHxZ/]ܿrEZY05vSy6~4n #vrڔّZ ,lB޾2>Rc8PAݝs 2%͓.'OS\R0m;ko/l z9Zt64\x{բ,bcA?84 Ό N-_4}6!CY %}$\ѻd w4:"$3~)%P BZЫkOka&yODأէ4d67]3w("\Jb! cCl1R&AЏk(Q{Xr͎Ls@xiu朞> ,yNd{5Rn6.?ݬϷ$PQAҾd&-9їl4/Ɛ[b)~n2-JpAzK Ov+r+ලߛT* o#pc0̏DDh2J@kZb $09/9v?]4u5e$P5j*?HD cDĮeJŬԿk9J9 m])e0Q.mnJ~l>;Lq [(86x;{ D˝=53p=ѴfR%[$z?ZɂM iΖœؽ0k2Lvt8Z\եHd%tGC! VAJ%X;՗DU=] 骭kA/A5Gy?3'+=9?o]2-/l Y K>6Fs*Kl}CG- ibz7ҍ)]ۜq}JMRp,]]1 gngEFjqբBh.xpC%e<7o(XAHŏCVcH~:{oKvTcmCzUP18XRiqgaGfiGim,D @3Xpmprp_z 9HuXV7 ZB,!k dStuTc:W*7f Q}KbXÑz .bdqO + Rqj.Nҳqdq0̛0yÐc@ e,nn?^hՒC5TߙWј/$|cŀpjQ/:  -q(H߮¡A<Fg5n`-ګ&Ӊ#vsXj9n!cB{_ztʹ/܊R,Z B#)+xŷC|#$(l^JVYF ٯwGҳ -D&6B-.c%<Fj 9:4]|n5 hȧM7շcln+vJ|ȃ2֑݄0/qzHlXDZ%o^7C`bD]f=@-NJGt ܗj.xHCҚFcNwAnSVVb@@A ;PHAOàdQRC6 [a,DP(H*(I^n8oy:KD & dO&eZ  mh Q4*c]:dқH{Ӥ- #ɶZhX} 1WA7o'֏ĸV 6iAZ>j)Wy ,%縖u]g!J:QDT?#kP~'?MH*Hcr28TteQnTflYԌSddsrc<0opM.3ufA )J@}҅&R,fldV۟L7dc ToF9:<fxU,}ڢ . h$m~ q2pͺݑe1Bfk5Q8gn͋IzD&гzs..ؠn8`j]qcG9cjK./ 3H1#cyN _8wΆ-a⇪媄əN"='%d6=M"d+ qF< CLVtr QKܼn'#M(^}6xL( SA%ЕSewQ,V?Y{Ex'2z׸B/l뜈qՆ;5r=juo.E-7q85/Z IDгI)lN8Oma5kworۋ2$QC_:HvQxO'wUfRnDTmHS=Wd6bmLfDUYZޙf9[t"-"'`M]o-/Ӡ|f!F7w1@t~4ߠ*-3Ěx[v7;n't3 #tF ϫZEƨb f|G39pa1]HgR,Κa+m*Ņ]3f&tMӱCt௮ 'V͝1*;L)xL a7'%%Ia9ڋ"E7Hr}/@,!ϯݐg]]|(.e`P刢V9<~=v).#g9:u4 p5xuߎ yL`bb(zYxgd)( Z̈́2{cYZ Ո޳LJ:PY%IPr]$h>c@:zҰ.;+]H 4( Ρ5#!_Sg4^ |,0o5K7 001yM7"O{շ]RA㾑u$mQ~>ߟ&N5Cc^ygPJV[!впC(.xerR) C?Yl("#p T^Q"$r!T8W_KD5R7S}Ո PޢOf"$b%*Gk"%ƓV̘]R/n޿yi@1l3ݏ@( $ܖتn~{d$]c aTDh؎ZzIu9ڷջ#ۓ?-2L?)*0?Ti~Sd%1H)woSacq[Pmy@d9*|{&@lpwiBJKi&P|P*ơZJwf"h/piZve2)a $<^2-J0/6ڌֽ+AjRL J}DGj0ff1ju aFw{#wmĕ㦦#kkG?J)K\Wh gZ )|Nƿt8D[,\{1UG3/w.ڴ;iO) *|yr_-OOw5aSsN%5&p0p{ c!^Ѻ2ʶyr"qxx>C>H&E4mLZ$"|kБ$>Ҵm65?ϑ V w$w7ُȋU%{Q p^R׌|BLUh*Ms vO%&# }"UWP=YE[C4[Qn EJn|3Ɗ%N!gYjj;V"E<"P[\R8TNS|'~X5[̛~,94"Abt2+?ݒDk^`PkE'}x*1%faJ^򚡒]´o405!eGe&yTᰨBd/+g8v"2XUzf76#xwRzw*'kV`+ & AL-]^.TLQG=XR)ʌ& >pұaw} O_k*UX/*!bggЃhX ?׊sH\5^ofFUJ"*okZǞj)\.`w.N?l_u2QyPnˏ~F==w/:d3L(=)tq[,ߎ/B-f9)[aGG:cL(ͷ~!ؔ0Z޺>@N'x?hlFx|I砷k^"l߲ź=Dԝĝ\:BLx|DHgÑtvk/-` JMS?١>779bA)ӥw!]i? cMڡEPaB\&\075uO1KcD{-=31})|*nYBa~ȡ\a vX6tіƟe̾ASe<]#]UK&ƪfx)Gskos܇(}fV Z}\_r6Q'H214E%|MD_.i͎CI%`^F% $O6E~RSHiⱶrVȢWvwDqϸ? 6U݀:U-)؊_{#σ(N!`bO&蔭K-\} Ioyŋsnc~vVdLS䣣n?ZW+˰T SU^ijE<p]lwZz+0pi7"zbP20F4e?g%&I]犓Q|cXrU:p~hQfWp5tf09DnKy/J]م y4dW5Im?i_oRPn|(лY4&OwKZ/=M饙β7t.fI}Za3= vl(O2s%$#e'r+TZ`ڟS҇u`BfM pdQEqSbDPyDžA&C&@{鿇ih|_{ ] $*x1P)>?C6D~&yZ8?\@p0k Rk3z=EDG@2K'L%xF>E=HJ1gDze~rAg>/۶%F1!{l' Ƈ6* ojv')LY^&k=p,jj$2r2Z ڞ>{9G)yBleh\sUn%9V>f'&.*gⲌ(I3n5 IJPEuRWe{a_f"~CZfށ\\d$[ Xϼ6?^~MQc  /DO/H9pipgi70c%w<_oT|ȇvѓ^YV$BE*`R S6$hV}wY1"0!亾]JmRܴ䷣]$)Tq"(} b~{~QUgÅz9NRA8>L͎֟fl\]Qu99f6t)Й 0g0cO| ҪRbl/c!xZ7?9"΃.WhYȺoހV.1t/ŷLRM$dRYLTXSqm^l_c$җb=_y3l܊g.'x V턝53ȑO$9j/(YekGvu 1 2bԲƐDS.`+ V^j8s5SHz<)jBv8=$69+F| `eF:~yMꈗGpX9V_rɫCF00N ~4kl3b1S>L!ăca68X} + {CiwiS|^L{MXrfťX:ЅoпVM@v >MC^m_^$ZyOc}@z 4Gq!s/U#1=kܛi;<-aŖPD,J"cb eekUpd&RC o*rh'm2@<.dc"c3~A WF1KT;_zb+0&y[/|4>w"hz9H/:URlQ4 _|A_ԇ~~}1 qG0I&MXO!gG10dg$UO׻H(+rc}W8|$6 . Bc!>亳v{9e/*~faQ"_U!#Β !(:B}-nGA-38k)Rlg$Q(4UP= eT\M?:4#ڄ@ /̓K]evw 3`FMSO/?T-;L:Xn|j)16/:!T9b^!J4?:%8EI&jzZ"(͟…lgW4ˈoG_ OEb%Iʯv;z6^\-CNs?NoGEMHT:HǓpn{5!!\c~mE(Ke(b4s;5:޾8ح_\ 6)\:8jbҾ {γvJW0+ot7vcB>ƍWTAD^R@7{}ZnV3dĄ#: 7y Kˡ=B4)e֟FIb1Ѓhqd~hvjRWbqI7+)2b\^ &y;G9Q{{@oDD3e )IFbIo-V O38R/r1Α @l|\N=3YO+|W@ "LvۡAp=8rzyB䈬0ͥ9aIWdO%䕛{+w91kF%W٬'h[̫;>oCw{1gIkuRz>ք“i\-ZijٽĺWSL& !zEjҺ溕x<#69UTHȊ>frvCuUl~{)e#ߑؚv1\^yg"czewa .UK SIf&LayP~T%ڽ8w9v͆_`H:3~jy֭@^ c#=#?\S?\\L,ۇX}@Q<.|!JXeg WQ^[yxkw'E9z{w4oCubŋp>RNSuqX]gK)fa7'Vjэ*o&Euܯ̌w2Qnũc3w) P9h i&APu8+sTKU@4"xJr+c;rzBO*ᴜ{oX3 -xug,U!_t $`0sDR&G@FĽ[Fq^3/mThM*t%ݾ~f@T Q7N7@ߒ@5k0ԯ<[ׁ"qSč5?#Ieg ߑ2g +Z*~:EH[c(=llrkdZ^/sESiS:)M#t0zF+,+r-*W6vc 'šu#Nf]j !N<(dhbAډ6r LU*gyXS5 N|ᒤBZMѩ^briE:.bt8%, ]|Y/آm:b~rn 7rkTkMjF0@>U2Jɰ%h(1 BMq`< 9[AHCC򻋫e(WM`?5@tE70*8wTHzjWTBX)e@:փMkC)M _.x46e,3e%b $k[r"ӣ>YKv_/%88+J@oM`7,0bB_9tB5w`mZl %.ȂH{ }JHL\XJM-hڒ*>lEaX#H;X40>˂%kWIv'}$$7E;%fq${emA*ꯔ#O'~ݡ+G9r4M3+yt0s/(w֍S7QLb 1mP,`4Mb›jG^N>j\!:gg_7F JZm2<­(vW4rVC >-5@Y oի_[jd;F&)O4m;xOCR]}{%k>GDqǣg'/OT(v;J .9"I 45t'H<jhurrClVEFVnA87絠Q3 t~ԍ4v/7& aֵi4g^>u&%hYohekÄt]L1hO.ٵcʇ)w4Qdb?uRćjc42< 6B=f-zxVt+蠳f)T-#@9t "YH/ #{a߸^x P =qbUקb8_ ֭Y2_%50*]1V%|Lȳ}Z7qnx[tٌcl0m ѱC/A B:HAJdhk7 !!K!ͷl/{|kI~- ";]ww =e#yY@ߕЁ_֍S3@ kbXR=X.5A(j!EN2Q2ee/N˯֨.C \Bx$j1A5-ޡZ5 gc t͓uweh~۴Rj7Uy05 D`o(`]HIc5 PBB~-?N>)*\5vx ȧڣo3QlJuh0:rB}&Xrg_P;wyHJVw@Y仟{Tw#G^ZkSCHFl~CH. ルW\s=XWK3gSDv"rH+K"L)wE=^9z(n[0IVㅬF{H,ͫ1lDɟAH:]J5cTk I*\]@nSQ%D]CܺiNX.vEx֝I.CoQe:;^mu xEXm0jY%𯘛eAf*W,J_G$~Vx%$ڴd3?f4YX[25]BA:\G)hI#ȝlAqDm4GUz#}›X`Z]M$;$HBq7Z9?E$YQHNg~&ĠU@FԜ^v] c9l 0Ke:&/#WE؋ j^hr/w(ʼn l4S0W"(?7<>)ppv[8ǽiǒo=G ѢOjp)"s]<`4(q+ʲXMA>CJ(]% dfcY-d%/-6rYHE8]p cRktvREĸh>źjDb >ŴeOJaᲿ?6O@E ARм -|A"5BHkH^{ POm?n(X`LF 0.֖a :N'nG0QW7$%i}Hjxh(iCUUgDKnL'QlwngY[s ޼F!o֝w;k9=~ʸQ31Ox;K1ˠ@KM:FkcGي3T^LΗ*&3ؼ"^Lt7evM)JYzH:I:!JV5SrMhTVJ0'}/-d{c)qfpl0wf8ed@b cfs$75;]*65! 6@j^닱nIay*dWk; 5j*nvQJ~miKh >fyDh9{|_ `^ggpiC̨KޙaEݚF + G8,=䤙a-/K׿Ys(3!+}oO9 duUxrAsx8ws)d 2cs$J;X#T(\bڮT=]hEuB>ILkkK1O{YI8SBrAԦS P4.V6jF5Ə7㕟z,VdQZAa런H?q_kFط`*MƔTa/,o9]3Ku5i%Ev{:ahdU3XhaZ}6ײ+u`jk' {}֘cBmU+gc̘1'IP^Q+JlA<T[w eC@O0B&ؓ"~ȹ?էh`&6@UyF\L.BL@"5rE]pnB S驲؊p+{V)l#/^JEvuGSϨѤ6? س O:4Gz0[^ZX(&UW9פtd}5P4Rҋd !G'j,s̿Q f@CtyN  ?*Orx` %0oa. D!M aiVԭ0!W]0n͠tJN~ٶ_ji?' 8*^HB~(n F>|{SbxysCwK`Ugve}}I(bc\"O-RտwaJ(;fL7weJawx\ԇ Iu@UG/{ !-|-WJS| s4J]=87MG8K'H(Hv.JW: )"%\-0Oݙ`e&G/ע0{Ӄqs (6*UX߱zTMf1uW +Cam/DZ+@j> g]%FR7OıWdz5GoQ4a'JZkP$JJM?T#6f;O|BwZ=jY2羋0=adcƪ6Ntk_w4 >YLݓƃTjP` V1тU*Y>a-m'tڨ+Â1:կ Uz ?dli]FƎtMlsq؞К'5H-M޼l!Ǟ#uhNNd{ׇ \:,оQqMnL #8CZ s> p.d# =vAm{MCu&Iz^|ciѸ\̈́Nߘx C"¿+ 1,iȽվ81a{HwW~"fQK|@t~s;GQ6֚qUm<'"މq[Ȇ"2Ftk$qT0~~. B:3;i^׶;b^C;E=_ (GU^8; dtэ XH*<4gLՖm aCxH|ĔD^7ݤz^ =[*>Π= .I J<vk7zOHU緍lz"Խat7hhJL?_;KQ_װ 'NFʅ^%V_ & (QƺLIMi7_/f3p 36}$jSfz(" ON1XlEӆB 7\$ư 2B!7Hi#Y]:'0SJT?d``iGsɌ]3i͕>MY&D8>$FAj蠹 0pNe!08=6Cewo:L0cyCfDӖnMFjXa]^hQE" ɋ-xRW!=eH%W{uŀYd< %E[ٝw\ 5# ^wʬ-!Y(x5I U8*0]c'Bu4NҁSG yj%@5A}-Jf?b.gemG4Q9]d\zn*8rw+poJ}wq_@o/*zn!«?*I!RܢʸtiXоE\oReN B :s [r`Ȟ'v vzύ Oߥ-b8v6o3C`3Lz*_ÆG݄FM;x 9MK)1@ K2܀p T<ųs#9?Mw Ͽ!#6'Ntǻyg6jƱc_VJ3<=1k ډp$?]\esqzpة|[ٓU%݅e. )È&GԶڛxO"&vk:G_  6svʍUKۑ#bpE`o H" 5|hc%c.]Ss&pQ E:5\;m%r"lT1kPW?ZL(23m +RT (lWwu#<;bL|ݵ9Y]r3+XY_J =*'Sx0x`3س]>!xi8| 0UǪe+yi W%M[3B.Xp1HçpK}?aſӹB7cXmn6Z[*r{usQfR%-l>᾿x=kZ *f'oS_>P842[vG)FۏaUr>>/5$5E&M`G[r&J?p>JW Bž7 }ZvMra e; B@Xڤ"=ǫ& FnyInna߯ 0z,<1}, ӿ ֬kLs*-hL2"2JH@DqliEv2xkZݼT:l$jցOBtv}VncY4Q}p甘J@7485d%K,= @y( sXGx* ǂY~#fخlqBH7#b=`(PU{S6~ ?sTm\f =,uɺ >ۯiʢ؆JnĜJ>ۘrQ \(Eƽ41H>0{_v۶w7͝)v8VtZNS#rHxu]!K nbnijMse@kק<Sc.;C1L9RH!oyq~DCYN'-@}- fU}csmTp[igf˔s7b\eXco{7;DTp,>fFU0i 9GON>QcCxZW} LGpKm=YkF/jI4DאYbsD,uWGNt>LV}3u.C&H1%V5{dcׄŊ@R'^BVgMB|[=yH3l >:nf/s~q̐T|;_w@Uw%0 ݹH!w=D+3T|B-urehIĂMjO%d->~gGKEahy0YiHH.|l xP2bHOQ4#|&ePZ]rJW1x&xhL^󕟁,ϯ\.40 -&ͰNY%lV>f>YHl-b*#u|[%=Ygd=Wd8#UJE]u aJYQR:6W$gɒC3}dV 1o3|"oVJNOL<00Hћn帝UO/ۜt굎Li5ݨ>qrYuO4% ,f3%3+B/_eȱT<.4Ul:}:ٶ!&ٵ-cdpCKF$6 Y ԫ׀1Z38ӍT.Y<,{X\f 僧+75_?JYV R 7)ƙįmV[wVkʝ^`3"V+)? پ砆k$YԒYބ}w}o1`Y`0֦eL^ۏB2:|rkEpBE0Z T|!I/F=Sz2Djy&?~M%Fw})Kާ[gS0>9`Bko@{ ӣ[vTU)oWΛq_^q8cz|j{]!}d dt)W[p+/Fh4BwǤF"BJO{Eb|sˎ%0)s 0E+ h?92usZwd\qԈ+ oQ8o%h)}wv> j'OWn]8 };ϥ")9 YJ\tOoa,!LO\A c,3)S6V] 8;]pSZL߼YnC1]YfYqsDv%P-L^Meth{:ߐF?E'NI6 UoWYLV-MhUKln_+0?$ #4nϙ)+KWC7c.8cd@7 5də e Jp7\m|1cVoygPa9Y۰.J5MO(}p,1@6JȠ@ZSXQ/,Q[m~R%)qp){EB$q KlktK0٪=aYMPZb#6sk< R ;$KהUO'rAu^WjykW:ͩبv姱L*{b7wL@KE6OK3()fdÑx=G0\''<<_3rHr/筀>ȉ&Nr]\"eDP$}p%;9"T _jucdR +AT׼-,"T7Νdx@鑙ͱOQD}Ga n}swYc{sz P*1= $yj?;"'qx}dAY_H [~l88tAܾk,2keӵ!hɂ3[.E;H^ 6 J 18 EG=$d=c_}dBfh<ƪĽ$f5쐴 %d2OcYarL"ίzf ݅vUwBMT 8aY+ā>w xrDnB|K~R`+X"FEn' c }m Q[) Y5g陶W63H08x^Zr4e?MGFt[e|2o#1*T##{ 9Hɭ]䥚]q!uA&42EL3U{QϹE΀)UijJ2YH'5J3_|Mz Ϫ2ΰ捠<wh"_;}xJ='ZU \zlxOOv^,€:8:TiF\(O d@{aLKGV+uc`)TUB'().<ϘceY|Rтm( 9[\2i 5ie+͟/[%fx] d ,CgSLcsi#>hFڙ57Hz!'5#Evz3s[S#R4#n!D\6fUVFD^W_/ D@Y4 6ܢ n\E#{ l EbdA^3K";`'S0扪5yWj4=[)koHL=F\)a^$H,x4gii6eYlPtW~*97mOǖY{׽0t~\vDHД͘g"1D.CSY[צ}b*j2(j!^ĩU)(b$mQ 8wJx^sU.bb?2_a\2h*r6Ǻ}qݭ}HtرB{]VzU kJX{,a9fhUI0wHG۠GV T2I6]me}#ĪkpHmKzhZUReE24 U9q?@Z} {OZTSJQ0n3(Ҁ]k1y?:*C$K0M^*_DZndX;ofl/9a-0+̅Cw/"Jʩ7cH`Vpuc>V79y#T1k(W?-;# :F^^C'4umԺ֫Anh'bŰ|[CGhVhfDKPNN8cni%qgH:j /ĩ 627I|H9MsfRr$pж|WYF,6}o_4ϬUj?nVEc4^f ]xDMe4~ A ⢭!`=f7lN ES|;a-_Į (Yby^*cd1:3Fum *AVEX_fSL`0xz-oS ݣ_A~&GslL^#*~@WD3*0]nf I`= $~f74|5.6a(RP䯮V`&D:V=JSYo5$6>=^DAL1؞Wen f)ôuP7xΟ72Fi wfS X24U`~~)\'Ntdqķ9ǜ/XytN7\]Ç d_E鄳%`^ t|ٯ;7ϙ AX"սzpaqfranz-62.2/man/000077500000000000000000000000001477324740300142455ustar00rootroot00000000000000zpaqfranz-62.2/man/LICENSE000066400000000000000000000022711477324740300152540ustar00rootroot00000000000000This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to https://unlicense.org zpaqfranz-62.2/man/README.md000066400000000000000000000001361477324740300155240ustar00rootroot00000000000000### This is the "man" for zpaqfranz, written and released to public domain by Franco Corbelli zpaqfranz-62.2/man/zpaqfranz.1000066400000000000000000000325421477324740300163510ustar00rootroot00000000000000.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "ZPAQFRANZ 1" .TH ZPAQFRANZ 1 "2023-09-12" "perl v5.32.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" zpaqfranz \- Swiss army knife for backup and disaster recovery .SH "SYNOPSIS" .IX Header "SYNOPSIS" zpaqfranz \fIcommand\fR \fIarchive\fR[\f(CW\*(C`.zpaq\*(C'\fR] [\fIfiles|directory\fR]... [\-\fIswitches\fR]... .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fIzpaqfranz\fR is like 7z or \s-1RAR\s0 on steroids, with versions/\*(L"snapshots\*(R" .PP .Vb 8 \& Conceptually similar to Mac time machine, but much more efficiently \& Keeps backup always\-to\-always, no need to ever prune (CryptoLocker) \& Easily handles millions of files and TBs of data, non\-latin support \& Cloud backups with full encryption, minimal data transfer/bandwidth \& Data integrity check CRC32+XXHASH|SHA\-1|SHA\-2|SHA\-3|MD5|XXH3|BLAKE3 \& Thorough data verification, multithread support (real world 1GB+/s) \& Specific zfs handling functions,full multiplatform interoperability \& Particularly suitable for minimal space storage of virtual machines \& \& Windows, FreeBSD, OpenBSD, Linux, MacOS, Solaris, OmniOS and others .Ve .SH "COMMANDS" .IX Header "COMMANDS" \&\fIarchive\fR assume by default a \f(CW\*(C`.zpaq\*(C'\fR extension. .PP If \fIarchive\fR contains wildcards \f(CW\*(C`*\*(C'\fR or \f(CW\*(C`?\*(C'\fR, then the archive is multipart, where \f(CW\*(C`*\*(C'\fR matches the part number and \f(CW\*(C`?\*(C'\fR matches single digits. The concatenation starts from 1. For example, \f(CW\*(C`arc??\*(C'\fR would match the concatenation of \f(CW\*(C`arc01.zpaq\*(C'\fR, \f(CW\*(C`arc02.zpaq\*(C'\fR, \f(CW\*(C`arc03.zpaq\*(C'\fR (...) until the last one. \s-1DO NOT FORGET THE DOUBLE\s0 QUOTEs! .PP The help is embedded : please use that or read the wiki on github .PP .Vb 5 \& zpaqfranz : short version \& zpaqfranz h : list of commands and switches \& zpaqfranz h h : help on everything (ALL IN) \& Help on XXX : zpaqfranz h XXX \& Examples of XXX : zpaqfranz \-he XXX \& \& XXX can be a COMMAND \& 1on1 : Delete folder2\*(Aqs files with same name/hash of folder1 \& a : Add or append files to archive \& autotest : Autotest for hidden errors after compiling from source \& b : CPU benchmark, speed index in (yes!) franzomips \& backup : Backup with hardened multipart \& c : Compare one master dir against one or more slave dir(s) \& consolidatebackup : Consolidate multipart backup \& cp : Friendly file copy with ETA (resumable) \& d : Deduplicate files inside a single folder WITHOUT MERCY \& dir : A better dir (yes, Windows\*(Aq dir) \& dirsize : Show cumulative folder(s) size \& e : Extract file(s) on current folder \& f : Free disk space fill (=reliability test) or wipe (privacy) \& find : Search file(s) with wildcards \& fzf : List archive filenames \*(Aqplain\-and\-dirty\*(Aq \& i : File (archive) information \& isopen : Check if a file isopen (by other software) \& k : Kill (delete) everything not in archive (RISKY!) \& l : List file(s) \& last : Get last multipart filename \& last2 : Compare last2 rows \& m : Merge (consolidate) multipart archive into one \& n : Decimate (keeping the newer X) older files \& p : Paranoid test (slow, lot of RAM needed) \& password : Change/remove password of single archive (no multipart) \& pause : Halt script execution until time or keypress \& r : Robocopy one master to multiple slave folders \& rd : Remove hard\-to\-delete Windows\*(Aq folder (ex. path too long) \& rsync : Delete rsync\*(Aqs dangling temporary files \& s : Get dir(s) size, return free disk space \& sum : Calc hash/checksums, find duplicated files \& t : Test archive integrity \& testbackup : Multipart hardening \& trim : Trim .zpaq archive from incomplete transaction \& utf : Convert filenames to latin, fix too long filenames etc \& v : Verify archive (against filesystem) \& versum : Hashdeep\-like double check of hashes \& w : Chunked extraction/test of very big files \& x : Extract file(s) \& z : Remove empty directories \& zfsadd : Freeze zfs\*(Aq snapshots inside archive \& zfsbackup : Backup of zfs\*(Aq streams \& zfslist : List zfs\*(Aq snapshots with wildcard \& zfsproxbackup : Backup of proxmox on zfs \& zfsproxrestore : Restore of proxmox on zfs \& zfspurge : Purge snapshots with wildcards \& zfsreceive : Restore (with zfs) from zpaq archive \& zfsrestore : Restore from extracted .zfs stream .Ve .SH "OPTIONS" .IX Header "OPTIONS" .Vb 1 \& Embbedded help on optional switches \& \& zpaqfranz h main : main switches \& zpaqfranz h franz : zpaqfranz\*(Aqs switches \& zpaqfranz h normal : 2nd line switches \& zpaqfranz h voodoo : nerd things .Ve .SH "EXIT STATUS" .IX Header "EXIT STATUS" 0=successfull, 1=warning, 2=error .SH "AVAILABILITY" .IX Header "AVAILABILITY" .Vb 2 \& https://github.com/fcorbelli/zpaqfranz \& https://sourceforge.net/projects/zpaqfranz/ .Ve .SH "BUGS" .IX Header "BUGS" .Vb 1 \& Provided as\-is, with no warranty whatsoever. .Ve .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" .Vb 8 \& Running on "weird things" requires compiling with the right switches \& \-DNOJIT : Not\-Intel CPU (ex. Apple M1/M2, ARM...) \& \-DSOLARIS : Solaris\-based OS \& \-DANCIENT : Very old system (cheap NAS...) \& \-DBIG : BIG ENDIAN \& \-DESX : ESXi server \& \-DALIGNMALLOC : Enforce mem alignment (sparc64...) \& \-DHWSHA2 : Enable HW SHA support (Ryzen...) \& \& Use the autotest command if necessary. \& \& If the executable is named "dir" act (just about)... like Windows\*(Aq dir \& \& If the executable is named "robocopy" runs... some kind of robocopy\-like \& WET RUNS (\-kill automagically enabled), with \-space enabled. \& ex robocopy /tmp/zp /tmp/backup1 /tmp/backup2 .Ve .SH "LIMITATIONS" .IX Header "LIMITATIONS" .Vb 2 \& zpaqfranz currently does not store owner/group (it will be in the future). \& If you really need you must use tar. \& \& "Strange" systems with little memory (NAS, ESX servers...) can crash. .Ve .SH "FEATURES" .IX Header "FEATURES" .Vb 1 \& zpaqfranz supports \-stdin and \-stdout (zpaq does not) .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" \&\f(CWbzip2(1)\fR \&\f(CWgzip(1)\fR \&\f(CWp7zip(1)\fR \&\f(CWrar(1)\fR \&\f(CWunzip(1)\fR \&\f(CWzip(1)\fR \&\f(CWzpaq(1)\fR .SH "AUTHORS" .IX Header "AUTHORS" This is a fork of zpaq 7.15 (released to public domain by Matt Mahoney) made by Franco Corbelli and released under \s-1MIT\s0 in 2021\-2023. .PP Licenses of various software (more details in the source code) .PP \&\fIPublic domain\fR for zpaq, libzpaq, \s-1AES\s0 from libtomcrypt by Tom St Denis,salsa20 by D. J. Bernstein, mod by data man and reg2s patch from encode.su forum Sha1Opt.asm, 7zAsm.asm by Igor Pavlov, PDCursesMod and SHA-Intrinsics; \&\fI\s-1MIT\s0\fR for Code from libdivsufsort 2.0 (C) Yuta Mori, 2003\-2008, Embedded Artistry, Nilsimsa implementation by Sepehr Laal; \&\fIzlib\fR for Crc32.h Copyright (c) 2011\-2019 Stephan Brumme, part of hash-library (\s-1MD5, SHA\-3\s0), crc32c.c Copyright (C) 2015 Mark Adler; \&\fIThe Unlicense\fR for wyhash (experimental) by WangYi; \&\fI\s-1BSD 2\s0\fR for xxHash Copyright (C) 2012\-2020 Yann Collet; \&\fI\s-1CC0 1.0 /\s0 Apache License 2.0\fR for the \s-1BLAKE3\s0 hasher and HighWay64 hasher; \&\fINothing explicit, seems \s-1BSD\s0\fR for Whirlpool by Paulo Barreto and Vincent Rijmen; \&\fIalmost-unrestricted\fR Twofish implementation by Niels Ferguson. .SH "EXAMPLE 1 create a temporary file, add /etc to mybackup.zpaq" .IX Header "EXAMPLE 1 create a temporary file, add /etc to mybackup.zpaq" .Vb 2 \& echo test_ONE >/etc/testfile.txt \& zpaqfranz a /tmp/mybackup.zpaq /etc .Ve .ie n .SH "EXAMPLE 2 create another version (""snapshot"") with different content" .el .SH "EXAMPLE 2 create another version (``snapshot'') with different content" .IX Header "EXAMPLE 2 create another version (snapshot) with different content" .Vb 2 \& echo test_TWO_FILE_LONGER_THAT_THE_FIRST >/etc/testfile.txt \& zpaqfranz a /tmp/mybackup.zpaq /etc .Ve .ie n .SH "EXAMPLE 3 show archive info (two versions/""snapshots"", 1 and 2)" .el .SH "EXAMPLE 3 show archive info (two versions/``snapshots'', 1 and 2)" .IX Header "EXAMPLE 3 show archive info (two versions/snapshots, 1 and 2)" .Vb 1 \& zpaqfranz i /tmp/mybackup.zpaq .Ve .SH "EXAMPLE 4 list the two different versions (look at different file size)" .IX Header "EXAMPLE 4 list the two different versions (look at different file size)" .Vb 2 \& zpaqfranz l /tmp/mybackup.zpaq \-find testfile.txt \-until 1 \& zpaqfranz l /tmp/mybackup.zpaq \-find testfile.txt \-until 2 .Ve .ie n .SH "EXAMPLE 5 restore the first version of /etc/testfile.txt (aka: rollback to ""snapshot"" #1)" .el .SH "EXAMPLE 5 restore the first version of /etc/testfile.txt (aka: rollback to ``snapshot'' #1)" .IX Header "EXAMPLE 5 restore the first version of /etc/testfile.txt (aka: rollback to snapshot #1)" .Vb 2 \& zpaqfranz x /tmp/mybackup.zpaq /etc/testfile.txt \-to /tmp/restoredfolder/the_first.txt \-until 1 \-space \& cat /tmp/restoredfolder/the_first.txt .Ve zpaqfranz-62.2/man/zpaqfranz.pod000066400000000000000000000212061477324740300167660ustar00rootroot00000000000000# zpaqfranz.pod - zpaqfranz 58.8 man page source # # Copyright # # Released to public domain by Franco Corbelli in 2023 # # Description # # To learn what TOP LEVEL section to use in manual pages, # see POSIX/Susv standard and "Utility Description Defaults" at # http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap01.html#tag_01_11 # # This is manual page in Perl POD format. Read more at # http://perldoc.perl.org/perlpod.html or run command: # # perldoc perlpod | less # # To check the syntax: # # podchecker *.pod # # Create manual page with command: # # pod2man PAGE.N.pod > PAGE.N =pod =head1 NAME zpaqfranz - Swiss army knife for backup and disaster recovery =head1 SYNOPSIS zpaqfranz I I[C<.zpaq>] [I]... [-I]... =head1 DESCRIPTION I is like 7z or RAR on steroids, with versions/"snapshots" Conceptually similar to Mac time machine, but much more efficiently Keeps backup always-to-always, no need to ever prune (CryptoLocker) Easily handles millions of files and TBs of data, non-latin support Cloud backups with full encryption, minimal data transfer/bandwidth Data integrity check CRC32+XXHASH|SHA-1|SHA-2|SHA-3|MD5|XXH3|BLAKE3 Thorough data verification, multithread support (real world 1GB+/s) Specific zfs handling functions,full multiplatform interoperability Particularly suitable for minimal space storage of virtual machines Windows, FreeBSD, OpenBSD, Linux, MacOS, Solaris, OmniOS and others =head1 COMMANDS I assume by default a C<.zpaq> extension. If I contains wildcards C<*> or C, then the archive is multipart, where C<*> matches the part number and C matches single digits. The concatenation starts from 1. For example, C would match the concatenation of C, C, C (...) until the last one. DO NOT FORGET THE DOUBLE QUOTEs! The help is embedded : please use that or read the wiki on github zpaqfranz : short version zpaqfranz h : list of commands and switches zpaqfranz h h : help on everything (ALL IN) Help on XXX : zpaqfranz h XXX Examples of XXX : zpaqfranz -he XXX XXX can be a COMMAND 1on1 : Delete folder2's files with same name/hash of folder1 a : Add or append files to archive autotest : Autotest for hidden errors after compiling from source b : CPU benchmark, speed index in (yes!) franzomips backup : Backup with hardened multipart c : Compare one master dir against one or more slave dir(s) consolidatebackup : Consolidate multipart backup cp : Friendly file copy with ETA (resumable) d : Deduplicate files inside a single folder WITHOUT MERCY dir : A better dir (yes, Windows' dir) dirsize : Show cumulative folder(s) size e : Extract file(s) on current folder f : Free disk space fill (=reliability test) or wipe (privacy) find : Search file(s) with wildcards fzf : List archive filenames 'plain-and-dirty' i : File (archive) information isopen : Check if a file isopen (by other software) k : Kill (delete) everything not in archive (RISKY!) l : List file(s) last : Get last multipart filename last2 : Compare last2 rows m : Merge (consolidate) multipart archive into one n : Decimate (keeping the newer X) older files p : Paranoid test (slow, lot of RAM needed) password : Change/remove password of single archive (no multipart) pause : Halt script execution until time or keypress r : Robocopy one master to multiple slave folders rd : Remove hard-to-delete Windows' folder (ex. path too long) rsync : Delete rsync's dangling temporary files s : Get dir(s) size, return free disk space sum : Calc hash/checksums, find duplicated files t : Test archive integrity testbackup : Multipart hardening trim : Trim .zpaq archive from incomplete transaction utf : Convert filenames to latin, fix too long filenames etc v : Verify archive (against filesystem) versum : Hashdeep-like double check of hashes w : Chunked extraction/test of very big files x : Extract file(s) z : Remove empty directories zfsadd : Freeze zfs' snapshots inside archive zfsbackup : Backup of zfs' streams zfslist : List zfs' snapshots with wildcard zfsproxbackup : Backup of proxmox on zfs zfsproxrestore : Restore of proxmox on zfs zfspurge : Purge snapshots with wildcards zfsreceive : Restore (with zfs) from zpaq archive zfsrestore : Restore from extracted .zfs stream =head1 OPTIONS Embbedded help on optional switches zpaqfranz h main : main switches zpaqfranz h franz : zpaqfranz's switches zpaqfranz h normal : 2nd line switches zpaqfranz h voodoo : nerd things =head1 EXIT STATUS 0=successfull, 1=warning, 2=error =head1 AVAILABILITY https://github.com/fcorbelli/zpaqfranz https://sourceforge.net/projects/zpaqfranz/ =head1 BUGS Provided as-is, with no warranty whatsoever. =head1 ENVIRONMENT Running on "weird things" requires compiling with the right switches -DNOJIT : Not-Intel CPU (ex. Apple M1/M2, ARM...) -DSOLARIS : Solaris-based OS -DANCIENT : Very old system (cheap NAS...) -DBIG : BIG ENDIAN -DESX : ESXi server -DALIGNMALLOC : Enforce mem alignment (sparc64...) -DHWSHA2 : Enable HW SHA support (Ryzen...) Use the autotest command if necessary. If the executable is named "dir" act (just about)... like Windows' dir If the executable is named "robocopy" runs... some kind of robocopy-like WET RUNS (-kill automagically enabled), with -space enabled. ex robocopy /tmp/zp /tmp/backup1 /tmp/backup2 =head1 LIMITATIONS zpaqfranz currently does not store owner/group (it will be in the future). If you really need you must use tar. "Strange" systems with little memory (NAS, ESX servers...) can crash. =head1 FEATURES zpaqfranz supports -stdin and -stdout (zpaq does not) =head1 SEE ALSO C C C C C C C =head1 AUTHORS This is a fork of zpaq 7.15 (released to public domain by Matt Mahoney) made by Franco Corbelli and released under MIT in 2021-2023. Licenses of various software (more details in the source code) I for zpaq, libzpaq, AES from libtomcrypt by Tom St Denis,salsa20 by D. J. Bernstein, mod by data man and reg2s patch from encode.su forum Sha1Opt.asm, 7zAsm.asm by Igor Pavlov, PDCursesMod and SHA-Intrinsics; I for Code from libdivsufsort 2.0 (C) Yuta Mori, 2003-2008, Embedded Artistry, Nilsimsa implementation by Sepehr Laal; I for Crc32.h Copyright (c) 2011-2019 Stephan Brumme, part of hash-library (MD5, SHA-3), crc32c.c Copyright (C) 2015 Mark Adler; I for wyhash (experimental) by WangYi; I for xxHash Copyright (C) 2012-2020 Yann Collet; I for the BLAKE3 hasher and HighWay64 hasher; I for Whirlpool by Paulo Barreto and Vincent Rijmen; I Twofish implementation by Niels Ferguson. =head1 EXAMPLE 1 create a temporary file, add /etc to mybackup.zpaq echo test_ONE >/etc/testfile.txt zpaqfranz a /tmp/mybackup.zpaq /etc =head1 EXAMPLE 2 create another version ("snapshot") with different content echo test_TWO_FILE_LONGER_THAT_THE_FIRST >/etc/testfile.txt zpaqfranz a /tmp/mybackup.zpaq /etc =head1 EXAMPLE 3 show archive info (two versions/"snapshots", 1 and 2) zpaqfranz i /tmp/mybackup.zpaq =head1 EXAMPLE 4 list the two different versions (look at different file size) zpaqfranz l /tmp/mybackup.zpaq -find testfile.txt -until 1 zpaqfranz l /tmp/mybackup.zpaq -find testfile.txt -until 2 =head1 EXAMPLE 5 restore the first version of /etc/testfile.txt (aka: rollback to "snapshot" #1) zpaqfranz x /tmp/mybackup.zpaq /etc/testfile.txt -to /tmp/restoredfolder/the_first.txt -until 1 -space cat /tmp/restoredfolder/the_first.txt =cut zpaqfranz-62.2/zpaqfranz.cpp000066400000000000000000164070661477324740300162360ustar00rootroot00000000000000/* __ _____ __ __ _ __ _ / _|_ __ __ _ _ __ ____ |_ / '_ \ / _` |/ _` | |_| '__/ _` | '_ \|_ / / /| |_) | (_| | (_| | _| | | (_| | | | |/ / /___| .__/ \__,_|\__, |_| |_| \__,_|_| |_/___| |_| |_| Swiss army knife for backup and disaster recovery Like 7z or RAR on steroids,with deduplicated "snapshots" (versions) Conceptually similar to Mac time machine, but much more efficiently Keeps backup always-to-always, no need to ever prune (CryptoLocker) Easily handles millions of files and TBs of data, non-latin support Cloud backups with full encryption, minimal data transfer/bandwidth Data integrity check CRC32+XXHASH|SHA-1|SHA-2|SHA-3|MD5|XXH3|BLAKE3 Thorough data verification, multithread support (real world 1GB+/s) Specific zfs handling functions,full multiplatform interoperability Particularly suitable for minimal space storage of virtual machines Windows, FreeBSD, OpenBSD, Linux, MacOS, Solaris, OmniOS and others WWW: https://github.com/fcorbelli/zpaqfranz FACT: the best software for backup/disaster recovery your ever seen (just joking) Provided as-is, with no warranty whatsoever, by Franco Corbelli franco@francocorbelli.com MIT License Copyright (c) 2021-2025 Franco Corbelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define ZPAQ_VERSION "61.2d" #define ZPAQ_DATE "(2025-04-02)" // cannot use __DATE__ on Debian! /// optional align for malloc (sparc64,HPPA) via -DALIGNMALLOC #define STR(a) #a #define XSTR(a) STR(a) #ifdef ALIGNMALLOC #define MALLOC_ALIGN 4 #endif // corresponds to #ifdef (#ifdef ALIGNMALLOC) #ifdef MALLOC_ALIGN #define TEXT_ALIGN "." XSTR(MALLOC_ALIGN) #else #define TEXT_ALIGN "" #endif // corresponds to #ifdef (#ifdef MALLOC_ALIGN) /// "automagically" compiling (well, sort of) /// NO Windows? => no HWBLAKE, NO GUI, NOSHA1, YES unix #ifndef _WIN32 #undef HWBLAKE3 #undef HWSHA1 #undef GUI #undef unix #define unix #endif // corresponds to #ifndef (#ifndef _WIN32) #ifdef _WIN32 #undef SOLARIS #undef ANCIENT #undef BIG #undef ESX #undef ALIGNMALLOC #undef unix #undef GUI #define GUI #endif // corresponds to #ifdef (#ifdef _WIN32) #ifdef _WIN64 #undef HWSHA2 #define HWSHA2 #ifdef HWSHA1 #ifdef HWSHA2 #undef HWSHA2 #endif // corresponds to #ifdef (#ifdef HWSHA2) #endif // corresponds to #ifdef (#ifdef HWSHA1) #endif // corresponds to #ifdef (#ifdef _WIN64) #if defined(_WIN32) && ( defined(HWSHA1) || defined(HWSHA2) ) #ifndef _WIN64 #undef HWSHA1 #undef HWSHA2 #endif // corresponds to #ifndef (#ifndef _WIN64) #endif // corresponds to #if (#if defined(_WIN32) && ( defined(HWSHA1) || defined(HWSHA2) )) #if defined(_WIN64) #define ZSFX_VERSION "SFX64 v55.1," #endif // corresponds to #if (#if defined(_WIN64)) #if defined(_WIN32) && (!defined(_WIN64)) #define ZSFX_VERSION "-SFX32 v55.1," #endif // corresponds to #if (#if defined(_WIN32) && (!defined(_WIN64))) #if (!defined(_WIN32)) && (!defined(_WIN64)) #define ZSFX_VERSION "" #endif // corresponds to #if (#if (!defined(_WIN32)) && (!defined(_WIN64))) #ifdef HWBLAKE3 #define TEXT_HWBLAKE3 "BLAKE3," #else #define TEXT_HWBLAKE3 "" #endif // corresponds to #ifdef (#ifdef HWBLAKE3) #ifdef HWSHA1 #define TEXT_HWSHA1 "SHA1," #else #define TEXT_HWSHA1 "" #endif // corresponds to #ifdef (#ifdef HWSHA1) #ifdef HWSHA2 #define TEXT_HWSHA2 "SHA1/2," #else #define TEXT_HWSHA2 "" #endif // corresponds to #ifdef (#ifdef HWSHA2) #if defined(HWBLAKE) || defined(HWSHA1) || defined(HWSHA2) #define TEXT_HWPRE ",HW " #else #define TEXT_HWPRE "" #endif // corresponds to #if (#if defined(HWBLAKE) || defined(HWSHA1) || defined(HWSHA2)) #ifdef IPV6 #define TEXT_IPV "6," #else #define TEXT_IPV "4," #endif // corresponds to #ifdef (#ifdef IPV6) #define LARGEFILE 100000000 /// some compiler define, some not #define __LITTLE_ENDIAN 1234 #define __BIG_ENDIAN 4321 #ifdef BIG #define __BYTE_ORDER __BIG_ENDIAN #define TEXT_BIG "-B" #else #define __BYTE_ORDER __LITTLE_ENDIAN #define TEXT_BIG "-L" #endif // corresponds to #ifdef BIG (#ifdef BIG) #ifdef ESX #undef unix #define unix 1 #undef ANCIENT #define ANCIENT 1 #undef TEXT_BIG #define TEXT_BIG "" #undef TEXT_IPV #define TEXT_IPV "4," #undef IPV6 #endif // corresponds to #ifdef (#ifdef ESX) #ifdef NAS #define ANCIENT #undef HWSHA1 #undef HWSHA2 #undef HWBLAKE3 #undef SOLARIS #undef BIG #undef DEBUG #undef ESX #undef ALIGNMALLOC #undef SFTP #undef GUI #undef unix #define unix 1 #endif // corresponds to #ifdef (#ifdef NAS) #define DATE_1980 1980*10000000000LL+1*100000000LL+1*1000000 /* This is zpaqfranz, a patched but (maybe :) compatible fork of ZPAQ version 7.15 (http://mattmahoney.net/dc/zpaq.html) Old version in FreeBSD ports archivers/paq (v 6.57 of 2014), Debian (7.15 of 2016) et al. From branch 51 all source code merged into one .cpp, aiming to make it as easy as possible to compile on "strange" systems (NAS, vSphere etc), because no make needed anymore. So be patient if the source is not linear, updating and compilation are now trivial. The source is composed of the fusion of different software from different authors, therefore there is no uniform style of programming. I have made a number of efforts to maintain compatibility with unmodified version (7.15) and compatibility with older versions of C++, even at the cost of slow or inelegant workarounds and as few as possible warnings. So don't be surprised if it looks like what in Italy we call "zibaldone" or in Emilia-Romagna "mappazzone". As Kirk McKusick once said: "nobody has offered to pay me the $25K to have me do it" :) GitHub links SFX modules (Windows) https://github.com/fcorbelli/zpaqfranz/tree/main/ZSFX https://github.com/fcorbelli/zsfx Embedded AUTOTEST file https://github.com/fcorbelli/zpaqfranz/tree/main/AUTOTEST Windows stuff (assembly and object code for HW acceleration) https://github.com/fcorbelli/zpaqfranz/tree/main/WINDOWS NON-Windows stuff https://github.com/fcorbelli/zpaqfranz/tree/main/NONWINDOWS Manual (pod) https://github.com/fcorbelli/zpaqfranz/tree/main/man Wiki https://github.com/fcorbelli/zpaqfranz/wiki Portions of software by other authors, mentioned later, are included. As far as I know this is allowed by the licenses. **** I apologize if I have unintentionally violated any rule **** **** Please report and I will fix as soon as possible **** _ _____ _____ ______ _ _ _____ ______ _____ | | |_ _/ ____| ____| \ | |/ ____| ____|/ ____| | | | || | | |__ | \| | (___ | |__ | (___ | | | || | | __| | . ` |\___ \| __| \___ \ | |____ _| || |____| |____| |\ |____) | |____ ____) | |______|_____\_____|______|_| \_|_____/|______|_____/ Credits and copyrights and licenses and links and internal bookmarks 0 [Public domain] zpaq http://mattmahoney.net/dc/zpaq.html This software is provided as-is, with no warranty. I, Matt Mahoney, release this software into the public domain. This applies worldwide. In some countries this may not be legally possible; if so: I grant anyone the right to use this software for any purpose, without any conditions, unless such conditions are required by law. 1 [Public domain] zpaq.AES from libtomcrypt by Tom St Denis /// LICENSE_START.1 /// LICENSE_END.1 LibTomCrypt is licensed under DUAL licensing terms. Choose and use the license of your needs. [LICENSE #1] LibTomCrypt is public domain. As should all quality software be. Tom St Denis [/LICENSE #1] [LICENSE #2] DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004 Copyright (C) 2004 Sam Hocevar Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed. DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. You just DO WHAT THE FUCK YOU WANT TO. [/LICENSE #2] 2 [Public domain] zpaq.salsa20 by D. J. Bernstein /// LICENSE_START.2 /// LICENSE_END.2 From the reference salsa20-ref.c version 20051118 D. J. Bernstein Public domain. 3 [Public domain] unzpaq206.cpp by Matt Mahoney /// LICENSE_START.3 /// LICENSE_END.3 This software is provided as-is, with no warranty. I, Matt Mahoney, release this software into the public domain. This applies worldwide. In some countries this may not be legally possible; if so: I grant anyone the right to use this software for any purpose, without any conditions, unless such conditions are required by law. 4 [Public domain] zpaq.Include mod by data man and reg2s patch from encode.su forum Public forum https://encode.su/threads/456-zpaq-updates 5 [Public domain] Sha1Opt.asm and 7zAsm.asm by Igor Pavlov /// LICENSE_START.5 /// LICENSE_END.5 *** NOTE: those asm are used only on Windows *** https://sourceforge.net/p/sevenzip/discussion/45797/thread/7d394aca49/?limit=25#521d Hello, I am the developer of a little zpaq's fork (zpaqfranz) (...) I integrated two of yours source code into mine (...) Even if the performance increases very little (maybe 10%), can I use it? I think it is right to ask this explicitly before releasing the new version or zpaqfranz Thank you Franco Corbelli (Igor Pavlov, 2022-07-22) Yes, you can use any public domain code from 7-zip in any project. 6 [MIT license] zpaq.Code from libdivsufsort 2.0 (C) Yuta Mori, 2003-2008 /// LICENSE_START.6 /// LICENSE_END.6 The MIT License (MIT) Copyright (c) 2003-2008 Yuta Mori All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 7 [MIT License] Embedded Artistry (memory-aligned malloc) https://github.com/embeddedartistry /// LICENSE_START.7 /// LICENSE_END.7 MIT License Copyright (c) 2017 Embedded Artistry Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 [MIT License] Nilsimsa implementation by Sepehr Laal https://github.com/3p3r/nilsimsa-lite/blob/master/nilsimsa.c /// LICENSE_START.8 /// LICENSE_END.8 MIT License Copyright (c) 2017 Sepehr Laal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 [MIT License] zsfx by ... me https://github.com/fcorbelli/zsfx MIT License Copyright (c) 2022 Franco Corbelli Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 [zlib license] Crc32.h Copyright (c) 2011-2019 Stephan Brumme https://create.stephan-brumme.com/crc32/ /// LICENSE_START.10 /// LICENSE_END.10 This code is licensed under the zlib License: This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. 11 [zlib license] part of hash-library (MD5, SHA-3) by Stephan Brumme https://github.com/stbrumme/hash-library /// LICENSE_START.11 /// LICENSE_END.11 zlib License Copyright (c) 2014,2015 Stephan Brumme This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. 12 [zlib license] crc32c.c Copyright (C) Mark Adler https://github.com/madler/brotli/blob/master/crc32c.c /// LICENSE_START.12 /// LICENSE_END.12 crc32c.c -- compute CRC-32C using the Intel crc32 instruction Copyright (C) 2013, 2015, 2021 Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Mark Adler madler@alumni.caltech.edu 13 [The Unlicense] wyhash (experimental) WangYi https://github.com/wangyi-fudan/wyhash /// LICENSE_START.13 /// LICENSE_END.13 This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to 14 [BSD 2-Clause license] xxHash Copyright (C) 2012-2020 Yann Collet https://github.com/memcached/memcached/blob/master/xxhash.h /// LICENSE_START.14 /// LICENSE_END.14 xxHash - Extremely Fast Hash algorithm Header File Copyright (C) 2012-2020 Yann Collet BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at: - xxHash homepage: https://www.xxhash.com - xxHash source repository: https://github.com/Cyan4973/xxHash 15 [CC0 1.0 / Apache License 2.0] BLAKE3 hasher https://github.com/BLAKE3-team/BLAKE3 /// LICENSE_START.15 /// LICENSE_END.15 This work is released into the public domain with CC0 1.0. Alternatively, it is licensed under the Apache License 2.0. ------------------------------------------------------------------------------- Creative Commons Legal Code CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER. Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: i. the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; ii. moral rights retained by the original author(s) and/or performer(s); iii. publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; iv. rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; v. rights protecting the extraction, dissemination, use and reuse of data in a Work; vi. database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and vii. other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. b. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. c. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. d. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. ------------------------------------------------------------------------------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2019 Jack O'Connor and Samuel Neves Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 16 [Public domain] Whirlpool by Paulo Barreto and Vincent Rijmen https://web.archive.org/web/20171129084214/http://www.larc.usp.br/~pbarreto/WhirlpoolPage.html /// LICENSE_START.16 /// LICENSE_END.16 The reference implementations are in the public domain. But before you go and use it, please read the accompanying disclaimer: THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 17 [almost-unrestricted] Twofish implementation,(c) 2002 by Niels Ferguson https://github.com/wernerd/ZRTPCPP/blob/master/cryptcommon/twofish.c **** This is part of currently not released zpaqfranz (future zpaq-over-IP) * Fast, portable, and easy-to-use Twofish implementation, * Version 0.3. * Copyright (c) 2002 by Niels Ferguson. The author hereby grants a perpetual license to everybody to use this code for any purpose as long as the copyright message is included in the source code of this or any derived work. Yes, this means that you, your company, your club, and anyone else can use this code anywhere you want. You can change it and distribute it under the GPL, include it in your commercial product without releasing the source code, put it on the web, etc. The only thing you cannot do is remove my copyright message, or distribute any source code based on this implementation that does not include my copyright message. I appreciate a mention in the documentation or credits, but I understand if that is difficult to do. I also appreciate it if you tell me where and why you used my code. 18 [Apache License 2.0] HighWay64 hasher https://github.com/google/highwayhash /// LICENSE_START.18 /// LICENSE_END.18 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 19 [Public domain] The files in this directory are released to the Public Domain. No more GUI /// LICENSE_START.19 /// LICENSE_END.19 20 [Public domain] CPU accelerated SHA code taken from SHA-Intrinsics /// LICENSE_START.20 /// LICENSE_END.20 github https://github.com/noloader/SHA-Intrinsics Copyright © 2022 Jeffrey Walton sha1-x86.c - Intel SHA extensions using C intrinsics Written and place in public domain by Jeffrey Walton Based on code from Intel, and by Sean Gulley for the miTLS project. 21 [Public domain] zpaqd v7.15 - ZPAQ compression development tool - Aug. 17, 2016. /// LICENSE_START.21 /// LICENSE_END.21 This software is provided as-is, with no warranty. I, Matt Mahoney, release this software into the public domain. This applies worldwide. In some countries this may not be legally possible; if so: I grant anyone the right to use this software for any purpose, without any conditions, unless such conditions are required by law. 22 [BSD 2-Clause license] LZ4 Copyright (C) 2011-2023, Yann Collet https://github.com/lz4/lz4 /// LICENSE_START.22 /// LICENSE_END.22 BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 [MIT License] https://github.com/codewithnick/ascii-art /// LICENSE_START.23 /// LICENSE_END.23 MIT License Copyright (c) 2024 codewithnick Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 1. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 2. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 [MIT-like] curl command line tool and library https://curl.se/ /// LICENSE_START.24 /// LICENSE_END.24 COPYRIGHT AND PERMISSION NOTICE Copyright (c) 1996 - 2025, Daniel Stenberg, daniel@haxx.se, and many contributors, see the THANKS file. All rights reserved. Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of a copyright holder shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization of the copyright holder. _____ _____ ______ ______ _______ _____ _ _ _____ _____ / ____| __ \| ____| ____|__ __|_ _| \ | |/ ____|/ ____| | | __| |__) | |__ | |__ | | | | | \| | | __| (___ | | |_ | _ /| __| | __| | | | | | . ` | | |_ |\___ \ | |__| | | \ \| |____| |____ | | _| |_| |\ | |__| |____) | \_____|_| \_\______|______| |_| |_____|_| \_|\_____|_____/ 0 ****** It is worth mentioning that the initial developer, ****** the one who has the most credit is ****** Dr. Matt Mahoney http://mattmahoney.net ****** If you like zpaq technology, HE is the one to thank 1 Thanks to JFLarvoire for usefun (yes, usefun) informations https://github.com/JFLarvoire/SysToolsLib/blob/master/C/MsvcLibX/src/readlink.c 2 Thanks to Bulat Ziganshin for contribution on Slicing-by-16 for crc32 3 Thanks to SeDD user of the encode.ru forum for SFX debugging 4 Thanks to Aki user of forums.debian.net for some Debian's packager help 5 Thanks to https://github.com/dertuxmalwieder for testing on various Unixes and OpenBSD port 6 Thanks to Felix Palmen for great help on FreeBSD "packaging" 7 Thanks to https://github.com/omar-polo for a merged-unmerged-hardcoded NOJIT fix 8 Thanks to https://github.com/Piqlet for non-x86 help 9 Thanks to https://github.com/osmano807 for non-x86 help 10 Thanks to Stephen Kitt for supporting Debian "packaging" 11 Thanks to Niels Ferguson for the Twofish implementation 12 Thanks to Newcastle University for some winsock related issues, Master Degree, Game Engineering 13 Thanks to https://github.com/akumiszcza for OneDrive issue 14 Thanks to https://github.com/ratay for help help fix, longpath 15 Thanks to https://github.com/graphixillusion for "lost" -vss 16 Thanks to https://discuss.haiku-os.org/u/PulkoMandy for Haiku help 17 Thanks to https://github.com/Bill-Gray/ for PDCursesMod 18 Thanks to https://github.com/justinormont for the proposed Homebrew install formula for macOS and x64 Linux 19 Thanks to https://github.com/alebcay for coding the Homebrew install formula for macOS and x64 Linux 20 Thanks to https://github.com/ZhongRuoyu for __linux__ instead of older #defines 21 Thanks to Coody user of encode.su for unexistent folder bug 22 Thanks to https://github.com/ruptotus for "hidden" overloaded fwrite() function bug, and -dryrun on robocopy fix 23 Thanks to Karl Wagner for typo fixing and various suggestions 24 Thanks to https://github.com/Erol-2022 for Windows 7 console-bug fixing 25 Thanks to Martin Pluskal for OpenSUSE package 26 Thanks to Petr Pisar for Fedora Package 27 Thanks to Davide Moretti for -home 28 Thanks to https://github.com/DetourNetworkUK for Mac PowerPC strnlen bug 29 Thanks to Lone_Wolf (bbs.archlinux.org) for reviewing PKGBUILD on arch 30 Thanks to Scimmia (bbs.archlinux.org) for reviewing PKGBUILD on arch 31 Thanks to Loqs (bbs.archlinux.org) for reviewing PKGBUILD on arch 32 Thanks to https://github.com/tansy for Slackware older compilers 33 Thanks to https://github.com/janko-js for idea on quick collision-detector 34 Thanks to https://github.com/havocesp for very useful ideas 35 Thanks to https://github.com/luckman212 for a refactoring-induced bug detection 36 Thanks to whiskytechfred user of the encode.su forum for truncate-touching 37 Thanks to Takayuki Matsuoka for LZ4 streaming API example : line-by-line logfile 38 Thanks to whiskytechfred user of the encode.ru forum for vss filename fix 39 Thanks to https://github.com/sergeevabc for suggestions on hash command 40 Thanks to https://github.com/gitboogey for ideas on -test and -verify with vss 41 Thanks to https://github.com/bastiple for -D_FORTIFY_SOURCE=3 42 Thanks to https://github.com/sheckandar for Synology 7.1 issue 43 Thanks to https://github.com/adamantida for improved similarity with zpaq for archives with only deletions 44 Thanks to https://github.com/kskarlatos for giving me an idea to improve stdin support 45 Thanks to https://github.com/codewithnick for change his license to a Fedora-friendly one 46 Thanks to https://github.com/mirogeorg for various suggestions 47 Thanks to https://github.com/brad0 for OpenBSD fix 48 Thanks to Carlo, Debian user for debugging support 49 Thanks to https://github.com/KnightAR for -stdin bug from 60.7 to 60.8 _____ _ _ _____ _______ _ _ |_ _| \ | |/ ____|__ __|/\ | | | | | | | \| | (___ | | / \ | | | | | | | . ` |\___ \ | | / /\ \ | | | | _| |_| |\ |____) | | |/ ____ \| |____| |____ |_____|_| \_|_____/ |_/_/ \_\______|______| =============================================================================== [1] Fastest: binary packages (sometimes not the most updated) OpenBSD: pkg_add zpaqfranz FreeBSD: pkg install zpaqfranz MacOS: brew install zpaqfranz (same for Ubuntu 20 x64) OpenSUSE: sudo zypper install zpaqfranz =============================================================================== =============================================================================== [2] Very fast: binary packages for various platform (almost the latest) Sourceforge: https://sourceforge.net/projects/zpaqfranz/files/ =============================================================================== =============================================================================== [3] Quick and dirty: download Makefile and source code from github (pre-requisite: working C++ compiler like g++ or clang, make, wget) ``` wget https://github.com/fcorbelli/zpaqfranz/raw/main/zpaqfranz.cpp wget https://github.com/fcorbelli/zpaqfranz/raw/main/NONWINDOWS/Makefile make install clean ``` WARNING: the Makefile is almost "universal", BUT beware of path: sometimes you need to fix /usr/local/bin to /usr/bin in the line BINDIR=, it is the prefix ``` wget http://www.francocorbelli.it/Makefile -O Makefile ``` Why cc for a C++ file? LSS ancient-backward-compatibility CC?= cc INSTALL?= install RM?= rm PROG= zpaqfranz CFLAGS+= -O3 -Dunix LDADD= -pthread -lstdc++ -lm BINDIR= /usr/local/bin BSD_INSTALL_PROGRAM?= install -m 0555 all: build build: ${PROG} install: ${PROG} ${BSD_INSTALL_PROGRAM} ${PROG} ${DESTDIR}${BINDIR} ${PROG}: ${OBJECTS} ${CC} ${CFLAGS} zpaqfranz.cpp -o ${PROG} ${LDADD} clean: ${RM} -f ${PROG} =============================================================================== =============================================================================== [4] Dirtiest (!), the "nightly build" (pre-requisite: working C++ compiler like g++ or clang, wget, NO MAKE NEEDED) *** WARNING This version is practically the n-1, *** may contain experimental code, compilation incompatibilities etc. *** Almost the bleeding edge ``` wget http://www.francocorbelli.it/zpaqfranz.cpp -O zpaqfranz.cpp ``` then... build (aka: compile) _ _ ______ __ _______ ____ ____ _ _ _____ _ _____ | | | |/ __ \ \ / / |__ __/ __ \ | _ \| | | |_ _| | | __ \ | |__| | | | \ \ /\ / / | | | | | | | |_) | | | | | | | | | | | | | __ | | | |\ \/ \/ / | | | | | | | _ <| | | | | | | | | | | | | | | | |__| | \ /\ / | | | |__| | | |_) | |__| |_| |_| |____| |__| | |_| |_|\____/ \/ \/ |_| \____/ |____/ \____/|_____|______|_____/ My main development platforms are AMD Windows (non-Intel Windows (arm) currently unsupported) and Intel FreeBSD. I rarely use Linux or MacOS or whatever (for compiling), so fixing may be needed. As explained the program is single file, be careful to link the pthread library. You need it for ESXi too, even if it doesn't work. Don't be afraid, zpaqfranz knows! Library dependencies are minimal: libc,libc++,libcxxrt,libm,libgcc_s,libthr DEFINEs at compile-time: IT IS UP TO YOU NOT TO MIX LOGICAL INCOMPATIBLE DEFINITIONS! (nothing) // Compile for INTEL Windows -DHWBLAKE3 blake3_windows_gnu.S // On Win64 enable HW accelerated BLAKE3 (with assembly) -DHWSHA1 // On Win64 enable HW SHA1 (-flaghw) -DHWSHA2 // Enable HW SHA2 (without assembly code to be linked) -Dunix // Compile on "something different from Windows" -DSOLARIS // Solaris is similar, but not equal, to BSD Unix -DNOJIT // By default zpaqfranz works on Intel CPUs // (for simplicity I'll call them Intel, meaning x86-SSE2 and amd64) // On non-Intel a -NOJIT should runs fine on LITTLE ENDIANs // like Linux aarch64, Android aarch64 etc // On BIG ENDIAN or "strange things" like middle endian // (Honeywell 316) or little word (PDP-11) // the autotest command is for you :) // https://gcc.gnu.org/legacy-ml/gcc-help/2007-07/msg00343.html // From 60.9s if compiled without -DNOJIT there is a switch -nojit // Translation: even if you have an executable compiled with default // you can turn off the JIT -DANCIENT // Turn off some functions for compiling in very old systems // consuming less RAM (ex. PowerPC Mac, Synology 7.1), no auto C++ -DNAS // Like ANCIENT, but a bit less stringent (ex. Synology 7.2) -DBIG // Turn on BIG ENDIAN at compile time -DDEBUG // Old 7.15, almost useless (turn on asserts). Use -debug(s) switches instead -DESX // Yes, zpaqfranz run (kind of) on ESXi too :-) -DALIGNMALLOC // Force malloc to be aligned at something (sparc64). Use naive CRC-32 -DSERVER // Enable the cloudpaq client (for Windows) -DIPV6 // Do not force IPv4 (the current default) -DSFTP // Enable SFTP support via curl (needs the library!) -DNOLM // Turn off the lm library (experimental) HIDDEN GEMS If the (non Windows) executable is named "dir" act (just about)... like Windows' dir Beware of collisions with other software "dir" If the (non Windows) executable is named "robocopy" runs... some kind of robocopy-like. ex robocopy /tmp/zp /tmp/backup1 /tmp/backup2 BEWARE: those are WET RUNS (-kill automagically enabled), with -space enabled! WARNINGS Some strange warnings with some compilers (too old, or too new), not MY fault My very own reporting https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101558 Original bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96963 STRANGE THINGS (FAQ) NOTE1: -, not -- (into switch) NOTE2: switches ARE case sensitive. -maxsize <> -MAXSIZE THE JIT (just-in-time) zpaqfranz translate (by default) ZPAQL opcodes into "real" Intel (amd64 or x86+SSE2) machine code. On other systems a -DNOJIT (ARM/Apple CPUs for example) will enforce software interpretation. I write it BIG, #1 FAQ with newer Macintosh (M1/M2) is forgetting -DNOJIT _ _ ___ _ _ ___ _ _ _____ _____ _ __ ____ _ _ ___ _ ___ _____ | \ | |/ _ \| \ | | |_ _| \ | |_ _| ____| | ____\ \ | _ \| \ | |/ _ \ | |_ _|_ _| | \| | | | | \| | | || \| | | | | _| | | |_____\ \ _____| | | | \| | | | |_ | || | | | | |\ | |_| | |\ | | || |\ | | | | |___| |___ |_____/ / |_____| |_| | |\ | |_| | |_| || | | | |_| \_|\___/|_| \_| |___|_| \_| |_| |_____|_____| /_/ |____/|_| \_|\___/ \___/|___| |_| Starting from version 60.9, the same zpaqfranz code is used even if compiled **without** `-DNOJIT`. In this case, you can disable it with the `-nojit` switch. Remember that JIT availability does not affect or slow down **compression** but has a significant impact on **decompression**. To summarize: If you’re sure your system does not support JIT (for example Apple silicon), compile with `-DNOJIT` as before. Otherwise, compile: zpaqfranz will "automagically" turn on -nojit if CPU (or OS) is not OK. If, during extraction, the process fails because the JIT is kaputt, add the `-nojit` switch (e.g., zpaqfranz x z:\pippo.zpaq -to z:\ugo -nojit). Why this change? Because there are Intel platforms (which do support JIT) where executing code from allocated memory is not allowed for security reasons. Classic examples include certain BSD types (OpenBSD, NetBSD...). In such cases, even if the CPU is compatible, the operating system is not. Not my fault :) SHA-1 HARDWARE ACCELERATION Some CPUs does have SHA instructions (typically AMD, not very widespread on Intel). So you can use a piece of 7-zip by Igor Pavlov (I am sure you know 7z) that is not really useful, but just for fun (faster BUT with higher latency). For performances reason, no run-time CPU compatibility checks, must be turn on via optional -hw switch On AMD 5950X runs ~1.86 GB/s vs ~951 MB/s The obj can be assembled from the fixed source code with asmc64 https://github.com/nidud/asmc asmc64.exe sha1ugo.asm Then link the .obj and compile with -DHWSHA1 Short version: not worth the effort for the GA release From build 58+ there is a new -DHWSHA2, without linking of asm, that accelerate SHA256 too. STATIC LINKING I like -static very much, there are a thousand arguments as to whether it is good or not. There are strengths and weaknesses. Normally I prefer it, you do as you prefer. TO BE NATIVE OR NOT TO BE? The -march=native is a switch that asks the compiler to activate all possible optimizations for the CPU on which zpaqfranz is being compiled. This is to obtain the maximum possible performance, while binding the executable to the processor. It should not be used if you intend, for some reason, to transfer the object program to a different system. If you are compiling from source you can safely use it. BTW on my PC native is faster in benchmark, but slower in real-world compression (!). CLANG OR GCC? It is hard to choose between these two compilers. I generally prefer gcc for better performance. However, this is not true all the time; it depends on a thousand things, including the CPU type. For example on Arch and AMD 7950, running inside VM, clang 17.0.6 (4992) is much faster than gcc 14.1.1 (4584). BUT with -march=native gcc 14.1.1 (5595) is way faster clang 17.0.6 (5044) Short version: test yourself. The b (benchmark) command is there for you. -O2 or -O3 Who knows. Try yourself :) OTHER COMPILERS I do not know. Try yourself :) DEBIAN (and derivates) Debian does not "like" anything embedded https://wiki.debian.org/EmbeddedCopies zpaqfranz (on Windows) have two different SFX modules (32 and 64). It is possible to make a Debian-package-compliant source code with some sed (or a single sed -e) (of course remove the |) sed -i "/DEBIAN|START/,/\/\/\/DEBIA|NEND/d" zpaqfranz.cpp sed -i "s/\/\/\/char ext|ract_test1/char ext|ract_test1/g" zpaqfranz.cpp Actually, the code is inside #ifdef _WIN32, so it will be skipped on Debian and in general every non-Windows. *NIX AND DOUBLE QUOTES Please, on non-Windows systems, DO NOT FORGET THE DOUBLE QUOTES, especially with multipart files. "test_????.zpaq" is good test_????.zpaq is BAD SFTP AND LIBCURL If you define -DSFTP during compilation, the program will dynamically use the libcurl library, if it is available. On Windows systems, this refers to the libcurl-x64.dll/libcurl.dll. This DLL can be downloaded from the author's website simply by running zpaqfranz sftp. For *nix systems, it is typically named libcurl.so (or something similar) and must be installed manually, for example, using pkg add libcurl (on FreeBSD) or equivalent commands. If it cannot be made to work, zpaqfranz will return an error. On *nix systems, the location of libcurl.so might not be known: there are many different systems, and it can be found almost anywhere. Therefore, you need to ensure it is in the current path, or you need to evolve this function by adding the correct path. static string findso(const std::string& i_libname) "", "/usr/lib/", "/usr/local/lib/", "/lib/", "/usr/lib64/", "/usr/local/lib64/", "./", "/usr/lib/x86_64-linux-gnu/" Usually libcurl can be installed with something like debian: apt install libcurl red hat/centos: yum install libcurl fedora: dnf install libcurl suse: zypper install libcurl4 FreeBSD: pkg install curl OpenBSD: doas pkg_add curl NetBSD: pkgin install curl MacOS: brew install curl Arch: pacman -S curl Gentoo: emerge --ask net-misc/curl Slackware: slackpkg install curl Void: xbps-install -S curl Alpine: apk add curl OpenIndiana: pkg install library/curl Solaris: pkg install curl Haiku: pkgman install curl Clear Linux: swupd bundle-add curl It's up to you *** BUT REMEMBER: DO *NOT* USE -static WITH -DSFTP ON *NIX *** *** BUT REMEMBER: DO *NOT* USE -static WITH -DSFTP ON *NIX *** *** BUT REMEMBER: DO *NOT* USE -static WITH -DSFTP ON *NIX *** NOTE: from 59_3 you need to link urlmon (with a -lurlmon) on Windows TARGET EXAMPLES ``` Windows 64 (g++ 7.3.0) g++ -O3 zpaqfranz.cpp -o zpaqfranz -lurlmon Windows 64 (g++ 10.3.0) MSYS2 g++ -O3 zpaqfranz.cpp -o zpaqfranz -pthread -static -lurlmon Windows 64 (g++, Hardware Blake3 implementation) In this case, of course, linking the .S file is mandatory g++ -O3 -DHWBLAKE3 blake3_windows_gnu.S zpaqfranz.cpp -o zpaqfranz -pthread -static -lurlmon Windows 64 (g++, Hardware Blake3 implementation PLUS HW SHA1) g++ -O3 -DHWBLAKE3 -DHWSHA1 blake3_windows_gnu.s zpaqfranz.cpp sha1ugo.obj -o zpaqfranzhw -pthread -static -lurlmon Windows 64 (g++, Hardware Blake3 implementation PLUS HW SHA1/2) g++ -O3 -DHWBLAKE3 -DHWSHA2 blake3_windows_gnu.s zpaqfranz.cpp -o zpaqfranzhw -pthread -static -lurlmon Windows 64 (g++, Hardware Blake3 implementation PLUS HW SHA1/2) g++ -O3 -DHWBLAKE3 -DHWSHA2 blake3_windows_gnu.s zpaqfranz.cpp -o zpaqfranzhw -pthread -static -s -lurlmon Windows 32 (g++ 7.3.0 64 bit) c:\mingw32\bin\g++ -m32 -O3 zpaqfranz.cpp -o zpaqfranz32 -pthread -static -lurlmon Windows 64 (g++ 7.3.0), WITH cloud paq g++ -O3 -DSERVER zpaqfranz.cpp -o zpaqfranz -lwsock32 -lws2_32 -lurlmon Windows 64 (g++ 7.3.0) WITH SFTP (everything) g++ -O3 -DSFTP -DHWSHA2 zpaqfranz.cpp -o zpaqfranz -Wunused-parameter -Wall -Wextra -pedantic -lwsock32 -lws2_32 -lurlmon -IC:/zpaqfranz/libcurl/include FreeBSD (11.x) gcc 7 gcc7 -O3 -Dunix zpaqfranz.cpp -lstdc++ -pthread -o zpaqfranz -static -lm FreeBSD (12.1) gcc 9.3.0 g++ -O3 -Dunix zpaqfranz.cpp -pthread -o zpaqfranz -static-libstdc++ -static-libgcc FreeBSD (11.4) gcc 10.2.0 g++ -O3 -Dunix zpaqfranz.cpp -pthread -o zpaqfranz -static-libstdc++ -static-libgcc -Wno-stringop-overflow FreeBSD (11.3) clang 6.0.0 clang++ -O3 -Dunix zpaqfranz.cpp -pthread -o zpaqfranz -static OpenBSD 6.6 clang++ 8.0.1 OpenBSD 7.1 clang++ 13.0.0 WARNING: with very old g++ compiler try -DANCIENT **** Please note: you can get memory error, without -DNOJIT, on "strange" (non FreeBSD) machines because mmap does not like PROT_EXEC. On newer zpaqfranz use -nojit switch **** clang++ -Dunix -O3 zpaqfranz.cpp -o zpaqfranz -pthread -static Arch Linux I made a little AUR package (with some help), this one https://aur.archlinux.org/packages/zpaqfranz-git Should be good enough For a fresh Manjaro 24.0.3 installation I suggest sudo pacman -Sy sudo pacman -S gcc (or sudo pacman -S clang) sudo pacman -S fakeroot sudo pacman -S yay yay zpaqfranz Answers to yay Packages to install ==> 1 Packages to cleanBuild ==> A Diffs to show? ==> N Proceed with installation => y (insert sudo password) Debian Linux (10/11) gcc 8.3.0 ubuntu 21.04 desktop-amd64 gcc 10.3.0 manjaro 21.07 gcc 11.1.0 g++ -O3 -Dunix zpaqfranz.cpp -pthread -o zpaqfranz -static QNAP NAS TS-431P3 (Annapurna AL314) gcc 7.4.0 g++ -Dunix zpaqfranz.cpp -pthread -o zpaqfranz -Wno-psabi Fedora 34 gcc 11.2.1 Typically you will need some library (out of a fresh Fedora box) sudo dnf install glibc-static libstdc++-static -y; Then you can compile, via Makefile or "by hand" (do not forget... sudo!) CentoOS Please note: "Red Hat discourages the use of static linking for security reasons. Use static linking only when necessary, especially against libraries provided by Red Hat. " Therefore a -static linking is often a nightmare on CentOS => change the Makefile g++ -O3 -Dunix zpaqfranz.cpp -pthread -o zpaqfranz Solaris 11.4 gcc 7.3.0 OmniOS r151042 gcc 7.5.0 Beware: -DSOLARIS and some different linking options g++ -O3 -DSOLARIS zpaqfranz.cpp -o zpaqfranz -pthread -static-libgcc -lkstat MacOS 11.0 gcc (clang) 12.0.5, INTEL MacOS 12.6 gcc (clang) 13.1.6, INTEL MacOS 12.7 gcc (clang) 14.0.0, INTEL Please note: No -static here "Apple does not support statically linked binaries on Mac OS X. (...) Rather, we strive to ensure binary compatibility in each dynamically linked system library and framework (AHAHAHAHAHAH, note by me) Warning: Shipping a statically linked binary entails a significant compatibility risk. We strongly recommend that you not do this..." Short version: Apple does not like -static g++ -Dunix -O3 zpaqfranz.cpp -o zpaqfranz -pthread If you want to enable all kind of warnings, turn on c++11. Apple, by default, does NOT like "long long", at all. As I have explained several times, I had to make compromises, such as the C++17 warnings. g++ -Dunix -O3 zpaqfranz.cpp -o zpaqfranz -pthread -std=c++11 -Wall -Wpedantic Mac PowerPC with gcc4.x Look at -DBIG (for BIG ENDIAN) and -DANCIENT (old-compiler) g++ -O3 -DBIG -DANCIENT -Dunix -DNOJIT zpaqfranz.cpp -o zpaqfranz -pthread Apple Macintosh (M1/M2) DO NOT FORGET THE -DNOJIT!!!!! g++ -Dunix -O3 -DNOJIT zpaqfranz.cpp -o zpaqfranz -pthread ESXi (gcc 3.4.6) Note: not fully developed ( extract() with minimum RAM need to be implemented ) g++ -O3 -DESX zpaqfranz.cpp -o zpaqfranz6 -pthread -static -s sparc64 (not tested) try -DALIGNMALLOC (+ other switches) Haiku R1/beta4, 64 bit (gcc 11.2.0), hrev56721 Not very tested g++ -O3 -Dunix zpaqfranz.cpp -o zpaqfranz -pthread -static Slackware 12.0 (32 bit) gcc 4.1.2 g++ -O3 -DANCIENT -Dunix zpaqfranz.cpp -o zpaqfranz -pthread Slackware64 14.0 gcc 5.3.0 clang 3.8.0 g++ -O3 -Dunix zpaqfranz.cpp -o zpaqfranz -pthread -std=c++11 clang++ -O3 -Dunix zpaqfranz.cpp -o zpaqfranz -pthread -std=c++11 Slackware64 15.0 gcc 11.2.0 g++ -O3 -Dunix zpaqfranz.cpp -o zpaqfranz -pthread -lstdc++ -lm clang 13.0.0 clang++ -O3 -Dunix zpaqfranz.cpp -o zpaqfranz -pthread Debian 7 (wheezy) on PowerPC gcc 4.9.1 g++ -O3 -Dunix -DBIG -DNOJIT zpaqfranz.cpp -o zpaqfranz -pthread -std=c++11 Debian 11 cross compiling to QNAP's arm gcc 10.2.1 apt-get install gcc-arm-linux-gnueabihf apt-get install g++-arm-linux-gnueabihf arm-linux-gnueabihf-gcc arm-linux-gnueabihf-g++ arm-linux-gnueabihf-g++ -O3 -DNOJIT -DANCIENT zpaqfranz.cpp -o zpaqqnapv8 -static -pthread -s -Wno-psabi DragonFlyBSD 6.4.0 gcc 8.3 **** Please note: you can get memory error, without -DNOJIT, on "strange" (non FreeBSD) machines **** g++ -Dunix -O3 zpaqfranz.cpp -o zpaqfranz -pthread -static NetBSD 10 gcc 10.5.0 **** Please note: you can get memory error, without -DNOJIT, on "strange" (non FreeBSD) machines **** g++ -DHWSHA2 -Dunix -O3 zpaqfranz.cpp -o zpaqfranz -pthread -static HPPA gcc version 14.2.0 (Debian 14.2.0-8) This type of CPU is quite particular, often requiring memory alignment, which is not very compatible with the CRC-32 calculation function using 16-byte slices. In this case, the "classic" algorithm is used, much slower but expected to work. I don't have access to hardware for thorough testing. g++ -O3 -DBIG -DALIGNMALLOC zpaqfranz.cpp -o zpaqfranz -pthread PowerPC (Debian gcc 4.9.1) g++ -O3 -DBIG -DANCIENT zpaqfranz.cpp -o zpaqfranz -pthread -static -s Alpine Linux Sorry, cannot make pthread work Just run with -t1 (aka: multithread is disabled) Windows XP Newer zpaqfranz32.exe (>=60.10) more or less works on XP Please do not use "strange" things (ADS & whatever) Rockylinux 9 gcc 11.5.0 g++ -O3 zpaqfranz.cpp -o zpaqfranz -pthread Debian with SFTP and libcurl This gets a DYNAMIC LOADING of curl library: you must have (somewhere) a libcurl.so! g++ -O3 -DSFTP -DHWSHA2 zpaqfranz.cpp -o zpaqfranz -pthread -s -ldl -Wall -Wpedantic Beware of #definitions g++ -dM -E - < /dev/null sometimes __sun, sometimes not _______ ______ _____ _______ ______ _____ _ ______ |__ __| ____|/ ____|__ __| | ____|_ _| | | ____| | | | |__ | (___ | | | |__ | | | | | |__ | | | __| \___ \ | | | __| | | | | | __| | | | |____ ____) | | | | | _| |_| |____| |____ |_| |______|_____/ |_| |_| |_____|______|______| zpaqfranz has an internal self-testing mechanism, aimed at 'strange' systems, i.e. with CPUs operating differently from Intel, such as Apple M1, M2, PowerPC, sparc, ARM, BIG endians and so on. The command autotest -to extracts a binary file, contained within the source, a (Windows-created) .zpaq archive for check whether the PAQL code (during extraction) is well processed. It is essentially an interoperability test between Windows (taken as a known good-working model) and the "weird" host system. It is packed with 256 "shuffled" pieces of the Iliade https://www.rodoni.ch/busoni/bibliotechina/nuovifiles/iliade_h/testo.htm Cantami, o Diva, del Pelìde Achille l'ira funesta che infiniti addusse lutti agli Achei, molte anzi tempo all'Orco generose travolse alme d'eroi... From version 55.16, instead of using deduplicated pseudorandom files, I preferred plaintext, in order to dispel any doubts about the contents of the binary archive: the theoretical coverage is minor, but it does not matter. The resulting archive (sha256.zpaq), compressed by -m5 on Windows, with every filenames == SHA-256(content), is mime64-encoded and "splitted" into 4 strings, becoming (inside the source code) char extract_test1[]={"N2tT... char extract_test2[]={"W1hY... char extract_test3[]={"+Au5... char extract_test4[]={"sFPj... It is quickly possible to double-check this way (just in case...) zpaqfranz autotest -to somewhere zpaqfranz x somewhere/sha256.zpaq -to extracted The sha256.zpaq should be this one SHA-256: D90223FAEE2878D7854B9438864B4856A3C1F920C34EFB8C136A8949B54E5400 [ 158.239] sha256.zpaq With these files inside SHA-256: 00D478184C1851145A712B8054D04789DA164CDEE61EDB2240F124E0AC3501AA [ 37.000] 00D478184C1851145A712B8054D04789DA164CDEE61EDB2240F124E0AC3501AA SHA-256: 010CE956B14903A000536ACEB4B12CF503B3D84E15985A5F6C5648DC772D8B54 [ 37.000] 010CE956B14903A000536ACEB4B12CF503B3D84E15985A5F6C5648DC772D8B54 SHA-256: 032EA211A2F1CA5F977A46BF3211FB9DF3DCBC29D13D6B1764EB4B2637819A6E [ 37.000] 032EA211A2F1CA5F977A46BF3211FB9DF3DCBC29D13D6B1764EB4B2637819A6E SHA-256: 0344D52DF32E001AC79B9EADEB75CD515A2325481B4A3EF5BD876B9A64915068 [ 37.000] 0344D52DF32E001AC79B9EADEB75CD515A2325481B4A3EF5BD876B9A64915068 SHA-256: 078E164828817CAC9D7FF1CAE2F88C695C1059D495B17832522264E0CD8CAE86 [ 37.000] 078E164828817CAC9D7FF1CAE2F88C695C1059D495B17832522264E0CD8CAE86 SHA-256: 0829C6BEA1EAEEB1303950F741079730134340B484F383F354882D81EBDCC350 [ 37.000] 0829C6BEA1EAEEB1303950F741079730134340B484F383F354882D81EBDCC350 SHA-256: 08BE3D4900A6CC3E9BD4159A91EE2D86E130503A0995F21BA99DC3060F285687 [ 37.000] 08BE3D4900A6CC3E9BD4159A91EE2D86E130503A0995F21BA99DC3060F285687 SHA-256: 0960E3A414FFC2FB928425C42E51992717C809A5FF4CF2F03F922D620E3A0C12 [ 37.000] 0960E3A414FFC2FB928425C42E51992717C809A5FF4CF2F03F922D620E3A0C12 SHA-256: 0A179201C68752B062168579F5F2423FE0B76B7CEE519674DF018C3559FEA0DE [ 37.000] 0A179201C68752B062168579F5F2423FE0B76B7CEE519674DF018C3559FEA0DE SHA-256: 0A404D353DDE54CE863A235689D13F1F3FAEAABDFB0733B5E48787BF8B1ABAA0 [ 37.000] 0A404D353DDE54CE863A235689D13F1F3FAEAABDFB0733B5E48787BF8B1ABAA0 SHA-256: 0A710AA592664A6A01C98338C46AE4F9364067CD43A224A77D4B47D02126C6D4 [ 37.000] 0A710AA592664A6A01C98338C46AE4F9364067CD43A224A77D4B47D02126C6D4 SHA-256: 0B430875FEABCD1B1E20F0D4A25B6B080F16485ADEEE27A740A8CF4CE6EB5DFF [ 37.000] 0B430875FEABCD1B1E20F0D4A25B6B080F16485ADEEE27A740A8CF4CE6EB5DFF SHA-256: 0B7C69CDFDBF4D41A65EE9FCC9C290DA947C0FDDCDE7C0D8CAB20870150A97A9 [ 37.000] 0B7C69CDFDBF4D41A65EE9FCC9C290DA947C0FDDCDE7C0D8CAB20870150A97A9 SHA-256: 0DC92BFBA489354B5BF53F8AADD17C9C4659524747F467FD85ADE369834B6379 [ 37.000] 0DC92BFBA489354B5BF53F8AADD17C9C4659524747F467FD85ADE369834B6379 SHA-256: 0E082AFA0578C194400693A23B477BA8A9B309A5AF60E2BE54D8695D8BC08112 [ 37.000] 0E082AFA0578C194400693A23B477BA8A9B309A5AF60E2BE54D8695D8BC08112 SHA-256: 0E505B858ED58BA66402789B512D136BBA22F16DF9CD22CACCABF122AA0B6962 [ 37.000] 0E505B858ED58BA66402789B512D136BBA22F16DF9CD22CACCABF122AA0B6962 SHA-256: 0F5E547E80F985B3F3C13EF0658D3D3C376387FB0B67A9545F0DF09F012C8EE4 [ 37.000] 0F5E547E80F985B3F3C13EF0658D3D3C376387FB0B67A9545F0DF09F012C8EE4 SHA-256: 108AAB75EE08118321A705601435EDCAC957120B70A0E2FF6AF292F1BC32B159 [ 37.000] 108AAB75EE08118321A705601435EDCAC957120B70A0E2FF6AF292F1BC32B159 SHA-256: 10CCE2C6F78285C608158A5A0EFF34BF004E528E42FC646B485F5BA683403C13 [ 37.000] 10CCE2C6F78285C608158A5A0EFF34BF004E528E42FC646B485F5BA683403C13 SHA-256: 10DEBF94E56498EB24725F471DE3CA7C0839A388DE130CDE923D20F10FF5366B [ 37.000] 10DEBF94E56498EB24725F471DE3CA7C0839A388DE130CDE923D20F10FF5366B SHA-256: 13355FF10342D3521A87570D377CFA94151697E335AEC6FDA898FE5EDB38EB60 [ 37.000] 13355FF10342D3521A87570D377CFA94151697E335AEC6FDA898FE5EDB38EB60 SHA-256: 15C367F88C3A0550E10253DD69F76B7876D02FF72DEB028EEEBEFB5FD41C2B29 [ 37.000] 15C367F88C3A0550E10253DD69F76B7876D02FF72DEB028EEEBEFB5FD41C2B29 SHA-256: 165120A494D7B6E6E9E3D5AC33AD00B0E5BA9362BBFF062CC2F8297D007D3790 [ 37.000] 165120A494D7B6E6E9E3D5AC33AD00B0E5BA9362BBFF062CC2F8297D007D3790 SHA-256: 16C8EDAEA5AB72A5BECF00E3395908ABB727E2C005C34AACA9EC5A89E1F839BB [ 37.000] 16C8EDAEA5AB72A5BECF00E3395908ABB727E2C005C34AACA9EC5A89E1F839BB SHA-256: 1812B7923D633AA2C688A6FB2E2B9B56C61BE416C7CEFDD5C11C64D62655855F [ 37.000] 1812B7923D633AA2C688A6FB2E2B9B56C61BE416C7CEFDD5C11C64D62655855F SHA-256: 1B9E31E11D96A5EF19F71E5E005EF89C8343C9E49F053FD1E27B8B48FD107B13 [ 37.000] 1B9E31E11D96A5EF19F71E5E005EF89C8343C9E49F053FD1E27B8B48FD107B13 SHA-256: 1BD84476ADFCEBD6459DC7FF6C4E8591A0196A461B7A16849E4825E8323A2C84 [ 37.000] 1BD84476ADFCEBD6459DC7FF6C4E8591A0196A461B7A16849E4825E8323A2C84 SHA-256: 1D1155709A45EBA6FE76DA1BDE8130D4DA0B6621D9D17411E8D9F41490AF0ADD [ 37.000] 1D1155709A45EBA6FE76DA1BDE8130D4DA0B6621D9D17411E8D9F41490AF0ADD SHA-256: 1DF209DB3D40B3988B75122DCD45FD1D84DC87D4A21415DB1CB7E894D4755213 [ 37.000] 1DF209DB3D40B3988B75122DCD45FD1D84DC87D4A21415DB1CB7E894D4755213 SHA-256: 1FC14CD3E1D394DB285B7113EFA5765455516C72C6B2ADD2710ABF810EBB5591 [ 37.000] 1FC14CD3E1D394DB285B7113EFA5765455516C72C6B2ADD2710ABF810EBB5591 SHA-256: 1FD808BD5631008B0F4B10FB3050A017A9D6AFA03EC2F99186E8D1980E458153 [ 37.000] 1FD808BD5631008B0F4B10FB3050A017A9D6AFA03EC2F99186E8D1980E458153 SHA-256: 210B63FA532B0CA36974F2E4208591CB84ABA9C599E8178A6FC5E5260E19353F [ 37.000] 210B63FA532B0CA36974F2E4208591CB84ABA9C599E8178A6FC5E5260E19353F SHA-256: 21B095AF58EE64FF3E75CAE759BF8D854E85830152ABDB50BF8E177DE2C38BB5 [ 37.000] 21B095AF58EE64FF3E75CAE759BF8D854E85830152ABDB50BF8E177DE2C38BB5 SHA-256: 234CAB0BD56614D8891934E71891B0FBFE1781350EB25EBCE0ED9FA398EF8A5F [ 37.000] 234CAB0BD56614D8891934E71891B0FBFE1781350EB25EBCE0ED9FA398EF8A5F SHA-256: 24A966A5D474A7A850688563489FEF0DAEC981CB4F3CBB7E1767ABBEEDBE722E [ 37.000] 24A966A5D474A7A850688563489FEF0DAEC981CB4F3CBB7E1767ABBEEDBE722E SHA-256: 252B1DB9F19113AEE3575B805B4B6BA768B4FC93EDB05A8E6EC61650FDF39D2B [ 37.000] 252B1DB9F19113AEE3575B805B4B6BA768B4FC93EDB05A8E6EC61650FDF39D2B SHA-256: 25D8AEE1BDE16464F72E0A7BBA0550F0BD843D1FF1BA817D8877739A6FB0CDDA [ 37.000] 25D8AEE1BDE16464F72E0A7BBA0550F0BD843D1FF1BA817D8877739A6FB0CDDA SHA-256: 26BFB864EEC92283547953EB66009274DE9E25C89C15C11571543925AEB06CFC [ 37.000] 26BFB864EEC92283547953EB66009274DE9E25C89C15C11571543925AEB06CFC SHA-256: 26FD9CBE82F02D2F1D40EC7D61F64992475005B071555FF0F7891BC90ED07DFF [ 37.000] 26FD9CBE82F02D2F1D40EC7D61F64992475005B071555FF0F7891BC90ED07DFF SHA-256: 27074DA8B7C6D97E09092CA36C801AB00E00DFE89A2DBFE3D0F9064C7B538AA9 [ 37.000] 27074DA8B7C6D97E09092CA36C801AB00E00DFE89A2DBFE3D0F9064C7B538AA9 SHA-256: 2756249F7862D948B8DADD7D6B94F2EABF616AE9BDD4FBB4E5D74B4F216988DF [ 37.000] 2756249F7862D948B8DADD7D6B94F2EABF616AE9BDD4FBB4E5D74B4F216988DF SHA-256: 27C54140CF47AA5B7D469FCABBBFEEA666D23C427A636C869350FCEA46C892B0 [ 37.000] 27C54140CF47AA5B7D469FCABBBFEEA666D23C427A636C869350FCEA46C892B0 SHA-256: 28A1435A0ECC1A521150DDECE1E1F213B42CBC2FF754824A8A0177DE2A4319C4 [ 37.000] 28A1435A0ECC1A521150DDECE1E1F213B42CBC2FF754824A8A0177DE2A4319C4 SHA-256: 2D8294F94A7B49E8A1CEEC70A9E204DAC69016ED681B07099370BBEB3D82352A [ 37.000] 2D8294F94A7B49E8A1CEEC70A9E204DAC69016ED681B07099370BBEB3D82352A SHA-256: 2F70BDF9416D3C0A2D00DC9526F8A95E0DF437B862B3DC8EE10418E58D73FADE [ 37.000] 2F70BDF9416D3C0A2D00DC9526F8A95E0DF437B862B3DC8EE10418E58D73FADE SHA-256: 3089FB37D22A22682CAA80F56B73DD7843A0C2567AB7373295F60340A8DE1038 [ 37.000] 3089FB37D22A22682CAA80F56B73DD7843A0C2567AB7373295F60340A8DE1038 SHA-256: 30C5E6037FCCC63994DB761FAF3D4E7ED5BABFC3D62F9C560058791437C6EFE4 [ 37.000] 30C5E6037FCCC63994DB761FAF3D4E7ED5BABFC3D62F9C560058791437C6EFE4 SHA-256: 31528C0C41EEA6E4234D1939DAC42BC389B6A9B1B2E4AA92918D30B7DF1587F2 [ 37.000] 31528C0C41EEA6E4234D1939DAC42BC389B6A9B1B2E4AA92918D30B7DF1587F2 SHA-256: 341F785E400CABD0688623FF248496BDA776D979FD184A07EC2A17CB1F9D44D1 [ 37.000] 341F785E400CABD0688623FF248496BDA776D979FD184A07EC2A17CB1F9D44D1 SHA-256: 3464F4CD9F1DE1E989FA8F07CB614A6324AF9121AE908A60137606CBE3866350 [ 37.000] 3464F4CD9F1DE1E989FA8F07CB614A6324AF9121AE908A60137606CBE3866350 SHA-256: 36BBB282BD737FFE945AF89A7108B70E626A980E8EA7B9A28F595AFE1908576A [ 37.000] 36BBB282BD737FFE945AF89A7108B70E626A980E8EA7B9A28F595AFE1908576A SHA-256: 37C94F56F8193D38C53846C05ED64C325E3CE31B83FD579F6FE4424D80AE2990 [ 37.000] 37C94F56F8193D38C53846C05ED64C325E3CE31B83FD579F6FE4424D80AE2990 SHA-256: 389CD2ACD8D2615C24233B16B6743B7CCFAF647D9071E3C6085F9407AE21EDA2 [ 37.000] 389CD2ACD8D2615C24233B16B6743B7CCFAF647D9071E3C6085F9407AE21EDA2 SHA-256: 3900A9A0227F16E20D73349CC5C35071AA7F074FF126F50D6D688DC68390F19D [ 37.000] 3900A9A0227F16E20D73349CC5C35071AA7F074FF126F50D6D688DC68390F19D SHA-256: 39343E6C33FD0F90C17A97148F94EE829F0E4B1CB2BAD01193A1CFE220AAFE52 [ 37.000] 39343E6C33FD0F90C17A97148F94EE829F0E4B1CB2BAD01193A1CFE220AAFE52 SHA-256: 39C3B48B173EA632FA8D5F024E3073E84F5027C4E7830DF3844CBDADD564C2B5 [ 37.000] 39C3B48B173EA632FA8D5F024E3073E84F5027C4E7830DF3844CBDADD564C2B5 SHA-256: 3B195045FE2AD01D640130A57775C456F9535946DEE65F5D960C6D3DD31F9E2A [ 37.000] 3B195045FE2AD01D640130A57775C456F9535946DEE65F5D960C6D3DD31F9E2A SHA-256: 3B7F9DFDAC53BEF07CF14030DFB0196AB8245B079B7BFB1DBBAA453677D0EAC1 [ 37.000] 3B7F9DFDAC53BEF07CF14030DFB0196AB8245B079B7BFB1DBBAA453677D0EAC1 SHA-256: 3BD4034DE33995B16866BD38101DD3E74CE7422CF4CA264C33C91D162A8F7B70 [ 37.000] 3BD4034DE33995B16866BD38101DD3E74CE7422CF4CA264C33C91D162A8F7B70 SHA-256: 3BE3FD05735B114206ABAC244D2990BC031DE034968848C27E58441DB0157FB8 [ 37.000] 3BE3FD05735B114206ABAC244D2990BC031DE034968848C27E58441DB0157FB8 SHA-256: 3BE556B87E0F6B64576646F8D1915DE5166F850730711A48A546589CA7A116F9 [ 37.000] 3BE556B87E0F6B64576646F8D1915DE5166F850730711A48A546589CA7A116F9 SHA-256: 3D4E6466502B9E393D833C61FE220D63A503855D5C2AEF061DEBAD645307E6C2 [ 37.000] 3D4E6466502B9E393D833C61FE220D63A503855D5C2AEF061DEBAD645307E6C2 SHA-256: 3D94BB464584A7AFFEC863D45FBE635E26E2E1936C76A280960D9FD51C85EB4D [ 37.000] 3D94BB464584A7AFFEC863D45FBE635E26E2E1936C76A280960D9FD51C85EB4D SHA-256: 3D98E7FC5B59489DE3FC5C2B39FAC5CAAD25F22E2FFD9DBF07C938029651FE80 [ 37.000] 3D98E7FC5B59489DE3FC5C2B39FAC5CAAD25F22E2FFD9DBF07C938029651FE80 SHA-256: 3E4A8132599AED13297DB87E69861257AF0253F050EF9A791907A9F7760E1E09 [ 37.000] 3E4A8132599AED13297DB87E69861257AF0253F050EF9A791907A9F7760E1E09 SHA-256: 3F3AFC1BC3DAD1A75AB79497BA4A7D795BC208DCF9CF8C3CCE01E75022D25C53 [ 37.000] 3F3AFC1BC3DAD1A75AB79497BA4A7D795BC208DCF9CF8C3CCE01E75022D25C53 SHA-256: 3FA10C9DF65691A1686059CCF4EAB20BF5E4EBD360A6663CDF88AE80D24593D2 [ 37.000] 3FA10C9DF65691A1686059CCF4EAB20BF5E4EBD360A6663CDF88AE80D24593D2 SHA-256: 446F672B5C291D11EE997A3BD6B0479C23179F28FB5D0D284CC35875727BDE73 [ 37.000] 446F672B5C291D11EE997A3BD6B0479C23179F28FB5D0D284CC35875727BDE73 SHA-256: 447E42ADEB6C7EBCD3ED68DCB8B7C91729227B3482CCF2392EC8ECB41C702E8B [ 37.000] 447E42ADEB6C7EBCD3ED68DCB8B7C91729227B3482CCF2392EC8ECB41C702E8B SHA-256: 45441B49D27BB4D48D26253901488318700DDA5E64E7475D46CC69529A6E1B5D [ 37.000] 45441B49D27BB4D48D26253901488318700DDA5E64E7475D46CC69529A6E1B5D SHA-256: 45DF6FD68BF0B4AB153492FB7492BC7CC518EEB4D77999F6838667D0CBB612E0 [ 37.000] 45DF6FD68BF0B4AB153492FB7492BC7CC518EEB4D77999F6838667D0CBB612E0 SHA-256: 462DA79124E977C9AFE38D773DE68178A14044B666C6CE3F58632DF2B64FE303 [ 37.000] 462DA79124E977C9AFE38D773DE68178A14044B666C6CE3F58632DF2B64FE303 SHA-256: 4639FAE9FEB3AC00269AF6CFB8FDDA191C3FFD51E7958B2C36123856E4652DAA [ 37.000] 4639FAE9FEB3AC00269AF6CFB8FDDA191C3FFD51E7958B2C36123856E4652DAA SHA-256: 474E4473A1BA757D56456B70C1B45A09E5EEDA080882C527FAD642774D769891 [ 37.000] 474E4473A1BA757D56456B70C1B45A09E5EEDA080882C527FAD642774D769891 SHA-256: 475EE529339349676C3C54CF7AB24B35D06163AED1888D23D8655F28AD6CA77C [ 37.000] 475EE529339349676C3C54CF7AB24B35D06163AED1888D23D8655F28AD6CA77C SHA-256: 47C6CD8953A795F630BC41CF3FAEF03742129CA779404C9E7384B73049EC710B [ 37.000] 47C6CD8953A795F630BC41CF3FAEF03742129CA779404C9E7384B73049EC710B SHA-256: 49BE9B32041ABAC22FFAA72A1DC14EF0E3EC5AC2BF2CB6A7276C1EA245FDEDFB [ 37.000] 49BE9B32041ABAC22FFAA72A1DC14EF0E3EC5AC2BF2CB6A7276C1EA245FDEDFB SHA-256: 4A9812764E2B1C34A22D298DA9BAB0032DB90C951BD890D903BE260A1842A0DF [ 37.000] 4A9812764E2B1C34A22D298DA9BAB0032DB90C951BD890D903BE260A1842A0DF SHA-256: 4BFDDC3ABF535FFFFE0597F3888C98836ABC39D263D965B56965309C1E97517A [ 37.000] 4BFDDC3ABF535FFFFE0597F3888C98836ABC39D263D965B56965309C1E97517A SHA-256: 4C39512F3778F92125BC22AE35CF128542B417B08FAE57BB9FA2B08BD53FB604 [ 37.000] 4C39512F3778F92125BC22AE35CF128542B417B08FAE57BB9FA2B08BD53FB604 SHA-256: 4D54FCF77DBBA3143F67EDDB073C598D161E8E4EBFA6F1296D3EFF7FB14DA9C5 [ 37.000] 4D54FCF77DBBA3143F67EDDB073C598D161E8E4EBFA6F1296D3EFF7FB14DA9C5 SHA-256: 50D7BF4E0E45BE449F054B756AE0D5BF615219AE40D46C63A5BEBC33AF525A73 [ 37.000] 50D7BF4E0E45BE449F054B756AE0D5BF615219AE40D46C63A5BEBC33AF525A73 SHA-256: 519E27584C601906882D7CEC1BA6DBF7FE156A940A9DC39F6CDBECF43D5A1FDC [ 37.000] 519E27584C601906882D7CEC1BA6DBF7FE156A940A9DC39F6CDBECF43D5A1FDC SHA-256: 526911B84F03A0C25B4D5FC23DD45DA5AD54CF20581006AC97B270AE943ADCF3 [ 37.000] 526911B84F03A0C25B4D5FC23DD45DA5AD54CF20581006AC97B270AE943ADCF3 SHA-256: 529CAAC78E5277E4D142F8261E53E6570C92ACA496F7A5DC8CF4DB674CFF9447 [ 37.000] 529CAAC78E5277E4D142F8261E53E6570C92ACA496F7A5DC8CF4DB674CFF9447 SHA-256: 544C881F08F27C926F3AFFC81C0CA4AACDCB8A0B748B8B5D685BE690CFEF8D5A [ 37.000] 544C881F08F27C926F3AFFC81C0CA4AACDCB8A0B748B8B5D685BE690CFEF8D5A SHA-256: 548F141A26913632C46AA174A36CFBD40AB0D6A968E83054AF35A3B5CEFAE1BA [ 37.000] 548F141A26913632C46AA174A36CFBD40AB0D6A968E83054AF35A3B5CEFAE1BA SHA-256: 55D7218CA360C0967A8D3C012FDBFB1EDE923BB6DC87244C2F6BC2944D449AD3 [ 37.000] 55D7218CA360C0967A8D3C012FDBFB1EDE923BB6DC87244C2F6BC2944D449AD3 SHA-256: 55E4CF5A088772EB94C4E6DDF0DB5381171F37E5B82ED363056CE22B426B13CB [ 37.000] 55E4CF5A088772EB94C4E6DDF0DB5381171F37E5B82ED363056CE22B426B13CB SHA-256: 5655700594E3E8057480DF1DB7395339FADEAD7600DE9FE1E704D3B37FDF3483 [ 37.000] 5655700594E3E8057480DF1DB7395339FADEAD7600DE9FE1E704D3B37FDF3483 SHA-256: 568860708726F8F86A8C64118DD81E1977A1068D501FA2C108D29F0E680D321E [ 37.000] 568860708726F8F86A8C64118DD81E1977A1068D501FA2C108D29F0E680D321E SHA-256: 56FB8A04E25A63192E9E540BC9FC4FD8DD50789EFC58337B0A7F8526FE2F95FA [ 37.000] 56FB8A04E25A63192E9E540BC9FC4FD8DD50789EFC58337B0A7F8526FE2F95FA SHA-256: 57A53D9564669D01DCE99B44A012CCD503D5727868C7B6DC5E3976AEF7397351 [ 37.000] 57A53D9564669D01DCE99B44A012CCD503D5727868C7B6DC5E3976AEF7397351 SHA-256: 57E24ECBA9F66747653EB16B09A4E252F6DDC4C1677C9A8547A283DF9A5CEB47 [ 37.000] 57E24ECBA9F66747653EB16B09A4E252F6DDC4C1677C9A8547A283DF9A5CEB47 SHA-256: 585FF005A50313F25EDA6A7E8BF31BCB61543C13E4156233C38A9CFBF98A91B1 [ 37.000] 585FF005A50313F25EDA6A7E8BF31BCB61543C13E4156233C38A9CFBF98A91B1 SHA-256: 5869F14D80E849BFCC43130983B64A9622FA1426E5CB4AD870E173AC5E2C881C [ 37.000] 5869F14D80E849BFCC43130983B64A9622FA1426E5CB4AD870E173AC5E2C881C SHA-256: 591F77D4E0D9A290D5928491661F6BC57FBB6F5D2D22C3CC21A2D82DBC0CB789 [ 37.000] 591F77D4E0D9A290D5928491661F6BC57FBB6F5D2D22C3CC21A2D82DBC0CB789 SHA-256: 5A0E32FD143AD117EBE107823C0168BC04228AAF21703009C077A41B0FBF457D [ 37.000] 5A0E32FD143AD117EBE107823C0168BC04228AAF21703009C077A41B0FBF457D SHA-256: 5A55CA569AA57411613844F1E908E7356C03136ECED223512CC34998968E1201 [ 37.000] 5A55CA569AA57411613844F1E908E7356C03136ECED223512CC34998968E1201 SHA-256: 5AE15A0204325884D4C9FDAF524E6A39019EEA61D177C2749A485C15960C51D2 [ 37.000] 5AE15A0204325884D4C9FDAF524E6A39019EEA61D177C2749A485C15960C51D2 SHA-256: 5CF9EF180B74B15F6B12C23F6EEE683FF2E21188844D364907BFB61D96108528 [ 37.000] 5CF9EF180B74B15F6B12C23F6EEE683FF2E21188844D364907BFB61D96108528 SHA-256: 5D631323E6C1CF993EB0722A5CECFC7B13E7FA34A60970841F39502543B9A553 [ 37.000] 5D631323E6C1CF993EB0722A5CECFC7B13E7FA34A60970841F39502543B9A553 SHA-256: 5DC3470EBC48F08A5F09D48306CAFDBA04A91FEE69983E066D261AB51C9862CE [ 37.000] 5DC3470EBC48F08A5F09D48306CAFDBA04A91FEE69983E066D261AB51C9862CE SHA-256: 5DE49182F8A1D29C04201C681FC04980B53A06FE25319BCF874AEA24397323F8 [ 37.000] 5DE49182F8A1D29C04201C681FC04980B53A06FE25319BCF874AEA24397323F8 SHA-256: 5E9ACB1D0E299FBE610A7BD551B4AB624F058B1AB1FDF0B05C75BCC963E8EEED [ 37.000] 5E9ACB1D0E299FBE610A7BD551B4AB624F058B1AB1FDF0B05C75BCC963E8EEED SHA-256: 5FB79AF55A64980E27C8EBEDDA7A65D53091B8558EDC01AEFEC34716420B26B5 [ 37.000] 5FB79AF55A64980E27C8EBEDDA7A65D53091B8558EDC01AEFEC34716420B26B5 SHA-256: 61A20B5037DEEC703B9E0420437B9227D53E2CF10165CEF6A881A95988F3FD50 [ 37.000] 61A20B5037DEEC703B9E0420437B9227D53E2CF10165CEF6A881A95988F3FD50 SHA-256: 62237E28DA9E8348BF4FD60816014DE340272EE3AF71D29AA846B2F17070FC60 [ 37.000] 62237E28DA9E8348BF4FD60816014DE340272EE3AF71D29AA846B2F17070FC60 SHA-256: 632D576C07DC4F0387CE451E4C9485F561CA374BC2CC6B4B3544A546DED2679A [ 37.000] 632D576C07DC4F0387CE451E4C9485F561CA374BC2CC6B4B3544A546DED2679A SHA-256: 64C51FDE6036CFEACF8793B20EC596CB420A2CB91487101E4048DE120EC9FFE9 [ 37.000] 64C51FDE6036CFEACF8793B20EC596CB420A2CB91487101E4048DE120EC9FFE9 SHA-256: 65300EB7090569287D264479CB84ACC2091867391F6151EC7CC17041DC4DBD9D [ 37.000] 65300EB7090569287D264479CB84ACC2091867391F6151EC7CC17041DC4DBD9D SHA-256: 659690FAA0059BD9487FC7081F057699774737F071C7081EB541A3B7329A4F47 [ 37.000] 659690FAA0059BD9487FC7081F057699774737F071C7081EB541A3B7329A4F47 SHA-256: 65FDC24F04EFDE97623AD9A3B1EEBF4B1AE5C92BA1B7006C18690B6DF3192070 [ 37.000] 65FDC24F04EFDE97623AD9A3B1EEBF4B1AE5C92BA1B7006C18690B6DF3192070 SHA-256: 6662229A32542A195E82D016C2CAA47C73733D13F395C7AB12DF838F19A7245B [ 37.000] 6662229A32542A195E82D016C2CAA47C73733D13F395C7AB12DF838F19A7245B SHA-256: 66A92DF3DFE7ECC7429FF033CF5BFBAE8F3B9D019403BA8BA0835B0F2CCEF98C [ 37.000] 66A92DF3DFE7ECC7429FF033CF5BFBAE8F3B9D019403BA8BA0835B0F2CCEF98C SHA-256: 67827811F2CB17E03415DE6E46EC2FE7561A7E07790FE1E97807C0F778760BCE [ 37.000] 67827811F2CB17E03415DE6E46EC2FE7561A7E07790FE1E97807C0F778760BCE SHA-256: 6AAAE32CBA8AA049FEAFE093E9EC9C4617534A7F37A4F90B81F6F27003C43C03 [ 37.000] 6AAAE32CBA8AA049FEAFE093E9EC9C4617534A7F37A4F90B81F6F27003C43C03 SHA-256: 6B7273DD6F79E6F3D4353989FB07983B5F47DFEF3946909BD7DA990C74708002 [ 37.000] 6B7273DD6F79E6F3D4353989FB07983B5F47DFEF3946909BD7DA990C74708002 SHA-256: 6DEDFAB01FE0573D34AF4546FFDC27341C985111473F6EB047731B3465AFCDCA [ 37.000] 6DEDFAB01FE0573D34AF4546FFDC27341C985111473F6EB047731B3465AFCDCA SHA-256: 706FED95A8978923F550C6C802F617A47C94CF7FA015353D59F01525D0109F7C [ 37.000] 706FED95A8978923F550C6C802F617A47C94CF7FA015353D59F01525D0109F7C SHA-256: 714D71D28B1ADE8FDEA1DBC297EE155FCF5318A97B0E561650C7B781778217BC [ 37.000] 714D71D28B1ADE8FDEA1DBC297EE155FCF5318A97B0E561650C7B781778217BC SHA-256: 7297DAF3C58DDDDEFCEF35296A90DD1DBFF8817682420F6B4E43BB2E1F02F153 [ 37.000] 7297DAF3C58DDDDEFCEF35296A90DD1DBFF8817682420F6B4E43BB2E1F02F153 SHA-256: 72DAF5A9F35AEB68EE403C1E711ED408E2BF19D1D42DAD6BE68EDEDFA30E8F82 [ 37.000] 72DAF5A9F35AEB68EE403C1E711ED408E2BF19D1D42DAD6BE68EDEDFA30E8F82 SHA-256: 744BABE76DE3DCB47E6EB868387591A543011514C842F8C1CA701E0247D9973A [ 37.000] 744BABE76DE3DCB47E6EB868387591A543011514C842F8C1CA701E0247D9973A SHA-256: 752571BDBB1D25A5AF56C96144E67BDCD8FDBA1CB2DA988C7727D5B4B71F1CC1 [ 37.000] 752571BDBB1D25A5AF56C96144E67BDCD8FDBA1CB2DA988C7727D5B4B71F1CC1 SHA-256: 77161315B7C3E9510C66514B7D6B144381B5F738411E5F5885E7906BF65ADF8A [ 37.000] 77161315B7C3E9510C66514B7D6B144381B5F738411E5F5885E7906BF65ADF8A SHA-256: 78A1EA5E4AF17BDC4E322D1EB9753633C27C6B8846FA25CEF93A12532208F6A0 [ 37.000] 78A1EA5E4AF17BDC4E322D1EB9753633C27C6B8846FA25CEF93A12532208F6A0 SHA-256: 7DBACBF41154D95C4D694AAA3579C0159DFB409FE0CA3529596554AC2C4EA256 [ 37.000] 7DBACBF41154D95C4D694AAA3579C0159DFB409FE0CA3529596554AC2C4EA256 SHA-256: 7F028BAA27EA9043E3E263913A53CC5E4059A4F8F4D0E06932552FAA777A42CC [ 37.000] 7F028BAA27EA9043E3E263913A53CC5E4059A4F8F4D0E06932552FAA777A42CC SHA-256: 7F94A6F0857C988EB107EF6A65559DC7B37A4D9BCBBBB94564244D61B8AB4B77 [ 37.000] 7F94A6F0857C988EB107EF6A65559DC7B37A4D9BCBBBB94564244D61B8AB4B77 SHA-256: 7FB17B349C66A0CD28A6A796BF262ADD149A70DF496E15177D5315CBA2EDF9A5 [ 37.000] 7FB17B349C66A0CD28A6A796BF262ADD149A70DF496E15177D5315CBA2EDF9A5 SHA-256: 80BCC74AA133D46752E346EC74AA050227B247DC79624065719294D49D284AE9 [ 37.000] 80BCC74AA133D46752E346EC74AA050227B247DC79624065719294D49D284AE9 SHA-256: 816BF2C6564FBD09FF2A2DE8B54684F19664F9D9274D87966C46FA768F0FB101 [ 37.000] 816BF2C6564FBD09FF2A2DE8B54684F19664F9D9274D87966C46FA768F0FB101 SHA-256: 81858D5E5EFC2A41A99EBC871AC25FE622B4E2601F7896FCF7DC7CB7844946BB [ 37.000] 81858D5E5EFC2A41A99EBC871AC25FE622B4E2601F7896FCF7DC7CB7844946BB SHA-256: 82041513A6416E9105FB4BE6DDEC0A301B200E3D0A051DAB56DF599E7D058C33 [ 37.000] 82041513A6416E9105FB4BE6DDEC0A301B200E3D0A051DAB56DF599E7D058C33 SHA-256: 83634D72BF480913A52F55DD7312273A4889E238BB31105FD6FF9292B9575E53 [ 37.000] 83634D72BF480913A52F55DD7312273A4889E238BB31105FD6FF9292B9575E53 SHA-256: 85DA854914FC7AECB458C9887FE9E3E8EADB5D9A51729FD4023E12A2A62BA84B [ 37.000] 85DA854914FC7AECB458C9887FE9E3E8EADB5D9A51729FD4023E12A2A62BA84B SHA-256: 87432D9300A3D974061765BD5E46C21DBD773B7531CA1F58313FFF475D0D55F7 [ 37.000] 87432D9300A3D974061765BD5E46C21DBD773B7531CA1F58313FFF475D0D55F7 SHA-256: 885537E91B77DA9E298B0827ED72951592BB0E6D48FBED9D079D7354335365CF [ 37.000] 885537E91B77DA9E298B0827ED72951592BB0E6D48FBED9D079D7354335365CF SHA-256: 885F1E5C7D3D223B10DCB8A986D7F2E443E05AF2EB7B39A815F16BE6AF8A55AC [ 37.000] 885F1E5C7D3D223B10DCB8A986D7F2E443E05AF2EB7B39A815F16BE6AF8A55AC SHA-256: 8869B76663373A64CE35E531AA3BF3248F8919C99BFE72D8925A4761BD292981 [ 37.000] 8869B76663373A64CE35E531AA3BF3248F8919C99BFE72D8925A4761BD292981 SHA-256: 889A86F182D19AACA016F89E8F8A12508FEDF87A387D0A2F4314CB240C205AB2 [ 37.000] 889A86F182D19AACA016F89E8F8A12508FEDF87A387D0A2F4314CB240C205AB2 SHA-256: 89FDFCB3293555F11F9B1F8D3F7F7039AB49C5772131DE80FD50BD26575F8FDA [ 37.000] 89FDFCB3293555F11F9B1F8D3F7F7039AB49C5772131DE80FD50BD26575F8FDA SHA-256: 8A20C46725F9E78C8DAAE2D749018CE4122C55976CFEE975800B8EB945AE64D3 [ 37.000] 8A20C46725F9E78C8DAAE2D749018CE4122C55976CFEE975800B8EB945AE64D3 SHA-256: 8DD92BF97911C490E4AB5CCEB75DC9D3FAF32933EC8B480C2369F8CDF570187F [ 37.000] 8DD92BF97911C490E4AB5CCEB75DC9D3FAF32933EC8B480C2369F8CDF570187F SHA-256: 8DE9D087F2067E5127162F010A0E2053A597DDE796545C7A2C0E52B047E06351 [ 37.000] 8DE9D087F2067E5127162F010A0E2053A597DDE796545C7A2C0E52B047E06351 SHA-256: 8E330005B0A7F402F2C6C9ACDB2B029875422B30FCE6F8C08186612E6C3512F8 [ 37.000] 8E330005B0A7F402F2C6C9ACDB2B029875422B30FCE6F8C08186612E6C3512F8 SHA-256: 8F9F0F05E638D6D1A1E7BCAE7EA837C8113FEB54790F36F1EB3870933DD0A407 [ 37.000] 8F9F0F05E638D6D1A1E7BCAE7EA837C8113FEB54790F36F1EB3870933DD0A407 SHA-256: 8FC82F03F95CE9FFF6A2E781415E0A903B0DEFF790C1F36FDDBE6F3D56FCD6F5 [ 37.000] 8FC82F03F95CE9FFF6A2E781415E0A903B0DEFF790C1F36FDDBE6F3D56FCD6F5 SHA-256: 8FD5B0F4F0F3CF882D70723C1432ABCA933A94E2A847BE7EA9314E61F552A195 [ 37.000] 8FD5B0F4F0F3CF882D70723C1432ABCA933A94E2A847BE7EA9314E61F552A195 SHA-256: 914671B460546BAF8D841BD9703176C02150590717D56124EF8B4BE9AA3E1CF7 [ 37.000] 914671B460546BAF8D841BD9703176C02150590717D56124EF8B4BE9AA3E1CF7 SHA-256: 92244AB4F4AF52B7C3E5F256A924A5D1C9ED323B52CC3F14A23AEA503FA3BBC7 [ 37.000] 92244AB4F4AF52B7C3E5F256A924A5D1C9ED323B52CC3F14A23AEA503FA3BBC7 SHA-256: 92F7BDEE518157ECD18968BE6E4AC17B2666FBB2A47789EFD84F05F21691200E [ 37.000] 92F7BDEE518157ECD18968BE6E4AC17B2666FBB2A47789EFD84F05F21691200E SHA-256: 934123B3BF2CE4BE47AE36BBDE8F9D23D77EAEAFA2A8B2ACD61D7AE8F577DED4 [ 37.000] 934123B3BF2CE4BE47AE36BBDE8F9D23D77EAEAFA2A8B2ACD61D7AE8F577DED4 SHA-256: 93BED1842035886A3BA8BF295E35B9D9F6CD10CC3711D1DD82E851A2BD3CCE58 [ 37.000] 93BED1842035886A3BA8BF295E35B9D9F6CD10CC3711D1DD82E851A2BD3CCE58 SHA-256: 93E35FD1D23278E82F57DE9C3281C9CA22622F60D8A7EDC59A4CACFF7149D009 [ 37.000] 93E35FD1D23278E82F57DE9C3281C9CA22622F60D8A7EDC59A4CACFF7149D009 SHA-256: 9444E16862B2A46EB999A2E23109002F2DD63AC9F8BD3830CDADFBE414ABC38B [ 37.000] 9444E16862B2A46EB999A2E23109002F2DD63AC9F8BD3830CDADFBE414ABC38B SHA-256: 952F5E3F51D123B7F18CE5999C7261404C2BD99CCFEE31FCD7C71579F27F51F8 [ 37.000] 952F5E3F51D123B7F18CE5999C7261404C2BD99CCFEE31FCD7C71579F27F51F8 SHA-256: 95AEFF7C413D4180BF1D19893F66E13DBE212DCD341349230921F8E91ECB7575 [ 37.000] 95AEFF7C413D4180BF1D19893F66E13DBE212DCD341349230921F8E91ECB7575 SHA-256: 9B92039B3A8800234BF0A30D5B76C3DF717D5BC3875F9765214711851425A899 [ 37.000] 9B92039B3A8800234BF0A30D5B76C3DF717D5BC3875F9765214711851425A899 SHA-256: 9C0BF94D6AEFCF1A145E52770998E29C56E341923FFB81C5ED8723FA18F59B52 [ 37.000] 9C0BF94D6AEFCF1A145E52770998E29C56E341923FFB81C5ED8723FA18F59B52 SHA-256: 9F01E7BC4C2296127E12A99EB2D632EB7336B7F8FD3FB338B380C607427D8268 [ 37.000] 9F01E7BC4C2296127E12A99EB2D632EB7336B7F8FD3FB338B380C607427D8268 SHA-256: A0F57829AFA6C0CEA1BABA37FF73DC9CE114B5D0D15A5A010D12C4F9F83C7AD3 [ 37.000] A0F57829AFA6C0CEA1BABA37FF73DC9CE114B5D0D15A5A010D12C4F9F83C7AD3 SHA-256: A1245F01239FA30E0D833AB8078065BFF8DE3F5DD79803A334C8872E7FFC6306 [ 37.000] A1245F01239FA30E0D833AB8078065BFF8DE3F5DD79803A334C8872E7FFC6306 SHA-256: A3D6E0C3733A036E06528F3762E89AECE4298D0602A3CF1BC8747951D3FE466F [ 37.000] A3D6E0C3733A036E06528F3762E89AECE4298D0602A3CF1BC8747951D3FE466F SHA-256: A48845D5582B2D884F159DFCE86B4664E584E1D3CE5ED203A710D88DB0C855B6 [ 37.000] A48845D5582B2D884F159DFCE86B4664E584E1D3CE5ED203A710D88DB0C855B6 SHA-256: A4B2756FA53988A9663BE419189AC5F39FCB1D4E88FCA6573FD62F69075DDD45 [ 37.000] A4B2756FA53988A9663BE419189AC5F39FCB1D4E88FCA6573FD62F69075DDD45 SHA-256: A4F387B0878F07F4D893180CBE03682B799E915E8C0B47A0A8CDDD580B273E67 [ 37.000] A4F387B0878F07F4D893180CBE03682B799E915E8C0B47A0A8CDDD580B273E67 SHA-256: A5F6F944B998606D0AA018081B05DF7128C0CE3564DE525AD97A762DA5BEB235 [ 37.000] A5F6F944B998606D0AA018081B05DF7128C0CE3564DE525AD97A762DA5BEB235 SHA-256: A6A354D4D57412DC2D322991A6384274A1AC875B264A0BE35066918656899C20 [ 37.000] A6A354D4D57412DC2D322991A6384274A1AC875B264A0BE35066918656899C20 SHA-256: A748FA178ED7A3797150AA1FD6171B62F870D77AA12C1A93CA995982F737C348 [ 37.000] A748FA178ED7A3797150AA1FD6171B62F870D77AA12C1A93CA995982F737C348 SHA-256: A7FCF9987603F0744E163C71A97723A83BD8DED7D29DEC9CAA5A905FE5AE4EA6 [ 37.000] A7FCF9987603F0744E163C71A97723A83BD8DED7D29DEC9CAA5A905FE5AE4EA6 SHA-256: A82EAF353C17B6C91221752985C6E193FE44A4F798E8C757D0058970A378CDC1 [ 37.000] A82EAF353C17B6C91221752985C6E193FE44A4F798E8C757D0058970A378CDC1 SHA-256: A86AE1B47BF3F390D361CC4D97E4544695664BD5B77607AE9A987F847F205BAC [ 37.000] A86AE1B47BF3F390D361CC4D97E4544695664BD5B77607AE9A987F847F205BAC SHA-256: A871EF3DE9F21D0192F34B624C414C73A4368FF1F6AD1A5297337FC68380ACE4 [ 37.000] A871EF3DE9F21D0192F34B624C414C73A4368FF1F6AD1A5297337FC68380ACE4 SHA-256: A9056DDF0D40648EFA52BFBBBC32E752E5059106F87E86F58DC2DF0B6B93FE15 [ 37.000] A9056DDF0D40648EFA52BFBBBC32E752E5059106F87E86F58DC2DF0B6B93FE15 SHA-256: AA463359197B0BE43B1A101EC200220230BC688FA6941DDB726456B1F0422804 [ 37.000] AA463359197B0BE43B1A101EC200220230BC688FA6941DDB726456B1F0422804 SHA-256: ABED942532E2E32FF3A1296CBE307C651AF4C906D9980DC740615516F457AF4A [ 37.000] ABED942532E2E32FF3A1296CBE307C651AF4C906D9980DC740615516F457AF4A SHA-256: ADDD5910D7071C29AB1507F4971E673CF2D30FABF403793AC5B85B36DE94F975 [ 37.000] ADDD5910D7071C29AB1507F4971E673CF2D30FABF403793AC5B85B36DE94F975 SHA-256: ADF51921DA80A6BBE7B30D8CC7CB94174E3E7EBAEF8DAD44389C35882A0220BE [ 37.000] ADF51921DA80A6BBE7B30D8CC7CB94174E3E7EBAEF8DAD44389C35882A0220BE SHA-256: AF230BB829E24655DD3654736A4F08025CEC27A2015DC80847481F72DF5465F4 [ 37.000] AF230BB829E24655DD3654736A4F08025CEC27A2015DC80847481F72DF5465F4 SHA-256: B15C62466B0AB8C4DB14A8D80DA6808EEF720F7F09AEB66663A61A1BA0533EC3 [ 37.000] B15C62466B0AB8C4DB14A8D80DA6808EEF720F7F09AEB66663A61A1BA0533EC3 SHA-256: B1F23843C8F238C08D4AEFCD64FED8C26525F826CEDBE5D15DA0C88F8C74F92A [ 37.000] B1F23843C8F238C08D4AEFCD64FED8C26525F826CEDBE5D15DA0C88F8C74F92A SHA-256: B40B640D8D750FB3E19CDF3A86D51D7065497DF0C043B4F7778681DFE4AB7FDF [ 37.000] B40B640D8D750FB3E19CDF3A86D51D7065497DF0C043B4F7778681DFE4AB7FDF SHA-256: B4F0CE880294117909FAD195C1132004CEA587E68592C7249EA7913DC4041D14 [ 37.000] B4F0CE880294117909FAD195C1132004CEA587E68592C7249EA7913DC4041D14 SHA-256: B587496E5038553959A20FD1286808608EC0F79C993E07C245845FF7C8C83626 [ 37.000] B587496E5038553959A20FD1286808608EC0F79C993E07C245845FF7C8C83626 SHA-256: B667B42A317718CB5294547E6A8DFA2C461EAFCE5D81409B8BD766228241FCAE [ 37.000] B667B42A317718CB5294547E6A8DFA2C461EAFCE5D81409B8BD766228241FCAE SHA-256: B82AB78154C96B5B5BF682604FB8C256C20A3D894C6199DF7A277304D0C390FD [ 37.000] B82AB78154C96B5B5BF682604FB8C256C20A3D894C6199DF7A277304D0C390FD SHA-256: B872FD54019BE3BCCF40D3C2E0805DF8832BABF5FA79A6ABCBD6224DB73B3AA8 [ 37.000] B872FD54019BE3BCCF40D3C2E0805DF8832BABF5FA79A6ABCBD6224DB73B3AA8 SHA-256: B8CC07752DF266ED084D4C58991CD1D7C486B7256C5ABBE30195954C5393AB22 [ 37.000] B8CC07752DF266ED084D4C58991CD1D7C486B7256C5ABBE30195954C5393AB22 SHA-256: BB8E03BA705D39FF477686157CEE4689BC4F2FF0F8AFA9B6EC22E7B76009C766 [ 37.000] BB8E03BA705D39FF477686157CEE4689BC4F2FF0F8AFA9B6EC22E7B76009C766 SHA-256: BBAB47571909E31E3E49F1B90FEB935375FCB58C0E58C28A788FF2158107BDD5 [ 37.000] BBAB47571909E31E3E49F1B90FEB935375FCB58C0E58C28A788FF2158107BDD5 SHA-256: BF24DAE09EC91C18E808C9871F8C1736C432F97034B329AC15411CFA2316B51D [ 37.000] BF24DAE09EC91C18E808C9871F8C1736C432F97034B329AC15411CFA2316B51D SHA-256: C0060FC19C32E45CE256244FF499738B9C0FE8BF4C13D38758AB109A712E7D99 [ 37.000] C0060FC19C32E45CE256244FF499738B9C0FE8BF4C13D38758AB109A712E7D99 SHA-256: C0C9527F6A605DB0CEB46C8D791FE313ADB74C183FB24E3919953C65F4A3153B [ 37.000] C0C9527F6A605DB0CEB46C8D791FE313ADB74C183FB24E3919953C65F4A3153B SHA-256: C0D4AB0D2F0D81E31015BB76F6B0E8C66E06DE52A976C4F81FAB103F39C4B803 [ 37.000] C0D4AB0D2F0D81E31015BB76F6B0E8C66E06DE52A976C4F81FAB103F39C4B803 SHA-256: C13A2143351DC5344A1E0DC1D397B8EACFC3E768C2CB35325B08EC7312ECEFDA [ 37.000] C13A2143351DC5344A1E0DC1D397B8EACFC3E768C2CB35325B08EC7312ECEFDA SHA-256: C380DDE9106121E656CF93D643E4CF4AFC9519C6C48543BE9BD764CC264EF23A [ 37.000] C380DDE9106121E656CF93D643E4CF4AFC9519C6C48543BE9BD764CC264EF23A SHA-256: C5A1F211BD2846572B77F47BDA91CE5BBEB1518AA58B4B9EBD71A8E390549F52 [ 37.000] C5A1F211BD2846572B77F47BDA91CE5BBEB1518AA58B4B9EBD71A8E390549F52 SHA-256: C5E23D66F360B83F58ADAFEA97175AB3CE772A3BE3A2DA54E7632DC262FEC745 [ 37.000] C5E23D66F360B83F58ADAFEA97175AB3CE772A3BE3A2DA54E7632DC262FEC745 SHA-256: C8A2570459BA91EF1BDCD43EF0894D192611F52067089939D1B0A35EEA6FB467 [ 37.000] C8A2570459BA91EF1BDCD43EF0894D192611F52067089939D1B0A35EEA6FB467 SHA-256: C8DC131BC15B7ECB331FD11FB7B1893134DFCF27A8FB38B2751D65CA60FE6D5C [ 37.000] C8DC131BC15B7ECB331FD11FB7B1893134DFCF27A8FB38B2751D65CA60FE6D5C SHA-256: C9BF9A57CB0CC14E1D8DC5CBE7D648666C11A24DCEE0EC755B50FA0C8E5112A6 [ 37.000] C9BF9A57CB0CC14E1D8DC5CBE7D648666C11A24DCEE0EC755B50FA0C8E5112A6 SHA-256: CA45B6A7A32709EAC16B758A4D9224B24C05D7A3A55EBC60CA3590C0E1FC2AD0 [ 37.000] CA45B6A7A32709EAC16B758A4D9224B24C05D7A3A55EBC60CA3590C0E1FC2AD0 SHA-256: CC98269F1547CAC14F6E18D907CA3020084B2B43EED33C027EA7C4E0CADFC632 [ 37.000] CC98269F1547CAC14F6E18D907CA3020084B2B43EED33C027EA7C4E0CADFC632 SHA-256: CDD0AA1D9AA5CCA4F1DC1DE5436659181FFF2E647166F9BF1AC6F18801431B8D [ 37.000] CDD0AA1D9AA5CCA4F1DC1DE5436659181FFF2E647166F9BF1AC6F18801431B8D SHA-256: D0F51667E9EDF939CAAD49A55993C24AC4996B9AFE38B4B68B7F06B243307278 [ 37.000] D0F51667E9EDF939CAAD49A55993C24AC4996B9AFE38B4B68B7F06B243307278 SHA-256: D15199382345ED1D1505662582522E3FABE974567FFFF1B1AFE03C7AAC578D9F [ 37.000] D15199382345ED1D1505662582522E3FABE974567FFFF1B1AFE03C7AAC578D9F SHA-256: D2FB130705BDE5240BB48844CC0D6AC5B37ADC6353E3057CF44A7304EFCD2CF7 [ 37.000] D2FB130705BDE5240BB48844CC0D6AC5B37ADC6353E3057CF44A7304EFCD2CF7 SHA-256: D424E0F8DEC9C4BA53D9824105B5A40F23F4C369A55EA9E63368F1ADA2642431 [ 37.000] D424E0F8DEC9C4BA53D9824105B5A40F23F4C369A55EA9E63368F1ADA2642431 SHA-256: D62F41ACA203C670D46A85010CE8B0FC4996DD8C7FCB0DF4CE2D2DE0BC1D0AA1 [ 37.000] D62F41ACA203C670D46A85010CE8B0FC4996DD8C7FCB0DF4CE2D2DE0BC1D0AA1 SHA-256: D75FB5E2F418E684E72F60771A479B1A1E1A0A42BE0E3379CA1DCEA753A8755B [ 37.000] D75FB5E2F418E684E72F60771A479B1A1E1A0A42BE0E3379CA1DCEA753A8755B SHA-256: D762DB5943A11BDD85D0697FC990C36AD98AA781C027416C999185C9DE9666E6 [ 37.000] D762DB5943A11BDD85D0697FC990C36AD98AA781C027416C999185C9DE9666E6 SHA-256: D81E6568DDDA59E0D3C8638F7E854E97748526E55F5E9AB5EE4114008058027D [ 37.000] D81E6568DDDA59E0D3C8638F7E854E97748526E55F5E9AB5EE4114008058027D SHA-256: D85D097158BA15C9C1246B8DE51A9D7DD3276C46108DF1C945FB43E2068D749C [ 37.000] D85D097158BA15C9C1246B8DE51A9D7DD3276C46108DF1C945FB43E2068D749C SHA-256: D8FD9797588F78F9462B866A8E2253ABAFBE231819C695E0CE2A168293F2D77C [ 37.000] D8FD9797588F78F9462B866A8E2253ABAFBE231819C695E0CE2A168293F2D77C SHA-256: D91BD71E5311E75B07FEFAE4E9D1ECB07905C8CD922D614273C1ADF5DA980B6A [ 37.000] D91BD71E5311E75B07FEFAE4E9D1ECB07905C8CD922D614273C1ADF5DA980B6A SHA-256: D95B7207AA116672A69633377E9007D21C1E67CF34BC215B590B91B4E7253CD1 [ 37.000] D95B7207AA116672A69633377E9007D21C1E67CF34BC215B590B91B4E7253CD1 SHA-256: DB1710EB7117F11B40DC669CC9E2346BD9312134294F692EE285971A213B7D36 [ 37.000] DB1710EB7117F11B40DC669CC9E2346BD9312134294F692EE285971A213B7D36 SHA-256: DB483F559D0CB9C7CCDAE01560050E0B8F8C64D2C36422BCDC8FA5DB583BBFF7 [ 37.000] DB483F559D0CB9C7CCDAE01560050E0B8F8C64D2C36422BCDC8FA5DB583BBFF7 SHA-256: DBE16FA616F8FD925855D1F76E90E05CF9FD379C85F5B132530D3B827F785460 [ 37.000] DBE16FA616F8FD925855D1F76E90E05CF9FD379C85F5B132530D3B827F785460 SHA-256: DC0DE21802BC89D3C39E82A26C3CED1487F56448ACC5255D54723891F4E44E8C [ 37.000] DC0DE21802BC89D3C39E82A26C3CED1487F56448ACC5255D54723891F4E44E8C SHA-256: DC4B3997FECBCB014212E627CDD65799A52EE7A96D8C3C3E5ADB784CC8826247 [ 37.000] DC4B3997FECBCB014212E627CDD65799A52EE7A96D8C3C3E5ADB784CC8826247 SHA-256: DC62148AC754739D5F1864B600CDBD36178712A61DA050443A8C58D6CD130F4C [ 37.000] DC62148AC754739D5F1864B600CDBD36178712A61DA050443A8C58D6CD130F4C SHA-256: DD2B293A54DE03F9DBD26504F3B5D77AC3BB917707CAA4E64D8D05D143DDB2F3 [ 37.000] DD2B293A54DE03F9DBD26504F3B5D77AC3BB917707CAA4E64D8D05D143DDB2F3 SHA-256: DD4D6B2C054230472B7B051999EEE80ABABF768CC3B9B4CB8695BD3F2A5537F8 [ 37.000] DD4D6B2C054230472B7B051999EEE80ABABF768CC3B9B4CB8695BD3F2A5537F8 SHA-256: DE029F18D92F6686ACF9228A1A4C2008585D56C6C7F3E0396414D52DCA2F4198 [ 37.000] DE029F18D92F6686ACF9228A1A4C2008585D56C6C7F3E0396414D52DCA2F4198 SHA-256: DF0B4CC2CFD2DC2E581B617DF9D63434CB7D3AF9952D8BB5F8EE4892609DA372 [ 37.000] DF0B4CC2CFD2DC2E581B617DF9D63434CB7D3AF9952D8BB5F8EE4892609DA372 SHA-256: DFF6560BCB4F4859925DBD3F2901730390643935F14BCEA9C063E3D198066DE8 [ 37.000] DFF6560BCB4F4859925DBD3F2901730390643935F14BCEA9C063E3D198066DE8 SHA-256: E34E6815F63AAFD8310235374723E00C8004363067CA22670FC90D3342AE3DCA [ 37.000] E34E6815F63AAFD8310235374723E00C8004363067CA22670FC90D3342AE3DCA SHA-256: E3A0ADE5348623E173F8E773321B7154CBF6F28EF0AF0930D650D09E63F41264 [ 37.000] E3A0ADE5348623E173F8E773321B7154CBF6F28EF0AF0930D650D09E63F41264 SHA-256: E3D797919BFAEDD334F332658AC09FEAED07FEABBB39D2F01B97FF18C70950CB [ 37.000] E3D797919BFAEDD334F332658AC09FEAED07FEABBB39D2F01B97FF18C70950CB SHA-256: E470CEACA5FA7F4463329471E95270B555CFAB56202687404CFC23E84E3C3707 [ 37.000] E470CEACA5FA7F4463329471E95270B555CFAB56202687404CFC23E84E3C3707 SHA-256: E81276941FB243AEFFC9447B4A57E3FFF8F4E218EAE62D337A8602E67ADF849E [ 37.000] E81276941FB243AEFFC9447B4A57E3FFF8F4E218EAE62D337A8602E67ADF849E SHA-256: E82738BD0D9105A81628EF0E2A6DEAA4FEC0B2F2828E45E8D8E87D736E549771 [ 37.000] E82738BD0D9105A81628EF0E2A6DEAA4FEC0B2F2828E45E8D8E87D736E549771 SHA-256: E90A9D5D5C1B195FC88FB6B222534C150F6D2DC5C4496E40F79AF80B784436C2 [ 37.000] E90A9D5D5C1B195FC88FB6B222534C150F6D2DC5C4496E40F79AF80B784436C2 SHA-256: E9F28C520987B842258F4D1F0ECD3004F991BB145FD8C011A4330A3E326FBBC9 [ 37.000] E9F28C520987B842258F4D1F0ECD3004F991BB145FD8C011A4330A3E326FBBC9 SHA-256: EB1E222D6B1B8EF70705FACB4F120CC8B1D1816A4AD058B4FE0492D91A132C30 [ 37.000] EB1E222D6B1B8EF70705FACB4F120CC8B1D1816A4AD058B4FE0492D91A132C30 SHA-256: EB4676576D04D2F10B4CE72288FA6E5DF5B1F6274604F521B9CDE01E5E0ACF15 [ 37.000] EB4676576D04D2F10B4CE72288FA6E5DF5B1F6274604F521B9CDE01E5E0ACF15 SHA-256: EBE41D6D35E597FFBE8F7C17929A9A27350F34538FAB8B5A8F75A961EF5373AF [ 37.000] EBE41D6D35E597FFBE8F7C17929A9A27350F34538FAB8B5A8F75A961EF5373AF SHA-256: ED169E0BF884A9A7DF1CD23B164CCBAAA4C3DFC0B0E962DF69836E3541915167 [ 37.000] ED169E0BF884A9A7DF1CD23B164CCBAAA4C3DFC0B0E962DF69836E3541915167 SHA-256: ED762370C31777D251DD92F4CC43D5D9468CFDF237465F68A1F18C1859A17E24 [ 37.000] ED762370C31777D251DD92F4CC43D5D9468CFDF237465F68A1F18C1859A17E24 SHA-256: F20E17924F71F116A87A28648433A61543C06F51ED06EFF4CFB1407D8FDE9EA5 [ 37.000] F20E17924F71F116A87A28648433A61543C06F51ED06EFF4CFB1407D8FDE9EA5 SHA-256: F30A039BEA38C80014B9CE80F54533FC314D279B73E689046602CD87E9BA4CED [ 37.000] F30A039BEA38C80014B9CE80F54533FC314D279B73E689046602CD87E9BA4CED SHA-256: F326C6AB37993AF0E23316711BCC5CBC5C2D47D7D3519AA5F2ADAE04DDE71945 [ 37.000] F326C6AB37993AF0E23316711BCC5CBC5C2D47D7D3519AA5F2ADAE04DDE71945 SHA-256: F33D356CCDA7C72B4FAC2BED2837E2D8D7FD116191C4D950BDA431011CCA0F76 [ 37.000] F33D356CCDA7C72B4FAC2BED2837E2D8D7FD116191C4D950BDA431011CCA0F76 SHA-256: F3825855F1485C6EB7A0DDA19FC097793B9FEADB813CD10EDD8A45B58D65BD97 [ 37.000] F3825855F1485C6EB7A0DDA19FC097793B9FEADB813CD10EDD8A45B58D65BD97 SHA-256: F39C5C8EC37EACC3E95FA51217E8A021B9975F7ED3459D6CE2DBA94BC8AC71B8 [ 37.000] F39C5C8EC37EACC3E95FA51217E8A021B9975F7ED3459D6CE2DBA94BC8AC71B8 SHA-256: F48C3742202FE05AD86E4F112279E87D7545C39A0FDCA1F5600E5C7BCEAF327A [ 37.000] F48C3742202FE05AD86E4F112279E87D7545C39A0FDCA1F5600E5C7BCEAF327A SHA-256: F589883E201672661A78D6FF21C4B3B749AF5853FC59BFFD940035069A68DD1D [ 37.000] F589883E201672661A78D6FF21C4B3B749AF5853FC59BFFD940035069A68DD1D SHA-256: F6706FA113237E866DE7B7E4D79BE98F21C46A93D2B8A98AE0316C2A10C3AE0E [ 37.000] F6706FA113237E866DE7B7E4D79BE98F21C46A93D2B8A98AE0316C2A10C3AE0E SHA-256: F88D8CCC7B844F640EA58D67BA8213BC657AD5C08C97B741CAE8B1BD1B8FF205 [ 37.000] F88D8CCC7B844F640EA58D67BA8213BC657AD5C08C97B741CAE8B1BD1B8FF205 SHA-256: FB4AF47721D4449692F3D1339BCBEC8578A7FE53BA01AD3B1335764BFFEB60A0 [ 37.000] FB4AF47721D4449692F3D1339BCBEC8578A7FE53BA01AD3B1335764BFFEB60A0 SHA-256: FB732127DB2B907DCEF4E87D8979146A43FA7AD915DD7587A8A890455F51FCC1 [ 37.000] FB732127DB2B907DCEF4E87D8979146A43FA7AD915DD7587A8A890455F51FCC1 SHA-256: FCA14D3C0B8CED91ACE33CCD96A13079E054311094D0B151BCB75622D768BADC [ 37.000] FCA14D3C0B8CED91ACE33CCD96A13079E054311094D0B151BCB75622D768BADC SHA-256: FCCE109C8360963EB18975B94BDBE434BE1A49D3F53BDD768A99093B3EB838D2 [ 37.000] FCCE109C8360963EB18975B94BDBE434BE1A49D3F53BDD768A99093B3EB838D2 */ /* Here start the program. zpaqfranz can use a backwards compatible archive format, using various "packages" Each FRANZOFFSET occupies, for each archived file, a certain space, upto ~500 bytes, but they are still compressed, so there is less waste V1 (little overhead) is the default V2 (up to zpaqfranz 56) is for extended hashes, like sha-3 V3 (from zpaqfranz 57+) is variable-sized in two "flavours": 190 bytes and 550. The shorter allows very long hashes (e.g. whirlpool), the bigger also contains a TAR-like format for storing symlinks (and other information) */ #define FRANZOFFSETV1 50 #define FRANZOFFSETV2 76 #define FRANZOFFSETV3 550 // 190 + 360 posix #define FRANZMAXPATH 240 #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) /* FRANZO_SOMETHING can be used inside zpaq archive ALGO_SOMETHING cannot (just for the sum command) */ #define FRANZO_NONE 0 #define FRANZO_CRC_32 1 #define FRANZO_XXHASH64 2 #define FRANZO_SHA_1 3 #define FRANZO_SHA_256 4 #define FRANZO_XXH3 5 #define FRANZO_BLAKE3 6 #define FRANZO_SHA3 7 #define FRANZO_MD5 8 #define FRANZO_WINHASH64 9 #define FRANZO_WHIRLPOOL 10 #define FRANZO_HIGHWAY64 11 #define FRANZO_HIGHWAY128 12 #define FRANZO_HIGHWAY256 13 #define FRANZO_XXHASH64B 14 #define FRANZO_MD5B 15 #define FRANZO_BLAKE3B 16 #define FRANZO_SHA_256B 17 #define FRANZO_SHA3B 18 #define FRANZO_XXH3B 19 #define FRANZO_SHA_1B 20 #define ALGO_CRC32C 100 #define ALGO_WYHASH 101 #define ALGO_NILSIMSA 103 #define ALGO_ENTROPY 104 #define ALGO_QUICK 105 #define ALGO_ZETA 106 #define ALGO_ZETAENC 107 #define _FILE_OFFSET_BITS 64 // In Linux make sizeof(off_t) == 8. Define BEFORE including windows.h!!! #ifndef UNICODE #define UNICODE // For Windows #endif // corresponds to #ifndef (#ifndef UNICODE) #ifndef DEBUG #define NDEBUG 1 #endif // corresponds to #ifndef (#ifndef DEBUG) #if defined(SOLARIS) || defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #ifndef unix #define unix 1 #endif // corresponds to #ifndef (#ifndef unix) #endif // corresponds to #if (#if defined(SOLARIS) || defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))) #ifdef IPV6 #include #include #include #endif // corresponds to #ifdef (#ifdef IPV6) #ifdef UNIX #define unix 1 #endif // corresponds to #ifdef (#ifdef UNIX) #ifdef unix #ifndef ANCIENT #include #include /// alpine #endif // corresponds to #ifndef (#ifndef ANCIENT) #if defined(SOLARIS) #include #endif // corresponds to #if (#if defined(SOLARIS)) #if defined(__linux__) || defined(SOLARIS) #include #endif // corresponds to #if (#if defined(__linux__) || defined(SOLARIS)) #if defined(__linux__) #include #endif // corresponds to #if (#if defined(__linux__)) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __HAIKU__ #include #endif // corresponds to #ifndef (#ifndef __HAIKU__) #ifdef __HAIKU__ #include #endif // corresponds to #ifdef (#ifdef __HAIKU__) #include #include #include #include #include #include #include #include #include #include #include #ifdef BSD #include #include #endif // corresponds to #ifdef (#ifdef BSD) #include #include #include #ifdef SFTP #include #endif #else // Assume Windows #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for setmode() using namespace std; #endif // corresponds to #ifdef (#ifdef unix) /// LICENSE_START.24 #ifdef SFTP #ifndef CURLINC_CURL_H #define CURLINC_CURL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* * If you have libcurl problems, all docs and details are found here: * https://curl.se/libcurl/ */ #ifdef CURL_NO_OLDIES #define CURL_STRICTER /* not used since 8.11.0 */ #endif /* Compile-time deprecation macros. */ #if (defined(__GNUC__) && \ ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1))) || \ (defined(__clang__) && __clang_major__ >= 3) || \ defined(__IAR_SYSTEMS_ICC__)) && \ !defined(__INTEL_COMPILER) && \ !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL) #define CURL_DEPRECATED(version, message) \ __attribute__((deprecated("since " # version ". " message))) #if defined(__IAR_SYSTEMS_ICC__) #define CURL_IGNORE_DEPRECATION(statements) \ _Pragma("diag_suppress=Pe1444") \ statements \ _Pragma("diag_default=Pe1444") #else #define CURL_IGNORE_DEPRECATION(statements) \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ statements \ _Pragma("GCC diagnostic pop") #endif #else #define CURL_DEPRECATED(version, message) #define CURL_IGNORE_DEPRECATION(statements) statements #endif #ifndef CURLINC_CURLVER_H #define CURLINC_CURLVER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* This header file contains nothing but libcurl version info, generated by a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ #define LIBCURL_COPYRIGHT "Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ #define LIBCURL_VERSION "8.11.1" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 #define LIBCURL_VERSION_MINOR 11 #define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: 0xXXYYZZ Where XX, YY and ZZ are the main version, release and patch numbers in hexadecimal (using 8 bits each). All three numbers are always represented using two digits. 1.2 would appear as "0x010200" while version 9.11.7 appears as "0x090b07". This 6-digit (24 bits) hexadecimal number does not show pre-release number, and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. Note: This define is the full hex number and _does not_ use the CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ #define LIBCURL_VERSION_NUM 0x080b01 /* * This is the date and time when the full source package was created. The * timestamp is not stored in git, as the timestamp is properly set in the * tarballs by the maketgz script. * * The format of the date follows this template: * * "2007-11-23" */ #define LIBCURL_TIMESTAMP "2024-12-11" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z)) #endif /* CURLINC_CURLVER_H */ #ifndef CURLINC_SYSTEM_H #define CURLINC_SYSTEM_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* * Try to keep one section per platform, compiler and architecture, otherwise, * if an existing section is reused for a different one and later on the * original is adjusted, probably the piggybacking one can be adversely * changed. * * In order to differentiate between platforms/compilers/architectures use * only compiler built-in predefined preprocessor symbols. * * curl_off_t * ---------- * * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit * wide signed integral data type. The width of this data type must remain * constant and independent of any possible large file support settings. * * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit * wide signed integral data type if there is no 64-bit type. * * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall * only be violated if off_t is the only 64-bit data type available and the * size of off_t is independent of large file support settings. Keep your * build on the safe side avoiding an off_t gating. If you have a 64-bit * off_t then take for sure that another 64-bit data type exists, dig deeper * and you will find it. * */ #if defined(__DJGPP__) || defined(__GO32__) # if defined(__DJGPP__) && (__DJGPP__ > 1) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__SALFORDC__) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__BORLANDC__) # if (__BORLANDC__ < 0x520) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TURBOC__) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__POCC__) # if (__POCC__ < 280) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # elif defined(_MSC_VER) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # else # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__LCC__) # if defined(__MCST__) /* MCST eLbrus Compiler Collection */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # else /* Local (or Little) C Compiler */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int # endif #elif defined(macintosh) # include # if TYPE_LONGLONG # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__TANDEM) # if ! defined(__LP64) /* Required for 32-bit NonStop builds only. */ # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T int # endif #elif defined(_WIN32_WCE) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__MINGW32__) # include # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T PRId64 # define CURL_FORMAT_CURL_OFF_TU PRIu64 # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T int # define CURL_PULL_SYS_TYPES_H 1 #elif defined(__VMS) # if defined(__VAX) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__OS400__) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__MVS__) # if defined(_LONG_LONG) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__370__) # if defined(__IBMC__) || defined(__IBMCPP__) # if defined(_ILP32) # elif defined(_LP64) # endif # if defined(_LONG_LONG) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 # endif #elif defined(TPF) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__TINYC__) /* also known as tcc */ # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* Oracle Solaris Studio */ # if !defined(__LP64) && (defined(__ILP32) || \ defined(__i386) || \ defined(__sparcv8) || \ defined(__sparcv8plus)) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__LP64) || \ defined(__amd64) || defined(__sparcv9) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__xlc__) /* IBM xlc compiler */ # if !defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__hpux) /* HP aCC compiler */ # if !defined(_LP64) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 /* ===================================== */ /* KEEP MSVC THE PENULTIMATE ENTRY */ /* ===================================== */ #elif defined(_MSC_VER) # if (_MSC_VER >= 1800) # include # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T PRId64 # define CURL_FORMAT_CURL_OFF_TU PRIu64 # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # elif (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64) # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" # define CURL_SUFFIX_CURL_OFF_T i64 # define CURL_SUFFIX_CURL_OFF_TU ui64 # else # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T int /* ===================================== */ /* KEEP GENERIC GCC THE LAST ENTRY */ /* ===================================== */ #elif defined(__GNUC__) && !defined(_SCO_DS) # if !defined(__LP64__) && \ (defined(__ILP32__) || defined(__i386__) || defined(__hppa__) || \ defined(__ppc__) || defined(__powerpc__) || defined(__arm__) || \ defined(__sparc__) || defined(__mips__) || defined(__sh__) || \ defined(__XTENSA__) || \ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 4) || \ (defined(__LONG_MAX__) && __LONG_MAX__ == 2147483647L)) # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL # elif defined(__LP64__) || \ defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ defined(__e2k__) || \ (defined(__SIZEOF_LONG__) && __SIZEOF_LONG__ == 8) || \ (defined(__LONG_MAX__) && __LONG_MAX__ == 9223372036854775807L) # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 # define CURL_PULL_SYS_SOCKET_H 1 #else /* generic "safe guess" on old 32-bit style */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL # define CURL_TYPEOF_CURL_SOCKLEN_T int #endif #ifdef _AIX /* AIX needs */ #define CURL_PULL_SYS_POLL_H #endif /* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */ /* sys/types.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_TYPES_H # include #endif /* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */ /* sys/socket.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_SOCKET_H # include #endif /* CURL_PULL_SYS_POLL_H is defined above when inclusion of header file */ /* sys/poll.h is required here to properly make type definitions below. */ #ifdef CURL_PULL_SYS_POLL_H # include #endif /* Data type definition of curl_socklen_t. */ #ifdef CURL_TYPEOF_CURL_SOCKLEN_T typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t; #endif /* Data type definition of curl_off_t. */ #ifdef CURL_TYPEOF_CURL_OFF_T typedef CURL_TYPEOF_CURL_OFF_T curl_off_t; #endif /* * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow * these to be visible and exported by the external libcurl interface API, * while also making them visible to the library internals, simply including * curl_setup.h, without actually needing to include curl.h internally. * If some day this section would grow big enough, all this should be moved * to its own header file. */ /* * Figure out if we can use the ## preprocessor operator, which is supported * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__ * or __cplusplus so we need to carefully check for them too. */ #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \ defined(__ILEC400__) /* This compiler is believed to have an ISO compatible preprocessor */ #define CURL_ISOCPP #else /* This compiler is believed NOT to have an ISO compatible preprocessor */ #undef CURL_ISOCPP #endif /* * Macros for minimum-width signed and unsigned curl_off_t integer constants. */ #if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551) # define CURLINC_OFF_T_C_HLPR2(x) x # define CURLINC_OFF_T_C_HLPR1(x) CURLINC_OFF_T_C_HLPR2(x) # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T) # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val) ## \ CURLINC_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU) #else # ifdef CURL_ISOCPP # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix # else # define CURLINC_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix # endif # define CURLINC_OFF_T_C_HLPR1(Val,Suffix) CURLINC_OFF_T_C_HLPR2(Val,Suffix) # define CURL_OFF_T_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T) # define CURL_OFF_TU_C(Val) CURLINC_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU) #endif #endif /* CURLINC_SYSTEM_H */ #include #include #if defined(__FreeBSD__) || defined(__MidnightBSD__) /* Needed for __FreeBSD_version or __MidnightBSD_version symbol definition */ #include #endif /* The include stuff here below is mainly for time_t! */ #include #include #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2.h inclusion if winsock.h already was included, since they cannot co-exist without problems */ #include #include #endif #endif /* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish libc5-based Linux systems. Only include it on systems that are known to require it! */ #if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \ defined(__minix) || defined(__INTEGRITY) || \ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \ defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \ (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \ defined(__sun__) || defined(__serenity__) || defined(__vxworks__) #include #endif #if !defined(_WIN32) && !defined(_WIN32_WCE) #include #endif #if !defined(_WIN32) #include #endif /* Compatibility for non-Clang compilers */ #ifndef __has_declspec_attribute # define __has_declspec_attribute(x) 0 #endif #ifdef __cplusplus extern "C" { #endif typedef void CURL; typedef void CURLSH; /* * libcurl external API function linkage decorations. */ #ifdef CURL_STATICLIB # define CURL_EXTERN #elif defined(_WIN32) || \ (__has_declspec_attribute(dllexport) && \ __has_declspec_attribute(dllimport)) # if defined(BUILDING_LIBCURL) # define CURL_EXTERN __declspec(dllexport) # else # define CURL_EXTERN __declspec(dllimport) # endif #elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS) # define CURL_EXTERN CURL_EXTERN_SYMBOL #else # define CURL_EXTERN #endif #ifndef curl_socket_typedef /* socket typedef */ #if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else typedef int curl_socket_t; #define CURL_SOCKET_BAD -1 #endif #define curl_socket_typedef #endif /* curl_socket_typedef */ /* enum for the different supported SSL backends */ typedef enum { CURLSSLBACKEND_NONE = 0, CURLSSLBACKEND_OPENSSL = 1, CURLSSLBACKEND_GNUTLS = 2, CURLSSLBACKEND_NSS CURL_DEPRECATED(8.3.0, "") = 3, CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */ CURLSSLBACKEND_GSKIT CURL_DEPRECATED(8.3.0, "") = 5, CURLSSLBACKEND_POLARSSL CURL_DEPRECATED(7.69.0, "") = 6, CURLSSLBACKEND_WOLFSSL = 7, CURLSSLBACKEND_SCHANNEL = 8, CURLSSLBACKEND_SECURETRANSPORT = 9, CURLSSLBACKEND_AXTLS CURL_DEPRECATED(7.61.0, "") = 10, CURLSSLBACKEND_MBEDTLS = 11, CURLSSLBACKEND_MESALINK CURL_DEPRECATED(7.82.0, "") = 12, CURLSSLBACKEND_BEARSSL = 13, CURLSSLBACKEND_RUSTLS = 14 } curl_sslbackend; /* aliases for library clones and renames */ #define CURLSSLBACKEND_AWSLC CURLSSLBACKEND_OPENSSL #define CURLSSLBACKEND_BORINGSSL CURLSSLBACKEND_OPENSSL #define CURLSSLBACKEND_LIBRESSL CURLSSLBACKEND_OPENSSL /* deprecated names: */ #define CURLSSLBACKEND_CYASSL CURLSSLBACKEND_WOLFSSL #define CURLSSLBACKEND_DARWINSSL CURLSSLBACKEND_SECURETRANSPORT struct curl_httppost { struct curl_httppost *next; /* next entry in the list */ char *name; /* pointer to allocated name */ long namelength; /* length of name length */ char *contents; /* pointer to allocated data contents */ long contentslength; /* length of contents field, see also CURL_HTTPPOST_LARGE */ char *buffer; /* pointer to allocated buffer contents */ long bufferlength; /* length of buffer field */ char *contenttype; /* Content-Type */ struct curl_slist *contentheader; /* list of extra headers for this form */ struct curl_httppost *more; /* if one field name has more than one file, this link should link to following files */ long flags; /* as defined below */ /* specified content is a filename */ #define CURL_HTTPPOST_FILENAME (1<<0) /* specified content is a filename */ #define CURL_HTTPPOST_READFILE (1<<1) /* name is only stored pointer do not free in formfree */ #define CURL_HTTPPOST_PTRNAME (1<<2) /* contents is only stored pointer do not free in formfree */ #define CURL_HTTPPOST_PTRCONTENTS (1<<3) /* upload file from buffer */ #define CURL_HTTPPOST_BUFFER (1<<4) /* upload file from pointer contents */ #define CURL_HTTPPOST_PTRBUFFER (1<<5) /* upload file contents by using the regular read callback to get the data and pass the given pointer as custom pointer */ #define CURL_HTTPPOST_CALLBACK (1<<6) /* use size in 'contentlen', added in 7.46.0 */ #define CURL_HTTPPOST_LARGE (1<<7) char *showfilename; /* The filename to show. If not set, the actual filename will be used (if this is a file part) */ void *userp; /* custom pointer used for HTTPPOST_CALLBACK posts */ curl_off_t contentlen; /* alternative length of contents field. Used if CURL_HTTPPOST_LARGE is set. Added in 7.46.0 */ }; /* This is a return code for the progress callback that, when returned, will signal libcurl to continue executing the default progress function */ #define CURL_PROGRESSFUNC_CONTINUE 0x10000001 /* This is the CURLOPT_PROGRESSFUNCTION callback prototype. It is now considered deprecated but was the only choice up until 7.31.0 */ typedef int (*curl_progress_callback)(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow); /* This is the CURLOPT_XFERINFOFUNCTION callback prototype. It was introduced in 7.32.0, avoids the use of floating point numbers and provides more detailed information. */ typedef int (*curl_xferinfo_callback)(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow); #ifndef CURL_MAX_READ_SIZE /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ #define CURL_MAX_READ_SIZE (10*1024*1024) #endif #ifndef CURL_MAX_WRITE_SIZE /* Tests have proven that 20K is a bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. We do the ifndef check to allow this value to easier be changed at build time for those who feel adventurous. The practical minimum is about 400 bytes since libcurl uses a buffer of this size as a scratch area (unrelated to network send operations). */ #define CURL_MAX_WRITE_SIZE 16384 #endif #ifndef CURL_MAX_HTTP_HEADER /* The only reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a never-ending header that will cause reallocs infinitely */ #define CURL_MAX_HTTP_HEADER (100*1024) #endif /* This is a magic return code for the write callback that, when returned, will signal libcurl to pause receiving on the current transfer. */ #define CURL_WRITEFUNC_PAUSE 0x10000001 /* This is a magic return code for the write callback that, when returned, will signal an error from the callback. */ #define CURL_WRITEFUNC_ERROR 0xFFFFFFFF typedef size_t (*curl_write_callback)(char *buffer, size_t size, size_t nitems, void *outstream); /* This callback will be called when a new resolver request is made */ typedef int (*curl_resolver_start_callback)(void *resolver_state, void *reserved, void *userdata); /* enumeration of file types */ typedef enum { CURLFILETYPE_FILE = 0, CURLFILETYPE_DIRECTORY, CURLFILETYPE_SYMLINK, CURLFILETYPE_DEVICE_BLOCK, CURLFILETYPE_DEVICE_CHAR, CURLFILETYPE_NAMEDPIPE, CURLFILETYPE_SOCKET, CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */ CURLFILETYPE_UNKNOWN /* should never occur */ } curlfiletype; #define CURLFINFOFLAG_KNOWN_FILENAME (1<<0) #define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1) #define CURLFINFOFLAG_KNOWN_TIME (1<<2) #define CURLFINFOFLAG_KNOWN_PERM (1<<3) #define CURLFINFOFLAG_KNOWN_UID (1<<4) #define CURLFINFOFLAG_KNOWN_GID (1<<5) #define CURLFINFOFLAG_KNOWN_SIZE (1<<6) #define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7) /* Information about a single file, used when doing FTP wildcard matching */ struct curl_fileinfo { char *filename; curlfiletype filetype; time_t time; /* always zero! */ unsigned int perm; int uid; int gid; curl_off_t size; long int hardlinks; struct { /* If some of these fields is not NULL, it is a pointer to b_data. */ char *time; char *perm; char *user; char *group; char *target; /* pointer to the target filename of a symlink */ } strings; unsigned int flags; /* These are libcurl private struct fields. Previously used by libcurl, so they must never be interfered with. */ char *b_data; size_t b_size; size_t b_used; }; /* return codes for CURLOPT_CHUNK_BGN_FUNCTION */ #define CURL_CHUNK_BGN_FUNC_OK 0 #define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */ #define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */ /* if splitting of data transfer is enabled, this callback is called before download of an individual chunk started. Note that parameter "remains" works only for FTP wildcard downloading (for now), otherwise is not used */ typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, void *ptr, int remains); /* return codes for CURLOPT_CHUNK_END_FUNCTION */ #define CURL_CHUNK_END_FUNC_OK 0 #define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */ /* If splitting of data transfer is enabled this callback is called after download of an individual chunk finished. Note! After this callback was set then it have to be called FOR ALL chunks. Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC. This is the reason why we do not need "transfer_info" parameter in this callback and we are not interested in "remains" parameter too. */ typedef long (*curl_chunk_end_callback)(void *ptr); /* return codes for FNMATCHFUNCTION */ #define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */ #define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern does not match the string */ #define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */ /* callback type for wildcard downloading pattern matching. If the string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */ typedef int (*curl_fnmatch_callback)(void *ptr, const char *pattern, const char *string); /* These are the return codes for the seek callbacks */ #define CURL_SEEKFUNC_OK 0 #define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */ #define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking cannot be done, so libcurl might try other means instead */ typedef int (*curl_seek_callback)(void *instream, curl_off_t offset, int origin); /* 'whence' */ /* This is a return code for the read callback that, when returned, will signal libcurl to immediately abort the current transfer. */ #define CURL_READFUNC_ABORT 0x10000000 /* This is a return code for the read callback that, when returned, will signal libcurl to pause sending data on the current transfer. */ #define CURL_READFUNC_PAUSE 0x10000001 /* Return code for when the trailing headers' callback has terminated without any errors */ #define CURL_TRAILERFUNC_OK 0 /* Return code for when was an error in the trailing header's list and we want to abort the request */ #define CURL_TRAILERFUNC_ABORT 1 typedef size_t (*curl_read_callback)(char *buffer, size_t size, size_t nitems, void *instream); typedef int (*curl_trailer_callback)(struct curl_slist **list, void *userdata); typedef enum { CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */ CURLSOCKTYPE_LAST /* never use */ } curlsocktype; /* The return code from the sockopt_callback can signal information back to libcurl: */ #define CURL_SOCKOPT_OK 0 #define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return CURLE_ABORTED_BY_CALLBACK */ #define CURL_SOCKOPT_ALREADY_CONNECTED 2 typedef int (*curl_sockopt_callback)(void *clientp, curl_socket_t curlfd, curlsocktype purpose); struct curl_sockaddr { int family; int socktype; int protocol; unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it turned really ugly and painful on the systems that lack this type */ struct sockaddr addr; }; typedef curl_socket_t (*curl_opensocket_callback)(void *clientp, curlsocktype purpose, struct curl_sockaddr *address); typedef int (*curl_closesocket_callback)(void *clientp, curl_socket_t item); typedef enum { CURLIOE_OK, /* I/O operation successful */ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */ CURLIOE_FAILRESTART, /* failed to restart the read */ CURLIOE_LAST /* never use */ } curlioerr; typedef enum { CURLIOCMD_NOP, /* no operation */ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */ CURLIOCMD_LAST /* never use */ } curliocmd; typedef curlioerr (*curl_ioctl_callback)(CURL *handle, int cmd, void *clientp); #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* * The following typedef's are signatures of malloc, free, realloc, strdup and * calloc respectively. Function pointers of these types can be passed to the * curl_global_init_mem() function to set user defined memory management * callback routines. */ typedef void *(*curl_malloc_callback)(size_t size); typedef void (*curl_free_callback)(void *ptr); typedef void *(*curl_realloc_callback)(void *ptr, size_t size); typedef char *(*curl_strdup_callback)(const char *str); typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); #define CURL_DID_MEMORY_FUNC_TYPEDEFS #endif /* the kind of data that is passed to information_callback */ typedef enum { CURLINFO_TEXT = 0, CURLINFO_HEADER_IN, /* 1 */ CURLINFO_HEADER_OUT, /* 2 */ CURLINFO_DATA_IN, /* 3 */ CURLINFO_DATA_OUT, /* 4 */ CURLINFO_SSL_DATA_IN, /* 5 */ CURLINFO_SSL_DATA_OUT, /* 6 */ CURLINFO_END } curl_infotype; typedef int (*curl_debug_callback) (CURL *handle, /* the handle/transfer this concerns */ curl_infotype type, /* what kind of data */ char *data, /* points to the data */ size_t size, /* size of the data pointed to */ void *userptr); /* whatever the user please */ /* This is the CURLOPT_PREREQFUNCTION callback prototype. */ typedef int (*curl_prereq_callback)(void *clientp, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port); /* Return code for when the pre-request callback has terminated without any errors */ #define CURL_PREREQFUNC_OK 0 /* Return code for when the pre-request callback wants to abort the request */ #define CURL_PREREQFUNC_ABORT 1 /* All possible error codes from all sorts of curl functions. Future versions may return other values, stay prepared. Always add new return codes last. Never *EVER* remove any. The return codes must remain the same! */ typedef enum { CURLE_OK = 0, CURLE_UNSUPPORTED_PROTOCOL, /* 1 */ CURLE_FAILED_INIT, /* 2 */ CURLE_URL_MALFORMAT, /* 3 */ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for 7.17.0, reused in April 2011 for 7.21.5] */ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ CURLE_WEIRD_SERVER_REPLY, /* 8 */ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for 7.15.4, reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server [was obsoleted in August 2007 for 7.17.0, reused in Dec 2011 for 7.24.0]*/ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */ CURLE_FTP_CANT_GET_HOST, /* 15 */ CURLE_HTTP2, /* 16 - A problem in the http2 framing layer. [was obsoleted in August 2007 for 7.17.0, reused in July 2014 for 7.38.0] */ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */ CURLE_PARTIAL_FILE, /* 18 */ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */ CURLE_OBSOLETE20, /* 20 - NOT USED */ CURLE_QUOTE_ERROR, /* 21 - quote command failure */ CURLE_HTTP_RETURNED_ERROR, /* 22 */ CURLE_WRITE_ERROR, /* 23 */ CURLE_OBSOLETE24, /* 24 - NOT USED */ CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */ CURLE_READ_ERROR, /* 26 - could not open/read from file */ CURLE_OUT_OF_MEMORY, /* 27 */ CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */ CURLE_OBSOLETE29, /* 29 - NOT USED */ CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */ CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */ CURLE_OBSOLETE32, /* 32 - NOT USED */ CURLE_RANGE_ERROR, /* 33 - RANGE "command" did not work */ CURLE_OBSOLETE34, /* 34 */ CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - could not resume download */ CURLE_FILE_COULDNT_READ_FILE, /* 37 */ CURLE_LDAP_CANNOT_BIND, /* 38 */ CURLE_LDAP_SEARCH_FAILED, /* 39 */ CURLE_OBSOLETE40, /* 40 - NOT USED */ CURLE_OBSOLETE41, /* 41 - NOT USED starting with 7.53.0 */ CURLE_ABORTED_BY_CALLBACK, /* 42 */ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ CURLE_OBSOLETE44, /* 44 - NOT USED */ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */ CURLE_OBSOLETE46, /* 46 - NOT USED */ CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */ CURLE_SETOPT_OPTION_SYNTAX, /* 49 - Malformed setopt option */ CURLE_OBSOLETE50, /* 50 - NOT USED */ CURLE_OBSOLETE51, /* 51 - NOT USED */ CURLE_GOT_NOTHING, /* 52 - when this is a specific error */ CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */ CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as default */ CURLE_SEND_ERROR, /* 55 - failed sending network data */ CURLE_RECV_ERROR, /* 56 - failure in receiving network data */ CURLE_OBSOLETE57, /* 57 - NOT IN USE */ CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */ CURLE_SSL_CIPHER, /* 59 - could not use specified cipher */ CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint was not verified fine */ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */ CURLE_OBSOLETE62, /* 62 - NOT IN USE since 7.82.0 */ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */ CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind that failed */ CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */ CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not accepted and we failed to login */ CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */ CURLE_TFTP_PERM, /* 69 - permission problem on server */ CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */ CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */ CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */ CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */ CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */ CURLE_OBSOLETE75, /* 75 - NOT IN USE since 7.82.0 */ CURLE_OBSOLETE76, /* 76 - NOT IN USE since 7.82.0 */ CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing or wrong format */ CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */ CURLE_SSH, /* 79 - error from the SSH layer, somewhat generic so the error message will be of interest when this has happened */ CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL connection */ CURLE_AGAIN, /* 81 - socket is not ready for send/recv, wait till it is ready and try again (Added in 7.18.2) */ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or wrong format (Added in 7.19.0) */ CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in 7.19.0) */ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the session will be queued */ CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not match */ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */ CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer */ CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from inside a callback */ CURLE_AUTH_ERROR, /* 94 - an authentication function returned an error */ CURLE_HTTP3, /* 95 - An HTTP/3 layer problem */ CURLE_QUIC_CONNECT_ERROR, /* 96 - QUIC connection error */ CURLE_PROXY, /* 97 - proxy handshake error */ CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */ CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */ CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */ CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */ CURL_LAST /* never use! */ } CURLcode; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* removed in 7.53.0 */ #define CURLE_FUNCTION_NOT_FOUND CURLE_OBSOLETE41 /* removed in 7.56.0 */ #define CURLE_HTTP_POST_ERROR CURLE_OBSOLETE34 /* Previously obsolete error code reused in 7.38.0 */ #define CURLE_OBSOLETE16 CURLE_HTTP2 /* Previously obsolete error codes reused in 7.24.0 */ #define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED #define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT /* compatibility with older names */ #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING #define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY /* The following were added in 7.62.0 */ #define CURLE_SSL_CACERT CURLE_PEER_FAILED_VERIFICATION /* The following were added in 7.21.5, April 2011 */ #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION /* Added for 7.78.0 */ #define CURLE_TELNET_OPTION_SYNTAX CURLE_SETOPT_OPTION_SYNTAX /* The following were added in 7.17.1 */ /* These are scheduled to disappear by 2009 */ #define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION /* The following were added in 7.17.0 */ /* These are scheduled to disappear by 2009 */ #define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */ #define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46 #define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44 #define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10 #define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16 #define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32 #define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29 #define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12 #define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20 #define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40 #define CURLE_MALFORMAT_USER CURLE_OBSOLETE24 #define CURLE_SHARE_IN_USE CURLE_OBSOLETE57 #define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN #define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED #define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE #define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR #define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL #define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS #define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR #define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED /* The following were added earlier */ #define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT #define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR #define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED #define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME #define CURLE_LDAP_INVALID_URL CURLE_OBSOLETE62 #define CURLE_CONV_REQD CURLE_OBSOLETE76 #define CURLE_CONV_FAILED CURLE_OBSOLETE75 /* This was the error code 50 in 7.7.3 and a few earlier versions, this is no longer used by libcurl but is instead #defined here only to not make programs break */ #define CURLE_ALREADY_COMPLETE 99999 /* Provide defines for really old option names */ #define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */ #define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */ #define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA /* Since long deprecated options with no code in the lib that does anything with them. */ #define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40 #define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72 #define CURLOPT_OBSOLETE72 9999 #define CURLOPT_OBSOLETE40 9999 #endif /* !CURL_NO_OLDIES */ /* * Proxy error codes. Returned in CURLINFO_PROXY_ERROR if CURLE_PROXY was * return for the transfers. */ typedef enum { CURLPX_OK, CURLPX_BAD_ADDRESS_TYPE, CURLPX_BAD_VERSION, CURLPX_CLOSED, CURLPX_GSSAPI, CURLPX_GSSAPI_PERMSG, CURLPX_GSSAPI_PROTECTION, CURLPX_IDENTD, CURLPX_IDENTD_DIFFER, CURLPX_LONG_HOSTNAME, CURLPX_LONG_PASSWD, CURLPX_LONG_USER, CURLPX_NO_AUTH, CURLPX_RECV_ADDRESS, CURLPX_RECV_AUTH, CURLPX_RECV_CONNECT, CURLPX_RECV_REQACK, CURLPX_REPLY_ADDRESS_TYPE_NOT_SUPPORTED, CURLPX_REPLY_COMMAND_NOT_SUPPORTED, CURLPX_REPLY_CONNECTION_REFUSED, CURLPX_REPLY_GENERAL_SERVER_FAILURE, CURLPX_REPLY_HOST_UNREACHABLE, CURLPX_REPLY_NETWORK_UNREACHABLE, CURLPX_REPLY_NOT_ALLOWED, CURLPX_REPLY_TTL_EXPIRED, CURLPX_REPLY_UNASSIGNED, CURLPX_REQUEST_FAILED, CURLPX_RESOLVE_HOST, CURLPX_SEND_AUTH, CURLPX_SEND_CONNECT, CURLPX_SEND_REQUEST, CURLPX_UNKNOWN_FAIL, CURLPX_UNKNOWN_MODE, CURLPX_USER_REJECTED, CURLPX_LAST /* never use */ } CURLproxycode; /* This prototype applies to all conversion callbacks */ typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ void *ssl_ctx, /* actually an OpenSSL or wolfSSL SSL_CTX, or an mbedTLS mbedtls_ssl_config */ void *userptr); typedef enum { CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use CONNECT HTTP/1.1 */ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ CURLPROXY_HTTPS = 2, /* HTTPS but stick to HTTP/1 added in 7.52.0 */ CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the hostname rather than the IP address. added in 7.18.0 */ } curl_proxytype; /* this enum was added in 7.10 */ /* * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options: * * CURLAUTH_NONE - No HTTP authentication * CURLAUTH_BASIC - HTTP Basic authentication (default) * CURLAUTH_DIGEST - HTTP Digest authentication * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated) * CURLAUTH_NTLM - HTTP NTLM authentication * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper * CURLAUTH_BEARER - HTTP Bearer token authentication * CURLAUTH_ONLY - Use together with a single other type to force no * authentication or just that single type * CURLAUTH_ANY - All fine types set * CURLAUTH_ANYSAFE - All fine types except Basic */ #define CURLAUTH_NONE ((unsigned long)0) #define CURLAUTH_BASIC (((unsigned long)1)<<0) #define CURLAUTH_DIGEST (((unsigned long)1)<<1) #define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2) /* Deprecated since the advent of CURLAUTH_NEGOTIATE */ #define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE /* Used for CURLOPT_SOCKS5_AUTH to stay terminologically correct */ #define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE #define CURLAUTH_NTLM (((unsigned long)1)<<3) #define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4) #ifndef CURL_NO_OLDIES /* functionality removed since 8.8.0 */ #define CURLAUTH_NTLM_WB (((unsigned long)1)<<5) #endif #define CURLAUTH_BEARER (((unsigned long)1)<<6) #define CURLAUTH_AWS_SIGV4 (((unsigned long)1)<<7) #define CURLAUTH_ONLY (((unsigned long)1)<<31) #define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) #define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) #define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ #define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ #define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ #define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ #define CURLSSH_AUTH_HOST (1<<2) /* host key files */ #define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ #define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ #define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY #define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ #define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ #define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ #define CURL_ERROR_SIZE 256 enum curl_khtype { CURLKHTYPE_UNKNOWN, CURLKHTYPE_RSA1, CURLKHTYPE_RSA, CURLKHTYPE_DSS, CURLKHTYPE_ECDSA, CURLKHTYPE_ED25519 }; struct curl_khkey { const char *key; /* points to a null-terminated string encoded with base64 if len is zero, otherwise to the "raw" data */ size_t len; enum curl_khtype keytype; }; /* this is the set of return values expected from the curl_sshkeycallback callback */ enum curl_khstat { CURLKHSTAT_FINE_ADD_TO_FILE, CURLKHSTAT_FINE, CURLKHSTAT_REJECT, /* reject the connection, return an error */ CURLKHSTAT_DEFER, /* do not accept it, but we cannot answer right now. Causes a CURLE_PEER_FAILED_VERIFICATION error but the connection will be left intact etc */ CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */ }; /* this is the set of status codes pass in to the callback */ enum curl_khmatch { CURLKHMATCH_OK, /* match */ CURLKHMATCH_MISMATCH, /* host found, key mismatch! */ CURLKHMATCH_MISSING, /* no matching host/key found */ CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */ }; typedef int (*curl_sshkeycallback) (CURL *easy, /* easy handle */ const struct curl_khkey *knownkey, /* known */ const struct curl_khkey *foundkey, /* found */ enum curl_khmatch, /* libcurl's view on the keys */ void *clientp); /* custom pointer passed with */ /* CURLOPT_SSH_KEYDATA */ typedef int (*curl_sshhostkeycallback) (void *clientp,/* custom pointer passed */ /* with CURLOPT_SSH_HOSTKEYDATA */ int keytype, /* CURLKHTYPE */ const char *key, /* hostkey to check */ size_t keylen); /* length of the key */ /* return CURLE_OK to accept */ /* or something else to refuse */ /* parameter for the CURLOPT_USE_SSL option */ typedef enum { CURLUSESSL_NONE, /* do not attempt to use SSL */ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */ CURLUSESSL_ALL, /* SSL for all communication or fail */ CURLUSESSL_LAST /* not an option, never use */ } curl_usessl; /* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */ /* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the name of improving interoperability with older servers. Some SSL libraries have introduced work-arounds for this flaw but those work-arounds sometimes make the SSL communication fail. To regain functionality with those broken servers, a user can this way allow the vulnerability back. */ #define CURLSSLOPT_ALLOW_BEAST (1<<0) /* - NO_REVOKE tells libcurl to disable certificate revocation checks for those SSL backends where such behavior is present. */ #define CURLSSLOPT_NO_REVOKE (1<<1) /* - NO_PARTIALCHAIN tells libcurl to *NOT* accept a partial certificate chain if possible. The OpenSSL backend has this ability. */ #define CURLSSLOPT_NO_PARTIALCHAIN (1<<2) /* - REVOKE_BEST_EFFORT tells libcurl to ignore certificate revocation offline checks and ignore missing revocation list for those SSL backends where such behavior is present. */ #define CURLSSLOPT_REVOKE_BEST_EFFORT (1<<3) /* - CURLSSLOPT_NATIVE_CA tells libcurl to use standard certificate store of operating system. Currently implemented under MS-Windows. */ #define CURLSSLOPT_NATIVE_CA (1<<4) /* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use a client certificate for authentication. (Schannel) */ #define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5) /* If possible, send data using TLS 1.3 early data */ #define CURLSSLOPT_EARLYDATA (1<<6) /* The default connection attempt delay in milliseconds for happy eyeballs. CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document this value, keep them in sync. */ #define CURL_HET_DEFAULT 200L /* The default connection upkeep interval in milliseconds. */ #define CURL_UPKEEP_INTERVAL_DEFAULT 60000L #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* Backwards compatibility with older names */ /* These are scheduled to disappear by 2009 */ #define CURLFTPSSL_NONE CURLUSESSL_NONE #define CURLFTPSSL_TRY CURLUSESSL_TRY #define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL #define CURLFTPSSL_ALL CURLUSESSL_ALL #define CURLFTPSSL_LAST CURLUSESSL_LAST #define curl_ftpssl curl_usessl #endif /* !CURL_NO_OLDIES */ /* parameter for the CURLOPT_FTP_SSL_CCC option */ typedef enum { CURLFTPSSL_CCC_NONE, /* do not send CCC */ CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ CURLFTPSSL_CCC_LAST /* not an option, never use */ } curl_ftpccc; /* parameter for the CURLOPT_FTPSSLAUTH option */ typedef enum { CURLFTPAUTH_DEFAULT, /* let libcurl decide */ CURLFTPAUTH_SSL, /* use "AUTH SSL" */ CURLFTPAUTH_TLS, /* use "AUTH TLS" */ CURLFTPAUTH_LAST /* not an option, never use */ } curl_ftpauth; /* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ typedef enum { CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD again if MKD succeeded, for SFTP this does similar magic */ CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD again even if MKD failed! */ CURLFTP_CREATE_DIR_LAST /* not an option, never use */ } curl_ftpcreatedir; /* parameter for the CURLOPT_FTP_FILEMETHOD option */ typedef enum { CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ CURLFTPMETHOD_NOCWD, /* no CWD at all */ CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ CURLFTPMETHOD_LAST /* not an option, never use */ } curl_ftpmethod; /* bitmask defines for CURLOPT_HEADEROPT */ #define CURLHEADER_UNIFIED 0 #define CURLHEADER_SEPARATE (1<<0) /* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ #define CURLALTSVC_READONLYFILE (1<<2) #define CURLALTSVC_H1 (1<<3) #define CURLALTSVC_H2 (1<<4) #define CURLALTSVC_H3 (1<<5) struct curl_hstsentry { char *name; size_t namelen; unsigned int includeSubDomains:1; char expire[18]; /* YYYYMMDD HH:MM:SS [null-terminated] */ }; struct curl_index { size_t index; /* the provided entry's "index" or count */ size_t total; /* total number of entries to save */ }; typedef enum { CURLSTS_OK, CURLSTS_DONE, CURLSTS_FAIL } CURLSTScode; typedef CURLSTScode (*curl_hstsread_callback)(CURL *easy, struct curl_hstsentry *e, void *userp); typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy, struct curl_hstsentry *e, struct curl_index *i, void *userp); /* CURLHSTS_* are bits for the CURLOPT_HSTS option */ #define CURLHSTS_ENABLE (long)(1<<0) #define CURLHSTS_READONLYFILE (long)(1<<1) /* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS options. Do not use. */ #define CURLPROTO_HTTP (1<<0) #define CURLPROTO_HTTPS (1<<1) #define CURLPROTO_FTP (1<<2) #define CURLPROTO_FTPS (1<<3) #define CURLPROTO_SCP (1<<4) #define CURLPROTO_SFTP (1<<5) #define CURLPROTO_TELNET (1<<6) #define CURLPROTO_LDAP (1<<7) #define CURLPROTO_LDAPS (1<<8) #define CURLPROTO_DICT (1<<9) #define CURLPROTO_FILE (1<<10) #define CURLPROTO_TFTP (1<<11) #define CURLPROTO_IMAP (1<<12) #define CURLPROTO_IMAPS (1<<13) #define CURLPROTO_POP3 (1<<14) #define CURLPROTO_POP3S (1<<15) #define CURLPROTO_SMTP (1<<16) #define CURLPROTO_SMTPS (1<<17) #define CURLPROTO_RTSP (1<<18) #define CURLPROTO_RTMP (1<<19) #define CURLPROTO_RTMPT (1<<20) #define CURLPROTO_RTMPE (1<<21) #define CURLPROTO_RTMPTE (1<<22) #define CURLPROTO_RTMPS (1<<23) #define CURLPROTO_RTMPTS (1<<24) #define CURLPROTO_GOPHER (1<<25) #define CURLPROTO_SMB (1<<26) #define CURLPROTO_SMBS (1<<27) #define CURLPROTO_MQTT (1<<28) #define CURLPROTO_GOPHERS (1<<29) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ #define CURLOPTTYPE_LONG 0 #define CURLOPTTYPE_OBJECTPOINT 10000 #define CURLOPTTYPE_FUNCTIONPOINT 20000 #define CURLOPTTYPE_OFF_T 30000 #define CURLOPTTYPE_BLOB 40000 /* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the string options from the header file */ #define CURLOPT(na,t,nu) na = t + nu #define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu /* CURLOPT aliases that make no runtime difference */ /* 'char *' argument to a string with a trailing zero */ #define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT /* 'struct curl_slist *' argument */ #define CURLOPTTYPE_SLISTPOINT CURLOPTTYPE_OBJECTPOINT /* 'void *' argument passed untouched to callback */ #define CURLOPTTYPE_CBPOINT CURLOPTTYPE_OBJECTPOINT /* 'long' argument with a set of values/bitmask */ #define CURLOPTTYPE_VALUES CURLOPTTYPE_LONG /* * All CURLOPT_* values. */ typedef enum { /* This is the FILE * or void * the regular output should be written to. */ CURLOPT(CURLOPT_WRITEDATA, CURLOPTTYPE_CBPOINT, 1), /* The full URL to get/put */ CURLOPT(CURLOPT_URL, CURLOPTTYPE_STRINGPOINT, 2), /* Port number to connect to, if other than default. */ CURLOPT(CURLOPT_PORT, CURLOPTTYPE_LONG, 3), /* Name of proxy to use. */ CURLOPT(CURLOPT_PROXY, CURLOPTTYPE_STRINGPOINT, 4), /* "user:password;options" to use when fetching. */ CURLOPT(CURLOPT_USERPWD, CURLOPTTYPE_STRINGPOINT, 5), /* "user:password" to use with proxy. */ CURLOPT(CURLOPT_PROXYUSERPWD, CURLOPTTYPE_STRINGPOINT, 6), /* Range to get, specified as an ASCII string. */ CURLOPT(CURLOPT_RANGE, CURLOPTTYPE_STRINGPOINT, 7), /* not used */ /* Specified file stream to upload from (use as input): */ CURLOPT(CURLOPT_READDATA, CURLOPTTYPE_CBPOINT, 9), /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE * bytes big. */ CURLOPT(CURLOPT_ERRORBUFFER, CURLOPTTYPE_OBJECTPOINT, 10), /* Function that will be called to store the output (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ CURLOPT(CURLOPT_WRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 11), /* Function that will be called to read the input (instead of fread). The * parameters will use fread() syntax, make sure to follow them. */ CURLOPT(CURLOPT_READFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 12), /* Time-out the read operation after this amount of seconds */ CURLOPT(CURLOPT_TIMEOUT, CURLOPTTYPE_LONG, 13), /* If CURLOPT_READDATA is used, this can be used to inform libcurl about * how large the file being sent really is. That allows better error * checking and better verifies that the upload was successful. -1 means * unknown size. * * For large file support, there is also a _LARGE version of the key * which takes an off_t type, allowing platforms with larger off_t * sizes to handle larger files. See below for INFILESIZE_LARGE. */ CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14), /* POST static input fields. */ CURLOPT(CURLOPT_POSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 15), /* Set the referrer page (needed by some CGIs) */ CURLOPT(CURLOPT_REFERER, CURLOPTTYPE_STRINGPOINT, 16), /* Set the FTP PORT string (interface name, named or numerical IP address) Use i.e '-' to use default address. */ CURLOPT(CURLOPT_FTPPORT, CURLOPTTYPE_STRINGPOINT, 17), /* Set the User-Agent string (examined by some CGIs) */ CURLOPT(CURLOPT_USERAGENT, CURLOPTTYPE_STRINGPOINT, 18), /* If the download receives less than "low speed limit" bytes/second * during "low speed time" seconds, the operations is aborted. * You could i.e if you have a pretty high speed connection, abort if * it is less than 2000 bytes/sec during 20 seconds. */ /* Set the "low speed limit" */ CURLOPT(CURLOPT_LOW_SPEED_LIMIT, CURLOPTTYPE_LONG, 19), /* Set the "low speed time" */ CURLOPT(CURLOPT_LOW_SPEED_TIME, CURLOPTTYPE_LONG, 20), /* Set the continuation offset. * * Note there is also a _LARGE version of this key which uses * off_t types, allowing for large file offsets on platforms which * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE. */ CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21), /* Set cookie in request: */ CURLOPT(CURLOPT_COOKIE, CURLOPTTYPE_STRINGPOINT, 22), /* This points to a linked list of headers, struct curl_slist kind. This list is also used for RTSP (in spite of its name) */ CURLOPT(CURLOPT_HTTPHEADER, CURLOPTTYPE_SLISTPOINT, 23), /* This points to a linked list of post entries, struct curl_httppost */ CURLOPTDEPRECATED(CURLOPT_HTTPPOST, CURLOPTTYPE_OBJECTPOINT, 24, 7.56.0, "Use CURLOPT_MIMEPOST"), /* name of the file keeping your private SSL-certificate */ CURLOPT(CURLOPT_SSLCERT, CURLOPTTYPE_STRINGPOINT, 25), /* password for the SSL or SSH private key */ CURLOPT(CURLOPT_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 26), /* send TYPE parameter? */ CURLOPT(CURLOPT_CRLF, CURLOPTTYPE_LONG, 27), /* send linked-list of QUOTE commands */ CURLOPT(CURLOPT_QUOTE, CURLOPTTYPE_SLISTPOINT, 28), /* send FILE * or void * to store headers to, if you use a callback it is simply passed to the callback unmodified */ CURLOPT(CURLOPT_HEADERDATA, CURLOPTTYPE_CBPOINT, 29), /* point to a file to read the initial cookies from, also enables "cookie awareness" */ CURLOPT(CURLOPT_COOKIEFILE, CURLOPTTYPE_STRINGPOINT, 31), /* What version to specifically try to use. See CURL_SSLVERSION defines below. */ CURLOPT(CURLOPT_SSLVERSION, CURLOPTTYPE_VALUES, 32), /* What kind of HTTP time condition to use, see defines */ CURLOPT(CURLOPT_TIMECONDITION, CURLOPTTYPE_VALUES, 33), /* Time to use with the above condition. Specified in number of seconds since 1 Jan 1970 */ CURLOPT(CURLOPT_TIMEVALUE, CURLOPTTYPE_LONG, 34), /* 35 = OBSOLETE */ /* Custom request, for customizing the get command like HTTP: DELETE, TRACE and others FTP: to use a different list command */ CURLOPT(CURLOPT_CUSTOMREQUEST, CURLOPTTYPE_STRINGPOINT, 36), /* FILE handle to use instead of stderr */ CURLOPT(CURLOPT_STDERR, CURLOPTTYPE_OBJECTPOINT, 37), /* 38 is not used */ /* send linked-list of post-transfer QUOTE commands */ CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39), /* 40 is not used */ /* talk a lot */ CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41), /* throw the header out too */ CURLOPT(CURLOPT_HEADER, CURLOPTTYPE_LONG, 42), /* shut off the progress meter */ CURLOPT(CURLOPT_NOPROGRESS, CURLOPTTYPE_LONG, 43), /* use HEAD to get http document */ CURLOPT(CURLOPT_NOBODY, CURLOPTTYPE_LONG, 44), /* no output on http error codes >= 400 */ CURLOPT(CURLOPT_FAILONERROR, CURLOPTTYPE_LONG, 45), /* this is an upload */ CURLOPT(CURLOPT_UPLOAD, CURLOPTTYPE_LONG, 46), /* HTTP POST method */ CURLOPT(CURLOPT_POST, CURLOPTTYPE_LONG, 47), /* bare names when listing directories */ CURLOPT(CURLOPT_DIRLISTONLY, CURLOPTTYPE_LONG, 48), /* Append instead of overwrite on upload! */ CURLOPT(CURLOPT_APPEND, CURLOPTTYPE_LONG, 50), /* Specify whether to read the user+password from the .netrc or the URL. * This must be one of the CURL_NETRC_* enums below. */ CURLOPT(CURLOPT_NETRC, CURLOPTTYPE_VALUES, 51), /* use Location: Luke! */ CURLOPT(CURLOPT_FOLLOWLOCATION, CURLOPTTYPE_LONG, 52), /* transfer data in text/ASCII format */ CURLOPT(CURLOPT_TRANSFERTEXT, CURLOPTTYPE_LONG, 53), /* HTTP PUT */ CURLOPTDEPRECATED(CURLOPT_PUT, CURLOPTTYPE_LONG, 54, 7.12.1, "Use CURLOPT_UPLOAD"), /* 55 = OBSOLETE */ /* DEPRECATED * Function that will be called instead of the internal progress display * function. This function should be defined as the curl_progress_callback * prototype defines. */ CURLOPTDEPRECATED(CURLOPT_PROGRESSFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 56, 7.32.0, "Use CURLOPT_XFERINFOFUNCTION"), /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION callbacks */ CURLOPT(CURLOPT_XFERINFODATA, CURLOPTTYPE_CBPOINT, 57), #define CURLOPT_PROGRESSDATA CURLOPT_XFERINFODATA /* We want the referrer field set automatically when following locations */ CURLOPT(CURLOPT_AUTOREFERER, CURLOPTTYPE_LONG, 58), /* Port of the proxy, can be set in the proxy string as well with: "[host]:[port]" */ CURLOPT(CURLOPT_PROXYPORT, CURLOPTTYPE_LONG, 59), /* size of the POST input data, if strlen() is not good to use */ CURLOPT(CURLOPT_POSTFIELDSIZE, CURLOPTTYPE_LONG, 60), /* tunnel non-http operations through an HTTP proxy */ CURLOPT(CURLOPT_HTTPPROXYTUNNEL, CURLOPTTYPE_LONG, 61), /* Set the interface string to use as outgoing network interface */ CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62), /* Set the krb4/5 security level, this also enables krb4/5 awareness. This * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string * is set but does not match one of these, 'private' will be used. */ CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63), /* Set if we should verify the peer in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 64), /* The CApath or CAfile used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAINFO, CURLOPTTYPE_STRINGPOINT, 65), /* 66 = OBSOLETE */ /* 67 = OBSOLETE */ /* Maximum number of http redirects to follow */ CURLOPT(CURLOPT_MAXREDIRS, CURLOPTTYPE_LONG, 68), /* Pass a long set to 1 to get the date of the requested document (if possible)! Pass a zero to shut it off. */ CURLOPT(CURLOPT_FILETIME, CURLOPTTYPE_LONG, 69), /* This points to a linked list of telnet options */ CURLOPT(CURLOPT_TELNETOPTIONS, CURLOPTTYPE_SLISTPOINT, 70), /* Max amount of cached alive connections */ CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71), /* 72 = OBSOLETE */ /* 73 = OBSOLETE */ /* Set to explicitly use a new connection for the upcoming transfer. Do not use this unless you are absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74), /* Set to explicitly forbid the upcoming transfer's connection to be reused when done. Do not use this unless you are absolutely sure of this, as it makes the operation slower and is less friendly for the network. */ CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75), /* Set to a filename that contains random data for libcurl to use to seed the random engine when doing SSL connects. */ CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76, 7.84.0, "Serves no purpose anymore"), /* Set to the Entropy Gathering Daemon socket pathname */ CURLOPTDEPRECATED(CURLOPT_EGDSOCKET, CURLOPTTYPE_STRINGPOINT, 77, 7.84.0, "Serves no purpose anymore"), /* Time-out connect operations after this amount of seconds, if connects are OK within this time, then fine... This only aborts the connect phase. */ CURLOPT(CURLOPT_CONNECTTIMEOUT, CURLOPTTYPE_LONG, 78), /* Function that will be called to store headers (instead of fwrite). The * parameters will use fwrite() syntax, make sure to follow them. */ CURLOPT(CURLOPT_HEADERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 79), /* Set this to force the HTTP request to get back to GET. Only really usable if POST, PUT or a custom request have been used first. */ CURLOPT(CURLOPT_HTTPGET, CURLOPTTYPE_LONG, 80), /* Set if we should verify the Common name from the peer certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches the * provided hostname. */ CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81), /* Specify which filename to write all known cookies in after completed operation. Set filename to "-" (dash) to make it go to stdout. */ CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82), /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use */ CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83), /* Specify which HTTP version to use! This must be set to one of the CURL_HTTP_VERSION* enums set below. */ CURLOPT(CURLOPT_HTTP_VERSION, CURLOPTTYPE_VALUES, 84), /* Specifically switch on or off the FTP engine's use of the EPSV command. By default, that one will always be attempted before the more traditional PASV command. */ CURLOPT(CURLOPT_FTP_USE_EPSV, CURLOPTTYPE_LONG, 85), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */ CURLOPT(CURLOPT_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 86), /* name of the file keeping your private SSL-key */ CURLOPT(CURLOPT_SSLKEY, CURLOPTTYPE_STRINGPOINT, 87), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */ CURLOPT(CURLOPT_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 88), /* crypto engine for the SSL-sub system */ CURLOPT(CURLOPT_SSLENGINE, CURLOPTTYPE_STRINGPOINT, 89), /* set the crypto engine for the SSL-sub system as default the param has no meaning... */ CURLOPT(CURLOPT_SSLENGINE_DEFAULT, CURLOPTTYPE_LONG, 90), /* Non-zero value means to use the global dns cache */ /* DEPRECATED, do not use! */ CURLOPTDEPRECATED(CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOPTTYPE_LONG, 91, 7.11.1, "Use CURLOPT_SHARE"), /* DNS cache timeout */ CURLOPT(CURLOPT_DNS_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 92), /* send linked-list of pre-transfer QUOTE commands */ CURLOPT(CURLOPT_PREQUOTE, CURLOPTTYPE_SLISTPOINT, 93), /* set the debug function */ CURLOPT(CURLOPT_DEBUGFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 94), /* set the data for the debug function */ CURLOPT(CURLOPT_DEBUGDATA, CURLOPTTYPE_CBPOINT, 95), /* mark this as start of a cookie session */ CURLOPT(CURLOPT_COOKIESESSION, CURLOPTTYPE_LONG, 96), /* The CApath directory used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAPATH, CURLOPTTYPE_STRINGPOINT, 97), /* Instruct libcurl to use a smaller receive buffer */ CURLOPT(CURLOPT_BUFFERSIZE, CURLOPTTYPE_LONG, 98), /* Instruct libcurl to not use any signal/alarm handlers, even when using timeouts. This option is useful for multi-threaded applications. See libcurl-the-guide for more background information. */ CURLOPT(CURLOPT_NOSIGNAL, CURLOPTTYPE_LONG, 99), /* Provide a CURLShare for mutexing non-ts data */ CURLOPT(CURLOPT_SHARE, CURLOPTTYPE_OBJECTPOINT, 100), /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ CURLOPT(CURLOPT_PROXYTYPE, CURLOPTTYPE_VALUES, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like the response to be compressed. Before 7.21.6, this was known as CURLOPT_ENCODING */ CURLOPT(CURLOPT_ACCEPT_ENCODING, CURLOPTTYPE_STRINGPOINT, 102), /* Set pointer to private data */ CURLOPT(CURLOPT_PRIVATE, CURLOPTTYPE_OBJECTPOINT, 103), /* Set aliases for HTTP 200 in the HTTP Response header */ CURLOPT(CURLOPT_HTTP200ALIASES, CURLOPTTYPE_SLISTPOINT, 104), /* Continue to send authentication (user+password) when following locations, even when hostname changed. This can potentially send off the name and password to whatever host the server decides. */ CURLOPT(CURLOPT_UNRESTRICTED_AUTH, CURLOPTTYPE_LONG, 105), /* Specifically switch on or off the FTP engine's use of the EPRT command ( it also disables the LPRT attempt). By default, those ones will always be attempted before the good old traditional PORT command. */ CURLOPT(CURLOPT_FTP_USE_EPRT, CURLOPTTYPE_LONG, 106), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_USERPWD. Note that setting multiple bits may cause extra network round-trips. */ CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107), /* Set the ssl context callback function, currently only for OpenSSL or wolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument. The function must match the curl_ssl_ctx_callback prototype. */ CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108), /* Set the userdata for the ssl context callback function's third argument */ CURLOPT(CURLOPT_SSL_CTX_DATA, CURLOPTTYPE_CBPOINT, 109), /* FTP Option that causes missing dirs to be created on the remote server. In 7.19.4 we introduced the convenience enums for this option using the CURLFTP_CREATE_DIR prefix. */ CURLOPT(CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPTTYPE_LONG, 110), /* Set this to a bitmask value to enable the particular authentications methods you like. Use this in combination with CURLOPT_PROXYUSERPWD. Note that setting multiple bits may cause extra network round-trips. */ CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111), /* Option that changes the timeout, in seconds, associated with getting a response. This is different from transfer timeout time and essentially places a demand on the server to acknowledge commands in a timely manner. For FTP, SMTP, IMAP and POP3. */ CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112), /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to tell libcurl to use those IP versions only. This only has effect on systems with support for more than one, i.e IPv4 _and_ IPv6. */ CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113), /* Set this option to limit the size of a file that will be downloaded from an HTTP or FTP server. Note there is also _LARGE version which adds large file support for platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */ CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114), /* See the comment for INFILESIZE above, but in short, specifies * the size of the file being uploaded. -1 means unknown. */ CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115), /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version * of this; look above for RESUME_FROM. */ CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116), /* Sets the maximum size of data that will be downloaded from * an HTTP or FTP server. See MAXFILESIZE above for the LONG version. */ CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117), /* Set this option to the filename of your .netrc file you want libcurl to parse (using the CURLOPT_NETRC option). If not set, libcurl will do a poor attempt to find the user's home directory and check for a .netrc file in there. */ CURLOPT(CURLOPT_NETRC_FILE, CURLOPTTYPE_STRINGPOINT, 118), /* Enable SSL/TLS for FTP, pick one of: CURLUSESSL_TRY - try using SSL, proceed anyway otherwise CURLUSESSL_CONTROL - SSL for the control connection or fail CURLUSESSL_ALL - SSL for all communication or fail */ CURLOPT(CURLOPT_USE_SSL, CURLOPTTYPE_VALUES, 119), /* The _LARGE version of the standard POSTFIELDSIZE option */ CURLOPT(CURLOPT_POSTFIELDSIZE_LARGE, CURLOPTTYPE_OFF_T, 120), /* Enable/disable the TCP Nagle algorithm */ CURLOPT(CURLOPT_TCP_NODELAY, CURLOPTTYPE_LONG, 121), /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 123 OBSOLETE. Gone in 7.16.0 */ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */ /* 127 OBSOLETE. Gone in 7.16.0 */ /* 128 OBSOLETE. Gone in 7.16.0 */ /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option can be used to change libcurl's default action which is to first try "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK response has been received. Available parameters are: CURLFTPAUTH_DEFAULT - let libcurl decide CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL */ CURLOPT(CURLOPT_FTPSSLAUTH, CURLOPTTYPE_VALUES, 129), CURLOPTDEPRECATED(CURLOPT_IOCTLFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 130, 7.18.0, "Use CURLOPT_SEEKFUNCTION"), CURLOPTDEPRECATED(CURLOPT_IOCTLDATA, CURLOPTTYPE_CBPOINT, 131, 7.18.0, "Use CURLOPT_SEEKDATA"), /* 132 OBSOLETE. Gone in 7.16.0 */ /* 133 OBSOLETE. Gone in 7.16.0 */ /* null-terminated string for pass on to the FTP server when asked for "account" info */ CURLOPT(CURLOPT_FTP_ACCOUNT, CURLOPTTYPE_STRINGPOINT, 134), /* feed cookie into cookie engine */ CURLOPT(CURLOPT_COOKIELIST, CURLOPTTYPE_STRINGPOINT, 135), /* ignore Content-Length */ CURLOPT(CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPTTYPE_LONG, 136), /* Set to non-zero to skip the IP address received in a 227 PASV FTP server response. Typically used for FTP-SSL purposes but is not restricted to that. libcurl will then instead use the same IP address it used for the control connection. */ CURLOPT(CURLOPT_FTP_SKIP_PASV_IP, CURLOPTTYPE_LONG, 137), /* Select "file method" to use when doing FTP, see the curl_ftpmethod above. */ CURLOPT(CURLOPT_FTP_FILEMETHOD, CURLOPTTYPE_VALUES, 138), /* Local port number to bind the socket to */ CURLOPT(CURLOPT_LOCALPORT, CURLOPTTYPE_LONG, 139), /* Number of ports to try, including the first one set with LOCALPORT. Thus, setting it to 1 will make no additional attempts but the first. */ CURLOPT(CURLOPT_LOCALPORTRANGE, CURLOPTTYPE_LONG, 140), /* no transfer, set up connection and let application use the socket by extracting it with CURLINFO_LASTSOCKET */ CURLOPT(CURLOPT_CONNECT_ONLY, CURLOPTTYPE_LONG, 141), /* Function that will be called to convert from the network encoding (instead of using the iconv calls in libcurl) */ CURLOPTDEPRECATED(CURLOPT_CONV_FROM_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 142, 7.82.0, "Serves no purpose anymore"), /* Function that will be called to convert to the network encoding (instead of using the iconv calls in libcurl) */ CURLOPTDEPRECATED(CURLOPT_CONV_TO_NETWORK_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 143, 7.82.0, "Serves no purpose anymore"), /* Function that will be called to convert from UTF8 (instead of using the iconv calls in libcurl) Note that this is used only for SSL certificate processing */ CURLOPTDEPRECATED(CURLOPT_CONV_FROM_UTF8_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 144, 7.82.0, "Serves no purpose anymore"), /* if the connection proceeds too quickly then need to slow it down */ /* limit-rate: maximum number of bytes per second to send or receive */ CURLOPT(CURLOPT_MAX_SEND_SPEED_LARGE, CURLOPTTYPE_OFF_T, 145), CURLOPT(CURLOPT_MAX_RECV_SPEED_LARGE, CURLOPTTYPE_OFF_T, 146), /* Pointer to command string to send if USER/PASS fails. */ CURLOPT(CURLOPT_FTP_ALTERNATIVE_TO_USER, CURLOPTTYPE_STRINGPOINT, 147), /* callback function for setting socket options */ CURLOPT(CURLOPT_SOCKOPTFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 148), CURLOPT(CURLOPT_SOCKOPTDATA, CURLOPTTYPE_CBPOINT, 149), /* set to 0 to disable session ID reuse for this transfer, default is enabled (== 1) */ CURLOPT(CURLOPT_SSL_SESSIONID_CACHE, CURLOPTTYPE_LONG, 150), /* allowed SSH authentication methods */ CURLOPT(CURLOPT_SSH_AUTH_TYPES, CURLOPTTYPE_VALUES, 151), /* Used by scp/sftp to do public/private key authentication */ CURLOPT(CURLOPT_SSH_PUBLIC_KEYFILE, CURLOPTTYPE_STRINGPOINT, 152), CURLOPT(CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPTTYPE_STRINGPOINT, 153), /* Send CCC (Clear Command Channel) after authentication */ CURLOPT(CURLOPT_FTP_SSL_CCC, CURLOPTTYPE_LONG, 154), /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */ CURLOPT(CURLOPT_TIMEOUT_MS, CURLOPTTYPE_LONG, 155), CURLOPT(CURLOPT_CONNECTTIMEOUT_MS, CURLOPTTYPE_LONG, 156), /* set to zero to disable the libcurl's decoding and thus pass the raw body data to the application even when it is encoded/compressed */ CURLOPT(CURLOPT_HTTP_TRANSFER_DECODING, CURLOPTTYPE_LONG, 157), CURLOPT(CURLOPT_HTTP_CONTENT_DECODING, CURLOPTTYPE_LONG, 158), /* Permission used when creating new files and directories on the remote server for protocols that support it, SFTP/SCP/FILE */ CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159), CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160), /* Set the behavior of POST when redirecting. Values must be set to one of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */ CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161), /* used by scp/sftp to verify the host's public key */ CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, CURLOPTTYPE_STRINGPOINT, 162), /* Callback function for opening socket (instead of socket(2)). Optionally, callback is able change the address or refuse to connect returning CURL_SOCKET_BAD. The callback should have type curl_opensocket_callback */ CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163), CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164), /* POST volatile input fields. */ CURLOPT(CURLOPT_COPYPOSTFIELDS, CURLOPTTYPE_OBJECTPOINT, 165), /* set transfer mode (;type=) when doing FTP via an HTTP proxy */ CURLOPT(CURLOPT_PROXY_TRANSFER_MODE, CURLOPTTYPE_LONG, 166), /* Callback function for seeking in the input stream */ CURLOPT(CURLOPT_SEEKFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 167), CURLOPT(CURLOPT_SEEKDATA, CURLOPTTYPE_CBPOINT, 168), /* CRL file */ CURLOPT(CURLOPT_CRLFILE, CURLOPTTYPE_STRINGPOINT, 169), /* Issuer certificate */ CURLOPT(CURLOPT_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 170), /* (IPv6) Address scope */ CURLOPT(CURLOPT_ADDRESS_SCOPE, CURLOPTTYPE_LONG, 171), /* Collect certificate chain info and allow it to get retrievable with CURLINFO_CERTINFO after the transfer is complete. */ CURLOPT(CURLOPT_CERTINFO, CURLOPTTYPE_LONG, 172), /* "name" and "pwd" to use when fetching. */ CURLOPT(CURLOPT_USERNAME, CURLOPTTYPE_STRINGPOINT, 173), CURLOPT(CURLOPT_PASSWORD, CURLOPTTYPE_STRINGPOINT, 174), /* "name" and "pwd" to use with Proxy when fetching. */ CURLOPT(CURLOPT_PROXYUSERNAME, CURLOPTTYPE_STRINGPOINT, 175), CURLOPT(CURLOPT_PROXYPASSWORD, CURLOPTTYPE_STRINGPOINT, 176), /* Comma separated list of hostnames defining no-proxy zones. These should match both hostnames directly, and hostnames within a domain. For example, local.com will match local.com and www.local.com, but NOT notlocal.com or www.notlocal.com. For compatibility with other implementations of this, .local.com will be considered to be the same as local.com. A single * is the only valid wildcard, and effectively disables the use of proxy. */ CURLOPT(CURLOPT_NOPROXY, CURLOPTTYPE_STRINGPOINT, 177), /* block size for TFTP transfers */ CURLOPT(CURLOPT_TFTP_BLKSIZE, CURLOPTTYPE_LONG, 178), /* Socks Service */ /* DEPRECATED, do not use! */ CURLOPTDEPRECATED(CURLOPT_SOCKS5_GSSAPI_SERVICE, CURLOPTTYPE_STRINGPOINT, 179, 7.49.0, "Use CURLOPT_PROXY_SERVICE_NAME"), /* Socks Service */ CURLOPT(CURLOPT_SOCKS5_GSSAPI_NEC, CURLOPTTYPE_LONG, 180), /* set the bitmask for the protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to CURLPROTO_ALL. */ CURLOPTDEPRECATED(CURLOPT_PROTOCOLS, CURLOPTTYPE_LONG, 181, 7.85.0, "Use CURLOPT_PROTOCOLS_STR"), /* set the bitmask for the protocols that libcurl is allowed to follow to, as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs to be set in both bitmasks to be allowed to get redirected to. */ CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182, 7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"), /* set the SSH knownhost filename to use */ CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ CURLOPT(CURLOPT_SSH_KEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 184), /* set the SSH host key callback custom pointer */ CURLOPT(CURLOPT_SSH_KEYDATA, CURLOPTTYPE_CBPOINT, 185), /* set the SMTP mail originator */ CURLOPT(CURLOPT_MAIL_FROM, CURLOPTTYPE_STRINGPOINT, 186), /* set the list of SMTP mail receiver(s) */ CURLOPT(CURLOPT_MAIL_RCPT, CURLOPTTYPE_SLISTPOINT, 187), /* FTP: send PRET before PASV */ CURLOPT(CURLOPT_FTP_USE_PRET, CURLOPTTYPE_LONG, 188), /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */ CURLOPT(CURLOPT_RTSP_REQUEST, CURLOPTTYPE_VALUES, 189), /* The RTSP session identifier */ CURLOPT(CURLOPT_RTSP_SESSION_ID, CURLOPTTYPE_STRINGPOINT, 190), /* The RTSP stream URI */ CURLOPT(CURLOPT_RTSP_STREAM_URI, CURLOPTTYPE_STRINGPOINT, 191), /* The Transport: header to use in RTSP requests */ CURLOPT(CURLOPT_RTSP_TRANSPORT, CURLOPTTYPE_STRINGPOINT, 192), /* Manually initialize the client RTSP CSeq for this handle */ CURLOPT(CURLOPT_RTSP_CLIENT_CSEQ, CURLOPTTYPE_LONG, 193), /* Manually initialize the server RTSP CSeq for this handle */ CURLOPT(CURLOPT_RTSP_SERVER_CSEQ, CURLOPTTYPE_LONG, 194), /* The stream to pass to INTERLEAVEFUNCTION. */ CURLOPT(CURLOPT_INTERLEAVEDATA, CURLOPTTYPE_CBPOINT, 195), /* Let the application define a custom write method for RTP data */ CURLOPT(CURLOPT_INTERLEAVEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 196), /* Turn on wildcard matching */ CURLOPT(CURLOPT_WILDCARDMATCH, CURLOPTTYPE_LONG, 197), /* Directory matching callback called before downloading of an individual file (chunk) started */ CURLOPT(CURLOPT_CHUNK_BGN_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 198), /* Directory matching callback called after the file (chunk) was downloaded, or skipped */ CURLOPT(CURLOPT_CHUNK_END_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 199), /* Change match (fnmatch-like) callback for wildcard matching */ CURLOPT(CURLOPT_FNMATCH_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 200), /* Let the application define custom chunk data pointer */ CURLOPT(CURLOPT_CHUNK_DATA, CURLOPTTYPE_CBPOINT, 201), /* FNMATCH_FUNCTION user pointer */ CURLOPT(CURLOPT_FNMATCH_DATA, CURLOPTTYPE_CBPOINT, 202), /* send linked-list of name:port:address sets */ CURLOPT(CURLOPT_RESOLVE, CURLOPTTYPE_SLISTPOINT, 203), /* Set a username for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 204), /* Set a password for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 205), /* Set authentication type for authenticated TLS */ CURLOPT(CURLOPT_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 206), /* Set to 1 to enable the "TE:" header in HTTP requests to ask for compressed transfer-encoded responses. Set to 0 to disable the use of TE: in outgoing requests. The current default is 0, but it might change in a future libcurl release. libcurl will ask for the compressed methods it knows of, and if that is not any, it will not ask for transfer-encoding at all even if this option is set to 1. */ CURLOPT(CURLOPT_TRANSFER_ENCODING, CURLOPTTYPE_LONG, 207), /* Callback function for closing socket (instead of close(2)). The callback should have type curl_closesocket_callback */ CURLOPT(CURLOPT_CLOSESOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 208), CURLOPT(CURLOPT_CLOSESOCKETDATA, CURLOPTTYPE_CBPOINT, 209), /* allow GSSAPI credential delegation */ CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210), /* Set the name servers to use for DNS resolution. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211), /* Time-out accept operations (currently for FTP only) after this amount of milliseconds. */ CURLOPT(CURLOPT_ACCEPTTIMEOUT_MS, CURLOPTTYPE_LONG, 212), /* Set TCP keepalive */ CURLOPT(CURLOPT_TCP_KEEPALIVE, CURLOPTTYPE_LONG, 213), /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */ CURLOPT(CURLOPT_TCP_KEEPIDLE, CURLOPTTYPE_LONG, 214), CURLOPT(CURLOPT_TCP_KEEPINTVL, CURLOPTTYPE_LONG, 215), /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ CURLOPT(CURLOPT_SSL_OPTIONS, CURLOPTTYPE_VALUES, 216), /* Set the SMTP auth originator */ CURLOPT(CURLOPT_MAIL_AUTH, CURLOPTTYPE_STRINGPOINT, 217), /* Enable/disable SASL initial response */ CURLOPT(CURLOPT_SASL_IR, CURLOPTTYPE_LONG, 218), /* Function that will be called instead of the internal progress display * function. This function should be defined as the curl_xferinfo_callback * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ CURLOPT(CURLOPT_XFERINFOFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 219), /* The XOAUTH2 bearer token */ CURLOPT(CURLOPT_XOAUTH2_BEARER, CURLOPTTYPE_STRINGPOINT, 220), /* Set the interface string to use as outgoing network * interface for DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_INTERFACE, CURLOPTTYPE_STRINGPOINT, 221), /* Set the local IPv4 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_LOCAL_IP4, CURLOPTTYPE_STRINGPOINT, 222), /* Set the local IPv6 address to use for outgoing DNS requests. * Only supported by the c-ares DNS backend */ CURLOPT(CURLOPT_DNS_LOCAL_IP6, CURLOPTTYPE_STRINGPOINT, 223), /* Set authentication options directly */ CURLOPT(CURLOPT_LOGIN_OPTIONS, CURLOPTTYPE_STRINGPOINT, 224), /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */ CURLOPTDEPRECATED(CURLOPT_SSL_ENABLE_NPN, CURLOPTTYPE_LONG, 225, 7.86.0, "Has no function"), /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */ CURLOPT(CURLOPT_SSL_ENABLE_ALPN, CURLOPTTYPE_LONG, 226), /* Time to wait for a response to an HTTP request containing an * Expect: 100-continue header before sending the data anyway. */ CURLOPT(CURLOPT_EXPECT_100_TIMEOUT_MS, CURLOPTTYPE_LONG, 227), /* This points to a linked list of headers used for proxy requests only, struct curl_slist kind */ CURLOPT(CURLOPT_PROXYHEADER, CURLOPTTYPE_SLISTPOINT, 228), /* Pass in a bitmask of "header options" */ CURLOPT(CURLOPT_HEADEROPT, CURLOPTTYPE_VALUES, 229), /* The public key in DER form used to validate the peer public key this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 230), /* Path to Unix domain socket */ CURLOPT(CURLOPT_UNIX_SOCKET_PATH, CURLOPTTYPE_STRINGPOINT, 231), /* Set if we should verify the certificate status. */ CURLOPT(CURLOPT_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 232), /* Set if we should enable TLS false start. */ CURLOPT(CURLOPT_SSL_FALSESTART, CURLOPTTYPE_LONG, 233), /* Do not squash dot-dot sequences */ CURLOPT(CURLOPT_PATH_AS_IS, CURLOPTTYPE_LONG, 234), /* Proxy Service Name */ CURLOPT(CURLOPT_PROXY_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 235), /* Service Name */ CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236), /* Wait/do not wait for pipe/mutex to clarify */ CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237), /* Set the protocol used when curl is given a URL without a protocol */ CURLOPT(CURLOPT_DEFAULT_PROTOCOL, CURLOPTTYPE_STRINGPOINT, 238), /* Set stream weight, 1 - 256 (default is 16) */ CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239), /* Set stream dependency on another CURL handle */ CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240), /* Set E-xclusive stream dependency on another CURL handle */ CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241), /* Do not send any tftp option requests to the server */ CURLOPT(CURLOPT_TFTP_NO_OPTIONS, CURLOPTTYPE_LONG, 242), /* Linked-list of host:port:connect-to-host:connect-to-port, overrides the URL's host:port (only for the network layer) */ CURLOPT(CURLOPT_CONNECT_TO, CURLOPTTYPE_SLISTPOINT, 243), /* Set TCP Fast Open */ CURLOPT(CURLOPT_TCP_FASTOPEN, CURLOPTTYPE_LONG, 244), /* Continue to send data if the server responds early with an * HTTP status code >= 300 */ CURLOPT(CURLOPT_KEEP_SENDING_ON_ERROR, CURLOPTTYPE_LONG, 245), /* The CApath or CAfile used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAINFO, CURLOPTTYPE_STRINGPOINT, 246), /* The CApath directory used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAPATH, CURLOPTTYPE_STRINGPOINT, 247), /* Set if we should verify the proxy in ssl handshake, set 1 to verify. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 248), /* Set if we should verify the Common name from the proxy certificate in ssl * handshake, set 1 to check existence, 2 to ensure that it matches * the provided hostname. */ CURLOPT(CURLOPT_PROXY_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 249), /* What version to specifically try to use for proxy. See CURL_SSLVERSION defines below. */ CURLOPT(CURLOPT_PROXY_SSLVERSION, CURLOPTTYPE_VALUES, 250), /* Set a username for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_USERNAME, CURLOPTTYPE_STRINGPOINT, 251), /* Set a password for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_PASSWORD, CURLOPTTYPE_STRINGPOINT, 252), /* Set authentication type for authenticated TLS for proxy */ CURLOPT(CURLOPT_PROXY_TLSAUTH_TYPE, CURLOPTTYPE_STRINGPOINT, 253), /* name of the file keeping your private SSL-certificate for proxy */ CURLOPT(CURLOPT_PROXY_SSLCERT, CURLOPTTYPE_STRINGPOINT, 254), /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for proxy */ CURLOPT(CURLOPT_PROXY_SSLCERTTYPE, CURLOPTTYPE_STRINGPOINT, 255), /* name of the file keeping your private SSL-key for proxy */ CURLOPT(CURLOPT_PROXY_SSLKEY, CURLOPTTYPE_STRINGPOINT, 256), /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for proxy */ CURLOPT(CURLOPT_PROXY_SSLKEYTYPE, CURLOPTTYPE_STRINGPOINT, 257), /* password for the SSL private key for proxy */ CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258), /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use for proxy */ CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259), /* CRL file for proxy */ CURLOPT(CURLOPT_PROXY_CRLFILE, CURLOPTTYPE_STRINGPOINT, 260), /* Enable/disable specific SSL features with a bitmask for proxy, see CURLSSLOPT_* */ CURLOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLOPTTYPE_LONG, 261), /* Name of pre proxy to use. */ CURLOPT(CURLOPT_PRE_PROXY, CURLOPTTYPE_STRINGPOINT, 262), /* The public key in DER form used to validate the proxy public key this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_PINNEDPUBLICKEY, CURLOPTTYPE_STRINGPOINT, 263), /* Path to an abstract Unix domain socket */ CURLOPT(CURLOPT_ABSTRACT_UNIX_SOCKET, CURLOPTTYPE_STRINGPOINT, 264), /* Suppress proxy CONNECT response headers from user callbacks */ CURLOPT(CURLOPT_SUPPRESS_CONNECT_HEADERS, CURLOPTTYPE_LONG, 265), /* The request target, instead of extracted from the URL */ CURLOPT(CURLOPT_REQUEST_TARGET, CURLOPTTYPE_STRINGPOINT, 266), /* bitmask of allowed auth methods for connections to SOCKS5 proxies */ CURLOPT(CURLOPT_SOCKS5_AUTH, CURLOPTTYPE_LONG, 267), /* Enable/disable SSH compression */ CURLOPT(CURLOPT_SSH_COMPRESSION, CURLOPTTYPE_LONG, 268), /* Post MIME data. */ CURLOPT(CURLOPT_MIMEPOST, CURLOPTTYPE_OBJECTPOINT, 269), /* Time to use with the CURLOPT_TIMECONDITION. Specified in number of seconds since 1 Jan 1970. */ CURLOPT(CURLOPT_TIMEVALUE_LARGE, CURLOPTTYPE_OFF_T, 270), /* Head start in milliseconds to give happy eyeballs. */ CURLOPT(CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS, CURLOPTTYPE_LONG, 271), /* Function that will be called before a resolver request is made */ CURLOPT(CURLOPT_RESOLVER_START_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 272), /* User data to pass to the resolver start callback. */ CURLOPT(CURLOPT_RESOLVER_START_DATA, CURLOPTTYPE_CBPOINT, 273), /* send HAProxy PROXY protocol header? */ CURLOPT(CURLOPT_HAPROXYPROTOCOL, CURLOPTTYPE_LONG, 274), /* shuffle addresses before use when DNS returns multiple */ CURLOPT(CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOPTTYPE_LONG, 275), /* Specify which TLS 1.3 ciphers suites to use */ CURLOPT(CURLOPT_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 276), CURLOPT(CURLOPT_PROXY_TLS13_CIPHERS, CURLOPTTYPE_STRINGPOINT, 277), /* Disallow specifying username/login in URL. */ CURLOPT(CURLOPT_DISALLOW_USERNAME_IN_URL, CURLOPTTYPE_LONG, 278), /* DNS-over-HTTPS URL */ CURLOPT(CURLOPT_DOH_URL, CURLOPTTYPE_STRINGPOINT, 279), /* Preferred buffer size to use for uploads */ CURLOPT(CURLOPT_UPLOAD_BUFFERSIZE, CURLOPTTYPE_LONG, 280), /* Time in ms between connection upkeep calls for long-lived connections. */ CURLOPT(CURLOPT_UPKEEP_INTERVAL_MS, CURLOPTTYPE_LONG, 281), /* Specify URL using CURL URL API. */ CURLOPT(CURLOPT_CURLU, CURLOPTTYPE_OBJECTPOINT, 282), /* add trailing data just after no more data is available */ CURLOPT(CURLOPT_TRAILERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 283), /* pointer to be passed to HTTP_TRAILER_FUNCTION */ CURLOPT(CURLOPT_TRAILERDATA, CURLOPTTYPE_CBPOINT, 284), /* set this to 1L to allow HTTP/0.9 responses or 0L to disallow */ CURLOPT(CURLOPT_HTTP09_ALLOWED, CURLOPTTYPE_LONG, 285), /* alt-svc control bitmask */ CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286), /* alt-svc cache filename to possibly read from/write to */ CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287), /* maximum age (idle time) of a connection to consider it for reuse * (in seconds) */ CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288), /* SASL authorization identity */ CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289), /* allow RCPT TO command to fail for some recipients */ CURLOPT(CURLOPT_MAIL_RCPT_ALLOWFAILS, CURLOPTTYPE_LONG, 290), /* the private SSL-certificate as a "blob" */ CURLOPT(CURLOPT_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 291), CURLOPT(CURLOPT_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 292), CURLOPT(CURLOPT_PROXY_SSLCERT_BLOB, CURLOPTTYPE_BLOB, 293), CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294), CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295), /* Issuer certificate for proxy */ CURLOPT(CURLOPT_PROXY_ISSUERCERT, CURLOPTTYPE_STRINGPOINT, 296), CURLOPT(CURLOPT_PROXY_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 297), /* the EC curves requested by the TLS client (RFC 8422, 5.1); * OpenSSL support via 'set_groups'/'set_curves': * https://docs.openssl.org/master/man3/SSL_CTX_set1_curves/ */ CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298), /* HSTS bitmask */ CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299), /* HSTS filename */ CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300), /* HSTS read callback */ CURLOPT(CURLOPT_HSTSREADFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 301), CURLOPT(CURLOPT_HSTSREADDATA, CURLOPTTYPE_CBPOINT, 302), /* HSTS write callback */ CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303), CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304), /* Parameters for V4 signature */ CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305), /* Same as CURLOPT_SSL_VERIFYPEER but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306), /* Same as CURLOPT_SSL_VERIFYHOST but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307), /* Same as CURLOPT_SSL_VERIFYSTATUS but for DoH (DNS-over-HTTPS) servers. */ CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308), /* The CA certificates as "blob" used to validate the peer certificate this option is used only if SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309), /* The CA certificates as "blob" used to validate the proxy certificate this option is used only if PROXY_SSL_VERIFYPEER is true */ CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310), /* used by scp/sftp to verify the host's public key */ CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311), /* Function that will be called immediately before the initial request is made on a connection (after any protocol negotiation step). */ CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312), /* Data passed to the CURLOPT_PREREQFUNCTION callback */ CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313), /* maximum age (since creation) of a connection to consider it for reuse * (in seconds) */ CURLOPT(CURLOPT_MAXLIFETIME_CONN, CURLOPTTYPE_LONG, 314), /* Set MIME option flags. */ CURLOPT(CURLOPT_MIME_OPTIONS, CURLOPTTYPE_LONG, 315), /* set the SSH host key callback, must point to a curl_sshkeycallback function */ CURLOPT(CURLOPT_SSH_HOSTKEYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 316), /* set the SSH host key callback custom pointer */ CURLOPT(CURLOPT_SSH_HOSTKEYDATA, CURLOPTTYPE_CBPOINT, 317), /* specify which protocols that are allowed to be used for the transfer, which thus helps the app which takes URLs from users or other external inputs and want to restrict what protocol(s) to deal with. Defaults to all built-in protocols. */ CURLOPT(CURLOPT_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 318), /* specify which protocols that libcurl is allowed to follow directs to */ CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319), /* WebSockets options */ CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320), /* CA cache timeout */ CURLOPT(CURLOPT_CA_CACHE_TIMEOUT, CURLOPTTYPE_LONG, 321), /* Can leak things, gonna exit() soon */ CURLOPT(CURLOPT_QUICK_EXIT, CURLOPTTYPE_LONG, 322), /* set a specific client IP for HAProxy PROXY protocol header? */ CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323), /* millisecond version */ CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324), /* set ECH configuration */ CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325), /* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */ CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326), CURLOPT_LASTENTRY /* the last unused */ } CURLoption; #ifndef CURL_NO_OLDIES /* define this to test if your app builds with all the obsolete stuff removed! */ /* Backwards compatibility with older names */ /* These are scheduled to disappear by 2011 */ /* This was added in version 7.19.1 */ #define CURLOPT_POST301 CURLOPT_POSTREDIR /* These are scheduled to disappear by 2009 */ /* The following were added in 7.17.0 */ #define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD #define CURLOPT_FTPAPPEND CURLOPT_APPEND #define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY #define CURLOPT_FTP_SSL CURLOPT_USE_SSL /* The following were added earlier */ #define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD #define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL /* */ #define CURLOPT_FTP_RESPONSE_TIMEOUT CURLOPT_SERVER_RESPONSE_TIMEOUT /* Added in 8.2.0 */ #define CURLOPT_MAIL_RCPT_ALLLOWFAILS CURLOPT_MAIL_RCPT_ALLOWFAILS #else /* This is set if CURL_NO_OLDIES is defined at compile-time */ #undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */ #endif /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host name resolves addresses using more than one IP protocol version, this option might be handy to force libcurl to use a specific IP version. */ #define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP versions that your system allows */ #define CURL_IPRESOLVE_V4 1 /* uses only IPv4 addresses/connections */ #define CURL_IPRESOLVE_V6 2 /* uses only IPv6 addresses/connections */ /* Convenient "aliases" */ #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER /* These enums are for use with the CURLOPT_HTTP_VERSION option. */ enum { CURL_HTTP_VERSION_NONE, /* setting this means we do not care, and that we would like the library to choose the best possible for us! */ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1 Upgrade */ CURL_HTTP_VERSION_3 = 30, /* Use HTTP/3, fallback to HTTP/2 or HTTP/1 if needed. For HTTPS only. For HTTP, this option makes libcurl return error. */ CURL_HTTP_VERSION_3ONLY = 31, /* Use HTTP/3 without fallback. For HTTPS only. For HTTP, this makes libcurl return error. */ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */ }; /* Convenience definition simple because the name of the version is HTTP/2 and not 2.0. The 2_0 version of the enum name was set while the version was still planned to be 2.0 and we stick to it for compatibility. */ #define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0 /* * Public API enums for RTSP requests */ enum { CURL_RTSPREQ_NONE, /* first in list */ CURL_RTSPREQ_OPTIONS, CURL_RTSPREQ_DESCRIBE, CURL_RTSPREQ_ANNOUNCE, CURL_RTSPREQ_SETUP, CURL_RTSPREQ_PLAY, CURL_RTSPREQ_PAUSE, CURL_RTSPREQ_TEARDOWN, CURL_RTSPREQ_GET_PARAMETER, CURL_RTSPREQ_SET_PARAMETER, CURL_RTSPREQ_RECORD, CURL_RTSPREQ_RECEIVE, CURL_RTSPREQ_LAST /* last in list */ }; /* These enums are for use with the CURLOPT_NETRC option. */ enum CURL_NETRC_OPTION { CURL_NETRC_IGNORED, /* The .netrc will never be read. * This is the default. */ CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred * to one in the .netrc. */ CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored. * Unless one is set programmatically, the .netrc * will be queried. */ CURL_NETRC_LAST }; #define CURL_SSLVERSION_DEFAULT 0 #define CURL_SSLVERSION_TLSv1 1 /* TLS 1.x */ #define CURL_SSLVERSION_SSLv2 2 #define CURL_SSLVERSION_SSLv3 3 #define CURL_SSLVERSION_TLSv1_0 4 #define CURL_SSLVERSION_TLSv1_1 5 #define CURL_SSLVERSION_TLSv1_2 6 #define CURL_SSLVERSION_TLSv1_3 7 #define CURL_SSLVERSION_LAST 8 /* never use, keep last */ #define CURL_SSLVERSION_MAX_NONE 0 #define CURL_SSLVERSION_MAX_DEFAULT (CURL_SSLVERSION_TLSv1 << 16) #define CURL_SSLVERSION_MAX_TLSv1_0 (CURL_SSLVERSION_TLSv1_0 << 16) #define CURL_SSLVERSION_MAX_TLSv1_1 (CURL_SSLVERSION_TLSv1_1 << 16) #define CURL_SSLVERSION_MAX_TLSv1_2 (CURL_SSLVERSION_TLSv1_2 << 16) #define CURL_SSLVERSION_MAX_TLSv1_3 (CURL_SSLVERSION_TLSv1_3 << 16) /* never use, keep last */ #define CURL_SSLVERSION_MAX_LAST (CURL_SSLVERSION_LAST << 16) enum CURL_TLSAUTH { CURL_TLSAUTH_NONE, CURL_TLSAUTH_SRP, CURL_TLSAUTH_LAST /* never use, keep last */ }; /* symbols to use with CURLOPT_POSTREDIR. CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303 can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ #define CURL_REDIR_GET_ALL 0 #define CURL_REDIR_POST_301 1 #define CURL_REDIR_POST_302 2 #define CURL_REDIR_POST_303 4 #define CURL_REDIR_POST_ALL \ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) typedef enum { CURL_TIMECOND_NONE, CURL_TIMECOND_IFMODSINCE, CURL_TIMECOND_IFUNMODSINCE, CURL_TIMECOND_LASTMOD, CURL_TIMECOND_LAST } curl_TimeCond; /* Special size_t value signaling a null-terminated string. */ #define CURL_ZERO_TERMINATED ((size_t) -1) /* curl_strequal() and curl_strnequal() are subject for removal in a future release */ CURL_EXTERN int curl_strequal(const char *s1, const char *s2); CURL_EXTERN int curl_strnequal(const char *s1, const char *s2, size_t n); /* Mime/form handling support. */ typedef struct curl_mime curl_mime; /* Mime context. */ typedef struct curl_mimepart curl_mimepart; /* Mime part context. */ /* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */ #define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */ /* * NAME curl_mime_init() * * DESCRIPTION * * Create a mime context and return its handle. The easy parameter is the * target handle. */ CURL_EXTERN curl_mime *curl_mime_init(CURL *easy); /* * NAME curl_mime_free() * * DESCRIPTION * * release a mime handle and its substructures. */ CURL_EXTERN void curl_mime_free(curl_mime *mime); /* * NAME curl_mime_addpart() * * DESCRIPTION * * Append a new empty part to the given mime context and return a handle to * the created part. */ CURL_EXTERN curl_mimepart *curl_mime_addpart(curl_mime *mime); /* * NAME curl_mime_name() * * DESCRIPTION * * Set mime/form part name. */ CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name); /* * NAME curl_mime_filename() * * DESCRIPTION * * Set mime part remote filename. */ CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part, const char *filename); /* * NAME curl_mime_type() * * DESCRIPTION * * Set mime part type. */ CURL_EXTERN CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype); /* * NAME curl_mime_encoder() * * DESCRIPTION * * Set mime data transfer encoder. */ CURL_EXTERN CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding); /* * NAME curl_mime_data() * * DESCRIPTION * * Set mime part data source from memory data, */ CURL_EXTERN CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize); /* * NAME curl_mime_filedata() * * DESCRIPTION * * Set mime part data source from named file. */ CURL_EXTERN CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename); /* * NAME curl_mime_data_cb() * * DESCRIPTION * * Set mime part data source from callback function. */ CURL_EXTERN CURLcode curl_mime_data_cb(curl_mimepart *part, curl_off_t datasize, curl_read_callback readfunc, curl_seek_callback seekfunc, curl_free_callback freefunc, void *arg); /* * NAME curl_mime_subparts() * * DESCRIPTION * * Set mime part data source from subparts. */ CURL_EXTERN CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts); /* * NAME curl_mime_headers() * * DESCRIPTION * * Set mime part headers. */ CURL_EXTERN CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership); typedef enum { /********* the first one is unused ************/ CURLFORM_NOTHING CURL_DEPRECATED(7.56.0, ""), CURLFORM_COPYNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"), CURLFORM_PTRNAME CURL_DEPRECATED(7.56.0, "Use curl_mime_name()"), CURLFORM_NAMELENGTH CURL_DEPRECATED(7.56.0, ""), CURLFORM_COPYCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_PTRCONTENTS CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_CONTENTSLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_FILECONTENT CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"), CURLFORM_ARRAY CURL_DEPRECATED(7.56.0, ""), CURLFORM_OBSOLETE, CURLFORM_FILE CURL_DEPRECATED(7.56.0, "Use curl_mime_filedata()"), CURLFORM_BUFFER CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"), CURLFORM_BUFFERPTR CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_BUFFERLENGTH CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_CONTENTTYPE CURL_DEPRECATED(7.56.0, "Use curl_mime_type()"), CURLFORM_CONTENTHEADER CURL_DEPRECATED(7.56.0, "Use curl_mime_headers()"), CURLFORM_FILENAME CURL_DEPRECATED(7.56.0, "Use curl_mime_filename()"), CURLFORM_END, CURLFORM_OBSOLETE2, CURLFORM_STREAM CURL_DEPRECATED(7.56.0, "Use curl_mime_data_cb()"), CURLFORM_CONTENTLEN /* added in 7.46.0, provide a curl_off_t length */ CURL_DEPRECATED(7.56.0, "Use curl_mime_data()"), CURLFORM_LASTENTRY /* the last unused */ } CURLformoption; /* structure to be used as parameter for CURLFORM_ARRAY */ struct curl_forms { CURLformoption option; const char *value; }; /* use this for multipart formpost building */ /* Returns code for curl_formadd() * * Returns: * CURL_FORMADD_OK on success * CURL_FORMADD_MEMORY if the FormInfo allocation fails * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form * CURL_FORMADD_NULL if a null pointer was given for a char * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error) * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated * CURL_FORMADD_MEMORY if some allocation for string copying failed. * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array * ***************************************************************************/ typedef enum { CURL_FORMADD_OK CURL_DEPRECATED(7.56.0, ""), /* 1st, no error */ CURL_FORMADD_MEMORY CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_OPTION_TWICE CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_NULL CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_UNKNOWN_OPTION CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_INCOMPLETE CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_ILLEGAL_ARRAY CURL_DEPRECATED(7.56.0, ""), /* libcurl was built with form api disabled */ CURL_FORMADD_DISABLED CURL_DEPRECATED(7.56.0, ""), CURL_FORMADD_LAST /* last */ } CURLFORMcode; /* * NAME curl_formadd() * * DESCRIPTION * * Pretty advanced function for building multi-part formposts. Each invoke * adds one part that together construct a full post. Then use * CURLOPT_HTTPPOST to send it off to libcurl. */ CURL_EXTERN CURLFORMcode CURL_DEPRECATED(7.56.0, "Use curl_mime_init()") curl_formadd(struct curl_httppost **httppost, struct curl_httppost **last_post, ...); /* * callback function for curl_formget() * The void *arg pointer will be the one passed as second argument to * curl_formget(). * The character buffer passed to it must not be freed. * Should return the buffer length passed to it as the argument "len" on * success. */ typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len); /* * NAME curl_formget() * * DESCRIPTION * * Serialize a curl_httppost struct built with curl_formadd(). * Accepts a void pointer as second argument which will be passed to * the curl_formget_callback function. * Returns 0 on success. */ CURL_EXTERN int CURL_DEPRECATED(7.56.0, "") curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append); /* * NAME curl_formfree() * * DESCRIPTION * * Free a multipart formpost previously built with curl_formadd(). */ CURL_EXTERN void CURL_DEPRECATED(7.56.0, "Use curl_mime_free()") curl_formfree(struct curl_httppost *form); /* * NAME curl_getenv() * * DESCRIPTION * * Returns a malloc()'ed string that MUST be curl_free()ed after usage is * complete. DEPRECATED - see lib/README.curlx */ CURL_EXTERN char *curl_getenv(const char *variable); /* * NAME curl_version() * * DESCRIPTION * * Returns a static ASCII string of the libcurl version. */ CURL_EXTERN char *curl_version(void); /* * NAME curl_easy_escape() * * DESCRIPTION * * Escapes URL strings (converts all letters consider illegal in URLs to their * %XX versions). This function returns a new allocated string or NULL if an * error occurred. */ CURL_EXTERN char *curl_easy_escape(CURL *handle, const char *string, int length); /* the previous version: */ CURL_EXTERN char *curl_escape(const char *string, int length); /* * NAME curl_easy_unescape() * * DESCRIPTION * * Unescapes URL encoding in strings (converts all %XX codes to their 8bit * versions). This function returns a new allocated string or NULL if an error * occurred. * Conversion Note: On non-ASCII platforms the ASCII %XX codes are * converted into the host encoding. */ CURL_EXTERN char *curl_easy_unescape(CURL *handle, const char *string, int length, int *outlength); /* the previous version */ CURL_EXTERN char *curl_unescape(const char *string, int length); /* * NAME curl_free() * * DESCRIPTION * * Provided for de-allocation in the same translation unit that did the * allocation. Added in libcurl 7.10 */ CURL_EXTERN void curl_free(void *p); /* * NAME curl_global_init() * * DESCRIPTION * * curl_global_init() should be invoked exactly once for each application that * uses libcurl and before any call of other libcurl functions. * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the * curl_version_info_data.features flag (fetch by curl_version_info()). */ CURL_EXTERN CURLcode curl_global_init(long flags); /* * NAME curl_global_init_mem() * * DESCRIPTION * * curl_global_init() or curl_global_init_mem() should be invoked exactly once * for each application that uses libcurl. This function can be used to * initialize libcurl and set user defined memory management callback * functions. Users can implement memory management routines to check for * memory leaks, check for mis-use of the curl library etc. User registered * callback routines will be invoked by this library instead of the system * memory management routines like malloc, free etc. */ CURL_EXTERN CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, curl_free_callback f, curl_realloc_callback r, curl_strdup_callback s, curl_calloc_callback c); /* * NAME curl_global_cleanup() * * DESCRIPTION * * curl_global_cleanup() should be invoked exactly once for each application * that uses libcurl */ CURL_EXTERN void curl_global_cleanup(void); /* * NAME curl_global_trace() * * DESCRIPTION * * curl_global_trace() can be invoked at application start to * configure which components in curl should participate in tracing. * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the * curl_version_info_data.features flag (fetch by curl_version_info()). */ CURL_EXTERN CURLcode curl_global_trace(const char *config); /* linked-list structure for the CURLOPT_QUOTE option (and other) */ struct curl_slist { char *data; struct curl_slist *next; }; /* * NAME curl_global_sslset() * * DESCRIPTION * * When built with multiple SSL backends, curl_global_sslset() allows to * choose one. This function can only be called once, and it must be called * *before* curl_global_init(). * * The backend can be identified by the id (e.g. CURLSSLBACKEND_OPENSSL). The * backend can also be specified via the name parameter (passing -1 as id). * If both id and name are specified, the name will be ignored. If neither id * nor name are specified, the function will fail with * CURLSSLSET_UNKNOWN_BACKEND and set the "avail" pointer to the * NULL-terminated list of available backends. * * Upon success, the function returns CURLSSLSET_OK. * * If the specified SSL backend is not available, the function returns * CURLSSLSET_UNKNOWN_BACKEND and sets the "avail" pointer to a NULL-terminated * list of available SSL backends. * * The SSL backend can be set only once. If it has already been set, a * subsequent attempt to change it will result in a CURLSSLSET_TOO_LATE. */ struct curl_ssl_backend { curl_sslbackend id; const char *name; }; typedef struct curl_ssl_backend curl_ssl_backend; typedef enum { CURLSSLSET_OK = 0, CURLSSLSET_UNKNOWN_BACKEND, CURLSSLSET_TOO_LATE, CURLSSLSET_NO_BACKENDS /* libcurl was built without any SSL support */ } CURLsslset; CURL_EXTERN CURLsslset curl_global_sslset(curl_sslbackend id, const char *name, const curl_ssl_backend ***avail); /* * NAME curl_slist_append() * * DESCRIPTION * * Appends a string to a linked list. If no list exists, it will be created * first. Returns the new list, after appending. */ CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *list, const char *data); /* * NAME curl_slist_free_all() * * DESCRIPTION * * free a previously built curl_slist. */ CURL_EXTERN void curl_slist_free_all(struct curl_slist *list); /* * NAME curl_getdate() * * DESCRIPTION * * Returns the time, in seconds since 1 Jan 1970 of the time string given in * the first argument. The time argument in the second parameter is unused * and should be set to NULL. */ CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); /* info about the certificate chain, for SSL backends that support it. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ struct curl_certinfo { int num_of_certs; /* number of certificates with information */ struct curl_slist **certinfo; /* for each index in this array, there is a linked list with textual information for a certificate in the format "name:content". eg "Subject:foo", "Issuer:bar", etc. */ }; /* Information about the SSL library used and the respective internal SSL handle, which can be used to obtain further information regarding the connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */ struct curl_tlssessioninfo { curl_sslbackend backend; void *internals; }; #define CURLINFO_STRING 0x100000 #define CURLINFO_LONG 0x200000 #define CURLINFO_DOUBLE 0x300000 #define CURLINFO_SLIST 0x400000 #define CURLINFO_PTR 0x400000 /* same as SLIST */ #define CURLINFO_SOCKET 0x500000 #define CURLINFO_OFF_T 0x600000 #define CURLINFO_MASK 0x0fffff #define CURLINFO_TYPEMASK 0xf00000 typedef enum { CURLINFO_NONE, /* first, never use this */ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1, CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2, CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3, CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4, CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5, CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6, CURLINFO_SIZE_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_UPLOAD_T") = CURLINFO_DOUBLE + 7, CURLINFO_SIZE_UPLOAD_T = CURLINFO_OFF_T + 7, CURLINFO_SIZE_DOWNLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SIZE_DOWNLOAD_T") = CURLINFO_DOUBLE + 8, CURLINFO_SIZE_DOWNLOAD_T = CURLINFO_OFF_T + 8, CURLINFO_SPEED_DOWNLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_DOWNLOAD_T") = CURLINFO_DOUBLE + 9, CURLINFO_SPEED_DOWNLOAD_T = CURLINFO_OFF_T + 9, CURLINFO_SPEED_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_SPEED_UPLOAD_T") = CURLINFO_DOUBLE + 10, CURLINFO_SPEED_UPLOAD_T = CURLINFO_OFF_T + 10, CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11, CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12, CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13, CURLINFO_FILETIME = CURLINFO_LONG + 14, CURLINFO_FILETIME_T = CURLINFO_OFF_T + 14, CURLINFO_CONTENT_LENGTH_DOWNLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_CONTENT_LENGTH_DOWNLOAD_T") = CURLINFO_DOUBLE + 15, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T = CURLINFO_OFF_T + 15, CURLINFO_CONTENT_LENGTH_UPLOAD CURL_DEPRECATED(7.55.0, "Use CURLINFO_CONTENT_LENGTH_UPLOAD_T") = CURLINFO_DOUBLE + 16, CURLINFO_CONTENT_LENGTH_UPLOAD_T = CURLINFO_OFF_T + 16, CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19, CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20, CURLINFO_PRIVATE = CURLINFO_STRING + 21, CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22, CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23, CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24, CURLINFO_OS_ERRNO = CURLINFO_LONG + 25, CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26, CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27, CURLINFO_COOKIELIST = CURLINFO_SLIST + 28, CURLINFO_LASTSOCKET CURL_DEPRECATED(7.45.0, "Use CURLINFO_ACTIVESOCKET") = CURLINFO_LONG + 29, CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30, CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31, CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32, CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33, CURLINFO_CERTINFO = CURLINFO_PTR + 34, CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35, CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36, CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37, CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38, CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39, CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40, CURLINFO_LOCAL_IP = CURLINFO_STRING + 41, CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42, CURLINFO_TLS_SESSION CURL_DEPRECATED(7.48.0, "Use CURLINFO_TLS_SSL_PTR") = CURLINFO_PTR + 43, CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45, CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, CURLINFO_PROTOCOL CURL_DEPRECATED(7.85.0, "Use CURLINFO_SCHEME") = CURLINFO_LONG + 48, CURLINFO_SCHEME = CURLINFO_STRING + 49, CURLINFO_TOTAL_TIME_T = CURLINFO_OFF_T + 50, CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51, CURLINFO_CONNECT_TIME_T = CURLINFO_OFF_T + 52, CURLINFO_PRETRANSFER_TIME_T = CURLINFO_OFF_T + 53, CURLINFO_STARTTRANSFER_TIME_T = CURLINFO_OFF_T + 54, CURLINFO_REDIRECT_TIME_T = CURLINFO_OFF_T + 55, CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56, CURLINFO_RETRY_AFTER = CURLINFO_OFF_T + 57, CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58, CURLINFO_PROXY_ERROR = CURLINFO_LONG + 59, CURLINFO_REFERER = CURLINFO_STRING + 60, CURLINFO_CAINFO = CURLINFO_STRING + 61, CURLINFO_CAPATH = CURLINFO_STRING + 62, CURLINFO_XFER_ID = CURLINFO_OFF_T + 63, CURLINFO_CONN_ID = CURLINFO_OFF_T + 64, CURLINFO_QUEUE_TIME_T = CURLINFO_OFF_T + 65, CURLINFO_USED_PROXY = CURLINFO_LONG + 66, CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67, CURLINFO_EARLYDATA_SENT_T = CURLINFO_OFF_T + 68, CURLINFO_LASTONE = 68 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as CURLINFO_HTTP_CODE */ #define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE typedef enum { CURLCLOSEPOLICY_NONE, /* first, never use this */ CURLCLOSEPOLICY_OLDEST, CURLCLOSEPOLICY_LEAST_RECENTLY_USED, CURLCLOSEPOLICY_LEAST_TRAFFIC, CURLCLOSEPOLICY_SLOWEST, CURLCLOSEPOLICY_CALLBACK, CURLCLOSEPOLICY_LAST /* last, never use this */ } curl_closepolicy; #define CURL_GLOBAL_SSL (1<<0) /* no purpose since 7.57.0 */ #define CURL_GLOBAL_WIN32 (1<<1) #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32) #define CURL_GLOBAL_NOTHING 0 #define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL #define CURL_GLOBAL_ACK_EINTR (1<<2) /***************************************************************************** * Setup defines, protos etc for the sharing stuff. */ /* Different data locks for a single share */ typedef enum { CURL_LOCK_DATA_NONE = 0, /* CURL_LOCK_DATA_SHARE is used internally to say that * the locking is just made to change the internal state of the share * itself. */ CURL_LOCK_DATA_SHARE, CURL_LOCK_DATA_COOKIE, CURL_LOCK_DATA_DNS, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_DATA_CONNECT, CURL_LOCK_DATA_PSL, CURL_LOCK_DATA_HSTS, CURL_LOCK_DATA_LAST } curl_lock_data; /* Different lock access types */ typedef enum { CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */ CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */ CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */ CURL_LOCK_ACCESS_LAST /* never use */ } curl_lock_access; typedef void (*curl_lock_function)(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr); typedef void (*curl_unlock_function)(CURL *handle, curl_lock_data data, void *userptr); typedef enum { CURLSHE_OK, /* all is fine */ CURLSHE_BAD_OPTION, /* 1 */ CURLSHE_IN_USE, /* 2 */ CURLSHE_INVALID, /* 3 */ CURLSHE_NOMEM, /* 4 out of memory */ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ CURLSHE_LAST /* never use */ } CURLSHcode; typedef enum { CURLSHOPT_NONE, /* do not use */ CURLSHOPT_SHARE, /* specify a data type to share */ CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */ CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */ CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */ CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock callback functions */ CURLSHOPT_LAST /* never use */ } CURLSHoption; CURL_EXTERN CURLSH *curl_share_init(void); CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *share, CURLSHoption option, ...); CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share); /**************************************************************************** * Structures for querying information about the curl library at runtime. */ typedef enum { CURLVERSION_FIRST, /* 7.10 */ CURLVERSION_SECOND, /* 7.11.1 */ CURLVERSION_THIRD, /* 7.12.0 */ CURLVERSION_FOURTH, /* 7.16.1 */ CURLVERSION_FIFTH, /* 7.57.0 */ CURLVERSION_SIXTH, /* 7.66.0 */ CURLVERSION_SEVENTH, /* 7.70.0 */ CURLVERSION_EIGHTH, /* 7.72.0 */ CURLVERSION_NINTH, /* 7.75.0 */ CURLVERSION_TENTH, /* 7.77.0 */ CURLVERSION_ELEVENTH, /* 7.87.0 */ CURLVERSION_TWELFTH, /* 8.8.0 */ CURLVERSION_LAST /* never actually use this */ } CURLversion; /* The 'CURLVERSION_NOW' is the symbolic name meant to be used by basically all programs ever that want to get version information. It is meant to be a built-in version number for what kind of struct the caller expects. If the struct ever changes, we redefine the NOW to another enum from above. */ #define CURLVERSION_NOW CURLVERSION_TWELFTH struct curl_version_info_data { CURLversion age; /* age of the returned struct */ const char *version; /* LIBCURL_VERSION */ unsigned int version_num; /* LIBCURL_VERSION_NUM */ const char *host; /* OS/host/cpu/machine when configured */ int features; /* bitmask, see defines below */ const char *ssl_version; /* human readable string */ long ssl_version_num; /* not used anymore, always 0 */ const char *libz_version; /* human readable string */ /* protocols is terminated by an entry with a NULL protoname */ const char * const *protocols; /* The fields below this were added in CURLVERSION_SECOND */ const char *ares; int ares_num; /* This field was added in CURLVERSION_THIRD */ const char *libidn; /* These field were added in CURLVERSION_FOURTH */ /* Same as '_libiconv_version' if built with HAVE_ICONV */ int iconv_ver_num; const char *libssh_version; /* human readable string */ /* These fields were added in CURLVERSION_FIFTH */ unsigned int brotli_ver_num; /* Numeric Brotli version (MAJOR << 24) | (MINOR << 12) | PATCH */ const char *brotli_version; /* human readable string. */ /* These fields were added in CURLVERSION_SIXTH */ unsigned int nghttp2_ver_num; /* Numeric nghttp2 version (MAJOR << 16) | (MINOR << 8) | PATCH */ const char *nghttp2_version; /* human readable string. */ const char *quic_version; /* human readable quic (+ HTTP/3) library + version or NULL */ /* These fields were added in CURLVERSION_SEVENTH */ const char *cainfo; /* the built-in default CURLOPT_CAINFO, might be NULL */ const char *capath; /* the built-in default CURLOPT_CAPATH, might be NULL */ /* These fields were added in CURLVERSION_EIGHTH */ unsigned int zstd_ver_num; /* Numeric Zstd version (MAJOR << 24) | (MINOR << 12) | PATCH */ const char *zstd_version; /* human readable string. */ /* These fields were added in CURLVERSION_NINTH */ const char *hyper_version; /* human readable string. */ /* These fields were added in CURLVERSION_TENTH */ const char *gsasl_version; /* human readable string. */ /* These fields were added in CURLVERSION_ELEVENTH */ /* feature_names is terminated by an entry with a NULL feature name */ const char * const *feature_names; /* These fields were added in CURLVERSION_TWELFTH */ const char *rtmp_version; /* human readable string. */ }; typedef struct curl_version_info_data curl_version_info_data; #define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */ #define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported (deprecated) */ #define CURL_VERSION_SSL (1<<2) /* SSL options are present */ #define CURL_VERSION_LIBZ (1<<3) /* libz features are present */ #define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */ #define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported (deprecated) */ #define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */ #define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */ #define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */ #define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */ #define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are supported */ #define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */ #define CURL_VERSION_CONV (1<<12) /* Character conversions supported */ #define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */ #define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */ #define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper is supported */ #define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */ #define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */ #define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */ #define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ #define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used for cookie domain verification */ #define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ #define CURL_VERSION_MULTI_SSL (1<<22) /* Multiple SSL backends available */ #define CURL_VERSION_BROTLI (1<<23) /* Brotli features are present. */ #define CURL_VERSION_ALTSVC (1<<24) /* Alt-Svc handling built-in */ #define CURL_VERSION_HTTP3 (1<<25) /* HTTP3 support built-in */ #define CURL_VERSION_ZSTD (1<<26) /* zstd features are present */ #define CURL_VERSION_UNICODE (1<<27) /* Unicode support on Windows */ #define CURL_VERSION_HSTS (1<<28) /* HSTS is supported */ #define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */ #define CURL_VERSION_THREADSAFE (1<<30) /* libcurl API is thread-safe */ /* * NAME curl_version_info() * * DESCRIPTION * * This function returns a pointer to a static copy of the version info * struct. See above. */ CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion); /* * NAME curl_easy_strerror() * * DESCRIPTION * * The curl_easy_strerror function may be used to turn a CURLcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ CURL_EXTERN const char *curl_easy_strerror(CURLcode); /* * NAME curl_share_strerror() * * DESCRIPTION * * The curl_share_strerror function may be used to turn a CURLSHcode value * into the equivalent human readable error string. This is useful * for printing meaningful error messages. */ CURL_EXTERN const char *curl_share_strerror(CURLSHcode); /* * NAME curl_easy_pause() * * DESCRIPTION * * The curl_easy_pause function pauses or unpauses transfers. Select the new * state by setting the bitmask, use the convenience defines below. * */ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask); #define CURLPAUSE_RECV (1<<0) #define CURLPAUSE_RECV_CONT (0) #define CURLPAUSE_SEND (1<<2) #define CURLPAUSE_SEND_CONT (0) #define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND) #define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT) #ifdef __cplusplus } /* end of extern "C" */ #endif /* unfortunately, the easy.h and multi.h include files need options and info stuff before they can be included! */ /* nothing in curl is fun without the easy stuff */ #ifndef CURLINC_EASY_H #define CURLINC_EASY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* Flag bits in the curl_blob struct: */ #define CURL_BLOB_COPY 1 /* tell libcurl to copy the data */ #define CURL_BLOB_NOCOPY 0 /* tell libcurl to NOT copy the data */ struct curl_blob { void *data; size_t len; unsigned int flags; /* bit 0 is defined, the rest are reserved and should be left zeroes */ }; CURL_EXTERN CURL *curl_easy_init(void); CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); CURL_EXTERN CURLcode curl_easy_perform(CURL *curl); CURL_EXTERN void curl_easy_cleanup(CURL *curl); /* * NAME curl_easy_getinfo() * * DESCRIPTION * * Request internal information from the curl session with this function. * The third argument MUST be pointing to the specific type of the used option * which is documented in each manpage of the option. The data pointed to * will be filled in accordingly and can be relied upon only if the function * returns CURLE_OK. This function is intended to get used *AFTER* a performed * transfer, all results from this function are undefined until the transfer * is completed. */ CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); /* * NAME curl_easy_duphandle() * * DESCRIPTION * * Creates a new curl session handle with the same options set for the handle * passed in. Duplicating a handle could only be a matter of cloning data and * options, internal state info and things like persistent connections cannot * be transferred. It is useful in multithreaded applications when you can run * curl_easy_duphandle() for each new thread to avoid a series of identical * curl_easy_setopt() invokes in every thread. */ CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); /* * NAME curl_easy_reset() * * DESCRIPTION * * Re-initializes a CURL handle to the default values. This puts back the * handle to the same state as it was in when it was just created. * * It does keep: live connections, the Session ID cache, the DNS cache and the * cookies. */ CURL_EXTERN void curl_easy_reset(CURL *curl); /* * NAME curl_easy_recv() * * DESCRIPTION * * Receives data from the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n); /* * NAME curl_easy_send() * * DESCRIPTION * * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, size_t *n); /* * NAME curl_easy_upkeep() * * DESCRIPTION * * Performs connection upkeep for the given session handle. */ CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif #ifndef CURLINC_MULTI_H #define CURLINC_MULTI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* This is an "external" header file. Do not give away any internals here! GOALS o Enable a "pull" interface. The application that uses libcurl decides where and when to ask libcurl to get/send data. o Enable multiple simultaneous transfers in the same thread without making it complicated for the application. o Enable the application to select() on its own file descriptors and curl's file descriptors simultaneous easily. */ /* * This header file should not really need to include "curl.h" since curl.h * itself includes this file and we expect user applications to do #include * without the need for especially including multi.h. * * For some reason we added this include here at one point, and rather than to * break existing (wrongly written) libcurl applications, we leave it as-is * but with this warning attached. */ #ifdef __cplusplus extern "C" { #endif typedef void CURLM; typedef enum { CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or curl_multi_socket*() soon */ CURLM_OK, CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */ CURLM_OUT_OF_MEMORY, /* if you ever get this, you are in deep sh*t */ CURLM_INTERNAL_ERROR, /* this is a libcurl bug */ CURLM_BAD_SOCKET, /* the passed in socket argument did not match */ CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */ CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was attempted to get added - again */ CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a callback */ CURLM_WAKEUP_FAILURE, /* wakeup is unavailable or failed */ CURLM_BAD_FUNCTION_ARGUMENT, /* function called with a bad parameter */ CURLM_ABORTED_BY_CALLBACK, CURLM_UNRECOVERABLE_POLL, CURLM_LAST } CURLMcode; /* just to make code nicer when using curl_multi_socket() you can now check for CURLM_CALL_MULTI_SOCKET too in the same style it works for curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */ #define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM /* bitmask bits for CURLMOPT_PIPELINING */ #define CURLPIPE_NOTHING 0L #define CURLPIPE_HTTP1 1L #define CURLPIPE_MULTIPLEX 2L typedef enum { CURLMSG_NONE, /* first, not used */ CURLMSG_DONE, /* This easy handle has completed. 'result' contains the CURLcode of the transfer */ CURLMSG_LAST /* last, not used */ } CURLMSG; struct CURLMsg { CURLMSG msg; /* what this message means */ CURL *easy_handle; /* the handle it concerns */ union { void *whatever; /* message-specific data */ CURLcode result; /* return code for transfer */ } data; }; typedef struct CURLMsg CURLMsg; /* Based on poll(2) structure and values. * We do not use pollfd and POLL* constants explicitly * to cover platforms without poll(). */ #define CURL_WAIT_POLLIN 0x0001 #define CURL_WAIT_POLLPRI 0x0002 #define CURL_WAIT_POLLOUT 0x0004 struct curl_waitfd { curl_socket_t fd; short events; short revents; }; /* * Name: curl_multi_init() * * Desc: initialize multi-style curl usage * * Returns: a new CURLM handle to use in all 'curl_multi' functions. */ CURL_EXTERN CURLM *curl_multi_init(void); /* * Name: curl_multi_add_handle() * * Desc: add a standard curl handle to the multi stack * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *curl_handle); /* * Name: curl_multi_remove_handle() * * Desc: removes a curl handle from the multi stack again * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *curl_handle); /* * Name: curl_multi_fdset() * * Desc: Ask curl for its fd_set sets. The app can use these to select() or * poll() on. We want curl_multi_perform() called as soon as one of * them are ready. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd); /* * Name: curl_multi_wait() * * Desc: Poll on all fds within a CURLM set as well as any * additional fds passed to the function. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret); /* * Name: curl_multi_poll() * * Desc: Poll on all fds within a CURLM set as well as any * additional fds passed to the function. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_poll(CURLM *multi_handle, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret); /* * Name: curl_multi_wakeup() * * Desc: wakes up a sleeping curl_multi_poll call. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle); /* * Name: curl_multi_perform() * * Desc: When the app thinks there is data available for curl it calls this * function to read/write whatever there is right now. This returns * as soon as the reads and writes are done. This function does not * require that there actually is data available for reading or that * data can be written, it can be called just in case. It returns * the number of handles that still transfer data in the second * argument's integer-pointer. * * Returns: CURLMcode type, general multi error code. *NOTE* that this only * returns errors etc regarding the whole multi stack. There might * still have occurred problems on individual transfers even when * this returns OK. */ CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles); /* * Name: curl_multi_cleanup() * * Desc: Cleans up and removes a whole multi stack. It does not free or * touch any individual easy handles in any way. We need to define * in what state those handles will be if this function is called * in the middle of a transfer. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle); /* * Name: curl_multi_info_read() * * Desc: Ask the multi handle if there is any messages/informationals from * the individual transfers. Messages include informationals such as * error code from the transfer or just the fact that a transfer is * completed. More details on these should be written down as well. * * Repeated calls to this function will return a new struct each * time, until a special "end of msgs" struct is returned as a signal * that there is no more to get at this point. * * The data the returned pointer points to will not survive calling * curl_multi_cleanup(). * * The 'CURLMsg' struct is meant to be simple and only contain basic * information. If more involved information is wanted, we will * provide the particular "transfer handle" in that struct and that * should/could/would be used in subsequent curl_easy_getinfo() calls * (or similar). The point being that we must never expose complex * structs to applications, as then we will undoubtably get backwards * compatibility problems in the future. * * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out * of structs. It also writes the number of messages left in the * queue (after this read) in the integer the second argument points * to. */ CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue); /* * Name: curl_multi_strerror() * * Desc: The curl_multi_strerror function may be used to turn a CURLMcode * value into the equivalent human readable error string. This is * useful for printing meaningful error messages. * * Returns: A pointer to a null-terminated error message. */ CURL_EXTERN const char *curl_multi_strerror(CURLMcode); /* * Name: curl_multi_socket() and * curl_multi_socket_all() * * Desc: An alternative version of curl_multi_perform() that allows the * application to pass in one of the file descriptors that have been * detected to have "action" on them and let libcurl perform. * See manpage for details. */ #define CURL_POLL_NONE 0 #define CURL_POLL_IN 1 #define CURL_POLL_OUT 2 #define CURL_POLL_INOUT 3 #define CURL_POLL_REMOVE 4 #define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD #define CURL_CSELECT_IN 0x01 #define CURL_CSELECT_OUT 0x02 #define CURL_CSELECT_ERR 0x04 typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ void *userp, /* private callback pointer */ void *socketp); /* private socket pointer */ /* * Name: curl_multi_timer_callback * * Desc: Called by libcurl whenever the library detects a change in the * maximum number of milliseconds the app is allowed to wait before * curl_multi_socket() or curl_multi_perform() must be called * (to allow libcurl's timed events to take place). * * Returns: The callback should return zero. */ typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp); /* private callback pointer */ CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()") curl_multi_socket(CURLM *multi_handle, curl_socket_t s, int *running_handles); CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, int ev_bitmask, int *running_handles); CURL_EXTERN CURLMcode CURL_DEPRECATED(7.19.5, "Use curl_multi_socket_action()") curl_multi_socket_all(CURLM *multi_handle, int *running_handles); #ifndef CURL_ALLOW_OLD_MULTI_SOCKET /* This macro below was added in 7.16.3 to push users who recompile to use the new curl_multi_socket_action() instead of the old curl_multi_socket() */ #define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z) #endif /* * Name: curl_multi_timeout() * * Desc: Returns the maximum number of milliseconds the app is allowed to * wait before curl_multi_socket() or curl_multi_perform() must be * called (to allow libcurl's timed events to take place). * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle, long *milliseconds); typedef enum { /* This is the socket callback function pointer */ CURLOPT(CURLMOPT_SOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 1), /* This is the argument passed to the socket callback */ CURLOPT(CURLMOPT_SOCKETDATA, CURLOPTTYPE_OBJECTPOINT, 2), /* set to 1 to enable pipelining for this multi handle */ CURLOPT(CURLMOPT_PIPELINING, CURLOPTTYPE_LONG, 3), /* This is the timer callback function pointer */ CURLOPT(CURLMOPT_TIMERFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 4), /* This is the argument passed to the timer callback */ CURLOPT(CURLMOPT_TIMERDATA, CURLOPTTYPE_OBJECTPOINT, 5), /* maximum number of entries in the connection cache */ CURLOPT(CURLMOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 6), /* maximum number of (pipelining) connections to one host */ CURLOPT(CURLMOPT_MAX_HOST_CONNECTIONS, CURLOPTTYPE_LONG, 7), /* maximum number of requests in a pipeline */ CURLOPT(CURLMOPT_MAX_PIPELINE_LENGTH, CURLOPTTYPE_LONG, 8), /* a connection with a content-length longer than this will not be considered for pipelining */ CURLOPT(CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 9), /* a connection with a chunk length longer than this will not be considered for pipelining */ CURLOPT(CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLOPTTYPE_OFF_T, 10), /* a list of site names(+port) that are blocked from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SITE_BL, CURLOPTTYPE_OBJECTPOINT, 11), /* a list of server types that are blocked from pipelining */ CURLOPT(CURLMOPT_PIPELINING_SERVER_BL, CURLOPTTYPE_OBJECTPOINT, 12), /* maximum number of open connections in total */ CURLOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, CURLOPTTYPE_LONG, 13), /* This is the server push callback function pointer */ CURLOPT(CURLMOPT_PUSHFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 14), /* This is the argument passed to the server push callback */ CURLOPT(CURLMOPT_PUSHDATA, CURLOPTTYPE_OBJECTPOINT, 15), /* maximum number of concurrent streams to support on a connection */ CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; /* * Name: curl_multi_setopt() * * Desc: Sets options for the multi handle. * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle, CURLMoption option, ...); /* * Name: curl_multi_assign() * * Desc: This function sets an association in the multi handle between the * given socket and a private pointer of the application. This is * (only) useful for curl_multi_socket uses. * * Returns: CURLM error code. */ CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd, void *sockp); /* * Name: curl_multi_get_handles() * * Desc: Returns an allocated array holding all handles currently added to * the multi handle. Marks the final entry with a NULL pointer. If * there is no easy handle added to the multi handle, this function * returns an array with the first entry as a NULL pointer. * * Returns: NULL on failure, otherwise a CURL **array pointer */ CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle); /* * Name: curl_push_callback * * Desc: This callback gets called when a new stream is being pushed by the * server. It approves or denies the new stream. It can also decide * to completely fail the connection. * * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT */ #define CURL_PUSH_OK 0 #define CURL_PUSH_DENY 1 #define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */ struct curl_pushheaders; /* forward declaration only */ CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num); CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h, const char *name); typedef int (*curl_push_callback)(CURL *parent, CURL *easy, size_t num_headers, struct curl_pushheaders *headers, void *userp); /* * Name: curl_multi_waitfds() * * Desc: Ask curl for fds for polling. The app can use these to poll on. * We want curl_multi_perform() called as soon as one of them are * ready. Passing zero size allows to get just a number of fds. * * Returns: CURLMcode type, general multi error code. */ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi, struct curl_waitfd *ufds, unsigned int size, unsigned int *fd_count); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif #ifndef CURLINC_URLAPI_H #define CURLINC_URLAPI_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif /* the error codes for the URL API */ typedef enum { CURLUE_OK, CURLUE_BAD_HANDLE, /* 1 */ CURLUE_BAD_PARTPOINTER, /* 2 */ CURLUE_MALFORMED_INPUT, /* 3 */ CURLUE_BAD_PORT_NUMBER, /* 4 */ CURLUE_UNSUPPORTED_SCHEME, /* 5 */ CURLUE_URLDECODE, /* 6 */ CURLUE_OUT_OF_MEMORY, /* 7 */ CURLUE_USER_NOT_ALLOWED, /* 8 */ CURLUE_UNKNOWN_PART, /* 9 */ CURLUE_NO_SCHEME, /* 10 */ CURLUE_NO_USER, /* 11 */ CURLUE_NO_PASSWORD, /* 12 */ CURLUE_NO_OPTIONS, /* 13 */ CURLUE_NO_HOST, /* 14 */ CURLUE_NO_PORT, /* 15 */ CURLUE_NO_QUERY, /* 16 */ CURLUE_NO_FRAGMENT, /* 17 */ CURLUE_NO_ZONEID, /* 18 */ CURLUE_BAD_FILE_URL, /* 19 */ CURLUE_BAD_FRAGMENT, /* 20 */ CURLUE_BAD_HOSTNAME, /* 21 */ CURLUE_BAD_IPV6, /* 22 */ CURLUE_BAD_LOGIN, /* 23 */ CURLUE_BAD_PASSWORD, /* 24 */ CURLUE_BAD_PATH, /* 25 */ CURLUE_BAD_QUERY, /* 26 */ CURLUE_BAD_SCHEME, /* 27 */ CURLUE_BAD_SLASHES, /* 28 */ CURLUE_BAD_USER, /* 29 */ CURLUE_LACKS_IDN, /* 30 */ CURLUE_TOO_LARGE, /* 31 */ CURLUE_LAST } CURLUcode; typedef enum { CURLUPART_URL, CURLUPART_SCHEME, CURLUPART_USER, CURLUPART_PASSWORD, CURLUPART_OPTIONS, CURLUPART_HOST, CURLUPART_PORT, CURLUPART_PATH, CURLUPART_QUERY, CURLUPART_FRAGMENT, CURLUPART_ZONEID /* added in 7.65.0 */ } CURLUPart; #define CURLU_DEFAULT_PORT (1<<0) /* return default port number */ #define CURLU_NO_DEFAULT_PORT (1<<1) /* act as if no port number was set, if the port number matches the default for the scheme */ #define CURLU_DEFAULT_SCHEME (1<<2) /* return default scheme if missing */ #define CURLU_NON_SUPPORT_SCHEME (1<<3) /* allow non-supported scheme */ #define CURLU_PATH_AS_IS (1<<4) /* leave dot sequences */ #define CURLU_DISALLOW_USER (1<<5) /* no user+password allowed */ #define CURLU_URLDECODE (1<<6) /* URL decode on get */ #define CURLU_URLENCODE (1<<7) /* URL encode on set */ #define CURLU_APPENDQUERY (1<<8) /* append a form style part */ #define CURLU_GUESS_SCHEME (1<<9) /* legacy curl-style guessing */ #define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the scheme is unknown. */ #define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */ #define CURLU_PUNYCODE (1<<12) /* get the hostname in punycode */ #define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */ #define CURLU_GET_EMPTY (1<<14) /* allow empty queries and fragments when extracting the URL or the components */ #define CURLU_NO_GUESS_SCHEME (1<<15) /* for get, do not accept a guess */ typedef struct Curl_URL CURLU; /* * curl_url() creates a new CURLU handle and returns a pointer to it. * Must be freed with curl_url_cleanup(). */ CURL_EXTERN CURLU *curl_url(void); /* * curl_url_cleanup() frees the CURLU handle and related resources used for * the URL parsing. It will not free strings previously returned with the URL * API. */ CURL_EXTERN void curl_url_cleanup(CURLU *handle); /* * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new * handle must also be freed with curl_url_cleanup(). */ CURL_EXTERN CURLU *curl_url_dup(const CURLU *in); /* * curl_url_get() extracts a specific part of the URL from a CURLU * handle. Returns error code. The returned pointer MUST be freed with * curl_free() afterwards. */ CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what, char **part, unsigned int flags); /* * curl_url_set() sets a specific part of the URL in a CURLU handle. Returns * error code. The passed in string will be copied. Passing a NULL instead of * a part string, clears that part. */ CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what, const char *part, unsigned int flags); /* * curl_url_strerror() turns a CURLUcode value into the equivalent human * readable error string. This is useful for printing meaningful error * messages. */ CURL_EXTERN const char *curl_url_strerror(CURLUcode); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif /* CURLINC_URLAPI_H */ #ifndef CURLINC_OPTIONS_H #define CURLINC_OPTIONS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif typedef enum { CURLOT_LONG, /* long (a range of values) */ CURLOT_VALUES, /* (a defined set or bitmask) */ CURLOT_OFF_T, /* curl_off_t (a range of values) */ CURLOT_OBJECT, /* pointer (void *) */ CURLOT_STRING, /* (char * to null-terminated buffer) */ CURLOT_SLIST, /* (struct curl_slist *) */ CURLOT_CBPTR, /* (void * passed as-is to a callback) */ CURLOT_BLOB, /* blob (struct curl_blob *) */ CURLOT_FUNCTION /* function pointer */ } curl_easytype; /* Flag bits */ /* "alias" means it is provided for old programs to remain functional, we prefer another name */ #define CURLOT_FLAG_ALIAS (1<<0) /* The CURLOPTTYPE_* id ranges can still be used to figure out what type/size to use for curl_easy_setopt() for the given id */ struct curl_easyoption { const char *name; CURLoption id; curl_easytype type; unsigned int flags; }; CURL_EXTERN const struct curl_easyoption * curl_easy_option_by_name(const char *name); CURL_EXTERN const struct curl_easyoption * curl_easy_option_by_id(CURLoption id); CURL_EXTERN const struct curl_easyoption * curl_easy_option_next(const struct curl_easyoption *prev); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif /* CURLINC_OPTIONS_H */ #ifndef CURLINC_HEADER_H #define CURLINC_HEADER_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif struct curl_header { char *name; /* this might not use the same case */ char *value; size_t amount; /* number of headers using this name */ size_t index; /* ... of this instance, 0 or higher */ unsigned int origin; /* see bits below */ void *anchor; /* handle privately used by libcurl */ }; /* 'origin' bits */ #define CURLH_HEADER (1<<0) /* plain server header */ #define CURLH_TRAILER (1<<1) /* trailers */ #define CURLH_CONNECT (1<<2) /* CONNECT headers */ #define CURLH_1XX (1<<3) /* 1xx headers */ #define CURLH_PSEUDO (1<<4) /* pseudo headers */ typedef enum { CURLHE_OK, CURLHE_BADINDEX, /* header exists but not with this index */ CURLHE_MISSING, /* no such header exists */ CURLHE_NOHEADERS, /* no headers at all exist (yet) */ CURLHE_NOREQUEST, /* no request with this number was used */ CURLHE_OUT_OF_MEMORY, /* out of memory while processing */ CURLHE_BAD_ARGUMENT, /* a function argument was not okay */ CURLHE_NOT_BUILT_IN /* if API was disabled in the build */ } CURLHcode; CURL_EXTERN CURLHcode curl_easy_header(CURL *easy, const char *name, size_t index, unsigned int origin, int request, struct curl_header **hout); CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy, unsigned int origin, int request, struct curl_header *prev); #ifdef __cplusplus } /* end of extern "C" */ #endif #endif /* CURLINC_HEADER_H */ #ifndef CURLINC_WEBSOCKETS_H #define CURLINC_WEBSOCKETS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #ifdef __cplusplus extern "C" { #endif struct curl_ws_frame { int age; /* zero */ int flags; /* See the CURLWS_* defines */ curl_off_t offset; /* the offset of this data into the frame */ curl_off_t bytesleft; /* number of pending bytes left of the payload */ size_t len; /* size of the current data chunk */ }; /* flag bits */ #define CURLWS_TEXT (1<<0) #define CURLWS_BINARY (1<<1) #define CURLWS_CONT (1<<2) #define CURLWS_CLOSE (1<<3) #define CURLWS_PING (1<<4) #define CURLWS_OFFSET (1<<5) /* * NAME curl_ws_recv() * * DESCRIPTION * * Receives data from the websocket connection. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen, size_t *recv, const struct curl_ws_frame **metap); /* flags for curl_ws_send() */ #define CURLWS_PONG (1<<6) /* * NAME curl_ws_send() * * DESCRIPTION * * Sends data over the websocket connection. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, size_t buflen, size_t *sent, curl_off_t fragsize, unsigned int flags); /* bits for the CURLOPT_WS_OPTIONS bitmask: */ #define CURLWS_RAW_MODE (1<<0) CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl); #ifdef __cplusplus } #endif #endif /* CURLINC_WEBSOCKETS_H */ #ifndef CURL_SKIP_INCLUDE_MPRINTF #ifndef CURLINC_MPRINTF_H #define CURLINC_MPRINTF_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ #include #include /* needed for FILE */ #ifdef __cplusplus extern "C" { #endif #ifndef CURL_TEMP_PRINTF #if (defined(__GNUC__) || defined(__clang__) || \ defined(__IAR_SYSTEMS_ICC__)) && \ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ !defined(CURL_NO_FMT_CHECKS) #if defined(__MINGW32__) && !defined(__clang__) #if defined(__MINGW_PRINTF_FORMAT) /* mingw-w64 3.0.0+. Needs stdio.h. */ #define CURL_TEMP_PRINTF(fmt, arg) \ __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg))) #else #define CURL_TEMP_PRINTF(fmt, arg) #endif #else #define CURL_TEMP_PRINTF(fmt, arg) \ __attribute__((format(printf, fmt, arg))) #endif #else #define CURL_TEMP_PRINTF(fmt, arg) #endif #endif CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2); CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...) CURL_TEMP_PRINTF(2, 3); CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...) CURL_TEMP_PRINTF(2, 3); CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...) CURL_TEMP_PRINTF(3, 4); CURL_EXTERN int curl_mvprintf(const char *format, va_list args) CURL_TEMP_PRINTF(1, 0); CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args) CURL_TEMP_PRINTF(2, 0); CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args) CURL_TEMP_PRINTF(2, 0); CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args) CURL_TEMP_PRINTF(3, 0); CURL_EXTERN char *curl_maprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2); CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args) CURL_TEMP_PRINTF(1, 0); #undef CURL_TEMP_PRINTF #ifdef __cplusplus } /* end of extern "C" */ #endif #endif /* CURLINC_MPRINTF_H */ #endif /* the typechecker does not work in C++ (yet) */ #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) #ifndef CURLINC_TYPECHECK_GCC_H #define CURLINC_TYPECHECK_GCC_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* wraps curl_easy_setopt() with typechecking */ /* To add a new kind of warning, add an * if(curlcheck_sometype_option(_curl_opt)) * if(!curlcheck_sometype(value)) * _curl_easy_setopt_err_sometype(); * block and define curlcheck_sometype_option, curlcheck_sometype and * _curl_easy_setopt_err_sometype below * * NOTE: We use two nested 'if' statements here instead of the && operator, in * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x * when compiling with -Wlogical-op. * * To add an option that uses the same type as an existing option, you will * just need to extend the appropriate _curl_*_option macro */ #define curl_easy_setopt(handle, option, value) \ __extension__({ \ CURLoption _curl_opt = (option); \ if(__builtin_constant_p(_curl_opt)) { \ CURL_IGNORE_DEPRECATION( \ if(curlcheck_long_option(_curl_opt)) \ if(!curlcheck_long(value)) \ _curl_easy_setopt_err_long(); \ if(curlcheck_off_t_option(_curl_opt)) \ if(!curlcheck_off_t(value)) \ _curl_easy_setopt_err_curl_off_t(); \ if(curlcheck_string_option(_curl_opt)) \ if(!curlcheck_string(value)) \ _curl_easy_setopt_err_string(); \ if(curlcheck_write_cb_option(_curl_opt)) \ if(!curlcheck_write_cb(value)) \ _curl_easy_setopt_err_write_callback(); \ if((_curl_opt) == CURLOPT_RESOLVER_START_FUNCTION) \ if(!curlcheck_resolver_start_callback(value)) \ _curl_easy_setopt_err_resolver_start_callback(); \ if((_curl_opt) == CURLOPT_READFUNCTION) \ if(!curlcheck_read_cb(value)) \ _curl_easy_setopt_err_read_cb(); \ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \ if(!curlcheck_ioctl_cb(value)) \ _curl_easy_setopt_err_ioctl_cb(); \ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \ if(!curlcheck_sockopt_cb(value)) \ _curl_easy_setopt_err_sockopt_cb(); \ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \ if(!curlcheck_opensocket_cb(value)) \ _curl_easy_setopt_err_opensocket_cb(); \ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \ if(!curlcheck_progress_cb(value)) \ _curl_easy_setopt_err_progress_cb(); \ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \ if(!curlcheck_debug_cb(value)) \ _curl_easy_setopt_err_debug_cb(); \ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \ if(!curlcheck_ssl_ctx_cb(value)) \ _curl_easy_setopt_err_ssl_ctx_cb(); \ if(curlcheck_conv_cb_option(_curl_opt)) \ if(!curlcheck_conv_cb(value)) \ _curl_easy_setopt_err_conv_cb(); \ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \ if(!curlcheck_seek_cb(value)) \ _curl_easy_setopt_err_seek_cb(); \ if(curlcheck_cb_data_option(_curl_opt)) \ if(!curlcheck_cb_data(value)) \ _curl_easy_setopt_err_cb_data(); \ if((_curl_opt) == CURLOPT_ERRORBUFFER) \ if(!curlcheck_error_buffer(value)) \ _curl_easy_setopt_err_error_buffer(); \ if((_curl_opt) == CURLOPT_STDERR) \ if(!curlcheck_FILE(value)) \ _curl_easy_setopt_err_FILE(); \ if(curlcheck_postfields_option(_curl_opt)) \ if(!curlcheck_postfields(value)) \ _curl_easy_setopt_err_postfields(); \ if((_curl_opt) == CURLOPT_HTTPPOST) \ if(!curlcheck_arr((value), struct curl_httppost)) \ _curl_easy_setopt_err_curl_httpost(); \ if((_curl_opt) == CURLOPT_MIMEPOST) \ if(!curlcheck_ptr((value), curl_mime)) \ _curl_easy_setopt_err_curl_mimepost(); \ if(curlcheck_slist_option(_curl_opt)) \ if(!curlcheck_arr((value), struct curl_slist)) \ _curl_easy_setopt_err_curl_slist(); \ if((_curl_opt) == CURLOPT_SHARE) \ if(!curlcheck_ptr((value), CURLSH)) \ _curl_easy_setopt_err_CURLSH(); \ ) \ } \ curl_easy_setopt(handle, _curl_opt, value); \ }) /* wraps curl_easy_getinfo() with typechecking */ #define curl_easy_getinfo(handle, info, arg) \ __extension__({ \ CURLINFO _curl_info = (info); \ if(__builtin_constant_p(_curl_info)) { \ CURL_IGNORE_DEPRECATION( \ if(curlcheck_string_info(_curl_info)) \ if(!curlcheck_arr((arg), char *)) \ _curl_easy_getinfo_err_string(); \ if(curlcheck_long_info(_curl_info)) \ if(!curlcheck_arr((arg), long)) \ _curl_easy_getinfo_err_long(); \ if(curlcheck_double_info(_curl_info)) \ if(!curlcheck_arr((arg), double)) \ _curl_easy_getinfo_err_double(); \ if(curlcheck_slist_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_slist *)) \ _curl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ _curl_easy_getinfo_err_curl_tlssesssioninfo(); \ if(curlcheck_certinfo_info(_curl_info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ _curl_easy_getinfo_err_curl_certinfo(); \ if(curlcheck_socket_info(_curl_info)) \ if(!curlcheck_arr((arg), curl_socket_t)) \ _curl_easy_getinfo_err_curl_socket(); \ if(curlcheck_off_t_info(_curl_info)) \ if(!curlcheck_arr((arg), curl_off_t)) \ _curl_easy_getinfo_err_curl_off_t(); \ ) \ } \ curl_easy_getinfo(handle, _curl_info, arg); \ }) /* * For now, just make sure that the functions are called with three arguments */ #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) /* the actual warnings, triggered by calling the _curl_easy_setopt_err* * functions */ /* To define a new warning, use _CURL_WARNING(identifier, "message") */ #define CURLWARNING(id, message) \ static void __attribute__((__warning__(message))) \ __attribute__((__unused__)) __attribute__((__noinline__)) \ id(void) { __asm__(""); } CURLWARNING(_curl_easy_setopt_err_long, "curl_easy_setopt expects a long argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument for this option") CURLWARNING(_curl_easy_setopt_err_string, "curl_easy_setopt expects a " "string ('char *' or char[]) argument for this option" ) CURLWARNING(_curl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_resolver_start_callback, "curl_easy_setopt expects a " "curl_resolver_start_callback argument for this option" ) CURLWARNING(_curl_easy_setopt_err_read_cb, "curl_easy_setopt expects a curl_read_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_ioctl_cb, "curl_easy_setopt expects a curl_ioctl_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_sockopt_cb, "curl_easy_setopt expects a curl_sockopt_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_opensocket_cb, "curl_easy_setopt expects a " "curl_opensocket_callback argument for this option" ) CURLWARNING(_curl_easy_setopt_err_progress_cb, "curl_easy_setopt expects a curl_progress_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_debug_cb, "curl_easy_setopt expects a curl_debug_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_ssl_ctx_cb, "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_conv_cb, "curl_easy_setopt expects a curl_conv_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_seek_cb, "curl_easy_setopt expects a curl_seek_callback argument for this option") CURLWARNING(_curl_easy_setopt_err_cb_data, "curl_easy_setopt expects a " "private data pointer as argument for this option") CURLWARNING(_curl_easy_setopt_err_error_buffer, "curl_easy_setopt expects a " "char buffer of CURL_ERROR_SIZE as argument for this option") CURLWARNING(_curl_easy_setopt_err_FILE, "curl_easy_setopt expects a 'FILE *' argument for this option") CURLWARNING(_curl_easy_setopt_err_postfields, "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_httpost, "curl_easy_setopt expects a 'struct curl_httppost *' " "argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_mimepost, "curl_easy_setopt expects a 'curl_mime *' " "argument for this option") CURLWARNING(_curl_easy_setopt_err_curl_slist, "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") CURLWARNING(_curl_easy_setopt_err_CURLSH, "curl_easy_setopt expects a CURLSH* argument for this option") CURLWARNING(_curl_easy_getinfo_err_string, "curl_easy_getinfo expects a pointer to 'char *' for this info") CURLWARNING(_curl_easy_getinfo_err_long, "curl_easy_getinfo expects a pointer to long for this info") CURLWARNING(_curl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double for this info") CURLWARNING(_curl_easy_getinfo_err_curl_slist, "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo, "curl_easy_getinfo expects a pointer to " "'struct curl_tlssessioninfo *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_certinfo, "curl_easy_getinfo expects a pointer to " "'struct curl_certinfo *' for this info") CURLWARNING(_curl_easy_getinfo_err_curl_socket, "curl_easy_getinfo expects a pointer to curl_socket_t for this info") CURLWARNING(_curl_easy_getinfo_err_curl_off_t, "curl_easy_getinfo expects a pointer to curl_off_t for this info") /* groups of curl_easy_setops options that take the same type of argument */ /* To add a new option to one of the groups, just add * (option) == CURLOPT_SOMETHING * to the or-expression. If the option takes a long or curl_off_t, you do not * have to do anything */ /* evaluates to true if option takes a long argument */ #define curlcheck_long_option(option) \ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT) #define curlcheck_off_t_option(option) \ (((option) > CURLOPTTYPE_OFF_T) && ((option) < CURLOPTTYPE_BLOB)) /* evaluates to true if option takes a char* argument */ #define curlcheck_string_option(option) \ ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ (option) == CURLOPT_ACCEPT_ENCODING || \ (option) == CURLOPT_ALTSVC || \ (option) == CURLOPT_CAINFO || \ (option) == CURLOPT_CAPATH || \ (option) == CURLOPT_COOKIE || \ (option) == CURLOPT_COOKIEFILE || \ (option) == CURLOPT_COOKIEJAR || \ (option) == CURLOPT_COOKIELIST || \ (option) == CURLOPT_CRLFILE || \ (option) == CURLOPT_CUSTOMREQUEST || \ (option) == CURLOPT_DEFAULT_PROTOCOL || \ (option) == CURLOPT_DNS_INTERFACE || \ (option) == CURLOPT_DNS_LOCAL_IP4 || \ (option) == CURLOPT_DNS_LOCAL_IP6 || \ (option) == CURLOPT_DNS_SERVERS || \ (option) == CURLOPT_DOH_URL || \ (option) == CURLOPT_ECH || \ (option) == CURLOPT_EGDSOCKET || \ (option) == CURLOPT_FTP_ACCOUNT || \ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \ (option) == CURLOPT_FTPPORT || \ (option) == CURLOPT_HSTS || \ (option) == CURLOPT_HAPROXY_CLIENT_IP || \ (option) == CURLOPT_INTERFACE || \ (option) == CURLOPT_ISSUERCERT || \ (option) == CURLOPT_KEYPASSWD || \ (option) == CURLOPT_KRBLEVEL || \ (option) == CURLOPT_LOGIN_OPTIONS || \ (option) == CURLOPT_MAIL_AUTH || \ (option) == CURLOPT_MAIL_FROM || \ (option) == CURLOPT_NETRC_FILE || \ (option) == CURLOPT_NOPROXY || \ (option) == CURLOPT_PASSWORD || \ (option) == CURLOPT_PINNEDPUBLICKEY || \ (option) == CURLOPT_PRE_PROXY || \ (option) == CURLOPT_PROTOCOLS_STR || \ (option) == CURLOPT_PROXY || \ (option) == CURLOPT_PROXY_CAINFO || \ (option) == CURLOPT_PROXY_CAPATH || \ (option) == CURLOPT_PROXY_CRLFILE || \ (option) == CURLOPT_PROXY_ISSUERCERT || \ (option) == CURLOPT_PROXY_KEYPASSWD || \ (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \ (option) == CURLOPT_PROXY_SERVICE_NAME || \ (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \ (option) == CURLOPT_PROXY_SSLCERT || \ (option) == CURLOPT_PROXY_SSLCERTTYPE || \ (option) == CURLOPT_PROXY_SSLKEY || \ (option) == CURLOPT_PROXY_SSLKEYTYPE || \ (option) == CURLOPT_PROXY_TLS13_CIPHERS || \ (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \ (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \ (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \ (option) == CURLOPT_PROXYPASSWORD || \ (option) == CURLOPT_PROXYUSERNAME || \ (option) == CURLOPT_PROXYUSERPWD || \ (option) == CURLOPT_RANDOM_FILE || \ (option) == CURLOPT_RANGE || \ (option) == CURLOPT_REDIR_PROTOCOLS_STR || \ (option) == CURLOPT_REFERER || \ (option) == CURLOPT_REQUEST_TARGET || \ (option) == CURLOPT_RTSP_SESSION_ID || \ (option) == CURLOPT_RTSP_STREAM_URI || \ (option) == CURLOPT_RTSP_TRANSPORT || \ (option) == CURLOPT_SASL_AUTHZID || \ (option) == CURLOPT_SERVICE_NAME || \ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256 || \ (option) == CURLOPT_SSH_KNOWNHOSTS || \ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \ (option) == CURLOPT_SSLCERT || \ (option) == CURLOPT_SSLCERTTYPE || \ (option) == CURLOPT_SSLENGINE || \ (option) == CURLOPT_SSLKEY || \ (option) == CURLOPT_SSLKEYTYPE || \ (option) == CURLOPT_SSL_CIPHER_LIST || \ (option) == CURLOPT_TLS13_CIPHERS || \ (option) == CURLOPT_TLSAUTH_PASSWORD || \ (option) == CURLOPT_TLSAUTH_TYPE || \ (option) == CURLOPT_TLSAUTH_USERNAME || \ (option) == CURLOPT_UNIX_SOCKET_PATH || \ (option) == CURLOPT_URL || \ (option) == CURLOPT_USERAGENT || \ (option) == CURLOPT_USERNAME || \ (option) == CURLOPT_AWS_SIGV4 || \ (option) == CURLOPT_USERPWD || \ (option) == CURLOPT_XOAUTH2_BEARER || \ (option) == CURLOPT_SSL_EC_CURVES || \ 0) /* evaluates to true if option takes a curl_write_callback argument */ #define curlcheck_write_cb_option(option) \ ((option) == CURLOPT_HEADERFUNCTION || \ (option) == CURLOPT_WRITEFUNCTION) /* evaluates to true if option takes a curl_conv_callback argument */ #define curlcheck_conv_cb_option(option) \ ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \ (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \ (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION) /* evaluates to true if option takes a data argument to pass to a callback */ #define curlcheck_cb_data_option(option) \ ((option) == CURLOPT_CHUNK_DATA || \ (option) == CURLOPT_CLOSESOCKETDATA || \ (option) == CURLOPT_DEBUGDATA || \ (option) == CURLOPT_FNMATCH_DATA || \ (option) == CURLOPT_HEADERDATA || \ (option) == CURLOPT_HSTSREADDATA || \ (option) == CURLOPT_HSTSWRITEDATA || \ (option) == CURLOPT_INTERLEAVEDATA || \ (option) == CURLOPT_IOCTLDATA || \ (option) == CURLOPT_OPENSOCKETDATA || \ (option) == CURLOPT_PREREQDATA || \ (option) == CURLOPT_PROGRESSDATA || \ (option) == CURLOPT_READDATA || \ (option) == CURLOPT_SEEKDATA || \ (option) == CURLOPT_SOCKOPTDATA || \ (option) == CURLOPT_SSH_KEYDATA || \ (option) == CURLOPT_SSL_CTX_DATA || \ (option) == CURLOPT_WRITEDATA || \ (option) == CURLOPT_RESOLVER_START_DATA || \ (option) == CURLOPT_TRAILERDATA || \ (option) == CURLOPT_SSH_HOSTKEYDATA || \ 0) /* evaluates to true if option takes a POST data argument (void* or char*) */ #define curlcheck_postfields_option(option) \ ((option) == CURLOPT_POSTFIELDS || \ (option) == CURLOPT_COPYPOSTFIELDS || \ 0) /* evaluates to true if option takes a struct curl_slist * argument */ #define curlcheck_slist_option(option) \ ((option) == CURLOPT_HTTP200ALIASES || \ (option) == CURLOPT_HTTPHEADER || \ (option) == CURLOPT_MAIL_RCPT || \ (option) == CURLOPT_POSTQUOTE || \ (option) == CURLOPT_PREQUOTE || \ (option) == CURLOPT_PROXYHEADER || \ (option) == CURLOPT_QUOTE || \ (option) == CURLOPT_RESOLVE || \ (option) == CURLOPT_TELNETOPTIONS || \ (option) == CURLOPT_CONNECT_TO || \ 0) /* groups of curl_easy_getinfo infos that take the same type of argument */ /* evaluates to true if info expects a pointer to char * argument */ #define curlcheck_string_info(info) \ (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG && \ (info) != CURLINFO_PRIVATE) /* evaluates to true if info expects a pointer to long argument */ #define curlcheck_long_info(info) \ (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE) /* evaluates to true if info expects a pointer to double argument */ #define curlcheck_double_info(info) \ (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST) /* true if info expects a pointer to struct curl_slist * argument */ #define curlcheck_slist_info(info) \ (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST)) /* true if info expects a pointer to struct curl_tlssessioninfo * argument */ #define curlcheck_tlssessioninfo_info(info) \ (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION)) /* true if info expects a pointer to struct curl_certinfo * argument */ #define curlcheck_certinfo_info(info) ((info) == CURLINFO_CERTINFO) /* true if info expects a pointer to struct curl_socket_t argument */ #define curlcheck_socket_info(info) \ (CURLINFO_SOCKET < (info) && (info) < CURLINFO_OFF_T) /* true if info expects a pointer to curl_off_t argument */ #define curlcheck_off_t_info(info) \ (CURLINFO_OFF_T < (info)) /* typecheck helpers -- check whether given expression has requested type */ /* For pointers, you can use the curlcheck_ptr/curlcheck_arr macros, * otherwise define a new macro. Search for __builtin_types_compatible_p * in the GCC manual. * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is * the actual expression passed to the curl_easy_setopt macro. This * means that you can only apply the sizeof and __typeof__ operators, no * == or whatsoever. */ /* XXX: should evaluate to true if expr is a pointer */ #define curlcheck_any_ptr(expr) \ (sizeof(expr) == sizeof(void *)) /* evaluates to true if expr is NULL */ /* XXX: must not evaluate expr, so this check is not accurate */ #define curlcheck_NULL(expr) \ (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL))) /* evaluates to true if expr is type*, const type* or NULL */ #define curlcheck_ptr(expr, type) \ (curlcheck_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), type *) || \ __builtin_types_compatible_p(__typeof__(expr), const type *)) /* evaluates to true if expr is one of type[], type*, NULL or const type* */ #define curlcheck_arr(expr, type) \ (curlcheck_ptr((expr), type) || \ __builtin_types_compatible_p(__typeof__(expr), type [])) /* evaluates to true if expr is a string */ #define curlcheck_string(expr) \ (curlcheck_arr((expr), char) || \ curlcheck_arr((expr), signed char) || \ curlcheck_arr((expr), unsigned char)) /* evaluates to true if expr is a long (no matter the signedness) * XXX: for now, int is also accepted (and therefore short and char, which * are promoted to int when passed to a variadic function) */ #define curlcheck_long(expr) \ (__builtin_types_compatible_p(__typeof__(expr), long) || \ __builtin_types_compatible_p(__typeof__(expr), signed long) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \ __builtin_types_compatible_p(__typeof__(expr), int) || \ __builtin_types_compatible_p(__typeof__(expr), signed int) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \ __builtin_types_compatible_p(__typeof__(expr), short) || \ __builtin_types_compatible_p(__typeof__(expr), signed short) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \ __builtin_types_compatible_p(__typeof__(expr), char) || \ __builtin_types_compatible_p(__typeof__(expr), signed char) || \ __builtin_types_compatible_p(__typeof__(expr), unsigned char)) /* evaluates to true if expr is of type curl_off_t */ #define curlcheck_off_t(expr) \ (__builtin_types_compatible_p(__typeof__(expr), curl_off_t)) /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ /* XXX: also check size of an char[] array? */ #define curlcheck_error_buffer(expr) \ (curlcheck_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), char *) || \ __builtin_types_compatible_p(__typeof__(expr), char[])) /* evaluates to true if expr is of type (const) void* or (const) FILE* */ #if 0 #define curlcheck_cb_data(expr) \ (curlcheck_ptr((expr), void) || \ curlcheck_ptr((expr), FILE)) #else /* be less strict */ #define curlcheck_cb_data(expr) \ curlcheck_any_ptr(expr) #endif /* evaluates to true if expr is of type FILE* */ #define curlcheck_FILE(expr) \ (curlcheck_NULL(expr) || \ (__builtin_types_compatible_p(__typeof__(expr), FILE *))) /* evaluates to true if expr can be passed as POST data (void* or char*) */ #define curlcheck_postfields(expr) \ (curlcheck_ptr((expr), void) || \ curlcheck_arr((expr), char) || \ curlcheck_arr((expr), unsigned char)) /* helper: __builtin_types_compatible_p distinguishes between functions and * function pointers, hide it */ #define curlcheck_cb_compatible(func, type) \ (__builtin_types_compatible_p(__typeof__(func), type) || \ __builtin_types_compatible_p(__typeof__(func) *, type)) /* evaluates to true if expr is of type curl_resolver_start_callback */ #define curlcheck_resolver_start_callback(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_resolver_start_callback)) /* evaluates to true if expr is of type curl_read_callback or "similar" */ #define curlcheck_read_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fread) *) || \ curlcheck_cb_compatible((expr), curl_read_callback) || \ curlcheck_cb_compatible((expr), _curl_read_callback1) || \ curlcheck_cb_compatible((expr), _curl_read_callback2) || \ curlcheck_cb_compatible((expr), _curl_read_callback3) || \ curlcheck_cb_compatible((expr), _curl_read_callback4) || \ curlcheck_cb_compatible((expr), _curl_read_callback5) || \ curlcheck_cb_compatible((expr), _curl_read_callback6)) typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *); typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *); typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *); typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *); typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *); typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_write_callback or "similar" */ #define curlcheck_write_cb(expr) \ (curlcheck_read_cb(expr) || \ curlcheck_cb_compatible((expr), __typeof__(fwrite) *) || \ curlcheck_cb_compatible((expr), curl_write_callback) || \ curlcheck_cb_compatible((expr), _curl_write_callback1) || \ curlcheck_cb_compatible((expr), _curl_write_callback2) || \ curlcheck_cb_compatible((expr), _curl_write_callback3) || \ curlcheck_cb_compatible((expr), _curl_write_callback4) || \ curlcheck_cb_compatible((expr), _curl_write_callback5) || \ curlcheck_cb_compatible((expr), _curl_write_callback6)) typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *); typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t, const void *); typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *); typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *); typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t, const void *); typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ #define curlcheck_ioctl_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ioctl_callback) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback1) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback2) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback3) || \ curlcheck_cb_compatible((expr), _curl_ioctl_callback4)) typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *); typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *); typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *); typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *); /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ #define curlcheck_sockopt_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_sockopt_callback) || \ curlcheck_cb_compatible((expr), _curl_sockopt_callback1) || \ curlcheck_cb_compatible((expr), _curl_sockopt_callback2)) typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype); typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t, curlsocktype); /* evaluates to true if expr is of type curl_opensocket_callback or "similar" */ #define curlcheck_opensocket_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_opensocket_callback) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback1) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback2) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback3) || \ curlcheck_cb_compatible((expr), _curl_opensocket_callback4)) typedef curl_socket_t (*_curl_opensocket_callback1) (void *, curlsocktype, struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback2) (void *, curlsocktype, const struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback3) (const void *, curlsocktype, struct curl_sockaddr *); typedef curl_socket_t (*_curl_opensocket_callback4) (const void *, curlsocktype, const struct curl_sockaddr *); /* evaluates to true if expr is of type curl_progress_callback or "similar" */ #define curlcheck_progress_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_progress_callback) || \ curlcheck_cb_compatible((expr), _curl_progress_callback1) || \ curlcheck_cb_compatible((expr), _curl_progress_callback2)) typedef int (*_curl_progress_callback1)(void *, double, double, double, double); typedef int (*_curl_progress_callback2)(const void *, double, double, double, double); /* evaluates to true if expr is of type curl_debug_callback or "similar" */ #define curlcheck_debug_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_debug_callback) || \ curlcheck_cb_compatible((expr), _curl_debug_callback1) || \ curlcheck_cb_compatible((expr), _curl_debug_callback2) || \ curlcheck_cb_compatible((expr), _curl_debug_callback3) || \ curlcheck_cb_compatible((expr), _curl_debug_callback4) || \ curlcheck_cb_compatible((expr), _curl_debug_callback5) || \ curlcheck_cb_compatible((expr), _curl_debug_callback6) || \ curlcheck_cb_compatible((expr), _curl_debug_callback7) || \ curlcheck_cb_compatible((expr), _curl_debug_callback8)) typedef int (*_curl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); typedef int (*_curl_debug_callback2) (CURL *, curl_infotype, char *, size_t, const void *); typedef int (*_curl_debug_callback3) (CURL *, curl_infotype, const char *, size_t, void *); typedef int (*_curl_debug_callback4) (CURL *, curl_infotype, const char *, size_t, const void *); typedef int (*_curl_debug_callback5) (CURL *, curl_infotype, unsigned char *, size_t, void *); typedef int (*_curl_debug_callback6) (CURL *, curl_infotype, unsigned char *, size_t, const void *); typedef int (*_curl_debug_callback7) (CURL *, curl_infotype, const unsigned char *, size_t, void *); typedef int (*_curl_debug_callback8) (CURL *, curl_infotype, const unsigned char *, size_t, const void *); /* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */ /* this is getting even messier... */ #define curlcheck_ssl_ctx_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_ssl_ctx_callback) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback1) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback2) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback3) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback4) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback5) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback6) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback7) || \ curlcheck_cb_compatible((expr), _curl_ssl_ctx_callback8)) typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *); typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *); typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *); typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *, const void *); #ifdef HEADER_SSL_H /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX * this will of course break if we are included before OpenSSL headers... */ typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *); typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *); typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *); typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *, const void *); #else typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7; typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8; #endif /* evaluates to true if expr is of type curl_conv_callback or "similar" */ #define curlcheck_conv_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_conv_callback) || \ curlcheck_cb_compatible((expr), _curl_conv_callback1) || \ curlcheck_cb_compatible((expr), _curl_conv_callback2) || \ curlcheck_cb_compatible((expr), _curl_conv_callback3) || \ curlcheck_cb_compatible((expr), _curl_conv_callback4)) typedef CURLcode (*_curl_conv_callback1)(char *, size_t length); typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length); typedef CURLcode (*_curl_conv_callback3)(void *, size_t length); typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length); /* evaluates to true if expr is of type curl_seek_callback or "similar" */ #define curlcheck_seek_cb(expr) \ (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_seek_callback) || \ curlcheck_cb_compatible((expr), _curl_seek_callback1) || \ curlcheck_cb_compatible((expr), _curl_seek_callback2)) typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int); typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int); #endif /* CURLINC_TYPECHECK_GCC_H */ #else #if defined(__STDC__) && (__STDC__ >= 1) /* This preprocessor magic that replaces a call with the exact same call is only done to make sure application authors pass exactly three arguments to these functions. */ #define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param) #define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg) #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) #define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) #endif /* __STDC__ >= 1 */ #endif /* gcc >= 4.3 && !__cplusplus && !CURL_DISABLE_TYPECHECK */ #endif /* CURLINC_CURL_H */ #endif /// LICENSE_END.24 bool g_control_c =false; int g_incomplete_version =0; int64_t g_starting_zpaqdate =0; int64_t g_starting_zpaqsize =0; int64_t g_starting_indexsize =0; int64_t g_starting_zpaqattr =0; std::string g_thememfileblock =""; std::string g_thememfileblock_h =""; int64_t g_thememfilestart =0; int64_t g_thememfilestart_h =0; int64_t g_thememfilelength =0; int g_thememfilefragstart =0; int g_thememfilefragend =0; FILE* g_output_handle; FILE* g_error_handle; bool flagignore; bool flagnotrim; bool flagonedrive; bool flaghw; // this slow down vs HWSHA1 bool flagdebug; bool flagdebug2; bool flagdebug3; bool flagdebug4; bool flagdebug5; std::string g_processorname=""; bool flagnojit; char* g_password; // points to password_string or NULL char g_password_string[32]; // hash of -key argument bool g_flagcreating; char command; std::string g_mysql_host; std::string g_mysql_user; std::string g_mysql_password; int g_mysql_port; #ifdef SFTP std::string g_sftp_host; std::string g_sftp_user; std::string g_sftp_password; int g_sftp_port; #endif // corresponds to #ifdef (#ifdef SFTP) std::string g_franzsnap; std::string g_vss_shadow; std::string g_replaceme; std::string g_copy; std::string g_freeze; std::string g_exec_error; std::string g_exec_warn; std::string g_exec_ok; std::string g_exec_text; std::string g_exec; int g_255; std::string g_output; std::string g_error; std::string g_ifexist; ///string g_ismounted; std::string g_script; std::string g_sfx; std::string g_sfxto; std::string g_sfxnot; std::string g_sfxonly; std::string g_sfxuntil; std::string g_deleteinto; bool g_sfxflagall; bool g_sfxflagforce; bool g_sse42; bool g_flagmultipart; std::string g_archive; std::string g_indexname; std::string g_externalname; std::string g_input; std::string g_destination; std::string g_csvstring; std::string g_csvhf; std::string g_bin; std::string g_pidname; bool flagnopid; FILE* g_pid_handle=0; std::string g_backupposition; int64_t g_robocopy_check_sorgente; int64_t g_robocopy_check_destinazione; int64_t g_robocopy_makepath; int64_t g_robocopy_makepath2; int64_t g_robocopy_isequal; int64_t g_robocopy_close; int64_t g_robocopy_close2; int64_t g_robocopy_touch; int64_t g_robocopy_delete; int64_t g_robocopy_readopen; int64_t g_robocopy_openoutfile; int64_t g_robocopy_fclose; int64_t g_robocopy_fread; int64_t g_robocopy_fwrite; bool g_testifselected; uint64_t g_chunk_size =0; int64_t g_start =0; int64_t g_dimensione =0; int64_t g_scritti =0; int64_t g_maxposition =0; int64_t g_zerotime =0; int64_t g_bytescanned =0; int64_t g_filescanned =0; int64_t g_worked =0; int64_t g_fwritten =0; int64_t g_fexpected =0; int64_t g_fwrittencrc32 =0; int64_t g_header_pos =0; bool g_crc_getheader =false; ///0 = header; 1= jidac; 2=body bool g_veryfirst =true; uint32_t g_crc_header =0; uint32_t g_crc_jidac =0; uint32_t g_crc_body =0; int64_t g_ramdisksize =0; int64_t g_rd =0; int64_t g_rd_expected =0; int64_t g_startrd =0; int64_t g_startdownload =0; int g_rd_ultimotempo=0; int64_t g_cdatasize =0; unsigned g_htsize =0; bool g_fakewrite =false; // in add() disable write (ransomware) uint64_t minsize; uint64_t maxsize; int64_t g_touch =0; int64_t g_datefrom =0; int64_t g_dateto =0; std::string g_until; int g_rangefrom =0; int g_rangeto =0; int g_rangelast =0; ///int red4 =-1; #ifdef unix std::string g_tempsnapshot; std::string g_basesnapshot; std::string g_dataset; #endif // corresponds to #ifdef (#ifdef unix) bool flagnosymlink; bool flagnochecksum; bool flagcrc32; bool flagxxhash64; bool flagxxhash64b; bool flagsha1; bool flagsha256; bool flagsha256b; bool flagxxh3; bool flagmd5; bool flagmd5b; bool flagsha1b; bool flagxxh3b; bool flagblake3; bool flagblake3b; bool flagsha3; bool flagsha3b; bool flagwhirlpool; bool flaghighway64; bool flaghighway128; bool flaghighway256; bool flagcrc32c; bool flagwyhash; bool flagnilsimsa; bool flagentropy; bool flagwindate; bool flagtmp; bool flagbackupxxh3; bool flagbackupzeta; bool flag715; bool flagappend; bool flagbig; bool flagchecksum; bool flagchecktxt; bool flagsfx; bool flagfasttxt; bool flagcomment; bool flagdesc; bool flagdonotforcexls; bool flagfilelist; bool flagexternal; bool flaginput; bool flagdestination; bool flagads; bool flagfast; bool flagfix255; bool flagfixeml; bool flagflat; bool flagforce; bool flagforcewindows; bool flagforcezfs; bool flagfrugal; bool flaghashdeep; bool flagkill; bool flaght; bool flagnocaptcha; bool flagmm; bool flagattr; bool flagthunderbird; bool flagnoattributes; bool flagnodedup; bool flagnoeta; bool flagnopath; bool flagnoqnap; bool flagnomac; bool flagnosynology; bool flagnorecursion; bool flagnosort; bool flagpakka; bool flagdistinct; bool flagparanoid; bool flagpaq; bool flagcollision; bool flagramdisk; bool flagrename; bool flagsilent; bool flagnoconsole; bool flagnocolor; bool flagnodelete; bool flagskipzfs; bool flagspace; bool flagssd; bool flagnomore; bool flagsalt; bool flaghdd; bool flagquick; bool flagzeta; bool flagzetaenc; bool flagquiet; bool flagstat; bool flagstdin; bool flagterse; bool flagnodel; bool flagcsv; bool flagstdout; bool flagstore; bool flagtar; bool flagtest; bool flagtouch; bool flagutc; bool flagdate; bool flagutf; bool flagpause; bool flagverbose; bool flagverify; bool flagvss; bool flagzero; bool flaghome; bool flagfixcase; #ifdef _WIN32 #define MYFOREGROUND_BLUE 0x0001 #define MYFOREGROUND_GREEN 0x0002 #define MYFOREGROUND_RED 0x0004 #define MYFOREGROUND_INTENSITY 0x0008 #define MYBACKGROUND_BLUE 0x0010 #define MYBACKGROUND_GREEN 0x0020 #define MYBACKGROUND_RED 0x0040 #define MYBACKGROUND_INTENSITY 0x0080 #else /// *nix colors #define TEXT_BLACK "\x1b[30m" #define TEXT_RED "\x1b[31m" #define TEXT_GREEN "\x1b[32m" #define TEXT_YELLOW "\x1b[33m" #define TEXT_BLUE "\x1b[34m" #define TEXT_MAGENTA "\x1b[35m" #define TEXT_CYAN "\x1b[36m" #define TEXT_WHITE "\x1b[37m" #define TEXT_RESET "\x1b[0m" ///#define TEXT_BLACK_BRIGHT "\x1b[1;30m" #define TEXT_BLACK_BRIGHT "\x1b[1;30m" #define TEXT_RED_BRIGHT "\x1b[1;31m" #define TEXT_GREEN_BRIGHT "\x1b[1;32m" #define TEXT_YELLOW_BRIGHT "\x1b[1;33m" #define TEXT_BLUE_BRIGHT "\x1b[1;34m" #define TEXT_MAGENTA_BRIGHT "\x1b[1;35m" #define TEXT_CYAN_BRIGHT "\x1b[1;36m" #define TEXT_WHITE_BRIGHT "\x1b[1;37m" #define TEXT_RESET_BRIGHT "\x1b[1;0m" #define BG_BLACK "\x1b[40m" #define BG_RED "\x1b[41m" #define BG_GREEN "\x1b[42m" #define BG_YELLOW "\x1b[43m" #define BG_BLUE "\x1b[44m" #define BG_MAGENTA "\x1b[45m" #define BG_CYAN "\x1b[46m" #define BG_WHITE "\x1b[47m" #define BG_BLACK_BRIGHT "\x1b[1;40m" #define BG_RED_BRIGHT "\x1b[1;41m" #define BG_GREEN_BRIGHT "\x1b[1;42m" #define BG_YELLOW_BRIGHT "\x1b[1;43m" #define BG_BLUE_BRIGHT "\x1b[1;44m" #define BG_MAGENTA_BRIGHT "\x1b[1;45m" #define BG_CYAN_BRIGHT "\x1b[1;46m" #define BG_WHITE_BRIGHT "\x1b[1;47m" #endif // corresponds to #ifdef (#ifdef _WIN32) int g_console_attributes=-1; bool iswindowsxp() { #ifdef _WIN32 OSVERSIONINFO osvi; osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); return (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1); #endif // corresponds to #ifdef (#ifdef _WIN32) return false; } #ifdef _WIN32 void color_save() { if (flagnocolor) return; HANDLE hconsole=GetStdHandle(STD_OUTPUT_HANDLE); if (hconsole==INVALID_HANDLE_VALUE) return; CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo(hconsole,&csbiInfo); if ((csbiInfo.wAttributes & MYFOREGROUND_BLUE) && (csbiInfo.wAttributes & MYFOREGROUND_GREEN) && (csbiInfo.wAttributes & MYFOREGROUND_RED)) g_console_attributes=csbiInfo.wAttributes; } #endif // corresponds to #ifdef (#ifdef _WIN32) void color_restore() { if (flagnocolor) return; #ifdef _WIN32 if (g_console_attributes<0) return; HANDLE hconsole=GetStdHandle(STD_OUTPUT_HANDLE); if (hconsole==INVALID_HANDLE_VALUE) return; SetConsoleTextAttribute(hconsole,g_console_attributes); #else printf(TEXT_RESET); #endif // corresponds to #ifdef (#ifdef _WIN32) } #ifdef _WIN32 void color_something(int i_color) { if (flagnocolor) return; if (g_console_attributes<0) return; HANDLE hconsole=GetStdHandle(STD_OUTPUT_HANDLE); if (hconsole==INVALID_HANDLE_VALUE) return; SetConsoleTextAttribute(hconsole,i_color); return; } #endif // corresponds to #ifdef (#ifdef _WIN32) void color_red() { if (flagnocolor) return; #ifdef _WIN32 color_something(4); #else printf(TEXT_RED_BRIGHT); #endif // corresponds to #ifdef (#ifdef _WIN32) } void color_green() { if (flagnocolor) return; #ifdef _WIN32 ///getenv("WT_SESSION") color_something(MYFOREGROUND_GREEN+MYFOREGROUND_INTENSITY); #else printf(TEXT_GREEN_BRIGHT); #endif // corresponds to #ifdef (#ifdef _WIN32) } void color_yellow() { if (flagnocolor) return; #ifdef _WIN32 color_something(14); #else printf(TEXT_YELLOW_BRIGHT); #endif // corresponds to #ifdef (#ifdef _WIN32) } void color_blackongreen() { if (flagnocolor) return; #ifdef _WIN32 color_something(160); #else #if (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) color_green(); #else printf("\x1b[30m" "\x1b[102m"); #endif // corresponds to #if (#if (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__)) #endif // corresponds to #ifdef (#ifdef _WIN32) } static const int64_t LIST_HT_BAD= -0x7FFFFFFFFFFFFFFALL; // no such frag std::string print_datetime(bool i_flagout=true); #ifdef _WIN32 // In Windows, convert UTF-8 string to wide string ignoring // invalid UTF-8 or >64K. Convert "/" to slash (default "\"). std::wstring utow(const char* ss, char slash = '\\') { assert(sizeof(wchar_t) == 2); assert((wchar_t)(-1) == 65535); std::wstring r; if (!ss) return r; const unsigned char* s = (const unsigned char*)ss; while (*s) { if (*s == '/') { r += slash; ++s; } else if (*s < 128) { r += *s; ++s; } else if (*s >= 192 && *s < 224 && s[1] >= 128 && s[1] < 192) { r += ((*s & 0x1F) << 6) | (s[1] & 0x3F); s += 2; } else if (*s >= 224 && *s < 240 && s[1] >= 128 && s[1] < 192 && s[2] >= 128 && s[2] < 192) { r += ((*s & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); s += 3; } else { // Carattere non valido o non supportato (es. 4 byte), salta r += L'?'; // Sostituisci con un placeholder ++s; } } return r; } #endif // corresponds to #ifdef (#ifdef _WIN32) void printUTF8(const char* s, FILE* f=stdout) { assert(f); assert(s); if (g_output_handle!=0) fprintf(g_output_handle,"%s",s); if (flagsilent) return; #ifdef unix fprintf(f, "%s", s); #else const HANDLE h=(HANDLE)_get_osfhandle(_fileno(f)); DWORD ft=GetFileType(h); if (ft==FILE_TYPE_CHAR) { fflush(f); std::wstring w=utow(s, '/'); DWORD n=0; WriteConsole(h, w.c_str(), w.size(), &n, 0); } else fprintf(f, "%s", s); #endif // corresponds to #ifdef (#ifdef unix) } void decode_print_flag(const char* i_buffer,bool& o_flagcolon,bool& o_flagerror,bool& o_flagwarning) { if (i_buffer==NULL) { printf("02734: i_buffer calcola flag NULL!\n"); exit(0); } o_flagcolon=false; o_flagerror=false; int format_len=strlen(i_buffer); if (format_len>7) { bool fivedigits=(isdigit(i_buffer[0])) && (isdigit(i_buffer[1])) && (isdigit(i_buffer[2])) && (isdigit(i_buffer[3])) && (isdigit(i_buffer[4])) && ((i_buffer[5]=='!') || (i_buffer[5]=='$') || (i_buffer[5]==':') ) && (i_buffer[6]==' '); if (fivedigits) { o_flagerror =(i_buffer[5]=='!'); o_flagwarning =(i_buffer[5]=='$'); o_flagcolon =(i_buffer[5]==':'); } } } void replacezwiths(const char *input, char *output) { const char *ptr = input; char *out_ptr = output; while (*ptr != '\0') { // Controlla se troviamo la coppia "%Z" if (ptr[0] == '%' && ptr[1] == 'Z') { // Sostituisci con "%s" *out_ptr++ = '%'; *out_ptr++ = 's'; ptr += 2; // Salta la coppia "%Z" } else { // Copia il carattere corrente *out_ptr++ = *ptr++; } } *out_ptr = '\0'; // Termina la stringa output } int mypos(const std::string& i_substring,const std::string& i_string) { size_t start_pos = i_string.find(i_substring); if (start_pos==std::string::npos) return -1; else return (int)start_pos; } bool fileexists(const std::string& i_filename) { #ifdef unix // true even for dirs no S_ISDIR struct stat buffer; return (stat(i_filename.c_str(),&buffer)==0); #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 if (flagads) if (mypos(":",i_filename)!=-1) { if (flagdebug3) printf("00109: flagads ON and : in i_filename\n"); HANDLE hFile = CreateFileW((utow(i_filename.c_str()).c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile!=INVALID_HANDLE_VALUE) { if (flagdebug3) printf("00110: ADS FOUNDED!\n"); CloseHandle(hFile); return true; } return false; } HANDLE myhandle; WIN32_FIND_DATA findfiledata; std::wstring wpattern=utow(i_filename.c_str()); myhandle=FindFirstFile(wpattern.c_str(),&findfiledata); if (myhandle!=INVALID_HANDLE_VALUE) { FindClose(myhandle); return true; } return false; #endif // corresponds to #ifdef (#ifdef _WIN32) return false; } // Delete a file, return true if successful bool delete_file(const char* filename) { #ifdef unix return remove(filename)==0; #else if (!fileexists(filename)) return true; SetFileAttributes(utow(filename).c_str(),FILE_ATTRIBUTE_NORMAL); return DeleteFile(utow(filename).c_str()); #endif // corresponds to #ifdef (#ifdef unix) } bool prepare_error_log() { if (g_error=="") return false; if (g_error_handle==0) { if (flagverbose) printf("02747: OPENING ERROR FILE %s\n",g_error.c_str()); g_error_handle=fopen(g_error.c_str(),"wb"); } if (g_error_handle==0) return false; return true; } void my_print_on_error_z(const char* i_input) { if (i_input==NULL) return; if (prepare_error_log()) { fprintf(g_error_handle,"%s",i_input); fflush(g_error_handle); } } void my_print_on_error_s(const char* i_buffer,const char* i_input) { if (i_buffer==NULL) return; if (i_input==NULL) return; if (prepare_error_log()) { fprintf(g_error_handle,i_buffer,i_input); fflush(g_error_handle); } } void my_print_on_error_i(char* i_buffer,int i_input) { if (i_buffer==NULL) return; if (prepare_error_log()) { fprintf(g_error_handle,i_buffer,i_input); fflush(g_error_handle); } } void my_print_on_error_u(char* i_buffer,unsigned int i_input) { if (i_buffer==NULL) return; if (prepare_error_log()) { fprintf(g_error_handle,i_buffer,i_input); fflush(g_error_handle); } } void my_print_on_error_d(const char* i_buffer,double i_input) { if (i_buffer==NULL) return; if (prepare_error_log()) { fprintf(g_error_handle,i_buffer,i_input); fflush(g_error_handle); } } // La nostra funzione myprintf migliorata void myprintf(const char *format, ...) { bool flagerror =false; bool flagcolon =false; bool flagwarning =false; char buffer[4096]; // Buffer temporaneo per formati complessi if (flagsilent) { char fixata[4096]; replacezwiths(format,fixata); va_list args2; va_start(args2,format); vsnprintf(buffer,sizeof(buffer),fixata,args2); va_end(args2); decode_print_flag(buffer,flagcolon,flagerror,flagwarning); if (g_output_handle!=0) fprintf(g_output_handle,"%s",buffer); if (flagerror) my_print_on_error_z(buffer); return; } va_list args; va_start(args, format); decode_print_flag(format,flagcolon,flagerror,flagwarning); if (flagcolon || flagwarning) { if (flagdebug) { color_green(); printf("%c%c%c%c%c: ",format[0],format[1],format[2],format[3],format[4]); color_restore(); } format+=7; } if (flagerror) color_red(); else { if (flagwarning) color_yellow(); } const char *p = format; while (*p) { if (*p == '%') { p++; // Passa al carattere successivo dopo '%' // Gestisce il caso di '%%' per stampare un singolo '%' if (*p == '%') { putchar('%'); } else { char *b = buffer; *b++ = '%'; // Aggiunge il carattere '%' nel buffer // Gestisce eventuali flag come '-' o '0' per l'allineamento o padding while (*p && (strchr("-+0 ", *p) != NULL)) *b++ = *p++; // Gestisce larghezza del campo (es. 10 in %10s) while (*p && (*p >= '0' && *p <= '9')) *b++ = *p++; // Gestisce la precisione (es. .2 in %5.2f) if (*p == '.') { *b++ = *p++; // Aggiunge il '.' while (*p && (*p >= '0' && *p <= '9')) *b++ = *p++; } // Gestisce il carattere finale del formato (es. 'd', 's', 'f') if (*p && strchr("diouxXfscZ", *p) != NULL) { *b++ = *p; // Aggiunge il carattere di conversione *b = '\0'; // Termina la stringa nel buffer } // Ora gestiamo il formato accumulato nel buffer if (*p == 'd' || *p == 'i') { int i = va_arg(args, int); printf(buffer, i); if (g_output_handle!=0) fprintf(g_output_handle,buffer,i); if (flagerror) my_print_on_error_i(buffer,i); } else if (*p == 'u') { unsigned int u = va_arg(args, unsigned int); printf(buffer, u); if (g_output_handle!=0) fprintf(g_output_handle,buffer,u); if (flagerror) my_print_on_error_u(buffer,u); } else if (*p == 'x' || *p == 'X') { unsigned int x = va_arg(args, unsigned int); printf(buffer, x); if (g_output_handle!=0) fprintf(g_output_handle,buffer,x); if (flagerror) my_print_on_error_u(buffer,x); } else if (*p == 'f') { double f = va_arg(args, double); printf(buffer, f); if (g_output_handle!=0) fprintf(g_output_handle,buffer,f); if (flagerror) my_print_on_error_d(buffer,f); } else if (*p == 's') { /* char *s = va_arg(args, char *); printf(buffer, s); if (g_output_handle!=0) fprintf(g_output_handle,buffer,s); if (flagerror) my_print_on_error_s(buffer,s); */ // Se c'è un asterisco nella formattazione if (strchr(buffer, '*') != NULL) { /// printf("TROVATOOOO\n"); /// exit(0); int width = va_arg(args, int); // Legge la larghezza char *s = va_arg(args, char *); // Legge la stringa printf(buffer, width, s); if (g_output_handle != 0) fprintf(g_output_handle, buffer, width, s); if (flagerror) my_print_on_error_s(buffer, s); // Nota: potrebbe richiedere adattamenti per width } else { char *s = va_arg(args, char *); printf(buffer, s); if (g_output_handle != 0) fprintf(g_output_handle, buffer, s); if (flagerror) my_print_on_error_s(buffer, s); } } else if (*p == 'c') { int c = va_arg(args, int); printf(buffer, c); if (g_output_handle!=0) fprintf(g_output_handle,buffer,c); if (flagerror) my_print_on_error_i(buffer,c); } else if (*p == 'Z') { // Gestione speciale del token %Z char *s = va_arg(args, char *); printUTF8(s); if (flagerror) my_print_on_error_z(s); } } } else { // Stampa un carattere normale (non un token di formato) putchar(*p); if (g_output_handle!=0) fputc(*p,g_output_handle); if (flagerror) { if (prepare_error_log()) fputc(*p,g_error_handle); } } p++; // Passiamo al carattere successivo nella stringa di formato } va_end(args); #ifndef _WIN32 fflush(stdout); #endif // corresponds to #ifndef (#ifndef _WIN32) if (flagerror || flagwarning) color_restore(); } /// LICENSE_START.23 // This is a reworked https://github.com/codewithnick/ascii-art // Just one font, different output char, no streams class Fonts { unsigned int def_rows; unsigned int def_cols; unsigned int char_rows; unsigned int char_cols; unsigned int curr_col; std::vector > letters; /* zpaqfranz.cpp:2930:25: note: the layout of aggregates containing vectors with 8-byte alignment has changed in GCC 5 2930 | this->char_rows = rows ? rows : def_rows; */ protected: char **getCharGrid(unsigned int rows = 0, unsigned int cols = 0) { this->char_rows = rows ? rows : def_rows; this->char_cols = cols ? cols : def_cols; char **char_grid = new char *[char_rows]; for (unsigned int i = 0; i < char_rows; i++) { char_grid[i] = new char[char_cols]; for (unsigned int j = 0; j < char_cols; j++) char_grid[i][j] = ' '; } return char_grid; } void destroyspace() { letters.clear(); } public: Fonts(int def_rows, int def_cols) { this->def_rows = def_rows; this->def_cols = def_cols; letters.reserve(def_rows); for (int i = 0; i < def_rows; i++) letters.push_back(std::vector(100, ' ')); // Create rows with 100 spaces each curr_col = 0; } void pushChar(char **character) { if (!character) return; while (letters.size() < char_rows) letters.push_back(std::vector(100, ' ')); // Create rows with 100 spaces each for (unsigned int i = 0; i < char_rows; i++) { for (unsigned int j = 0; j < char_cols; j++) { letters[i][j + curr_col] = character[i][j]; } } curr_col += (char_cols + 2); } /* std::vector > getletters() { return letters; } */ void printvector() { for (unsigned int i = 0; i < letters.size(); i++) { unsigned int lastspace=letters[0].size(); for (unsigned int j=letters[0].size()-1; j>0; j--) if (letters[i][j]!=' ') { lastspace=j; break; } ///for (unsigned int j = 0; j < letters[0].size(); j++) for (unsigned int j = 0; j < lastspace; j++) myprintf("%c",letters[i][j]); myprintf("\n"); } } /********************************adding virtual functions********************************/ // Virtual functions for space virtual char **space() { return 0; } // Virtual functions for lowercase letters virtual char **a() { return 0; } virtual char **b() { return 0; } virtual char **c() { return 0; } virtual char **d() { return 0; } virtual char **e() { return 0; } virtual char **f() { return 0; } virtual char **g() { return 0; } virtual char **h() { return 0; } virtual char **i() { return 0; } virtual char **j() { return 0; } virtual char **k() { return 0; } virtual char **l() { return 0; } virtual char **m() { return 0; } virtual char **n() { return 0; } virtual char **o() { return 0; } virtual char **p() { return 0; } virtual char **q() { return 0; } virtual char **r() { return 0; } virtual char **s() { return 0; } virtual char **t() { return 0; } virtual char **u() { return 0; } virtual char **v() { return 0; } virtual char **w() { return 0; } virtual char **x() { return 0; } virtual char **y() { return 0; } virtual char **z() { return 0; } // Virtual functions for uppercase letters virtual char **A() { return 0; } virtual char **B() { return 0; } virtual char **C() { return 0; } virtual char **D() { return 0; } virtual char **E() { return 0; } virtual char **F() { return 0; } virtual char **G() { return 0; } virtual char **H() { return 0; } virtual char **I() { return 0; } virtual char **J() { return 0; } virtual char **K() { return 0; } virtual char **L() { return 0; } virtual char **M() { return 0; } virtual char **N() { return 0; } virtual char **O() { return 0; } virtual char **P() { return 0; } virtual char **Q() { return 0; } virtual char **R() { return 0; } virtual char **S() { return 0; } virtual char **T() { return 0; } virtual char **U() { return 0; } virtual char **V() { return 0; } virtual char **W() { return 0; } virtual char **X() { return 0; } virtual char **Y() { return 0; } virtual char **Z() { return 0; } virtual char **zero() { return 0; } virtual char **one() { return 0; } virtual char **two() { return 0; } virtual char **three() { return 0; } virtual char **four() { return 0; } virtual char **five() { return 0; } virtual char **six() { return 0; } virtual char **seven() { return 0; } virtual char **eight() { return 0; } virtual char **nine() { return 0; } /********************************done adding virtual functions********************************/ virtual ~Fonts() { destroyspace(); } /* ~Fonts() { destroyspace(); } */ }; class SevenStar : public Fonts { static const int rows = 7; static const int cols = 7; public: SevenStar() : Fonts(rows, cols) {} char **A() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j == 2 || j == 3 || j == 4) character[i][j] = 'A'; else character[i][j] = ' '; } if (i == 1) { if (j % 3 == 0) { character[i][j] = ' '; } else character[i][j] = 'A'; } if (i == 2 || i == 3 || i == 5 || i == 6) { if (j == 0 || j == 1 || j == 5 || j == 6) { character[i][j] = 'A'; } else { character[i][j] = ' '; } } if (i == 4) { character[i][j] = 'A'; } } } return character; } char **B() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = 'B'; } if (i >= 1 && i <= 5 && i != 3) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'B'; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = 'B'; } } } return character; } char **C() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { // first aur last line if (i == 0 || i == 6) { if ((j % 7) % 3 != 0) { character[i][j] = 'C'; } else { character[i][j] = ' '; } } // second nd second last line if (i == 1 || i == 5) { if (((j) % 7) < 2 || ((j) % 7) > 4) { character[i][j] = 'C'; } else { character[i][j] = ' '; } } // rest if (i == 2 || i == 4 || i == 3) { if (((j) % 7) < 2) { character[i][j] = 'C'; } else { character[i][j] = ' '; } } } } return character; } char **D() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (((j) % 7) != 0 && ((j) % 7) % 3 == 0) character[i][j] = ' '; else character[i][j] = 'D'; } else { if (((j) % 7) == 1 || ((j) % 7) == 2 || ((j) % 7) == 5 || ((j) % 7) == 6) character[i][j] = 'D'; else character[i][j] = ' '; } } } return character; } char **E() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { character[i][j] = 'E'; } if (i == 1 || i == 5) { if (j == 0 || j == 1 || j == 5 || j == 6) character[i][j] = 'E'; else character[i][j] = ' '; } if (i == 2 || i == 4) { if (j == 0 || j == 1) character[i][j] = 'E'; else character[i][j] = ' '; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = 'E'; } } } return character; } char **F() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { character[i][j] = 'F'; } if (i == 2 || i == 5 || i == 6 || i == 1 || i == 4) { if (j == 0 || j == 1) character[i][j] = 'F'; else character[i][j] = ' '; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = 'F'; } } // cout<= 0 && i <= 6) { if (j == 0 || j == 1 || j == 5 || j == 6) character[i][j] = 'H'; else character[i][j] = ' '; } if (i == 3) { if (j > 1 && j < 5) character[i][j] = 'H'; } } } return character; } char **I() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { character[i][j] = 'I'; } else { if (j == 2 || j == 3 || j == 4) { character[i][j] = 'I'; } else character[i][j] = ' '; } } } return character; } char **J() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j < 3) character[i][j] = ' '; else character[i][j] = 'J'; } if (i == 1 || i == 2 || i == 3) { if (j == 4 || j == 5) character[i][j] = 'J'; else character[i][j] = ' '; } if (i == 4 || i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = 'J'; } if (i == 6) { if (j == 0 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = 'J'; } } } return character; } char **K() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'K'; } if (i == 1 || i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = 'K'; } if (i == 3) { if (j == 4 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = 'K'; } if (i == 2 || i == 4) { if (j == 2 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = 'K'; } } } return character; } char **L() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i < 6) { if (j == 0 || j == 1) character[i][j] = 'L'; else character[i][j] = ' '; } else character[i][j] = 'L'; } } return character; } char **M() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'M'; } if (i == 1) { if (j == 3) { character[i][j] = ' '; } else character[i][j] = 'M'; } if (i == 2) { character[i][j] = 'M'; } if (i == 3) { if (j == 2 || j == 4) character[i][j] = ' '; else character[i][j] = 'M'; } if (i >= 4 && i <= 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'M'; } } } return character; } char **N() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'N'; } if (i == 2 || i == 1) { if (j == 3 || j == 4) { character[i][j] = ' '; } else character[i][j] = 'N'; } if (i == 3) { if (j == 2 || j == 4) { character[i][j] = ' '; } else { character[i][j] = 'N'; } } if (i == 4 || i == 5) { if (j == 2 || j == 3) character[i][j] = ' '; else character[i][j] = 'N'; } } } return character; } char **O() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 6 || i == 0) { if (j == 0 || j == 6) character[i][j] = ' '; else character[i][j] = 'O'; } else { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'O'; } } // cout<= 4 && i <= 6) { if (j == 0 || j == 1) { character[i][j] = 'P'; } else { character[i][j] = ' '; } } } } return character; } char **Q() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j % 3 == 0) character[i][j] = ' '; else character[i][j] = 'Q'; } if (i >= 1 && i <= 4) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'Q'; } if (i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = 'Q'; } if (i == 6) { if (j == 0 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = 'Q'; } } // cout<= 1 && i <= 6) { if (j == 3 || j == 2) character[i][j] = 'T'; else character[i][j] = ' '; } } // cout< 3) { if (j == 2 || j == 3) character[i][j] = 'Y'; else character[i][j] = ' '; } } } return character; } char **Z() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j > 0) character[i][j] = 'Z'; else character[i][j] = ' '; } if (i == 1) { if (j == 5 || j == 6) character[i][j] = 'Z'; else character[i][j] = ' '; } if (i == 2) { if (j == 4 || j == 5) character[i][j] = 'Z'; else character[i][j] = ' '; } if (i == 3) { if (j == 3 || j == 4) character[i][j] = 'Z'; else character[i][j] = ' '; } if (i == 4) { if (j == 3 || j == 2) character[i][j] = 'Z'; else character[i][j] = ' '; } if (i == 5) { if (j == 1 || j == 2) character[i][j] = 'Z'; else character[i][j] = ' '; } } // cout<= 1 && i <= 5 && i != 3) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **c() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { // first aur last line if (i == 0 || i == 6) { if ((j % 7) % 3 != 0) { character[i][j] = '%'; } else { character[i][j] = ' '; } } // second nd second last line if (i == 1 || i == 5) { if (((j) % 7) < 2 || ((j) % 7) > 4) { character[i][j] = '%'; } else { character[i][j] = ' '; } } // rest if (i == 2 || i == 4 || i == 3) { if (((j) % 7) < 2) { character[i][j] = '%'; } else { character[i][j] = ' '; } } } } return character; } char **d() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (((j) % 7) != 0 && ((j) % 7) % 3 == 0) character[i][j] = ' '; else character[i][j] = '%'; } else { if (((j) % 7) == 1 || ((j) % 7) == 2 || ((j) % 7) == 5 || ((j) % 7) == 6) character[i][j] = '%'; else character[i][j] = ' '; } } } return character; } char **e() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { character[i][j] = '%'; } if (i == 1 || i == 5) { if (j == 0 || j == 1 || j == 5 || j == 6) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 2 || i == 4) { if (j == 0 || j == 1) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **f() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { character[i][j] = '%'; } if (i == 2 || i == 5 || i == 6 || i == 1 || i == 4) { if (j == 0 || j == 1) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 3) { if (j == 6) character[i][j] = ' '; else character[i][j] = '%'; } } // cout<= 0 && i <= 6) { if (j == 0 || j == 1 || j == 5 || j == 6) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 3) { if (j > 1 && j < 5) character[i][j] = '%'; } } } return character; } char **i() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { character[i][j] = '%'; } else { if (j == 2 || j == 3 || j == 4) { character[i][j] = '%'; } else character[i][j] = ' '; } } } return character; } char **j() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j < 3) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 1 || i == 2 || i == 3) { if (j == 4 || j == 5) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 4 || i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 6) { if (j == 0 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **k() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 1 || i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 3) { if (j == 4 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 2 || i == 4) { if (j == 2 || j == 5 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **l() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i < 6) { if (j == 0 || j == 1) character[i][j] = '%'; else character[i][j] = ' '; } else character[i][j] = '%'; } } return character; } char **m() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 1) { if (j == 3) { character[i][j] = ' '; } else character[i][j] = '%'; } if (i == 2) { character[i][j] = '%'; } if (i == 3) { if (j == 2 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i >= 4 && i <= 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **n() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 2 || i == 1) { if (j == 3 || j == 4) { character[i][j] = ' '; } else character[i][j] = '%'; } if (i == 3) { if (j == 2 || j == 4) { character[i][j] = ' '; } else { character[i][j] = '%'; } } if (i == 4 || i == 5) { if (j == 2 || j == 3) character[i][j] = ' '; else character[i][j] = '%'; } } } return character; } char **o() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 6 || i == 0) { if (j == 0 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } else { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } } // cout<= 4 && i <= 6) { if (j == 0 || j == 1) { character[i][j] = '%'; } else { character[i][j] = ' '; } } } } return character; } char **q() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0) { if (j % 3 == 0) character[i][j] = ' '; else character[i][j] = '%'; } if (i >= 1 && i <= 4) { if (j == 2 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 5) { if (j == 2 || j == 3 || j == 6) character[i][j] = ' '; else character[i][j] = '%'; } if (i == 6) { if (j == 0 || j == 3 || j == 4) character[i][j] = ' '; else character[i][j] = '%'; } } // cout<= 1 && i <= 6) { if (j == 3 || j == 2) character[i][j] = '%'; else character[i][j] = ' '; } } // cout< 3) { if (j == 2 || j == 3) character[i][j] = '%'; else character[i][j] = ' '; } } } return character; } char **z() { char **character = getCharGrid(); for (int i = 0; i < 7; i++) { for (int j = 0; j < 7; j++) { if (i == 0 || i == 6) { if (j > 0) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 1) { if (j == 5 || j == 6) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 2) { if (j == 4 || j == 5) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 3) { if (j == 3 || j == 4) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 4) { if (j == 3 || j == 2) character[i][j] = '%'; else character[i][j] = ' '; } if (i == 5) { if (j == 1 || j == 2) character[i][j] = '%'; else character[i][j] = ' '; } } // cout<font = new SevenStar(); } void print(const std::string &text) { char **character = 0; for (size_t i = 0; i < text.size(); i++) { char c = text[i]; // Uppercase alphabets if (c == 'A') character = font->A(); else if (c == 'B') character = font->B(); else if (c == 'C') character = font->C(); else if (c == 'D') character = font->D(); else if (c == 'E') character = font->E(); else if (c == 'F') character = font->F(); else if (c == 'G') character = font->G(); else if (c == 'H') character = font->H(); else if (c == 'I') character = font->I(); else if (c == 'J') character = font->J(); else if (c == 'K') character = font->K(); else if (c == 'L') character = font->L(); else if (c == 'M') character = font->M(); else if (c == 'N') character = font->N(); else if (c == 'O') character = font->O(); else if (c == 'P') character = font->P(); else if (c == 'Q') character = font->Q(); else if (c == 'R') character = font->R(); else if (c == 'S') character = font->S(); else if (c == 'T') character = font->T(); else if (c == 'U') character = font->U(); else if (c == 'V') character = font->V(); else if (c == 'W') character = font->W(); else if (c == 'X') character = font->X(); else if (c == 'Y') character = font->Y(); else if (c == 'Z') character = font->Z(); // Lowercase alphabets else if (c == 'a') character = font->a(); else if (c == 'b') character = font->b(); else if (c == 'c') character = font->c(); else if (c == 'd') character = font->d(); else if (c == 'e') character = font->e(); else if (c == 'f') character = font->f(); else if (c == 'g') character = font->g(); else if (c == 'h') character = font->h(); else if (c == 'i') character = font->i(); else if (c == 'j') character = font->j(); else if (c == 'k') character = font->k(); else if (c == 'l') character = font->l(); else if (c == 'm') character = font->m(); else if (c == 'n') character = font->n(); else if (c == 'o') character = font->o(); else if (c == 'p') character = font->p(); else if (c == 'q') character = font->q(); else if (c == 'r') character = font->r(); else if (c == 's') character = font->s(); else if (c == 't') character = font->t(); else if (c == 'u') character = font->u(); else if (c == 'v') character = font->v(); else if (c == 'w') character = font->w(); else if (c == 'x') character = font->x(); else if (c == 'y') character = font->y(); else if (c == 'z') character = font->z(); // Numbers else if (c == '0') character = font->zero(); else if (c == '1') character = font->one(); else if (c == '2') character = font->two(); else if (c == '3') character = font->three(); else if (c == '4') character = font->four(); else if (c == '5') character = font->five(); else if (c == '6') character = font->six(); else if (c == '7') character = font->seven(); else if (c == '8') character = font->eight(); else if (c == '9') character = font->nine(); // for space else if (c == ' ') character = font->space(); font->pushChar(character); } font->printvector(); // font->destroyspace(); } }; } // namespace ascii /// LICENSE_END.23 int64_t g_allocatedram=0; int64_t g_arrayram=0; char* mymigliaia(int64_t i_bytes,char* i_buffer,int i_buffersize) { if (i_buffer==NULL) { printf("02096: guru i_buffer null\n"); exit(0); } if (i_buffersize<10) { printf("02106: guru buffer too small\n"); exit(0); } if (i_bytes<0) { snprintf(i_buffer,10,"negative"); return i_buffer; } char *p=&i_buffer[i_buffersize-1]; unsigned int i=0; *p='\0'; do { if ((i%3==0) && (i!=0)) *--p='.'; *--p='0'+i_bytes%10; i_bytes/=10; i++; } while(i_bytes!=0); return p; } /// very quick and very dirty output inline char* migliaia(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } inline char* migliaia2(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } inline char* migliaia3(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } inline char* migliaia4(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } inline char* migliaia5(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } inline char* migliaia6(int64_t n) { static char retbuf[30]; return mymigliaia(n,retbuf,30); } /// LICENSE_START.7 /// OK we need a fix for 64-byte-align problem on some Linux compiler /* https://github.com/embeddedartistry/embedded-resources/blob/master/examples/c/malloc_aligned.c */ #ifndef align_up #define align_up(num, align) \ (((num) + ((align) - 1)) & ~((align) - 1)) #endif // corresponds to #ifndef (#ifndef align_up) //Convenience macro for memalign, the linux API ///#define memalign(align, size) aligned_malloc(align, size) //Number of bytes we're using for storing the aligned pointer offset typedef uint16_t myoffset_t; #define PTR_OFFSET_SZ sizeof(myoffset_t) /** * aligned_malloc takes in the requested alignment and size * We will call malloc with extra bytes for our header and the offset * required to guarantee the desired alignment. * Some fix by me (better error handling) */ void * aligned_malloc(size_t align, size_t size) { void * ptr = NULL; //We want it to be a power of two since align_up operates on powers of two /// assert((align & (align - 1)) == 0); if ((align & (align - 1)) != 0 || align < sizeof(void*)) return NULL; if(align && size) { /* * We know we have to fit an offset value * We also allocate extra bytes to ensure we can meet the alignment */ uint32_t hdr_size = PTR_OFFSET_SZ + (align - 1); void * p = malloc(size + hdr_size); if(p) { /* * Add the offset size to malloc's pointer (we will always store that) * Then align the resulting value to the arget alignment */ ptr = (void *) align_up(((uintptr_t)p + PTR_OFFSET_SZ), align); //Calculate the offset and store it behind our aligned pointer ///*((myoffset_t *)ptr - 1) = (myoffset_t)((uintptr_t)ptr - (uintptr_t)p); if (ptr) { // Calcola l'offset e memorizzalo *((myoffset_t *)ptr - 1) = (myoffset_t)((uintptr_t)ptr - (uintptr_t)p); } else { // Se il calcolo del puntatore fallisce, libera la memoria free(p); return NULL; } } // else NULL, could not malloc else { return NULL; } } //else NULL, invalid arguments return ptr; } /** * aligned_free works like free(), but we work backwards from the returned * pointer to find the correct offset and pointer location to return to free() * Note that it is VERY BAD to call free() on an aligned_malloc() pointer. */ void aligned_free(void * ptr) { ///return; if (flagdebug5) myprintf("72252: aligned_free [1]\n"); if (!ptr) return; if (flagdebug5) myprintf("72254: aligned_free [2]\n"); //assert(ptr); /* * Walk backwards from the passed-in pointer to get the pointer offset * We convert to an offset_t pointer and rely on pointer math to get the data */ myoffset_t offset = *((myoffset_t *)ptr - 1); if (flagdebug5) myprintf("72254: aligned_free [3]\n"); /* * Once we have the offset, we can get our original pointer and call free */ void * p = (void *)((uint8_t *)ptr - offset); if (flagdebug5) myprintf("72254: aligned_free [4] ptr %s offset %s voidp %s\n",migliaia(int64_t(ptr)),migliaia2(int64_t(offset)),migliaia3(int64_t(p))); free(p); if (flagdebug5) myprintf("72254: aligned_free [5]\n"); } /// LICENSE_END.7 /* Let's try to force align everywhere, on some kind of "choosy" CPUs I do not have such kind of iron, just a try... */ static void* franz_malloc(size_t i_size) { assert(i_size>0); if (i_size==0) { myprintf("06112: franz_malloc i_size zero!\n"); exit(0); } g_allocatedram+=i_size; #ifdef MALLOC_ALIGN return aligned_malloc(MALLOC_ALIGN,i_size); #else return malloc(i_size); #endif // corresponds to #ifdef (#ifdef MALLOC_ALIGN) } static void franz_free(void* i_mem) { if (i_mem==NULL) return; #ifdef MALLOC_ALIGN aligned_free(i_mem); #else free(i_mem); #endif // corresponds to #ifdef (#ifdef MALLOC_ALIGN) } static void* franz_extend(void* i_mem,size_t i_size,size_t i_oldsize) { #ifdef MALLOC_ALIGN void *new_mem; if (i_size==0) { ///#ifdef DEBUG printf("01200: realloc i_size == 0\n"); ///#endif franz_free(i_mem); return NULL; } if (!i_mem) { ///#ifdef DEBUG printf("01205: realloc from empty, allocating %08d\n",(int)i_size); ///#endif ///g_allocatedram+=i_size; return franz_malloc(i_size); } if (i_oldsize0) i_oldsize++; /// compiler be quiet! g_allocatedram+=i_size; g_allocatedram-=i_oldsize; return realloc(i_mem,i_size); #endif // corresponds to #ifdef (#ifdef MALLOC_ALIGN) } void mystrrev(char *i_str) { if (i_str==NULL) return; int i,j; char a; unsigned len=strlen((const char *)i_str); for (i=0,j=len-1;i19) i_len=19; static const char xlat[] = "0123456789"; char tmp[20]; char *p1=tmp; memset(tmp,0,sizeof(tmp)); do { *p1++ = xlat[value % 10]; } while((value /= 10)); mystrrev(&tmp[0]); std::string risultato=tmp; if (i_len>0) if (risultato.size()<(unsigned int)i_len) risultato=std::string(i_len-risultato.size(), '0') + risultato; return risultato; } std::string bin2hex_32(uint32_t i_thenumber) { static const char dec2hex[16+1] = "0123456789ABCDEF"; char buf[16+1]; ///yep, a bit large uint8_t numerino; for (int j=3;j>=0;j--) { numerino=i_thenumber&255; buf[j*2+1] =dec2hex[numerino&15]; buf[j*2] =dec2hex[(numerino>>4)&15]; i_thenumber>>=8; } buf[8]=0; return buf; } std::string bin2hex_64(uint64_t i_thenumber) { static const char dec2hex[16+1] = "0123456789ABCDEF"; char buf[16+1]; uint8_t numerino; for (int j=7;j>=0;j--) { numerino=i_thenumber&255; buf[j*2+1] =dec2hex[numerino&15]; buf[j*2] =dec2hex[(numerino>>4)&15]; i_thenumber>>=8; } buf[16]=0; return buf; } std::string bin2hex_128(uint64_t i_high,uint64_t i_low) { std::string shigh=bin2hex_64(i_high); std::string slow =bin2hex_64(i_low); return shigh+slow; } #ifdef _WIN32 /// LICENSE_START.22 /// A "stripped" LZ4 #define LZ4_HEAPMODE 0 #define LZ4_ACCELERATION_DEFAULT 1 #define LZ4_ACCELERATION_MAX 65537 #define LZ4_MEMORY_USAGE_MIN 10 //1KB #define LZ4_MEMORY_USAGE_DEFAULT 14 /// 16KB #define LZ4_MEMORY_USAGE_MAX 20 #define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) #define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */ #define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32) #define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */ #define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */ #define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */ #define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */ #define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) #define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) #define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ #define LZ4_FORCE_O2 #define LZ4_ALIGN_TEST 1 #define LZ4_STREAMDECODE_MINSIZE 32 #define LZ4_STREAM_MINSIZE ((1UL << (LZ4_MEMORY_USAGE)) + 32) /* static size, for inter-version compatibility */ #define MINMATCH 4 #define WILDCOPYLENGTH 8 #define LASTLITERALS 5 /* see ../doc/lz4_Block_format.md#parsing-restrictions */ #define MFLIMIT 12 /* see ../doc/lz4_Block_format.md#parsing-restrictions */ #define MATCH_SAFEGUARD_DISTANCE ((2*WILDCOPYLENGTH) - MINMATCH) /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */ #define FASTLOOP_SAFE_DISTANCE 64 static const int LZ4_minLength = (MFLIMIT+1); #define KB *(1 <<10) #define MB *(1 <<20) #define GB *(1U<<30) #define LZ4_DISTANCE_ABSOLUTE_MAX 65535 #define ML_BITS 4 #define ML_MASK ((1U<= 199901L /* C99 */ # ifdef __GNUC__ # define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) # else # define LZ4_FORCE_INLINE static inline # endif # else # define LZ4_FORCE_INLINE static # endif /* __STDC_VERSION__ */ # endif /* _MSC_VER */ #endif /* LZ4_FORCE_INLINE */ // corresponds to #ifndef (#ifndef LZ4_FORCE_INLINE) #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) #endif // corresponds to #if (#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)) #ifndef likely #define likely(expr) expect((expr) != 0, 1) #endif // corresponds to #ifndef (#ifndef likely) #ifndef unlikely #define unlikely(expr) expect((expr) != 0, 0) #endif // corresponds to #ifndef (#ifndef unlikely) #define ALLOC(s) malloc(s) #define ALLOC_AND_ZERO(s) calloc(1,s) #define FREEMEM(p) free(p) #define LZ4_memset(p,v,s) memset((p),(v),(s)) #define MEM_INIT(p,v,s) LZ4_memset((p),(v),(s)) static int LZ4_isAligned(const void* ptr, size_t alignment) { return ((size_t)ptr & (alignment -1)) == 0; } typedef uint8_t BYTE; typedef uint16_t U16; typedef uint32_t U32; typedef int32_t S32; typedef uint64_t U64; typedef uintptr_t uptrval; #if defined(__x86_64__) typedef U64 reg_t; /* 64-bits in x32 mode */ #else typedef size_t reg_t; /* 32-bits in x32 mode */ #endif // corresponds to #if (#if defined(__x86_64__)) typedef enum { notLimited = 0, limitedOutput = 1, fillOutput = 2 } limitedOutput_directive; #if !defined(LZ4_memcpy) # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) # else # define LZ4_memcpy(dst, src, size) memcpy(dst, src, size) # endif #endif // corresponds to #if (#if !defined(LZ4_memcpy)) #if !defined(LZ4_memmove) # if defined(__GNUC__) && (__GNUC__ >= 4) # define LZ4_memmove __builtin_memmove # else # define LZ4_memmove memmove # endif #endif // corresponds to #if (#if !defined(LZ4_memmove)) static unsigned LZ4_isLittleEndian(void) { return 1; ///const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ ///return one.c[0]; } #if defined(__GNUC__) || defined(__INTEL_COMPILER) #define LZ4_PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) #elif defined(_MSC_VER) #define LZ4_PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) #endif // corresponds to #if (#if defined(__GNUC__) || defined(__INTEL_COMPILER)) LZ4_PACK(typedef struct { U16 u16; }) LZ4_unalign16; LZ4_PACK(typedef struct { U32 u32; }) LZ4_unalign32; LZ4_PACK(typedef struct { reg_t uArch; }) LZ4_unalignST; static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign16*)ptr)->u16; } static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign32*)ptr)->u32; } static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalignST*)ptr)->uArch; } static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign16*)memPtr)->u16 = value; } static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign32*)memPtr)->u32 = value; } static U16 LZ4_readLE16(const void* memPtr) { if (LZ4_isLittleEndian()) { return LZ4_read16(memPtr); } else { const BYTE* p = (const BYTE*)memPtr; return (U16)((U16)p[0] + (p[1]<<8)); } } static void LZ4_writeLE16(void* memPtr, U16 value) { if (LZ4_isLittleEndian()) { LZ4_write16(memPtr, value); } else { BYTE* p = (BYTE*)memPtr; p[0] = (BYTE) value; p[1] = (BYTE)(value>>8); } } /* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ LZ4_FORCE_INLINE void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d= 16. */ LZ4_FORCE_INLINE void LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd) { BYTE* d = (BYTE*)dstPtr; const BYTE* s = (const BYTE*)srcPtr; BYTE* const e = (BYTE*)dstEnd; do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d= dstPtr + MINMATCH * - there is at least 8 bytes available to write after dstEnd */ LZ4_FORCE_INLINE void LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) { BYTE v[8]; assert(dstEnd >= dstPtr + MINMATCH); switch(offset) { case 1: MEM_INIT(v, *srcPtr, 8); break; case 2: LZ4_memcpy(v, srcPtr, 2); LZ4_memcpy(&v[2], srcPtr, 2); #if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ # pragma warning(push) # pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ #endif // corresponds to #if (#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */) LZ4_memcpy(&v[4], v, 4); #if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ # pragma warning(pop) #endif // corresponds to #if (#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */) break; case 4: LZ4_memcpy(v, srcPtr, 4); LZ4_memcpy(&v[4], srcPtr, 4); break; default: LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset); return; } LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; while (dstPtr < dstEnd) { LZ4_memcpy(dstPtr, v, 8); dstPtr += 8; } } #endif // corresponds to #if (#if LZ4_FAST_DEC_LOOP) /*-************************************ * Common functions **************************************/ static unsigned LZ4_NbCommonBytes (reg_t val) { assert(val != 0); if (LZ4_isLittleEndian()) { if (sizeof(val) == 8) { # if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT) /*-************************************************************************************************* * ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11. * The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics * including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC. ****************************************************************************************************/ # if defined(__clang__) && (__clang_major__ < 10) /* Avoid undefined clang-cl intrinsics issue. * See https://github.com/lz4/lz4/pull/1017 for details. */ return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3; # else /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */ return (unsigned)_tzcnt_u64(val) >> 3; # endif # elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; _BitScanForward64(&r, (U64)val); return (unsigned)r >> 3; # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctzll((U64)val) >> 3; # else const U64 m = 0x0101010101010101ULL; val ^= val - 1; return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56); # endif } else /* 32 bits */ { # if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; _BitScanForward(&r, (U32)val); return (unsigned)r >> 3; # elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_ctz((U32)val) >> 3; # else const U32 m = 0x01010101; return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24; # endif } } else /* Big Endian CPU */ { if (sizeof(val)==8) { # if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clzll((U64)val) >> 3; # else #if 1 /* this method is probably faster, * but adds a 128 bytes lookup table */ static const unsigned char ctz7_tab[128] = { 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, }; U64 const mask = 0x0101010101010101ULL; U64 const t = (((val >> 8) - mask) | val) & mask; return ctz7_tab[(t * 0x0080402010080402ULL) >> 57]; #else /* this method doesn't consume memory space like the previous one, * but it contains several branches, * that may end up slowing execution */ static const U32 by32 = sizeof(val)*4; /* 32 on 64 bits (goal), 16 on 32 bits. Just to avoid some static analyzer complaining about shift by 32 on 32-bits target. Note that this code path is never triggered in 32-bits mode. */ unsigned r; if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; } if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } r += (!val); return r; #endif // corresponds to #if (#if 1) # endif } else /* 32 bits */ { # if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ !defined(LZ4_FORCE_SW_BITCOUNT) return (unsigned)__builtin_clz((U32)val) >> 3; # else val >>= 8; val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) | (val + 0x00FF0000)) >> 24; return (unsigned)val ^ 3; # endif } } } #define STEPSIZE sizeof(reg_t) LZ4_FORCE_INLINE unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { const BYTE* const pStart = pIn; if (likely(pIn < pInLimit-(STEPSIZE-1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; } else { return LZ4_NbCommonBytes(diff); } } while (likely(pIn < pInLimit-(STEPSIZE-1))) { reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn); if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; } pIn += LZ4_NbCommonBytes(diff); return (unsigned)(pIn - pStart); } if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; } if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; } if ((pIn compression run slower on incompressible data */ typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize); int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const void* dictStart, size_t dictSize); LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; if (LZ4_isLittleEndian()) { const U64 prime5bytes = 889523592379ULL; return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); } else { const U64 prime8bytes = 11400714785074694791ULL; return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } } LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); return LZ4_hash4(LZ4_read32(p), tableType); } LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { default: /* fallthrough */ case clearedTable: { /* illegal! */ assert(0); return; } case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; } case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; } case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; } } } LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) { switch (tableType) { default: /* fallthrough */ case clearedTable: /* fallthrough */ case byPtr: { /* illegal! */ assert(0); return; } case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; } case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; } } } /* LZ4_putPosition*() : only used in byPtr mode */ LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType) { const BYTE** const hashTable = (const BYTE**)tableBase; assert(tableType == byPtr); (void)tableType; hashTable[h] = p; } LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType); } /* LZ4_getIndexOnHash() : * Index of match position registered in hash table. * hash position must be calculated by using base+index, or dictBase+index. * Assumption 1 : only valid if tableType == byU32 or byU16. * Assumption 2 : h is presumed valid (within limits of hash table) */ LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) { LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); if (tableType == byU32) { const U32* const hashTable = (const U32*) tableBase; assert(h < (1U << (LZ4_MEMORY_USAGE-2))); return hashTable[h]; } if (tableType == byU16) { const U16* const hashTable = (const U16*) tableBase; assert(h < (1U << (LZ4_MEMORY_USAGE-1))); return hashTable[h]; } assert(0); return 0; /* forbidden case */ } static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType) { assert(tableType == byPtr); (void)tableType; { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } } LZ4_FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, const void* tableBase, tableType_t tableType) { U32 const h = LZ4_hashPosition(p, tableType); return LZ4_getPositionOnHash(h, tableBase, tableType); } /** LZ4_compress_generic_validated() : * inlined, to ensure branches are decided at compilation time. * The following conditions are presumed already validated: * - source != NULL * - inputSize > 0 */ LZ4_FORCE_INLINE int LZ4_compress_generic_validated( LZ4_stream_t_internal* const cctx, const char* const source, char* const dest, const int inputSize, int* inputConsumed, /* only written when outputDirective == fillOutput */ const int maxOutputSize, const limitedOutput_directive outputDirective, const tableType_t tableType, const dict_directive dictDirective, const dictIssue_directive dictIssue, const int acceleration) { int result; const BYTE* ip = (const BYTE*)source; U32 const startIndex = cctx->currentOffset; const BYTE* base = (const BYTE*)source - startIndex; const BYTE* lowLimit; const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx; const BYTE* const dictionary = dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary; const U32 dictSize = dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize; const U32 dictDelta = (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with indexes in current context */ int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; const BYTE* const matchlimit = iend - LASTLITERALS; /* the dictCtx currentOffset is indexed on the start of the dictionary, * while a dictionary in the current context precedes the currentOffset */ const BYTE* dictBase = (dictionary == NULL) ? NULL : (dictDirective == usingDictCtx) ? dictionary + dictSize - dictCtx->currentOffset : dictionary + dictSize - startIndex; BYTE* op = (BYTE*) dest; BYTE* const olimit = op + maxOutputSize; U32 offset = 0; U32 forwardH; DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType); assert(ip != NULL); if (tableType == byU16) assert(inputSize= 1); lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0); /* Update context state */ if (dictDirective == usingDictCtx) { /* Subsequent linked blocks can't use the dictionary. */ /* Instead, they use the block we just compressed. */ cctx->dictCtx = NULL; cctx->dictSize = (U32)inputSize; } else { cctx->dictSize += (U32)inputSize; } cctx->currentOffset += (U32)inputSize; cctx->tableType = (U32)tableType; if (inputSizehashTable, byPtr); } else { LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType); } } ip++; forwardH = LZ4_hashPosition(ip, tableType); /* Main Loop */ for ( ; ; ) { const BYTE* match; BYTE* token; const BYTE* filledIp; /* Find a match */ if (tableType == byPtr) { const BYTE* forwardIp = ip; int step = 1; int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; assert(ip < mflimitPlusOne); match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType); forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType); } while ( (match+LZ4_DISTANCE_MAX < ip) || (LZ4_read32(match) != LZ4_read32(ip)) ); } else { /* byU32, byU16 */ const BYTE* forwardIp = ip; int step = 1; int searchMatchNb = acceleration << LZ4_skipTrigger; do { U32 const h = forwardH; U32 const current = (U32)(forwardIp - base); U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); assert(matchIndex <= current); assert(forwardIp - base < (ptrdiff_t)(2 GB - 1)); ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; assert(ip < mflimitPlusOne); if (dictDirective == usingDictCtx) { if (matchIndex < startIndex) { /* there was no match, try the dictionary */ assert(tableType == byU32); matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); match = dictBase + matchIndex; matchIndex += dictDelta; /* make dictCtx index comparable with current context */ lowLimit = dictionary; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; } } else if (dictDirective == usingExtDict) { if (matchIndex < startIndex) { DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex); assert(startIndex - matchIndex >= MINMATCH); assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; } } else { /* single continuous memory segment */ match = base + matchIndex; } forwardH = LZ4_hashPosition(forwardIp, tableType); LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); DEBUGLOG(7, "candidate at pos=%u (offset=%u \n", matchIndex, current - matchIndex); if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; } /* match outside of valid area */ assert(matchIndex < current); if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX)) && (matchIndex+LZ4_DISTANCE_MAX < current)) { continue; } /* too far */ assert((current - matchIndex) <= LZ4_DISTANCE_MAX); /* match now expected within distance */ if (LZ4_read32(match) == LZ4_read32(ip)) { if (maybe_extMem) offset = current - matchIndex; break; /* match found */ } } while(1); } /* Catch up */ filledIp = ip; assert(ip > anchor); /* this is always true as ip has been advanced before entering the main loop */ if ((match > lowLimit) && unlikely(ip[-1] == match[-1])) { do { ip--; match--; } while (((ip > anchor) & (match > lowLimit)) && (unlikely(ip[-1] == match[-1]))); } /* Encode Literals */ { unsigned const litLength = (unsigned)(ip - anchor); token = op++; if ((outputDirective == limitedOutput) && /* Check output buffer overflow */ (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) { return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } if ((outputDirective == fillOutput) && (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) { op--; goto _last_literals; } if (litLength >= RUN_MASK) { int len = (int)(litLength - RUN_MASK); *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } else *token = (BYTE)(litLength< olimit)) { /* the match was too close to the end, rewind and go to last literals */ op = token; goto _last_literals; } /* Encode Offset */ if (maybe_extMem) { /* static test */ DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE*)source)); assert(offset <= LZ4_DISTANCE_MAX && offset > 0); LZ4_writeLE16(op, (U16)offset); op+=2; } else { DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match)); assert(ip-match <= LZ4_DISTANCE_MAX); LZ4_writeLE16(op, (U16)(ip - match)); op+=2; } /* Encode MatchLength */ { unsigned matchCode; if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx) && (lowLimit==dictionary) /* match within extDict */ ) { const BYTE* limit = ip + (dictEnd-match); assert(dictEnd > match); if (limit > matchlimit) limit = matchlimit; matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); ip += (size_t)matchCode + MINMATCH; if (ip==limit) { unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit); matchCode += more; ip += more; } DEBUGLOG(6, " with matchLength=%d starting in extDict", matchCode+MINMATCH); } else { matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); ip += (size_t)matchCode + MINMATCH; DEBUGLOG(6, " with matchLength=%d", matchCode+MINMATCH); } if ((outputDirective) && /* Check output buffer overflow */ (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) { if (outputDirective == fillOutput) { /* Match description too long : reduce it */ U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255; ip -= matchCode - newMatchCode; assert(newMatchCode < matchCode); matchCode = newMatchCode; if (unlikely(ip <= filledIp)) { /* We have already filled up to filledIp so if ip ends up less than filledIp * we have positions in the hash table beyond the current position. This is * a problem if we reuse the hash table. So we have to remove these positions * from the hash table. */ const BYTE* ptr; DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip)); for (ptr = ip; ptr <= filledIp; ++ptr) { U32 const h = LZ4_hashPosition(ptr, tableType); LZ4_clearHash(h, cctx->hashTable, tableType); } } } else { assert(outputDirective == limitedOutput); return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } } if (matchCode >= ML_MASK) { *token += ML_MASK; matchCode -= ML_MASK; LZ4_write32(op, 0xFFFFFFFF); while (matchCode >= 4*255) { op+=4; LZ4_write32(op, 0xFFFFFFFF); matchCode -= 4*255; } op += matchCode / 255; *op++ = (BYTE)(matchCode % 255); } else *token += (BYTE)(matchCode); } /* Ensure we have enough space for the last literals. */ assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit)); anchor = ip; /* Test end of chunk */ if (ip >= mflimitPlusOne) break; /* Fill table */ { U32 const h = LZ4_hashPosition(ip-2, tableType); if (tableType == byPtr) { LZ4_putPositionOnHash(ip-2, h, cctx->hashTable, byPtr); } else { U32 const idx = (U32)((ip-2) - base); LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType); } } /* Test next position */ if (tableType == byPtr) { match = LZ4_getPosition(ip, cctx->hashTable, tableType); LZ4_putPosition(ip, cctx->hashTable, tableType); if ( (match+LZ4_DISTANCE_MAX >= ip) && (LZ4_read32(match) == LZ4_read32(ip)) ) { token=op++; *token=0; goto _next_match; } } else { /* byU32, byU16 */ U32 const h = LZ4_hashPosition(ip, tableType); U32 const current = (U32)(ip-base); U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); assert(matchIndex < current); if (dictDirective == usingDictCtx) { if (matchIndex < startIndex) { /* there was no match, try the dictionary */ assert(tableType == byU32); matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ matchIndex += dictDelta; } else { match = base + matchIndex; lowLimit = (const BYTE*)source; /* required for match length counter */ } } else if (dictDirective==usingExtDict) { if (matchIndex < startIndex) { assert(dictBase); match = dictBase + matchIndex; lowLimit = dictionary; /* required for match length counter */ } else { match = base + matchIndex; lowLimit = (const BYTE*)source; /* required for match length counter */ } } else { /* single memory segment */ match = base + matchIndex; } LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); assert(matchIndex < current); if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current)) && (LZ4_read32(match) == LZ4_read32(ip)) ) { token=op++; *token=0; if (maybe_extMem) offset = current - matchIndex; DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source)); goto _next_match; } } /* Prepare next loop */ forwardH = LZ4_hashPosition(++ip, tableType); } _last_literals: /* Encode Last Literals */ { size_t lastRun = (size_t)(iend - anchor); if ( (outputDirective) && /* Check output buffer overflow */ (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) { if (outputDirective == fillOutput) { /* adapt lastRun to fill 'dst' */ assert(olimit >= op); lastRun = (size_t)(olimit-op) - 1/*token*/; lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/ } else { assert(outputDirective == limitedOutput); return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ } } DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun); if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; } else { *op++ = (BYTE)(lastRun< 0); DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result); return result; } /** LZ4_compress_generic() : * inlined, to ensure branches are decided at compilation time; * takes care of src == (NULL, 0) * and forward the rest to LZ4_compress_generic_validated */ LZ4_FORCE_INLINE int LZ4_compress_generic( LZ4_stream_t_internal* const cctx, const char* const src, char* const dst, const int srcSize, int *inputConsumed, /* only written when outputDirective == fillOutput */ const int dstCapacity, const limitedOutput_directive outputDirective, const tableType_t tableType, const dict_directive dictDirective, const dictIssue_directive dictIssue, const int acceleration) { DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i", srcSize, dstCapacity); if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */ if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */ if (outputDirective != notLimited && dstCapacity <= 0) return 0; /* no output, can't write anything */ DEBUGLOG(5, "Generating an empty block"); assert(outputDirective == notLimited || dstCapacity >= 1); assert(dst != NULL); dst[0] = 0; if (outputDirective == fillOutput) { assert (inputConsumed != NULL); *inputConsumed = 0; } return 1; } assert(src != NULL); return LZ4_compress_generic_validated(cctx, src, dst, srcSize, inputConsumed, /* only written into if outputDirective == fillOutput */ dstCapacity, outputDirective, tableType, dictDirective, dictIssue, acceleration); } LZ4_stream_t* LZ4_createStream(void) { LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); g_allocatedram+=sizeof(LZ4_stream_t); LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal)); DEBUGLOG(4, "LZ4_createStream %p", lz4s); if (lz4s == NULL) return NULL; LZ4_initStream(lz4s, sizeof(*lz4s)); return lz4s; } static size_t LZ4_stream_t_alignment(void) { #if LZ4_ALIGN_TEST typedef struct { char c; LZ4_stream_t t; } t_a; return sizeof(t_a) - sizeof(LZ4_stream_t); #else return 1; /* effectively disabled */ #endif // corresponds to #if (#if LZ4_ALIGN_TEST) } LZ4_stream_t* LZ4_initStream (void* buffer, size_t size) { DEBUGLOG(5, "LZ4_initStream"); if (buffer == NULL) { return NULL; } if (size < sizeof(LZ4_stream_t)) { return NULL; } if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL; MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal)); return (LZ4_stream_t*)buffer; } int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { if (!LZ4_stream) return 0; /* support free on NULL */ DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream); FREEMEM(LZ4_stream); return (0); } #define HASH_UNIT sizeof(reg_t) static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize) { assert(nextSize >= 0); if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ /* rescale hash table */ U32 const delta = LZ4_dict->currentOffset - 64 KB; const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; DEBUGLOG(4, "LZ4_renormDictT"); for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; else LZ4_dict->hashTable[i] -= delta; } LZ4_dict->currentOffset = 64 KB; if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB; LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize; } } int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { const tableType_t tableType = byU32; LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse; const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL; DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize); LZ4_renormDictT(streamPtr, inputSize); /* fix index overflow */ if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; /* invalidate tiny dictionaries */ if ( (streamPtr->dictSize < 4) /* tiny dictionary : not enough for a hash */ && (dictEnd != source) /* prefix mode */ && (inputSize > 0) /* tolerance : don't lose history, in case next invocation would use prefix mode */ && (streamPtr->dictCtx == NULL) /* usingDictCtx */ ) { DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary); /* remove dictionary existence from history, to employ faster prefix mode */ streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE*)source; dictEnd = source; } /* Check overlapping input/dictionary space */ { const char* const sourceEnd = source + inputSize; if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ if (dictEnd == source) { if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); else return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration); } /* external dictionary mode */ { int result; if (streamPtr->dictCtx) { /* We depend here on the fact that dictCtx'es (produced by * LZ4_loadDict) guarantee that their tables contain no references * to offsets between dictCtx->currentOffset - 64 KB and * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe * to use noDictIssue even when the dict isn't a full 64 KB. */ if (inputSize > 4 KB) { /* For compressing large blobs, it is faster to pay the setup * cost to copy the dictionary's tables into the active context, * so that the compression loop is only looking into one table. */ LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); } else { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); } } else { /* small data <= 4 KB */ if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); } else { result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); } } streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; return result; } } typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; #undef MIN #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) /* Read the variable-length literal or match length. * * @ip : input pointer * @ilimit : position after which if length is not decoded, the input is necessarily corrupted. * @initial_check - check ip >= ipmax before start of loop. Returns initial_error if so. * @error (output) - error code. Must be set to 0 before call. **/ typedef size_t Rvl_t; static const Rvl_t rvl_error = (Rvl_t)(-1); LZ4_FORCE_INLINE Rvl_t read_variable_length(const BYTE** ip, const BYTE* ilimit, int initial_check) { Rvl_t s, length = 0; assert(ip != NULL); assert(*ip != NULL); assert(ilimit != NULL); if (initial_check && unlikely((*ip) >= ilimit)) { /* read limit reached */ return rvl_error; } s = **ip; (*ip)++; length += s; if (unlikely((*ip) > ilimit)) { /* read limit reached */ return rvl_error; } /* accumulator overflow detection (32-bit mode only) */ if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { return rvl_error; } if (likely(s != 255)) return length; do { s = **ip; (*ip)++; length += s; if (unlikely((*ip) > ilimit)) { /* read limit reached */ return rvl_error; } /* accumulator overflow detection (32-bit mode only) */ if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { return rvl_error; } } while (s == 255); return length; } /*! LZ4_decompress_generic() : * This generic decompression function covers all use cases. * It shall be instantiated several times, using different sets of directives. * Note that it is important for performance that this function really get inlined, * in order to remove useless branches during compilation optimization. */ LZ4_FORCE_INLINE int LZ4_decompress_generic( const char* const src, char* const dst, int srcSize, int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ earlyEnd_directive partialDecoding, /* full, partial */ dict_directive dict, /* noDict, withPrefix64k, usingExtDict */ const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { if ((src == NULL) || (outputSize < 0)) { return -1; } { const BYTE* ip = (const BYTE*) src; const BYTE* const iend = ip + srcSize; BYTE* op = (BYTE*) dst; BYTE* const oend = op + outputSize; BYTE* cpy; const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize; const int checkOffset = (dictSize < (int)(64 KB)); /* Set up the "end" pointers for the shortcut. */ const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/; const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/; const BYTE* match; size_t offset; unsigned token; size_t length; DEBUGLOG(5, "LZ4_decompress_generic (srcSize:%i, dstSize:%i)", srcSize, outputSize); /* Special cases */ assert(lowPrefix <= op); if (unlikely(outputSize==0)) { /* Empty output buffer */ if (partialDecoding) return 0; return ((srcSize==1) && (*ip==0)) ? 0 : -1; } if (unlikely(srcSize==0)) { return -1; } /* LZ4_FAST_DEC_LOOP: * designed for modern OoO performance cpus, * where copying reliably 32-bytes is preferable to an unpredictable branch. * note : fast loop may show a regression for some client arm chips. */ #if LZ4_FAST_DEC_LOOP if ((oend - op) < FASTLOOP_SAFE_DISTANCE) { DEBUGLOG(6, "skip fast decode loop"); goto safe_decode; } /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */ DEBUGLOG(6, "using fast decode loop"); while (1) { /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */ assert(oend - op >= FASTLOOP_SAFE_DISTANCE); assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ /* decode literal length */ if (length == RUN_MASK) { size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); if (addl == rvl_error) { DEBUGLOG(6, "error reading long literal length"); goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ /* copy literals */ LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); if ((op+length>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; } LZ4_wildCopy32(op, ip, op+length); ip += length; op += length; } else if (ip <= iend-(16 + 1/*max lit + offset + nextToken*/)) { /* We don't need to check oend, since we check it once for each loop below */ DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */ LZ4_memcpy(op, ip, 16); ip += length; op += length; } else { goto safe_literal_copy; } /* get offset */ offset = LZ4_readLE16(ip); ip+=2; DEBUGLOG(6, " offset = %zu", offset); match = op - offset; assert(match <= op); /* overflow check */ /* get matchlength */ length = token & ML_MASK; if (length == ML_MASK) { size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); if (addl == rvl_error) { DEBUGLOG(6, "error reading long match length"); goto _output_error; } length += addl; length += MINMATCH; if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; } } else { length += MINMATCH; if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { goto safe_match_copy; } /* Fastpath check: skip LZ4_wildCopy32 when true */ if ((dict == withPrefix64k) || (match >= lowPrefix)) { if (offset >= 8) { assert(match >= lowPrefix); assert(match <= op); assert(op + 18 <= oend); LZ4_memcpy(op, match, 8); LZ4_memcpy(op+8, match+8, 8); LZ4_memcpy(op+16, match+16, 2); op += length; continue; } } } if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) { DEBUGLOG(6, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match); goto _output_error; } /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) { DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd"); length = MIN(length, (size_t)(oend-op)); } else { DEBUGLOG(6, "end-of-block condition violated") goto _output_error; } } if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) { *op++ = *copyFrom++; } } else { LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; } /* copy match within block */ cpy = op + length; assert((op <= oend) && (oend-op >= 32)); if (unlikely(offset<16)) { LZ4_memcpy_using_offset(op, match, cpy, offset); } else { LZ4_wildCopy32(op, match, cpy); } op = cpy; /* wildcopy correction */ } safe_decode: #endif // corresponds to #if (#if LZ4_FAST_DEC_LOOP) /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */ DEBUGLOG(6, "using safe decode loop"); while (1) { assert(ip < iend); token = *ip++; length = token >> ML_BITS; /* literal length */ /* A two-stage shortcut for the most common case: * 1) If the literal length is 0..14, and there is enough space, * enter the shortcut and copy 16 bytes on behalf of the literals * (in the fast mode, only 8 bytes can be safely copied this way). * 2) Further if the match length is 4..18, copy 18 bytes in a similar * manner; but we ensure that there's enough space in the output for * those 18 bytes earlier, upon entering the shortcut (in other words, * there is a combined check for both stages). */ if ( (length != RUN_MASK) /* strictly "less than" on input, to re-enter the loop with at least one byte */ && likely((ip < shortiend) & (op <= shortoend)) ) { /* Copy the literals */ LZ4_memcpy(op, ip, 16); op += length; ip += length; /* The second stage: prepare for match copying, decode full info. * If it doesn't work out, the info won't be wasted. */ length = token & ML_MASK; /* match length */ offset = LZ4_readLE16(ip); ip += 2; match = op - offset; assert(match <= op); /* check overflow */ /* Do not deal with overlapping matches. */ if ( (length != ML_MASK) && (offset >= 8) && (dict==withPrefix64k || match >= lowPrefix) ) { /* Copy the match. */ LZ4_memcpy(op + 0, match + 0, 8); LZ4_memcpy(op + 8, match + 8, 8); LZ4_memcpy(op +16, match +16, 2); op += length + MINMATCH; /* Both stages worked, load the next token. */ continue; } /* The second stage didn't work out, but the info is ready. * Propel it right to the point of match copying. */ goto _copy_match; } /* decode literal length */ if (length == RUN_MASK) { size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); if (addl == rvl_error) { goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ } #if LZ4_FAST_DEC_LOOP safe_literal_copy: #endif // corresponds to #if (#if LZ4_FAST_DEC_LOOP) /* copy literals */ cpy = op+length; LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) { /* We've either hit the input parsing restriction or the output parsing restriction. * In the normal scenario, decoding a full block, it must be the last sequence, * otherwise it's an error (invalid input or dimensions). * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow. */ if (partialDecoding) { /* Since we are partial decoding we may be in this block because of the output parsing * restriction, which is not valid since the output buffer is allowed to be undersized. */ DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end") DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length); DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op)); DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip)); /* Finishing in the middle of a literals segment, * due to lack of input. */ if (ip+length > iend) { length = (size_t)(iend-ip); cpy = op + length; } /* Finishing in the middle of a literals segment, * due to lack of output space. */ if (cpy > oend) { cpy = oend; assert(op<=oend); length = (size_t)(oend-op); } } else { /* We must be on the last sequence (or invalid) because of the parsing limitations * so check that we exactly consume the input and don't overrun the output buffer. */ if ((ip+length != iend) || (cpy > oend)) { DEBUGLOG(6, "should have been last run of literals") DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend); goto _output_error; } } LZ4_memmove(op, ip, length); /* supports overlapping memory regions, for in-place decompression scenarios */ ip += length; op += length; /* Necessarily EOF when !partialDecoding. * When partialDecoding, it is EOF if we've either * filled the output buffer or * can't proceed with reading an offset for following match. */ if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) { break; } } else { LZ4_wildCopy8(op, ip, cpy); /* can overwrite up to 8 bytes beyond cpy */ ip += length; op = cpy; } /* get offset */ offset = LZ4_readLE16(ip); ip+=2; match = op - offset; /* get matchlength */ length = token & ML_MASK; _copy_match: if (length == ML_MASK) { size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); if (addl == rvl_error) { goto _output_error; } length += addl; if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ } length += MINMATCH; #if LZ4_FAST_DEC_LOOP safe_match_copy: #endif // corresponds to #if (#if LZ4_FAST_DEC_LOOP) if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ /* match starting within external dictionary */ if ((dict==usingExtDict) && (match < lowPrefix)) { assert(dictEnd != NULL); if (unlikely(op+length > oend-LASTLITERALS)) { if (partialDecoding) length = MIN(length, (size_t)(oend-op)); else goto _output_error; /* doesn't respect parsing restriction */ } if (length <= (size_t)(lowPrefix-match)) { /* match fits entirely within external dictionary : just copy */ LZ4_memmove(op, dictEnd - (lowPrefix-match), length); op += length; } else { /* match stretches into both external dictionary and current block */ size_t const copySize = (size_t)(lowPrefix - match); size_t const restSize = length - copySize; LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ BYTE* const endOfMatch = op + restSize; const BYTE* copyFrom = lowPrefix; while (op < endOfMatch) *op++ = *copyFrom++; } else { LZ4_memcpy(op, lowPrefix, restSize); op += restSize; } } continue; } assert(match >= lowPrefix); /* copy match within block */ cpy = op + length; /* partialDecoding : may end anywhere within the block */ assert(op<=oend); if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { size_t const mlen = MIN(length, (size_t)(oend-op)); const BYTE* const matchEnd = match + mlen; BYTE* const copyEnd = op + mlen; if (matchEnd > op) { /* overlap copy */ while (op < copyEnd) { *op++ = *match++; } } else { LZ4_memcpy(op, match, mlen); } op = copyEnd; if (op == oend) { break; } continue; } if (unlikely(offset<8)) { LZ4_write32(op, 0); /* silence msan warning when offset==0 */ op[0] = match[0]; op[1] = match[1]; op[2] = match[2]; op[3] = match[3]; match += inc32table[offset]; LZ4_memcpy(op+4, match, 4); match -= dec64table[offset]; } else { LZ4_memcpy(op, match, 8); match += 8; } op += 8; if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1); if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ if (op < oCopyLimit) { LZ4_wildCopy8(op, match, oCopyLimit); match += oCopyLimit - op; op = oCopyLimit; } while (op < cpy) { *op++ = *match++; } } else { LZ4_memcpy(op, match, 8); if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } } op = cpy; /* wildcopy correction */ } /* end of decoding */ DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst)); return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ /* Overflow error detected */ _output_error: return (int) (-(((const char*)ip)-src))-1; } } LZ4_FORCE_O2 int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, decode_full_block, noDict, (BYTE*)dest, NULL, 0); } LZ4_FORCE_O2 /* Exported, an obsolete API function. */ int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 0); } LZ4_FORCE_O2 static int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize, size_t prefixSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, noDict, (BYTE*)dest-prefixSize, NULL, 0); } LZ4_FORCE_O2 int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const void* dictStart, size_t dictSize) { DEBUGLOG(5, "LZ4_decompress_safe_forceExtDict"); return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); } /* The "double dictionary" mode, for use with e.g. ring buffers: the first part * of the dictionary is passed as prefix, and the second via dictStart + dictSize. * These routines are used only once, in LZ4_decompress_*_continue(). */ LZ4_FORCE_INLINE int LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize, size_t prefixSize, const void* dictStart, size_t dictSize) { return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, decode_full_block, usingExtDict, (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize); } /*===== streaming decompression functions =====*/ LZ4_streamDecode_t* LZ4_createStreamDecode(void) { LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal)); g_allocatedram+=sizeof(LZ4_streamDecode_t); return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) { if (LZ4_stream == NULL) { return 0; } /* support free on NULL */ FREEMEM(LZ4_stream); return 0; } /* *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. Previously decoded blocks must still be available at the memory position where they were decoded. If it's not possible, save the relevant part of decoded data into a safe buffer, and indicate where it stands using LZ4_setStreamDecode() */ LZ4_FORCE_O2 int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; if (lz4sd->prefixSize == 0) { /* The first call, no dictionary yet. */ assert(lz4sd->extDictSize == 0); result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE*)dest + result; } else if (lz4sd->prefixEnd == (BYTE*)dest) { /* They're rolling the current segment. */ if (lz4sd->prefixSize >= 64 KB - 1) result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize); else if (lz4sd->extDictSize == 0) result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, lz4sd->prefixSize); else result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize, lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize += (size_t)result; lz4sd->prefixEnd += result; } else { /* The buffer wraps around, or they're switching to another buffer. */ lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE*)dest + result; } return result; } /// LICENSE_END.22 #endif // corresponds to #ifdef (#ifdef _WIN32) ///https://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20 ///banner font void bigguru() { myprintf("\n\n"); myprintf(" ##### # # ###### # #\n"); myprintf("# # # # # # # #\n"); myprintf("# # # # # # #\n"); myprintf("# #### # # ###### # #\n"); myprintf("# # # # # # # #\n"); myprintf("# # # # # # # #\n"); myprintf(" ##### ##### # # ##### \n"); myprintf("\n\n"); } void bigok() { myprintf("\n\n"); myprintf("####### # #\n"); myprintf("# # # #\n"); myprintf("# # # #\n"); myprintf("# # ###!\n"); myprintf("# # # #\n"); myprintf("# # # #\n"); myprintf("####### # #\n"); myprintf("\n\n"); } void bigerror() { myprintf("\n\n"); myprintf("####### ###### ###### ####### ###### ###\n"); myprintf("# # # # # # # # # ###\n"); myprintf("# # # # # # # # # ###\n"); myprintf("##### ###### ###### # # ###### #\n"); myprintf("# # # # # # # # #\n"); myprintf("# # # # # # # # # ###\n"); myprintf("####### # # # # ####### # # ###\n"); myprintf("\n\n"); } void bigwarning() { myprintf("\n\n"); myprintf("# # # ###### # # ### # # #####\n"); myprintf("# # # # # # # ## # # ## # # #\n"); myprintf("# # # # # # # # # # # # # # #\n"); myprintf("# # # # # ###### # # # # # # # # ####\n"); myprintf("# # # ####### # # # # # # # # # # #\n"); myprintf("# # # # # # # # ## # # ## # #\n"); myprintf(" ## ## # # # # # # ### # # #####\n"); myprintf("\n\n"); } #ifdef HWSHA2 void getcpuid(uint32_t eax, uint32_t ecx, uint32_t& o_a,uint32_t& o_b,uint32_t& o_c,uint32_t& o_d) { uint32_t ebx=0; uint32_t edx=0; // on some kind of ancient HW ebx need to be saved. Not sure if and why, readed here and there // It is unpredictable what exactly the compiler will do // https://sites.uclouvain.be/SystInfo/usr/include/cpuid.h.html #if defined(__i386__) && defined(__PIC__) __asm__ __volatile__ ( "movl %%ebx, %%edi;" "cpuid;" "xchgl %%ebx, %%edi;" : "=D"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx)); #else __asm__("cpuid;" : "+b"(ebx), "+a"(eax), "+c"(ecx), "=d"(edx)); #endif // corresponds to #if (#if defined(__i386__) && defined(__PIC__)) o_a=eax; // cpuid silently change the input parameter, so we have to store back o_b=ebx; o_c=ecx; o_d=edx; } #else void getcpuid(uint32_t eax, uint32_t ecx, uint32_t& o_a,uint32_t& o_b,uint32_t& o_c,uint32_t& o_d) { o_a=0; o_b=0; o_c=0; o_d=0; } #endif // corresponds to #ifdef (#ifdef HWSHA2) #ifdef HWSHA2 /// LICENSE_START.20 /* This is a reworked CPU accelerated SHA code taken from SHA-Intrinsics - Public Domain (https://github.com/noloader/SHA-Intrinsics) */ #define ALIGNED(m) __attribute__ ((__aligned__(m))) #define bswap_uint64 __builtin_bswap64 #define bswap_uint32 __builtin_bswap32 #define bswap_uint16 __builtin_bswap16 #define read_swap32(p) bswap_uint32(*(const uint32_t*)(const uint8_t*)(p)) #define read_swap64(p) bswap_uint64(*(const uint64_t*)(const uint8_t*)(p)) #define PREFETCH64(m) do { __builtin_prefetch(m, 0, 0); __builtin_prefetch(m+32, 0, 0); } while(0) #define write_swap16(p,v) (*(uint16_t*)(void*)(p)) = bswap_uint16(v) #define write_swap32(p,v) (*(uint32_t*)(void*)(p)) = bswap_uint32(v) #define write_swap64(p,v) (*(uint64_t*)(void*)(p)) = bswap_uint64(v) #define safe_strlen(str) ((((char*)(str))==NULL)?0:strlen(str)) /* Includes for SHA-1 and SHA-256 intrinsics */ #include #define MY_ENABLE_GCC_ARCH(arch) __attribute__ ((target (arch))) /* Blocksize for each algorithm - Must be a power of 2 */ #define SHA1_BLOCKSIZE 64 #define SHA256_BLOCKSIZE 64 #define MAX_BLOCKSIZE SHA256_BLOCKSIZE /* * Rotate 32 or 64 bit integers by n bytes. * Don't bother trying to hand-optimize those, as the * compiler usually does a pretty good job at that. */ #define ROL32(a,b) (((a) << (b)) | ((a) >> (32-(b)))) #define ROR32(a,b) (((a) >> (b)) | ((a) << (32-(b)))) #define ROL64(a,b) (((a) << (b)) | ((a) >> (64-(b)))) #define ROR64(a,b) (((a) >> (b)) | ((a) << (64-(b)))) /* * SHA-256 common macros (use Wikipedia SHA-2 names for clarity) */ #define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) #define Ma(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) /* SHA-256 constants */ static const uint32_t K256[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; /* * For convenience, we use a common context for all the checksum algorithms, * which means some elements may be unused... Please note the ALIGNED that makes a lot of trouble... */ typedef struct ALIGNED(64) { uint8_t buf[MAX_BLOCKSIZE]; uint64_t state[8]; uint64_t bytecount; } SUM_CONTEXT; static void sha1_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89; ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476; ctx->state[4] = 0xc3d2e1f0; } static void sha256_init(SUM_CONTEXT *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; ctx->state[2] = 0x3c6ef372; ctx->state[3] = 0xa54ff53a; ctx->state[4] = 0x510e527f; ctx->state[5] = 0x9b05688c; ctx->state[6] = 0x1f83d9ab; ctx->state[7] = 0x5be0cd19; } /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ static void sha1_transform_cc(SUM_CONTEXT *ctx, const uint8_t *data) { uint32_t a, b, c, d, e, tm, x[16]; /* get values from the chaining vars */ a = (uint32_t)ctx->state[0]; b = (uint32_t)ctx->state[1]; c = (uint32_t)ctx->state[2]; d = (uint32_t)ctx->state[3]; e = (uint32_t)ctx->state[4]; #ifdef BIG memcpy(x, data, sizeof(x)); #else { unsigned k; for (k = 0; k < 16; k += 4) { const uint8_t *p2 = data + k * 4; x[k] = read_swap32(p2); x[k + 1] = read_swap32(p2 + 4); x[k + 2] = read_swap32(p2 + 8); x[k + 3] = read_swap32(p2 + 12); } } #endif // corresponds to #ifdef (#ifdef BIG) #define K1 0x5a827999L #define K2 0x6ed9eba1L #define K3 0x8f1bbcdcL #define K4 0xca62c1d6L #define F1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) #define F2(x,y,z) ( x ^ y ^ z ) #define F3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) #define F4(x,y,z) ( x ^ y ^ z ) #define M(i) ( tm = x[i&0x0f] ^ x[(i-14)&0x0f] ^ x[(i-8)&0x0f] ^ x[(i-3)&0x0f], (x[i&0x0f] = ROL32(tm,1)) ) #define SHA1STEP(a, b, c, d, e, f, k, m) do { e += ROL32(a, 5) + f(b, c, d) + k + m; \ b = ROL32(b, 30); } while(0) SHA1STEP(a, b, c, d, e, F1, K1, x[0]); SHA1STEP(e, a, b, c, d, F1, K1, x[1]); SHA1STEP(d, e, a, b, c, F1, K1, x[2]); SHA1STEP(c, d, e, a, b, F1, K1, x[3]); SHA1STEP(b, c, d, e, a, F1, K1, x[4]); SHA1STEP(a, b, c, d, e, F1, K1, x[5]); SHA1STEP(e, a, b, c, d, F1, K1, x[6]); SHA1STEP(d, e, a, b, c, F1, K1, x[7]); SHA1STEP(c, d, e, a, b, F1, K1, x[8]); SHA1STEP(b, c, d, e, a, F1, K1, x[9]); SHA1STEP(a, b, c, d, e, F1, K1, x[10]); SHA1STEP(e, a, b, c, d, F1, K1, x[11]); SHA1STEP(d, e, a, b, c, F1, K1, x[12]); SHA1STEP(c, d, e, a, b, F1, K1, x[13]); SHA1STEP(b, c, d, e, a, F1, K1, x[14]); SHA1STEP(a, b, c, d, e, F1, K1, x[15]); SHA1STEP(e, a, b, c, d, F1, K1, M(16)); SHA1STEP(d, e, a, b, c, F1, K1, M(17)); SHA1STEP(c, d, e, a, b, F1, K1, M(18)); SHA1STEP(b, c, d, e, a, F1, K1, M(19)); SHA1STEP(a, b, c, d, e, F2, K2, M(20)); SHA1STEP(e, a, b, c, d, F2, K2, M(21)); SHA1STEP(d, e, a, b, c, F2, K2, M(22)); SHA1STEP(c, d, e, a, b, F2, K2, M(23)); SHA1STEP(b, c, d, e, a, F2, K2, M(24)); SHA1STEP(a, b, c, d, e, F2, K2, M(25)); SHA1STEP(e, a, b, c, d, F2, K2, M(26)); SHA1STEP(d, e, a, b, c, F2, K2, M(27)); SHA1STEP(c, d, e, a, b, F2, K2, M(28)); SHA1STEP(b, c, d, e, a, F2, K2, M(29)); SHA1STEP(a, b, c, d, e, F2, K2, M(30)); SHA1STEP(e, a, b, c, d, F2, K2, M(31)); SHA1STEP(d, e, a, b, c, F2, K2, M(32)); SHA1STEP(c, d, e, a, b, F2, K2, M(33)); SHA1STEP(b, c, d, e, a, F2, K2, M(34)); SHA1STEP(a, b, c, d, e, F2, K2, M(35)); SHA1STEP(e, a, b, c, d, F2, K2, M(36)); SHA1STEP(d, e, a, b, c, F2, K2, M(37)); SHA1STEP(c, d, e, a, b, F2, K2, M(38)); SHA1STEP(b, c, d, e, a, F2, K2, M(39)); SHA1STEP(a, b, c, d, e, F3, K3, M(40)); SHA1STEP(e, a, b, c, d, F3, K3, M(41)); SHA1STEP(d, e, a, b, c, F3, K3, M(42)); SHA1STEP(c, d, e, a, b, F3, K3, M(43)); SHA1STEP(b, c, d, e, a, F3, K3, M(44)); SHA1STEP(a, b, c, d, e, F3, K3, M(45)); SHA1STEP(e, a, b, c, d, F3, K3, M(46)); SHA1STEP(d, e, a, b, c, F3, K3, M(47)); SHA1STEP(c, d, e, a, b, F3, K3, M(48)); SHA1STEP(b, c, d, e, a, F3, K3, M(49)); SHA1STEP(a, b, c, d, e, F3, K3, M(50)); SHA1STEP(e, a, b, c, d, F3, K3, M(51)); SHA1STEP(d, e, a, b, c, F3, K3, M(52)); SHA1STEP(c, d, e, a, b, F3, K3, M(53)); SHA1STEP(b, c, d, e, a, F3, K3, M(54)); SHA1STEP(a, b, c, d, e, F3, K3, M(55)); SHA1STEP(e, a, b, c, d, F3, K3, M(56)); SHA1STEP(d, e, a, b, c, F3, K3, M(57)); SHA1STEP(c, d, e, a, b, F3, K3, M(58)); SHA1STEP(b, c, d, e, a, F3, K3, M(59)); SHA1STEP(a, b, c, d, e, F4, K4, M(60)); SHA1STEP(e, a, b, c, d, F4, K4, M(61)); SHA1STEP(d, e, a, b, c, F4, K4, M(62)); SHA1STEP(c, d, e, a, b, F4, K4, M(63)); SHA1STEP(b, c, d, e, a, F4, K4, M(64)); SHA1STEP(a, b, c, d, e, F4, K4, M(65)); SHA1STEP(e, a, b, c, d, F4, K4, M(66)); SHA1STEP(d, e, a, b, c, F4, K4, M(67)); SHA1STEP(c, d, e, a, b, F4, K4, M(68)); SHA1STEP(b, c, d, e, a, F4, K4, M(69)); SHA1STEP(a, b, c, d, e, F4, K4, M(70)); SHA1STEP(e, a, b, c, d, F4, K4, M(71)); SHA1STEP(d, e, a, b, c, F4, K4, M(72)); SHA1STEP(c, d, e, a, b, F4, K4, M(73)); SHA1STEP(b, c, d, e, a, F4, K4, M(74)); SHA1STEP(a, b, c, d, e, F4, K4, M(75)); SHA1STEP(e, a, b, c, d, F4, K4, M(76)); SHA1STEP(d, e, a, b, c, F4, K4, M(77)); SHA1STEP(c, d, e, a, b, F4, K4, M(78)); SHA1STEP(b, c, d, e, a, F4, K4, M(79)); #undef F1 #undef F2 #undef F3 #undef F4 /* Update chaining vars */ ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; ctx->state[4] += e; } /* * Transform the message X which consists of 16 32-bit-words (SHA-1) * The code is public domain taken from https://github.com/noloader/SHA-Intrinsics. */ MY_ENABLE_GCC_ARCH("ssse3,sse4.1,sha") static void sha1_transform_x86(uint64_t state64[5], const uint8_t *data, size_t length) { __m128i ABCD, E0, E1; __m128i MSG0, MSG1, MSG2, MSG3; const __m128i MYMASK = _mm_set_epi64x(0x0001020304050607ULL, 0x08090a0b0c0d0e0fULL); uint32_t state[5] = { (uint32_t)state64[0], (uint32_t)state64[1], (uint32_t)state64[2], (uint32_t)state64[3], (uint32_t)state64[4] }; /* Load initial values */ ABCD = _mm_loadu_si128((const __m128i*) state); E0 = _mm_set_epi32(state[4], 0, 0, 0); ABCD = _mm_shuffle_epi32(ABCD, 0x1B); while (length >= SHA1_BLOCKSIZE) { /* Save current state */ const __m128i ABCD_SAVE = ABCD; const __m128i E0_SAVE = E0; /* Rounds 0-3 */ MSG0 = _mm_loadu_si128((const __m128i*)(data + 0)); MSG0 = _mm_shuffle_epi8(MSG0, MYMASK); E0 = _mm_add_epi32(E0, MSG0); E1 = ABCD; ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); /* Rounds 4-7 */ MSG1 = _mm_loadu_si128((const __m128i*)(data + 16)); MSG1 = _mm_shuffle_epi8(MSG1, MYMASK); E1 = _mm_sha1nexte_epu32(E1, MSG1); E0 = ABCD; ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); /* Rounds 8-11 */ MSG2 = _mm_loadu_si128((const __m128i*)(data + 32)); MSG2 = _mm_shuffle_epi8(MSG2, MYMASK); E0 = _mm_sha1nexte_epu32(E0, MSG2); E1 = ABCD; ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); MSG0 = _mm_xor_si128(MSG0, MSG2); /* Rounds 12-15 */ MSG3 = _mm_loadu_si128((const __m128i*)(data + 48)); MSG3 = _mm_shuffle_epi8(MSG3, MYMASK); E1 = _mm_sha1nexte_epu32(E1, MSG3); E0 = ABCD; MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 0); MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); MSG1 = _mm_xor_si128(MSG1, MSG3); /* Rounds 16-19 */ E0 = _mm_sha1nexte_epu32(E0, MSG0); E1 = ABCD; MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 0); MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); MSG2 = _mm_xor_si128(MSG2, MSG0); /* Rounds 20-23 */ E1 = _mm_sha1nexte_epu32(E1, MSG1); E0 = ABCD; MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); MSG3 = _mm_xor_si128(MSG3, MSG1); /* Rounds 24-27 */ E0 = _mm_sha1nexte_epu32(E0, MSG2); E1 = ABCD; MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); MSG0 = _mm_xor_si128(MSG0, MSG2); /* Rounds 28-31 */ E1 = _mm_sha1nexte_epu32(E1, MSG3); E0 = ABCD; MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); MSG1 = _mm_xor_si128(MSG1, MSG3); /* Rounds 32-35 */ E0 = _mm_sha1nexte_epu32(E0, MSG0); E1 = ABCD; MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 1); MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); MSG2 = _mm_xor_si128(MSG2, MSG0); /* Rounds 36-39 */ E1 = _mm_sha1nexte_epu32(E1, MSG1); E0 = ABCD; MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 1); MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); MSG3 = _mm_xor_si128(MSG3, MSG1); /* Rounds 40-43 */ E0 = _mm_sha1nexte_epu32(E0, MSG2); E1 = ABCD; MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); MSG0 = _mm_xor_si128(MSG0, MSG2); /* Rounds 44-47 */ E1 = _mm_sha1nexte_epu32(E1, MSG3); E0 = ABCD; MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); MSG1 = _mm_xor_si128(MSG1, MSG3); /* Rounds 48-51 */ E0 = _mm_sha1nexte_epu32(E0, MSG0); E1 = ABCD; MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); MSG2 = _mm_xor_si128(MSG2, MSG0); /* Rounds 52-55 */ E1 = _mm_sha1nexte_epu32(E1, MSG1); E0 = ABCD; MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 2); MSG0 = _mm_sha1msg1_epu32(MSG0, MSG1); MSG3 = _mm_xor_si128(MSG3, MSG1); /* Rounds 56-59 */ E0 = _mm_sha1nexte_epu32(E0, MSG2); E1 = ABCD; MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 2); MSG1 = _mm_sha1msg1_epu32(MSG1, MSG2); MSG0 = _mm_xor_si128(MSG0, MSG2); /* Rounds 60-63 */ E1 = _mm_sha1nexte_epu32(E1, MSG3); E0 = ABCD; MSG0 = _mm_sha1msg2_epu32(MSG0, MSG3); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); MSG2 = _mm_sha1msg1_epu32(MSG2, MSG3); MSG1 = _mm_xor_si128(MSG1, MSG3); /* Rounds 64-67 */ E0 = _mm_sha1nexte_epu32(E0, MSG0); E1 = ABCD; MSG1 = _mm_sha1msg2_epu32(MSG1, MSG0); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); MSG3 = _mm_sha1msg1_epu32(MSG3, MSG0); MSG2 = _mm_xor_si128(MSG2, MSG0); /* Rounds 68-71 */ E1 = _mm_sha1nexte_epu32(E1, MSG1); E0 = ABCD; MSG2 = _mm_sha1msg2_epu32(MSG2, MSG1); ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); MSG3 = _mm_xor_si128(MSG3, MSG1); /* Rounds 72-75 */ E0 = _mm_sha1nexte_epu32(E0, MSG2); E1 = ABCD; MSG3 = _mm_sha1msg2_epu32(MSG3, MSG2); ABCD = _mm_sha1rnds4_epu32(ABCD, E0, 3); /* Rounds 76-79 */ E1 = _mm_sha1nexte_epu32(E1, MSG3); E0 = ABCD; ABCD = _mm_sha1rnds4_epu32(ABCD, E1, 3); /* Combine state */ E0 = _mm_sha1nexte_epu32(E0, E0_SAVE); ABCD = _mm_add_epi32(ABCD, ABCD_SAVE); data += 64; length -= 64; } /* Save state */ ABCD = _mm_shuffle_epi32(ABCD, 0x1B); _mm_storeu_si128((__m128i*) state, ABCD); state[4] = _mm_extract_epi32(E0, 3); /* Repack into uint64_t. */ state64[0] = state[0]; state64[1] = state[1]; state64[2] = state[2]; state64[3] = state[3]; state64[4] = state[4]; } /* Transform the message X which consists of 16 32-bit-words (SHA-1) */ static void sha1_transform(SUM_CONTEXT *ctx, const uint8_t *data) { if (flaghw) sha1_transform_x86(ctx->state, data, SHA1_BLOCKSIZE); else sha1_transform_cc(ctx, data); } /* Transform the message X which consists of 16 32-bit-words (SHA-256) */ static __inline void sha256_transform_cc(SUM_CONTEXT *ctx, const uint8_t *data) { uint32_t a, b, c, d, e, f, g, h, j, x[16]; a = (uint32_t)ctx->state[0]; b = (uint32_t)ctx->state[1]; c = (uint32_t)ctx->state[2]; d = (uint32_t)ctx->state[3]; e = (uint32_t)ctx->state[4]; f = (uint32_t)ctx->state[5]; g = (uint32_t)ctx->state[6]; h = (uint32_t)ctx->state[7]; // Nesting the ROR allows for single register compiler optimizations #define S0(x) (ROR32(ROR32(ROR32(x,9)^(x),11)^(x),2)) // Σ0 (Sigma 0) #define S1(x) (ROR32(ROR32(ROR32(x,14)^(x),5)^(x),6)) // Σ1 (Sigma 1) #define s0(x) (ROR32(ROR32(x,11)^(x),7)^((x)>>3)) // σ0 (sigma 0) #define s1(x) (ROR32(ROR32(x,2)^(x),17)^((x)>>10)) // σ1 (sigma 1) #define BLK0(i) (x[i]) #define BLK2(i) (x[i] += s1(x[((i)-2)&15]) + x[((i)-7)&15] + s0(x[((i)-15)&15])) #define R(a, b, c, d, e, f, g, h, i) \ h += S1(e) + Ch(e,f,g) + K256[(i)+(j)] + (j ? BLK2(i) : BLK0(i)); \ d += h; \ h += S0(a) + Ma(a, b, c) #define RX_8(i) \ R(a, b, c, d, e, f, g, h, i); \ R(h, a, b, c, d, e, f, g, i+1); \ R(g, h, a, b, c, d, e, f, i+2); \ R(f, g, h, a, b, c, d, e, i+3); \ R(e, f, g, h, a, b, c, d, i+4); \ R(d, e, f, g, h, a, b, c, i+5); \ R(c, d, e, f, g, h, a, b, i+6); \ R(b, c, d, e, f, g, h, a, i+7) #ifdef BIG memcpy(x, data, sizeof(x)); #else { uint32_t k; for (k = 0; k < 16; k += 4) { const uint8_t* p2 = data + k * 4; x[k] = read_swap32(p2); x[k + 1] = read_swap32(p2 + 4); x[k + 2] = read_swap32(p2 + 8); x[k + 3] = read_swap32(p2 + 12); } } #endif // corresponds to #ifdef (#ifdef BIG) for (j = 0; j < 64; j += 16) { RX_8(0); RX_8(8); } #undef S0 #undef S1 #undef s0 #undef s1 #undef BLK0 #undef BLK2 #undef R #undef RX_8 ctx->state[0] += a; ctx->state[1] += b; ctx->state[2] += c; ctx->state[3] += d; ctx->state[4] += e; ctx->state[5] += f; ctx->state[6] += g; ctx->state[7] += h; } /* * Transform the message X which consists of 16 32-bit-words (SHA-256) * The code is public domain taken from https://github.com/noloader/SHA-Intrinsics. */ MY_ENABLE_GCC_ARCH("ssse3,sse4.1,sha") static __inline void sha256_transform_x86(uint64_t state64[8], const uint8_t *data, size_t length) { __m128i STATE0, STATE1; __m128i MSG, TMP; __m128i MSG0, MSG1, MSG2, MSG3; const __m128i MYMASK = _mm_set_epi64x(0x0c0d0e0f08090a0bULL, 0x0405060700010203ULL); uint32_t state[8] = { (uint32_t)state64[0], (uint32_t)state64[1], (uint32_t)state64[2], (uint32_t)state64[3], (uint32_t)state64[4], (uint32_t)state64[5], (uint32_t)state64[6], (uint32_t)state64[7] }; /* Load initial values */ TMP = _mm_loadu_si128((const __m128i*) (state+0)); STATE1 = _mm_loadu_si128((const __m128i*) (state+4)); TMP = _mm_shuffle_epi32(TMP, 0xB1); /* CDAB */ STATE1 = _mm_shuffle_epi32(STATE1, 0x1B); /* EFGH */ STATE0 = _mm_alignr_epi8(TMP, STATE1, 8); /* ABEF */ STATE1 = _mm_blend_epi16(STATE1, TMP, 0xF0); /* CDGH */ while (length >= SHA256_BLOCKSIZE) { /* Save current state */ const __m128i ABEF_SAVE = STATE0; const __m128i CDGH_SAVE = STATE1; /* Rounds 0-3 */ MSG = _mm_loadu_si128((const __m128i*) (data+0)); MSG0 = _mm_shuffle_epi8(MSG, MYMASK); MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0xE9B5DBA5B5C0FBCFULL, 0x71374491428A2F98ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); /* Rounds 4-7 */ MSG1 = _mm_loadu_si128((const __m128i*) (data+16)); MSG1 = _mm_shuffle_epi8(MSG1, MYMASK); MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0xAB1C5ED5923F82A4ULL, 0x59F111F13956C25BULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1); /* Rounds 8-11 */ MSG2 = _mm_loadu_si128((const __m128i*) (data+32)); MSG2 = _mm_shuffle_epi8(MSG2, MYMASK); MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x550C7DC3243185BEULL, 0x12835B01D807AA98ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2); /* Rounds 12-15 */ MSG3 = _mm_loadu_si128((const __m128i*) (data+48)); MSG3 = _mm_shuffle_epi8(MSG3, MYMASK); MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC19BF1749BDC06A7ULL, 0x80DEB1FE72BE5D74ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG3, MSG2, 4); MSG0 = _mm_add_epi32(MSG0, TMP); MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3); /* Rounds 16-19 */ MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x240CA1CC0FC19DC6ULL, 0xEFBE4786E49B69C1ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG0, MSG3, 4); MSG1 = _mm_add_epi32(MSG1, TMP); MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0); /* Rounds 20-23 */ MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x76F988DA5CB0A9DCULL, 0x4A7484AA2DE92C6FULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG1, MSG0, 4); MSG2 = _mm_add_epi32(MSG2, TMP); MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1); /* Rounds 24-27 */ MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xBF597FC7B00327C8ULL, 0xA831C66D983E5152ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG2, MSG1, 4); MSG3 = _mm_add_epi32(MSG3, TMP); MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2); /* Rounds 28-31 */ MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x1429296706CA6351ULL, 0xD5A79147C6E00BF3ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG3, MSG2, 4); MSG0 = _mm_add_epi32(MSG0, TMP); MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3); /* Rounds 32-35 */ MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x53380D134D2C6DFCULL, 0x2E1B213827B70A85ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG0, MSG3, 4); MSG1 = _mm_add_epi32(MSG1, TMP); MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0); /* Rounds 36-39 */ MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x92722C8581C2C92EULL, 0x766A0ABB650A7354ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG1, MSG0, 4); MSG2 = _mm_add_epi32(MSG2, TMP); MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG0 = _mm_sha256msg1_epu32(MSG0, MSG1); /* Rounds 40-43 */ MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0xC76C51A3C24B8B70ULL, 0xA81A664BA2BFE8A1ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG2, MSG1, 4); MSG3 = _mm_add_epi32(MSG3, TMP); MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG1 = _mm_sha256msg1_epu32(MSG1, MSG2); /* Rounds 44-47 */ MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0x106AA070F40E3585ULL, 0xD6990624D192E819ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG3, MSG2, 4); MSG0 = _mm_add_epi32(MSG0, TMP); MSG0 = _mm_sha256msg2_epu32(MSG0, MSG3); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG2 = _mm_sha256msg1_epu32(MSG2, MSG3); /* Rounds 48-51 */ MSG = _mm_add_epi32(MSG0, _mm_set_epi64x(0x34B0BCB52748774CULL, 0x1E376C0819A4C116ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG0, MSG3, 4); MSG1 = _mm_add_epi32(MSG1, TMP); MSG1 = _mm_sha256msg2_epu32(MSG1, MSG0); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); MSG3 = _mm_sha256msg1_epu32(MSG3, MSG0); /* Rounds 52-55 */ MSG = _mm_add_epi32(MSG1, _mm_set_epi64x(0x682E6FF35B9CCA4FULL, 0x4ED8AA4A391C0CB3ULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG1, MSG0, 4); MSG2 = _mm_add_epi32(MSG2, TMP); MSG2 = _mm_sha256msg2_epu32(MSG2, MSG1); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); /* Rounds 56-59 */ MSG = _mm_add_epi32(MSG2, _mm_set_epi64x(0x8CC7020884C87814ULL, 0x78A5636F748F82EEULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); TMP = _mm_alignr_epi8(MSG2, MSG1, 4); MSG3 = _mm_add_epi32(MSG3, TMP); MSG3 = _mm_sha256msg2_epu32(MSG3, MSG2); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); /* Rounds 60-63 */ MSG = _mm_add_epi32(MSG3, _mm_set_epi64x(0xC67178F2BEF9A3F7ULL, 0xA4506CEB90BEFFFAULL)); STATE1 = _mm_sha256rnds2_epu32(STATE1, STATE0, MSG); MSG = _mm_shuffle_epi32(MSG, 0x0E); STATE0 = _mm_sha256rnds2_epu32(STATE0, STATE1, MSG); /* Combine state */ STATE0 = _mm_add_epi32(STATE0, ABEF_SAVE); STATE1 = _mm_add_epi32(STATE1, CDGH_SAVE); data += 64; length -= 64; } TMP = _mm_shuffle_epi32(STATE0, 0x1B); /* FEBA */ STATE1 = _mm_shuffle_epi32(STATE1, 0xB1); /* DCHG */ STATE0 = _mm_blend_epi16(TMP, STATE1, 0xF0); /* DCBA */ STATE1 = _mm_alignr_epi8(STATE1, TMP, 8); /* ABEF */ /* Save state */ _mm_storeu_si128((__m128i*) (state+0), STATE0); _mm_storeu_si128((__m128i*) (state+4), STATE1); /* Repack into uint64_t. */ state64[0] = state[0]; state64[1] = state[1]; state64[2] = state[2]; state64[3] = state[3]; state64[4] = state[4]; state64[5] = state[5]; state64[6] = state[6]; state64[7] = state[7]; } static __inline void sha256_transform(SUM_CONTEXT *ctx, const uint8_t *data) { if (flaghw) sha256_transform_x86(ctx->state, data, SHA256_BLOCKSIZE); else sha256_transform_cc(ctx, data); } /* Update the message digest with the contents of the buffer (SHA-1) */ static void sha1_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len) { size_t num = ctx->bytecount & (SHA1_BLOCKSIZE - 1); /* Update bytecount */ ctx->bytecount += len; /* Handle any leading odd-sized chunks */ if (num) { uint8_t *p = ctx->buf + num; num = SHA1_BLOCKSIZE - num; if (len < num) { memcpy(p, buf, len); return; } memcpy(p, buf, num); sha1_transform(ctx, ctx->buf); buf += num; len -= num; } if (flaghw) { /* Process all full blocks at once */ if (len >= SHA1_BLOCKSIZE) { /* Calculate full blocks, in bytes */ num = (len / SHA1_BLOCKSIZE) * SHA1_BLOCKSIZE; /* SHA-1 acceleration using intrinsics */ sha1_transform_x86(ctx->state, buf, num); buf += num; len -= num; } } else { /* Process data in blocksize chunks */ while (len >= SHA1_BLOCKSIZE) { PREFETCH64(buf + SHA1_BLOCKSIZE); sha1_transform(ctx, buf); buf += SHA1_BLOCKSIZE; len -= SHA1_BLOCKSIZE; } } /* Handle any remaining bytes of data. */ memcpy(ctx->buf, buf, len); } /* Update the message digest with the contents of the buffer (SHA-256) */ static void sha256_write(SUM_CONTEXT *ctx, const uint8_t *buf, size_t len) { size_t num = ctx->bytecount & (SHA256_BLOCKSIZE - 1); /* Update bytecount */ ctx->bytecount += len; /* Handle any leading odd-sized chunks */ if (num) { uint8_t *p = ctx->buf + num; num = SHA256_BLOCKSIZE - num; if (len < num) { memcpy(p, buf, len); return; } memcpy(p, buf, num); sha256_transform(ctx, ctx->buf); buf += num; len -= num; } if (flaghw) { /* Process all full blocks at once */ if (len >= SHA256_BLOCKSIZE) { /* Calculate full blocks, in bytes */ num = (len / SHA256_BLOCKSIZE) * SHA256_BLOCKSIZE; /* SHA-256 acceleration using intrinsics */ sha256_transform_x86(ctx->state, buf, num); buf += num; len -= num; } } else { /* Process data in blocksize chunks */ while (len >= SHA256_BLOCKSIZE) { PREFETCH64(buf + SHA256_BLOCKSIZE); sha256_transform(ctx, buf); buf += SHA256_BLOCKSIZE; len -= SHA256_BLOCKSIZE; } } /* Handle any remaining bytes of data. */ memcpy(ctx->buf, buf, len); } /* Finalize the computation and write the digest in ctx->state[] (SHA-1) */ static void sha1_final(SUM_CONTEXT *ctx) { size_t pos = ((size_t)ctx->bytecount) & (SHA1_BLOCKSIZE - 1); uint64_t bitcount = ctx->bytecount << 3; uint8_t *p; ctx->buf[pos++] = 0x80; /* Pad whatever data is left in the buffer */ while (pos != (SHA1_BLOCKSIZE - sizeof(uint64_t))) { pos &= (SHA1_BLOCKSIZE - 1); if (pos == 0) sha1_transform(ctx, ctx->buf); ctx->buf[pos++] = 0; } /* Append to the padding the total message's length in bits and transform */ ctx->buf[SHA1_BLOCKSIZE - 1] = (uint8_t) bitcount; ctx->buf[SHA1_BLOCKSIZE - 2] = (uint8_t) (bitcount >> 8); ctx->buf[SHA1_BLOCKSIZE - 3] = (uint8_t) (bitcount >> 16); ctx->buf[SHA1_BLOCKSIZE - 4] = (uint8_t) (bitcount >> 24); ctx->buf[SHA1_BLOCKSIZE - 5] = (uint8_t) (bitcount >> 32); ctx->buf[SHA1_BLOCKSIZE - 6] = (uint8_t) (bitcount >> 40); ctx->buf[SHA1_BLOCKSIZE - 7] = (uint8_t) (bitcount >> 48); ctx->buf[SHA1_BLOCKSIZE - 8] = (uint8_t) (bitcount >> 56); sha1_transform(ctx, ctx->buf); p = ctx->buf; #ifdef BIG #define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0) #else #define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0); #endif // corresponds to #ifdef (#ifdef BIG) X(0); X(1); X(2); X(3); X(4); #undef X } /* Finalize the computation and write the digest in ctx->state[] (SHA-256) */ static void sha256_final(SUM_CONTEXT *ctx) { size_t pos = ((size_t)ctx->bytecount) & (SHA256_BLOCKSIZE - 1); uint64_t bitcount = ctx->bytecount << 3; uint8_t *p; ctx->buf[pos++] = 0x80; /* Pad whatever data is left in the buffer */ while (pos != (SHA256_BLOCKSIZE - sizeof(uint64_t))) { pos &= (SHA256_BLOCKSIZE - 1); if (pos == 0) sha256_transform(ctx, ctx->buf); ctx->buf[pos++] = 0; } /* Append to the padding the total message's length in bits and transform */ ctx->buf[SHA256_BLOCKSIZE - 1] = (uint8_t) bitcount; ctx->buf[SHA256_BLOCKSIZE - 2] = (uint8_t) (bitcount >> 8); ctx->buf[SHA256_BLOCKSIZE - 3] = (uint8_t) (bitcount >> 16); ctx->buf[SHA256_BLOCKSIZE - 4] = (uint8_t) (bitcount >> 24); ctx->buf[SHA256_BLOCKSIZE - 5] = (uint8_t) (bitcount >> 32); ctx->buf[SHA256_BLOCKSIZE - 6] = (uint8_t) (bitcount >> 40); ctx->buf[SHA256_BLOCKSIZE - 7] = (uint8_t) (bitcount >> 48); ctx->buf[SHA256_BLOCKSIZE - 8] = (uint8_t) (bitcount >> 56); sha256_transform(ctx, ctx->buf); p = ctx->buf; #ifdef BIG #define X(a) do { *(uint32_t*)p = (uint32_t)ctx->state[a]; p += 4; } while(0) #else #define X(a) do { write_swap32(p, (uint32_t)ctx->state[a]); p += 4; } while(0); #endif // corresponds to #ifdef (#ifdef BIG) X(0); X(1); X(2); X(3); X(4); X(5); X(6); X(7); #undef X } #endif // corresponds to #ifdef (#ifdef HWSHA2) /// LICENSE_END.20 /// LICENSE_START.5 #ifdef HWSHA1 /* This is SHA1 via linked asm (Windows only) */ #define MY_ALIGN(n) __attribute__ ((aligned(n))) #define MY_NO_INLINE __attribute__((noinline)) #define MY_FAST_CALL typedef unsigned char Byte; typedef short Int16; typedef int Int32; typedef long long int Int64; typedef unsigned short UInt16; typedef unsigned int UInt32; typedef unsigned long long int UInt64; typedef int BoolInt; #define SHA1_NUM_BLOCK_WORDS 16 #define SHA1_NUM_DIGEST_WORDS 5 #define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4) #define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4) typedef void (MY_FAST_CALL *SHA1_FUNC_UPDATE_BLOCKS)(UInt32 state[5], const Byte *data, size_t numBlocks); typedef struct { SHA1_FUNC_UPDATE_BLOCKS func_UpdateBlocks; UInt64 count; UInt64 __pad_2[2]; UInt32 state[SHA1_NUM_DIGEST_WORDS]; UInt32 __pad_3[3]; Byte buffer[SHA1_BLOCK_SIZE]; } CSha1; void Sha1Prepare(bool i_flaghardware=false); void Sha1_InitState(CSha1 *p); void Sha1_Init(CSha1 *p); void Sha1_Update(CSha1 *p, const Byte *data, size_t size); void Sha1_Final (CSha1 *p, Byte *digest); void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size); void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest); void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks); extern "C" void MY_FAST_CALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks); static SHA1_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS = Sha1_UpdateBlocks; static SHA1_FUNC_UPDATE_BLOCKS g_FUNC_UPDATE_BLOCKS_HW; #define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) #define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n)))) #define STEP_PRE 20 #define STEP_MAIN 20 #define kNumW 16 #define w(i) W[(i)&15] #define w0(i) (W[i] = GetBe32(data + (size_t)(i) * 4)) #define w1(i) (w(i) = rotlFixed(w((size_t)(i)-3) ^ w((size_t)(i)-8) ^ w((size_t)(i)-14) ^ w((size_t)(i)-16), 1)) #define sha1_f0(x,y,z) ( 0x5a827999 + (z^(x&(y^z))) ) #define sha1_f1(x,y,z) ( 0x6ed9eba1 + (x^y^z) ) #define sha1_f2(x,y,z) ( 0x8f1bbcdc + ((x&y)|(z&(x|y))) ) #define sha1_f3(x,y,z) ( 0xca62c1d6 + (x^y^z) ) #define T5(a,b,c,d,e, fx, ww) \ e += fx(b,c,d) + ww + rotlFixed(a, 5); \ b = rotlFixed(b, 30); \ #define M5(i, fx, wx0, wx1) \ T5 ( a,b,c,d,e, fx, wx0((i) ) ); \ T5 ( e,a,b,c,d, fx, wx1((i)+1) ); \ T5 ( d,e,a,b,c, fx, wx1((i)+2) ); \ T5 ( c,d,e,a,b, fx, wx1((i)+3) ); \ T5 ( b,c,d,e,a, fx, wx1((i)+4) ); \ #define R5(i, fx, wx) \ M5 ( i, fx, wx, wx) \ #if STEP_PRE > 5 #define R20_START \ R5 ( 0, sha1_f0, w0); \ R5 ( 5, sha1_f0, w0); \ R5 ( 10, sha1_f0, w0); \ M5 ( 15, sha1_f0, w0, w1); \ #elif STEP_PRE == 5 #define R20_START \ { size_t i; for (i = 0; i < 15; i += STEP_PRE) \ { R5(i, sha1_f0, w0); } } \ M5 ( 15, sha1_f0, w0, w1); \ #else #if STEP_PRE == 1 #define R_PRE R1 #elif STEP_PRE == 2 #define R_PRE R2 #elif STEP_PRE == 4 #define R_PRE R4 #endif // corresponds to #if (#if STEP_PRE == 1) #define R20_START \ { size_t i; for (i = 0; i < 16; i += STEP_PRE) \ { R_PRE(i, sha1_f0, w0); } } \ R4 ( 16, sha1_f0, w1); \ #endif // corresponds to #if (#if STEP_PRE > 5) #if STEP_MAIN > 5 #define R20(ii, fx) \ R5 ( (ii) , fx, w1); \ R5 ( (ii) + 5 , fx, w1); \ R5 ( (ii) + 10, fx, w1); \ R5 ( (ii) + 15, fx, w1); \ #else #if STEP_MAIN == 1 #define R_MAIN R1 #elif STEP_MAIN == 2 #define R_MAIN R2 #elif STEP_MAIN == 4 #define R_MAIN R4 #elif STEP_MAIN == 5 #define R_MAIN R5 #endif // corresponds to #if (#if STEP_MAIN == 1) #define R20(ii, fx) \ { size_t i; for (i = (ii); i < (ii) + 20; i += STEP_MAIN) \ { R_MAIN(i, fx, w1); } } \ #endif // corresponds to #if (#if STEP_MAIN > 5) #define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); } #define GetBe32(p) ( \ ((UInt32)((const Byte *)(p))[0] << 24) | \ ((UInt32)((const Byte *)(p))[1] << 16) | \ ((UInt32)((const Byte *)(p))[2] << 8) | \ ((const Byte *)(p))[3] ) #define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \ _ppp_[0] = (Byte)(_vvv_ >> 24); \ _ppp_[1] = (Byte)(_vvv_ >> 16); \ _ppp_[2] = (Byte)(_vvv_ >> 8); \ _ppp_[3] = (Byte)_vvv_; } void Sha1_InitState(CSha1 *p) { p->count = 0; p->state[0] = 0x67452301; p->state[1] = 0xEFCDAB89; p->state[2] = 0x98BADCFE; p->state[3] = 0x10325476; p->state[4] = 0xC3D2E1F0; } void Sha1_Init(CSha1 *p) { p->func_UpdateBlocks = g_FUNC_UPDATE_BLOCKS; Sha1_InitState(p); } MY_NO_INLINE void MY_FAST_CALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks) { UInt32 a, b, c, d, e; UInt32 W[kNumW]; if (numBlocks==0) return; a = state[0]; b = state[1]; c = state[2]; d = state[3]; e = state[4]; do { #if STEP_PRE < 5 || STEP_MAIN < 5 UInt32 tmp; #endif // corresponds to #if (#if STEP_PRE < 5 || STEP_MAIN < 5) R20_START R20(20, sha1_f1); R20(40, sha1_f2); R20(60, sha1_f3); a += state[0]; b += state[1]; c += state[2]; d += state[3]; e += state[4]; state[0] = a; state[1] = b; state[2] = c; state[3] = d; state[4] = e; data += 64; } while (--numBlocks); } void Sha1_Update(CSha1 *p, const Byte *data, size_t size) { if (size==0) return; unsigned pos = (unsigned)p->count & 0x3F; unsigned num; p->count += size; num=64-pos; if (num > size) { memcpy(p->buffer + pos, data, size); return; } if (pos != 0) { size -= num; memcpy(p->buffer + pos, data, num); data += num; p->func_UpdateBlocks(p->state, p->buffer, 1); } size_t numBlocks = size >> 6; p->func_UpdateBlocks(p->state, data, numBlocks); size &= 0x3F; if (size==0) return; data += (numBlocks << 6); memcpy(p->buffer, data, size); } void Sha1_Final(CSha1 *p, Byte *digest) { unsigned pos = (unsigned)p->count & 0x3F; p->buffer[pos++] = 0x80; if (pos > (64 - 8)) { while (pos != 64) p->buffer[pos++]=0; p->func_UpdateBlocks(p->state, p->buffer, 1); pos = 0; } memset(&p->buffer[pos], 0, (64 - 8) - pos); UInt64 numBits = (p->count << 3); SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32)); SetBe32(p->buffer + 64 - 4, (UInt32)(numBits)); p->func_UpdateBlocks(p->state, p->buffer, 1); SetBe32(digest, p->state[0]); SetBe32(digest + 4, p->state[1]); SetBe32(digest + 8, p->state[2]); SetBe32(digest + 12, p->state[3]); SetBe32(digest + 16, p->state[4]); Sha1_InitState(p); } void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size) { const UInt64 numBits = (p->count + size) << 3; SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 2], (UInt32)(numBits >> 32)); SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 1], (UInt32)(numBits)); SetUi32((UInt32 *)(void *)(block + size), 0x80); size += 4; while (size != (SHA1_NUM_BLOCK_WORDS - 2) * 4) { *((UInt32 *)(void *)(block + size)) = 0; size += 4; } } void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest) { MY_ALIGN (16) UInt32 st[SHA1_NUM_DIGEST_WORDS]; st[0] = p->state[0]; st[1] = p->state[1]; st[2] = p->state[2]; st[3] = p->state[3]; st[4] = p->state[4]; p->func_UpdateBlocks(st, data, 1); SetBe32(destDigest + 0 , st[0]); SetBe32(destDigest + 1 * 4, st[1]); SetBe32(destDigest + 2 * 4, st[2]); SetBe32(destDigest + 3 * 4, st[3]); SetBe32(destDigest + 4 * 4, st[4]); } void Sha1Prepare(bool i_flaghardware) { SHA1_FUNC_UPDATE_BLOCKS f, f_hw; f = Sha1_UpdateBlocks; if (i_flaghardware) f = f_hw = Sha1_UpdateBlocks_HW; g_FUNC_UPDATE_BLOCKS = f; g_FUNC_UPDATE_BLOCKS_HW = f_hw; } #endif // HWSHA1 // corresponds to #ifdef (#ifdef HWSHA1) /// LICENSE_END.5 /* Section: libzpaq */ // 1, 2, 4, 8 byte unsigned integers typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; namespace libzpaq { // Tables for parsing ZPAQL source code extern const char* compname[256]; // list of ZPAQL component types extern const int compsize[256]; // number of bytes to encode a component extern const char* opcodelist[272]; // list of ZPAQL instructions // Callback for error handling extern void error(const char* msg); // Virtual base classes for input and output // get() and put() must be overridden to read or write 1 byte. // read() and write() may be overridden to read or write n bytes more // efficiently than calling get() or put() n times. class Reader { public: virtual int get() = 0; // should return 0..255, or -1 at EOF virtual int read(char* buf, int n); // read to buf[n], return no. read virtual ~Reader() {} }; class Writer { public: virtual void put(int c) = 0; // should output low 8 bits of c virtual void write(const char* buf, int n); // write buf[n] virtual ~Writer() {} }; // Read 16 bit little-endian number int toU16(const char* p); // An Array of T is cleared and aligned on a 64 byte address // with no constructors called. No copy or assignment. // Array a(n, ex=0); - creates n< class Array { T *data; // user location of [0] on a 64 byte boundary size_t n; // user size int offset; // distance back in bytes to start of actual allocation void operator=(const Array&); // no assignment Array(const Array&); // no copy public: Array(size_t sz=0, int ex=0): data(0), n(0), offset(0) { resize(sz, ex);} // [0..sz-1] = 0 void resize(size_t sz, int ex=0); // change size, erase content to zeros ~Array() {resize(0);} // free memory size_t size() const {return n;} // get size int isize() const {return int(n);} // get size as an int T& operator[](size_t i) {assert(n>0 && i0 && i0 && (n&(n-1))==0); return data[i&(n-1)];} }; // Change size to sz< void Array::resize(size_t sz, int ex) { assert(size_t(-1)>0); // unsigned type? while (ex>0) { if (sz>sz*2) error("Array too big"); sz*=2, --ex; } if (n>0) { assert(offset>0 && offset<=64); assert((char*)data-offset); ::free((char*)data-offset); g_arrayram-=n; } n=0; offset=0; if (sz==0) return; n=sz; const size_t nb=128+n*sizeof(T); // test for overflow if (nb<=128 || (nb-128)/sizeof(T)!=n) n=0, error("Array too big"); data=(T*)::calloc(nb, 1); g_arrayram+=nb; if (!data) n=0, error("Out of memory"); offset=64-(((char*)data-(char*)0)&63); assert(offset>0 && offset<=64); data=(T*)((char*)data+offset); } //////////////////////////// SHA1 //////////////////////////// // SHA1 code, see http://en.wikipedia.org/wiki/SHA-1 #define SHA1CHUNK 64 class SHA1 { public: void put(int c); void write(const char* buf, int64_t n); uint64_t usize() const {return len/8;} const char* result(); SHA1() {init();} private: #ifdef HWSHA1 int bufpos; // 7-Zip SHA1 is rather different from CSha1 myhasher; // the original 7.15. So I put an input buffer unsigned char w_hw[SHA1CHUNK]; // Slower, in fact, but it works #else #ifdef HWSHA2 int bufpos; // 7-Zip SHA1 is rather different from SUM_CONTEXT sum_ctx; unsigned char w_hw[SHA1CHUNK]; // Slower, in fact, but it works #else // no HW U32 w[16]; ///puoi togliere U32 h[5]; ///puoi togliere #endif // corresponds to #ifdef (#ifdef HWSHA2) #endif // corresponds to #ifdef (#ifdef HWSHA1) U64 len; char hbuf[20]; void process(); void init(); }; #ifdef HWSHA2 /// This "thing" seems weird, and not very optimized, must be a "plug in" replacment void SHA1::init() { len=0; bufpos=0; memset(&sum_ctx,0,sizeof(sum_ctx)); sha1_init(&sum_ctx); } void SHA1::put(int c) { ///sha1_write(&sum_ctx,(const uint8_t*)&c,1); w_hw[bufpos++]=c; if (bufpos==SHA1CHUNK) { sha1_write(&sum_ctx,w_hw,SHA1CHUNK); bufpos=0; } len+=8; } const char* SHA1::result() { sha1_write(&sum_ctx,w_hw,bufpos); sha1_final(&sum_ctx); memcpy(hbuf, sum_ctx.buf,20); init(); return hbuf; } void SHA1::write(const char* buf, int64_t n) { sha1_write(&sum_ctx,(const uint8_t*)buf,n); len+=n*8; } void SHA1::process() { } #else #ifdef HWSHA1 /// This "thing" seems weird, and not very optimized, must be a "plug in" replacment void SHA1::init() { len=0; bufpos=0; Sha1_Init(&myhasher); } void SHA1::put(int c) { w_hw[bufpos++]=c; if (bufpos==SHA1CHUNK) { Sha1_Update(&myhasher,(const Byte*)w_hw,SHA1CHUNK); bufpos=0; } len+=8; } const char* SHA1::result() { Sha1_Update(&myhasher,(const Byte*)w_hw,bufpos); Sha1_Final(&myhasher,(Byte*)hbuf); init(); return hbuf; } void SHA1::write(const char* buf, int64_t n) { Sha1_Update(&myhasher,(const Byte*)buf,n); len+=n*8; } void SHA1::process() { } #else /// zpaq 7.15 use a very, very, very good implementation of SHA1, but full of very dirty tricks void SHA1::init() { len=0; memset(w, 0, sizeof(w)); h[0]=0x67452301; h[1]=0xEFCDAB89; h[2]=0x98BADCFE; h[3]=0x10325476; h[4]=0xC3D2E1F0; } void SHA1::put(int c) { U32& r=w[U32(len)>>5&15]; r=(r<<8)|(c&255); len+=8; if ((U32(len)&511)==0) process(); } const char* SHA1::result() { const U64 s=len; put(0x80); while ((len&511)!=448) put(0); put(s>>56); put(s>>48); put(s>>40); put(s>>32); put(s>>24); put(s>>16); put(s>>8); put(s); for (unsigned int i=0; i<5; ++i) { hbuf[4*i]=h[i]>>24; hbuf[4*i+1]=h[i]>>16; hbuf[4*i+2]=h[i]>>8; hbuf[4*i+3]=h[i]; } init(); return hbuf; } void SHA1::write(const char* buf, int64_t n) { const unsigned char* p=(const unsigned char*) buf; for (; n>0 && (U32(len)&511)!=0; --n) put(*p++); for (; n>=64; n-=64) { for (unsigned int i=0; i<16; ++i) w[i]=p[0]<<24|p[1]<<16|p[2]<<8|p[3], p+=4; len+=512; process(); } for (; n>0; --n) put(*p++); } void SHA1::process() { U32 a=h[0], b=h[1], c=h[2], d=h[3], e=h[4]; static const U32 k[4]={0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6}; #define f(a,b,c,d,e,i) \ if (i>=16) \ w[(i)&15]^=w[(i-3)&15]^w[(i-8)&15]^w[(i-14)&15], \ w[(i)&15]=w[(i)&15]<<1|w[(i)&15]>>31; \ e+=(a<<5|a>>27)+k[(i)/20]+w[(i)&15] \ +((i)%40>=20 ? b^c^d : i>=40 ? (b&c)|(d&(b|c)) : d^(b&(c^d))); \ b=b<<30|b>>2; #define r(i) f(a,b,c,d,e,i) f(e,a,b,c,d,i+1) f(d,e,a,b,c,i+2) \ f(c,d,e,a,b,i+3) f(b,c,d,e,a,i+4) r(0) r(5) r(10) r(15) r(20) r(25) r(30) r(35) r(40) r(45) r(50) r(55) r(60) r(65) r(70) r(75) #undef f #undef r h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; h[4]+=e; } #endif // corresponds to #ifdef (#ifdef HWSHA1) #endif // corresponds to #ifdef (#ifdef HWSHA2) //////////////////////////// SHA256 ////////////////////////// // For computing SHA-256 checksums // http://en.wikipedia.org/wiki/SHA-2 #define SHA2CHUNK 64 class SHA256 { public: void put(int c); void write(const char* buf, int64_t n); const char* result(); SHA256() {init();} private: void init(); #ifndef HWSHA2 unsigned len0, len1; /// puoi togliere? unsigned s[8]; ///puoi togliere unsigned w[16]; ///puoitogliere #endif // corresponds to #ifndef (#ifndef HWSHA2) char hbuf[32]; void process(); #ifdef HWSHA2 int bufpos; SUM_CONTEXT sum_ctx; unsigned char w_hw[SHA2CHUNK]; #endif // corresponds to #ifdef (#ifdef HWSHA2) }; #ifdef HWSHA2 //////////////////////////// SHA256 ////////////////////////// void SHA256::init() { bufpos=0; memset(&sum_ctx,0,sizeof(sum_ctx)); sha256_init(&sum_ctx); } void SHA256::put(int c) { w_hw[bufpos++]=c; if (bufpos==SHA2CHUNK) { sha256_write(&sum_ctx,w_hw,SHA2CHUNK); bufpos=0; } } const char* SHA256::result() { sha256_write(&sum_ctx,w_hw,bufpos); sha256_final(&sum_ctx); memcpy(hbuf, sum_ctx.buf,32); init(); return hbuf; } void SHA256::write(const char* buf, int64_t n) { sha256_write(&sum_ctx,(const uint8_t*)buf,n); } void SHA256::process() { } #else //////////////////////////// SHA256 ////////////////////////// void SHA256::put(int c) { // hash 1 byte unsigned& r=w[len0>>5&15]; r=(r<<8)|(c&255); if (!(len0+=8)) ++len1; if ((len0&511)==0) process(); } void SHA256::init() { len0=len1=0; s[0]=0x6a09e667; s[1]=0xbb67ae85; s[2]=0x3c6ef372; s[3]=0xa54ff53a; s[4]=0x510e527f; s[5]=0x9b05688c; s[6]=0x1f83d9ab; s[7]=0x5be0cd19; memset(w, 0, sizeof(w)); } void SHA256::process() { #define ror(a,b) ((a)>>(b)|(a<<(32-(b)))) #define m(i) \ w[(i)&15]+=w[(i-7)&15] \ +(ror(w[(i-15)&15],7)^ror(w[(i-15)&15],18)^(w[(i-15)&15]>>3)) \ +(ror(w[(i-2)&15],17)^ror(w[(i-2)&15],19)^(w[(i-2)&15]>>10)) #define r(a,b,c,d,e,f,g,h,i) { \ unsigned t1=ror(e,14)^e; \ t1=ror(t1,5)^e; \ h+=ror(t1,6)+((e&f)^(~e&g))+k[i]+w[(i)&15]; } \ d+=h; \ {unsigned t1=ror(a,9)^a; \ t1=ror(t1,11)^a; \ h+=ror(t1,2)+((a&b)^(c&(a^b))); } #define mr(a,b,c,d,e,f,g,h,i) m(i); r(a,b,c,d,e,f,g,h,i); #define r8(i) \ r(a,b,c,d,e,f,g,h,i); \ r(h,a,b,c,d,e,f,g,i+1); \ r(g,h,a,b,c,d,e,f,i+2); \ r(f,g,h,a,b,c,d,e,i+3); \ r(e,f,g,h,a,b,c,d,i+4); \ r(d,e,f,g,h,a,b,c,i+5); \ r(c,d,e,f,g,h,a,b,i+6); \ r(b,c,d,e,f,g,h,a,i+7); #define mr8(i) \ mr(a,b,c,d,e,f,g,h,i); \ mr(h,a,b,c,d,e,f,g,i+1); \ mr(g,h,a,b,c,d,e,f,i+2); \ mr(f,g,h,a,b,c,d,e,i+3); \ mr(e,f,g,h,a,b,c,d,i+4); \ mr(d,e,f,g,h,a,b,c,i+5); \ mr(c,d,e,f,g,h,a,b,i+6); \ mr(b,c,d,e,f,g,h,a,i+7); static const unsigned k[64]={ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; unsigned a=s[0]; unsigned b=s[1]; unsigned c=s[2]; unsigned d=s[3]; unsigned e=s[4]; unsigned f=s[5]; unsigned g=s[6]; unsigned h=s[7]; r8(0); r8(8); mr8(16); mr8(24); mr8(32); mr8(40); mr8(48); mr8(56); s[0]+=a; s[1]+=b; s[2]+=c; s[3]+=d; s[4]+=e; s[5]+=f; s[6]+=g; s[7]+=h; #undef mr8 #undef r8 #undef mr #undef r #undef m #undef ror } const char* SHA256::result() { const unsigned s1=len1, s0=len0; put(0x80); while ((len0&511)!=448) put(0); put(s1>>24); put(s1>>16); put(s1>>8); put(s1); put(s0>>24); put(s0>>16); put(s0>>8); put(s0); for (unsigned int i=0; i<8; ++i) { hbuf[4*i]=s[i]>>24; hbuf[4*i+1]=s[i]>>16; hbuf[4*i+2]=s[i]>>8; hbuf[4*i+3]=s[i]; } init(); return hbuf; } void SHA256::write(const char* buf, int64_t n) { for (int64_t i=0;i header; // hsize[2] hh hm ph pm n COMP (guard) HCOMP (guard) int cend; // COMP in header[7...cend-1] int hbegin, hend; // HCOMP/PCOMP in header[hbegin...hend-1] private: // Machine state for executing HCOMP Array m; // memory array M for HCOMP Array h; // hash array H for HCOMP Array r; // 256 element register array Array outbuf; // output buffer int bufptr; // number of bytes in outbuf U32 a, b, c, d; // machine registers int f; // condition flag int pc; // program counter int rcode_size; // length of rcode U8* rcode; // JIT code for run() // Support code int assemble(); // put JIT code in rcode void init(int hbits, int mbits); // initialize H and M sizes int execute(); // interpret 1 instruction, return 0 after HALT, else 1 void run0(U32 input); // default run() if not JIT void zdiv(U32 x) {if (x) a/=x; else a=0;} void mod(U32 x) {if (x) a%=x; else a=0;} void swap(U32& x) {a^=x; x^=a; a^=x;} void swap(U8& x) {a^=x; x^=a; a^=x;} void err(); // exit with run time error }; ///////////////////////// Component ////////////////////////// // A Component is a context model, indirect context model, match model, // fixed weight mixer, adaptive 2 input mixer without or with current // partial byte as context, adaptive m input mixer (without or with), // or SSE (without or with). struct Component { size_t limit; // max count for cm size_t cxt; // saved context size_t a, b, c; // multi-purpose variables Array cm; // cm[cxt] -> p in bits 31..10, n in 9..0; MATCH index Array ht; // ICM/ISSE hash table[0..size1][0..15] and MATCH buf Array a16; // MIX weights void init(); // initialize to all 0 Component() {init();} }; ////////////////////////// StateTable //////////////////////// // Next state table class StateTable { public: U8 ns[1024]; // state*4 -> next state if 0, if 1, n0, n1 int next(int state, int y) { // next state for bit y assert(state>=0 && state<256); assert(y>=0 && y<4); return ns[state*4+y]; } int cminit(int state) { // initial probability of 1 * 2^23 assert(state>=0 && state<256); return ((ns[state*4+3]*2+1)<<22)/(ns[state*4+2]+ns[state*4+3]+1); } StateTable(); }; ///////////////////////// Predictor ////////////////////////// // A predictor guesses the next bit class Predictor { public: Predictor(ZPAQL&); ~Predictor(); void init(); // build model int predict(); // probability that next bit is a 1 (0..4095) void update(int y); // train on bit y (0..1) int stat(int); // Defined externally bool isModeled() { // n>0 components? assert(z.header.isize()>6); return z.header[6]!=0; } private: // Predictor state int c8; // last 0...7 bits. int hmap4; // c8 split into nibbles int p[256]; // predictions U32 h[256]; // unrolled copy of z.h ZPAQL& z; // VM to compute context hashes, includes H, n Component comp[256]; // the model, includes P bool initTables; // are tables initialized? // Modeling support functions int predict0(); // default void update0(int y); // default int dt2k[256]; // division table for match: dt2k[i] = 2^12/i int dt[1024]; // division table for cm: dt[i] = 2^16/(i+1.5) U16 squasht[4096]; // squash() lookup table short stretcht[32768];// stretch() lookup table StateTable st; // next, cminit functions U8* pcode; // JIT code for predict() and update() int pcode_size; // length of pcode // reduce prediction error in cr.cm void train(Component& cr, int y) { assert(y==0 || y==1); U32& pn=cr.cm(cr.cxt); U32 count=pn&0x3ff; int error=y*32767-(cr.cm(cr.cxt)>>17); pn+=(error*dt[count]&-1024)+(count floor(32768/(1+exp(-x/64))) int squash(int x) { assert(initTables); assert(x>=-2048 && x<=2047); return squasht[x+2048]; } // x -> round(64*log((x+0.5)/(32767.5-x))), approx inverse of squash int stretch(int x) { assert(initTables); assert(x>=0 && x<=32767); return stretcht[x]; } // bound x to a 12 bit signed int int clamp2k(int x) { if (x<-2048) return -2048; else if (x>2047) return 2047; else return x; } // bound x to a 20 bit signed int int clamp512k(int x) { if (x<-(1<<19)) return -(1<<19); else if (x>=(1<<19)) return (1<<19)-1; else return x; } // Get cxt in ht, creating a new row if needed size_t find(Array& ht, int sizebits, U32 cxt); // Put JIT code in pcode int assemble_p(); }; //////////////////////////// Decoder ///////////////////////// // Decoder decompresses using an arithmetic code class Decoder: public Reader { public: Reader* in; // destination Decoder(ZPAQL& z); int decompress(); // return a byte or EOF int skip(); // skip to the end of the segment, return next byte void init(); // initialize at start of block int stat(int x) {return pr.stat(x);} int get() { // return 1 byte of buffered input or EOF if (rpos==wpos) { rpos=0; wpos=in ? in->read(&buf[0], BUFSIZE) : 0; assert(wpos<=BUFSIZE); } return rpos buf; // input buffer of size BUFSIZE bytes int decode(int p); // return decoded bit (0..1) with prob. p (0..65535) }; /////////////////////////// PostProcessor //////////////////// class PostProcessor { int state; // input parse state: 0=INIT, 1=PASS, 2..4=loading, 5=POST int hsize; // header size int ph, pm; // sizes of H and M in z public: ZPAQL z; // holds PCOMP PostProcessor(): state(0), hsize(0), ph(0), pm(0) {} void init(int h, int m); // ph, pm sizes of H and M int write(int c); // Input a byte, return state int getState() const {return state;} void setOutput(Writer* out) {z.output=out;} void setSHA1(SHA1* sha1ptr) {z.sha1=sha1ptr;} }; //////////////////////// Decompresser //////////////////////// // For decompression and listing archive contents class Decompresser { public: Decompresser(): z(), dec(z), pp(), state(BLOCK), decode_state(FIRSTSEG) {} void setInput(Reader* in) {dec.in=in;} bool findBlock(double* memptr = 0); void hcomp(Writer* out2) {z.write(out2, false);} bool findFilename(Writer* = 0); void readComment(Writer* = 0); void setOutput(Writer* out) {pp.setOutput(out);} void setSHA1(SHA1* sha1ptr) {pp.setSHA1(sha1ptr);} bool decompress(int n = -1); // n bytes, -1=all, return true until done bool pcomp(Writer* out2) {return pp.z.write(out2, true);} void readSegmentEnd(char* sha1string = 0); int stat(int x) {return dec.stat(x);} int buffered() {return dec.buffered();} private: ZPAQL z; Decoder dec; PostProcessor pp; enum {BLOCK, FILENAME, COMMENT, DATA, SEGEND} state; // expected next enum {FIRSTSEG, SEG, SKIP} decode_state; // which segment in block? }; /////////////////////////// decompress() ///////////////////// void decompress(Reader* in, Writer* out); //////////////////////////// Encoder ///////////////////////// // Encoder compresses using an arithmetic code class Encoder { public: Encoder(ZPAQL& z): out(0), low(1), high(0xFFFFFFFF), pr(z) {} void init(); void compress(int c); // c is 0..255 or EOF int stat(int x) {return pr.stat(x);} Writer* out; // destination private: U32 low, high; // range Predictor pr; // to get p Array buf; // unmodeled input void encode(int y, int p); // encode bit y (0..1) with prob. p (0..65535) }; //////////////////////////// Compiler //////////////////////// // Input ZPAQL source code with args and store the compiled code // in hz and pz and write pcomp_cmd to out2. class Compiler { public: Compiler(const char* in, int* args, ZPAQL& hz, ZPAQL& pz, Writer* out2); private: const char* in; // ZPAQL source code int* args; // Array of up to 9 args, default NULL = all 0 ZPAQL& hz; // Output of COMP and HCOMP sections ZPAQL& pz; // Output of PCOMP section Writer* out2; // Output ... of "PCOMP ... ;" int line; // Input line number for reporting errors int state; // parse state: 0=space -1=word >0 (nest level) // Symbolic constants typedef enum {NONE,CONS,CM,ICM,MATCH,AVG,MIX2,MIX,ISSE,SSE, JT=39,JF=47,JMP=63,LJ=255, POST=256,PCOMP,END,IF,IFNOT,ELSE,ENDIF,DO, WHILE,UNTIL,FOREVER,IFL,IFNOTL,ELSEL,SEMICOLON} CompType; void syntaxError(const char* msg, const char* expected=0); // error() void next(); // advance in to next token bool matchToken(const char* tok);// in==token? int rtoken(int low, int high); // return token which must be in range int rtoken(const char* list[]); // return token by position in list void rtoken(const char* s); // return token which must be s int compile_comp(ZPAQL& z); // compile either HCOMP or PCOMP // Stack of n elements class Stack { libzpaq::Array s; size_t top; public: Stack(int n): s(n), top(0) {} void push(const U16& x) { if (top>=s.size()) error("IF or DO nested too deep"); s[top++]=x; } U16 pop() { if (top<=0) error("unmatched IF or DO"); return s[--top]; } }; Stack if_stack, do_stack; }; //////////////////////// Compressor ////////////////////////// class Compressor { public: Compressor(): enc(z), in(0), state(INIT), verify(false) {} void setOutput(Writer* out) {enc.out=out;} void writeTag(); void startBlock(int level); // level=1,2,3 void startBlock(const char* hcomp); // ZPAQL byte code void startBlock(const char* config, // ZPAQL source code int* args, // NULL or int[9] arguments Writer* pcomp_cmd = 0); // retrieve preprocessor command #ifdef DEBUG void setVerify(bool v) {verify = v;} // check postprocessing? #endif // corresponds to #ifdef (#ifdef DEBUG) void hcomp(Writer* out2) {z.write(out2, false);} bool pcomp(Writer* out2) {return pz.write(out2, true);} void startSegment(const char* filename = 0, const char* comment = 0); void setInput(Reader* i) {in=i;} void postProcess(const char* pcomp = 0, int len = 0); // byte code bool compress(int n = -1); // n bytes, -1=all, return true until done void endSegment(const char* sha1string = 0); #ifdef DEBUG char* endSegmentChecksum(int64_t* size = 0, bool dosha1=true); #endif // corresponds to #ifdef (#ifdef DEBUG) void endBlock(); int stat(int x) {return enc.stat(x);} private: ZPAQL z, pz; // model and test postprocessor Encoder enc; // arithmetic encoder containing predictor Reader* in; // input source SHA1 sha1; // to test pz output /// char sha1result[20]; // sha1 output enum {INIT, BLOCK1, SEG1, BLOCK2, SEG2} state; bool verify; // if true then test by postprocessing }; /////////////////////////// StringBuffer ///////////////////// // For (de)compressing to/from a string. Writing appends bytes // which can be later read. class StringBuffer: public libzpaq::Reader, public libzpaq::Writer { unsigned char* p; // allocated memory, not NUL terminated, may be NULL size_t al; // number of bytes allocated, 0 iff p is NULL size_t wpos; // index of next byte to write, wpos <= al size_t rpos; // index of next byte to read, rpos < wpos or return EOF. size_t limit; // max size, default = -1 const size_t init; // initial size on first use after reset // Increase capacity to a without changing size void reserve(size_t a) { assert(!al==!p); if (a<=al) return; ///g_allocatedram+=a; unsigned char* q=0; if (a>0) q=(unsigned char*)(p ? franz_extend(p,a,al) : franz_malloc(a)); if (a>0 && !q) error("Out of memory"); p=q; al=a; } // Enlarge al to make room to write at least n bytes. void lengthen(size_t n) { assert(wpos<=al); if (wpos+n>limit || wpos+n=a) a=a*2+init; reserve(a); } // No assignment or copy void operator=(const StringBuffer&); StringBuffer(const StringBuffer&); public: // Direct access to data unsigned char* data() {assert(p || wpos==0); return p;} // Allocate no memory initially StringBuffer(size_t n=0): p(0), al(0), wpos(0), rpos(0), limit(size_t(-1)), init(n>128?n:128) {} // Set output limit void setLimit(size_t n) {limit=n;} // Free memory ~StringBuffer() {if (p) {franz_free(p);g_allocatedram-=al;}} // Return number of bytes written. size_t size() const {return wpos;} // Return number of bytes left to read ///size_t remaining() const {return wpos-rpos;} // Reset size to 0 and free memory. void reset() { if (p) {franz_free(p); g_allocatedram-=al; } p=0; al=rpos=wpos=0; } // Write a single byte. void put(int c) { // write 1 byte lengthen(1); assert(p); assert(wposwpos) n=wpos-rpos; if (n>0 && buf) memcpy(buf, p+rpos, n); rpos+=n; return n; } // Return the entire string as a read-only array. const char* c_str() const {return (const char*)p;} // Truncate the string to size i. void resize(size_t i) { wpos=i; if (rpos>wpos) rpos=wpos; } // Swap efficiently (init is not swapped) void swap(StringBuffer& s) { std::swap(p, s.p); std::swap(al, s.al); std::swap(wpos, s.wpos); std::swap(rpos, s.rpos); std::swap(limit, s.limit); } }; /////////////////////////// compress() /////////////////////// // Compress in to out in multiple blocks. Default method is "14,128,0" // Default filename is "". Comment is appended to input size. // dosha1 means save the SHA-1 checksum. void compress(Reader* in, Writer* out, const char* method, const char* filename=0, const char* comment=0, bool dosha1=true); // Same as compress() but output is 1 block, ignoring block size parameter. void compressBlock(StringBuffer* in, Writer* out, const char* method, const char* filename=0, const char* comment=0, bool dosha1=true); // Read 16 bit little-endian number int toU16(const char* p) { return (p[0]&255)+256*(p[1]&255); } // Default read() and write() int Reader::read(char* buf, int n) { int i=0, c; while (i=0) buf[i++]=c; return i; } void Writer::write(const char* buf, int n) { for (int i=0; i 0 bytes of executable memory and update // p to point to it and newsize = n. Free any previously // allocated memory first. If newsize is 0 then free only. // Call error in case of failure. If NOJIT, ignore newsize // and set p=0, n=0 without allocating memory. void allocx(U8* &p, int &n, int newsize) { if (flagnojit) { p=0; n=0; } else { if (p || n) { if (p) #ifdef unix munmap(p, n); #else // Windows VirtualFree(p, 0, MEM_RELEASE); #endif // corresponds to #ifdef (#ifdef unix) g_allocatedram-=n; p=0; n=0; } if (newsize>0) { #ifdef unix ///myprintf("BEFORE mmap of newsize %s\n",migliaia(newsize)); /// PROT_EXEC can be stopped p=(U8*)mmap(0, newsize, PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANON, -1, 0); ////myprintf("AFTER mmap\n"); if ((void*)p==MAP_FAILED) { if (flagdebug3) myprintf("10253$ MAP FAILED!\n"); p=0; } #else p=(U8*)VirtualAlloc(0, newsize, MEM_RESERVE|MEM_COMMIT,PAGE_EXECUTE_READWRITE); #endif // corresponds to #ifdef (#ifdef unix) if (p) { g_allocatedram+=newsize; n=newsize; } else { n=0; myprintf("\n\n"); myprintf("02249! allocx KO for %s (maybe non-Intel CPU? Unsupported OS?)\n",migliaia(newsize)); myprintf("02250! try to run with -nojit or compile using -DNOJIT\n\n"); color_restore(); exit(0); } } } } /// LICENSE_START.1 //////////////////////////// AES ///////////////////////////// // Some AES code is derived from libtomcrypt 1.17 (public domain). #define Te4_0 0x000000FF & Te4 #define Te4_1 0x0000FF00 & Te4 #define Te4_2 0x00FF0000 & Te4 #define Te4_3 0xFF000000 & Te4 // Extract byte n of x static inline unsigned byte(unsigned x, unsigned n) {return (x>>(8*n))&255;} // x = y[0..3] MSB first static inline void LOAD32H(U32& x, const char* y) { const unsigned char* u=(const unsigned char*)y; x=u[0]<<24|u[1]<<16|u[2]<<8|u[3]; } // y[0..3] = x MSB first static inline void STORE32H(U32& x, unsigned char* y) { y[0]=x>>24; y[1]=x>>16; y[2]=x>>8; y[3]=x; } #define setup_mix(temp) \ ((Te4_3[byte(temp, 2)]) ^ (Te4_2[byte(temp, 1)]) ^ \ (Te4_1[byte(temp, 0)]) ^ (Te4_0[byte(temp, 3)])) // Initialize encryption tables and round key. keylen is 16, 24, or 32. AES_CTR::AES_CTR(const char* key, int keylen, const char* iv) { assert(key != NULL); assert(keylen==16 || keylen==24 || keylen==32); // Initialize IV (default 0) iv0=iv1=0; if (iv) { LOAD32H(iv0, iv); LOAD32H(iv1, iv+4); } // Initialize encryption tables for (unsigned int i=0; i<256; ++i) { unsigned s1= "\x63\x7c\x77\x7b\xf2\x6b\x6f\xc5\x30\x01\x67\x2b\xfe\xd7\xab\x76" "\xca\x82\xc9\x7d\xfa\x59\x47\xf0\xad\xd4\xa2\xaf\x9c\xa4\x72\xc0" "\xb7\xfd\x93\x26\x36\x3f\xf7\xcc\x34\xa5\xe5\xf1\x71\xd8\x31\x15" "\x04\xc7\x23\xc3\x18\x96\x05\x9a\x07\x12\x80\xe2\xeb\x27\xb2\x75" "\x09\x83\x2c\x1a\x1b\x6e\x5a\xa0\x52\x3b\xd6\xb3\x29\xe3\x2f\x84" "\x53\xd1\x00\xed\x20\xfc\xb1\x5b\x6a\xcb\xbe\x39\x4a\x4c\x58\xcf" "\xd0\xef\xaa\xfb\x43\x4d\x33\x85\x45\xf9\x02\x7f\x50\x3c\x9f\xa8" "\x51\xa3\x40\x8f\x92\x9d\x38\xf5\xbc\xb6\xda\x21\x10\xff\xf3\xd2" "\xcd\x0c\x13\xec\x5f\x97\x44\x17\xc4\xa7\x7e\x3d\x64\x5d\x19\x73" "\x60\x81\x4f\xdc\x22\x2a\x90\x88\x46\xee\xb8\x14\xde\x5e\x0b\xdb" "\xe0\x32\x3a\x0a\x49\x06\x24\x5c\xc2\xd3\xac\x62\x91\x95\xe4\x79" "\xe7\xc8\x37\x6d\x8d\xd5\x4e\xa9\x6c\x56\xf4\xea\x65\x7a\xae\x08" "\xba\x78\x25\x2e\x1c\xa6\xb4\xc6\xe8\xdd\x74\x1f\x4b\xbd\x8b\x8a" "\x70\x3e\xb5\x66\x48\x03\xf6\x0e\x61\x35\x57\xb9\x86\xc1\x1d\x9e" "\xe1\xf8\x98\x11\x69\xd9\x8e\x94\x9b\x1e\x87\xe9\xce\x55\x28\xdf" "\x8c\xa1\x89\x0d\xbf\xe6\x42\x68\x41\x99\x2d\x0f\xb0\x54\xbb\x16" [i]&255; unsigned s2=s1<<1; if (s2>=0x100) s2^=0x11b; unsigned s3=s1^s2; Te0[i]=s2<<24|s1<<16|s1<<8|s3; Te1[i]=s3<<24|s2<<16|s1<<8|s1; Te2[i]=s1<<24|s3<<16|s2<<8|s1; Te3[i]=s1<<24|s1<<16|s3<<8|s2; Te4[i]=s1<<24|s1<<16|s1<<8|s1; } // setup the forward key Nr = 10 + ((keylen/8)-2)*2; // 10, 12, or 14 rounds int i = 0; U32* rk = &ek[0]; U32 temp; static const U32 rcon[10] = { 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL}; // round constants LOAD32H(rk[0], key ); LOAD32H(rk[1], key + 4); LOAD32H(rk[2], key + 8); LOAD32H(rk[3], key + 12); if (keylen == 16) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { break; } rk += 4; } } else if (keylen == 24) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); for (;;) { temp = rk[5]; rk[ 6] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { break; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } else if (keylen == 32) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); LOAD32H(rk[6], key + 24); LOAD32H(rk[7], key + 28); for (;;) { temp = rk[7]; rk[ 8] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { break; } temp = rk[11]; rk[12] = rk[ 4] ^ setup_mix(temp<<24|temp>>8); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } } // Encrypt to ct[16] void AES_CTR::encrypt(U32 s0, U32 s1, U32 s2, U32 s3, unsigned char* ct) { int r = Nr >> 1; U32 *rk = &ek[0]; U32 t0=0, t1=0, t2=0, t3=0; s0 ^= rk[0]; s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; for (;;) { t0 = Te0[byte(s0, 3)] ^ Te1[byte(s1, 2)] ^ Te2[byte(s2, 1)] ^ Te3[byte(s3, 0)] ^ rk[4]; t1 = Te0[byte(s1, 3)] ^ Te1[byte(s2, 2)] ^ Te2[byte(s3, 1)] ^ Te3[byte(s0, 0)] ^ rk[5]; t2 = Te0[byte(s2, 3)] ^ Te1[byte(s3, 2)] ^ Te2[byte(s0, 1)] ^ Te3[byte(s1, 0)] ^ rk[6]; t3 = Te0[byte(s3, 3)] ^ Te1[byte(s0, 2)] ^ Te2[byte(s1, 1)] ^ Te3[byte(s2, 0)] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[byte(t0, 3)] ^ Te1[byte(t1, 2)] ^ Te2[byte(t2, 1)] ^ Te3[byte(t3, 0)] ^ rk[0]; s1 = Te0[byte(t1, 3)] ^ Te1[byte(t2, 2)] ^ Te2[byte(t3, 1)] ^ Te3[byte(t0, 0)] ^ rk[1]; s2 = Te0[byte(t2, 3)] ^ Te1[byte(t3, 2)] ^ Te2[byte(t0, 1)] ^ Te3[byte(t1, 0)] ^ rk[2]; s3 = Te0[byte(t3, 3)] ^ Te1[byte(t0, 2)] ^ Te2[byte(t1, 1)] ^ Te3[byte(t2, 0)] ^ rk[3]; } // apply last round and map cipher state to byte array block: s0 = (Te4_3[byte(t0, 3)]) ^ (Te4_2[byte(t1, 2)]) ^ (Te4_1[byte(t2, 1)]) ^ (Te4_0[byte(t3, 0)]) ^ rk[0]; STORE32H(s0, ct); s1 = (Te4_3[byte(t1, 3)]) ^ (Te4_2[byte(t2, 2)]) ^ (Te4_1[byte(t3, 1)]) ^ (Te4_0[byte(t0, 0)]) ^ rk[1]; STORE32H(s1, ct+4); s2 = (Te4_3[byte(t2, 3)]) ^ (Te4_2[byte(t3, 2)]) ^ (Te4_1[byte(t0, 1)]) ^ (Te4_0[byte(t1, 0)]) ^ rk[2]; STORE32H(s2, ct+8); s3 = (Te4_3[byte(t3, 3)]) ^ (Te4_2[byte(t0, 2)]) ^ (Te4_1[byte(t1, 1)]) ^ (Te4_0[byte(t2, 0)]) ^ rk[3]; STORE32H(s3, ct+12); } // Encrypt or decrypt slice buf[0..n-1] at offset by XOR with AES(i) where // i is the 128 bit big-endian distance from the start in 16 byte blocks. void AES_CTR::encrypt(char* buf, int n, U64 offset) { for (U64 i=offset/16; i<=(offset+n)/16; ++i) { unsigned char ct[16]; encrypt(iv0, iv1, i>>32, i, ct); for (int j=0; j<16; ++j) { const int k=(i*16-offset)+j; if (k>=0 && k=0; j-=8) sha256.put(i>>j); memcpy(b, sha256.result(), 32); for (int j=0; j>(32-b))) x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); #undef R } for (unsigned int i=0; i<16; ++i) b[i]+=x[i]; } // BlockMix_{Salsa20/8, r} on b[0..128*r-1] static void blockmix(U32* b, int r) { assert(r<=8); U32 x[16]; U32 y[256]; memcpy(x, b+32*r-16, 64); for (int i=0; i<2*r; ++i) { for (int j=0; j<16; ++j) x[j]^=b[i*16+j]; salsa8(x); memcpy(&y[i*16], x, 64); } for (int i=0; i x(32*r), v(32*r*n); for (int i=0; i>(i%4*8); } // Strengthen password pw[0..pwlen-1] and salt[0..saltlen-1] // to produce key buf[0..buflen-1]. Uses O(n*r*p) time and 128*r*n bytes // of memory. n must be a power of 2 and r <= 8. void scrypt(const char* pw, int pwlen, const char* salt, int saltlen, int n, int r, int p, char* buf, int buflen) { assert(r<=8); assert(n>0 && (n&(n-1))==0); // power of 2? libzpaq::Array b(p*r*128); pbkdf2(pw, pwlen, salt, saltlen, &b[0], p*r*128); for (int i=0; i=1 && (buf[0]=='z' || buf[0]=='7')) buf[0]^=0x80; } //////////////////////////// Component /////////////////////// // A Component is a context model, indirect context model, match model, // fixed weight mixer, adaptive 2 input mixer without or with current // partial byte as context, adaptive m input mixer (without or with), // or SSE (without or with). const int compsize[256]={0,2,3,2,3,4,6,6,3,5}; void Component::init() { limit=cxt=a=b=c=0; cm.resize(0); ht.resize(0); a16.resize(0); } ////////////////////////// StateTable //////////////////////// // sns[i*4] -> next state if 0, next state if 1, n0, n1 static const U8 sns[1024]={ 1, 2, 0, 0, 3, 5, 1, 0, 4, 6, 0, 1, 7, 9, 2, 0, 8, 11, 1, 1, 8, 11, 1, 1, 10, 12, 0, 2, 13, 15, 3, 0, 14, 17, 2, 1, 14, 17, 2, 1, 16, 19, 1, 2, 16, 19, 1, 2, 18, 20, 0, 3, 21, 23, 4, 0, 22, 25, 3, 1, 22, 25, 3, 1, 24, 27, 2, 2, 24, 27, 2, 2, 26, 29, 1, 3, 26, 29, 1, 3, 28, 30, 0, 4, 31, 33, 5, 0, 32, 35, 4, 1, 32, 35, 4, 1, 34, 37, 3, 2, 34, 37, 3, 2, 36, 39, 2, 3, 36, 39, 2, 3, 38, 41, 1, 4, 38, 41, 1, 4, 40, 42, 0, 5, 43, 33, 6, 0, 44, 47, 5, 1, 44, 47, 5, 1, 46, 49, 4, 2, 46, 49, 4, 2, 48, 51, 3, 3, 48, 51, 3, 3, 50, 53, 2, 4, 50, 53, 2, 4, 52, 55, 1, 5, 52, 55, 1, 5, 40, 56, 0, 6, 57, 45, 7, 0, 58, 47, 6, 1, 58, 47, 6, 1, 60, 63, 5, 2, 60, 63, 5, 2, 62, 65, 4, 3, 62, 65, 4, 3, 64, 67, 3, 4, 64, 67, 3, 4, 66, 69, 2, 5, 66, 69, 2, 5, 52, 71, 1, 6, 52, 71, 1, 6, 54, 72, 0, 7, 73, 59, 8, 0, 74, 61, 7, 1, 74, 61, 7, 1, 76, 63, 6, 2, 76, 63, 6, 2, 78, 81, 5, 3, 78, 81, 5, 3, 80, 83, 4, 4, 80, 83, 4, 4, 82, 85, 3, 5, 82, 85, 3, 5, 66, 87, 2, 6, 66, 87, 2, 6, 68, 89, 1, 7, 68, 89, 1, 7, 70, 90, 0, 8, 91, 59, 9, 0, 92, 77, 8, 1, 92, 77, 8, 1, 94, 79, 7, 2, 94, 79, 7, 2, 96, 81, 6, 3, 96, 81, 6, 3, 98, 101, 5, 4, 98, 101, 5, 4, 100, 103, 4, 5, 100, 103, 4, 5, 82, 105, 3, 6, 82, 105, 3, 6, 84, 107, 2, 7, 84, 107, 2, 7, 86, 109, 1, 8, 86, 109, 1, 8, 70, 110, 0, 9, 111, 59, 10, 0, 112, 77, 9, 1, 112, 77, 9, 1, 114, 97, 8, 2, 114, 97, 8, 2, 116, 99, 7, 3, 116, 99, 7, 3, 62, 101, 6, 4, 62, 101, 6, 4, 80, 83, 5, 5, 80, 83, 5, 5, 100, 67, 4, 6, 100, 67, 4, 6, 102, 119, 3, 7, 102, 119, 3, 7, 104, 121, 2, 8, 104, 121, 2, 8, 86, 123, 1, 9, 86, 123, 1, 9, 70, 124, 0, 10, 125, 59, 11, 0, 126, 77, 10, 1, 126, 77, 10, 1, 128, 97, 9, 2, 128, 97, 9, 2, 60, 63, 8, 3, 60, 63, 8, 3, 66, 69, 3, 8, 66, 69, 3, 8, 104, 131, 2, 9, 104, 131, 2, 9, 86, 133, 1, 10, 86, 133, 1, 10, 70, 134, 0, 11, 135, 59, 12, 0, 136, 77, 11, 1, 136, 77, 11, 1, 138, 97, 10, 2, 138, 97, 10, 2, 104, 141, 2, 10, 104, 141, 2, 10, 86, 143, 1, 11, 86, 143, 1, 11, 70, 144, 0, 12, 145, 59, 13, 0, 146, 77, 12, 1, 146, 77, 12, 1, 148, 97, 11, 2, 148, 97, 11, 2, 104, 151, 2, 11, 104, 151, 2, 11, 86, 153, 1, 12, 86, 153, 1, 12, 70, 154, 0, 13, 155, 59, 14, 0, 156, 77, 13, 1, 156, 77, 13, 1, 158, 97, 12, 2, 158, 97, 12, 2, 104, 161, 2, 12, 104, 161, 2, 12, 86, 163, 1, 13, 86, 163, 1, 13, 70, 164, 0, 14, 165, 59, 15, 0, 166, 77, 14, 1, 166, 77, 14, 1, 168, 97, 13, 2, 168, 97, 13, 2, 104, 171, 2, 13, 104, 171, 2, 13, 86, 173, 1, 14, 86, 173, 1, 14, 70, 174, 0, 15, 175, 59, 16, 0, 176, 77, 15, 1, 176, 77, 15, 1, 178, 97, 14, 2, 178, 97, 14, 2, 104, 181, 2, 14, 104, 181, 2, 14, 86, 183, 1, 15, 86, 183, 1, 15, 70, 184, 0, 16, 185, 59, 17, 0, 186, 77, 16, 1, 186, 77, 16, 1, 74, 97, 15, 2, 74, 97, 15, 2, 104, 89, 2, 15, 104, 89, 2, 15, 86, 187, 1, 16, 86, 187, 1, 16, 70, 188, 0, 17, 189, 59, 18, 0, 190, 77, 17, 1, 86, 191, 1, 17, 70, 192, 0, 18, 193, 59, 19, 0, 194, 77, 18, 1, 86, 195, 1, 18, 70, 196, 0, 19, 193, 59, 20, 0, 197, 77, 19, 1, 86, 198, 1, 19, 70, 196, 0, 20, 199, 77, 20, 1, 86, 200, 1, 20, 201, 77, 21, 1, 86, 202, 1, 21, 203, 77, 22, 1, 86, 204, 1, 22, 205, 77, 23, 1, 86, 206, 1, 23, 207, 77, 24, 1, 86, 208, 1, 24, 209, 77, 25, 1, 86, 210, 1, 25, 211, 77, 26, 1, 86, 212, 1, 26, 213, 77, 27, 1, 86, 214, 1, 27, 215, 77, 28, 1, 86, 216, 1, 28, 217, 77, 29, 1, 86, 218, 1, 29, 219, 77, 30, 1, 86, 220, 1, 30, 221, 77, 31, 1, 86, 222, 1, 31, 223, 77, 32, 1, 86, 224, 1, 32, 225, 77, 33, 1, 86, 226, 1, 33, 227, 77, 34, 1, 86, 228, 1, 34, 229, 77, 35, 1, 86, 230, 1, 35, 231, 77, 36, 1, 86, 232, 1, 36, 233, 77, 37, 1, 86, 234, 1, 37, 235, 77, 38, 1, 86, 236, 1, 38, 237, 77, 39, 1, 86, 238, 1, 39, 239, 77, 40, 1, 86, 240, 1, 40, 241, 77, 41, 1, 86, 242, 1, 41, 243, 77, 42, 1, 86, 244, 1, 42, 245, 77, 43, 1, 86, 246, 1, 43, 247, 77, 44, 1, 86, 248, 1, 44, 249, 77, 45, 1, 86, 250, 1, 45, 251, 77, 46, 1, 86, 252, 1, 46, 253, 77, 47, 1, 86, 254, 1, 47, 253, 77, 48, 1, 86, 254, 1, 48, 0, 0, 0, 0 }; // Initialize next state table ns[state*4] -> next if 0, next if 1, n0, n1 StateTable::StateTable() { memcpy(ns, sns, sizeof(ns)); } /////////////////////////// ZPAQL ////////////////////////// // Write header to out2, return true if HCOMP/PCOMP section is present. // If pp is true, then write only the postprocessor code. bool ZPAQL::write(Writer* out2, bool pp) { if (header.size()<=6) return false; assert(header[0]+256*header[1]==(cend-2)+hend-hbegin); assert(cend>=7); assert(hbegin>=cend); assert(hend>=hbegin); assert(out2); if (!pp) { // if not a postprocessor then write COMP for (int i=0; iput(header[i]); } else { // write PCOMP size only out2->put((hend-hbegin)&255); out2->put((hend-hbegin)>>8); } for (int i=hbegin; iput(header[i]); return true; } // Read header from in2 int ZPAQL::read(Reader* in2) { // Get header size and allocate int hsize=in2->get(); hsize+=in2->get()*256; header.resize(hsize+300); cend=hbegin=hend=0; header[cend++]=hsize&255; header[cend++]=hsize>>8; while (cend<7) header[cend++]=in2->get(); // hh hm ph pm n // Read COMP int n=header[cend-1]; for (int i=0; iget(); // component type if (type<0 || type>255) error("unexpected end of file"); header[cend++]=type; // component type int size=compsize[type]; if (size<1) error("Invalid component type"); if (cend+size>hsize) error("COMP overflows header"); for (int j=1; jget(); } if ((header[cend++]=in2->get())!=0) error("missing COMP END"); // Insert a guard gap and read HCOMP hbegin=hend=cend+128; if (hend>hsize+129) error("missing HCOMP"); while (hendget(); if (op==-1) error("unexpected end of file"); header[hend++]=op; } if ((header[hend++]=in2->get())!=0) error("missing HCOMP END"); assert(cend>=7 && cendhbegin && hend6); assert(output==0); assert(sha1==0); init(header[2], header[3]); // hh, hm } // Initialize machine state as PCOMP void ZPAQL::initp() { assert(header.isize()>6); init(header[4], header[5]); // ph, pm } // Flush pending output void ZPAQL::flush() { if (output) output->write(&outbuf[0], bufptr); if (sha1) sha1->write(&outbuf[0], bufptr); bufptr=0; } // pow(2, x) static double pow2(int x) { double r=1; for (; x>0; x--) r+=r; return r; } // Return memory requirement in bytes double ZPAQL::memory() { double mem=pow2(header[2]+2)+pow2(header[3]) // hh hm +pow2(header[4]+2)+pow2(header[5]) // ph pm +header.size(); int cp=7; // start of comp list for (unsigned int i=0; i0); assert(cend>=7); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend0); if (hbits>32) error("H too big"); if (mbits>32) error("M too big"); h.resize(1, hbits); m.resize(1, mbits); r.resize(256); a=b=c=d=pc=f=0; } // Run program on input by interpreting header void ZPAQL::run0(U32 input) { assert(cend>6); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend0); assert(h.size()>0); assert(header[0]+256*header[1]==cend+hend-hbegin-2); pc=hbegin; a=input; while (execute()) ; } // Execute one instruction, return 0 after HALT else 1 int ZPAQL::execute() { switch(header[pc++]) { case 0: err(); break; // ERROR case 1: ++a; break; // A++ case 2: --a; break; // A-- case 3: a = ~a; break; // A! case 4: a = 0; break; // A=0 case 7: a = r[header[pc++]]; break; // A=R N case 8: swap(b); break; // B<>A case 9: ++b; break; // B++ case 10: --b; break; // B-- case 11: b = ~b; break; // B! case 12: b = 0; break; // B=0 case 15: b = r[header[pc++]]; break; // B=R N case 16: swap(c); break; // C<>A case 17: ++c; break; // C++ case 18: --c; break; // C-- case 19: c = ~c; break; // C! case 20: c = 0; break; // C=0 case 23: c = r[header[pc++]]; break; // C=R N case 24: swap(d); break; // D<>A case 25: ++d; break; // D++ case 26: --d; break; // D-- case 27: d = ~d; break; // D! case 28: d = 0; break; // D=0 case 31: d = r[header[pc++]]; break; // D=R N case 32: swap(m(b)); break; // *B<>A case 33: ++m(b); break; // *B++ case 34: --m(b); break; // *B-- case 35: m(b) = ~m(b); break; // *B! case 36: m(b) = 0; break; // *B=0 case 39: if (f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JT N case 40: swap(m(c)); break; // *C<>A case 41: ++m(c); break; // *C++ case 42: --m(c); break; // *C-- case 43: m(c) = ~m(c); break; // *C! case 44: m(c) = 0; break; // *C=0 case 47: if (!f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JF N case 48: swap(h(d)); break; // *D<>A case 49: ++h(d); break; // *D++ case 50: --h(d); break; // *D-- case 51: h(d) = ~h(d); break; // *D! case 52: h(d) = 0; break; // *D=0 case 55: r[header[pc++]] = a; break; // R=A N case 56: return 0 ; // HALT case 57: outc(a&255); break; // OUT case 59: a = (a+m(b)+512)*773; break; // HASH case 60: h(d) = (h(d)+a+512)*773; break; // HASHD case 63: pc+=((header[pc]+128)&255)-127; break; // JMP N case 64: break; // A=A case 65: a = b; break; // A=B case 66: a = c; break; // A=C case 67: a = d; break; // A=D case 68: a = m(b); break; // A=*B case 69: a = m(c); break; // A=*C case 70: a = h(d); break; // A=*D case 71: a = header[pc++]; break; // A= N case 72: b = a; break; // B=A case 73: break; // B=B case 74: b = c; break; // B=C case 75: b = d; break; // B=D case 76: b = m(b); break; // B=*B case 77: b = m(c); break; // B=*C case 78: b = h(d); break; // B=*D case 79: b = header[pc++]; break; // B= N case 80: c = a; break; // C=A case 81: c = b; break; // C=B case 82: break; // C=C case 83: c = d; break; // C=D case 84: c = m(b); break; // C=*B case 85: c = m(c); break; // C=*C case 86: c = h(d); break; // C=*D case 87: c = header[pc++]; break; // C= N case 88: d = a; break; // D=A case 89: d = b; break; // D=B case 90: d = c; break; // D=C case 91: break; // D=D case 92: d = m(b); break; // D=*B case 93: d = m(c); break; // D=*C case 94: d = h(d); break; // D=*D case 95: d = header[pc++]; break; // D= N case 96: m(b) = a; break; // *B=A case 97: m(b) = b; break; // *B=B case 98: m(b) = c; break; // *B=C case 99: m(b) = d; break; // *B=D case 100: break; // *B=*B case 101: m(b) = m(c); break; // *B=*C case 102: m(b) = h(d); break; // *B=*D case 103: m(b) = header[pc++]; break; // *B= N case 104: m(c) = a; break; // *C=A case 105: m(c) = b; break; // *C=B case 106: m(c) = c; break; // *C=C case 107: m(c) = d; break; // *C=D case 108: m(c) = m(b); break; // *C=*B case 109: break; // *C=*C case 110: m(c) = h(d); break; // *C=*D case 111: m(c) = header[pc++]; break; // *C= N case 112: h(d) = a; break; // *D=A case 113: h(d) = b; break; // *D=B case 114: h(d) = c; break; // *D=C case 115: h(d) = d; break; // *D=D case 116: h(d) = m(b); break; // *D=*B case 117: h(d) = m(c); break; // *D=*C case 118: break; // *D=*D case 119: h(d) = header[pc++]; break; // *D= N case 128: a += a; break; // A+=A case 129: a += b; break; // A+=B case 130: a += c; break; // A+=C case 131: a += d; break; // A+=D case 132: a += m(b); break; // A+=*B case 133: a += m(c); break; // A+=*C case 134: a += h(d); break; // A+=*D case 135: a += header[pc++]; break; // A+= N case 136: a -= a; break; // A-=A case 137: a -= b; break; // A-=B case 138: a -= c; break; // A-=C case 139: a -= d; break; // A-=D case 140: a -= m(b); break; // A-=*B case 141: a -= m(c); break; // A-=*C case 142: a -= h(d); break; // A-=*D case 143: a -= header[pc++]; break; // A-= N case 144: a *= a; break; // A*=A case 145: a *= b; break; // A*=B case 146: a *= c; break; // A*=C case 147: a *= d; break; // A*=D case 148: a *= m(b); break; // A*=*B case 149: a *= m(c); break; // A*=*C case 150: a *= h(d); break; // A*=*D case 151: a *= header[pc++]; break; // A*= N case 152: zdiv(a); break; // A/=A case 153: zdiv(b); break; // A/=B case 154: zdiv(c); break; // A/=C case 155: zdiv(d); break; // A/=D case 156: zdiv(m(b)); break; // A/=*B case 157: zdiv(m(c)); break; // A/=*C case 158: zdiv(h(d)); break; // A/=*D case 159: zdiv(header[pc++]); break; // A/= N case 160: mod(a); break; // A%=A case 161: mod(b); break; // A%=B case 162: mod(c); break; // A%=C case 163: mod(d); break; // A%=D case 164: mod(m(b)); break; // A%=*B case 165: mod(m(c)); break; // A%=*C case 166: mod(h(d)); break; // A%=*D case 167: mod(header[pc++]); break; // A%= N case 168: a &= a; break; // A&=A case 169: a &= b; break; // A&=B case 170: a &= c; break; // A&=C case 171: a &= d; break; // A&=D case 172: a &= m(b); break; // A&=*B case 173: a &= m(c); break; // A&=*C case 174: a &= h(d); break; // A&=*D case 175: a &= header[pc++]; break; // A&= N case 176: a &= ~ a; break; // A&~A case 177: a &= ~ b; break; // A&~B case 178: a &= ~ c; break; // A&~C case 179: a &= ~ d; break; // A&~D case 180: a &= ~ m(b); break; // A&~*B case 181: a &= ~ m(c); break; // A&~*C case 182: a &= ~ h(d); break; // A&~*D case 183: a &= ~ header[pc++]; break; // A&~ N case 184: a |= a; break; // A|=A case 185: a |= b; break; // A|=B case 186: a |= c; break; // A|=C case 187: a |= d; break; // A|=D case 188: a |= m(b); break; // A|=*B case 189: a |= m(c); break; // A|=*C case 190: a |= h(d); break; // A|=*D case 191: a |= header[pc++]; break; // A|= N case 192: a ^= a; break; // A^=A case 193: a ^= b; break; // A^=B case 194: a ^= c; break; // A^=C case 195: a ^= d; break; // A^=D case 196: a ^= m(b); break; // A^=*B case 197: a ^= m(c); break; // A^=*C case 198: a ^= h(d); break; // A^=*D case 199: a ^= header[pc++]; break; // A^= N case 200: a <<= (a&31); break; // A<<=A case 201: a <<= (b&31); break; // A<<=B case 202: a <<= (c&31); break; // A<<=C case 203: a <<= (d&31); break; // A<<=D case 204: a <<= (m(b)&31); break; // A<<=*B case 205: a <<= (m(c)&31); break; // A<<=*C case 206: a <<= (h(d)&31); break; // A<<=*D case 207: a <<= (header[pc++]&31); break; // A<<= N case 208: a >>= (a&31); break; // A>>=A case 209: a >>= (b&31); break; // A>>=B case 210: a >>= (c&31); break; // A>>=C case 211: a >>= (d&31); break; // A>>=D case 212: a >>= (m(b)&31); break; // A>>=*B case 213: a >>= (m(c)&31); break; // A>>=*C case 214: a >>= (h(d)&31); break; // A>>=*D case 215: a >>= (header[pc++]&31); break; // A>>= N case 216: f = 1; break; // A==A case 217: f = (a == b); break; // A==B case 218: f = (a == c); break; // A==C case 219: f = (a == d); break; // A==D case 220: f = (a == U32(m(b))); break; // A==*B case 221: f = (a == U32(m(c))); break; // A==*C case 222: f = (a == h(d)); break; // A==*D case 223: f = (a == U32(header[pc++])); break; // A== N case 224: f = 0; break; // AA case 233: f = (a > b); break; // A>B case 234: f = (a > c); break; // A>C case 235: f = (a > d); break; // A>D case 236: f = (a > U32(m(b))); break; // A>*B case 237: f = (a > U32(m(c))); break; // A>*C case 238: f = (a > h(d)); break; // A>*D case 239: f = (a > U32(header[pc++])); break; // A> N case 255: if((pc=hbegin+header[pc]+256*header[pc+1])>=hend)err();break;//LJ default: err(); } return 1; } // Print illegal instruction error message and exit void ZPAQL::err() { error("ZPAQL execution error"); } ///////////////////////// Predictor ///////////////////////// // sdt2k[i]=2048/i; static const int sdt2k[256]={ 0, 2048, 1024, 682, 512, 409, 341, 292, 256, 227, 204, 186, 170, 157, 146, 136, 128, 120, 113, 107, 102, 97, 93, 89, 85, 81, 78, 75, 73, 70, 68, 66, 64, 62, 60, 58, 56, 55, 53, 52, 51, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 40, 39, 38, 37, 37, 36, 35, 35, 34, 34, 33, 33, 32, 32, 31, 31, 30, 30, 29, 29, 28, 28, 28, 27, 27, 26, 26, 26, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23, 22, 22, 22, 22, 21, 21, 21, 21, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; // sdt[i]=(1<<17)/(i*2+3)*2; static const int sdt[1024]={ 87380, 52428, 37448, 29126, 23830, 20164, 17476, 15420, 13796, 12482, 11396, 10484, 9708, 9038, 8456, 7942, 7488, 7084, 6720, 6392, 6096, 5824, 5576, 5348, 5140, 4946, 4766, 4598, 4442, 4296, 4160, 4032, 3912, 3798, 3692, 3590, 3494, 3404, 3318, 3236, 3158, 3084, 3012, 2944, 2880, 2818, 2758, 2702, 2646, 2594, 2544, 2496, 2448, 2404, 2360, 2318, 2278, 2240, 2202, 2166, 2130, 2096, 2064, 2032, 2000, 1970, 1940, 1912, 1884, 1858, 1832, 1806, 1782, 1758, 1736, 1712, 1690, 1668, 1648, 1628, 1608, 1588, 1568, 1550, 1532, 1514, 1496, 1480, 1464, 1448, 1432, 1416, 1400, 1386, 1372, 1358, 1344, 1330, 1316, 1304, 1290, 1278, 1266, 1254, 1242, 1230, 1218, 1208, 1196, 1186, 1174, 1164, 1154, 1144, 1134, 1124, 1114, 1106, 1096, 1086, 1078, 1068, 1060, 1052, 1044, 1036, 1028, 1020, 1012, 1004, 996, 988, 980, 974, 966, 960, 952, 946, 938, 932, 926, 918, 912, 906, 900, 894, 888, 882, 876, 870, 864, 858, 852, 848, 842, 836, 832, 826, 820, 816, 810, 806, 800, 796, 790, 786, 782, 776, 772, 768, 764, 758, 754, 750, 746, 742, 738, 734, 730, 726, 722, 718, 714, 710, 706, 702, 698, 694, 690, 688, 684, 680, 676, 672, 670, 666, 662, 660, 656, 652, 650, 646, 644, 640, 636, 634, 630, 628, 624, 622, 618, 616, 612, 610, 608, 604, 602, 598, 596, 594, 590, 588, 586, 582, 580, 578, 576, 572, 570, 568, 566, 562, 560, 558, 556, 554, 550, 548, 546, 544, 542, 540, 538, 536, 532, 530, 528, 526, 524, 522, 520, 518, 516, 514, 512, 510, 508, 506, 504, 502, 500, 498, 496, 494, 492, 490, 488, 488, 486, 484, 482, 480, 478, 476, 474, 474, 472, 470, 468, 466, 464, 462, 462, 460, 458, 456, 454, 454, 452, 450, 448, 448, 446, 444, 442, 442, 440, 438, 436, 436, 434, 432, 430, 430, 428, 426, 426, 424, 422, 422, 420, 418, 418, 416, 414, 414, 412, 410, 410, 408, 406, 406, 404, 402, 402, 400, 400, 398, 396, 396, 394, 394, 392, 390, 390, 388, 388, 386, 386, 384, 382, 382, 380, 380, 378, 378, 376, 376, 374, 372, 372, 370, 370, 368, 368, 366, 366, 364, 364, 362, 362, 360, 360, 358, 358, 356, 356, 354, 354, 352, 352, 350, 350, 348, 348, 348, 346, 346, 344, 344, 342, 342, 340, 340, 340, 338, 338, 336, 336, 334, 334, 332, 332, 332, 330, 330, 328, 328, 328, 326, 326, 324, 324, 324, 322, 322, 320, 320, 320, 318, 318, 316, 316, 316, 314, 314, 312, 312, 312, 310, 310, 310, 308, 308, 308, 306, 306, 304, 304, 304, 302, 302, 302, 300, 300, 300, 298, 298, 298, 296, 296, 296, 294, 294, 294, 292, 292, 292, 290, 290, 290, 288, 288, 288, 286, 286, 286, 284, 284, 284, 284, 282, 282, 282, 280, 280, 280, 278, 278, 278, 276, 276, 276, 276, 274, 274, 274, 272, 272, 272, 272, 270, 270, 270, 268, 268, 268, 268, 266, 266, 266, 266, 264, 264, 264, 262, 262, 262, 262, 260, 260, 260, 260, 258, 258, 258, 258, 256, 256, 256, 256, 254, 254, 254, 254, 252, 252, 252, 252, 250, 250, 250, 250, 248, 248, 248, 248, 248, 246, 246, 246, 246, 244, 244, 244, 244, 242, 242, 242, 242, 242, 240, 240, 240, 240, 238, 238, 238, 238, 238, 236, 236, 236, 236, 234, 234, 234, 234, 234, 232, 232, 232, 232, 232, 230, 230, 230, 230, 230, 228, 228, 228, 228, 228, 226, 226, 226, 226, 226, 224, 224, 224, 224, 224, 222, 222, 222, 222, 222, 220, 220, 220, 220, 220, 220, 218, 218, 218, 218, 218, 216, 216, 216, 216, 216, 216, 214, 214, 214, 214, 214, 212, 212, 212, 212, 212, 212, 210, 210, 210, 210, 210, 210, 208, 208, 208, 208, 208, 208, 206, 206, 206, 206, 206, 206, 204, 204, 204, 204, 204, 204, 204, 202, 202, 202, 202, 202, 202, 200, 200, 200, 200, 200, 200, 198, 198, 198, 198, 198, 198, 198, 196, 196, 196, 196, 196, 196, 196, 194, 194, 194, 194, 194, 194, 194, 192, 192, 192, 192, 192, 192, 192, 190, 190, 190, 190, 190, 190, 190, 188, 188, 188, 188, 188, 188, 188, 186, 186, 186, 186, 186, 186, 186, 186, 184, 184, 184, 184, 184, 184, 184, 182, 182, 182, 182, 182, 182, 182, 182, 180, 180, 180, 180, 180, 180, 180, 180, 178, 178, 178, 178, 178, 178, 178, 178, 176, 176, 176, 176, 176, 176, 176, 176, 176, 174, 174, 174, 174, 174, 174, 174, 174, 172, 172, 172, 172, 172, 172, 172, 172, 172, 170, 170, 170, 170, 170, 170, 170, 170, 170, 168, 168, 168, 168, 168, 168, 168, 168, 168, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 164, 164, 164, 164, 164, 164, 164, 164, 164, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 126 }; // ssquasht[i]=int(32768.0/(1+exp((i-2048)*(-1.0/64)))); // Middle 1344 of 4096 entries only. static const U16 ssquasht[1344]={ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 21, 22, 22, 22, 23, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34, 35, 36, 36, 37, 37, 38, 38, 39, 40, 40, 41, 42, 42, 43, 44, 44, 45, 46, 46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 79, 81, 82, 83, 84, 86, 87, 88, 90, 91, 93, 94, 96, 97, 99, 100, 102, 103, 105, 107, 108, 110, 112, 114, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 144, 146, 148, 151, 153, 155, 158, 160, 163, 165, 168, 171, 173, 176, 179, 182, 184, 187, 190, 193, 196, 199, 202, 206, 209, 212, 215, 219, 222, 226, 229, 233, 237, 240, 244, 248, 252, 256, 260, 264, 268, 272, 276, 281, 285, 289, 294, 299, 303, 308, 313, 318, 323, 328, 333, 338, 343, 349, 354, 360, 365, 371, 377, 382, 388, 394, 401, 407, 413, 420, 426, 433, 440, 446, 453, 460, 467, 475, 482, 490, 497, 505, 513, 521, 529, 537, 545, 554, 562, 571, 580, 589, 598, 607, 617, 626, 636, 646, 656, 666, 676, 686, 697, 708, 719, 730, 741, 752, 764, 776, 788, 800, 812, 825, 837, 850, 863, 876, 890, 903, 917, 931, 946, 960, 975, 990, 1005, 1020, 1036, 1051, 1067, 1084, 1100, 1117, 1134, 1151, 1169, 1186, 1204, 1223, 1241, 1260, 1279, 1298, 1318, 1338, 1358, 1379, 1399, 1421, 1442, 1464, 1486, 1508, 1531, 1554, 1577, 1600, 1624, 1649, 1673, 1698, 1724, 1749, 1775, 1802, 1829, 1856, 1883, 1911, 1940, 1968, 1998, 2027, 2057, 2087, 2118, 2149, 2181, 2213, 2245, 2278, 2312, 2345, 2380, 2414, 2450, 2485, 2521, 2558, 2595, 2633, 2671, 2709, 2748, 2788, 2828, 2869, 2910, 2952, 2994, 3037, 3080, 3124, 3168, 3213, 3259, 3305, 3352, 3399, 3447, 3496, 3545, 3594, 3645, 3696, 3747, 3799, 3852, 3906, 3960, 4014, 4070, 4126, 4182, 4240, 4298, 4356, 4416, 4476, 4537, 4598, 4660, 4723, 4786, 4851, 4916, 4981, 5048, 5115, 5183, 5251, 5320, 5390, 5461, 5533, 5605, 5678, 5752, 5826, 5901, 5977, 6054, 6131, 6210, 6289, 6369, 6449, 6530, 6613, 6695, 6779, 6863, 6949, 7035, 7121, 7209, 7297, 7386, 7476, 7566, 7658, 7750, 7842, 7936, 8030, 8126, 8221, 8318, 8415, 8513, 8612, 8712, 8812, 8913, 9015, 9117, 9221, 9324, 9429, 9534, 9640, 9747, 9854, 9962, 10071, 10180, 10290, 10401, 10512, 10624, 10737, 10850, 10963, 11078, 11192, 11308, 11424, 11540, 11658, 11775, 11893, 12012, 12131, 12251, 12371, 12491, 12612, 12734, 12856, 12978, 13101, 13224, 13347, 13471, 13595, 13719, 13844, 13969, 14095, 14220, 14346, 14472, 14599, 14725, 14852, 14979, 15106, 15233, 15361, 15488, 15616, 15744, 15872, 16000, 16128, 16256, 16384, 16511, 16639, 16767, 16895, 17023, 17151, 17279, 17406, 17534, 17661, 17788, 17915, 18042, 18168, 18295, 18421, 18547, 18672, 18798, 18923, 19048, 19172, 19296, 19420, 19543, 19666, 19789, 19911, 20033, 20155, 20276, 20396, 20516, 20636, 20755, 20874, 20992, 21109, 21227, 21343, 21459, 21575, 21689, 21804, 21917, 22030, 22143, 22255, 22366, 22477, 22587, 22696, 22805, 22913, 23020, 23127, 23233, 23338, 23443, 23546, 23650, 23752, 23854, 23955, 24055, 24155, 24254, 24352, 24449, 24546, 24641, 24737, 24831, 24925, 25017, 25109, 25201, 25291, 25381, 25470, 25558, 25646, 25732, 25818, 25904, 25988, 26072, 26154, 26237, 26318, 26398, 26478, 26557, 26636, 26713, 26790, 26866, 26941, 27015, 27089, 27162, 27234, 27306, 27377, 27447, 27516, 27584, 27652, 27719, 27786, 27851, 27916, 27981, 28044, 28107, 28169, 28230, 28291, 28351, 28411, 28469, 28527, 28585, 28641, 28697, 28753, 28807, 28861, 28915, 28968, 29020, 29071, 29122, 29173, 29222, 29271, 29320, 29368, 29415, 29462, 29508, 29554, 29599, 29643, 29687, 29730, 29773, 29815, 29857, 29898, 29939, 29979, 30019, 30058, 30096, 30134, 30172, 30209, 30246, 30282, 30317, 30353, 30387, 30422, 30455, 30489, 30522, 30554, 30586, 30618, 30649, 30680, 30710, 30740, 30769, 30799, 30827, 30856, 30884, 30911, 30938, 30965, 30992, 31018, 31043, 31069, 31094, 31118, 31143, 31167, 31190, 31213, 31236, 31259, 31281, 31303, 31325, 31346, 31368, 31388, 31409, 31429, 31449, 31469, 31488, 31507, 31526, 31544, 31563, 31581, 31598, 31616, 31633, 31650, 31667, 31683, 31700, 31716, 31731, 31747, 31762, 31777, 31792, 31807, 31821, 31836, 31850, 31864, 31877, 31891, 31904, 31917, 31930, 31942, 31955, 31967, 31979, 31991, 32003, 32015, 32026, 32037, 32048, 32059, 32070, 32081, 32091, 32101, 32111, 32121, 32131, 32141, 32150, 32160, 32169, 32178, 32187, 32196, 32205, 32213, 32222, 32230, 32238, 32246, 32254, 32262, 32270, 32277, 32285, 32292, 32300, 32307, 32314, 32321, 32327, 32334, 32341, 32347, 32354, 32360, 32366, 32373, 32379, 32385, 32390, 32396, 32402, 32407, 32413, 32418, 32424, 32429, 32434, 32439, 32444, 32449, 32454, 32459, 32464, 32468, 32473, 32478, 32482, 32486, 32491, 32495, 32499, 32503, 32507, 32511, 32515, 32519, 32523, 32527, 32530, 32534, 32538, 32541, 32545, 32548, 32552, 32555, 32558, 32561, 32565, 32568, 32571, 32574, 32577, 32580, 32583, 32585, 32588, 32591, 32594, 32596, 32599, 32602, 32604, 32607, 32609, 32612, 32614, 32616, 32619, 32621, 32623, 32626, 32628, 32630, 32632, 32634, 32636, 32638, 32640, 32642, 32644, 32646, 32648, 32650, 32652, 32653, 32655, 32657, 32659, 32660, 32662, 32664, 32665, 32667, 32668, 32670, 32671, 32673, 32674, 32676, 32677, 32679, 32680, 32681, 32683, 32684, 32685, 32686, 32688, 32689, 32690, 32691, 32693, 32694, 32695, 32696, 32697, 32698, 32699, 32700, 32701, 32702, 32703, 32704, 32705, 32706, 32707, 32708, 32709, 32710, 32711, 32712, 32713, 32713, 32714, 32715, 32716, 32717, 32718, 32718, 32719, 32720, 32721, 32721, 32722, 32723, 32723, 32724, 32725, 32725, 32726, 32727, 32727, 32728, 32729, 32729, 32730, 32730, 32731, 32731, 32732, 32733, 32733, 32734, 32734, 32735, 32735, 32736, 32736, 32737, 32737, 32738, 32738, 32739, 32739, 32739, 32740, 32740, 32741, 32741, 32742, 32742, 32742, 32743, 32743, 32744, 32744, 32744, 32745, 32745, 32745, 32746, 32746, 32746, 32747, 32747, 32747, 32748, 32748, 32748, 32749, 32749, 32749, 32749, 32750, 32750, 32750, 32750, 32751, 32751, 32751, 32752, 32752, 32752, 32752, 32752, 32753, 32753, 32753, 32753, 32754, 32754, 32754, 32754, 32754, 32755, 32755, 32755, 32755, 32755, 32756, 32756, 32756, 32756, 32756, 32757, 32757, 32757, 32757, 32757, 32757, 32757, 32758, 32758, 32758, 32758, 32758, 32758, 32759, 32759, 32759, 32759, 32759, 32759, 32759, 32759, 32760, 32760, 32760, 32760, 32760, 32760, 32760, 32760, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32761, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32762, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32763, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32764, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32765, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32766, 32767, 32767, 32767, 32767, 32767, 32767 }; // stdt[i]=count of -i or i in botton or top of stretcht[] static const U8 stdt[712]={ 64, 128, 128, 128, 128, 128, 127, 128, 127, 128, 127, 127, 127, 127, 126, 126, 126, 126, 126, 125, 125, 124, 125, 124, 123, 123, 123, 123, 122, 122, 121, 121, 120, 120, 119, 119, 118, 118, 118, 116, 117, 115, 116, 114, 114, 113, 113, 112, 112, 111, 110, 110, 109, 108, 108, 107, 106, 106, 105, 104, 104, 102, 103, 101, 101, 100, 99, 98, 98, 97, 96, 96, 94, 94, 94, 92, 92, 91, 90, 89, 89, 88, 87, 86, 86, 84, 84, 84, 82, 82, 81, 80, 79, 79, 78, 77, 76, 76, 75, 74, 73, 73, 72, 71, 70, 70, 69, 68, 67, 67, 66, 65, 65, 64, 63, 62, 62, 61, 61, 59, 59, 59, 57, 58, 56, 56, 55, 54, 54, 53, 52, 52, 51, 51, 50, 49, 49, 48, 48, 47, 47, 45, 46, 44, 45, 43, 43, 43, 42, 41, 41, 40, 40, 40, 39, 38, 38, 37, 37, 36, 36, 36, 35, 34, 34, 34, 33, 32, 33, 32, 31, 31, 30, 31, 29, 30, 28, 29, 28, 28, 27, 27, 27, 26, 26, 25, 26, 24, 25, 24, 24, 23, 23, 23, 23, 22, 22, 21, 22, 21, 20, 21, 20, 19, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 14, 13, 13, 13, 12, 13, 12, 12, 12, 11, 12, 11, 11, 11, 11, 11, 10, 11, 10, 10, 10, 10, 9, 10, 9, 9, 9, 9, 9, 8, 9, 8, 9, 8, 8, 8, 7, 8, 8, 7, 7, 8, 7, 7, 7, 6, 7, 7, 6, 6, 7, 6, 6, 6, 6, 6, 6, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 5, 4, 5, 4, 4, 5, 4, 4, 4, 4, 4, 4, 3, 4, 4, 3, 4, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 2, 3, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 }; Predictor::Predictor(ZPAQL& zr): c8(1), hmap4(1), z(zr) { assert(sizeof(U8)==1); assert(sizeof(U16)==2); assert(sizeof(U32)==4); assert(sizeof(U64)==8); assert(sizeof(short)==2); assert(sizeof(int)==4); pcode=0; pcode_size=0; initTables=false; } Predictor::~Predictor() { allocx(pcode, pcode_size, 0); // free executable memory } // Initialize the predictor with a new model in z void Predictor::init() { // Clear old JIT code if any allocx(pcode, pcode_size, 0); // Initialize context hash function z.inith(); // Initialize model independent tables if (!initTables && isModeled()) { initTables=true; memcpy(dt2k, sdt2k, sizeof(dt2k)); memcpy(dt, sdt, sizeof(dt)); // ssquasht[i]=int(32768.0/(1+exp((i-2048)*(-1.0/64)))); // Copy middle 1344 of 4096 entries. memset(squasht, 0, 1376*2); memcpy(squasht+1376, ssquasht, 1344*2); for (int i=2720; i<4096; ++i) squasht[i]=32767; // sstretcht[i]=int(log((i+0.5)/(32767.5-i))*64+0.5+100000)-100000; int k=16384; for (unsigned int i=0; i<712; ++i) for (int j=stdt[i]; j>0; --j) stretcht[k++]=i; assert(k==32768); for (unsigned int i=0; i<16384; ++i) stretcht[i]=-stretcht[32767-i]; #ifndef NDEBUG // Verify floating point math for squash() and stretch() U32 sqsum=0, stsum=0; for (int i=32767; i>=0; --i) stsum=stsum*3+stretch(i); for (int i=4095; i>=0; --i) sqsum=sqsum*3+squash(i-2048); assert(stsum==3887533746u); assert(sqsum==2278286169u); #endif // corresponds to #ifndef (#ifndef NDEBUG) } // Initialize predictions for (unsigned int i=0; i<256; ++i) h[i]=p[i]=0; // Initialize components for (unsigned int i=0; i<256; ++i) // clear old model comp[i].init(); int n=z.header[6]; // hsize[0..1] hh hm ph pm n (comp)[n] END 0[128] (hcomp) END const U8* cp=&z.header[7]; // start of component list for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); Component& cr=comp[i]; switch(cp[0]) { case CONS: // c p[i]=(cp[1]-128)*4; break; case CM: // sizebits limit if (cp[1]>32) error("max size for CM is 32"); cr.cm.resize(1, cp[1]); // packed CM (22 bits) + CMCOUNT (10 bits) cr.limit=cp[2]*4; for (size_t j=0; j26) error("max size for ICM is 26"); cr.limit=1023; cr.cm.resize(256); cr.ht.resize(64, cp[1]); for (size_t j=0; j32 || cp[2]>32) error("max size for MATCH is 32 32"); cr.cm.resize(1, cp[1]); // index cr.ht.resize(1, cp[2]); // buf cr.ht(0)=1; break; case AVG: // j k wt if (cp[1]>=i) error("AVG j >= i"); if (cp[2]>=i) error("AVG k >= i"); break; case MIX2: // sizebits j k rate mask if (cp[1]>32) error("max size for MIX2 is 32"); if (cp[3]>=i) error("MIX2 k >= i"); if (cp[2]>=i) error("MIX2 j >= i"); cr.c=(size_t(1)<32) error("max size for MIX is 32"); if (cp[2]>=i) error("MIX j >= i"); if (cp[3]<1 || cp[3]>i-cp[2]) error("MIX m not in 1..i-j"); int m=cp[3]; // number of inputs assert(m>=1); cr.c=(size_t(1)<32) error("max size for ISSE is 32"); if (cp[2]>=i) error("ISSE j >= i"); cr.ht.resize(64, cp[1]); cr.cm.resize(512); for (int j=0; j<256; ++j) { cr.cm[j*2]=1<<15; cr.cm[j*2+1]=clamp512k(stretch(st.cminit(j)>>8)*1024); } break; case SSE: // sizebits j start limit if (cp[1]>32) error("max size for SSE is 32"); if (cp[2]>=i) error("SSE j >= i"); if (cp[3]>cp[4]*4) error("SSE start > limit*4"); cr.cm.resize(32, cp[1]); cr.limit=cp[4]*4; for (size_t j=0; j0); cp+=compsize[*cp]; assert(cp>=&z.header[7] && cp<&z.header[z.cend]); } } // Return next bit prediction using interpreted COMP code int Predictor::predict0() { assert(initTables); assert(c8>=1 && c8<=255); // Predict next bit int n=z.header[6]; assert(n>0 && n<=255); const U8* cp=&z.header[7]; ///assert(cp[-1]==n); for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); Component& cr=comp[i]; switch(cp[0]) { case CONS: // c break; case CM: // sizebits limit cr.cxt=h[i]^hmap4; p[i]=stretch(cr.cm(cr.cxt)>>17); break; case ICM: // sizebits assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; p[i]=stretch(cr.cm(cr.cxt)>>8); break; case MATCH: // sizebits bufbits: a=len, b=offset, c=bit, cxt=bitpos, // ht=buf, limit=pos assert(cr.cm.size()==(size_t(1)<>(7-cr.cxt))&1; // predicted bit p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767); } break; case AVG: // j k wt p[i]=(p[cp[1]]*cp[3]+p[cp[2]]*(256-cp[3]))>>8; break; case MIX2: { // sizebits j k rate mask // c=size cm=wt[size] cxt=input cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1)); assert(cr.cxt=0 && w<65536); p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16; assert(p[i]>=-2048 && p[i]<2048); } break; case MIX: { // sizebits j m rate mask // c=size cm=wt[size][m] cxt=index of wt in cm int m=cp[3]; assert(m>=1 && m<=i); cr.cxt=h[i]+(c8&cp[5]); cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights assert(cr.cxt<=cr.cm.size()-m); int* wt=(int*)&cr.cm[cr.cxt]; p[i]=0; for (int j=0; j>8)*p[cp[2]+j]; p[i]=clamp2k(p[i]>>8); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; // bit history int *wt=(int*)&cr.cm[cr.cxt*2]; p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16); } break; case SSE: { // sizebits j start limit cr.cxt=(h[i]+c8)*32; int pq=p[cp[2]]+992; if (pq<0) pq=0; if (pq>1983) pq=1983; int wt=pq&63; pq>>=6; assert(pq>=0 && pq<=30); cr.cxt+=pq; p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt)+(cr.cm(cr.cxt+1)>>10)*wt)>>13); cr.cxt+=wt>>5; } break; default: error("component predict not implemented"); } cp+=compsize[cp[0]]; assert(cp<&z.header[z.cend]); assert(p[i]>=-2048 && p[i]<2048); } assert(cp[0]==NONE); return squash(p[n-1]); } // Update model with decoded bit y (0...1) void Predictor::update0(int y) { assert(initTables); assert(y==0 || y==1); assert(c8>=1 && c8<=255); assert(hmap4>=1 && hmap4<=511); // Update components const U8* cp=&z.header[7]; int n=z.header[6]; assert(n>=1 && n<=255); ///assert(cp[-1]==n); for (int i=0; i>8))>>2; } break; case MATCH: // sizebits bufbits: // a=len, b=offset, c=bit, cm=index, cxt=bitpos // ht=buf, limit=pos { assert(cr.a<=255); assert(cr.c==0 || cr.c==1); assert(cr.cxt<8); assert(cr.cm.size()==(size_t(1)<>5; int w=cr.a16[cr.cxt]; w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13; if (w<0) w=0; if (w>65535) w=65535; cr.a16[cr.cxt]=w; } break; case MIX: { // sizebits j m rate mask // cm=wt[size][m], cxt=input int m=cp[3]; assert(m>0 && m<=i); assert(cr.cm.size()==m*cr.c); assert(cr.cxt+m<=cr.cm.size()); int err=(y*32767-squash(p[i]))*cp[4]>>4; int* wt=(int*)&cr.cm[cr.cxt]; for (int j=0; j>13)); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert(cr.cxt==cr.ht[cr.c+(hmap4&15)]); int err=y*32767-squash(p[i]); int *wt=(int*)&cr.cm[cr.cxt*2]; wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13)); wt[1]=clamp512k(wt[1]+((err+16)>>5)); cr.ht[cr.c+(hmap4&15)]=st.next(cr.cxt, y); } break; case SSE: // sizebits j start limit train(cr, y); break; default: assert(0); } cp+=compsize[cp[0]]; assert(cp>=&z.header[7] && cp<&z.header[z.cend] && cp<&z.header[z.header.isize()-8]); } assert(cp[0]==NONE); // Save bit y in c8, hmap4 c8+=c8+y; if (c8>=256) { z.run(c8-256); hmap4=1; c8=1; for (int i=0; i=16 && c8<32) hmap4=(hmap4&0xf)<<5|y<<4|1; else hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf); } // Find cxt row in hash table ht. ht has rows of 16 indexed by the // low sizebits of cxt with element 0 having the next higher 8 bits for // collision detection. If not found after 3 adjacent tries, replace the // row with lowest element 1 as priority. Return index of row. size_t Predictor::find(Array& ht, int sizebits, U32 cxt) { assert(initTables); assert(ht.size()==size_t(16)<>sizebits&255; size_t h0=(cxt*16)&(ht.size()-16); if (ht[h0]==chk) return h0; size_t h1=h0^16; if (ht[h1]==chk) return h1; size_t h2=h0^32; if (ht[h2]==chk) return h2; if (ht[h0+1]<=ht[h1+1] && ht[h0+1]<=ht[h2+1]) return memset(&ht[h0], 0, 16), ht[h0]=chk, h0; else if (ht[h1+1]=0 && p<65536); assert(high>low && low>0); if (currhigh) error("archive corrupted"); assert(curr>=low && curr<=high); U32 mid=low+U32(((high-low)*U64(U32(p)))>>16); // split range assert(high>mid && mid>=low); int y; if (curr<=mid) y=1, high=mid; // pick half else y=0, low=mid+1; while ((high^low)<0x1000000) { // shift out identical leading bytes high=high<<8|255; low=low<<8; low+=(low==0); int c=get(); if (c<0) error("unexpected end of file"); curr=curr<<8|c; } return y; } // Decompress 1 byte or -1 at end of input int Decoder::decompress() { if (pr.isModeled()) { // n>0 components? if (curr==0) { // segment initialization for (int i=0; i<4; ++i) curr=curr<<8|get(); } if (decode(0)) { if (curr!=0) error("decoding end of stream"); return -1; } else { int c=1; while (c<256) { // get 8 bits int p=pr.predict()*2+1; c+=c+decode(p); pr.update(c&1); } return c-256; } } else { if (curr==0) { for (int i=0; i<4; ++i) curr=curr<<8|get(); if (curr==0) return -1; } --curr; return get(); } } // Find end of compressed data and return next byte int Decoder::skip() { int c=-1; if (pr.isModeled()) { while (curr==0) // at start? curr=get(); while (curr && (c=get())>=0) // find 4 zeros curr=curr<<8|c; while ((c=get())==0) ; // might be more than 4 return c; } else { if (curr==0) // at start? for (int i=0; i<4 && (c=get())>=0; ++i) curr=curr<<8|c; while (curr>0) { while (curr>0) { --curr; if (get()<0) return error("skipped to EOF"), -1; } for (int i=0; i<4 && (c=get())>=0; ++i) curr=curr<<8|c; } if (c>=0) c=get(); return c; } } ////////////////////// PostProcessor ////////////////////// // Copy ph, pm from block header void PostProcessor::init(int h, int m) { state=hsize=0; ph=h; pm=m; z.clear(); } // (PASS=0 | PROG=1 psize[0..1] pcomp[0..psize-1]) data... EOB=-1 // Return state: 1=PASS, 2..4=loading PROG, 5=PROG loaded int PostProcessor::write(int c) { assert(c>=-1 && c<=255); switch (state) { case 0: // initial state if (c<0) error("Unexpected EOS"); state=c+1; // 1=PASS, 2=PROG if (state>2) error("unknown post processing type"); if (state==1) z.clear(); break; case 1: // PASS z.outc(c); break; case 2: // PROG if (c<0) error("Unexpected EOS"); hsize=c; // low byte of size state=3; break; case 3: // PROG psize[0] if (c<0) error("Unexpected EOS"); hsize+=c*256; // high byte of psize if (hsize<1) error("Empty PCOMP"); z.header.resize(hsize+300); z.cend=8; z.hbegin=z.hend=z.cend+128; z.header[4]=ph; z.header[5]=pm; state=4; break; case 4: // PROG psize[0..1] pcomp[0...] if (c<0) error("Unexpected EOS"); assert(z.hend>8; z.initp(); state=5; } break; case 5: // PROG ... data z.run(c); if (c<0) z.flush(); break; } return state; } /////////////////////// Decompresser ///////////////////// // Find the start of a block and return true if found. Set memptr // to memory used. bool Decompresser::findBlock(double* memptr) { assert(state==BLOCK); // Find start of block U32 h1=0x3D49B113, h2=0x29EB7F93, h3=0x2614BE13, h4=0x3828EB13; // Rolling hashes initialized to hash of first 13 bytes int c; while ((c=dec.get())!=-1) { h1=h1*12+c; h2=h2*20+c; h3=h3*28+c; h4=h4*44+c; if (h1==0xB16B88F1 && h2==0xFF5376F1 && h3==0x72AC5BF1 && h4==0x2F909AF1) break; // hash of 16 byte string } if (c==-1) return false; // Read header if ((c=dec.get())!=1 && c!=2) error("unsupported ZPAQ level"); if (dec.get()!=1) error("unsupported ZPAQL type"); z.read(&dec); if (c==1 && z.header.isize()>6 && z.header[6]==0) error("ZPAQ level 1 requires at least 1 component"); if (memptr) *memptr=z.memory(); state=FILENAME; decode_state=FIRSTSEG; return true; } // Read the start of a segment (1) or end of block code (255). // If a segment is found, write the filename and return true, else false. bool Decompresser::findFilename(Writer* filename) { assert(state==FILENAME); int c=dec.get(); if (c==1) { // segment found while (true) { c=dec.get(); if (c==-1) error("unexpected EOF"); if (c==0) { state=COMMENT; return true; } if (filename) filename->put(c); } } else if (c==255) { // end of block found state=BLOCK; return false; } else error("missing segment or end of block"); return false; } // Read the comment from the segment header void Decompresser::readComment(Writer* comment) { assert(state==COMMENT); state=DATA; while (true) { int c=dec.get(); if (c==-1) error("unexpected EOF"); if (c==0) break; if (comment) comment->put(c); } if (dec.get()!=0) error("missing reserved byte"); } // Decompress n bytes, or all if n < 0. Return false if done bool Decompresser::decompress(int n) { assert(state==DATA); if (decode_state==SKIP) error("decompression after skipped segment"); assert(decode_state!=SKIP); // Initialize models to start decompressing block if (decode_state==FIRSTSEG) { dec.init(); assert(z.header.size()>5); pp.init(z.header[4], z.header[5]); decode_state=SEG; } // Decompress and load PCOMP into postprocessor while ((pp.getState()&3)!=1) pp.write(dec.decompress()); // Decompress n bytes, or all if n < 0 while (n) { int c=dec.decompress(); pp.write(c); if (c==-1) { state=SEGEND; return false; } if (n>0) --n; } return true; } // Read end of block. If a SHA1 checksum is present, write 1 and the // 20 byte checksum into sha1string, else write 0 in first byte. // If sha1string is 0 then discard it. void Decompresser::readSegmentEnd(char* sha1string) { assert(state==DATA || state==SEGEND); // Skip remaining data if any and get next byte int c=0; if (state==DATA) { c=dec.skip(); decode_state=SKIP; } else if (state==SEGEND) c=dec.get(); state=FILENAME; // Read checksum if (c==254) { if (sha1string) sha1string[0]=0; // no checksum } else if (c==253) { if (sha1string) sha1string[0]=1; for (int i=1; i<=20; ++i) { c=dec.get(); if (sha1string) sha1string[i]=c; } } else error("missing end of segment marker"); } /////////////////////////// decompress() ////////////////////// void decompress(Reader* in, Writer* out) { Decompresser d; d.setInput(in); d.setOutput(out); while (d.findBlock()) { // don't calculate memory while (d.findFilename()) { // discard filename d.readComment(); // discard comment d.decompress(); // to end of segment d.readSegmentEnd(); // discard sha1string } } } /////////////////////////// Encoder /////////////////////////// // Initialize for start of block void Encoder::init() { low=1; high=0xFFFFFFFF; pr.init(); if (!pr.isModeled()) low=0, buf.resize(1<<16); } // compress bit y having probability p/64K void Encoder::encode(int y, int p) { assert(out); assert(p>=0 && p<65536); assert(y==0 || y==1); assert(high>low && low>0); U32 mid=low+U32(((high-low)*U64(U32(p)))>>16); // split range assert(high>mid && mid>=low); if (y) high=mid; else low=mid+1; // pick half while ((high^low)<0x1000000) { // write identical leading bytes out->put(high>>24); // same as low>>24 high=high<<8|255; low=low<<8; low+=(low==0); // so we don't code 4 0 bytes in a row } } // compress byte c (0..255 or -1=EOS) void Encoder::compress(int c) { assert(out); if (pr.isModeled()) { if (c==-1) encode(1, 0); else { assert(c>=0 && c<=255); encode(0, 0); for (int i=7; i>=0; --i) { int p=pr.predict()*2+1; assert(p>0 && p<65536); int y=c>>i&1; encode(y, p); pr.update(y); } } } else { if (low && (c<0 || low==buf.size())) { out->put((low>>24)&255); out->put((low>>16)&255); out->put((low>>8)&255); out->put(low&255); out->write(&buf[0], low); low=0; } if (c>=0) buf[low++]=c; } } //////////////////////////// Compiler ///////////////////////// // Component names const char* compname[256]= {"","const","cm","icm","match","avg","mix2","mix","isse","sse",0}; // Opcodes const char* opcodelist[272]={ "error","a++", "a--", "a!", "a=0", "", "", "a=r", "b<>a", "b++", "b--", "b!", "b=0", "", "", "b=r", "c<>a", "c++", "c--", "c!", "c=0", "", "", "c=r", "d<>a", "d++", "d--", "d!", "d=0", "", "", "d=r", "*b<>a","*b++", "*b--", "*b!", "*b=0", "", "", "jt", "*c<>a","*c++", "*c--", "*c!", "*c=0", "", "", "jf", "*d<>a","*d++", "*d--", "*d!", "*d=0", "", "", "r=a", "halt", "out", "", "hash", "hashd","", "", "jmp", "a=a", "a=b", "a=c", "a=d", "a=*b", "a=*c", "a=*d", "a=", "b=a", "b=b", "b=c", "b=d", "b=*b", "b=*c", "b=*d", "b=", "c=a", "c=b", "c=c", "c=d", "c=*b", "c=*c", "c=*d", "c=", "d=a", "d=b", "d=c", "d=d", "d=*b", "d=*c", "d=*d", "d=", "*b=a", "*b=b", "*b=c", "*b=d", "*b=*b","*b=*c","*b=*d","*b=", "*c=a", "*c=b", "*c=c", "*c=d", "*c=*b","*c=*c","*c=*d","*c=", "*d=a", "*d=b", "*d=c", "*d=d", "*d=*b","*d=*c","*d=*d","*d=", "", "", "", "", "", "", "", "", "a+=a", "a+=b", "a+=c", "a+=d", "a+=*b","a+=*c","a+=*d","a+=", "a-=a", "a-=b", "a-=c", "a-=d", "a-=*b","a-=*c","a-=*d","a-=", "a*=a", "a*=b", "a*=c", "a*=d", "a*=*b","a*=*c","a*=*d","a*=", "a/=a", "a/=b", "a/=c", "a/=d", "a/=*b","a/=*c","a/=*d","a/=", "a%=a", "a%=b", "a%=c", "a%=d", "a%=*b","a%=*c","a%=*d","a%=", "a&=a", "a&=b", "a&=c", "a&=d", "a&=*b","a&=*c","a&=*d","a&=", "a&~a", "a&~b", "a&~c", "a&~d", "a&~*b","a&~*c","a&~*d","a&~", "a|=a", "a|=b", "a|=c", "a|=d", "a|=*b","a|=*c","a|=*d","a|=", "a^=a", "a^=b", "a^=c", "a^=d", "a^=*b","a^=*c","a^=*d","a^=", "a<<=a","a<<=b","a<<=c","a<<=d","a<<=*b","a<<=*c","a<<=*d","a<<=", "a>>=a","a>>=b","a>>=c","a>>=d","a>>=*b","a>>=*c","a>>=*d","a>>=", "a==a", "a==b", "a==c", "a==d", "a==*b","a==*c","a==*d","a==", "aa", "a>b", "a>c", "a>d", "a>*b", "a>*c", "a>*d", "a>", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "lj", "post", "pcomp","end", "if", "ifnot","else", "endif","do", "while","until","forever","ifl","ifnotl","elsel",";", 0}; // Advance in to start of next token. Tokens are delimited by white // space. Comments inclosed in ((nested) parenthsis) are skipped. void Compiler::next() { assert(in); for (; *in; ++in) { if (*in=='\n') ++line; if (*in=='(') state+=1+(state<0); else if (state>0 && *in==')') --state; else if (state<0 && *in<=' ') state=0; else if (state==0 && *in>' ') {state=-1; break;} } if (!*in) error("unexpected end of config"); } // convert to lower case int tolower(int c) {return (c>='A' && c<='Z') ? c+'a'-'A' : c;} // return true if in==word up to white space or '(', case insensitive bool Compiler::matchToken(const char* word) { const char* a=in; for (; (*a>' ' && *a!='(' && *word); ++a, ++word) if (tolower(*a)!=tolower(*word)) return false; return !*word && (*a<=' ' || *a=='('); } // Print error message and exit void Compiler::syntaxError(const char* msg, const char* expected) { Array sbuf(128); // error message to report char* s=&sbuf[0]; strcat(s, "Config line "); for (int i=strlen(s), r=1000000; r; r/=10) // append line number if (line/r) s[i++]='0'+line/r%10; strcat(s, " at "); for (int i=strlen(s); i<40 && *in>' '; ++i) // append token found s[i]=*in++; strcat(s, ": "); strncat(s, msg, 40); // append message if (expected) { strcat(s, ", expected: "); strncat(s, expected, 20); // append expected token if any } error(s); } // Read a token, which must be in the NULL terminated list or else // exit with an error. If found, return its index. int Compiler::rtoken(const char* list[]) { assert(in); assert(list); next(); for (int i=0; list[i]; ++i) if (matchToken(list[i])) return i; syntaxError("unexpected"); assert(0); return -1; // not reached } // Read a token which must be the specified value s void Compiler::rtoken(const char* s) { assert(s); next(); if (!matchToken(s)) syntaxError("expected", s); } // Read a number in (low...high) or exit with an error // For numbers like $N+M, return arg[N-1]+M int Compiler::rtoken(int low, int high) { next(); int r=0; if (in[0]=='$' && in[1]>='1' && in[1]<='9') { if (in[2]=='+') r=atoi(in+3); if (args) r+=args[in[1]-'1']; } else if (in[0]=='-' || (in[0]>='0' && in[0]<='9')) r=atoi(in); else syntaxError("expected a number"); if (rhigh) syntaxError("number too high"); return r; } // Compile HCOMP or PCOMP code. Exit on error. Return // code for end token (POST, PCOMP, END) int Compiler::compile_comp(ZPAQL& z) { int op=0; const int comp_begin=z.hend; while (true) { op=rtoken(opcodelist); if (op==POST || op==PCOMP || op==END) break; int operand=-1; // 0...255 if 2 bytes int operand2=-1; // 0...255 if 3 bytes if (op==IF) { op=JF; operand=0; // set later if_stack.push(z.hend+1); // save jump target location } else if (op==IFNOT) { op=JT; operand=0; if_stack.push(z.hend+1); // save jump target location } else if (op==IFL || op==IFNOTL) { // long if if (op==IFL) z.header[z.hend++]=(JT); if (op==IFNOTL) z.header[z.hend++]=(JF); z.header[z.hend++]=(3); op=LJ; operand=operand2=0; if_stack.push(z.hend+1); } else if (op==ELSE || op==ELSEL) { if (op==ELSE) op=JMP, operand=0; if (op==ELSEL) op=LJ, operand=operand2=0; int a=if_stack.pop(); // conditional jump target location assert(a>comp_begin && a=0); if (j>127) syntaxError("IF too big, try IFL, IFNOTL"); z.header[a]=j; } else { // IFL, IFNOTL int j=z.hend-comp_begin+2+(op==LJ); assert(j>=0); z.header[a]=j&255; z.header[a+1]=(j>>8)&255; } if_stack.push(z.hend+1); // save JMP target location } else if (op==ENDIF) { int a=if_stack.pop(); // jump target address assert(a>comp_begin && a=0); if (z.header[a-1]!=LJ) { assert(z.header[a-1]==JT || z.header[a-1]==JF || z.header[a-1]==JMP); if (j>127) syntaxError("IF too big, try IFL, IFNOTL, ELSEL\n"); z.header[a]=j; } else { assert(a+1>8)&255; } } else if (op==DO) { do_stack.push(z.hend); } else if (op==WHILE || op==UNTIL || op==FOREVER) { int a=do_stack.pop(); assert(a>=comp_begin && a=-127) { // backward short jump if (op==WHILE) op=JT; if (op==UNTIL) op=JF; if (op==FOREVER) op=JMP; operand=j&255; } else { // backward long jump j=a-comp_begin; assert(j>=0 && j>8; } } else if ((op&7)==7) { // 2 byte operand, read N if (op==LJ) { operand=rtoken(0, 65535); operand2=operand>>8; operand&=255; } else if (op==JT || op==JF || op==JMP) { operand=rtoken(-128, 127); operand&=255; } else operand=rtoken(0, 255); } if (op>=0 && op<=255) z.header[z.hend++]=(op); if (operand>=0) z.header[z.hend++]=(operand); if (operand2>=0) z.header[z.hend++]=(operand2); if (z.hend>=z.header.isize()-130 || z.hend-z.hbegin+z.cend-2>65535) syntaxError("program too big"); } z.header[z.hend++]=(0); // END return op; } // Compile a configuration file. Store COMP/HCOMP section in hcomp. // If there is a PCOMP section, store it in pcomp and store the PCOMP // command in pcomp_cmd. Replace "$1..$9+n" with args[0..8]+n Compiler::Compiler(const char* in_, int* args_, ZPAQL& hz_, ZPAQL& pz_, Writer* out2_): in(in_), args(args_), hz(hz_), pz(pz_), out2(out2_), if_stack(1000), do_stack(1000) { line=1; state=0; hz.clear(); pz.clear(); hz.header.resize(68000); // Compile the COMP section of header rtoken("comp"); hz.header[2]=rtoken(0, 255); // hh hz.header[3]=rtoken(0, 255); // hm hz.header[4]=rtoken(0, 255); // ph hz.header[5]=rtoken(0, 255); // pm const int n=hz.header[6]=rtoken(0, 255); // n hz.cend=7; for (int i=0; i10) syntaxError("invalid component"); for (int j=1; j>8; // Compile POST 0 END if (op==POST) { rtoken(0, 0); rtoken("end"); } // Compile PCOMP pcomp_cmd ; program... END else if (op==PCOMP) { pz.header.resize(68000); pz.header[4]=hz.header[4]; // ph pz.header[5]=hz.header[5]; // pm pz.cend=8; pz.hbegin=pz.hend=pz.cend+128; // get pcomp_cmd ending with ";" (case sensitive) next(); while (*in && *in!=';') { if (out2) out2->put(*in); ++in; } if (*in) ++in; // Compile PCOMP op=compile_comp(pz); int len=(pz.cend-2)+pz.hend-pz.hbegin; // insert header size assert(len>=0); pz.header[0]=len&255; pz.header[1]=len>>8; if (op!=END) syntaxError("expected END"); } else if (op!=END) syntaxError("expected END or POST 0 END or PCOMP cmd ; ... END"); } ///////////////////// Compressor ////////////////////// // Write 13 byte start tag // "\x37\x6B\x53\x74\xA0\x31\x83\xD3\x8C\xB2\x28\xB0\xD3" void Compressor::writeTag() { assert(state==INIT); enc.out->put(0x37); enc.out->put(0x6b); enc.out->put(0x53); enc.out->put(0x74); enc.out->put(0xa0); enc.out->put(0x31); enc.out->put(0x83); enc.out->put(0xd3); enc.out->put(0x8c); enc.out->put(0xb2); enc.out->put(0x28); enc.out->put(0xb0); enc.out->put(0xd3); } void Compressor::startBlock(int level) { // Model 1 - min.cfg static const char models[]={ 26,0,1,2,0,0,2,3,16,8,19,0,0,96,4,28, 59,10,59,112,25,10,59,10,59,112,56,0, // Model 2 - mid.cfg 69,0,3,3,0,0,8,3,5,8,13,0,8,17,1,8, 18,2,8,18,3,8,19,4,4,22,24,7,16,0,7,24, (char)-1,0,17,104,74,4,95,1,59,112,10,25,59,112,10,25, 59,112,10,25,59,112,10,25,59,112,10,25,59,10,59,112, 25,69,(char)-49,8,112,56,0, // Model 3 - max.cfg (char)-60,0,5,9,0,0,22,1,(char)-96,3,5,8,13,1,8,16, 2,8,18,3,8,19,4,8,19,5,8,20,6,4,22,24, 3,17,8,19,9,3,13,3,13,3,13,3,14,7,16,0, 15,24,(char)-1,7,8,0,16,10,(char)-1,6,0,15,16,24,0,9, 8,17,32,(char)-1,6,8,17,18,16,(char)-1,9,16,19,32,(char)-1,6, 0,19,20,16,0,0,17,104,74,4,95,2,59,112,10,25, 59,112,10,25,59,112,10,25,59,112,10,25,59,112,10,25, 59,10,59,112,10,25,59,112,10,25,69,(char)-73,32,(char)-17,64,47, 14,(char)-25,91,47,10,25,60,26,48,(char)-122,(char)-105,20,112,63,9,70, (char)-33,0,39,3,25,112,26,52,25,25,74,10,4,59,112,25, 10,4,59,112,25,10,4,59,112,25,65,(char)-113,(char)-44,72,4,59, 112,8,(char)-113,(char)-40,8,68,(char)-81,60,60,25,69,(char)-49,9,112,25,25, 25,25,25,112,56,0, 0,0}; // 0,0 = end of list if (level<1) error("compression level must be at least 1"); const char* p=models; int i; for (i=1; i6); enc.out->put('z'); enc.out->put('P'); enc.out->put('Q'); enc.out->put(1+(z.header[6]==0)); // level 1 or 2 enc.out->put(1); z.write(enc.out, false); state=BLOCK1; } void Compressor::startBlock(const char* config, int* args, Writer* pcomp_cmd) { assert(state==INIT); Compiler(config, args, z, pz, pcomp_cmd); pz.sha1=&sha1; assert(z.header.isize()>6); enc.out->put('z'); enc.out->put('P'); enc.out->put('Q'); enc.out->put(1+(z.header[6]==0)); // level 1 or 2 enc.out->put(1); z.write(enc.out, false); state=BLOCK1; } // Write a segment header void Compressor::startSegment(const char* filename, const char* comment) { assert(state==BLOCK1 || state==BLOCK2); enc.out->put(1); while (filename && *filename) enc.out->put(*filename++); enc.out->put(0); while (comment && *comment) enc.out->put(*comment++); enc.out->put(0); enc.out->put(0); if (state==BLOCK1) state=SEG1; if (state==BLOCK2) state=SEG2; } // Initialize encoding and write pcomp to first segment // If len is 0 then length is encoded in pcomp[0..1] // if pcomp is 0 then get pcomp from pz.header void Compressor::postProcess(const char* pcomp, int len) { if (state==SEG2) return; assert(state==SEG1); enc.init(); if (!pcomp) { len=pz.hend-pz.hbegin; if (len>0) { assert(pz.header.isize()>pz.hend); assert(pz.hbegin>=0); pcomp=(const char*)&pz.header[pz.hbegin]; } assert(len>=0); } else if (len==0) { len=toU16(pcomp); pcomp+=2; } if (len>0) { enc.compress(1); enc.compress(len&255); enc.compress((len>>8)&255); for (int i=0; i=0 && nread(buf, nbuf); if (nr<0 || nr>BUFSIZE || nr>nbuf) error("invalid read size"); if (nr<=0) return false; if (n>=0) n-=nr; for (int i=0; iput(0); enc.out->put(0); enc.out->put(0); enc.out->put(0); if (sha1string) { enc.out->put(253); for (int i=0; i<20; ++i) enc.out->put(sha1string[i]); } else enc.out->put(254); state=BLOCK2; } #ifdef DEBUG // End segment, write checksum and size is verify is true char* Compressor::endSegmentChecksum(int64_t* size, bool dosha1) { if (state==SEG1) postProcess(); assert(state==SEG2); enc.compress(-1); if (verify && pz.hend) { pz.run(-1); pz.flush(); } enc.out->put(0); enc.out->put(0); enc.out->put(0); enc.out->put(0); if (verify) { if (size) *size=sha1.usize(); memcpy(sha1result, sha1.result(), 20); } if (verify && dosha1) { enc.out->put(253); for (int i=0; i<20; ++i) enc.out->put(sha1result[i]); } else enc.out->put(254); state=BLOCK2; return verify ? sha1result : 0; } #endif // corresponds to #ifdef (#ifdef DEBUG) // End block void Compressor::endBlock() { assert(state==BLOCK2); enc.out->put(255); state=INIT; } //////////////////////// ZPAQL::assemble() //////////////////// /* assemble(); Assembles the ZPAQL code in hcomp[0..hlen-1] and stores x86-32 or x86-64 code in rcode[0..rcode_size-1]. Execution begins at rcode[0]. It will not write beyond the end of rcode, but in any case it returns the number of bytes that would have been written. It returns 0 in case of error. The assembled code implements int run() and returns 0 if successful, 1 if the ZPAQL code executes an invalid instruction or jumps out of bounds, or 2 if OUT throws bad_alloc, or 3 for other OUT exceptions. A ZPAQL virtual machine has the following state. All values are unsigned and initially 0: a, b, c, d: 32 bit registers (pointed to by their respective parameters) f: 1 bit flag register (pointed to) r[0..255]: 32 bit registers m[0..msize-1]: 8 bit registers, where msize is a power of 2 h[0..hsize-1]: 32 bit registers, where hsize is a power of 2 out: pointer to a Writer sha1: pointer to a SHA1 Generally a ZPAQL machine is used to compute contexts which are placed in h. A second machine might post-process, and write its output to out and sha1. In either case, a machine is called with its input in a, representing a single byte (0..255) or (for a postprocessor) EOF (0xffffffff). Execution returs after a ZPAQL halt instruction. ZPAQL instructions are 1 byte unless the last 3 bits are 1. In this case, a second operand byte follows. Opcode 255 is the only 3 byte instruction. They are organized: 00dddxxx = unary opcode xxx on destination ddd (ddd < 111) 00111xxx = special instruction xxx 01dddsss = assignment: ddd = sss (ddd < 111) 1xxxxsss = operation xxxx from sss to a The meaning of sss and ddd are as follows: 000 = a (accumulator) 001 = b 010 = c 011 = d 100 = *b (means m[b mod msize]) 101 = *c (means m[c mod msize]) 110 = *d (means h[d mod hsize]) 111 = n (constant 0..255 in second byte of instruction) For example, 01001110 assigns *d to b. The other instructions xxx are as follows: Group 00dddxxx where ddd < 111 and xxx is: 000 = ddd<>a, swap with a (except 00000000 is an error, and swap with *b or *c leaves the high bits of a unchanged) 001 = ddd++, increment 010 = ddd--, decrement 011 = ddd!, not (invert all bits) 100 = ddd=0, clear (set all bits of ddd to 0) 101 = not used (error) 110 = not used 111 = ddd=r n, assign from r[n] to ddd, n=0..255 in next opcode byte Except: 00100111 = jt n, jump if f is true (n = -128..127, relative to next opcode) 00101111 = jf n, jump if f is false (n = -128..127) 00110111 = r=a n, assign r[n] = a (n = 0..255) Group 00111xxx where xxx is: 000 = halt (return) 001 = output a 010 = not used 011 = hash: a = (a + *b + 512) * 773 100 = hashd: *d = (*d + a + 512) * 773 101 = not used 110 = not used 111 = unconditional jump (n = -128 to 127, relative to next opcode) Group 1xxxxsss where xxxx is: 0000 = a += sss (add, subtract, multiply, divide sss to a) 0001 = a -= sss 0010 = a *= sss 0011 = a /= sss (unsigned, except set a = 0 if sss is 0) 0100 = a %= sss (remainder, except set a = 0 if sss is 0) 0101 = a &= sss (bitwise AND) 0110 = a &= ~sss (bitwise AND with complement of sss) 0111 = a |= sss (bitwise OR) 1000 = a ^= sss (bitwise XOR) 1001 = a <<= (sss % 32) (left shift by low 5 bits of sss) 1010 = a >>= (sss % 32) (unsigned, zero bits shifted in) 1011 = a == sss (compare, set f = true if equal or false otherwise) 1100 = a < sss (unsigned compare, result in f) 1101 = a > sss (unsigned compare) 1110 = not used 1111 = not used except 11111111 is a 3 byte jump to the absolute address in the next 2 bytes in little-endian (LSB first) order. assemble() translates ZPAQL to 32 bit x86 code to be executed by run(). Registers are mapped as follows: eax = source sss from *b, *c, *d or sometimes n ecx = pointer to destination *b, *c, *d, or spare edx = a ebx = f (1 for true, 0 for false) esp = stack pointer ebp = d esi = b edi = c run() saves non-volatile registers (ebp, esi, edi, ebx) on the stack, loads a, b, c, d, f, and executes the translated instructions. A halt instruction saves a, b, c, d, f, pops the saved registers and returns. Invalid instructions or jumps outside of the range of the ZPAQL code call libzpaq::error(). In 64 bit mode, the following additional registers are used: r12 = h r14 = r r15 = m */ // Called by out static int flush1(ZPAQL* z) { try { z->flush(); return 0; } catch(std::bad_alloc& x) { return 2; } catch(...) { return 3; } } // return true if op is an undefined ZPAQL instruction static bool iserr(int op) { return op==0 || (op>=120 && op<=127) || (op>=240 && op<=254) || op==58 || (op<64 && (op%8==5 || op%8==6)); } // Return length of ZPAQL instruction at hcomp[0]. Assume 0 padding at end. // A run of identical ++ or -- is counted as 1 instruction. static int oplen(const U8* hcomp) { if (*hcomp==255) return 3; if (*hcomp%8==7) return 2; if (*hcomp<51 && (*hcomp%8-1)/2==0) { // ++ or -- opcode int i; for (i=1; i<127 && hcomp[i]==hcomp[0]; ++i); return i; } return 1; } // Write k bytes of x to rcode[o++] MSB first static void put(U8* rcode, int n, int& o, U32 x, int k) { while (k-->0) { if (o>(k*8))&255; ++o; } } // Write 4 bytes of x to rcode[o++] LSB first static void put4lsb(U8* rcode, int n, int& o, U32 x) { for (int k=0; k<4; ++k) { if (o>(k*8))&255; ++o; } } // Write a 1-4 byte x86 opcode without or with an 4 byte operand // to rcode[o...] #define put1(x) put(rcode, rcode_size, o, (x), 1) #define put2(x) put(rcode, rcode_size, o, (x), 2) #define put3(x) put(rcode, rcode_size, o, (x), 3) #define put4(x) put(rcode, rcode_size, o, (x), 4) #define put5(x,y) put4(x), put1(y) #define put6(x,y) put4(x), put2(y) #define put4r(x) put4lsb(rcode, rcode_size, o, x) #define puta(x) t=U32(size_t(x)), put4r(t) #define put1a(x,y) put1(x), puta(y) #define put2a(x,y) put2(x), puta(y) #define put3a(x,y) put3(x), puta(y) #define put4a(x,y) put4(x), puta(y) ///#define put5a(x,y,z) put4(x), put1(y), puta(z) #define put2l(x,y) put2(x), t=U32(size_t(y)), put4r(t), \ t=U32(size_t(y)>>(S*4)), put4r(t) // Assemble ZPAQL in in the HCOMP section of header to rcode, // but do not write beyond rcode_size. Return the number of // bytes output or that would have been output. // Execution starts at rcode[0] and returns 1 if successful or 0 // in case of a ZPAQL execution error. int ZPAQL::assemble() { // x86? (not foolproof) const int S=sizeof(char*); // 4 = x86, 8 = x86-64 U32 t=0x12345678; if (*(char*)&t!=0x78 || (S!=4 && S!=8)) error("JIT supported only for x86-32 and x86-64"); const U8* hcomp=&header[hbegin]; const int hlen=(hend-hbegin)+2; const int msize=m.size(); const int hsize=h.size(); static const int regcode[8]={2,6,7,5}; // a,b,c,d.. -> edx,esi,edi,ebp,eax.. Array it(hlen); // hcomp -> rcode locations int done=0; // number of instructions assembled (0..hlen) int o=5; // rcode output index, reserve space for jmp // Code for the halt instruction (restore registers and return) const int halt=o; if (S==8) { put2l(0x48b9, &a); // mov rcx, a put2(0x8911); // mov [rcx], edx put2l(0x48b9, &b); // mov rcx, b put2(0x8931); // mov [rcx], esi put2l(0x48b9, &c); // mov rcx, c put2(0x8939); // mov [rcx], edi put2l(0x48b9, &d); // mov rcx, d put2(0x8929); // mov [rcx], ebp put2l(0x48b9, &f); // mov rcx, f put2(0x8919); // mov [rcx], ebx put4(0x4883c408); // add rsp, 8 put2(0x415f); // pop r15 put2(0x415e); // pop r14 put2(0x415d); // pop r13 put2(0x415c); // pop r12 } else { put2a(0x8915, &a); // mov [a], edx put2a(0x8935, &b); // mov [b], esi put2a(0x893d, &c); // mov [c], edi put2a(0x892d, &d); // mov [d], ebp put2a(0x891d, &f); // mov [f], ebx put3(0x83c40c); // add esp, 12 } put1(0x5b); // pop ebx put1(0x5f); // pop edi put1(0x5e); // pop esi put1(0x5d); // pop ebp put1(0xc3); // ret // Code for the out instruction. // Store a=edx at outbuf[bufptr++]. If full, call flush1(). const int outlabel=o; if (S==8) { put2l(0x48b8, &outbuf[0]);// mov rax, outbuf.p put2l(0x49ba, &bufptr); // mov r10, &bufptr put3(0x418b0a); // mov rcx, [r10] put3(0x881408); // mov [rax+rcx], dl put2(0xffc1); // inc rcx put3(0x41890a); // mov [r10], ecx put2a(0x81f9, outbuf.size()); // cmp rcx, outbuf.size() put2(0x7403); // jz L1 put2(0x31c0); // xor eax, eax put1(0xc3); // ret put1(0x55); // L1: push rbp ; call flush1(this) put1(0x57); // push rdi put1(0x56); // push rsi put1(0x52); // push rdx put1(0x51); // push rcx put3(0x4889e5); // mov rbp, rsp put4(0x4883c570); // add rbp, 112 #if defined(unix) && !defined(__CYGWIN__) put2l(0x48bf, this); // mov rdi, this #else // Windows put2l(0x48b9, this); // mov rcx, this #endif // corresponds to #if (#if defined(unix) && !defined(__CYGWIN__)) put2l(0x49bb, &flush1); // mov r11, &flush1 put3(0x41ffd3); // call r11 put1(0x59); // pop rcx put1(0x5a); // pop rdx put1(0x5e); // pop rsi put1(0x5f); // pop rdi put1(0x5d); // pop rbp } else { put1a(0xb8, &outbuf[0]); // mov eax, outbuf.p put2a(0x8b0d, &bufptr); // mov ecx, [bufptr] put3(0x881408); // mov [eax+ecx], dl put2(0xffc1); // inc ecx put2a(0x890d, &bufptr); // mov [bufptr], ecx put2a(0x81f9, outbuf.size()); // cmp ecx, outbuf.size() put2(0x7403); // jz L1 put2(0x31c0); // xor eax, eax put1(0xc3); // ret put3(0x83ec0c); // L1: sub esp, 12 put4(0x89542404); // mov [esp+4], edx put3a(0xc70424, this); // mov [esp], this put1a(0xb8, &flush1); // mov eax, &flush1 put2(0xffd0); // call eax put4(0x8b542404); // mov edx, [esp+4] put3(0x83c40c); // add esp, 12 } put1(0xc3); // ret // Set it[i]=1 for each ZPAQL instruction reachable from the previous // instruction + 2 if reachable by a jump (or 3 if both). it[0]=2; assert(hlen>0 && hcomp[hlen-1]==0); // ends with error do { done=0; const int NONE=0x80000000; for (int i=0; i>24);// jt,jf,jmp if (op==63) next1=NONE; // jmp if ((next2<0 || next2>=hlen) && next2!=NONE) next2=hlen-1; // error if (next1>=0 && next1=0 && next20); // Set it[i] bits 2-3 to 4, 8, or 12 if a comparison // (==, <, > respectively) does not need to save the result in f, // or if a conditional jump (jt, jf) does not need to read f. // This is true if a comparison is followed directly by a jt/jf, // the jt/jf is not a jump target, the byte before is not a jump // target (for a 2 byte comparison), and for the comparison instruction // if both paths after the jt/jf lead to another comparison or error // before another jt/jf. At most hlen steps are traced because after // that it must be an infinite loop. for (int i=0; i=216 && op1<240 && (op2==39 || op2==47) && it[i2]==1 && (i2==i+1 || it[i+1]==0)) { int code=(op1-208)/8*4; // 4,8,12 is ==,<,> it[i2]+=code; // OK to test CF, ZF instead of f for (int j=0; j<2 && code; ++j) { // trace each path from i2 int k=i2+2; // branch not taken if (j==1) k=i2+2+(hcomp[i2+1]<<24>>24); // branch taken for (int l=0; l=hlen) break; // out of bounds, pass const int op=hcomp[k]; if (op==39 || op==47) code=0; // jt,jf, fail else if (op>=216 && op<240) break; // ==,<,>, pass else if (iserr(op)) break; // error, pass else if (op==255) k=hcomp[k+1]+256*hcomp[k+2]; // lj else if (op==63) k=k+2+(hcomp[k+1]<<24>>24); // jmp else if (op==56) k=0; // halt else k=k+1+(op%8==7); // ordinary instruction } } it[i]+=code; // if > 0 then OK to not save flags in f (bl) } } // Start of run(): Save x86 and load ZPAQL registers const int start=o; assert(start>=16); put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi put1(0x53); // push ebx/rbx if (S==8) { put2(0x4154); // push r12 put2(0x4155); // push r13 put2(0x4156); // push r14 put2(0x4157); // push r15 put4(0x4883ec08); // sub rsp, 8 put2l(0x48b8, &a); // mov rax, a put2(0x8b10); // mov edx, [rax] put2l(0x48b8, &b); // mov rax, b put2(0x8b30); // mov esi, [rax] put2l(0x48b8, &c); // mov rax, c put2(0x8b38); // mov edi, [rax] put2l(0x48b8, &d); // mov rax, d put2(0x8b28); // mov ebp, [rax] put2l(0x48b8, &f); // mov rax, f put2(0x8b18); // mov ebx, [rax] put2l(0x49bc, &h[0]); // mov r12, h put2l(0x49bd, &outbuf[0]); // mov r13, outbuf.p put2l(0x49be, &r[0]); // mov r14, r put2l(0x49bf, &m[0]); // mov r15, m } else { put3(0x83ec0c); // sub esp, 12 put2a(0x8b15, &a); // mov edx, [a] put2a(0x8b35, &b); // mov esi, [b] put2a(0x8b3d, &c); // mov edi, [c] put2a(0x8b2d, &d); // mov ebp, [d] put2a(0x8b1d, &f); // mov ebx, [f] } // Assemble in multiple passes until every byte of hcomp has a translation for (int istart=0; istarti); assert(i>=0 && i=16) { if (i>istart) { int a=code-o; if (a>-120 && a<120) put2(0xeb00+((a-2)&255)); // jmp short o else put1a(0xe9, a-5); // jmp near o } break; } // Else assemble the instruction at hcomp[i] to rcode[o] else { assert(i>=0 && i0 && it[i]<16); assert(o>=16); it[i]=o; ++done; const int op=hcomp[i]; const int arg=hcomp[i+1]+((op==255)?256*hcomp[i+2]:0); const int ddd=op/8%8; const int sss=op%8; // error instruction: return 1 if (iserr(op)) { put1a(0xb8, 1); // mov eax, 1 put1a(0xe9, halt-o-4); // jmp near halt continue; } // Load source *b, *c, *d, or hash (*b) into eax except: // {a,b,c,d}=*d, a{+,-,*,&,|,^,=,==,>,>}=*d: load address to eax // {a,b,c,d}={*b,*c}: load source into ddd if (op==59 || (op>=64 && op<240 && op%8>=4 && op%8<7)) { put2(0x89c0+8*regcode[sss-3+(op==59)]); // mov eax, {esi,edi,ebp} const int sz=(sss==6?hsize:msize)-1; if (sz>=128) put1a(0x25, sz); // and eax, dword msize-1 else put3(0x83e000+sz); // and eax, byte msize-1 const int move=(op>=64 && op<112); // = or else ddd is eax if (sss<6) { // ddd={a,b,c,d,*b,*c} if (S==8) put5(0x410fb604+8*move*regcode[ddd],0x07); // movzx ddd, byte [r15+rax] else put3a(0x0fb680+8*move*regcode[ddd], &m[0]); // movzx ddd, byte [m+eax] } else if ((0x06587000>>(op/8))&1) {// {*b,*c,*d,a/,a%,a&~,a<<,a>>}=*d if (S==8) put4(0x418b0484); // mov eax, [r12+rax*4] else put3a(0x8b0485, &h[0]); // mov eax, [h+eax*4] } } // Load destination address *b, *c, *d or hashd (*d) into ecx if ((op>=32 && op<56 && op%8<5) || (op>=96 && op<120) || op==60) { put2(0x89c1+8*regcode[op/8%8-3-(op==60)]);// mov ecx,{esi,edi,ebp} const int sz=(ddd==6||op==60?hsize:msize)-1; if (sz>=128) put2a(0x81e1, sz); // and ecx, dword sz else put3(0x83e100+sz); // and ecx, byte sz if (op/8%8==6 || op==60) { // *d if (S==8) put4(0x498d0c8c); // lea rcx, [r12+rcx*4] else put3a(0x8d0c8d, &h[0]); // lea ecx, [ecx*4+h] } else { // *b, *c if (S==8) put4(0x498d0c0f); // lea rcx, [r15+rcx] else put2a(0x8d89, &m[0]); // lea ecx, [ecx+h] } } // Translate by opcode switch((op/8)&31) { case 0: // ddd = a case 1: // ddd = b case 2: // ddd = c case 3: // ddd = d switch(sss) { case 0: // ddd<>a (swap) put2(0x87d0+regcode[ddd]); // xchg edx, ddd break; case 1: // ddd++ put3(0x83c000+256*regcode[ddd]+inc); // add ddd, inc break; case 2: // ddd-- put3(0x83e800+256*regcode[ddd]+inc); // sub ddd, inc break; case 3: // ddd! put2(0xf7d0+regcode[ddd]); // not ddd break; case 4: // ddd=0 put2(0x31c0+9*regcode[ddd]); // xor ddd,ddd break; case 7: // ddd=r n if (S==8) put3a(0x418b86+8*regcode[ddd], arg*4); // mov ddd, [r14+n*4] else put2a(0x8b05+8*regcode[ddd], (&r[arg]));//mov ddd, [r+n] break; } break; case 4: // ddd = *b case 5: // ddd = *c switch(sss) { case 0: // ddd<>a (swap) put2(0x8611); // xchg dl, [ecx] break; case 1: // ddd++ put3(0x800100+inc); // add byte [ecx], inc break; case 2: // ddd-- put3(0x802900+inc); // sub byte [ecx], inc break; case 3: // ddd! put2(0xf611); // not byte [ecx] break; case 4: // ddd=0 put2(0x31c0); // xor eax, eax put2(0x8801); // mov [ecx], al break; case 7: // jt, jf { assert(code>=0 && code<16); static const unsigned char jtab[2][4]={{5,4,2,7},{4,5,3,6}}; // jnz,je,jb,ja, jz,jne,jae,jbe if (code<4) put2(0x84db); // test bl, bl if (arg>=128 && arg-257-i>=0 && o-it[arg-257-i]<120) put2(0x7000+256*jtab[op==47][code/4]); // jx short 0 else put2a(0x0f80+jtab[op==47][code/4], 0); // jx near 0 break; } } break; case 6: // ddd = *d switch(sss) { case 0: // ddd<>a (swap) put2(0x8711); // xchg edx, [ecx] break; case 1: // ddd++ put3(0x830100+inc); // add dword [ecx], inc break; case 2: // ddd-- put3(0x832900+inc); // sub dword [ecx], inc break; case 3: // ddd! put2(0xf711); // not dword [ecx] break; case 4: // ddd=0 put2(0x31c0); // xor eax, eax put2(0x8901); // mov [ecx], eax break; case 7: // ddd=r n if (S==8) put3a(0x418996, arg*4); // mov [r14+n*4], edx else put2a(0x8915, &r[arg]); // mov [r+n], edx break; } break; case 7: // special switch(op) { case 56: // halt put2(0x31c0); // xor eax, eax ; return 0 put1a(0xe9, halt-o-4); // jmp near halt break; case 57: // out put1a(0xe8, outlabel-o-4);// call outlabel put3(0x83f800); // cmp eax, 0 ; returned error code put2(0x7405); // je L1: put1a(0xe9, halt-o-4); // jmp near halt ; L1: break; case 59: // hash: a = (a + *b + 512) * 773 put3a(0x8d8410, 512); // lea edx, [eax+edx+512] put2a(0x69d0, 773); // imul edx, eax, 773 break; case 60: // hashd: *d = (*d + a + 512) * 773 put2(0x8b01); // mov eax, [ecx] put3a(0x8d8410, 512); // lea eax, [eax+edx+512] put2a(0x69c0, 773); // imul eax, eax, 773 put2(0x8901); // mov [ecx], eax break; case 63: // jmp put1a(0xe9, 0); // jmp near 0 (fill in target later) break; } break; case 8: // a= case 9: // b= case 10: // c= case 11: // d= if (sss==7) // n put1a(0xb8+regcode[ddd], arg); // mov ddd, n else if (sss==6) { // *d if (S==8) put4(0x418b0484+(regcode[ddd]<<11)); // mov ddd, [r12+rax*4] else put3a(0x8b0485+(regcode[ddd]<<11),&h[0]);// mov ddd, [h+eax*4] } else if (sss<4) // a, b, c, d put2(0x89c0+regcode[ddd]+8*regcode[sss]);// mov ddd,sss break; case 12: // *b= case 13: // *c= if (sss==7) put3(0xc60100+arg); // mov byte [ecx], n else if (sss==0) put2(0x8811); // mov byte [ecx], dl else { if (sss<4) put2(0x89c0+8*regcode[sss]);// mov eax, sss put2(0x8801); // mov byte [ecx], al } break; case 14: // *d= if (sss<7) put2(0x8901+8*regcode[sss]); // mov [ecx], sss else put2a(0xc701, arg); // mov dword [ecx], n break; case 15: break; // not used case 16: // a+= if (sss==6) { if (S==8) put4(0x41031484); // add edx, [r12+rax*4] else put3a(0x031485, &h[0]); // add edx, [h+eax*4] } else if (sss<7) put2(0x01c2+8*regcode[sss]);// add edx, sss else if (arg>=128) put2a(0x81c2, arg); // add edx, n else put3(0x83c200+arg); // add edx, byte n break; case 17: // a-= if (sss==6) { if (S==8) put4(0x412b1484); // sub edx, [r12+rax*4] else put3a(0x2b1485, &h[0]); // sub edx, [h+eax*4] } else if (sss<7) put2(0x29c2+8*regcode[sss]);// sub edx, sss else if (arg>=128) put2a(0x81ea, arg); // sub edx, n else put3(0x83ea00+arg); // sub edx, byte n break; case 18: // a*= if (sss==6) { if (S==8) put5(0x410faf14,0x84); // imul edx, [r12+rax*4] else put4a(0x0faf1485, &h[0]); // imul edx, [h+eax*4] } else if (sss<7) put3(0x0fafd0+regcode[sss]);// imul edx, sss else if (arg>=128) put2a(0x69d2, arg); // imul edx, n else put3(0x6bd200+arg); // imul edx, byte n break; case 19: // a/= case 20: // a%= if (sss<7) put2(0x89c1+8*regcode[sss]); // mov ecx, sss else put1a(0xb9, arg); // mov ecx, n put2(0x85c9); // test ecx, ecx put3(0x0f44d1); // cmovz edx, ecx put2(0x7408-2*(op/8==20)); // jz (over rest) put2(0x89d0); // mov eax, edx put2(0x31d2); // xor edx, edx put2(0xf7f1); // div ecx if (op/8==19) put2(0x89c2); // mov edx, eax break; case 21: // a&= if (sss==6) { if (S==8) put4(0x41231484); // and edx, [r12+rax*4] else put3a(0x231485, &h[0]); // and edx, [h+eax*4] } else if (sss<7) put2(0x21c2+8*regcode[sss]);// and edx, sss else if (arg>=128) put2a(0x81e2, arg); // and edx, n else put3(0x83e200+arg); // and edx, byte n break; case 22: // a&~ if (sss==7) { if (arg<128) put3(0x83e200+(~arg&255));// and edx, byte ~n else put2a(0x81e2, ~arg); // and edx, ~n } else { if (sss<4) put2(0x89c0+8*regcode[sss]);// mov eax, sss put2(0xf7d0); // not eax put2(0x21c2); // and edx, eax } break; case 23: // a|= if (sss==6) { if (S==8) put4(0x410b1484); // or edx, [r12+rax*4] else put3a(0x0b1485, &h[0]); // or edx, [h+eax*4] } else if (sss<7) put2(0x09c2+8*regcode[sss]);// or edx, sss else if (arg>=128) put2a(0x81ca, arg); // or edx, n else put3(0x83ca00+arg); // or edx, byte n break; case 24: // a^= if (sss==6) { if (S==8) put4(0x41331484); // xor edx, [r12+rax*4] else put3a(0x331485, &h[0]); // xor edx, [h+eax*4] } else if (sss<7) put2(0x31c2+8*regcode[sss]);// xor edx, sss else if (arg>=128) put2a(0x81f2, arg); // xor edx, byte n else put3(0x83f200+arg); // xor edx, n break; case 25: // a<<= case 26: // a>>= if (sss==7) // sss = n put3(0xc1e200+8*256*(op/8==26)+arg); // shl/shr n else { put2(0x89c1+8*regcode[sss]); // mov ecx, sss put2(0xd3e2+8*(op/8==26)); // shl/shr edx, cl } break; case 27: // a== case 28: // a< case 29: // a> if (sss==6) { if (S==8) put4(0x413b1484); // cmp edx, [r12+rax*4] else put3a(0x3b1485, &h[0]); // cmp edx, [h+eax*4] } else if (sss==7) // sss = n put2a(0x81fa, arg); // cmp edx, dword n else put2(0x39c2+8*regcode[sss]); // cmp edx, sss if (code<4) { if (op/8==27) put3(0x0f94c3); // setz bl if (op/8==28) put3(0x0f92c3); // setc bl if (op/8==29) put3(0x0f97c3); // seta bl } break; case 30: // not used case 31: // 255 = lj if (op==255) put1a(0xe9, 0); // jmp near break; } } } } // Finish first pass const int rsize=o; if (o>rcode_size) return rsize; // Fill in jump addresses (second pass) for (int i=0; i=128) target-=256; target+=i+2; } if (target<0 || target>=hlen) target=hlen-1; // runtime ZPAQL error o=it[i]; assert(o>=16 && o skip test assert(o>=16 && o=0x72 && op<0x78) || op==0xeb) { // jx, jmp short --target; if (target<-128 || target>127) error("Cannot code x86 short jump"); assert(o=0x82 && op<0x88) || op==0xe9) // jx, jmp near { target-=4; puta(target); } else assert(false); // not a x86 jump } } // Jump to start o=0; put1a(0xe9, start-5); // jmp near start return rsize; } //////////////////////// Predictor::assemble_p() ///////////////////// // Assemble the ZPAQL code in the HCOMP section of z.header to pcomp and // return the number of bytes of x86 or x86-64 code written, or that would // be written if pcomp were large enough. The code for predict() begins // at pr.pcomp[0] and update() at pr.pcomp[5], both as jmp instructions. // The assembled code is equivalent to int predict(Predictor*) // and void update(Predictor*, int y); The Preditor address is placed in // edi/rdi. The update bit y is placed in ebp/rbp. int Predictor::assemble_p() { Predictor& pr=*this; U8* rcode=pr.pcode; // x86 output array int rcode_size=pcode_size; // output size int o=0; // output index in pcode const int S=sizeof(char*); // 4 or 8 U8* hcomp=&pr.z.header[0]; // The code to translate #define off(x) ((char*)&(pr.x)-(char*)&pr) #define offc(x) ((char*)&(pr.comp[i].x)-(char*)&pr) // test for little-endian (probably x86) U32 t=0x12345678; if (*(char*)&t!=0x78 || (S!=4 && S!=8)) error("JIT supported only for x86-32 and x86-64"); // Initialize for predict(). Put predictor address in edi/rdi put1a(0xe9, 5); // jmp predict put1a(0, 0x90909000); // reserve space for jmp update put1(0x53); // push ebx/rbx put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi if (S==4) put4(0x8b7c2414); // mov edi,[esp+0x14] ; pr else { #if !defined(unix) || defined(__CYGWIN__) put3(0x4889cf); // mov rdi, rcx (1st arg in Win64) #endif // corresponds to #if (#if !defined(unix) || defined(__CYGWIN__)) } // Code predict() for each component const int n=hcomp[6]; // number of components U8* cp=hcomp+7; for (int i=0; i=pr.z.cend) error("comp too big"); if (cp[0]<1 || cp[0]>9) error("invalid component"); assert(compsize[cp[0]]>0 && compsize[cp[0]]<8); switch (cp[0]) { case CONS: // c break; case CM: // sizebits limit // Component& cr=comp[i]; // cr.cxt=h[i]^hmap4; // p[i]=stretch(cr.cm(cr.cxt)>>17); put2a(0x8b87, off(h[i])); // mov eax, [edi+&h[i]] put2a(0x3387, off(hmap4)); // xor eax, [edi+&hmap4] put1a(0x25, (1<rsi) put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] put3(0x8b0486); // mov eax, [esi+eax*4] put3(0xc1e811); // shr eax, 17 put4a(0x0fbf8447, off(stretcht)); // movsx eax,word[edi+eax*2+..] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; case ISSE: // sizebits j -- c=hi, cxt=bh // assert((hmap4&15)>0); // if (c8==1 || (c8&0xf0)==16) // cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); // cr.cxt=cr.ht[cr.c+(hmap4&15)]; // bit history // int *wt=(int*)&cr.cm[cr.cxt*2]; // p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16); case ICM: // sizebits // assert((hmap4&15)>0); // if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); // cr.cxt=cr.ht[cr.c+(hmap4&15)]; // p[i]=stretch(cr.cm(cr.cxt)>>8); // // Find cxt row in hash table ht. ht has rows of 16 indexed by the low // sizebits of cxt with element 0 having the next higher 8 bits for // collision detection. If not found after 3 adjacent tries, replace // row with lowest element 1 as priority. Return index of row. // // size_t Predictor::find(Array& ht, int sizebits, U32 cxt) { // assert(ht.size()==size_t(16)<>sizebits&255; // size_t h0=(cxt*16)&(ht.size()-16); // if (ht[h0]==chk) return h0; // size_t h1=h0^16; // if (ht[h1]==chk) return h1; // size_t h2=h0^32; // if (ht[h2]==chk) return h2; // if (ht[h0+1]<=ht[h1+1] && ht[h0+1]<=ht[h2+1]) // return memset(&ht[h0], 0, 16), ht[h0]=chk, h0; // else if (ht[h1+1]>(7-cr.cxt))&1; // predicted bit // p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767); // } if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(ht)); // mov esi, [edi+&ht] // If match length (a) is 0 then p[i]=0 put2a(0x8b87, offc(a)); // mov eax, [edi+&a] put2(0x85c0); // test eax, eax put2(0x7449); // jz L2 ; p[i]=0 // Else put predicted bit in c put1a(0xb9, 7); // mov ecx, 7 put2a(0x2b8f, offc(cxt)); // sub ecx, [edi+&cxt] put2a(0x8b87, offc(limit)); // mov eax, [edi+&limit] put2a(0x2b87, offc(b)); // sub eax, [edi+&b] put1a(0x25, (1<>8; put2a(0x8b87, off(p[cp[1]])); // mov eax, [edi+&p[j]] put2a(0x2b87, off(p[cp[2]])); // sub eax, [edi+&p[k]] put2a(0x69c0, cp[3]); // imul eax, wt put3(0xc1f808); // sar eax, 8 put2a(0x0387, off(p[cp[2]])); // add eax, [edi+&p[k]] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; case MIX2: // sizebits j k rate mask // c=size cm=wt[size] cxt=input // cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1)); // assert(cr.cxt=0 && w<65536); // p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16; // assert(p[i]>=-2048 && p[i]<2048); put2(0x8b07); // mov eax, [edi] ; c8 put1a(0x25, cp[5]); // and eax, mask put2a(0x0387, off(h[i])); // add eax, [edi+&h[i]] put1a(0x25, (1<=1 && m<=i); // cr.cxt=h[i]+(c8&cp[5]); // cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights // assert(cr.cxt<=cr.cm.size()-m); // int* wt=(int*)&cr.cm[cr.cxt]; // p[i]=0; // for (int j=0; j>8)*p[cp[2]+j]; // p[i]=clamp2k(p[i]>>8); put2(0x8b07); // mov eax, [edi] ; c8 put1a(0x25, cp[5]); // and eax, mask put2a(0x0387, off(h[i])); // add eax, [edi+&h[i]] put1a(0x25, (1<3) put4a(0xf30f6f96, k*4+16);//movdqu xmm2, [esi+k*4+16] put5(0x660f72e1,0x08); // psrad xmm1, 8 if (tail>3) put5(0x660f72e2,0x08); // psrad xmm2, 8 put4(0x660f6bca); // packssdw xmm1, xmm2 put4a(0xf30f6f9f, off(p[cp[2]+k])); // movdqu xmm3, [edi+&p[j+k]] if (tail>3) put4a(0xf30f6fa7,off(p[cp[2]+k+4]));//movdqu xmm4, [edi+&p[j+k+4]] put4(0x660f6bdc); // packssdw, xmm3, xmm4 if (tail>0 && tail<8) { // last loop, mask extra weights put4(0x660f76ed); // pcmpeqd xmm5, xmm5 ; -1 put5(0x660f73dd, 16-tail*2); // psrldq xmm5, 16-tail*2 put4(0x660fdbcd); // pand xmm1, xmm5 } if (k==0) { // first loop, initialize sum in xmm0 put4(0xf30f6fc1); // movdqu xmm0, xmm1 put4(0x660ff5c3); // pmaddwd xmm0, xmm3 } else { // accumulate sum in xmm0 put4(0x660ff5cb); // pmaddwd xmm1, xmm3 put4(0x660ffec1); // paddd xmm0, xmm1 } } // Add up the 4 elements of xmm0 = p[i] in the first element put4(0xf30f6fc8); // movdqu xmm1, xmm0 put5(0x660f73d9,0x08); // psrldq xmm1, 8 put4(0x660ffec1); // paddd xmm0, xmm1 put4(0xf30f6fc8); // movdqu xmm1, xmm0 put5(0x660f73d9,0x04); // psrldq xmm1, 4 put4(0x660ffec1); // paddd xmm0, xmm1 put4(0x660f7ec0); // movd eax, xmm0 ; p[i] put3(0xc1f808); // sar eax, 8 put1a(0x3d, 2047); // cmp eax, 2047 put2(0x7e05); // jle L1 put1a(0xb8, 2047); // mov eax, 2047 put1a(0x3d, -2048); // L1: cmp eax, -2048 put2(0x7d05); // jge, L2 put1a(0xb8, -2048); // mov eax, -2048 put2a(0x8987, off(p[i])); // L2: mov [edi+&p[i]], eax break; case SSE: // sizebits j start limit // cr.cxt=(h[i]+c8)*32; // int pq=p[cp[2]]+992; // if (pq<0) pq=0; // if (pq>1983) pq=1983; // int wt=pq&63; // pq>>=6; // assert(pq>=0 && pq<=30); // cr.cxt+=pq; // p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt) // p0 // +(cr.cm(cr.cxt+1)>>10)*wt)>>13); // p1 // // p = p0*(64-wt)+p1*wt = (p1-p0)*wt + p0*64 // cr.cxt+=wt>>5; put2a(0x8b8f, off(h[i])); // mov ecx, [edi+&h[i]] put2(0x030f); // add ecx, [edi] ; c0 put2a(0x81e1, (1<>5 put2a(0x898f, offc(cxt)); // mov [edi+cxt], ecx ; cxt saved put3(0xc1e80a); // shr eax, 10 ; p0 = cm[cxt]>>10 put3(0xc1eb0a); // shr ebx, 10 ; p1 = cm[cxt+1]>>10 put2(0x29c3); // sub ebx, eax, ; p1-p0 put3(0x0fafda); // imul ebx, edx ; (p1-p0)*wt put3(0xc1e006); // shr eax, 6 put2(0x01d8); // add eax, ebx ; p in 0..2^28-1 put3(0xc1e80d); // shr eax, 13 ; p in 0..32767 put4a(0x0fbf8447, off(stretcht)); // movsx eax, word [edi+eax*2+...] put2a(0x8987, off(p[i])); // mov [edi+&p[i]], eax break; default: error("invalid ZPAQ component"); } } // return squash(p[n-1]) put2a(0x8b87, off(p[n-1])); // mov eax, [edi+...] put1a(0x05, 0x800); // add eax, 2048 put4a(0x0fbf8447, off(squasht[0])); // movsx eax, word [edi+eax*2+...] put1(0x5f); // pop edi put1(0x5e); // pop esi put1(0x5d); // pop ebp put1(0x5b); // pop ebx put1(0xc3); // ret // Initialize for update() Put predictor address in edi/rdi // and bit y=0..1 in ebp int save_o=o; o=5; put1a(0xe9, save_o-10); // jmp update o=save_o; put1(0x53); // push ebx/rbx put1(0x55); // push ebp/rbp put1(0x56); // push esi/rsi put1(0x57); // push edi/rdi if (S==4) { put4(0x8b7c2414); // mov edi,[esp+0x14] ; (1st arg = pr) put4(0x8b6c2418); // mov ebp,[esp+0x18] ; (2nd arg = y) } else { #if defined(unix) && !defined(__CYGWIN__) // (1st arg already in rdi) put3(0x4889f5); // mov rbp, rsi (2nd arg in Linux-64) #else put3(0x4889cf); // mov rdi, rcx (1st arg in Win64) put3(0x4889d5); // mov rbp, rdx (2nd arg) #endif // corresponds to #if (#if defined(unix) && !defined(__CYGWIN__) // (1st arg already in rdi)) } // Code update() for each component cp=hcomp+7; for (int i=0; i=1 && cp[0]<=9); assert(compsize[cp[0]]>0 && compsize[cp[0]]<8); switch (cp[0]) { case CONS: // c break; case SSE: // sizebits j start limit case CM: // sizebits limit // train(cr, y); // // reduce prediction error in cr.cm // void train(Component& cr, int y) { // assert(y==0 || y==1); // U32& pn=cr.cm(cr.cxt); // U32 count=pn&0x3ff; // int error=y*32767-(cr.cm(cr.cxt)>>17); // pn+=(error*dt[count]&-1024)+(countrsi) put2a(0x8bb7, offc(cm)); // mov esi,[edi+cm] ; cm put2a(0x8b87, offc(cxt)); // mov eax,[edi+cxt] ; cxt put1a(0x25, pr.comp[i].cm.size()-1); // and eax, size-1 if (S==8) put1(0x48); // rex.w put3(0x8d3486); // lea esi,[esi+eax*4] ; &cm[cxt] put2(0x8b06); // mov eax,[esi] ; cm[cxt] put2(0x89c2); // mov edx, eax ; cm[cxt] put3(0xc1e811); // shr eax, 17 ; cm[cxt]>>17 put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 ; y*32768 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax ; error put2a(0x81e2, 0x3ff); // and edx, 1023 ; count put3a(0x8b8497, off(dt)); // mov eax,[edi+edx*4+dt] ; dt[count] put3(0x0fafc8); // imul ecx, eax ; error*dt[count] put2a(0x81e1, 0xfffffc00); // and ecx, -1024 put2a(0x81fa, cp[2+2*(cp[0]==SSE)]*4); // cmp edx, limit*4 put2(0x110e); // adc [esi], ecx ; pn+=... break; case ICM: // sizebits: cxt=bh, ht[c][0..15]=bh row // cr.ht[cr.c+(hmap4&15)]=st.next(cr.ht[cr.c+(hmap4&15)], y); // U32& pn=cr.cm(cr.cxt); // pn+=int(y*32767-(pn>>8))>>2; case ISSE: // sizebits j -- c=hi, cxt=bh // assert(cr.cxt==cr.ht[cr.c+(hmap4&15)]); // int err=y*32767-squash(p[i]); // int *wt=(int*)&cr.cm[cr.cxt*2]; // wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13)); // wt[1]=clamp512k(wt[1]+((err+16)>>5)); // cr.ht[cr.c+(hmap4&15)]=st.next(cr.cxt, y); // update bit history bh to next(bh,y=ebp) in ht[c+(hmap4&15)] put3(0x8b4700+off(hmap4)); // mov eax, [edi+&hmap4] put3(0x83e00f); // and eax, 15 put2a(0x0387, offc(c)); // add eax [edi+&c] ; cxt if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(ht)); // mov esi, [edi+&ht] put4(0x0fb61406); // movzx edx, byte [esi+eax] ; bh put4(0x8d5c9500); // lea ebx, [ebp+edx*4] ; index to st put4a(0x0fb69c1f, off(st)); // movzx ebx,byte[edi+ebx+st]; next bh put3(0x881c06); // mov [esi+eax], bl ; save next bh if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] // ICM: update cm[cxt=edx=bit history] to reduce prediction error // esi = &cm if (cp[0]==ICM) { if (S==8) put1(0x48); // rex.w put3(0x8d3496); // lea esi, [esi+edx*4] ; &cm[bh] put2(0x8b06); // mov eax, [esi] ; pn put3(0xc1e808); // shr eax, 8 ; pn>>8 put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put3(0xc1f902); // sar ecx, 2 put2(0x010e); // add [esi], ecx } // ISSE: update weights. edx=cxt=bit history (0..255), esi=cm[512] else { put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht)); // movzx eax, word [edi+eax*2+..] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax ; err put2a(0x8b87, off(p[cp[2]]));// mov eax, [edi+&p[j]] put3(0x0fafc1); // imul eax, ecx put1a(0x05, (1<<12)); // add eax, 4096 put3(0xc1f80d); // sar eax, 13 put3(0x0304d6); // add eax, [esi+edx*8] ; wt[0] put1a(0x3d, (1<<19)-1); // cmp eax, (1<<19)-1 put2(0x7e05); // jle L1 put1a(0xb8, (1<<19)-1); // mov eax, (1<<19)-1 put1a(0x3d, 0xfff80000); // cmp eax, -1<<19 put2(0x7d05); // jge L2 put1a(0xb8, 0xfff80000); // mov eax, -1<<19 put3(0x8904d6); // L2: mov [esi+edx*8], eax put3(0x83c110); // add ecx, 16 ; err put3(0xc1f905); // sar ecx, 5 put4(0x034cd604); // add ecx, [esi+edx*8+4] ; wt[1] put2a(0x81f9, (1<<19)-1); // cmp ecx, (1<<19)-1 put2(0x7e05); // jle L3 put1a(0xb9, (1<<19)-1); // mov ecx, (1<<19)-1 put2a(0x81f9, 0xfff80000); // cmp ecx, -1<<19 put2(0x7d05); // jge L4 put1a(0xb9, 0xfff80000); // mov ecx, -1<<19 put4(0x894cd604); // L4: mov [esi+edx*8+4], ecx } break; case MATCH: // sizebits bufbits: // a=len, b=offset, c=bit, cm=index, cxt=bitpos // ht=buf, limit=pos // assert(cr.a<=255); // assert(cr.c==0 || cr.c==1); // assert(cr.cxt<8); // assert(cr.cm.size()==(size_t(1)<>5; // int w=cr.a16[cr.cxt]; // w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13; // if (w<0) w=0; // if (w>65535) w=65535; // cr.a16[cr.cxt]=w; // set ecx=err put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht));//movzx eax, word [edi+eax*2+&squasht] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put2a(0x69c9, cp[4]); // imul ecx, rate put3(0xc1f905); // sar ecx, 5 ; err // Update w put2a(0x8b87, offc(cxt)); // mov eax, [edi+&cxt] if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(a16)); // mov esi, [edi+&a16] if (S==8) put1(0x48); // rex.w put3(0x8d3446); // lea esi, [esi+eax*2] ; &w put2a(0x8b87, off(p[cp[2]])); // mov eax, [edi+&p[j]] put2a(0x2b87, off(p[cp[3]])); // sub eax, [edi+&p[k]] ; p[j]-p[k] put3(0x0fafc1); // imul eax, ecx ; * err put1a(0x05, 1<<12); // add eax, 4096 put3(0xc1f80d); // sar eax, 13 put3(0x0fb716); // movzx edx, word [esi] ; w put2(0x01d0); // add eax, edx put1a(0xba, 0xffff); // mov edx, 65535 put2(0x39d0); // cmp eax, edx put3(0x0f4fc2); // cmovg eax, edx put2(0x31d2); // xor edx, edx put2(0x39d0); // cmp eax, edx put3(0x0f4cc2); // cmovl eax, edx put3(0x668906); // mov word [esi], ax break; case MIX: // sizebits j m rate mask // cm=wt[size][m], cxt=input // int m=cp[3]; // assert(m>0 && m<=i); // assert(cr.cm.size()==m*cr.c); // assert(cr.cxt+m<=cr.cm.size()); // int err=(y*32767-squash(p[i]))*cp[4]>>4; // int* wt=(int*)&cr.cm[cr.cxt]; // for (int j=0; j>13)); // set ecx=err put2a(0x8b87, off(p[i])); // mov eax, [edi+&p[i]] put1a(0x05, 2048); // add eax, 2048 put4a(0x0fb78447, off(squasht));//movzx eax, word [edi+eax*2+&squasht] put2(0x89e9); // mov ecx, ebp ; y put3(0xc1e10f); // shl ecx, 15 put2(0x29e9); // sub ecx, ebp ; y*32767 put2(0x29c1); // sub ecx, eax put2a(0x69c9, cp[4]); // imul ecx, rate put3(0xc1f904); // sar ecx, 4 ; err // set esi=wt put2a(0x8b87, offc(cxt)); // mov eax, [edi+&cxt] ; cxt if (S==8) put1(0x48); // rex.w put2a(0x8bb7, offc(cm)); // mov esi, [edi+&cm] if (S==8) put1(0x48); // rex.w put3(0x8d3486); // lea esi, [esi+eax*4] ; wt for (int k=0; kpcode_size) { allocx(pcode, pcode_size, n); n=assemble_p(); } if (!pcode || n<15 || pcode_size<15) error("run JIT failed"); } ///assert(pcode && pcode[0]); if (!(pcode && pcode[0])) error("14367: pcode/pcode[0] kaputt\n"); if (!pcode || !pcode[10]) error("Invalid function pointer at pcode[10]"); return ((int(*)(Predictor*))&pcode[10])(this); } // Update the model with bit y = 0..1 // Use the JIT code starting at pcode[5]. void Predictor::update(int y) { if (flagnojit) { update0(y); return; } assert(pcode && pcode[5]); ((void(*)(Predictor*, int))&pcode[5])(this, y); // Save bit y in c8, hmap4 (not implemented in JIT) c8+=c8+y; if (c8>=256) { z.run(c8-256); hmap4=1; c8=1; for (int i=0; i=16 && c8<32) hmap4=(hmap4&0xf)<<5|y<<4|1; else hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf); } // Execute the ZPAQL code with input byte or -1 for EOF. // Use JIT code at rcode if available, or else create it. void ZPAQL::run(U32 input) { if (flagnojit) { run0(input); return; } if (!rcode) { allocx(rcode, rcode_size, (hend*10+4096)&-4096); int n=assemble(); if (n>rcode_size) { allocx(rcode, rcode_size, n); n=assemble(); } if (!rcode || n<10 || rcode_size<10) error("run JIT failed"); } a=input; if (rcode && rcode[0]) { const U32 rc = ((int(*)())(&rcode[0]))(); if (rc == 0) return; else if (rc == 1) libzpaq::error("Bad ZPAQL opcode"); else if (rc == 2) libzpaq::error("Out of memory"); else if (rc == 3) libzpaq::error("Write error"); else libzpaq::error("ZPAQL execution error"); } else { libzpaq::error("14427 Invalid function pointer in rcode[0]"); } /* const U32 rc=((int(*)())(&rcode[0]))(); if (rc==0) return; else if (rc==1) libzpaq::error("Bad ZPAQL opcode"); else if (rc==2) libzpaq::error("Out of memory"); else if (rc==3) libzpaq::error("Write error"); else libzpaq::error("ZPAQL execution error"); */ } /// LICENSE_START.6 ////////////////////////// divsufsort /////////////////////////////// /* * divsufsort.c for libdivsufsort-lite * Copyright (c) 2003-2008 Yuta Mori All Rights Reserved. Just a bit stripped */ #define INLINE_divsuf __inline #if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1) # undef ALPHABET_SIZE #endif // corresponds to #if (#if defined(ALPHABET_SIZE) && (ALPHABET_SIZE < 1)) #if !defined(ALPHABET_SIZE) # define ALPHABET_SIZE (256) #endif // corresponds to #if (#if !defined(ALPHABET_SIZE)) #define BUCKET_A_SIZE (ALPHABET_SIZE) #define BUCKET_B_SIZE (ALPHABET_SIZE * ALPHABET_SIZE) #if defined(SS_INSERTIONSORT_THRESHOLD) # if SS_INSERTIONSORT_THRESHOLD < 1 # undef SS_INSERTIONSORT_THRESHOLD # define SS_INSERTIONSORT_THRESHOLD (1) # endif #else # define SS_INSERTIONSORT_THRESHOLD (8) #endif // corresponds to #if (#if defined(SS_INSERTIONSORT_THRESHOLD)) #if defined(SS_BLOCKSIZE) # if SS_BLOCKSIZE < 0 # undef SS_BLOCKSIZE # define SS_BLOCKSIZE (0) # elif 32768 <= SS_BLOCKSIZE # undef SS_BLOCKSIZE # define SS_BLOCKSIZE (32767) # endif #else # define SS_BLOCKSIZE (1024) #endif // corresponds to #if (#if defined(SS_BLOCKSIZE)) #if SS_BLOCKSIZE == 0 # define SS_MISORT_STACKSIZE (96) #elif SS_BLOCKSIZE <= 4096 # define SS_MISORT_STACKSIZE (16) #else # define SS_MISORT_STACKSIZE (24) #endif // corresponds to #if (#if SS_BLOCKSIZE == 0) #define SS_SMERGE_STACKSIZE (32) #define TR_INSERTIONSORT_THRESHOLD (8) #define TR_STACKSIZE (64) #ifndef SWAP # define SWAP(_a, _b) do { t = (_a); (_a) = (_b); (_b) = t; } while(0) #endif // corresponds to #ifndef (#ifndef SWAP) #ifndef MIN # define MIN(_a, _b) (((_a) < (_b)) ? (_a) : (_b)) #endif // corresponds to #ifndef (#ifndef MIN) #ifndef MAX # define MAX(_a, _b) (((_a) > (_b)) ? (_a) : (_b)) #endif // corresponds to #ifndef (#ifndef MAX) #define STACK_PUSH(_a, _b, _c, _d)\ do {\ assert(ssize < STACK_SIZE);\ stack[ssize].a = (_a), stack[ssize].b = (_b),\ stack[ssize].c = (_c), stack[ssize++].d = (_d);\ } while(0) #define STACK_PUSH5(_a, _b, _c, _d, _e)\ do {\ assert(ssize < STACK_SIZE);\ stack[ssize].a = (_a), stack[ssize].b = (_b),\ stack[ssize].c = (_c), stack[ssize].d = (_d), stack[ssize++].e = (_e);\ } while(0) #define STACK_POP(_a, _b, _c, _d)\ do {\ assert(0 <= ssize);\ if(ssize == 0) { return; }\ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ (_c) = stack[ssize].c, (_d) = stack[ssize].d;\ } while(0) #define STACK_POP5(_a, _b, _c, _d, _e)\ do {\ assert(0 <= ssize);\ if(ssize == 0) { return; }\ (_a) = stack[--ssize].a, (_b) = stack[ssize].b,\ (_c) = stack[ssize].c, (_d) = stack[ssize].d, (_e) = stack[ssize].e;\ } while(0) #define BUCKET_A(_c0) bucket_A[(_c0)] #if ALPHABET_SIZE == 256 #define BUCKET_B(_c0, _c1) (bucket_B[((_c1) << 8) | (_c0)]) #define BUCKET_BSTAR(_c0, _c1) (bucket_B[((_c0) << 8) | (_c1)]) #else #define BUCKET_B(_c0, _c1) (bucket_B[(_c1) * ALPHABET_SIZE + (_c0)]) #define BUCKET_BSTAR(_c0, _c1) (bucket_B[(_c0) * ALPHABET_SIZE + (_c1)]) #endif // corresponds to #if (#if ALPHABET_SIZE == 256) static const int lg_table[256]= { -1,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 }; #if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) static INLINE_divsuf int ss_ilg(int n) { #if SS_BLOCKSIZE == 0 return (n & 0xffff0000) ? ((n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]); #elif SS_BLOCKSIZE < 256 return lg_table[n]; #else return (n & 0xff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]; #endif // corresponds to #if (#if SS_BLOCKSIZE == 0) } #endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ // corresponds to #if (#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)) #if SS_BLOCKSIZE != 0 static const int sqq_table[256] = { 0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57, 59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83, 84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102, 103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178, 179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197, 198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255 }; static INLINE_divsuf int ss_isqrt(int x) { int y, e; if(x >= (SS_BLOCKSIZE * SS_BLOCKSIZE)) { return SS_BLOCKSIZE; } e = (x & 0xffff0000) ? ((x & 0xff000000) ? 24 + lg_table[(x >> 24) & 0xff] : 16 + lg_table[(x >> 16) & 0xff]) : ((x & 0x0000ff00) ? 8 + lg_table[(x >> 8) & 0xff] : 0 + lg_table[(x >> 0) & 0xff]); if(e >= 16) { y = sqq_table[x >> ((e - 6) - (e & 1))] << ((e >> 1) - 7); if(e >= 24) { y = (y + 1 + x / y) >> 1; } y = (y + 1 + x / y) >> 1; } else if(e >= 8) { y = (sqq_table[x >> ((e - 6) - (e & 1))] >> (7 - (e >> 1))) + 1; } else { return sqq_table[x] >> 4; } return (x < (y * y)) ? y - 1 : y; } #endif /* SS_BLOCKSIZE != 0 */ // corresponds to #if (#if SS_BLOCKSIZE != 0) static INLINE_divsuf int ss_compare(const unsigned char *T, const int *p1, const int *p2, int depth) { const unsigned char *U1, *U2, *U1n, *U2n; for(U1 = T + depth + *p1, U2 = T + depth + *p2, U1n = T + *(p1 + 1) + 2, U2n = T + *(p2 + 1) + 2; (U1 < U1n) && (U2 < U2n) && (*U1 == *U2); ++U1, ++U2) { } return U1 < U1n ? (U2 < U2n ? *U1 - *U2 : 1) : (U2 < U2n ? -1 : 0); } #if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) static void ss_insertionsort(const unsigned char *T, const int *PA, int *first, int *last, int depth) { int *i, *j; int t; int r; for(i = last - 2; first <= i; --i) { for(t = *i, j = i + 1; 0 < (r = ss_compare(T, PA + t, PA + *j, depth));) { do { *(j - 1) = *j; } while((++j < last) && (*j < 0)); if(last <= j) { break; } } if(r == 0) { *j = ~*j; } *(j - 1) = t; } } #endif /* (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1) */ // corresponds to #if (#if (SS_BLOCKSIZE != 1) && (SS_INSERTIONSORT_THRESHOLD != 1)) #if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) static INLINE_divsuf void ss_fixdown(const unsigned char *Td, const int *PA, int *SA, int i, int size) { int j, k; int v; int c, d, e; for(v = SA[i], c = Td[PA[v]]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { d = Td[PA[SA[k = j++]]]; if(d < (e = Td[PA[SA[j]]])) { k = j; d = e; } if(d <= c) { break; } } SA[i] = v; } /* Simple top-down heapsort. */ static void ss_heapsort(const unsigned char *Td, const int *PA, int *SA, int size) { int i, m; int t; m = size; if((size % 2) == 0) { m--; if(Td[PA[SA[m / 2]]] < Td[PA[SA[m]]]) { SWAP(SA[m], SA[m / 2]); } } for(i = m / 2 - 1; 0 <= i; --i) { ss_fixdown(Td, PA, SA, i, m); } if((size % 2) == 0) { SWAP(SA[0], SA[m]); ss_fixdown(Td, PA, SA, 0, m); } for(i = m - 1; 0 < i; --i) { t = SA[0], SA[0] = SA[i]; ss_fixdown(Td, PA, SA, 0, i); SA[i] = t; } } /* Returns the median of three elements. */ static INLINE_divsuf int * ss_median3(const unsigned char *Td, const int *PA, int *v1, int *v2, int *v3) { int *t; if(Td[PA[*v1]] > Td[PA[*v2]]) { SWAP(v1, v2); } if(Td[PA[*v2]] > Td[PA[*v3]]) { if(Td[PA[*v1]] > Td[PA[*v3]]) { return v1; } else { return v3; } } return v2; } /* Returns the median of five elements. */ static INLINE_divsuf int * ss_median5(const unsigned char *Td, const int *PA, int *v1, int *v2, int *v3, int *v4, int *v5) { int *t; if(Td[PA[*v2]] > Td[PA[*v3]]) { SWAP(v2, v3); } if(Td[PA[*v4]] > Td[PA[*v5]]) { SWAP(v4, v5); } if(Td[PA[*v2]] > Td[PA[*v4]]) { SWAP(v2, v4); SWAP(v3, v5); } if(Td[PA[*v1]] > Td[PA[*v3]]) { SWAP(v1, v3); } if(Td[PA[*v1]] > Td[PA[*v4]]) { SWAP(v1, v4); SWAP(v3, v5); } if(Td[PA[*v3]] > Td[PA[*v4]]) { return v4; } return v3; } /* Returns the pivot element. */ static INLINE_divsuf int * ss_pivot(const unsigned char *Td, const int *PA, int *first, int *last) { int *middle; int t; t = last - first; middle = first + t / 2; if(t <= 512) { if(t <= 32) { return ss_median3(Td, PA, first, middle, last - 1); } else { t >>= 2; return ss_median5(Td, PA, first, first + t, middle, last - 1 - t, last - 1); } } t >>= 3; first = ss_median3(Td, PA, first, first + t, first + (t << 1)); middle = ss_median3(Td, PA, middle - t, middle, middle + t); last = ss_median3(Td, PA, last - 1 - (t << 1), last - 1 - t, last - 1); return ss_median3(Td, PA, first, middle, last); } /* Binary partition for substrings. */ static INLINE_divsuf int * ss_partition(const int *PA, int *first, int *last, int depth) { int *a, *b; int t; for(a = first - 1, b = last;;) { for(; (++a < b) && ((PA[*a] + depth) >= (PA[*a + 1] + 1));) { *a = ~*a; } for(; (a < --b) && ((PA[*b] + depth) < (PA[*b + 1] + 1));) { } if(b <= a) { break; } t = ~*b; *b = *a; *a = t; } if(first < a) { *first = ~*first; } return a; } /* Multikey introsort for medium size groups. */ static void ss_mintrosort(const unsigned char *T, const int *PA, int *first, int *last, int depth) { #define STACK_SIZE SS_MISORT_STACKSIZE struct { int *a, *b, c; int d; } stack[STACK_SIZE]; const unsigned char *Td; int *a, *b, *c, *d, *e, *f; int s, t; int ssize; int limit; int v, x = 0; for(ssize = 0, limit = ss_ilg(last - first);;) { if((last - first) <= SS_INSERTIONSORT_THRESHOLD) { #if 1 < SS_INSERTIONSORT_THRESHOLD if(1 < (last - first)) { ss_insertionsort(T, PA, first, last, depth); } #endif // corresponds to #if (#if 1 < SS_INSERTIONSORT_THRESHOLD) STACK_POP(first, last, depth, limit); continue; } Td = T + depth; if(limit-- == 0) { ss_heapsort(Td, PA, first, last - first); } if(limit < 0) { for(a = first + 1, v = Td[PA[*first]]; a < last; ++a) { if((x = Td[PA[*a]]) != v) { if(1 < (a - first)) { break; } v = x; first = a; } } if(Td[PA[*first] - 1] < v) { first = ss_partition(PA, first, a, depth); } if((a - first) <= (last - a)) { if(1 < (a - first)) { STACK_PUSH(a, last, depth, -1); last = a, depth += 1, limit = ss_ilg(a - first); } else { first = a, limit = -1; } } else { if(1 < (last - a)) { STACK_PUSH(first, a, depth + 1, ss_ilg(a - first)); first = a, limit = -1; } else { last = a, depth += 1, limit = ss_ilg(a - first); } } continue; } /* choose pivot */ a = ss_pivot(Td, PA, first, last); v = Td[PA[*a]]; SWAP(*first, *a); /* partition */ for(b = first; (++b < last) && ((x = Td[PA[*b]]) == v);) { } if(((a = b) < last) && (x < v)) { for(; (++b < last) && ((x = Td[PA[*b]]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } } for(c = last; (b < --c) && ((x = Td[PA[*c]]) == v);) { } if((b < (d = c)) && (x > v)) { for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } for(; b < c;) { SWAP(*b, *c); for(; (++b < c) && ((x = Td[PA[*b]]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } for(; (b < --c) && ((x = Td[PA[*c]]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } if(a <= d) { c = b - 1; if((s = a - first) > (t = b - a)) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } if((s = d - c) > (t = last - d - 1)) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } a = first + (b - a), c = last - (d - c); b = (v <= Td[PA[*a] - 1]) ? a : ss_partition(PA, a, c, depth); if((a - first) <= (last - c)) { if((last - c) <= (c - b)) { STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); STACK_PUSH(c, last, depth, limit); last = a; } else if((a - first) <= (c - b)) { STACK_PUSH(c, last, depth, limit); STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); last = a; } else { STACK_PUSH(c, last, depth, limit); STACK_PUSH(first, a, depth, limit); first = b, last = c, depth += 1, limit = ss_ilg(c - b); } } else { if((a - first) <= (c - b)) { STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); STACK_PUSH(first, a, depth, limit); first = c; } else if((last - c) <= (c - b)) { STACK_PUSH(first, a, depth, limit); STACK_PUSH(b, c, depth + 1, ss_ilg(c - b)); first = c; } else { STACK_PUSH(first, a, depth, limit); STACK_PUSH(c, last, depth, limit); first = b, last = c, depth += 1, limit = ss_ilg(c - b); } } } else { limit += 1; if(Td[PA[*first] - 1] < v) { first = ss_partition(PA, first, last, depth); limit = ss_ilg(last - first); } depth += 1; } } #undef STACK_SIZE } #endif /* (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) */ // corresponds to #if (#if (SS_BLOCKSIZE == 0) || (SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE)) #if SS_BLOCKSIZE != 0 static INLINE_divsuf void ss_blockswap(int *a, int *b, int n) { int t; for(; 0 < n; --n, ++a, ++b) { t = *a, *a = *b, *b = t; } } static INLINE_divsuf void ss_rotate(int *first, int *middle, int *last) { int *a, *b, t; int l, r; l = middle - first, r = last - middle; for(; (0 < l) && (0 < r);) { if(l == r) { ss_blockswap(first, middle, l); break; } if(l < r) { a = last - 1, b = middle - 1; t = *a; do { *a-- = *b, *b-- = *a; if(b < first) { *a = t; last = a; if((r -= l + 1) <= l) { break; } a -= 1, b = middle - 1; t = *a; } } while(1); } else { a = first, b = middle; t = *a; do { *a++ = *b, *b++ = *a; if(last <= b) { *a = t; first = a + 1; if((l -= r + 1) <= r) { break; } a += 1, b = middle; t = *a; } } while(1); } } } static void ss_inplacemerge(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int depth) { const int *p; int *a, *b; int len, half; int q, r; int x; for(;;) { if(*(last - 1) < 0) { x = 1; p = PA + ~*(last - 1); } else { x = 0; p = PA + *(last - 1); } for(a = first, len = middle - first, half = len >> 1, r = -1; 0 < len; len = half, half >>= 1) { b = a + half; q = ss_compare(T, PA + ((0 <= *b) ? *b : ~*b), p, depth); if(q < 0) { a = b + 1; half -= (len & 1) ^ 1; } else { r = q; } } if(a < middle) { if(r == 0) { *a = ~*a; } ss_rotate(a, middle, last); last -= middle - a; middle = a; if(first == middle) { break; } } --last; if(x != 0) { while(*--last < 0) { } } if(middle == last) { break; } } } /* Merge-forward with internal buffer. */ static void ss_mergeforward(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int depth) { int *a, *b, *c, *bufend; int t; int r; bufend = buf + (middle - first) - 1; ss_blockswap(buf, first, middle - first); for(t = *(a = first), b = buf, c = middle;;) { r = ss_compare(T, PA + *b, PA + *c, depth); if(r < 0) { do { *a++ = *b; if(bufend <= b) { *bufend = t; return; } *b++ = *a; } while(*b < 0); } else if(r > 0) { do { *a++ = *c, *c++ = *a; if(last <= c) { while(b < bufend) { *a++ = *b, *b++ = *a; } *a = *b, *b = t; return; } } while(*c < 0); } else { *c = ~*c; do { *a++ = *b; if(bufend <= b) { *bufend = t; return; } *b++ = *a; } while(*b < 0); do { *a++ = *c, *c++ = *a; if(last <= c) { while(b < bufend) { *a++ = *b, *b++ = *a; } *a = *b, *b = t; return; } } while(*c < 0); } } } /* Merge-backward with internal buffer. */ static void ss_mergebackward(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int depth) { const int *p1, *p2; int *a, *b, *c, *bufend; int t; int r; int x; bufend = buf + (last - middle) - 1; ss_blockswap(buf, middle, last - middle); x = 0; if(*bufend < 0) { p1 = PA + ~*bufend; x |= 1; } else { p1 = PA + *bufend; } if(*(middle - 1) < 0) { p2 = PA + ~*(middle - 1); x |= 2; } else { p2 = PA + *(middle - 1); } for(t = *(a = last - 1), b = bufend, c = middle - 1;;) { r = ss_compare(T, p1, p2, depth); if(0 < r) { if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } *a-- = *b; if(b <= buf) { *buf = t; break; } *b-- = *a; if(*b < 0) { p1 = PA + ~*b; x |= 1; } else { p1 = PA + *b; } } else if(r < 0) { if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } *a-- = *c, *c-- = *a; if(c < first) { while(buf < b) { *a-- = *b, *b-- = *a; } *a = *b, *b = t; break; } if(*c < 0) { p2 = PA + ~*c; x |= 2; } else { p2 = PA + *c; } } else { if(x & 1) { do { *a-- = *b, *b-- = *a; } while(*b < 0); x ^= 1; } *a-- = ~*b; if(b <= buf) { *buf = t; break; } *b-- = *a; if(x & 2) { do { *a-- = *c, *c-- = *a; } while(*c < 0); x ^= 2; } *a-- = *c, *c-- = *a; if(c < first) { while(buf < b) { *a-- = *b, *b-- = *a; } *a = *b, *b = t; break; } if(*b < 0) { p1 = PA + ~*b; x |= 1; } else { p1 = PA + *b; } if(*c < 0) { p2 = PA + ~*c; x |= 2; } else { p2 = PA + *c; } } } } /* D&C based merge. */ static void ss_swapmerge(const unsigned char *T, const int *PA, int *first, int *middle, int *last, int *buf, int bufsize, int depth) { #define STACK_SIZE SS_SMERGE_STACKSIZE #define GETIDX(a) ((0 <= (a)) ? (a) : (~(a))) #define MERGE_CHECK(a, b, c)\ do {\ if(((c) & 1) ||\ (((c) & 2) && (ss_compare(T, PA + GETIDX(*((a) - 1)), PA + *(a), depth) == 0))) {\ *(a) = ~*(a);\ }\ if(((c) & 4) && ((ss_compare(T, PA + GETIDX(*((b) - 1)), PA + *(b), depth) == 0))) {\ *(b) = ~*(b);\ }\ } while(0) struct { int *a, *b, *c; int d; } stack[STACK_SIZE]; int *l, *r, *lm, *rm; int m, len, half; int ssize; int check, next; for(check = 0, ssize = 0;;) { if((last - middle) <= bufsize) { if((first < middle) && (middle < last)) { ss_mergebackward(T, PA, first, middle, last, buf, depth); } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); continue; } if((middle - first) <= bufsize) { if(first < middle) { ss_mergeforward(T, PA, first, middle, last, buf, depth); } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); continue; } for(m = 0, len = MIN(middle - first, last - middle), half = len >> 1; 0 < len; len = half, half >>= 1) { if(ss_compare(T, PA + GETIDX(*(middle + m + half)), PA + GETIDX(*(middle - m - half - 1)), depth) < 0) { m += half + 1; half -= (len & 1) ^ 1; } } if(0 < m) { lm = middle - m, rm = middle + m; ss_blockswap(lm, middle, m); l = r = middle, next = 0; if(rm < last) { if(*rm < 0) { *rm = ~*rm; if(first < lm) { for(; *--l < 0;) { } next |= 4; } next |= 1; } else if(first < lm) { for(; *r < 0; ++r) { } next |= 2; } } if((l - first) <= (last - r)) { STACK_PUSH(r, rm, last, (next & 3) | (check & 4)); middle = lm, last = l, check = (check & 3) | (next & 4); } else { if((next & 2) && (r == middle)) { next ^= 6; } STACK_PUSH(first, lm, l, (check & 3) | (next & 4)); first = r, middle = rm, check = (next & 3) | (check & 4); } } else { if(ss_compare(T, PA + GETIDX(*(middle - 1)), PA + *middle, depth) == 0) { *middle = ~*middle; } MERGE_CHECK(first, last, check); STACK_POP(first, middle, last, check); } } #undef STACK_SIZE } #endif /* SS_BLOCKSIZE != 0 */ // corresponds to #if (#if SS_BLOCKSIZE != 0) /* Substring sort */ static void sssort(const unsigned char *T, const int *PA, int *first, int *last, int *buf, int bufsize, int depth, int n, int lastsuffix) { int *a; #if SS_BLOCKSIZE != 0 int *b, *middle, *curbuf; int j, k, curbufsize, limit; #endif // corresponds to #if (#if SS_BLOCKSIZE != 0) int i; if(lastsuffix != 0) { ++first; } #if SS_BLOCKSIZE == 0 ss_mintrosort(T, PA, first, last, depth); #else if((bufsize < SS_BLOCKSIZE) && (bufsize < (last - first)) && (bufsize < (limit = ss_isqrt(last - first)))) { if(SS_BLOCKSIZE < limit) { limit = SS_BLOCKSIZE; } buf = middle = last - limit, bufsize = limit; } else { middle = last, limit = 0; } for(a = first, i = 0; SS_BLOCKSIZE < (middle - a); a += SS_BLOCKSIZE, ++i) { #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, a, a + SS_BLOCKSIZE, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, a, a + SS_BLOCKSIZE, depth); #endif // corresponds to #if (#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) curbufsize = last - (a + SS_BLOCKSIZE); curbuf = a + SS_BLOCKSIZE; if(curbufsize <= bufsize) { curbufsize = bufsize, curbuf = buf; } for(b = a, k = SS_BLOCKSIZE, j = i; j & 1; b -= k, k <<= 1, j >>= 1) { ss_swapmerge(T, PA, b - k, b, b + k, curbuf, curbufsize, depth); } } #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, a, middle, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, a, middle, depth); #endif // corresponds to #if (#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) for(k = SS_BLOCKSIZE; i != 0; k <<= 1, i >>= 1) { if(i & 1) { ss_swapmerge(T, PA, a - k, a, middle, buf, bufsize, depth); a -= k; } } if(limit != 0) { #if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE ss_mintrosort(T, PA, middle, last, depth); #elif 1 < SS_BLOCKSIZE ss_insertionsort(T, PA, middle, last, depth); #endif // corresponds to #if (#if SS_INSERTIONSORT_THRESHOLD < SS_BLOCKSIZE) ss_inplacemerge(T, PA, first, middle, last, depth); } #endif // corresponds to #if (#if SS_BLOCKSIZE == 0) if(lastsuffix != 0) { /* Insert last type B* suffix. */ int PAi[2]; PAi[0] = PA[*(first - 1)], PAi[1] = n - 2; for(a = first, i = *(first - 1); (a < last) && ((*a < 0) || (0 < ss_compare(T, &(PAi[0]), PA + *a, depth))); ++a) { *(a - 1) = *a; } *(a - 1) = i; } } static INLINE_divsuf int tr_ilg(int n) { return (n & 0xffff0000) ? ((n & 0xff000000) ? 24 + lg_table[(n >> 24) & 0xff] : 16 + lg_table[(n >> 16) & 0xff]) : ((n & 0x0000ff00) ? 8 + lg_table[(n >> 8) & 0xff] : 0 + lg_table[(n >> 0) & 0xff]); } /* Simple insertionsort for small size groups. */ static void tr_insertionsort(const int *ISAd, int *first, int *last) { int *a, *b; int t, r; for(a = first + 1; a < last; ++a) { for(t = *a, b = a - 1; 0 > (r = ISAd[t] - ISAd[*b]);) { do { *(b + 1) = *b; } while((first <= --b) && (*b < 0)); if(b < first) { break; } } if(r == 0) { *b = ~*b; } *(b + 1) = t; } } static INLINE_divsuf void tr_fixdown(const int *ISAd, int *SA, int i, int size) { int j, k; int v; int c, d, e; for(v = SA[i], c = ISAd[v]; (j = 2 * i + 1) < size; SA[i] = SA[k], i = k) { d = ISAd[SA[k = j++]]; if(d < (e = ISAd[SA[j]])) { k = j; d = e; } if(d <= c) { break; } } SA[i] = v; } /* Simple top-down heapsort. */ static void tr_heapsort(const int *ISAd, int *SA, int size) { int i, m; int t; m = size; if((size % 2) == 0) { m--; if(ISAd[SA[m / 2]] < ISAd[SA[m]]) { SWAP(SA[m], SA[m / 2]); } } for(i = m / 2 - 1; 0 <= i; --i) { tr_fixdown(ISAd, SA, i, m); } if((size % 2) == 0) { SWAP(SA[0], SA[m]); tr_fixdown(ISAd, SA, 0, m); } for(i = m - 1; 0 < i; --i) { t = SA[0], SA[0] = SA[i]; tr_fixdown(ISAd, SA, 0, i); SA[i] = t; } } /* Returns the median of three elements. */ static INLINE_divsuf int * tr_median3(const int *ISAd, int *v1, int *v2, int *v3) { int *t; if(ISAd[*v1] > ISAd[*v2]) { SWAP(v1, v2); } if(ISAd[*v2] > ISAd[*v3]) { if(ISAd[*v1] > ISAd[*v3]) { return v1; } else { return v3; } } return v2; } static INLINE_divsuf int * tr_median5(const int *ISAd, int *v1, int *v2, int *v3, int *v4, int *v5) { int *t; if(ISAd[*v2] > ISAd[*v3]) { SWAP(v2, v3); } if(ISAd[*v4] > ISAd[*v5]) { SWAP(v4, v5); } if(ISAd[*v2] > ISAd[*v4]) { SWAP(v2, v4); SWAP(v3, v5); } if(ISAd[*v1] > ISAd[*v3]) { SWAP(v1, v3); } if(ISAd[*v1] > ISAd[*v4]) { SWAP(v1, v4); SWAP(v3, v5); } if(ISAd[*v3] > ISAd[*v4]) { return v4; } return v3; } static INLINE_divsuf int * tr_pivot(const int *ISAd, int *first, int *last) { int *middle; int t; t = last - first; middle = first + t / 2; if(t <= 512) { if(t <= 32) { return tr_median3(ISAd, first, middle, last - 1); } else { t >>= 2; return tr_median5(ISAd, first, first + t, middle, last - 1 - t, last - 1); } } t >>= 3; first = tr_median3(ISAd, first, first + t, first + (t << 1)); middle = tr_median3(ISAd, middle - t, middle, middle + t); last = tr_median3(ISAd, last - 1 - (t << 1), last - 1 - t, last - 1); return tr_median3(ISAd, first, middle, last); } typedef struct _trbudget_t trbudget_t; struct _trbudget_t { int chance; int remain; int incval; int count; }; static INLINE_divsuf void trbudget_init(trbudget_t *budget, int chance, int incval) { budget->chance = chance; budget->remain = budget->incval = incval; } static INLINE_divsuf int trbudget_check(trbudget_t *budget, int size) { if(size <= budget->remain) { budget->remain -= size; return 1; } if(budget->chance == 0) { budget->count += size; return 0; } budget->remain += budget->incval - size; budget->chance -= 1; return 1; } static INLINE_divsuf void tr_partition(const int *ISAd, int *first, int *middle, int *last, int **pa, int **pb, int v) { int *a, *b, *c, *d, *e, *f; int t, s; int x = 0; for(b = middle - 1; (++b < last) && ((x = ISAd[*b]) == v);) { } if(((a = b) < last) && (x < v)) { for(; (++b < last) && ((x = ISAd[*b]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } } for(c = last; (b < --c) && ((x = ISAd[*c]) == v);) { } if((b < (d = c)) && (x > v)) { for(; (b < --c) && ((x = ISAd[*c]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } for(; b < c;) { SWAP(*b, *c); for(; (++b < c) && ((x = ISAd[*b]) <= v);) { if(x == v) { SWAP(*b, *a); ++a; } } for(; (b < --c) && ((x = ISAd[*c]) >= v);) { if(x == v) { SWAP(*c, *d); --d; } } } if(a <= d) { c = b - 1; if((s = a - first) > (t = b - a)) { s = t; } for(e = first, f = b - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } if((s = d - c) > (t = last - d - 1)) { s = t; } for(e = b, f = last - s; 0 < s; --s, ++e, ++f) { SWAP(*e, *f); } first += (b - a), last -= (d - c); } *pa = first, *pb = last; } static void tr_copy(int *ISA, const int *SA, int *first, int *a, int *b, int *last, int depth) { /* sort suffixes of middle partition by using sorted order of suffixes of left and right partition. */ int *c, *d, *e; int s, v; v = b - SA - 1; for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; ISA[s] = d - SA; } } for(c = last - 1, e = d + 1, d = b; e < d; --c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; ISA[s] = d - SA; } } } static void tr_partialcopy(int *ISA, const int *SA, int *first, int *a, int *b, int *last, int depth) { int *c, *d, *e; int s, v; int rank, lastrank, newrank = -1; v = b - SA - 1; lastrank = -1; for(c = first, d = a - 1; c <= d; ++c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *++d = s; rank = ISA[s + depth]; if(lastrank != rank) { lastrank = rank; newrank = d - SA; } ISA[s] = newrank; } } lastrank = -1; for(e = d; first <= e; --e) { rank = ISA[*e]; if(lastrank != rank) { lastrank = rank; newrank = e - SA; } if(newrank != rank) { ISA[*e] = newrank; } } lastrank = -1; for(c = last - 1, e = d + 1, d = b; e < d; --c) { if((0 <= (s = *c - depth)) && (ISA[s] == v)) { *--d = s; rank = ISA[s + depth]; if(lastrank != rank) { lastrank = rank; newrank = d - SA; } ISA[s] = newrank; } } } static void tr_introsort(int *ISA, const int *ISAd, int *SA, int *first, int *last, trbudget_t *budget) { #define STACK_SIZE TR_STACKSIZE struct { const int *a; int *b, *c; int d, e; }stack[STACK_SIZE]; int *a, *b, *c; int t; int v, x = 0; int incr = ISAd - ISA; int limit, next; int ssize, trlink = -1; for(ssize = 0, limit = tr_ilg(last - first);;) { if(limit < 0) { if(limit == -1) { /* tandem repeat partition */ tr_partition(ISAd - incr, first, first, last, &a, &b, last - SA - 1); /* update ranks */ if(a < last) { for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } } if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } /* push */ if(1 < (b - a)) { STACK_PUSH5(NULL, a, b, 0, 0); STACK_PUSH5(ISAd - incr, first, last, -2, trlink); trlink = ssize - 2; } if((a - first) <= (last - b)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, tr_ilg(last - b), trlink); last = a, limit = tr_ilg(a - first); } else if(1 < (last - b)) { first = b, limit = tr_ilg(last - b); } else { STACK_POP5(ISAd, first, last, limit, trlink); } } else { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, tr_ilg(a - first), trlink); first = b, limit = tr_ilg(last - b); } else if(1 < (a - first)) { last = a, limit = tr_ilg(a - first); } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } else if(limit == -2) { /* tandem repeat copy */ a = stack[--ssize].b, b = stack[ssize].c; if(stack[ssize].d == 0) { tr_copy(ISA, SA, first, a, b, last, ISAd - ISA); } else { if(0 <= trlink) { stack[trlink].d = -1; } tr_partialcopy(ISA, SA, first, a, b, last, ISAd - ISA); } STACK_POP5(ISAd, first, last, limit, trlink); } else { /* sorted partition */ if(0 <= *first) { a = first; do { ISA[*a] = a - SA; } while((++a < last) && (0 <= *a)); first = a; } if(first < last) { a = first; do { *a = ~*a; } while(*++a < 0); next = (ISA[*a] != ISAd[*a]) ? tr_ilg(a - first + 1) : -1; if(++a < last) { for(b = first, v = a - SA - 1; b < a; ++b) { ISA[*b] = v; } } /* push */ if(trbudget_check(budget, a - first)) { if((a - first) <= (last - a)) { STACK_PUSH5(ISAd, a, last, -3, trlink); ISAd += incr, last = a, limit = next; } else { if(1 < (last - a)) { STACK_PUSH5(ISAd + incr, first, a, next, trlink); first = a, limit = -3; } else { ISAd += incr, last = a, limit = next; } } } else { if(0 <= trlink) { stack[trlink].d = -1; } if(1 < (last - a)) { first = a, limit = -3; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } else { STACK_POP5(ISAd, first, last, limit, trlink); } } continue; } if((last - first) <= TR_INSERTIONSORT_THRESHOLD) { tr_insertionsort(ISAd, first, last); limit = -3; continue; } if(limit-- == 0) { tr_heapsort(ISAd, first, last - first); for(a = last - 1; first < a; a = b) { for(x = ISAd[*a], b = a - 1; (first <= b) && (ISAd[*b] == x); --b) { *b = ~*b; } } limit = -3; continue; } /* choose pivot */ a = tr_pivot(ISAd, first, last); SWAP(*first, *a); v = ISAd[*first]; /* partition */ tr_partition(ISAd, first, first + 1, last, &a, &b, v); if((last - first) != (b - a)) { next = (ISA[*a] != v) ? tr_ilg(b - a) : -1; /* update ranks */ for(c = first, v = a - SA - 1; c < a; ++c) { ISA[*c] = v; } if(b < last) { for(c = a, v = b - SA - 1; c < b; ++c) { ISA[*c] = v; } } /* push */ if((1 < (b - a)) && (trbudget_check(budget, b - a))) { if((a - first) <= (last - b)) { if((last - b) <= (b - a)) { if(1 < (a - first)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); STACK_PUSH5(ISAd, b, last, limit, trlink); last = a; } else if(1 < (last - b)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); first = b; } else { ISAd += incr, first = a, last = b, limit = next; } } else if((a - first) <= (b - a)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, limit, trlink); STACK_PUSH5(ISAd + incr, a, b, next, trlink); last = a; } else { STACK_PUSH5(ISAd, b, last, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { STACK_PUSH5(ISAd, b, last, limit, trlink); STACK_PUSH5(ISAd, first, a, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { if((a - first) <= (b - a)) { if(1 < (last - b)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); STACK_PUSH5(ISAd, first, a, limit, trlink); first = b; } else if(1 < (a - first)) { STACK_PUSH5(ISAd + incr, a, b, next, trlink); last = a; } else { ISAd += incr, first = a, last = b, limit = next; } } else if((last - b) <= (b - a)) { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, limit, trlink); STACK_PUSH5(ISAd + incr, a, b, next, trlink); first = b; } else { STACK_PUSH5(ISAd, first, a, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } else { STACK_PUSH5(ISAd, first, a, limit, trlink); STACK_PUSH5(ISAd, b, last, limit, trlink); ISAd += incr, first = a, last = b, limit = next; } } } else { if((1 < (b - a)) && (0 <= trlink)) { stack[trlink].d = -1; } if((a - first) <= (last - b)) { if(1 < (a - first)) { STACK_PUSH5(ISAd, b, last, limit, trlink); last = a; } else if(1 < (last - b)) { first = b; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } else { if(1 < (last - b)) { STACK_PUSH5(ISAd, first, a, limit, trlink); first = b; } else if(1 < (a - first)) { last = a; } else { STACK_POP5(ISAd, first, last, limit, trlink); } } } } else { if(trbudget_check(budget, last - first)) { limit = tr_ilg(last - first), ISAd += incr; } else { if(0 <= trlink) { stack[trlink].d = -1; } STACK_POP5(ISAd, first, last, limit, trlink); } } } #undef STACK_SIZE } /* Tandem repeat sort */ static void trsort(int *ISA, int *SA, int n, int depth) { int *ISAd; int *first, *last; trbudget_t budget; int t, skip, unsorted; trbudget_init(&budget, tr_ilg(n) * 2 / 3, n); /* trbudget_init(&budget, tr_ilg(n) * 3 / 4, n); */ for(ISAd = ISA + depth; -n < *SA; ISAd += ISAd - ISA) { first = SA; skip = 0; unsorted = 0; do { if((t = *first) < 0) { first -= t; skip += t; } else { if(skip != 0) { *(first + skip) = skip; skip = 0; } last = SA + ISA[t] + 1; if(1 < (last - first)) { budget.count = 0; tr_introsort(ISA, ISAd, SA, first, last, &budget); if(budget.count != 0) { unsorted += budget.count; } else { skip = first - last; } } else if((last - first) == 1) { skip = -1; } first = last; } } while(first < (SA + n)); if(skip != 0) { *(first + skip) = skip; } if(unsorted == 0) { break; } } } /* Sorts suffixes of type B*. */ static int sort_typeBstar(const unsigned char *T, int *SA, int *bucket_A, int *bucket_B, int n) { int *PAb, *ISAb, *buf; int i, j, k, t, m, bufsize; int c0, c1; /* Initialize bucket arrays. */ for(i = 0; i < BUCKET_A_SIZE; ++i) { bucket_A[i] = 0; } for(i = 0; i < BUCKET_B_SIZE; ++i) { bucket_B[i] = 0; } /* Count the number of occurrences of the first one or two characters of each type A, B and B* suffix. Moreover, store the beginning position of all type B* suffixes into the array SA. */ for(i = n - 1, m = n, c0 = T[n - 1]; 0 <= i;) { /* type A suffix. */ do { ++BUCKET_A(c1 = c0); } while((0 <= --i) && ((c0 = T[i]) >= c1)); if(0 <= i) { /* type B* suffix. */ ++BUCKET_BSTAR(c0, c1); SA[--m] = i; /* type B suffix. */ for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { ++BUCKET_B(c0, c1); } } } m = n - m; /* note: A type B* suffix is lexicographically smaller than a type B suffix that begins with the same first two characters. */ /* Calculate the index of start/end point of each bucket. */ for(c0 = 0, i = 0, j = 0; c0 < ALPHABET_SIZE; ++c0) { t = i + BUCKET_A(c0); BUCKET_A(c0) = i + j; /* start point */ i = t + BUCKET_B(c0, c0); for(c1 = c0 + 1; c1 < ALPHABET_SIZE; ++c1) { j += BUCKET_BSTAR(c0, c1); BUCKET_BSTAR(c0, c1) = j; /* end point */ i += BUCKET_B(c0, c1); } } if(0 < m) { /* Sort the type B* suffixes by their first two characters. */ PAb = SA + n - m; ISAb = SA + m; for(i = m - 2; 0 <= i; --i) { t = PAb[i], c0 = T[t], c1 = T[t + 1]; SA[--BUCKET_BSTAR(c0, c1)] = i; } t = PAb[m - 1], c0 = T[t], c1 = T[t + 1]; SA[--BUCKET_BSTAR(c0, c1)] = m - 1; /* Sort the type B* substrings using sssort. */ buf = SA + m, bufsize = n - (2 * m); for(c0 = ALPHABET_SIZE - 2, j = m; 0 < j; --c0) { for(c1 = ALPHABET_SIZE - 1; c0 < c1; j = i, --c1) { i = BUCKET_BSTAR(c0, c1); if(1 < (j - i)) { sssort(T, PAb, SA + i, SA + j, buf, bufsize, 2, n, *(SA + i) == (m - 1)); } } } /* Compute ranks of type B* substrings. */ for(i = m - 1; 0 <= i; --i) { if(0 <= SA[i]) { j = i; do { ISAb[SA[i]] = i; } while((0 <= --i) && (0 <= SA[i])); SA[i + 1] = i - j; if(i <= 0) { break; } } j = i; do { ISAb[SA[i] = ~SA[i]] = j; } while(SA[--i] < 0); ISAb[SA[i]] = j; } /* Construct the inverse suffix array of type B* suffixes using trsort. */ trsort(ISAb, SA, m, 1); /* Set the sorted order of tyoe B* suffixes. */ for(i = n - 1, j = m, c0 = T[n - 1]; 0 <= i;) { for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) >= c1); --i, c1 = c0) { } if(0 <= i) { t = i; for(--i, c1 = c0; (0 <= i) && ((c0 = T[i]) <= c1); --i, c1 = c0) { } SA[ISAb[--j]] = ((t == 0) || (1 < (t - i))) ? t : ~t; } } /* Calculate the index of start/end point of each bucket. */ BUCKET_B(ALPHABET_SIZE - 1, ALPHABET_SIZE - 1) = n; /* end point */ for(c0 = ALPHABET_SIZE - 2, k = m - 1; 0 <= c0; --c0) { i = BUCKET_A(c0 + 1) - 1; for(c1 = ALPHABET_SIZE - 1; c0 < c1; --c1) { t = i - BUCKET_B(c0, c1); BUCKET_B(c0, c1) = i; /* end point */ /* Move all type B* suffixes to the correct position. */ for(i = t, j = BUCKET_BSTAR(c0, c1); j <= k; --i, --k) { SA[i] = SA[k]; } } BUCKET_BSTAR(c0, c0 + 1) = i - BUCKET_B(c0, c0) + 1; /* start point */ BUCKET_B(c0, c0) = i; /* end point */ } } return m; } /* Constructs the suffix array by using the sorted order of type B* suffixes. */ static void construct_SA(const unsigned char *T, int *SA, int *bucket_A, int *bucket_B, int n, int m) { int *i, *j, *k; int s; int c0, c1, c2; if(0 < m) { /* Construct the sorted order of type B suffixes by using the sorted order of type B* suffixes. */ for(c1 = ALPHABET_SIZE - 2; 0 <= c1; --c1) { /* Scan the suffix array from right to left. */ for(i = SA + BUCKET_BSTAR(c1, c1 + 1), j = SA + BUCKET_A(c1 + 1) - 1, k = NULL, c2 = -1; i <= j; --j) { if(0 < (s = *j)) { assert(T[s] == c1); assert(((s + 1) < n) && (T[s] <= T[s + 1])); assert(T[s - 1] <= T[s]); *j = ~s; c0 = T[--s]; if((0 < s) && (T[s - 1] > c0)) { s = ~s; } if(c0 != c2) { if(0 <= c2) { BUCKET_B(c2, c1) = k - SA; } k = SA + BUCKET_B(c2 = c0, c1); } assert(k < j); if (k!=NULL) *k-- = s; else { myprintf("15845: k null!\n"); exit(0); } } else { assert(((s == 0) && (T[s] == c1)) || (s < 0)); *j = ~s; } } } } /* Construct the suffix array by using the sorted order of type B suffixes. */ k = SA + BUCKET_A(c2 = T[n - 1]); *k++ = (T[n - 2] < c2) ? ~(n - 1) : (n - 1); /* Scan the suffix array from left to right. */ for(i = SA, j = SA + n; i < j; ++i) { if(0 < (s = *i)) { assert(T[s - 1] >= T[s]); c0 = T[--s]; if((s == 0) || (T[s - 1] < c0)) { s = ~s; } if(c0 != c2) { BUCKET_A(c2) = k - SA; k = SA + BUCKET_A(c2 = c0); } assert(i < k); *k++ = s; } else { assert(s < 0); *i = ~s; } } } /*- Function -*/ int divsufsort(const unsigned char *T, int *SA, int n) { int *bucket_A, *bucket_B; int m; int err = 0; /* Check arguments. */ if((T == NULL) || (SA == NULL) || (n < 0)) { return -1; } else if(n == 0) { return 0; } else if(n == 1) { SA[0] = 0; return 0; } else if(n == 2) { m = (T[0] < T[1]); SA[m ^ 1] = 0, SA[m] = 1; return 0; } bucket_A = (int *)franz_malloc(BUCKET_A_SIZE * sizeof(int)); bucket_B = (int *)franz_malloc(BUCKET_B_SIZE * sizeof(int)); // g_allocatedram+=BUCKET_A_SIZE * sizeof(int)+BUCKET_B_SIZE * sizeof(int); /* Suffixsort. */ if((bucket_A != NULL) && (bucket_B != NULL)) { m = sort_typeBstar(T, SA, bucket_A, bucket_B, n); construct_SA(T, SA, bucket_A, bucket_B, n, m); } else { err = -2; } franz_free(bucket_B); franz_free(bucket_A); return err; } // End divsufsort.c /// LICENSE_END.6 /////////////////////////////// add /////////////////////////////////// // Convert non-negative decimal number x to string of at least n digits std::string itos(int64_t x, int n=1) { assert(x>=0); assert(n>=0); std::string r; for (; x || n>0; x/=10, --n) r=std::string(1, '0'+x%10)+r; return r; } // E8E9 transform of buf[0..n-1] to improve compression of .exe and .dll. // Patterns (E8|E9 xx xx xx 00|FF) at offset i replace the 3 middle // bytes with x+i mod 2^24, LSB first, reading backward. void e8e9(unsigned char* buf, int n) { for (int i=n-5; i>=0; --i) { if (((buf[i]&254)==0xe8) && ((buf[i+4]+1)&254)==0) { unsigned a=(buf[i+1]|buf[i+2]<<8|buf[i+3]<<16)+i; buf[i+1]=a; buf[i+2]=a>>8; buf[i+3]=a>>16; } } } // Encode inbuf to buf using LZ77. args are as follows: // args[0] is log2 buffer size in MB. // args[1] is level (1=var. length, 2=byte aligned lz77, 3=bwt) + 4 if E8E9. // args[2] is the lz77 minimum match length and context order. // args[3] is the lz77 higher context order to search first, or else 0. // args[4] is the log2 hash bucket size (number of searches). // args[5] is the log2 hash table size. If 21+args[0] then use a suffix array. // args[6] is the secondary context look ahead // sap is pointer to external suffix array of inbuf or 0. If supplied and // args[0]=5..7 then it is assumed that E8E9 was already applied to // both the input and sap and the input buffer is not modified. class LZBuffer: public libzpaq::Reader { libzpaq::Array ht;// hash table, confirm in low bits, or SA+ISA const unsigned char* in; // input pointer const int checkbits; // hash confirmation size or lg(ISA size) const int level; // 1=var length LZ77, 2=byte aligned LZ77, 3=BWT const unsigned htsize; // size of hash table const unsigned n; // input length unsigned i; // current location in in (0 <= i < n) const unsigned minMatch; // minimum match length const unsigned minMatch2; // second context order or 0 if not used const unsigned maxMatch; // longest match length allowed const unsigned maxLiteral; // longest literal length allowed const unsigned lookahead; // second context look ahead unsigned h1, h2; // low, high order context hashes of in[i..] const unsigned bucket; // number of matches to search per hash - 1 const unsigned shift1, shift2; // how far to shift h1, h2 per hash const int minMatchBoth; // max(minMatch, minMatch2) const unsigned rb; // number of level 1 r bits in match code unsigned bits; // pending output bits (level 1) unsigned nbits; // number of bits in bits unsigned rpos, wpos; // read, write pointers unsigned idx; // BWT index const unsigned* sa; // suffix array for BWT or LZ77-SA unsigned* isa; // inverse suffix array for LZ77-SA enum {BUFSIZE=1<<14}; // output buffer size unsigned char buf[BUFSIZE]; // output buffer void write_literal(unsigned i, unsigned& lit); void write_match(unsigned len, unsigned off); void fill(); // encode to buf // write k bits of x void putb(unsigned x, int k) { x&=(1<7) { assert(wpos>=8, nbits-=8; } } // write last byte void flush() { assert(wpos0) buf[wpos++]=bits; bits=nbits=0; } // write 1 byte void put(int c) { assert(wpos 00) = match 4*n+ll at offset (q<=65536) r=16, x>>=16; if (x>=256) r+=8, x>>=8; if (x>=16) r+=4, x>>=4; assert(x>=0 && x<16); return "\x00\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x04\x04\x04\x04"[x]+r; } // return number of 1 bits in x int nbits(unsigned x) { int r; for (r=0; x; x>>=1) r+=x&1; return r; } // catch buffer overflow with gdb backtrace void *alpine_memcpy(void *dest, const void *src, size_t n) { if (dest==NULL) { myprintf("15965: GURU dest NULL\n"); exit(0); } if (src==NULL) { myprintf("15970: GURU src NULL\n"); exit(0); } if (n==0) return dest; unsigned char *d = (unsigned char *)dest; const unsigned char *s = (const unsigned char *)src; for (size_t i=0;iint(wpos-rpos)) nr=wpos-rpos; ///alpine linux does not like this. why? I do not know. if (flagdebug5) { if (nr) alpine_memcpy(p, buf+rpos, nr); } else { if (nr) memcpy(p, buf+rpos, nr); } rpos+=nr; assert(rpos<=wpos); if (rpos==wpos) rpos=wpos=0; return nr; } LZBuffer::LZBuffer(StringBuffer& inbuf, int args[], const unsigned* sap): ht((args[1]&3)==3 ? (inbuf.size()+1)*!sap // for BWT suffix array : args[5]-args[0]<21 ? 1u<0 ? (args[5]-1)/minMatch+1 : 1), shift2(minMatch2>0 ? (args[5]-1)/minMatch2+1 : 0), minMatchBoth(MAX(minMatch, minMatch2+lookahead)+4), rb(args[0]>4 ? args[0]-4 : 0), bits(0), nbits(0), rpos(0), wpos(0), idx(0), sa(0), isa(0) { assert(args[0]>=0); assert(n<=(1u<<20<=1 && args[1]<=7 && args[1]!=4); assert(level>=1 && level<=3); if ((minMatch<4 && level==1) || (minMatch<1 && level==2)) error("match length $3 too small"); // e8e9 transform if (args[1]>4 && !sap) e8e9(inbuf.data(), n); // build suffix array if not supplied if (args[5]-args[0]>=21 || level==3) { // LZ77-SA or BWT if (sap) sa=sap; else { assert(ht.size()>=n); assert(ht.size()>0); sa=&ht[0]; if (n>0) divsufsort((const unsigned char*)in, (int*)sa, n); } if (level<3) { assert(ht.size()>=(n*(sap==0))+(1u<<17<0 ? in[n-1] : 255); else if (i>n) put(idx&255), idx>>=8; else if (sa[i-1]==0) idx=i, put(255); else put(in[sa[i-1]-1]); } return; } // LZ77: scan the input unsigned lit=0; // number of output literals pending const unsigned mask=(1<0 && in[p+l1-1]==in[i+l1-1]; --l1); int score=int(l-l1)*8-lg(i-p)-4*(lit==0 && l1>0)-11; for (unsigned a=0; abscore) blen=l, bp=p, blit=l1, bscore=score; if (l255) break; } } } if (bscore<=0 || blen0) { for (unsigned k=0; k<=bucket; ++k) { unsigned p=ht[h2^k]; if (p && (p&mask)==(in[i+3]&mask)) { p>>=checkbits; if (p=minMatch2+lookahead) { int l1; // length back from lookahead for (l1=lookahead; l1>0 && in[p+l1-1]==in[i+l1-1]; --l1); assert(l1>=0 && l1<=int(lookahead)); int score=int(l-l1)*8-lg(i-p)-8*(lit==0 && l1>0)-11; if (score>bscore) blen=l, bp=p, blit=l1, bscore=score; } } } if (blen>=128) break; } } // Search the lower order context if (!minMatch2 || blen>=checkbits; if (p0)-11; if (score>bscore) blen=l, bp=p, blit=0, bscore=score; } } if (blen>=128) break; } } } // If match is long enough, then output any pending literals first, // and then the match. blen is the length of the match. assert(i>=bp); const unsigned off=i-bp; // offset if (off>0 && bscore>0 && blen-blit>=minMatch+(level==2)*((off>=(1<<16))+(off>=(1<<24)))) { lit+=blit; write_literal(i+blit, lit); write_match(blen-blit, off); } // Otherwise add to literal length else { blen=1; ++lit; } // Update index, advance blen bytes if (isa) i+=blen; else { while (blen--) { if (i+minMatchBoth>19)&bucket; const unsigned p=(i<=maxLiteral) write_literal(i, lit); } // Write pending literals at end of input assert(i<=n); if (i==n) { write_literal(n, lit); flush(); } } // Write literal sequence in[i-lit..i-1], set lit=0 void LZBuffer::write_literal(unsigned i, unsigned& lit) { assert(lit>=0); assert(i>=0 && i<=n); assert(i>=lit); if (level==1) { if (lit<1) return; int ll=lg(lit); assert(ll>=1 && ll<=24); putb(0, 2); --ll; while (--ll>=0) { putb(1, 1); putb((lit>>ll)&1, 1); } putb(0, 1); while (lit) putb(in[i-lit--], 8); } else { assert(level==2); while (lit>0) { unsigned lit1=lit; if (lit1>64) lit1=64; put(lit1-1); for (unsigned j=i-lit; j=minMatch && len<=maxMatch); assert(off>0); assert(len>=4); assert(rb>=0 && rb<=8); int ll=lg(len)-1; assert(ll>=2); off+=(1<=0 && lo<=23); putb((lo+8)>>3, 2);// mm putb(lo&7, 3); // mmm while (--ll>=2) { // n putb(1, 1); putb((len>>ll)&1, 1); } putb(0, 1); putb(len&3, 2); // ll putb(off, rb); // r putb(off>>rb, lo); // q } // x[2]:len[6] off[x-1] else { assert(level==2); assert(minMatch>=1 && minMatch<=64); --off; while (len>0) { // Split long matches to len1=minMatch..minMatch+63 const unsigned len1=len>minMatch*2+63 ? minMatch+63 : len>minMatch+63 ? len-minMatch : len; assert(wpos=minMatch && len1>8); put(off); } else if (off<(1<<24)) { put(128+len1-minMatch); put(off>>16); put(off>>8); put(off); } else { put(192+len1-minMatch); put(off>>24); put(off>>16); put(off>>8); put(off); } len-=len1; } } } // Generate a config file from the method argument with syntax: // {0|x|s|i}[N1[,N2]...][{ciamtswf}[N1[,N2]]...]... std::string makeConfig(const char* method, int args[]) { assert(method); const char type=method[0]; assert(type=='x' || type=='s' || type=='0' || type=='i'); // Read "{x|s|i|0}N1,N2...N9" into args[0..8] ($1..$9) args[0]=0; // log block size in MiB args[1]=0; // 0=none, 1=var-LZ77, 2=byte-LZ77, 3=BWT, 4..7 adds E8E9 args[2]=0; // lz77 minimum match length args[3]=0; // secondary context length args[4]=0; // log searches args[5]=0; // lz77 hash table size or SA if args[0]+21 args[6]=0; // secondary context look ahead args[7]=0; // not used args[8]=0; // not used if (isdigit(*++method)) args[0]=0; for (int i=0; i<9 && (isdigit(*method) || *method==',' || *method=='.');) { if (isdigit(*method)) args[i]=args[i]*10+*method-'0'; else if (++i<9) args[i]=0; ++method; } // "0..." = No compression if (type=='0') return "comp 0 0 0 0 0 hcomp end\n"; // Generate the postprocessor std::string hdr, pcomp; const int level=args[1]&3; const bool doe8=args[1]>=4 && args[1]<=7; // LZ77+Huffman, with or without E8E9 if (level==1) { const int rb=args[0]>4 ? args[0]-4 : 0; hdr="comp 9 16 0 $1+20 "; pcomp= "pcomp lazy2 3 ;\n" " (r1 = state\n" " r2 = len - match or literal length\n" " r3 = m - number of offset bits expected\n" " r4 = ptr to buf\n" " r5 = r - low bits of offset\n" " c = bits - input buffer\n" " d = n - number of bits in c)\n" "\n" " a> 255 if\n"; if (doe8) pcomp+= " b=0 d=r 4 do (for b=0..d-1, d = end of buf)\n" " a=b a==d ifnot\n" " a+= 4 a>= 8 b++\n" " *b=a a>>= 8 b++\n" " *b=a b++\n" " endif\n" " b=c\n" " endif\n" " endif\n" " a=*b out b++\n" " forever\n" " endif\n" "\n"; pcomp+= " (reset state)\n" " a=0 b=0 c=0 d=0 r=a 1 r=a 2 r=a 3 r=a 4\n" " halt\n" " endif\n" "\n" " a<<=d a+=c c=a (bits+=a< 0 if (if (bits&3))\n" " a-- a<<= 3 r=a 3 (m=((bits&3)-1)*8)\n" " a=c a>>= 2 c=a (bits>>=2)\n" " b=r 3 a&= 7 a+=b r=a 3 (m+=bits&7)\n" " a=c a>>= 3 c=a (bits>>=3)\n" " a=d a-= 5 d=a (n-=5)\n" " a= 1 r=a 1 (state=1)\n" " else (literal, discard 00)\n" " a=c a>>= 2 c=a (bits>>=2)\n" " d-- d-- (n-=2)\n" " a= 3 r=a 1 (state=3)\n" " endif\n" " endif\n" "\n" " (while state==1 && n>=3 (expect match length n*4+ll -> r2))\n" " do a=r 1 a== 1 if a=d a> 2 if\n" " a=c a&= 1 a== 1 if (if bits&1)\n" " a=c a>>= 1 c=a (bits>>=1)\n" " b=r 2 a=c a&= 1 a+=b a+=b r=a 2 (len+=len+(bits&1))\n" " a=c a>>= 1 c=a (bits>>=1)\n" " d-- d-- (n-=2)\n" " else\n" " a=c a>>= 1 c=a (bits>>=1)\n" " a=r 2 a<<= 2 b=a (len<<=2)\n" " a=c a&= 3 a+=b r=a 2 (len+=bits&3)\n" " a=c a>>= 2 c=a (bits>>=2)\n" " d-- d-- d-- (n-=3)\n"; if (rb) pcomp+=" a= 5 r=a 1 (state=5)\n"; else pcomp+=" a= 2 r=a 1 (state=2)\n"; pcomp+= " endif\n" " forever endif endif\n" "\n"; if (rb) pcomp+= // save r in r5 " (if state==5 && n>=8) (expect low bits of offset to put in r5)\n" " a=r 1 a== 5 if a=d a> "+itos(rb-1)+" if\n" " a=c a&= "+itos((1<>= "+itos(rb)+" c=a\n" " a=d a-= "+itos(rb)+ " d=a\n" " a= 2 r=a 1 (go to state 2)\n" " endif endif\n" "\n"; pcomp+= " (if state==2 && n>=m) (expect m offset bits)\n" " a=r 1 a== 2 if a=r 3 a>d ifnot\n" " a=c r=a 6 a=d r=a 7 (save c=bits, d=n in r6,r7)\n" " b=r 3 a= 1 a<<=b d=a (d=1< 0 if d--\n" " a=*c *b=a c++ b++ (buf[ptr++]-buf[p++])\n"; if (!doe8) pcomp+=" out\n"; pcomp+= " forever endif\n" " a=b r=a 4\n" "\n" " a=r 6 b=r 3 a>>=b c=a (bits>>=m)\n" " a=r 7 a-=b d=a (n-=m)\n" " a=0 r=a 1 (state=0)\n" " endif endif\n" "\n" " (while state==3 && n>=2 (expect literal length))\n" " do a=r 1 a== 3 if a=d a> 1 if\n" " a=c a&= 1 a== 1 if (if bits&1)\n" " a=c a>>= 1 c=a (bits>>=1)\n" " b=r 2 a&= 1 a+=b a+=b r=a 2 (len+=len+(bits&1))\n" " a=c a>>= 1 c=a (bits>>=1)\n" " d-- d-- (n-=2)\n" " else\n" " a=c a>>= 1 c=a (bits>>=1)\n" " d-- (--n)\n" " a= 4 r=a 1 (state=4)\n" " endif\n" " forever endif endif\n" "\n" " (if state==4 && n>=8 (expect len literals))\n" " a=r 1 a== 4 if a=d a> 7 if\n" " b=r 4 a=c *b=a\n"; if (!doe8) pcomp+=" out\n"; pcomp+= " b++ a=b r=a 4 (buf[ptr++]=bits)\n" " a=c a>>= 8 c=a (bits>>=8)\n" " a=d a-= 8 d=a (n-=8)\n" " a=r 2 a-- r=a 2 a== 0 if (if --len<1)\n" " a=0 r=a 1 (state=0)\n" " endif\n" " endif endif\n" " halt\n" "end\n"; } // Byte aligned LZ77, with or without E8E9 else if (level==2) { hdr="comp 9 16 0 $1+20 "; pcomp= "pcomp lzpre c ;\n" " (Decode LZ77: d=state, M=output buffer, b=size)\n" " a> 255 if (at EOF decode e8e9 and output)\n"; if (doe8) pcomp+= " d=b b=0 do (for b=0..d-1, d = end of buf)\n" " a=b a==d ifnot\n" " a+= 4 a>= 8 b++\n" " *b=a a>>= 8 b++\n" " *b=a b++\n" " endif\n" " b=c\n" " endif\n" " endif\n" " a=*b out b++\n" " forever\n" " endif\n"; pcomp+= " b=0 c=0 d=0 a=0 r=a 1 r=a 2 (reset state)\n" " halt\n" " endif\n" "\n" " (in state d==0, expect a new code)\n" " (put length in r1 and initial part of offset in r2)\n" " c=a a=d a== 0 if\n" " a=c a>>= 6 a++ d=a\n" " a== 1 if (literal?)\n" " a+=c r=a 1 a=0 r=a 2\n" " else (3 to 5 byte match)\n" " d++ a=c a&= 63 a+= $3 r=a 1 a=0 r=a 2\n" " endif\n" " else\n" " a== 1 if (writing literal)\n" " a=c *b=a b++\n"; if (!doe8) pcomp+=" out\n"; pcomp+= " a=r 1 a-- a== 0 if d=0 endif r=a 1 (if (--len==0) state=0)\n" " else\n" " a> 2 if (reading offset)\n" " a=r 2 a<<= 8 a|=c r=a 2 d-- (off=off<<8|c, --state)\n" " else (state==2, write match)\n" " a=r 2 a<<= 8 a|=c c=a a=b a-=c a-- c=a (c=i-off-1)\n" " d=r 1 (d=len)\n" " do (copy and output d=len bytes)\n" " a=*c *b=a c++ b++\n"; if (!doe8) pcomp+=" out\n"; pcomp+= " d-- a=d a> 0 while\n" " (d=state=0. off, len don\'t matter)\n" " endif\n" " endif\n" " endif\n" " halt\n" "end\n"; } // BWT with or without E8E9 else if (level==3) { // IBWT hdr="comp 9 16 $1+20 $1+20 "; // 2^$1 = block size in MB pcomp= "pcomp bwtrle c ;\n" "\n" " (read BWT, index into M, size in b)\n" " a> 255 ifnot\n" " *b=a b++\n" "\n" " (inverse BWT)\n" " elsel\n" "\n" " (index in last 4 bytes, put in c and R1)\n" " b-- a=*b\n" " b-- a<<= 8 a+=*b\n" " b-- a<<= 8 a+=*b\n" " b-- a<<= 8 a+=*b c=a r=a 1\n" "\n" " (save size in R2)\n" " a=b r=a 2\n" "\n" " (count bytes in H[~1..~255, ~0])\n" " do\n" " a=b a> 0 if\n" " b-- a=*b a++ a&= 255 d=a d! *d++\n" " forever\n" " endif\n" "\n" " (cumulative counts: H[~i=0..255] = count of bytes before i)\n" " d=0 d! *d= 1 a=0\n" " do\n" " a+=*d *d=a d--\n" " d<>a a! a> 255 a! d<>a until\n" "\n" " (build first part of linked list in H[0..idx-1])\n" " b=0 do\n" " a=c a>b if\n" " d=*b d! *d++ d=*d d-- *d=b\n" " b++ forever\n" " endif\n" "\n" " (rest of list in H[idx+1..n-1])\n" " b=c b++ c=r 2 do\n" " a=c a>b if\n" " d=*b d! *d++ d=*d d-- *d=b\n" " b++ forever\n" " endif\n" "\n"; if (args[0]<=4) { // faster IBWT list traversal limited to 16 MB blocks pcomp+= " (copy M to low 8 bits of H to reduce cache misses in next loop)\n" " b=0 do\n" " a=c a>b if\n" " d=b a=*d a<<= 8 a+=*b *d=a\n" " b++ forever\n" " endif\n" "\n" " (traverse list and output or copy to M)\n" " d=r 1 b=0 do\n" " a=d a== 0 ifnot\n" " a=*d a>>= 8 d=a\n"; if (doe8) pcomp+=" *b=*d b++\n"; else pcomp+=" a=*d out\n"; pcomp+= " forever\n" " endif\n" "\n"; if (doe8) // IBWT+E8E9 pcomp+= " (e8e9 transform to out)\n" " d=b b=0 do (for b=0..d-1, d = end of buf)\n" " a=b a==d ifnot\n" " a+= 4 a>= 8 b++\n" " *b=a a>>= 8 b++\n" " *b=a b++\n" " endif\n" " b=c\n" " endif\n" " endif\n" " a=*b out b++\n" " forever\n" " endif\n"; pcomp+= " endif\n" " halt\n" "end\n"; } else { // slower IBWT list traversal for all sized blocks if (doe8) { // E8E9 after IBWT pcomp+= " (R2 = output size without EOS)\n" " a=r 2 a-- r=a 2\n" "\n" " (traverse list (d = IBWT pointer) and output inverse e8e9)\n" " (C = offset = 0..R2-1)\n" " (R4 = last 4 bytes shifted in from MSB end)\n" " (R5 = temp pending output byte)\n" " c=0 d=r 1 do\n" " a=d a== 0 ifnot\n" " d=*d\n" "\n" " (store byte in R4 and shift out to R5)\n" " b=d a=*b a<<= 24 b=a\n" " a=r 4 r=a 5 a>>= 8 a|=b r=a 4\n" "\n" " (if E8|E9 xx xx xx 00|FF in R4:R5 then subtract c from x)\n" " a=c a> 3 if\n" " a=r 5 a&= 254 a== 232 if\n" " a=r 4 a>>= 24 b=a a++ a&= 254 a< 2 if\n" " a=r 4 a-=c a+= 4 a<<= 8 a>>= 8 \n" " b<>a a<<= 24 a+=b r=a 4\n" " endif\n" " endif\n" " endif\n" "\n" " (output buffered byte)\n" " a=c a> 3 if a=r 5 out endif c++\n" "\n" " forever\n" " endif\n" "\n" " (output up to 4 pending bytes in R4)\n" " b=r 4\n" " a=c a> 3 a=b if out endif a>>= 8 b=a\n" " a=c a> 2 a=b if out endif a>>= 8 b=a\n" " a=c a> 1 a=b if out endif a>>= 8 b=a\n" " a=c a> 0 a=b if out endif\n" "\n" " endif\n" " halt\n" "end\n"; } else { pcomp+= " (traverse list and output)\n" " d=r 1 do\n" " a=d a== 0 ifnot\n" " d=*d\n" " b=d a=*b out\n" " forever\n" " endif\n" " endif\n" " halt\n" "end\n"; } } } // E8E9 or no preprocessing else if (level==0) { hdr="comp 9 16 0 0 "; if (doe8) { // E8E9? pcomp= "pcomp e8e9 d ;\n" " a> 255 if\n" " a=c a> 4 if\n" " c= 4\n" " else\n" " a! a+= 5 a<<= 3 d=a a=b a>>=d b=a\n" " endif\n" " do a=c a> 0 if\n" " a=b out a>>= 8 b=a c--\n" " forever endif\n" " else\n" " *b=b a<<= 24 d=a a=b a>>= 8 a+=d b=a c++\n" " a=c a> 4 if\n" " a=*b out\n" " a&= 254 a== 232 if\n" " a=b a>>= 24 a++ a&= 254 a== 0 if\n" " a=b a>>= 24 a<<= 24 d=a\n" " a=b a-=c a+= 5\n" " a<<= 8 a>>= 8 a|=d b=a\n" " endif\n" " endif\n" " endif\n" " endif\n" " halt\n" "end\n"; } else pcomp="end\n"; } else error("Unsupported method"); // Build context model (comp, hcomp) assuming: // H[0..254] = contexts // H[255..511] = location of last byte i-255 // M = last 64K bytes, filling backward // C = pointer to most recent byte // R1 = level 2 lz77 1+bytes expected until next code, 0=init // R2 = level 2 lz77 first byte of code int ncomp=0; // number of components const int membits=args[0]+20; int sb=5; // bits in last context std::string comp; std::string hcomp="hcomp\n" "c-- *c=a a+= 255 d=a *d=c\n"; if (level==2) { // put level 2 lz77 parse state in R1, R2 hcomp+= " (decode lz77 into M. Codes:\n" " 00xxxxxx = literal length xxxxxx+1\n" " xx......, xx > 0 = match with xx offset bytes to follow)\n" "\n" " a=r 1 a== 0 if (init)\n" " a= "+itos(111+57*doe8)+" (skip post code)\n" " else a== 1 if (new code?)\n" " a=*c r=a 2 (save code in R2)\n" " a> 63 if a>>= 6 a++ a++ (match)\n" " else a++ a++ endif (literal)\n" " else (read rest of code)\n" " a--\n" " endif endif\n" " r=a 1 (R1 = 1+expected bytes to next code)\n"; } // Generate the context model while (*method && ncomp<254) { // parse command C[N1[,N2]...] into v = {C, N1, N2...} std::vector v; v.push_back(*method++); if (isdigit(*method)) { v.push_back(*method++-'0'); while (isdigit(*method) || *method==',' || *method=='.') { if (isdigit(*method)) v.back()=v.back()*10+*method++-'0'; else { v.push_back(0); ++method; } } } // c: context model // N1%1000: 0=ICM 1..256=CM limit N1-1 // N1/1000: number of times to halve memory // N2: 1..255=offset mod N2. 1000..1255=distance to N2-1000 // N3...: 0..255=byte mask + 256=lz77 state. 1000+=run of N3-1000 zeros. if (v[0]=='c') { while (v.size()<3) v.push_back(0); comp+=itos(ncomp)+" "; sb=11; // count context bits if (v[2]<256) sb+=lg(v[2]); else sb+=6; for (unsigned i=3; imembits) sb=membits; if (v[1]%1000==0) comp+="icm "+itos(sb-6-v[1]/1000)+"\n"; else comp+="cm "+itos(sb-2-v[1]/1000)+" "+itos(v[1]%1000-1)+"\n"; // special contexts hcomp+="d= "+itos(ncomp)+" *d=0\n"; if (v[2]>1 && v[2]<=255) { // periodic context if (lg(v[2])!=lg(v[2]-1)) hcomp+="a=c a&= "+itos(v[2]-1)+" hashd\n"; else hcomp+="a=c a%= "+itos(v[2])+" hashd\n"; } else if (v[2]>=1000 && v[2]<=1255) // distance context hcomp+="a= 255 a+= "+itos(v[2]-1000)+ " d=a a=*d a-=c a> 255 if a= 255 endif d= "+ itos(ncomp)+" hashd\n"; // Masked context for (unsigned i=3; i0 && v[i]<255) hcomp+="a=*b a&= "+itos(v[i])+" hashd\n"; // masked byte else if (v[i]>=256 && v[i]<512) { // lz77 state or masked literal byte hcomp+= "a=r 1 a> 1 if\n" // expect literal or offset " a=r 2 a< 64 if\n" // expect literal " a=*b "; if (v[i]<511) hcomp+="a&= "+itos(v[i]-256); hcomp+=" hashd\n" " else\n" // expect match offset byte " a>>= 6 hashd a=r 1 hashd\n" " endif\n" "else\n" // expect new code " a= 255 hashd a=r 2 hashd\n" "endif\n"; } else if (v[i]>=1256) // skip v[i]-1000 bytes hcomp+="a= "+itos(((v[i]-1000)>>8)&255)+" a<<= 8 a+= " +itos((v[i]-1000)&255)+ " a+=b b=a\n"; else if (v[i]>1000) hcomp+="a= "+itos(v[i]-1000)+" a+=b b=a\n"; /// if (v[i]<512 && iint(v[0]=='t')) { if (v.size()<=1) v.push_back(8); if (v.size()<=2) v.push_back(24+8*(v[0]=='s')); if (v[0]=='s' && v.size()<=3) v.push_back(255); comp+=itos(ncomp); sb=5+v[1]*3/4; if (v[0]=='m') comp+=" mix "+itos(v[1])+" 0 "+itos(ncomp)+" "+itos(v[2])+" 255\n"; else if (v[0]=='t') comp+=" mix2 "+itos(v[1])+" "+itos(ncomp-1)+" "+itos(ncomp-2) +" "+itos(v[2])+" 255\n"; else // s comp+=" sse "+itos(v[1])+" "+itos(ncomp-1)+" "+itos(v[2])+" " +itos(v[3])+"\n"; if (v[1]>8) { hcomp+="d= "+itos(ncomp)+" *d=0 b=c a=0\n"; for (; v[1]>=16; v[1]-=8) { hcomp+="a<<= 8 a+=*b"; if (v[1]>16) hcomp+=" b++"; hcomp+="\n"; } if (v[1]>8) hcomp+="a<<= 8 a+=*b a>>= "+itos(16-v[1])+"\n"; hcomp+="a<<= 8 *d=a\n"; } ++ncomp; } // i: ISSE chain with order increasing by N1,N2... if (v[0]=='i' && ncomp>0) { assert(sb>=5); hcomp+="d= "+itos(ncomp-1)+" b=c a=*d d++\n"; for (unsigned i=1; imembits) sb=membits; comp+=itos(ncomp)+" isse "+itos(sb-6-v[i]/10)+" "+itos(ncomp-1)+"\n"; ++ncomp; } } // a24,0,0: MATCH. N1=hash multiplier. N2,N3=halve buf, table. if (v[0]=='a') { if (v.size()<=1) v.push_back(24); while (v.size()<4) v.push_back(0); comp+=itos(ncomp)+" match "+itos(membits-v[3]-2)+" " +itos(membits-v[2])+"\n"; hcomp+="d= "+itos(ncomp)+" a=*d a*= "+itos(v[1]) +" a+=*c a++ *d=a\n"; sb=5+(membits-v[2])*3/4; ++ncomp; } // w1,65,26,223,20,0: ICM-ISSE chain of length N1 with word contexts, // where a word is a sequence of c such that c&N4 is in N2..N2+N3-1. // Word is hashed by: hash := hash*N5+c+1 // Decrease memory by 2^-N6. if (v[0]=='w') { if (v.size()<=1) v.push_back(1); if (v.size()<=2) v.push_back(65); if (v.size()<=3) v.push_back(26); if (v.size()<=4) v.push_back(223); if (v.size()<=5) v.push_back(20); if (v.size()<=6) v.push_back(0); comp+=itos(ncomp)+" icm "+itos(membits-6-v[6])+"\n"; for (int i=1; i0; --i) hcomp+=" d= "+itos(ncomp+i-1)+" a=*d d++ *d=a\n"; hcomp+=" d= "+itos(ncomp)+" *d=0\n" "endif\n"; ncomp+=v[1]-1; sb=membits-v[6]; ++ncomp; } } return hdr+itos(ncomp)+"\n"+comp+hcomp+"halt\n"+pcomp; } // Compress from in to out in 1 segment in 1 block using the algorithm // descried in method. If method begins with a digit then choose // a method depending on type. Save filename and comment // in the segment header. If comment is 0 then the default is the input size // as a decimal string, plus " jDC\x01" for a journaling method (method[0] // is not 's'). Write the generated method to methodOut if not 0. void compressBlock(StringBuffer* in, Writer* out, const char* method_, const char* filename, const char* comment, bool dosha1) { assert(in); assert(out); assert(method_); assert(method_[0]); std::string method=method_; const unsigned n=in->size(); // input size const int arg0=MAX(lg(n+4095)-20, 0); // block size assert((1u<<(arg0+20))>=n+4096); // Get type from method "LB,R,t" where L is level 0..5, B is block // size 0..11, R is redundancy 0..255, t = 0..3 = binary, text, exe, both. unsigned type=0; if (isdigit(method[0])) { int commas=0, arg[4]={0}; for (int i=1; ic_str(), n); sha1ptr=sha1.result(); } // Expand default methods if (isdigit(method[0])) { const int level=method[0]-'0'; assert(level>=0 && level<=9); // build models const int doe8=(type&2)*2; method="x"+itos(arg0); std::string htsz=","+itos(19+arg0+(arg0<=6)); // lz77 hash table size std::string sasz=","+itos(21+arg0); // lz77 suffix array size // store uncompressed if (level==0) method="0"+itos(arg0)+",0"; // LZ77, no model. Store if hard to compress else if (level==1) { if (type<40) method+=",0"; else { method+=","+itos(1+doe8)+","; if (type<80) method+="4,0,1,15"; else if (type<128) method+="4,0,2,16"; else if (type<256) method+="4,0,2"+htsz; else if (type<960) method+="5,0,3"+htsz; else method+="6,0,3"+htsz; } } // LZ77 with longer search else if (level==2) { if (type<32) method+=",0"; else { method+=","+itos(1+doe8)+","; if (type<64) method+="4,0,3"+htsz; else method+="4,0,7"+sasz+",1"; } } // LZ77 with CM depending on redundancy else if (level==3) { if (type<20) // store if not compressible method+=",0"; else if (type<48) // fast LZ77 if barely compressible method+=","+itos(1+doe8)+",4,0,3"+htsz; else if (type>=640 || (type&1)) // BWT if text or highly compressible method+=","+itos(3+doe8)+"ci1"; else // LZ77 with O0-1 compression of up to 12 literals method+=","+itos(2+doe8)+",12,0,7"+sasz+",1c0,0,511i2"; } // LZ77+CM, fast CM, or BWT depending on type else if (level==4) { if (type<12) method+=",0"; else if (type<24) method+=","+itos(1+doe8)+",4,0,3"+htsz; else if (type<48) method+=","+itos(2+doe8)+",5,0,7"+sasz+"1c0,0,511"; else if (type<900) { method+=","+itos(doe8)+"ci1,1,1,1,2a"; if (type&1) method+="w"; method+="m"; } else method+=","+itos(3+doe8)+"ci1"; } // Slow CM with lots of models else { // 5..9 // Model text files method+=","+itos(doe8); if (type&1) method+="w2c0,1010,255i1"; else method+="w1i1"; method+="c256ci1,1,1,1,1,1,2a"; // Analyze the data const int NR=1<<12; int pt[256]={0}; // position of last occurrence int r[NR]={0}; // count repetition gaps of length r const unsigned char* p=in->data(); if (level>0) { for (unsigned i=0; i0 && kscore) score=s, period=j; t+=r[j]; } if (period>4 && score>0.1) { method+="c0,0,"+itos(999+period)+",255i1"; if (period<=255) method+="c0,"+itos(period)+"i1"; n1-=r[period]; r[period]=0; } else break; } method+="c0,2,0,255i1c0,3,0,0,255i1c0,4,0,0,0,255i1mm16ts19t0"; } } // Compress std::string config; int args[9]={0}; config=makeConfig(method.c_str(), args); assert(n<=(0x100000u<=1 && args[1]<=7 && args[1]!=4) { // LZ77 or BWT LZBuffer lz(*in, args); co.setInput(&lz); co.compress(); } else { // compress with e8e9 or no preprocessing if (args[1]>=4 && args[1]<=7) e8e9(in->data(), in->size()); co.setInput(in); co.compress(); } #ifdef DEBUG // verify pre-post processing are inverses int64_t outsize; const char* sha1result=co.endSegmentChecksum(&outsize, dosha1); assert(sha1result); assert(sha1ptr); if (memcmp(sha1result, sha1ptr, 20)!=0) error("Pre/post-processor test failed"); #else co.endSegment(sha1ptr); #endif // corresponds to #ifdef (#ifdef DEBUG // verify pre-post processing are inverses) co.endBlock(); } } // end namespace libzpaq /////// main source using std::string; using std::vector; using std::map; using libzpaq::StringBuffer; int unz(const char * archive,const char * key); // paranoid unzpaq 2.06 typedef string (*voidhelpfunction)(bool i_usage,bool i_example); typedef map MAPPAHELP; typedef map MAPPACOMMENTI; typedef map MAPPAFILEHASH; typedef map MAPPASTRINGASTRINGA; typedef map MAPPAINT64STRING; typedef map MAPPASTRINGINTEGER; typedef map MAPPAINTINT; struct hash_check { int algotype; int checkedok; int checkedfailed; int checkednotfound; int64_t checksize; hash_check(): algotype(0), checkedok(0),checkedfailed(0),checkednotfound(0),checksize(0) {}; }; typedef map MAPPACHECK; struct hash_autocheck { string ok; string calculated; hash_autocheck() {ok="";calculated="";}; }; typedef map MAPPAAUTOCHECK; struct s_crc32block { string filename; uint64_t crc32start; uint64_t crc32size; uint32_t crc32; s_crc32block(): crc32start(0),crc32size(0),crc32(0) {} }; struct s_error { int counter; string text; vector filenames; vector attrs; s_error(): counter(0) {text="";} }; typedef map MAPPAERRORS; /// Global variables /// not in for pthread that does not like class and methods pthread_mutex_t g_mylock = PTHREAD_MUTEX_INITIALIZER; vector g_crc32; vector g_arraybytescanned; vector g_arrayfilescanned; MAPPAERRORS g_errors; #ifdef _WIN32 ///bool flagdd; bool flagfindzpaq; bool flagfixreserved; bool flagimage; bool flaglongpath; bool flagopen; int g_ConsoleCP; int g_ConsoleOutputCP; #endif // corresponds to #ifdef (#ifdef _WIN32) bool flagbarraod; bool flagbarraon; bool flagbarraos; vector g_addedchunklist; int g_franzotype; int g_franzotypelen; string g_optional; string orderby; vector g_theorderby; int g_ioBUFSIZE=1048576; int g_thechosenhash; string g_thechosenhash_str; void seppuku() { if (g_output_handle) fclose(g_output_handle); if (g_error_handle) fclose(g_error_handle); color_restore(); exit(0); } bool ihavehw() { #ifndef HWSHA2 return false; #endif // corresponds to #ifndef (#ifndef HWSHA2) uint32_t a=0,b=0,c=0,d=0; getcpuid(0,0,a,b,c,d); if (a<7) { myprintf("00001! cpuid cannot get at least EAX 7\n"); return false; } bool supported_ssse3 =false; bool supported_sse41 =false; bool supported_sha =false; getcpuid(1,0,a,b,c,d); supported_ssse3 =(c & (1UL << 9)); supported_sse41 =(c & (1UL << 19)); if (flagdebug3) myprintf("00002: new ecx %d\n",(int)c); getcpuid(7,0,a,b,c,d); supported_sha =(b & (1UL << 29)); if (flagdebug3) myprintf("00003: new ebx %d\n",(int)b); if (flagdebug) { myprintf("00004: SSSE3 :"); if (supported_ssse3) myprintf("OK\n"); else myprintf("NO\n"); myprintf("00005: SSE41 :"); if (supported_sse41) myprintf("OK\n"); else myprintf("NO\n"); myprintf("00006: SHA :"); if (supported_sha) myprintf("OK\n"); else myprintf("NO\n"); } return supported_ssse3 && supported_sse41 && supported_sha; } string print_datetime(bool i_flagout) { int hours, minutes, seconds, day, month, year; time_t nowz; time(&nowz); const struct tm *local = localtime(&nowz); if (local==NULL) { myprintf("00007! guru on tm\n"); exit(0); } hours = local->tm_hour; minutes = local->tm_min; seconds = local->tm_sec; day = local->tm_mday; month = local->tm_mon + 1; year = local->tm_year + 1900; char buffer[40]; snprintf(buffer,sizeof(buffer),"%02d/%02d/%d %02d:%02d:%02d ", day, month, year, hours,minutes,seconds); if (i_flagout) myprintf("%s",buffer); return buffer; } typedef map MAPPAFLAGS; typedef map HELPFLAGS; /* Section: hashers */ bool isdirectory(const string i_filename) { if (i_filename.length()==0) return false; else return i_filename[i_filename.size()-1]=='/'; } typedef string (*finalize_function)(void*); // type for conciseness struct tipohash { string hashname; string switchname; string hashdescription; string franzocode; string hasherror; int hashlen; bool* switchflag; bool flagiszpaq; bool flagisbenchmark; int checkedok; int checkedfailed; int checkednotfound; int64_t checksize; finalize_function ffinalize; tipohash(const string& i_hashname,int i_hashlen, const string& i_hashdescription,bool i_iszpaq,const string& i_switchname,bool* i_switchflag,finalize_function i_finalize,string i_franzcode): franzocode(""),switchflag(NULL),flagiszpaq(i_iszpaq),flagisbenchmark(false), checkedok(0),checkedfailed(0),checkednotfound(0),checksize(0) { hashname =i_hashname; hashdescription =i_hashdescription; switchname =i_switchname; switchflag =i_switchflag; if (i_finalize==NULL) { myprintf("00008! i_finalize NULL! %s\n",i_hashname.c_str()); } ffinalize =i_finalize; hashlen =i_hashlen; franzocode =""; if (i_franzcode.size()==2) franzocode=std::string()+ i_franzcode[0]+i_franzcode[1]; hasherror="!ERROR!"; while (hasherror.size()<(unsigned int)i_hashlen) hasherror+=' '; } void resetcheckstat() { checkedok=0; checkedfailed=0; checkednotfound=0; checksize=0; } }; typedef std::map MAPPATIPOHASH; MAPPATIPOHASH g_mappatipohash; tipohash* franz_get_hash(const string& i_hashstring) { for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (i_hashstring==p->second.hashname) return &p->second; return NULL; } string binarytohex(const unsigned char* i_risultato,const int i_lunghezza) { if ((i_risultato==NULL) || (i_lunghezza<=0)) return ""; /// slow, and dirty string risultato=""; char myhex[4]; if (i_lunghezza>0) for (int j=0;jsecond.flagiszpaq) { string temp="13888: franzotype does not seems iszpaq "+myto_string(franzotype); perror(temp.c_str()); return ""; } return p->second.hashname; } string decodefranzoffset(int franzotype) { if (franzotype==FRANZO_NONE) return "NOTHING (LIKE 7.15)"; if (franzotype==FRANZO_CRC_32) return "CRC-32"; MAPPATIPOHASH::iterator p=g_mappatipohash.find(franzotype); if (p==g_mappatipohash.end()) { string temp="16839: franzotype strange "+myto_string(franzotype); perror(temp.c_str()); return ""; } if (!p->second.flagiszpaq) { string temp="09603: franzotype does not seems iszpaq "+myto_string(franzotype); perror(temp.c_str()); return ""; } return p->second.hashname+"+CRC-32"; } string emptyalgo(const string& i_string) { if (i_string=="BLAKE3") return "AF1349B9F5F9A1A6A0404DEA36DCC9499BCB25C9ADC112B7CC9A93CAE41F3262"; else if (i_string=="BLAKE3B") return "AF1349B9F5F9A1A6A0404DEA36DCC9499BCB25C9ADC112B7CC9A93CAE41F3262"; else if (i_string=="QUICK") return "EF46DB3751D8E999"; else if (i_string=="XXHASH64") return "EF46DB3751D8E999"; else if (i_string=="WINHASH64") return "EF46DB3751D8E999"; else if (i_string=="XXHASH64B") return "EF46DB3751D8E999"; else if (i_string=="WYHASH") return ""; else if (i_string=="CRC-32") return "00000000"; else if (i_string=="ENTROPY") return "00000000"; else if (i_string=="CRC-32C") return "00000000"; else if (i_string=="XXH3") return "99AA06D3014798D86001C324468D497F"; else if (i_string=="XXH3B") return "99AA06D3014798D86001C324468D497F"; else if (i_string=="SHA-256") return "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"; else if (i_string=="SHA-256B") return "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855"; else if (i_string=="WHIRLPOOL") return "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3"; else if (i_string=="MD5") return "D41D8CD98F00B204E9800998ECF8427E"; else if (i_string=="MD5B") return "D41D8CD98F00B204E9800998ECF8427E"; else if (i_string=="NILSIMSA") return "VUOTO"; else if (i_string=="HIGHWAY64") return "92943A34E3447FAA"; else if (i_string=="HIGHWAY128") return "D39FAE4F2222AD3611D8E8215B1B01F2"; else if (i_string=="HIGHWAY256") return "D6EB09DBE820BC5A8050209986CEDE586E78E6815864E99DC22811C2FCFE001B"; else if (i_string=="ZETA") return "0000000000000000"; else if (i_string=="ZETAENC") return "0000000000000000"; else if (i_string=="SHA-3") return "A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A"; else if (i_string=="SHA-3B") return "A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A"; else return "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"; //sha1 } /// LICENSE_START.8 /* Experimental "antihash" function: sort "similar" files */ /*! * The MIT License (MIT) * ===================== * * Copyright 2017 Sepehr Laal * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /*! * @fn nilsimsa_compute * @brief computes the Nilsimsa hash of the given data. * @arg data [IN] input data byte (char) array * @arg size [IN] input data size * @arg out [OUT] output hash string (must be allocated * to hold exactly 64 characters + 1 null character. So * total of 65 characters e.g. char hash[65]) */ void nilsimsa_compute(const char* data, int size, char* out); /*! * @fn nilsimsa_compare * @brief compares two given Nilsimsa hashes * @returns A score between -127 and 128 where -127 means * completely uncorrelated data and 128 means same data. * @arg lhs [IN] left hand side hash * @arg rhs [IN] right hand side hash */ static int __tran3(int a, int b, int c, int n); static const char* __int_to_hexchar(int num); #define ACCUM_LENGTH 256 #define DIGEST_LENGTH 32 #define WINDOW_LENGTH 4 void nilsimsa_compute(const char* data, int n, char* out) { int accum[ACCUM_LENGTH] = { 0 }; int digest[DIGEST_LENGTH] = { 0 }; int window[WINDOW_LENGTH] = { -1, -1, -1, -1 }; for (int i = 0; i < n; ++i) { int ch = data[i] & 0xFF; if (window[1] > -1) { accum[__tran3(ch, window[0], window[1], 0)] += 1; } if (window[2] > -1) { accum[__tran3(ch, window[0], window[2], 1)] += 1; accum[__tran3(ch, window[1], window[2], 2)] += 1; } if (window[3] > -1) { accum[__tran3(ch, window[0], window[3], 3)] += 1; accum[__tran3(ch, window[1], window[3], 4)] += 1; accum[__tran3(ch, window[2], window[3], 5)] += 1; accum[__tran3(window[3], window[0], ch, 6)] += 1; accum[__tran3(window[3], window[2], ch, 7)] += 1; } window[3] = window[2]; window[2] = window[1]; window[1] = window[0]; window[0] = ch; } int total = 0; if (n == 3) total = 1; else if (n == 4) total = 4; else if (n > 4) total = 8 * n - 28; int threshold = total / ACCUM_LENGTH; for (int i = 0; i < ACCUM_LENGTH; i++) if (accum[i] > threshold) digest[i >> 3] += 1 << (i & 7); int rev_index; for (int i = 0; i < DIGEST_LENGTH; ++i) { rev_index = DIGEST_LENGTH - i - 1; out[2*i ] = __int_to_hexchar(digest[rev_index])[0]; out[2*i+1] = __int_to_hexchar(digest[rev_index])[1]; } out[2 * DIGEST_LENGTH] = '\0'; } // This is a precomputed constant for the standard Nilsimsa "53"-based transition table. static const int __TRAN53[] = { 0x02, 0xD6, 0x9E, 0x6F, 0xF9, 0x1D, 0x04, 0xAB, 0xD0, 0x22, 0x16, 0x1F, 0xD8, 0x73, 0xA1, 0xAC, 0x3B, 0x70, 0x62, 0x96, 0x1E, 0x6E, 0x8F, 0x39, 0x9D, 0x05, 0x14, 0x4A, 0xA6, 0xBE, 0xAE, 0x0E, 0xCF, 0xB9, 0x9C, 0x9A, 0xC7, 0x68, 0x13, 0xE1, 0x2D, 0xA4, 0xEB, 0x51, 0x8D, 0x64, 0x6B, 0x50, 0x23, 0x80, 0x03, 0x41, 0xEC, 0xBB, 0x71, 0xCC, 0x7A, 0x86, 0x7F, 0x98, 0xF2, 0x36, 0x5E, 0xEE, 0x8E, 0xCE, 0x4F, 0xB8, 0x32, 0xB6, 0x5F, 0x59, 0xDC, 0x1B, 0x31, 0x4C, 0x7B, 0xF0, 0x63, 0x01, 0x6C, 0xBA, 0x07, 0xE8, 0x12, 0x77, 0x49, 0x3C, 0xDA, 0x46, 0xFE, 0x2F, 0x79, 0x1C, 0x9B, 0x30, 0xE3, 0x00, 0x06, 0x7E, 0x2E, 0x0F, 0x38, 0x33, 0x21, 0xAD, 0xA5, 0x54, 0xCA, 0xA7, 0x29, 0xFC, 0x5A, 0x47, 0x69, 0x7D, 0xC5, 0x95, 0xB5, 0xF4, 0x0B, 0x90, 0xA3, 0x81, 0x6D, 0x25, 0x55, 0x35, 0xF5, 0x75, 0x74, 0x0A, 0x26, 0xBF, 0x19, 0x5C, 0x1A, 0xC6, 0xFF, 0x99, 0x5D, 0x84, 0xAA, 0x66, 0x3E, 0xAF, 0x78, 0xB3, 0x20, 0x43, 0xC1, 0xED, 0x24, 0xEA, 0xE6, 0x3F, 0x18, 0xF3, 0xA0, 0x42, 0x57, 0x08, 0x53, 0x60, 0xC3, 0xC0, 0x83, 0x40, 0x82, 0xD7, 0x09, 0xBD, 0x44, 0x2A, 0x67, 0xA8, 0x93, 0xE0, 0xC2, 0x56, 0x9F, 0xD9, 0xDD, 0x85, 0x15, 0xB4, 0x8A, 0x27, 0x28, 0x92, 0x76, 0xDE, 0xEF, 0xF8, 0xB2, 0xB7, 0xC9, 0x3D, 0x45, 0x94, 0x4B, 0x11, 0x0D, 0x65, 0xD5, 0x34, 0x8B, 0x91, 0x0C, 0xFA, 0x87, 0xE9, 0x7C, 0x5B, 0xB1, 0x4D, 0xE5, 0xD4, 0xCB, 0x10, 0xA2, 0x17, 0x89, 0xBC, 0xDB, 0xB0, 0xE2, 0x97, 0x88, 0x52, 0xF7, 0x48, 0xD3, 0x61, 0x2C, 0x3A, 0x2B, 0xD1, 0x8C, 0xFB, 0xF1, 0xCD, 0xE4, 0x6A, 0xE7, 0xA9, 0xFD, 0xC4, 0x37, 0xC8, 0xD2, 0xF6, 0xDF, 0x58, 0x72, 0x4E }; /* * Used to convert integers to 1-byte hex strings * Integers in between the range of 0 and 256. */ static const char* __HEX_BYTE_DIGITS[] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" }; static int __tran3(int a, int b, int c, int n) { return (((__TRAN53[(a + n) & 255] ^ __TRAN53[b] * (n + n + 1)) + __TRAN53[c ^ __TRAN53[n]]) & 255); } static const char* __int_to_hexchar(int num) { return __HEX_BYTE_DIGITS[num]; } /// LICENSE_END.8 /// LICENSE_START.18 /// This is a (minor) rework of https://github.com/google/highwayhash/tree/master/c /* By Jan Wassenberg jan.wassenberg@gmail.com and Jyrki Alakuijala jyrki.alakuijala@gmail.com This is not an official Google product. */ /*////////////////////////////////////////////////////////////////////////////*/ /* Low-level API, use for implementing streams etc... */ /*////////////////////////////////////////////////////////////////////////////*/ typedef struct { uint64_t v0[4]; uint64_t v1[4]; uint64_t mul0[4]; uint64_t mul1[4]; } HighwayHashState; /* Initializes state with given key */ static void HighwayHashReset(const uint64_t key[4], HighwayHashState* state); /* Takes a packet of 32 bytes */ void HighwayHashUpdatePacket(const uint8_t* packet, HighwayHashState* state); /* Adds the final 1..31 bytes, do not use if 0 remain */ void HighwayHashUpdateRemainder(const uint8_t* bytes, const size_t size_mod32, HighwayHashState* state); /* Compute final hash value. Makes state invalid. */ static uint64_t HighwayHashFinalize64(HighwayHashState* state); static void HighwayHashFinalize128(HighwayHashState* state, uint64_t hash[2]); static void HighwayHashFinalize256(HighwayHashState* state, uint64_t hash[4]); /*////////////////////////////////////////////////////////////////////////////*/ /* Non-cat API: single call on full data */ /*////////////////////////////////////////////////////////////////////////////*/ /*////////////////////////////////////////////////////////////////////////////*/ /* Cat API: allows appending with multiple calls */ /*////////////////////////////////////////////////////////////////////////////*/ typedef struct { HighwayHashState state; uint8_t packet[32]; int num; } HighwayHashCat; /* Allocates new state for a new streaming hash computation */ void HighwayHashCatStart(const uint64_t key[4], HighwayHashCat* state); void HighwayHashCatAppend(const uint8_t* bytes, size_t num, HighwayHashCat* state); /* Computes final hash value */ uint64_t HighwayHashCatFinish64(const HighwayHashCat* state); void HighwayHashCatFinish128(const HighwayHashCat* state, uint64_t hash[2]); void HighwayHashCatFinish256(const HighwayHashCat* state, uint64_t hash[4]); /* This code is compatible with C90 with the additional requirement of supporting uint64_t. */ /*////////////////////////////////////////////////////////////////////////////*/ /* Internal implementation */ /*////////////////////////////////////////////////////////////////////////////*/ /// this is a weird "fix" for gcc bug https://github.com/fcorbelli/zpaqfranz/issues/71 /// please don't ask anything, took a couple of hours void fixgcc(const char* fmt, ...) { va_list args; va_start(args, fmt); va_end(args); } void HighwayHashReset(const uint64_t key[4], HighwayHashState* state) { state->mul0[0] = 0xdbe6d5d5fe4cce2full; state->mul0[1] = 0xa4093822299f31d0ull; state->mul0[2] = 0x13198a2e03707344ull; state->mul0[3] = 0x243f6a8885a308d3ull; state->mul1[0] = 0x3bd39e10cb0ef593ull; state->mul1[1] = 0xc0acf169b5f18a8cull; state->mul1[2] = 0xbe5466cf34e90c6cull; state->mul1[3] = 0x452821e638d01377ull; state->v0[0] = state->mul0[0] ^ key[0]; state->v0[1] = state->mul0[1] ^ key[1]; state->v0[2] = state->mul0[2] ^ key[2]; state->v0[3] = state->mul0[3] ^ key[3]; state->v1[0] = state->mul1[0] ^ ((key[0] >> 32) | (key[0] << 32)); state->v1[1] = state->mul1[1] ^ ((key[1] >> 32) | (key[1] << 32)); state->v1[2] = state->mul1[2] ^ ((key[2] >> 32) | (key[2] << 32)); fixgcc("ciao"); state->v1[3] = state->mul1[3] ^ ((key[3] >> 32) | (key[3] << 32)); } static void ZipperMergeAndAdd(const uint64_t v1, const uint64_t v0, uint64_t* add1, uint64_t* add0) { *add0 += (((v0 & 0xff000000ull) | (v1 & 0xff00000000ull)) >> 24) | (((v0 & 0xff0000000000ull) | (v1 & 0xff000000000000ull)) >> 16) | (v0 & 0xff0000ull) | ((v0 & 0xff00ull) << 32) | ((v1 & 0xff00000000000000ull) >> 8) | (v0 << 56); *add1 += (((v1 & 0xff000000ull) | (v0 & 0xff00000000ull)) >> 24) | (v1 & 0xff0000ull) | ((v1 & 0xff0000000000ull) >> 16) | ((v1 & 0xff00ull) << 24) | ((v0 & 0xff000000000000ull) >> 8) | ((v1 & 0xffull) << 48) | (v0 & 0xff00000000000000ull); } static void Update(const uint64_t lanes[4], HighwayHashState* state) { int i; for (i = 0; i < 4; ++i) { state->v1[i] += state->mul0[i] + lanes[i]; state->mul0[i] ^= (state->v1[i] & 0xffffffff) * (state->v0[i] >> 32); state->v0[i] += state->mul1[i]; state->mul1[i] ^= (state->v0[i] & 0xffffffff) * (state->v1[i] >> 32); } ZipperMergeAndAdd(state->v1[1], state->v1[0], &state->v0[1], &state->v0[0]); ZipperMergeAndAdd(state->v1[3], state->v1[2], &state->v0[3], &state->v0[2]); ZipperMergeAndAdd(state->v0[1], state->v0[0], &state->v1[1], &state->v1[0]); ZipperMergeAndAdd(state->v0[3], state->v0[2], &state->v1[3], &state->v1[2]); } static uint64_t Read64(const uint8_t* src) { return (uint64_t)src[0] | ((uint64_t)src[1] << 8) | ((uint64_t)src[2] << 16) | ((uint64_t)src[3] << 24) | ((uint64_t)src[4] << 32) | ((uint64_t)src[5] << 40) | ((uint64_t)src[6] << 48) | ((uint64_t)src[7] << 56); } void HighwayHashUpdatePacket(const uint8_t* packet, HighwayHashState* state) { uint64_t lanes[4]; lanes[0] = Read64(packet + 0); lanes[1] = Read64(packet + 8); lanes[2] = Read64(packet + 16); lanes[3] = Read64(packet + 24); Update(lanes, state); } static void Rotate32By(uint64_t count, uint64_t lanes[4]) { int i; for (i = 0; i < 4; ++i) { uint32_t half0 = lanes[i] & 0xffffffff; uint32_t half1 = (lanes[i] >> 32); lanes[i] = (half0 << count) | (half0 >> (32 - count)); lanes[i] |= (uint64_t)((half1 << count) | (half1 >> (32 - count))) << 32; } } void HighwayHashUpdateRemainder(const uint8_t* bytes, const size_t size_mod32, HighwayHashState* state) { int i; const size_t size_mod4 = size_mod32 & 3; const uint8_t* remainder = bytes + (size_mod32 & ~3); uint8_t packet[32] = {0}; for (i = 0; i < 4; ++i) { state->v0[i] += ((uint64_t)size_mod32 << 32) + size_mod32; } Rotate32By(size_mod32, state->v1); for (i = 0; i < remainder - bytes; i++) { packet[i] = bytes[i]; } if (size_mod32 & 16) { for (i = 0; i < 4; i++) { packet[28 + i] = remainder[i + size_mod4 - 4]; } } else { if (size_mod4) { packet[16 + 0] = remainder[0]; packet[16 + 1] = remainder[size_mod4 >> 1]; packet[16 + 2] = remainder[size_mod4 - 1]; } } HighwayHashUpdatePacket(packet, state); } static void Permute(const uint64_t v[4], uint64_t* permuted) { permuted[0] = (v[2] >> 32) | (v[2] << 32); permuted[1] = (v[3] >> 32) | (v[3] << 32); permuted[2] = (v[0] >> 32) | (v[0] << 32); permuted[3] = (v[1] >> 32) | (v[1] << 32); } void PermuteAndUpdate(HighwayHashState* state) { uint64_t permuted[4]; Permute(state->v0, permuted); Update(permuted, state); } static void ModularReduction(uint64_t a3_unmasked, uint64_t a2, uint64_t a1, uint64_t a0, uint64_t* m1, uint64_t* m0) { uint64_t a3 = a3_unmasked & 0x3FFFFFFFFFFFFFFFull; *m1 = a1 ^ ((a3 << 1) | (a2 >> 63)) ^ ((a3 << 2) | (a2 >> 62)); *m0 = a0 ^ (a2 << 1) ^ (a2 << 2); } static uint64_t HighwayHashFinalize64(HighwayHashState* state) { int i; for (i = 0; i < 4; i++) { PermuteAndUpdate(state); } return state->v0[0] + state->v1[0] + state->mul0[0] + state->mul1[0]; } static void HighwayHashFinalize128(HighwayHashState* state, uint64_t hash[2]) { int i; for (i = 0; i < 6; i++) { PermuteAndUpdate(state); } hash[0] = state->v0[0] + state->mul0[0] + state->v1[2] + state->mul1[2]; hash[1] = state->v0[1] + state->mul0[1] + state->v1[3] + state->mul1[3]; } static void HighwayHashFinalize256(HighwayHashState* state, uint64_t hash[4]) { int i; /* We anticipate that 256-bit hashing will be mostly used with long messages because storing and using the 256-bit hash (in contrast to 128-bit) carries a larger additional constant cost by itself. Doing extra rounds here hardly increases the per-byte cost of long messages. */ for (i = 0; i < 10; i++) { PermuteAndUpdate(state); } ModularReduction(state->v1[1] + state->mul1[1], state->v1[0] + state->mul1[0], state->v0[1] + state->mul0[1], state->v0[0] + state->mul0[0], &hash[1], &hash[0]); ModularReduction(state->v1[3] + state->mul1[3], state->v1[2] + state->mul1[2], state->v0[3] + state->mul0[3], state->v0[2] + state->mul0[2], &hash[3], &hash[2]); } /*////////////////////////////////////////////////////////////////////////////*/ /* Cat API: allows appending with multiple calls */ /*////////////////////////////////////////////////////////////////////////////*/ void HighwayHashCatStart(const uint64_t key[4], HighwayHashCat* state) { HighwayHashReset(key, &state->state); state->num = 0; } void HighwayHashCatAppend(const uint8_t* bytes, size_t num, HighwayHashCat* state) { size_t i; if (state->num != 0) { size_t num_add = num > (32u - state->num) ? (32u - state->num) : num; for (i = 0; i < num_add; i++) { state->packet[state->num + i] = bytes[i]; } state->num += num_add; num -= num_add; bytes += num_add; if (state->num == 32) { HighwayHashUpdatePacket(state->packet, &state->state); state->num = 0; } } while (num >= 32) { HighwayHashUpdatePacket(bytes, &state->state); num -= 32; bytes += 32; } for (i = 0; i < num; i++) { state->packet[state->num] = bytes[i]; state->num++; } } uint64_t HighwayHashCatFinish64(const HighwayHashCat* state) { HighwayHashState copy = state->state; if (state->num) { HighwayHashUpdateRemainder(state->packet, state->num, ©); } return HighwayHashFinalize64(©); } void HighwayHashCatFinish128(const HighwayHashCat* state, uint64_t hash[2]) { HighwayHashState copy = state->state; if (state->num) { HighwayHashUpdateRemainder(state->packet, state->num, ©); } HighwayHashFinalize128(©, hash); } void HighwayHashCatFinish256(const HighwayHashCat* state, uint64_t hash[4]) { HighwayHashState copy = state->state; if (state->num) { HighwayHashUpdateRemainder(state->packet, state->num, ©); } HighwayHashFinalize256(©, hash); } /// LICENSE_END.18 /// LICENSE_START.11 // ////////////////////////////////////////////////////////// // sha3.h // Copyright (c) 2014,2015 Stephan Brumme. All rights reserved. // see http://create.stephan-brumme.com/disclaimer.html // class SHA3 { public: enum Bits { Bits224 = 224, Bits256 = 256, Bits384 = 384, Bits512 = 512 }; explicit SHA3(Bits bits = Bits256); void add(const void* data, size_t numBytes); std::string getHash(); void reset(); private: void processBlock(const void* data); void processBuffer(); /// 1600 bits, stored as 25x64 bit, BlockSize is no more than 1152 bits (Keccak224) enum { StateSize = 1600 / (8 * 8), MaxBlockSize = 200 - 2 * (224 / 8) }; /// hash uint64_t m_hash[StateSize]; /// size of processed data in bytes uint64_t m_numBytes; /// block size (less or equal to MaxBlockSize) size_t m_blockSize; /// valid bytes in m_buffer size_t m_bufferSize; /// bytes not processed yet uint8_t m_buffer[MaxBlockSize]; /// variant Bits m_bits; }; SHA3::SHA3(Bits bits) : m_blockSize(200 - 2 * (bits / 8)), m_bits(bits) { reset(); } void SHA3::reset() { for (size_t i = 0; i < StateSize; i++) m_hash[i] = 0; m_numBytes = 0; m_bufferSize = 0; } namespace { const unsigned int Rounds = 24; const uint64_t XorMasks[Rounds] = { 0x0000000000000001ULL, 0x0000000000008082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, 0x000000000000808bULL, 0x0000000080000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, 0x000000000000008aULL, 0x0000000000000088ULL, 0x0000000080008009ULL, 0x000000008000000aULL, 0x000000008000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, 0x8000000000008002ULL, 0x8000000000000080ULL, 0x000000000000800aULL, 0x800000008000000aULL, 0x8000000080008081ULL, 0x8000000000008080ULL, 0x0000000080000001ULL, 0x8000000080008008ULL }; inline uint64_t rotateLeft(uint64_t x, uint8_t numBits) { return (x << numBits) | (x >> (64 - numBits)); } /// convert litte vs big endian #ifdef BIG inline uint64_t swap(uint64_t x) { #ifdef ANCIENT return (x >> 56) | ((x >> 40) & 0x000000000000FF00ULL) | ((x >> 24) & 0x0000000000FF0000ULL) | ((x >> 8) & 0x00000000FF000000ULL) | ((x << 8) & 0x000000FF00000000ULL) | ((x << 24) & 0x0000FF0000000000ULL) | ((x << 40) & 0x00FF000000000000ULL) | (x << 56); #else return __builtin_bswap64(x); #endif // corresponds to #ifdef (#ifdef ANCIENT) } #endif // corresponds to #ifdef (#ifdef BIG) unsigned int mod5(unsigned int x) { if (x < 5) return x; return x - 5; } } void SHA3::processBlock(const void* data) { #ifdef BIG #define MYLITTLEENDIAN2(x) swap(x) #else #define MYLITTLEENDIAN2(x) (x) #endif // corresponds to #ifdef (#ifdef BIG) const uint64_t* data64 = (const uint64_t*) data; for (unsigned int i = 0; i < m_blockSize / 8; i++) m_hash[i] ^= MYLITTLEENDIAN2(data64[i]); for (unsigned int round = 0; round < Rounds; round++) { uint64_t coefficients[5]; for (unsigned int i = 0; i < 5; i++) coefficients[i] = m_hash[i] ^ m_hash[i + 5] ^ m_hash[i + 10] ^ m_hash[i + 15] ^ m_hash[i + 20]; for (unsigned int i = 0; i < 5; i++) { uint64_t one = coefficients[mod5(i + 4)] ^ rotateLeft(coefficients[mod5(i + 1)], 1); m_hash[i ] ^= one; m_hash[i + 5] ^= one; m_hash[i + 10] ^= one; m_hash[i + 15] ^= one; m_hash[i + 20] ^= one; } uint64_t one; uint64_t last = m_hash[1]; one = m_hash[10]; m_hash[10] = rotateLeft(last, 1); last = one; one = m_hash[ 7]; m_hash[ 7] = rotateLeft(last, 3); last = one; one = m_hash[11]; m_hash[11] = rotateLeft(last, 6); last = one; one = m_hash[17]; m_hash[17] = rotateLeft(last, 10); last = one; one = m_hash[18]; m_hash[18] = rotateLeft(last, 15); last = one; one = m_hash[ 3]; m_hash[ 3] = rotateLeft(last, 21); last = one; one = m_hash[ 5]; m_hash[ 5] = rotateLeft(last, 28); last = one; one = m_hash[16]; m_hash[16] = rotateLeft(last, 36); last = one; one = m_hash[ 8]; m_hash[ 8] = rotateLeft(last, 45); last = one; one = m_hash[21]; m_hash[21] = rotateLeft(last, 55); last = one; one = m_hash[24]; m_hash[24] = rotateLeft(last, 2); last = one; one = m_hash[ 4]; m_hash[ 4] = rotateLeft(last, 14); last = one; one = m_hash[15]; m_hash[15] = rotateLeft(last, 27); last = one; one = m_hash[23]; m_hash[23] = rotateLeft(last, 41); last = one; one = m_hash[19]; m_hash[19] = rotateLeft(last, 56); last = one; one = m_hash[13]; m_hash[13] = rotateLeft(last, 8); last = one; one = m_hash[12]; m_hash[12] = rotateLeft(last, 25); last = one; one = m_hash[ 2]; m_hash[ 2] = rotateLeft(last, 43); last = one; one = m_hash[20]; m_hash[20] = rotateLeft(last, 62); last = one; one = m_hash[14]; m_hash[14] = rotateLeft(last, 18); last = one; one = m_hash[22]; m_hash[22] = rotateLeft(last, 39); last = one; one = m_hash[ 9]; m_hash[ 9] = rotateLeft(last, 61); last = one; one = m_hash[ 6]; m_hash[ 6] = rotateLeft(last, 20); last = one; m_hash[ 1] = rotateLeft(last, 44); for (unsigned int j = 0; j < StateSize; j += 5) { uint64_t one = m_hash[j]; uint64_t two = m_hash[j + 1]; m_hash[j] ^= m_hash[j + 2] & ~two; m_hash[j + 1] ^= m_hash[j + 3] & ~m_hash[j + 2]; m_hash[j + 2] ^= m_hash[j + 4] & ~m_hash[j + 3]; m_hash[j + 3] ^= one & ~m_hash[j + 4]; m_hash[j + 4] ^= two & ~one; } m_hash[0] ^= XorMasks[round]; } } void SHA3::add(const void* data, size_t numBytes) { const uint8_t* current = (const uint8_t*) data; // copy data to buffer if (m_bufferSize > 0) while (numBytes > 0 && m_bufferSize < m_blockSize) { m_buffer[m_bufferSize++] = *current++; numBytes--; } // full buffer if (m_bufferSize == m_blockSize) { processBlock((void*)m_buffer); m_numBytes += m_blockSize; m_bufferSize = 0; } // no more data ? if (numBytes == 0) return; // process full blocks while (numBytes >= m_blockSize) { processBlock(current); current += m_blockSize; m_numBytes += m_blockSize; numBytes -= m_blockSize; } // keep remaining bytes in buffer while (numBytes > 0) { m_buffer[m_bufferSize++] = *current++; numBytes--; } } void SHA3::processBuffer() { // add padding size_t offset = m_bufferSize; // add a "1" byte m_buffer[offset++] = 0x06; // fill with zeros while (offset < m_blockSize) m_buffer[offset++] = 0; // and add a single set bit m_buffer[offset - 1] |= 0x80; processBlock(m_buffer); } std::string SHA3::getHash() { // save hash state uint64_t oldHash[StateSize]; for (unsigned int i = 0; i < StateSize; i++) oldHash[i] = m_hash[i]; processBuffer(); static const char dec2hex[16 + 1] = "0123456789ABCDEF"; // number of significant elements in hash (uint64_t) unsigned int hashLength = m_bits / 64; std::string result; result.reserve(m_bits / 4); for (unsigned int i = 0; i < hashLength; i++) for (unsigned int j = 0; j < 8; j++) // 64 bits => 8 bytes { // convert a byte to hex unsigned char oneByte = (unsigned char) (m_hash[i] >> (8 * j)); result += dec2hex[oneByte >> 4]; result += dec2hex[oneByte & 15]; } // SHA3-224's last entry in m_hash provides only 32 bits instead of 64 bits unsigned int remainder = m_bits - hashLength * 64; unsigned int processed = 0; while (processed < remainder) { // convert a byte to hex unsigned char oneByte = (unsigned char) (m_hash[hashLength] >> processed); result += dec2hex[oneByte >> 4]; result += dec2hex[oneByte & 15]; processed += 8; } // restore state for (unsigned int i = 0; i < StateSize; i++) m_hash[i] = oldHash[i]; return result; } // ////////////////////////////////////////////////////////// // md5.h // Copyright (c) 2014 Stephan Brumme. All rights reserved. // see http://create.stephan-brumme.com/disclaimer.html // /** Usage: MD5 md5; while (more data available) md5.add(pointer to fresh data, number of new bytes); std::string myHash3 = md5.getHash(); */ class MD5 { public: /// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long enum { BlockSize = 512 / 8, HashBytes = 16 }; MD5(); void add(const void* data, size_t numBytes); std::string getHash(); void getHash(unsigned char buffer[HashBytes]); void reset(); private: void processBlock(const void* data); void processBuffer(); /// size of processed data in bytes uint64_t m_numBytes; /// valid bytes in m_buffer size_t m_bufferSize; /// bytes not processed yet uint8_t m_buffer[BlockSize]; enum { HashValues = HashBytes / 4 }; /// hash, stored as integers uint32_t m_hash[HashValues]; }; /// same as reset() MD5::MD5() { reset(); } /// restart void MD5::reset() { m_numBytes = 0; m_bufferSize = 0; // according to RFC 1321 m_hash[0] = 0x67452301; m_hash[1] = 0xefcdab89; m_hash[2] = 0x98badcfe; m_hash[3] = 0x10325476; } namespace { // mix functions for processBlock() inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d) { return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d); } inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d) { return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d)); } inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d) { return b ^ c ^ d; } inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d) { return c ^ (b | ~d); } inline uint32_t rotate(uint32_t a, uint32_t c) { return (a << c) | (a >> (32 - c)); } #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) static inline uint32_t swap(uint32_t x) { #ifdef ANCIENT return (x >> 24) | ((x >> 8) & 0x0000FF00) | ((x << 8) & 0x00FF0000) | (x << 24); #else return __builtin_bswap32(x); #endif // corresponds to #ifdef (#ifdef ANCIENT) } #endif // corresponds to #if (#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)) } /// process 64 bytes void MD5::processBlock(const void* data) { // get last hash uint32_t a = m_hash[0]; uint32_t b = m_hash[1]; uint32_t c = m_hash[2]; uint32_t d = m_hash[3]; // data represented as 16x 32-bit words const uint32_t* words = (uint32_t*) data; // computations are little endian, swap data if necessary #if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN) #define MYLITTLEENDIAN(x) swap(x) #else #define MYLITTLEENDIAN(x) (x) #endif // corresponds to #if (#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)) // first round uint32_t word0 = MYLITTLEENDIAN(words[ 0]); a = rotate(a + f1(b,c,d) + word0 + 0xd76aa478, 7) + b; uint32_t word1 = MYLITTLEENDIAN(words[ 1]); d = rotate(d + f1(a,b,c) + word1 + 0xe8c7b756, 12) + a; uint32_t word2 = MYLITTLEENDIAN(words[ 2]); c = rotate(c + f1(d,a,b) + word2 + 0x242070db, 17) + d; uint32_t word3 = MYLITTLEENDIAN(words[ 3]); b = rotate(b + f1(c,d,a) + word3 + 0xc1bdceee, 22) + c; uint32_t word4 = MYLITTLEENDIAN(words[ 4]); a = rotate(a + f1(b,c,d) + word4 + 0xf57c0faf, 7) + b; uint32_t word5 = MYLITTLEENDIAN(words[ 5]); d = rotate(d + f1(a,b,c) + word5 + 0x4787c62a, 12) + a; uint32_t word6 = MYLITTLEENDIAN(words[ 6]); c = rotate(c + f1(d,a,b) + word6 + 0xa8304613, 17) + d; uint32_t word7 = MYLITTLEENDIAN(words[ 7]); b = rotate(b + f1(c,d,a) + word7 + 0xfd469501, 22) + c; uint32_t word8 = MYLITTLEENDIAN(words[ 8]); a = rotate(a + f1(b,c,d) + word8 + 0x698098d8, 7) + b; uint32_t word9 = MYLITTLEENDIAN(words[ 9]); d = rotate(d + f1(a,b,c) + word9 + 0x8b44f7af, 12) + a; uint32_t word10 = MYLITTLEENDIAN(words[10]); c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d; uint32_t word11 = MYLITTLEENDIAN(words[11]); b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c; uint32_t word12 = MYLITTLEENDIAN(words[12]); a = rotate(a + f1(b,c,d) + word12 + 0x6b901122, 7) + b; uint32_t word13 = MYLITTLEENDIAN(words[13]); d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a; uint32_t word14 = MYLITTLEENDIAN(words[14]); c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d; uint32_t word15 = MYLITTLEENDIAN(words[15]); b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c; // second round a = rotate(a + f2(b,c,d) + word1 + 0xf61e2562, 5) + b; d = rotate(d + f2(a,b,c) + word6 + 0xc040b340, 9) + a; c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d; b = rotate(b + f2(c,d,a) + word0 + 0xe9b6c7aa, 20) + c; a = rotate(a + f2(b,c,d) + word5 + 0xd62f105d, 5) + b; d = rotate(d + f2(a,b,c) + word10 + 0x02441453, 9) + a; c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d; b = rotate(b + f2(c,d,a) + word4 + 0xe7d3fbc8, 20) + c; a = rotate(a + f2(b,c,d) + word9 + 0x21e1cde6, 5) + b; d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6, 9) + a; c = rotate(c + f2(d,a,b) + word3 + 0xf4d50d87, 14) + d; b = rotate(b + f2(c,d,a) + word8 + 0x455a14ed, 20) + c; a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905, 5) + b; d = rotate(d + f2(a,b,c) + word2 + 0xfcefa3f8, 9) + a; c = rotate(c + f2(d,a,b) + word7 + 0x676f02d9, 14) + d; b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c; // third round a = rotate(a + f3(b,c,d) + word5 + 0xfffa3942, 4) + b; d = rotate(d + f3(a,b,c) + word8 + 0x8771f681, 11) + a; c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d; b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c; a = rotate(a + f3(b,c,d) + word1 + 0xa4beea44, 4) + b; d = rotate(d + f3(a,b,c) + word4 + 0x4bdecfa9, 11) + a; c = rotate(c + f3(d,a,b) + word7 + 0xf6bb4b60, 16) + d; b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c; a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6, 4) + b; d = rotate(d + f3(a,b,c) + word0 + 0xeaa127fa, 11) + a; c = rotate(c + f3(d,a,b) + word3 + 0xd4ef3085, 16) + d; b = rotate(b + f3(c,d,a) + word6 + 0x04881d05, 23) + c; a = rotate(a + f3(b,c,d) + word9 + 0xd9d4d039, 4) + b; d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a; c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d; b = rotate(b + f3(c,d,a) + word2 + 0xc4ac5665, 23) + c; // fourth round a = rotate(a + f4(b,c,d) + word0 + 0xf4292244, 6) + b; d = rotate(d + f4(a,b,c) + word7 + 0x432aff97, 10) + a; c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d; b = rotate(b + f4(c,d,a) + word5 + 0xfc93a039, 21) + c; a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3, 6) + b; d = rotate(d + f4(a,b,c) + word3 + 0x8f0ccc92, 10) + a; c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d; b = rotate(b + f4(c,d,a) + word1 + 0x85845dd1, 21) + c; a = rotate(a + f4(b,c,d) + word8 + 0x6fa87e4f, 6) + b; d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a; c = rotate(c + f4(d,a,b) + word6 + 0xa3014314, 15) + d; b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c; a = rotate(a + f4(b,c,d) + word4 + 0xf7537e82, 6) + b; d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a; c = rotate(c + f4(d,a,b) + word2 + 0x2ad7d2bb, 15) + d; b = rotate(b + f4(c,d,a) + word9 + 0xeb86d391, 21) + c; // update hash m_hash[0] += a; m_hash[1] += b; m_hash[2] += c; m_hash[3] += d; } /// add arbitrary number of bytes void MD5::add(const void* data, size_t numBytes) { const uint8_t* current = (const uint8_t*) data; if (m_bufferSize > 0) { while (numBytes > 0 && m_bufferSize < BlockSize) { m_buffer[m_bufferSize++] = *current++; numBytes--; } } // full buffer if (m_bufferSize == BlockSize) { processBlock(m_buffer); m_numBytes += BlockSize; m_bufferSize = 0; } // no more data ? if (numBytes == 0) return; // process full blocks while (numBytes >= BlockSize) { processBlock(current); current += BlockSize; m_numBytes += BlockSize; numBytes -= BlockSize; } // keep remaining bytes in buffer while (numBytes > 0) { m_buffer[m_bufferSize++] = *current++; numBytes--; } } /// process final block, less than 64 bytes void MD5::processBuffer() { // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte // - append "1" bit to message // - append "0" bits until message length in bit mod 512 is 448 // - append length as 64 bit integer // number of bits size_t paddedLength = m_bufferSize * 8; // plus one bit set to 1 (always appended) paddedLength++; // number of bits must be (numBits % 512) = 448 size_t lower11Bits = paddedLength & 511; if (lower11Bits <= 448) paddedLength += 448 - lower11Bits; else paddedLength += 512 + 448 - lower11Bits; // convert from bits to bytes paddedLength /= 8; // only needed if additional data flows over into a second block unsigned char extra[BlockSize]; // append a "1" bit, 128 => binary 10000000 if (m_bufferSize < BlockSize) m_buffer[m_bufferSize] = 128; else extra[0] = 128; size_t i; for (i = m_bufferSize + 1; i < BlockSize; i++) m_buffer[i] = 0; for (; i < paddedLength; i++) extra[i - BlockSize] = 0; // add message length in bits as 64 bit number uint64_t msgBits = 8 * (m_numBytes + m_bufferSize); // find right position unsigned char* addLength; if (paddedLength < BlockSize) addLength = m_buffer + paddedLength; else addLength = extra + paddedLength - BlockSize; // must be little endian *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; msgBits >>= 8; *addLength++ = msgBits & 0xFF; // process blocks processBlock(m_buffer); // flowed over into a second block ? if (paddedLength > BlockSize) processBlock(extra); } /// return latest hash as 32 hex characters std::string MD5::getHash() { // compute hash (as raw bytes) unsigned char rawHash[HashBytes]; getHash(rawHash); // convert to hex string std::string result; result.reserve(2 * HashBytes); for (int i = 0; i < HashBytes; i++) { static const char dec2hex[16+1] = "0123456789ABCDEF"; result += dec2hex[(rawHash[i] >> 4) & 15]; result += dec2hex[ rawHash[i] & 15]; } return result; } /// return latest hash as bytes void MD5::getHash(unsigned char buffer[MD5::HashBytes]) { // save old hash if buffer is partially filled uint32_t oldHash[HashValues]; for (int i = 0; i < HashValues; i++) oldHash[i] = m_hash[i]; // process remaining bytes processBuffer(); unsigned char* current = buffer; for (int i = 0; i < HashValues; i++) { *current++ = m_hash[i] & 0xFF; *current++ = (m_hash[i] >> 8) & 0xFF; *current++ = (m_hash[i] >> 16) & 0xFF; *current++ = (m_hash[i] >> 24) & 0xFF; // restore old hash m_hash[i] = oldHash[i]; } } /// LICENSE_END.11 /// LICENSE_START.15 #if !defined(HWBLAKE3) // Sligthly reworked to compile on C++ (and FreeBSD) #define BLAKE3_KEY_LEN 32 #define BLAKE3_OUT_LEN 32 #define BLAKE3_BLOCK_LEN 64 #define BLAKE3_CHUNK_LEN 1024 #define BLAKE3_MAX_DEPTH 54 typedef struct { uint32_t cv[8]; uint64_t chunk_counter; uint8_t buf[BLAKE3_BLOCK_LEN]; uint8_t buf_len; uint8_t blocks_compressed; uint8_t flags; } blake3_chunk_state; typedef struct { uint32_t key[8]; blake3_chunk_state chunk; uint8_t cv_stack_len; uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; } blake3_hasher; void blake3_hasher_init(blake3_hasher *self); void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len); void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); enum blake3_flags { CHUNK_START = 1 << 0, CHUNK_END = 1 << 1, PARENT = 1 << 2, ROOT = 1 << 3, KEYED_HASH = 1 << 4, DERIVE_KEY_CONTEXT = 1 << 5, DERIVE_KEY_MATERIAL = 1 << 6 }; #define MAX_SIMD_DEGREE 1 #define MAX_SIMD_DEGREE_OR_2 (MAX_SIMD_DEGREE > 2 ? MAX_SIMD_DEGREE : 2) static const uint32_t IV[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; static const uint8_t MSG_SCHEDULE[7][16] = { {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}, {3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1}, {10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6}, {12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4}, {9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7}, {11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13}, }; static unsigned int highest_one(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return 63 ^ __builtin_clzll(x); #elif defined(_MSC_VER) && defined(IS_X86_64) unsigned long index; _BitScanReverse64(&index, x); return index; #elif defined(_MSC_VER) && defined(IS_X86_32) if(x >> 32) { unsigned long index; _BitScanReverse(&index, x >> 32); return 32 + index; } else { unsigned long index; _BitScanReverse(&index, x); return index; } #else unsigned int c = 0; if(x & 0xffffffff00000000ULL) { x >>= 32; c += 32; } if(x & 0x00000000ffff0000ULL) { x >>= 16; c += 16; } if(x & 0x000000000000ff00ULL) { x >>= 8; c += 8; } if(x & 0x00000000000000f0ULL) { x >>= 4; c += 4; } if(x & 0x000000000000000cULL) { x >>= 2; c += 2; } if(x & 0x0000000000000002ULL) { c += 1; } return c; #endif // corresponds to #if (#if defined(__GNUC__) || defined(__clang__)) } INLINE_divsuf unsigned int popcnt(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return __builtin_popcountll(x); #else unsigned int count = 0; while (x != 0) { count += 1; x &= x - 1; } return count; #endif // corresponds to #if (#if defined(__GNUC__) || defined(__clang__)) } INLINE_divsuf uint64_t round_down_to_power_of_2(uint64_t x) { return 1ULL << highest_one(x | 1); } INLINE_divsuf uint32_t counter_low(uint64_t counter) { return (uint32_t)counter; } INLINE_divsuf uint32_t counter_high(uint64_t counter) { return (uint32_t)(counter >> 32); } INLINE_divsuf uint32_t load32(const void *src) { const uint8_t *p = (const uint8_t *)src; return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) | ((uint32_t)(p[2]) << 16) | ((uint32_t)(p[3]) << 24); } INLINE_divsuf void store32(void *dst, uint32_t w) { uint8_t *p = (uint8_t *)dst; p[0] = (uint8_t)(w >> 0); p[1] = (uint8_t)(w >> 8); p[2] = (uint8_t)(w >> 16); p[3] = (uint8_t)(w >> 24); } INLINE_divsuf void store_cv_words(uint8_t bytes_out[32], uint32_t cv_words[8]) { store32(&bytes_out[0 * 4], cv_words[0]); store32(&bytes_out[1 * 4], cv_words[1]); store32(&bytes_out[2 * 4], cv_words[2]); store32(&bytes_out[3 * 4], cv_words[3]); store32(&bytes_out[4 * 4], cv_words[4]); store32(&bytes_out[5 * 4], cv_words[5]); store32(&bytes_out[6 * 4], cv_words[6]); store32(&bytes_out[7 * 4], cv_words[7]); } void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); size_t blake3_simd_degree(void); void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); INLINE_divsuf void chunk_state_init(blake3_chunk_state *self, const uint32_t key[8], uint8_t flags) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; self->blocks_compressed = 0; self->flags = flags; } INLINE_divsuf void chunk_state_reset(blake3_chunk_state *self, const uint32_t key[8], uint64_t chunk_counter) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = chunk_counter; self->blocks_compressed = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; } INLINE_divsuf size_t chunk_state_len(const blake3_chunk_state *self) { return (BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed) + ((size_t)self->buf_len); } INLINE_divsuf size_t chunk_state_fill_buf(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { size_t take = BLAKE3_BLOCK_LEN - ((size_t)self->buf_len); if (take > input_len) { take = input_len; } uint8_t *dest = self->buf + ((size_t)self->buf_len); memcpy(dest, input, take); self->buf_len += (uint8_t)take; return take; } INLINE_divsuf uint8_t chunk_state_maybe_start_flag(const blake3_chunk_state *self) { if (self->blocks_compressed == 0) { return CHUNK_START; } else { return 0; } } typedef struct { uint32_t input_cv[8]; uint64_t counter; uint8_t block[BLAKE3_BLOCK_LEN]; uint8_t block_len; uint8_t flags; } output_t; INLINE_divsuf output_t make_output(const uint32_t input_cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { output_t ret; memcpy(ret.input_cv, input_cv, 32); memcpy(ret.block, block, BLAKE3_BLOCK_LEN); ret.block_len = block_len; ret.counter = counter; ret.flags = flags; return ret; } INLINE_divsuf void output_chaining_value(const output_t *self, uint8_t cv[32]) { uint32_t cv_words[8]; memcpy(cv_words, self->input_cv, 32); blake3_compress_in_place(cv_words, self->block, self->block_len, self->counter, self->flags); store_cv_words(cv, cv_words); } INLINE_divsuf void output_root_bytes(const output_t *self, uint64_t seek, uint8_t *out, size_t out_len) { uint64_t output_block_counter = seek / 64; size_t offset_within_block = seek % 64; uint8_t wide_buf[64]; while (out_len > 0) { blake3_compress_xof(self->input_cv, self->block, self->block_len, output_block_counter, self->flags | ROOT, wide_buf); size_t available_bytes = 64 - offset_within_block; size_t memcpy_len; if (out_len > available_bytes) { memcpy_len = available_bytes; } else { memcpy_len = out_len; } memcpy(out, wide_buf + offset_within_block, memcpy_len); out += memcpy_len; out_len -= memcpy_len; output_block_counter += 1; offset_within_block = 0; } } INLINE_divsuf void chunk_state_update(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { if (self->buf_len > 0) { size_t take = chunk_state_fill_buf(self, input, input_len); input += take; input_len -= take; if (input_len > 0) { blake3_compress_in_place( self->cv, self->buf, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; self->buf_len = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); } } while (input_len > BLAKE3_BLOCK_LEN) { blake3_compress_in_place(self->cv, input, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; input += BLAKE3_BLOCK_LEN; input_len -= BLAKE3_BLOCK_LEN; } (void)chunk_state_fill_buf(self, input, input_len); /// size_t take = chunk_state_fill_buf(self, input, input_len); /// input += take; /// input_len -= take; } INLINE_divsuf output_t chunk_state_output(const blake3_chunk_state *self) { uint8_t block_flags = self->flags | chunk_state_maybe_start_flag(self) | CHUNK_END; return make_output(self->cv, self->buf, self->buf_len, self->chunk_counter, block_flags); } INLINE_divsuf output_t parent_output(const uint8_t block[BLAKE3_BLOCK_LEN], const uint32_t key[8], uint8_t flags) { return make_output(key, block, BLAKE3_BLOCK_LEN, 0, flags | PARENT); } INLINE_divsuf size_t left_len(size_t content_len) { size_t full_chunks = (content_len - 1) / BLAKE3_CHUNK_LEN; return round_down_to_power_of_2(full_chunks) * BLAKE3_CHUNK_LEN; } INLINE_divsuf size_t compress_chunks_parallel(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(0 < input_len); assert(input_len <= MAX_SIMD_DEGREE * BLAKE3_CHUNK_LEN); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) const uint8_t *chunks_array[MAX_SIMD_DEGREE]; size_t input_position = 0; size_t chunks_array_len = 0; while (input_len - input_position >= BLAKE3_CHUNK_LEN) { chunks_array[chunks_array_len] = &input[input_position]; input_position += BLAKE3_CHUNK_LEN; chunks_array_len += 1; } blake3_hash_many(chunks_array, chunks_array_len, BLAKE3_CHUNK_LEN / BLAKE3_BLOCK_LEN, key, chunk_counter, true, flags, CHUNK_START, CHUNK_END, out); if (input_len > input_position) { uint64_t counter = chunk_counter + (uint64_t)chunks_array_len; blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, key, flags); chunk_state.chunk_counter = counter; chunk_state_update(&chunk_state, &input[input_position], input_len - input_position); output_t output = chunk_state_output(&chunk_state); output_chaining_value(&output, &out[chunks_array_len * BLAKE3_OUT_LEN]); return chunks_array_len + 1; } else { return chunks_array_len; } } INLINE_divsuf size_t compress_parents_parallel(const uint8_t *child_chaining_values, size_t num_chaining_values, const uint32_t key[8], uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(2 <= num_chaining_values); assert(num_chaining_values <= 2 * MAX_SIMD_DEGREE_OR_2); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) const uint8_t *parents_array[MAX_SIMD_DEGREE_OR_2]; size_t parents_array_len = 0; while (num_chaining_values - (2 * parents_array_len) >= 2) { parents_array[parents_array_len] = &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN]; parents_array_len += 1; } blake3_hash_many(parents_array, parents_array_len, 1, key, 0, false, flags | PARENT, 0, 0, out); if (num_chaining_values > 2 * parents_array_len) { memcpy(&out+(parents_array_len * BLAKE3_OUT_LEN), &child_chaining_values+(2 * parents_array_len * BLAKE3_OUT_LEN), BLAKE3_OUT_LEN); /// FAKE COMPILER WARNING return parents_array_len + 1; } else { return parents_array_len; } } static size_t blake3_compress_subtree_wide(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out) { if (input_len <= blake3_simd_degree() * BLAKE3_CHUNK_LEN) { return compress_chunks_parallel(input, input_len, key, chunk_counter, flags, out); } size_t left_input_len = left_len(input_len); size_t right_input_len = input_len - left_input_len; const uint8_t *right_input = &input[left_input_len]; uint64_t right_chunk_counter = chunk_counter + (uint64_t)(left_input_len / BLAKE3_CHUNK_LEN); uint8_t cv_array[2 * MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t degree = blake3_simd_degree(); if (left_input_len > BLAKE3_CHUNK_LEN && degree == 1) { degree = 2; } uint8_t *right_cvs = &cv_array[degree * BLAKE3_OUT_LEN]; size_t left_n = blake3_compress_subtree_wide(input, left_input_len, key, chunk_counter, flags, cv_array); size_t right_n = blake3_compress_subtree_wide( right_input, right_input_len, key, right_chunk_counter, flags, right_cvs); if (left_n == 1) { memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); return 2; } size_t num_chaining_values = left_n + right_n; return compress_parents_parallel(cv_array, num_chaining_values, key, flags, out); /// FAKE WARNING } INLINE_divsuf void compress_subtree_to_parent_node( const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t out[2 * BLAKE3_OUT_LEN]) { #if defined(BLAKE3_TESTING) assert(input_len > BLAKE3_CHUNK_LEN); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) uint8_t cv_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t num_cvs = blake3_compress_subtree_wide(input, input_len, key, chunk_counter, flags, cv_array); uint8_t out_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN ]; while (num_cvs > 2) { num_cvs = compress_parents_parallel(cv_array, num_cvs, key, flags, out_array); memcpy(cv_array, out_array, num_cvs * BLAKE3_OUT_LEN); } memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); } INLINE_divsuf void hasher_init_base(blake3_hasher *self, const uint32_t key[8], uint8_t flags) { memcpy(self->key, key, BLAKE3_KEY_LEN); chunk_state_init(&self->chunk, key, flags); self->cv_stack_len = 0; } void blake3_hasher_init(blake3_hasher *self) { hasher_init_base(self, IV, 0); } INLINE_divsuf void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { size_t post_merge_stack_len = (size_t)popcnt(total_len); while (self->cv_stack_len > post_merge_stack_len) { uint8_t *parent_node = &self->cv_stack[(self->cv_stack_len - 2) * BLAKE3_OUT_LEN]; output_t output = parent_output(parent_node, self->key, self->chunk.flags); output_chaining_value(&output, parent_node); self->cv_stack_len -= 1; } } INLINE_divsuf void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN], uint64_t chunk_counter) { hasher_merge_cv_stack(self, chunk_counter); memcpy(&self->cv_stack[self->cv_stack_len * BLAKE3_OUT_LEN], new_cv, BLAKE3_OUT_LEN); self->cv_stack_len += 1; } void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len) { if (input_len == 0) { return; } const uint8_t *input_bytes = (const uint8_t *)input; if (chunk_state_len(&self->chunk) > 0) { size_t take = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk); if (take > input_len) { take = input_len; } chunk_state_update(&self->chunk, input_bytes, take); input_bytes += take; input_len -= take; if (input_len > 0) { output_t output = chunk_state_output(&self->chunk); uint8_t chunk_cv[32]; output_chaining_value(&output, chunk_cv); hasher_push_cv(self, chunk_cv, self->chunk.chunk_counter); chunk_state_reset(&self->chunk, self->key, self->chunk.chunk_counter + 1); } else { return; } } while (input_len > BLAKE3_CHUNK_LEN) { size_t subtree_len = round_down_to_power_of_2(input_len); uint64_t count_so_far = self->chunk.chunk_counter * BLAKE3_CHUNK_LEN; while ((((uint64_t)(subtree_len - 1)) & count_so_far) != 0) { subtree_len /= 2; } uint64_t subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN; if (subtree_len <= BLAKE3_CHUNK_LEN) { blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, self->key, self->chunk.flags); chunk_state.chunk_counter = self->chunk.chunk_counter; chunk_state_update(&chunk_state, input_bytes, subtree_len); output_t output = chunk_state_output(&chunk_state); uint8_t cv[BLAKE3_OUT_LEN]; output_chaining_value(&output, cv); hasher_push_cv(self, cv, chunk_state.chunk_counter); } else { uint8_t cv_pair[2 * BLAKE3_OUT_LEN]; compress_subtree_to_parent_node(input_bytes, subtree_len, self->key, self->chunk.chunk_counter, self->chunk.flags, cv_pair); /// FAKE COMPILER WARNING HERE! hasher_push_cv(self, cv_pair, self->chunk.chunk_counter); hasher_push_cv(self, &cv_pair[BLAKE3_OUT_LEN], self->chunk.chunk_counter + (subtree_chunks / 2)); } self->chunk.chunk_counter += subtree_chunks; input_bytes += subtree_len; input_len -= subtree_len; } if (input_len > 0) { chunk_state_update(&self->chunk, input_bytes, input_len); hasher_merge_cv_stack(self, self->chunk.chunk_counter); } } void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len) { blake3_hasher_finalize_seek(self, 0, out, out_len); } void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len) { if (out_len == 0) { return; } if (self->cv_stack_len == 0) { output_t output = chunk_state_output(&self->chunk); output_root_bytes(&output, seek, out, out_len); return; } output_t output; size_t cvs_remaining; if (chunk_state_len(&self->chunk) > 0) { cvs_remaining = self->cv_stack_len; output = chunk_state_output(&self->chunk); } else { cvs_remaining = self->cv_stack_len - 2; output = parent_output(&self->cv_stack[cvs_remaining * 32], self->key, self->chunk.flags); } while (cvs_remaining > 0) { cvs_remaining -= 1; uint8_t parent_block[BLAKE3_BLOCK_LEN]; memcpy(parent_block, &self->cv_stack[cvs_remaining * 32], 32); output_chaining_value(&output, &parent_block[32]); output = parent_output(parent_block, self->key, self->chunk.flags); } output_root_bytes(&output, seek, out, out_len); } #define MAYBE_UNUSED(x) (void)((x)) #if defined(IS_X86) static uint64_t xgetbv() { #if defined(_MSC_VER) return _xgetbv(0); #else uint32_t eax = 0, edx = 0; __asm__ __volatile__("xgetbv\n" : "=a"(eax), "=d"(edx) : "c"(0)); return ((uint64_t)edx << 32) | eax; #endif // corresponds to #if (#if defined(_MSC_VER)) } static void cpuid(uint32_t out[4], uint32_t id) { #if defined(_MSC_VER) __cpuid((int *)out, id); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #endif // corresponds to #if (#if defined(_MSC_VER)) } static void cpuidex(uint32_t out[4], uint32_t id, uint32_t sid) { #if defined(_MSC_VER) __cpuidex((int *)out, id, sid); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #endif // corresponds to #if (#if defined(_MSC_VER)) } #endif // corresponds to #if (#if defined(IS_X86)) void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { blake3_compress_in_place_portable(cv, block, block_len, counter, flags); } void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { blake3_compress_xof_portable(cv, block, block_len, counter, flags, out); } void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); } size_t blake3_simd_degree(void) { return 1; } INLINE_divsuf uint32_t rotr32(uint32_t w, uint32_t c) { return (w >> c) | (w << (32 - c)); } INLINE_divsuf void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, uint32_t x, uint32_t y) { state[a] = state[a] + state[b] + x; state[d] = rotr32(state[d] ^ state[a], 16); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 12); state[a] = state[a] + state[b] + y; state[d] = rotr32(state[d] ^ state[a], 8); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 7); } INLINE_divsuf void round_fn(uint32_t state[16], const uint32_t *msg, size_t round) { const uint8_t *schedule = MSG_SCHEDULE[round]; g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); } INLINE_divsuf void compress_pre(uint32_t state[16], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t block_words[16]; block_words[0] = load32(block + 4 * 0); block_words[1] = load32(block + 4 * 1); block_words[2] = load32(block + 4 * 2); block_words[3] = load32(block + 4 * 3); block_words[4] = load32(block + 4 * 4); block_words[5] = load32(block + 4 * 5); block_words[6] = load32(block + 4 * 6); block_words[7] = load32(block + 4 * 7); block_words[8] = load32(block + 4 * 8); block_words[9] = load32(block + 4 * 9); block_words[10] = load32(block + 4 * 10); block_words[11] = load32(block + 4 * 11); block_words[12] = load32(block + 4 * 12); block_words[13] = load32(block + 4 * 13); block_words[14] = load32(block + 4 * 14); block_words[15] = load32(block + 4 * 15); state[0] = cv[0]; state[1] = cv[1]; state[2] = cv[2]; state[3] = cv[3]; state[4] = cv[4]; state[5] = cv[5]; state[6] = cv[6]; state[7] = cv[7]; state[8] = IV[0]; state[9] = IV[1]; state[10] = IV[2]; state[11] = IV[3]; state[12] = counter_low(counter); state[13] = counter_high(counter); state[14] = (uint32_t)block_len; state[15] = (uint32_t)flags; round_fn(state, &block_words[0], 0); round_fn(state, &block_words[0], 1); round_fn(state, &block_words[0], 2); round_fn(state, &block_words[0], 3); round_fn(state, &block_words[0], 4); round_fn(state, &block_words[0], 5); round_fn(state, &block_words[0], 6); } void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); cv[0] = state[0] ^ state[8]; cv[1] = state[1] ^ state[9]; cv[2] = state[2] ^ state[10]; cv[3] = state[3] ^ state[11]; cv[4] = state[4] ^ state[12]; cv[5] = state[5] ^ state[13]; cv[6] = state[6] ^ state[14]; cv[7] = state[7] ^ state[15]; } void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); store32(&out[0 * 4], state[0] ^ state[8]); store32(&out[1 * 4], state[1] ^ state[9]); store32(&out[2 * 4], state[2] ^ state[10]); store32(&out[3 * 4], state[3] ^ state[11]); store32(&out[4 * 4], state[4] ^ state[12]); store32(&out[5 * 4], state[5] ^ state[13]); store32(&out[6 * 4], state[6] ^ state[14]); store32(&out[7 * 4], state[7] ^ state[15]); store32(&out[8 * 4], state[8] ^ cv[0]); store32(&out[9 * 4], state[9] ^ cv[1]); store32(&out[10 * 4], state[10] ^ cv[2]); store32(&out[11 * 4], state[11] ^ cv[3]); store32(&out[12 * 4], state[12] ^ cv[4]); store32(&out[13 * 4], state[13] ^ cv[5]); store32(&out[14 * 4], state[14] ^ cv[6]); store32(&out[15 * 4], state[15] ^ cv[7]); } INLINE_divsuf void hash_one_portable(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } store_cv_words(out, cv); } void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs > 0) { hash_one_portable(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } #else #define BLAKE3_VERSION_STRING "1.0.0" #define BLAKE3_KEY_LEN 32 #define BLAKE3_OUT_LEN 32 #define BLAKE3_BLOCK_LEN 64 #define BLAKE3_CHUNK_LEN 1024 #define BLAKE3_MAX_DEPTH 54 typedef struct { uint32_t cv[8]; uint64_t chunk_counter; uint8_t buf[BLAKE3_BLOCK_LEN]; uint8_t buf_len; uint8_t blocks_compressed; uint8_t flags; } blake3_chunk_state; typedef struct { uint32_t key[8]; blake3_chunk_state chunk; uint8_t cv_stack_len; uint8_t cv_stack[(BLAKE3_MAX_DEPTH + 1) * BLAKE3_OUT_LEN]; } blake3_hasher; void blake3_hasher_init(blake3_hasher *self); void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context); void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len); void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len); void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len); void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len); enum blake3_flags { CHUNK_START = 1 << 0, CHUNK_END = 1 << 1, PARENT = 1 << 2, ROOT = 1 << 3, KEYED_HASH = 1 << 4, DERIVE_KEY_CONTEXT = 1 << 5, DERIVE_KEY_MATERIAL = 1 << 6, }; #if defined(_MSC_VER) #define INLINE static __forceinline #else #define INLINE static inline __attribute__((always_inline)) #endif // corresponds to #if (#if defined(_MSC_VER)) #if defined(__x86_64__) || defined(_M_X64) #define IS_X86 #define IS_X86_64 #endif // corresponds to #if (#if defined(__x86_64__) || defined(_M_X64)) #if defined(__i386__) || defined(_M_IX86) #define IS_X86 #define IS_X86_32 #endif // corresponds to #if (#if defined(__i386__) || defined(_M_IX86)) #if defined(IS_X86) #if defined(_MSC_VER) #include #endif // corresponds to #if (#if defined(_MSC_VER)) #include #endif // corresponds to #if (#if defined(IS_X86)) #if defined(IS_X86) #define MAX_SIMD_DEGREE 16 #elif defined(BLAKE3_USE_NEON) #define MAX_SIMD_DEGREE 4 #else #define MAX_SIMD_DEGREE 1 #endif // corresponds to #if (#if defined(IS_X86)) #define MAX_SIMD_DEGREE_OR_2 (MAX_SIMD_DEGREE > 2 ? MAX_SIMD_DEGREE : 2) static const uint32_t IV[8] = {0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL}; static const uint8_t MSG_SCHEDULE[7][16] = { {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, {2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8}, {3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1}, {10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6}, {12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4}, {9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7}, {11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13}, }; static unsigned int highest_one(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return 63 ^ __builtin_clzll(x); #elif defined(_MSC_VER) && defined(IS_X86_64) unsigned long index; _BitScanReverse64(&index, x); return index; #elif defined(_MSC_VER) && defined(IS_X86_32) if(x >> 32) { unsigned long index; _BitScanReverse(&index, x >> 32); return 32 + index; } else { unsigned long index; _BitScanReverse(&index, x); return index; } #else unsigned int c = 0; if(x & 0xffffffff00000000ULL) { x >>= 32; c += 32; } if(x & 0x00000000ffff0000ULL) { x >>= 16; c += 16; } if(x & 0x000000000000ff00ULL) { x >>= 8; c += 8; } if(x & 0x00000000000000f0ULL) { x >>= 4; c += 4; } if(x & 0x000000000000000cULL) { x >>= 2; c += 2; } if(x & 0x0000000000000002ULL) { c += 1; } return c; #endif // corresponds to #if (#if defined(__GNUC__) || defined(__clang__)) } INLINE unsigned int popcnt(uint64_t x) { #if defined(__GNUC__) || defined(__clang__) return __builtin_popcountll(x); #else unsigned int count = 0; while (x != 0) { count += 1; x &= x - 1; } return count; #endif // corresponds to #if (#if defined(__GNUC__) || defined(__clang__)) } INLINE uint64_t round_down_to_power_of_2(uint64_t x) { return 1ULL << highest_one(x | 1); } INLINE uint32_t counter_low(uint64_t counter) { return (uint32_t)counter; } INLINE uint32_t counter_high(uint64_t counter) { return (uint32_t)(counter >> 32); } INLINE uint32_t load32(const void *src) { const uint8_t *p = (const uint8_t *)src; return ((uint32_t)(p[0]) << 0) | ((uint32_t)(p[1]) << 8) | ((uint32_t)(p[2]) << 16) | ((uint32_t)(p[3]) << 24); } INLINE void load_key_words(const uint8_t key[BLAKE3_KEY_LEN], uint32_t key_words[8]) { key_words[0] = load32(&key[0 * 4]); key_words[1] = load32(&key[1 * 4]); key_words[2] = load32(&key[2 * 4]); key_words[3] = load32(&key[3 * 4]); key_words[4] = load32(&key[4 * 4]); key_words[5] = load32(&key[5 * 4]); key_words[6] = load32(&key[6 * 4]); key_words[7] = load32(&key[7 * 4]); } INLINE void store32(void *dst, uint32_t w) { uint8_t *p = (uint8_t *)dst; p[0] = (uint8_t)(w >> 0); p[1] = (uint8_t)(w >> 8); p[2] = (uint8_t)(w >> 16); p[3] = (uint8_t)(w >> 24); } INLINE void store_cv_words(uint8_t bytes_out[32], uint32_t cv_words[8]) { store32(&bytes_out[0 * 4], cv_words[0]); store32(&bytes_out[1 * 4], cv_words[1]); store32(&bytes_out[2 * 4], cv_words[2]); store32(&bytes_out[3 * 4], cv_words[3]); store32(&bytes_out[4 * 4], cv_words[4]); store32(&bytes_out[5 * 4], cv_words[5]); store32(&bytes_out[6 * 4], cv_words[6]); store32(&bytes_out[7 * 4], cv_words[7]); } void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); size_t blake3_simd_degree(void); void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #if defined(IS_X86) #if !defined(BLAKE3_NO_SSE2) extern "C" void blake3_compress_in_place_sse2(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); extern "C" void blake3_compress_xof_sse2(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); extern "C" void blake3_hash_many_sse2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE2)) #if !defined(BLAKE3_NO_SSE41) extern "C" void blake3_compress_in_place_sse41(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); extern "C" void blake3_compress_xof_sse41(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); extern "C" void blake3_hash_many_sse41(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE41)) #if !defined(BLAKE3_NO_AVX2) extern "C" void blake3_hash_many_avx2(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX2)) #if !defined(BLAKE3_NO_AVX512) extern "C" void blake3_compress_in_place_avx512(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags); extern "C" void blake3_compress_xof_avx512(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]); extern "C" void blake3_hash_many_avx512(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX512)) #endif // corresponds to #if (#if defined(IS_X86)) #if defined(BLAKE3_USE_NEON) void blake3_hash_many_neon(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out); #endif // corresponds to #if (#if defined(BLAKE3_USE_NEON)) #if defined(IS_X86) #if defined(_MSC_VER) #include #elif defined(__GNUC__) #include #else #error "Unimplemented!" #endif // corresponds to #if (#if defined(_MSC_VER)) #endif // corresponds to #if (#if defined(IS_X86)) #define MAYBE_UNUSED(x) (void)((x)) #if defined(IS_X86) static uint64_t xgetbv() { #if defined(_MSC_VER) return _xgetbv(0); #else uint32_t eax = 0, edx = 0; __asm__ __volatile__("xgetbv\n" : "=a"(eax), "=d"(edx) : "c"(0)); return ((uint64_t)edx << 32) | eax; #endif // corresponds to #if (#if defined(_MSC_VER)) } static void cpuid(uint32_t out[4], uint32_t id) { #if defined(_MSC_VER) __cpuid((int *)out, id); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id)); #endif // corresponds to #if (#if defined(_MSC_VER)) } static void cpuidex(uint32_t out[4], uint32_t id, uint32_t sid) { #if defined(_MSC_VER) __cpuidex((int *)out, id, sid); #elif defined(__i386__) || defined(_M_IX86) __asm__ __volatile__("movl %%ebx, %1\n" "cpuid\n" "xchgl %1, %%ebx\n" : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #else __asm__ __volatile__("cpuid\n" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(id), "c"(sid)); #endif // corresponds to #if (#if defined(_MSC_VER)) } #endif // corresponds to #if (#if defined(IS_X86)) #define FRANZFIX #define SSE2 1 #define SSSE3 2 #define SSE41 4 #define AVX 8 #define AVX2 16 #define AVX512F 32 #define AVX512VL 64 #define UNDEFINED 1<<30 #ifdef FRANZFIX #else enum cpu_feature { SSE2 = 1 << 0, SSSE3 = 1 << 1, SSE41 = 1 << 2, AVX = 1 << 3, AVX2 = 1 << 4, AVX512F = 1 << 5, AVX512VL = 1 << 6, UNDEFINED = 1 << 30 }; #endif // corresponds to #ifdef (#ifdef FRANZFIX) #if !defined(BLAKE3_TESTING) static #endif // corresponds to #if (#if !defined(BLAKE3_TESTING)) #ifdef FRANZFIX uint32_t g_cpu_features = UNDEFINED; #else enum cpu_feature g_cpu_features = UNDEFINED; #endif // corresponds to #ifdef (#ifdef FRANZFIX) #if !defined(BLAKE3_TESTING) static #endif // corresponds to #if (#if !defined(BLAKE3_TESTING)) #ifdef FRANZFIX uint32_t #else enum cpu_feature #endif // corresponds to #ifdef (#ifdef FRANZFIX) get_cpu_features() { if (g_cpu_features != UNDEFINED) { return g_cpu_features; } else { #if defined(IS_X86) uint32_t regs[4] = {0}; uint32_t *eax = ®s[0], *ebx = ®s[1], *ecx = ®s[2], *edx = ®s[3]; (void)edx; #ifdef FRANZFIX uint32_t features = 0; #else enum cpu_feature features = 0; #endif // corresponds to #ifdef (#ifdef FRANZFIX) cpuid(regs, 0); const int max_id = *eax; cpuid(regs, 1); #if defined(__amd64__) || defined(_M_X64) features |= SSE2; #else if (*edx & (1UL << 26)) features |= SSE2; #endif // corresponds to #if (#if defined(__amd64__) || defined(_M_X64)) if (*ecx & (1UL << 0)) features |= SSSE3; if (*ecx & (1UL << 19)) features |= SSE41; if (*ecx & (1UL << 27)) { const uint64_t mask = xgetbv(); if ((mask & 6) == 6) { if (*ecx & (1UL << 28)) features |= AVX; if (max_id >= 7) { cpuidex(regs, 7, 0); if (*ebx & (1UL << 5)) features |= AVX2; if ((mask & 224) == 224) { if (*ebx & (1UL << 31)) features |= AVX512VL; if (*ebx & (1UL << 16)) features |= AVX512F; } } } } g_cpu_features = features; if (flagdebug3) myprintf("00009: CPU feature %04X\n",features); return features; #else return 0; #endif // corresponds to #if (#if defined(IS_X86)) } } void blake3_compress_in_place(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { #if defined(IS_X86) #ifdef FRANZFIX uint32_t features = get_cpu_features(); #else const enum cpu_feature features = get_cpu_features(); #endif // corresponds to #ifdef (#ifdef FRANZFIX) MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if (features & AVX512VL) { blake3_compress_in_place_avx512(cv, block, block_len, counter, flags); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX512)) #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_compress_in_place_sse41(cv, block, block_len, counter, flags); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE41)) #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_compress_in_place_sse2(cv, block, block_len, counter, flags); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE2)) #endif // corresponds to #if (#if defined(IS_X86)) blake3_compress_in_place_portable(cv, block, block_len, counter, flags); } void blake3_compress_xof(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { #if defined(IS_X86) #ifdef FRANZFIX const uint32_t features = get_cpu_features(); #else const enum cpu_feature features = get_cpu_features(); #endif // corresponds to #ifdef (#ifdef FRANZFIX) MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if (features & AVX512VL) { blake3_compress_xof_avx512(cv, block, block_len, counter, flags, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX512)) #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_compress_xof_sse41(cv, block, block_len, counter, flags, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE41)) #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_compress_xof_sse2(cv, block, block_len, counter, flags, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE2)) #endif // corresponds to #if (#if defined(IS_X86)) blake3_compress_xof_portable(cv, block, block_len, counter, flags, out); } void blake3_hash_many(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { #if defined(IS_X86) #ifdef FRANZFIX const uint32_t features = get_cpu_features(); #else const enum cpu_feature features = get_cpu_features(); #endif // corresponds to #ifdef (#ifdef FRANZFIX) MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { blake3_hash_many_avx512(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX512)) #if !defined(BLAKE3_NO_AVX2) if (features & AVX2) { blake3_hash_many_avx2(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX2)) #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { blake3_hash_many_sse41(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE41)) #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { blake3_hash_many_sse2(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE2)) #endif // corresponds to #if (#if defined(IS_X86)) #if defined(BLAKE3_USE_NEON) blake3_hash_many_neon(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); return; #endif // corresponds to #if (#if defined(BLAKE3_USE_NEON)) blake3_hash_many_portable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); } size_t blake3_simd_degree(void) { #if defined(IS_X86) #ifdef FRANZFIX uint32_t features = get_cpu_features(); #else const enum cpu_feature features = get_cpu_features(); #endif // corresponds to #ifdef (#ifdef FRANZFIX) MAYBE_UNUSED(features); #if !defined(BLAKE3_NO_AVX512) if ((features & (AVX512F|AVX512VL)) == (AVX512F|AVX512VL)) { return 16; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX512)) #if !defined(BLAKE3_NO_AVX2) if (features & AVX2) { return 8; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_AVX2)) #if !defined(BLAKE3_NO_SSE41) if (features & SSE41) { return 4; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE41)) #if !defined(BLAKE3_NO_SSE2) if (features & SSE2) { return 4; } #endif // corresponds to #if (#if !defined(BLAKE3_NO_SSE2)) #endif // corresponds to #if (#if defined(IS_X86)) #if defined(BLAKE3_USE_NEON) return 4; #endif // corresponds to #if (#if defined(BLAKE3_USE_NEON)) return 1; } INLINE uint32_t rotr32(uint32_t w, uint32_t c) { return (w >> c) | (w << (32 - c)); } INLINE void g(uint32_t *state, size_t a, size_t b, size_t c, size_t d, uint32_t x, uint32_t y) { state[a] = state[a] + state[b] + x; state[d] = rotr32(state[d] ^ state[a], 16); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 12); state[a] = state[a] + state[b] + y; state[d] = rotr32(state[d] ^ state[a], 8); state[c] = state[c] + state[d]; state[b] = rotr32(state[b] ^ state[c], 7); } INLINE void round_fn(uint32_t state[16], const uint32_t *msg, size_t round) { const uint8_t *schedule = MSG_SCHEDULE[round]; g(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]); g(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]); g(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]); g(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]); g(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]); g(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]); g(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]); g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]); } INLINE void compress_pre(uint32_t state[16], const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t block_words[16]; block_words[0] = load32(block + 4 * 0); block_words[1] = load32(block + 4 * 1); block_words[2] = load32(block + 4 * 2); block_words[3] = load32(block + 4 * 3); block_words[4] = load32(block + 4 * 4); block_words[5] = load32(block + 4 * 5); block_words[6] = load32(block + 4 * 6); block_words[7] = load32(block + 4 * 7); block_words[8] = load32(block + 4 * 8); block_words[9] = load32(block + 4 * 9); block_words[10] = load32(block + 4 * 10); block_words[11] = load32(block + 4 * 11); block_words[12] = load32(block + 4 * 12); block_words[13] = load32(block + 4 * 13); block_words[14] = load32(block + 4 * 14); block_words[15] = load32(block + 4 * 15); state[0] = cv[0]; state[1] = cv[1]; state[2] = cv[2]; state[3] = cv[3]; state[4] = cv[4]; state[5] = cv[5]; state[6] = cv[6]; state[7] = cv[7]; state[8] = IV[0]; state[9] = IV[1]; state[10] = IV[2]; state[11] = IV[3]; state[12] = counter_low(counter); state[13] = counter_high(counter); state[14] = (uint32_t)block_len; state[15] = (uint32_t)flags; round_fn(state, &block_words[0], 0); round_fn(state, &block_words[0], 1); round_fn(state, &block_words[0], 2); round_fn(state, &block_words[0], 3); round_fn(state, &block_words[0], 4); round_fn(state, &block_words[0], 5); round_fn(state, &block_words[0], 6); } void blake3_compress_in_place_portable(uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); cv[0] = state[0] ^ state[8]; cv[1] = state[1] ^ state[9]; cv[2] = state[2] ^ state[10]; cv[3] = state[3] ^ state[11]; cv[4] = state[4] ^ state[12]; cv[5] = state[5] ^ state[13]; cv[6] = state[6] ^ state[14]; cv[7] = state[7] ^ state[15]; } void blake3_compress_xof_portable(const uint32_t cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags, uint8_t out[64]) { uint32_t state[16]; compress_pre(state, cv, block, block_len, counter, flags); store32(&out[0 * 4], state[0] ^ state[8]); store32(&out[1 * 4], state[1] ^ state[9]); store32(&out[2 * 4], state[2] ^ state[10]); store32(&out[3 * 4], state[3] ^ state[11]); store32(&out[4 * 4], state[4] ^ state[12]); store32(&out[5 * 4], state[5] ^ state[13]); store32(&out[6 * 4], state[6] ^ state[14]); store32(&out[7 * 4], state[7] ^ state[15]); store32(&out[8 * 4], state[8] ^ cv[0]); store32(&out[9 * 4], state[9] ^ cv[1]); store32(&out[10 * 4], state[10] ^ cv[2]); store32(&out[11 * 4], state[11] ^ cv[3]); store32(&out[12 * 4], state[12] ^ cv[4]); store32(&out[13 * 4], state[13] ^ cv[5]); store32(&out[14 * 4], state[14] ^ cv[6]); store32(&out[15 * 4], state[15] ^ cv[7]); } INLINE void hash_one_portable(const uint8_t *input, size_t blocks, const uint32_t key[8], uint64_t counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t out[BLAKE3_OUT_LEN]) { uint32_t cv[8]; memcpy(cv, key, BLAKE3_KEY_LEN); uint8_t block_flags = flags | flags_start; while (blocks > 0) { if (blocks == 1) { block_flags |= flags_end; } blake3_compress_in_place_portable(cv, input, BLAKE3_BLOCK_LEN, counter, block_flags); input = &input[BLAKE3_BLOCK_LEN]; blocks -= 1; block_flags = flags; } store_cv_words(out, cv); } void blake3_hash_many_portable(const uint8_t *const *inputs, size_t num_inputs, size_t blocks, const uint32_t key[8], uint64_t counter, bool increment_counter, uint8_t flags, uint8_t flags_start, uint8_t flags_end, uint8_t *out) { while (num_inputs > 0) { hash_one_portable(inputs[0], blocks, key, counter, flags, flags_start, flags_end, out); if (increment_counter) { counter += 1; } inputs += 1; num_inputs -= 1; out = &out[BLAKE3_OUT_LEN]; } } INLINE void chunk_state_init(blake3_chunk_state *self, const uint32_t key[8], uint8_t flags) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; self->blocks_compressed = 0; self->flags = flags; } INLINE void chunk_state_reset(blake3_chunk_state *self, const uint32_t key[8], uint64_t chunk_counter) { memcpy(self->cv, key, BLAKE3_KEY_LEN); self->chunk_counter = chunk_counter; self->blocks_compressed = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); self->buf_len = 0; } INLINE size_t chunk_state_len(const blake3_chunk_state *self) { return (BLAKE3_BLOCK_LEN * (size_t)self->blocks_compressed) + ((size_t)self->buf_len); } INLINE size_t chunk_state_fill_buf(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { size_t take = BLAKE3_BLOCK_LEN - ((size_t)self->buf_len); if (take > input_len) { take = input_len; } uint8_t *dest = self->buf + ((size_t)self->buf_len); memcpy(dest, input, take); self->buf_len += (uint8_t)take; return take; } INLINE uint8_t chunk_state_maybe_start_flag(const blake3_chunk_state *self) { if (self->blocks_compressed == 0) { return CHUNK_START; } else { return 0; } } typedef struct { uint32_t input_cv[8]; uint64_t counter; uint8_t block[BLAKE3_BLOCK_LEN]; uint8_t block_len; uint8_t flags; } output_t; INLINE output_t make_output(const uint32_t input_cv[8], const uint8_t block[BLAKE3_BLOCK_LEN], uint8_t block_len, uint64_t counter, uint8_t flags) { output_t ret; memcpy(ret.input_cv, input_cv, 32); memcpy(ret.block, block, BLAKE3_BLOCK_LEN); ret.block_len = block_len; ret.counter = counter; ret.flags = flags; return ret; } INLINE void output_chaining_value(const output_t *self, uint8_t cv[32]) { uint32_t cv_words[8]; memcpy(cv_words, self->input_cv, 32); blake3_compress_in_place(cv_words, self->block, self->block_len, self->counter, self->flags); store_cv_words(cv, cv_words); } INLINE void output_root_bytes(const output_t *self, uint64_t seek, uint8_t *out, size_t out_len) { uint64_t output_block_counter = seek / 64; size_t offset_within_block = seek % 64; uint8_t wide_buf[64]; while (out_len > 0) { blake3_compress_xof(self->input_cv, self->block, self->block_len, output_block_counter, self->flags | ROOT, wide_buf); size_t available_bytes = 64 - offset_within_block; size_t memcpy_len; if (out_len > available_bytes) { memcpy_len = available_bytes; } else { memcpy_len = out_len; } memcpy(out, wide_buf + offset_within_block, memcpy_len); out += memcpy_len; out_len -= memcpy_len; output_block_counter += 1; offset_within_block = 0; } } INLINE void chunk_state_update(blake3_chunk_state *self, const uint8_t *input, size_t input_len) { if (self->buf_len > 0) { size_t take = chunk_state_fill_buf(self, input, input_len); input += take; input_len -= take; if (input_len > 0) { blake3_compress_in_place( self->cv, self->buf, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; self->buf_len = 0; memset(self->buf, 0, BLAKE3_BLOCK_LEN); } } while (input_len > BLAKE3_BLOCK_LEN) { blake3_compress_in_place(self->cv, input, BLAKE3_BLOCK_LEN, self->chunk_counter, self->flags | chunk_state_maybe_start_flag(self)); self->blocks_compressed += 1; input += BLAKE3_BLOCK_LEN; input_len -= BLAKE3_BLOCK_LEN; } size_t take = chunk_state_fill_buf(self, input, input_len); input += take; input_len -= take; } INLINE output_t chunk_state_output(const blake3_chunk_state *self) { uint8_t block_flags = self->flags | chunk_state_maybe_start_flag(self) | CHUNK_END; return make_output(self->cv, self->buf, self->buf_len, self->chunk_counter, block_flags); } INLINE output_t parent_output(const uint8_t block[BLAKE3_BLOCK_LEN], const uint32_t key[8], uint8_t flags) { return make_output(key, block, BLAKE3_BLOCK_LEN, 0, flags | PARENT); } INLINE size_t left_len(size_t content_len) { size_t full_chunks = (content_len - 1) / BLAKE3_CHUNK_LEN; return round_down_to_power_of_2(full_chunks) * BLAKE3_CHUNK_LEN; } INLINE size_t compress_chunks_parallel(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(0 < input_len); assert(input_len <= MAX_SIMD_DEGREE * BLAKE3_CHUNK_LEN); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) const uint8_t *chunks_array[MAX_SIMD_DEGREE]; size_t input_position = 0; size_t chunks_array_len = 0; while (input_len - input_position >= BLAKE3_CHUNK_LEN) { chunks_array[chunks_array_len] = &input[input_position]; input_position += BLAKE3_CHUNK_LEN; chunks_array_len += 1; } blake3_hash_many(chunks_array, chunks_array_len, BLAKE3_CHUNK_LEN / BLAKE3_BLOCK_LEN, key, chunk_counter, true, flags, CHUNK_START, CHUNK_END, out); if (input_len > input_position) { uint64_t counter = chunk_counter + (uint64_t)chunks_array_len; blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, key, flags); chunk_state.chunk_counter = counter; chunk_state_update(&chunk_state, &input[input_position], input_len - input_position); output_t output = chunk_state_output(&chunk_state); output_chaining_value(&output, &out[chunks_array_len * BLAKE3_OUT_LEN]); return chunks_array_len + 1; } else { return chunks_array_len; } } INLINE size_t compress_parents_parallel(const uint8_t *child_chaining_values, size_t num_chaining_values, const uint32_t key[8], uint8_t flags, uint8_t *out) { #if defined(BLAKE3_TESTING) assert(2 <= num_chaining_values); assert(num_chaining_values <= 2 * MAX_SIMD_DEGREE_OR_2); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) const uint8_t *parents_array[MAX_SIMD_DEGREE_OR_2]; size_t parents_array_len = 0; while (num_chaining_values - (2 * parents_array_len) >= 2) { parents_array[parents_array_len] = &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN]; parents_array_len += 1; } blake3_hash_many(parents_array, parents_array_len, 1, key, 0, false, flags | PARENT, 0, 0, out); if (num_chaining_values > 2 * parents_array_len) { memcpy(&out[parents_array_len * BLAKE3_OUT_LEN], &child_chaining_values[2 * parents_array_len * BLAKE3_OUT_LEN], BLAKE3_OUT_LEN); return parents_array_len + 1; } else { return parents_array_len; } } static size_t blake3_compress_subtree_wide(const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t *out) { if (input_len <= blake3_simd_degree() * BLAKE3_CHUNK_LEN) { return compress_chunks_parallel(input, input_len, key, chunk_counter, flags, out); } size_t left_input_len = left_len(input_len); size_t right_input_len = input_len - left_input_len; const uint8_t *right_input = &input[left_input_len]; uint64_t right_chunk_counter = chunk_counter + (uint64_t)(left_input_len / BLAKE3_CHUNK_LEN); uint8_t cv_array[2 * MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t degree = blake3_simd_degree(); if (left_input_len > BLAKE3_CHUNK_LEN && degree == 1) { degree = 2; } uint8_t *right_cvs = &cv_array[degree * BLAKE3_OUT_LEN]; size_t left_n = blake3_compress_subtree_wide(input, left_input_len, key, chunk_counter, flags, cv_array); size_t right_n = blake3_compress_subtree_wide( right_input, right_input_len, key, right_chunk_counter, flags, right_cvs); if (left_n == 1) { memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); return 2; } size_t num_chaining_values = left_n + right_n; return compress_parents_parallel(cv_array, num_chaining_values, key, flags, out); } INLINE void compress_subtree_to_parent_node( const uint8_t *input, size_t input_len, const uint32_t key[8], uint64_t chunk_counter, uint8_t flags, uint8_t out[2 * BLAKE3_OUT_LEN]) { #if defined(BLAKE3_TESTING) assert(input_len > BLAKE3_CHUNK_LEN); #endif // corresponds to #if (#if defined(BLAKE3_TESTING)) uint8_t cv_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN]; size_t num_cvs = blake3_compress_subtree_wide(input, input_len, key, chunk_counter, flags, cv_array); uint8_t out_array[MAX_SIMD_DEGREE_OR_2 * BLAKE3_OUT_LEN / 2]; while (num_cvs > 2) { num_cvs = compress_parents_parallel(cv_array, num_cvs, key, flags, out_array); memcpy(cv_array, out_array, num_cvs * BLAKE3_OUT_LEN); } memcpy(out, cv_array, 2 * BLAKE3_OUT_LEN); } INLINE void hasher_init_base(blake3_hasher *self, const uint32_t key[8], uint8_t flags) { memcpy(self->key, key, BLAKE3_KEY_LEN); chunk_state_init(&self->chunk, key, flags); self->cv_stack_len = 0; } void blake3_hasher_init(blake3_hasher *self) { hasher_init_base(self, IV, 0); } void blake3_hasher_init_derive_key_raw(blake3_hasher *self, const void *context, size_t context_len) { blake3_hasher context_hasher; hasher_init_base(&context_hasher, IV, DERIVE_KEY_CONTEXT); blake3_hasher_update(&context_hasher, context, context_len); uint8_t context_key[BLAKE3_KEY_LEN]; blake3_hasher_finalize(&context_hasher, context_key, BLAKE3_KEY_LEN); uint32_t context_key_words[8]; load_key_words(context_key, context_key_words); hasher_init_base(self, context_key_words, DERIVE_KEY_MATERIAL); } void blake3_hasher_init_derive_key(blake3_hasher *self, const char *context) { blake3_hasher_init_derive_key_raw(self, context, strlen(context)); } INLINE void hasher_merge_cv_stack(blake3_hasher *self, uint64_t total_len) { size_t post_merge_stack_len = (size_t)popcnt(total_len); while (self->cv_stack_len > post_merge_stack_len) { uint8_t *parent_node = &self->cv_stack[(self->cv_stack_len - 2) * BLAKE3_OUT_LEN]; output_t output = parent_output(parent_node, self->key, self->chunk.flags); output_chaining_value(&output, parent_node); self->cv_stack_len -= 1; } } INLINE void hasher_push_cv(blake3_hasher *self, uint8_t new_cv[BLAKE3_OUT_LEN], uint64_t chunk_counter) { hasher_merge_cv_stack(self, chunk_counter); memcpy(&self->cv_stack[self->cv_stack_len * BLAKE3_OUT_LEN], new_cv, BLAKE3_OUT_LEN); self->cv_stack_len += 1; } void blake3_hasher_update(blake3_hasher *self, const void *input, size_t input_len) { if (input_len == 0) { return; } const uint8_t *input_bytes = (const uint8_t *)input; if (chunk_state_len(&self->chunk) > 0) { size_t take = BLAKE3_CHUNK_LEN - chunk_state_len(&self->chunk); if (take > input_len) { take = input_len; } chunk_state_update(&self->chunk, input_bytes, take); input_bytes += take; input_len -= take; if (input_len > 0) { output_t output = chunk_state_output(&self->chunk); uint8_t chunk_cv[32]; output_chaining_value(&output, chunk_cv); hasher_push_cv(self, chunk_cv, self->chunk.chunk_counter); chunk_state_reset(&self->chunk, self->key, self->chunk.chunk_counter + 1); } else { return; } } while (input_len > BLAKE3_CHUNK_LEN) { size_t subtree_len = round_down_to_power_of_2(input_len); uint64_t count_so_far = self->chunk.chunk_counter * BLAKE3_CHUNK_LEN; while ((((uint64_t)(subtree_len - 1)) & count_so_far) != 0) { subtree_len /= 2; } uint64_t subtree_chunks = subtree_len / BLAKE3_CHUNK_LEN; if (subtree_len <= BLAKE3_CHUNK_LEN) { blake3_chunk_state chunk_state; chunk_state_init(&chunk_state, self->key, self->chunk.flags); chunk_state.chunk_counter = self->chunk.chunk_counter; chunk_state_update(&chunk_state, input_bytes, subtree_len); output_t output = chunk_state_output(&chunk_state); uint8_t cv[BLAKE3_OUT_LEN]; output_chaining_value(&output, cv); hasher_push_cv(self, cv, chunk_state.chunk_counter); } else { uint8_t cv_pair[2 * BLAKE3_OUT_LEN]; compress_subtree_to_parent_node(input_bytes, subtree_len, self->key, self->chunk.chunk_counter, self->chunk.flags, cv_pair); hasher_push_cv(self, cv_pair, self->chunk.chunk_counter); hasher_push_cv(self, &cv_pair[BLAKE3_OUT_LEN], self->chunk.chunk_counter + (subtree_chunks / 2)); } self->chunk.chunk_counter += subtree_chunks; input_bytes += subtree_len; input_len -= subtree_len; } if (input_len > 0) { chunk_state_update(&self->chunk, input_bytes, input_len); hasher_merge_cv_stack(self, self->chunk.chunk_counter); } } void blake3_hasher_finalize(const blake3_hasher *self, uint8_t *out, size_t out_len) { blake3_hasher_finalize_seek(self, 0, out, out_len); } void blake3_hasher_finalize_seek(const blake3_hasher *self, uint64_t seek, uint8_t *out, size_t out_len) { if (out_len == 0) { return; } if (self->cv_stack_len == 0) { output_t output = chunk_state_output(&self->chunk); output_root_bytes(&output, seek, out, out_len); return; } output_t output; size_t cvs_remaining; if (chunk_state_len(&self->chunk) > 0) { cvs_remaining = self->cv_stack_len; output = chunk_state_output(&self->chunk); } else { cvs_remaining = self->cv_stack_len - 2; output = parent_output(&self->cv_stack[cvs_remaining * 32], self->key, self->chunk.flags); } while (cvs_remaining > 0) { cvs_remaining -= 1; uint8_t parent_block[BLAKE3_BLOCK_LEN]; memcpy(parent_block, &self->cv_stack[cvs_remaining * 32], 32); output_chaining_value(&output, &parent_block[32]); output = parent_output(parent_block, self->key, self->chunk.flags); } output_root_bytes(&output, seek, out, out_len); } #endif ///HWBLAKE3 // corresponds to #if (#if !defined(HWBLAKE3)) /// LICENSE_END.15 /// LICENSE_START.16 /** * The Whirlpool hashing function. * *

* References * *

" : migliaia(entry.size), entry.name.c_str(), "\n"); if (i_more) { if (!more(buffer)) break; } else myprintf(buffer); } // Se la modalità ricorsiva è attivata, esplora le sottodirectory if (recursive) { for (const auto& entry : entries) { if (entry.is_directory) { std::string subdir_path; if (current_path=="") subdir_path = entry.name; else subdir_path = current_path + "/" + entry.name; if (flagdebug5) myprintf("\n--- Entering directory: %s more %d---\n", subdir_path.c_str(),int(i_more)); dir(subdir_path.c_str(), true, i_more); } } } // Ripristina il percorso originale se era stato cambiato if (!path_str.empty() && path_str[0] != '-') current_path = temp_path; } void dirprimolivello() { std::vector entries; for (DTMap::const_iterator file = (*pjidac).dt.begin(); file != (*pjidac).dt.end(); ++file) if (file->second.date != 0) if (isdirectory(file->first)) if (isfirstlevel(file->first)) { direntry entry; entry.name = file->first; entry.size = file->second.size; entry.date = file->second.date; entry.is_directory = true; entries.push_back(entry); } // Stampa il contenuto della directory corrente for (const auto& entry : entries) { char buffer[4096]; snprintf(buffer, sizeof(buffer), "%s %21s %s%s", dateToString(flagutc, entry.date).c_str(), entry.is_directory ? "" : migliaia(entry.size), entry.name.c_str(), "\n"); myprintf(buffer); } } bool handle_wildcard_cd(const std::string& path_str) { if (flagdebug5) myprintf("DEBUG WILDCARD: Original path_str='%s'\n", path_str.c_str()); // Special handling for drive letter paths std::string search_pattern = path_str; if (search_pattern.length() == 2 && search_pattern[1] == ':') search_pattern += "*"; // Find prefix for matching size_t star_pos = search_pattern.find('*'); std::string prefix = (star_pos != std::string::npos) ? search_pattern.substr(0, star_pos) : search_pattern; if (flagdebug5) myprintf("DEBUG WILDCARD: Adjusted prefix='%s'\n", prefix.c_str()); std::vector matches; for (DTMap::const_iterator file = (*pjidac).dt.begin(); file != (*pjidac).dt.end(); ++file) { if (file->first.empty() || file->first.back() != '/') continue; std::string dir_name = file->first; // Remove trailing slash for comparison if (!dir_name.empty() && dir_name.back() == '/') dir_name.pop_back(); #ifdef _WIN32 bool match = stringtolower(dir_name).find(stringtolower(prefix)) == 0; #else bool match = dir_name.find(prefix) == 0; #endif if (match) { matches.push_back(file->first); if (flagdebug5) myprintf("DEBUG WILDCARD: Match found='%s'\n", file->first.c_str()); } } if (matches.size() == 1) { current_path = matches[0]; if (!current_path.empty() && current_path.back() == '/') current_path.pop_back(); if (flagdebug5) myprintf("DEBUG WILDCARD: Single match, changing to '%s'\n", current_path.c_str()); return true; } if (flagdebug5) myprintf("DEBUG WILDCARD: No unique match found\n"); return false; } bool cd(const char* path) { if (flagdebug5) { myprintf("DEBUG CD: Entering cd() with full path='%s' current_path %s\n", path,current_path.c_str()); } std::string path_str = path; if (flagdebug5) myprintf("DEBUG CD: Initial path_str='%s', length=%d\n", path_str.c_str(), path_str.length()); // Replace backslashes with forward slashes std::replace(path_str.begin(), path_str.end(), '\\', '/'); if (flagdebug5) myprintf("DEBUG CD: Normalized path='%s'\n", path_str.c_str()); // Special root and parent directory handling if (path_str == "/" || path_str == "..") { if (path_str == "/") { if (flagdebug5) myprintf("DEBUG CD: Changing to root directory\n"); current_path.clear(); return true; } if (flagdebug5) myprintf("DEBUG CD: Moving up from current path='%s'\n", current_path.c_str()); current_path = find_previous_slash(current_path); return true; } // Normalize the path for absolute paths std::string search_path = path_str; if (path_str[0] == '/') { ///search_path = path_str.substr(1); // Remove leading slash for comparison } else { ///printf("_____ path_str %s current_path %s\n",path_str.c_str(),current_path.c_str()); // For relative paths, combine with current path ///if (!current_path.empty()) ///search_path = current_path + "/" + path_str; } // Remove trailing slash if present if (!search_path.empty() && search_path.back() == '/') search_path.pop_back(); if (flagdebug5) myprintf("DEBUG CD: (2) Search path='%s'\n", search_path.c_str()); // Look for exact matches first for (DTMap::const_iterator file = (*pjidac).dt.begin(); file != (*pjidac).dt.end(); ++file) { std::string dir_name = file->first; if (dir_name.empty() || dir_name.back() != '/') continue; // Remove trailing slash for comparison if (dir_name.back() == '/') dir_name.pop_back(); #ifdef _WIN32 if (stringtolower(dir_name) == stringtolower(search_path)) { #else if (dir_name == search_path) { #endif current_path = search_path; if (flagdebug5) myprintf("DEBUG CD: Exact match found, changing to '%s'\n", current_path.c_str()); return true; } } // If no exact match, try wildcard matching if (path_str.find('*') != std::string::npos) return handle_wildcard_cd(path_str); // Look for partial matches (helpful for directories without full paths) std::string partial_search = search_path; if (partial_search.find('/') == std::string::npos) { for (DTMap::const_iterator file = (*pjidac).dt.begin(); file != (*pjidac).dt.end(); ++file) { std::string dir_name = file->first; if (dir_name.empty() || dir_name.back() != '/') continue; size_t last_slash = dir_name.rfind('/', dir_name.length() - 2); std::string last_component = dir_name.substr( last_slash == std::string::npos ? 0 : last_slash + 1, dir_name.length() - (last_slash == std::string::npos ? 1 : last_slash + 2) ); #ifdef _WIN32 if (stringtolower(last_component) == stringtolower(partial_search)) { #else if (last_component == partial_search) { #endif current_path = dir_name; if (!current_path.empty() && current_path.back() == '/') current_path.pop_back(); if (flagdebug5) myprintf("DEBUG CD: Partial match found, changing to '%s'\n", current_path.c_str()); return true; } } } if (flagdebug5) myprintf("DEBUG CD: No matching directory found\n"); return false; } int getpipednumber(const std::string& str) { if (str.empty() || str.back() != '|') return -1; string numerini; for (size_t i = 0; i < str.size() - 1; ++i) { if (!isdigit(str[i])) return -1; numerini+=str[i]; } return myatoll(numerini.c_str()); } void x(const char* filename) { string relative=getuserinput("Where to extract? (default: current): ","./"); relative=wintolinuxpath(relative); if (relative=="") return; #ifdef _WIN32 if (relative=="./") if (flaglongpath) { relative = relativetolongpath(relative); myprintf("=> Windows longpath => %Z\n", relative.c_str()); } #endif relative=includetrailingbackslash(relative); myprintf("1554: Multiple extraction in folder <<%Z>>\n",relative.c_str()); (*pjidac).files.clear(); std::string pattern = filename; bool found_any = false; int64_t sizetobeextracted =0; int selectedfolders =0; int piped=-1; if (tobeprinted.size()>0) piped=getpipednumber(filename); if (piped>-1) { string filetobegetted; if (piped=43) { string lunghezza=filetobegetted.substr(19,22); myreplace(lunghezza,".",""); myreplaceall(lunghezza," ",""); myprintf("lunghezza |%s|\n",lunghezza.c_str()); string nomefile=includetrailingbackslash(get_current_path())+filetobegetted.substr(42,filetobegetted.size()-42-1); myprintf("file |%s|\n",nomefile.c_str()); sizetobeextracted+=myatoll(lunghezza.c_str()); (*pjidac).files.push_back(nomefile); found_any=true; } } else { bool has_wildcard = (pattern.find('*') != std::string::npos); // Costruisci il percorso completo per la ricerca std::string base_path; if (pattern[0] == '/') { // Percorso assoluto base_path = pattern.substr(1); } else { // Percorso relativo base_path = current_path; if (!current_path.empty()) base_path += "/"; base_path += pattern; } // Divide il pattern in parte prefissa e suffissa attorno all'asterisco std::string prefix, suffix; if (has_wildcard) { size_t star_pos = base_path.find('*'); prefix = base_path.substr(0, star_pos); suffix = base_path.substr(star_pos + 1); } // Cerca i file che corrispondono for (DTMap::const_iterator myfile = (*pjidac).dt.begin(); myfile != (*pjidac).dt.end(); ++myfile) { bool match = false; if (has_wildcard) { std::string filename_to_check = myfile->first; #ifdef _WIN32 filename_to_check = stringtolower(filename_to_check); std::string lower_prefix = stringtolower(prefix); std::string lower_suffix = stringtolower(suffix); match = filename_to_check.find(lower_prefix) == 0 && (lower_suffix.empty() || (filename_to_check.length() >= lower_suffix.length() && filename_to_check.substr(filename_to_check.length() - lower_suffix.length()) == lower_suffix)); #else match = filename_to_check.find(prefix) == 0 && (suffix.empty() || (filename_to_check.length() >= suffix.length() && filename_to_check.substr(filename_to_check.length() - suffix.length()) == suffix)); #endif } else { #ifdef _WIN32 match = (stringtolower(myfile->first) == stringtolower(base_path)); #else match = (myfile->first == base_path); #endif } if (match) // && !isdirectory(myfile.first)) { found_any = true; if (flagverbose) myprintf("14544: X of <<%Z>>:\n%d\n", myfile->first.c_str(), myfile->second.size); if (!isdirectory(myfile->first)) sizetobeextracted+=myfile->second.size; else selectedfolders++; (*pjidac).files.push_back(myfile->first); } } } // Se abbiamo trovato dei file, procedi con l'estrazione if (found_any) xto(relative,current_path,sizetobeextracted); else myprintf("14579! No files found matching '%s'\n", filename); } }; std::string get_line_with_tab_completion(franzfilesystem& fs) { std::string current_input; int c; const char TAB = '\t'; const char BACKSPACE = 8; const char ENTER = 13; while (true) { #ifdef _WIN32 c = _getch(); #else c = linux_getch(); #endif if (c == 3) { color_restore(); myprintf("\n"); myprintf("Goodbye (Control-C detected)\n"); seppuku(); } if ((c==ENTER) || (c== '\n')) { myprintf("\n"); break; } if ((c==BACKSPACE) || (c==127)) // Linux usa 127 per backspace { if (!current_input.empty()) { current_input.pop_back(); myprintf("\b \b"); } continue; } if (c==TAB) { std::string completed = fs.handle_input(current_input); if (completed!=current_input) { for (size_t i=0;i>\n",archive.c_str()); return 2; } franzfilesystem fs; myprintf("'help' to ... get help. Ready on %s lines\n\n",migliaia((*pjidac).dt.size())); while (true) { color_green(); myprintf("[? bye exit]"); color_restore(); myprintf(" %s> ", fs.get_current_path().c_str()); fflush(stdout); std::string input = get_line_with_tab_completion(fs); if (input.empty()) continue; std::string command, arg1, arg2; parse_command(input, command, arg1, arg2); if ((command == "exit") || (command == "bye") || (command == "quit")) break; else if ((command == "help") || (command == "?")) fs.help(); else if ((command == "ls") || (command == "dir")) { bool recursive = false; const char* path = NULL; if (!arg1.empty()) { if (arg1 == "-r" || arg1 == "/r") { recursive = true; if (!arg2.empty()) path = arg2.c_str(); } else path = arg1.c_str(); } std::string temp = (path != nullptr) ? path : ""; // Evita l'errore bool needmore=false; size_t pos=temp.find("|more"); if (pos!=std::string::npos) { needmore=true; temp.erase(pos,5); while ((pos>0) && (temp[pos-1]==' ')) { temp.erase(pos-1,1); --pos; } while ((pos\n"); continue; } if (!fs.cd(arg1.c_str())) myprintf("15313$ Directory not found: %s\n", arg1.c_str()); } else if (command == "get") { if (arg1.empty()) { myprintf("Usage: get \n"); continue; } fs.x(arg1.c_str()); } else if (command == "debug5") { flagdebug5=!flagdebug5; } else { myprintf("15327$ Unknown command: %s\n", command.c_str()); myprintf("15328$ Type 'help' for list of commands\n"); } } return 0; } /// TUI ... Text User UI (like DOS :-) void hidecursor() { #ifdef _WIN32 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO cursorInfo; GetConsoleCursorInfo(hConsole, &cursorInfo); cursorInfo.bVisible = FALSE; SetConsoleCursorInfo(hConsole, &cursorInfo); #else printf("\x1B[?25l"); // Nasconde il cursore fflush(stdout); #endif } void showcursor() { #ifdef _WIN32 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO cursorInfo; GetConsoleCursorInfo(hConsole, &cursorInfo); cursorInfo.bVisible = TRUE; SetConsoleCursorInfo(hConsole, &cursorInfo); #else printf("\x1B[?25h"); // Mostra il cursore fflush(stdout); #endif } // Struttura per memorizzare i dati in modo ordinabile struct fileentry { std::string name; int64_t date; int64_t size; bool selected; bool is_directory; fileentry(const std::string& n, int64_t d, int64_t s, bool dir) : name(n), date(d), size(s), selected(false), is_directory(dir) {} }; class franztui { private: std::vector entries; // pezzi di dt int current_pos; // posizione corrente del cursore int top_line; // prima riga visualizzata int sort_mode; // modalità di ordinamento corrente int screen_width; // larghezza dello schermo int screen_height; // altezza dello schermo std::string current_path; // Percorso corrente (vuoto = root) std::vector path_positions; // Stack delle posizioni per backspace vector added_path; // path aggiungi (debug) std::string filtervisible; // rendi solo parte visibile void init_console() { #ifdef _WIN32 // Abilita il supporto ANSI su Windows HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; SetConsoleMode(hOut, dwMode); #endif } // Funzioni per la gestione dei colori void start_inverse() { printf("\033[7m"); // Inverte i colori } void end_inverse() { printf("\033[0m"); // Resetta i colori } // Funzioni di supporto per l'ordinamento static bool compare_default(const fileentry& a, const fileentry& b) { if (a.is_directory != b.is_directory) return a.is_directory > b.is_directory; #ifdef _WIN32 return stringtolower(a.name) < stringtolower(b.name); #else return a.name < b.name; #endif } static bool compare_size(const fileentry& a, const fileentry& b) { if (a.is_directory != b.is_directory) return a.is_directory > b.is_directory; if (a.is_directory) return a.name < b.name; return a.size < b.size; } static bool compare_date(const fileentry& a, const fileentry& b) { if (a.is_directory != b.is_directory) return a.is_directory > b.is_directory; if (a.is_directory) return a.name < b.name; return a.date < b.date; } // Ordina le entries secondo la modalità corrente void sort_entries() { switch(sort_mode) { case 1: // predefinito alfabetico std::sort(entries.begin(), entries.end(), compare_default); break; case 2: // dimensione crescente std::sort(entries.begin(), entries.end(), compare_size); break; case 3: // data crescente std::sort(entries.begin(), entries.end(), compare_date); break; case 4: // alfabetico inverso std::sort(entries.begin(), entries.end(), compare_default); std::reverse(entries.begin(), entries.end()); break; case 5: // dimensione decrescente std::sort(entries.begin(), entries.end(), compare_size); std::reverse(entries.begin(), entries.end()); break; case 6: // data decrescente std::sort(entries.begin(), entries.end(), compare_date); std::reverse(entries.begin(), entries.end()); break; } } void move_cursor(int row, int col) { printf("\033[%d;%dH", row, col); } // Funzione che usa un codice colore compatibile con l'inversione void my_color_green() { printf("\033[92m"); // Verde base senza modificare lo sfondo } void draw_entry(int index, bool is_current_line) { const fileentry& entry = entries[index]; std::string display_name = truncate_with_extension(entry.name, screen_width - 40); // Posizionati all'inizio della riga printf("\r"); // Clear the entire line printf("\033[K"); // Se è una directory, resettiamo prima tutti gli attributi if (entry.is_directory) color_restore(); // Applichiamo prima l'inversione se è la riga corrente if (is_current_line) start_inverse(); // Poi il colore verde per le directory if (entry.is_directory) my_color_green(); printf("%c[%c] %08d| %s %21s %s", is_current_line ? '>' : ' ', entry.selected ? 'X' : ' ', index + 1, dateToString(true, entry.date).c_str(), entry.is_directory ? "" : migliaia(entry.size), display_name.c_str() ); // Ripristiniamo nello stesso ordine: prima il colore poi l'inversione if (entry.is_directory) color_restore(); if (is_current_line) end_inverse(); fflush(stdout); } void redraw_changed_lines(int old_pos, int new_pos) { // Save cursor position printf("\033[s"); // Calculate screen positions (relative to visible area) int old_screen_pos = old_pos - top_line + 3; // +3 for header lines int new_screen_pos = new_pos - top_line + 3; // Only redraw if positions are within visible area if (old_screen_pos >= 2 && old_screen_pos <(screen_height+2)) { // Clear and redraw old position line move_cursor(old_screen_pos, 1); printf("\033[K"); // Clear the entire line draw_entry(old_pos, false); } if (new_screen_pos >= 2 && new_screen_pos <(screen_height+2)) { // Clear and redraw new position line move_cursor(new_screen_pos, 1); printf("\033[K"); // Clear the entire line draw_entry(new_pos, true); } // Restore cursor position printf("\033[u"); // Move cursor to the bottom for status line move_cursor(screen_height, 1); // Flush output to ensure immediate display fflush(stdout); } // Mostra la schermata di aiuto void show_help() { clearscreen(); printf("Help on available commands (W=%d) (H=%d)\n\n",screen_width,screen_height); printf("ESC, q, Q - Exit the program\n"); printf("ENTER - Enter a folder\n"); printf("BACKSPACE - Go back\n"); printf("Arrows - Move the cursor up/down\n"); printf("PageUp/PageDown - Scroll one page up/down\n"); printf("Home/End - Go to the beginning/end of the list\n"); printf("Space - Select/Deselect the current item\n"); printf("a - Select all items\n"); printf("n - Deselect all items\n"); printf("i - Invert selection\n"); printf("F1 - Sort alphabetically (A-Z)\n"); printf("F2 - Sort by size (ascending)\n"); printf("F3 - Sort by date (ascending)\n"); printf("F4 - Sort alphabetically (Z-A)\n"); printf("F5 - Sort by size (descending)\n"); printf("F6 - Sort by date (descending)\n"); printf("s - Search files by name\n"); printf("f - Filter files by name\n"); printf("x, g - Extract/get selected files\n"); printf(": - Go to a specific line\n"); printf("\nPress any key to return to the list..."); get_key(); } void filter_files() { move_cursor_to_input(); // Sposta il cursore sotto la riga di help showcursor(); std::string filter = getuserinput("\nFilter: ", ""); hidecursor(); if (filter.empty()) filtervisible.clear(); // Reset del filtro -> mostra tutto else { #ifdef _WIN32 filtervisible = stringtolower(filter); #else filtervisible = filter; #endif } update_entries(); show(); } // Gestisce la ricerca dei file void search_files() { move_cursor_to_input(); // Sposta il cursore sotto la riga di help std::string search_str = getuserinput("\nSearchtext: ", ""); if (search_str=="") return; #ifdef _WIN32 search_str = stringtolower(search_str); #endif // Deseleziona tutto prima di iniziare la ricerca for (fileentry& entry : entries) { std::string name = entry.name; #ifdef _WIN32 name = stringtolower(name); #endif entry.selected = (name.find(search_str) != std::string::npos); } } // Gestisce il goto line void goto_line() { std::string line_str = getuserinput("\nGoto: ", ""); if (line_str=="") return; int line = atoi(line_str.c_str()); if (line > 0 && line <= (int)entries.size()) { current_pos = line - 1; top_line = current_pos - (screen_height / 2); if (top_line < 0) top_line = 0; } } // Enumera i file selezionati per estrazione void enumerate_selected() { clearscreen(); int64_t sizetobeextracted =0; int selectedfiles =0; int selectedfolders =0; for (const fileentry& entry : entries) { if (entry.selected) { string fullfile=current_path+entry.name; sizetobeextracted+=entry.size; if (isdirectory(entry.name)) selectedfolders++; else selectedfiles++; myprintf("%Z\n",fullfile.c_str()); } } if ((selectedfiles+selectedfolders)==0) { myprintf("15597: Nothing selected\n"); printf("\nPress a key..."); get_key(); return; } printbar('-'); myprintf("15947: Selected files %s folders %s\n",migliaia(selectedfiles),migliaia(selectedfolders)); if (sizetobeextracted>0) myprintf("15948: Total files %s bytes\n",migliaia(sizetobeextracted)); string relative=getuserinput("Where to extract? (default: current): ","./"); relative=wintolinuxpath(relative); for (const fileentry& entry : entries) if (entry.selected) (*pjidac).files.push_back(current_path+entry.name); xto(relative,current_path,sizetobeextracted); printf("\nPress a key..."); get_key(); } int barcount(const string& i_stringa) { int risultato=0; for (unsigned int i=0;i= (int)entries.size()) current_pos = entries.size() - 1; } } void debug_print(const char* msg, const std::string& s) { if (flagdebug5) { printf("DEBUG: %s: '%s'\n", msg, s.c_str()); fflush(stdout); } } public: franztui(int i_width, int i_height) : current_pos(0), top_line(0), sort_mode(1), screen_width(i_width), screen_height(i_height),current_path("") { filtervisible=""; init_console(); // Carica tutti i dati dalla DTMap globale for (DTMap::const_iterator pair = (*pjidac).dt.begin(); pair != (*pjidac).dt.end(); ++pair) { bool is_dir = pair->first.back() == '/'; entries.push_back(fileentry( pair->first, pair->second.date, pair->second.size, is_dir )); } int larghezzaconsole=terminalwidth()-4; int ognipunto=0; if (larghezzaconsole>0) ognipunto=(*pjidac).dt.size()/larghezzaconsole; if (ognipunto==0) ognipunto++; bool wehaveslash=false; int contatore=0; for (DTMap::iterator a=(*pjidac).dt.begin(); a!=(*pjidac).dt.end(); ++a) { contatore++; if ((contatore%ognipunto)==0) { myprintf("+"); fflush(stdout); } if (!a->first.empty()) if (a->first[0]=='/') wehaveslash=true; ///if (iswindowspath(a->first)) generate_directories(a->first,added_path); } myprintf("\n"); /* if (added_path.size()>=1) myprintf("14500$ Entering with a cd %Z\n",added_path[0].c_str()); */ ///add_directory("/etc/"); //add_directory("/root/"); //add_directory("/usr/"); if (wehaveslash) current_path="/"; //LINUX!! // Filtra e ordina le entries per il percorso root update_entries(); } void show() { clearscreen(); string percorsotagliato=current_path.empty() ? "/" : current_path; percorsotagliato=truncate_with_extension(percorsotagliato,screen_width-20); color_yellow(); myprintf("ENTR %08d|", entries.size()); start_inverse(); myprintf("%Z\n",percorsotagliato.c_str()); end_inverse(); color_restore(); myprintf("\n"); // Mostra le entries nella pagina corrente for (int i = 0; i < screen_height - 1 && (top_line + i) < (int)entries.size(); i++) { const fileentry& entry = entries[top_line + i]; std::string display_name = truncate_with_extension(entry.name, screen_width - 40); // Se questa è la riga corrente, inizia l'inversione if (top_line + i == current_pos) start_inverse(); if (entry.is_directory) color_green(); // Formatta la riga printf("%c[%c] %08d| %s %21s %s", (top_line + i == current_pos) ? '>' : ' ', entry.selected ? 'X' : ' ', top_line + i + 1, // numerazione one-based dateToString(true, entry.date).c_str(), entry.is_directory ? "" : migliaia(entry.size), display_name.c_str() ); if (entry.is_directory) color_restore(); // Se questa è la riga corrente, termina l'inversione if (top_line + i == current_pos) end_inverse(); printf("\n"); // A capo dopo aver gestito l'inversione } // Mostra la riga informativa ///move_cursor(screen_height+2, 1); ///fflush(stdout); color_yellow(); printf("ESC/q F1-F6=Sort all not inv search filter get SPACE :go ?help\n"); color_restore(); hidecursor(); } void process() { bool running = true; show(); // Initial full draw while (running) { int ch = get_key(); bool need_full_redraw = false; switch(ch) { case 3: //control-C color_restore(); myprintf("\n"); myprintf("Goodbye(CONTROL-C detected)\n"); seppuku(); break; case 27: // ESC case 'q': case 'Q': running = false; break; case 'k': // Up arrow if (current_pos > 0) { int old_pos = current_pos; current_pos--; if (current_pos < top_line) { top_line = current_pos; need_full_redraw = true; } else redraw_changed_lines(old_pos, current_pos); } break; case 'j': // Down arrow if (current_pos < (int)entries.size() - 1) { int old_pos = current_pos; current_pos++; if (current_pos >= top_line + screen_height - 1) { top_line = current_pos - screen_height + 2; need_full_redraw = true; } else redraw_changed_lines(old_pos, current_pos); } break; case 'u': // PagSu if (current_pos > 0) { // Non fare nulla se sei già in cima int step = screen_height - 1; ///printf("\nPRE Step is %d current_pos %d currentpos-step %d top_line %d\n",step,current_pos,current_pos-step,top_line); if (current_pos - step < 0) { ///printf("\nMInore di zero\n"); current_pos = 0; top_line = 0; } else { ///printf("\nELSE\n"); current_pos -= step; top_line -= step; } if (top_line<0) top_line=0; if (current_pos<0) current_pos=0; ///printf("\nPOST current_pos %d top_line %d\n",current_pos,top_line); ///mygetch(false); ///draw_entry(current_pos, true); show(); } break; case 'd': // PagGiù ///if (current_pos != (int)entries.size() - 1) { int step = screen_height - 1; if (current_pos + step >= (int)entries.size()) { current_pos = entries.size() - 1; top_line = current_pos - screen_height + 2; if (top_line < 0) top_line = 0; } else { current_pos += step; top_line += step; } show(); } break; case 'h': // Home if (current_pos > 0) { // Non fare nulla se sei già in cima current_pos = 0; top_line = 0; ///draw_entry(current_pos, true); show(); } break; case 'e': // End if (current_pos < (int)entries.size() - 1) { // Non fare nulla se sei già in fondo current_pos = entries.size() - 1; top_line = current_pos - screen_height + 2; if (top_line < 0) top_line = 0; ///draw_entry(current_pos, true); show(); } break; case ' ': // Seleziona/Deseleziona if (current_pos < (int)entries.size()) { entries[current_pos].selected = !entries[current_pos].selected; if (current_pos < (int)entries.size() - 1) { int old_pos = current_pos; current_pos++; if (current_pos >= top_line + screen_height - 1) { top_line = current_pos - screen_height + 2; show(); } else // Redraw both the selected item and the new position redraw_changed_lines(old_pos, current_pos); } else // Just redraw the selected item if we're at the end draw_entry(current_pos, true); } break; case 'a': // Seleziona tutti for (fileentry& entry : entries) entry.selected = true; show(); break; case 'n': // Deseleziona tutti for (fileentry& entry : entries) entry.selected = false; show(); break; case 'i': // Inverti selezione for (fileentry& entry : entries) entry.selected = !entry.selected; show(); break; case 128: // F1 - Default sort case 129: // F2 - Size sort case 130: // F3 - Date sort case 131: // F4 - Default reverse case 132: // F5 - Size reverse case 133: // F6 - Date reverse sort_mode = ch == 128 ? 1 : ch == 129 ? 2 : ch == 130 ? 3 : ch == 131 ? 4 : ch == 132 ? 5 : 6; sort_entries(); show(); break; case '?': // Help case 'H': // Help (maiuscolo per evitare conflitto con Home) show_help(); show(); break; case 's': // Select showcursor(); search_files(); hidecursor(); show(); break; case 'f': // filter showcursor(); filter_files(); hidecursor(); show(); break; case ':': // Goto line showcursor(); goto_line(); hidecursor(); show(); break; case 'x': // Process selected case 'g': showcursor(); enumerate_selected(); hidecursor(); show(); break; case 13: // Invio if ((current_pos < (int)entries.size()) && (entries[current_pos].is_directory)) { enter_directory(entries[current_pos].name); show(); } break; case 8: // Backspace go_back(); show(); break; } if (need_full_redraw || needs_full_redraw(ch)) show(); } showcursor(); move_cursor_to_input(); // Posiziona il cursore quando esci } void move_cursor_to_input() { move_cursor(screen_height+4, 1); // Posiziona il cursore sotto la riga di help fflush(stdout); } bool needs_full_redraw(int ch) { return ch == ' ' || // Selection changes ch == 'a' || // Select all ch == 'n' || // Deselect all ch == 'i' || // Invert selection ch == 'u' || // Page up ch == 'd' || // Page down ch == 'h' || // Home ch == 'e' || // End (ch >= 128 && ch <= 133); // F1-F6 sort operations } void update_entries() { if (flagdebug5) { printf("*************************************\n"); printf("*************************************\n"); printf("*************************************\n"); printf("*************************************\n"); printf("DEBUG: update_entries %zu entries on current_path |%s|\n", entries.size(),current_path.c_str()); } entries.clear(); for (DTMap::const_iterator pair = (*pjidac).dt.begin(); pair != (*pjidac).dt.end(); ++pair) { if (pair->second.date!=0) { if (flagdebug5) printf("Pair.first %s current_path %s barcount %d\n",pair->first.c_str(),current_path.c_str(),barcount(pair->first)); bool flagaggiungi=true; if (pair->first!=current_path) if (starts_with(pair->first,current_path)) { string percorsino=pair->first; myreplace(percorsino,current_path,""); ///if (flagdebug5) ///printf("Percorsino 1 |%s|\n",percorsino.c_str()); if (!isdirectory(percorsino)) { int limite=0; if (iswindowspath(percorsino)) limite=1; ///printf("Perkorsino %s barcount %d limite %d\n",percorsino.c_str(),barcount(percorsino),limite); if (barcount(percorsino)>limite) flagaggiungi=false; } } /// flagaggiungi=true; if (flagaggiungi) { bool is_dir = pair->first.back() == '/'; entries.push_back(fileentry( pair->first, pair->second.date, pair->second.size, is_dir )); } ///else ///myprintf("Scarto %s\n",pair.first.c_str()); } } if (flagdebug5) { printbar('-'); for (unsigned int i=0;i100) break; } printbar('-'); } std::vector filtered; for (const auto& entry : entries) { if (is_in_current_path(entry.name)) { fileentry new_entry = entry; if (!current_path.empty()) new_entry.name = entry.name.substr(current_path.length()); if (new_entry.name!="") { bool flagaggiungi=true; if (!filtervisible.empty()) { std::string fullpath = current_path + new_entry.name; // Percorso completo #ifdef _WIN32 fullpath = stringtolower(fullpath); #endif flagaggiungi = fullpath.find(filtervisible) != std::string::npos; } if (flagaggiungi) { filtered.push_back(new_entry); debug_print("added entry", new_entry.name); } } } } if (flagdebug5) printf("DEBUG: filtered to %zu entries\n", filtered.size()); // Sostituisci le entries con quelle filtrate entries = filtered; // Cambiato da swap a assegnamento diretto // Reset della posizione current_pos = 0; top_line = 0; ///if (flagdebug5) ///getch(); // Riordina secondo il modo corrente sort_entries(); } }; int Jidac::tui() { myprintf("14235: Entering TUI\n"); if (archive=="") { myprintf("14232! archive is empty\n"); return 2; } archive=getbackupnameifany(archive); command ='l'; g_optional ="versum"; //force isselected int64_t csize=read_archive(NULL,archive.c_str());//,&errors,0,false); myprintf("\n"); if (csize==0) { myprintf("14905! Cannot open archive <<%Z>>\n",archive.c_str()); return 2; } int altezzaconsole =terminalheight(); int larghezzaconsole =terminalwidth(); if ((altezzaconsole<6) || (larghezzaconsole<21)) { myprintf("16446: Console too small Width %d Height %d\n",larghezzaconsole,altezzaconsole); return 1; } ///franztui fg(80,20); franztui fg(larghezzaconsole-21,altezzaconsole-6); fg.process(); showcursor(); return 0; } #endif // ANCIENT /* double testDeviceSpeed(FILE* file, int64_t fileSize) { const int TEST_BLOCKS = 10; const int64_t BLOCK_SIZE = 1024 * 1024; // Aumentato a 1MB per misurazioni più accurate vector speeds; for(int i = 0; i < TEST_BLOCKS; i++) { int64_t position = (fileSize / TEST_BLOCKS) * i; char* buffer = new char[BLOCK_SIZE]; fseeko(file, position, SEEK_SET); int64_t startTime = mtime(); size_t bytesRead = fread(buffer, 1, BLOCK_SIZE, file); int64_t endTime = mtime(); delete[] buffer; if(bytesRead > 0) { int64_t elapsed = endTime - startTime; if (elapsed > 0) { double speed = bytesRead / (double)elapsed; // bytes per millisecond speeds.push_back(speed); } } } // Se non abbiamo misurazioni valide, usa una stima conservativa più realistica if (speeds.empty()) return 1024 * 1024; // 1MB/s = circa 1024 bytes/ms // Rimuovi il valore più alto e più basso per evitare outlier if (speeds.size() > 2) { sort(speeds.begin(), speeds.end()); speeds.erase(speeds.begin()); // rimuovi il più lento speeds.pop_back(); // rimuovi il più veloce } // Calcola la velocità media double totalSpeed = 0; for(double speed : speeds) totalSpeed += speed; double avgSpeed = totalSpeed / speeds.size(); // Usa il 75% della velocità media per essere conservativi return avgSpeed * 0.75; } */ #ifdef _WIN32 std::string searchfile(const std::string& i_directory, const std::string& i_file) { std::wstring directory = utow(i_directory.c_str()); std::wstring file = utow(i_file.c_str()); if (directory.back() != L'\\') directory += L'\\'; std::wstring searchPath = directory + L"*.*"; WIN32_FIND_DATAW findData; HANDLE hFind = FindFirstFileW(searchPath.c_str(), &findData); if (hFind == INVALID_HANDLE_VALUE) return ""; // Restituisci una stringa vuota se errore nell'aprire la directory do { // Salta i file speciali "." e ".." if (wcscmp(findData.cFileName, L".") == 0 || wcscmp(findData.cFileName, L"..") == 0) continue; std::wstring fullPath = directory + findData.cFileName; if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { std::string result = searchfile(wtou(fullPath.c_str()), i_file); if (!result.empty()) { FindClose(hFind); // Chiudi il gestore del find prima di restituire il risultato return result; // Se un file è trovato, lo restituiamo subito } } else { // Se è un file, confronta il nome con quello cercato if (_wcsicmp(findData.cFileName, file.c_str()) == 0) { std::string result = wtou(fullPath.c_str()); // Converti il percorso in stringa if (flagdebug) myprintf("99718: Founded %s\n", result.c_str()); FindClose(hFind); // Chiudi il gestore del find prima di restituire il risultato return result; // Restituisci il percorso del file trovato } } } while (FindNextFileW(hFind, &findData)); if (GetLastError() != ERROR_NO_MORE_FILES) myprintf("99343! Filesystem error: %d\n", GetLastError()); FindClose(hFind); return ""; } bool Jidac::getmysqlfrominternet() { #ifndef _WIN32 myprintf("99736: Sorry cannot get binaries for non-Windows\n"); return false; #endif string http_mysql ="http://www.francocorbelli.it/zpaqfranz/win64/mysql.exe"; string http_mysqldump ="http://www.francocorbelli.it/zpaqfranz/win64/mysqldump.exe"; ///z:\mysql from 11.1.2-MariaDB, client 15.2 for Win64 (AMD64), source revision 9bc25d98209df6810f7a7d5e7dd3ae677a313ab5 string http_mysql_sha256 ="65DCBF7897E062A02B6018FFDE4635183E75DBCC075F21D3BE7CC5A27C45FD12"; ///z:\mysqldump from 11.1.2-MariaDB, client 10.19 for Win64 (AMD64) string http_mysqldump_sha256 ="F2114A565E8A4D23FC62FD190B59BFFF56C71B8E06B2F9308D246875708A0091"; #if defined(_WIN32) && (!defined(_WIN64)) http_mysql ="http://www.francocorbelli.it/zpaqfranz/win32/mysql.exe"; http_mysqldump ="http://www.francocorbelli.it/zpaqfranz/win32/mysqldump.exe"; #endif string randnocache="?"+generaterandomstring(10); http_mysql =http_mysql+randnocache; http_mysqldump =http_mysqldump+randnocache; string mypath=includetrailingbackslash(extractfilepath(fullzpaqexename.c_str())); string themysql =mypath+"mysql.exe"; string themysqldump =mypath+"mysqldump.exe"; myprintf("99765: Downloading mysql.exe in %Z...\n",themysql.c_str()); if (!downloadfile(http_mysql,themysql,true)) { myprintf("99678! Cannot download themysql\n"); return false; } myprintf("\n"); franz_do_hash dummy("SHA-256"); int64_t starthash=mtime(); string mysql_hash=dummy.filehash(themysql,false,starthash,prendidimensionefile(themysql.c_str())); if (mysql_hash!=http_mysql_sha256) { myprintf("99792$ mysql.exe hash invalid\n"); delete_file(themysql.c_str()); return false; } myprintf("\n"); myprintf("99776: Downloading mysqldump.exe in %Z...\n",themysqldump.c_str()); if (!downloadfile(http_mysqldump,themysqldump,true)) { myprintf("99678! Cannot download themysqldump\n"); delete_file(themysql.c_str()); delete_file(themysqldump.c_str()); return false; } franz_do_hash dummy2("SHA-256"); starthash=mtime(); string mysqldump_hash=dummy2.filehash(themysqldump,false,starthash,prendidimensionefile(themysqldump.c_str())); myprintf("\n"); if (mysqldump_hash!=http_mysqldump_sha256) { myprintf("99800$ mysqldump.exe hash invalid\n"); delete_file(themysql.c_str()); delete_file(themysqldump.c_str()); return false; } color_green(); myprintf("99806: Download seems OK\n"); color_restore(); return true; } #else bool findmysql(std::string& o_mysql, std::string& o_mysqldump) { o_mysql = ""; o_mysqldump = ""; // Dichiarazione dei vettori senza inizializzazione diretta std::vector common_paths; std::vector mysql_names; std::vector mysqldump_names; // Popolamento di common_paths common_paths.push_back("/usr/bin/"); common_paths.push_back("/usr/local/bin/"); common_paths.push_back("/bin/"); common_paths.push_back("/usr/sbin/"); common_paths.push_back("/opt/mysql/bin/"); common_paths.push_back("/usr/local/mysql/bin/"); common_paths.push_back("/usr/local/mariadb/bin/"); common_paths.push_back("/usr/local/opt/mysql/bin/"); common_paths.push_back("/opt/bitnami/mysql/bin/"); common_paths.push_back("/opt/lampp/bin/"); common_paths.push_back("/snap/bin/"); common_paths.push_back("/usr/local/var/mysql/bin/"); common_paths.push_back("/usr/local/lib/mysql/bin/"); common_paths.push_back("/usr/pkg/mysql/bin/"); common_paths.push_back("/usr/opt/mysql/bin/"); common_paths.push_back("/usr/local/mysql-advanced/bin/"); common_paths.push_back("/opt/plesk/mysql/bin/"); common_paths.push_back("/opt/azuracast/mysql/bin/"); common_paths.push_back("/usr/lib/mysql/mysql-bin/"); common_paths.push_back("/var/lib/mysql/mysql-bin/"); common_paths.push_back("/usr/share/mysql/"); common_paths.push_back("/usr/sfw/mysql/bin/"); common_paths.push_back("/opt/sfw/mysql/bin/"); common_paths.push_back("/opt/QNAP/mysql/bin/"); common_paths.push_back("/mnt/HDA_ROOT/opt/mysql/bin/"); common_paths.push_back("/opt/bin/"); common_paths.push_back("/usr/local/lib/mysql/bin/"); common_paths.push_back("/volume1/@appstore/mysql/bin/"); common_paths.push_back("/volume1/@appstore/mariadb/bin/"); common_paths.push_back("/opt/mysql/bin/"); common_paths.push_back("/usr/syno/mysql/bin/"); common_paths.push_back("/volume1/mysql/bin/"); common_paths.push_back("/usr/local/mariadb/bin/"); common_paths.push_back("/usr/local/opt/mysql/bin/"); // Popolamento di mysql_names mysql_names.push_back("mysql"); mysql_names.push_back("mariadb"); // Popolamento di mysqldump_names mysqldump_names.push_back("mysqldump"); mysqldump_names.push_back("mariadb-dump"); bool found_mysql = false; bool found_mysqldump = false; for (unsigned int i = 0; i < common_paths.size(); ++i) { for (unsigned int j = 0; j < mysql_names.size(); ++j) { std::string full_path = common_paths[i] + mysql_names[j]; if (flagdebug2) myprintf("52649: Checking <<%Z>>\n", full_path.c_str()); if (fileexists(full_path.c_str())) { o_mysql = full_path; found_mysql = true; break; } } if (found_mysql) break; } for (unsigned int i = 0; i < common_paths.size(); ++i) { for (unsigned int j = 0; j < mysqldump_names.size(); ++j) { std::string full_path = common_paths[i] + mysqldump_names[j]; if (flagdebug2) myprintf("52650: Checking <<%Z>>\n", full_path.c_str()); if (fileexists(full_path.c_str())) { o_mysqldump = full_path; found_mysqldump = true; break; } } if (found_mysqldump) break; } return found_mysql && found_mysqldump; } #endif #ifdef unix void exec_with_realtime_output(const char* cmd) { #ifdef ANCIENT myprintf("00321: Real-time output not supported in ANCIENT mode\n"); #else char buffer[128]; FILE* pipe = popen(cmd, "r"); if (!pipe) { myprintf("00322! popen kaputt\n"); return; } while (fgets(buffer, sizeof(buffer), pipe) != NULL) myprintf("%s", buffer); int status = pclose(pipe); if (status == -1) { myprintf("00323! pclose failed\n"); } else if (status != 0) { myprintf("00324! Command '%s' exited with status %d\n", cmd, status); } #endif } #endif int Jidac::mysql() { if (archive=="") { myprintf("14237! archive is empty\n"); return 2; } if (g_mysql_host=="") { myprintf("99656: mysql host empty\n"); return 2; } if (g_mysql_user=="") { myprintf("99661: mysql user empty\n"); return 2; } if (flagverbose) myprintf("99664: Working on mysql %s port %d user %s bin %s\n",g_mysql_host.c_str(),g_mysql_port,g_mysql_user.c_str(),g_bin.c_str()); string themysql =""; string themysqldump =""; string mypath=includetrailingbackslash(extractfilepath(fullzpaqexename.c_str())); if (g_bin=="") { #ifdef _WIN32 if (fileexists(mypath + "mysqldump.exe")) themysqldump = mypath + "mysqldump.exe"; else { myprintf("99761: Searching for mysqldump.exe or mariadb-dump.exe into c:/program files:"); themysqldump = searchfile("c:/program files", "mysqldump.exe"); if (themysqldump.empty()) { // Prova con mariadb-dump.exe se mysqldump.exe non è stato trovato themysqldump = searchfile("c:/program files", "mariadb-dump.exe"); if (themysqldump.empty()) { color_red(); myprintf("CANNOT FIND\n"); color_restore(); } else { color_green(); myprintf("OK (found mariadb-dump.exe)\n"); color_restore(); } } else { color_green(); myprintf("OK (found mysqldump.exe)\n"); color_restore(); } } if (fileexists(mypath + "mysql.exe")) themysql = mypath + "mysql.exe"; else { myprintf("99768: Searching for mysql.exe or mariadb.exe into c:/program files:"); themysql = searchfile("c:/program files", "mysql.exe"); if (themysql.empty()) { // Prova con mariadb.exe se mysql.exe non è stato trovato themysql = searchfile("c:/program files", "mariadb.exe"); if (themysql.empty()) { color_red(); myprintf("CANNOT FIND\n"); color_restore(); } else { color_green(); myprintf("OK (found mariadb.exe)\n"); color_restore(); } } else { color_green(); myprintf("OK (found mysql.exe)\n"); color_restore(); } } #endif } else { themysqldump=includetrailingbackslash(g_bin)+"mysqldump"; if (fileexists(includetrailingbackslash(g_bin)+"mariadb-dump")) themysqldump=includetrailingbackslash(g_bin)+"mariadb-dump"; themysql=includetrailingbackslash(g_bin)+"mysql"; if (fileexists(includetrailingbackslash(g_bin)+"mariadb")) themysql=includetrailingbackslash(g_bin)+"mariadb"; #ifdef _WIN32 themysqldump+=".exe"; themysql+=".exe"; #endif } #ifdef _WIN32 if (flagspace) if ((themysqldump=="") || (themysql=="")) { myprintf("99794$ Cannot find mysql.exe and mysqldump.exe, getting from my website due to -space...\n"); if (getmysqlfrominternet()) { if (fileexists(mypath+"mysqldump.exe")) themysqldump=mypath+"mysqldump.exe"; if (fileexists(mypath+"mysql.exe")) themysql=mypath+"mysql.exe"; } } #endif #ifdef unix if ((themysqldump=="") || (themysql=="")) findmysql(themysql,themysqldump); #endif if (!fileexists(themysqldump)) { #ifdef _WIN32 myprintf("99822! cannot find mysqldump.exe, use -bin to specify the folder or -space to get from Internet\n"); #else myprintf("99821! cannot find mysqldump, use -bin to specify the folder\n"); #endif return 2; } if (!fileexists(themysql)) { #ifdef _WIN32 myprintf("99811! cannot find mysql.exe, use -bin to specify the folder or -space to get from Internet\n"); #else myprintf("99811! cannot find mysql, use -bin to specify the folder\n"); #endif return 2; } if (flagverbose) { myprintf("99895: Using mysql <<%Z>>\n",themysql.c_str()); myprintf("99894: Using mysqldump <<%Z>>\n",themysqldump.c_str()); } int64_t presize=prendidimensionefile(archive.c_str()); #ifdef _WIN32 string filebatch =g_gettempdirectory()+"mysqlz.bat"; #else string filebatch ="/tmp/mysqlz.sh"; #endif filebatch=nomefileseesistegia(filebatch); if (fileexists(filebatch)) if (remove(filebatch.c_str())!=0) { myprintf("99672! Highlander batch %s\n", filebatch.c_str()); return 2; } FILE* batch=fopen(filebatch.c_str(), "wb"); if (batch==NULL) { myprintf("99678! cannot write on %s\n",filebatch.c_str()); return 2; } string parametrini; parametrini+=" -m"+method; if (plainpassword!="") parametrini+=" -key "+plainpassword; if (flagverbose) myprintf("99922: Parameters |%s|\n",parametrini.c_str()); ///--single-transaction #ifdef _WIN32 string temp = linuxtowinpath(archive); themysql = linuxtowinpath(themysql); themysqldump = linuxtowinpath(themysqldump); string winexename = linuxtowinpath(fullzpaqexename); fprintf(batch, "@echo off\n"); fprintf(batch, "setlocal enabledelayedexpansion\n"); fprintf(batch, "set \"MYSQL_HOST=%s\"\n", g_mysql_host.c_str()); fprintf(batch, "set \"MYSQL_USER=%s\"\n", g_mysql_user.c_str()); fprintf(batch, "set \"MYSQL_PASSWORD=%s\"\n", g_mysql_password.c_str()); fprintf(batch, "set \"MYSQL_PORT=%d\"\n", g_mysql_port); fprintf(batch, "set \"BACKUP_DEST=%s\"\n", temp.c_str()); // Genera la lista dei database fprintf(batch, "\"%s\" -u%%MYSQL_USER%% -p%%MYSQL_PASSWORD%% -h%%MYSQL_HOST%% -P%%MYSQL_PORT%% -e \"SHOW DATABASES;\" > \"%%TEMP%%\\db_list.txt\"\n", themysql.c_str()); // Gestione dei filtri di inclusione/esclusione con supporto wildcard if (!onlyfiles.empty()) { // Modalità inclusione: processa solo i database che corrispondono ai pattern specificati fprintf(batch, "echo Processing only specified database patterns...\n"); fprintf(batch, "type \"%%TEMP%%\\db_list.txt\" | findstr /v \"Database\" > \"%%TEMP%%\\db_list_clean.txt\"\n"); fprintf(batch, "for /f \"tokens=1\" %%%%d in ('type \"%%TEMP%%\\db_list_clean.txt\"') do (\n"); fprintf(batch, " set \"DB_NAME=%%%%d\"\n"); fprintf(batch, " set \"MATCH=0\"\n"); // Verifica se il database corrisponde a qualcuno dei pattern specificati for (size_t i=0;i nul\n", winPattern.c_str()); fprintf(batch, " if !errorlevel! equ 0 set \"MATCH=1\"\n"); } fprintf(batch, " if !MATCH! equ 1 (\n"); if (flagverbose) fprintf(batch, " echo Processing matched database !DB_NAME!...\n"); fprintf(batch, " \"%s\" -u%%MYSQL_USER%% -p%%MYSQL_PASSWORD%% -h%%MYSQL_HOST%% -P%%MYSQL_PORT%% --add-drop-database --databases !DB_NAME! | \"%s\" a \"%%BACKUP_DEST%%\" \"!DB_NAME!.sql\" -stdin -silent %s\n", themysqldump.c_str(), winexename.c_str(), parametrini.c_str()); fprintf(batch, " if !errorlevel! equ 0 (\n"); fprintf(batch, " echo * Backup !DB_NAME! OK\n"); fprintf(batch, " ) else (\n"); fprintf(batch, " echo * ERROR on database !DB_NAME!\n"); fprintf(batch, " )\n"); fprintf(batch, " )\n"); fprintf(batch, ")\n"); } else { // Processa tutti i database con possibili esclusioni basate su pattern fprintf(batch, "for /f \"skip=1 tokens=1\" %%%%d in ('type \"%%TEMP%%\\db_list.txt\"') do (\n"); fprintf(batch, " set \"DB_NAME=%%%%d\"\n"); fprintf(batch, " set \"EXCLUDE=0\"\n"); // Escludiamo sempre i database di sistema fprintf(batch, " echo !DB_NAME! | findstr /i \"information_schema performance_schema sys\" > nul\n"); fprintf(batch, " if !errorlevel! equ 0 set \"EXCLUDE=1\"\n"); // Controlla le esclusioni personalizzate con wildcard if (!notfiles.empty()) { for (size_t i=0;i nul\n", winPattern.c_str()); fprintf(batch, " if !errorlevel! equ 0 set \"EXCLUDE=1\"\n"); } } // Backup del database se non è stato escluso fprintf(batch, " if !EXCLUDE! equ 0 (\n"); if (flagverbose) fprintf(batch, " echo Processing database !DB_NAME!...\n"); fprintf(batch, " \"%s\" -u%%MYSQL_USER%% -p%%MYSQL_PASSWORD%% -h%%MYSQL_HOST%% -P%%MYSQL_PORT%% --add-drop-database --databases !DB_NAME! | \"%s\" a \"%%BACKUP_DEST%%\" \"!DB_NAME!.sql\" -stdin -silent %s\n", themysqldump.c_str(), winexename.c_str(), parametrini.c_str()); fprintf(batch, " if !errorlevel! equ 0 (\n"); fprintf(batch, " echo * Backup !DB_NAME! OK\n"); fprintf(batch, " ) else (\n"); fprintf(batch, " echo * ERROR on database !DB_NAME!\n"); fprintf(batch, " )\n"); fprintf(batch, " )\n"); fprintf(batch, ")\n"); } fprintf(batch, "del \"%%TEMP%%\\db_list.txt\" > nul 2>&1\n"); fprintf(batch, "del \"%%TEMP%%\\db_list_clean.txt\" > nul 2>&1\n"); fclose(batch); if (flagverbose) myprintf("93958: Wait Execute %s\n",filebatch.c_str()); waitexecutepadre(filebatch,""); #else fprintf(batch, "#!/bin/bash\n\n"); fprintf(batch, "MYSQL_HOST=\"%s\"\n", g_mysql_host.c_str()); fprintf(batch, "MYSQL_USER=\"%s\"\n", g_mysql_user.c_str()); fprintf(batch, "MYSQL_PASSWORD=\"%s\"\n", g_mysql_password.c_str()); fprintf(batch, "MYSQL_PORT=%d\n", g_mysql_port); fprintf(batch, "ZPAQ_PATH=\"%s\"\n", extractfilepath(fullzpaqexename.c_str()).c_str()); fprintf(batch, "BACKUP_DEST=\"%s\"\n", archive.c_str()); fprintf(batch, "TEMP_DIR=\"/tmp\"\n\n"); fprintf(batch, "echo \"Starting MySQL backup...\"\n\n"); // Crea la lista dei database fprintf(batch, "%s -u${MYSQL_USER} -p${MYSQL_PASSWORD} -h${MYSQL_HOST} -P${MYSQL_PORT} -e \"SHOW DATABASES;\" > \"${TEMP_DIR}/db_list.txt\"\n\n", themysql.c_str()); fprintf(batch, "grep -v \"Database\" \"${TEMP_DIR}/db_list.txt\" > \"${TEMP_DIR}/db_list_clean.txt\"\n\n"); // Gestione filtri di inclusione/esclusione con supporto wildcard if (!onlyfiles.empty()) { // Modalità inclusione: processa solo i database che corrispondono ai pattern specificati fprintf(batch, "echo \"Processing only specified database patterns...\"\n"); fprintf(batch, "while read DB_NAME; do\n"); fprintf(batch, " MATCH=0\n"); // Verifica se il database corrisponde a uno dei pattern specificati for (size_t i=0;i>\n",filebatch.c_str()); return 2; } exec_with_realtime_output(filebatch.c_str()); #endif int64_t postsize=prendidimensionefile(archive.c_str()); if (postsize>presize) color_green(); myprintf("99710: Archive size %s (%s) + %s => %s (%s)\n",migliaia(presize),tohuman(presize),migliaia2(postsize-presize),migliaia3(postsize),tohuman2(postsize)); color_restore(); if (!flagdebug) remove_temp_file(filebatch); return 0; } zpaqfranz-62.2/zpaqfranz.jpg000066400000000000000000000704341477324740300162200ustar00rootroot00000000000000JFIFHHExifMM*;JiRr >utente dutente XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmC   %# , #&')*)-0-(0%()(C   (((((((((((((((((((((((((((((((((((((((((((((((((((" U!1A"Qa2qB#R$3rbcu%CSTUst&45Dd,!1"A2Qa#q3BC ?_ ;ȋ&n;c!@ BL3]"T84]y!qVBGdk Xrz_%(RJR.Tl=Uj5:TӴ8R]Ԥ2-ǨFy\DWę )yuHXAqq҂LRR qusQu3&͊c/ :CFI=7팭@D:C WU`Յ.,ɖsjKަci@T@nm??ViU mڒWKuƺ{cu3 -]n>;;C6Zܷ͘Ru5) GSiHh_qn_d7kLH;|>C/ȦR̝HRu6>U&R:g/T'pI̙yK jE.,c4`JΔZ}9Mp<&\?%bU"Siz˂CPU+2:N4 'c !.Pr c yqRRG5)y>Z11 ),Z-۝* ̆4LCC soqul6Ƈfu$/n`~&x~1$dʀ̕\7zmQy s D(I}E{_u"f&!%KjM-rQS<%r܍zbin[V@;V*$m$QA.-=7|7>DiT@i N\Q& 6D H JRt *EBٗUYi'k\'M .(7V-2xѣDԹ&ãj*qJ} =lV* LnMPl8iw?<}/!f] iql~xlm4g3 bsڏn>m+K'ۮ0ӡ&f4ZQԥ-TRN#CH >XiXeHʯBȗyp rRBlַ#!9Ugq䴎YTg~ p{/C.RO|6]S-JYI ~? U2z_yjP](Zǘ6ޮ/BPBP mbB8MՙUR$Ji5) VscU괦-YiuazN49'Vz92u<d.n&˫CtGPn)I{-ܝ*RxiFRn*8a:5UH_żeVX\鏸ږAHR Zrmv (ܘ<%M"l{!XI9qK]h./c-U=0f1kZTTޛ5 [?GXI/߽s:!WmC)T Ǚ*&흓맷ruzkC`W8I0=Wsj5Mz͓%G/&5q7<×X nmR|^rM.Vv2)ɥkO |:z%_LYEmI͕LaRKJ]@P^ǾpJ戮drJe*#ivBX[M*]kg̥j?n!*?d$3iH-ZAU"km{|Su)'׬W"i_)cKmM+Wۦ#lq2T/U>|:L bPL%^R/H~:x^4Ɛ]B|ܤz\uT r،TLa?N8߬er/ՠǘ케|<,#{ҦQ6u<Ra/-ҥ&dʏ4ٙ~--6-Yh4 aq(IMQIn#po}Ma5J +N^B }*bxlo*It$}1tHm?W?&ă_ A'凒6cҋ9rzXrRXeRmɜR;_VySZ_d%n⅘V-"KB(,;DG]ψhҩr&kW-)K.ot-'p@U za$T`79ߋ9זfT9]4zMB&`o0::-$Kc-gMͱʙ]fI-: բH#cu[S"\QW6KeوMmM+Gɗx%;)m!*:$웗c}6Yۥ+Ei . w#|W)rGIH] r//zD[ q2&?$ṃ`&de71 D+:^;BB+lwY N"rGˆ+Ds]ɔڊ]MDcER3?oN4DV O8$0Ԥo{T[? o)-%VWE ('S]f5RJHC͒Rkp)2VTE1 e NbSV2 Kf)2m+ %(x&*̰ܒ<G97*.2PHlk U`]J1SDn)d1sZcRZY w>-xZY\VU/ٛH_'tt*Xݘ*D(GH o#SiDg~eb@l2NjVXǰ7rW S+1KO|MvCvt m؋ЃOo'ڔX7sY͑ªc_igWFPP=AΧȕGyP Rt4}_`By8 Ɋ̥gʽ&YJlвu&fZ (Yˊ]EY@$8!I9J+q29|i8%=qħ\'ʡ졹{(GQmy[nN(OV$ߴJJKR[f`Uo2H$f(ASy"d}%Hn:QqBRI:CpJ½߇ۡŨdڂ~!+k(!C}--&*&]:s,oghfJ-KX%:RM s"Ǡ1O]G^nZB7@v? yʷu=.Tr5.7ˌ" RY6@?=Xr.:Fej K&h|m%؃m̈iT߹.u+{?pfW-U5 dg5͔:8ҎOmo,.L&BYJd%}Aþ.ILϲڧD=E-H%]JQ`7|lEü?.GCDmS=0|R 5 #Nwj>)5 8!HP#{87mn|Ȍ'WϊE? L{g>i?xz۾+i3  ? *m`^窦M"LuCP=F:(ڎ{̧1d=*lnO_ !,g4ZsL!G[!БAuIJ4n ;VPm$nfJ ݧcrZ: ! SEzai?\q8Su%>̻\e+Oo\s+l[ʚplEHczJ]DRP_)iu' OPG*pdZRDՀ-a"%\'7Gkyc3>ETBʸv:]RmJ Q%vPdCTiCZۭBVJz!͈j&42LI\jh:K6s>c[8g#"FJ.W("Lq7;67q!Q/Rm,q 伍ʄHg^ғ&Y%6i hWqxy0řx{P鎦gYa+V IAcK faSjͫO%C=Gq >쑘_RJB%<,O.1{7RY ur·%]cx@QGΠSc<\ݻ">+zʐb_dmG_J"e[+I~&_"ZuR~AҤVV a2Bu!kܕjGWɗM"5mSkJҥjS!]9>e4UrDTG<ŗqӮ=f631IuX nKa* MQb*JUJj#{[,?+uZm6!xS gTQRB9'[jHSncsQ=GѴ샤.u<TRƪ#Q[hnRa[\ϝ_93\ 'H#ac-]ʺ29:䨠8J}lF&iPC4-&Jih3[JUKbG0-W2"]3)˒KyO<$F6Xf<è*2@h>M]f"ʣk.?d4M\Srs יT)hrj$n U'rOyLH ӨiZDu6pK<Wvېۜ[Sc Z٫'ir*6H .e)vMw;w(yW;)xJmKJm'`Uk.$˝pZzDz%Ob:MиZxXYOkYzW*# lJ }*,Ì U(HA,wj\w)0&ayͫʫz;ٵJ[DI>g%y*r#Ǒ9M+Ď,=d,:PJo!d5N.J= wjB㥈,Vk~VʽJ0(n[ns1AvDëquIwJo;_:#S˼Ұ4ʞ T\s *)lQ+).i27弎e$R.tqp/`EمfeU J>>.'WCMR˹ j92Fu 23|Ѫ+Ay_6O1gN ZbʹȎ~#R}7ۍS-U΁L%rT}*:}J >Bu9,f]fZ`DI$s[吝[8/fJo$hd% mE͕3;VZBPZvn~˔&Sd{3RKrUqGshIps.Δ|FYI1Gw*Qfj ɔҝBŊ7R eHN{ c- pBw#x%WkuZzd0ڐR@MБ }݆^p~ j;l gYSR"AhKC\.eYHs^ƞy*F o=Aa򧓑6CA*~OZW՜!dLyDR.]-W_,ЪԷF tV ݛrˌ+a@ jc}NAǛd::)GGRq Ϯ4D"[w`~z.1یd?t$~ ]%>9 U30.4$]LPR 7ZIgX^8PFXzs$^U@IPqNTH굔؞ݙu'nll͓b%&* ,!五쭛>SS">kzB.>xG[.bn.~R;n&T#T SРK '効[ U:35g3N -I f . 76p1|BrĊc;SPUqQ'2B\tBR^C'Jդ?ky^dB%3q J"@#J۲Hnp+_eE~zTrH燜2]!:ҧ-!I#Pq2g 6ėm/C1[MAJ\+ki'Vla]s/<Q{dȖmA2Au\h`8 W?NЕmy?rLx6%-#mAa;<xUjQ=:#2]PN̎x0O4jJ"(FMk.zP!,{Cz2H^Qx-P r~4 `7"q2KN im_u$|@"nRUu3Qƴ1]^[=1uf1p-M>~o cl\`;&S.@ ]EN!R)rpCsy >.]Rb:BK£ԯ@7 ƶPעU}!!]aZ%[>`9*τ*#o{y|B6TE"K;3)m+^̞hl~}'3O͙q:ilR|Tj{ƥ|~Z>mp:UJYײmHY[j"[b) No#n-5IO%֤3R}qj-d8mˆEMAAUݾ!pa("N0^ >I:V>8pQ(Y1'+Un!t0n*Գ+  ]5LEnPRJnxI7yΒRikG *YHͻ#Bzzh+`b|eTN:! Y(ecFec$tC᳊%Ӝ,7+C#QJP$ \)2׫S+hwA-q0"Myq1ԚmRϴTVF~53O:  E"l&JϲZlJ}/?[cr]ԑ79bϴ5)0V!l73@A\(ʕ_\j[N4DT|싄zb[VkhVZ$ [ 4S(un~ۦ+{#.Kk x7Djb+ \N4p,N"1oJÚҵ%*_]E ؟[`ymAQn|d&A?A.ji݃6#2 $uZÎ{+b:l|Tb;6aY4 ̵YMMtsT=JQ⡀r" o>k2ȼ(GG(9(괠|@Ӛz,F˜ĥsHפoP:GK_e% t!(U t6v&ƹXcX}4 n4pU~Q]q"늓\Bjd\]4*ze)- qpl-aFQ$%$?w%WPzNo5әpQfJp%J`F ɈrlJRmQ+W+Ar(-ɹ!SQ Z9)_WG$ܥ'nnq}~Kzt ()A#`0K˩ys̻3!@؁{* PqS%ml{߶9OThgf 42F3Śa!^A# 9 reϧm-fBibS?y'uRXPq+/әTYc.LҠ5tZ=7$I" rrS2 (h Ӹ16ؗrPG s75V CY+u]6*$MUS.+ND)ZT@ܬ\SP͵%d~ `g,\}*G0fjZH D\(I#ǰVmmХ?rH*†iwfpZ ˨fJ:MKVS) ͈6ߦI N&[.*d5\t۶+CxĶζehq'es3pQE%5U"kОœr1'x\TUQWA>!~_nr].9nOٿ2x<( VA[ͳ+Z֔{Yi7_wEkYR!GUCaM5kW^ɿq}Me '2=ǞRP6:j3vIR  MCY\a,ØZOD7|qBbQ3 zeڦiqԭA$$P0[][_KĞ*J?͏8xvzVu.)6>~Ku 9s<0@ G)ֺbRhh9JŪ`:dURE@hl7q[7jHxy7*& tǝ2RMA|]qS|O=q7 :+é-'8Zㆼu]HaR9UϜ)ɇe:PMn=UMly{a˸R%|&"*:5R7;•HF9Ab%b;[?#%8 w̘{ǘ~ ,%N-@#8%DjuFDE-ҞPГTJMSc9hshU.^ͣQuX R ҝ, BMKr4RI[nMZM,~!.ғ)%XćSd+Ju^m- t'IzJeb>%id@9iV $8U*TT>(Є+}0j*ƭ?R[l8ZRI7rj@L5 -#))?xa Tz I*;6T-,0)UuL~ M2Qp-+K'嶴 !DlO|QURd++S줝C$B2u:O\>LTŴ$%; ?.hjZrrZ}16k!ڜW^PT-[e&TzӅ+:p⍎@W˭<̪ތR*?!55iR?5vNI-eB]%V CTHBltIVD}$VT4%:ztmkq#,YقEz=%ZzM]:oo&֩Mk!ARUZFe^Y.TlTi[kR {\lkue6.>5*}S )6 `:5'eFL8iy)w1'Q<5/Rc AGy*%*;%7\P H,YQmGQfNdi1|A̅ }oǷ玠 : $Լ6P :݀O0UN4J[uCh+**  nZնXZ4iJ]&<9as&K-$v',–TTv|]JRES鉾nm*Ki |9EO(n uCW>2p ,/VE*I^!Ok-qZYFQt3䲠4>ʉ 9$G ¹h\%C 㾰4E)hV9)g$-r+NiPn ٶj< ߌ?ҵ9k.2v~4Őu\ѡW!zAaq̼EJ`*"icjOE"oH,m~'KY,nF=Օ0RlH պ@[~-q~(^jgǿګ@TEbz}PmbHcJfKHhDt}|ZK4XJ[L `8Q%Ǩ%T (}҄2>SHR9HVV-.%.Zs"O7V$4XqM* 9ү2{vqkRө=uVQՋ2H{V9 7ųRUX>`4 Hv;fiqI m{ -Ssu6.z߻ha:V&“/h·{tƟjm9i[N7n#;"}YW^UST%-'bN 1nE_'D}JZig}M+c6yQ_*(x3a*;*HﵺuZ1ڜY '䤟+Y)[a MCA}Dtn&P߲9kB!ĝˠQkvŏL Ԕ[uFB[HX!:Ŭ%uʤ m+n:yHO!1{8"3RcVް{j6$-eQ)ʓ %m FRkBH3uڴ%i );z1r nR=[EquK%);'so!lJ%Ҁ%@ul?[(ƱwTa)Ym-[[cr%U5X4%GPvH73sU,T~yߖpDt'V#E7'FM5n8Z45?^#T]n*rx3%ZܫbŞ^ȢTe A,8AYA6&[af**_X'" ۮ9Х|=_S=Zx-Ke=PB[+jܶ/A q?ZKjdo;w4".I5(muZX:l7#~ayoӷQº:%ʍ9n냵#0adV5R͏CY`[>ᑗk6҅'k:a&Ϥ:ROq~=2RE c>jcGU2jE=I-"^_ .Yg2Ʃ>ߺqdm}Ǩiiz1}JQGڊDz2cil/;_qy'k J){|ncκ8QI;zcA3WPQ-C"B,#$[i2(זN@v-j7`@j З6(!,5@!I>wzL{U4TWqa,H7pHs ȫ9"CW*b,ÄX"X[ ef\W-Rt<\e~Co4FSԤx7%?ĩqP euDQaN)lZTڼ#4AP~DHJRp? cVt3X)R,rJ-&tB6v=qLtiUKh A$ [^BJrpql9tܱIJcl0"\\Dx+u]D@rk,%l)(c+[01Nd߶JPʂ~Όnma1Q|>רjSrXMheWLNyllGil8RT6 ¶qXK3)J}v {mpim֪,RCihS#RQrlg' U8l 平^-^ z-$e2aL~ jS+ӥn*Զ (8p#o{^սIչ@.?d3}*aۅrЀ!b =|ۥ&ָeX&ʊjy>U)+Q%P#2QJE,mHٟ%En<_T< ng:\C•#&(ӫ3EB롶ڐ\lmu%c  N>Qg89)ym\PZPs}ܟSH*tʜ]UI;cz|SA|&K'ddL!NNu;Jֳ8fTC\8&$잃pd[Ϣs_ mE.ݱ-w8n Nk6U3 S&,ܑ۠9Æ FK|n g`eopXpLח%o. ?`_cF9|5,TR0lrNG"F@{jHHҐ@6l~*Wsqyjr7= LQQf#7. wCxa}2M]zK }7%nO@7c0>$Ե K]4:"JqKsYH, ͌=KrH "J^wO/%$Թ-"ZʚVo7؆ JfY[Rv6\8LP!HOR:@m:ψq,W"IKLhֹ,,T6ۜZr+ ]i[VJ$mWauf ꔵ"͙^'u>x]U& 4 I.6`,|䪛7$݈ 7,7B-uilQ> cZiמm[+t|V%ȵv$-l:F⻝2F+B!XD \kdg W%f )|G qҕN9:uBR6r`[(RCљpH*/o<:f44ڕX;/ 9jx[J\=E1 XPO|K}JIUʈ>DS9Q!l6ӁN(W}ħ=.ir߯0Maz9E:?/BmԞih 8@Mo г [Ti7緸kql/}C ĭ:%_8qRʁ.=1t7d*| @Ҡ@RۓrO%195NJQBXC*l`=1)hiKZ4Xv{~’QWo^k_Kx)P)u^-FSʴeb;Uԅ'q> -b4W$ue:ZEb5R }1yujgx%)H,GKs< 5"c\ SPG8&&t2uOs@%Ecbaju HJN`Bl4F#WU6ClJ6OC8; ˓EA)u%r`oӨqߏS9w *Aj}nYBb> 0e׵&־@fefKIk7VZCiR 6 Cf( bqv $#G5f ,1 Kniݺ퀢[{YJ|vYVZ|\뿮(b\'62J;6dxkhF絾hRI@mӠ\|Mq^r5~Gdl1>c%sj?rN$m}=Mŏ~̇g99:O8]ۤtn7?,s*3CJ*t¡>2Ǘ' EnZK e.LZt;u?;aFoۙB -8徧5Fc.jܖ|JpxZ=~a ]/H[Ϋ;$~ҏaF(K|+(rD&=XSnO64W(aJ>{ELeD=,mlK`ot);3c))-'Ub Pܔz`E6N<ds!JnO)*AڒlQrbzjZ\VŚf.\I-{oCV%G$6+Q']f=r)*NW_sӋPlm% f,-BIi.4a )vK@$uB2SRZrc`T@OSԓ4r`JQPR.RK'o\ʙ]R%:uO 9>3F1S rk.W_&ѻptXl}>*˱Z):+.mnl:,XsoMw[;l'$wu8b a%=5g.Bu-'o: K|SYKloD'w8s1IznCQ>@(س;H ) z⼼Оz(9 ;VYqPR[ImpA`r{D t/nlU嫯 Wˬ3kiYq/t('0j&FZ!* 'B͙EDM^RMKxቕ8SGIi{)-$yYG >y\Ǖ`2$aSVTT-\m:ԄJ$c:H[LQf!libnԵ ]@o'S@=!,0ڧ4dw#f|A%c0gSw`|q5QRҪL)@%l4 Sr ň7[tIKNM$-D1(^gz2(,O2#5)ZFBƨr 6nT vWm6|径"+lʷ'lә S`B9qS1I֧#~ߧ8ʙː7rjUOJ-a#2)[Or1:\b']ROU l2Ĝ#%嬫c VBhBy2Q`bJF%n-m8nA & PaD}IÅY\rK k]XmKnt#uJ6!m "dKLROA-܅.K'R6~8u9.>(ީ,h孥_}=o>xT5&dK\X0.ou Pr9'{,Og\ԥE6'ëbllUCZX=U i$⹋THy`,%d4:M4nr[YH)=AQqR EgFj%{'6gz*1ң q U~5pG^^fPm_x{qt)#PjjtޟQLwKfk(v'͕j+GQSb6OlBya]ԝ ?`p#Unæ\l-H H< f†Ra ue rISۣO4E l_ [ t@Ruq'ùD:$9R(sX~TGu_X|A㜸)񐢦ˡzq[~ƪ!7MЫC6b^HRa >DL%b5A3;4E Cu `HRe?i%#7[7R| ۔Wxu}q鐧܄*$ _5Fe?.ڝ{"9j}ZHҲI!Rd KEM{#!kqˋ?+`S̹bT64u6Ejlte ^]:8=MV퍊gZ*pT.f#3*)gCBۯPAu!b-c&cQ%O

* The Whirlpool algorithm was developed by * Paulo S. L. M. Barreto and * Vincent Rijmen. */ typedef signed char s8; typedef unsigned char u8; #if UINT_MAX >= 4294967295UL typedef signed short s16; typedef signed int s32; typedef unsigned short u16; typedef unsigned int u32; #define ONE32 0xffffffffU #else typedef signed int s16; typedef signed long s32; typedef unsigned int u16; typedef unsigned long u32; #define ONE32 0xffffffffUL #endif // corresponds to #if (#if UINT_MAX >= 4294967295UL) #define ONE8 0xffU #define ONE16 0xffffU #define T8(x) ((x) & ONE8) #define T16(x) ((x) & ONE16) #define T32(x) ((x) & ONE32) #ifdef _MSC_VER typedef unsigned __int64 u64; typedef signed __int64 s64; #define LL(v) (v##i64) #define ONE64 LL(0xffffffffffffffff) #else typedef unsigned long long u64; typedef signed long long s64; #define LL(v) (v##ULL) #define ONE64 LL(0xffffffffffffffff) #endif // corresponds to #ifdef (#ifdef _MSC_VER) #define T64(x) ((x) & ONE64) #define ROTR64(v, n) (((v) >> (n)) | T64((v) << (64 - (n)))) #define U8TO32_BIG(c) (((u32)T8(*(c)) << 24) | ((u32)T8(*((c) + 1)) << 16) | ((u32)T8(*((c) + 2)) << 8) | ((u32)T8(*((c) + 3)))) #define U8TO32_LITTLE(c) (((u32)T8(*(c))) | ((u32)T8(*((c) + 1)) << 8) | (u32)T8(*((c) + 2)) << 16) | ((u32)T8(*((c) + 3)) << 24)) #define U32TO8_BIG(c, v) do { u32 x = (v); u8 *d = (c); d[0] = T8(x >> 24); d[1] = T8(x >> 16); d[2] = T8(x >> 8); d[3] = T8(x); } while (0) #define U32TO8_LITTLE(c, v) do { u32 x = (v); u8 *d = (c); d[0] = T8(x); d[1] = T8(x >> 8); d[2] = T8(x >> 16); d[3] = T8(x >> 24); } while (0) #define ROTL32(v, n) (T32((v) << (n)) | ((v) >> (32 - (n)))) #define DIGESTBYTES 64 #define DIGESTBITS (8*DIGESTBYTES) #define WBLOCKBYTES 64 #define WBLOCKBITS (8*WBLOCKBYTES) #define LENGTHBYTES 32 #define LENGTHBITS (8*LENGTHBYTES) typedef struct NESSIEstruct { u8 bitLength[LENGTHBYTES]; u8 buffer[WBLOCKBYTES]; int bufferBits; int bufferPos; u64 hash[DIGESTBYTES/8]; } NESSIEstruct; #define WHIRLPOOL_R 10 static const u64 C0[256] = { LL(0x18186018c07830d8), LL(0x23238c2305af4626), LL(0xc6c63fc67ef991b8), LL(0xe8e887e8136fcdfb), LL(0x878726874ca113cb), LL(0xb8b8dab8a9626d11), LL(0x0101040108050209), LL(0x4f4f214f426e9e0d), LL(0x3636d836adee6c9b), LL(0xa6a6a2a6590451ff), LL(0xd2d26fd2debdb90c), LL(0xf5f5f3f5fb06f70e), LL(0x7979f979ef80f296), LL(0x6f6fa16f5fcede30), LL(0x91917e91fcef3f6d), LL(0x52525552aa07a4f8), LL(0x60609d6027fdc047), LL(0xbcbccabc89766535), LL(0x9b9b569baccd2b37), LL(0x8e8e028e048c018a), LL(0xa3a3b6a371155bd2), LL(0x0c0c300c603c186c), LL(0x7b7bf17bff8af684), LL(0x3535d435b5e16a80), LL(0x1d1d741de8693af5), LL(0xe0e0a7e05347ddb3), LL(0xd7d77bd7f6acb321), LL(0xc2c22fc25eed999c), LL(0x2e2eb82e6d965c43), LL(0x4b4b314b627a9629), LL(0xfefedffea321e15d), LL(0x575741578216aed5), LL(0x15155415a8412abd), LL(0x7777c1779fb6eee8), LL(0x3737dc37a5eb6e92), LL(0xe5e5b3e57b56d79e), LL(0x9f9f469f8cd92313), LL(0xf0f0e7f0d317fd23), LL(0x4a4a354a6a7f9420), LL(0xdada4fda9e95a944), LL(0x58587d58fa25b0a2), LL(0xc9c903c906ca8fcf), LL(0x2929a429558d527c), LL(0x0a0a280a5022145a), LL(0xb1b1feb1e14f7f50), LL(0xa0a0baa0691a5dc9), LL(0x6b6bb16b7fdad614), LL(0x85852e855cab17d9), LL(0xbdbdcebd8173673c), LL(0x5d5d695dd234ba8f), LL(0x1010401080502090), LL(0xf4f4f7f4f303f507), LL(0xcbcb0bcb16c08bdd), LL(0x3e3ef83eedc67cd3), LL(0x0505140528110a2d), LL(0x676781671fe6ce78), LL(0xe4e4b7e47353d597), LL(0x27279c2725bb4e02), LL(0x4141194132588273), LL(0x8b8b168b2c9d0ba7), LL(0xa7a7a6a7510153f6), LL(0x7d7de97dcf94fab2), LL(0x95956e95dcfb3749), LL(0xd8d847d88e9fad56), LL(0xfbfbcbfb8b30eb70), LL(0xeeee9fee2371c1cd), LL(0x7c7ced7cc791f8bb), LL(0x6666856617e3cc71), LL(0xdddd53dda68ea77b), LL(0x17175c17b84b2eaf), LL(0x4747014702468e45), LL(0x9e9e429e84dc211a), LL(0xcaca0fca1ec589d4), LL(0x2d2db42d75995a58), LL(0xbfbfc6bf9179632e), LL(0x07071c07381b0e3f), LL(0xadad8ead012347ac), LL(0x5a5a755aea2fb4b0), LL(0x838336836cb51bef), LL(0x3333cc3385ff66b6), LL(0x636391633ff2c65c), LL(0x02020802100a0412), LL(0xaaaa92aa39384993), LL(0x7171d971afa8e2de), LL(0xc8c807c80ecf8dc6), LL(0x19196419c87d32d1), LL(0x494939497270923b), LL(0xd9d943d9869aaf5f), LL(0xf2f2eff2c31df931), LL(0xe3e3abe34b48dba8), LL(0x5b5b715be22ab6b9), LL(0x88881a8834920dbc), LL(0x9a9a529aa4c8293e), LL(0x262698262dbe4c0b), LL(0x3232c8328dfa64bf), LL(0xb0b0fab0e94a7d59), LL(0xe9e983e91b6acff2), LL(0x0f0f3c0f78331e77), LL(0xd5d573d5e6a6b733), LL(0x80803a8074ba1df4), LL(0xbebec2be997c6127), LL(0xcdcd13cd26de87eb), LL(0x3434d034bde46889), LL(0x48483d487a759032), LL(0xffffdbffab24e354), LL(0x7a7af57af78ff48d), LL(0x90907a90f4ea3d64), LL(0x5f5f615fc23ebe9d), LL(0x202080201da0403d), LL(0x6868bd6867d5d00f), LL(0x1a1a681ad07234ca), LL(0xaeae82ae192c41b7), LL(0xb4b4eab4c95e757d), LL(0x54544d549a19a8ce), LL(0x93937693ece53b7f), LL(0x222288220daa442f), LL(0x64648d6407e9c863), LL(0xf1f1e3f1db12ff2a), LL(0x7373d173bfa2e6cc), LL(0x12124812905a2482), LL(0x40401d403a5d807a), LL(0x0808200840281048), LL(0xc3c32bc356e89b95), LL(0xecec97ec337bc5df), LL(0xdbdb4bdb9690ab4d), LL(0xa1a1bea1611f5fc0), LL(0x8d8d0e8d1c830791), LL(0x3d3df43df5c97ac8), LL(0x97976697ccf1335b), LL(0x0000000000000000), LL(0xcfcf1bcf36d483f9), LL(0x2b2bac2b4587566e), LL(0x7676c57697b3ece1), LL(0x8282328264b019e6), LL(0xd6d67fd6fea9b128), LL(0x1b1b6c1bd87736c3), LL(0xb5b5eeb5c15b7774), LL(0xafaf86af112943be), LL(0x6a6ab56a77dfd41d), LL(0x50505d50ba0da0ea), LL(0x45450945124c8a57), LL(0xf3f3ebf3cb18fb38), LL(0x3030c0309df060ad), LL(0xefef9bef2b74c3c4), LL(0x3f3ffc3fe5c37eda), LL(0x55554955921caac7), LL(0xa2a2b2a2791059db), LL(0xeaea8fea0365c9e9), LL(0x656589650fecca6a), LL(0xbabad2bab9686903), LL(0x2f2fbc2f65935e4a), LL(0xc0c027c04ee79d8e), LL(0xdede5fdebe81a160), LL(0x1c1c701ce06c38fc), LL(0xfdfdd3fdbb2ee746), LL(0x4d4d294d52649a1f), LL(0x92927292e4e03976), LL(0x7575c9758fbceafa), LL(0x06061806301e0c36), LL(0x8a8a128a249809ae), LL(0xb2b2f2b2f940794b), LL(0xe6e6bfe66359d185), LL(0x0e0e380e70361c7e), LL(0x1f1f7c1ff8633ee7), LL(0x6262956237f7c455), LL(0xd4d477d4eea3b53a), LL(0xa8a89aa829324d81), LL(0x96966296c4f43152), LL(0xf9f9c3f99b3aef62), LL(0xc5c533c566f697a3), LL(0x2525942535b14a10), LL(0x59597959f220b2ab), LL(0x84842a8454ae15d0), LL(0x7272d572b7a7e4c5), LL(0x3939e439d5dd72ec), LL(0x4c4c2d4c5a619816), LL(0x5e5e655eca3bbc94), LL(0x7878fd78e785f09f), LL(0x3838e038ddd870e5), LL(0x8c8c0a8c14860598), LL(0xd1d163d1c6b2bf17), LL(0xa5a5aea5410b57e4), LL(0xe2e2afe2434dd9a1), LL(0x616199612ff8c24e), LL(0xb3b3f6b3f1457b42), LL(0x2121842115a54234), LL(0x9c9c4a9c94d62508), LL(0x1e1e781ef0663cee), LL(0x4343114322528661), LL(0xc7c73bc776fc93b1), LL(0xfcfcd7fcb32be54f), LL(0x0404100420140824), LL(0x51515951b208a2e3), LL(0x99995e99bcc72f25), LL(0x6d6da96d4fc4da22), LL(0x0d0d340d68391a65), LL(0xfafacffa8335e979), LL(0xdfdf5bdfb684a369), LL(0x7e7ee57ed79bfca9), LL(0x242490243db44819), LL(0x3b3bec3bc5d776fe), LL(0xabab96ab313d4b9a), LL(0xcece1fce3ed181f0), LL(0x1111441188552299), LL(0x8f8f068f0c890383), LL(0x4e4e254e4a6b9c04), LL(0xb7b7e6b7d1517366), LL(0xebeb8beb0b60cbe0), LL(0x3c3cf03cfdcc78c1), LL(0x81813e817cbf1ffd), LL(0x94946a94d4fe3540), LL(0xf7f7fbf7eb0cf31c), LL(0xb9b9deb9a1676f18), LL(0x13134c13985f268b), LL(0x2c2cb02c7d9c5851), LL(0xd3d36bd3d6b8bb05), LL(0xe7e7bbe76b5cd38c), LL(0x6e6ea56e57cbdc39), LL(0xc4c437c46ef395aa), LL(0x03030c03180f061b), LL(0x565645568a13acdc), LL(0x44440d441a49885e), LL(0x7f7fe17fdf9efea0), LL(0xa9a99ea921374f88), LL(0x2a2aa82a4d825467), LL(0xbbbbd6bbb16d6b0a), LL(0xc1c123c146e29f87), LL(0x53535153a202a6f1), LL(0xdcdc57dcae8ba572), LL(0x0b0b2c0b58271653), LL(0x9d9d4e9d9cd32701), LL(0x6c6cad6c47c1d82b), LL(0x3131c43195f562a4), LL(0x7474cd7487b9e8f3), LL(0xf6f6fff6e309f115), LL(0x464605460a438c4c), LL(0xacac8aac092645a5), LL(0x89891e893c970fb5), LL(0x14145014a04428b4), LL(0xe1e1a3e15b42dfba), LL(0x16165816b04e2ca6), LL(0x3a3ae83acdd274f7), LL(0x6969b9696fd0d206), LL(0x09092409482d1241), LL(0x7070dd70a7ade0d7), LL(0xb6b6e2b6d954716f), LL(0xd0d067d0ceb7bd1e), LL(0xeded93ed3b7ec7d6), LL(0xcccc17cc2edb85e2), LL(0x424215422a578468), LL(0x98985a98b4c22d2c), LL(0xa4a4aaa4490e55ed), LL(0x2828a0285d885075), LL(0x5c5c6d5cda31b886), LL(0xf8f8c7f8933fed6b), LL(0x8686228644a411c2), }; static const u64 C1[256] = { LL(0xd818186018c07830), LL(0x2623238c2305af46), LL(0xb8c6c63fc67ef991), LL(0xfbe8e887e8136fcd), LL(0xcb878726874ca113), LL(0x11b8b8dab8a9626d), LL(0x0901010401080502), LL(0x0d4f4f214f426e9e), LL(0x9b3636d836adee6c), LL(0xffa6a6a2a6590451), LL(0x0cd2d26fd2debdb9), LL(0x0ef5f5f3f5fb06f7), LL(0x967979f979ef80f2), LL(0x306f6fa16f5fcede), LL(0x6d91917e91fcef3f), LL(0xf852525552aa07a4), LL(0x4760609d6027fdc0), LL(0x35bcbccabc897665), LL(0x379b9b569baccd2b), LL(0x8a8e8e028e048c01), LL(0xd2a3a3b6a371155b), LL(0x6c0c0c300c603c18), LL(0x847b7bf17bff8af6), LL(0x803535d435b5e16a), LL(0xf51d1d741de8693a), LL(0xb3e0e0a7e05347dd), LL(0x21d7d77bd7f6acb3), LL(0x9cc2c22fc25eed99), LL(0x432e2eb82e6d965c), LL(0x294b4b314b627a96), LL(0x5dfefedffea321e1), LL(0xd5575741578216ae), LL(0xbd15155415a8412a), LL(0xe87777c1779fb6ee), LL(0x923737dc37a5eb6e), LL(0x9ee5e5b3e57b56d7), LL(0x139f9f469f8cd923), LL(0x23f0f0e7f0d317fd), LL(0x204a4a354a6a7f94), LL(0x44dada4fda9e95a9), LL(0xa258587d58fa25b0), LL(0xcfc9c903c906ca8f), LL(0x7c2929a429558d52), LL(0x5a0a0a280a502214), LL(0x50b1b1feb1e14f7f), LL(0xc9a0a0baa0691a5d), LL(0x146b6bb16b7fdad6), LL(0xd985852e855cab17), LL(0x3cbdbdcebd817367), LL(0x8f5d5d695dd234ba), LL(0x9010104010805020), LL(0x07f4f4f7f4f303f5), LL(0xddcbcb0bcb16c08b), LL(0xd33e3ef83eedc67c), LL(0x2d0505140528110a), LL(0x78676781671fe6ce), LL(0x97e4e4b7e47353d5), LL(0x0227279c2725bb4e), LL(0x7341411941325882), LL(0xa78b8b168b2c9d0b), LL(0xf6a7a7a6a7510153), LL(0xb27d7de97dcf94fa), LL(0x4995956e95dcfb37), LL(0x56d8d847d88e9fad), LL(0x70fbfbcbfb8b30eb), LL(0xcdeeee9fee2371c1), LL(0xbb7c7ced7cc791f8), LL(0x716666856617e3cc), LL(0x7bdddd53dda68ea7), LL(0xaf17175c17b84b2e), LL(0x454747014702468e), LL(0x1a9e9e429e84dc21), LL(0xd4caca0fca1ec589), LL(0x582d2db42d75995a), LL(0x2ebfbfc6bf917963), LL(0x3f07071c07381b0e), LL(0xacadad8ead012347), LL(0xb05a5a755aea2fb4), LL(0xef838336836cb51b), LL(0xb63333cc3385ff66), LL(0x5c636391633ff2c6), LL(0x1202020802100a04), LL(0x93aaaa92aa393849), LL(0xde7171d971afa8e2), LL(0xc6c8c807c80ecf8d), LL(0xd119196419c87d32), LL(0x3b49493949727092), LL(0x5fd9d943d9869aaf), LL(0x31f2f2eff2c31df9), LL(0xa8e3e3abe34b48db), LL(0xb95b5b715be22ab6), LL(0xbc88881a8834920d), LL(0x3e9a9a529aa4c829), LL(0x0b262698262dbe4c), LL(0xbf3232c8328dfa64), LL(0x59b0b0fab0e94a7d), LL(0xf2e9e983e91b6acf), LL(0x770f0f3c0f78331e), LL(0x33d5d573d5e6a6b7), LL(0xf480803a8074ba1d), LL(0x27bebec2be997c61), LL(0xebcdcd13cd26de87), LL(0x893434d034bde468), LL(0x3248483d487a7590), LL(0x54ffffdbffab24e3), LL(0x8d7a7af57af78ff4), LL(0x6490907a90f4ea3d), LL(0x9d5f5f615fc23ebe), LL(0x3d202080201da040), LL(0x0f6868bd6867d5d0), LL(0xca1a1a681ad07234), LL(0xb7aeae82ae192c41), LL(0x7db4b4eab4c95e75), LL(0xce54544d549a19a8), LL(0x7f93937693ece53b), LL(0x2f222288220daa44), LL(0x6364648d6407e9c8), LL(0x2af1f1e3f1db12ff), LL(0xcc7373d173bfa2e6), LL(0x8212124812905a24), LL(0x7a40401d403a5d80), LL(0x4808082008402810), LL(0x95c3c32bc356e89b), LL(0xdfecec97ec337bc5), LL(0x4ddbdb4bdb9690ab), LL(0xc0a1a1bea1611f5f), LL(0x918d8d0e8d1c8307), LL(0xc83d3df43df5c97a), LL(0x5b97976697ccf133), LL(0x0000000000000000), LL(0xf9cfcf1bcf36d483), LL(0x6e2b2bac2b458756), LL(0xe17676c57697b3ec), LL(0xe68282328264b019), LL(0x28d6d67fd6fea9b1), LL(0xc31b1b6c1bd87736), LL(0x74b5b5eeb5c15b77), LL(0xbeafaf86af112943), LL(0x1d6a6ab56a77dfd4), LL(0xea50505d50ba0da0), LL(0x5745450945124c8a), LL(0x38f3f3ebf3cb18fb), LL(0xad3030c0309df060), LL(0xc4efef9bef2b74c3), LL(0xda3f3ffc3fe5c37e), LL(0xc755554955921caa), LL(0xdba2a2b2a2791059), LL(0xe9eaea8fea0365c9), LL(0x6a656589650fecca), LL(0x03babad2bab96869), LL(0x4a2f2fbc2f65935e), LL(0x8ec0c027c04ee79d), LL(0x60dede5fdebe81a1), LL(0xfc1c1c701ce06c38), LL(0x46fdfdd3fdbb2ee7), LL(0x1f4d4d294d52649a), LL(0x7692927292e4e039), LL(0xfa7575c9758fbcea), LL(0x3606061806301e0c), LL(0xae8a8a128a249809), LL(0x4bb2b2f2b2f94079), LL(0x85e6e6bfe66359d1), LL(0x7e0e0e380e70361c), LL(0xe71f1f7c1ff8633e), LL(0x556262956237f7c4), LL(0x3ad4d477d4eea3b5), LL(0x81a8a89aa829324d), LL(0x5296966296c4f431), LL(0x62f9f9c3f99b3aef), LL(0xa3c5c533c566f697), LL(0x102525942535b14a), LL(0xab59597959f220b2), LL(0xd084842a8454ae15), LL(0xc57272d572b7a7e4), LL(0xec3939e439d5dd72), LL(0x164c4c2d4c5a6198), LL(0x945e5e655eca3bbc), LL(0x9f7878fd78e785f0), LL(0xe53838e038ddd870), LL(0x988c8c0a8c148605), LL(0x17d1d163d1c6b2bf), LL(0xe4a5a5aea5410b57), LL(0xa1e2e2afe2434dd9), LL(0x4e616199612ff8c2), LL(0x42b3b3f6b3f1457b), LL(0x342121842115a542), LL(0x089c9c4a9c94d625), LL(0xee1e1e781ef0663c), LL(0x6143431143225286), LL(0xb1c7c73bc776fc93), LL(0x4ffcfcd7fcb32be5), LL(0x2404041004201408), LL(0xe351515951b208a2), LL(0x2599995e99bcc72f), LL(0x226d6da96d4fc4da), LL(0x650d0d340d68391a), LL(0x79fafacffa8335e9), LL(0x69dfdf5bdfb684a3), LL(0xa97e7ee57ed79bfc), LL(0x19242490243db448), LL(0xfe3b3bec3bc5d776), LL(0x9aabab96ab313d4b), LL(0xf0cece1fce3ed181), LL(0x9911114411885522), LL(0x838f8f068f0c8903), LL(0x044e4e254e4a6b9c), LL(0x66b7b7e6b7d15173), LL(0xe0ebeb8beb0b60cb), LL(0xc13c3cf03cfdcc78), LL(0xfd81813e817cbf1f), LL(0x4094946a94d4fe35), LL(0x1cf7f7fbf7eb0cf3), LL(0x18b9b9deb9a1676f), LL(0x8b13134c13985f26), LL(0x512c2cb02c7d9c58), LL(0x05d3d36bd3d6b8bb), LL(0x8ce7e7bbe76b5cd3), LL(0x396e6ea56e57cbdc), LL(0xaac4c437c46ef395), LL(0x1b03030c03180f06), LL(0xdc565645568a13ac), LL(0x5e44440d441a4988), LL(0xa07f7fe17fdf9efe), LL(0x88a9a99ea921374f), LL(0x672a2aa82a4d8254), LL(0x0abbbbd6bbb16d6b), LL(0x87c1c123c146e29f), LL(0xf153535153a202a6), LL(0x72dcdc57dcae8ba5), LL(0x530b0b2c0b582716), LL(0x019d9d4e9d9cd327), LL(0x2b6c6cad6c47c1d8), LL(0xa43131c43195f562), LL(0xf37474cd7487b9e8), LL(0x15f6f6fff6e309f1), LL(0x4c464605460a438c), LL(0xa5acac8aac092645), LL(0xb589891e893c970f), LL(0xb414145014a04428), LL(0xbae1e1a3e15b42df), LL(0xa616165816b04e2c), LL(0xf73a3ae83acdd274), LL(0x066969b9696fd0d2), LL(0x4109092409482d12), LL(0xd77070dd70a7ade0), LL(0x6fb6b6e2b6d95471), LL(0x1ed0d067d0ceb7bd), LL(0xd6eded93ed3b7ec7), LL(0xe2cccc17cc2edb85), LL(0x68424215422a5784), LL(0x2c98985a98b4c22d), LL(0xeda4a4aaa4490e55), LL(0x752828a0285d8850), LL(0x865c5c6d5cda31b8), LL(0x6bf8f8c7f8933fed), LL(0xc28686228644a411), }; static const u64 C2[256] = { LL(0x30d818186018c078), LL(0x462623238c2305af), LL(0x91b8c6c63fc67ef9), LL(0xcdfbe8e887e8136f), LL(0x13cb878726874ca1), LL(0x6d11b8b8dab8a962), LL(0x0209010104010805), LL(0x9e0d4f4f214f426e), LL(0x6c9b3636d836adee), LL(0x51ffa6a6a2a65904), LL(0xb90cd2d26fd2debd), LL(0xf70ef5f5f3f5fb06), LL(0xf2967979f979ef80), LL(0xde306f6fa16f5fce), LL(0x3f6d91917e91fcef), LL(0xa4f852525552aa07), LL(0xc04760609d6027fd), LL(0x6535bcbccabc8976), LL(0x2b379b9b569baccd), LL(0x018a8e8e028e048c), LL(0x5bd2a3a3b6a37115), LL(0x186c0c0c300c603c), LL(0xf6847b7bf17bff8a), LL(0x6a803535d435b5e1), LL(0x3af51d1d741de869), LL(0xddb3e0e0a7e05347), LL(0xb321d7d77bd7f6ac), LL(0x999cc2c22fc25eed), LL(0x5c432e2eb82e6d96), LL(0x96294b4b314b627a), LL(0xe15dfefedffea321), LL(0xaed5575741578216), LL(0x2abd15155415a841), LL(0xeee87777c1779fb6), LL(0x6e923737dc37a5eb), LL(0xd79ee5e5b3e57b56), LL(0x23139f9f469f8cd9), LL(0xfd23f0f0e7f0d317), LL(0x94204a4a354a6a7f), LL(0xa944dada4fda9e95), LL(0xb0a258587d58fa25), LL(0x8fcfc9c903c906ca), LL(0x527c2929a429558d), LL(0x145a0a0a280a5022), LL(0x7f50b1b1feb1e14f), LL(0x5dc9a0a0baa0691a), LL(0xd6146b6bb16b7fda), LL(0x17d985852e855cab), LL(0x673cbdbdcebd8173), LL(0xba8f5d5d695dd234), LL(0x2090101040108050), LL(0xf507f4f4f7f4f303), LL(0x8bddcbcb0bcb16c0), LL(0x7cd33e3ef83eedc6), LL(0x0a2d050514052811), LL(0xce78676781671fe6), LL(0xd597e4e4b7e47353), LL(0x4e0227279c2725bb), LL(0x8273414119413258), LL(0x0ba78b8b168b2c9d), LL(0x53f6a7a7a6a75101), LL(0xfab27d7de97dcf94), LL(0x374995956e95dcfb), LL(0xad56d8d847d88e9f), LL(0xeb70fbfbcbfb8b30), LL(0xc1cdeeee9fee2371), LL(0xf8bb7c7ced7cc791), LL(0xcc716666856617e3), LL(0xa77bdddd53dda68e), LL(0x2eaf17175c17b84b), LL(0x8e45474701470246), LL(0x211a9e9e429e84dc), LL(0x89d4caca0fca1ec5), LL(0x5a582d2db42d7599), LL(0x632ebfbfc6bf9179), LL(0x0e3f07071c07381b), LL(0x47acadad8ead0123), LL(0xb4b05a5a755aea2f), LL(0x1bef838336836cb5), LL(0x66b63333cc3385ff), LL(0xc65c636391633ff2), LL(0x041202020802100a), LL(0x4993aaaa92aa3938), LL(0xe2de7171d971afa8), LL(0x8dc6c8c807c80ecf), LL(0x32d119196419c87d), LL(0x923b494939497270), LL(0xaf5fd9d943d9869a), LL(0xf931f2f2eff2c31d), LL(0xdba8e3e3abe34b48), LL(0xb6b95b5b715be22a), LL(0x0dbc88881a883492), LL(0x293e9a9a529aa4c8), LL(0x4c0b262698262dbe), LL(0x64bf3232c8328dfa), LL(0x7d59b0b0fab0e94a), LL(0xcff2e9e983e91b6a), LL(0x1e770f0f3c0f7833), LL(0xb733d5d573d5e6a6), LL(0x1df480803a8074ba), LL(0x6127bebec2be997c), LL(0x87ebcdcd13cd26de), LL(0x68893434d034bde4), LL(0x903248483d487a75), LL(0xe354ffffdbffab24), LL(0xf48d7a7af57af78f), LL(0x3d6490907a90f4ea), LL(0xbe9d5f5f615fc23e), LL(0x403d202080201da0), LL(0xd00f6868bd6867d5), LL(0x34ca1a1a681ad072), LL(0x41b7aeae82ae192c), LL(0x757db4b4eab4c95e), LL(0xa8ce54544d549a19), LL(0x3b7f93937693ece5), LL(0x442f222288220daa), LL(0xc86364648d6407e9), LL(0xff2af1f1e3f1db12), LL(0xe6cc7373d173bfa2), LL(0x248212124812905a), LL(0x807a40401d403a5d), LL(0x1048080820084028), LL(0x9b95c3c32bc356e8), LL(0xc5dfecec97ec337b), LL(0xab4ddbdb4bdb9690), LL(0x5fc0a1a1bea1611f), LL(0x07918d8d0e8d1c83), LL(0x7ac83d3df43df5c9), LL(0x335b97976697ccf1), LL(0x0000000000000000), LL(0x83f9cfcf1bcf36d4), LL(0x566e2b2bac2b4587), LL(0xece17676c57697b3), LL(0x19e68282328264b0), LL(0xb128d6d67fd6fea9), LL(0x36c31b1b6c1bd877), LL(0x7774b5b5eeb5c15b), LL(0x43beafaf86af1129), LL(0xd41d6a6ab56a77df), LL(0xa0ea50505d50ba0d), LL(0x8a5745450945124c), LL(0xfb38f3f3ebf3cb18), LL(0x60ad3030c0309df0), LL(0xc3c4efef9bef2b74), LL(0x7eda3f3ffc3fe5c3), LL(0xaac755554955921c), LL(0x59dba2a2b2a27910), LL(0xc9e9eaea8fea0365), LL(0xca6a656589650fec), LL(0x6903babad2bab968), LL(0x5e4a2f2fbc2f6593), LL(0x9d8ec0c027c04ee7), LL(0xa160dede5fdebe81), LL(0x38fc1c1c701ce06c), LL(0xe746fdfdd3fdbb2e), LL(0x9a1f4d4d294d5264), LL(0x397692927292e4e0), LL(0xeafa7575c9758fbc), LL(0x0c3606061806301e), LL(0x09ae8a8a128a2498), LL(0x794bb2b2f2b2f940), LL(0xd185e6e6bfe66359), LL(0x1c7e0e0e380e7036), LL(0x3ee71f1f7c1ff863), LL(0xc4556262956237f7), LL(0xb53ad4d477d4eea3), LL(0x4d81a8a89aa82932), LL(0x315296966296c4f4), LL(0xef62f9f9c3f99b3a), LL(0x97a3c5c533c566f6), LL(0x4a102525942535b1), LL(0xb2ab59597959f220), LL(0x15d084842a8454ae), LL(0xe4c57272d572b7a7), LL(0x72ec3939e439d5dd), LL(0x98164c4c2d4c5a61), LL(0xbc945e5e655eca3b), LL(0xf09f7878fd78e785), LL(0x70e53838e038ddd8), LL(0x05988c8c0a8c1486), LL(0xbf17d1d163d1c6b2), LL(0x57e4a5a5aea5410b), LL(0xd9a1e2e2afe2434d), LL(0xc24e616199612ff8), LL(0x7b42b3b3f6b3f145), LL(0x42342121842115a5), LL(0x25089c9c4a9c94d6), LL(0x3cee1e1e781ef066), LL(0x8661434311432252), LL(0x93b1c7c73bc776fc), LL(0xe54ffcfcd7fcb32b), LL(0x0824040410042014), LL(0xa2e351515951b208), LL(0x2f2599995e99bcc7), LL(0xda226d6da96d4fc4), LL(0x1a650d0d340d6839), LL(0xe979fafacffa8335), LL(0xa369dfdf5bdfb684), LL(0xfca97e7ee57ed79b), LL(0x4819242490243db4), LL(0x76fe3b3bec3bc5d7), LL(0x4b9aabab96ab313d), LL(0x81f0cece1fce3ed1), LL(0x2299111144118855), LL(0x03838f8f068f0c89), LL(0x9c044e4e254e4a6b), LL(0x7366b7b7e6b7d151), LL(0xcbe0ebeb8beb0b60), LL(0x78c13c3cf03cfdcc), LL(0x1ffd81813e817cbf), LL(0x354094946a94d4fe), LL(0xf31cf7f7fbf7eb0c), LL(0x6f18b9b9deb9a167), LL(0x268b13134c13985f), LL(0x58512c2cb02c7d9c), LL(0xbb05d3d36bd3d6b8), LL(0xd38ce7e7bbe76b5c), LL(0xdc396e6ea56e57cb), LL(0x95aac4c437c46ef3), LL(0x061b03030c03180f), LL(0xacdc565645568a13), LL(0x885e44440d441a49), LL(0xfea07f7fe17fdf9e), LL(0x4f88a9a99ea92137), LL(0x54672a2aa82a4d82), LL(0x6b0abbbbd6bbb16d), LL(0x9f87c1c123c146e2), LL(0xa6f153535153a202), LL(0xa572dcdc57dcae8b), LL(0x16530b0b2c0b5827), LL(0x27019d9d4e9d9cd3), LL(0xd82b6c6cad6c47c1), LL(0x62a43131c43195f5), LL(0xe8f37474cd7487b9), LL(0xf115f6f6fff6e309), LL(0x8c4c464605460a43), LL(0x45a5acac8aac0926), LL(0x0fb589891e893c97), LL(0x28b414145014a044), LL(0xdfbae1e1a3e15b42), LL(0x2ca616165816b04e), LL(0x74f73a3ae83acdd2), LL(0xd2066969b9696fd0), LL(0x124109092409482d), LL(0xe0d77070dd70a7ad), LL(0x716fb6b6e2b6d954), LL(0xbd1ed0d067d0ceb7), LL(0xc7d6eded93ed3b7e), LL(0x85e2cccc17cc2edb), LL(0x8468424215422a57), LL(0x2d2c98985a98b4c2), LL(0x55eda4a4aaa4490e), LL(0x50752828a0285d88), LL(0xb8865c5c6d5cda31), LL(0xed6bf8f8c7f8933f), LL(0x11c28686228644a4), }; static const u64 C3[256] = { LL(0x7830d818186018c0), LL(0xaf462623238c2305), LL(0xf991b8c6c63fc67e), LL(0x6fcdfbe8e887e813), LL(0xa113cb878726874c), LL(0x626d11b8b8dab8a9), LL(0x0502090101040108), LL(0x6e9e0d4f4f214f42), LL(0xee6c9b3636d836ad), LL(0x0451ffa6a6a2a659), LL(0xbdb90cd2d26fd2de), LL(0x06f70ef5f5f3f5fb), LL(0x80f2967979f979ef), LL(0xcede306f6fa16f5f), LL(0xef3f6d91917e91fc), LL(0x07a4f852525552aa), LL(0xfdc04760609d6027), LL(0x766535bcbccabc89), LL(0xcd2b379b9b569bac), LL(0x8c018a8e8e028e04), LL(0x155bd2a3a3b6a371), LL(0x3c186c0c0c300c60), LL(0x8af6847b7bf17bff), LL(0xe16a803535d435b5), LL(0x693af51d1d741de8), LL(0x47ddb3e0e0a7e053), LL(0xacb321d7d77bd7f6), LL(0xed999cc2c22fc25e), LL(0x965c432e2eb82e6d), LL(0x7a96294b4b314b62), LL(0x21e15dfefedffea3), LL(0x16aed55757415782), LL(0x412abd15155415a8), LL(0xb6eee87777c1779f), LL(0xeb6e923737dc37a5), LL(0x56d79ee5e5b3e57b), LL(0xd923139f9f469f8c), LL(0x17fd23f0f0e7f0d3), LL(0x7f94204a4a354a6a), LL(0x95a944dada4fda9e), LL(0x25b0a258587d58fa), LL(0xca8fcfc9c903c906), LL(0x8d527c2929a42955), LL(0x22145a0a0a280a50), LL(0x4f7f50b1b1feb1e1), LL(0x1a5dc9a0a0baa069), LL(0xdad6146b6bb16b7f), LL(0xab17d985852e855c), LL(0x73673cbdbdcebd81), LL(0x34ba8f5d5d695dd2), LL(0x5020901010401080), LL(0x03f507f4f4f7f4f3), LL(0xc08bddcbcb0bcb16), LL(0xc67cd33e3ef83eed), LL(0x110a2d0505140528), LL(0xe6ce78676781671f), LL(0x53d597e4e4b7e473), LL(0xbb4e0227279c2725), LL(0x5882734141194132), LL(0x9d0ba78b8b168b2c), LL(0x0153f6a7a7a6a751), LL(0x94fab27d7de97dcf), LL(0xfb374995956e95dc), LL(0x9fad56d8d847d88e), LL(0x30eb70fbfbcbfb8b), LL(0x71c1cdeeee9fee23), LL(0x91f8bb7c7ced7cc7), LL(0xe3cc716666856617), LL(0x8ea77bdddd53dda6), LL(0x4b2eaf17175c17b8), LL(0x468e454747014702), LL(0xdc211a9e9e429e84), LL(0xc589d4caca0fca1e), LL(0x995a582d2db42d75), LL(0x79632ebfbfc6bf91), LL(0x1b0e3f07071c0738), LL(0x2347acadad8ead01), LL(0x2fb4b05a5a755aea), LL(0xb51bef838336836c), LL(0xff66b63333cc3385), LL(0xf2c65c636391633f), LL(0x0a04120202080210), LL(0x384993aaaa92aa39), LL(0xa8e2de7171d971af), LL(0xcf8dc6c8c807c80e), LL(0x7d32d119196419c8), LL(0x70923b4949394972), LL(0x9aaf5fd9d943d986), LL(0x1df931f2f2eff2c3), LL(0x48dba8e3e3abe34b), LL(0x2ab6b95b5b715be2), LL(0x920dbc88881a8834), LL(0xc8293e9a9a529aa4), LL(0xbe4c0b262698262d), LL(0xfa64bf3232c8328d), LL(0x4a7d59b0b0fab0e9), LL(0x6acff2e9e983e91b), LL(0x331e770f0f3c0f78), LL(0xa6b733d5d573d5e6), LL(0xba1df480803a8074), LL(0x7c6127bebec2be99), LL(0xde87ebcdcd13cd26), LL(0xe468893434d034bd), LL(0x75903248483d487a), LL(0x24e354ffffdbffab), LL(0x8ff48d7a7af57af7), LL(0xea3d6490907a90f4), LL(0x3ebe9d5f5f615fc2), LL(0xa0403d202080201d), LL(0xd5d00f6868bd6867), LL(0x7234ca1a1a681ad0), LL(0x2c41b7aeae82ae19), LL(0x5e757db4b4eab4c9), LL(0x19a8ce54544d549a), LL(0xe53b7f93937693ec), LL(0xaa442f222288220d), LL(0xe9c86364648d6407), LL(0x12ff2af1f1e3f1db), LL(0xa2e6cc7373d173bf), LL(0x5a24821212481290), LL(0x5d807a40401d403a), LL(0x2810480808200840), LL(0xe89b95c3c32bc356), LL(0x7bc5dfecec97ec33), LL(0x90ab4ddbdb4bdb96), LL(0x1f5fc0a1a1bea161), LL(0x8307918d8d0e8d1c), LL(0xc97ac83d3df43df5), LL(0xf1335b97976697cc), LL(0x0000000000000000), LL(0xd483f9cfcf1bcf36), LL(0x87566e2b2bac2b45), LL(0xb3ece17676c57697), LL(0xb019e68282328264), LL(0xa9b128d6d67fd6fe), LL(0x7736c31b1b6c1bd8), LL(0x5b7774b5b5eeb5c1), LL(0x2943beafaf86af11), LL(0xdfd41d6a6ab56a77), LL(0x0da0ea50505d50ba), LL(0x4c8a574545094512), LL(0x18fb38f3f3ebf3cb), LL(0xf060ad3030c0309d), LL(0x74c3c4efef9bef2b), LL(0xc37eda3f3ffc3fe5), LL(0x1caac75555495592), LL(0x1059dba2a2b2a279), LL(0x65c9e9eaea8fea03), LL(0xecca6a656589650f), LL(0x686903babad2bab9), LL(0x935e4a2f2fbc2f65), LL(0xe79d8ec0c027c04e), LL(0x81a160dede5fdebe), LL(0x6c38fc1c1c701ce0), LL(0x2ee746fdfdd3fdbb), LL(0x649a1f4d4d294d52), LL(0xe0397692927292e4), LL(0xbceafa7575c9758f), LL(0x1e0c360606180630), LL(0x9809ae8a8a128a24), LL(0x40794bb2b2f2b2f9), LL(0x59d185e6e6bfe663), LL(0x361c7e0e0e380e70), LL(0x633ee71f1f7c1ff8), LL(0xf7c4556262956237), LL(0xa3b53ad4d477d4ee), LL(0x324d81a8a89aa829), LL(0xf4315296966296c4), LL(0x3aef62f9f9c3f99b), LL(0xf697a3c5c533c566), LL(0xb14a102525942535), LL(0x20b2ab59597959f2), LL(0xae15d084842a8454), LL(0xa7e4c57272d572b7), LL(0xdd72ec3939e439d5), LL(0x6198164c4c2d4c5a), LL(0x3bbc945e5e655eca), LL(0x85f09f7878fd78e7), LL(0xd870e53838e038dd), LL(0x8605988c8c0a8c14), LL(0xb2bf17d1d163d1c6), LL(0x0b57e4a5a5aea541), LL(0x4dd9a1e2e2afe243), LL(0xf8c24e616199612f), LL(0x457b42b3b3f6b3f1), LL(0xa542342121842115), LL(0xd625089c9c4a9c94), LL(0x663cee1e1e781ef0), LL(0x5286614343114322), LL(0xfc93b1c7c73bc776), LL(0x2be54ffcfcd7fcb3), LL(0x1408240404100420), LL(0x08a2e351515951b2), LL(0xc72f2599995e99bc), LL(0xc4da226d6da96d4f), LL(0x391a650d0d340d68), LL(0x35e979fafacffa83), LL(0x84a369dfdf5bdfb6), LL(0x9bfca97e7ee57ed7), LL(0xb44819242490243d), LL(0xd776fe3b3bec3bc5), LL(0x3d4b9aabab96ab31), LL(0xd181f0cece1fce3e), LL(0x5522991111441188), LL(0x8903838f8f068f0c), LL(0x6b9c044e4e254e4a), LL(0x517366b7b7e6b7d1), LL(0x60cbe0ebeb8beb0b), LL(0xcc78c13c3cf03cfd), LL(0xbf1ffd81813e817c), LL(0xfe354094946a94d4), LL(0x0cf31cf7f7fbf7eb), LL(0x676f18b9b9deb9a1), LL(0x5f268b13134c1398), LL(0x9c58512c2cb02c7d), LL(0xb8bb05d3d36bd3d6), LL(0x5cd38ce7e7bbe76b), LL(0xcbdc396e6ea56e57), LL(0xf395aac4c437c46e), LL(0x0f061b03030c0318), LL(0x13acdc565645568a), LL(0x49885e44440d441a), LL(0x9efea07f7fe17fdf), LL(0x374f88a9a99ea921), LL(0x8254672a2aa82a4d), LL(0x6d6b0abbbbd6bbb1), LL(0xe29f87c1c123c146), LL(0x02a6f153535153a2), LL(0x8ba572dcdc57dcae), LL(0x2716530b0b2c0b58), LL(0xd327019d9d4e9d9c), LL(0xc1d82b6c6cad6c47), LL(0xf562a43131c43195), LL(0xb9e8f37474cd7487), LL(0x09f115f6f6fff6e3), LL(0x438c4c464605460a), LL(0x2645a5acac8aac09), LL(0x970fb589891e893c), LL(0x4428b414145014a0), LL(0x42dfbae1e1a3e15b), LL(0x4e2ca616165816b0), LL(0xd274f73a3ae83acd), LL(0xd0d2066969b9696f), LL(0x2d12410909240948), LL(0xade0d77070dd70a7), LL(0x54716fb6b6e2b6d9), LL(0xb7bd1ed0d067d0ce), LL(0x7ec7d6eded93ed3b), LL(0xdb85e2cccc17cc2e), LL(0x578468424215422a), LL(0xc22d2c98985a98b4), LL(0x0e55eda4a4aaa449), LL(0x8850752828a0285d), LL(0x31b8865c5c6d5cda), LL(0x3fed6bf8f8c7f893), LL(0xa411c28686228644), }; static const u64 C4[256] = { LL(0xc07830d818186018), LL(0x05af462623238c23), LL(0x7ef991b8c6c63fc6), LL(0x136fcdfbe8e887e8), LL(0x4ca113cb87872687), LL(0xa9626d11b8b8dab8), LL(0x0805020901010401), LL(0x426e9e0d4f4f214f), LL(0xadee6c9b3636d836), LL(0x590451ffa6a6a2a6), LL(0xdebdb90cd2d26fd2), LL(0xfb06f70ef5f5f3f5), LL(0xef80f2967979f979), LL(0x5fcede306f6fa16f), LL(0xfcef3f6d91917e91), LL(0xaa07a4f852525552), LL(0x27fdc04760609d60), LL(0x89766535bcbccabc), LL(0xaccd2b379b9b569b), LL(0x048c018a8e8e028e), LL(0x71155bd2a3a3b6a3), LL(0x603c186c0c0c300c), LL(0xff8af6847b7bf17b), LL(0xb5e16a803535d435), LL(0xe8693af51d1d741d), LL(0x5347ddb3e0e0a7e0), LL(0xf6acb321d7d77bd7), LL(0x5eed999cc2c22fc2), LL(0x6d965c432e2eb82e), LL(0x627a96294b4b314b), LL(0xa321e15dfefedffe), LL(0x8216aed557574157), LL(0xa8412abd15155415), LL(0x9fb6eee87777c177), LL(0xa5eb6e923737dc37), LL(0x7b56d79ee5e5b3e5), LL(0x8cd923139f9f469f), LL(0xd317fd23f0f0e7f0), LL(0x6a7f94204a4a354a), LL(0x9e95a944dada4fda), LL(0xfa25b0a258587d58), LL(0x06ca8fcfc9c903c9), LL(0x558d527c2929a429), LL(0x5022145a0a0a280a), LL(0xe14f7f50b1b1feb1), LL(0x691a5dc9a0a0baa0), LL(0x7fdad6146b6bb16b), LL(0x5cab17d985852e85), LL(0x8173673cbdbdcebd), LL(0xd234ba8f5d5d695d), LL(0x8050209010104010), LL(0xf303f507f4f4f7f4), LL(0x16c08bddcbcb0bcb), LL(0xedc67cd33e3ef83e), LL(0x28110a2d05051405), LL(0x1fe6ce7867678167), LL(0x7353d597e4e4b7e4), LL(0x25bb4e0227279c27), LL(0x3258827341411941), LL(0x2c9d0ba78b8b168b), LL(0x510153f6a7a7a6a7), LL(0xcf94fab27d7de97d), LL(0xdcfb374995956e95), LL(0x8e9fad56d8d847d8), LL(0x8b30eb70fbfbcbfb), LL(0x2371c1cdeeee9fee), LL(0xc791f8bb7c7ced7c), LL(0x17e3cc7166668566), LL(0xa68ea77bdddd53dd), LL(0xb84b2eaf17175c17), LL(0x02468e4547470147), LL(0x84dc211a9e9e429e), LL(0x1ec589d4caca0fca), LL(0x75995a582d2db42d), LL(0x9179632ebfbfc6bf), LL(0x381b0e3f07071c07), LL(0x012347acadad8ead), LL(0xea2fb4b05a5a755a), LL(0x6cb51bef83833683), LL(0x85ff66b63333cc33), LL(0x3ff2c65c63639163), LL(0x100a041202020802), LL(0x39384993aaaa92aa), LL(0xafa8e2de7171d971), LL(0x0ecf8dc6c8c807c8), LL(0xc87d32d119196419), LL(0x7270923b49493949), LL(0x869aaf5fd9d943d9), LL(0xc31df931f2f2eff2), LL(0x4b48dba8e3e3abe3), LL(0xe22ab6b95b5b715b), LL(0x34920dbc88881a88), LL(0xa4c8293e9a9a529a), LL(0x2dbe4c0b26269826), LL(0x8dfa64bf3232c832), LL(0xe94a7d59b0b0fab0), LL(0x1b6acff2e9e983e9), LL(0x78331e770f0f3c0f), LL(0xe6a6b733d5d573d5), LL(0x74ba1df480803a80), LL(0x997c6127bebec2be), LL(0x26de87ebcdcd13cd), LL(0xbde468893434d034), LL(0x7a75903248483d48), LL(0xab24e354ffffdbff), LL(0xf78ff48d7a7af57a), LL(0xf4ea3d6490907a90), LL(0xc23ebe9d5f5f615f), LL(0x1da0403d20208020), LL(0x67d5d00f6868bd68), LL(0xd07234ca1a1a681a), LL(0x192c41b7aeae82ae), LL(0xc95e757db4b4eab4), LL(0x9a19a8ce54544d54), LL(0xece53b7f93937693), LL(0x0daa442f22228822), LL(0x07e9c86364648d64), LL(0xdb12ff2af1f1e3f1), LL(0xbfa2e6cc7373d173), LL(0x905a248212124812), LL(0x3a5d807a40401d40), LL(0x4028104808082008), LL(0x56e89b95c3c32bc3), LL(0x337bc5dfecec97ec), LL(0x9690ab4ddbdb4bdb), LL(0x611f5fc0a1a1bea1), LL(0x1c8307918d8d0e8d), LL(0xf5c97ac83d3df43d), LL(0xccf1335b97976697), LL(0x0000000000000000), LL(0x36d483f9cfcf1bcf), LL(0x4587566e2b2bac2b), LL(0x97b3ece17676c576), LL(0x64b019e682823282), LL(0xfea9b128d6d67fd6), LL(0xd87736c31b1b6c1b), LL(0xc15b7774b5b5eeb5), LL(0x112943beafaf86af), LL(0x77dfd41d6a6ab56a), LL(0xba0da0ea50505d50), LL(0x124c8a5745450945), LL(0xcb18fb38f3f3ebf3), LL(0x9df060ad3030c030), LL(0x2b74c3c4efef9bef), LL(0xe5c37eda3f3ffc3f), LL(0x921caac755554955), LL(0x791059dba2a2b2a2), LL(0x0365c9e9eaea8fea), LL(0x0fecca6a65658965), LL(0xb9686903babad2ba), LL(0x65935e4a2f2fbc2f), LL(0x4ee79d8ec0c027c0), LL(0xbe81a160dede5fde), LL(0xe06c38fc1c1c701c), LL(0xbb2ee746fdfdd3fd), LL(0x52649a1f4d4d294d), LL(0xe4e0397692927292), LL(0x8fbceafa7575c975), LL(0x301e0c3606061806), LL(0x249809ae8a8a128a), LL(0xf940794bb2b2f2b2), LL(0x6359d185e6e6bfe6), LL(0x70361c7e0e0e380e), LL(0xf8633ee71f1f7c1f), LL(0x37f7c45562629562), LL(0xeea3b53ad4d477d4), LL(0x29324d81a8a89aa8), LL(0xc4f4315296966296), LL(0x9b3aef62f9f9c3f9), LL(0x66f697a3c5c533c5), LL(0x35b14a1025259425), LL(0xf220b2ab59597959), LL(0x54ae15d084842a84), LL(0xb7a7e4c57272d572), LL(0xd5dd72ec3939e439), LL(0x5a6198164c4c2d4c), LL(0xca3bbc945e5e655e), LL(0xe785f09f7878fd78), LL(0xddd870e53838e038), LL(0x148605988c8c0a8c), LL(0xc6b2bf17d1d163d1), LL(0x410b57e4a5a5aea5), LL(0x434dd9a1e2e2afe2), LL(0x2ff8c24e61619961), LL(0xf1457b42b3b3f6b3), LL(0x15a5423421218421), LL(0x94d625089c9c4a9c), LL(0xf0663cee1e1e781e), LL(0x2252866143431143), LL(0x76fc93b1c7c73bc7), LL(0xb32be54ffcfcd7fc), LL(0x2014082404041004), LL(0xb208a2e351515951), LL(0xbcc72f2599995e99), LL(0x4fc4da226d6da96d), LL(0x68391a650d0d340d), LL(0x8335e979fafacffa), LL(0xb684a369dfdf5bdf), LL(0xd79bfca97e7ee57e), LL(0x3db4481924249024), LL(0xc5d776fe3b3bec3b), LL(0x313d4b9aabab96ab), LL(0x3ed181f0cece1fce), LL(0x8855229911114411), LL(0x0c8903838f8f068f), LL(0x4a6b9c044e4e254e), LL(0xd1517366b7b7e6b7), LL(0x0b60cbe0ebeb8beb), LL(0xfdcc78c13c3cf03c), LL(0x7cbf1ffd81813e81), LL(0xd4fe354094946a94), LL(0xeb0cf31cf7f7fbf7), LL(0xa1676f18b9b9deb9), LL(0x985f268b13134c13), LL(0x7d9c58512c2cb02c), LL(0xd6b8bb05d3d36bd3), LL(0x6b5cd38ce7e7bbe7), LL(0x57cbdc396e6ea56e), LL(0x6ef395aac4c437c4), LL(0x180f061b03030c03), LL(0x8a13acdc56564556), LL(0x1a49885e44440d44), LL(0xdf9efea07f7fe17f), LL(0x21374f88a9a99ea9), LL(0x4d8254672a2aa82a), LL(0xb16d6b0abbbbd6bb), LL(0x46e29f87c1c123c1), LL(0xa202a6f153535153), LL(0xae8ba572dcdc57dc), LL(0x582716530b0b2c0b), LL(0x9cd327019d9d4e9d), LL(0x47c1d82b6c6cad6c), LL(0x95f562a43131c431), LL(0x87b9e8f37474cd74), LL(0xe309f115f6f6fff6), LL(0x0a438c4c46460546), LL(0x092645a5acac8aac), LL(0x3c970fb589891e89), LL(0xa04428b414145014), LL(0x5b42dfbae1e1a3e1), LL(0xb04e2ca616165816), LL(0xcdd274f73a3ae83a), LL(0x6fd0d2066969b969), LL(0x482d124109092409), LL(0xa7ade0d77070dd70), LL(0xd954716fb6b6e2b6), LL(0xceb7bd1ed0d067d0), LL(0x3b7ec7d6eded93ed), LL(0x2edb85e2cccc17cc), LL(0x2a57846842421542), LL(0xb4c22d2c98985a98), LL(0x490e55eda4a4aaa4), LL(0x5d8850752828a028), LL(0xda31b8865c5c6d5c), LL(0x933fed6bf8f8c7f8), LL(0x44a411c286862286), }; static const u64 C5[256] = { LL(0x18c07830d8181860), LL(0x2305af462623238c), LL(0xc67ef991b8c6c63f), LL(0xe8136fcdfbe8e887), LL(0x874ca113cb878726), LL(0xb8a9626d11b8b8da), LL(0x0108050209010104), LL(0x4f426e9e0d4f4f21), LL(0x36adee6c9b3636d8), LL(0xa6590451ffa6a6a2), LL(0xd2debdb90cd2d26f), LL(0xf5fb06f70ef5f5f3), LL(0x79ef80f2967979f9), LL(0x6f5fcede306f6fa1), LL(0x91fcef3f6d91917e), LL(0x52aa07a4f8525255), LL(0x6027fdc04760609d), LL(0xbc89766535bcbcca), LL(0x9baccd2b379b9b56), LL(0x8e048c018a8e8e02), LL(0xa371155bd2a3a3b6), LL(0x0c603c186c0c0c30), LL(0x7bff8af6847b7bf1), LL(0x35b5e16a803535d4), LL(0x1de8693af51d1d74), LL(0xe05347ddb3e0e0a7), LL(0xd7f6acb321d7d77b), LL(0xc25eed999cc2c22f), LL(0x2e6d965c432e2eb8), LL(0x4b627a96294b4b31), LL(0xfea321e15dfefedf), LL(0x578216aed5575741), LL(0x15a8412abd151554), LL(0x779fb6eee87777c1), LL(0x37a5eb6e923737dc), LL(0xe57b56d79ee5e5b3), LL(0x9f8cd923139f9f46), LL(0xf0d317fd23f0f0e7), LL(0x4a6a7f94204a4a35), LL(0xda9e95a944dada4f), LL(0x58fa25b0a258587d), LL(0xc906ca8fcfc9c903), LL(0x29558d527c2929a4), LL(0x0a5022145a0a0a28), LL(0xb1e14f7f50b1b1fe), LL(0xa0691a5dc9a0a0ba), LL(0x6b7fdad6146b6bb1), LL(0x855cab17d985852e), LL(0xbd8173673cbdbdce), LL(0x5dd234ba8f5d5d69), LL(0x1080502090101040), LL(0xf4f303f507f4f4f7), LL(0xcb16c08bddcbcb0b), LL(0x3eedc67cd33e3ef8), LL(0x0528110a2d050514), LL(0x671fe6ce78676781), LL(0xe47353d597e4e4b7), LL(0x2725bb4e0227279c), LL(0x4132588273414119), LL(0x8b2c9d0ba78b8b16), LL(0xa7510153f6a7a7a6), LL(0x7dcf94fab27d7de9), LL(0x95dcfb374995956e), LL(0xd88e9fad56d8d847), LL(0xfb8b30eb70fbfbcb), LL(0xee2371c1cdeeee9f), LL(0x7cc791f8bb7c7ced), LL(0x6617e3cc71666685), LL(0xdda68ea77bdddd53), LL(0x17b84b2eaf17175c), LL(0x4702468e45474701), LL(0x9e84dc211a9e9e42), LL(0xca1ec589d4caca0f), LL(0x2d75995a582d2db4), LL(0xbf9179632ebfbfc6), LL(0x07381b0e3f07071c), LL(0xad012347acadad8e), LL(0x5aea2fb4b05a5a75), LL(0x836cb51bef838336), LL(0x3385ff66b63333cc), LL(0x633ff2c65c636391), LL(0x02100a0412020208), LL(0xaa39384993aaaa92), LL(0x71afa8e2de7171d9), LL(0xc80ecf8dc6c8c807), LL(0x19c87d32d1191964), LL(0x497270923b494939), LL(0xd9869aaf5fd9d943), LL(0xf2c31df931f2f2ef), LL(0xe34b48dba8e3e3ab), LL(0x5be22ab6b95b5b71), LL(0x8834920dbc88881a), LL(0x9aa4c8293e9a9a52), LL(0x262dbe4c0b262698), LL(0x328dfa64bf3232c8), LL(0xb0e94a7d59b0b0fa), LL(0xe91b6acff2e9e983), LL(0x0f78331e770f0f3c), LL(0xd5e6a6b733d5d573), LL(0x8074ba1df480803a), LL(0xbe997c6127bebec2), LL(0xcd26de87ebcdcd13), LL(0x34bde468893434d0), LL(0x487a75903248483d), LL(0xffab24e354ffffdb), LL(0x7af78ff48d7a7af5), LL(0x90f4ea3d6490907a), LL(0x5fc23ebe9d5f5f61), LL(0x201da0403d202080), LL(0x6867d5d00f6868bd), LL(0x1ad07234ca1a1a68), LL(0xae192c41b7aeae82), LL(0xb4c95e757db4b4ea), LL(0x549a19a8ce54544d), LL(0x93ece53b7f939376), LL(0x220daa442f222288), LL(0x6407e9c86364648d), LL(0xf1db12ff2af1f1e3), LL(0x73bfa2e6cc7373d1), LL(0x12905a2482121248), LL(0x403a5d807a40401d), LL(0x0840281048080820), LL(0xc356e89b95c3c32b), LL(0xec337bc5dfecec97), LL(0xdb9690ab4ddbdb4b), LL(0xa1611f5fc0a1a1be), LL(0x8d1c8307918d8d0e), LL(0x3df5c97ac83d3df4), LL(0x97ccf1335b979766), LL(0x0000000000000000), LL(0xcf36d483f9cfcf1b), LL(0x2b4587566e2b2bac), LL(0x7697b3ece17676c5), LL(0x8264b019e6828232), LL(0xd6fea9b128d6d67f), LL(0x1bd87736c31b1b6c), LL(0xb5c15b7774b5b5ee), LL(0xaf112943beafaf86), LL(0x6a77dfd41d6a6ab5), LL(0x50ba0da0ea50505d), LL(0x45124c8a57454509), LL(0xf3cb18fb38f3f3eb), LL(0x309df060ad3030c0), LL(0xef2b74c3c4efef9b), LL(0x3fe5c37eda3f3ffc), LL(0x55921caac7555549), LL(0xa2791059dba2a2b2), LL(0xea0365c9e9eaea8f), LL(0x650fecca6a656589), LL(0xbab9686903babad2), LL(0x2f65935e4a2f2fbc), LL(0xc04ee79d8ec0c027), LL(0xdebe81a160dede5f), LL(0x1ce06c38fc1c1c70), LL(0xfdbb2ee746fdfdd3), LL(0x4d52649a1f4d4d29), LL(0x92e4e03976929272), LL(0x758fbceafa7575c9), LL(0x06301e0c36060618), LL(0x8a249809ae8a8a12), LL(0xb2f940794bb2b2f2), LL(0xe66359d185e6e6bf), LL(0x0e70361c7e0e0e38), LL(0x1ff8633ee71f1f7c), LL(0x6237f7c455626295), LL(0xd4eea3b53ad4d477), LL(0xa829324d81a8a89a), LL(0x96c4f43152969662), LL(0xf99b3aef62f9f9c3), LL(0xc566f697a3c5c533), LL(0x2535b14a10252594), LL(0x59f220b2ab595979), LL(0x8454ae15d084842a), LL(0x72b7a7e4c57272d5), LL(0x39d5dd72ec3939e4), LL(0x4c5a6198164c4c2d), LL(0x5eca3bbc945e5e65), LL(0x78e785f09f7878fd), LL(0x38ddd870e53838e0), LL(0x8c148605988c8c0a), LL(0xd1c6b2bf17d1d163), LL(0xa5410b57e4a5a5ae), LL(0xe2434dd9a1e2e2af), LL(0x612ff8c24e616199), LL(0xb3f1457b42b3b3f6), LL(0x2115a54234212184), LL(0x9c94d625089c9c4a), LL(0x1ef0663cee1e1e78), LL(0x4322528661434311), LL(0xc776fc93b1c7c73b), LL(0xfcb32be54ffcfcd7), LL(0x0420140824040410), LL(0x51b208a2e3515159), LL(0x99bcc72f2599995e), LL(0x6d4fc4da226d6da9), LL(0x0d68391a650d0d34), LL(0xfa8335e979fafacf), LL(0xdfb684a369dfdf5b), LL(0x7ed79bfca97e7ee5), LL(0x243db44819242490), LL(0x3bc5d776fe3b3bec), LL(0xab313d4b9aabab96), LL(0xce3ed181f0cece1f), LL(0x1188552299111144), LL(0x8f0c8903838f8f06), LL(0x4e4a6b9c044e4e25), LL(0xb7d1517366b7b7e6), LL(0xeb0b60cbe0ebeb8b), LL(0x3cfdcc78c13c3cf0), LL(0x817cbf1ffd81813e), LL(0x94d4fe354094946a), LL(0xf7eb0cf31cf7f7fb), LL(0xb9a1676f18b9b9de), LL(0x13985f268b13134c), LL(0x2c7d9c58512c2cb0), LL(0xd3d6b8bb05d3d36b), LL(0xe76b5cd38ce7e7bb), LL(0x6e57cbdc396e6ea5), LL(0xc46ef395aac4c437), LL(0x03180f061b03030c), LL(0x568a13acdc565645), LL(0x441a49885e44440d), LL(0x7fdf9efea07f7fe1), LL(0xa921374f88a9a99e), LL(0x2a4d8254672a2aa8), LL(0xbbb16d6b0abbbbd6), LL(0xc146e29f87c1c123), LL(0x53a202a6f1535351), LL(0xdcae8ba572dcdc57), LL(0x0b582716530b0b2c), LL(0x9d9cd327019d9d4e), LL(0x6c47c1d82b6c6cad), LL(0x3195f562a43131c4), LL(0x7487b9e8f37474cd), LL(0xf6e309f115f6f6ff), LL(0x460a438c4c464605), LL(0xac092645a5acac8a), LL(0x893c970fb589891e), LL(0x14a04428b4141450), LL(0xe15b42dfbae1e1a3), LL(0x16b04e2ca6161658), LL(0x3acdd274f73a3ae8), LL(0x696fd0d2066969b9), LL(0x09482d1241090924), LL(0x70a7ade0d77070dd), LL(0xb6d954716fb6b6e2), LL(0xd0ceb7bd1ed0d067), LL(0xed3b7ec7d6eded93), LL(0xcc2edb85e2cccc17), LL(0x422a578468424215), LL(0x98b4c22d2c98985a), LL(0xa4490e55eda4a4aa), LL(0x285d8850752828a0), LL(0x5cda31b8865c5c6d), LL(0xf8933fed6bf8f8c7), LL(0x8644a411c2868622), }; static const u64 C6[256] = { LL(0x6018c07830d81818), LL(0x8c2305af46262323), LL(0x3fc67ef991b8c6c6), LL(0x87e8136fcdfbe8e8), LL(0x26874ca113cb8787), LL(0xdab8a9626d11b8b8), LL(0x0401080502090101), LL(0x214f426e9e0d4f4f), LL(0xd836adee6c9b3636), LL(0xa2a6590451ffa6a6), LL(0x6fd2debdb90cd2d2), LL(0xf3f5fb06f70ef5f5), LL(0xf979ef80f2967979), LL(0xa16f5fcede306f6f), LL(0x7e91fcef3f6d9191), LL(0x5552aa07a4f85252), LL(0x9d6027fdc0476060), LL(0xcabc89766535bcbc), LL(0x569baccd2b379b9b), LL(0x028e048c018a8e8e), LL(0xb6a371155bd2a3a3), LL(0x300c603c186c0c0c), LL(0xf17bff8af6847b7b), LL(0xd435b5e16a803535), LL(0x741de8693af51d1d), LL(0xa7e05347ddb3e0e0), LL(0x7bd7f6acb321d7d7), LL(0x2fc25eed999cc2c2), LL(0xb82e6d965c432e2e), LL(0x314b627a96294b4b), LL(0xdffea321e15dfefe), LL(0x41578216aed55757), LL(0x5415a8412abd1515), LL(0xc1779fb6eee87777), LL(0xdc37a5eb6e923737), LL(0xb3e57b56d79ee5e5), LL(0x469f8cd923139f9f), LL(0xe7f0d317fd23f0f0), LL(0x354a6a7f94204a4a), LL(0x4fda9e95a944dada), LL(0x7d58fa25b0a25858), LL(0x03c906ca8fcfc9c9), LL(0xa429558d527c2929), LL(0x280a5022145a0a0a), LL(0xfeb1e14f7f50b1b1), LL(0xbaa0691a5dc9a0a0), LL(0xb16b7fdad6146b6b), LL(0x2e855cab17d98585), LL(0xcebd8173673cbdbd), LL(0x695dd234ba8f5d5d), LL(0x4010805020901010), LL(0xf7f4f303f507f4f4), LL(0x0bcb16c08bddcbcb), LL(0xf83eedc67cd33e3e), LL(0x140528110a2d0505), LL(0x81671fe6ce786767), LL(0xb7e47353d597e4e4), LL(0x9c2725bb4e022727), LL(0x1941325882734141), LL(0x168b2c9d0ba78b8b), LL(0xa6a7510153f6a7a7), LL(0xe97dcf94fab27d7d), LL(0x6e95dcfb37499595), LL(0x47d88e9fad56d8d8), LL(0xcbfb8b30eb70fbfb), LL(0x9fee2371c1cdeeee), LL(0xed7cc791f8bb7c7c), LL(0x856617e3cc716666), LL(0x53dda68ea77bdddd), LL(0x5c17b84b2eaf1717), LL(0x014702468e454747), LL(0x429e84dc211a9e9e), LL(0x0fca1ec589d4caca), LL(0xb42d75995a582d2d), LL(0xc6bf9179632ebfbf), LL(0x1c07381b0e3f0707), LL(0x8ead012347acadad), LL(0x755aea2fb4b05a5a), LL(0x36836cb51bef8383), LL(0xcc3385ff66b63333), LL(0x91633ff2c65c6363), LL(0x0802100a04120202), LL(0x92aa39384993aaaa), LL(0xd971afa8e2de7171), LL(0x07c80ecf8dc6c8c8), LL(0x6419c87d32d11919), LL(0x39497270923b4949), LL(0x43d9869aaf5fd9d9), LL(0xeff2c31df931f2f2), LL(0xabe34b48dba8e3e3), LL(0x715be22ab6b95b5b), LL(0x1a8834920dbc8888), LL(0x529aa4c8293e9a9a), LL(0x98262dbe4c0b2626), LL(0xc8328dfa64bf3232), LL(0xfab0e94a7d59b0b0), LL(0x83e91b6acff2e9e9), LL(0x3c0f78331e770f0f), LL(0x73d5e6a6b733d5d5), LL(0x3a8074ba1df48080), LL(0xc2be997c6127bebe), LL(0x13cd26de87ebcdcd), LL(0xd034bde468893434), LL(0x3d487a7590324848), LL(0xdbffab24e354ffff), LL(0xf57af78ff48d7a7a), LL(0x7a90f4ea3d649090), LL(0x615fc23ebe9d5f5f), LL(0x80201da0403d2020), LL(0xbd6867d5d00f6868), LL(0x681ad07234ca1a1a), LL(0x82ae192c41b7aeae), LL(0xeab4c95e757db4b4), LL(0x4d549a19a8ce5454), LL(0x7693ece53b7f9393), LL(0x88220daa442f2222), LL(0x8d6407e9c8636464), LL(0xe3f1db12ff2af1f1), LL(0xd173bfa2e6cc7373), LL(0x4812905a24821212), LL(0x1d403a5d807a4040), LL(0x2008402810480808), LL(0x2bc356e89b95c3c3), LL(0x97ec337bc5dfecec), LL(0x4bdb9690ab4ddbdb), LL(0xbea1611f5fc0a1a1), LL(0x0e8d1c8307918d8d), LL(0xf43df5c97ac83d3d), LL(0x6697ccf1335b9797), LL(0x0000000000000000), LL(0x1bcf36d483f9cfcf), LL(0xac2b4587566e2b2b), LL(0xc57697b3ece17676), LL(0x328264b019e68282), LL(0x7fd6fea9b128d6d6), LL(0x6c1bd87736c31b1b), LL(0xeeb5c15b7774b5b5), LL(0x86af112943beafaf), LL(0xb56a77dfd41d6a6a), LL(0x5d50ba0da0ea5050), LL(0x0945124c8a574545), LL(0xebf3cb18fb38f3f3), LL(0xc0309df060ad3030), LL(0x9bef2b74c3c4efef), LL(0xfc3fe5c37eda3f3f), LL(0x4955921caac75555), LL(0xb2a2791059dba2a2), LL(0x8fea0365c9e9eaea), LL(0x89650fecca6a6565), LL(0xd2bab9686903baba), LL(0xbc2f65935e4a2f2f), LL(0x27c04ee79d8ec0c0), LL(0x5fdebe81a160dede), LL(0x701ce06c38fc1c1c), LL(0xd3fdbb2ee746fdfd), LL(0x294d52649a1f4d4d), LL(0x7292e4e039769292), LL(0xc9758fbceafa7575), LL(0x1806301e0c360606), LL(0x128a249809ae8a8a), LL(0xf2b2f940794bb2b2), LL(0xbfe66359d185e6e6), LL(0x380e70361c7e0e0e), LL(0x7c1ff8633ee71f1f), LL(0x956237f7c4556262), LL(0x77d4eea3b53ad4d4), LL(0x9aa829324d81a8a8), LL(0x6296c4f431529696), LL(0xc3f99b3aef62f9f9), LL(0x33c566f697a3c5c5), LL(0x942535b14a102525), LL(0x7959f220b2ab5959), LL(0x2a8454ae15d08484), LL(0xd572b7a7e4c57272), LL(0xe439d5dd72ec3939), LL(0x2d4c5a6198164c4c), LL(0x655eca3bbc945e5e), LL(0xfd78e785f09f7878), LL(0xe038ddd870e53838), LL(0x0a8c148605988c8c), LL(0x63d1c6b2bf17d1d1), LL(0xaea5410b57e4a5a5), LL(0xafe2434dd9a1e2e2), LL(0x99612ff8c24e6161), LL(0xf6b3f1457b42b3b3), LL(0x842115a542342121), LL(0x4a9c94d625089c9c), LL(0x781ef0663cee1e1e), LL(0x1143225286614343), LL(0x3bc776fc93b1c7c7), LL(0xd7fcb32be54ffcfc), LL(0x1004201408240404), LL(0x5951b208a2e35151), LL(0x5e99bcc72f259999), LL(0xa96d4fc4da226d6d), LL(0x340d68391a650d0d), LL(0xcffa8335e979fafa), LL(0x5bdfb684a369dfdf), LL(0xe57ed79bfca97e7e), LL(0x90243db448192424), LL(0xec3bc5d776fe3b3b), LL(0x96ab313d4b9aabab), LL(0x1fce3ed181f0cece), LL(0x4411885522991111), LL(0x068f0c8903838f8f), LL(0x254e4a6b9c044e4e), LL(0xe6b7d1517366b7b7), LL(0x8beb0b60cbe0ebeb), LL(0xf03cfdcc78c13c3c), LL(0x3e817cbf1ffd8181), LL(0x6a94d4fe35409494), LL(0xfbf7eb0cf31cf7f7), LL(0xdeb9a1676f18b9b9), LL(0x4c13985f268b1313), LL(0xb02c7d9c58512c2c), LL(0x6bd3d6b8bb05d3d3), LL(0xbbe76b5cd38ce7e7), LL(0xa56e57cbdc396e6e), LL(0x37c46ef395aac4c4), LL(0x0c03180f061b0303), LL(0x45568a13acdc5656), LL(0x0d441a49885e4444), LL(0xe17fdf9efea07f7f), LL(0x9ea921374f88a9a9), LL(0xa82a4d8254672a2a), LL(0xd6bbb16d6b0abbbb), LL(0x23c146e29f87c1c1), LL(0x5153a202a6f15353), LL(0x57dcae8ba572dcdc), LL(0x2c0b582716530b0b), LL(0x4e9d9cd327019d9d), LL(0xad6c47c1d82b6c6c), LL(0xc43195f562a43131), LL(0xcd7487b9e8f37474), LL(0xfff6e309f115f6f6), LL(0x05460a438c4c4646), LL(0x8aac092645a5acac), LL(0x1e893c970fb58989), LL(0x5014a04428b41414), LL(0xa3e15b42dfbae1e1), LL(0x5816b04e2ca61616), LL(0xe83acdd274f73a3a), LL(0xb9696fd0d2066969), LL(0x2409482d12410909), LL(0xdd70a7ade0d77070), LL(0xe2b6d954716fb6b6), LL(0x67d0ceb7bd1ed0d0), LL(0x93ed3b7ec7d6eded), LL(0x17cc2edb85e2cccc), LL(0x15422a5784684242), LL(0x5a98b4c22d2c9898), LL(0xaaa4490e55eda4a4), LL(0xa0285d8850752828), LL(0x6d5cda31b8865c5c), LL(0xc7f8933fed6bf8f8), LL(0x228644a411c28686), }; static const u64 C7[256] = { LL(0x186018c07830d818), LL(0x238c2305af462623), LL(0xc63fc67ef991b8c6), LL(0xe887e8136fcdfbe8), LL(0x8726874ca113cb87), LL(0xb8dab8a9626d11b8), LL(0x0104010805020901), LL(0x4f214f426e9e0d4f), LL(0x36d836adee6c9b36), LL(0xa6a2a6590451ffa6), LL(0xd26fd2debdb90cd2), LL(0xf5f3f5fb06f70ef5), LL(0x79f979ef80f29679), LL(0x6fa16f5fcede306f), LL(0x917e91fcef3f6d91), LL(0x525552aa07a4f852), LL(0x609d6027fdc04760), LL(0xbccabc89766535bc), LL(0x9b569baccd2b379b), LL(0x8e028e048c018a8e), LL(0xa3b6a371155bd2a3), LL(0x0c300c603c186c0c), LL(0x7bf17bff8af6847b), LL(0x35d435b5e16a8035), LL(0x1d741de8693af51d), LL(0xe0a7e05347ddb3e0), LL(0xd77bd7f6acb321d7), LL(0xc22fc25eed999cc2), LL(0x2eb82e6d965c432e), LL(0x4b314b627a96294b), LL(0xfedffea321e15dfe), LL(0x5741578216aed557), LL(0x155415a8412abd15), LL(0x77c1779fb6eee877), LL(0x37dc37a5eb6e9237), LL(0xe5b3e57b56d79ee5), LL(0x9f469f8cd923139f), LL(0xf0e7f0d317fd23f0), LL(0x4a354a6a7f94204a), LL(0xda4fda9e95a944da), LL(0x587d58fa25b0a258), LL(0xc903c906ca8fcfc9), LL(0x29a429558d527c29), LL(0x0a280a5022145a0a), LL(0xb1feb1e14f7f50b1), LL(0xa0baa0691a5dc9a0), LL(0x6bb16b7fdad6146b), LL(0x852e855cab17d985), LL(0xbdcebd8173673cbd), LL(0x5d695dd234ba8f5d), LL(0x1040108050209010), LL(0xf4f7f4f303f507f4), LL(0xcb0bcb16c08bddcb), LL(0x3ef83eedc67cd33e), LL(0x05140528110a2d05), LL(0x6781671fe6ce7867), LL(0xe4b7e47353d597e4), LL(0x279c2725bb4e0227), LL(0x4119413258827341), LL(0x8b168b2c9d0ba78b), LL(0xa7a6a7510153f6a7), LL(0x7de97dcf94fab27d), LL(0x956e95dcfb374995), LL(0xd847d88e9fad56d8), LL(0xfbcbfb8b30eb70fb), LL(0xee9fee2371c1cdee), LL(0x7ced7cc791f8bb7c), LL(0x66856617e3cc7166), LL(0xdd53dda68ea77bdd), LL(0x175c17b84b2eaf17), LL(0x47014702468e4547), LL(0x9e429e84dc211a9e), LL(0xca0fca1ec589d4ca), LL(0x2db42d75995a582d), LL(0xbfc6bf9179632ebf), LL(0x071c07381b0e3f07), LL(0xad8ead012347acad), LL(0x5a755aea2fb4b05a), LL(0x8336836cb51bef83), LL(0x33cc3385ff66b633), LL(0x6391633ff2c65c63), LL(0x020802100a041202), LL(0xaa92aa39384993aa), LL(0x71d971afa8e2de71), LL(0xc807c80ecf8dc6c8), LL(0x196419c87d32d119), LL(0x4939497270923b49), LL(0xd943d9869aaf5fd9), LL(0xf2eff2c31df931f2), LL(0xe3abe34b48dba8e3), LL(0x5b715be22ab6b95b), LL(0x881a8834920dbc88), LL(0x9a529aa4c8293e9a), LL(0x2698262dbe4c0b26), LL(0x32c8328dfa64bf32), LL(0xb0fab0e94a7d59b0), LL(0xe983e91b6acff2e9), LL(0x0f3c0f78331e770f), LL(0xd573d5e6a6b733d5), LL(0x803a8074ba1df480), LL(0xbec2be997c6127be), LL(0xcd13cd26de87ebcd), LL(0x34d034bde4688934), LL(0x483d487a75903248), LL(0xffdbffab24e354ff), LL(0x7af57af78ff48d7a), LL(0x907a90f4ea3d6490), LL(0x5f615fc23ebe9d5f), LL(0x2080201da0403d20), LL(0x68bd6867d5d00f68), LL(0x1a681ad07234ca1a), LL(0xae82ae192c41b7ae), LL(0xb4eab4c95e757db4), LL(0x544d549a19a8ce54), LL(0x937693ece53b7f93), LL(0x2288220daa442f22), LL(0x648d6407e9c86364), LL(0xf1e3f1db12ff2af1), LL(0x73d173bfa2e6cc73), LL(0x124812905a248212), LL(0x401d403a5d807a40), LL(0x0820084028104808), LL(0xc32bc356e89b95c3), LL(0xec97ec337bc5dfec), LL(0xdb4bdb9690ab4ddb), LL(0xa1bea1611f5fc0a1), LL(0x8d0e8d1c8307918d), LL(0x3df43df5c97ac83d), LL(0x976697ccf1335b97), LL(0x0000000000000000), LL(0xcf1bcf36d483f9cf), LL(0x2bac2b4587566e2b), LL(0x76c57697b3ece176), LL(0x82328264b019e682), LL(0xd67fd6fea9b128d6), LL(0x1b6c1bd87736c31b), LL(0xb5eeb5c15b7774b5), LL(0xaf86af112943beaf), LL(0x6ab56a77dfd41d6a), LL(0x505d50ba0da0ea50), LL(0x450945124c8a5745), LL(0xf3ebf3cb18fb38f3), LL(0x30c0309df060ad30), LL(0xef9bef2b74c3c4ef), LL(0x3ffc3fe5c37eda3f), LL(0x554955921caac755), LL(0xa2b2a2791059dba2), LL(0xea8fea0365c9e9ea), LL(0x6589650fecca6a65), LL(0xbad2bab9686903ba), LL(0x2fbc2f65935e4a2f), LL(0xc027c04ee79d8ec0), LL(0xde5fdebe81a160de), LL(0x1c701ce06c38fc1c), LL(0xfdd3fdbb2ee746fd), LL(0x4d294d52649a1f4d), LL(0x927292e4e0397692), LL(0x75c9758fbceafa75), LL(0x061806301e0c3606), LL(0x8a128a249809ae8a), LL(0xb2f2b2f940794bb2), LL(0xe6bfe66359d185e6), LL(0x0e380e70361c7e0e), LL(0x1f7c1ff8633ee71f), LL(0x62956237f7c45562), LL(0xd477d4eea3b53ad4), LL(0xa89aa829324d81a8), LL(0x966296c4f4315296), LL(0xf9c3f99b3aef62f9), LL(0xc533c566f697a3c5), LL(0x25942535b14a1025), LL(0x597959f220b2ab59), LL(0x842a8454ae15d084), LL(0x72d572b7a7e4c572), LL(0x39e439d5dd72ec39), LL(0x4c2d4c5a6198164c), LL(0x5e655eca3bbc945e), LL(0x78fd78e785f09f78), LL(0x38e038ddd870e538), LL(0x8c0a8c148605988c), LL(0xd163d1c6b2bf17d1), LL(0xa5aea5410b57e4a5), LL(0xe2afe2434dd9a1e2), LL(0x6199612ff8c24e61), LL(0xb3f6b3f1457b42b3), LL(0x21842115a5423421), LL(0x9c4a9c94d625089c), LL(0x1e781ef0663cee1e), LL(0x4311432252866143), LL(0xc73bc776fc93b1c7), LL(0xfcd7fcb32be54ffc), LL(0x0410042014082404), LL(0x515951b208a2e351), LL(0x995e99bcc72f2599), LL(0x6da96d4fc4da226d), LL(0x0d340d68391a650d), LL(0xfacffa8335e979fa), LL(0xdf5bdfb684a369df), LL(0x7ee57ed79bfca97e), LL(0x2490243db4481924), LL(0x3bec3bc5d776fe3b), LL(0xab96ab313d4b9aab), LL(0xce1fce3ed181f0ce), LL(0x1144118855229911), LL(0x8f068f0c8903838f), LL(0x4e254e4a6b9c044e), LL(0xb7e6b7d1517366b7), LL(0xeb8beb0b60cbe0eb), LL(0x3cf03cfdcc78c13c), LL(0x813e817cbf1ffd81), LL(0x946a94d4fe354094), LL(0xf7fbf7eb0cf31cf7), LL(0xb9deb9a1676f18b9), LL(0x134c13985f268b13), LL(0x2cb02c7d9c58512c), LL(0xd36bd3d6b8bb05d3), LL(0xe7bbe76b5cd38ce7), LL(0x6ea56e57cbdc396e), LL(0xc437c46ef395aac4), LL(0x030c03180f061b03), LL(0x5645568a13acdc56), LL(0x440d441a49885e44), LL(0x7fe17fdf9efea07f), LL(0xa99ea921374f88a9), LL(0x2aa82a4d8254672a), LL(0xbbd6bbb16d6b0abb), LL(0xc123c146e29f87c1), LL(0x535153a202a6f153), LL(0xdc57dcae8ba572dc), LL(0x0b2c0b582716530b), LL(0x9d4e9d9cd327019d), LL(0x6cad6c47c1d82b6c), LL(0x31c43195f562a431), LL(0x74cd7487b9e8f374), LL(0xf6fff6e309f115f6), LL(0x4605460a438c4c46), LL(0xac8aac092645a5ac), LL(0x891e893c970fb589), LL(0x145014a04428b414), LL(0xe1a3e15b42dfbae1), LL(0x165816b04e2ca616), LL(0x3ae83acdd274f73a), LL(0x69b9696fd0d20669), LL(0x092409482d124109), LL(0x70dd70a7ade0d770), LL(0xb6e2b6d954716fb6), LL(0xd067d0ceb7bd1ed0), LL(0xed93ed3b7ec7d6ed), LL(0xcc17cc2edb85e2cc), LL(0x4215422a57846842), LL(0x985a98b4c22d2c98), LL(0xa4aaa4490e55eda4), LL(0x28a0285d88507528), LL(0x5c6d5cda31b8865c), LL(0xf8c7f8933fed6bf8), LL(0x86228644a411c286), }; static const u64 rc[WHIRLPOOL_R + 1] = { LL(0x0000000000000000), LL(0x1823c6e887b8014f), LL(0x36a6d2f5796f9152), LL(0x60bc9b8ea30c7b35), LL(0x1de0d7c22e4bfe57), LL(0x157737e59ff04ada), LL(0x58c9290ab1a06b85), LL(0xbd5d10f4cb3e0567), LL(0xe427418ba77d95d8), LL(0xfbee7c66dd17479e), LL(0xca2dbf07ad5a8333), }; static void processBuffer(struct NESSIEstruct * const structpointer) { int i, r; u64 K[8]; u64 block[8]; u64 state[8]; u64 L[8]; u8 *buffer = structpointer->buffer; for (i = 0; i < 8; i++, buffer += 8) { block[i] = (((u64)buffer[0] ) << 56) ^ (((u64)buffer[1] & 0xffL) << 48) ^ (((u64)buffer[2] & 0xffL) << 40) ^ (((u64)buffer[3] & 0xffL) << 32) ^ (((u64)buffer[4] & 0xffL) << 24) ^ (((u64)buffer[5] & 0xffL) << 16) ^ (((u64)buffer[6] & 0xffL) << 8) ^ (((u64)buffer[7] & 0xffL) ); } state[0] = block[0] ^ (K[0] = structpointer->hash[0]); state[1] = block[1] ^ (K[1] = structpointer->hash[1]); state[2] = block[2] ^ (K[2] = structpointer->hash[2]); state[3] = block[3] ^ (K[3] = structpointer->hash[3]); state[4] = block[4] ^ (K[4] = structpointer->hash[4]); state[5] = block[5] ^ (K[5] = structpointer->hash[5]); state[6] = block[6] ^ (K[6] = structpointer->hash[6]); state[7] = block[7] ^ (K[7] = structpointer->hash[7]); for (r = 1; r <= WHIRLPOOL_R; r++) { L[0] = C0[(int)(K[0] >> 56) ] ^ C1[(int)(K[7] >> 48) & 0xff] ^ C2[(int)(K[6] >> 40) & 0xff] ^ C3[(int)(K[5] >> 32) & 0xff] ^ C4[(int)(K[4] >> 24) & 0xff] ^ C5[(int)(K[3] >> 16) & 0xff] ^ C6[(int)(K[2] >> 8) & 0xff] ^ C7[(int)(K[1] ) & 0xff] ^ rc[r]; L[1] = C0[(int)(K[1] >> 56) ] ^ C1[(int)(K[0] >> 48) & 0xff] ^ C2[(int)(K[7] >> 40) & 0xff] ^ C3[(int)(K[6] >> 32) & 0xff] ^ C4[(int)(K[5] >> 24) & 0xff] ^ C5[(int)(K[4] >> 16) & 0xff] ^ C6[(int)(K[3] >> 8) & 0xff] ^ C7[(int)(K[2] ) & 0xff]; L[2] = C0[(int)(K[2] >> 56) ] ^ C1[(int)(K[1] >> 48) & 0xff] ^ C2[(int)(K[0] >> 40) & 0xff] ^ C3[(int)(K[7] >> 32) & 0xff] ^ C4[(int)(K[6] >> 24) & 0xff] ^ C5[(int)(K[5] >> 16) & 0xff] ^ C6[(int)(K[4] >> 8) & 0xff] ^ C7[(int)(K[3] ) & 0xff]; L[3] = C0[(int)(K[3] >> 56) ] ^ C1[(int)(K[2] >> 48) & 0xff] ^ C2[(int)(K[1] >> 40) & 0xff] ^ C3[(int)(K[0] >> 32) & 0xff] ^ C4[(int)(K[7] >> 24) & 0xff] ^ C5[(int)(K[6] >> 16) & 0xff] ^ C6[(int)(K[5] >> 8) & 0xff] ^ C7[(int)(K[4] ) & 0xff]; L[4] = C0[(int)(K[4] >> 56) ] ^ C1[(int)(K[3] >> 48) & 0xff] ^ C2[(int)(K[2] >> 40) & 0xff] ^ C3[(int)(K[1] >> 32) & 0xff] ^ C4[(int)(K[0] >> 24) & 0xff] ^ C5[(int)(K[7] >> 16) & 0xff] ^ C6[(int)(K[6] >> 8) & 0xff] ^ C7[(int)(K[5] ) & 0xff]; L[5] = C0[(int)(K[5] >> 56) ] ^ C1[(int)(K[4] >> 48) & 0xff] ^ C2[(int)(K[3] >> 40) & 0xff] ^ C3[(int)(K[2] >> 32) & 0xff] ^ C4[(int)(K[1] >> 24) & 0xff] ^ C5[(int)(K[0] >> 16) & 0xff] ^ C6[(int)(K[7] >> 8) & 0xff] ^ C7[(int)(K[6] ) & 0xff]; L[6] = C0[(int)(K[6] >> 56) ] ^ C1[(int)(K[5] >> 48) & 0xff] ^ C2[(int)(K[4] >> 40) & 0xff] ^ C3[(int)(K[3] >> 32) & 0xff] ^ C4[(int)(K[2] >> 24) & 0xff] ^ C5[(int)(K[1] >> 16) & 0xff] ^ C6[(int)(K[0] >> 8) & 0xff] ^ C7[(int)(K[7] ) & 0xff]; L[7] = C0[(int)(K[7] >> 56) ] ^ C1[(int)(K[6] >> 48) & 0xff] ^ C2[(int)(K[5] >> 40) & 0xff] ^ C3[(int)(K[4] >> 32) & 0xff] ^ C4[(int)(K[3] >> 24) & 0xff] ^ C5[(int)(K[2] >> 16) & 0xff] ^ C6[(int)(K[1] >> 8) & 0xff] ^ C7[(int)(K[0] ) & 0xff]; K[0] = L[0]; K[1] = L[1]; K[2] = L[2]; K[3] = L[3]; K[4] = L[4]; K[5] = L[5]; K[6] = L[6]; K[7] = L[7]; L[0] = C0[(int)(state[0] >> 56) ] ^ C1[(int)(state[7] >> 48) & 0xff] ^ C2[(int)(state[6] >> 40) & 0xff] ^ C3[(int)(state[5] >> 32) & 0xff] ^ C4[(int)(state[4] >> 24) & 0xff] ^ C5[(int)(state[3] >> 16) & 0xff] ^ C6[(int)(state[2] >> 8) & 0xff] ^ C7[(int)(state[1] ) & 0xff] ^ K[0]; L[1] = C0[(int)(state[1] >> 56) ] ^ C1[(int)(state[0] >> 48) & 0xff] ^ C2[(int)(state[7] >> 40) & 0xff] ^ C3[(int)(state[6] >> 32) & 0xff] ^ C4[(int)(state[5] >> 24) & 0xff] ^ C5[(int)(state[4] >> 16) & 0xff] ^ C6[(int)(state[3] >> 8) & 0xff] ^ C7[(int)(state[2] ) & 0xff] ^ K[1]; L[2] = C0[(int)(state[2] >> 56) ] ^ C1[(int)(state[1] >> 48) & 0xff] ^ C2[(int)(state[0] >> 40) & 0xff] ^ C3[(int)(state[7] >> 32) & 0xff] ^ C4[(int)(state[6] >> 24) & 0xff] ^ C5[(int)(state[5] >> 16) & 0xff] ^ C6[(int)(state[4] >> 8) & 0xff] ^ C7[(int)(state[3] ) & 0xff] ^ K[2]; L[3] = C0[(int)(state[3] >> 56) ] ^ C1[(int)(state[2] >> 48) & 0xff] ^ C2[(int)(state[1] >> 40) & 0xff] ^ C3[(int)(state[0] >> 32) & 0xff] ^ C4[(int)(state[7] >> 24) & 0xff] ^ C5[(int)(state[6] >> 16) & 0xff] ^ C6[(int)(state[5] >> 8) & 0xff] ^ C7[(int)(state[4] ) & 0xff] ^ K[3]; L[4] = C0[(int)(state[4] >> 56) ] ^ C1[(int)(state[3] >> 48) & 0xff] ^ C2[(int)(state[2] >> 40) & 0xff] ^ C3[(int)(state[1] >> 32) & 0xff] ^ C4[(int)(state[0] >> 24) & 0xff] ^ C5[(int)(state[7] >> 16) & 0xff] ^ C6[(int)(state[6] >> 8) & 0xff] ^ C7[(int)(state[5] ) & 0xff] ^ K[4]; L[5] = C0[(int)(state[5] >> 56) ] ^ C1[(int)(state[4] >> 48) & 0xff] ^ C2[(int)(state[3] >> 40) & 0xff] ^ C3[(int)(state[2] >> 32) & 0xff] ^ C4[(int)(state[1] >> 24) & 0xff] ^ C5[(int)(state[0] >> 16) & 0xff] ^ C6[(int)(state[7] >> 8) & 0xff] ^ C7[(int)(state[6] ) & 0xff] ^ K[5]; L[6] = C0[(int)(state[6] >> 56) ] ^ C1[(int)(state[5] >> 48) & 0xff] ^ C2[(int)(state[4] >> 40) & 0xff] ^ C3[(int)(state[3] >> 32) & 0xff] ^ C4[(int)(state[2] >> 24) & 0xff] ^ C5[(int)(state[1] >> 16) & 0xff] ^ C6[(int)(state[0] >> 8) & 0xff] ^ C7[(int)(state[7] ) & 0xff] ^ K[6]; L[7] = C0[(int)(state[7] >> 56) ] ^ C1[(int)(state[6] >> 48) & 0xff] ^ C2[(int)(state[5] >> 40) & 0xff] ^ C3[(int)(state[4] >> 32) & 0xff] ^ C4[(int)(state[3] >> 24) & 0xff] ^ C5[(int)(state[2] >> 16) & 0xff] ^ C6[(int)(state[1] >> 8) & 0xff] ^ C7[(int)(state[0] ) & 0xff] ^ K[7]; state[0] = L[0]; state[1] = L[1]; state[2] = L[2]; state[3] = L[3]; state[4] = L[4]; state[5] = L[5]; state[6] = L[6]; state[7] = L[7]; } structpointer->hash[0] ^= state[0] ^ block[0]; structpointer->hash[1] ^= state[1] ^ block[1]; structpointer->hash[2] ^= state[2] ^ block[2]; structpointer->hash[3] ^= state[3] ^ block[3]; structpointer->hash[4] ^= state[4] ^ block[4]; structpointer->hash[5] ^= state[5] ^ block[5]; structpointer->hash[6] ^= state[6] ^ block[6]; structpointer->hash[7] ^= state[7] ^ block[7]; } void NESSIEinit(struct NESSIEstruct * const structpointer) { int i; memset(structpointer->bitLength, 0, 32); structpointer->bufferBits = structpointer->bufferPos = 0; structpointer->buffer[0] = 0; for (i = 0; i < 8; i++) { structpointer->hash[i] = 0L; } } void NESSIEadd(const unsigned char * const source, unsigned long sourceBits, struct NESSIEstruct * const structpointer) { int sourcePos = 0; int sourceGap = (8 - ((int)sourceBits & 7)) & 7; int bufferRem = structpointer->bufferBits & 7; int i; u32 b, carry; u8 *buffer = structpointer->buffer; u8 *bitLength = structpointer->bitLength; int bufferBits = structpointer->bufferBits; int bufferPos = structpointer->bufferPos; u64 value = sourceBits; for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != LL(0)); i--) { carry += bitLength[i] + ((u32)value & 0xff); bitLength[i] = (u8)carry; carry >>= 8; value >>= 8; } while (sourceBits > 8) { b = ((source[sourcePos] << sourceGap) & 0xff) | ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap)); buffer[bufferPos++] |= (u8)(b >> bufferRem); bufferBits += 8 - bufferRem; if (bufferBits == DIGESTBITS) { processBuffer(structpointer); bufferBits = bufferPos = 0; } buffer[bufferPos] = b << (8 - bufferRem); bufferBits += bufferRem; sourceBits -= 8; sourcePos++; } if (sourceBits > 0) { b = (source[sourcePos] << sourceGap) & 0xff; buffer[bufferPos] |= b >> bufferRem; } else { b = 0; } if (bufferRem + sourceBits < 8) { bufferBits += sourceBits; } else { bufferPos++; bufferBits += 8 - bufferRem; sourceBits -= 8 - bufferRem; if (bufferBits == DIGESTBITS) { processBuffer(structpointer); bufferBits = bufferPos = 0; } buffer[bufferPos] = b << (8 - bufferRem); bufferBits += (int)sourceBits; } structpointer->bufferBits = bufferBits; structpointer->bufferPos = bufferPos; } void NESSIEadd64(const unsigned char * const source, uint64_t sourceBits, struct NESSIEstruct * const structpointer) { int sourcePos = 0; int sourceGap = (8 - ((int)sourceBits & 7)) & 7; int bufferRem = structpointer->bufferBits & 7; int i; u32 b, carry; u8 *buffer = structpointer->buffer; u8 *bitLength = structpointer->bitLength; int bufferBits = structpointer->bufferBits; int bufferPos = structpointer->bufferPos; u64 value = sourceBits; for (i = 31, carry = 0; i >= 0 && (carry != 0 || value != LL(0)); i--) { carry += bitLength[i] + ((u32)value & 0xff); bitLength[i] = (u8)carry; carry >>= 8; value >>= 8; } while (sourceBits > 8) { b = ((source[sourcePos] << sourceGap) & 0xff) | ((source[sourcePos + 1] & 0xff) >> (8 - sourceGap)); buffer[bufferPos++] |= (u8)(b >> bufferRem); bufferBits += 8 - bufferRem; if (bufferBits == DIGESTBITS) { processBuffer(structpointer); bufferBits = bufferPos = 0; } buffer[bufferPos] = b << (8 - bufferRem); bufferBits += bufferRem; sourceBits -= 8; sourcePos++; } if (sourceBits > 0) { b = (source[sourcePos] << sourceGap) & 0xff; buffer[bufferPos] |= b >> bufferRem; } else { b = 0; } if (bufferRem + sourceBits < 8) { bufferBits += sourceBits; } else { bufferPos++; bufferBits += 8 - bufferRem; sourceBits -= 8 - bufferRem; if (bufferBits == DIGESTBITS) { processBuffer(structpointer); bufferBits = bufferPos = 0; } buffer[bufferPos] = b << (8 - bufferRem); bufferBits += (int)sourceBits; } structpointer->bufferBits = bufferBits; structpointer->bufferPos = bufferPos; } void NESSIEfinalize(struct NESSIEstruct * const structpointer, unsigned char * const result) { int i; u8 *buffer = structpointer->buffer; const u8 *bitLength = structpointer->bitLength; int bufferBits = structpointer->bufferBits; int bufferPos = structpointer->bufferPos; u8 *digest = result; buffer[bufferPos] |= 0x80U >> (bufferBits & 7); bufferPos++; if (bufferPos > WBLOCKBYTES - LENGTHBYTES) { if (bufferPos < WBLOCKBYTES) { memset(&buffer[bufferPos], 0, WBLOCKBYTES - bufferPos); } processBuffer(structpointer); bufferPos = 0; } if (bufferPos < WBLOCKBYTES - LENGTHBYTES) { memset(&buffer[bufferPos], 0, (WBLOCKBYTES - LENGTHBYTES) - bufferPos); } bufferPos = WBLOCKBYTES - LENGTHBYTES; memcpy(&buffer[WBLOCKBYTES - LENGTHBYTES], bitLength, LENGTHBYTES); processBuffer(structpointer); for (i = 0; i < DIGESTBYTES/8; i++) { digest[0] = (u8)(structpointer->hash[i] >> 56); digest[1] = (u8)(structpointer->hash[i] >> 48); digest[2] = (u8)(structpointer->hash[i] >> 40); digest[3] = (u8)(structpointer->hash[i] >> 32); digest[4] = (u8)(structpointer->hash[i] >> 24); digest[5] = (u8)(structpointer->hash[i] >> 16); digest[6] = (u8)(structpointer->hash[i] >> 8); digest[7] = (u8)(structpointer->hash[i] ); digest += 8; } structpointer->bufferBits = bufferBits; structpointer->bufferPos = bufferPos; } /// LICENSE_END.16 /// LICENSE_START.13 // This is free and unencumbered software released into the public domain under The Unlicense (http://unlicense.org/) // main repo: https://github.com/wangyi-fudan/wyhash // author: 王一 Wang Yi // contributors: Reini Urban, Dietrich Epp, Joshua Haberman, Tommy Ettinger, Daniel Lemire, Otmar Ertl, cocowalla, leo-yuriev, Diego Barrios Romero, paulie-g, dumblob, Yann Collet, ivte-ms, hyb, James Z.M. Gao, easyaspi314 (Devin), TheOneric /* quick example: string s="fjsakfdsjkf"; uint64_t hash=wyhash(s.c_str(), s.size(), 0, _wyp); A bit reworked */ //likely and unlikely macros #if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) #define _likely_(x) __builtin_expect(x,1) #define _unlikely_(x) __builtin_expect(x,0) #else #define _likely_(x) (x) #define _unlikely_(x) (x) #endif // corresponds to #if (#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)) //128bit multiply function ///static inline uint64_t _wyrot(uint64_t x) { return (x>>32)|(x<<32); } static inline void _wymum(uint64_t *A, uint64_t *B){ #if defined(__SIZEOF_INT128__) __uint128_t r=*A; r*=*B; *A=(uint64_t)r; *B=(uint64_t)(r>>64); #elif defined(_MSC_VER) && defined(_M_X64) *A=_umul128(*A,*B,B); #else uint64_t ha=*A>>32, hb=*B>>32, la=(uint32_t)*A, lb=(uint32_t)*B, hi, lo; uint64_t rh=ha*hb, rm0=ha*lb, rm1=hb*la, rl=la*lb, t=rl+(rm0<<32), c=t>32)+(rm1>>32)+c; *A=lo; *B=hi; #endif // corresponds to #if (#if defined(__SIZEOF_INT128__)) } //multiply and xor mix function, aka MUM static inline uint64_t _wymix(uint64_t A, uint64_t B){ _wymum(&A,&B); return A^B; } //endian macros #ifdef BIG #define WYHASH_LITTLE_ENDIAN 0 #else #define WYHASH_LITTLE_ENDIAN 1 #endif // corresponds to #ifdef (#ifdef BIG) //read functions #if (WYHASH_LITTLE_ENDIAN) static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return v;} static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return v;} #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); #ifdef ANCIENT return (v >> 56) | ((v >> 40) & 0x000000000000FF00ULL) | ((v >> 24) & 0x0000000000FF0000ULL) | ((v >> 8) & 0x00000000FF000000ULL) | ((v << 8) & 0x000000FF00000000ULL) | ((v << 24) & 0x0000FF0000000000ULL) | ((v << 40) & 0x00FF000000000000ULL) | (v << 56); #else return __builtin_bswap64(v); #endif // corresponds to #ifdef (#ifdef ANCIENT) } static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); #ifdef ANCIENT return (v >> 24) | ((v >> 8) & 0x0000FF00) | ((v << 8) & 0x00FF0000) | (v << 24); #else return __builtin_bswap32(v); #endif // corresponds to #ifdef (#ifdef ANCIENT) } #elif defined(_MSC_VER) static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return _byteswap_uint64(v);} static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return _byteswap_ulong(v);} #else static inline uint64_t _wyr8(const uint8_t *p) { uint64_t v; memcpy(&v, p, 8); return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); } static inline uint64_t _wyr4(const uint8_t *p) { uint32_t v; memcpy(&v, p, 4); return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); } #endif // corresponds to #if (#if (WYHASH_LITTLE_ENDIAN)) static inline uint64_t _wyr3(const uint8_t *p, size_t k) { return (((uint64_t)p[0])<<16)|(((uint64_t)p[k>>1])<<8)|p[k-1];} //wyhash main function static inline uint64_t wyhash(const void *key, size_t len, uint64_t seed, const uint64_t *secret){ const uint8_t *p=(const uint8_t *)key; seed^=*secret; uint64_t a, b; if(_likely_(len<=16)){ if(_likely_(len>=4)){ a=(_wyr4(p)<<32)|_wyr4(p+((len>>3)<<2)); b=(_wyr4(p+len-4)<<32)|_wyr4(p+len-4-((len>>3)<<2)); } else if(_likely_(len>0)){ a=_wyr3(p,len); b=0;} else a=b=0; } else{ size_t i=len; if(_unlikely_(i>48)){ uint64_t see1=seed, see2=seed; do{ seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); see1=_wymix(_wyr8(p+16)^secret[2],_wyr8(p+24)^see1); see2=_wymix(_wyr8(p+32)^secret[3],_wyr8(p+40)^see2); p+=48; i-=48; }while(_likely_(i>48)); seed^=see1^see2; } while(_unlikely_(i>16)){ seed=_wymix(_wyr8(p)^secret[1],_wyr8(p+8)^seed); i-=16; p+=16; } a=_wyr8(p+i-16); b=_wyr8(p+i-8); } return _wymix(secret[1]^len,_wymix(a^secret[1],b^seed)); } //the default secret parameters ///static const uint64_t _wyp[4] = {0xa0761d6478bd642full, 0xe7037ed1a0b428dbull, 0x8ebc6af09c88c6e3ull, 0x589965cc75374cc3ull}; //The wyrand PRNG that pass BigCrush and PractRand static inline uint64_t wyrand(uint64_t *seed){ *seed+=0xa0761d6478bd642full; return _wymix(*seed,*seed^0xe7037ed1a0b428dbull);} //make your own secret static inline void make_secret(uint64_t seed, uint64_t *secret){ uint8_t c[] = {15, 23, 27, 29, 30, 39, 43, 45, 46, 51, 53, 54, 57, 58, 60, 71, 75, 77, 78, 83, 85, 86, 89, 90, 92, 99, 101, 102, 105, 106, 108, 113, 114, 116, 120, 135, 139, 141, 142, 147, 149, 150, 153, 154, 156, 163, 165, 166, 169, 170, 172, 177, 178, 180, 184, 195, 197, 198, 201, 202, 204, 209, 210, 212, 216, 225, 226, 228, 232, 240 }; for(size_t i=0;i<4;i++){ uint8_t ok; do{ ok=1; secret[i]=0; for(size_t j=0;j<64;j+=8) secret[i]|=((uint64_t)c[wyrand(&seed)%sizeof(c)])<> 1) & 0x5555555555555555; x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333); x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f; x = (x * 0x0101010101010101) >> 56; if(x!=32){ ok=0; break; } #endif // corresponds to #if (#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)) } }while(!ok); } } /// LICENSE_END.13 /// LICENSE_START.14 /// I made a bit of fix of this incredibly (perhaps even too) complex implementation /* * xxHash - Extremely Fast Hash algorithm * Header File * Copyright (C) 2012-2020 Yann Collet * * BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php) */ # define XXH_NAMESPACE XXH_INLINE_ # define XXH_IPREF(Id) XXH_INLINE_ ## Id # define XXH_OK XXH_IPREF(XXH_OK) # define XXH_ERROR XXH_IPREF(XXH_ERROR) # define XXH_errorcode XXH_IPREF(XXH_errorcode) # define XXH64_state_s XXH_IPREF(XXH64_state_s) # define XXH64_state_t XXH_IPREF(XXH64_state_t) # define XXH3_state_s XXH_IPREF(XXH3_state_s) # define XXH3_state_t XXH_IPREF(XXH3_state_t) # define XXH128_hash_t XXH_IPREF(XXH128_hash_t) /* **************************************************************** * Stable API *****************************************************************/ # define XXH_CAT(A,B) A##B # define XXH_NAME2(A,B) XXH_CAT(A,B) /* XXH64 */ # define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState) # define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset) # define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update) # define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest) /* XXH3_64bits */ /* */ # define XXH128 XXH_NAME2(XXH_NAMESPACE, XXH128) # define XXH3_128bits_withSecret XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_withSecret) # define XXH3_128bits_reset XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_reset) # define XXH3_128bits_update XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_update) # define XXH3_128bits_digest XXH_NAME2(XXH_NAMESPACE, XXH3_128bits_digest) /* **************************** * Definitions ******************************/ typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode; typedef uint32_t XXH32_hash_t; typedef uint64_t XXH64_hash_t; typedef uint8_t xxh_u8; typedef XXH32_hash_t xxh_u32; XXH64_hash_t XXH64 (const void* input, size_t length, XXH64_hash_t seed); /******* Streaming *******/ typedef struct XXH64_state_s XXH64_state_t; /* incomplete type */ XXH64_state_t* XXH64_createState(void); XXH_errorcode XXH64_reset (XXH64_state_t* statePtr, XXH64_hash_t seed); XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length); XXH64_hash_t XXH64_digest (const XXH64_state_t* statePtr); /******* Canonical representation *******/ #define XXH3_SECRET_SIZE_MIN 136 typedef struct XXH3_state_s XXH3_state_t; typedef struct { XXH64_hash_t low64; XXH64_hash_t high64; } XXH128_hash_t; XXH128_hash_t XXH3_128bits_withSecret(const void* data, size_t len, const void* secret, size_t secretSize); XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr); XXH_errorcode XXH3_128bits_update (XXH3_state_t* statePtr, const void* input, size_t length); XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* statePtr); struct XXH64_state_s { XXH64_hash_t total_len; XXH64_hash_t v1; XXH64_hash_t v2; XXH64_hash_t v3; XXH64_hash_t v4; XXH64_hash_t mem64[4]; XXH32_hash_t memsize; XXH32_hash_t reserved32; /* required for padding anyway */ XXH64_hash_t reserved64; /* never read nor write, might be removed in a future version */ }; /* typedef'd to XXH64_state_t */ #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11+ */ # include # define XXH_ALIGN(n) alignas(n) #elif defined(__GNUC__) # define XXH_ALIGN(n) __attribute__ ((aligned(n))) #elif defined(_MSC_VER) # define XXH_ALIGN(n) __declspec(align(n)) #else # define XXH_ALIGN(n) /* disabled */ #endif // corresponds to #if (#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) /* C11+ */) /* Old GCC versions only accept the attribute after the type in structures. */ #if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \ && defined(__GNUC__) # define XXH_ALIGN_MEMBER(align, type) type XXH_ALIGN(align) #else # define XXH_ALIGN_MEMBER(align, type) XXH_ALIGN(align) type #endif // corresponds to #if (#if !(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) /* C11+ */ \) #define XXH3_INTERNALBUFFER_SIZE 256 #define XXH3_SECRET_DEFAULT_SIZE 192 struct XXH3_state_s { XXH_ALIGN_MEMBER(64, XXH64_hash_t acc[8]); /* used to store a custom secret generated from a seed */ XXH_ALIGN_MEMBER(64, unsigned char customSecret[XXH3_SECRET_DEFAULT_SIZE]); XXH_ALIGN_MEMBER(64, unsigned char buffer[XXH3_INTERNALBUFFER_SIZE]); XXH32_hash_t bufferedSize; XXH32_hash_t reserved32; size_t nbStripesSoFar; XXH64_hash_t totalLen; size_t nbStripesPerBlock; size_t secretLimit; XXH64_hash_t seed; XXH64_hash_t reserved64; const unsigned char* extSecret; /* reference to external secret; * if == NULL, use .customSecret instead */ /* note: there may be some padding at the end due to alignment on 64 bytes */ }; /* typedef'd to XXH3_state_t */ #undef XXH_ALIGN_MEMBER /* When the XXH3_state_t structure is merely emplaced on stack, * it should be initialized with XXH3_INITSTATE() or a memset() * in case its first reset uses XXH3_NNbits_reset_withSeed(). * This init can be omitted if the first reset uses default or _withSecret mode. * This operation isn't necessary when the state is created with XXH3_createState(). * Note that this doesn't prepare the state for a streaming operation, * it's still necessary to use XXH3_NNbits_reset*() afterwards. */ #define XXH3_INITSTATE(XXH3_state_ptr) { (XXH3_state_ptr)->seed = 0; } /* simple short-cut to pre-selected XXH3_128bits variant */ XXH128_hash_t XXH128(const void* data, size_t len, XXH64_hash_t seed); # if !defined(__clang__) && defined(__GNUC__) && defined(__ARM_FEATURE_UNALIGNED) && defined(__ARM_ARCH) && (__ARM_ARCH == 6) # define XXH_FORCE_MEMORY_ACCESS 2 # elif !defined(__clang__) && ((defined(__INTEL_COMPILER) && !defined(_WIN32)) || \ (defined(__GNUC__) && (defined(__ARM_ARCH) && __ARM_ARCH >= 7))) # define XXH_FORCE_MEMORY_ACCESS 1 # endif #ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */ # define XXH_ACCEPT_NULL_INPUT_POINTER 0 #endif // corresponds to #ifndef (#ifndef XXH_ACCEPT_NULL_INPUT_POINTER /* can be defined externally */) #ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */ # if defined(__i386) || defined(__x86_64__) || defined(__aarch64__) \ || defined(_M_IX86) || defined(_M_X64) || defined(_M_ARM64) /* visual */ # define XXH_FORCE_ALIGN_CHECK 0 # else # define XXH_FORCE_ALIGN_CHECK 1 # endif #endif // corresponds to #ifndef (#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */) #ifndef XXH_NO_INLINE_HINTS # if defined(__OPTIMIZE_SIZE__) /* -Os, -Oz */ \ || defined(__NO_INLINE__) /* -O0, -fno-inline */ # define XXH_NO_INLINE_HINTS 1 # else # define XXH_NO_INLINE_HINTS 0 # endif #endif // corresponds to #ifndef (#ifndef XXH_NO_INLINE_HINTS) #ifndef XXH_REROLL # if defined(__OPTIMIZE_SIZE__) # define XXH_REROLL 1 # else # define XXH_REROLL 0 # endif #endif // corresponds to #ifndef (#ifndef XXH_REROLL) /* ************************************* * Includes & Memory related functions ***************************************/ /*! * Modify the local functions below should you wish to use * different memory routines for malloc() and free() */ static void* XXH_malloc(size_t s) { return franz_malloc(s);} /*! and for memcpy() */ static void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); } /* ************************************* * Compiler Specific Options ***************************************/ #ifdef _MSC_VER /* Visual Studio warning fix */ # pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ #endif // corresponds to #ifdef (#ifdef _MSC_VER /* Visual Studio warning fix */) #if XXH_NO_INLINE_HINTS /* disable inlining hints */ # if defined(__GNUC__) # define XXH_FORCE_INLINE static __attribute__((unused)) # else # define XXH_FORCE_INLINE static # endif # define XXH_NO_INLINE static /* enable inlining hints */ #elif defined(_MSC_VER) /* Visual Studio */ # define XXH_FORCE_INLINE static __forceinline # define XXH_NO_INLINE static __declspec(noinline) #elif defined(__GNUC__) # define XXH_FORCE_INLINE static __inline__ __attribute__((always_inline, unused)) # define XXH_NO_INLINE static __attribute__((noinline)) #elif defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) /* C99 */ # define XXH_FORCE_INLINE static inline # define XXH_NO_INLINE static #else # define XXH_FORCE_INLINE static # define XXH_NO_INLINE static #endif // corresponds to #if (#if XXH_NO_INLINE_HINTS /* disable inlining hints */) #ifndef XXH_DEBUGLEVEL # ifdef DEBUGLEVEL /* backwards compat */ # define XXH_DEBUGLEVEL DEBUGLEVEL # else # define XXH_DEBUGLEVEL 0 # endif #endif // corresponds to #ifndef (#ifndef XXH_DEBUGLEVEL) #if (XXH_DEBUGLEVEL>=1) # include /* note: can still be disabled with NDEBUG */ # define XXH_ASSERT(c) assert(c) #else # define XXH_ASSERT(c) ((void)0) #endif // corresponds to #if (#if (XXH_DEBUGLEVEL>=1)) /* note: use after variable declarations */ #define XXH_STATIC_ASSERT(c) do { enum { XXH_sa = 1/(int)(!!(c)) }; } while (0) /* ************************************* * Basic Types ***************************************/ /* *** Memory access *** */ /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE32 and XXH_readBE32. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* * Force direct memory access. Only works on CPU which support unaligned memory * access in hardware. */ static xxh_u32 XXH_read32(const void* memPtr) { return *(const xxh_u32*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __pack instructions are safer but compiler specific, hence potentially * problematic for some compilers. * * Currently only defined for GCC and ICC. */ static xxh_u32 XXH_read32(const void* ptr) { typedef union { xxh_u32 u32; } __attribute__((packed)) xxh_unalign; return ((const xxh_unalign*)ptr)->u32; } #else /* * Portable and safe solution. Generally efficient. * see: https://stackoverflow.com/a/32095106/646947 */ static xxh_u32 XXH_read32(const void* memPtr) { xxh_u32 val; memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ // corresponds to #if (#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))) /* *** Endianess *** */ typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess; #ifdef BIG # define XXH_CPU_LITTLE_ENDIAN 0 #else # define XXH_CPU_LITTLE_ENDIAN 1 #endif // corresponds to #ifdef (#ifdef BIG) /* **************************************** * Compiler-specific Functions and Macros ******************************************/ #define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) #ifdef __has_builtin # define XXH_HAS_BUILTIN(x) __has_builtin(x) #else # define XXH_HAS_BUILTIN(x) 0 #endif // corresponds to #ifdef (#ifdef __has_builtin) #if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \ && XXH_HAS_BUILTIN(__builtin_rotateleft64) # define XXH_rotl32 __builtin_rotateleft32 # define XXH_rotl64 __builtin_rotateleft64 /* Note: although _rotl exists for minGW (GCC under windows), performance seems poor */ #elif defined(_MSC_VER) # define XXH_rotl32(x,r) _rotl(x,r) # define XXH_rotl64(x,r) _rotl64(x,r) #else # define XXH_rotl32(x,r) (((x) << (r)) | ((x) >> (32 - (r)))) # define XXH_rotl64(x,r) (((x) << (r)) | ((x) >> (64 - (r)))) #endif // corresponds to #if (#if !defined(NO_CLANG_BUILTIN) && XXH_HAS_BUILTIN(__builtin_rotateleft32) \) #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap32 _byteswap_ulong #elif XXH_GCC_VERSION >= 403 # define XXH_swap32 __builtin_bswap32 #else static xxh_u32 XXH_swap32 (xxh_u32 x) { return ((x << 24) & 0xff000000 ) | ((x << 8) & 0x00ff0000 ) | ((x >> 8) & 0x0000ff00 ) | ((x >> 24) & 0x000000ff ); } #endif // corresponds to #if (#if defined(_MSC_VER) /* Visual Studio */) /* *************************** * Memory reads *****************************/ typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment; /* * XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. * * This is ideal for older compilers which don't inline memcpy. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u32)bytePtr[1] << 8) | ((xxh_u32)bytePtr[2] << 16) | ((xxh_u32)bytePtr[3] << 24); } #else XXH_FORCE_INLINE xxh_u32 XXH_readLE32(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr)); } #endif // corresponds to #if (#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))) XXH_FORCE_INLINE xxh_u32 XXH_readLE32_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) { return XXH_readLE32(ptr); } else { return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u32*)ptr : XXH_swap32(*(const xxh_u32*)ptr); } } /* ************************************* * Misc ***************************************/ /* ******************************************************************* * 32-bit hash functions *********************************************************************/ static const xxh_u32 XXH_PRIME32_1 = 0x9E3779B1U; /* 0b10011110001101110111100110110001 */ static const xxh_u32 XXH_PRIME32_2 = 0x85EBCA77U; /* 0b10000101111010111100101001110111 */ static const xxh_u32 XXH_PRIME32_3 = 0xC2B2AE3DU; /* 0b11000010101100101010111000111101 */ #define XXH_get32bits(p) XXH_readLE32_align(p, align) # undef XXH_PROCESS1 # undef XXH_PROCESS4 /* ******************************************************************* * 64-bit hash functions *********************************************************************/ /******* Memory access *******/ typedef XXH64_hash_t xxh_u64; #ifndef XXH_REROLL_XXH64 # if (defined(__ILP32__) || defined(_ILP32)) /* ILP32 is often defined on 32-bit GCC family */ \ || !(defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64) /* x86-64 */ \ || defined(_M_ARM64) || defined(__aarch64__) || defined(__arm64__) /* aarch64 */ \ || defined(__PPC64__) || defined(__PPC64LE__) || defined(__ppc64__) || defined(__powerpc64__) /* ppc64 */ \ || defined(__mips64__) || defined(__mips64)) /* mips64 */ \ || (!defined(SIZE_MAX) || SIZE_MAX < ULLONG_MAX) /* check limits */ # define XXH_REROLL_XXH64 1 # else # define XXH_REROLL_XXH64 0 # endif #endif /* !defined(XXH_REROLL_XXH64) */ // corresponds to #ifndef (#ifndef XXH_REROLL_XXH64) #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) /* * Manual byteshift. Best for old compilers which don't inline memcpy. * We actually directly use XXH_readLE64 and XXH_readBE64. */ #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2)) /* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */ static xxh_u64 XXH_read64(const void* memPtr) { return *(const xxh_u64*) memPtr; } #elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1)) /* * __pack instructions are safer, but compiler specific, hence potentially * problematic for some compilers. * * Currently only defined for GCC and ICC. */ static xxh_u64 XXH_read64(const void* ptr) { typedef union { xxh_u32 u32; xxh_u64 u64; } __attribute__((packed)) xxh_unalign64; return ((const xxh_unalign64*)ptr)->u64; } #else /* * Portable and safe solution. Generally efficient. * see: https://stackoverflow.com/a/32095106/646947 */ static xxh_u64 XXH_read64(const void* memPtr) { xxh_u64 val; memcpy(&val, memPtr, sizeof(val)); return val; } #endif /* XXH_FORCE_DIRECT_MEMORY_ACCESS */ // corresponds to #if (#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))) #if defined(_MSC_VER) /* Visual Studio */ # define XXH_swap64 _byteswap_uint64 #elif XXH_GCC_VERSION >= 403 # define XXH_swap64 __builtin_bswap64 #else static xxh_u64 XXH_swap64 (xxh_u64 x) { return ((x << 56) & 0xff00000000000000ULL) | ((x << 40) & 0x00ff000000000000ULL) | ((x << 24) & 0x0000ff0000000000ULL) | ((x << 8) & 0x000000ff00000000ULL) | ((x >> 8) & 0x00000000ff000000ULL) | ((x >> 24) & 0x0000000000ff0000ULL) | ((x >> 40) & 0x000000000000ff00ULL) | ((x >> 56) & 0x00000000000000ffULL); } #endif // corresponds to #if (#if defined(_MSC_VER) /* Visual Studio */) /* XXH_FORCE_MEMORY_ACCESS==3 is an endian-independent byteshift load. */ #if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3)) XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* memPtr) { const xxh_u8* bytePtr = (const xxh_u8 *)memPtr; return bytePtr[0] | ((xxh_u64)bytePtr[1] << 8) | ((xxh_u64)bytePtr[2] << 16) | ((xxh_u64)bytePtr[3] << 24) | ((xxh_u64)bytePtr[4] << 32) | ((xxh_u64)bytePtr[5] << 40) | ((xxh_u64)bytePtr[6] << 48) | ((xxh_u64)bytePtr[7] << 56); } #else XXH_FORCE_INLINE xxh_u64 XXH_readLE64(const void* ptr) { return XXH_CPU_LITTLE_ENDIAN ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr)); } #endif // corresponds to #if (#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==3))) XXH_FORCE_INLINE xxh_u64 XXH_readLE64_align(const void* ptr, XXH_alignment align) { if (align==XXH_unaligned) return XXH_readLE64(ptr); else return XXH_CPU_LITTLE_ENDIAN ? *(const xxh_u64*)ptr : XXH_swap64(*(const xxh_u64*)ptr); } /******* xxh64 *******/ static const xxh_u64 XXH_PRIME64_1 = 0x9E3779B185EBCA87ULL; /* 0b1001111000110111011110011011000110000101111010111100101010000111 */ static const xxh_u64 XXH_PRIME64_2 = 0xC2B2AE3D27D4EB4FULL; /* 0b1100001010110010101011100011110100100111110101001110101101001111 */ static const xxh_u64 XXH_PRIME64_3 = 0x165667B19E3779F9ULL; /* 0b0001011001010110011001111011000110011110001101110111100111111001 */ static const xxh_u64 XXH_PRIME64_4 = 0x85EBCA77C2B2AE63ULL; /* 0b1000010111101011110010100111011111000010101100101010111001100011 */ static const xxh_u64 XXH_PRIME64_5 = 0x27D4EB2F165667C5ULL; /* 0b0010011111010100111010110010111100010110010101100110011111000101 */ static xxh_u64 XXH64_round(xxh_u64 acc, xxh_u64 input) { acc += input * XXH_PRIME64_2; acc = XXH_rotl64(acc, 31); acc *= XXH_PRIME64_1; return acc; } static xxh_u64 XXH64_mergeRound(xxh_u64 acc, xxh_u64 val) { val = XXH64_round(0, val); acc ^= val; acc = acc * XXH_PRIME64_1 + XXH_PRIME64_4; return acc; } static xxh_u64 XXH64_avalanche(xxh_u64 h64) { h64 ^= h64 >> 33; h64 *= XXH_PRIME64_2; h64 ^= h64 >> 29; h64 *= XXH_PRIME64_3; h64 ^= h64 >> 32; return h64; } #define XXH_get64bits(p) XXH_readLE64_align(p, align) static xxh_u64 XXH64_finalize(xxh_u64 h64, const xxh_u8* ptr, size_t len, XXH_alignment align) { #define XXH_PROCESS1_64 do { \ h64 ^= (*ptr++) * XXH_PRIME64_5; \ h64 = XXH_rotl64(h64, 11) * XXH_PRIME64_1; \ } while (0) #define XXH_PROCESS4_64 do { \ h64 ^= (xxh_u64)(XXH_get32bits(ptr)) * XXH_PRIME64_1; \ ptr += 4; \ h64 = XXH_rotl64(h64, 23) * XXH_PRIME64_2 + XXH_PRIME64_3; \ } while (0) #define XXH_PROCESS8_64 do { \ xxh_u64 const k1 = XXH64_round(0, XXH_get64bits(ptr)); \ ptr += 8; \ h64 ^= k1; \ h64 = XXH_rotl64(h64,27) * XXH_PRIME64_1 + XXH_PRIME64_4; \ } while (0) /* Rerolled version for 32-bit targets is faster and much smaller. */ if (XXH_REROLL || XXH_REROLL_XXH64) { len &= 31; while (len >= 8) { XXH_PROCESS8_64; len -= 8; } if (len >= 4) { XXH_PROCESS4_64; len -= 4; } while (len > 0) { XXH_PROCESS1_64; --len; } return XXH64_avalanche(h64); } else { switch(len & 31) { case 24: XXH_PROCESS8_64; /* fallthrough */ case 16: XXH_PROCESS8_64; /* fallthrough */ case 8: XXH_PROCESS8_64; return XXH64_avalanche(h64); case 28: XXH_PROCESS8_64; /* fallthrough */ case 20: XXH_PROCESS8_64; /* fallthrough */ case 12: XXH_PROCESS8_64; /* fallthrough */ case 4: XXH_PROCESS4_64; return XXH64_avalanche(h64); case 25: XXH_PROCESS8_64; /* fallthrough */ case 17: XXH_PROCESS8_64; /* fallthrough */ case 9: XXH_PROCESS8_64; XXH_PROCESS1_64; return XXH64_avalanche(h64); case 29: XXH_PROCESS8_64; /* fallthrough */ case 21: XXH_PROCESS8_64; /* fallthrough */ case 13: XXH_PROCESS8_64; /* fallthrough */ case 5: XXH_PROCESS4_64; XXH_PROCESS1_64; return XXH64_avalanche(h64); case 26: XXH_PROCESS8_64; /* fallthrough */ case 18: XXH_PROCESS8_64; /* fallthrough */ case 10: XXH_PROCESS8_64; XXH_PROCESS1_64; XXH_PROCESS1_64; return XXH64_avalanche(h64); case 30: XXH_PROCESS8_64; /* fallthrough */ case 22: XXH_PROCESS8_64; /* fallthrough */ case 14: XXH_PROCESS8_64; /* fallthrough */ case 6: XXH_PROCESS4_64; XXH_PROCESS1_64; XXH_PROCESS1_64; return XXH64_avalanche(h64); case 27: XXH_PROCESS8_64; /* fallthrough */ case 19: XXH_PROCESS8_64; /* fallthrough */ case 11: XXH_PROCESS8_64; XXH_PROCESS1_64; XXH_PROCESS1_64; XXH_PROCESS1_64; return XXH64_avalanche(h64); case 31: XXH_PROCESS8_64; /* fallthrough */ case 23: XXH_PROCESS8_64; /* fallthrough */ case 15: XXH_PROCESS8_64; /* fallthrough */ case 7: XXH_PROCESS4_64; /* fallthrough */ case 3: XXH_PROCESS1_64; /* fallthrough */ case 2: XXH_PROCESS1_64; /* fallthrough */ case 1: XXH_PROCESS1_64; /* fallthrough */ case 0: return XXH64_avalanche(h64); } } /* impossible to reach */ XXH_ASSERT(0); return 0; /* unreachable, but some compilers complain without it */ } # undef XXH_PROCESS1_64 # undef XXH_PROCESS4_64 # undef XXH_PROCESS8_64 /******* Hash Streaming *******/ XXH64_state_t* XXH64_createState(void) { g_allocatedram+=sizeof(XXH64_state_t); return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t)); } XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, XXH64_hash_t seed) { XXH64_state_t state; /* use a local state to memcpy() in order to avoid strict-aliasing warnings */ memset(&state, 0, sizeof(state)); state.v1 = seed + XXH_PRIME64_1 + XXH_PRIME64_2; state.v2 = seed + XXH_PRIME64_2; state.v3 = seed + 0; state.v4 = seed - XXH_PRIME64_1; /* do not write into reserved64, might be removed in a future version */ memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved64)); return XXH_OK; } XXH_errorcode XXH64_update (XXH64_state_t* state, const void* input, size_t len) { if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; #else return XXH_ERROR; #endif // corresponds to #if (#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)) { const xxh_u8* p = (const xxh_u8*)input; const xxh_u8* const bEnd = p + len; state->total_len += len; if (state->memsize + len < 32) { /* fill in tmp buffer */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, len); state->memsize += (xxh_u32)len; return XXH_OK; } if (state->memsize) { /* tmp buffer is full */ XXH_memcpy(((xxh_u8*)state->mem64) + state->memsize, input, 32-state->memsize); state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0)); state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1)); state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2)); state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3)); p += 32-state->memsize; state->memsize = 0; } if (p+32 <= bEnd) { const xxh_u8* const limit = bEnd - 32; xxh_u64 v1 = state->v1; xxh_u64 v2 = state->v2; xxh_u64 v3 = state->v3; xxh_u64 v4 = state->v4; do { v1 = XXH64_round(v1, XXH_readLE64(p)); p+=8; v2 = XXH64_round(v2, XXH_readLE64(p)); p+=8; v3 = XXH64_round(v3, XXH_readLE64(p)); p+=8; v4 = XXH64_round(v4, XXH_readLE64(p)); p+=8; } while (p<=limit); state->v1 = v1; state->v2 = v2; state->v3 = v3; state->v4 = v4; } if (p < bEnd) { XXH_memcpy(state->mem64, p, (size_t)(bEnd-p)); state->memsize = (unsigned)(bEnd-p); } } return XXH_OK; } XXH64_hash_t XXH64_digest (const XXH64_state_t* state) { xxh_u64 h64; if (state->total_len >= 32) { xxh_u64 const v1 = state->v1; xxh_u64 const v2 = state->v2; xxh_u64 const v3 = state->v3; xxh_u64 const v4 = state->v4; h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); h64 = XXH64_mergeRound(h64, v1); h64 = XXH64_mergeRound(h64, v2); h64 = XXH64_mergeRound(h64, v3); h64 = XXH64_mergeRound(h64, v4); } else { h64 = state->v3 /*seed*/ + XXH_PRIME64_5; } h64 += (xxh_u64) state->total_len; return XXH64_finalize(h64, (const xxh_u8*)state->mem64, (size_t)state->total_len, XXH_aligned); } /******* Canonical representation *******/ /* ********************************************************************* * XXH3 * New generation hash designed for speed on small keys and vectorization ************************************************************************ */ /* === Compiler specifics === */ #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && (!defined(SOLARIS)) /* franzfix >= C99 */ # define XXH_RESTRICT restrict #else /* Note: it might be useful to define __restrict or __restrict__ for some C++ compilers */ # define XXH_RESTRICT /* disable */ #endif // corresponds to #if (#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && (!defined(SOLARIS)) /* franzfix >= C99 */) #if (defined(__GNUC__) && (__GNUC__ >= 3)) \ || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) \ || defined(__clang__) # define XXH_likely(x) __builtin_expect(x, 1) ///# define XXH_unlikely(x) __builtin_expect(x, 0) #else # define XXH_likely(x) (x) ///# define XXH_unlikely(x) (x) #endif // corresponds to #if (#if (defined(__GNUC__) && (__GNUC__ >= 3)) \) #if defined(__GNUC__) # if defined(__AVX2__) # include # elif defined(__SSE2__) # include # elif defined(__ARM_NEON__) || defined(__ARM_NEON) # define inline __inline__ /* circumvent a clang bug */ # include # undef inline # endif #elif defined(_MSC_VER) # include #endif // corresponds to #if (#if defined(__GNUC__)) #if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM) # warning "XXH3 is highly inefficient without ARM or Thumb-2." #endif // corresponds to #if (#if defined(__thumb__) && !defined(__thumb2__) && defined(__ARM_ARCH_ISA_ARM)) /* ========================================== * Vectorization detection * ========================================== */ #define XXH_SCALAR 0 /* Portable scalar version */ #define XXH_SSE2 1 /* SSE2 for Pentium 4 and all x86_64 */ #define XXH_AVX2 2 /* AVX2 for Haswell and Bulldozer */ #define XXH_AVX512 3 /* AVX512 for Skylake and Icelake */ #define XXH_NEON 4 /* NEON for most ARMv7-A and all AArch64 */ #define XXH_VSX 5 /* VSX and ZVector for POWER8/z13 */ #ifndef XXH_VECTOR /* can be defined on command line */ # if defined(__AVX512F__) # define XXH_VECTOR XXH_AVX512 # elif defined(__AVX2__) # define XXH_VECTOR XXH_AVX2 # elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) || (defined(_M_IX86_FP) && (_M_IX86_FP == 2)) # define XXH_VECTOR XXH_SSE2 # elif defined(__GNUC__) /* msvc support maybe later */ \ && (defined(__ARM_NEON__) || defined(__ARM_NEON)) \ && (defined(__LITTLE_ENDIAN__) /* We only support little endian NEON */ \ || (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) # define XXH_VECTOR XXH_NEON # elif (defined(__PPC64__) && defined(__POWER8_VECTOR__)) \ || (defined(__s390x__) && defined(__VEC__)) \ && defined(__GNUC__) /* TODO: IBM XL */ # define XXH_VECTOR XXH_VSX # else # define XXH_VECTOR XXH_SCALAR # endif #endif // corresponds to #ifndef (#ifndef XXH_VECTOR /* can be defined on command line */) /* * Controls the alignment of the accumulator, * for compatibility with aligned vector loads, which are usually faster. */ #ifndef XXH_ACC_ALIGN # if defined(XXH_X86DISPATCH) # define XXH_ACC_ALIGN 64 /* for compatibility with avx512 */ # elif XXH_VECTOR == XXH_SCALAR /* scalar */ # define XXH_ACC_ALIGN 8 # elif XXH_VECTOR == XXH_SSE2 /* sse2 */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX2 /* avx2 */ # define XXH_ACC_ALIGN 32 # elif XXH_VECTOR == XXH_NEON /* neon */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_VSX /* vsx */ # define XXH_ACC_ALIGN 16 # elif XXH_VECTOR == XXH_AVX512 /* avx512 */ # define XXH_ACC_ALIGN 64 # endif #endif // corresponds to #ifndef (#ifndef XXH_ACC_ALIGN) #if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \ || XXH_VECTOR == XXH_AVX2 || XXH_VECTOR == XXH_AVX512 # define XXH_SEC_ALIGN XXH_ACC_ALIGN #else # define XXH_SEC_ALIGN 8 #endif // corresponds to #if (#if defined(XXH_X86DISPATCH) || XXH_VECTOR == XXH_SSE2 \) #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ # pragma GCC push_options # pragma GCC optimize("-O2") #endif // corresponds to #if (#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \) #if XXH_VECTOR == XXH_NEON # if !defined(XXH_NO_VZIP_HACK) /* define to disable */ \ && defined(__GNUC__) \ && !defined(__aarch64__) && !defined(__arm64__) # define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ do { \ /* Undocumented GCC/Clang operand modifier: %e0 = lower D half, %f0 = upper D half */ \ /* https://github.com/gcc-mirror/gcc/blob/38cf91e5/gcc/config/arm/arm.c#L22486 */ \ /* https://github.com/llvm-mirror/llvm/blob/2c4ca683/lib/Target/ARM/ARMAsmPrinter.cpp#L399 */ \ __asm__("vzip.32 %e0, %f0" : "+w" (in)); \ (outLo) = vget_low_u32 (vreinterpretq_u32_u64(in)); \ (outHi) = vget_high_u32(vreinterpretq_u32_u64(in)); \ } while (0) # else # define XXH_SPLIT_IN_PLACE(in, outLo, outHi) \ do { \ (outLo) = vmovn_u64 (in); \ (outHi) = vshrn_n_u64 ((in), 32); \ } while (0) # endif #endif /* XXH_VECTOR == XXH_NEON */ // corresponds to #if (#if XXH_VECTOR == XXH_NEON) /* * VSX and Z Vector helpers. * * This is very messy, and any pull requests to clean this up are welcome. * * There are a lot of problems with supporting VSX and s390x, due to * inconsistent intrinsics, spotty coverage, and multiple endiannesses. */ #if XXH_VECTOR == XXH_VSX # if defined(__s390x__) # include # else /* gcc's altivec.h can have the unwanted consequence to unconditionally * #define bool, vector, and pixel keywords, * with bad consequences for programs already using these keywords for other purposes. * The paragraph defining these macros is skipped when __APPLE_ALTIVEC__ is defined. * __APPLE_ALTIVEC__ is _generally_ defined automatically by the compiler, * but it seems that, in some cases, it isn't. * Force the build macro to be defined, so that keywords are not altered. */ # if defined(__GNUC__) && !defined(__APPLE_ALTIVEC__) # define __APPLE_ALTIVEC__ # endif # include # endif typedef __vector unsigned long long xxh_u64x2; typedef __vector unsigned char xxh_u8x16; typedef __vector unsigned xxh_u32x4; /* * Performs an unaligned load and byte swaps it on big endian. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_loadu(const void *ptr) { xxh_u64x2 ret; memcpy(&ret, ptr, sizeof(xxh_u64x2)); # if XXH_VSX_BE ret = XXH_vec_revb(ret); # endif return ret; } /* * vec_mulo and vec_mule are very problematic intrinsics on PowerPC * * These intrinsics weren't added until GCC 8, despite existing for a while, * and they are endian dependent. Also, their meaning swap depending on version. * */ # if defined(__s390x__) /* s390x is always big endian, no issue on this platform */ # define XXH_vec_mulo vec_mulo # define XXH_vec_mule vec_mule # elif defined(__clang__) && XXH_HAS_BUILTIN(__builtin_altivec_vmuleuw) /* Clang has a better way to control this, we can just use the builtin which doesn't swap. */ # define XXH_vec_mulo __builtin_altivec_vmulouw # define XXH_vec_mule __builtin_altivec_vmuleuw # else /* gcc needs inline assembly */ /* Adapted from https://github.com/google/highwayhash/blob/master/highwayhash/hh_vsx.h. */ XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mulo(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmulouw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } XXH_FORCE_INLINE xxh_u64x2 XXH_vec_mule(xxh_u32x4 a, xxh_u32x4 b) { xxh_u64x2 result; __asm__("vmuleuw %0, %1, %2" : "=v" (result) : "v" (a), "v" (b)); return result; } # endif /* XXH_vec_mulo, XXH_vec_mule */ #endif /* XXH_VECTOR == XXH_VSX */ // corresponds to #if (#if XXH_VECTOR == XXH_VSX) /* prefetch * can be disabled, by declaring XXH_NO_PREFETCH build macro */ #if defined(XXH_NO_PREFETCH) # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ #else # if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) /* _mm_prefetch() is not defined outside of x86/x64 */ # include /* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ # define XXH_PREFETCH(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) # elif defined(__GNUC__) && ( (__GNUC__ >= 4) || ( (__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) ) ) # define XXH_PREFETCH(ptr) __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) # else # define XXH_PREFETCH(ptr) (void)(ptr) /* disabled */ # endif #endif /* XXH_NO_PREFETCH */ // corresponds to #if (#if defined(XXH_NO_PREFETCH)) /* ========================================== * XXH3 default settings * ========================================== */ #define XXH_SECRET_DEFAULT_SIZE 192 /* minimum XXH3_SECRET_SIZE_MIN */ #if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN) # error "default keyset is not large enough" #endif // corresponds to #if (#if (XXH_SECRET_DEFAULT_SIZE < XXH3_SECRET_SIZE_MIN)) /* Pseudorandom secret taken directly from FARSH */ XXH_ALIGN(64) static const xxh_u8 XXH3_kSecret[XXH_SECRET_DEFAULT_SIZE] = { 0xb8, 0xfe, 0x6c, 0x39, 0x23, 0xa4, 0x4b, 0xbe, 0x7c, 0x01, 0x81, 0x2c, 0xf7, 0x21, 0xad, 0x1c, 0xde, 0xd4, 0x6d, 0xe9, 0x83, 0x90, 0x97, 0xdb, 0x72, 0x40, 0xa4, 0xa4, 0xb7, 0xb3, 0x67, 0x1f, 0xcb, 0x79, 0xe6, 0x4e, 0xcc, 0xc0, 0xe5, 0x78, 0x82, 0x5a, 0xd0, 0x7d, 0xcc, 0xff, 0x72, 0x21, 0xb8, 0x08, 0x46, 0x74, 0xf7, 0x43, 0x24, 0x8e, 0xe0, 0x35, 0x90, 0xe6, 0x81, 0x3a, 0x26, 0x4c, 0x3c, 0x28, 0x52, 0xbb, 0x91, 0xc3, 0x00, 0xcb, 0x88, 0xd0, 0x65, 0x8b, 0x1b, 0x53, 0x2e, 0xa3, 0x71, 0x64, 0x48, 0x97, 0xa2, 0x0d, 0xf9, 0x4e, 0x38, 0x19, 0xef, 0x46, 0xa9, 0xde, 0xac, 0xd8, 0xa8, 0xfa, 0x76, 0x3f, 0xe3, 0x9c, 0x34, 0x3f, 0xf9, 0xdc, 0xbb, 0xc7, 0xc7, 0x0b, 0x4f, 0x1d, 0x8a, 0x51, 0xe0, 0x4b, 0xcd, 0xb4, 0x59, 0x31, 0xc8, 0x9f, 0x7e, 0xc9, 0xd9, 0x78, 0x73, 0x64, 0xea, 0xc5, 0xac, 0x83, 0x34, 0xd3, 0xeb, 0xc3, 0xc5, 0x81, 0xa0, 0xff, 0xfa, 0x13, 0x63, 0xeb, 0x17, 0x0d, 0xdd, 0x51, 0xb7, 0xf0, 0xda, 0x49, 0xd3, 0x16, 0x55, 0x26, 0x29, 0xd4, 0x68, 0x9e, 0x2b, 0x16, 0xbe, 0x58, 0x7d, 0x47, 0xa1, 0xfc, 0x8f, 0xf8, 0xb8, 0xd1, 0x7a, 0xd0, 0x31, 0xce, 0x45, 0xcb, 0x3a, 0x8f, 0x95, 0x16, 0x04, 0x28, 0xaf, 0xd7, 0xfb, 0xca, 0xbb, 0x4b, 0x40, 0x7e, }; #if defined(_MSC_VER) && defined(_M_IX86) # include # define XXH_mult32to64(x, y) __emulu((unsigned)(x), (unsigned)(y)) #else /* * Downcast + upcast is usually better than masking on older compilers like * GCC 4.2 (especially 32-bit ones), all without affecting newer compilers. * * The other method, (x & 0xFFFFFFFF) * (y & 0xFFFFFFFF), will AND both operands * and perform a full 64x64 multiply -- entirely redundant on 32-bit. */ # define XXH_mult32to64(x, y) ((xxh_u64)(xxh_u32)(x) * (xxh_u64)(xxh_u32)(y)) #endif // corresponds to #if (#if defined(_MSC_VER) && defined(_M_IX86)) /* * Calculates a 64->128-bit long multiply. * * Uses __uint128_t and _umul128 if available, otherwise uses a scalar version. */ static XXH128_hash_t XXH_mult64to128(xxh_u64 lhs, xxh_u64 rhs) { #if defined(__GNUC__) && !defined(__wasm__) \ && defined(__SIZEOF_INT128__) \ || (defined(_INTEGRAL_MAX_BITS) && _INTEGRAL_MAX_BITS >= 128) __uint128_t const product = (__uint128_t)lhs * (__uint128_t)rhs; XXH128_hash_t r128; r128.low64 = (xxh_u64)(product); r128.high64 = (xxh_u64)(product >> 64); return r128; /* * MSVC for x64's _umul128 method. * * xxh_u64 _umul128(xxh_u64 Multiplier, xxh_u64 Multiplicand, xxh_u64 *HighProduct); * * This compiles to single operand MUL on x64. */ #elif defined(_M_X64) || defined(_M_IA64) #ifndef _MSC_VER # pragma intrinsic(_umul128) #endif // corresponds to #ifndef (#ifndef _MSC_VER) xxh_u64 product_high; xxh_u64 const product_low = _umul128(lhs, rhs, &product_high); XXH128_hash_t r128; r128.low64 = product_low; r128.high64 = product_high; return r128; #else /* First calculate all of the cross products. */ xxh_u64 const lo_lo = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs & 0xFFFFFFFF); xxh_u64 const hi_lo = XXH_mult32to64(lhs >> 32, rhs & 0xFFFFFFFF); xxh_u64 const lo_hi = XXH_mult32to64(lhs & 0xFFFFFFFF, rhs >> 32); xxh_u64 const hi_hi = XXH_mult32to64(lhs >> 32, rhs >> 32); /* Now add the products together. These will never overflow. */ xxh_u64 const cross = (lo_lo >> 32) + (hi_lo & 0xFFFFFFFF) + lo_hi; xxh_u64 const upper = (hi_lo >> 32) + (cross >> 32) + hi_hi; xxh_u64 const lower = (cross << 32) | (lo_lo & 0xFFFFFFFF); XXH128_hash_t r128; r128.low64 = lower; r128.high64 = upper; return r128; #endif // corresponds to #if (#if defined(__GNUC__) && !defined(__wasm__) \) } static xxh_u64 XXH3_mul128_fold64(xxh_u64 lhs, xxh_u64 rhs) { XXH128_hash_t product = XXH_mult64to128(lhs, rhs); return product.low64 ^ product.high64; } /* Seems to produce slightly better code on GCC for some reason. */ XXH_FORCE_INLINE xxh_u64 XXH_xorshift64(xxh_u64 v64, int shift) { XXH_ASSERT(0 <= shift && shift < 64); return v64 ^ (v64 >> shift); } /* * This is a fast avalanche stage, * suitable when input bits are already partially mixed */ static XXH64_hash_t XXH3_avalanche(xxh_u64 h64) { h64 = XXH_xorshift64(h64, 37); h64 *= 0x165667919E3779F9ULL; h64 = XXH_xorshift64(h64, 32); return h64; } XXH_FORCE_INLINE xxh_u64 XXH3_mix16B(const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, xxh_u64 seed64) { #if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__i386__) && defined(__SSE2__) /* x86 + SSE2 */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable like XXH32 hack */ __asm__ ("" : "+r" (seed64)); #endif // corresponds to #if (#if defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \) { xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 const input_hi = XXH_readLE64(input+8); return XXH3_mul128_fold64( input_lo ^ (XXH_readLE64(secret) + seed64), input_hi ^ (XXH_readLE64(secret+8) - seed64) ); } } #define XXH3_MIDSIZE_MAX 240 #define XXH3_MIDSIZE_STARTOFFSET 3 #define XXH3_MIDSIZE_LASTOFFSET 17 /* ======= Long Keys ======= */ #define XXH_STRIPE_LEN 64 #define XXH_SECRET_CONSUME_RATE 8 /* nb of secret bytes consumed at each accumulation */ #define XXH_ACC_NB (XXH_STRIPE_LEN / sizeof(xxh_u64)) XXH_FORCE_INLINE void XXH_writeLE64(void* dst, xxh_u64 v64) { if (!XXH_CPU_LITTLE_ENDIAN) v64 = XXH_swap64(v64); memcpy(dst, &v64, sizeof(v64)); } /* Several intrinsic functions below are supposed to accept __int64 as argument, * as documented in https://software.intel.com/sites/landingpage/IntrinsicsGuide/ . * However, several environments do not define __int64 type, * requiring a workaround. */ #if !defined (__VMS) \ && (defined (__cplusplus) \ || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) typedef int64_t xxh_i64; #else /* the following type must have a width of 64-bit */ typedef long long xxh_i64; #endif // corresponds to #if (#if !defined (__VMS) \) #if (XXH_VECTOR == XXH_AVX512) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_AVX512 # define XXH_TARGET_AVX512 /* disable attribute target */ #endif // corresponds to #ifndef (#ifndef XXH_TARGET_AVX512) XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_accumulate_512_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ALIGN(64) __m512i* const xacc = (__m512i *) acc; XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { /* data_vec = input[0]; */ __m512i const data_vec = _mm512_loadu_si512 (input); /* key_vec = secret[0]; */ __m512i const key_vec = _mm512_loadu_si512 (secret); /* data_key = data_vec ^ key_vec; */ __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m512i const data_key_lo = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m512i const product = _mm512_mul_epu32 (data_key, data_key_lo); /* xacc[0] += swap(data_vec); */ __m512i const data_swap = _mm512_shuffle_epi32(data_vec, (_MM_PERM_ENUM)_MM_SHUFFLE(1, 0, 3, 2)); __m512i const sum = _mm512_add_epi64(*xacc, data_swap); /* xacc[0] += product; */ *xacc = _mm512_add_epi64(product, sum); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_scrambleAcc_avx512(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 63) == 0); XXH_STATIC_ASSERT(XXH_STRIPE_LEN == sizeof(__m512i)); { XXH_ALIGN(64) __m512i* const xacc = (__m512i*) acc; const __m512i prime32 = _mm512_set1_epi32((int)XXH_PRIME32_1); /* xacc[0] ^= (xacc[0] >> 47) */ __m512i const acc_vec = *xacc; __m512i const shifted = _mm512_srli_epi64 (acc_vec, 47); __m512i const data_vec = _mm512_xor_si512 (acc_vec, shifted); /* xacc[0] ^= secret; */ __m512i const key_vec = _mm512_loadu_si512 (secret); __m512i const data_key = _mm512_xor_si512 (data_vec, key_vec); /* xacc[0] *= XXH_PRIME32_1; */ __m512i const data_key_hi = _mm512_shuffle_epi32 (data_key, (_MM_PERM_ENUM)_MM_SHUFFLE(0, 3, 0, 1)); __m512i const prod_lo = _mm512_mul_epu32 (data_key, prime32); __m512i const prod_hi = _mm512_mul_epu32 (data_key_hi, prime32); *xacc = _mm512_add_epi64(prod_lo, _mm512_slli_epi64(prod_hi, 32)); } } XXH_FORCE_INLINE XXH_TARGET_AVX512 void XXH3_initCustomSecret_avx512(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 63) == 0); XXH_STATIC_ASSERT(XXH_SEC_ALIGN == 64); XXH_ASSERT(((size_t)customSecret & 63) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m512i); __m512i const seed = _mm512_mask_set1_epi64(_mm512_set1_epi64((xxh_i64)seed64), 0xAA, -(xxh_i64)seed64); XXH_ALIGN(64) const __m512i* const src = (const __m512i*) XXH3_kSecret; XXH_ALIGN(64) __m512i* const dest = ( __m512i*) customSecret; int i; for (i=0; i < nbRounds; ++i) { /* GCC has a bug, _mm512_stream_load_si512 accepts 'void*', not 'void const*', * this will warn "discards ?const? qualifier". */ union { XXH_ALIGN(64) const __m512i* cp; XXH_ALIGN(64) void* p; } remote_const_void; remote_const_void.cp = src + i; dest[i] = _mm512_add_epi64(_mm512_stream_load_si512(remote_const_void.p), seed); } } } #endif // corresponds to #if (#if (XXH_VECTOR == XXH_AVX512) || defined(XXH_X86DISPATCH)) #if (XXH_VECTOR == XXH_AVX2) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_AVX2 # define XXH_TARGET_AVX2 /* disable attribute target */ #endif // corresponds to #ifndef (#ifndef XXH_TARGET_AVX2) XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_accumulate_512_avx2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { XXH_ALIGN(32) __m256i* const xacc = (__m256i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xinput = (const __m256i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* data_vec = xinput[i]; */ __m256i const data_vec = _mm256_loadu_si256 (xinput+i); /* key_vec = xsecret[i]; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m256i const data_key_lo = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m256i const product = _mm256_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m256i const data_swap = _mm256_shuffle_epi32(data_vec, _MM_SHUFFLE(1, 0, 3, 2)); __m256i const sum = _mm256_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm256_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_scrambleAcc_avx2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 31) == 0); { XXH_ALIGN(32) __m256i* const xacc = (__m256i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm256_loadu_si256 requires a const __m256i * pointer for some reason. */ const __m256i* const xsecret = (const __m256i *) secret; const __m256i prime32 = _mm256_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m256i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m256i const acc_vec = xacc[i]; __m256i const shifted = _mm256_srli_epi64 (acc_vec, 47); __m256i const data_vec = _mm256_xor_si256 (acc_vec, shifted); /* xacc[i] ^= xsecret; */ __m256i const key_vec = _mm256_loadu_si256 (xsecret+i); __m256i const data_key = _mm256_xor_si256 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m256i const data_key_hi = _mm256_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); __m256i const prod_lo = _mm256_mul_epu32 (data_key, prime32); __m256i const prod_hi = _mm256_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm256_add_epi64(prod_lo, _mm256_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_AVX2 void XXH3_initCustomSecret_avx2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 31) == 0); XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE / sizeof(__m256i)) == 6); XXH_STATIC_ASSERT(XXH_SEC_ALIGN <= 64); (void)(&XXH_writeLE64); XXH_PREFETCH(customSecret); { __m256i const seed = _mm256_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64, -(xxh_i64)seed64, (xxh_i64)seed64); XXH_ALIGN(64) const __m256i* const src = (const __m256i*) XXH3_kSecret; XXH_ALIGN(64) __m256i* dest = ( __m256i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack * The asm hack causes Clang to assume that XXH3_kSecretPtr aliases with * customSecret, and on aarch64, this prevented LDP from merging two * loads together for free. Putting the loads together before the stores * properly generates LDP. */ __asm__("" : "+r" (dest)); # endif /* GCC -O2 need unroll loop manually */ dest[0] = _mm256_add_epi64(_mm256_stream_load_si256(src+0), seed); dest[1] = _mm256_add_epi64(_mm256_stream_load_si256(src+1), seed); dest[2] = _mm256_add_epi64(_mm256_stream_load_si256(src+2), seed); dest[3] = _mm256_add_epi64(_mm256_stream_load_si256(src+3), seed); dest[4] = _mm256_add_epi64(_mm256_stream_load_si256(src+4), seed); dest[5] = _mm256_add_epi64(_mm256_stream_load_si256(src+5), seed); } } #endif // corresponds to #if (#if (XXH_VECTOR == XXH_AVX2) || defined(XXH_X86DISPATCH)) #if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH) #ifndef XXH_TARGET_SSE2 # define XXH_TARGET_SSE2 /* disable attribute target */ #endif // corresponds to #ifndef (#ifndef XXH_TARGET_SSE2) XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_accumulate_512_sse2( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { /* SSE2 is just a half-scale version of the AVX2 version. */ XXH_ASSERT((((size_t)acc) & 15) == 0); { XXH_ALIGN(16) __m128i* const xacc = (__m128i *) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xinput = (const __m128i *) input; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* data_vec = xinput[i]; */ __m128i const data_vec = _mm_loadu_si128 (xinput+i); /* key_vec = xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); /* data_key = data_vec ^ key_vec; */ __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* data_key_lo = data_key >> 32; */ __m128i const data_key_lo = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); /* product = (data_key & 0xffffffff) * (data_key_lo & 0xffffffff); */ __m128i const product = _mm_mul_epu32 (data_key, data_key_lo); /* xacc[i] += swap(data_vec); */ __m128i const data_swap = _mm_shuffle_epi32(data_vec, _MM_SHUFFLE(1,0,3,2)); __m128i const sum = _mm_add_epi64(xacc[i], data_swap); /* xacc[i] += product; */ xacc[i] = _mm_add_epi64(product, sum); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_scrambleAcc_sse2(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { XXH_ALIGN(16) __m128i* const xacc = (__m128i*) acc; /* Unaligned. This is mainly for pointer arithmetic, and because * _mm_loadu_si128 requires a const __m128i * pointer for some reason. */ const __m128i* const xsecret = (const __m128i *) secret; const __m128i prime32 = _mm_set1_epi32((int)XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(__m128i); i++) { /* xacc[i] ^= (xacc[i] >> 47) */ __m128i const acc_vec = xacc[i]; __m128i const shifted = _mm_srli_epi64 (acc_vec, 47); __m128i const data_vec = _mm_xor_si128 (acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ __m128i const key_vec = _mm_loadu_si128 (xsecret+i); __m128i const data_key = _mm_xor_si128 (data_vec, key_vec); /* xacc[i] *= XXH_PRIME32_1; */ __m128i const data_key_hi = _mm_shuffle_epi32 (data_key, _MM_SHUFFLE(0, 3, 0, 1)); __m128i const prod_lo = _mm_mul_epu32 (data_key, prime32); __m128i const prod_hi = _mm_mul_epu32 (data_key_hi, prime32); xacc[i] = _mm_add_epi64(prod_lo, _mm_slli_epi64(prod_hi, 32)); } } } XXH_FORCE_INLINE XXH_TARGET_SSE2 void XXH3_initCustomSecret_sse2(void* XXH_RESTRICT customSecret, xxh_u64 seed64) { XXH_STATIC_ASSERT((XXH_SECRET_DEFAULT_SIZE & 15) == 0); (void)(&XXH_writeLE64); { int const nbRounds = XXH_SECRET_DEFAULT_SIZE / sizeof(__m128i); # if defined(_MSC_VER) && defined(_M_IX86) && _MSC_VER < 1900 // MSVC 32bit mode does not support _mm_set_epi64x before 2015 XXH_ALIGN(16) const xxh_i64 seed64x2[2] = { (xxh_i64)seed64, -(xxh_i64)seed64 }; __m128i const seed = _mm_load_si128((__m128i const*)seed64x2); # else __m128i const seed = _mm_set_epi64x(-(xxh_i64)seed64, (xxh_i64)seed64); # endif int i; XXH_ALIGN(64) const float* const src = (float const*) XXH3_kSecret; XXH_ALIGN(XXH_SEC_ALIGN) __m128i* dest = (__m128i*) customSecret; # if defined(__GNUC__) || defined(__clang__) /* * On GCC & Clang, marking 'dest' as modified will cause the compiler: * - do not extract the secret from sse registers in the internal loop * - use less common registers, and avoid pushing these reg into stack */ __asm__("" : "+r" (dest)); # endif for (i=0; i < nbRounds; ++i) { dest[i] = _mm_add_epi64(_mm_castps_si128(_mm_load_ps(src+i*4)), seed); } } } #endif // corresponds to #if (#if (XXH_VECTOR == XXH_SSE2) || defined(XXH_X86DISPATCH)) #if (XXH_VECTOR == XXH_NEON) XXH_FORCE_INLINE void XXH3_accumulate_512_neon( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { XXH_ALIGN(16) uint64x2_t* const xacc = (uint64x2_t *) acc; /* We don't use a uint32x4_t pointer because it causes bus errors on ARMv7. */ uint8_t const* const xinput = (const uint8_t *) input; uint8_t const* const xsecret = (const uint8_t *) secret; size_t i; for (i=0; i < XXH_STRIPE_LEN / sizeof(uint64x2_t); i++) { /* data_vec = xinput[i]; */ uint8x16_t data_vec = vld1q_u8(xinput + (i * 16)); /* key_vec = xsecret[i]; */ uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); uint64x2_t data_key; uint32x2_t data_key_lo, data_key_hi; /* xacc[i] += swap(data_vec); */ uint64x2_t const data64 = vreinterpretq_u64_u8(data_vec); uint64x2_t const swapped = vextq_u64(data64, data64, 1); xacc[i] = vaddq_u64 (xacc[i], swapped); /* data_key = data_vec ^ key_vec; */ data_key = vreinterpretq_u64_u8(veorq_u8(data_vec, key_vec)); /* data_key_lo = (uint32x2_t) (data_key & 0xFFFFFFFF); * data_key_hi = (uint32x2_t) (data_key >> 32); * data_key = UNDEFINED; */ XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); /* xacc[i] += (uint64x2_t) data_key_lo * (uint64x2_t) data_key_hi; */ xacc[i] = vmlal_u32 (xacc[i], data_key_lo, data_key_hi); } } } XXH_FORCE_INLINE void XXH3_scrambleAcc_neon(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { uint64x2_t* xacc = (uint64x2_t*) acc; uint8_t const* xsecret = (uint8_t const*) secret; uint32x2_t prime = vdup_n_u32 (XXH_PRIME32_1); size_t i; for (i=0; i < XXH_STRIPE_LEN/sizeof(uint64x2_t); i++) { /* xacc[i] ^= (xacc[i] >> 47); */ uint64x2_t acc_vec = xacc[i]; uint64x2_t shifted = vshrq_n_u64 (acc_vec, 47); uint64x2_t data_vec = veorq_u64 (acc_vec, shifted); /* xacc[i] ^= xsecret[i]; */ uint8x16_t key_vec = vld1q_u8(xsecret + (i * 16)); uint64x2_t data_key = veorq_u64(data_vec, vreinterpretq_u64_u8(key_vec)); /* xacc[i] *= XXH_PRIME32_1 */ uint32x2_t data_key_lo, data_key_hi; /* data_key_lo = (uint32x2_t) (xacc[i] & 0xFFFFFFFF); * data_key_hi = (uint32x2_t) (xacc[i] >> 32); * xacc[i] = UNDEFINED; */ XXH_SPLIT_IN_PLACE(data_key, data_key_lo, data_key_hi); { /* * prod_hi = (data_key >> 32) * XXH_PRIME32_1; * * Avoid vmul_u32 + vshll_n_u32 since Clang 6 and 7 will * incorrectly "optimize" this: * tmp = vmul_u32(vmovn_u64(a), vmovn_u64(b)); * shifted = vshll_n_u32(tmp, 32); * to this: * tmp = "vmulq_u64"(a, b); // no such thing! * shifted = vshlq_n_u64(tmp, 32); * * However, unlike SSE, Clang lacks a 64-bit multiply routine * for NEON, and it scalarizes two 64-bit multiplies instead. * * vmull_u32 has the same timing as vmul_u32, and it avoids * this bug completely. * See https://bugs.llvm.org/show_bug.cgi?id=39967 */ uint64x2_t prod_hi = vmull_u32 (data_key_hi, prime); /* xacc[i] = prod_hi << 32; */ xacc[i] = vshlq_n_u64(prod_hi, 32); /* xacc[i] += (prod_hi & 0xFFFFFFFF) * XXH_PRIME32_1; */ xacc[i] = vmlal_u32(xacc[i], data_key_lo, prime); } } } } #endif // corresponds to #if (#if (XXH_VECTOR == XXH_NEON)) #if (XXH_VECTOR == XXH_VSX) XXH_FORCE_INLINE void XXH3_accumulate_512_vsx( void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { xxh_u64x2* const xacc = (xxh_u64x2*) acc; /* presumed aligned */ xxh_u64x2 const* const xinput = (xxh_u64x2 const*) input; /* no alignment restriction */ xxh_u64x2 const* const xsecret = (xxh_u64x2 const*) secret; /* no alignment restriction */ xxh_u64x2 const v32 = { 32, 32 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* data_vec = xinput[i]; */ xxh_u64x2 const data_vec = XXH_vec_loadu(xinput + i); /* key_vec = xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* shuffled = (data_key << 32) | (data_key >> 32); */ xxh_u32x4 const shuffled = (xxh_u32x4)vec_rl(data_key, v32); /* product = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)shuffled & 0xFFFFFFFF); */ xxh_u64x2 const product = XXH_vec_mulo((xxh_u32x4)data_key, shuffled); xacc[i] += product; /* swap high and low halves */ #ifdef __s390x__ xacc[i] += vec_permi(data_vec, data_vec, 2); #else xacc[i] += vec_xxpermdi(data_vec, data_vec, 2); #endif // corresponds to #ifdef (#ifdef __s390x__) } } XXH_FORCE_INLINE void XXH3_scrambleAcc_vsx(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ASSERT((((size_t)acc) & 15) == 0); { xxh_u64x2* const xacc = (xxh_u64x2*) acc; const xxh_u64x2* const xsecret = (const xxh_u64x2*) secret; /* constants */ xxh_u64x2 const v32 = { 32, 32 }; xxh_u64x2 const v47 = { 47, 47 }; xxh_u32x4 const prime = { XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1, XXH_PRIME32_1 }; size_t i; for (i = 0; i < XXH_STRIPE_LEN / sizeof(xxh_u64x2); i++) { /* xacc[i] ^= (xacc[i] >> 47); */ xxh_u64x2 const acc_vec = xacc[i]; xxh_u64x2 const data_vec = acc_vec ^ (acc_vec >> v47); /* xacc[i] ^= xsecret[i]; */ xxh_u64x2 const key_vec = XXH_vec_loadu(xsecret + i); xxh_u64x2 const data_key = data_vec ^ key_vec; /* xacc[i] *= XXH_PRIME32_1 */ /* prod_lo = ((xxh_u64x2)data_key & 0xFFFFFFFF) * ((xxh_u64x2)prime & 0xFFFFFFFF); */ xxh_u64x2 const prod_even = XXH_vec_mule((xxh_u32x4)data_key, prime); /* prod_hi = ((xxh_u64x2)data_key >> 32) * ((xxh_u64x2)prime >> 32); */ xxh_u64x2 const prod_odd = XXH_vec_mulo((xxh_u32x4)data_key, prime); xacc[i] = prod_odd + (prod_even << v32); } } } #endif // corresponds to #if (#if (XXH_VECTOR == XXH_VSX)) /* scalar variants - universal */ XXH_FORCE_INLINE void XXH3_accumulate_512_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT input, const void* XXH_RESTRICT secret) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ const xxh_u8* const xinput = (const xxh_u8*) input; /* no alignment restriction */ const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ size_t i; XXH_ASSERT(((size_t)acc & (XXH_ACC_ALIGN-1)) == 0); for (i=0; i < XXH_ACC_NB; i++) { xxh_u64 const data_val = XXH_readLE64(xinput + 8*i); xxh_u64 const data_key = data_val ^ XXH_readLE64(xsecret + i*8); xacc[i ^ 1] += data_val; /* swap adjacent lanes */ xacc[i] += XXH_mult32to64(data_key & 0xFFFFFFFF, data_key >> 32); } } XXH_FORCE_INLINE void XXH3_scrambleAcc_scalar(void* XXH_RESTRICT acc, const void* XXH_RESTRICT secret) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64* const xacc = (xxh_u64*) acc; /* presumed aligned */ const xxh_u8* const xsecret = (const xxh_u8*) secret; /* no alignment restriction */ size_t i; XXH_ASSERT((((size_t)acc) & (XXH_ACC_ALIGN-1)) == 0); for (i=0; i < XXH_ACC_NB; i++) { xxh_u64 const key64 = XXH_readLE64(xsecret + 8*i); xxh_u64 acc64 = xacc[i]; acc64 = XXH_xorshift64(acc64, 47); acc64 ^= key64; acc64 *= XXH_PRIME32_1; xacc[i] = acc64; } } typedef void (*XXH3_f_accumulate_512)(void* XXH_RESTRICT, const void*, const void*); typedef void (*XXH3_f_scrambleAcc)(void* XXH_RESTRICT, const void*); typedef void (*XXH3_f_initCustomSecret)(void* XXH_RESTRICT, xxh_u64); #if (XXH_VECTOR == XXH_AVX512) #define XXH3_accumulate_512 XXH3_accumulate_512_avx512 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx512 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx512 #elif (XXH_VECTOR == XXH_AVX2) #define XXH3_accumulate_512 XXH3_accumulate_512_avx2 #define XXH3_scrambleAcc XXH3_scrambleAcc_avx2 #define XXH3_initCustomSecret XXH3_initCustomSecret_avx2 #elif (XXH_VECTOR == XXH_SSE2) #define XXH3_accumulate_512 XXH3_accumulate_512_sse2 #define XXH3_scrambleAcc XXH3_scrambleAcc_sse2 #define XXH3_initCustomSecret XXH3_initCustomSecret_sse2 #elif (XXH_VECTOR == XXH_NEON) #define XXH3_accumulate_512 XXH3_accumulate_512_neon #define XXH3_scrambleAcc XXH3_scrambleAcc_neon #elif (XXH_VECTOR == XXH_VSX) #define XXH3_accumulate_512 XXH3_accumulate_512_vsx #define XXH3_scrambleAcc XXH3_scrambleAcc_vsx #else /* scalar */ #define XXH3_accumulate_512 XXH3_accumulate_512_scalar #define XXH3_scrambleAcc XXH3_scrambleAcc_scalar #endif // corresponds to #if (#if (XXH_VECTOR == XXH_AVX512)) #ifndef XXH_PREFETCH_DIST # ifdef __clang__ # define XXH_PREFETCH_DIST 320 # else # if (XXH_VECTOR == XXH_AVX512) # define XXH_PREFETCH_DIST 512 # else # define XXH_PREFETCH_DIST 384 # endif # endif /* __clang__ */ #endif /* XXH_PREFETCH_DIST */ // corresponds to #ifndef (#ifndef XXH_PREFETCH_DIST) /* * XXH3_accumulate() * Loops over XXH3_accumulate_512(). * Assumption: nbStripes will not overflow the secret size */ XXH_FORCE_INLINE void XXH3_accumulate( xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, const xxh_u8* XXH_RESTRICT secret, size_t nbStripes, XXH3_f_accumulate_512 f_acc512) { size_t n; for (n = 0; n < nbStripes; n++ ) { const xxh_u8* const in = input + n*XXH_STRIPE_LEN; XXH_PREFETCH(in + XXH_PREFETCH_DIST); f_acc512(acc, in, secret + n*XXH_SECRET_CONSUME_RATE); } } XXH_FORCE_INLINE void XXH3_hashLong_internal_loop(xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) { size_t const nbStripesPerBlock = (secretSize - XXH_STRIPE_LEN) / XXH_SECRET_CONSUME_RATE; size_t const block_len = XXH_STRIPE_LEN * nbStripesPerBlock; size_t const nb_blocks = (len - 1) / block_len; size_t n; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); for (n = 0; n < nb_blocks; n++) { XXH3_accumulate(acc, input + n*block_len, secret, nbStripesPerBlock, f_acc512); f_scramble(acc, secret + secretSize - XXH_STRIPE_LEN); } /* last partial block */ XXH_ASSERT(len > XXH_STRIPE_LEN); { size_t const nbStripes = ((len - 1) - (block_len * nb_blocks)) / XXH_STRIPE_LEN; XXH_ASSERT(nbStripes <= (secretSize / XXH_SECRET_CONSUME_RATE)); XXH3_accumulate(acc, input + nb_blocks*block_len, secret, nbStripes, f_acc512); /* last stripe */ { const xxh_u8* const p = input + len - XXH_STRIPE_LEN; #define XXH_SECRET_LASTACC_START 7 /* not aligned on 8, last secret is different from acc & scrambler */ f_acc512(acc, p, secret + secretSize - XXH_STRIPE_LEN - XXH_SECRET_LASTACC_START); } } } XXH_FORCE_INLINE xxh_u64 XXH3_mix2Accs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret) { return XXH3_mul128_fold64( acc[0] ^ XXH_readLE64(secret), acc[1] ^ XXH_readLE64(secret+8) ); } static XXH64_hash_t XXH3_mergeAccs(const xxh_u64* XXH_RESTRICT acc, const xxh_u8* XXH_RESTRICT secret, xxh_u64 start) { xxh_u64 result64 = start; size_t i = 0; for (i = 0; i < 4; i++) { result64 += XXH3_mix2Accs(acc+2*i, secret + 16*i); #if defined(__clang__) /* Clang */ \ && (defined(__arm__) || defined(__thumb__)) /* ARMv7 */ \ && (defined(__ARM_NEON) || defined(__ARM_NEON__)) /* NEON */ \ && !defined(XXH_ENABLE_AUTOVECTORIZE) /* Define to disable */ /* * UGLY HACK: * Prevent autovectorization on Clang ARMv7-a. Exact same problem as * the one in XXH3_len_129to240_64b. Speeds up shorter keys > 240b. * XXH3_64bits, len == 256, Snapdragon 835: * without hack: 2063.7 MB/s * with hack: 2560.7 MB/s */ __asm__("" : "+r" (result64)); #endif // corresponds to #if (#if defined(__clang__) /* Clang */ \) } return XXH3_avalanche(result64); } #define XXH3_INIT_ACC { XXH_PRIME32_3, XXH_PRIME64_1, XXH_PRIME64_2, XXH_PRIME64_3, \ XXH_PRIME64_4, XXH_PRIME32_2, XXH_PRIME64_5, XXH_PRIME32_1 } #define XXH_SECRET_MERGEACCS_START 11 /* * It's important for performance that XXH3_hashLong is not inlined. */ typedef XXH64_hash_t (*XXH3_hashLong64_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const xxh_u8* XXH_RESTRICT, size_t); /* === Public entry point === */ static void XXH3_64bits_reset_internal(XXH3_state_t* statePtr, XXH64_hash_t seed, const void* secret, size_t secretSize) { size_t const initStart = offsetof(XXH3_state_t, bufferedSize); size_t const initLength = offsetof(XXH3_state_t, nbStripesPerBlock) - initStart; XXH_ASSERT(offsetof(XXH3_state_t, nbStripesPerBlock) > initStart); XXH_ASSERT(statePtr != NULL); /* set members from bufferedSize to nbStripesPerBlock (excluded) to 0 */ memset((char*)statePtr + initStart, 0, initLength); statePtr->acc[0] = XXH_PRIME32_3; statePtr->acc[1] = XXH_PRIME64_1; statePtr->acc[2] = XXH_PRIME64_2; statePtr->acc[3] = XXH_PRIME64_3; statePtr->acc[4] = XXH_PRIME64_4; statePtr->acc[5] = XXH_PRIME32_2; statePtr->acc[6] = XXH_PRIME64_5; statePtr->acc[7] = XXH_PRIME32_1; statePtr->seed = seed; statePtr->extSecret = (const unsigned char*)secret; XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); statePtr->secretLimit = secretSize - XXH_STRIPE_LEN; statePtr->nbStripesPerBlock = statePtr->secretLimit / XXH_SECRET_CONSUME_RATE; } /* Note : when XXH3_consumeStripes() is invoked, * there must be a guarantee that at least one more byte must be consumed from input * so that the function can blindly consume all stripes using the "normal" secret segment */ XXH_FORCE_INLINE void XXH3_consumeStripes(xxh_u64* XXH_RESTRICT acc, size_t* XXH_RESTRICT nbStripesSoFarPtr, size_t nbStripesPerBlock, const xxh_u8* XXH_RESTRICT input, size_t nbStripes, const xxh_u8* XXH_RESTRICT secret, size_t secretLimit, XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) { XXH_ASSERT(nbStripes <= nbStripesPerBlock); /* can handle max 1 scramble per invocation */ XXH_ASSERT(*nbStripesSoFarPtr < nbStripesPerBlock); if (nbStripesPerBlock - *nbStripesSoFarPtr <= nbStripes) { /* need a scrambling operation */ size_t const nbStripesToEndofBlock = nbStripesPerBlock - *nbStripesSoFarPtr; size_t const nbStripesAfterBlock = nbStripes - nbStripesToEndofBlock; XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripesToEndofBlock, f_acc512); f_scramble(acc, secret + secretLimit); XXH3_accumulate(acc, input + nbStripesToEndofBlock * XXH_STRIPE_LEN, secret, nbStripesAfterBlock, f_acc512); *nbStripesSoFarPtr = nbStripesAfterBlock; } else { XXH3_accumulate(acc, input, secret + nbStripesSoFarPtr[0] * XXH_SECRET_CONSUME_RATE, nbStripes, f_acc512); *nbStripesSoFarPtr += nbStripes; } } /* * Both XXH3_64bits_update and XXH3_128bits_update use this routine. */ XXH_FORCE_INLINE XXH_errorcode XXH3_update(XXH3_state_t* state, const xxh_u8* input, size_t len, XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) { if (input==NULL) #if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1) return XXH_OK; #else return XXH_ERROR; #endif // corresponds to #if (#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)) { const xxh_u8* const bEnd = input + len; const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; state->totalLen += len; if (state->bufferedSize + len <= XXH3_INTERNALBUFFER_SIZE) { /* fill in tmp buffer */ XXH_memcpy(state->buffer + state->bufferedSize, input, len); state->bufferedSize += (XXH32_hash_t)len; return XXH_OK; } /* total input is now > XXH3_INTERNALBUFFER_SIZE */ #define XXH3_INTERNALBUFFER_STRIPES (XXH3_INTERNALBUFFER_SIZE / XXH_STRIPE_LEN) XXH_STATIC_ASSERT(XXH3_INTERNALBUFFER_SIZE % XXH_STRIPE_LEN == 0); /* clean multiple */ /* * Internal buffer is partially filled (always, except at beginning) * Complete it, then consume it. */ if (state->bufferedSize) { size_t const loadSize = XXH3_INTERNALBUFFER_SIZE - state->bufferedSize; XXH_memcpy(state->buffer + state->bufferedSize, input, loadSize); input += loadSize; XXH3_consumeStripes(state->acc, &state->nbStripesSoFar, state->nbStripesPerBlock, state->buffer, XXH3_INTERNALBUFFER_STRIPES, secret, state->secretLimit, f_acc512, f_scramble); state->bufferedSize = 0; } XXH_ASSERT(input < bEnd); /* Consume input by a multiple of internal buffer size */ if (input+XXH3_INTERNALBUFFER_SIZE < bEnd) { const xxh_u8* const limit = bEnd - XXH3_INTERNALBUFFER_SIZE; do { XXH3_consumeStripes(state->acc, &state->nbStripesSoFar, state->nbStripesPerBlock, input, XXH3_INTERNALBUFFER_STRIPES, secret, state->secretLimit, f_acc512, f_scramble); input += XXH3_INTERNALBUFFER_SIZE; } while (inputbuffer + sizeof(state->buffer) - XXH_STRIPE_LEN, input - XXH_STRIPE_LEN, XXH_STRIPE_LEN); } XXH_ASSERT(input < bEnd); /* Some remaining input (always) : buffer it */ XXH_memcpy(state->buffer, input, (size_t)(bEnd-input)); state->bufferedSize = (XXH32_hash_t)(bEnd-input); } return XXH_OK; } XXH_FORCE_INLINE void XXH3_digest_long (XXH64_hash_t* acc, const XXH3_state_t* state, const unsigned char* secret) { /* * Digest on a local copy. This way, the state remains unaltered, and it can * continue ingesting more input afterwards. */ memcpy(acc, state->acc, sizeof(state->acc)); if (state->bufferedSize >= XXH_STRIPE_LEN) { size_t const nbStripes = (state->bufferedSize - 1) / XXH_STRIPE_LEN; size_t nbStripesSoFar = state->nbStripesSoFar; XXH3_consumeStripes(acc, &nbStripesSoFar, state->nbStripesPerBlock, state->buffer, nbStripes, secret, state->secretLimit, XXH3_accumulate_512, XXH3_scrambleAcc); /* last stripe */ XXH3_accumulate_512(acc, state->buffer + state->bufferedSize - XXH_STRIPE_LEN, secret + state->secretLimit - XXH_SECRET_LASTACC_START); } else { /* bufferedSize < XXH_STRIPE_LEN */ xxh_u8 lastStripe[XXH_STRIPE_LEN]; size_t const catchupSize = XXH_STRIPE_LEN - state->bufferedSize; XXH_ASSERT(state->bufferedSize > 0); /* there is always some input buffered */ memcpy(lastStripe, state->buffer + sizeof(state->buffer) - catchupSize, catchupSize); memcpy(lastStripe + catchupSize, state->buffer, state->bufferedSize); XXH3_accumulate_512(acc, lastStripe, secret + state->secretLimit - XXH_SECRET_LASTACC_START); } } #define XXH_MIN(x, y) (((x) > (y)) ? (y) : (x)) XXH_FORCE_INLINE XXH128_hash_t XXH3_len_1to3_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { /* A doubled version of 1to3_64b with different constants. */ XXH_ASSERT(input != NULL); XXH_ASSERT(1 <= len && len <= 3); XXH_ASSERT(secret != NULL); /* * len = 1: combinedl = { input[0], 0x01, input[0], input[0] } * len = 2: combinedl = { input[1], 0x02, input[0], input[1] } * len = 3: combinedl = { input[2], 0x03, input[0], input[1] } */ { xxh_u8 const c1 = input[0]; xxh_u8 const c2 = input[len >> 1]; xxh_u8 const c3 = input[len - 1]; xxh_u32 const combinedl = ((xxh_u32)c1 <<16) | ((xxh_u32)c2 << 24) | ((xxh_u32)c3 << 0) | ((xxh_u32)len << 8); xxh_u32 const combinedh = XXH_rotl32(XXH_swap32(combinedl), 13); xxh_u64 const bitflipl = (XXH_readLE32(secret) ^ XXH_readLE32(secret+4)) + seed; xxh_u64 const bitfliph = (XXH_readLE32(secret+8) ^ XXH_readLE32(secret+12)) - seed; xxh_u64 const keyed_lo = (xxh_u64)combinedl ^ bitflipl; xxh_u64 const keyed_hi = (xxh_u64)combinedh ^ bitfliph; XXH128_hash_t h128; h128.low64 = XXH64_avalanche(keyed_lo); h128.high64 = XXH64_avalanche(keyed_hi); return h128; } } XXH_FORCE_INLINE XXH128_hash_t XXH3_len_4to8_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(4 <= len && len <= 8); seed ^= (xxh_u64)XXH_swap32((xxh_u32)seed) << 32; { xxh_u32 const input_lo = XXH_readLE32(input); xxh_u32 const input_hi = XXH_readLE32(input + len - 4); xxh_u64 const input_64 = input_lo + ((xxh_u64)input_hi << 32); xxh_u64 const bitflip = (XXH_readLE64(secret+16) ^ XXH_readLE64(secret+24)) + seed; xxh_u64 const keyed = input_64 ^ bitflip; /* Shift len to the left to ensure it is even, this avoids even multiplies. */ XXH128_hash_t m128 = XXH_mult64to128(keyed, XXH_PRIME64_1 + (len << 2)); m128.high64 += (m128.low64 << 1); m128.low64 ^= (m128.high64 >> 3); m128.low64 = XXH_xorshift64(m128.low64, 35); m128.low64 *= 0x9FB21C651E98DF25ULL; m128.low64 = XXH_xorshift64(m128.low64, 28); m128.high64 = XXH3_avalanche(m128.high64); return m128; } } XXH_FORCE_INLINE XXH128_hash_t XXH3_len_9to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(input != NULL); XXH_ASSERT(secret != NULL); XXH_ASSERT(9 <= len && len <= 16); { xxh_u64 const bitflipl = (XXH_readLE64(secret+32) ^ XXH_readLE64(secret+40)) - seed; xxh_u64 const bitfliph = (XXH_readLE64(secret+48) ^ XXH_readLE64(secret+56)) + seed; xxh_u64 const input_lo = XXH_readLE64(input); xxh_u64 input_hi = XXH_readLE64(input + len - 8); XXH128_hash_t m128 = XXH_mult64to128(input_lo ^ input_hi ^ bitflipl, XXH_PRIME64_1); /* * Put len in the middle of m128 to ensure that the length gets mixed to * both the low and high bits in the 128x64 multiply below. */ m128.low64 += (xxh_u64)(len - 1) << 54; input_hi ^= bitfliph; /* * Add the high 32 bits of input_hi to the high 32 bits of m128, then * add the long product of the low 32 bits of input_hi and XXH_PRIME32_2 to * the high 64 bits of m128. * * The best approach to this operation is different on 32-bit and 64-bit. */ if (sizeof(void *) < sizeof(xxh_u64)) { /* 32-bit */ /* * 32-bit optimized version, which is more readable. * * On 32-bit, it removes an ADC and delays a dependency between the two * halves of m128.high64, but it generates an extra mask on 64-bit. */ m128.high64 += (input_hi & 0xFFFFFFFF00000000ULL) + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2); } else { m128.high64 += input_hi + XXH_mult32to64((xxh_u32)input_hi, XXH_PRIME32_2 - 1); } /* m128 ^= XXH_swap64(m128 >> 64); */ m128.low64 ^= XXH_swap64(m128.high64); { /* 128x64 multiply: h128 = m128 * XXH_PRIME64_2; */ XXH128_hash_t h128 = XXH_mult64to128(m128.low64, XXH_PRIME64_2); h128.high64 += m128.high64 * XXH_PRIME64_2; h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = XXH3_avalanche(h128.high64); return h128; } } } /* * Assumption: `secret` size is >= XXH3_SECRET_SIZE_MIN */ XXH_FORCE_INLINE XXH128_hash_t XXH3_len_0to16_128b(const xxh_u8* input, size_t len, const xxh_u8* secret, XXH64_hash_t seed) { XXH_ASSERT(len <= 16); { if (len > 8) return XXH3_len_9to16_128b(input, len, secret, seed); if (len >= 4) return XXH3_len_4to8_128b(input, len, secret, seed); if (len) return XXH3_len_1to3_128b(input, len, secret, seed); { XXH128_hash_t h128; xxh_u64 const bitflipl = XXH_readLE64(secret+64) ^ XXH_readLE64(secret+72); xxh_u64 const bitfliph = XXH_readLE64(secret+80) ^ XXH_readLE64(secret+88); h128.low64 = XXH64_avalanche(seed ^ bitflipl); h128.high64 = XXH64_avalanche( seed ^ bitfliph); return h128; } } } /* * A bit slower than XXH3_mix16B, but handles multiply by zero better. */ XXH_FORCE_INLINE XXH128_hash_t XXH128_mix32B(XXH128_hash_t acc, const xxh_u8* input_1, const xxh_u8* input_2, const xxh_u8* secret, XXH64_hash_t seed) { acc.low64 += XXH3_mix16B (input_1, secret+0, seed); acc.low64 ^= XXH_readLE64(input_2) + XXH_readLE64(input_2 + 8); acc.high64 += XXH3_mix16B (input_2, secret+16, seed); acc.high64 ^= XXH_readLE64(input_1) + XXH_readLE64(input_1 + 8); return acc; } XXH_FORCE_INLINE XXH128_hash_t XXH3_len_17to128_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(16 < len && len <= 128); { XXH128_hash_t acc; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; if (len > 32) { if (len > 64) { if (len > 96) { acc = XXH128_mix32B(acc, input+48, input+len-64, secret+96, seed); } acc = XXH128_mix32B(acc, input+32, input+len-48, secret+64, seed); } acc = XXH128_mix32B(acc, input+16, input+len-32, secret+32, seed); } acc = XXH128_mix32B(acc, input, input+len-16, secret, seed); { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_NO_INLINE XXH128_hash_t XXH3_len_129to240_128b(const xxh_u8* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH64_hash_t seed) { XXH_ASSERT(secretSize >= XXH3_SECRET_SIZE_MIN); (void)secretSize; XXH_ASSERT(128 < len && len <= XXH3_MIDSIZE_MAX); { XXH128_hash_t acc; int const nbRounds = (int)len / 32; int i; acc.low64 = len * XXH_PRIME64_1; acc.high64 = 0; for (i=0; i<4; i++) { acc = XXH128_mix32B(acc, input + (32 * i), input + (32 * i) + 16, secret + (32 * i), seed); } acc.low64 = XXH3_avalanche(acc.low64); acc.high64 = XXH3_avalanche(acc.high64); XXH_ASSERT(nbRounds >= 4); for (i=4 ; i < nbRounds; i++) { acc = XXH128_mix32B(acc, input + (32 * i), input + (32 * i) + 16, secret + XXH3_MIDSIZE_STARTOFFSET + (32 * (i - 4)), seed); } /* last bytes */ acc = XXH128_mix32B(acc, input + len - 16, input + len - 32, secret + XXH3_SECRET_SIZE_MIN - XXH3_MIDSIZE_LASTOFFSET - 16, 0ULL - seed); { XXH128_hash_t h128; h128.low64 = acc.low64 + acc.high64; h128.high64 = (acc.low64 * XXH_PRIME64_1) + (acc.high64 * XXH_PRIME64_4) + ((len - seed) * XXH_PRIME64_2); h128.low64 = XXH3_avalanche(h128.low64); h128.high64 = (XXH64_hash_t)0 - XXH3_avalanche(h128.high64); return h128; } } } XXH_FORCE_INLINE XXH128_hash_t XXH3_hashLong_128b_internal(const void* XXH_RESTRICT input, size_t len, const xxh_u8* XXH_RESTRICT secret, size_t secretSize, XXH3_f_accumulate_512 f_acc512, XXH3_f_scrambleAcc f_scramble) { XXH_ALIGN(XXH_ACC_ALIGN) xxh_u64 acc[XXH_ACC_NB] = XXH3_INIT_ACC; XXH3_hashLong_internal_loop(acc, (const xxh_u8*)input, len, secret, secretSize, f_acc512, f_scramble); /* converge into final hash */ XXH_STATIC_ASSERT(sizeof(acc) == 64); XXH_ASSERT(secretSize >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)len * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + secretSize - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)len * XXH_PRIME64_2)); return h128; } } /* * It's important for performance that XXH3_hashLong is not inlined. */ XXH_NO_INLINE XXH128_hash_t XXH3_hashLong_128b_withSecret(const void* XXH_RESTRICT input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen) { (void)seed64; return XXH3_hashLong_128b_internal(input, len, (const xxh_u8*)secret, secretLen, XXH3_accumulate_512, XXH3_scrambleAcc); } /* * It's important for performance that XXH3_hashLong is not inlined. */ typedef XXH128_hash_t (*XXH3_hashLong128_f)(const void* XXH_RESTRICT, size_t, XXH64_hash_t, const void* XXH_RESTRICT, size_t); XXH_FORCE_INLINE XXH128_hash_t XXH3_128bits_internal(const void* input, size_t len, XXH64_hash_t seed64, const void* XXH_RESTRICT secret, size_t secretLen, XXH3_hashLong128_f f_hl128) { XXH_ASSERT(secretLen >= XXH3_SECRET_SIZE_MIN); /* * If an action is to be taken if `secret` conditions are not respected, * it should be done here. * For now, it's a contract pre-condition. * Adding a check and a branch here would cost performance at every hash. */ if (len <= 16) return XXH3_len_0to16_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, seed64); if (len <= 128) return XXH3_len_17to128_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); if (len <= XXH3_MIDSIZE_MAX) return XXH3_len_129to240_128b((const xxh_u8*)input, len, (const xxh_u8*)secret, secretLen, seed64); return f_hl128(input, len, seed64, secret, secretLen); } /* === Public XXH128 API === */ XXH128_hash_t XXH3_128bits_withSecret(const void* input, size_t len, const void* secret, size_t secretSize) { return XXH3_128bits_internal(input, len, 0, (const xxh_u8*)secret, secretSize, XXH3_hashLong_128b_withSecret); } /* === XXH3 128-bit streaming === */ /* * All the functions are actually the same as for 64-bit streaming variant. * The only difference is the finalizatiom routine. */ static void XXH3_128bits_reset_internal(XXH3_state_t* statePtr, XXH64_hash_t seed, const void* secret, size_t secretSize) { XXH3_64bits_reset_internal(statePtr, seed, secret, secretSize); } XXH_errorcode XXH3_128bits_reset(XXH3_state_t* statePtr) { if (statePtr == NULL) return XXH_ERROR; XXH3_128bits_reset_internal(statePtr, 0, XXH3_kSecret, XXH_SECRET_DEFAULT_SIZE); return XXH_OK; } XXH_errorcode XXH3_128bits_update(XXH3_state_t* state, const void* input, size_t len) { return XXH3_update(state, (const xxh_u8*)input, len, XXH3_accumulate_512, XXH3_scrambleAcc); } XXH128_hash_t XXH3_128bits_digest (const XXH3_state_t* state) { const unsigned char* const secret = (state->extSecret == NULL) ? state->customSecret : state->extSecret; if (state->totalLen > XXH3_MIDSIZE_MAX) { XXH_ALIGN(XXH_ACC_ALIGN) XXH64_hash_t acc[XXH_ACC_NB]; XXH3_digest_long(acc, state, secret); XXH_ASSERT(state->secretLimit + XXH_STRIPE_LEN >= sizeof(acc) + XXH_SECRET_MERGEACCS_START); { XXH128_hash_t h128; h128.low64 = XXH3_mergeAccs(acc, secret + XXH_SECRET_MERGEACCS_START, (xxh_u64)state->totalLen * XXH_PRIME64_1); h128.high64 = XXH3_mergeAccs(acc, secret + state->secretLimit + XXH_STRIPE_LEN - sizeof(acc) - XXH_SECRET_MERGEACCS_START, ~((xxh_u64)state->totalLen * XXH_PRIME64_2)); return h128; } } /* len <= XXH3_MIDSIZE_MAX : short code */ if (state->seed) { myprintf("00010! GURU XXH NO SEED!\n"); seppuku(); } return XXH3_128bits_withSecret(state->buffer, (size_t)(state->totalLen), secret, state->secretLimit + XXH_STRIPE_LEN); } /* 128-bit utility functions */ /*====== Canonical representation ======*/ /* Pop our optimization override from above */ #if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \ && defined(__GNUC__) && !defined(__clang__) /* GCC, not Clang */ \ && defined(__OPTIMIZE__) && !defined(__OPTIMIZE_SIZE__) /* respect -O0 and -Os */ # pragma GCC pop_options #endif // corresponds to #if (#if XXH_VECTOR == XXH_AVX2 /* AVX2 */ \) /// LICENSE_END.14 /// incapsulate Yann's xxhash like Brumme's (not BIG ENDIAN compatible) class XXHash64 { public: explicit XXHash64(uint64_t seed) { XXH64_hash_t seme=seed; state = XXH64_createState(); assert(state != NULL && "Out of memory!"); XXH64_reset(state,seme); } bool add(const void* input, uint64_t length) { if (!input || length == 0) return false; XXH64_update(state, input,length); return true; } uint64_t hash() const { return XXH64_digest(state); } string getHash() { return bin2hex_64(XXH64_digest(state)); } ~XXHash64() { if (state != NULL) { ///myprintf("23865: DESTROY XXHASH64\n"); franz_free(state); state=NULL; } } private: XXH64_state_t* state; }; XXHash64 g_franzhash_file(0); int64_t g_franzhash_file_bytes=0; XXHash64 g_franzhash_index(0); char g_franzhash_104[104]; int b64invs[] = { 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; int ismime(char i_c) { if ((i_c>='0') && (i_c<='9')) return 1; if ((i_c >='A') && (i_c<='Z')) return 1; if ((i_c>='a') && (i_c <= 'z')) return 1; if ((i_c=='+') || (i_c=='/') || (i_c =='=')) return 1; return 0; } size_t mimesize(const char *i_input) { if (i_input==NULL) return 0; size_t len; size_t ret; size_t i; len=strlen(i_input); // risky! ret=len/4*3; for (i=len; i-->0;) if (i_input[i] == '=') ret--; else break; return ret; } int mime2binary(const char *i_in, unsigned char *o_out, size_t outlen) { if (i_in==NULL) return 0; if (o_out==NULL) return 0; size_t lunghezza=strlen(i_in); if ((outlen> 16) & 0xFF; if (i_in[i+2] != '=') o_out[j+1] = (temp >> 8) & 0xFF; if (i_in[i+3] != '=') o_out[j+2] = temp & 0xFF; } return 1; } // Handle errors in libzpaq and elsewhere void libzpaq::error(const char* msg) { g_exec_text=msg; if (strstr(msg, "ut of memory")) throw std::bad_alloc(); throw std::runtime_error(msg); } using libzpaq::error; // Portable thread types and functions for Windows and Linux. Use like this: // // // Create mutex for locking thread-unsafe code // Mutex mutex; // shared by all threads // init_mutex(mutex); // initialize in unlocked state // Semaphore sem(n); // n >= 0 is initial state // // // Declare a thread function // ThreadReturn thread(void *arg) { // arg points to in/out parameters // lock(mutex); // wait if another thread has it first // release(mutex); // allow another waiting thread to continue // sem.wait(); // wait until n>0, then --n // sem.signal(); // ++n to allow waiting threads to continue // return 0; // must return 0 to exit thread // } // // // Start a thread // ThreadID tid; // run(tid, thread, &arg); // runs in parallel // join(tid); // wait for thread to return // destroy_mutex(mutex); // deallocate resources used by mutex // sem.destroy(); // deallocate resources used by semaphore #ifdef unix typedef void* ThreadReturn; // job return type typedef pthread_t ThreadID; // job ID type void run(ThreadID& tid, ThreadReturn(*f)(void*), void* arg)// start job {pthread_create(&tid, NULL, f, arg);} void join(ThreadID tid) {pthread_join(tid, NULL);} // wait for job typedef pthread_mutex_t Mutex; // mutex type void init_mutex(Mutex& m) {pthread_mutex_init(&m, 0);} // init mutex void lock(Mutex& m) {pthread_mutex_lock(&m);} // wait for mutex void release(Mutex& m) {pthread_mutex_unlock(&m);} // release mutex void destroy_mutex(Mutex& m) {pthread_mutex_destroy(&m);} // destroy mutex class Semaphore { public: Semaphore() {sem=-1;} void init(int n) { assert(n>=0); assert(sem==-1); pthread_cond_init(&cv, 0); pthread_mutex_init(&mutex, 0); sem=n; } void destroy() { assert(sem>=0); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cv); } int wait() { assert(sem>=0); pthread_mutex_lock(&mutex); int r=0; if (sem==0) r=pthread_cond_wait(&cv, &mutex); assert(sem>0); --sem; pthread_mutex_unlock(&mutex); return r; } void signal() { assert(sem>=0); pthread_mutex_lock(&mutex); ++sem; pthread_cond_signal(&cv); pthread_mutex_unlock(&mutex); } private: pthread_cond_t cv; // to signal FINISHED pthread_mutex_t mutex; // protects cv int sem; // semaphore count }; #else // Windows typedef DWORD ThreadReturn; typedef HANDLE ThreadID; void run(ThreadID& tid, ThreadReturn(*f)(void*), void* arg) { tid=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, arg, 0, NULL); if (tid==NULL) error("CreateThread failed"); } void join(ThreadID& tid) {WaitForSingleObject(tid, INFINITE);} typedef HANDLE Mutex; void init_mutex(Mutex& m) {m=CreateMutex(NULL, FALSE, NULL);} void lock(Mutex& m) {WaitForSingleObject(m, INFINITE);} void release(Mutex& m) {ReleaseMutex(m);} void destroy_mutex(Mutex& m) {CloseHandle(m);} class Semaphore { public: enum {MAXCOUNT=2000000000}; Semaphore(): h(NULL) {} void init(int n) {assert(!h); h=CreateSemaphore(NULL, n, MAXCOUNT, NULL);} void destroy() {assert(h); CloseHandle(h);} int wait() {assert(h); return WaitForSingleObject(h, INFINITE);} void signal() {assert(h); ReleaseSemaphore(h, 1, NULL);} private: HANDLE h; // Windows semaphore }; #endif // corresponds to #ifdef (#ifdef unix) string stringtolower(string i_stringa) { for (unsigned int i=0;i>\n",decodedcommand.c_str(),hashato.c_str(),i_archive.c_str()); myprintf("17276! Sorry, another zpaqfranz is running, we need to abort\n"); exit(0); return false; } #endif // corresponds to #ifdef (#ifdef _WIN32) return true; } #ifdef _WIN32 int64_t mtime() { int64_t t=GetTickCount(); if (t0) && (isdirectory(i_filename))) i_filename+="/"; HANDLE h=FindFirstFile(utow(i_filename.c_str()).c_str(), &ffd); if (h!=INVALID_HANDLE_VALUE) { string kz=wtou(ffd.cFileName); myprintf("kkkkk %s\n",kz.c_str()); FindClose(h); return wtou(ffd.cFileName); } return i_filename; } */ string win_getcomputername() { wchar_t buffer[256]; DWORD size=256; string risultato=""; if (GetComputerName(buffer,&size)) risultato=wtou(buffer); return risultato; } string win_getusername() { wchar_t buffer[256]; DWORD size=256; string risultato=""; if (GetUserName(buffer,&size)) risultato=wtou(buffer); return risultato; } string my_realpath(std::string const& i_path) { if (i_path=="") return ""; char linkbuffer[66000]={0}; size_t linksize=66000; HANDLE h = CreateFileW(utow(i_path.c_str()).c_str(), 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, NULL); char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; DWORD dwBytesReturned = 0; DeviceIoControl(h, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, sizeof(buffer), &dwBytesReturned, 0); typedef struct { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; union { struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; ULONG Flags; WCHAR PathBuffer[1]; } SymbolicLinkReparseBuffer; struct { USHORT SubstituteNameOffset; USHORT SubstituteNameLength; USHORT PrintNameOffset; USHORT PrintNameLength; WCHAR PathBuffer[1]; } MountPointReparseBuffer; struct { UCHAR DataBuffer[1]; } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER; REPARSE_DATA_BUFFER* pRDB = reinterpret_cast(buffer); if (pRDB->ReparseTag == IO_REPARSE_TAG_SYMLINK) { int nameLength = pRDB->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); wchar_t* pName = (wchar_t*)((char*)pRDB->SymbolicLinkReparseBuffer.PathBuffer + pRDB->SymbolicLinkReparseBuffer.SubstituteNameOffset); WideCharToMultiByte(CP_UTF8, 0, pName, nameLength, linkbuffer, linksize, NULL, NULL); return linkbuffer; } CloseHandle(h); return ""; } uint32_t convert_unicode_to_ansi_string(std::string& ansi,const wchar_t* unicode,const size_t unicode_size) { uint32_t error = 0; do { if ((nullptr == unicode) || (0 == unicode_size)) { error = ERROR_INVALID_PARAMETER; break; } ansi.clear(); int required_cch=::WideCharToMultiByte( CP_ACP, 0, unicode, static_cast(unicode_size), nullptr, 0, nullptr, nullptr ); if (required_cch==0) { error=::GetLastError(); break; } ansi.resize(required_cch); if (0 == ::WideCharToMultiByte( CP_ACP, 0, unicode, static_cast(unicode_size), const_cast(ansi.c_str()), static_cast(ansi.size()), nullptr, nullptr )) { error =::GetLastError(); break; } } while (false); return error; } uint32_t convert_utf8_to_unicode_string(std::wstring& unicode,const char* utf8,const size_t utf8_size) { uint32_t error = 0; do { if ((nullptr == utf8) || (0 == utf8_size)) { error = ERROR_INVALID_PARAMETER; break; } unicode.clear(); int required_cch = ::MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8, static_cast(utf8_size), nullptr, 0 ); if (required_cch==0) { error = ::GetLastError(); break; } unicode.resize(required_cch); if (0 == ::MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, utf8, static_cast(utf8_size), const_cast(unicode.c_str()), static_cast(unicode.size()) )) { error=::GetLastError(); break; } } while (false); return error; } // Windows: double converison std::string utf8toansi(const std::string & utf8) { std::wstring unicode = L""; convert_utf8_to_unicode_string(unicode, utf8.c_str(), utf8.size()); std::string ansi = ""; convert_unicode_to_ansi_string(ansi, unicode.c_str(), unicode.size()); return ansi; } int erredbarras(const std::wstring &wi_path) { std::wstring wpattern = wi_path+L"\\*.*"; const std::string s_pattern(wpattern.begin(),wpattern.end()); if (flagdebug) myprintf("00014: get handle FOR %s\n",s_pattern.c_str()); int secondi=(mtime()-g_startrd)/1000; if (secondi!=g_rd_ultimotempo) { g_rd_ultimotempo=secondi; if (g_rd_expected) myprintf("00015: Deleted objects %12s of (~) %12s @ %s/s\r",migliaia(g_rd),migliaia2(g_rd_expected),migliaia3(g_rd/secondi)); else myprintf("00016: Deleted objects %12s\r",migliaia(g_rd)); } WIN32_FIND_DATAW findfiledata; HANDLE myhandle=FindFirstFileW(wpattern.c_str(),&findfiledata); if (myhandle==INVALID_HANDLE_VALUE) { if (flagdebug) myprintf("00017: Invalid handle %s\n",s_pattern.c_str()); return 0; } do { std::string t=wtou(findfiledata.cFileName); if ((t!=".") && (t!="..")) { std::wstring wfilepath=wi_path+L"\\"+findfiledata.cFileName; const std::string s_wfilepath(wfilepath.begin(),wfilepath.end()); if (flagdebug3) myprintf("00018: Working on %s\n",s_wfilepath.c_str()); if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (flagdebug3) { myprintf("\n"); myprintf("00019: recurse on %s\n",s_wfilepath.c_str()); } int myresult=erredbarras(wfilepath); if (myresult) return myresult; } else { if (flagdebug3) myprintf("00020: set attribute on file %s\n",s_wfilepath.c_str()); if (SetFileAttributesW(wfilepath.c_str(),FILE_ATTRIBUTE_NORMAL) == FALSE) { if (flagdebug) myprintf("00021! ERROR cannot change attr of %s\n",s_wfilepath.c_str()); return GetLastError(); } if (flagdebug3) myprintf("00022: try to delete file %s\n",s_wfilepath.c_str()); if (DeleteFileW(wfilepath.c_str())==FALSE) { if (flagdebug) myprintf("00023! ERROR highlander file %s\n",s_wfilepath.c_str()); return GetLastError(); } else g_rd++; } } } while(FindNextFile(myhandle,&findfiledata)==TRUE); if (myhandle) FindClose(myhandle); DWORD myerror=GetLastError(); if (myerror==ERROR_NO_MORE_FILES) { const std::string s_wipath(wi_path.begin(), wi_path.end()); if (flagdebug3) myprintf("00024: Change folder attr %s\n",s_wipath.c_str()); if (SetFileAttributesW(wi_path.c_str(),FILE_ATTRIBUTE_NORMAL)==FALSE) { if (flagdebug) myprintf("00025! ERROR cannot change folder attr %s\n",s_wipath.c_str()); return GetLastError(); } if (flagdebug3) myprintf("00026: RemoveDirectory %s\n",s_wipath.c_str()); if (RemoveDirectoryW(wi_path.c_str())==FALSE) { if (flagdebug) myprintf("00027! ERROR highlander dir %s\n",s_wipath.c_str()); return GetLastError(); } else g_rd++; } else return myerror; return 0; } int64_t getwinattributes(string i_filename) { WIN32_FIND_DATA ffd; if ( (i_filename.size()>0) && (isdirectory(i_filename))) i_filename+="*"; HANDLE h=FindFirstFile(utow(i_filename.c_str()).c_str(), &ffd); if (h!=INVALID_HANDLE_VALUE) { FindClose(h); return ffd.dwFileAttributes; } return 0; } /// reworked https://github.com/JFLarvoire/SysToolsLib/blob/master/C/MsvcLibX/src/readlink.c typedef struct _REPARSE_READ_BUFFER { DWORD ReparseTag; WORD ReparseDataLength; WORD Reserved; UCHAR DataBuffer[1]; } REPARSE_READ_BUFFER, *PREPARSE_READ_BUFFER; bool getreparsepointW(bool i_flagdebug,const string i_path, char *i_buf, size_t i_bufsize,size_t& o_byteletti,DWORD& o_tag,string& o_type) { o_byteletti =0; o_tag =0; o_type =""; myprintf("00028: REPPAAA\n"); return true; wstring wi_path=utow(i_path.c_str()); PREPARSE_READ_BUFFER pIoctlBuf; DWORD attributi = GetFileAttributesW(wi_path.c_str()); if (attributi==INVALID_FILE_ATTRIBUTES) { myprintf("00029! failed GetFileAttributesW\n"); return false; } if (!(attributi & FILE_ATTRIBUTE_REPARSE_POINT)) { myprintf("00030! fake file is not a reparse point\n"); return false; } DWORD flag=FILE_FLAG_OPEN_REPARSE_POINT; if (attributi & FILE_ATTRIBUTE_DIRECTORY) flag|=FILE_FLAG_BACKUP_SEMANTICS; HANDLE h=CreateFileW(wi_path.c_str(),0,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,flag,NULL); if (h==INVALID_HANDLE_VALUE) { myprintf("00031! cannot createfile on reparse point\n"); return false; } DWORD byteletti; BOOL fattoio=DeviceIoControl(h,FSCTL_GET_REPARSE_POINT,NULL,0,i_buf,(DWORD)i_bufsize,&byteletti,NULL); CloseHandle(h); if (!fattoio) { myprintf("00032! DeviceIoControl kaputt\n"); return false; } if (byteletti<8) { myprintf("00033! something wrong\n"); return false; } pIoctlBuf = (PREPARSE_READ_BUFFER)i_buf; o_tag =pIoctlBuf->ReparseTag; o_byteletti =pIoctlBuf->ReparseDataLength; switch (o_tag) { case 0x00000000: o_type="Reserved0"; break; case 0x00000001: o_type="Reserved1"; break; case 0x00000002: o_type="Reserved2"; break; case 0xA0000003: o_type="Mount point or junction"; break; case 0xC0000004: o_type="Hierarchical Storage Manager"; break; case 0x80000005: o_type="Home server drive extender"; break; case 0x80000006: o_type="Hierarchical Storage Manager Product #2"; break; case 0x80000007: o_type="Single-instance storage filter driver"; break; case 0x80000008: o_type="Windows boot Image File"; break; case 0x80000009: o_type="Cluster Shared Volume"; break; case 0x8000000A: o_type="Distributed File System"; break; case 0x8000000B: o_type="Filter manager test harness"; break; case 0xA000000C: o_type="Symbolic link"; break; case 0xA0000010: o_type="Internet Information Services cache"; break; case 0x80000012: o_type="Distributed File System R filter"; break; case 0x80000013: o_type="Deduplicated file"; break; case 0x80000014: o_type="NFS symbolic link"; break; case 0xC0000014: o_type="APPXSTREAM (Not used?)"; break; case 0x80000015: o_type="Placeholder for a OneDrive file"; break; case 0x80000016: o_type="Dynamic File filter"; break; case 0x80000017: o_type="Windows Overlay Filesystem compressed file"; break; case 0x80000018: o_type="Windows Container Isolation filter"; break; case 0xA0000019: o_type="NPFS server silo named pipe symbolic link into the host silo"; break; case 0x9000001A: o_type="Cloud Files filter"; break; case 0x8000001B: o_type="Application Execution link"; break; case 0x9000001C: o_type="Projected File System VFS filter, ex for git"; break; case 0xA000001D: o_type="Linux Sub-System Symbolic Link"; break; case 0x8000001E: o_type="Azure File Sync (AFS) filter"; break; case 0xA000001F: o_type="Windows Container Isolation filter tombstone"; break; case 0xA0000020: o_type="Unhandled Windows Container Isolation filter"; break; case 0xA0000021: o_type="One Drive (Not used?)"; break; case 0xA0000022: o_type="Projected File System VFS filter tombstone, ex for git"; break; case 0xA0000023: o_type="Linux Sub-System Socket"; break; case 0xA0000024: o_type="Linux Sub-System FIFO"; break; case 0xA0000025: o_type="Linux Sub-System Character Device"; break; case 0xA0000026: o_type="Linux Sub-System Block Device"; break; case 0xA0000027: o_type="Windows Container Isolation filter Link"; break; default: o_type="35701: Microsoft strikes back!"; break; } if (!i_flagdebug) return true; unsigned int ul; unsigned int u; unsigned int uMax; for (ul = 0; ul < (unsigned)(pIoctlBuf->ReparseDataLength); ul += 16) { myprintf("%08X ", ul); uMax = (unsigned)(pIoctlBuf->ReparseDataLength) - ul; if (uMax > 16) uMax = 16; /* Display the hex dump */ for (u=0; u<16; u++) { if (!(u&3)) myprintf(" "); if (u < uMax) myprintf("%2.2X ", ((unsigned char *)pIoctlBuf->DataBuffer)[ul + u]); else myprintf(" "); } /* Display the ASCII characters dump */ for (u=0; u<16; u++) { char c = ((char *)pIoctlBuf->DataBuffer)[ul + u]; if (!(u&7)) myprintf(" "); if (c < ' ') c = ' '; if ((unsigned char)c > '\x7F') c = ' '; myprintf("%c", c); } myprintf("\n"); } return true; } #else // Houston, we have Unix int64_t mtime() { timeval tv; gettimeofday(&tv, 0); return tv.tv_sec*1000LL+tv.tv_usec/1000; } std::string utf8toansi(const std::string & utf8) { return utf8; } void setupConsole(void) { } void restoreConsole(void) { if (flagnoconsole) return; if (flagsilent) return; printf("\x1b[0m"); } #endif // corresponds to #ifdef (#ifdef _WIN32) int terminalwidth() { #if defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return (int) csbi.srWindow.Right - csbi.srWindow.Left + 1; #else struct winsize w; int colonna=80; if (ioctl(fileno(stdout), TIOCGWINSZ, &w)==0) colonna=(w.ws_col); if (colonna>200) colonna=200; return colonna; #endif // corresponds to #if (#if defined(_WIN32)) } int terminalheight() { #if defined(_WIN32) CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); return (int)csbi.srWindow.Bottom - csbi.srWindow.Top + 1; #else struct winsize w; int riga=30; if (ioctl(fileno(stdout), TIOCGWINSZ, &w)==0) riga=(w.ws_row); if (riga>200) riga=30; return riga; #endif // corresponds to #if (#if defined(_WIN32)) } bool iskeypressed(int i_thekey) { #ifdef _WIN32 if (kbhit()) { int keypressed=::getch(); if (flagdebug) printf("21029: WIN32 getch %d %c\n",keypressed,keypressed); if (i_thekey==0) return true; else return (i_thekey==keypressed); } return false; #else struct termios old_t; struct termios new_t; tcgetattr (0,&old_t); new_t = old_t; new_t.c_lflag &= ~( ICANON | ECHO ); new_t.c_cc[VMIN] = 0; new_t.c_cc[VTIME] = 0; tcsetattr(0,TCSANOW,&new_t); char ch; int letti=read(0,&ch,1); tcsetattr(0,TCSANOW,&old_t); if (i_thekey==0) return (letti!=0); else return ((letti!=0) && (i_thekey==ch)); #endif // corresponds to #ifdef (#ifdef _WIN32) } int mygetch(bool i_flagmore) { int mychar=0; #if defined(_WIN32) mychar=::getch(); #endif // corresponds to #if (#if defined(_WIN32)) #ifdef unix /// BSD Unix struct termios oldt, newt; tcgetattr ( STDIN_FILENO, &oldt ); newt = oldt; newt.c_lflag &= ~( ICANON | ECHO ); tcsetattr ( STDIN_FILENO, TCSANOW, &newt ); mychar = getchar(); tcsetattr ( STDIN_FILENO, TCSANOW, &oldt ); #endif // corresponds to #ifdef (#ifdef unix) if (!i_flagmore) return mychar; if ((mychar==113) || (mychar==81) || (mychar==3)) /// q, Q, control-C { #ifdef unix myprintf("\n\n"); #endif // corresponds to #ifdef (#ifdef unix) seppuku(); } return mychar; } /* void clear_from_cursor_to_end() { CONSOLE_SCREEN_BUFFER_INFO csbi; HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); DWORD charsWritten; DWORD consoleSize; // Ottieni le informazioni sul buffer della console if (GetConsoleScreenBufferInfo(hConsole, &csbi)) { // Calcola il numero di caratteri dalla posizione corrente del cursore alla fine della riga consoleSize = csbi.dwSize.X - csbi.dwCursorPosition.X; // Riempie lo spazio con spazi vuoti FillConsoleOutputCharacter(hConsole, ' ', consoleSize, csbi.dwCursorPosition, &charsWritten); // Riposiziona il cursore alla riga successiva COORD newCursorPos = {0, csbi.dwCursorPosition.Y + 1}; SetConsoleCursorPosition(hConsole, newCursorPos); } else { printf("Errore nel recupero delle informazioni della console.\n"); } } */ void printbar(char i_carattere,bool i_printbarraenne=true) { if (flagpakka) return; int twidth=terminalwidth(); if (twidth<10) twidth=100; for (int i=0;i(altezzaconsole-2)) { printf("-- More (q, Q or control C to exit) --\r"); mygetch(true); for (int i=0;i(altezzaconsole-2)) { printf("-- More (q, Q or control C to exit) --\r"); mygetch(true); for (int i=0;i100) twidth=100; std::string temp(twidth-4, i_carattere); moreprint(temp.c_str()); } bool getcaptcha(const string& i_captcha,const string& i_reason) { if (flagnocaptcha) return true; if (i_captcha=="") return false; if (i_reason=="") return false; printf("\nTo confirm a dangerous command\n"); printf(">>> %s\n",i_reason.c_str()); printf("enter EXACTLY the capcha, then press CR (return)\n"); printf("Entering anything else will quit.\n"); printf("\nCaptcha to continue: %s\n",i_captcha.c_str()); char myline[81]; int dummy=scanf("%80s", myline); if (dummy==888888) // compiler be quiet! printf("no-warning-please\n"); if (myline!=i_captcha) { printf("Wrong captcha\n"); return false; } myprintf("00034: Captcha OK\n"); return true; } class franz_flags { public: MAPPAFLAGS mappaflags; HELPFLAGS helpflags; HELPFLAGS helpflagsscope; bool get(const string& i_name) { MAPPAFLAGS::iterator p=mappaflags.find(i_name); if (p==mappaflags.end()) { printf("42098: guru doing getflag %s \n",i_name.c_str()); seppuku(); } if (p->second==NULL) { printf("42913: guru empty pointer flag%s\n",i_name.c_str()); seppuku(); } return (*p->second); } bool exists(const string& i_name) { return (mappaflags.find(i_name)!=mappaflags.end()); } void set(string i_name, bool i_value) { MAPPAFLAGS::iterator p=mappaflags.find(i_name); if (p==mappaflags.end()) { } if (p==mappaflags.end()) { printf("42923: GURU doing setflag %s \n",i_name.c_str()); seppuku(); } if (p->second==NULL) { printf("42928: guru empty pointer flag%s\n",i_name.c_str()); seppuku(); } (*p->second)=i_value; } void settrue(const string& i_name) { set(i_name,true); } void debugga() { /// printf("48149: array franz flag size %s\n",migliaia(mappaflags.size())); for (MAPPAFLAGS::iterator p=mappaflags.begin(); p!=mappaflags.end(); ++p) { myprintf("48150: %-20s %d ",p->first.c_str(),(int)*p->second); HELPFLAGS::iterator a=helpflags.find(p->first); if (p!=mappaflags.end()) myprintf(" <<%s>>",a->second.c_str()); myprintf("\n"); } } void tutti() { for (MAPPAFLAGS::iterator p=mappaflags.begin(); p!=mappaflags.end(); ++p) { char buffer[200]; HELPFLAGS::iterator a=helpflags.find(p->first); if (p!=mappaflags.end()) { color_green(); snprintf(buffer,sizeof(buffer),"%-20s",p->first.c_str()); moreprint(buffer,true); color_restore(); snprintf(buffer,sizeof(buffer)," %s",a->second.c_str()); moreprint(buffer); } } } string compact() { string risultato=""; for (MAPPAFLAGS::iterator p=mappaflags.begin(); p!=mappaflags.end(); ++p) if (*p->second) risultato+=p->first+' '; return risultato; } void add(bool* i_thebool,string i_name,string i_help,string i_helpscope,bool i_default=false) { if (i_name=="") { printf("48125: GURU i_name empty\n"); seppuku(); } if (i_thebool==NULL) { printf("09778: GURU thebool NULL\n"); seppuku(); } MAPPAFLAGS::iterator p=mappaflags.find(i_name); if (p==mappaflags.end()) { *(i_thebool)=i_default; mappaflags.insert(std::pair(i_name, i_thebool)); if (i_help!="") helpflags.insert(std::pair(i_name, i_help)); if (i_helpscope!="") helpflags.insert(std::pair(i_name, i_helpscope)); } } }; franz_flags g_programflags; char* stristr(const char* str1,const char* str2) { const char* p1 = str1; const char* p2 = str2; const char* r = *p2 == 0 ? str1 : 0 ; while((*p1!=0) && (*p2!=0)) { if( tolower((unsigned char)*p1)==tolower((unsigned char)*p2)) { if(r==0) r=p1; p2++; } else { p2=str2; if(r!=0) p1=r+1; if(tolower((unsigned char)*p1)==tolower((unsigned char)*p2)) { r=p1; p2++; } else r=0; } p1++; } return *p2 == 0 ? (char*)r : 0 ; } bool havedoublequote(const string i_filename) { if (i_filename.length()==0) return false; else return i_filename[i_filename.size()-1]=='"'; } string mypopback(const string& i_string) { if (i_string=="") return ""; return i_string.substr(i_string.size() - 1); } string cutdoublequote(const string& i_string) { if (i_string=="") return ""; string temp=i_string; if (havedoublequote(i_string)) temp=i_string.substr(i_string.size() - 1); return temp; } bool isextension(const char* i_filename,const char* i_ext) { if (!i_filename) return false; if (!i_ext) return false; if (isdirectory(i_filename)) return false; const char * posizione=stristr(i_filename, i_ext); if (!posizione) return false; return (posizione-i_filename)+strlen(i_ext)==strlen(i_filename); } bool iszpaq(const string i_filename) { return isextension(i_filename.c_str(), ".zpaq"); } #ifdef _WIN32 bool isexe(const string i_filename) { return isextension(i_filename.c_str(), ".exe"); } #endif // corresponds to #ifdef (#ifdef _WIN32) bool isxls(const string i_filename) { return (isextension(i_filename.c_str(), ".xls") || isextension(i_filename.c_str(), ".ppt") || isextension(i_filename.c_str(), ".pps")); } bool isads(const string i_filename) { if (i_filename.length()==0) return false; else return strstr(i_filename.c_str(), ":$DATA")!=0; } bool iszfs(const string i_filename) { if (i_filename.length()==0) return false; else return strstr(i_filename.c_str(), ".zfs")!=0; } bool replaceinsensitive(std::string& str, const std::string& from, const std::string& to) { if (from.empty()) return false; std::string str_lower = str; std::string from_lower = from; for (size_t i = 0; i < str_lower.length(); ++i) { if (str_lower[i] >= 'A' && str_lower[i] <= 'Z') { str_lower[i] = str_lower[i] + ('a' - 'A'); } } for (size_t i = 0; i < from_lower.length(); ++i) { if (from_lower[i] >= 'A' && from_lower[i] <= 'Z') { from_lower[i] = from_lower[i] + ('a' - 'A'); } } size_t start_pos = str_lower.find(from_lower); if (start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } bool replace(std::string& str, const std::string& from, const std::string& to) { size_t start_pos = str.find(from); if(start_pos == std::string::npos) return false; str.replace(start_pos, from.length(), to); return true; } void myreplaceall(std::string& str, const std::string& from, const std::string& to) { if(from.empty()) return; size_t start_pos = 0; while((start_pos = str.find(from, start_pos)) != std::string::npos) { str.replace(start_pos, from.length(), to); start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } string format_datetime(string i_formato,tm* t=NULL) { char temp[12]; if (t==NULL) { time_t nowz=time(NULL); t=localtime(&nowz); } snprintf(temp,sizeof(temp),"%02d",t->tm_hour); string hour=temp; snprintf(temp,sizeof(temp),"%02d",t->tm_min); string min=temp; snprintf(temp,sizeof(temp),"%02d",t->tm_sec); string sec=temp; snprintf(temp,sizeof(temp),"%d",t->tm_wday); string weekday=temp; snprintf(temp,sizeof(temp),"%04d",t->tm_year+1900); string year=temp; snprintf(temp,sizeof(temp),"%02d",t->tm_mon+1); string month=temp; snprintf(temp,sizeof(temp),"%02d",t->tm_mday); string day=temp; snprintf(temp,sizeof(temp),"%02d",(t->tm_yday-t->tm_wday+7)/7); string week=temp; string date=year+'-'+month+'-'+day; string time=hour+'-'+min+'-'+sec; string datetime=date+'_'+time; myreplaceall(i_formato,"%hour",hour); myreplaceall(i_formato,"%min",min); myreplaceall(i_formato,"%sec",sec); myreplaceall(i_formato,"%weekday",weekday); myreplaceall(i_formato,"%year",year); myreplaceall(i_formato,"%month",month); myreplaceall(i_formato,"%day",day); myreplaceall(i_formato,"%week",week); myreplaceall(i_formato,"%timestamp",datetime); myreplaceall(i_formato,"%datetime",datetime); myreplaceall(i_formato,"%date",date); myreplaceall(i_formato,"%time",time); myreplaceall(i_formato,"$hour",hour); myreplaceall(i_formato,"$min",min); myreplaceall(i_formato,"$sec",sec); myreplaceall(i_formato,"$weekday",weekday); myreplaceall(i_formato,"$year",year); myreplaceall(i_formato,"$month",month); myreplaceall(i_formato,"$day",day); myreplaceall(i_formato,"$week",week); myreplaceall(i_formato,"$timestamp",datetime); myreplaceall(i_formato,"$datetime",datetime); myreplaceall(i_formato,"$date",date); myreplaceall(i_formato,"$time",time); #ifdef _WIN32 string pcname=stringtolower(win_getcomputername()); myreplaceall(i_formato,"$pcname",pcname); myreplaceall(i_formato,"$computername",pcname); string username=stringtolower(win_getusername()); myreplaceall(i_formato,"$username",username); #endif // corresponds to #ifdef (#ifdef _WIN32 ) return i_formato; } bool myreplace(string& i_str, const string& i_from, const string& i_to) { size_t start_pos = i_str.find(i_from); if(start_pos == std::string::npos) return false; i_str.replace(start_pos, i_from.length(), i_to); return true; } std::string myright(std::string const& source, size_t const length) { if (length >= source.size()) return source; return source.substr(source.size() - length); } std::string myleft(std::string const& source, size_t const length) { if (length >= source.size()) return source; return source.substr(0,length); } string mytrim(const string& i_str) { size_t first = i_str.find_first_not_of(' '); if (string::npos == first) return i_str; size_t last = i_str.find_last_not_of(' '); return i_str.substr(first, ((last-first)+1)); } void explode(string i_string,char i_delimiter,vector& array) { unsigned int i=0; while(i=i_string.size()) break; } } struct s_fileandsize { string filename; uint64_t size; int64_t attr; int64_t date; int64_t data; bool isdir; string hashhex; string hashtype; bool flaghashstored; string writtenfilename; bool hashok; bool filenotfound; s_fileandsize(): filename(""),size(0),attr(0),date(0),data(-1),isdir(false),hashhex(""),hashtype(""),flaghashstored(false),writtenfilename(""),hashok(false),filenotfound(false) {} }; const std::string WHITESPACE = " \n\r\t\f\v"; std::string myltrim(const std::string &s) { size_t start = s.find_first_not_of(WHITESPACE); return (start == std::string::npos) ? "" : s.substr(start); } std::string myrtrim(const std::string &s) { size_t end = s.find_last_not_of(WHITESPACE); return (end == std::string::npos) ? "" : s.substr(0, end + 1); } std::string mytrim2(const std::string &s) { return myrtrim(myltrim(s)); } string extractfilename(const string& i_string) { size_t i = i_string.rfind('/', i_string.length()); if (i != string::npos) return(i_string.substr(i+1, i_string.length() - i)); return(i_string); } string prendiestensione(const string& s) { if (isdirectory(s)) return (""); string nomefile=extractfilename(s); size_t i = nomefile.rfind('.', nomefile.length()); if (i != string::npos) { size_t lunghezzaestensione=nomefile.length() - i; /// sometimes it is hard to get the extension: pippo.plutopaperino if (lunghezzaestensione>20) return(""); return(nomefile.substr(i+1, lunghezzaestensione)); } return(""); } string extractfilepath(const string& i_string) { size_t i = i_string.rfind('/', i_string.length()); if (i != string::npos) return(i_string.substr(0, i+1)); i = i_string.rfind('\\', i_string.length()); if (i != string::npos) return(i_string.substr(0, i+1)); return(""); } string prendinomefileebasta(const string& s) { string nomefile=extractfilename(s); size_t i = nomefile.rfind('.', nomefile.length()); if (i != string::npos) return(nomefile.substr(0,i)); return(nomefile); } string path(const string& fn) { int n=0; for (int i=0; fn[i]; ++i) if (fn[i]=='/' || fn[i]=='\\') n=i+1; return fn.substr(0, n); } string purgeansi(string i_string,bool i_keeppath=false) { if (i_string=="") return (""); string purged; for (unsigned int i=0;i (greater than) : (colon) " (double quote) / (forward slash) \ (backslash) | (vertical bar or pipe) ? (question mark) * (asterisk) */ case ' ': case '-': case '#': case '~': case '%': case '^': case '_': case '.': case '+': case '=': purged+=i_string[i]; break; case '&': purged+="_and_"; break; case ',': case '`': case '@': case '$': case '*': case '|': case ':': case ';': case '"': case '\'': case '<': case '>': case '\n': case '\r': case '\t': purged+='_'; break; case '(': case '{': purged+='('; break; case ')': case '}': purged+=')'; break; default: purged+='_'; } } } return purged; } string forcelatinansi(string i_string) { return i_string; } string purgedouble(const string& i_string,const string& i_from,const string& i_to) { if (i_string=="") return(""); if (i_from=="") return(""); if (i_to=="") return(""); string purged=i_string; myreplaceall(purged,i_from,i_to); return purged; } string compressemlfilename(const string& i_string) { if (i_string=="") return(""); string uniqfilename=extractfilename(i_string); string percorso=extractfilepath(i_string); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," "," "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"..","."); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Fw ","Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Fwd Fwd ","Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," R "," Re "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"R Fwd ","Re Fwd"); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," RE "," Re "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Re Re ","Re "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Fwd Re Fwd Re ","Fwd Re "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Re Fwd Re Fwd ","Re Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," SV SV "," SV "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Fwd FW ","Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"Fwd I ","Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"I Fwd ","Fwd "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"R Re ","Re "); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename,"__","_"); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," _ ","_"); for (int k=0;k<10;k++) uniqfilename=purgedouble(uniqfilename," "," "); for (int k=uniqfilename.length()-1;k>0;k--) { if ((uniqfilename[k]=='-') || (uniqfilename[k]=='.') || (uniqfilename[k]==' ')) { uniqfilename=mypopback(uniqfilename); } else { break; } } uniqfilename=mytrim2(uniqfilename); uniqfilename=percorso+uniqfilename; return uniqfilename; } FILE* freadopen(const char* i_filename) { #ifdef _WIN32 wstring widename=utow(i_filename); FILE* myfp=_wfopen(widename.c_str(), L"rb" ); #else FILE* myfp=fopen(i_filename, "rb" ); #endif // corresponds to #ifdef (#ifdef _WIN32) if (myfp==NULL) { if (flagdebug) { myprintf("\n"); myprintf("00035! freadopen cannot open: %Z\n",i_filename); } return 0; } return myfp; } int64_t prendidimensionehandle(FILE* i_handle) { if (i_handle==0) return 0; fseeko(i_handle, 0, SEEK_END); int64_t dimensione=ftello(i_handle); fseeko(i_handle, 0, SEEK_SET); return dimensione; } int64_t prendidimensionefile(const char* i_filename) { if (!i_filename) return 0; FILE* myfile = freadopen(i_filename); if (myfile) { fseeko(myfile, 0, SEEK_END); int64_t dimensione=ftello(myfile); fclose(myfile); return dimensione; } else return 0; } #ifdef _WIN32 bool islonguncpath(string i_filename) { if (i_filename.size()<8) return false; if (i_filename[0]=='/') if (i_filename[1]=='/') if (i_filename[2]=='?') if (i_filename[3]=='/') if (toupper(i_filename[4])=='U') if (toupper(i_filename[5])=='N') if (toupper(i_filename[6])=='C') if (i_filename[7]=='/') return true; return false; } #endif // corresponds to #ifdef (#ifdef _WIN32) bool islongpath(string i_filename) { if (i_filename.size()<8) return false; if (i_filename[0]=='/') if (i_filename[1]=='/') if (i_filename[2]=='?') if (i_filename[3]=='/') if (isalpha(i_filename[4])) if (i_filename[5]==':') if (i_filename[6]=='/') return true; return false; } bool comparechar(char c1, char c2) { if (c1 == c2) return true; else if (std::toupper(c1) == std::toupper(c2)) return true; return false; } string stringtoupper(string i_stringa) { for (unsigned int i=0;i=4) return "0000:00:00"; else if (i_fixedlength==3) return "000:00:00"; else return "00:00:00"; } int h=(i_seconds/3600); int m=(i_seconds -(3600*h))/60; int s=(i_seconds -(3600*h)-(m*60)); char temporaneo[20]; if ((h<=99) || (i_fixedlength==2)) snprintf(temporaneo,sizeof(temporaneo),"%02d:%02d:%02d",h,m,s); else if ((h<=999) || (i_fixedlength==3)) snprintf(temporaneo,sizeof(temporaneo),"%03d:%02d:%02d",h,m,s); else snprintf(temporaneo,sizeof(temporaneo),"%d:%02d:%02d",h,m,s); return temporaneo; } char* mytohuman(int64_t i_bytes,char* i_buffer,int i_buffersize) { if (i_buffer==NULL) { myprintf("00037! guru i_buffer null\n"); seppuku(); } if (i_buffersize<5) { myprintf("00038! guru buffer too small\n"); seppuku(); } if (i_bytes<0) { snprintf(i_buffer,5,"neg"); return i_buffer; } char const *myappend[] = {" B","KB","MB","GB","TB","PB"}; char length = sizeof(myappend)/sizeof(myappend[0]); double mybytes=i_bytes; int i=0; if (i_bytes>1024) for (i=0;(i_bytes/1024)> 0 && (i14)) { myprintf("00048! datelength >14 (%d) |%s|\n",lunghezza,purged.c_str()); return -1; } if (lunghezza%2!=0) { myprintf("00049! datelength must be even (use leading zeros) (%d) |%s|\n",lunghezza,purged.c_str()); return -1; } int year =0; int month =0; int day =0; int hour =0; int minute =0; int second =0; if (lunghezza>=4) year =mystoi(purged.substr(0,4)); if (lunghezza>=6) month =mystoi(purged.substr(4,2)); if (lunghezza>=8) day =mystoi(purged.substr(6,2)); if (lunghezza>=10) hour =mystoi(purged.substr(8,2)); if (lunghezza>=12) minute =mystoi(purged.substr(10,2)); if (lunghezza>=14) second =mystoi(purged.substr(12,2)); if (i_flagfrom) { if (lunghezza==4) /// 2022 { month =1; day =1; } if (lunghezza==6) /// 202209 day =1; } else { if (lunghezza==4) /// 2022 { month =12; day =31; } if (lunghezza==6) /// 202209 { if (month==2) day=28; else if ((month==4) || (month==6) || (month==9) || (month==11)) day =30; else day=31; } } if (flagdebug2) myprintf("00050: date %04d-%02d-%02d %02d:%02d:%02d\n",year,month,day,hour,minute,second); if ((year<1970) || (year>2070)) { myprintf("00051! year not from 1970 to 2070\n"); return -1; } if ((month<1) || (month>12)) { myprintf("00052! month not in [01..12]. Use leading zero (not 3 but 03)\n"); return -1; } if ((day<1) || (day>31)) { myprintf("00053! day not in [01..31]. Use leading zero (not 4 but 04)\n"); return -1; } if (hour>24) { myprintf("00054! hour >24\n"); return -1; } if (minute>60) { myprintf("00055! minute >60\n"); return -1; } if (second>60) { myprintf("00056! second >60\n"); return -1; } bool isleap= (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); if (month == 2) { if (isleap) { if (!(day <=29)) { myprintf("00057! leap year, feb must be <=29\n"); return -1; } } else if (!(day <=28)) { myprintf("00058! NO leap year, feb must be <=28\n"); return -1; } } if ((month==4) || (month==6) || (month==9) || (month==11)) if (!(day <= 30)) { myprintf("00059! this month (%d) cannot have more than 30 days\n",month); return -1; } return year *10000000000LL + month *100000000LL + day *1000000 + hour *10000 + minute *100 + second; } // Convert non-negative decimal number x to string of at least n digits string itos(int64_t x, int n=1) { assert(x>=0); assert(n>=0); string r; for (; x || n>0; x/=10, --n) r=string(1, '0'+x%10)+r; return r; } // Replace * and ? in fn with part or digits of part string subpart(string fn, int part) { for (int j=fn.size()-1; j>=0; --j) { if (fn[j]=='?') fn[j]='0'+part%10, part/=10; else if (fn[j]=='*') fn=fn.substr(0, j)+itos(part)+fn.substr(j+1), part=0; } return fn; } // Return relative time in milliseconds /// Slow, working on string instead of char *. But who cares? #define NO_WARNING_PLEASE 36 string ConvertUtcToLocalTime(const string& i_date) { #if defined(_WIN32_WINNT) && ((_WIN32_WINNT == 0x0501) || (_WIN32_WINNT == 0x0502)) return i_date; #endif // corresponds to #if (#if defined(_WIN32_WINNT) && ((_WIN32_WINNT == 0x0501) || (_WIN32_WINNT == 0x0502))) if (flagdebug3) { myprintf("\n"); myprintf("00060: converting to localtime %s\n",i_date.c_str()); } if (i_date.length()!=19) { myprintf("25854$ i_date is not 19 chars long |%s|\n",i_date.c_str()); return i_date; } struct tm t; memset(&t,0,sizeof(t)); t.tm_year = atoi(i_date.c_str())-1900; t.tm_mon = atoi(i_date.c_str()+5)-1; t.tm_mday = atoi(i_date.c_str()+8); t.tm_hour = atoi(i_date.c_str()+11); t.tm_min = atoi(i_date.c_str()+14); t.tm_sec = atoi(i_date.c_str()+17); #ifdef _WIN32 // #ifdef _WIN64 time_t tt = _mkgmtime64(&t); #else time_t tt =-1; /// time_t tt = _mkgmtime32(&t); #endif // corresponds to #ifdef (#ifdef _WIN64) if (tt==-1) return i_date; struct tm* t2=NULL; t2 = &t; *t2 = *localtime(&tt); #else /// not Windows time_t utcTime = timegm(&t); // converte in UTC const struct tm* t2 = localtime(&utcTime); if (t2==NULL) { myprintf("25871$ ERROR in localtime!\n"); return i_date; } #endif // corresponds to #ifdef (#ifdef _WIN32) char ds[NO_WARNING_PLEASE]; memset(ds,0,NO_WARNING_PLEASE); snprintf(ds,NO_WARNING_PLEASE, "%04d-%02d-%02d %02d:%02d:%02d", t2->tm_year + 1900, t2->tm_mon + 1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec); ///snprintf(ds,sizeof(ds),"%.4d-%.2d-%.2d %.2d:%.2d:%.2d", t2->tm_year + 1900,t2->tm_mon + 1, t2->tm_mday, t2->tm_hour, t2->tm_min, t2->tm_sec); if (flagdebug) myprintf("00061: localtime is %s\n",ds); return ds; } // Convert 64 bit decimal YYYYMMDDHHMMSS to "YYYY-MM-DD HH:MM:SS" // where -1 = unknown date, 0 = deleted. string dateToString(bool i_flagutc,int64_t date,bool i_mylocal=false) { if (date<=0) return " "; string s="0000-00-00 00:00:00"; static const int t[]={18,17,15,14,12,11,9,8,6,5,3,2,1,0}; for (int i=0; i<14; ++i) s[t[i]]+=int(date%10), date/=10; if (!i_flagutc) s=ConvertUtcToLocalTime(s); if (i_mylocal) { ///string "0000-00-00 00:00:00"; /// 0123 56 89 12345 char mylocal[30]; mylocal[ 0]=s.at(8); mylocal[ 1]=s.at( 9); mylocal[ 2]='/'; mylocal[ 3]=s.at( 5); mylocal[ 4]=s.at( 6); mylocal[ 5]='/'; mylocal[ 6]=s.at( 0); mylocal[ 7]=s.at( 1); mylocal[ 8]=s.at( 2); mylocal[ 9]=s.at( 3); mylocal[10]=' '; mylocal[11]=' '; mylocal[12]=s.at(11); mylocal[13]=s.at(12); mylocal[14]=s.at(13); mylocal[15]=s.at(14); mylocal[16]=s.at(15); mylocal[17]=0; s=mylocal; } return s; } int64_t now() { time_t mynow=time(NULL); const tm* t=localtime(&mynow); if (t==NULL) return 0; return (t->tm_year+1900) *10000000000LL + (t->tm_mon+1) *100000000LL + t->tm_mday *1000000 + t->tm_hour *10000 + t->tm_min *100 + t->tm_sec; } string attrToString(int64_t attrib) { string r=" "; if ((attrib&255)=='u') { r[0]="0pc3d5b7 9lBsDEF"[(attrib>>20)&15]; for (int i=0; i<4; ++i) r[4-i]=(attrib>>(8+3*i))%8+'0'; } else if ((attrib&255)=='w') { for (int i=0, j=0; i<32; ++i) { if ((attrib>>(i+8))&1) { char c="RHS DAdFTprCoIEivs89012345678901"[i]; if (j<5) r[j]=c; else r+=c; ++j; } } } return r; } // Convert seconds since 0000 1/1/1970 to 64 bit decimal YYYYMMDDHHMMSS // Valid from 1970 to 2099. int64_t decimal_time(time_t tt) { if (tt==-1) tt=0; int64_t t=(sizeof(tt)==4) ? unsigned(tt) : tt; const int second=t%60; const int minute=t/60%60; const int hour=t/3600%24; t/=86400; // days since Jan 1 1970 const int term=t/1461; // 4 year terms since 1970 t%=1461; t+=(t>=59); // insert Feb 29 on non leap years t+=(t>=425); t+=(t>=1157); const int year=term*4+t/366+1970; // actual year t%=366; t+=(t>=60)*2; // make Feb. 31 days t+=(t>=123); // insert Apr 31 t+=(t>=185); // insert June 31 t+=(t>=278); // insert Sept 31 t+=(t>=340); // insert Nov 31 const int month=t/31+1; const int day=t%31+1; return year*10000000000LL+month*100000000+day*1000000 +hour*10000+minute*100+second; } // Convert decimal date to time_t - inverse of decimal_time() time_t unix_time(int64_t date) { if (date<=0) return -1; static const int days[12]={0,31,59,90,120,151,181,212,243,273,304,334}; const int year=date/10000000000LL%10000; const int month=(date/100000000%100-1)%12; const int day=date/1000000%100; const int hour=date/10000%100; const int min=date/100%100; const int sec=date%100; if (month<0) return 0; return (day-1+days[month]+(year%4==0 && month>1)+((year-1970)*1461+1)/4) *86400+hour*3600+min*60+sec; } /* section: errors */ #ifdef BSD int64_t fsbtoblk(int64_t num, uint64_t fsbs, u_long bs) { return (num * (intmax_t) fsbs / (int64_t) bs); } #endif // corresponds to #ifdef (#ifdef BSD) #ifdef _WIN32 bool isdospath(const string& i_filename) { if (i_filename.size()>3) if (isalpha(i_filename[0])) if (i_filename[1]==':') return true; return false; } #endif // corresponds to #ifdef (#ifdef _WIN32) bool iswindowspath(const string& i_filename) { /// printf("Y1 |%s|\n",i_filename.c_str()); if (i_filename.size()>3) if (isalpha(i_filename[0])) if (i_filename[1]==':') if ((i_filename[2]=='\\') || (i_filename[2]=='/')) { // printf("trueeeeeeeeeeeeeee\n"); return true; } return false; } bool iswindowsunc(const string& i_filename) { if (i_filename=="") return false; if (i_filename.size()<3) return false; if (i_filename[0]!='/') return false; if (i_filename[2]=='?') // longpath { if (i_filename.size()>5) if (i_filename[5]==':') return false; return true; } bool foundslash=false; for (unsigned int i=3;i pezzi; explode(i_path,'/',pezzi); if (pezzi.size()>=2) { string percorso="/"; for (unsigned int i=1;i255) { snprintf(buffer,sizeof(buffer),"%08d",(int)strlen(i_filename)); string lunghezza=buffer; risultato+=" : maybe length "+lunghezza+" >255?"; g_255++; } } else if (i_error==4L) risultato="ERROR_TOO_MANY_OPEN_FILES"; else if (i_error==5L) risultato="ERROR_ACCESS_DENIED"; else if (i_error==6L) risultato="ERROR_INVALID_HANDLE"; else if (i_error==7L) risultato="ERROR_ARENA_TRASHED"; else if (i_error==8L) risultato="ERROR_NOT_ENOUGH_MEMORY"; else if (i_error==9L) risultato="ERROR_INVALID_BLOCK"; else if (i_error==10L) risultato="ERROR_BAD_ENVIRONMENT"; else if (i_error==11L) risultato="ERROR_BAD_FORMAT"; else if (i_error==12L) risultato="ERROR_INVALID_ACCESS"; else if (i_error==13L) risultato="ERROR_INVALID_DATA"; else if (i_error==14L) risultato="ERROR_OUTOFMEMORY"; else if (i_error==15L) risultato="ERROR_INVALID_DRIVE"; else if (i_error==16L) risultato="ERROR_CURRENT_DIRECTORY"; else if (i_error==17L) risultato="ERROR_NOT_SAME_DEVICE"; else if (i_error==18L) risultato="ERROR_NO_MORE_FILES"; else if (i_error==19L) risultato="ERROR_WRITE_PROTECT"; else if (i_error==20L) risultato="ERROR_BAD_UNIT"; else if (i_error==21L) risultato="ERROR_NOT_READY"; else if (i_error==22L) risultato="ERROR_BAD_COMMAND"; else if (i_error==23L) risultato="ERROR_CRC"; else if (i_error==24L) risultato="ERROR_BAD_LENGTH"; else if (i_error==25L) risultato="ERROR_SEEK"; else if (i_error==26L) risultato="ERROR_NOT_DOS_DISK"; else if (i_error==27L) risultato="ERROR_SECTOR_NOT_FOUND"; else if (i_error==28L) risultato="ERROR_OUT_OF_PAPER"; else if (i_error==29L) risultato="ERROR_WRITE_FAULT"; else if (i_error==30L) risultato="ERROR_READ_FAULT"; else if (i_error==31L) risultato="ERROR_GEN_FAILURE"; else if (i_error==32L) risultato="ERROR_SHARING_VIOLATION"; else if (i_error==33L) risultato="ERROR_LOCK_VIOLATION"; else if (i_error==34L) risultato="ERROR_WRONG_DISK"; else if (i_error==36L) risultato="ERROR_SHARING_BUFFER_EXCEEDED"; else if (i_error==38L) risultato="ERROR_HANDLE_EOF"; else if (i_error==39L) risultato="ERROR_HANDLE_DISK_FULL"; else if (i_error==50L) risultato="ERROR_NOT_SUPPORTED"; else if (i_error==51L) risultato="ERROR_REM_NOT_LIST"; else if (i_error==52L) risultato="ERROR_DUP_NAME"; else if (i_error==53L) risultato="ERROR_BAD_NETPATH"; else if (i_error==54L) risultato="ERROR_NETWORK_BUSY"; else if (i_error==55L) risultato="ERROR_DEV_NOT_EXIST"; else if (i_error==56L) risultato="ERROR_TOO_MANY_CMDS"; else if (i_error==57L) risultato="ERROR_ADAP_HDW_ERR"; else if (i_error==58L) risultato="ERROR_BAD_NET_RESP"; else if (i_error==59L) risultato="ERROR_UNEXP_NET_ERR"; else if (i_error==60L) risultato="ERROR_BAD_REM_ADAP"; else if (i_error==61L) risultato="ERROR_PRINTQ_FULL"; else if (i_error==62L) risultato="ERROR_NO_SPOOL_SPACE"; else if (i_error==63L) risultato="ERROR_PRINT_CANCELLED"; else if (i_error==64L) risultato="ERROR_NETNAME_DELETED"; else if (i_error==65L) risultato="ERROR_NETWORK_ACCESS_DENIED"; else if (i_error==66L) risultato="ERROR_BAD_DEV_TYPE"; else if (i_error==67L) risultato="ERROR_BAD_NET_NAME"; else if (i_error==68L) risultato="ERROR_TOO_MANY_NAMES"; else if (i_error==69L) risultato="ERROR_TOO_MANY_SESS"; else if (i_error==70L) risultato="ERROR_SHARING_PAUSED"; else if (i_error==71L) risultato="ERROR_REQ_NOT_ACCEP"; else if (i_error==72L) risultato="ERROR_REDIR_PAUSED"; else if (i_error==80L) risultato="ERROR_FILE_EXISTS"; else if (i_error==82L) risultato="ERROR_CANNOT_MAKE"; else if (i_error==83L) risultato="ERROR_FAIL_I24"; else if (i_error==84L) risultato="ERROR_OUT_OF_STRUCTURES"; else if (i_error==85L) risultato="ERROR_ALREADY_ASSIGNED"; else if (i_error==86L) risultato="ERROR_INVALID_PASSWORD"; else if (i_error==87L) risultato="ERROR_INVALID_PARAMETER"; else if (i_error==88L) risultato="ERROR_NET_WRITE_FAULT"; else if (i_error==89L) risultato="ERROR_NO_PROC_SLOTS"; else if (i_error==100L) risultato="ERROR_TOO_MANY_SEMAPHORES"; else if (i_error==101L) risultato="ERROR_EXCL_SEM_ALREADY_OWNED"; else if (i_error==102L) risultato="ERROR_SEM_IS_SET"; else if (i_error==103L) risultato="ERROR_TOO_MANY_SEM_REQUESTS"; else if (i_error==104L) risultato="ERROR_INVALID_AT_INTERRUPT_TIME"; else if (i_error==105L) risultato="ERROR_SEM_OWNER_DIED"; else if (i_error==106L) risultato="ERROR_SEM_USER_LIMIT"; else if (i_error==107L) risultato="ERROR_DISK_CHANGE"; else if (i_error==108L) risultato="ERROR_DRIVE_LOCKED"; else if (i_error==109L) risultato="ERROR_BROKEN_PIPE"; else if (i_error==110L) risultato="ERROR_OPEN_FAILED"; else if (i_error==111L) risultato="ERROR_BUFFER_OVERFLOW"; else if (i_error==112L) risultato="ERROR_DISK_FULL"; else if (i_error==113L) risultato="ERROR_NO_MORE_SEARCH_HANDLES"; else if (i_error==114L) risultato="ERROR_INVALID_TARGET_HANDLE"; else if (i_error==117L) risultato="ERROR_INVALID_CATEGORY"; else if (i_error==118L) risultato="ERROR_INVALID_VERIFY_SWITCH"; else if (i_error==119L) risultato="ERROR_BAD_DRIVER_LEVEL"; else if (i_error==120L) risultato="ERROR_CALL_NOT_IMPLEMENTED"; else if (i_error==121L) risultato="ERROR_SEM_TIMEOUT"; else if (i_error==122L) risultato="ERROR_INSUFFICIENT_BUFFER"; else if (i_error==123L) risultato="ERROR_INVALID_NAME"; else if (i_error==124L) risultato="ERROR_INVALID_LEVEL"; else if (i_error==125L) risultato="ERROR_NO_VOLUME_LABEL"; else if (i_error==126L) risultato="ERROR_MOD_NOT_FOUND"; else if (i_error==127L) risultato="ERROR_PROC_NOT_FOUND"; else if (i_error==128L) risultato="ERROR_WAIT_NO_CHILDREN"; else if (i_error==129L) risultato="ERROR_CHILD_NOT_COMPLETE"; else if (i_error==130L) risultato="ERROR_DIRECT_ACCESS_HANDLE"; else if (i_error==131L) risultato="ERROR_NEGATIVE_SEEK"; else if (i_error==132L) risultato="ERROR_SEEK_ON_DEVICE"; else if (i_error==133L) risultato="ERROR_IS_JOIN_TARGET"; else if (i_error==134L) risultato="ERROR_IS_JOINED"; else if (i_error==135L) risultato="ERROR_IS_SUBSTED"; else if (i_error==136L) risultato="ERROR_NOT_JOINED"; else if (i_error==137L) risultato="ERROR_NOT_SUBSTED"; else if (i_error==138L) risultato="ERROR_JOIN_TO_JOIN"; else if (i_error==139L) risultato="ERROR_SUBST_TO_SUBST"; else if (i_error==140L) risultato="ERROR_JOIN_TO_SUBST"; else if (i_error==141L) risultato="ERROR_SUBST_TO_JOIN"; else if (i_error==142L) risultato="ERROR_BUSY_DRIVE"; else if (i_error==143L) risultato="ERROR_SAME_DRIVE"; else if (i_error==144L) risultato="ERROR_DIR_NOT_ROOT"; else if (i_error==145L) risultato="ERROR_DIR_NOT_EMPTY"; else if (i_error==146L) risultato="ERROR_IS_SUBST_PATH"; else if (i_error==147L) risultato="ERROR_IS_JOIN_PATH"; else if (i_error==148L) risultato="ERROR_PATH_BUSY"; else if (i_error==149L) risultato="ERROR_IS_SUBST_TARGET"; else if (i_error==150L) risultato="ERROR_SYSTEM_TRACE"; else if (i_error==151L) risultato="ERROR_INVALID_EVENT_COUNT"; else if (i_error==152L) risultato="ERROR_TOO_MANY_MUXWAITERS"; else if (i_error==153L) risultato="ERROR_INVALID_LISTFORMAT"; else if (i_error==154L) risultato="ERROR_LABEL_TOO_LONG"; else if (i_error==155L) risultato="ERROR_TOO_MANY_TCBS"; else if (i_error==156L) risultato="ERROR_SIGNAL_REFUSED"; else if (i_error==157L) risultato="ERROR_DISCARDED"; else if (i_error==158L) risultato="ERROR_NOT_LOCKED"; else if (i_error==159L) risultato="ERROR_BAD_THREADID_ADDR"; else if (i_error==160L) risultato="ERROR_BAD_ARGUMENTS"; else if (i_error==161L) risultato="ERROR_BAD_PATHNAME"; else if (i_error==162L) risultato="ERROR_SIGNAL_PENDING"; else if (i_error==164L) risultato="ERROR_MAX_THRDS_REACHED"; else if (i_error==167L) risultato="ERROR_LOCK_FAILED"; else if (i_error==170L) risultato="ERROR_BUSY"; else if (i_error==171L) risultato="ERROR_DEVICE_SUPPORT_IN_PROGRESS"; else if (i_error==173L) risultato="ERROR_CANCEL_VIOLATION"; else if (i_error==174L) risultato="ERROR_ATOMIC_LOCKS_NOT_SUPPORTED"; else if (i_error==180L) risultato="ERROR_INVALID_SEGMENT_NUMBER"; else if (i_error==182L) risultato="ERROR_INVALID_ORDINAL"; else if (i_error==183L) risultato="ERROR_ALREADY_EXISTS"; else if (i_error==186L) risultato="ERROR_INVALID_FLAG_NUMBER"; else if (i_error==187L) risultato="ERROR_SEM_NOT_FOUND"; else if (i_error==188L) risultato="ERROR_INVALID_STARTING_CODESEG"; else if (i_error==189L) risultato="ERROR_INVALID_STACKSEG"; else if (i_error==190L) risultato="ERROR_INVALID_MODULETYPE"; else if (i_error==191L) risultato="ERROR_INVALID_EXE_SIGNATURE"; else if (i_error==192L) risultato="ERROR_EXE_MARKED_INVALID"; else if (i_error==193L) risultato="ERROR_BAD_EXE_FORMAT"; else if (i_error==194L) risultato="ERROR_ITERATED_DATA_EXCEEDS_64k"; else if (i_error==195L) risultato="ERROR_INVALID_MINALLOCSIZE"; else if (i_error==196L) risultato="ERROR_DYNLINK_FROM_INVALID_RING"; else if (i_error==197L) risultato="ERROR_IOPL_NOT_ENABLED"; else if (i_error==198L) risultato="ERROR_INVALID_SEGDPL"; else if (i_error==199L) risultato="ERROR_AUTODATASEG_EXCEEDS_64k"; else if (i_error==200L) risultato="ERROR_RING2SEG_MUST_BE_MOVABLE"; else if (i_error==201L) risultato="ERROR_RELOC_CHAIN_XEEDS_SEGLIM"; else if (i_error==202L) risultato="ERROR_INFLOOP_IN_RELOC_CHAIN"; else if (i_error==203L) risultato="ERROR_ENVVAR_NOT_FOUND"; else if (i_error==205L) risultato="ERROR_NO_SIGNAL_SENT"; else if (i_error==206L) risultato="ERROR_FILENAME_EXCED_RANGE"; else if (i_error==207L) risultato="ERROR_RING2_STACK_IN_USE"; else if (i_error==208L) risultato="ERROR_META_EXPANSION_TOO_LONG"; else if (i_error==209L) risultato="ERROR_INVALID_SIGNAL_NUMBER"; else if (i_error==210L) risultato="ERROR_THREAD_1_INACTIVE"; else if (i_error==212L) risultato="ERROR_LOCKED"; else if (i_error==214L) risultato="ERROR_TOO_MANY_MODULES"; else if (i_error==215L) risultato="ERROR_NESTING_NOT_ALLOWED"; else if (i_error==216L) risultato="ERROR_EXE_MACHINE_TYPE_MISMATCH"; else if (i_error==217L) risultato="ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY"; else if (i_error==218L) risultato="ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY"; else if (i_error==220L) risultato="ERROR_FILE_CHECKED_OUT"; else if (i_error==221L) risultato="ERROR_CHECKOUT_REQUIRED"; else if (i_error==222L) risultato="ERROR_BAD_FILE_TYPE"; else if (i_error==223L) risultato="ERROR_FILE_TOO_LARGE"; else if (i_error==224L) risultato="ERROR_FORMS_AUTH_REQUIRED"; else if (i_error==225L) risultato="ERROR_VIRUS_INFECTED"; else if (i_error==226L) risultato="ERROR_VIRUS_DELETED"; else if (i_error==229L) risultato="ERROR_PIPE_LOCAL"; else if (i_error==230L) risultato="ERROR_BAD_PIPE"; else if (i_error==231L) risultato="ERROR_PIPE_BUSY"; else if (i_error==232L) risultato="ERROR_NO_DATA"; else if (i_error==233L) risultato="ERROR_PIPE_NOT_CONNECTED"; else if (i_error==234L) risultato="ERROR_MORE_DATA"; else if (i_error==235L) risultato="ERROR_NO_WORK_DONE"; else if (i_error==240L) risultato="ERROR_VC_DISCONNECTED"; else if (i_error==254L) risultato="ERROR_INVALID_EA_NAME"; else if (i_error==255L) risultato="ERROR_EA_LISTINCONSISTENT"; else if (i_error==258L) risultato="WAIT_TIMEOUT"; else if (i_error==259L) risultato="ERROR_NO_MORE_ITEMS"; else if (i_error==266L) risultato="ERROR_CANNOT_COPY"; else if (i_error==267L) risultato="ERROR_DIRECTORY"; else if (i_error==275L) risultato="ERROR_EAS_DIDNT_FIT"; else if (i_error==276L) risultato="ERROR_EA_FILE_CORRUPT"; else if (i_error==277L) risultato="ERROR_EA_TABLE_FULL"; else if (i_error==278L) risultato="ERROR_INVALID_EA_HANDLE"; else if (i_error==282L) risultato="ERROR_EAS_NOT_SUPPORTED"; else if (i_error==288L) risultato="ERROR_NOT_OWNER"; else if (i_error==298L) risultato="ERROR_TOO_MANY_POSTS"; else if (i_error==299L) risultato="ERROR_PARTIAL_COPY"; else if (i_error==300L) risultato="ERROR_OPLOCK_NOT_GRANTED"; else if (i_error==301L) risultato="ERROR_INVALID_OPLOCK_PROTOCOL"; else if (i_error==302L) risultato="ERROR_DISK_TOO_FRAGMENTED"; else if (i_error==303L) risultato="ERROR_DELETE_PENDING"; else if (i_error==304L) risultato="ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING"; else if (i_error==305L) risultato="ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME"; else if (i_error==306L) risultato="ERROR_SECURITY_STREAM_IS_INCONSISTENT"; else if (i_error==307L) risultato="ERROR_INVALID_LOCK_RANGE"; else if (i_error==308L) risultato="ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT"; else if (i_error==309L) risultato="ERROR_NOTIFICATION_GUID_ALREADY_DEFINED"; else if (i_error==310L) risultato="ERROR_INVALID_EXCEPTION_HANDLER"; else if (i_error==311L) risultato="ERROR_DUPLICATE_PRIVILEGES"; else if (i_error==312L) risultato="ERROR_NO_RANGES_PROCESSED"; else if (i_error==313L) risultato="ERROR_NOT_ALLOWED_ON_SYSTEM_FILE"; else if (i_error==314L) risultato="ERROR_DISK_RESOURCES_EXHAUSTED"; else if (i_error==315L) risultato="ERROR_INVALID_TOKEN"; else if (i_error==316L) risultato="ERROR_DEVICE_FEATURE_NOT_SUPPORTED"; else if (i_error==317L) risultato="ERROR_MR_MID_NOT_FOUND"; else if (i_error==318L) risultato="ERROR_SCOPE_NOT_FOUND"; else if (i_error==319L) risultato="ERROR_UNDEFINED_SCOPE"; else if (i_error==320L) risultato="ERROR_INVALID_CAP"; else if (i_error==321L) risultato="ERROR_DEVICE_UNREACHABLE"; else if (i_error==322L) risultato="ERROR_DEVICE_NO_RESOURCES"; else if (i_error==323L) risultato="ERROR_DATA_CHECKSUM_ERROR"; else if (i_error==324L) risultato="ERROR_INTERMIXED_KERNEL_EA_OPERATION"; else if (i_error==326L) risultato="ERROR_FILE_LEVEL_TRIM_NOT_SUPPORTED"; else if (i_error==327L) risultato="ERROR_OFFSET_ALIGNMENT_VIOLATION"; else if (i_error==328L) risultato="ERROR_INVALID_FIELD_IN_PARAMETER_LIST"; else if (i_error==329L) risultato="ERROR_OPERATION_IN_PROGRESS"; else if (i_error==330L) risultato="ERROR_BAD_DEVICE_PATH"; else if (i_error==331L) risultato="ERROR_TOO_MANY_DESCRIPTORS"; else if (i_error==332L) risultato="ERROR_SCRUB_DATA_DISABLED"; else if (i_error==333L) risultato="ERROR_NOT_REDUNDANT_STORAGE"; else if (i_error==334L) risultato="ERROR_RESIDENT_FILE_NOT_SUPPORTED"; else if (i_error==335L) risultato="ERROR_COMPRESSED_FILE_NOT_SUPPORTED"; else if (i_error==336L) risultato="ERROR_DIRECTORY_NOT_SUPPORTED"; else if (i_error==337L) risultato="ERROR_NOT_READ_FROM_COPY"; else if (i_error==338L) risultato="ERROR_FT_WRITE_FAILURE"; else if (i_error==339L) risultato="ERROR_FT_DI_SCAN_REQUIRED"; else if (i_error==340L) risultato="ERROR_INVALID_KERNEL_INFO_VERSION"; else if (i_error==341L) risultato="ERROR_INVALID_PEP_INFO_VERSION"; else if (i_error==342L) risultato="ERROR_OBJECT_NOT_EXTERNALLY_BACKED"; else if (i_error==343L) risultato="ERROR_EXTERNAL_BACKING_PROVIDER_UNKNOWN"; else if (i_error==344L) risultato="ERROR_COMPRESSION_NOT_BENEFICIAL"; else if (i_error==345L) risultato="ERROR_STORAGE_TOPOLOGY_ID_MISMATCH"; else if (i_error==346L) risultato="ERROR_BLOCKED_BY_PARENTAL_CONTROLS"; else if (i_error==347L) risultato="ERROR_BLOCK_TOO_MANY_REFERENCES"; else if (i_error==348L) risultato="ERROR_MARKED_TO_DISALLOW_WRITES"; else if (i_error==349L) risultato="ERROR_ENCLAVE_FAILURE"; else if (i_error==350L) risultato="ERROR_FAIL_NOACTION_REBOOT"; else if (i_error==351L) risultato="ERROR_FAIL_SHUTDOWN"; else if (i_error==352L) risultato="ERROR_FAIL_RESTART"; else if (i_error==353L) risultato="ERROR_MAX_SESSIONS_REACHED"; else if (i_error==354L) risultato="ERROR_NETWORK_ACCESS_DENIED_EDP"; else if (i_error==355L) risultato="ERROR_DEVICE_HINT_NAME_BUFFER_TOO_SMALL"; else if (i_error==356L) risultato="ERROR_EDP_POLICY_DENIES_OPERATION"; else if (i_error==357L) risultato="ERROR_EDP_DPL_POLICY_CANT_BE_SATISFIED"; else if (i_error==358L) risultato="ERROR_CLOUD_FILE_PROVIDER_UNKNOWN"; else if (i_error==359L) risultato="ERROR_DEVICE_IN_MAINTENANCE"; else if (i_error==360L) risultato="ERROR_NOT_SUPPORTED_ON_DAX"; else if (i_error==361L) risultato="ERROR_DAX_MAPPING_EXISTS"; else if (i_error==362L) risultato="ERROR_CLOUD_FILE_PROVIDER_NOT_RUNNING"; else if (i_error==363L) risultato="ERROR_CLOUD_FILE_METADATA_CORRUPT"; else if (i_error==364L) risultato="ERROR_CLOUD_FILE_METADATA_TOO_LARGE"; else if (i_error==365L) risultato="ERROR_CLOUD_FILE_PROPERTY_BLOB_TOO_LARGE"; else if (i_error==366L) risultato="ERROR_CLOUD_FILE_PROPERTY_BLOB_CHECKSUM_MISMATCH"; else if (i_error==367L) risultato="ERROR_CHILD_PROCESS_BLOCKED"; else if (i_error==368L) risultato="ERROR_STORAGE_LOST_DATA_PERSISTENCE"; else if (i_error==400L) risultato="ERROR_THREAD_MODE_ALREADY_BACKGROUND"; else if (i_error==401L) risultato="ERROR_THREAD_MODE_NOT_BACKGROUND"; else if (i_error==402L) risultato="ERROR_PROCESS_MODE_ALREADY_BACKGROUND"; else if (i_error==403L) risultato="ERROR_PROCESS_MODE_NOT_BACKGROUND"; else if (i_error==450L) risultato="ERROR_CAPAUTHZ_NOT_DEVUNLOCKED"; else if (i_error==451L) risultato="ERROR_CAPAUTHZ_CHANGE_TYPE"; else if (i_error==452L) risultato="ERROR_CAPAUTHZ_NOT_PROVISIONED"; else if (i_error==453L) risultato="ERROR_CAPAUTHZ_NOT_AUTHORIZED"; else if (i_error==454L) risultato="ERROR_CAPAUTHZ_NO_POLICY"; else if (i_error==455L) risultato="ERROR_CAPAUTHZ_DB_CORRUPTED"; else if (i_error==483L) risultato="ERROR_DEVICE_HARDWARE_ERROR"; else if (i_error==487L) risultato="ERROR_INVALID_ADDRESS"; else if (i_error==500L) risultato="ERROR_USER_PROFILE_LOAD"; else if (i_error==534L) risultato="ERROR_ARITHMETIC_OVERFLOW"; else if (i_error==535L) risultato="ERROR_PIPE_CONNECTED"; else if (i_error==536L) risultato="ERROR_PIPE_LISTENING"; else if (i_error==537L) risultato="ERROR_VERIFIER_STOP"; else if (i_error==538L) risultato="ERROR_ABIOS_ERROR"; else if (i_error==539L) risultato="ERROR_WX86_WARNING"; else if (i_error==540L) risultato="ERROR_WX86_ERROR"; else if (i_error==541L) risultato="ERROR_TIMER_NOT_CANCELED"; else if (i_error==542L) risultato="ERROR_UNWIND"; else if (i_error==543L) risultato="ERROR_BAD_STACK"; else if (i_error==544L) risultato="ERROR_INVALID_UNWIND_TARGET"; else if (i_error==545L) risultato="ERROR_INVALID_PORT_ATTRIBUTES"; else if (i_error==546L) risultato="ERROR_PORT_MESSAGE_TOO_LONG"; else if (i_error==547L) risultato="ERROR_INVALID_QUOTA_LOWER"; else if (i_error==548L) risultato="ERROR_DEVICE_ALREADY_ATTACHED"; else if (i_error==549L) risultato="ERROR_INSTRUCTION_MISALIGNMENT"; else if (i_error==550L) risultato="ERROR_PROFILING_NOT_STARTED"; else if (i_error==551L) risultato="ERROR_PROFILING_NOT_STOPPED"; else if (i_error==552L) risultato="ERROR_COULD_NOT_INTERPRET"; else if (i_error==553L) risultato="ERROR_PROFILING_AT_LIMIT"; else if (i_error==554L) risultato="ERROR_CANT_WAIT"; else if (i_error==555L) risultato="ERROR_CANT_TERMINATE_SELF"; else if (i_error==556L) risultato="ERROR_UNEXPECTED_MM_CREATE_ERR"; else if (i_error==557L) risultato="ERROR_UNEXPECTED_MM_MAP_ERROR"; else if (i_error==558L) risultato="ERROR_UNEXPECTED_MM_EXTEND_ERR"; else if (i_error==559L) risultato="ERROR_BAD_FUNCTION_TABLE"; else if (i_error==560L) risultato="ERROR_NO_GUID_TRANSLATION"; else if (i_error==561L) risultato="ERROR_INVALID_LDT_SIZE"; else if (i_error==563L) risultato="ERROR_INVALID_LDT_OFFSET"; else if (i_error==564L) risultato="ERROR_INVALID_LDT_DESCRIPTOR"; else if (i_error==565L) risultato="ERROR_TOO_MANY_THREADS"; else if (i_error==566L) risultato="ERROR_THREAD_NOT_IN_PROCESS"; else if (i_error==567L) risultato="ERROR_PAGEFILE_QUOTA_EXCEEDED"; else if (i_error==568L) risultato="ERROR_LOGON_SERVER_CONFLICT"; else if (i_error==569L) risultato="ERROR_SYNCHRONIZATION_REQUIRED"; else if (i_error==570L) risultato="ERROR_NET_OPEN_FAILED"; else if (i_error==571L) risultato="ERROR_IO_PRIVILEGE_FAILED"; else if (i_error==572L) risultato="ERROR_CONTROL_C_EXIT"; else if (i_error==573L) risultato="ERROR_MISSING_SYSTEMFILE"; else if (i_error==574L) risultato="ERROR_UNHANDLED_EXCEPTION"; else if (i_error==575L) risultato="ERROR_APP_INIT_FAILURE"; else if (i_error==576L) risultato="ERROR_PAGEFILE_CREATE_FAILED"; else if (i_error==577L) risultato="ERROR_INVALID_IMAGE_HASH"; else if (i_error==578L) risultato="ERROR_NO_PAGEFILE"; else if (i_error==579L) risultato="ERROR_ILLEGAL_FLOAT_CONTEXT"; else if (i_error==580L) risultato="ERROR_NO_EVENT_PAIR"; else if (i_error==581L) risultato="ERROR_DOMAIN_CTRLR_CONFIG_ERROR"; else if (i_error==582L) risultato="ERROR_ILLEGAL_CHARACTER"; else if (i_error==583L) risultato="ERROR_UNDEFINED_CHARACTER"; else if (i_error==584L) risultato="ERROR_FLOPPY_VOLUME"; else if (i_error==585L) risultato="ERROR_BIOS_FAILED_TO_CONNECT_INTERRUPT"; else if (i_error==586L) risultato="ERROR_BACKUP_CONTROLLER"; else if (i_error==587L) risultato="ERROR_MUTANT_LIMIT_EXCEEDED"; else if (i_error==588L) risultato="ERROR_FS_DRIVER_REQUIRED"; else if (i_error==589L) risultato="ERROR_CANNOT_LOAD_REGISTRY_FILE"; else if (i_error==590L) risultato="ERROR_DEBUG_ATTACH_FAILED"; else if (i_error==591L) risultato="ERROR_SYSTEM_PROCESS_TERMINATED"; else if (i_error==592L) risultato="ERROR_DATA_NOT_ACCEPTED"; else if (i_error==593L) risultato="ERROR_VDM_HARD_ERROR"; else if (i_error==594L) risultato="ERROR_DRIVER_CANCEL_TIMEOUT"; else if (i_error==595L) risultato="ERROR_REPLY_MESSAGE_MISMATCH"; else if (i_error==596L) risultato="ERROR_LOST_WRITEBEHIND_DATA"; else if (i_error==597L) risultato="ERROR_CLIENT_SERVER_PARAMETERS_INVALID"; else if (i_error==598L) risultato="ERROR_NOT_TINY_STREAM"; else if (i_error==599L) risultato="ERROR_STACK_OVERFLOW_READ"; else if (i_error==600L) risultato="ERROR_CONVERT_TO_LARGE"; else if (i_error==601L) risultato="ERROR_FOUND_OUT_OF_SCOPE"; else if (i_error==602L) risultato="ERROR_ALLOCATE_BUCKET"; else if (i_error==603L) risultato="ERROR_MARSHALL_OVERFLOW"; else if (i_error==604L) risultato="ERROR_INVALID_VARIANT"; else if (i_error==605L) risultato="ERROR_BAD_COMPRESSION_BUFFER"; else if (i_error==606L) risultato="ERROR_AUDIT_FAILED"; else if (i_error==607L) risultato="ERROR_TIMER_RESOLUTION_NOT_SET"; else if (i_error==608L) risultato="ERROR_INSUFFICIENT_LOGON_INFO"; else if (i_error==609L) risultato="ERROR_BAD_DLL_ENTRYPOINT"; else if (i_error==610L) risultato="ERROR_BAD_SERVICE_ENTRYPOINT"; else if (i_error==611L) risultato="ERROR_IP_ADDRESS_CONFLICT1"; else if (i_error==612L) risultato="ERROR_IP_ADDRESS_CONFLICT2"; else if (i_error==613L) risultato="ERROR_REGISTRY_QUOTA_LIMIT"; else if (i_error==614L) risultato="ERROR_NO_CALLBACK_ACTIVE"; else if (i_error==615L) risultato="ERROR_PWD_TOO_SHORT"; else if (i_error==616L) risultato="ERROR_PWD_TOO_RECENT"; else if (i_error==617L) risultato="ERROR_PWD_HISTORY_CONFLICT"; else if (i_error==618L) risultato="ERROR_UNSUPPORTED_COMPRESSION"; else if (i_error==619L) risultato="ERROR_INVALID_HW_PROFILE"; else if (i_error==620L) risultato="ERROR_INVALID_PLUGPLAY_DEVICE_PATH"; else if (i_error==621L) risultato="ERROR_QUOTA_LISTINCONSISTENT"; else if (i_error==622L) risultato="ERROR_EVALUATION_EXPIRATION"; else if (i_error==623L) risultato="ERROR_ILLEGAL_DLL_RELOCATION"; else if (i_error==624L) risultato="ERROR_DLL_INIT_FAILED_LOGOFF"; else if (i_error==625L) risultato="ERROR_VALIDATE_CONTINUE"; else if (i_error==626L) risultato="ERROR_NO_MORE_MATCHES"; else if (i_error==627L) risultato="ERROR_RANGE_LISTCONFLICT"; else if (i_error==628L) risultato="ERROR_SERVER_SID_MISMATCH"; else if (i_error==629L) risultato="ERROR_CANT_ENABLE_DENY_ONLY"; else if (i_error==630L) risultato="ERROR_FLOAT_MULTIPLE_FAULTS"; else if (i_error==631L) risultato="ERROR_FLOAT_MULTIPLE_TRAPS"; else if (i_error==632L) risultato="ERROR_NOINTERFACE"; else if (i_error==633L) risultato="ERROR_DRIVER_FAILED_SLEEP"; else if (i_error==634L) risultato="ERROR_CORRUPT_SYSTEM_FILE"; else if (i_error==635L) risultato="ERROR_COMMITMENT_MINIMUM"; else if (i_error==636L) risultato="ERROR_PNP_RESTART_ENUMERATION"; else if (i_error==637L) risultato="ERROR_SYSTEM_IMAGE_BAD_SIGNATURE"; else if (i_error==638L) risultato="ERROR_PNP_REBOOT_REQUIRED"; else if (i_error==639L) risultato="ERROR_INSUFFICIENT_POWER"; else if (i_error==640L) risultato="ERROR_MULTIPLE_FAULT_VIOLATION"; else if (i_error==641L) risultato="ERROR_SYSTEM_SHUTDOWN"; else if (i_error==642L) risultato="ERROR_PORT_NOT_SET"; else if (i_error==643L) risultato="ERROR_DS_VERSION_CHECK_FAILURE"; else if (i_error==644L) risultato="ERROR_RANGE_NOT_FOUND"; else if (i_error==646L) risultato="ERROR_NOT_SAFE_MODE_DRIVER"; else if (i_error==647L) risultato="ERROR_FAILED_DRIVER_ENTRY"; else if (i_error==648L) risultato="ERROR_DEVICE_ENUMERATION_ERROR"; else if (i_error==649L) risultato="ERROR_MOUNT_POINT_NOT_RESOLVED"; else if (i_error==650L) risultato="ERROR_INVALID_DEVICE_OBJECT_PARAMETER"; else if (i_error==651L) risultato="ERROR_MCA_OCCURED"; else if (i_error==652L) risultato="ERROR_DRIVER_DATABASE_ERROR"; else if (i_error==653L) risultato="ERROR_SYSTEM_HIVE_TOO_LARGE"; else if (i_error==654L) risultato="ERROR_DRIVER_FAILED_PRIOR_UNLOAD"; else if (i_error==655L) risultato="ERROR_VOLSNAP_PREPARE_HIBERNATE"; else if (i_error==656L) risultato="ERROR_HIBERNATION_FAILURE"; else if (i_error==657L) risultato="ERROR_PWD_TOO_LONG"; else if (i_error==665L) risultato="ERROR_FILE_SYSTEM_LIMITATION"; else if (i_error==668L) risultato="ERROR_ASSERTION_FAILURE"; else if (i_error==669L) risultato="ERROR_ACPI_ERROR"; else if (i_error==670L) risultato="ERROR_WOW_ASSERTION"; else if (i_error==671L) risultato="ERROR_PNP_BAD_MPS_TABLE"; else if (i_error==672L) risultato="ERROR_PNP_TRANSLATION_FAILED"; else if (i_error==673L) risultato="ERROR_PNP_IRQ_TRANSLATION_FAILED"; else if (i_error==674L) risultato="ERROR_PNP_INVALID_ID"; else if (i_error==675L) risultato="ERROR_WAKE_SYSTEM_DEBUGGER"; else if (i_error==676L) risultato="ERROR_HANDLES_CLOSED"; else if (i_error==677L) risultato="ERROR_EXTRANEOUS_INFORMATION"; else if (i_error==678L) risultato="ERROR_RXACT_COMMIT_NECESSARY"; else if (i_error==679L) risultato="ERROR_MEDIA_CHECK"; else if (i_error==680L) risultato="ERROR_GUID_SUBSTITUTION_MADE"; else if (i_error==681L) risultato="ERROR_STOPPED_ON_SYMLINK"; else if (i_error==682L) risultato="ERROR_LONGJUMP"; else if (i_error==683L) risultato="ERROR_PLUGPLAY_QUERY_VETOED"; else if (i_error==684L) risultato="ERROR_UNWIND_CONSOLIDATE"; else if (i_error==685L) risultato="ERROR_REGISTRY_HIVE_RECOVERED"; else if (i_error==686L) risultato="ERROR_DLL_MIGHT_BE_INSECURE"; else if (i_error==687L) risultato="ERROR_DLL_MIGHT_BE_INCOMPATIBLE"; else if (i_error==688L) risultato="ERROR_DBG_EXCEPTION_NOT_HANDLED"; else if (i_error==689L) risultato="ERROR_DBG_REPLY_LATER"; else if (i_error==690L) risultato="ERROR_DBG_UNABLE_TO_PROVIDE_HANDLE"; else if (i_error==691L) risultato="ERROR_DBG_TERMINATE_THREAD"; else if (i_error==692L) risultato="ERROR_DBG_TERMINATE_PROCESS"; else if (i_error==693L) risultato="ERROR_DBG_CONTROL_C"; else if (i_error==694L) risultato="ERROR_DBG_PRINTEXCEPTION_C"; else if (i_error==695L) risultato="ERROR_DBG_RIPEXCEPTION"; else if (i_error==696L) risultato="ERROR_DBG_CONTROL_BREAK"; else if (i_error==697L) risultato="ERROR_DBG_COMMAND_EXCEPTION"; else if (i_error==698L) risultato="ERROR_OBJECT_NAME_EXISTS"; else if (i_error==699L) risultato="ERROR_THREAD_WAS_SUSPENDED"; else if (i_error==700L) risultato="ERROR_IMAGE_NOT_AT_BASE"; else if (i_error==701L) risultato="ERROR_RXACT_STATE_CREATED"; else if (i_error==702L) risultato="ERROR_SEGMENT_NOTIFICATION"; else if (i_error==703L) risultato="ERROR_BAD_CURRENT_DIRECTORY"; else if (i_error==704L) risultato="ERROR_FT_READ_RECOVERY_FROM_BACKUP"; else if (i_error==705L) risultato="ERROR_FT_WRITE_RECOVERY"; else if (i_error==706L) risultato="ERROR_IMAGE_MACHINE_TYPE_MISMATCH"; else if (i_error==707L) risultato="ERROR_RECEIVE_PARTIAL"; else if (i_error==708L) risultato="ERROR_RECEIVE_EXPEDITED"; else if (i_error==709L) risultato="ERROR_RECEIVE_PARTIAL_EXPEDITED"; else if (i_error==710L) risultato="ERROR_EVENT_DONE"; else if (i_error==711L) risultato="ERROR_EVENT_PENDING"; else if (i_error==712L) risultato="ERROR_CHECKING_FILE_SYSTEM"; else if (i_error==713L) risultato="ERROR_FATAL_APP_EXIT"; else if (i_error==714L) risultato="ERROR_PREDEFINED_HANDLE"; else if (i_error==715L) risultato="ERROR_WAS_UNLOCKED"; else if (i_error==716L) risultato="ERROR_SERVICE_NOTIFICATION"; else if (i_error==717L) risultato="ERROR_WAS_LOCKED"; else if (i_error==718L) risultato="ERROR_LOG_HARD_ERROR"; else if (i_error==719L) risultato="ERROR_ALREADY_WIN32"; else if (i_error==720L) risultato="ERROR_IMAGE_MACHINE_TYPE_MISMATCH_EXE"; else if (i_error==721L) risultato="ERROR_NO_YIELD_PERFORMED"; else if (i_error==722L) risultato="ERROR_TIMER_RESUME_IGNORED"; else if (i_error==723L) risultato="ERROR_ARBITRATION_UNHANDLED"; else if (i_error==724L) risultato="ERROR_CARDBUS_NOT_SUPPORTED"; else if (i_error==725L) risultato="ERROR_MP_PROCESSOR_MISMATCH"; else if (i_error==726L) risultato="ERROR_HIBERNATED"; else if (i_error==727L) risultato="ERROR_RESUME_HIBERNATION"; else if (i_error==728L) risultato="ERROR_FIRMWARE_UPDATED"; else if (i_error==729L) risultato="ERROR_DRIVERS_LEAKING_LOCKED_PAGES"; else if (i_error==730L) risultato="ERROR_WAKE_SYSTEM"; else if (i_error==731L) risultato="ERROR_WAIT_1"; else if (i_error==732L) risultato="ERROR_WAIT_2"; else if (i_error==733L) risultato="ERROR_WAIT_3"; else if (i_error==734L) risultato="ERROR_WAIT_63"; else if (i_error==735L) risultato="ERROR_ABANDONED_WAIT_0"; else if (i_error==736L) risultato="ERROR_ABANDONED_WAIT_63"; else if (i_error==737L) risultato="ERROR_USER_APC"; else if (i_error==738L) risultato="ERROR_KERNEL_APC"; else if (i_error==739L) risultato="ERROR_ALERTED"; else if (i_error==740L) risultato="ERROR_ELEVATION_REQUIRED"; else if (i_error==741L) risultato="ERROR_REPARSE"; else if (i_error==742L) risultato="ERROR_OPLOCK_BREAK_IN_PROGRESS"; else if (i_error==743L) risultato="ERROR_VOLUME_MOUNTED"; else if (i_error==744L) risultato="ERROR_RXACT_COMMITTED"; else if (i_error==745L) risultato="ERROR_NOTIFY_CLEANUP"; else if (i_error==746L) risultato="ERROR_PRIMARY_TRANSPORT_CONNECT_FAILED"; else if (i_error==747L) risultato="ERROR_PAGE_FAULT_TRANSITION"; else if (i_error==748L) risultato="ERROR_PAGE_FAULT_DEMAND_ZERO"; else if (i_error==749L) risultato="ERROR_PAGE_FAULT_COPY_ON_WRITE"; else if (i_error==750L) risultato="ERROR_PAGE_FAULT_GUARD_PAGE"; else if (i_error==751L) risultato="ERROR_PAGE_FAULT_PAGING_FILE"; else if (i_error==752L) risultato="ERROR_CACHE_PAGE_LOCKED"; else if (i_error==753L) risultato="ERROR_CRASH_DUMP"; else if (i_error==754L) risultato="ERROR_BUFFER_ALL_ZEROS"; else if (i_error==755L) risultato="ERROR_REPARSE_OBJECT"; else if (i_error==756L) risultato="ERROR_RESOURCE_REQUIREMENTS_CHANGED"; else if (i_error==757L) risultato="ERROR_TRANSLATION_COMPLETE"; else if (i_error==758L) risultato="ERROR_NOTHING_TO_TERMINATE"; else if (i_error==759L) risultato="ERROR_PROCESS_NOT_IN_JOB"; else if (i_error==760L) risultato="ERROR_PROCESS_IN_JOB"; else if (i_error==761L) risultato="ERROR_VOLSNAP_HIBERNATE_READY"; else if (i_error==762L) risultato="ERROR_FSFILTER_OP_COMPLETED_SUCCESSFULLY"; else if (i_error==763L) risultato="ERROR_INTERRUPT_VECTOR_ALREADY_CONNECTED"; else if (i_error==764L) risultato="ERROR_INTERRUPT_STILL_CONNECTED"; else if (i_error==765L) risultato="ERROR_WAIT_FOR_OPLOCK"; else if (i_error==766L) risultato="ERROR_DBG_EXCEPTION_HANDLED"; else if (i_error==767L) risultato="ERROR_DBG_CONTINUE"; else if (i_error==768L) risultato="ERROR_CALLBACK_POP_STACK"; else if (i_error==769L) risultato="ERROR_COMPRESSION_DISABLED"; else if (i_error==770L) risultato="ERROR_CANTFETCHBACKWARDS"; else if (i_error==771L) risultato="ERROR_CANTSCROLLBACKWARDS"; else if (i_error==772L) risultato="ERROR_ROWSNOTRELEASED"; else if (i_error==773L) risultato="ERROR_BAD_ACCESSOR_FLAGS"; else if (i_error==774L) risultato="ERROR_ERRORS_ENCOUNTERED"; else if (i_error==775L) risultato="ERROR_NOT_CAPABLE"; else if (i_error==776L) risultato="ERROR_REQUEST_OUT_OF_SEQUENCE"; else if (i_error==777L) risultato="ERROR_VERSION_PARSE_ERROR"; else if (i_error==778L) risultato="ERROR_BADSTARTPOSITION"; else if (i_error==779L) risultato="ERROR_MEMORY_HARDWARE"; else if (i_error==780L) risultato="ERROR_DISK_REPAIR_DISABLED"; else if (i_error==781L) risultato="ERROR_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE"; else if (i_error==782L) risultato="ERROR_SYSTEM_POWERSTATE_TRANSITION"; else if (i_error==783L) risultato="ERROR_SYSTEM_POWERSTATE_COMPLEX_TRANSITION"; else if (i_error==784L) risultato="ERROR_MCA_EXCEPTION"; else if (i_error==785L) risultato="ERROR_ACCESS_AUDIT_BY_POLICY"; else if (i_error==786L) risultato="ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY"; else if (i_error==787L) risultato="ERROR_ABANDON_HIBERFILE"; else if (i_error==788L) risultato="ERROR_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED"; else if (i_error==789L) risultato="ERROR_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR"; else if (i_error==790L) risultato="ERROR_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR"; else if (i_error==791L) risultato="ERROR_BAD_MCFG_TABLE"; else if (i_error==792L) risultato="ERROR_DISK_REPAIR_REDIRECTED"; else if (i_error==793L) risultato="ERROR_DISK_REPAIR_UNSUCCESSFUL"; else if (i_error==794L) risultato="ERROR_CORRUPT_LOG_OVERFULL"; else if (i_error==795L) risultato="ERROR_CORRUPT_LOG_CORRUPTED"; else if (i_error==796L) risultato="ERROR_CORRUPT_LOG_UNAVAILABLE"; else if (i_error==797L) risultato="ERROR_CORRUPT_LOG_DELETED_FULL"; else if (i_error==798L) risultato="ERROR_CORRUPT_LOG_CLEARED"; else if (i_error==799L) risultato="ERROR_ORPHAN_NAME_EXHAUSTED"; else if (i_error==800L) risultato="ERROR_OPLOCK_SWITCHED_TO_NEW_HANDLE"; else if (i_error==801L) risultato="ERROR_CANNOT_GRANT_REQUESTED_OPLOCK"; else if (i_error==802L) risultato="ERROR_CANNOT_BREAK_OPLOCK"; else if (i_error==803L) risultato="ERROR_OPLOCK_HANDLE_CLOSED"; else if (i_error==804L) risultato="ERROR_NO_ACE_CONDITION"; else if (i_error==805L) risultato="ERROR_INVALID_ACE_CONDITION"; else if (i_error==806L) risultato="ERROR_FILE_HANDLE_REVOKED"; else if (i_error==807L) risultato="ERROR_IMAGE_AT_DIFFERENT_BASE"; else if (i_error==808L) risultato="ERROR_ENCRYPTED_IO_NOT_POSSIBLE"; else if (i_error==809L) risultato="ERROR_FILE_METADATA_OPTIMIZATION_IN_PROGRESS"; else if (i_error==810L) risultato="ERROR_QUOTA_ACTIVITY"; else if (i_error==811L) risultato="ERROR_HANDLE_REVOKED"; else if (i_error==812L) risultato="ERROR_CALLBACK_INVOKE_INLINE"; else if (i_error==813L) risultato="ERROR_CPU_SET_INVALID"; else if (i_error==994L) risultato="ERROR_EA_ACCESS_DENIED"; else if (i_error==995L) risultato="ERROR_OPERATION_ABORTED"; else if (i_error==996L) risultato="ERROR_IO_INCOMPLETE"; else if (i_error==997L) risultato="ERROR_IO_PENDING"; else if (i_error==998L) risultato="ERROR_NOACCESS"; else if (i_error==999L) risultato="ERROR_SWAPERROR"; else if (i_error==1001L) risultato="ERROR_STACK_OVERFLOW"; else if (i_error==1002L) risultato="ERROR_INVALID_MESSAGE"; else if (i_error==1003L) risultato="ERROR_CAN_NOT_COMPLETE"; else if (i_error==1004L) risultato="ERROR_INVALID_FLAGS"; else if (i_error==1005L) risultato="ERROR_UNRECOGNIZED_VOLUME"; else if (i_error==1006L) risultato="ERROR_FILE_INVALID"; else if (i_error==1007L) risultato="ERROR_FULLSCREEN_MODE"; else if (i_error==1008L) risultato="ERROR_NO_TOKEN"; else if (i_error==1009L) risultato="ERROR_BADDB"; else if (i_error==1010L) risultato="ERROR_BADKEY"; else if (i_error==1011L) risultato="ERROR_CANTOPEN"; else if (i_error==1012L) risultato="ERROR_CANTREAD"; else if (i_error==1013L) risultato="ERROR_CANTWRITE"; else if (i_error==1014L) risultato="ERROR_REGISTRY_RECOVERED"; else if (i_error==1015L) risultato="ERROR_REGISTRY_CORRUPT"; else if (i_error==1016L) risultato="ERROR_REGISTRY_IO_FAILED"; else if (i_error==1017L) risultato="ERROR_NOT_REGISTRY_FILE"; else if (i_error==1018L) risultato="ERROR_KEY_DELETED"; else if (i_error==1019L) risultato="ERROR_NO_LOG_SPACE"; else if (i_error==1020L) risultato="ERROR_KEY_HAS_CHILDREN"; else if (i_error==1021L) risultato="ERROR_CHILD_MUST_BE_VOLATILE"; else if (i_error==1022L) risultato="ERROR_NOTIFY_ENUM_DIR"; else if (i_error==1051L) risultato="ERROR_DEPENDENT_SERVICES_RUNNING"; else if (i_error==1052L) risultato="ERROR_INVALID_SERVICE_CONTROL"; else if (i_error==1053L) risultato="ERROR_SERVICE_REQUEST_TIMEOUT"; else if (i_error==1054L) risultato="ERROR_SERVICE_NO_THREAD"; else if (i_error==1055L) risultato="ERROR_SERVICE_DATABASE_LOCKED"; else if (i_error==1056L) risultato="ERROR_SERVICE_ALREADY_RUNNING"; else if (i_error==1057L) risultato="ERROR_INVALID_SERVICE_ACCOUNT"; else if (i_error==1058L) risultato="ERROR_SERVICE_DISABLED"; else if (i_error==1059L) risultato="ERROR_CIRCULAR_DEPENDENCY"; else if (i_error==1060L) risultato="ERROR_SERVICE_DOES_NOT_EXIST"; else if (i_error==1061L) risultato="ERROR_SERVICE_CANNOT_ACCEPT_CTRL"; else if (i_error==1062L) risultato="ERROR_SERVICE_NOT_ACTIVE"; else if (i_error==1063L) risultato="ERROR_FAILED_SERVICE_CONTROLLER_CONNECT"; else if (i_error==1064L) risultato="ERROR_EXCEPTION_IN_SERVICE"; else if (i_error==1065L) risultato="ERROR_DATABASE_DOES_NOT_EXIST"; else if (i_error==1066L) risultato="ERROR_SERVICE_SPECIFIC_ERROR"; else if (i_error==1067L) risultato="ERROR_PROCESS_ABORTED"; else if (i_error==1068L) risultato="ERROR_SERVICE_DEPENDENCY_FAIL"; else if (i_error==1069L) risultato="ERROR_SERVICE_LOGON_FAILED"; else if (i_error==1070L) risultato="ERROR_SERVICE_START_HANG"; else if (i_error==1071L) risultato="ERROR_INVALID_SERVICE_LOCK"; else if (i_error==1072L) risultato="ERROR_SERVICE_MARKED_FOR_DELETE"; else if (i_error==1073L) risultato="ERROR_SERVICE_EXISTS"; else if (i_error==1074L) risultato="ERROR_ALREADY_RUNNING_LKG"; else if (i_error==1075L) risultato="ERROR_SERVICE_DEPENDENCY_DELETED"; else if (i_error==1076L) risultato="ERROR_BOOT_ALREADY_ACCEPTED"; else if (i_error==1077L) risultato="ERROR_SERVICE_NEVER_STARTED"; else if (i_error==1078L) risultato="ERROR_DUPLICATE_SERVICE_NAME"; else if (i_error==1079L) risultato="ERROR_DIFFERENT_SERVICE_ACCOUNT"; else if (i_error==1080L) risultato="ERROR_CANNOT_DETECT_DRIVER_FAILURE"; else if (i_error==1081L) risultato="ERROR_CANNOT_DETECT_PROCESS_ABORT"; else if (i_error==1082L) risultato="ERROR_NO_RECOVERY_PROGRAM"; else if (i_error==1083L) risultato="ERROR_SERVICE_NOT_IN_EXE"; else if (i_error==1084L) risultato="ERROR_NOT_SAFEBOOT_SERVICE"; else if (i_error==1100L) risultato="ERROR_END_OF_MEDIA"; else if (i_error==1101L) risultato="ERROR_FILEMARK_DETECTED"; else if (i_error==1102L) risultato="ERROR_BEGINNING_OF_MEDIA"; else if (i_error==1103L) risultato="ERROR_SETMARK_DETECTED"; else if (i_error==1104L) risultato="ERROR_NO_DATA_DETECTED"; else if (i_error==1105L) risultato="ERROR_PARTITION_FAILURE"; else if (i_error==1106L) risultato="ERROR_INVALID_BLOCK_LENGTH"; else if (i_error==1107L) risultato="ERROR_DEVICE_NOT_PARTITIONED"; else if (i_error==1108L) risultato="ERROR_UNABLE_TO_LOCK_MEDIA"; else if (i_error==1109L) risultato="ERROR_UNABLE_TO_UNLOAD_MEDIA"; else if (i_error==1110L) risultato="ERROR_MEDIA_CHANGED"; else if (i_error==1111L) risultato="ERROR_BUS_RESET"; else if (i_error==1112L) risultato="ERROR_NO_MEDIA_IN_DRIVE"; else if (i_error==1113L) risultato="ERROR_NO_UNICODE_TRANSLATION"; else if (i_error==1114L) risultato="ERROR_DLL_INIT_FAILED"; else if (i_error==1115L) risultato="ERROR_SHUTDOWN_IN_PROGRESS"; else if (i_error==1116L) risultato="ERROR_NO_SHUTDOWN_IN_PROGRESS"; else if (i_error==1117L) risultato="ERROR_IO_DEVICE"; else if (i_error==1118L) risultato="ERROR_SERIAL_NO_DEVICE"; else if (i_error==1119L) risultato="ERROR_IRQ_BUSY"; else if (i_error==1120L) risultato="ERROR_MORE_WRITES"; else if (i_error==1121L) risultato="ERROR_COUNTER_TIMEOUT"; else if (i_error==1122L) risultato="ERROR_FLOPPY_ID_MARK_NOT_FOUND"; else if (i_error==1123L) risultato="ERROR_FLOPPY_WRONG_CYLINDER"; else if (i_error==1124L) risultato="ERROR_FLOPPY_UNKNOWN_ERROR"; else if (i_error==1125L) risultato="ERROR_FLOPPY_BAD_REGISTERS"; else if (i_error==1126L) risultato="ERROR_DISK_RECALIBRATE_FAILED"; else if (i_error==1127L) risultato="ERROR_DISK_OPERATION_FAILED"; else if (i_error==1128L) risultato="ERROR_DISK_RESET_FAILED"; else if (i_error==1129L) risultato="ERROR_EOM_OVERFLOW"; else if (i_error==1130L) risultato="ERROR_NOT_ENOUGH_SERVER_MEMORY"; else if (i_error==1131L) risultato="ERROR_POSSIBLE_DEADLOCK"; else if (i_error==1132L) risultato="ERROR_MAPPED_ALIGNMENT"; else if (i_error==1140L) risultato="ERROR_SET_POWER_STATE_VETOED"; else if (i_error==1141L) risultato="ERROR_SET_POWER_STATE_FAILED"; else if (i_error==1142L) risultato="ERROR_TOO_MANY_LINKS"; else if (i_error==1150L) risultato="ERROR_OLD_WIN_VERSION"; else if (i_error==1151L) risultato="ERROR_APP_WRONG_OS"; else if (i_error==1152L) risultato="ERROR_SINGLE_INSTANCE_APP"; else if (i_error==1153L) risultato="ERROR_RMODE_APP"; else if (i_error==1154L) risultato="ERROR_INVALID_DLL"; else if (i_error==1155L) risultato="ERROR_NO_ASSOCIATION"; else if (i_error==1156L) risultato="ERROR_DDE_FAIL"; else if (i_error==1157L) risultato="ERROR_DLL_NOT_FOUND"; else if (i_error==1158L) risultato="ERROR_NO_MORE_USER_HANDLES"; else if (i_error==1159L) risultato="ERROR_MESSAGE_SYNC_ONLY"; else if (i_error==1160L) risultato="ERROR_SOURCE_ELEMENT_EMPTY"; else if (i_error==1161L) risultato="ERROR_DESTINATION_ELEMENT_FULL"; else if (i_error==1162L) risultato="ERROR_ILLEGAL_ELEMENT_ADDRESS"; else if (i_error==1163L) risultato="ERROR_MAGAZINE_NOT_PRESENT"; else if (i_error==1164L) risultato="ERROR_DEVICE_REINITIALIZATION_NEEDED"; else if (i_error==1165L) risultato="ERROR_DEVICE_REQUIRES_CLEANING"; else if (i_error==1166L) risultato="ERROR_DEVICE_DOOR_OPEN"; else if (i_error==1167L) risultato="ERROR_DEVICE_NOT_CONNECTED"; else if (i_error==1168L) risultato="ERROR_NOT_FOUND"; else if (i_error==1169L) risultato="ERROR_NO_MATCH"; else if (i_error==1170L) risultato="ERROR_SET_NOT_FOUND"; else if (i_error==1171L) risultato="ERROR_POINT_NOT_FOUND"; else if (i_error==1172L) risultato="ERROR_NO_TRACKING_SERVICE"; else if (i_error==1173L) risultato="ERROR_NO_VOLUME_ID"; else if (i_error==1175L) risultato="ERROR_UNABLE_TO_REMOVE_REPLACED"; else if (i_error==1176L) risultato="ERROR_UNABLE_TO_MOVE_REPLACEMENT"; else if (i_error==1177L) risultato="ERROR_UNABLE_TO_MOVE_REPLACEMENT_2"; else if (i_error==1178L) risultato="ERROR_JOURNAL_DELETE_IN_PROGRESS"; else if (i_error==1179L) risultato="ERROR_JOURNAL_NOT_ACTIVE"; else if (i_error==1180L) risultato="ERROR_POTENTIAL_FILE_FOUND"; else if (i_error==1181L) risultato="ERROR_JOURNAL_ENTRY_DELETED"; else if (i_error==1190L) risultato="ERROR_SHUTDOWN_IS_SCHEDULED"; else if (i_error==1191L) risultato="ERROR_SHUTDOWN_USERS_LOGGED_ON"; else if (i_error==1200L) risultato="ERROR_BAD_DEVICE"; else if (i_error==1201L) risultato="ERROR_CONNECTION_UNAVAIL"; else if (i_error==1202L) risultato="ERROR_DEVICE_ALREADY_REMEMBERED"; else if (i_error==1203L) risultato="ERROR_NO_NET_OR_BAD_PATH"; else if (i_error==1204L) risultato="ERROR_BAD_PROVIDER"; else if (i_error==1205L) risultato="ERROR_CANNOT_OPEN_PROFILE"; else if (i_error==1206L) risultato="ERROR_BAD_PROFILE"; else if (i_error==1207L) risultato="ERROR_NOT_CONTAINER"; else if (i_error==1208L) risultato="ERROR_EXTENDED_ERROR"; else if (i_error==1209L) risultato="ERROR_INVALID_GROUPNAME"; else if (i_error==1210L) risultato="ERROR_INVALID_COMPUTERNAME"; else if (i_error==1211L) risultato="ERROR_INVALID_EVENTNAME"; else if (i_error==1212L) risultato="ERROR_INVALID_DOMAINNAME"; else if (i_error==1213L) risultato="ERROR_INVALID_SERVICENAME"; else if (i_error==1214L) risultato="ERROR_INVALID_NETNAME"; else if (i_error==1215L) risultato="ERROR_INVALID_SHARENAME"; else if (i_error==1216L) risultato="ERROR_INVALID_PASSWORDNAME"; else if (i_error==1217L) risultato="ERROR_INVALID_MESSAGENAME"; else if (i_error==1218L) risultato="ERROR_INVALID_MESSAGEDEST"; else if (i_error==1219L) risultato="ERROR_SESSION_CREDENTIAL_CONFLICT"; else if (i_error==1220L) risultato="ERROR_REMOTE_SESSION_LIMIT_EXCEEDED"; else if (i_error==1221L) risultato="ERROR_DUP_DOMAINNAME"; else if (i_error==1222L) risultato="ERROR_NO_NETWORK"; else if (i_error==1223L) risultato="ERROR_CANCELLED"; else if (i_error==1224L) risultato="ERROR_USER_MAPPED_FILE"; else if (i_error==1225L) risultato="ERROR_CONNECTION_REFUSED"; else if (i_error==1226L) risultato="ERROR_GRACEFUL_DISCONNECT"; else if (i_error==1227L) risultato="ERROR_ADDRESS_ALREADY_ASSOCIATED"; else if (i_error==1228L) risultato="ERROR_ADDRESS_NOT_ASSOCIATED"; else if (i_error==1229L) risultato="ERROR_CONNECTION_INVALID"; else if (i_error==1230L) risultato="ERROR_CONNECTION_ACTIVE"; else if (i_error==1231L) risultato="ERROR_NETWORK_UNREACHABLE"; else if (i_error==1232L) risultato="ERROR_HOST_UNREACHABLE"; else if (i_error==1233L) risultato="ERROR_PROTOCOL_UNREACHABLE"; else if (i_error==1234L) risultato="ERROR_PORT_UNREACHABLE"; else if (i_error==1235L) risultato="ERROR_REQUEST_ABORTED"; else if (i_error==1236L) risultato="ERROR_CONNECTION_ABORTED"; else if (i_error==1237L) risultato="ERROR_RETRY"; else if (i_error==1238L) risultato="ERROR_CONNECTION_COUNT_LIMIT"; else if (i_error==1239L) risultato="ERROR_LOGIN_TIME_RESTRICTION"; else if (i_error==1240L) risultato="ERROR_LOGIN_WKSTA_RESTRICTION"; else if (i_error==1241L) risultato="ERROR_INCORRECT_ADDRESS"; else if (i_error==1242L) risultato="ERROR_ALREADY_REGISTERED"; else if (i_error==1243L) risultato="ERROR_SERVICE_NOT_FOUND"; else if (i_error==1244L) risultato="ERROR_NOT_AUTHENTICATED"; else if (i_error==1245L) risultato="ERROR_NOT_LOGGED_ON"; else if (i_error==1246L) risultato="ERROR_CONTINUE"; else if (i_error==1247L) risultato="ERROR_ALREADY_INITIALIZED"; else if (i_error==1248L) risultato="ERROR_NO_MORE_DEVICES"; else if (i_error==1249L) risultato="ERROR_NO_SUCH_SITE"; else if (i_error==1250L) risultato="ERROR_DOMAIN_CONTROLLER_EXISTS"; else if (i_error==1251L) risultato="ERROR_ONLY_IF_CONNECTED"; else if (i_error==1252L) risultato="ERROR_OVERRIDE_NOCHANGES"; else if (i_error==1253L) risultato="ERROR_BAD_USER_PROFILE"; else if (i_error==1254L) risultato="ERROR_NOT_SUPPORTED_ON_SBS"; else if (i_error==1255L) risultato="ERROR_SERVER_SHUTDOWN_IN_PROGRESS"; else if (i_error==1256L) risultato="ERROR_HOST_DOWN"; else if (i_error==1257L) risultato="ERROR_NON_ACCOUNT_SID"; else if (i_error==1258L) risultato="ERROR_NON_DOMAIN_SID"; else if (i_error==1259L) risultato="ERROR_APPHELP_BLOCK"; else if (i_error==1260L) risultato="ERROR_ACCESS_DISABLED_BY_POLICY"; else if (i_error==1261L) risultato="ERROR_REG_NAT_CONSUMPTION"; else if (i_error==1262L) risultato="ERROR_CSCSHARE_OFFLINE"; else if (i_error==1263L) risultato="ERROR_PKINIT_FAILURE"; else if (i_error==1264L) risultato="ERROR_SMARTCARD_SUBSYSTEM_FAILURE"; else if (i_error==1265L) risultato="ERROR_DOWNGRADE_DETECTED"; else if (i_error==1271L) risultato="ERROR_MACHINE_LOCKED"; else if (i_error==1272L) risultato="ERROR_SMB_GUEST_LOGON_BLOCKED"; else if (i_error==1273L) risultato="ERROR_CALLBACK_SUPPLIED_INVALID_DATA"; else if (i_error==1274L) risultato="ERROR_SYNC_FOREGROUND_REFRESH_REQUIRED"; else if (i_error==1275L) risultato="ERROR_DRIVER_BLOCKED"; else if (i_error==1276L) risultato="ERROR_INVALID_IMPORT_OF_NON_DLL"; else if (i_error==1277L) risultato="ERROR_ACCESS_DISABLED_WEBBLADE"; else if (i_error==1278L) risultato="ERROR_ACCESS_DISABLED_WEBBLADE_TAMPER"; else if (i_error==1279L) risultato="ERROR_RECOVERY_FAILURE"; else if (i_error==1280L) risultato="ERROR_ALREADY_FIBER"; else if (i_error==1281L) risultato="ERROR_ALREADY_THREAD"; else if (i_error==1282L) risultato="ERROR_STACK_BUFFER_OVERRUN"; else if (i_error==1283L) risultato="ERROR_PARAMETER_QUOTA_EXCEEDED"; else if (i_error==1284L) risultato="ERROR_DEBUGGER_INACTIVE"; else if (i_error==1285L) risultato="ERROR_DELAY_LOAD_FAILED"; else if (i_error==1286L) risultato="ERROR_VDM_DISALLOWED"; else if (i_error==1287L) risultato="ERROR_UNIDENTIFIED_ERROR"; else if (i_error==1288L) risultato="ERROR_INVALID_CRUNTIME_PARAMETER"; else if (i_error==1289L) risultato="ERROR_BEYOND_VDL"; else if (i_error==1290L) risultato="ERROR_INCOMPATIBLE_SERVICE_SID_TYPE"; else if (i_error==1291L) risultato="ERROR_DRIVER_PROCESS_TERMINATED"; else if (i_error==1292L) risultato="ERROR_IMPLEMENTATION_LIMIT"; else if (i_error==1293L) risultato="ERROR_PROCESS_IS_PROTECTED"; else if (i_error==1294L) risultato="ERROR_SERVICE_NOTIFY_CLIENT_LAGGING"; else if (i_error==1295L) risultato="ERROR_DISK_QUOTA_EXCEEDED"; else if (i_error==1296L) risultato="ERROR_CONTENT_BLOCKED"; else if (i_error==1297L) risultato="ERROR_INCOMPATIBLE_SERVICE_PRIVILEGE"; else if (i_error==1298L) risultato="ERROR_APP_HANG"; else if (i_error==1299L) risultato="ERROR_INVALID_LABEL"; else if (i_error==1300L) risultato="ERROR_NOT_ALL_ASSIGNED"; else if (i_error==1301L) risultato="ERROR_SOME_NOT_MAPPED"; else if (i_error==1302L) risultato="ERROR_NO_QUOTAS_FOR_ACCOUNT"; else if (i_error==1303L) risultato="ERROR_LOCAL_USER_SESSION_KEY"; else if (i_error==1304L) risultato="ERROR_NULL_LM_PASSWORD"; else if (i_error==1305L) risultato="ERROR_UNKNOWN_REVISION"; else if (i_error==1306L) risultato="ERROR_REVISION_MISMATCH"; else if (i_error==1307L) risultato="ERROR_INVALID_OWNER"; else if (i_error==1308L) risultato="ERROR_INVALID_PRIMARY_GROUP"; else if (i_error==1309L) risultato="ERROR_NO_IMPERSONATION_TOKEN"; else if (i_error==1310L) risultato="ERROR_CANT_DISABLE_MANDATORY"; else if (i_error==1311L) risultato="ERROR_NO_LOGON_SERVERS"; else if (i_error==1312L) risultato="ERROR_NO_SUCH_LOGON_SESSION"; else if (i_error==1313L) risultato="ERROR_NO_SUCH_PRIVILEGE"; else if (i_error==1314L) risultato="ERROR_PRIVILEGE_NOT_HELD"; else if (i_error==1315L) risultato="ERROR_INVALID_ACCOUNT_NAME"; else if (i_error==1316L) risultato="ERROR_USER_EXISTS"; else if (i_error==1317L) risultato="ERROR_NO_SUCH_USER"; else if (i_error==1318L) risultato="ERROR_GROUP_EXISTS"; else if (i_error==1319L) risultato="ERROR_NO_SUCH_GROUP"; else if (i_error==1320L) risultato="ERROR_MEMBER_IN_GROUP"; else if (i_error==1321L) risultato="ERROR_MEMBER_NOT_IN_GROUP"; else if (i_error==1322L) risultato="ERROR_LAST_ADMIN"; else if (i_error==1323L) risultato="ERROR_WRONG_PASSWORD"; else if (i_error==1324L) risultato="ERROR_ILL_FORMED_PASSWORD"; else if (i_error==1325L) risultato="ERROR_PASSWORD_RESTRICTION"; else if (i_error==1326L) risultato="ERROR_LOGON_FAILURE"; else if (i_error==1327L) risultato="ERROR_ACCOUNT_RESTRICTION"; else if (i_error==1328L) risultato="ERROR_INVALID_LOGON_HOURS"; else if (i_error==1329L) risultato="ERROR_INVALID_WORKSTATION"; else if (i_error==1330L) risultato="ERROR_PASSWORD_EXPIRED"; else if (i_error==1331L) risultato="ERROR_ACCOUNT_DISABLED"; else if (i_error==1332L) risultato="ERROR_NONE_MAPPED"; else if (i_error==1333L) risultato="ERROR_TOO_MANY_LUIDS_REQUESTED"; else if (i_error==1334L) risultato="ERROR_LUIDS_EXHAUSTED"; else if (i_error==1335L) risultato="ERROR_INVALID_SUB_AUTHORITY"; else if (i_error==1336L) risultato="ERROR_INVALID_ACL"; else if (i_error==1337L) risultato="ERROR_INVALID_SID"; else if (i_error==1338L) risultato="ERROR_INVALID_SECURITY_DESCR"; else if (i_error==1340L) risultato="ERROR_BAD_INHERITANCE_ACL"; else if (i_error==1341L) risultato="ERROR_SERVER_DISABLED"; else if (i_error==1342L) risultato="ERROR_SERVER_NOT_DISABLED"; else if (i_error==1343L) risultato="ERROR_INVALID_ID_AUTHORITY"; else if (i_error==1344L) risultato="ERROR_ALLOTTED_SPACE_EXCEEDED"; else if (i_error==1345L) risultato="ERROR_INVALID_GROUP_ATTRIBUTES"; else if (i_error==1346L) risultato="ERROR_BAD_IMPERSONATION_LEVEL"; else if (i_error==1347L) risultato="ERROR_CANT_OPEN_ANONYMOUS"; else if (i_error==1348L) risultato="ERROR_BAD_VALIDATION_CLASS"; else if (i_error==1349L) risultato="ERROR_BAD_TOKEN_TYPE"; else if (i_error==1350L) risultato="ERROR_NO_SECURITY_ON_OBJECT"; else if (i_error==1351L) risultato="ERROR_CANT_ACCESS_DOMAIN_INFO"; else if (i_error==1352L) risultato="ERROR_INVALID_SERVER_STATE"; else if (i_error==1353L) risultato="ERROR_INVALID_DOMAIN_STATE"; else if (i_error==1354L) risultato="ERROR_INVALID_DOMAIN_ROLE"; else if (i_error==1355L) risultato="ERROR_NO_SUCH_DOMAIN"; else if (i_error==1356L) risultato="ERROR_DOMAIN_EXISTS"; else if (i_error==1357L) risultato="ERROR_DOMAIN_LIMIT_EXCEEDED"; else if (i_error==1358L) risultato="ERROR_INTERNAL_DB_CORRUPTION"; else if (i_error==1359L) risultato="ERROR_INTERNAL_ERROR"; else if (i_error==1360L) risultato="ERROR_GENERIC_NOT_MAPPED"; else if (i_error==1361L) risultato="ERROR_BAD_DESCRIPTOR_FORMAT"; else if (i_error==1362L) risultato="ERROR_NOT_LOGON_PROCESS"; else if (i_error==1363L) risultato="ERROR_LOGON_SESSION_EXISTS"; else if (i_error==1364L) risultato="ERROR_NO_SUCH_PACKAGE"; else if (i_error==1365L) risultato="ERROR_BAD_LOGON_SESSION_STATE"; else if (i_error==1366L) risultato="ERROR_LOGON_SESSION_COLLISION"; else if (i_error==1367L) risultato="ERROR_INVALID_LOGON_TYPE"; else if (i_error==1368L) risultato="ERROR_CANNOT_IMPERSONATE"; else if (i_error==1369L) risultato="ERROR_RXACT_INVALID_STATE"; else if (i_error==1370L) risultato="ERROR_RXACT_COMMIT_FAILURE"; else if (i_error==1371L) risultato="ERROR_SPECIAL_ACCOUNT"; else if (i_error==1372L) risultato="ERROR_SPECIAL_GROUP"; else if (i_error==1373L) risultato="ERROR_SPECIAL_USER"; else if (i_error==1374L) risultato="ERROR_MEMBERS_PRIMARY_GROUP"; else if (i_error==1375L) risultato="ERROR_TOKEN_ALREADY_IN_USE"; else if (i_error==1376L) risultato="ERROR_NO_SUCH_ALIAS"; else if (i_error==1377L) risultato="ERROR_MEMBER_NOT_IN_ALIAS"; else if (i_error==1378L) risultato="ERROR_MEMBER_IN_ALIAS"; else if (i_error==1379L) risultato="ERROR_ALIAS_EXISTS"; else if (i_error==1380L) risultato="ERROR_LOGON_NOT_GRANTED"; else if (i_error==1381L) risultato="ERROR_TOO_MANY_SECRETS"; else if (i_error==1382L) risultato="ERROR_SECRET_TOO_LONG"; else if (i_error==1383L) risultato="ERROR_INTERNAL_DB_ERROR"; else if (i_error==1384L) risultato="ERROR_TOO_MANY_CONTEXT_IDS"; else if (i_error==1385L) risultato="ERROR_LOGON_TYPE_NOT_GRANTED"; else if (i_error==1386L) risultato="ERROR_NT_CROSS_ENCRYPTION_REQUIRED"; else if (i_error==1387L) risultato="ERROR_NO_SUCH_MEMBER"; else if (i_error==1388L) risultato="ERROR_INVALID_MEMBER"; else if (i_error==1389L) risultato="ERROR_TOO_MANY_SIDS"; else if (i_error==1390L) risultato="ERROR_LM_CROSS_ENCRYPTION_REQUIRED"; else if (i_error==1391L) risultato="ERROR_NO_INHERITANCE"; else if (i_error==1392L) risultato="ERROR_FILE_CORRUPT"; else if (i_error==1393L) risultato="ERROR_DISK_CORRUPT"; else if (i_error==1394L) risultato="ERROR_NO_USER_SESSION_KEY"; else if (i_error==1395L) risultato="ERROR_LICENSE_QUOTA_EXCEEDED"; else if (i_error==1396L) risultato="ERROR_WRONG_TARGET_NAME"; else if (i_error==1397L) risultato="ERROR_MUTUAL_AUTH_FAILED"; else if (i_error==1398L) risultato="ERROR_TIME_SKEW"; else if (i_error==1399L) risultato="ERROR_CURRENT_DOMAIN_NOT_ALLOWED"; else if (i_error==1400L) risultato="ERROR_INVALID_WINDOW_HANDLE"; else if (i_error==1401L) risultato="ERROR_INVALID_MENU_HANDLE"; else if (i_error==1402L) risultato="ERROR_INVALID_CURSOR_HANDLE"; else if (i_error==1403L) risultato="ERROR_INVALID_ACCEL_HANDLE"; else if (i_error==1404L) risultato="ERROR_INVALID_HOOK_HANDLE"; else if (i_error==1405L) risultato="ERROR_INVALID_DWP_HANDLE"; else if (i_error==1406L) risultato="ERROR_TLW_WITH_WSCHILD"; else if (i_error==1407L) risultato="ERROR_CANNOT_FIND_WND_CLASS"; else if (i_error==1408L) risultato="ERROR_WINDOW_OF_OTHER_THREAD"; else if (i_error==1409L) risultato="ERROR_HOTKEY_ALREADY_REGISTERED"; else if (i_error==1410L) risultato="ERROR_CLASS_ALREADY_EXISTS"; else if (i_error==1411L) risultato="ERROR_CLASS_DOES_NOT_EXIST"; else if (i_error==1412L) risultato="ERROR_CLASS_HAS_WINDOWS"; else if (i_error==1413L) risultato="ERROR_INVALID_INDEX"; else if (i_error==1414L) risultato="ERROR_INVALID_ICON_HANDLE"; else if (i_error==1415L) risultato="ERROR_PRIVATE_DIALOG_INDEX"; else if (i_error==1416L) risultato="ERROR_LISTBOX_ID_NOT_FOUND"; else if (i_error==1417L) risultato="ERROR_NO_WILDCARD_CHARACTERS"; else if (i_error==1418L) risultato="ERROR_CLIPBOARD_NOT_OPEN"; else if (i_error==1419L) risultato="ERROR_HOTKEY_NOT_REGISTERED"; else if (i_error==1420L) risultato="ERROR_WINDOW_NOT_DIALOG"; else if (i_error==1421L) risultato="ERROR_CONTROL_ID_NOT_FOUND"; else if (i_error==1422L) risultato="ERROR_INVALID_COMBOBOX_MESSAGE"; else if (i_error==1423L) risultato="ERROR_WINDOW_NOT_COMBOBOX"; else if (i_error==1424L) risultato="ERROR_INVALID_EDIT_HEIGHT"; else if (i_error==1425L) risultato="ERROR_DC_NOT_FOUND"; else if (i_error==1426L) risultato="ERROR_INVALID_HOOK_FILTER"; else if (i_error==1427L) risultato="ERROR_INVALID_FILTER_PROC"; else if (i_error==1428L) risultato="ERROR_HOOK_NEEDS_HMOD"; else if (i_error==1429L) risultato="ERROR_GLOBAL_ONLY_HOOK"; else if (i_error==1430L) risultato="ERROR_JOURNAL_HOOK_SET"; else if (i_error==1431L) risultato="ERROR_HOOK_NOT_INSTALLED"; else if (i_error==1432L) risultato="ERROR_INVALID_LB_MESSAGE"; else if (i_error==1433L) risultato="ERROR_SETCOUNT_ON_BAD_LB"; else if (i_error==1434L) risultato="ERROR_LB_WITHOUT_TABSTOPS"; else if (i_error==1435L) risultato="ERROR_DESTROY_OBJECT_OF_OTHER_THREAD"; else if (i_error==1436L) risultato="ERROR_CHILD_WINDOW_MENU"; else if (i_error==1437L) risultato="ERROR_NO_SYSTEM_MENU"; else if (i_error==1438L) risultato="ERROR_INVALID_MSGBOX_STYLE"; else if (i_error==1439L) risultato="ERROR_INVALID_SPI_VALUE"; else if (i_error==1440L) risultato="ERROR_SCREEN_ALREADY_LOCKED"; else if (i_error==1441L) risultato="ERROR_HWNDS_HAVE_DIFF_PARENT"; else if (i_error==1442L) risultato="ERROR_NOT_CHILD_WINDOW"; else if (i_error==1443L) risultato="ERROR_INVALID_GW_COMMAND"; else if (i_error==1444L) risultato="ERROR_INVALID_THREAD_ID"; else if (i_error==1445L) risultato="ERROR_NON_MDICHILD_WINDOW"; else if (i_error==1446L) risultato="ERROR_POPUP_ALREADY_ACTIVE"; else if (i_error==1447L) risultato="ERROR_NO_SCROLLBARS"; else if (i_error==1448L) risultato="ERROR_INVALID_SCROLLBAR_RANGE"; else if (i_error==1449L) risultato="ERROR_INVALID_SHOWWIN_COMMAND"; else if (i_error==1450L) risultato="ERROR_NO_SYSTEM_RESOURCES"; else if (i_error==1451L) risultato="ERROR_NONPAGED_SYSTEM_RESOURCES"; else if (i_error==1452L) risultato="ERROR_PAGED_SYSTEM_RESOURCES"; else if (i_error==1453L) risultato="ERROR_WORKING_SET_QUOTA"; else if (i_error==1454L) risultato="ERROR_PAGEFILE_QUOTA"; else if (i_error==1455L) risultato="ERROR_COMMITMENT_LIMIT"; else if (i_error==1456L) risultato="ERROR_MENU_ITEM_NOT_FOUND"; else if (i_error==1457L) risultato="ERROR_INVALID_KEYBOARD_HANDLE"; else if (i_error==1458L) risultato="ERROR_HOOK_TYPE_NOT_ALLOWED"; else if (i_error==1459L) risultato="ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION"; else if (i_error==1460L) risultato="ERROR_TIMEOUT"; else if (i_error==1461L) risultato="ERROR_INVALID_MONITOR_HANDLE"; else if (i_error==1462L) risultato="ERROR_INCORRECT_SIZE"; else if (i_error==1463L) risultato="ERROR_SYMLINK_CLASS_DISABLED"; else if (i_error==1464L) risultato="ERROR_SYMLINK_NOT_SUPPORTED"; else if (i_error==1465L) risultato="ERROR_XML_PARSE_ERROR"; else if (i_error==1466L) risultato="ERROR_XMLDSIG_ERROR"; else if (i_error==1467L) risultato="ERROR_RESTART_APPLICATION"; else if (i_error==1468L) risultato="ERROR_WRONG_COMPARTMENT"; else if (i_error==1469L) risultato="ERROR_AUTHIP_FAILURE"; else if (i_error==1470L) risultato="ERROR_NO_NVRAM_RESOURCES"; else if (i_error==1471L) risultato="ERROR_NOT_GUI_PROCESS"; else if (i_error==1500L) risultato="ERROR_EVENTLOG_FILE_CORRUPT"; else if (i_error==1501L) risultato="ERROR_EVENTLOG_CANT_START"; else if (i_error==1502L) risultato="ERROR_LOG_FILE_FULL"; else if (i_error==1503L) risultato="ERROR_EVENTLOG_FILE_CHANGED"; else if (i_error==1504L) risultato="ERROR_CONTAINER_ASSIGNED"; else if (i_error==1505L) risultato="ERROR_JOB_NO_CONTAINER"; else if (i_error==1550L) risultato="ERROR_INVALID_TASK_NAME"; else if (i_error==1551L) risultato="ERROR_INVALID_TASK_INDEX"; else if (i_error==1552L) risultato="ERROR_THREAD_ALREADY_IN_TASK"; else if (i_error==1601L) risultato="ERROR_INSTALL_SERVICE_FAILURE"; else if (i_error==1602L) risultato="ERROR_INSTALL_USEREXIT"; else if (i_error==1603L) risultato="ERROR_INSTALL_FAILURE"; else if (i_error==1604L) risultato="ERROR_INSTALL_SUSPEND"; else if (i_error==1605L) risultato="ERROR_UNKNOWN_PRODUCT"; else if (i_error==1606L) risultato="ERROR_UNKNOWN_FEATURE"; else if (i_error==1607L) risultato="ERROR_UNKNOWN_COMPONENT"; else if (i_error==1608L) risultato="ERROR_UNKNOWN_PROPERTY"; else if (i_error==1609L) risultato="ERROR_INVALID_HANDLE_STATE"; else if (i_error==1610L) risultato="ERROR_BAD_CONFIGURATION"; else if (i_error==1611L) risultato="ERROR_INDEX_ABSENT"; else if (i_error==1612L) risultato="ERROR_INSTALL_SOURCE_ABSENT"; else if (i_error==1613L) risultato="ERROR_INSTALL_PACKAGE_VERSION"; else if (i_error==1614L) risultato="ERROR_PRODUCT_UNINSTALLED"; else if (i_error==1615L) risultato="ERROR_BAD_QUERY_SYNTAX"; else if (i_error==1616L) risultato="ERROR_INVALID_FIELD"; else if (i_error==1617L) risultato="ERROR_DEVICE_REMOVED"; else if (i_error==1618L) risultato="ERROR_INSTALL_ALREADY_RUNNING"; else if (i_error==1619L) risultato="ERROR_INSTALL_PACKAGE_OPEN_FAILED"; else if (i_error==1620L) risultato="ERROR_INSTALL_PACKAGE_INVALID"; else if (i_error==1621L) risultato="ERROR_INSTALL_UI_FAILURE"; else if (i_error==1622L) risultato="ERROR_INSTALL_LOG_FAILURE"; else if (i_error==1623L) risultato="ERROR_INSTALL_LANGUAGE_UNSUPPORTED"; else if (i_error==1624L) risultato="ERROR_INSTALL_TRANSFORM_FAILURE"; else if (i_error==1625L) risultato="ERROR_INSTALL_PACKAGE_REJECTED"; else if (i_error==1626L) risultato="ERROR_FUNCTION_NOT_CALLED"; else if (i_error==1627L) risultato="ERROR_FUNCTION_FAILED"; else if (i_error==1628L) risultato="ERROR_INVALID_TABLE"; else if (i_error==1629L) risultato="ERROR_DATATYPE_MISMATCH"; else if (i_error==1630L) risultato="ERROR_UNSUPPORTED_TYPE"; else if (i_error==1631L) risultato="ERROR_CREATE_FAILED"; else if (i_error==1632L) risultato="ERROR_INSTALL_TEMP_UNWRITABLE"; else if (i_error==1633L) risultato="ERROR_INSTALL_PLATFORM_UNSUPPORTED"; else if (i_error==1634L) risultato="ERROR_INSTALL_NOTUSED"; else if (i_error==1635L) risultato="ERROR_PATCH_PACKAGE_OPEN_FAILED"; else if (i_error==1636L) risultato="ERROR_PATCH_PACKAGE_INVALID"; else if (i_error==1637L) risultato="ERROR_PATCH_PACKAGE_UNSUPPORTED"; else if (i_error==1638L) risultato="ERROR_PRODUCT_VERSION"; else if (i_error==1639L) risultato="ERROR_INVALID_COMMAND_LINE"; else if (i_error==1640L) risultato="ERROR_INSTALL_REMOTE_DISALLOWED"; else if (i_error==1641L) risultato="ERROR_SUCCESS_REBOOT_INITIATED"; else if (i_error==1642L) risultato="ERROR_PATCH_TARGET_NOT_FOUND"; else if (i_error==1643L) risultato="ERROR_PATCH_PACKAGE_REJECTED"; else if (i_error==1644L) risultato="ERROR_INSTALL_TRANSFORM_REJECTED"; else if (i_error==1645L) risultato="ERROR_INSTALL_REMOTE_PROHIBITED"; else if (i_error==1646L) risultato="ERROR_PATCH_REMOVAL_UNSUPPORTED"; else if (i_error==1647L) risultato="ERROR_UNKNOWN_PATCH"; else if (i_error==1648L) risultato="ERROR_PATCH_NO_SEQUENCE"; else if (i_error==1649L) risultato="ERROR_PATCH_REMOVAL_DISALLOWED"; else if (i_error==1650L) risultato="ERROR_INVALID_PATCH_XML"; else if (i_error==1651L) risultato="ERROR_PATCH_MANAGED_ADVERTISED_PRODUCT"; else if (i_error==1652L) risultato="ERROR_INSTALL_SERVICE_SAFEBOOT"; else if (i_error==1653L) risultato="ERROR_FAIL_FAST_EXCEPTION"; else if (i_error==1654L) risultato="ERROR_INSTALL_REJECTED"; else if (i_error==1655L) risultato="ERROR_DYNAMIC_CODE_BLOCKED"; else if (i_error==1656L) risultato="ERROR_NOT_SAME_OBJECT"; else if (i_error==1700L) risultato="RPC_S_INVALID_STRING_BINDING"; else if (i_error==1701L) risultato="RPC_S_WRONG_KIND_OF_BINDING"; else if (i_error==1702L) risultato="RPC_S_INVALID_BINDING"; else if (i_error==1703L) risultato="RPC_S_PROTSEQ_NOT_SUPPORTED"; else if (i_error==1704L) risultato="RPC_S_INVALID_RPC_PROTSEQ"; else if (i_error==1705L) risultato="RPC_S_INVALID_STRING_UUID"; else if (i_error==1706L) risultato="RPC_S_INVALID_ENDPOINT_FORMAT"; else if (i_error==1707L) risultato="RPC_S_INVALID_NET_ADDR"; else if (i_error==1708L) risultato="RPC_S_NO_ENDPOINT_FOUND"; else if (i_error==1709L) risultato="RPC_S_INVALID_TIMEOUT"; else if (i_error==1710L) risultato="RPC_S_OBJECT_NOT_FOUND"; else if (i_error==1711L) risultato="RPC_S_ALREADY_REGISTERED"; else if (i_error==1712L) risultato="RPC_S_TYPE_ALREADY_REGISTERED"; else if (i_error==1713L) risultato="RPC_S_ALREADY_LISTENING"; else if (i_error==1714L) risultato="RPC_S_NO_PROTSEQS_REGISTERED"; else if (i_error==1715L) risultato="RPC_S_NOT_LISTENING"; else if (i_error==1716L) risultato="RPC_S_UNKNOWN_MGR_TYPE"; else if (i_error==1717L) risultato="RPC_S_UNKNOWN_IF"; else if (i_error==1718L) risultato="RPC_S_NO_BINDINGS"; else if (i_error==1719L) risultato="RPC_S_NO_PROTSEQS"; else if (i_error==1720L) risultato="RPC_S_CANT_CREATE_ENDPOINT"; else if (i_error==1721L) risultato="RPC_S_OUT_OF_RESOURCES"; else if (i_error==1722L) risultato="RPC_S_SERVER_UNAVAILABLE"; else if (i_error==1723L) risultato="RPC_S_SERVER_TOO_BUSY"; else if (i_error==1724L) risultato="RPC_S_INVALID_NETWORK_OPTIONS"; else if (i_error==1725L) risultato="RPC_S_NO_CALL_ACTIVE"; else if (i_error==1726L) risultato="RPC_S_CALL_FAILED"; else if (i_error==1727L) risultato="RPC_S_CALL_FAILED_DNE"; else if (i_error==1728L) risultato="RPC_S_PROTOCOL_ERROR"; else if (i_error==1729L) risultato="RPC_S_PROXY_ACCESS_DENIED"; else if (i_error==1730L) risultato="RPC_S_UNSUPPORTED_TRANS_SYN"; else if (i_error==1732L) risultato="RPC_S_UNSUPPORTED_TYPE"; else if (i_error==1733L) risultato="RPC_S_INVALID_TAG"; else if (i_error==1734L) risultato="RPC_S_INVALID_BOUND"; else if (i_error==1735L) risultato="RPC_S_NO_ENTRY_NAME"; else if (i_error==1736L) risultato="RPC_S_INVALID_NAME_SYNTAX"; else if (i_error==1737L) risultato="RPC_S_UNSUPPORTED_NAME_SYNTAX"; else if (i_error==1739L) risultato="RPC_S_UUID_NO_ADDRESS"; else if (i_error==1740L) risultato="RPC_S_DUPLICATE_ENDPOINT"; else if (i_error==1741L) risultato="RPC_S_UNKNOWN_AUTHN_TYPE"; else if (i_error==1742L) risultato="RPC_S_MAX_CALLS_TOO_SMALL"; else if (i_error==1743L) risultato="RPC_S_STRING_TOO_LONG"; else if (i_error==1744L) risultato="RPC_S_PROTSEQ_NOT_FOUND"; else if (i_error==1745L) risultato="RPC_S_PROCNUM_OUT_OF_RANGE"; else if (i_error==1746L) risultato="RPC_S_BINDING_HAS_NO_AUTH"; else if (i_error==1747L) risultato="RPC_S_UNKNOWN_AUTHN_SERVICE"; else if (i_error==1748L) risultato="RPC_S_UNKNOWN_AUTHN_LEVEL"; else if (i_error==1749L) risultato="RPC_S_INVALID_AUTH_IDENTITY"; else if (i_error==1750L) risultato="RPC_S_UNKNOWN_AUTHZ_SERVICE"; else if (i_error==1751L) risultato="EPT_S_INVALID_ENTRY"; else if (i_error==1752L) risultato="EPT_S_CANT_PERFORM_OP"; else if (i_error==1753L) risultato="EPT_S_NOT_REGISTERED"; else if (i_error==1754L) risultato="RPC_S_NOTHING_TO_EXPORT"; else if (i_error==1755L) risultato="RPC_S_INCOMPLETE_NAME"; else if (i_error==1756L) risultato="RPC_S_INVALID_VERS_OPTION"; else if (i_error==1757L) risultato="RPC_S_NO_MORE_MEMBERS"; else if (i_error==1758L) risultato="RPC_S_NOT_ALL_OBJS_UNEXPORTED"; else if (i_error==1759L) risultato="RPC_S_INTERFACE_NOT_FOUND"; else if (i_error==1760L) risultato="RPC_S_ENTRY_ALREADY_EXISTS"; else if (i_error==1761L) risultato="RPC_S_ENTRY_NOT_FOUND"; else if (i_error==1762L) risultato="RPC_S_NAME_SERVICE_UNAVAILABLE"; else if (i_error==1763L) risultato="RPC_S_INVALID_NAF_ID"; else if (i_error==1764L) risultato="RPC_S_CANNOT_SUPPORT"; else if (i_error==1765L) risultato="RPC_S_NO_CONTEXT_AVAILABLE"; else if (i_error==1766L) risultato="RPC_S_INTERNAL_ERROR"; else if (i_error==1767L) risultato="RPC_S_ZERO_DIVIDE"; else if (i_error==1768L) risultato="RPC_S_ADDRESS_ERROR"; else if (i_error==1769L) risultato="RPC_S_FP_DIV_ZERO"; else if (i_error==1770L) risultato="RPC_S_FP_UNDERFLOW"; else if (i_error==1771L) risultato="RPC_S_FP_OVERFLOW"; else if (i_error==1772L) risultato="RPC_X_NO_MORE_ENTRIES"; else if (i_error==1773L) risultato="RPC_X_SS_CHAR_TRANS_OPEN_FAIL"; else if (i_error==1774L) risultato="RPC_X_SS_CHAR_TRANS_SHORT_FILE"; else if (i_error==1775L) risultato="RPC_X_SS_IN_NULL_CONTEXT"; else if (i_error==1777L) risultato="RPC_X_SS_CONTEXT_DAMAGED"; else if (i_error==1778L) risultato="RPC_X_SS_HANDLES_MISMATCH"; else if (i_error==1779L) risultato="RPC_X_SS_CANNOT_GET_CALL_HANDLE"; else if (i_error==1780L) risultato="RPC_X_NULL_REF_POINTER"; else if (i_error==1781L) risultato="RPC_X_ENUM_VALUE_OUT_OF_RANGE"; else if (i_error==1782L) risultato="RPC_X_BYTE_COUNT_TOO_SMALL"; else if (i_error==1783L) risultato="RPC_X_BAD_STUB_DATA"; else if (i_error==1784L) risultato="ERROR_INVALID_USER_BUFFER"; else if (i_error==1785L) risultato="ERROR_UNRECOGNIZED_MEDIA"; else if (i_error==1786L) risultato="ERROR_NO_TRUST_LSA_SECRET"; else if (i_error==1787L) risultato="ERROR_NO_TRUST_SAM_ACCOUNT"; else if (i_error==1788L) risultato="ERROR_TRUSTED_DOMAIN_FAILURE"; else if (i_error==1789L) risultato="ERROR_TRUSTED_RELATIONSHIP_FAILURE"; else if (i_error==1790L) risultato="ERROR_TRUST_FAILURE"; else if (i_error==1791L) risultato="RPC_S_CALL_IN_PROGRESS"; else if (i_error==1792L) risultato="ERROR_NETLOGON_NOT_STARTED"; else if (i_error==1793L) risultato="ERROR_ACCOUNT_EXPIRED"; else if (i_error==1794L) risultato="ERROR_REDIRECTOR_HAS_OPEN_HANDLES"; else if (i_error==1795L) risultato="ERROR_PRINTER_DRIVER_ALREADY_INSTALLED"; else if (i_error==1796L) risultato="ERROR_UNKNOWN_PORT"; else if (i_error==1797L) risultato="ERROR_UNKNOWN_PRINTER_DRIVER"; else if (i_error==1798L) risultato="ERROR_UNKNOWN_PRINTPROCESSOR"; else if (i_error==1799L) risultato="ERROR_INVALID_SEPARATOR_FILE"; else if (i_error==1800L) risultato="ERROR_INVALID_PRIORITY"; else if (i_error==1801L) risultato="ERROR_INVALID_PRINTER_NAME"; else if (i_error==1802L) risultato="ERROR_PRINTER_ALREADY_EXISTS"; else if (i_error==1803L) risultato="ERROR_INVALID_PRINTER_COMMAND"; else if (i_error==1804L) risultato="ERROR_INVALID_DATATYPE"; else if (i_error==1805L) risultato="ERROR_INVALID_ENVIRONMENT"; else if (i_error==1806L) risultato="RPC_S_NO_MORE_BINDINGS"; else if (i_error==1807L) risultato="ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"; else if (i_error==1808L) risultato="ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT"; else if (i_error==1809L) risultato="ERROR_NOLOGON_SERVER_TRUST_ACCOUNT"; else if (i_error==1810L) risultato="ERROR_DOMAIN_TRUST_INCONSISTENT"; else if (i_error==1811L) risultato="ERROR_SERVER_HAS_OPEN_HANDLES"; else if (i_error==1812L) risultato="ERROR_RESOURCE_DATA_NOT_FOUND"; else if (i_error==1813L) risultato="ERROR_RESOURCE_TYPE_NOT_FOUND"; else if (i_error==1814L) risultato="ERROR_RESOURCE_NAME_NOT_FOUND"; else if (i_error==1815L) risultato="ERROR_RESOURCE_LANG_NOT_FOUND"; else if (i_error==1816L) risultato="ERROR_NOT_ENOUGH_QUOTA"; else if (i_error==1817L) risultato="RPC_S_NO_INTERFACES"; else if (i_error==1818L) risultato="RPC_S_CALL_CANCELLED"; else if (i_error==1819L) risultato="RPC_S_BINDING_INCOMPLETE"; else if (i_error==1820L) risultato="RPC_S_COMM_FAILURE"; else if (i_error==1821L) risultato="RPC_S_UNSUPPORTED_AUTHN_LEVEL"; else if (i_error==1822L) risultato="RPC_S_NO_PRINC_NAME"; else if (i_error==1823L) risultato="RPC_S_NOT_RPC_ERROR"; else if (i_error==1824L) risultato="RPC_S_UUID_LOCAL_ONLY"; else if (i_error==1825L) risultato="RPC_S_SEC_PKG_ERROR"; else if (i_error==1826L) risultato="RPC_S_NOT_CANCELLED"; else if (i_error==1827L) risultato="RPC_X_INVALID_ES_ACTION"; else if (i_error==1828L) risultato="RPC_X_WRONG_ES_VERSION"; else if (i_error==1829L) risultato="RPC_X_WRONG_STUB_VERSION"; else if (i_error==1830L) risultato="RPC_X_INVALID_PIPE_OBJECT"; else if (i_error==1831L) risultato="RPC_X_WRONG_PIPE_ORDER"; else if (i_error==1832L) risultato="RPC_X_WRONG_PIPE_VERSION"; else if (i_error==1833L) risultato="RPC_S_COOKIE_AUTH_FAILED"; else if (i_error==1834L) risultato="RPC_S_DO_NOT_DISTURB"; else if (i_error==1835L) risultato="RPC_S_SYSTEM_HANDLE_COUNT_EXCEEDED"; else if (i_error==1836L) risultato="RPC_S_SYSTEM_HANDLE_TYPE_MISMATCH"; else if (i_error==1898L) risultato="RPC_S_GROUP_MEMBER_NOT_FOUND"; else if (i_error==1899L) risultato="EPT_S_CANT_CREATE"; else if (i_error==1900L) risultato="RPC_S_INVALID_OBJECT"; else if (i_error==1901L) risultato="ERROR_INVALID_TIME"; else if (i_error==1902L) risultato="ERROR_INVALID_FORM_NAME"; else if (i_error==1903L) risultato="ERROR_INVALID_FORM_SIZE"; else if (i_error==1904L) risultato="ERROR_ALREADY_WAITING"; else if (i_error==1905L) risultato="ERROR_PRINTER_DELETED"; else if (i_error==1906L) risultato="ERROR_INVALID_PRINTER_STATE"; else if (i_error==1907L) risultato="ERROR_PASSWORD_MUST_CHANGE"; else if (i_error==1908L) risultato="ERROR_DOMAIN_CONTROLLER_NOT_FOUND"; else if (i_error==1909L) risultato="ERROR_ACCOUNT_LOCKED_OUT"; else if (i_error==1910L) risultato="OR_INVALID_OXID"; else if (i_error==1911L) risultato="OR_INVALID_OID"; else if (i_error==1912L) risultato="OR_INVALID_SET"; else if (i_error==1913L) risultato="RPC_S_SEND_INCOMPLETE"; else if (i_error==1914L) risultato="RPC_S_INVALID_ASYNC_HANDLE"; else if (i_error==1915L) risultato="RPC_S_INVALID_ASYNC_CALL"; else if (i_error==1916L) risultato="RPC_X_PIPE_CLOSED"; else if (i_error==1917L) risultato="RPC_X_PIPE_DISCIPLINE_ERROR"; else if (i_error==1918L) risultato="RPC_X_PIPE_EMPTY"; else if (i_error==1919L) risultato="ERROR_NO_SITENAME"; else if (i_error==1920L) risultato="ERROR_CANT_ACCESS_FILE"; else if (i_error==1921L) risultato="ERROR_CANT_RESOLVE_FILENAME"; else if (i_error==1922L) risultato="RPC_S_ENTRY_TYPE_MISMATCH"; else if (i_error==1923L) risultato="RPC_S_NOT_ALL_OBJS_EXPORTED"; else if (i_error==1924L) risultato="RPC_S_INTERFACE_NOT_EXPORTED"; else if (i_error==1925L) risultato="RPC_S_PROFILE_NOT_ADDED"; else if (i_error==1926L) risultato="RPC_S_PRF_ELT_NOT_ADDED"; else if (i_error==1927L) risultato="RPC_S_PRF_ELT_NOT_REMOVED"; else if (i_error==1928L) risultato="RPC_S_GRP_ELT_NOT_ADDED"; else if (i_error==1929L) risultato="RPC_S_GRP_ELT_NOT_REMOVED"; else if (i_error==1930L) risultato="ERROR_KM_DRIVER_BLOCKED"; else if (i_error==1931L) risultato="ERROR_CONTEXT_EXPIRED"; else if (i_error==1932L) risultato="ERROR_PER_USER_TRUST_QUOTA_EXCEEDED"; else if (i_error==1933L) risultato="ERROR_ALL_USER_TRUST_QUOTA_EXCEEDED"; else if (i_error==1934L) risultato="ERROR_USER_DELETE_TRUST_QUOTA_EXCEEDED"; else if (i_error==1935L) risultato="ERROR_AUTHENTICATION_FIREWALL_FAILED"; else if (i_error==1936L) risultato="ERROR_REMOTE_PRINT_CONNECTIONS_BLOCKED"; else if (i_error==1937L) risultato="ERROR_NTLM_BLOCKED"; else if (i_error==1938L) risultato="ERROR_PASSWORD_CHANGE_REQUIRED"; else if (i_error==2000L) risultato="ERROR_INVALID_PIXEL_FORMAT"; else if (i_error==2001L) risultato="ERROR_BAD_DRIVER"; else if (i_error==2002L) risultato="ERROR_INVALID_WINDOW_STYLE"; else if (i_error==2003L) risultato="ERROR_METAFILE_NOT_SUPPORTED"; else if (i_error==2004L) risultato="ERROR_TRANSFORM_NOT_SUPPORTED"; else if (i_error==2005L) risultato="ERROR_CLIPPING_NOT_SUPPORTED"; else if (i_error==2010L) risultato="ERROR_INVALID_CMM"; else if (i_error==2011L) risultato="ERROR_INVALID_PROFILE"; else if (i_error==2012L) risultato="ERROR_TAG_NOT_FOUND"; else if (i_error==2013L) risultato="ERROR_TAG_NOT_PRESENT"; else if (i_error==2014L) risultato="ERROR_DUPLICATE_TAG"; else if (i_error==2015L) risultato="ERROR_PROFILE_NOT_ASSOCIATED_WITH_DEVICE"; else if (i_error==2016L) risultato="ERROR_PROFILE_NOT_FOUND"; else if (i_error==2017L) risultato="ERROR_INVALID_COLORSPACE"; else if (i_error==2018L) risultato="ERROR_ICM_NOT_ENABLED"; else if (i_error==2019L) risultato="ERROR_DELETING_ICM_XFORM"; else if (i_error==2020L) risultato="ERROR_INVALID_TRANSFORM"; else if (i_error==2021L) risultato="ERROR_COLORSPACE_MISMATCH"; else if (i_error==2022L) risultato="ERROR_INVALID_COLORINDEX"; else if (i_error==2023L) risultato="ERROR_PROFILE_DOES_NOT_MATCH_DEVICE"; else if (i_error==2108L) risultato="ERROR_CONNECTED_OTHER_PASSWORD"; else if (i_error==2109L) risultato="ERROR_CONNECTED_OTHER_PASSWORD_DEFAULT"; else if (i_error==2202L) risultato="ERROR_BAD_USERNAME"; else if (i_error==2250L) risultato="ERROR_NOT_CONNECTED"; else if (i_error==2401L) risultato="ERROR_OPEN_FILES"; else if (i_error==2402L) risultato="ERROR_ACTIVE_CONNECTIONS"; else if (i_error==2404L) risultato="ERROR_DEVICE_IN_USE"; else if (i_error==3000L) risultato="ERROR_UNKNOWN_PRINT_MONITOR"; else if (i_error==3001L) risultato="ERROR_PRINTER_DRIVER_IN_USE"; else if (i_error==3002L) risultato="ERROR_SPOOL_FILE_NOT_FOUND"; else if (i_error==3003L) risultato="ERROR_SPL_NO_STARTDOC"; else if (i_error==3004L) risultato="ERROR_SPL_NO_ADDJOB"; else if (i_error==3005L) risultato="ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED"; else if (i_error==3006L) risultato="ERROR_PRINT_MONITOR_ALREADY_INSTALLED"; else if (i_error==3007L) risultato="ERROR_INVALID_PRINT_MONITOR"; else if (i_error==3008L) risultato="ERROR_PRINT_MONITOR_IN_USE"; else if (i_error==3009L) risultato="ERROR_PRINTER_HAS_JOBS_QUEUED"; else if (i_error==3010L) risultato="ERROR_SUCCESS_REBOOT_REQUIRED"; else if (i_error==3011L) risultato="ERROR_SUCCESS_RESTART_REQUIRED"; else if (i_error==3012L) risultato="ERROR_PRINTER_NOT_FOUND"; else if (i_error==3013L) risultato="ERROR_PRINTER_DRIVER_WARNED"; else if (i_error==3014L) risultato="ERROR_PRINTER_DRIVER_BLOCKED"; else if (i_error==3015L) risultato="ERROR_PRINTER_DRIVER_PACKAGE_IN_USE"; else if (i_error==3016L) risultato="ERROR_CORE_DRIVER_PACKAGE_NOT_FOUND"; else if (i_error==3017L) risultato="ERROR_FAIL_REBOOT_REQUIRED"; else if (i_error==3018L) risultato="ERROR_FAIL_REBOOT_INITIATED"; else if (i_error==3019L) risultato="ERROR_PRINTER_DRIVER_DOWNLOAD_NEEDED"; else if (i_error==3020L) risultato="ERROR_PRINT_JOB_RESTART_REQUIRED"; else if (i_error==3021L) risultato="ERROR_INVALID_PRINTER_DRIVER_MANIFEST"; else if (i_error==3022L) risultato="ERROR_PRINTER_NOT_SHAREABLE"; else if (i_error==3050L) risultato="ERROR_REQUEST_PAUSED"; else if (i_error==3950L) risultato="ERROR_IO_REISSUE_AS_CACHED"; else if (i_error==4000L) risultato="ERROR_WINS_INTERNAL"; else if (i_error==4001L) risultato="ERROR_CAN_NOT_DEL_LOCAL_WINS"; else if (i_error==4002L) risultato="ERROR_STATIC_INIT"; else if (i_error==4003L) risultato="ERROR_INC_BACKUP"; else if (i_error==4004L) risultato="ERROR_FULL_BACKUP"; else if (i_error==4005L) risultato="ERROR_REC_NON_EXISTENT"; else if (i_error==4006L) risultato="ERROR_RPL_NOT_ALLOWED"; else if (i_error==4050L) risultato="PEERDIST_ERROR_CONTENTINFO_VERSION_UNSUPPORTED"; else if (i_error==4051L) risultato="PEERDIST_ERROR_CANNOT_PARSE_CONTENTINFO"; else if (i_error==4052L) risultato="PEERDIST_ERROR_MISSING_DATA"; else if (i_error==4053L) risultato="PEERDIST_ERROR_NO_MORE"; else if (i_error==4054L) risultato="PEERDIST_ERROR_NOT_INITIALIZED"; else if (i_error==4055L) risultato="PEERDIST_ERROR_ALREADY_INITIALIZED"; else if (i_error==4056L) risultato="PEERDIST_ERROR_SHUTDOWN_IN_PROGRESS"; else if (i_error==4057L) risultato="PEERDIST_ERROR_INVALIDATED"; else if (i_error==4058L) risultato="PEERDIST_ERROR_ALREADY_EXISTS"; else if (i_error==4059L) risultato="PEERDIST_ERROR_OPERATION_NOTFOUND"; else if (i_error==4060L) risultato="PEERDIST_ERROR_ALREADY_COMPLETED"; else if (i_error==4061L) risultato="PEERDIST_ERROR_OUT_OF_BOUNDS"; else if (i_error==4062L) risultato="PEERDIST_ERROR_VERSION_UNSUPPORTED"; else if (i_error==4063L) risultato="PEERDIST_ERROR_INVALID_CONFIGURATION"; else if (i_error==4064L) risultato="PEERDIST_ERROR_NOT_LICENSED"; else if (i_error==4065L) risultato="PEERDIST_ERROR_SERVICE_UNAVAILABLE"; else if (i_error==4066L) risultato="PEERDIST_ERROR_TRUST_FAILURE"; else if (i_error==4100L) risultato="ERROR_DHCP_ADDRESS_CONFLICT"; else if (i_error==4200L) risultato="ERROR_WMI_GUID_NOT_FOUND"; else if (i_error==4201L) risultato="ERROR_WMI_INSTANCE_NOT_FOUND"; else if (i_error==4202L) risultato="ERROR_WMI_ITEMID_NOT_FOUND"; else if (i_error==4203L) risultato="ERROR_WMI_TRY_AGAIN"; else if (i_error==4204L) risultato="ERROR_WMI_DP_NOT_FOUND"; else if (i_error==4205L) risultato="ERROR_WMI_UNRESOLVED_INSTANCE_REF"; else if (i_error==4206L) risultato="ERROR_WMI_ALREADY_ENABLED"; else if (i_error==4207L) risultato="ERROR_WMI_GUID_DISCONNECTED"; else if (i_error==4208L) risultato="ERROR_WMI_SERVER_UNAVAILABLE"; else if (i_error==4209L) risultato="ERROR_WMI_DP_FAILED"; else if (i_error==4210L) risultato="ERROR_WMI_INVALID_MOF"; else if (i_error==4211L) risultato="ERROR_WMI_INVALID_REGINFO"; else if (i_error==4212L) risultato="ERROR_WMI_ALREADY_DISABLED"; else if (i_error==4213L) risultato="ERROR_WMI_READ_ONLY"; else if (i_error==4214L) risultato="ERROR_WMI_SET_FAILURE"; else if (i_error==4250L) risultato="ERROR_NOT_APPCONTAINER"; else if (i_error==4251L) risultato="ERROR_APPCONTAINER_REQUIRED"; else if (i_error==4252L) risultato="ERROR_NOT_SUPPORTED_IN_APPCONTAINER"; else if (i_error==4253L) risultato="ERROR_INVALID_PACKAGE_SID_LENGTH"; else if (i_error==4300L) risultato="ERROR_INVALID_MEDIA"; else if (i_error==4301L) risultato="ERROR_INVALID_LIBRARY"; else if (i_error==4302L) risultato="ERROR_INVALID_MEDIA_POOL"; else if (i_error==4303L) risultato="ERROR_DRIVE_MEDIA_MISMATCH"; else if (i_error==4304L) risultato="ERROR_MEDIA_OFFLINE"; else if (i_error==4305L) risultato="ERROR_LIBRARY_OFFLINE"; else if (i_error==4306L) risultato="ERROR_EMPTY"; else if (i_error==4307L) risultato="ERROR_NOT_EMPTY"; else if (i_error==4308L) risultato="ERROR_MEDIA_UNAVAILABLE"; else if (i_error==4309L) risultato="ERROR_RESOURCE_DISABLED"; else if (i_error==4310L) risultato="ERROR_INVALID_CLEANER"; else if (i_error==4311L) risultato="ERROR_UNABLE_TO_CLEAN"; else if (i_error==4312L) risultato="ERROR_OBJECT_NOT_FOUND"; else if (i_error==4313L) risultato="ERROR_DATABASE_FAILURE"; else if (i_error==4314L) risultato="ERROR_DATABASE_FULL"; else if (i_error==4315L) risultato="ERROR_MEDIA_INCOMPATIBLE"; else if (i_error==4316L) risultato="ERROR_RESOURCE_NOT_PRESENT"; else if (i_error==4317L) risultato="ERROR_INVALID_OPERATION"; else if (i_error==4318L) risultato="ERROR_MEDIA_NOT_AVAILABLE"; else if (i_error==4319L) risultato="ERROR_DEVICE_NOT_AVAILABLE"; else if (i_error==4320L) risultato="ERROR_REQUEST_REFUSED"; else if (i_error==4321L) risultato="ERROR_INVALID_DRIVE_OBJECT"; else if (i_error==4322L) risultato="ERROR_LIBRARY_FULL"; else if (i_error==4323L) risultato="ERROR_MEDIUM_NOT_ACCESSIBLE"; else if (i_error==4324L) risultato="ERROR_UNABLE_TO_LOAD_MEDIUM"; else if (i_error==4325L) risultato="ERROR_UNABLE_TO_INVENTORY_DRIVE"; else if (i_error==4326L) risultato="ERROR_UNABLE_TO_INVENTORY_SLOT"; else if (i_error==4327L) risultato="ERROR_UNABLE_TO_INVENTORY_TRANSPORT"; else if (i_error==4328L) risultato="ERROR_TRANSPORT_FULL"; else if (i_error==4329L) risultato="ERROR_CONTROLLING_IEPORT"; else if (i_error==4330L) risultato="ERROR_UNABLE_TO_EJECT_MOUNTED_MEDIA"; else if (i_error==4331L) risultato="ERROR_CLEANER_SLOT_SET"; else if (i_error==4332L) risultato="ERROR_CLEANER_SLOT_NOT_SET"; else if (i_error==4333L) risultato="ERROR_CLEANER_CARTRIDGE_SPENT"; else if (i_error==4334L) risultato="ERROR_UNEXPECTED_OMID"; else if (i_error==4335L) risultato="ERROR_CANT_DELETE_LAST_ITEM"; else if (i_error==4336L) risultato="ERROR_MESSAGE_EXCEEDS_MAX_SIZE"; else if (i_error==4337L) risultato="ERROR_VOLUME_CONTAINS_SYS_FILES"; else if (i_error==4338L) risultato="ERROR_INDIGENOUS_TYPE"; else if (i_error==4339L) risultato="ERROR_NO_SUPPORTING_DRIVES"; else if (i_error==4340L) risultato="ERROR_CLEANER_CARTRIDGE_INSTALLED"; else if (i_error==4341L) risultato="ERROR_IEPORT_FULL"; else if (i_error==4350L) risultato="ERROR_FILE_OFFLINE"; else if (i_error==4351L) risultato="ERROR_REMOTE_STORAGE_NOT_ACTIVE"; else if (i_error==4352L) risultato="ERROR_REMOTE_STORAGE_MEDIA_ERROR"; else if (i_error==4390L) risultato="ERROR_NOT_A_REPARSE_POINT"; else if (i_error==4391L) risultato="ERROR_REPARSE_ATTRIBUTE_CONFLICT"; else if (i_error==4392L) risultato="ERROR_INVALID_REPARSE_DATA"; else if (i_error==4393L) risultato="ERROR_REPARSE_TAG_INVALID"; else if (i_error==4394L) risultato="ERROR_REPARSE_TAG_MISMATCH"; else if (i_error==4395L) risultato="ERROR_REPARSE_POINT_ENCOUNTERED"; else if (i_error==4400L) risultato="ERROR_APP_DATA_NOT_FOUND"; else if (i_error==4401L) risultato="ERROR_APP_DATA_EXPIRED"; else if (i_error==4402L) risultato="ERROR_APP_DATA_CORRUPT"; else if (i_error==4403L) risultato="ERROR_APP_DATA_LIMIT_EXCEEDED"; else if (i_error==4404L) risultato="ERROR_APP_DATA_REBOOT_REQUIRED"; else if (i_error==4420L) risultato="ERROR_SECUREBOOT_ROLLBACK_DETECTED"; else if (i_error==4421L) risultato="ERROR_SECUREBOOT_POLICY_VIOLATION"; else if (i_error==4422L) risultato="ERROR_SECUREBOOT_INVALID_POLICY"; else if (i_error==4423L) risultato="ERROR_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND"; else if (i_error==4424L) risultato="ERROR_SECUREBOOT_POLICY_NOT_SIGNED"; else if (i_error==4425L) risultato="ERROR_SECUREBOOT_NOT_ENABLED"; else if (i_error==4426L) risultato="ERROR_SECUREBOOT_FILE_REPLACED"; else if (i_error==4427L) risultato="ERROR_SECUREBOOT_POLICY_NOT_AUTHORIZED"; else if (i_error==4428L) risultato="ERROR_SECUREBOOT_POLICY_UNKNOWN"; else if (i_error==4429L) risultato="ERROR_SECUREBOOT_POLICY_MISSING_ANTIROLLBACKVERSION"; else if (i_error==4430L) risultato="ERROR_SECUREBOOT_PLATFORM_ID_MISMATCH"; else if (i_error==4431L) risultato="ERROR_SECUREBOOT_POLICY_ROLLBACK_DETECTED"; else if (i_error==4432L) risultato="ERROR_SECUREBOOT_POLICY_UPGRADE_MISMATCH"; else if (i_error==4433L) risultato="ERROR_SECUREBOOT_REQUIRED_POLICY_FILE_MISSING"; else if (i_error==4434L) risultato="ERROR_SECUREBOOT_NOT_BASE_POLICY"; else if (i_error==4435L) risultato="ERROR_SECUREBOOT_NOT_SUPPLEMENTAL_POLICY"; else if (i_error==4440L) risultato="ERROR_OFFLOAD_READ_FLT_NOT_SUPPORTED"; else if (i_error==4441L) risultato="ERROR_OFFLOAD_WRITE_FLT_NOT_SUPPORTED"; else if (i_error==4442L) risultato="ERROR_OFFLOAD_READ_FILE_NOT_SUPPORTED"; else if (i_error==4443L) risultato="ERROR_OFFLOAD_WRITE_FILE_NOT_SUPPORTED"; else if (i_error==4500L) risultato="ERROR_VOLUME_NOT_SIS_ENABLED"; else if (i_error==4550L) risultato="ERROR_SYSTEM_INTEGRITY_ROLLBACK_DETECTED"; else if (i_error==4551L) risultato="ERROR_SYSTEM_INTEGRITY_POLICY_VIOLATION"; else if (i_error==4552L) risultato="ERROR_SYSTEM_INTEGRITY_INVALID_POLICY"; else if (i_error==4553L) risultato="ERROR_SYSTEM_INTEGRITY_POLICY_NOT_SIGNED"; else if (i_error==4560L) risultato="ERROR_VSM_NOT_INITIALIZED"; else if (i_error==4561L) risultato="ERROR_VSM_DMA_PROTECTION_NOT_IN_USE"; else if (i_error==4570L) risultato="ERROR_PLATFORM_MANIFEST_NOT_AUTHORIZED"; else if (i_error==4571L) risultato="ERROR_PLATFORM_MANIFEST_INVALID"; else if (i_error==4572L) risultato="ERROR_PLATFORM_MANIFEST_FILE_NOT_AUTHORIZED"; else if (i_error==4573L) risultato="ERROR_PLATFORM_MANIFEST_CATALOG_NOT_AUTHORIZED"; else if (i_error==4574L) risultato="ERROR_PLATFORM_MANIFEST_BINARY_ID_NOT_FOUND"; else if (i_error==4575L) risultato="ERROR_PLATFORM_MANIFEST_NOT_ACTIVE"; else if (i_error==4576L) risultato="ERROR_PLATFORM_MANIFEST_NOT_SIGNED"; else if (i_error==5001L) risultato="ERROR_DEPENDENT_RESOURCE_EXISTS"; else if (i_error==5002L) risultato="ERROR_DEPENDENCY_NOT_FOUND"; else if (i_error==5003L) risultato="ERROR_DEPENDENCY_ALREADY_EXISTS"; else if (i_error==5004L) risultato="ERROR_RESOURCE_NOT_ONLINE"; else if (i_error==5005L) risultato="ERROR_HOST_NODE_NOT_AVAILABLE"; else if (i_error==5006L) risultato="ERROR_RESOURCE_NOT_AVAILABLE"; else if (i_error==5007L) risultato="ERROR_RESOURCE_NOT_FOUND"; else if (i_error==5008L) risultato="ERROR_SHUTDOWN_CLUSTER"; else if (i_error==5009L) risultato="ERROR_CANT_EVICT_ACTIVE_NODE"; else if (i_error==5010L) risultato="ERROR_OBJECT_ALREADY_EXISTS"; else if (i_error==5011L) risultato="ERROR_OBJECT_IN_LIST"; else if (i_error==5012L) risultato="ERROR_GROUP_NOT_AVAILABLE"; else if (i_error==5013L) risultato="ERROR_GROUP_NOT_FOUND"; else if (i_error==5014L) risultato="ERROR_GROUP_NOT_ONLINE"; else if (i_error==5015L) risultato="ERROR_HOST_NODE_NOT_RESOURCE_OWNER"; else if (i_error==5016L) risultato="ERROR_HOST_NODE_NOT_GROUP_OWNER"; else if (i_error==5017L) risultato="ERROR_RESMON_CREATE_FAILED"; else if (i_error==5018L) risultato="ERROR_RESMON_ONLINE_FAILED"; else if (i_error==5019L) risultato="ERROR_RESOURCE_ONLINE"; else if (i_error==5020L) risultato="ERROR_QUORUM_RESOURCE"; else if (i_error==5021L) risultato="ERROR_NOT_QUORUM_CAPABLE"; else if (i_error==5022L) risultato="ERROR_CLUSTER_SHUTTING_DOWN"; else if (i_error==5023L) risultato="ERROR_INVALID_STATE"; else if (i_error==5024L) risultato="ERROR_RESOURCE_PROPERTIES_STORED"; else if (i_error==5025L) risultato="ERROR_NOT_QUORUM_CLASS"; else if (i_error==5026L) risultato="ERROR_CORE_RESOURCE"; else if (i_error==5027L) risultato="ERROR_QUORUM_RESOURCE_ONLINE_FAILED"; else if (i_error==5028L) risultato="ERROR_QUORUMLOG_OPEN_FAILED"; else if (i_error==5029L) risultato="ERROR_CLUSTERLOG_CORRUPT"; else if (i_error==5030L) risultato="ERROR_CLUSTERLOG_RECORD_EXCEEDS_MAXSIZE"; else if (i_error==5031L) risultato="ERROR_CLUSTERLOG_EXCEEDS_MAXSIZE"; else if (i_error==5032L) risultato="ERROR_CLUSTERLOG_CHKPOINT_NOT_FOUND"; else if (i_error==5033L) risultato="ERROR_CLUSTERLOG_NOT_ENOUGH_SPACE"; else if (i_error==5034L) risultato="ERROR_QUORUM_OWNER_ALIVE"; else if (i_error==5035L) risultato="ERROR_NETWORK_NOT_AVAILABLE"; else if (i_error==5036L) risultato="ERROR_NODE_NOT_AVAILABLE"; else if (i_error==5037L) risultato="ERROR_ALL_NODES_NOT_AVAILABLE"; else if (i_error==5038L) risultato="ERROR_RESOURCE_FAILED"; else if (i_error==5039L) risultato="ERROR_CLUSTER_INVALID_NODE"; else if (i_error==5040L) risultato="ERROR_CLUSTER_NODE_EXISTS"; else if (i_error==5041L) risultato="ERROR_CLUSTER_JOIN_IN_PROGRESS"; else if (i_error==5042L) risultato="ERROR_CLUSTER_NODE_NOT_FOUND"; else if (i_error==5043L) risultato="ERROR_CLUSTER_LOCAL_NODE_NOT_FOUND"; else if (i_error==5044L) risultato="ERROR_CLUSTER_NETWORK_EXISTS"; else if (i_error==5045L) risultato="ERROR_CLUSTER_NETWORK_NOT_FOUND"; else if (i_error==5046L) risultato="ERROR_CLUSTER_NETINTERFACE_EXISTS"; else if (i_error==5047L) risultato="ERROR_CLUSTER_NETINTERFACE_NOT_FOUND"; else if (i_error==5048L) risultato="ERROR_CLUSTER_INVALID_REQUEST"; else if (i_error==5049L) risultato="ERROR_CLUSTER_INVALID_NETWORK_PROVIDER"; else if (i_error==5050L) risultato="ERROR_CLUSTER_NODE_DOWN"; else if (i_error==5051L) risultato="ERROR_CLUSTER_NODE_UNREACHABLE"; else if (i_error==5052L) risultato="ERROR_CLUSTER_NODE_NOT_MEMBER"; else if (i_error==5053L) risultato="ERROR_CLUSTER_JOIN_NOT_IN_PROGRESS"; else if (i_error==5054L) risultato="ERROR_CLUSTER_INVALID_NETWORK"; else if (i_error==5056L) risultato="ERROR_CLUSTER_NODE_UP"; else if (i_error==5057L) risultato="ERROR_CLUSTER_IPADDR_IN_USE"; else if (i_error==5058L) risultato="ERROR_CLUSTER_NODE_NOT_PAUSED"; else if (i_error==5059L) risultato="ERROR_CLUSTER_NO_SECURITY_CONTEXT"; else if (i_error==5060L) risultato="ERROR_CLUSTER_NETWORK_NOT_INTERNAL"; else if (i_error==5061L) risultato="ERROR_CLUSTER_NODE_ALREADY_UP"; else if (i_error==5062L) risultato="ERROR_CLUSTER_NODE_ALREADY_DOWN"; else if (i_error==5063L) risultato="ERROR_CLUSTER_NETWORK_ALREADY_ONLINE"; else if (i_error==5064L) risultato="ERROR_CLUSTER_NETWORK_ALREADY_OFFLINE"; else if (i_error==5065L) risultato="ERROR_CLUSTER_NODE_ALREADY_MEMBER"; else if (i_error==5066L) risultato="ERROR_CLUSTER_LAST_INTERNAL_NETWORK"; else if (i_error==5067L) risultato="ERROR_CLUSTER_NETWORK_HAS_DEPENDENTS"; else if (i_error==5068L) risultato="ERROR_INVALID_OPERATION_ON_QUORUM"; else if (i_error==5069L) risultato="ERROR_DEPENDENCY_NOT_ALLOWED"; else if (i_error==5070L) risultato="ERROR_CLUSTER_NODE_PAUSED"; else if (i_error==5071L) risultato="ERROR_NODE_CANT_HOST_RESOURCE"; else if (i_error==5072L) risultato="ERROR_CLUSTER_NODE_NOT_READY"; else if (i_error==5073L) risultato="ERROR_CLUSTER_NODE_SHUTTING_DOWN"; else if (i_error==5074L) risultato="ERROR_CLUSTER_JOIN_ABORTED"; else if (i_error==5075L) risultato="ERROR_CLUSTER_INCOMPATIBLE_VERSIONS"; else if (i_error==5076L) risultato="ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED"; else if (i_error==5077L) risultato="ERROR_CLUSTER_SYSTEM_CONFIG_CHANGED"; else if (i_error==5078L) risultato="ERROR_CLUSTER_RESOURCE_TYPE_NOT_FOUND"; else if (i_error==5079L) risultato="ERROR_CLUSTER_RESTYPE_NOT_SUPPORTED"; else if (i_error==5080L) risultato="ERROR_CLUSTER_RESNAME_NOT_FOUND"; else if (i_error==5081L) risultato="ERROR_CLUSTER_NO_RPC_PACKAGES_REGISTERED"; else if (i_error==5082L) risultato="ERROR_CLUSTER_OWNER_NOT_IN_PREFLIST"; else if (i_error==5083L) risultato="ERROR_CLUSTER_DATABASE_SEQMISMATCH"; else if (i_error==5084L) risultato="ERROR_RESMON_INVALID_STATE"; else if (i_error==5085L) risultato="ERROR_CLUSTER_GUM_NOT_LOCKER"; else if (i_error==5086L) risultato="ERROR_QUORUM_DISK_NOT_FOUND"; else if (i_error==5087L) risultato="ERROR_DATABASE_BACKUP_CORRUPT"; else if (i_error==5088L) risultato="ERROR_CLUSTER_NODE_ALREADY_HAS_DFS_ROOT"; else if (i_error==5089L) risultato="ERROR_RESOURCE_PROPERTY_UNCHANGEABLE"; else if (i_error==5090L) risultato="ERROR_NO_ADMIN_ACCESS_POINT"; else if (i_error==5890L) risultato="ERROR_CLUSTER_MEMBERSHIP_INVALID_STATE"; else if (i_error==5891L) risultato="ERROR_CLUSTER_QUORUMLOG_NOT_FOUND"; else if (i_error==5892L) risultato="ERROR_CLUSTER_MEMBERSHIP_HALT"; else if (i_error==5893L) risultato="ERROR_CLUSTER_INSTANCE_ID_MISMATCH"; else if (i_error==5894L) risultato="ERROR_CLUSTER_NETWORK_NOT_FOUND_FOR_IP"; else if (i_error==5895L) risultato="ERROR_CLUSTER_PROPERTY_DATA_TYPE_MISMATCH"; else if (i_error==5896L) risultato="ERROR_CLUSTER_EVICT_WITHOUT_CLEANUP"; else if (i_error==5897L) risultato="ERROR_CLUSTER_PARAMETER_MISMATCH"; else if (i_error==5898L) risultato="ERROR_NODE_CANNOT_BE_CLUSTERED"; else if (i_error==5899L) risultato="ERROR_CLUSTER_WRONG_OS_VERSION"; else if (i_error==5900L) risultato="ERROR_CLUSTER_CANT_CREATE_DUP_CLUSTER_NAME"; else if (i_error==5901L) risultato="ERROR_CLUSCFG_ALREADY_COMMITTED"; else if (i_error==5902L) risultato="ERROR_CLUSCFG_ROLLBACK_FAILED"; else if (i_error==5903L) risultato="ERROR_CLUSCFG_SYSTEM_DISK_DRIVE_LETTER_CONFLICT"; else if (i_error==5904L) risultato="ERROR_CLUSTER_OLD_VERSION"; else if (i_error==5905L) risultato="ERROR_CLUSTER_MISMATCHED_COMPUTER_ACCT_NAME"; else if (i_error==5906L) risultato="ERROR_CLUSTER_NO_NET_ADAPTERS"; else if (i_error==5907L) risultato="ERROR_CLUSTER_POISONED"; else if (i_error==5908L) risultato="ERROR_CLUSTER_GROUP_MOVING"; else if (i_error==5909L) risultato="ERROR_CLUSTER_RESOURCE_TYPE_BUSY"; else if (i_error==5910L) risultato="ERROR_RESOURCE_CALL_TIMED_OUT"; else if (i_error==5911L) risultato="ERROR_INVALID_CLUSTER_IPV6_ADDRESS"; else if (i_error==5912L) risultato="ERROR_CLUSTER_INTERNAL_INVALID_FUNCTION"; else if (i_error==5913L) risultato="ERROR_CLUSTER_PARAMETER_OUT_OF_BOUNDS"; else if (i_error==5914L) risultato="ERROR_CLUSTER_PARTIAL_SEND"; else if (i_error==5915L) risultato="ERROR_CLUSTER_REGISTRY_INVALID_FUNCTION"; else if (i_error==5916L) risultato="ERROR_CLUSTER_INVALID_STRING_TERMINATION"; else if (i_error==5917L) risultato="ERROR_CLUSTER_INVALID_STRING_FORMAT"; else if (i_error==5918L) risultato="ERROR_CLUSTER_DATABASE_TRANSACTION_IN_PROGRESS"; else if (i_error==5919L) risultato="ERROR_CLUSTER_DATABASE_TRANSACTION_NOT_IN_PROGRESS"; else if (i_error==5920L) risultato="ERROR_CLUSTER_NULL_DATA"; else if (i_error==5921L) risultato="ERROR_CLUSTER_PARTIAL_READ"; else if (i_error==5922L) risultato="ERROR_CLUSTER_PARTIAL_WRITE"; else if (i_error==5923L) risultato="ERROR_CLUSTER_CANT_DESERIALIZE_DATA"; else if (i_error==5924L) risultato="ERROR_DEPENDENT_RESOURCE_PROPERTY_CONFLICT"; else if (i_error==5925L) risultato="ERROR_CLUSTER_NO_QUORUM"; else if (i_error==5926L) risultato="ERROR_CLUSTER_INVALID_IPV6_NETWORK"; else if (i_error==5927L) risultato="ERROR_CLUSTER_INVALID_IPV6_TUNNEL_NETWORK"; else if (i_error==5928L) risultato="ERROR_QUORUM_NOT_ALLOWED_IN_THIS_GROUP"; else if (i_error==5929L) risultato="ERROR_DEPENDENCY_TREE_TOO_COMPLEX"; else if (i_error==5930L) risultato="ERROR_EXCEPTION_IN_RESOURCE_CALL"; else if (i_error==5931L) risultato="ERROR_CLUSTER_RHS_FAILED_INITIALIZATION"; else if (i_error==5932L) risultato="ERROR_CLUSTER_NOT_INSTALLED"; else if (i_error==5933L) risultato="ERROR_CLUSTER_RESOURCES_MUST_BE_ONLINE_ON_THE_SAME_NODE"; else if (i_error==5934L) risultato="ERROR_CLUSTER_MAX_NODES_IN_CLUSTER"; else if (i_error==5935L) risultato="ERROR_CLUSTER_TOO_MANY_NODES"; else if (i_error==5936L) risultato="ERROR_CLUSTER_OBJECT_ALREADY_USED"; else if (i_error==5937L) risultato="ERROR_NONCORE_GROUPS_FOUND"; else if (i_error==5938L) risultato="ERROR_FILE_SHARE_RESOURCE_CONFLICT"; else if (i_error==5939L) risultato="ERROR_CLUSTER_EVICT_INVALID_REQUEST"; else if (i_error==5940L) risultato="ERROR_CLUSTER_SINGLETON_RESOURCE"; else if (i_error==5941L) risultato="ERROR_CLUSTER_GROUP_SINGLETON_RESOURCE"; else if (i_error==5942L) risultato="ERROR_CLUSTER_RESOURCE_PROVIDER_FAILED"; else if (i_error==5943L) risultato="ERROR_CLUSTER_RESOURCE_CONFIGURATION_ERROR"; else if (i_error==5944L) risultato="ERROR_CLUSTER_GROUP_BUSY"; else if (i_error==5945L) risultato="ERROR_CLUSTER_NOT_SHARED_VOLUME"; else if (i_error==5946L) risultato="ERROR_CLUSTER_INVALID_SECURITY_DESCRIPTOR"; else if (i_error==5947L) risultato="ERROR_CLUSTER_SHARED_VOLUMES_IN_USE"; else if (i_error==5948L) risultato="ERROR_CLUSTER_USE_SHARED_VOLUMES_API"; else if (i_error==5949L) risultato="ERROR_CLUSTER_BACKUP_IN_PROGRESS"; else if (i_error==5950L) risultato="ERROR_NON_CSV_PATH"; else if (i_error==5951L) risultato="ERROR_CSV_VOLUME_NOT_LOCAL"; else if (i_error==5952L) risultato="ERROR_CLUSTER_WATCHDOG_TERMINATING"; else if (i_error==5953L) risultato="ERROR_CLUSTER_RESOURCE_VETOED_MOVE_INCOMPATIBLE_NODES"; else if (i_error==5954L) risultato="ERROR_CLUSTER_INVALID_NODE_WEIGHT"; else if (i_error==5955L) risultato="ERROR_CLUSTER_RESOURCE_VETOED_CALL"; else if (i_error==5956L) risultato="ERROR_RESMON_SYSTEM_RESOURCES_LACKING"; else if (i_error==5957L) risultato="ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_DESTINATION"; else if (i_error==5958L) risultato="ERROR_CLUSTER_RESOURCE_VETOED_MOVE_NOT_ENOUGH_RESOURCES_ON_SOURCE"; else if (i_error==5959L) risultato="ERROR_CLUSTER_GROUP_QUEUED"; else if (i_error==5960L) risultato="ERROR_CLUSTER_RESOURCE_LOCKED_STATUS"; else if (i_error==5961L) risultato="ERROR_CLUSTER_SHARED_VOLUME_FAILOVER_NOT_ALLOWED"; else if (i_error==5962L) risultato="ERROR_CLUSTER_NODE_DRAIN_IN_PROGRESS"; else if (i_error==5963L) risultato="ERROR_CLUSTER_DISK_NOT_CONNECTED"; else if (i_error==5964L) risultato="ERROR_DISK_NOT_CSV_CAPABLE"; else if (i_error==5965L) risultato="ERROR_RESOURCE_NOT_IN_AVAILABLE_STORAGE"; else if (i_error==5966L) risultato="ERROR_CLUSTER_SHARED_VOLUME_REDIRECTED"; else if (i_error==5967L) risultato="ERROR_CLUSTER_SHARED_VOLUME_NOT_REDIRECTED"; else if (i_error==5968L) risultato="ERROR_CLUSTER_CANNOT_RETURN_PROPERTIES"; else if (i_error==5969L) risultato="ERROR_CLUSTER_RESOURCE_CONTAINS_UNSUPPORTED_DIFF_AREA_FOR_SHARED_VOLUMES"; else if (i_error==5970L) risultato="ERROR_CLUSTER_RESOURCE_IS_IN_MAINTENANCE_MODE"; else if (i_error==5971L) risultato="ERROR_CLUSTER_AFFINITY_CONFLICT"; else if (i_error==5972L) risultato="ERROR_CLUSTER_RESOURCE_IS_REPLICA_VIRTUAL_MACHINE"; else if (i_error==5973L) risultato="ERROR_CLUSTER_UPGRADE_INCOMPATIBLE_VERSIONS"; else if (i_error==5974L) risultato="ERROR_CLUSTER_UPGRADE_FIX_QUORUM_NOT_SUPPORTED"; else if (i_error==5975L) risultato="ERROR_CLUSTER_UPGRADE_RESTART_REQUIRED"; else if (i_error==5976L) risultato="ERROR_CLUSTER_UPGRADE_IN_PROGRESS"; else if (i_error==5977L) risultato="ERROR_CLUSTER_UPGRADE_INCOMPLETE"; else if (i_error==5978L) risultato="ERROR_CLUSTER_NODE_IN_GRACE_PERIOD"; else if (i_error==5979L) risultato="ERROR_CLUSTER_CSV_IO_PAUSE_TIMEOUT"; else if (i_error==5980L) risultato="ERROR_NODE_NOT_ACTIVE_CLUSTER_MEMBER"; else if (i_error==5981L) risultato="ERROR_CLUSTER_RESOURCE_NOT_MONITORED"; else if (i_error==5982L) risultato="ERROR_CLUSTER_RESOURCE_DOES_NOT_SUPPORT_UNMONITORED"; else if (i_error==5983L) risultato="ERROR_CLUSTER_RESOURCE_IS_REPLICATED"; else if (i_error==5984L) risultato="ERROR_CLUSTER_NODE_ISOLATED"; else if (i_error==5985L) risultato="ERROR_CLUSTER_NODE_QUARANTINED"; else if (i_error==5986L) risultato="ERROR_CLUSTER_DATABASE_UPDATE_CONDITION_FAILED"; else if (i_error==5987L) risultato="ERROR_CLUSTER_SPACE_DEGRADED"; else if (i_error==5988L) risultato="ERROR_CLUSTER_TOKEN_DELEGATION_NOT_SUPPORTED"; else if (i_error==5989L) risultato="ERROR_CLUSTER_CSV_INVALID_HANDLE"; else if (i_error==5990L) risultato="ERROR_CLUSTER_CSV_SUPPORTED_ONLY_ON_COORDINATOR"; else if (i_error==5991L) risultato="ERROR_GROUPSET_NOT_AVAILABLE"; else if (i_error==5992L) risultato="ERROR_GROUPSET_NOT_FOUND"; else if (i_error==5993L) risultato="ERROR_GROUPSET_CANT_PROVIDE"; else if (i_error==5994L) risultato="ERROR_CLUSTER_FAULT_DOMAIN_PARENT_NOT_FOUND"; else if (i_error==5995L) risultato="ERROR_CLUSTER_FAULT_DOMAIN_INVALID_HIERARCHY"; else if (i_error==5996L) risultato="ERROR_CLUSTER_FAULT_DOMAIN_FAILED_S2D_VALIDATION"; else if (i_error==5997L) risultato="ERROR_CLUSTER_FAULT_DOMAIN_S2D_CONNECTIVITY_LOSS"; else if (i_error==6000L) risultato="ERROR_ENCRYPTION_FAILED"; else if (i_error==6001L) risultato="ERROR_DECRYPTION_FAILED"; else if (i_error==6002L) risultato="ERROR_FILE_ENCRYPTED"; else if (i_error==6003L) risultato="ERROR_NO_RECOVERY_POLICY"; else if (i_error==6004L) risultato="ERROR_NO_EFS"; else if (i_error==6005L) risultato="ERROR_WRONG_EFS"; else if (i_error==6006L) risultato="ERROR_NO_USER_KEYS"; else if (i_error==6007L) risultato="ERROR_FILE_NOT_ENCRYPTED"; else if (i_error==6008L) risultato="ERROR_NOT_EXPORT_FORMAT"; else if (i_error==6009L) risultato="ERROR_FILE_READ_ONLY"; else if (i_error==6010L) risultato="ERROR_DIR_EFS_DISALLOWED"; else if (i_error==6011L) risultato="ERROR_EFS_SERVER_NOT_TRUSTED"; else if (i_error==6012L) risultato="ERROR_BAD_RECOVERY_POLICY"; else if (i_error==6013L) risultato="ERROR_EFS_ALG_BLOB_TOO_BIG"; else if (i_error==6014L) risultato="ERROR_VOLUME_NOT_SUPPORT_EFS"; else if (i_error==6015L) risultato="ERROR_EFS_DISABLED"; else if (i_error==6016L) risultato="ERROR_EFS_VERSION_NOT_SUPPORT"; else if (i_error==6017L) risultato="ERROR_CS_ENCRYPTION_INVALID_SERVER_RESPONSE"; else if (i_error==6018L) risultato="ERROR_CS_ENCRYPTION_UNSUPPORTED_SERVER"; else if (i_error==6019L) risultato="ERROR_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE"; else if (i_error==6020L) risultato="ERROR_CS_ENCRYPTION_NEW_ENCRYPTED_FILE"; else if (i_error==6021L) risultato="ERROR_CS_ENCRYPTION_FILE_NOT_CSE"; else if (i_error==6022L) risultato="ERROR_ENCRYPTION_POLICY_DENIES_OPERATION"; else if (i_error==6118L) risultato="ERROR_NO_BROWSER_SERVERS_FOUND"; else if (i_error==6200L) risultato="SCHED_E_SERVICE_NOT_LOCALSYSTEM"; else if (i_error==6600L) risultato="ERROR_LOG_SECTOR_INVALID"; else if (i_error==6601L) risultato="ERROR_LOG_SECTOR_PARITY_INVALID"; else if (i_error==6602L) risultato="ERROR_LOG_SECTOR_REMAPPED"; else if (i_error==6603L) risultato="ERROR_LOG_BLOCK_INCOMPLETE"; else if (i_error==6604L) risultato="ERROR_LOG_INVALID_RANGE"; else if (i_error==6605L) risultato="ERROR_LOG_BLOCKS_EXHAUSTED"; else if (i_error==6606L) risultato="ERROR_LOG_READ_CONTEXT_INVALID"; else if (i_error==6607L) risultato="ERROR_LOG_RESTART_INVALID"; else if (i_error==6608L) risultato="ERROR_LOG_BLOCK_VERSION"; else if (i_error==6609L) risultato="ERROR_LOG_BLOCK_INVALID"; else if (i_error==6610L) risultato="ERROR_LOG_READ_MODE_INVALID"; else if (i_error==6611L) risultato="ERROR_LOG_NO_RESTART"; else if (i_error==6612L) risultato="ERROR_LOG_METADATA_CORRUPT"; else if (i_error==6613L) risultato="ERROR_LOG_METADATA_INVALID"; else if (i_error==6614L) risultato="ERROR_LOG_METADATA_INCONSISTENT"; else if (i_error==6615L) risultato="ERROR_LOG_RESERVATION_INVALID"; else if (i_error==6616L) risultato="ERROR_LOG_CANT_DELETE"; else if (i_error==6617L) risultato="ERROR_LOG_CONTAINER_LIMIT_EXCEEDED"; else if (i_error==6618L) risultato="ERROR_LOG_START_OF_LOG"; else if (i_error==6619L) risultato="ERROR_LOG_POLICY_ALREADY_INSTALLED"; else if (i_error==6620L) risultato="ERROR_LOG_POLICY_NOT_INSTALLED"; else if (i_error==6621L) risultato="ERROR_LOG_POLICY_INVALID"; else if (i_error==6622L) risultato="ERROR_LOG_POLICY_CONFLICT"; else if (i_error==6623L) risultato="ERROR_LOG_PINNED_ARCHIVE_TAIL"; else if (i_error==6624L) risultato="ERROR_LOG_RECORD_NONEXISTENT"; else if (i_error==6625L) risultato="ERROR_LOG_RECORDS_RESERVED_INVALID"; else if (i_error==6626L) risultato="ERROR_LOG_SPACE_RESERVED_INVALID"; else if (i_error==6627L) risultato="ERROR_LOG_TAIL_INVALID"; else if (i_error==6628L) risultato="ERROR_LOG_FULL"; else if (i_error==6629L) risultato="ERROR_COULD_NOT_RESIZE_LOG"; else if (i_error==6630L) risultato="ERROR_LOG_MULTIPLEXED"; else if (i_error==6631L) risultato="ERROR_LOG_DEDICATED"; else if (i_error==6632L) risultato="ERROR_LOG_ARCHIVE_NOT_IN_PROGRESS"; else if (i_error==6633L) risultato="ERROR_LOG_ARCHIVE_IN_PROGRESS"; else if (i_error==6634L) risultato="ERROR_LOG_EPHEMERAL"; else if (i_error==6635L) risultato="ERROR_LOG_NOT_ENOUGH_CONTAINERS"; else if (i_error==6636L) risultato="ERROR_LOG_CLIENT_ALREADY_REGISTERED"; else if (i_error==6637L) risultato="ERROR_LOG_CLIENT_NOT_REGISTERED"; else if (i_error==6638L) risultato="ERROR_LOG_FULL_HANDLER_IN_PROGRESS"; else if (i_error==6639L) risultato="ERROR_LOG_CONTAINER_READ_FAILED"; else if (i_error==6640L) risultato="ERROR_LOG_CONTAINER_WRITE_FAILED"; else if (i_error==6641L) risultato="ERROR_LOG_CONTAINER_OPEN_FAILED"; else if (i_error==6642L) risultato="ERROR_LOG_CONTAINER_STATE_INVALID"; else if (i_error==6643L) risultato="ERROR_LOG_STATE_INVALID"; else if (i_error==6644L) risultato="ERROR_LOG_PINNED"; else if (i_error==6645L) risultato="ERROR_LOG_METADATA_FLUSH_FAILED"; else if (i_error==6646L) risultato="ERROR_LOG_INCONSISTENT_SECURITY"; else if (i_error==6647L) risultato="ERROR_LOG_APPENDED_FLUSH_FAILED"; else if (i_error==6648L) risultato="ERROR_LOG_PINNED_RESERVATION"; else if (i_error==6700L) risultato="ERROR_INVALID_TRANSACTION"; else if (i_error==6701L) risultato="ERROR_TRANSACTION_NOT_ACTIVE"; else if (i_error==6702L) risultato="ERROR_TRANSACTION_REQUEST_NOT_VALID"; else if (i_error==6703L) risultato="ERROR_TRANSACTION_NOT_REQUESTED"; else if (i_error==6704L) risultato="ERROR_TRANSACTION_ALREADY_ABORTED"; else if (i_error==6705L) risultato="ERROR_TRANSACTION_ALREADY_COMMITTED"; else if (i_error==6706L) risultato="ERROR_TM_INITIALIZATION_FAILED"; else if (i_error==6707L) risultato="ERROR_RESOURCEMANAGER_READ_ONLY"; else if (i_error==6708L) risultato="ERROR_TRANSACTION_NOT_JOINED"; else if (i_error==6709L) risultato="ERROR_TRANSACTION_SUPERIOR_EXISTS"; else if (i_error==6710L) risultato="ERROR_CRM_PROTOCOL_ALREADY_EXISTS"; else if (i_error==6711L) risultato="ERROR_TRANSACTION_PROPAGATION_FAILED"; else if (i_error==6712L) risultato="ERROR_CRM_PROTOCOL_NOT_FOUND"; else if (i_error==6713L) risultato="ERROR_TRANSACTION_INVALID_MARSHALL_BUFFER"; else if (i_error==6714L) risultato="ERROR_CURRENT_TRANSACTION_NOT_VALID"; else if (i_error==6715L) risultato="ERROR_TRANSACTION_NOT_FOUND"; else if (i_error==6716L) risultato="ERROR_RESOURCEMANAGER_NOT_FOUND"; else if (i_error==6717L) risultato="ERROR_ENLISTMENT_NOT_FOUND"; else if (i_error==6718L) risultato="ERROR_TRANSACTIONMANAGER_NOT_FOUND"; else if (i_error==6719L) risultato="ERROR_TRANSACTIONMANAGER_NOT_ONLINE"; else if (i_error==6720L) risultato="ERROR_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION"; else if (i_error==6721L) risultato="ERROR_TRANSACTION_NOT_ROOT"; else if (i_error==6722L) risultato="ERROR_TRANSACTION_OBJECT_EXPIRED"; else if (i_error==6723L) risultato="ERROR_TRANSACTION_RESPONSE_NOT_ENLISTED"; else if (i_error==6724L) risultato="ERROR_TRANSACTION_RECORD_TOO_LONG"; else if (i_error==6725L) risultato="ERROR_IMPLICIT_TRANSACTION_NOT_SUPPORTED"; else if (i_error==6726L) risultato="ERROR_TRANSACTION_INTEGRITY_VIOLATED"; else if (i_error==6727L) risultato="ERROR_TRANSACTIONMANAGER_IDENTITY_MISMATCH"; else if (i_error==6728L) risultato="ERROR_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT"; else if (i_error==6729L) risultato="ERROR_TRANSACTION_MUST_WRITETHROUGH"; else if (i_error==6730L) risultato="ERROR_TRANSACTION_NO_SUPERIOR"; else if (i_error==6731L) risultato="ERROR_HEURISTIC_DAMAGE_POSSIBLE"; else if (i_error==6800L) risultato="ERROR_TRANSACTIONAL_CONFLICT"; else if (i_error==6801L) risultato="ERROR_RM_NOT_ACTIVE"; else if (i_error==6802L) risultato="ERROR_RM_METADATA_CORRUPT"; else if (i_error==6803L) risultato="ERROR_DIRECTORY_NOT_RM"; else if (i_error==6805L) risultato="ERROR_TRANSACTIONS_UNSUPPORTED_REMOTE"; else if (i_error==6806L) risultato="ERROR_LOG_RESIZE_INVALID_SIZE"; else if (i_error==6807L) risultato="ERROR_OBJECT_NO_LONGER_EXISTS"; else if (i_error==6808L) risultato="ERROR_STREAM_MINIVERSION_NOT_FOUND"; else if (i_error==6809L) risultato="ERROR_STREAM_MINIVERSION_NOT_VALID"; else if (i_error==6810L) risultato="ERROR_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION"; else if (i_error==6811L) risultato="ERROR_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT"; else if (i_error==6812L) risultato="ERROR_CANT_CREATE_MORE_STREAM_MINIVERSIONS"; else if (i_error==6814L) risultato="ERROR_REMOTE_FILE_VERSION_MISMATCH"; else if (i_error==6815L) risultato="ERROR_HANDLE_NO_LONGER_VALID"; else if (i_error==6816L) risultato="ERROR_NO_TXF_METADATA"; else if (i_error==6817L) risultato="ERROR_LOG_CORRUPTION_DETECTED"; else if (i_error==6818L) risultato="ERROR_CANT_RECOVER_WITH_HANDLE_OPEN"; else if (i_error==6819L) risultato="ERROR_RM_DISCONNECTED"; else if (i_error==6820L) risultato="ERROR_ENLISTMENT_NOT_SUPERIOR"; else if (i_error==6821L) risultato="ERROR_RECOVERY_NOT_NEEDED"; else if (i_error==6822L) risultato="ERROR_RM_ALREADY_STARTED"; else if (i_error==6823L) risultato="ERROR_FILE_IDENTITY_NOT_PERSISTENT"; else if (i_error==6824L) risultato="ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY"; else if (i_error==6825L) risultato="ERROR_CANT_CROSS_RM_BOUNDARY"; else if (i_error==6826L) risultato="ERROR_TXF_DIR_NOT_EMPTY"; else if (i_error==6827L) risultato="ERROR_INDOUBT_TRANSACTIONS_EXIST"; else if (i_error==6828L) risultato="ERROR_TM_VOLATILE"; else if (i_error==6829L) risultato="ERROR_ROLLBACK_TIMER_EXPIRED"; else if (i_error==6830L) risultato="ERROR_TXF_ATTRIBUTE_CORRUPT"; else if (i_error==6831L) risultato="ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION"; else if (i_error==6832L) risultato="ERROR_TRANSACTIONAL_OPEN_NOT_ALLOWED"; else if (i_error==6833L) risultato="ERROR_LOG_GROWTH_FAILED"; else if (i_error==6834L) risultato="ERROR_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE"; else if (i_error==6835L) risultato="ERROR_TXF_METADATA_ALREADY_PRESENT"; else if (i_error==6836L) risultato="ERROR_TRANSACTION_SCOPE_CALLBACKS_NOT_SET"; else if (i_error==6837L) risultato="ERROR_TRANSACTION_REQUIRED_PROMOTION"; else if (i_error==6838L) risultato="ERROR_CANNOT_EXECUTE_FILE_IN_TRANSACTION"; else if (i_error==6839L) risultato="ERROR_TRANSACTIONS_NOT_FROZEN"; else if (i_error==6840L) risultato="ERROR_TRANSACTION_FREEZE_IN_PROGRESS"; else if (i_error==6841L) risultato="ERROR_NOT_SNAPSHOT_VOLUME"; else if (i_error==6842L) risultato="ERROR_NO_SAVEPOINT_WITH_OPEN_FILES"; else if (i_error==6843L) risultato="ERROR_DATA_LOST_REPAIR"; else if (i_error==6844L) risultato="ERROR_SPARSE_NOT_ALLOWED_IN_TRANSACTION"; else if (i_error==6845L) risultato="ERROR_TM_IDENTITY_MISMATCH"; else if (i_error==6846L) risultato="ERROR_FLOATED_SECTION"; else if (i_error==6847L) risultato="ERROR_CANNOT_ACCEPT_TRANSACTED_WORK"; else if (i_error==6848L) risultato="ERROR_CANNOT_ABORT_TRANSACTIONS"; else if (i_error==6849L) risultato="ERROR_BAD_CLUSTERS"; else if (i_error==6850L) risultato="ERROR_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION"; else if (i_error==6851L) risultato="ERROR_VOLUME_DIRTY"; else if (i_error==6852L) risultato="ERROR_NO_LINK_TRACKING_IN_TRANSACTION"; else if (i_error==6853L) risultato="ERROR_OPERATION_NOT_SUPPORTED_IN_TRANSACTION"; else if (i_error==6854L) risultato="ERROR_EXPIRED_HANDLE"; else if (i_error==6855L) risultato="ERROR_TRANSACTION_NOT_ENLISTED"; else if (i_error==7001L) risultato="ERROR_CTX_WINSTATION_NAME_INVALID"; else if (i_error==7002L) risultato="ERROR_CTX_INVALID_PD"; else if (i_error==7003L) risultato="ERROR_CTX_PD_NOT_FOUND"; else if (i_error==7004L) risultato="ERROR_CTX_WD_NOT_FOUND"; else if (i_error==7005L) risultato="ERROR_CTX_CANNOT_MAKE_EVENTLOG_ENTRY"; else if (i_error==7006L) risultato="ERROR_CTX_SERVICE_NAME_COLLISION"; else if (i_error==7007L) risultato="ERROR_CTX_CLOSE_PENDING"; else if (i_error==7008L) risultato="ERROR_CTX_NO_OUTBUF"; else if (i_error==7009L) risultato="ERROR_CTX_MODEM_INF_NOT_FOUND"; else if (i_error==7010L) risultato="ERROR_CTX_INVALID_MODEMNAME"; else if (i_error==7011L) risultato="ERROR_CTX_MODEM_RESPONSE_ERROR"; else if (i_error==7012L) risultato="ERROR_CTX_MODEM_RESPONSE_TIMEOUT"; else if (i_error==7013L) risultato="ERROR_CTX_MODEM_RESPONSE_NO_CARRIER"; else if (i_error==7014L) risultato="ERROR_CTX_MODEM_RESPONSE_NO_DIALTONE"; else if (i_error==7015L) risultato="ERROR_CTX_MODEM_RESPONSE_BUSY"; else if (i_error==7016L) risultato="ERROR_CTX_MODEM_RESPONSE_VOICE"; else if (i_error==7017L) risultato="ERROR_CTX_TD_ERROR"; else if (i_error==7022L) risultato="ERROR_CTX_WINSTATION_NOT_FOUND"; else if (i_error==7023L) risultato="ERROR_CTX_WINSTATION_ALREADY_EXISTS"; else if (i_error==7024L) risultato="ERROR_CTX_WINSTATION_BUSY"; else if (i_error==7025L) risultato="ERROR_CTX_BAD_VIDEO_MODE"; else if (i_error==7035L) risultato="ERROR_CTX_GRAPHICS_INVALID"; else if (i_error==7037L) risultato="ERROR_CTX_LOGON_DISABLED"; else if (i_error==7038L) risultato="ERROR_CTX_NOT_CONSOLE"; else if (i_error==7040L) risultato="ERROR_CTX_CLIENT_QUERY_TIMEOUT"; else if (i_error==7041L) risultato="ERROR_CTX_CONSOLE_DISCONNECT"; else if (i_error==7042L) risultato="ERROR_CTX_CONSOLE_CONNECT"; else if (i_error==7044L) risultato="ERROR_CTX_SHADOW_DENIED"; else if (i_error==7045L) risultato="ERROR_CTX_WINSTATION_ACCESS_DENIED"; else if (i_error==7049L) risultato="ERROR_CTX_INVALID_WD"; else if (i_error==7050L) risultato="ERROR_CTX_SHADOW_INVALID"; else if (i_error==7051L) risultato="ERROR_CTX_SHADOW_DISABLED"; else if (i_error==7052L) risultato="ERROR_CTX_CLIENT_LICENSE_IN_USE"; else if (i_error==7053L) risultato="ERROR_CTX_CLIENT_LICENSE_NOT_SET"; else if (i_error==7054L) risultato="ERROR_CTX_LICENSE_NOT_AVAILABLE"; else if (i_error==7055L) risultato="ERROR_CTX_LICENSE_CLIENT_INVALID"; else if (i_error==7056L) risultato="ERROR_CTX_LICENSE_EXPIRED"; else if (i_error==7057L) risultato="ERROR_CTX_SHADOW_NOT_RUNNING"; else if (i_error==7058L) risultato="ERROR_CTX_SHADOW_ENDED_BY_MODE_CHANGE"; else if (i_error==7059L) risultato="ERROR_ACTIVATION_COUNT_EXCEEDED"; else if (i_error==7060L) risultato="ERROR_CTX_WINSTATIONS_DISABLED"; else if (i_error==7061L) risultato="ERROR_CTX_ENCRYPTION_LEVEL_REQUIRED"; else if (i_error==7062L) risultato="ERROR_CTX_SESSION_IN_USE"; else if (i_error==7063L) risultato="ERROR_CTX_NO_FORCE_LOGOFF"; else if (i_error==7064L) risultato="ERROR_CTX_ACCOUNT_RESTRICTION"; else if (i_error==7065L) risultato="ERROR_RDP_PROTOCOL_ERROR"; else if (i_error==7066L) risultato="ERROR_CTX_CDM_CONNECT"; else if (i_error==7067L) risultato="ERROR_CTX_CDM_DISCONNECT"; else if (i_error==7068L) risultato="ERROR_CTX_SECURITY_LAYER_ERROR"; else if (i_error==7069L) risultato="ERROR_TS_INCOMPATIBLE_SESSIONS"; else if (i_error==7070L) risultato="ERROR_TS_VIDEO_SUBSYSTEM_ERROR"; else if (i_error==8001L) risultato="FRS_ERR_INVALID_API_SEQUENCE"; else if (i_error==8002L) risultato="FRS_ERR_STARTING_SERVICE"; else if (i_error==8003L) risultato="FRS_ERR_STOPPING_SERVICE"; else if (i_error==8004L) risultato="FRS_ERR_INTERNAL_API"; else if (i_error==8005L) risultato="FRS_ERR_INTERNAL"; else if (i_error==8006L) risultato="FRS_ERR_SERVICE_COMM"; else if (i_error==8007L) risultato="FRS_ERR_INSUFFICIENT_PRIV"; else if (i_error==8008L) risultato="FRS_ERR_AUTHENTICATION"; else if (i_error==8009L) risultato="FRS_ERR_PARENT_INSUFFICIENT_PRIV"; else if (i_error==8010L) risultato="FRS_ERR_PARENT_AUTHENTICATION"; else if (i_error==8011L) risultato="FRS_ERR_CHILD_TO_PARENT_COMM"; else if (i_error==8012L) risultato="FRS_ERR_PARENT_TO_CHILD_COMM"; else if (i_error==8013L) risultato="FRS_ERR_SYSVOL_POPULATE"; else if (i_error==8014L) risultato="FRS_ERR_SYSVOL_POPULATE_TIMEOUT"; else if (i_error==8015L) risultato="FRS_ERR_SYSVOL_IS_BUSY"; else if (i_error==8016L) risultato="FRS_ERR_SYSVOL_DEMOTE"; else if (i_error==8017L) risultato="FRS_ERR_INVALID_SERVICE_PARAMETER"; else if (i_error==NO_ERROR) risultato="DS_S_SUCCESS"; else if (i_error==8200L) risultato="ERROR_DS_NOT_INSTALLED"; else if (i_error==8201L) risultato="ERROR_DS_MEMBERSHIP_EVALUATED_LOCALLY"; else if (i_error==8202L) risultato="ERROR_DS_NO_ATTRIBUTE_OR_VALUE"; else if (i_error==8203L) risultato="ERROR_DS_INVALID_ATTRIBUTE_SYNTAX"; else if (i_error==8204L) risultato="ERROR_DS_ATTRIBUTE_TYPE_UNDEFINED"; else if (i_error==8205L) risultato="ERROR_DS_ATTRIBUTE_OR_VALUE_EXISTS"; else if (i_error==8206L) risultato="ERROR_DS_BUSY"; else if (i_error==8207L) risultato="ERROR_DS_UNAVAILABLE"; else if (i_error==8208L) risultato="ERROR_DS_NO_RIDS_ALLOCATED"; else if (i_error==8209L) risultato="ERROR_DS_NO_MORE_RIDS"; else if (i_error==8210L) risultato="ERROR_DS_INCORRECT_ROLE_OWNER"; else if (i_error==8211L) risultato="ERROR_DS_RIDMGR_INIT_ERROR"; else if (i_error==8212L) risultato="ERROR_DS_OBJ_CLASS_VIOLATION"; else if (i_error==8213L) risultato="ERROR_DS_CANT_ON_NON_LEAF"; else if (i_error==8214L) risultato="ERROR_DS_CANT_ON_RDN"; else if (i_error==8215L) risultato="ERROR_DS_CANT_MOD_OBJ_CLASS"; else if (i_error==8216L) risultato="ERROR_DS_CROSS_DOM_MOVE_ERROR"; else if (i_error==8217L) risultato="ERROR_DS_GC_NOT_AVAILABLE"; else if (i_error==8218L) risultato="ERROR_SHARED_POLICY"; else if (i_error==8219L) risultato="ERROR_POLICY_OBJECT_NOT_FOUND"; else if (i_error==8220L) risultato="ERROR_POLICY_ONLY_IN_DS"; else if (i_error==8221L) risultato="ERROR_PROMOTION_ACTIVE"; else if (i_error==8222L) risultato="ERROR_NO_PROMOTION_ACTIVE"; else if (i_error==8224L) risultato="ERROR_DS_OPERATIONS_ERROR"; else if (i_error==8225L) risultato="ERROR_DS_PROTOCOL_ERROR"; else if (i_error==8226L) risultato="ERROR_DS_TIMELIMIT_EXCEEDED"; else if (i_error==8227L) risultato="ERROR_DS_SIZELIMIT_EXCEEDED"; else if (i_error==8228L) risultato="ERROR_DS_ADMIN_LIMIT_EXCEEDED"; else if (i_error==8229L) risultato="ERROR_DS_COMPARE_FALSE"; else if (i_error==8230L) risultato="ERROR_DS_COMPARE_TRUE"; else if (i_error==8231L) risultato="ERROR_DS_AUTH_METHOD_NOT_SUPPORTED"; else if (i_error==8232L) risultato="ERROR_DS_STRONG_AUTH_REQUIRED"; else if (i_error==8233L) risultato="ERROR_DS_INAPPROPRIATE_AUTH"; else if (i_error==8234L) risultato="ERROR_DS_AUTH_UNKNOWN"; else if (i_error==8235L) risultato="ERROR_DS_REFERRAL"; else if (i_error==8236L) risultato="ERROR_DS_UNAVAILABLE_CRIT_EXTENSION"; else if (i_error==8237L) risultato="ERROR_DS_CONFIDENTIALITY_REQUIRED"; else if (i_error==8238L) risultato="ERROR_DS_INAPPROPRIATE_MATCHING"; else if (i_error==8239L) risultato="ERROR_DS_CONSTRAINT_VIOLATION"; else if (i_error==8240L) risultato="ERROR_DS_NO_SUCH_OBJECT"; else if (i_error==8241L) risultato="ERROR_DS_ALIAS_PROBLEM"; else if (i_error==8242L) risultato="ERROR_DS_INVALID_DN_SYNTAX"; else if (i_error==8243L) risultato="ERROR_DS_IS_LEAF"; else if (i_error==8244L) risultato="ERROR_DS_ALIAS_DEREF_PROBLEM"; else if (i_error==8245L) risultato="ERROR_DS_UNWILLING_TO_PERFORM"; else if (i_error==8246L) risultato="ERROR_DS_LOOP_DETECT"; else if (i_error==8247L) risultato="ERROR_DS_NAMING_VIOLATION"; else if (i_error==8248L) risultato="ERROR_DS_OBJECT_RESULTS_TOO_LARGE"; else if (i_error==8249L) risultato="ERROR_DS_AFFECTS_MULTIPLE_DSAS"; else if (i_error==8250L) risultato="ERROR_DS_SERVER_DOWN"; else if (i_error==8251L) risultato="ERROR_DS_LOCAL_ERROR"; else if (i_error==8252L) risultato="ERROR_DS_ENCODING_ERROR"; else if (i_error==8253L) risultato="ERROR_DS_DECODING_ERROR"; else if (i_error==8254L) risultato="ERROR_DS_FILTER_UNKNOWN"; else if (i_error==8255L) risultato="ERROR_DS_PARAM_ERROR"; else if (i_error==8256L) risultato="ERROR_DS_NOT_SUPPORTED"; else if (i_error==8257L) risultato="ERROR_DS_NO_RESULTS_RETURNED"; else if (i_error==8258L) risultato="ERROR_DS_CONTROL_NOT_FOUND"; else if (i_error==8259L) risultato="ERROR_DS_CLIENT_LOOP"; else if (i_error==8260L) risultato="ERROR_DS_REFERRAL_LIMIT_EXCEEDED"; else if (i_error==8261L) risultato="ERROR_DS_SORT_CONTROL_MISSING"; else if (i_error==8262L) risultato="ERROR_DS_OFFSET_RANGE_ERROR"; else if (i_error==8263L) risultato="ERROR_DS_RIDMGR_DISABLED"; else if (i_error==8301L) risultato="ERROR_DS_ROOT_MUST_BE_NC"; else if (i_error==8302L) risultato="ERROR_DS_ADD_REPLICA_INHIBITED"; else if (i_error==8303L) risultato="ERROR_DS_ATT_NOT_DEF_IN_SCHEMA"; else if (i_error==8304L) risultato="ERROR_DS_MAX_OBJ_SIZE_EXCEEDED"; else if (i_error==8305L) risultato="ERROR_DS_OBJ_STRING_NAME_EXISTS"; else if (i_error==8306L) risultato="ERROR_DS_NO_RDN_DEFINED_IN_SCHEMA"; else if (i_error==8307L) risultato="ERROR_DS_RDN_DOESNT_MATCH_SCHEMA"; else if (i_error==8308L) risultato="ERROR_DS_NO_REQUESTED_ATTS_FOUND"; else if (i_error==8309L) risultato="ERROR_DS_USER_BUFFER_TO_SMALL"; else if (i_error==8310L) risultato="ERROR_DS_ATT_IS_NOT_ON_OBJ"; else if (i_error==8311L) risultato="ERROR_DS_ILLEGAL_MOD_OPERATION"; else if (i_error==8312L) risultato="ERROR_DS_OBJ_TOO_LARGE"; else if (i_error==8313L) risultato="ERROR_DS_BAD_INSTANCE_TYPE"; else if (i_error==8314L) risultato="ERROR_DS_MASTERDSA_REQUIRED"; else if (i_error==8315L) risultato="ERROR_DS_OBJECT_CLASS_REQUIRED"; else if (i_error==8316L) risultato="ERROR_DS_MISSING_REQUIRED_ATT"; else if (i_error==8317L) risultato="ERROR_DS_ATT_NOT_DEF_FOR_CLASS"; else if (i_error==8318L) risultato="ERROR_DS_ATT_ALREADY_EXISTS"; else if (i_error==8320L) risultato="ERROR_DS_CANT_ADD_ATT_VALUES"; else if (i_error==8321L) risultato="ERROR_DS_SINGLE_VALUE_CONSTRAINT"; else if (i_error==8322L) risultato="ERROR_DS_RANGE_CONSTRAINT"; else if (i_error==8323L) risultato="ERROR_DS_ATT_VAL_ALREADY_EXISTS"; else if (i_error==8324L) risultato="ERROR_DS_CANT_REM_MISSING_ATT"; else if (i_error==8325L) risultato="ERROR_DS_CANT_REM_MISSING_ATT_VAL"; else if (i_error==8326L) risultato="ERROR_DS_ROOT_CANT_BE_SUBREF"; else if (i_error==8327L) risultato="ERROR_DS_NO_CHAINING"; else if (i_error==8328L) risultato="ERROR_DS_NO_CHAINED_EVAL"; else if (i_error==8329L) risultato="ERROR_DS_NO_PARENT_OBJECT"; else if (i_error==8330L) risultato="ERROR_DS_PARENT_IS_AN_ALIAS"; else if (i_error==8331L) risultato="ERROR_DS_CANT_MIX_MASTER_AND_REPS"; else if (i_error==8332L) risultato="ERROR_DS_CHILDREN_EXIST"; else if (i_error==8333L) risultato="ERROR_DS_OBJ_NOT_FOUND"; else if (i_error==8334L) risultato="ERROR_DS_ALIASED_OBJ_MISSING"; else if (i_error==8335L) risultato="ERROR_DS_BAD_NAME_SYNTAX"; else if (i_error==8336L) risultato="ERROR_DS_ALIAS_POINTS_TO_ALIAS"; else if (i_error==8337L) risultato="ERROR_DS_CANT_DEREF_ALIAS"; else if (i_error==8338L) risultato="ERROR_DS_OUT_OF_SCOPE"; else if (i_error==8339L) risultato="ERROR_DS_OBJECT_BEING_REMOVED"; else if (i_error==8340L) risultato="ERROR_DS_CANT_DELETE_DSA_OBJ"; else if (i_error==8341L) risultato="ERROR_DS_GENERIC_ERROR"; else if (i_error==8342L) risultato="ERROR_DS_DSA_MUST_BE_INT_MASTER"; else if (i_error==8343L) risultato="ERROR_DS_CLASS_NOT_DSA"; else if (i_error==8344L) risultato="ERROR_DS_INSUFF_ACCESS_RIGHTS"; else if (i_error==8345L) risultato="ERROR_DS_ILLEGAL_SUPERIOR"; else if (i_error==8346L) risultato="ERROR_DS_ATTRIBUTE_OWNED_BY_SAM"; else if (i_error==8347L) risultato="ERROR_DS_NAME_TOO_MANY_PARTS"; else if (i_error==8348L) risultato="ERROR_DS_NAME_TOO_LONG"; else if (i_error==8349L) risultato="ERROR_DS_NAME_VALUE_TOO_LONG"; else if (i_error==8350L) risultato="ERROR_DS_NAME_UNPARSEABLE"; else if (i_error==8351L) risultato="ERROR_DS_NAME_TYPE_UNKNOWN"; else if (i_error==8352L) risultato="ERROR_DS_NOT_AN_OBJECT"; else if (i_error==8353L) risultato="ERROR_DS_SEC_DESC_TOO_SHORT"; else if (i_error==8354L) risultato="ERROR_DS_SEC_DESC_INVALID"; else if (i_error==8355L) risultato="ERROR_DS_NO_DELETED_NAME"; else if (i_error==8356L) risultato="ERROR_DS_SUBREF_MUST_HAVE_PARENT"; else if (i_error==8357L) risultato="ERROR_DS_NCNAME_MUST_BE_NC"; else if (i_error==8358L) risultato="ERROR_DS_CANT_ADD_SYSTEM_ONLY"; else if (i_error==8359L) risultato="ERROR_DS_CLASS_MUST_BE_CONCRETE"; else if (i_error==8360L) risultato="ERROR_DS_INVALID_DMD"; else if (i_error==8361L) risultato="ERROR_DS_OBJ_GUID_EXISTS"; else if (i_error==8362L) risultato="ERROR_DS_NOT_ON_BACKLINK"; else if (i_error==8363L) risultato="ERROR_DS_NO_CROSSREF_FOR_NC"; else if (i_error==8364L) risultato="ERROR_DS_SHUTTING_DOWN"; else if (i_error==8365L) risultato="ERROR_DS_UNKNOWN_OPERATION"; else if (i_error==8366L) risultato="ERROR_DS_INVALID_ROLE_OWNER"; else if (i_error==8367L) risultato="ERROR_DS_COULDNT_CONTACT_FSMO"; else if (i_error==8368L) risultato="ERROR_DS_CROSS_NC_DN_RENAME"; else if (i_error==8369L) risultato="ERROR_DS_CANT_MOD_SYSTEM_ONLY"; else if (i_error==8370L) risultato="ERROR_DS_REPLICATOR_ONLY"; else if (i_error==8371L) risultato="ERROR_DS_OBJ_CLASS_NOT_DEFINED"; else if (i_error==8372L) risultato="ERROR_DS_OBJ_CLASS_NOT_SUBCLASS"; else if (i_error==8373L) risultato="ERROR_DS_NAME_REFERENCE_INVALID"; else if (i_error==8374L) risultato="ERROR_DS_CROSS_REF_EXISTS"; else if (i_error==8375L) risultato="ERROR_DS_CANT_DEL_MASTER_CROSSREF"; else if (i_error==8376L) risultato="ERROR_DS_SUBTREE_NOTIFY_NOT_NC_HEAD"; else if (i_error==8377L) risultato="ERROR_DS_NOTIFY_FILTER_TOO_COMPLEX"; else if (i_error==8378L) risultato="ERROR_DS_DUP_RDN"; else if (i_error==8379L) risultato="ERROR_DS_DUP_OID"; else if (i_error==8380L) risultato="ERROR_DS_DUP_MAPI_ID"; else if (i_error==8381L) risultato="ERROR_DS_DUP_SCHEMA_ID_GUID"; else if (i_error==8382L) risultato="ERROR_DS_DUP_LDAP_DISPLAY_NAME"; else if (i_error==8383L) risultato="ERROR_DS_SEMANTIC_ATT_TEST"; else if (i_error==8384L) risultato="ERROR_DS_SYNTAX_MISMATCH"; else if (i_error==8385L) risultato="ERROR_DS_EXISTS_IN_MUST_HAVE"; else if (i_error==8386L) risultato="ERROR_DS_EXISTS_IN_MAY_HAVE"; else if (i_error==8387L) risultato="ERROR_DS_NONEXISTENT_MAY_HAVE"; else if (i_error==8388L) risultato="ERROR_DS_NONEXISTENT_MUST_HAVE"; else if (i_error==8389L) risultato="ERROR_DS_AUX_CLS_TEST_FAIL"; else if (i_error==8390L) risultato="ERROR_DS_NONEXISTENT_POSS_SUP"; else if (i_error==8391L) risultato="ERROR_DS_SUB_CLS_TEST_FAIL"; else if (i_error==8392L) risultato="ERROR_DS_BAD_RDN_ATT_ID_SYNTAX"; else if (i_error==8393L) risultato="ERROR_DS_EXISTS_IN_AUX_CLS"; else if (i_error==8394L) risultato="ERROR_DS_EXISTS_IN_SUB_CLS"; else if (i_error==8395L) risultato="ERROR_DS_EXISTS_IN_POSS_SUP"; else if (i_error==8396L) risultato="ERROR_DS_RECALCSCHEMA_FAILED"; else if (i_error==8397L) risultato="ERROR_DS_TREE_DELETE_NOT_FINISHED"; else if (i_error==8398L) risultato="ERROR_DS_CANT_DELETE"; else if (i_error==8399L) risultato="ERROR_DS_ATT_SCHEMA_REQ_ID"; else if (i_error==8400L) risultato="ERROR_DS_BAD_ATT_SCHEMA_SYNTAX"; else if (i_error==8401L) risultato="ERROR_DS_CANT_CACHE_ATT"; else if (i_error==8402L) risultato="ERROR_DS_CANT_CACHE_CLASS"; else if (i_error==8403L) risultato="ERROR_DS_CANT_REMOVE_ATT_CACHE"; else if (i_error==8404L) risultato="ERROR_DS_CANT_REMOVE_CLASS_CACHE"; else if (i_error==8405L) risultato="ERROR_DS_CANT_RETRIEVE_DN"; else if (i_error==8406L) risultato="ERROR_DS_MISSING_SUPREF"; else if (i_error==8407L) risultato="ERROR_DS_CANT_RETRIEVE_INSTANCE"; else if (i_error==8408L) risultato="ERROR_DS_CODE_INCONSISTENCY"; else if (i_error==8409L) risultato="ERROR_DS_DATABASE_ERROR"; else if (i_error==8410L) risultato="ERROR_DS_GOVERNSID_MISSING"; else if (i_error==8411L) risultato="ERROR_DS_MISSING_EXPECTED_ATT"; else if (i_error==8412L) risultato="ERROR_DS_NCNAME_MISSING_CR_REF"; else if (i_error==8413L) risultato="ERROR_DS_SECURITY_CHECKING_ERROR"; else if (i_error==8414L) risultato="ERROR_DS_SCHEMA_NOT_LOADED"; else if (i_error==8415L) risultato="ERROR_DS_SCHEMA_ALLOC_FAILED"; else if (i_error==8416L) risultato="ERROR_DS_ATT_SCHEMA_REQ_SYNTAX"; else if (i_error==8417L) risultato="ERROR_DS_GCVERIFY_ERROR"; else if (i_error==8418L) risultato="ERROR_DS_DRA_SCHEMA_MISMATCH"; else if (i_error==8419L) risultato="ERROR_DS_CANT_FIND_DSA_OBJ"; else if (i_error==8420L) risultato="ERROR_DS_CANT_FIND_EXPECTED_NC"; else if (i_error==8421L) risultato="ERROR_DS_CANT_FIND_NC_IN_CACHE"; else if (i_error==8422L) risultato="ERROR_DS_CANT_RETRIEVE_CHILD"; else if (i_error==8423L) risultato="ERROR_DS_SECURITY_ILLEGAL_MODIFY"; else if (i_error==8424L) risultato="ERROR_DS_CANT_REPLACE_HIDDEN_REC"; else if (i_error==8425L) risultato="ERROR_DS_BAD_HIERARCHY_FILE"; else if (i_error==8426L) risultato="ERROR_DS_BUILD_HIERARCHY_TABLE_FAILED"; else if (i_error==8427L) risultato="ERROR_DS_CONFIG_PARAM_MISSING"; else if (i_error==8428L) risultato="ERROR_DS_COUNTING_AB_INDICES_FAILED"; else if (i_error==8429L) risultato="ERROR_DS_HIERARCHY_TABLE_MALLOC_FAILED"; else if (i_error==8430L) risultato="ERROR_DS_INTERNAL_FAILURE"; else if (i_error==8431L) risultato="ERROR_DS_UNKNOWN_ERROR"; else if (i_error==8432L) risultato="ERROR_DS_ROOT_REQUIRES_CLASS_TOP"; else if (i_error==8433L) risultato="ERROR_DS_REFUSING_FSMO_ROLES"; else if (i_error==8434L) risultato="ERROR_DS_MISSING_FSMO_SETTINGS"; else if (i_error==8435L) risultato="ERROR_DS_UNABLE_TO_SURRENDER_ROLES"; else if (i_error==8436L) risultato="ERROR_DS_DRA_GENERIC"; else if (i_error==8437L) risultato="ERROR_DS_DRA_INVALID_PARAMETER"; else if (i_error==8438L) risultato="ERROR_DS_DRA_BUSY"; else if (i_error==8439L) risultato="ERROR_DS_DRA_BAD_DN"; else if (i_error==8440L) risultato="ERROR_DS_DRA_BAD_NC"; else if (i_error==8441L) risultato="ERROR_DS_DRA_DN_EXISTS"; else if (i_error==8442L) risultato="ERROR_DS_DRA_INTERNAL_ERROR"; else if (i_error==8443L) risultato="ERROR_DS_DRA_INCONSISTENT_DIT"; else if (i_error==8444L) risultato="ERROR_DS_DRA_CONNECTION_FAILED"; else if (i_error==8445L) risultato="ERROR_DS_DRA_BAD_INSTANCE_TYPE"; else if (i_error==8446L) risultato="ERROR_DS_DRA_OUT_OF_MEM"; else if (i_error==8447L) risultato="ERROR_DS_DRA_MAIL_PROBLEM"; else if (i_error==8448L) risultato="ERROR_DS_DRA_REF_ALREADY_EXISTS"; else if (i_error==8449L) risultato="ERROR_DS_DRA_REF_NOT_FOUND"; else if (i_error==8450L) risultato="ERROR_DS_DRA_OBJ_IS_REP_SOURCE"; else if (i_error==8451L) risultato="ERROR_DS_DRA_DB_ERROR"; else if (i_error==8452L) risultato="ERROR_DS_DRA_NO_REPLICA"; else if (i_error==8453L) risultato="ERROR_DS_DRA_ACCESS_DENIED"; else if (i_error==8454L) risultato="ERROR_DS_DRA_NOT_SUPPORTED"; else if (i_error==8455L) risultato="ERROR_DS_DRA_RPC_CANCELLED"; else if (i_error==8456L) risultato="ERROR_DS_DRA_SOURCE_DISABLED"; else if (i_error==8457L) risultato="ERROR_DS_DRA_SINK_DISABLED"; else if (i_error==8458L) risultato="ERROR_DS_DRA_NAME_COLLISION"; else if (i_error==8459L) risultato="ERROR_DS_DRA_SOURCE_REINSTALLED"; else if (i_error==8460L) risultato="ERROR_DS_DRA_MISSING_PARENT"; else if (i_error==8461L) risultato="ERROR_DS_DRA_PREEMPTED"; else if (i_error==8462L) risultato="ERROR_DS_DRA_ABANDON_SYNC"; else if (i_error==8463L) risultato="ERROR_DS_DRA_SHUTDOWN"; else if (i_error==8464L) risultato="ERROR_DS_DRA_INCOMPATIBLE_PARTIAL_SET"; else if (i_error==8465L) risultato="ERROR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA"; else if (i_error==8466L) risultato="ERROR_DS_DRA_EXTN_CONNECTION_FAILED"; else if (i_error==8467L) risultato="ERROR_DS_INSTALL_SCHEMA_MISMATCH"; else if (i_error==8468L) risultato="ERROR_DS_DUP_LINK_ID"; else if (i_error==8469L) risultato="ERROR_DS_NAME_ERROR_RESOLVING"; else if (i_error==8470L) risultato="ERROR_DS_NAME_ERROR_NOT_FOUND"; else if (i_error==8471L) risultato="ERROR_DS_NAME_ERROR_NOT_UNIQUE"; else if (i_error==8472L) risultato="ERROR_DS_NAME_ERROR_NO_MAPPING"; else if (i_error==8473L) risultato="ERROR_DS_NAME_ERROR_DOMAIN_ONLY"; else if (i_error==8474L) risultato="ERROR_DS_NAME_ERROR_NO_SYNTACTICAL_MAPPING"; else if (i_error==8475L) risultato="ERROR_DS_CONSTRUCTED_ATT_MOD"; else if (i_error==8476L) risultato="ERROR_DS_WRONG_OM_OBJ_CLASS"; else if (i_error==8477L) risultato="ERROR_DS_DRA_REPL_PENDING"; else if (i_error==8478L) risultato="ERROR_DS_DS_REQUIRED"; else if (i_error==8479L) risultato="ERROR_DS_INVALID_LDAP_DISPLAY_NAME"; else if (i_error==8480L) risultato="ERROR_DS_NON_BASE_SEARCH"; else if (i_error==8481L) risultato="ERROR_DS_CANT_RETRIEVE_ATTS"; else if (i_error==8482L) risultato="ERROR_DS_BACKLINK_WITHOUT_LINK"; else if (i_error==8483L) risultato="ERROR_DS_EPOCH_MISMATCH"; else if (i_error==8484L) risultato="ERROR_DS_SRC_NAME_MISMATCH"; else if (i_error==8485L) risultato="ERROR_DS_SRC_AND_DST_NC_IDENTICAL"; else if (i_error==8486L) risultato="ERROR_DS_DST_NC_MISMATCH"; else if (i_error==8487L) risultato="ERROR_DS_NOT_AUTHORITIVE_FOR_DST_NC"; else if (i_error==8488L) risultato="ERROR_DS_SRC_GUID_MISMATCH"; else if (i_error==8489L) risultato="ERROR_DS_CANT_MOVE_DELETED_OBJECT"; else if (i_error==8490L) risultato="ERROR_DS_PDC_OPERATION_IN_PROGRESS"; else if (i_error==8491L) risultato="ERROR_DS_CROSS_DOMAIN_CLEANUP_REQD"; else if (i_error==8492L) risultato="ERROR_DS_ILLEGAL_XDOM_MOVE_OPERATION"; else if (i_error==8493L) risultato="ERROR_DS_CANT_WITH_ACCT_GROUP_MEMBERSHPS"; else if (i_error==8494L) risultato="ERROR_DS_NC_MUST_HAVE_NC_PARENT"; else if (i_error==8495L) risultato="ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE"; else if (i_error==8496L) risultato="ERROR_DS_DST_DOMAIN_NOT_NATIVE"; else if (i_error==8497L) risultato="ERROR_DS_MISSING_INFRASTRUCTURE_CONTAINER"; else if (i_error==8498L) risultato="ERROR_DS_CANT_MOVE_ACCOUNT_GROUP"; else if (i_error==8499L) risultato="ERROR_DS_CANT_MOVE_RESOURCE_GROUP"; else if (i_error==8500L) risultato="ERROR_DS_INVALID_SEARCH_FLAG"; else if (i_error==8501L) risultato="ERROR_DS_NO_TREE_DELETE_ABOVE_NC"; else if (i_error==8502L) risultato="ERROR_DS_COULDNT_LOCK_TREE_FOR_DELETE"; else if (i_error==8503L) risultato="ERROR_DS_COULDNT_IDENTIFY_OBJECTS_FOR_TREE_DELETE"; else if (i_error==8504L) risultato="ERROR_DS_SAM_INIT_FAILURE"; else if (i_error==8505L) risultato="ERROR_DS_SENSITIVE_GROUP_VIOLATION"; else if (i_error==8506L) risultato="ERROR_DS_CANT_MOD_PRIMARYGROUPID"; else if (i_error==8507L) risultato="ERROR_DS_ILLEGAL_BASE_SCHEMA_MOD"; else if (i_error==8508L) risultato="ERROR_DS_NONSAFE_SCHEMA_CHANGE"; else if (i_error==8509L) risultato="ERROR_DS_SCHEMA_UPDATE_DISALLOWED"; else if (i_error==8510L) risultato="ERROR_DS_CANT_CREATE_UNDER_SCHEMA"; else if (i_error==8511L) risultato="ERROR_DS_INSTALL_NO_SRC_SCH_VERSION"; else if (i_error==8512L) risultato="ERROR_DS_INSTALL_NO_SCH_VERSION_IN_INIFILE"; else if (i_error==8513L) risultato="ERROR_DS_INVALID_GROUP_TYPE"; else if (i_error==8514L) risultato="ERROR_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN"; else if (i_error==8515L) risultato="ERROR_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN"; else if (i_error==8516L) risultato="ERROR_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER"; else if (i_error==8517L) risultato="ERROR_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER"; else if (i_error==8518L) risultato="ERROR_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER"; else if (i_error==8519L) risultato="ERROR_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER"; else if (i_error==8520L) risultato="ERROR_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER"; else if (i_error==8521L) risultato="ERROR_DS_HAVE_PRIMARY_MEMBERS"; else if (i_error==8522L) risultato="ERROR_DS_STRING_SD_CONVERSION_FAILED"; else if (i_error==8523L) risultato="ERROR_DS_NAMING_MASTER_GC"; else if (i_error==8524L) risultato="ERROR_DS_DNS_LOOKUP_FAILURE"; else if (i_error==8525L) risultato="ERROR_DS_COULDNT_UPDATE_SPNS"; else if (i_error==8526L) risultato="ERROR_DS_CANT_RETRIEVE_SD"; else if (i_error==8527L) risultato="ERROR_DS_KEY_NOT_UNIQUE"; else if (i_error==8528L) risultato="ERROR_DS_WRONG_LINKED_ATT_SYNTAX"; else if (i_error==8529L) risultato="ERROR_DS_SAM_NEED_BOOTKEY_PASSWORD"; else if (i_error==8530L) risultato="ERROR_DS_SAM_NEED_BOOTKEY_FLOPPY"; else if (i_error==8531L) risultato="ERROR_DS_CANT_START"; else if (i_error==8532L) risultato="ERROR_DS_INIT_FAILURE"; else if (i_error==8533L) risultato="ERROR_DS_NO_PKT_PRIVACY_ON_CONNECTION"; else if (i_error==8534L) risultato="ERROR_DS_SOURCE_DOMAIN_IN_FOREST"; else if (i_error==8535L) risultato="ERROR_DS_DESTINATION_DOMAIN_NOT_IN_FOREST"; else if (i_error==8536L) risultato="ERROR_DS_DESTINATION_AUDITING_NOT_ENABLED"; else if (i_error==8537L) risultato="ERROR_DS_CANT_FIND_DC_FOR_SRC_DOMAIN"; else if (i_error==8538L) risultato="ERROR_DS_SRC_OBJ_NOT_GROUP_OR_USER"; else if (i_error==8539L) risultato="ERROR_DS_SRC_SID_EXISTS_IN_FOREST"; else if (i_error==8540L) risultato="ERROR_DS_SRC_AND_DST_OBJECT_CLASS_MISMATCH"; else if (i_error==8541L) risultato="ERROR_SAM_INIT_FAILURE"; else if (i_error==8542L) risultato="ERROR_DS_DRA_SCHEMA_INFO_SHIP"; else if (i_error==8543L) risultato="ERROR_DS_DRA_SCHEMA_CONFLICT"; else if (i_error==8544L) risultato="ERROR_DS_DRA_EARLIER_SCHEMA_CONFLICT"; else if (i_error==8545L) risultato="ERROR_DS_DRA_OBJ_NC_MISMATCH"; else if (i_error==8546L) risultato="ERROR_DS_NC_STILL_HAS_DSAS"; else if (i_error==8547L) risultato="ERROR_DS_GC_REQUIRED"; else if (i_error==8548L) risultato="ERROR_DS_LOCAL_MEMBER_OF_LOCAL_ONLY"; else if (i_error==8549L) risultato="ERROR_DS_NO_FPO_IN_UNIVERSAL_GROUPS"; else if (i_error==8550L) risultato="ERROR_DS_CANT_ADD_TO_GC"; else if (i_error==8551L) risultato="ERROR_DS_NO_CHECKPOINT_WITH_PDC"; else if (i_error==8552L) risultato="ERROR_DS_SOURCE_AUDITING_NOT_ENABLED"; else if (i_error==8553L) risultato="ERROR_DS_CANT_CREATE_IN_NONDOMAIN_NC"; else if (i_error==8554L) risultato="ERROR_DS_INVALID_NAME_FOR_SPN"; else if (i_error==8555L) risultato="ERROR_DS_FILTER_USES_CONTRUCTED_ATTRS"; else if (i_error==8556L) risultato="ERROR_DS_UNICODEPWD_NOT_IN_QUOTES"; else if (i_error==8557L) risultato="ERROR_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED"; else if (i_error==8558L) risultato="ERROR_DS_MUST_BE_RUN_ON_DST_DC"; else if (i_error==8559L) risultato="ERROR_DS_SRC_DC_MUST_BE_SP4_OR_GREATER"; else if (i_error==8560L) risultato="ERROR_DS_CANT_TREE_DELETE_CRITICAL_OBJ"; else if (i_error==8561L) risultato="ERROR_DS_INIT_FAILURE_CONSOLE"; else if (i_error==8562L) risultato="ERROR_DS_SAM_INIT_FAILURE_CONSOLE"; else if (i_error==8563L) risultato="ERROR_DS_FOREST_VERSION_TOO_HIGH"; else if (i_error==8564L) risultato="ERROR_DS_DOMAIN_VERSION_TOO_HIGH"; else if (i_error==8565L) risultato="ERROR_DS_FOREST_VERSION_TOO_LOW"; else if (i_error==8566L) risultato="ERROR_DS_DOMAIN_VERSION_TOO_LOW"; else if (i_error==8567L) risultato="ERROR_DS_INCOMPATIBLE_VERSION"; else if (i_error==8568L) risultato="ERROR_DS_LOW_DSA_VERSION"; else if (i_error==8569L) risultato="ERROR_DS_NO_BEHAVIOR_VERSION_IN_MIXEDDOMAIN"; else if (i_error==8570L) risultato="ERROR_DS_NOT_SUPPORTED_SORT_ORDER"; else if (i_error==8571L) risultato="ERROR_DS_NAME_NOT_UNIQUE"; else if (i_error==8572L) risultato="ERROR_DS_MACHINE_ACCOUNT_CREATED_PRENT4"; else if (i_error==8573L) risultato="ERROR_DS_OUT_OF_VERSION_STORE"; else if (i_error==8574L) risultato="ERROR_DS_INCOMPATIBLE_CONTROLS_USED"; else if (i_error==8575L) risultato="ERROR_DS_NO_REF_DOMAIN"; else if (i_error==8576L) risultato="ERROR_DS_RESERVED_LINK_ID"; else if (i_error==8577L) risultato="ERROR_DS_LINK_ID_NOT_AVAILABLE"; else if (i_error==8578L) risultato="ERROR_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER"; else if (i_error==8579L) risultato="ERROR_DS_MODIFYDN_DISALLOWED_BY_INSTANCE_TYPE"; else if (i_error==8580L) risultato="ERROR_DS_NO_OBJECT_MOVE_IN_SCHEMA_NC"; else if (i_error==8581L) risultato="ERROR_DS_MODIFYDN_DISALLOWED_BY_FLAG"; else if (i_error==8582L) risultato="ERROR_DS_MODIFYDN_WRONG_GRANDPARENT"; else if (i_error==8583L) risultato="ERROR_DS_NAME_ERROR_TRUST_REFERRAL"; else if (i_error==8584L) risultato="ERROR_NOT_SUPPORTED_ON_STANDARD_SERVER"; else if (i_error==8585L) risultato="ERROR_DS_CANT_ACCESS_REMOTE_PART_OF_AD"; else if (i_error==8586L) risultato="ERROR_DS_CR_IMPOSSIBLE_TO_VALIDATE_V2"; else if (i_error==8587L) risultato="ERROR_DS_THREAD_LIMIT_EXCEEDED"; else if (i_error==8588L) risultato="ERROR_DS_NOT_CLOSEST"; else if (i_error==8589L) risultato="ERROR_DS_CANT_DERIVE_SPN_WITHOUT_SERVER_REF"; else if (i_error==8590L) risultato="ERROR_DS_SINGLE_USER_MODE_FAILED"; else if (i_error==8591L) risultato="ERROR_DS_NTDSCRIPT_SYNTAX_ERROR"; else if (i_error==8592L) risultato="ERROR_DS_NTDSCRIPT_PROCESS_ERROR"; else if (i_error==8593L) risultato="ERROR_DS_DIFFERENT_REPL_EPOCHS"; else if (i_error==8594L) risultato="ERROR_DS_DRS_EXTENSIONS_CHANGED"; else if (i_error==8595L) risultato="ERROR_DS_REPLICA_SET_CHANGE_NOT_ALLOWED_ON_DISABLED_CR"; else if (i_error==8596L) risultato="ERROR_DS_NO_MSDS_INTID"; else if (i_error==8597L) risultato="ERROR_DS_DUP_MSDS_INTID"; else if (i_error==8598L) risultato="ERROR_DS_EXISTS_IN_RDNATTID"; else if (i_error==8599L) risultato="ERROR_DS_AUTHORIZATION_FAILED"; else if (i_error==8600L) risultato="ERROR_DS_INVALID_SCRIPT"; else if (i_error==8601L) risultato="ERROR_DS_REMOTE_CROSSREF_OP_FAILED"; else if (i_error==8602L) risultato="ERROR_DS_CROSS_REF_BUSY"; else if (i_error==8603L) risultato="ERROR_DS_CANT_DERIVE_SPN_FOR_DELETED_DOMAIN"; else if (i_error==8604L) risultato="ERROR_DS_CANT_DEMOTE_WITH_WRITEABLE_NC"; else if (i_error==8605L) risultato="ERROR_DS_DUPLICATE_ID_FOUND"; else if (i_error==8606L) risultato="ERROR_DS_INSUFFICIENT_ATTR_TO_CREATE_OBJECT"; else if (i_error==8607L) risultato="ERROR_DS_GROUP_CONVERSION_ERROR"; else if (i_error==8608L) risultato="ERROR_DS_CANT_MOVE_APP_BASIC_GROUP"; else if (i_error==8609L) risultato="ERROR_DS_CANT_MOVE_APP_QUERY_GROUP"; else if (i_error==8610L) risultato="ERROR_DS_ROLE_NOT_VERIFIED"; else if (i_error==8611L) risultato="ERROR_DS_WKO_CONTAINER_CANNOT_BE_SPECIAL"; else if (i_error==8612L) risultato="ERROR_DS_DOMAIN_RENAME_IN_PROGRESS"; else if (i_error==8613L) risultato="ERROR_DS_EXISTING_AD_CHILD_NC"; else if (i_error==8614L) risultato="ERROR_DS_REPL_LIFETIME_EXCEEDED"; else if (i_error==8615L) risultato="ERROR_DS_DISALLOWED_IN_SYSTEM_CONTAINER"; else if (i_error==8616L) risultato="ERROR_DS_LDAP_SEND_QUEUE_FULL"; else if (i_error==8617L) risultato="ERROR_DS_DRA_OUT_SCHEDULE_WINDOW"; else if (i_error==8618L) risultato="ERROR_DS_POLICY_NOT_KNOWN"; else if (i_error==8619L) risultato="ERROR_NO_SITE_SETTINGS_OBJECT"; else if (i_error==8620L) risultato="ERROR_NO_SECRETS"; else if (i_error==8621L) risultato="ERROR_NO_WRITABLE_DC_FOUND"; else if (i_error==8622L) risultato="ERROR_DS_NO_SERVER_OBJECT"; else if (i_error==8623L) risultato="ERROR_DS_NO_NTDSA_OBJECT"; else if (i_error==8624L) risultato="ERROR_DS_NON_ASQ_SEARCH"; else if (i_error==8625L) risultato="ERROR_DS_AUDIT_FAILURE"; else if (i_error==8626L) risultato="ERROR_DS_INVALID_SEARCH_FLAG_SUBTREE"; else if (i_error==8627L) risultato="ERROR_DS_INVALID_SEARCH_FLAG_TUPLE"; else if (i_error==8628L) risultato="ERROR_DS_HIERARCHY_TABLE_TOO_DEEP"; else if (i_error==8629L) risultato="ERROR_DS_DRA_CORRUPT_UTD_VECTOR"; else if (i_error==8630L) risultato="ERROR_DS_DRA_SECRETS_DENIED"; else if (i_error==8631L) risultato="ERROR_DS_RESERVED_MAPI_ID"; else if (i_error==8632L) risultato="ERROR_DS_MAPI_ID_NOT_AVAILABLE"; else if (i_error==8633L) risultato="ERROR_DS_DRA_MISSING_KRBTGT_SECRET"; else if (i_error==8634L) risultato="ERROR_DS_DOMAIN_NAME_EXISTS_IN_FOREST"; else if (i_error==8635L) risultato="ERROR_DS_FLAT_NAME_EXISTS_IN_FOREST"; else if (i_error==8636L) risultato="ERROR_INVALID_USER_PRINCIPAL_NAME"; else if (i_error==8637L) risultato="ERROR_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS"; else if (i_error==8638L) risultato="ERROR_DS_OID_NOT_FOUND"; else if (i_error==8639L) risultato="ERROR_DS_DRA_RECYCLED_TARGET"; else if (i_error==8640L) risultato="ERROR_DS_DISALLOWED_NC_REDIRECT"; else if (i_error==8641L) risultato="ERROR_DS_HIGH_ADLDS_FFL"; else if (i_error==8642L) risultato="ERROR_DS_HIGH_DSA_VERSION"; else if (i_error==8643L) risultato="ERROR_DS_LOW_ADLDS_FFL"; else if (i_error==8644L) risultato="ERROR_DOMAIN_SID_SAME_AS_LOCAL_WORKSTATION"; else if (i_error==8645L) risultato="ERROR_DS_UNDELETE_SAM_VALIDATION_FAILED"; else if (i_error==8646L) risultato="ERROR_INCORRECT_ACCOUNT_TYPE"; else if (i_error==8647L) risultato="ERROR_DS_SPN_VALUE_NOT_UNIQUE_IN_FOREST"; else if (i_error==8648L) risultato="ERROR_DS_UPN_VALUE_NOT_UNIQUE_IN_FOREST"; else if (i_error==8649L) risultato="ERROR_DS_MISSING_FOREST_TRUST"; else if (i_error==8650L) risultato="ERROR_DS_VALUE_KEY_NOT_UNIQUE"; else if (i_error==9000) risultato="DNS_ERROR_RESPONSE_CODES_BASE"; else if (i_error==NO_ERROR) risultato="DNS_ERROR_RCODE_NO_ERROR"; else if (i_error==0x00002328) risultato="DNS_ERROR_MASK"; else if (i_error==9001L) risultato="DNS_ERROR_RCODE_FORMAT_ERROR"; else if (i_error==9002L) risultato="DNS_ERROR_RCODE_SERVER_FAILURE"; else if (i_error==9003L) risultato="DNS_ERROR_RCODE_NAME_ERROR"; else if (i_error==9004L) risultato="DNS_ERROR_RCODE_NOT_IMPLEMENTED"; else if (i_error==9005L) risultato="DNS_ERROR_RCODE_REFUSED"; else if (i_error==9006L) risultato="DNS_ERROR_RCODE_YXDOMAIN"; else if (i_error==9007L) risultato="DNS_ERROR_RCODE_YXRRSET"; else if (i_error==9008L) risultato="DNS_ERROR_RCODE_NXRRSET"; else if (i_error==9009L) risultato="DNS_ERROR_RCODE_NOTAUTH"; else if (i_error==9010L) risultato="DNS_ERROR_RCODE_NOTZONE"; else if (i_error==9016L) risultato="DNS_ERROR_RCODE_BADSIG"; else if (i_error==9017L) risultato="DNS_ERROR_RCODE_BADKEY"; else if (i_error==9018L) risultato="DNS_ERROR_RCODE_BADTIME"; else if (i_error==DNS_ERROR_RCODE_BADTIME) risultato="DNS_ERROR_RCODE_LAST"; else if (i_error==9100) risultato="DNS_ERROR_DNSSEC_BASE"; else if (i_error==9101L) risultato="DNS_ERROR_KEYMASTER_REQUIRED"; else if (i_error==9102L) risultato="DNS_ERROR_NOT_ALLOWED_ON_SIGNED_ZONE"; else if (i_error==9103L) risultato="DNS_ERROR_NSEC3_INCOMPATIBLE_WITH_RSA_SHA1"; else if (i_error==9104L) risultato="DNS_ERROR_NOT_ENOUGH_SIGNING_KEY_DESCRIPTORS"; else if (i_error==9105L) risultato="DNS_ERROR_UNSUPPORTED_ALGORITHM"; else if (i_error==9106L) risultato="DNS_ERROR_INVALID_KEY_SIZE"; else if (i_error==9107L) risultato="DNS_ERROR_SIGNING_KEY_NOT_ACCESSIBLE"; else if (i_error==9108L) risultato="DNS_ERROR_KSP_DOES_NOT_SUPPORT_PROTECTION"; else if (i_error==9109L) risultato="DNS_ERROR_UNEXPECTED_DATA_PROTECTION_ERROR"; else if (i_error==9110L) risultato="DNS_ERROR_UNEXPECTED_CNG_ERROR"; else if (i_error==9111L) risultato="DNS_ERROR_UNKNOWN_SIGNING_PARAMETER_VERSION"; else if (i_error==9112L) risultato="DNS_ERROR_KSP_NOT_ACCESSIBLE"; else if (i_error==9113L) risultato="DNS_ERROR_TOO_MANY_SKDS"; else if (i_error==9114L) risultato="DNS_ERROR_INVALID_ROLLOVER_PERIOD"; else if (i_error==9115L) risultato="DNS_ERROR_INVALID_INITIAL_ROLLOVER_OFFSET"; else if (i_error==9116L) risultato="DNS_ERROR_ROLLOVER_IN_PROGRESS"; else if (i_error==9117L) risultato="DNS_ERROR_STANDBY_KEY_NOT_PRESENT"; else if (i_error==9118L) risultato="DNS_ERROR_NOT_ALLOWED_ON_ZSK"; else if (i_error==9119L) risultato="DNS_ERROR_NOT_ALLOWED_ON_ACTIVE_SKD"; else if (i_error==9120L) risultato="DNS_ERROR_ROLLOVER_ALREADY_QUEUED"; else if (i_error==9121L) risultato="DNS_ERROR_NOT_ALLOWED_ON_UNSIGNED_ZONE"; else if (i_error==9122L) risultato="DNS_ERROR_BAD_KEYMASTER"; else if (i_error==9123L) risultato="DNS_ERROR_INVALID_SIGNATURE_VALIDITY_PERIOD"; else if (i_error==9124L) risultato="DNS_ERROR_INVALID_NSEC3_ITERATION_COUNT"; else if (i_error==9125L) risultato="DNS_ERROR_DNSSEC_IS_DISABLED"; else if (i_error==9126L) risultato="DNS_ERROR_INVALID_XML"; else if (i_error==9127L) risultato="DNS_ERROR_NO_VALID_TRUST_ANCHORS"; else if (i_error==9128L) risultato="DNS_ERROR_ROLLOVER_NOT_POKEABLE"; else if (i_error==9129L) risultato="DNS_ERROR_NSEC3_NAME_COLLISION"; else if (i_error==9130L) risultato="DNS_ERROR_NSEC_INCOMPATIBLE_WITH_NSEC3_RSA_SHA1"; else if (i_error==9500) risultato="DNS_ERROR_PACKET_FMT_BASE"; else if (i_error==9501L) risultato="DNS_INFO_NO_RECORDS"; else if (i_error==9502L) risultato="DNS_ERROR_BAD_PACKET"; else if (i_error==9503L) risultato="DNS_ERROR_NO_PACKET"; else if (i_error==9504L) risultato="DNS_ERROR_RCODE"; else if (i_error==9505L) risultato="DNS_ERROR_UNSECURE_PACKET"; else if (i_error==DNS_ERROR_UNSECURE_PACKET) risultato="DNS_STATUS_PACKET_UNSECURE"; else if (i_error==9506L) risultato="DNS_REQUEST_PENDING"; else if (i_error==ERROR_OUTOFMEMORY) risultato="DNS_ERROR_NO_MEMORY"; else if (i_error==ERROR_INVALID_NAME) risultato="DNS_ERROR_INVALID_NAME"; else if (i_error==ERROR_INVALID_DATA) risultato="DNS_ERROR_INVALID_DATA"; else if (i_error==9550) risultato="DNS_ERROR_GENERAL_API_BASE"; else if (i_error==9551L) risultato="DNS_ERROR_INVALID_TYPE"; else if (i_error==9552L) risultato="DNS_ERROR_INVALID_IP_ADDRESS"; else if (i_error==9553L) risultato="DNS_ERROR_INVALID_PROPERTY"; else if (i_error==9554L) risultato="DNS_ERROR_TRY_AGAIN_LATER"; else if (i_error==9555L) risultato="DNS_ERROR_NOT_UNIQUE"; else if (i_error==9556L) risultato="DNS_ERROR_NON_RFC_NAME"; else if (i_error==9557L) risultato="DNS_STATUS_FQDN"; else if (i_error==9558L) risultato="DNS_STATUS_DOTTED_NAME"; else if (i_error==9559L) risultato="DNS_STATUS_SINGLE_PART_NAME"; else if (i_error==9560L) risultato="DNS_ERROR_INVALID_NAME_CHAR"; else if (i_error==9561L) risultato="DNS_ERROR_NUMERIC_NAME"; else if (i_error==9562L) risultato="DNS_ERROR_NOT_ALLOWED_ON_ROOT_SERVER"; else if (i_error==9563L) risultato="DNS_ERROR_NOT_ALLOWED_UNDER_DELEGATION"; else if (i_error==9564L) risultato="DNS_ERROR_CANNOT_FIND_ROOT_HINTS"; else if (i_error==9565L) risultato="DNS_ERROR_INCONSISTENT_ROOT_HINTS"; else if (i_error==9566L) risultato="DNS_ERROR_DWORD_VALUE_TOO_SMALL"; else if (i_error==9567L) risultato="DNS_ERROR_DWORD_VALUE_TOO_LARGE"; else if (i_error==9568L) risultato="DNS_ERROR_BACKGROUND_LOADING"; else if (i_error==9569L) risultato="DNS_ERROR_NOT_ALLOWED_ON_RODC"; else if (i_error==9570L) risultato="DNS_ERROR_NOT_ALLOWED_UNDER_DNAME"; else if (i_error==9571L) risultato="DNS_ERROR_DELEGATION_REQUIRED"; else if (i_error==9572L) risultato="DNS_ERROR_INVALID_POLICY_TABLE"; else if (i_error==9573L) risultato="DNS_ERROR_ADDRESS_REQUIRED"; else if (i_error==9600) risultato="DNS_ERROR_ZONE_BASE"; else if (i_error==9601L) risultato="DNS_ERROR_ZONE_DOES_NOT_EXIST"; else if (i_error==9602L) risultato="DNS_ERROR_NO_ZONE_INFO"; else if (i_error==9603L) risultato="DNS_ERROR_INVALID_ZONE_OPERATION"; else if (i_error==9604L) risultato="DNS_ERROR_ZONE_CONFIGURATION_ERROR"; else if (i_error==9605L) risultato="DNS_ERROR_ZONE_HAS_NO_SOA_RECORD"; else if (i_error==9606L) risultato="DNS_ERROR_ZONE_HAS_NO_NS_RECORDS"; else if (i_error==9607L) risultato="DNS_ERROR_ZONE_LOCKED"; else if (i_error==9608L) risultato="DNS_ERROR_ZONE_CREATION_FAILED"; else if (i_error==9609L) risultato="DNS_ERROR_ZONE_ALREADY_EXISTS"; else if (i_error==9610L) risultato="DNS_ERROR_AUTOZONE_ALREADY_EXISTS"; else if (i_error==9611L) risultato="DNS_ERROR_INVALID_ZONE_TYPE"; else if (i_error==9612L) risultato="DNS_ERROR_SECONDARY_REQUIRES_MASTER_IP"; else if (i_error==9613L) risultato="DNS_ERROR_ZONE_NOT_SECONDARY"; else if (i_error==9614L) risultato="DNS_ERROR_NEED_SECONDARY_ADDRESSES"; else if (i_error==9615L) risultato="DNS_ERROR_WINS_INIT_FAILED"; else if (i_error==9616L) risultato="DNS_ERROR_NEED_WINS_SERVERS"; else if (i_error==9617L) risultato="DNS_ERROR_NBSTAT_INIT_FAILED"; else if (i_error==9618L) risultato="DNS_ERROR_SOA_DELETE_INVALID"; else if (i_error==9619L) risultato="DNS_ERROR_FORWARDER_ALREADY_EXISTS"; else if (i_error==9620L) risultato="DNS_ERROR_ZONE_REQUIRES_MASTER_IP"; else if (i_error==9621L) risultato="DNS_ERROR_ZONE_IS_SHUTDOWN"; else if (i_error==9622L) risultato="DNS_ERROR_ZONE_LOCKED_FOR_SIGNING"; else if (i_error==9650) risultato="DNS_ERROR_DATAFILE_BASE"; else if (i_error==9651L) risultato="DNS_ERROR_PRIMARY_REQUIRES_DATAFILE"; else if (i_error==9652L) risultato="DNS_ERROR_INVALID_DATAFILE_NAME"; else if (i_error==9653L) risultato="DNS_ERROR_DATAFILE_OPEN_FAILURE"; else if (i_error==9654L) risultato="DNS_ERROR_FILE_WRITEBACK_FAILED"; else if (i_error==9655L) risultato="DNS_ERROR_DATAFILE_PARSING"; else if (i_error==9700) risultato="DNS_ERROR_DATABASE_BASE"; else if (i_error==9701L) risultato="DNS_ERROR_RECORD_DOES_NOT_EXIST"; else if (i_error==9702L) risultato="DNS_ERROR_RECORD_FORMAT"; else if (i_error==9703L) risultato="DNS_ERROR_NODE_CREATION_FAILED"; else if (i_error==9704L) risultato="DNS_ERROR_UNKNOWN_RECORD_TYPE"; else if (i_error==9705L) risultato="DNS_ERROR_RECORD_TIMED_OUT"; else if (i_error==9706L) risultato="DNS_ERROR_NAME_NOT_IN_ZONE"; else if (i_error==9707L) risultato="DNS_ERROR_CNAME_LOOP"; else if (i_error==9708L) risultato="DNS_ERROR_NODE_IS_CNAME"; else if (i_error==9709L) risultato="DNS_ERROR_CNAME_COLLISION"; else if (i_error==9710L) risultato="DNS_ERROR_RECORD_ONLY_AT_ZONE_ROOT"; else if (i_error==9711L) risultato="DNS_ERROR_RECORD_ALREADY_EXISTS"; else if (i_error==9712L) risultato="DNS_ERROR_SECONDARY_DATA"; else if (i_error==9713L) risultato="DNS_ERROR_NO_CREATE_CACHE_DATA"; else if (i_error==9714L) risultato="DNS_ERROR_NAME_DOES_NOT_EXIST"; else if (i_error==9715L) risultato="DNS_WARNING_PTR_CREATE_FAILED"; else if (i_error==9716L) risultato="DNS_WARNING_DOMAIN_UNDELETED"; else if (i_error==9717L) risultato="DNS_ERROR_DS_UNAVAILABLE"; else if (i_error==9718L) risultato="DNS_ERROR_DS_ZONE_ALREADY_EXISTS"; else if (i_error==9719L) risultato="DNS_ERROR_NO_BOOTFILE_IF_DS_ZONE"; else if (i_error==9720L) risultato="DNS_ERROR_NODE_IS_DNAME"; else if (i_error==9721L) risultato="DNS_ERROR_DNAME_COLLISION"; else if (i_error==9722L) risultato="DNS_ERROR_ALIAS_LOOP"; else if (i_error==9750) risultato="DNS_ERROR_OPERATION_BASE"; else if (i_error==9751L) risultato="DNS_INFO_AXFR_COMPLETE"; else if (i_error==9752L) risultato="DNS_ERROR_AXFR"; else if (i_error==9753L) risultato="DNS_INFO_ADDED_LOCAL_WINS"; else if (i_error==9800) risultato="DNS_ERROR_SECURE_BASE"; else if (i_error==9801L) risultato="DNS_STATUS_CONTINUE_NEEDED"; else if (i_error==9850) risultato="DNS_ERROR_SETUP_BASE"; else if (i_error==9851L) risultato="DNS_ERROR_NO_TCPIP"; else if (i_error==9852L) risultato="DNS_ERROR_NO_DNS_SERVERS"; else if (i_error==9900) risultato="DNS_ERROR_DP_BASE"; else if (i_error==9901L) risultato="DNS_ERROR_DP_DOES_NOT_EXIST"; else if (i_error==9902L) risultato="DNS_ERROR_DP_ALREADY_EXISTS"; else if (i_error==9903L) risultato="DNS_ERROR_DP_NOT_ENLISTED"; else if (i_error==9904L) risultato="DNS_ERROR_DP_ALREADY_ENLISTED"; else if (i_error==9905L) risultato="DNS_ERROR_DP_NOT_AVAILABLE"; else if (i_error==9906L) risultato="DNS_ERROR_DP_FSMO_ERROR"; else if (i_error==9911L) risultato="DNS_ERROR_RRL_NOT_ENABLED"; else if (i_error==9912L) risultato="DNS_ERROR_RRL_INVALID_WINDOW_SIZE"; else if (i_error==9913L) risultato="DNS_ERROR_RRL_INVALID_IPV4_PREFIX"; else if (i_error==9914L) risultato="DNS_ERROR_RRL_INVALID_IPV6_PREFIX"; else if (i_error==9915L) risultato="DNS_ERROR_RRL_INVALID_TC_RATE"; else if (i_error==9916L) risultato="DNS_ERROR_RRL_INVALID_LEAK_RATE"; else if (i_error==9917L) risultato="DNS_ERROR_RRL_LEAK_RATE_LESSTHAN_TC_RATE"; else if (i_error==9921L) risultato="DNS_ERROR_VIRTUALIZATION_INSTANCE_ALREADY_EXISTS"; else if (i_error==9922L) risultato="DNS_ERROR_VIRTUALIZATION_INSTANCE_DOES_NOT_EXIST"; else if (i_error==9923L) risultato="DNS_ERROR_VIRTUALIZATION_TREE_LOCKED"; else if (i_error==9924L) risultato="DNS_ERROR_INVAILD_VIRTUALIZATION_INSTANCE_NAME"; else if (i_error==9925L) risultato="DNS_ERROR_DEFAULT_VIRTUALIZATION_INSTANCE"; else if (i_error==9951L) risultato="DNS_ERROR_ZONESCOPE_ALREADY_EXISTS"; else if (i_error==9952L) risultato="DNS_ERROR_ZONESCOPE_DOES_NOT_EXIST"; else if (i_error==9953L) risultato="DNS_ERROR_DEFAULT_ZONESCOPE"; else if (i_error==9954L) risultato="DNS_ERROR_INVALID_ZONESCOPE_NAME"; else if (i_error==9955L) risultato="DNS_ERROR_NOT_ALLOWED_WITH_ZONESCOPES"; else if (i_error==9956L) risultato="DNS_ERROR_LOAD_ZONESCOPE_FAILED"; else if (i_error==9957L) risultato="DNS_ERROR_ZONESCOPE_FILE_WRITEBACK_FAILED"; else if (i_error==9958L) risultato="DNS_ERROR_INVALID_SCOPE_NAME"; else if (i_error==9959L) risultato="DNS_ERROR_SCOPE_DOES_NOT_EXIST"; else if (i_error==9960L) risultato="DNS_ERROR_DEFAULT_SCOPE"; else if (i_error==9961L) risultato="DNS_ERROR_INVALID_SCOPE_OPERATION"; else if (i_error==9962L) risultato="DNS_ERROR_SCOPE_LOCKED"; else if (i_error==9963L) risultato="DNS_ERROR_SCOPE_ALREADY_EXISTS"; else if (i_error==9971L) risultato="DNS_ERROR_POLICY_ALREADY_EXISTS"; else if (i_error==9972L) risultato="DNS_ERROR_POLICY_DOES_NOT_EXIST"; else if (i_error==9973L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA"; else if (i_error==9974L) risultato="DNS_ERROR_POLICY_INVALID_SETTINGS"; else if (i_error==9975L) risultato="DNS_ERROR_CLIENT_SUBNET_IS_ACCESSED"; else if (i_error==9976L) risultato="DNS_ERROR_CLIENT_SUBNET_DOES_NOT_EXIST"; else if (i_error==9977L) risultato="DNS_ERROR_CLIENT_SUBNET_ALREADY_EXISTS"; else if (i_error==9978L) risultato="DNS_ERROR_SUBNET_DOES_NOT_EXIST"; else if (i_error==9979L) risultato="DNS_ERROR_SUBNET_ALREADY_EXISTS"; else if (i_error==9980L) risultato="DNS_ERROR_POLICY_LOCKED"; else if (i_error==9981L) risultato="DNS_ERROR_POLICY_INVALID_WEIGHT"; else if (i_error==9982L) risultato="DNS_ERROR_POLICY_INVALID_NAME"; else if (i_error==9983L) risultato="DNS_ERROR_POLICY_MISSING_CRITERIA"; else if (i_error==9984L) risultato="DNS_ERROR_INVALID_CLIENT_SUBNET_NAME"; else if (i_error==9985L) risultato="DNS_ERROR_POLICY_PROCESSING_ORDER_INVALID"; else if (i_error==9986L) risultato="DNS_ERROR_POLICY_SCOPE_MISSING"; else if (i_error==9987L) risultato="DNS_ERROR_POLICY_SCOPE_NOT_ALLOWED"; else if (i_error==9988L) risultato="DNS_ERROR_SERVERSCOPE_IS_REFERENCED"; else if (i_error==9989L) risultato="DNS_ERROR_ZONESCOPE_IS_REFERENCED"; else if (i_error==9990L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_CLIENT_SUBNET"; else if (i_error==9991L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_TRANSPORT_PROTOCOL"; else if (i_error==9992L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_NETWORK_PROTOCOL"; else if (i_error==9993L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_INTERFACE"; else if (i_error==9994L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_FQDN"; else if (i_error==9995L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_QUERY_TYPE"; else if (i_error==9996L) risultato="DNS_ERROR_POLICY_INVALID_CRITERIA_TIME_OF_DAY"; else if (i_error==10000) risultato="WSABASEERR"; else if (i_error==10004L) risultato="WSAEINTR"; else if (i_error==10009L) risultato="WSAEBADF"; else if (i_error==10013L) risultato="WSAEACCES"; else if (i_error==10014L) risultato="WSAEFAULT"; else if (i_error==10022L) risultato="WSAEINVAL"; else if (i_error==10024L) risultato="WSAEMFILE"; else if (i_error==10035L) risultato="WSAEWOULDBLOCK"; else if (i_error==10036L) risultato="WSAEINPROGRESS"; else if (i_error==10037L) risultato="WSAEALREADY"; else if (i_error==10038L) risultato="WSAENOTSOCK"; else if (i_error==10039L) risultato="WSAEDESTADDRREQ"; else if (i_error==10040L) risultato="WSAEMSGSIZE"; else if (i_error==10041L) risultato="WSAEPROTOTYPE"; else if (i_error==10042L) risultato="WSAENOPROTOOPT"; else if (i_error==10043L) risultato="WSAEPROTONOSUPPORT"; else if (i_error==10044L) risultato="WSAESOCKTNOSUPPORT"; else if (i_error==10045L) risultato="WSAEOPNOTSUPP"; else if (i_error==10046L) risultato="WSAEPFNOSUPPORT"; else if (i_error==10047L) risultato="WSAEAFNOSUPPORT"; else if (i_error==10048L) risultato="WSAEADDRINUSE"; else if (i_error==10049L) risultato="WSAEADDRNOTAVAIL"; else if (i_error==10050L) risultato="WSAENETDOWN"; else if (i_error==10051L) risultato="WSAENETUNREACH"; else if (i_error==10052L) risultato="WSAENETRESET"; else if (i_error==10053L) risultato="WSAECONNABORTED"; else if (i_error==10054L) risultato="WSAECONNRESET"; else if (i_error==10055L) risultato="WSAENOBUFS"; else if (i_error==10056L) risultato="WSAEISCONN"; else if (i_error==10057L) risultato="WSAENOTCONN"; else if (i_error==10058L) risultato="WSAESHUTDOWN"; else if (i_error==10059L) risultato="WSAETOOMANYREFS"; else if (i_error==10060L) risultato="WSAETIMEDOUT"; else if (i_error==10061L) risultato="WSAECONNREFUSED"; else if (i_error==10062L) risultato="WSAELOOP"; else if (i_error==10063L) risultato="WSAENAMETOOLONG"; else if (i_error==10064L) risultato="WSAEHOSTDOWN"; else if (i_error==10065L) risultato="WSAEHOSTUNREACH"; else if (i_error==10066L) risultato="WSAENOTEMPTY"; else if (i_error==10067L) risultato="WSAEPROCLIM"; else if (i_error==10068L) risultato="WSAEUSERS"; else if (i_error==10069L) risultato="WSAEDQUOT"; else if (i_error==10070L) risultato="WSAESTALE"; else if (i_error==10071L) risultato="WSAEREMOTE"; else if (i_error==10091L) risultato="WSASYSNOTREADY"; else if (i_error==10092L) risultato="WSAVERNOTSUPPORTED"; else if (i_error==10093L) risultato="WSANOTINITIALISED"; else if (i_error==10101L) risultato="WSAEDISCON"; else if (i_error==10102L) risultato="WSAENOMORE"; else if (i_error==10103L) risultato="WSAECANCELLED"; else if (i_error==10104L) risultato="WSAEINVALIDPROCTABLE"; else if (i_error==10105L) risultato="WSAEINVALIDPROVIDER"; else if (i_error==10106L) risultato="WSAEPROVIDERFAILEDINIT"; else if (i_error==10107L) risultato="WSASYSCALLFAILURE"; else if (i_error==10108L) risultato="WSASERVICE_NOT_FOUND"; else if (i_error==10109L) risultato="WSATYPE_NOT_FOUND"; else if (i_error==10110L) risultato="WSA_E_NO_MORE"; else if (i_error==10111L) risultato="WSA_E_CANCELLED"; else if (i_error==10112L) risultato="WSAEREFUSED"; else if (i_error==11001L) risultato="WSAHOST_NOT_FOUND"; else if (i_error==11002L) risultato="WSATRY_AGAIN"; else if (i_error==11003L) risultato="WSANO_RECOVERY"; else if (i_error==11004L) risultato="WSANO_DATA"; else if (i_error==11005L) risultato="WSA_QOS_RECEIVERS"; else if (i_error==11006L) risultato="WSA_QOS_SENDERS"; else if (i_error==11007L) risultato="WSA_QOS_NO_SENDERS"; else if (i_error==11008L) risultato="WSA_QOS_NO_RECEIVERS"; else if (i_error==11009L) risultato="WSA_QOS_REQUEST_CONFIRMED"; else if (i_error==11010L) risultato="WSA_QOS_ADMISSION_FAILURE"; else if (i_error==11011L) risultato="WSA_QOS_POLICY_FAILURE"; else if (i_error==11012L) risultato="WSA_QOS_BAD_STYLE"; else if (i_error==11013L) risultato="WSA_QOS_BAD_OBJECT"; else if (i_error==11014L) risultato="WSA_QOS_TRAFFIC_CTRL_ERROR"; else if (i_error==11015L) risultato="WSA_QOS_GENERIC_ERROR"; else if (i_error==11016L) risultato="WSA_QOS_ESERVICETYPE"; else if (i_error==11017L) risultato="WSA_QOS_EFLOWSPEC"; else if (i_error==11018L) risultato="WSA_QOS_EPROVSPECBUF"; else if (i_error==11019L) risultato="WSA_QOS_EFILTERSTYLE"; else if (i_error==11020L) risultato="WSA_QOS_EFILTERTYPE"; else if (i_error==11021L) risultato="WSA_QOS_EFILTERCOUNT"; else if (i_error==11022L) risultato="WSA_QOS_EOBJLENGTH"; else if (i_error==11023L) risultato="WSA_QOS_EFLOWCOUNT"; else if (i_error==11024L) risultato="WSA_QOS_EUNKOWNPSOBJ"; else if (i_error==11025L) risultato="WSA_QOS_EPOLICYOBJ"; else if (i_error==11026L) risultato="WSA_QOS_EFLOWDESC"; else if (i_error==11027L) risultato="WSA_QOS_EPSFLOWSPEC"; else if (i_error==11028L) risultato="WSA_QOS_EPSFILTERSPEC"; else if (i_error==11029L) risultato="WSA_QOS_ESDMODEOBJ"; else if (i_error==11030L) risultato="WSA_QOS_ESHAPERATEOBJ"; else if (i_error==11031L) risultato="WSA_QOS_RESERVED_PETYPE"; else if (i_error==11032L) risultato="WSA_SECURE_HOST_NOT_FOUND"; else if (i_error==11033L) risultato="WSA_IPSEC_NAME_POLICY_ERROR"; else if (i_error==13000L) risultato="ERROR_IPSEC_QM_POLICY_EXISTS"; else if (i_error==13001L) risultato="ERROR_IPSEC_QM_POLICY_NOT_FOUND"; else if (i_error==13002L) risultato="ERROR_IPSEC_QM_POLICY_IN_USE"; else if (i_error==13003L) risultato="ERROR_IPSEC_MM_POLICY_EXISTS"; else if (i_error==13004L) risultato="ERROR_IPSEC_MM_POLICY_NOT_FOUND"; else if (i_error==13005L) risultato="ERROR_IPSEC_MM_POLICY_IN_USE"; else if (i_error==13006L) risultato="ERROR_IPSEC_MM_FILTER_EXISTS"; else if (i_error==13007L) risultato="ERROR_IPSEC_MM_FILTER_NOT_FOUND"; else if (i_error==13008L) risultato="ERROR_IPSEC_TRANSPORT_FILTER_EXISTS"; else if (i_error==13009L) risultato="ERROR_IPSEC_TRANSPORT_FILTER_NOT_FOUND"; else if (i_error==13010L) risultato="ERROR_IPSEC_MM_AUTH_EXISTS"; else if (i_error==13011L) risultato="ERROR_IPSEC_MM_AUTH_NOT_FOUND"; else if (i_error==13012L) risultato="ERROR_IPSEC_MM_AUTH_IN_USE"; else if (i_error==13013L) risultato="ERROR_IPSEC_DEFAULT_MM_POLICY_NOT_FOUND"; else if (i_error==13014L) risultato="ERROR_IPSEC_DEFAULT_MM_AUTH_NOT_FOUND"; else if (i_error==13015L) risultato="ERROR_IPSEC_DEFAULT_QM_POLICY_NOT_FOUND"; else if (i_error==13016L) risultato="ERROR_IPSEC_TUNNEL_FILTER_EXISTS"; else if (i_error==13017L) risultato="ERROR_IPSEC_TUNNEL_FILTER_NOT_FOUND"; else if (i_error==13018L) risultato="ERROR_IPSEC_MM_FILTER_PENDING_DELETION"; else if (i_error==13019L) risultato="ERROR_IPSEC_TRANSPORT_FILTER_PENDING_DELETION"; else if (i_error==13020L) risultato="ERROR_IPSEC_TUNNEL_FILTER_PENDING_DELETION"; else if (i_error==13021L) risultato="ERROR_IPSEC_MM_POLICY_PENDING_DELETION"; else if (i_error==13022L) risultato="ERROR_IPSEC_MM_AUTH_PENDING_DELETION"; else if (i_error==13023L) risultato="ERROR_IPSEC_QM_POLICY_PENDING_DELETION"; else if (i_error==13024L) risultato="WARNING_IPSEC_MM_POLICY_PRUNED"; else if (i_error==13025L) risultato="WARNING_IPSEC_QM_POLICY_PRUNED"; else if (i_error==13800L) risultato="ERROR_IPSEC_IKE_NEG_STATUS_BEGIN"; else if (i_error==13801L) risultato="ERROR_IPSEC_IKE_AUTH_FAIL"; else if (i_error==13802L) risultato="ERROR_IPSEC_IKE_ATTRIB_FAIL"; else if (i_error==13803L) risultato="ERROR_IPSEC_IKE_NEGOTIATION_PENDING"; else if (i_error==13804L) risultato="ERROR_IPSEC_IKE_GENERAL_PROCESSING_ERROR"; else if (i_error==13805L) risultato="ERROR_IPSEC_IKE_TIMED_OUT"; else if (i_error==13806L) risultato="ERROR_IPSEC_IKE_NO_CERT"; else if (i_error==13807L) risultato="ERROR_IPSEC_IKE_SA_DELETED"; else if (i_error==13808L) risultato="ERROR_IPSEC_IKE_SA_REAPED"; else if (i_error==13809L) risultato="ERROR_IPSEC_IKE_MM_ACQUIRE_DROP"; else if (i_error==13810L) risultato="ERROR_IPSEC_IKE_QM_ACQUIRE_DROP"; else if (i_error==13811L) risultato="ERROR_IPSEC_IKE_QUEUE_DROP_MM"; else if (i_error==13812L) risultato="ERROR_IPSEC_IKE_QUEUE_DROP_NO_MM"; else if (i_error==13813L) risultato="ERROR_IPSEC_IKE_DROP_NO_RESPONSE"; else if (i_error==13814L) risultato="ERROR_IPSEC_IKE_MM_DELAY_DROP"; else if (i_error==13815L) risultato="ERROR_IPSEC_IKE_QM_DELAY_DROP"; else if (i_error==13816L) risultato="ERROR_IPSEC_IKE_ERROR"; else if (i_error==13817L) risultato="ERROR_IPSEC_IKE_CRL_FAILED"; else if (i_error==13818L) risultato="ERROR_IPSEC_IKE_INVALID_KEY_USAGE"; else if (i_error==13819L) risultato="ERROR_IPSEC_IKE_INVALID_CERT_TYPE"; else if (i_error==13820L) risultato="ERROR_IPSEC_IKE_NO_PRIVATE_KEY"; else if (i_error==13821L) risultato="ERROR_IPSEC_IKE_SIMULTANEOUS_REKEY"; else if (i_error==13822L) risultato="ERROR_IPSEC_IKE_DH_FAIL"; else if (i_error==13823L) risultato="ERROR_IPSEC_IKE_CRITICAL_PAYLOAD_NOT_RECOGNIZED"; else if (i_error==13824L) risultato="ERROR_IPSEC_IKE_INVALID_HEADER"; else if (i_error==13825L) risultato="ERROR_IPSEC_IKE_NO_POLICY"; else if (i_error==13826L) risultato="ERROR_IPSEC_IKE_INVALID_SIGNATURE"; else if (i_error==13827L) risultato="ERROR_IPSEC_IKE_KERBEROS_ERROR"; else if (i_error==13828L) risultato="ERROR_IPSEC_IKE_NO_PUBLIC_KEY"; else if (i_error==13829L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR"; else if (i_error==13830L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_SA"; else if (i_error==13831L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_PROP"; else if (i_error==13832L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_TRANS"; else if (i_error==13833L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_KE"; else if (i_error==13834L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_ID"; else if (i_error==13835L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_CERT"; else if (i_error==13836L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_CERT_REQ"; else if (i_error==13837L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_HASH"; else if (i_error==13838L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_SIG"; else if (i_error==13839L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_NONCE"; else if (i_error==13840L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_NOTIFY"; else if (i_error==13841L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_DELETE"; else if (i_error==13842L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_VENDOR"; else if (i_error==13843L) risultato="ERROR_IPSEC_IKE_INVALID_PAYLOAD"; else if (i_error==13844L) risultato="ERROR_IPSEC_IKE_LOAD_SOFT_SA"; else if (i_error==13845L) risultato="ERROR_IPSEC_IKE_SOFT_SA_TORN_DOWN"; else if (i_error==13846L) risultato="ERROR_IPSEC_IKE_INVALID_COOKIE"; else if (i_error==13847L) risultato="ERROR_IPSEC_IKE_NO_PEER_CERT"; else if (i_error==13848L) risultato="ERROR_IPSEC_IKE_PEER_CRL_FAILED"; else if (i_error==13849L) risultato="ERROR_IPSEC_IKE_POLICY_CHANGE"; else if (i_error==13850L) risultato="ERROR_IPSEC_IKE_NO_MM_POLICY"; else if (i_error==13851L) risultato="ERROR_IPSEC_IKE_NOTCBPRIV"; else if (i_error==13852L) risultato="ERROR_IPSEC_IKE_SECLOADFAIL"; else if (i_error==13853L) risultato="ERROR_IPSEC_IKE_FAILSSPINIT"; else if (i_error==13854L) risultato="ERROR_IPSEC_IKE_FAILQUERYSSP"; else if (i_error==13855L) risultato="ERROR_IPSEC_IKE_SRVACQFAIL"; else if (i_error==13856L) risultato="ERROR_IPSEC_IKE_SRVQUERYCRED"; else if (i_error==13857L) risultato="ERROR_IPSEC_IKE_GETSPIFAIL"; else if (i_error==13858L) risultato="ERROR_IPSEC_IKE_INVALID_FILTER"; else if (i_error==13859L) risultato="ERROR_IPSEC_IKE_OUT_OF_MEMORY"; else if (i_error==13860L) risultato="ERROR_IPSEC_IKE_ADD_UPDATE_KEY_FAILED"; else if (i_error==13861L) risultato="ERROR_IPSEC_IKE_INVALID_POLICY"; else if (i_error==13862L) risultato="ERROR_IPSEC_IKE_UNKNOWN_DOI"; else if (i_error==13863L) risultato="ERROR_IPSEC_IKE_INVALID_SITUATION"; else if (i_error==13864L) risultato="ERROR_IPSEC_IKE_DH_FAILURE"; else if (i_error==13865L) risultato="ERROR_IPSEC_IKE_INVALID_GROUP"; else if (i_error==13866L) risultato="ERROR_IPSEC_IKE_ENCRYPT"; else if (i_error==13867L) risultato="ERROR_IPSEC_IKE_DECRYPT"; else if (i_error==13868L) risultato="ERROR_IPSEC_IKE_POLICY_MATCH"; else if (i_error==13869L) risultato="ERROR_IPSEC_IKE_UNSUPPORTED_ID"; else if (i_error==13870L) risultato="ERROR_IPSEC_IKE_INVALID_HASH"; else if (i_error==13871L) risultato="ERROR_IPSEC_IKE_INVALID_HASH_ALG"; else if (i_error==13872L) risultato="ERROR_IPSEC_IKE_INVALID_HASH_SIZE"; else if (i_error==13873L) risultato="ERROR_IPSEC_IKE_INVALID_ENCRYPT_ALG"; else if (i_error==13874L) risultato="ERROR_IPSEC_IKE_INVALID_AUTH_ALG"; else if (i_error==13875L) risultato="ERROR_IPSEC_IKE_INVALID_SIG"; else if (i_error==13876L) risultato="ERROR_IPSEC_IKE_LOAD_FAILED"; else if (i_error==13877L) risultato="ERROR_IPSEC_IKE_RPC_DELETE"; else if (i_error==13878L) risultato="ERROR_IPSEC_IKE_BENIGN_REINIT"; else if (i_error==13879L) risultato="ERROR_IPSEC_IKE_INVALID_RESPONDER_LIFETIME_NOTIFY"; else if (i_error==13880L) risultato="ERROR_IPSEC_IKE_INVALID_MAJOR_VERSION"; else if (i_error==13881L) risultato="ERROR_IPSEC_IKE_INVALID_CERT_KEYLEN"; else if (i_error==13882L) risultato="ERROR_IPSEC_IKE_MM_LIMIT"; else if (i_error==13883L) risultato="ERROR_IPSEC_IKE_NEGOTIATION_DISABLED"; else if (i_error==13884L) risultato="ERROR_IPSEC_IKE_QM_LIMIT"; else if (i_error==13885L) risultato="ERROR_IPSEC_IKE_MM_EXPIRED"; else if (i_error==13886L) risultato="ERROR_IPSEC_IKE_PEER_MM_ASSUMED_INVALID"; else if (i_error==13887L) risultato="ERROR_IPSEC_IKE_CERT_CHAIN_POLICY_MISMATCH"; else if (i_error==13888L) risultato="ERROR_IPSEC_IKE_UNEXPECTED_MESSAGE_ID"; else if (i_error==13889L) risultato="ERROR_IPSEC_IKE_INVALID_AUTH_PAYLOAD"; else if (i_error==13890L) risultato="ERROR_IPSEC_IKE_DOS_COOKIE_SENT"; else if (i_error==13891L) risultato="ERROR_IPSEC_IKE_SHUTTING_DOWN"; else if (i_error==13892L) risultato="ERROR_IPSEC_IKE_CGA_AUTH_FAILED"; else if (i_error==13893L) risultato="ERROR_IPSEC_IKE_PROCESS_ERR_NATOA"; else if (i_error==13894L) risultato="ERROR_IPSEC_IKE_INVALID_MM_FOR_QM"; else if (i_error==13895L) risultato="ERROR_IPSEC_IKE_QM_EXPIRED"; else if (i_error==13896L) risultato="ERROR_IPSEC_IKE_TOO_MANY_FILTERS"; else if (i_error==13897L) risultato="ERROR_IPSEC_IKE_NEG_STATUS_END"; else if (i_error==13898L) risultato="ERROR_IPSEC_IKE_KILL_DUMMY_NAP_TUNNEL"; else if (i_error==13899L) risultato="ERROR_IPSEC_IKE_INNER_IP_ASSIGNMENT_FAILURE"; else if (i_error==13900L) risultato="ERROR_IPSEC_IKE_REQUIRE_CP_PAYLOAD_MISSING"; else if (i_error==13901L) risultato="ERROR_IPSEC_KEY_MODULE_IMPERSONATION_NEGOTIATION_PENDING"; else if (i_error==13902L) risultato="ERROR_IPSEC_IKE_COEXISTENCE_SUPPRESS"; else if (i_error==13903L) risultato="ERROR_IPSEC_IKE_RATELIMIT_DROP"; else if (i_error==13904L) risultato="ERROR_IPSEC_IKE_PEER_DOESNT_SUPPORT_MOBIKE"; else if (i_error==13905L) risultato="ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE"; else if (i_error==13906L) risultato="ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_FAILURE"; else if (i_error==13907L) risultato="ERROR_IPSEC_IKE_AUTHORIZATION_FAILURE_WITH_OPTIONAL_RETRY"; else if (i_error==13908L) risultato="ERROR_IPSEC_IKE_STRONG_CRED_AUTHORIZATION_AND_CERTMAP_FAILURE"; else if (i_error==13909L) risultato="ERROR_IPSEC_IKE_NEG_STATUS_EXTENDED_END"; else if (i_error==13910L) risultato="ERROR_IPSEC_BAD_SPI"; else if (i_error==13911L) risultato="ERROR_IPSEC_SA_LIFETIME_EXPIRED"; else if (i_error==13912L) risultato="ERROR_IPSEC_WRONG_SA"; else if (i_error==13913L) risultato="ERROR_IPSEC_REPLAY_CHECK_FAILED"; else if (i_error==13914L) risultato="ERROR_IPSEC_INVALID_PACKET"; else if (i_error==13915L) risultato="ERROR_IPSEC_INTEGRITY_CHECK_FAILED"; else if (i_error==13916L) risultato="ERROR_IPSEC_CLEAR_TEXT_DROP"; else if (i_error==13917L) risultato="ERROR_IPSEC_AUTH_FIREWALL_DROP"; else if (i_error==13918L) risultato="ERROR_IPSEC_THROTTLE_DROP"; else if (i_error==13925L) risultato="ERROR_IPSEC_DOSP_BLOCK"; else if (i_error==13926L) risultato="ERROR_IPSEC_DOSP_RECEIVED_MULTICAST"; else if (i_error==13927L) risultato="ERROR_IPSEC_DOSP_INVALID_PACKET"; else if (i_error==13928L) risultato="ERROR_IPSEC_DOSP_STATE_LOOKUP_FAILED"; else if (i_error==13929L) risultato="ERROR_IPSEC_DOSP_MAX_ENTRIES"; else if (i_error==13930L) risultato="ERROR_IPSEC_DOSP_KEYMOD_NOT_ALLOWED"; else if (i_error==13931L) risultato="ERROR_IPSEC_DOSP_NOT_INSTALLED"; else if (i_error==13932L) risultato="ERROR_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES"; else if (i_error==14000L) risultato="ERROR_SXS_SECTION_NOT_FOUND"; else if (i_error==14001L) risultato="ERROR_SXS_CANT_GEN_ACTCTX"; else if (i_error==14002L) risultato="ERROR_SXS_INVALID_ACTCTXDATA_FORMAT"; else if (i_error==14003L) risultato="ERROR_SXS_ASSEMBLY_NOT_FOUND"; else if (i_error==14004L) risultato="ERROR_SXS_MANIFEST_FORMAT_ERROR"; else if (i_error==14005L) risultato="ERROR_SXS_MANIFEST_PARSE_ERROR"; else if (i_error==14006L) risultato="ERROR_SXS_ACTIVATION_CONTEXT_DISABLED"; else if (i_error==14007L) risultato="ERROR_SXS_KEY_NOT_FOUND"; else if (i_error==14008L) risultato="ERROR_SXS_VERSION_CONFLICT"; else if (i_error==14009L) risultato="ERROR_SXS_WRONG_SECTION_TYPE"; else if (i_error==14010L) risultato="ERROR_SXS_THREAD_QUERIES_DISABLED"; else if (i_error==14011L) risultato="ERROR_SXS_PROCESS_DEFAULT_ALREADY_SET"; else if (i_error==14012L) risultato="ERROR_SXS_UNKNOWN_ENCODING_GROUP"; else if (i_error==14013L) risultato="ERROR_SXS_UNKNOWN_ENCODING"; else if (i_error==14014L) risultato="ERROR_SXS_INVALID_XML_NAMESPACE_URI"; else if (i_error==14015L) risultato="ERROR_SXS_ROOT_MANIFEST_DEPENDENCY_NOT_INSTALLED"; else if (i_error==14016L) risultato="ERROR_SXS_LEAF_MANIFEST_DEPENDENCY_NOT_INSTALLED"; else if (i_error==14017L) risultato="ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE"; else if (i_error==14018L) risultato="ERROR_SXS_MANIFEST_MISSING_REQUIRED_DEFAULT_NAMESPACE"; else if (i_error==14019L) risultato="ERROR_SXS_MANIFEST_INVALID_REQUIRED_DEFAULT_NAMESPACE"; else if (i_error==14020L) risultato="ERROR_SXS_PRIVATE_MANIFEST_CROSS_PATH_WITH_REPARSE_POINT"; else if (i_error==14021L) risultato="ERROR_SXS_DUPLICATE_DLL_NAME"; else if (i_error==14022L) risultato="ERROR_SXS_DUPLICATE_WINDOWCLASS_NAME"; else if (i_error==14023L) risultato="ERROR_SXS_DUPLICATE_CLSID"; else if (i_error==14024L) risultato="ERROR_SXS_DUPLICATE_IID"; else if (i_error==14025L) risultato="ERROR_SXS_DUPLICATE_TLBID"; else if (i_error==14026L) risultato="ERROR_SXS_DUPLICATE_PROGID"; else if (i_error==14027L) risultato="ERROR_SXS_DUPLICATE_ASSEMBLY_NAME"; else if (i_error==14028L) risultato="ERROR_SXS_FILE_HASH_MISMATCH"; else if (i_error==14029L) risultato="ERROR_SXS_POLICY_PARSE_ERROR"; else if (i_error==14030L) risultato="ERROR_SXS_XML_E_MISSINGQUOTE"; else if (i_error==14031L) risultato="ERROR_SXS_XML_E_COMMENTSYNTAX"; else if (i_error==14032L) risultato="ERROR_SXS_XML_E_BADSTARTNAMECHAR"; else if (i_error==14033L) risultato="ERROR_SXS_XML_E_BADNAMECHAR"; else if (i_error==14034L) risultato="ERROR_SXS_XML_E_BADCHARINSTRING"; else if (i_error==14035L) risultato="ERROR_SXS_XML_E_XMLDECLSYNTAX"; else if (i_error==14036L) risultato="ERROR_SXS_XML_E_BADCHARDATA"; else if (i_error==14037L) risultato="ERROR_SXS_XML_E_MISSINGWHITESPACE"; else if (i_error==14038L) risultato="ERROR_SXS_XML_E_EXPECTINGTAGEND"; else if (i_error==14039L) risultato="ERROR_SXS_XML_E_MISSINGSEMICOLON"; else if (i_error==14040L) risultato="ERROR_SXS_XML_E_UNBALANCEDPAREN"; else if (i_error==14041L) risultato="ERROR_SXS_XML_E_INTERNALERROR"; else if (i_error==14042L) risultato="ERROR_SXS_XML_E_UNEXPECTED_WHITESPACE"; else if (i_error==14043L) risultato="ERROR_SXS_XML_E_INCOMPLETE_ENCODING"; else if (i_error==14044L) risultato="ERROR_SXS_XML_E_MISSING_PAREN"; else if (i_error==14045L) risultato="ERROR_SXS_XML_E_EXPECTINGCLOSEQUOTE"; else if (i_error==14046L) risultato="ERROR_SXS_XML_E_MULTIPLE_COLONS"; else if (i_error==14047L) risultato="ERROR_SXS_XML_E_INVALID_DECIMAL"; else if (i_error==14048L) risultato="ERROR_SXS_XML_E_INVALID_HEXIDECIMAL"; else if (i_error==14049L) risultato="ERROR_SXS_XML_E_INVALID_UNICODE"; else if (i_error==14050L) risultato="ERROR_SXS_XML_E_WHITESPACEORQUESTIONMARK"; else if (i_error==14051L) risultato="ERROR_SXS_XML_E_UNEXPECTEDENDTAG"; else if (i_error==14052L) risultato="ERROR_SXS_XML_E_UNCLOSEDTAG"; else if (i_error==14053L) risultato="ERROR_SXS_XML_E_DUPLICATEATTRIBUTE"; else if (i_error==14054L) risultato="ERROR_SXS_XML_E_MULTIPLEROOTS"; else if (i_error==14055L) risultato="ERROR_SXS_XML_E_INVALIDATROOTLEVEL"; else if (i_error==14056L) risultato="ERROR_SXS_XML_E_BADXMLDECL"; else if (i_error==14057L) risultato="ERROR_SXS_XML_E_MISSINGROOT"; else if (i_error==14058L) risultato="ERROR_SXS_XML_E_UNEXPECTEDEOF"; else if (i_error==14059L) risultato="ERROR_SXS_XML_E_BADPEREFINSUBSET"; else if (i_error==14060L) risultato="ERROR_SXS_XML_E_UNCLOSEDSTARTTAG"; else if (i_error==14061L) risultato="ERROR_SXS_XML_E_UNCLOSEDENDTAG"; else if (i_error==14062L) risultato="ERROR_SXS_XML_E_UNCLOSEDSTRING"; else if (i_error==14063L) risultato="ERROR_SXS_XML_E_UNCLOSEDCOMMENT"; else if (i_error==14064L) risultato="ERROR_SXS_XML_E_UNCLOSEDDECL"; else if (i_error==14065L) risultato="ERROR_SXS_XML_E_UNCLOSEDCDATA"; else if (i_error==14066L) risultato="ERROR_SXS_XML_E_RESERVEDNAMESPACE"; else if (i_error==14067L) risultato="ERROR_SXS_XML_E_INVALIDENCODING"; else if (i_error==14068L) risultato="ERROR_SXS_XML_E_INVALIDSWITCH"; else if (i_error==14069L) risultato="ERROR_SXS_XML_E_BADXMLCASE"; else if (i_error==14070L) risultato="ERROR_SXS_XML_E_INVALID_STANDALONE"; else if (i_error==14071L) risultato="ERROR_SXS_XML_E_UNEXPECTED_STANDALONE"; else if (i_error==14072L) risultato="ERROR_SXS_XML_E_INVALID_VERSION"; else if (i_error==14073L) risultato="ERROR_SXS_XML_E_MISSINGEQUALS"; else if (i_error==14074L) risultato="ERROR_SXS_PROTECTION_RECOVERY_FAILED"; else if (i_error==14075L) risultato="ERROR_SXS_PROTECTION_PUBLIC_KEY_TOO_SHORT"; else if (i_error==14076L) risultato="ERROR_SXS_PROTECTION_CATALOG_NOT_VALID"; else if (i_error==14077L) risultato="ERROR_SXS_UNTRANSLATABLE_HRESULT"; else if (i_error==14078L) risultato="ERROR_SXS_PROTECTION_CATALOG_FILE_MISSING"; else if (i_error==14079L) risultato="ERROR_SXS_MISSING_ASSEMBLY_IDENTITY_ATTRIBUTE"; else if (i_error==14080L) risultato="ERROR_SXS_INVALID_ASSEMBLY_IDENTITY_ATTRIBUTE_NAME"; else if (i_error==14081L) risultato="ERROR_SXS_ASSEMBLY_MISSING"; else if (i_error==14082L) risultato="ERROR_SXS_CORRUPT_ACTIVATION_STACK"; else if (i_error==14083L) risultato="ERROR_SXS_CORRUPTION"; else if (i_error==14084L) risultato="ERROR_SXS_EARLY_DEACTIVATION"; else if (i_error==14085L) risultato="ERROR_SXS_INVALID_DEACTIVATION"; else if (i_error==14086L) risultato="ERROR_SXS_MULTIPLE_DEACTIVATION"; else if (i_error==14087L) risultato="ERROR_SXS_PROCESS_TERMINATION_REQUESTED"; else if (i_error==14088L) risultato="ERROR_SXS_RELEASE_ACTIVATION_CONTEXT"; else if (i_error==14089L) risultato="ERROR_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY"; else if (i_error==14090L) risultato="ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE"; else if (i_error==14091L) risultato="ERROR_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME"; else if (i_error==14092L) risultato="ERROR_SXS_IDENTITY_DUPLICATE_ATTRIBUTE"; else if (i_error==14093L) risultato="ERROR_SXS_IDENTITY_PARSE_ERROR"; else if (i_error==14094L) risultato="ERROR_MALFORMED_SUBSTITUTION_STRING"; else if (i_error==14095L) risultato="ERROR_SXS_INCORRECT_PUBLIC_KEY_TOKEN"; else if (i_error==14096L) risultato="ERROR_UNMAPPED_SUBSTITUTION_STRING"; else if (i_error==14097L) risultato="ERROR_SXS_ASSEMBLY_NOT_LOCKED"; else if (i_error==14098L) risultato="ERROR_SXS_COMPONENT_STORE_CORRUPT"; else if (i_error==14099L) risultato="ERROR_ADVANCED_INSTALLER_FAILED"; else if (i_error==14100L) risultato="ERROR_XML_ENCODING_MISMATCH"; else if (i_error==14101L) risultato="ERROR_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT"; else if (i_error==14102L) risultato="ERROR_SXS_IDENTITIES_DIFFERENT"; else if (i_error==14103L) risultato="ERROR_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT"; else if (i_error==14104L) risultato="ERROR_SXS_FILE_NOT_PART_OF_ASSEMBLY"; else if (i_error==14105L) risultato="ERROR_SXS_MANIFEST_TOO_BIG"; else if (i_error==14106L) risultato="ERROR_SXS_SETTING_NOT_REGISTERED"; else if (i_error==14107L) risultato="ERROR_SXS_TRANSACTION_CLOSURE_INCOMPLETE"; else if (i_error==14108L) risultato="ERROR_SMI_PRIMITIVE_INSTALLER_FAILED"; else if (i_error==14109L) risultato="ERROR_GENERIC_COMMAND_FAILED"; else if (i_error==14110L) risultato="ERROR_SXS_FILE_HASH_MISSING"; else if (i_error==15000L) risultato="ERROR_EVT_INVALID_CHANNEL_PATH"; else if (i_error==15001L) risultato="ERROR_EVT_INVALID_QUERY"; else if (i_error==15002L) risultato="ERROR_EVT_PUBLISHER_METADATA_NOT_FOUND"; else if (i_error==15003L) risultato="ERROR_EVT_EVENT_TEMPLATE_NOT_FOUND"; else if (i_error==15004L) risultato="ERROR_EVT_INVALID_PUBLISHER_NAME"; else if (i_error==15005L) risultato="ERROR_EVT_INVALID_EVENT_DATA"; else if (i_error==15007L) risultato="ERROR_EVT_CHANNEL_NOT_FOUND"; else if (i_error==15008L) risultato="ERROR_EVT_MALFORMED_XML_TEXT"; else if (i_error==15009L) risultato="ERROR_EVT_SUBSCRIPTION_TO_DIRECT_CHANNEL"; else if (i_error==15010L) risultato="ERROR_EVT_CONFIGURATION_ERROR"; else if (i_error==15011L) risultato="ERROR_EVT_QUERY_RESULT_STALE"; else if (i_error==15012L) risultato="ERROR_EVT_QUERY_RESULT_INVALID_POSITION"; else if (i_error==15013L) risultato="ERROR_EVT_NON_VALIDATING_MSXML"; else if (i_error==15014L) risultato="ERROR_EVT_FILTER_ALREADYSCOPED"; else if (i_error==15015L) risultato="ERROR_EVT_FILTER_NOTELTSET"; else if (i_error==15016L) risultato="ERROR_EVT_FILTER_INVARG"; else if (i_error==15017L) risultato="ERROR_EVT_FILTER_INVTEST"; else if (i_error==15018L) risultato="ERROR_EVT_FILTER_INVTYPE"; else if (i_error==15019L) risultato="ERROR_EVT_FILTER_PARSEERR"; else if (i_error==15020L) risultato="ERROR_EVT_FILTER_UNSUPPORTEDOP"; else if (i_error==15021L) risultato="ERROR_EVT_FILTER_UNEXPECTEDTOKEN"; else if (i_error==15022L) risultato="ERROR_EVT_INVALID_OPERATION_OVER_ENABLED_DIRECT_CHANNEL"; else if (i_error==15023L) risultato="ERROR_EVT_INVALID_CHANNEL_PROPERTY_VALUE"; else if (i_error==15024L) risultato="ERROR_EVT_INVALID_PUBLISHER_PROPERTY_VALUE"; else if (i_error==15025L) risultato="ERROR_EVT_CHANNEL_CANNOT_ACTIVATE"; else if (i_error==15026L) risultato="ERROR_EVT_FILTER_TOO_COMPLEX"; else if (i_error==15027L) risultato="ERROR_EVT_MESSAGE_NOT_FOUND"; else if (i_error==15028L) risultato="ERROR_EVT_MESSAGE_ID_NOT_FOUND"; else if (i_error==15029L) risultato="ERROR_EVT_UNRESOLVED_VALUE_INSERT"; else if (i_error==15030L) risultato="ERROR_EVT_UNRESOLVED_PARAMETER_INSERT"; else if (i_error==15031L) risultato="ERROR_EVT_MAX_INSERTS_REACHED"; else if (i_error==15032L) risultato="ERROR_EVT_EVENT_DEFINITION_NOT_FOUND"; else if (i_error==15033L) risultato="ERROR_EVT_MESSAGE_LOCALE_NOT_FOUND"; else if (i_error==15034L) risultato="ERROR_EVT_VERSION_TOO_OLD"; else if (i_error==15035L) risultato="ERROR_EVT_VERSION_TOO_NEW"; else if (i_error==15036L) risultato="ERROR_EVT_CANNOT_OPEN_CHANNEL_OF_QUERY"; else if (i_error==15037L) risultato="ERROR_EVT_PUBLISHER_DISABLED"; else if (i_error==15038L) risultato="ERROR_EVT_FILTER_OUT_OF_RANGE"; else if (i_error==15080L) risultato="ERROR_EC_SUBSCRIPTION_CANNOT_ACTIVATE"; else if (i_error==15081L) risultato="ERROR_EC_LOG_DISABLED"; else if (i_error==15082L) risultato="ERROR_EC_CIRCULAR_FORWARDING"; else if (i_error==15083L) risultato="ERROR_EC_CREDSTORE_FULL"; else if (i_error==15084L) risultato="ERROR_EC_CRED_NOT_FOUND"; else if (i_error==15085L) risultato="ERROR_EC_NO_ACTIVE_CHANNEL"; else if (i_error==15100L) risultato="ERROR_MUI_FILE_NOT_FOUND"; else if (i_error==15101L) risultato="ERROR_MUI_INVALID_FILE"; else if (i_error==15102L) risultato="ERROR_MUI_INVALID_RC_CONFIG"; else if (i_error==15103L) risultato="ERROR_MUI_INVALID_LOCALE_NAME"; else if (i_error==15104L) risultato="ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME"; else if (i_error==15105L) risultato="ERROR_MUI_FILE_NOT_LOADED"; else if (i_error==15106L) risultato="ERROR_RESOURCE_ENUM_USER_STOP"; else if (i_error==15107L) risultato="ERROR_MUI_INTLSETTINGS_UILANG_NOT_INSTALLED"; else if (i_error==15108L) risultato="ERROR_MUI_INTLSETTINGS_INVALID_LOCALE_NAME"; else if (i_error==15110L) risultato="ERROR_MRM_RUNTIME_NO_DEFAULT_OR_NEUTRAL_RESOURCE"; else if (i_error==15111L) risultato="ERROR_MRM_INVALID_PRICONFIG"; else if (i_error==15112L) risultato="ERROR_MRM_INVALID_FILE_TYPE"; else if (i_error==15113L) risultato="ERROR_MRM_UNKNOWN_QUALIFIER"; else if (i_error==15114L) risultato="ERROR_MRM_INVALID_QUALIFIER_VALUE"; else if (i_error==15115L) risultato="ERROR_MRM_NO_CANDIDATE"; else if (i_error==15116L) risultato="ERROR_MRM_NO_MATCH_OR_DEFAULT_CANDIDATE"; else if (i_error==15117L) risultato="ERROR_MRM_RESOURCE_TYPE_MISMATCH"; else if (i_error==15118L) risultato="ERROR_MRM_DUPLICATE_MAP_NAME"; else if (i_error==15119L) risultato="ERROR_MRM_DUPLICATE_ENTRY"; else if (i_error==15120L) risultato="ERROR_MRM_INVALID_RESOURCE_IDENTIFIER"; else if (i_error==15121L) risultato="ERROR_MRM_FILEPATH_TOO_LONG"; else if (i_error==15122L) risultato="ERROR_MRM_UNSUPPORTED_DIRECTORY_TYPE"; else if (i_error==15126L) risultato="ERROR_MRM_INVALID_PRI_FILE"; else if (i_error==15127L) risultato="ERROR_MRM_NAMED_RESOURCE_NOT_FOUND"; else if (i_error==15135L) risultato="ERROR_MRM_MAP_NOT_FOUND"; else if (i_error==15136L) risultato="ERROR_MRM_UNSUPPORTED_PROFILE_TYPE"; else if (i_error==15137L) risultato="ERROR_MRM_INVALID_QUALIFIER_OPERATOR"; else if (i_error==15138L) risultato="ERROR_MRM_INDETERMINATE_QUALIFIER_VALUE"; else if (i_error==15139L) risultato="ERROR_MRM_AUTOMERGE_ENABLED"; else if (i_error==15140L) risultato="ERROR_MRM_TOO_MANY_RESOURCES"; else if (i_error==15141L) risultato="ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_MERGE"; else if (i_error==15142L) risultato="ERROR_MRM_UNSUPPORTED_FILE_TYPE_FOR_LOAD_UNLOAD_PRI_FILE"; else if (i_error==15143L) risultato="ERROR_MRM_NO_CURRENT_VIEW_ON_THREAD"; else if (i_error==15144L) risultato="ERROR_DIFFERENT_PROFILE_RESOURCE_MANAGER_EXIST"; else if (i_error==15145L) risultato="ERROR_OPERATION_NOT_ALLOWED_FROM_SYSTEM_COMPONENT"; else if (i_error==15146L) risultato="ERROR_MRM_DIRECT_REF_TO_NON_DEFAULT_RESOURCE"; else if (i_error==15147L) risultato="ERROR_MRM_GENERATION_COUNT_MISMATCH"; else if (i_error==15148L) risultato="ERROR_PRI_MERGE_VERSION_MISMATCH"; else if (i_error==15149L) risultato="ERROR_PRI_MERGE_MISSING_SCHEMA"; else if (i_error==15150L) risultato="ERROR_PRI_MERGE_LOAD_FILE_FAILED"; else if (i_error==15151L) risultato="ERROR_PRI_MERGE_ADD_FILE_FAILED"; else if (i_error==15152L) risultato="ERROR_PRI_MERGE_WRITE_FILE_FAILED"; else if (i_error==15200L) risultato="ERROR_MCA_INVALID_CAPABILITIES_STRING"; else if (i_error==15201L) risultato="ERROR_MCA_INVALID_VCP_VERSION"; else if (i_error==15202L) risultato="ERROR_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION"; else if (i_error==15203L) risultato="ERROR_MCA_MCCS_VERSION_MISMATCH"; else if (i_error==15204L) risultato="ERROR_MCA_UNSUPPORTED_MCCS_VERSION"; else if (i_error==15205L) risultato="ERROR_MCA_INTERNAL_ERROR"; else if (i_error==15206L) risultato="ERROR_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED"; else if (i_error==15207L) risultato="ERROR_MCA_UNSUPPORTED_COLOR_TEMPERATURE"; else if (i_error==15250L) risultato="ERROR_AMBIGUOUS_SYSTEM_DEVICE"; else if (i_error==15299L) risultato="ERROR_SYSTEM_DEVICE_NOT_FOUND"; else if (i_error==15300L) risultato="ERROR_HASH_NOT_SUPPORTED"; else if (i_error==15301L) risultato="ERROR_HASH_NOT_PRESENT"; else if (i_error==15321L) risultato="ERROR_SECONDARY_IC_PROVIDER_NOT_REGISTERED"; else if (i_error==15322L) risultato="ERROR_GPIO_CLIENT_INFORMATION_INVALID"; else if (i_error==15323L) risultato="ERROR_GPIO_VERSION_NOT_SUPPORTED"; else if (i_error==15324L) risultato="ERROR_GPIO_INVALID_REGISTRATION_PACKET"; else if (i_error==15325L) risultato="ERROR_GPIO_OPERATION_DENIED"; else if (i_error==15326L) risultato="ERROR_GPIO_INCOMPATIBLE_CONNECT_MODE"; else if (i_error==15327L) risultato="ERROR_GPIO_INTERRUPT_ALREADY_UNMASKED"; else if (i_error==15400L) risultato="ERROR_CANNOT_SWITCH_RUNLEVEL"; else if (i_error==15401L) risultato="ERROR_INVALID_RUNLEVEL_SETTING"; else if (i_error==15402L) risultato="ERROR_RUNLEVEL_SWITCH_TIMEOUT"; else if (i_error==15403L) risultato="ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT"; else if (i_error==15404L) risultato="ERROR_RUNLEVEL_SWITCH_IN_PROGRESS"; else if (i_error==15405L) risultato="ERROR_SERVICES_FAILED_AUTOSTART"; else if (i_error==15501L) risultato="ERROR_COM_TASK_STOP_PENDING"; else if (i_error==15600L) risultato="ERROR_INSTALL_OPEN_PACKAGE_FAILED"; else if (i_error==15601L) risultato="ERROR_INSTALL_PACKAGE_NOT_FOUND"; else if (i_error==15602L) risultato="ERROR_INSTALL_INVALID_PACKAGE"; else if (i_error==15603L) risultato="ERROR_INSTALL_RESOLVE_DEPENDENCY_FAILED"; else if (i_error==15604L) risultato="ERROR_INSTALL_OUT_OF_DISK_SPACE"; else if (i_error==15605L) risultato="ERROR_INSTALL_NETWORK_FAILURE"; else if (i_error==15606L) risultato="ERROR_INSTALL_REGISTRATION_FAILURE"; else if (i_error==15607L) risultato="ERROR_INSTALL_DEREGISTRATION_FAILURE"; else if (i_error==15608L) risultato="ERROR_INSTALL_CANCEL"; else if (i_error==15609L) risultato="ERROR_INSTALL_FAILED"; else if (i_error==15610L) risultato="ERROR_REMOVE_FAILED"; else if (i_error==15611L) risultato="ERROR_PACKAGE_ALREADY_EXISTS"; else if (i_error==15612L) risultato="ERROR_NEEDS_REMEDIATION"; else if (i_error==15613L) risultato="ERROR_INSTALL_PREREQUISITE_FAILED"; else if (i_error==15614L) risultato="ERROR_PACKAGE_REPOSITORY_CORRUPTED"; else if (i_error==15615L) risultato="ERROR_INSTALL_POLICY_FAILURE"; else if (i_error==15616L) risultato="ERROR_PACKAGE_UPDATING"; else if (i_error==15617L) risultato="ERROR_DEPLOYMENT_BLOCKED_BY_POLICY"; else if (i_error==15618L) risultato="ERROR_PACKAGES_IN_USE"; else if (i_error==15619L) risultato="ERROR_RECOVERY_FILE_CORRUPT"; else if (i_error==15620L) risultato="ERROR_INVALID_STAGED_SIGNATURE"; else if (i_error==15621L) risultato="ERROR_DELETING_EXISTING_APPLICATIONDATA_STORE_FAILED"; else if (i_error==15622L) risultato="ERROR_INSTALL_PACKAGE_DOWNGRADE"; else if (i_error==15623L) risultato="ERROR_SYSTEM_NEEDS_REMEDIATION"; else if (i_error==15624L) risultato="ERROR_APPX_INTEGRITY_FAILURE_CLR_NGEN"; else if (i_error==15625L) risultato="ERROR_RESILIENCY_FILE_CORRUPT"; else if (i_error==15626L) risultato="ERROR_INSTALL_FIREWALL_SERVICE_NOT_RUNNING"; else if (i_error==15627L) risultato="ERROR_PACKAGE_MOVE_FAILED"; else if (i_error==15628L) risultato="ERROR_INSTALL_VOLUME_NOT_EMPTY"; else if (i_error==15629L) risultato="ERROR_INSTALL_VOLUME_OFFLINE"; else if (i_error==15630L) risultato="ERROR_INSTALL_VOLUME_CORRUPT"; else if (i_error==15631L) risultato="ERROR_NEEDS_REGISTRATION"; else if (i_error==15632L) risultato="ERROR_INSTALL_WRONG_PROCESSOR_ARCHITECTURE"; else if (i_error==15633L) risultato="ERROR_DEV_SIDELOAD_LIMIT_EXCEEDED"; else if (i_error==15634L) risultato="ERROR_INSTALL_OPTIONAL_PACKAGE_REQUIRES_MAIN_PACKAGE"; else if (i_error==15635L) risultato="ERROR_PACKAGE_NOT_SUPPORTED_ON_FILESYSTEM"; else if (i_error==15700L) risultato="APPMODEL_ERROR_NO_PACKAGE"; else if (i_error==15701L) risultato="APPMODEL_ERROR_PACKAGE_RUNTIME_CORRUPT"; else if (i_error==15702L) risultato="APPMODEL_ERROR_PACKAGE_IDENTITY_CORRUPT"; else if (i_error==15703L) risultato="APPMODEL_ERROR_NO_APPLICATION"; else if (i_error==15704L) risultato="APPMODEL_ERROR_DYNAMIC_PROPERTY_READ_FAILED"; else if (i_error==15705L) risultato="APPMODEL_ERROR_DYNAMIC_PROPERTY_INVALID"; else if (i_error==15706L) risultato="APPMODEL_ERROR_PACKAGE_NOT_AVAILABLE"; else if (i_error==15800L) risultato="ERROR_STATE_LOAD_STORE_FAILED"; else if (i_error==15801L) risultato="ERROR_STATE_GET_VERSION_FAILED"; else if (i_error==15802L) risultato="ERROR_STATE_SET_VERSION_FAILED"; else if (i_error==15803L) risultato="ERROR_STATE_STRUCTURED_RESET_FAILED"; else if (i_error==15804L) risultato="ERROR_STATE_OPEN_CONTAINER_FAILED"; else if (i_error==15805L) risultato="ERROR_STATE_CREATE_CONTAINER_FAILED"; else if (i_error==15806L) risultato="ERROR_STATE_DELETE_CONTAINER_FAILED"; else if (i_error==15807L) risultato="ERROR_STATE_READ_SETTING_FAILED"; else if (i_error==15808L) risultato="ERROR_STATE_WRITE_SETTING_FAILED"; else if (i_error==15809L) risultato="ERROR_STATE_DELETE_SETTING_FAILED"; else if (i_error==15810L) risultato="ERROR_STATE_QUERY_SETTING_FAILED"; else if (i_error==15811L) risultato="ERROR_STATE_READ_COMPOSITE_SETTING_FAILED"; else if (i_error==15812L) risultato="ERROR_STATE_WRITE_COMPOSITE_SETTING_FAILED"; else if (i_error==15813L) risultato="ERROR_STATE_ENUMERATE_CONTAINER_FAILED"; else if (i_error==15814L) risultato="ERROR_STATE_ENUMERATE_SETTINGS_FAILED"; else if (i_error==15815L) risultato="ERROR_STATE_COMPOSITE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED"; else if (i_error==15816L) risultato="ERROR_STATE_SETTING_VALUE_SIZE_LIMIT_EXCEEDED"; else if (i_error==15817L) risultato="ERROR_STATE_SETTING_NAME_SIZE_LIMIT_EXCEEDED"; else if (i_error==15818L) risultato="ERROR_STATE_CONTAINER_NAME_SIZE_LIMIT_EXCEEDED"; else if (i_error==15841L) risultato="ERROR_API_UNAVAILABLE"; else if (i_error==15861L) risultato="STORE_ERROR_UNLICENSED"; else if (i_error==15862L) risultato="STORE_ERROR_UNLICENSED_USER"; else if (i_error==15863L) risultato="STORE_ERROR_PENDING_COM_TRANSACTION"; else if (i_error==15864L) risultato="STORE_ERROR_LICENSE_REVOKED"; else if (i_error==0x8000FFFFL) risultato="E_UNEXPECTED"; else if (i_error==0x80004001L) risultato="E_NOTIMPL"; else if (i_error==0x8007000EL) risultato="E_OUTOFMEMORY"; else if (i_error==0x80070057L) risultato="E_INVALIDARG"; else if (i_error==0x80004002L) risultato="E_NOINTERFACE"; else if (i_error==0x80004003L) risultato="E_POINTER"; else if (i_error==0x80070006L) risultato="E_HANDLE"; else if (i_error==0x80004004L) risultato="E_ABORT"; else if (i_error==0x80004005L) risultato="E_FAIL"; else if (i_error==0x80070005L) risultato="E_ACCESSDENIED"; else if (i_error==0x80000001L) risultato="E_NOTIMPL"; else if (i_error==0x80000002L) risultato="E_OUTOFMEMORY"; else if (i_error==0x80000003L) risultato="E_INVALIDARG"; else if (i_error==0x80000004L) risultato="E_NOINTERFACE"; else if (i_error==0x80000005L) risultato="E_POINTER"; else if (i_error==0x80000006L) risultato="E_HANDLE"; else if (i_error==0x80000007L) risultato="E_ABORT"; else if (i_error==0x80000008L) risultato="E_FAIL"; else if (i_error==0x80000009L) risultato="E_ACCESSDENIED"; else if (i_error==0x8000000AL) risultato="E_PENDING"; else if (i_error==0x8000000BL) risultato="E_BOUNDS"; else if (i_error==0x8000000CL) risultato="E_CHANGED_STATE"; else if (i_error==0x8000000DL) risultato="E_ILLEGAL_STATE_CHANGE"; else if (i_error==0x8000000EL) risultato="E_ILLEGAL_METHOD_CALL"; else if (i_error==0x8000000FL) risultato="RO_E_METADATA_NAME_NOT_FOUND"; else if (i_error==0x80000010L) risultato="RO_E_METADATA_NAME_IS_NAMESPACE"; else if (i_error==0x80000011L) risultato="RO_E_METADATA_INVALID_TYPE_FORMAT"; else if (i_error==0x80000012L) risultato="RO_E_INVALID_METADATA_FILE"; else if (i_error==0x80000013L) risultato="RO_E_CLOSED"; else if (i_error==0x80000014L) risultato="RO_E_EXCLUSIVE_WRITE"; else if (i_error==0x80000015L) risultato="RO_E_CHANGE_NOTIFICATION_IN_PROGRESS"; else if (i_error==0x80000016L) risultato="RO_E_ERROR_STRING_NOT_FOUND"; else if (i_error==0x80000017L) risultato="E_STRING_NOT_NULL_TERMINATED"; else if (i_error==0x80000018L) risultato="E_ILLEGAL_DELEGATE_ASSIGNMENT"; else if (i_error==0x80000019L) risultato="E_ASYNC_OPERATION_NOT_STARTED"; else if (i_error==0x8000001AL) risultato="E_APPLICATION_EXITING"; else if (i_error==0x8000001BL) risultato="E_APPLICATION_VIEW_EXITING"; else if (i_error==0x8000001CL) risultato="RO_E_MUST_BE_AGILE"; else if (i_error==0x8000001DL) risultato="RO_E_UNSUPPORTED_FROM_MTA"; else if (i_error==0x8000001EL) risultato="RO_E_COMMITTED"; else if (i_error==0x8000001FL) risultato="RO_E_BLOCKED_CROSS_ASTA_CALL"; else if (i_error==0x80004006L) risultato="CO_E_INIT_TLS"; else if (i_error==0x80004007L) risultato="CO_E_INIT_SHARED_ALLOCATOR"; else if (i_error==0x80004008L) risultato="CO_E_INIT_MEMORY_ALLOCATOR"; else if (i_error==0x80004009L) risultato="CO_E_INIT_CLASS_CACHE"; else if (i_error==0x8000400AL) risultato="CO_E_INIT_RPC_CHANNEL"; else if (i_error==0x8000400BL) risultato="CO_E_INIT_TLS_SET_CHANNEL_CONTROL"; else if (i_error==0x8000400CL) risultato="CO_E_INIT_TLS_CHANNEL_CONTROL"; else if (i_error==0x8000400DL) risultato="CO_E_INIT_UNACCEPTED_USER_ALLOCATOR"; else if (i_error==0x8000400EL) risultato="CO_E_INIT_SCM_MUTEX_EXISTS"; else if (i_error==0x8000400FL) risultato="CO_E_INIT_SCM_FILE_MAPPING_EXISTS"; else if (i_error==0x80004010L) risultato="CO_E_INIT_SCM_MAP_VIEW_OF_FILE"; else if (i_error==0x80004011L) risultato="CO_E_INIT_SCM_EXEC_FAILURE"; else if (i_error==0x80004012L) risultato="CO_E_INIT_ONLY_SINGLE_THREADED"; else if (i_error==0x80004013L) risultato="CO_E_CANT_REMOTE"; else if (i_error==0x80004014L) risultato="CO_E_BAD_SERVER_NAME"; else if (i_error==0x80004015L) risultato="CO_E_WRONG_SERVER_IDENTITY"; else if (i_error==0x80004016L) risultato="CO_E_OLE1DDE_DISABLED"; else if (i_error==0x80004017L) risultato="CO_E_RUNAS_SYNTAX"; else if (i_error==0x80004018L) risultato="CO_E_CREATEPROCESS_FAILURE"; else if (i_error==0x80004019L) risultato="CO_E_RUNAS_CREATEPROCESS_FAILURE"; else if (i_error==0x8000401AL) risultato="CO_E_RUNAS_LOGON_FAILURE"; else if (i_error==0x8000401BL) risultato="CO_E_LAUNCH_PERMSSION_DENIED"; else if (i_error==0x8000401CL) risultato="CO_E_START_SERVICE_FAILURE"; else if (i_error==0x8000401DL) risultato="CO_E_REMOTE_COMMUNICATION_FAILURE"; else if (i_error==0x8000401EL) risultato="CO_E_SERVER_START_TIMEOUT"; else if (i_error==0x8000401FL) risultato="CO_E_CLSREG_INCONSISTENT"; else if (i_error==0x80004020L) risultato="CO_E_IIDREG_INCONSISTENT"; else if (i_error==0x80004021L) risultato="CO_E_NOT_SUPPORTED"; else if (i_error==0x80004022L) risultato="CO_E_RELOAD_DLL"; else if (i_error==0x80004023L) risultato="CO_E_MSI_ERROR"; else if (i_error==0x80004024L) risultato="CO_E_ATTEMPT_TO_CREATE_OUTSIDE_CLIENT_CONTEXT"; else if (i_error==0x80004025L) risultato="CO_E_SERVER_PAUSED"; else if (i_error==0x80004026L) risultato="CO_E_SERVER_NOT_PAUSED"; else if (i_error==0x80004027L) risultato="CO_E_CLASS_DISABLED"; else if (i_error==0x80004028L) risultato="CO_E_CLRNOTAVAILABLE"; else if (i_error==0x80004029L) risultato="CO_E_ASYNC_WORK_REJECTED"; else if (i_error==0x8000402AL) risultato="CO_E_SERVER_INIT_TIMEOUT"; else if (i_error==0x8000402BL) risultato="CO_E_NO_SECCTX_IN_ACTIVATE"; else if (i_error==0x80004030L) risultato="CO_E_TRACKER_CONFIG"; else if (i_error==0x80004031L) risultato="CO_E_THREADPOOL_CONFIG"; else if (i_error==0x80004032L) risultato="CO_E_SXS_CONFIG"; else if (i_error==0x80004033L) risultato="CO_E_MALFORMED_SPN"; else if (i_error==0x80004034L) risultato="CO_E_UNREVOKED_REGISTRATION_ON_APARTMENT_SHUTDOWN"; else if (i_error==0x80004035L) risultato="CO_E_PREMATURE_STUB_RUNDOWN"; else if (i_error==0x80040000L) risultato="OLE_E_FIRST"; else if (i_error==0x800400FFL) risultato="OLE_E_LAST"; else if (i_error==0x00040000L) risultato="OLE_S_FIRST"; else if (i_error==0x000400FFL) risultato="OLE_S_LAST"; else if (i_error==0x80040000L) risultato="OLE_E_OLEVERB"; else if (i_error==0x80040001L) risultato="OLE_E_ADVF"; else if (i_error==0x80040002L) risultato="OLE_E_ENUM_NOMORE"; else if (i_error==0x80040003L) risultato="OLE_E_ADVISENOTSUPPORTED"; else if (i_error==0x80040004L) risultato="OLE_E_NOCONNECTION"; else if (i_error==0x80040005L) risultato="OLE_E_NOTRUNNING"; else if (i_error==0x80040006L) risultato="OLE_E_NOCACHE"; else if (i_error==0x80040007L) risultato="OLE_E_BLANK"; else if (i_error==0x80040008L) risultato="OLE_E_CLASSDIFF"; else if (i_error==0x80040009L) risultato="OLE_E_CANT_GETMONIKER"; else if (i_error==0x8004000AL) risultato="OLE_E_CANT_BINDTOSOURCE"; else if (i_error==0x8004000BL) risultato="OLE_E_STATIC"; else if (i_error==0x8004000CL) risultato="OLE_E_PROMPTSAVECANCELLED"; else if (i_error==0x8004000DL) risultato="OLE_E_INVALIDRECT"; else if (i_error==0x8004000EL) risultato="OLE_E_WRONGCOMPOBJ"; else if (i_error==0x8004000FL) risultato="OLE_E_INVALIDHWND"; else if (i_error==0x80040010L) risultato="OLE_E_NOT_INPLACEACTIVE"; else if (i_error==0x80040011L) risultato="OLE_E_CANTCONVERT"; else if (i_error==0x80040012L) risultato="OLE_E_NOSTORAGE"; else if (i_error==0x80040064L) risultato="DV_E_FORMATETC"; else if (i_error==0x80040065L) risultato="DV_E_DVTARGETDEVICE"; else if (i_error==0x80040066L) risultato="DV_E_STGMEDIUM"; else if (i_error==0x80040067L) risultato="DV_E_STATDATA"; else if (i_error==0x80040068L) risultato="DV_E_LINDEX"; else if (i_error==0x80040069L) risultato="DV_E_TYMED"; else if (i_error==0x8004006AL) risultato="DV_E_CLIPFORMAT"; else if (i_error==0x8004006BL) risultato="DV_E_DVASPECT"; else if (i_error==0x8004006CL) risultato="DV_E_DVTARGETDEVICE_SIZE"; else if (i_error==0x8004006DL) risultato="DV_E_NOIVIEWOBJECT"; else if (i_error==0x80040100L) risultato="DRAGDROP_E_FIRST"; else if (i_error==0x8004010FL) risultato="DRAGDROP_E_LAST"; else if (i_error==0x00040100L) risultato="DRAGDROP_S_FIRST"; else if (i_error==0x0004010FL) risultato="DRAGDROP_S_LAST"; else if (i_error==0x80040100L) risultato="DRAGDROP_E_NOTREGISTERED"; else if (i_error==0x80040101L) risultato="DRAGDROP_E_ALREADYREGISTERED"; else if (i_error==0x80040102L) risultato="DRAGDROP_E_INVALIDHWND"; else if (i_error==0x80040103L) risultato="DRAGDROP_E_CONCURRENT_DRAG_ATTEMPTED"; else if (i_error==0x80040110L) risultato="CLASSFACTORY_E_FIRST"; else if (i_error==0x8004011FL) risultato="CLASSFACTORY_E_LAST"; else if (i_error==0x00040110L) risultato="CLASSFACTORY_S_FIRST"; else if (i_error==0x0004011FL) risultato="CLASSFACTORY_S_LAST"; else if (i_error==0x80040110L) risultato="CLASS_E_NOAGGREGATION"; else if (i_error==0x80040111L) risultato="CLASS_E_CLASSNOTAVAILABLE"; else if (i_error==0x80040112L) risultato="CLASS_E_NOTLICENSED"; else if (i_error==0x80040120L) risultato="MARSHAL_E_FIRST"; else if (i_error==0x8004012FL) risultato="MARSHAL_E_LAST"; else if (i_error==0x00040120L) risultato="MARSHAL_S_FIRST"; else if (i_error==0x0004012FL) risultato="MARSHAL_S_LAST"; else if (i_error==0x80040130L) risultato="DATA_E_FIRST"; else if (i_error==0x8004013FL) risultato="DATA_E_LAST"; else if (i_error==0x00040130L) risultato="DATA_S_FIRST"; else if (i_error==0x0004013FL) risultato="DATA_S_LAST"; else if (i_error==0x80040140L) risultato="VIEW_E_FIRST"; else if (i_error==0x8004014FL) risultato="VIEW_E_LAST"; else if (i_error==0x00040140L) risultato="VIEW_S_FIRST"; else if (i_error==0x0004014FL) risultato="VIEW_S_LAST"; else if (i_error==0x80040140L) risultato="VIEW_E_DRAW"; else if (i_error==0x80040150L) risultato="REGDB_E_FIRST"; else if (i_error==0x8004015FL) risultato="REGDB_E_LAST"; else if (i_error==0x00040150L) risultato="REGDB_S_FIRST"; else if (i_error==0x0004015FL) risultato="REGDB_S_LAST"; else if (i_error==0x80040150L) risultato="REGDB_E_READREGDB"; else if (i_error==0x80040151L) risultato="REGDB_E_WRITEREGDB"; else if (i_error==0x80040152L) risultato="REGDB_E_KEYMISSING"; else if (i_error==0x80040153L) risultato="REGDB_E_INVALIDVALUE"; else if (i_error==0x80040154L) risultato="REGDB_E_CLASSNOTREG"; else if (i_error==0x80040155L) risultato="REGDB_E_IIDNOTREG"; else if (i_error==0x80040156L) risultato="REGDB_E_BADTHREADINGMODEL"; else if (i_error==0x80040157L) risultato="REGDB_E_PACKAGEPOLICYVIOLATION"; else if (i_error==0x80040160L) risultato="CAT_E_FIRST"; else if (i_error==0x80040161L) risultato="CAT_E_LAST"; else if (i_error==0x80040160L) risultato="CAT_E_CATIDNOEXIST"; else if (i_error==0x80040161L) risultato="CAT_E_NODESCRIPTION"; else if (i_error==0x80040164L) risultato="CS_E_FIRST"; else if (i_error==0x8004016FL) risultato="CS_E_LAST"; else if (i_error==0x80040164L) risultato="CS_E_PACKAGE_NOTFOUND"; else if (i_error==0x80040165L) risultato="CS_E_NOT_DELETABLE"; else if (i_error==0x80040166L) risultato="CS_E_CLASS_NOTFOUND"; else if (i_error==0x80040167L) risultato="CS_E_INVALID_VERSION"; else if (i_error==0x80040168L) risultato="CS_E_NO_CLASSSTORE"; else if (i_error==0x80040169L) risultato="CS_E_OBJECT_NOTFOUND"; else if (i_error==0x8004016AL) risultato="CS_E_OBJECT_ALREADY_EXISTS"; else if (i_error==0x8004016BL) risultato="CS_E_INVALID_PATH"; else if (i_error==0x8004016CL) risultato="CS_E_NETWORK_ERROR"; else if (i_error==0x8004016DL) risultato="CS_E_ADMIN_LIMIT_EXCEEDED"; else if (i_error==0x8004016EL) risultato="CS_E_SCHEMA_MISMATCH"; else if (i_error==0x8004016FL) risultato="CS_E_INTERNAL_ERROR"; else if (i_error==0x80040170L) risultato="CACHE_E_FIRST"; else if (i_error==0x8004017FL) risultato="CACHE_E_LAST"; else if (i_error==0x00040170L) risultato="CACHE_S_FIRST"; else if (i_error==0x0004017FL) risultato="CACHE_S_LAST"; else if (i_error==0x80040170L) risultato="CACHE_E_NOCACHE_UPDATED"; else if (i_error==0x80040180L) risultato="OLEOBJ_E_FIRST"; else if (i_error==0x8004018FL) risultato="OLEOBJ_E_LAST"; else if (i_error==0x00040180L) risultato="OLEOBJ_S_FIRST"; else if (i_error==0x0004018FL) risultato="OLEOBJ_S_LAST"; else if (i_error==0x80040180L) risultato="OLEOBJ_E_NOVERBS"; else if (i_error==0x80040181L) risultato="OLEOBJ_E_INVALIDVERB"; else if (i_error==0x80040190L) risultato="CLIENTSITE_E_FIRST"; else if (i_error==0x8004019FL) risultato="CLIENTSITE_E_LAST"; else if (i_error==0x00040190L) risultato="CLIENTSITE_S_FIRST"; else if (i_error==0x0004019FL) risultato="CLIENTSITE_S_LAST"; else if (i_error==0x800401A0L) risultato="INPLACE_E_NOTUNDOABLE"; else if (i_error==0x800401A1L) risultato="INPLACE_E_NOTOOLSPACE"; else if (i_error==0x800401A0L) risultato="INPLACE_E_FIRST"; else if (i_error==0x800401AFL) risultato="INPLACE_E_LAST"; else if (i_error==0x000401A0L) risultato="INPLACE_S_FIRST"; else if (i_error==0x000401AFL) risultato="INPLACE_S_LAST"; else if (i_error==0x800401B0L) risultato="ENUM_E_FIRST"; else if (i_error==0x800401BFL) risultato="ENUM_E_LAST"; else if (i_error==0x000401B0L) risultato="ENUM_S_FIRST"; else if (i_error==0x000401BFL) risultato="ENUM_S_LAST"; else if (i_error==0x800401C0L) risultato="CONVERT10_E_FIRST"; else if (i_error==0x800401CFL) risultato="CONVERT10_E_LAST"; else if (i_error==0x000401C0L) risultato="CONVERT10_S_FIRST"; else if (i_error==0x000401CFL) risultato="CONVERT10_S_LAST"; else if (i_error==0x800401C0L) risultato="CONVERT10_E_OLESTREAM_GET"; else if (i_error==0x800401C1L) risultato="CONVERT10_E_OLESTREAM_PUT"; else if (i_error==0x800401C2L) risultato="CONVERT10_E_OLESTREAM_FMT"; else if (i_error==0x800401C3L) risultato="CONVERT10_E_OLESTREAM_BITMAP_TO_DIB"; else if (i_error==0x800401C4L) risultato="CONVERT10_E_STG_FMT"; else if (i_error==0x800401C5L) risultato="CONVERT10_E_STG_NO_STD_STREAM"; else if (i_error==0x800401C6L) risultato="CONVERT10_E_STG_DIB_TO_BITMAP"; else if (i_error==0x800401D0L) risultato="CLIPBRD_E_FIRST"; else if (i_error==0x800401DFL) risultato="CLIPBRD_E_LAST"; else if (i_error==0x000401D0L) risultato="CLIPBRD_S_FIRST"; else if (i_error==0x000401DFL) risultato="CLIPBRD_S_LAST"; else if (i_error==0x800401D0L) risultato="CLIPBRD_E_CANT_OPEN"; else if (i_error==0x800401D1L) risultato="CLIPBRD_E_CANT_EMPTY"; else if (i_error==0x800401D2L) risultato="CLIPBRD_E_CANT_SET"; else if (i_error==0x800401D3L) risultato="CLIPBRD_E_BAD_DATA"; else if (i_error==0x800401D4L) risultato="CLIPBRD_E_CANT_CLOSE"; else if (i_error==0x800401E0L) risultato="MK_E_FIRST"; else if (i_error==0x800401EFL) risultato="MK_E_LAST"; else if (i_error==0x000401E0L) risultato="MK_S_FIRST"; else if (i_error==0x000401EFL) risultato="MK_S_LAST"; else if (i_error==0x800401E0L) risultato="MK_E_CONNECTMANUALLY"; else if (i_error==0x800401E1L) risultato="MK_E_EXCEEDEDDEADLINE"; else if (i_error==0x800401E2L) risultato="MK_E_NEEDGENERIC"; else if (i_error==0x800401E3L) risultato="MK_E_UNAVAILABLE"; else if (i_error==0x800401E4L) risultato="MK_E_SYNTAX"; else if (i_error==0x800401E5L) risultato="MK_E_NOOBJECT"; else if (i_error==0x800401E6L) risultato="MK_E_INVALIDEXTENSION"; else if (i_error==0x800401E7L) risultato="MK_E_INTERMEDIATEINTERFACENOTSUPPORTED"; else if (i_error==0x800401E8L) risultato="MK_E_NOTBINDABLE"; else if (i_error==0x800401E9L) risultato="MK_E_NOTBOUND"; else if (i_error==0x800401EAL) risultato="MK_E_CANTOPENFILE"; else if (i_error==0x800401EBL) risultato="MK_E_MUSTBOTHERUSER"; else if (i_error==0x800401ECL) risultato="MK_E_NOINVERSE"; else if (i_error==0x800401EDL) risultato="MK_E_NOSTORAGE"; else if (i_error==0x800401EEL) risultato="MK_E_NOPREFIX"; else if (i_error==0x800401EFL) risultato="MK_E_ENUMERATION_FAILED"; else if (i_error==0x800401F0L) risultato="CO_E_FIRST"; else if (i_error==0x800401FFL) risultato="CO_E_LAST"; else if (i_error==0x000401F0L) risultato="CO_S_FIRST"; else if (i_error==0x000401FFL) risultato="CO_S_LAST"; else if (i_error==0x800401F0L) risultato="CO_E_NOTINITIALIZED"; else if (i_error==0x800401F1L) risultato="CO_E_ALREADYINITIALIZED"; else if (i_error==0x800401F2L) risultato="CO_E_CANTDETERMINECLASS"; else if (i_error==0x800401F3L) risultato="CO_E_CLASSSTRING"; else if (i_error==0x800401F4L) risultato="CO_E_IIDSTRING"; else if (i_error==0x800401F5L) risultato="CO_E_APPNOTFOUND"; else if (i_error==0x800401F6L) risultato="CO_E_APPSINGLEUSE"; else if (i_error==0x800401F7L) risultato="CO_E_ERRORINAPP"; else if (i_error==0x800401F8L) risultato="CO_E_DLLNOTFOUND"; else if (i_error==0x800401F9L) risultato="CO_E_ERRORINDLL"; else if (i_error==0x800401FAL) risultato="CO_E_WRONGOSFORAPP"; else if (i_error==0x800401FBL) risultato="CO_E_OBJNOTREG"; else if (i_error==0x800401FCL) risultato="CO_E_OBJISREG"; else if (i_error==0x800401FDL) risultato="CO_E_OBJNOTCONNECTED"; else if (i_error==0x800401FEL) risultato="CO_E_APPDIDNTREG"; else if (i_error==0x800401FFL) risultato="CO_E_RELEASED"; else if (i_error==0x80040200L) risultato="EVENT_E_FIRST"; else if (i_error==0x8004021FL) risultato="EVENT_E_LAST"; else if (i_error==0x00040200L) risultato="EVENT_S_FIRST"; else if (i_error==0x0004021FL) risultato="EVENT_S_LAST"; else if (i_error==0x00040200L) risultato="EVENT_S_SOME_SUBSCRIBERS_FAILED"; else if (i_error==0x80040201L) risultato="EVENT_E_ALL_SUBSCRIBERS_FAILED"; else if (i_error==0x00040202L) risultato="EVENT_S_NOSUBSCRIBERS"; else if (i_error==0x80040203L) risultato="EVENT_E_QUERYSYNTAX"; else if (i_error==0x80040204L) risultato="EVENT_E_QUERYFIELD"; else if (i_error==0x80040205L) risultato="EVENT_E_INTERNALEXCEPTION"; else if (i_error==0x80040206L) risultato="EVENT_E_INTERNALERROR"; else if (i_error==0x80040207L) risultato="EVENT_E_INVALID_PER_USER_SID"; else if (i_error==0x80040208L) risultato="EVENT_E_USER_EXCEPTION"; else if (i_error==0x80040209L) risultato="EVENT_E_TOO_MANY_METHODS"; else if (i_error==0x8004020AL) risultato="EVENT_E_MISSING_EVENTCLASS"; else if (i_error==0x8004020BL) risultato="EVENT_E_NOT_ALL_REMOVED"; else if (i_error==0x8004020CL) risultato="EVENT_E_COMPLUS_NOT_INSTALLED"; else if (i_error==0x8004020DL) risultato="EVENT_E_CANT_MODIFY_OR_DELETE_UNCONFIGURED_OBJECT"; else if (i_error==0x8004020EL) risultato="EVENT_E_CANT_MODIFY_OR_DELETE_CONFIGURED_OBJECT"; else if (i_error==0x8004020FL) risultato="EVENT_E_INVALID_EVENT_CLASS_PARTITION"; else if (i_error==0x80040210L) risultato="EVENT_E_PER_USER_SID_NOT_LOGGED_ON"; else if (i_error==0x80040241L) risultato="TPC_E_INVALID_PROPERTY"; else if (i_error==0x80040212L) risultato="TPC_E_NO_DEFAULT_TABLET"; else if (i_error==0x8004021BL) risultato="TPC_E_UNKNOWN_PROPERTY"; else if (i_error==0x80040219L) risultato="TPC_E_INVALID_INPUT_RECT"; else if (i_error==0x80040222L) risultato="TPC_E_INVALID_STROKE"; else if (i_error==0x80040223L) risultato="TPC_E_INITIALIZE_FAIL"; else if (i_error==0x80040232L) risultato="TPC_E_NOT_RELEVANT"; else if (i_error==0x80040233L) risultato="TPC_E_INVALID_PACKET_DESCRIPTION"; else if (i_error==0x80040235L) risultato="TPC_E_RECOGNIZER_NOT_REGISTERED"; else if (i_error==0x80040236L) risultato="TPC_E_INVALID_RIGHTS"; else if (i_error==0x80040237L) risultato="TPC_E_OUT_OF_ORDER_CALL"; else if (i_error==0x80040238L) risultato="TPC_E_QUEUE_FULL"; else if (i_error==0x80040239L) risultato="TPC_E_INVALID_CONFIGURATION"; else if (i_error==0x8004023AL) risultato="TPC_E_INVALID_DATA_FROM_RECOGNIZER"; else if (i_error==0x00040252L) risultato="TPC_S_TRUNCATED"; else if (i_error==0x00040253L) risultato="TPC_S_INTERRUPTED"; else if (i_error==0x00040254L) risultato="TPC_S_NO_DATA_TO_PROCESS"; else if (i_error==0x8004D000) risultato="XACT_E_FIRST"; else if (i_error==0x8004D02B) risultato="XACT_E_LAST"; else if (i_error==0x0004D000) risultato="XACT_S_FIRST"; else if (i_error==0x0004D010) risultato="XACT_S_LAST"; else if (i_error==0x8004D000L) risultato="XACT_E_ALREADYOTHERSINGLEPHASE"; else if (i_error==0x8004D001L) risultato="XACT_E_CANTRETAIN"; else if (i_error==0x8004D002L) risultato="XACT_E_COMMITFAILED"; else if (i_error==0x8004D003L) risultato="XACT_E_COMMITPREVENTED"; else if (i_error==0x8004D004L) risultato="XACT_E_HEURISTICABORT"; else if (i_error==0x8004D005L) risultato="XACT_E_HEURISTICCOMMIT"; else if (i_error==0x8004D006L) risultato="XACT_E_HEURISTICDAMAGE"; else if (i_error==0x8004D007L) risultato="XACT_E_HEURISTICDANGER"; else if (i_error==0x8004D008L) risultato="XACT_E_ISOLATIONLEVEL"; else if (i_error==0x8004D009L) risultato="XACT_E_NOASYNC"; else if (i_error==0x8004D00AL) risultato="XACT_E_NOENLIST"; else if (i_error==0x8004D00BL) risultato="XACT_E_NOISORETAIN"; else if (i_error==0x8004D00CL) risultato="XACT_E_NORESOURCE"; else if (i_error==0x8004D00DL) risultato="XACT_E_NOTCURRENT"; else if (i_error==0x8004D00EL) risultato="XACT_E_NOTRANSACTION"; else if (i_error==0x8004D00FL) risultato="XACT_E_NOTSUPPORTED"; else if (i_error==0x8004D010L) risultato="XACT_E_UNKNOWNRMGRID"; else if (i_error==0x8004D011L) risultato="XACT_E_WRONGSTATE"; else if (i_error==0x8004D012L) risultato="XACT_E_WRONGUOW"; else if (i_error==0x8004D013L) risultato="XACT_E_XTIONEXISTS"; else if (i_error==0x8004D014L) risultato="XACT_E_NOIMPORTOBJECT"; else if (i_error==0x8004D015L) risultato="XACT_E_INVALIDCOOKIE"; else if (i_error==0x8004D016L) risultato="XACT_E_INDOUBT"; else if (i_error==0x8004D017L) risultato="XACT_E_NOTIMEOUT"; else if (i_error==0x8004D018L) risultato="XACT_E_ALREADYINPROGRESS"; else if (i_error==0x8004D019L) risultato="XACT_E_ABORTED"; else if (i_error==0x8004D01AL) risultato="XACT_E_LOGFULL"; else if (i_error==0x8004D01BL) risultato="XACT_E_TMNOTAVAILABLE"; else if (i_error==0x8004D01CL) risultato="XACT_E_CONNECTION_DOWN"; else if (i_error==0x8004D01DL) risultato="XACT_E_CONNECTION_DENIED"; else if (i_error==0x8004D01EL) risultato="XACT_E_REENLISTTIMEOUT"; else if (i_error==0x8004D01FL) risultato="XACT_E_TIP_CONNECT_FAILED"; else if (i_error==0x8004D020L) risultato="XACT_E_TIP_PROTOCOL_ERROR"; else if (i_error==0x8004D021L) risultato="XACT_E_TIP_PULL_FAILED"; else if (i_error==0x8004D022L) risultato="XACT_E_DEST_TMNOTAVAILABLE"; else if (i_error==0x8004D023L) risultato="XACT_E_TIP_DISABLED"; else if (i_error==0x8004D024L) risultato="XACT_E_NETWORK_TX_DISABLED"; else if (i_error==0x8004D025L) risultato="XACT_E_PARTNER_NETWORK_TX_DISABLED"; else if (i_error==0x8004D026L) risultato="XACT_E_XA_TX_DISABLED"; else if (i_error==0x8004D027L) risultato="XACT_E_UNABLE_TO_READ_DTC_CONFIG"; else if (i_error==0x8004D028L) risultato="XACT_E_UNABLE_TO_LOAD_DTC_PROXY"; else if (i_error==0x8004D029L) risultato="XACT_E_ABORTING"; else if (i_error==0x8004D02AL) risultato="XACT_E_PUSH_COMM_FAILURE"; else if (i_error==0x8004D02BL) risultato="XACT_E_PULL_COMM_FAILURE"; else if (i_error==0x8004D02CL) risultato="XACT_E_LU_TX_DISABLED"; else if (i_error==0x8004D080L) risultato="XACT_E_CLERKNOTFOUND"; else if (i_error==0x8004D081L) risultato="XACT_E_CLERKEXISTS"; else if (i_error==0x8004D082L) risultato="XACT_E_RECOVERYINPROGRESS"; else if (i_error==0x8004D083L) risultato="XACT_E_TRANSACTIONCLOSED"; else if (i_error==0x8004D084L) risultato="XACT_E_INVALIDLSN"; else if (i_error==0x8004D085L) risultato="XACT_E_REPLAYREQUEST"; else if (i_error==0x0004D000L) risultato="XACT_S_ASYNC"; else if (i_error==0x0004D001L) risultato="XACT_S_DEFECT"; else if (i_error==0x0004D002L) risultato="XACT_S_READONLY"; else if (i_error==0x0004D003L) risultato="XACT_S_SOMENORETAIN"; else if (i_error==0x0004D004L) risultato="XACT_S_OKINFORM"; else if (i_error==0x0004D005L) risultato="XACT_S_MADECHANGESCONTENT"; else if (i_error==0x0004D006L) risultato="XACT_S_MADECHANGESINFORM"; else if (i_error==0x0004D007L) risultato="XACT_S_ALLNORETAIN"; else if (i_error==0x0004D008L) risultato="XACT_S_ABORTING"; else if (i_error==0x0004D009L) risultato="XACT_S_SINGLEPHASE"; else if (i_error==0x0004D00AL) risultato="XACT_S_LOCALLY_OK"; else if (i_error==0x0004D010L) risultato="XACT_S_LASTRESOURCEMANAGER"; else if (i_error==0x8004E000L) risultato="CONTEXT_E_FIRST"; else if (i_error==0x8004E02FL) risultato="CONTEXT_E_LAST"; else if (i_error==0x0004E000L) risultato="CONTEXT_S_FIRST"; else if (i_error==0x0004E02FL) risultato="CONTEXT_S_LAST"; else if (i_error==0x8004E002L) risultato="CONTEXT_E_ABORTED"; else if (i_error==0x8004E003L) risultato="CONTEXT_E_ABORTING"; else if (i_error==0x8004E004L) risultato="CONTEXT_E_NOCONTEXT"; else if (i_error==0x8004E005L) risultato="CONTEXT_E_WOULD_DEADLOCK"; else if (i_error==0x8004E006L) risultato="CONTEXT_E_SYNCH_TIMEOUT"; else if (i_error==0x8004E007L) risultato="CONTEXT_E_OLDREF"; else if (i_error==0x8004E00CL) risultato="CONTEXT_E_ROLENOTFOUND"; else if (i_error==0x8004E00FL) risultato="CONTEXT_E_TMNOTAVAILABLE"; else if (i_error==0x8004E021L) risultato="CO_E_ACTIVATIONFAILED"; else if (i_error==0x8004E022L) risultato="CO_E_ACTIVATIONFAILED_EVENTLOGGED"; else if (i_error==0x8004E023L) risultato="CO_E_ACTIVATIONFAILED_CATALOGERROR"; else if (i_error==0x8004E024L) risultato="CO_E_ACTIVATIONFAILED_TIMEOUT"; else if (i_error==0x8004E025L) risultato="CO_E_INITIALIZATIONFAILED"; else if (i_error==0x8004E026L) risultato="CONTEXT_E_NOJIT"; else if (i_error==0x8004E027L) risultato="CONTEXT_E_NOTRANSACTION"; else if (i_error==0x8004E028L) risultato="CO_E_THREADINGMODEL_CHANGED"; else if (i_error==0x8004E029L) risultato="CO_E_NOIISINTRINSICS"; else if (i_error==0x8004E02AL) risultato="CO_E_NOCOOKIES"; else if (i_error==0x8004E02BL) risultato="CO_E_DBERROR"; else if (i_error==0x8004E02CL) risultato="CO_E_NOTPOOLED"; else if (i_error==0x8004E02DL) risultato="CO_E_NOTCONSTRUCTED"; else if (i_error==0x8004E02EL) risultato="CO_E_NOSYNCHRONIZATION"; else if (i_error==0x8004E02FL) risultato="CO_E_ISOLEVELMISMATCH"; else if (i_error==0x8004E030L) risultato="CO_E_CALL_OUT_OF_TX_SCOPE_NOT_ALLOWED"; else if (i_error==0x8004E031L) risultato="CO_E_EXIT_TRANSACTION_SCOPE_NOT_CALLED"; else if (i_error==0x00040000L) risultato="OLE_S_USEREG"; else if (i_error==0x00040001L) risultato="OLE_S_STATIC"; else if (i_error==0x00040002L) risultato="OLE_S_MAC_CLIPFORMAT"; else if (i_error==0x00040100L) risultato="DRAGDROP_S_DROP"; else if (i_error==0x00040101L) risultato="DRAGDROP_S_CANCEL"; else if (i_error==0x00040102L) risultato="DRAGDROP_S_USEDEFAULTCURSORS"; else if (i_error==0x00040130L) risultato="DATA_S_SAMEFORMATETC"; else if (i_error==0x00040140L) risultato="VIEW_S_ALREADY_FROZEN"; else if (i_error==0x00040170L) risultato="CACHE_S_FORMATETC_NOTSUPPORTED"; else if (i_error==0x00040171L) risultato="CACHE_S_SAMECACHE"; else if (i_error==0x00040172L) risultato="CACHE_S_SOMECACHES_NOTUPDATED"; else if (i_error==0x00040180L) risultato="OLEOBJ_S_INVALIDVERB"; else if (i_error==0x00040181L) risultato="OLEOBJ_S_CANNOT_DOVERB_NOW"; else if (i_error==0x00040182L) risultato="OLEOBJ_S_INVALIDHWND"; else if (i_error==0x000401A0L) risultato="INPLACE_S_TRUNCATED"; else if (i_error==0x000401C0L) risultato="CONVERT10_S_NO_PRESENTATION"; else if (i_error==0x000401E2L) risultato="MK_S_REDUCED_TO_SELF"; else if (i_error==0x000401E4L) risultato="MK_S_ME"; else if (i_error==0x000401E5L) risultato="MK_S_HIM"; else if (i_error==0x000401E6L) risultato="MK_S_US"; else if (i_error==0x000401E7L) risultato="MK_S_MONIKERALREADYREGISTERED"; else if (i_error==0x00041300L) risultato="SCHED_S_TASK_READY"; else if (i_error==0x00041301L) risultato="SCHED_S_TASK_RUNNING"; else if (i_error==0x00041302L) risultato="SCHED_S_TASK_DISABLED"; else if (i_error==0x00041303L) risultato="SCHED_S_TASK_HAS_NOT_RUN"; else if (i_error==0x00041304L) risultato="SCHED_S_TASK_NO_MORE_RUNS"; else if (i_error==0x00041305L) risultato="SCHED_S_TASK_NOT_SCHEDULED"; else if (i_error==0x00041306L) risultato="SCHED_S_TASK_TERMINATED"; else if (i_error==0x00041307L) risultato="SCHED_S_TASK_NO_VALID_TRIGGERS"; else if (i_error==0x00041308L) risultato="SCHED_S_EVENT_TRIGGER"; else if (i_error==0x80041309L) risultato="SCHED_E_TRIGGER_NOT_FOUND"; else if (i_error==0x8004130AL) risultato="SCHED_E_TASK_NOT_READY"; else if (i_error==0x8004130BL) risultato="SCHED_E_TASK_NOT_RUNNING"; else if (i_error==0x8004130CL) risultato="SCHED_E_SERVICE_NOT_INSTALLED"; else if (i_error==0x8004130DL) risultato="SCHED_E_CANNOT_OPEN_TASK"; else if (i_error==0x8004130EL) risultato="SCHED_E_INVALID_TASK"; else if (i_error==0x8004130FL) risultato="SCHED_E_ACCOUNT_INFORMATION_NOT_SET"; else if (i_error==0x80041310L) risultato="SCHED_E_ACCOUNT_NAME_NOT_FOUND"; else if (i_error==0x80041311L) risultato="SCHED_E_ACCOUNT_DBASE_CORRUPT"; else if (i_error==0x80041312L) risultato="SCHED_E_NO_SECURITY_SERVICES"; else if (i_error==0x80041313L) risultato="SCHED_E_UNKNOWN_OBJECT_VERSION"; else if (i_error==0x80041314L) risultato="SCHED_E_UNSUPPORTED_ACCOUNT_OPTION"; else if (i_error==0x80041315L) risultato="SCHED_E_SERVICE_NOT_RUNNING"; else if (i_error==0x80041316L) risultato="SCHED_E_UNEXPECTEDNODE"; else if (i_error==0x80041317L) risultato="SCHED_E_NAMESPACE"; else if (i_error==0x80041318L) risultato="SCHED_E_INVALIDVALUE"; else if (i_error==0x80041319L) risultato="SCHED_E_MISSINGNODE"; else if (i_error==0x8004131AL) risultato="SCHED_E_MALFORMEDXML"; else if (i_error==0x0004131BL) risultato="SCHED_S_SOME_TRIGGERS_FAILED"; else if (i_error==0x0004131CL) risultato="SCHED_S_BATCH_LOGON_PROBLEM"; else if (i_error==0x8004131DL) risultato="SCHED_E_TOO_MANY_NODES"; else if (i_error==0x8004131EL) risultato="SCHED_E_PAST_END_BOUNDARY"; else if (i_error==0x8004131FL) risultato="SCHED_E_ALREADY_RUNNING"; else if (i_error==0x80041320L) risultato="SCHED_E_USER_NOT_LOGGED_ON"; else if (i_error==0x80041321L) risultato="SCHED_E_INVALID_TASK_HASH"; else if (i_error==0x80041322L) risultato="SCHED_E_SERVICE_NOT_AVAILABLE"; else if (i_error==0x80041323L) risultato="SCHED_E_SERVICE_TOO_BUSY"; else if (i_error==0x80041324L) risultato="SCHED_E_TASK_ATTEMPTED"; else if (i_error==0x00041325L) risultato="SCHED_S_TASK_QUEUED"; else if (i_error==0x80041326L) risultato="SCHED_E_TASK_DISABLED"; else if (i_error==0x80041327L) risultato="SCHED_E_TASK_NOT_V1_COMPAT"; else if (i_error==0x80041328L) risultato="SCHED_E_START_ON_DEMAND"; else if (i_error==0x80041329L) risultato="SCHED_E_TASK_NOT_UBPM_COMPAT"; else if (i_error==0x80041330L) risultato="SCHED_E_DEPRECATED_FEATURE_USED"; else if (i_error==0x80080001L) risultato="CO_E_CLASS_CREATE_FAILED"; else if (i_error==0x80080002L) risultato="CO_E_SCM_ERROR"; else if (i_error==0x80080003L) risultato="CO_E_SCM_RPC_FAILURE"; else if (i_error==0x80080004L) risultato="CO_E_BAD_PATH"; else if (i_error==0x80080005L) risultato="CO_E_SERVER_EXEC_FAILURE"; else if (i_error==0x80080006L) risultato="CO_E_OBJSRV_RPC_FAILURE"; else if (i_error==0x80080007L) risultato="MK_E_NO_NORMALIZED"; else if (i_error==0x80080008L) risultato="CO_E_SERVER_STOPPING"; else if (i_error==0x80080009L) risultato="MEM_E_INVALID_ROOT"; else if (i_error==0x80080010L) risultato="MEM_E_INVALID_LINK"; else if (i_error==0x80080011L) risultato="MEM_E_INVALID_SIZE"; else if (i_error==0x00080012L) risultato="CO_S_NOTALLINTERFACES"; else if (i_error==0x00080013L) risultato="CO_S_MACHINENAMENOTFOUND"; else if (i_error==0x80080015L) risultato="CO_E_MISSING_DISPLAYNAME"; else if (i_error==0x80080016L) risultato="CO_E_RUNAS_VALUE_MUST_BE_AAA"; else if (i_error==0x80080017L) risultato="CO_E_ELEVATION_DISABLED"; else if (i_error==0x80080200L) risultato="APPX_E_PACKAGING_INTERNAL"; else if (i_error==0x80080201L) risultato="APPX_E_INTERLEAVING_NOT_ALLOWED"; else if (i_error==0x80080202L) risultato="APPX_E_RELATIONSHIPS_NOT_ALLOWED"; else if (i_error==0x80080203L) risultato="APPX_E_MISSING_REQUIRED_FILE"; else if (i_error==0x80080204L) risultato="APPX_E_INVALID_MANIFEST"; else if (i_error==0x80080205L) risultato="APPX_E_INVALID_BLOCKMAP"; else if (i_error==0x80080206L) risultato="APPX_E_CORRUPT_CONTENT"; else if (i_error==0x80080207L) risultato="APPX_E_BLOCK_HASH_INVALID"; else if (i_error==0x80080208L) risultato="APPX_E_REQUESTED_RANGE_TOO_LARGE"; else if (i_error==0x80080209L) risultato="APPX_E_INVALID_SIP_CLIENT_DATA"; else if (i_error==0x8008020AL) risultato="APPX_E_INVALID_KEY_INFO"; else if (i_error==0x80080300L) risultato="BT_E_SPURIOUS_ACTIVATION"; else if (i_error==0x80020001L) risultato="DISP_E_UNKNOWNINTERFACE"; else if (i_error==0x80020003L) risultato="DISP_E_MEMBERNOTFOUND"; else if (i_error==0x80020004L) risultato="DISP_E_PARAMNOTFOUND"; else if (i_error==0x80020005L) risultato="DISP_E_TYPEMISMATCH"; else if (i_error==0x80020006L) risultato="DISP_E_UNKNOWNNAME"; else if (i_error==0x80020007L) risultato="DISP_E_NONAMEDARGS"; else if (i_error==0x80020008L) risultato="DISP_E_BADVARTYPE"; else if (i_error==0x80020009L) risultato="DISP_E_EXCEPTION"; else if (i_error==0x8002000AL) risultato="DISP_E_OVERFLOW"; else if (i_error==0x8002000BL) risultato="DISP_E_BADINDEX"; else if (i_error==0x8002000CL) risultato="DISP_E_UNKNOWNLCID"; else if (i_error==0x8002000DL) risultato="DISP_E_ARRAYISLOCKED"; else if (i_error==0x8002000EL) risultato="DISP_E_BADPARAMCOUNT"; else if (i_error==0x8002000FL) risultato="DISP_E_PARAMNOTOPTIONAL"; else if (i_error==0x80020010L) risultato="DISP_E_BADCALLEE"; else if (i_error==0x80020011L) risultato="DISP_E_NOTACOLLECTION"; else if (i_error==0x80020012L) risultato="DISP_E_DIVBYZERO"; else if (i_error==0x80020013L) risultato="DISP_E_BUFFERTOOSMALL"; else if (i_error==0x80028016L) risultato="TYPE_E_BUFFERTOOSMALL"; else if (i_error==0x80028017L) risultato="TYPE_E_FIELDNOTFOUND"; else if (i_error==0x80028018L) risultato="TYPE_E_INVDATAREAD"; else if (i_error==0x80028019L) risultato="TYPE_E_UNSUPFORMAT"; else if (i_error==0x8002801CL) risultato="TYPE_E_REGISTRYACCESS"; else if (i_error==0x8002801DL) risultato="TYPE_E_LIBNOTREGISTERED"; else if (i_error==0x80028027L) risultato="TYPE_E_UNDEFINEDTYPE"; else if (i_error==0x80028028L) risultato="TYPE_E_QUALIFIEDNAMEDISALLOWED"; else if (i_error==0x80028029L) risultato="TYPE_E_INVALIDSTATE"; else if (i_error==0x8002802AL) risultato="TYPE_E_WRONGTYPEKIND"; else if (i_error==0x8002802BL) risultato="TYPE_E_ELEMENTNOTFOUND"; else if (i_error==0x8002802CL) risultato="TYPE_E_AMBIGUOUSNAME"; else if (i_error==0x8002802DL) risultato="TYPE_E_NAMECONFLICT"; else if (i_error==0x8002802EL) risultato="TYPE_E_UNKNOWNLCID"; else if (i_error==0x8002802FL) risultato="TYPE_E_DLLFUNCTIONNOTFOUND"; else if (i_error==0x800288BDL) risultato="TYPE_E_BADMODULEKIND"; else if (i_error==0x800288C5L) risultato="TYPE_E_SIZETOOBIG"; else if (i_error==0x800288C6L) risultato="TYPE_E_DUPLICATEID"; else if (i_error==0x800288CFL) risultato="TYPE_E_INVALIDID"; else if (i_error==0x80028CA0L) risultato="TYPE_E_TYPEMISMATCH"; else if (i_error==0x80028CA1L) risultato="TYPE_E_OUTOFBOUNDS"; else if (i_error==0x80028CA2L) risultato="TYPE_E_IOERROR"; else if (i_error==0x80028CA3L) risultato="TYPE_E_CANTCREATETMPFILE"; else if (i_error==0x80029C4AL) risultato="TYPE_E_CANTLOADLIBRARY"; else if (i_error==0x80029C83L) risultato="TYPE_E_INCONSISTENTPROPFUNCS"; else if (i_error==0x80029C84L) risultato="TYPE_E_CIRCULARTYPE"; else if (i_error==0x80030001L) risultato="STG_E_INVALIDFUNCTION"; else if (i_error==0x80030002L) risultato="STG_E_FILENOTFOUND"; else if (i_error==0x80030003L) risultato="STG_E_PATHNOTFOUND"; else if (i_error==0x80030004L) risultato="STG_E_TOOMANYOPENFILES"; else if (i_error==0x80030005L) risultato="STG_E_ACCESSDENIED"; else if (i_error==0x80030006L) risultato="STG_E_INVALIDHANDLE"; else if (i_error==0x80030008L) risultato="STG_E_INSUFFICIENTMEMORY"; else if (i_error==0x80030009L) risultato="STG_E_INVALIDPOINTER"; else if (i_error==0x80030012L) risultato="STG_E_NOMOREFILES"; else if (i_error==0x80030013L) risultato="STG_E_DISKISWRITEPROTECTED"; else if (i_error==0x80030019L) risultato="STG_E_SEEKERROR"; else if (i_error==0x8003001DL) risultato="STG_E_WRITEFAULT"; else if (i_error==0x8003001EL) risultato="STG_E_READFAULT"; else if (i_error==0x80030020L) risultato="STG_E_SHAREVIOLATION"; else if (i_error==0x80030021L) risultato="STG_E_LOCKVIOLATION"; else if (i_error==0x80030050L) risultato="STG_E_FILEALREADYEXISTS"; else if (i_error==0x80030057L) risultato="STG_E_INVALIDPARAMETER"; else if (i_error==0x80030070L) risultato="STG_E_MEDIUMFULL"; else if (i_error==0x800300F0L) risultato="STG_E_PROPSETMISMATCHED"; else if (i_error==0x800300FAL) risultato="STG_E_ABNORMALAPIEXIT"; else if (i_error==0x800300FBL) risultato="STG_E_INVALIDHEADER"; else if (i_error==0x800300FCL) risultato="STG_E_INVALIDNAME"; else if (i_error==0x800300FDL) risultato="STG_E_UNKNOWN"; else if (i_error==0x800300FEL) risultato="STG_E_UNIMPLEMENTEDFUNCTION"; else if (i_error==0x800300FFL) risultato="STG_E_INVALIDFLAG"; else if (i_error==0x80030100L) risultato="STG_E_INUSE"; else if (i_error==0x80030101L) risultato="STG_E_NOTCURRENT"; else if (i_error==0x80030102L) risultato="STG_E_REVERTED"; else if (i_error==0x80030103L) risultato="STG_E_CANTSAVE"; else if (i_error==0x80030104L) risultato="STG_E_OLDFORMAT"; else if (i_error==0x80030105L) risultato="STG_E_OLDDLL"; else if (i_error==0x80030106L) risultato="STG_E_SHAREREQUIRED"; else if (i_error==0x80030107L) risultato="STG_E_NOTFILEBASEDSTORAGE"; else if (i_error==0x80030108L) risultato="STG_E_EXTANTMARSHALLINGS"; else if (i_error==0x80030109L) risultato="STG_E_DOCFILECORRUPT"; else if (i_error==0x80030110L) risultato="STG_E_BADBASEADDRESS"; else if (i_error==0x80030111L) risultato="STG_E_DOCFILETOOLARGE"; else if (i_error==0x80030112L) risultato="STG_E_NOTSIMPLEFORMAT"; else if (i_error==0x80030201L) risultato="STG_E_INCOMPLETE"; else if (i_error==0x80030202L) risultato="STG_E_TERMINATED"; else if (i_error==0x00030200L) risultato="STG_S_CONVERTED"; else if (i_error==0x00030201L) risultato="STG_S_BLOCK"; else if (i_error==0x00030202L) risultato="STG_S_RETRYNOW"; else if (i_error==0x00030203L) risultato="STG_S_MONITORING"; else if (i_error==0x00030204L) risultato="STG_S_MULTIPLEOPENS"; else if (i_error==0x00030205L) risultato="STG_S_CONSOLIDATIONFAILED"; else if (i_error==0x00030206L) risultato="STG_S_CANNOTCONSOLIDATE"; else if (i_error==0x00030207L) risultato="STG_S_POWER_CYCLE_REQUIRED"; else if (i_error==0x80030208L) risultato="STG_E_FIRMWARE_SLOT_INVALID"; else if (i_error==0x80030209L) risultato="STG_E_FIRMWARE_IMAGE_INVALID"; else if (i_error==0x8003020AL) risultato="STG_E_DEVICE_UNRESPONSIVE"; else if (i_error==0x80030305L) risultato="STG_E_STATUS_COPY_PROTECTION_FAILURE"; else if (i_error==0x80030306L) risultato="STG_E_CSS_AUTHENTICATION_FAILURE"; else if (i_error==0x80030307L) risultato="STG_E_CSS_KEY_NOT_PRESENT"; else if (i_error==0x80030308L) risultato="STG_E_CSS_KEY_NOT_ESTABLISHED"; else if (i_error==0x80030309L) risultato="STG_E_CSS_SCRAMBLED_SECTOR"; else if (i_error==0x8003030AL) risultato="STG_E_CSS_REGION_MISMATCH"; else if (i_error==0x8003030BL) risultato="STG_E_RESETS_EXHAUSTED"; else if (i_error==0x80010001L) risultato="RPC_E_CALL_REJECTED"; else if (i_error==0x80010002L) risultato="RPC_E_CALL_CANCELED"; else if (i_error==0x80010003L) risultato="RPC_E_CANTPOST_INSENDCALL"; else if (i_error==0x80010004L) risultato="RPC_E_CANTCALLOUT_INASYNCCALL"; else if (i_error==0x80010005L) risultato="RPC_E_CANTCALLOUT_INEXTERNALCALL"; else if (i_error==0x80010006L) risultato="RPC_E_CONNECTION_TERMINATED"; else if (i_error==0x80010007L) risultato="RPC_E_SERVER_DIED"; else if (i_error==0x80010008L) risultato="RPC_E_CLIENT_DIED"; else if (i_error==0x80010009L) risultato="RPC_E_INVALID_DATAPACKET"; else if (i_error==0x8001000AL) risultato="RPC_E_CANTTRANSMIT_CALL"; else if (i_error==0x8001000BL) risultato="RPC_E_CLIENT_CANTMARSHAL_DATA"; else if (i_error==0x8001000CL) risultato="RPC_E_CLIENT_CANTUNMARSHAL_DATA"; else if (i_error==0x8001000DL) risultato="RPC_E_SERVER_CANTMARSHAL_DATA"; else if (i_error==0x8001000EL) risultato="RPC_E_SERVER_CANTUNMARSHAL_DATA"; else if (i_error==0x8001000FL) risultato="RPC_E_INVALID_DATA"; else if (i_error==0x80010010L) risultato="RPC_E_INVALID_PARAMETER"; else if (i_error==0x80010011L) risultato="RPC_E_CANTCALLOUT_AGAIN"; else if (i_error==0x80010012L) risultato="RPC_E_SERVER_DIED_DNE"; else if (i_error==0x80010100L) risultato="RPC_E_SYS_CALL_FAILED"; else if (i_error==0x80010101L) risultato="RPC_E_OUT_OF_RESOURCES"; else if (i_error==0x80010102L) risultato="RPC_E_ATTEMPTED_MULTITHREAD"; else if (i_error==0x80010103L) risultato="RPC_E_NOT_REGISTERED"; else if (i_error==0x80010104L) risultato="RPC_E_FAULT"; else if (i_error==0x80010105L) risultato="RPC_E_SERVERFAULT"; else if (i_error==0x80010106L) risultato="RPC_E_CHANGED_MODE"; else if (i_error==0x80010107L) risultato="RPC_E_INVALIDMETHOD"; else if (i_error==0x80010108L) risultato="RPC_E_DISCONNECTED"; else if (i_error==0x80010109L) risultato="RPC_E_RETRY"; else if (i_error==0x8001010AL) risultato="RPC_E_SERVERCALL_RETRYLATER"; else if (i_error==0x8001010BL) risultato="RPC_E_SERVERCALL_REJECTED"; else if (i_error==0x8001010CL) risultato="RPC_E_INVALID_CALLDATA"; else if (i_error==0x8001010DL) risultato="RPC_E_CANTCALLOUT_ININPUTSYNCCALL"; else if (i_error==0x8001010EL) risultato="RPC_E_WRONG_THREAD"; else if (i_error==0x8001010FL) risultato="RPC_E_THREAD_NOT_INIT"; else if (i_error==0x80010110L) risultato="RPC_E_VERSION_MISMATCH"; else if (i_error==0x80010111L) risultato="RPC_E_INVALID_HEADER"; else if (i_error==0x80010112L) risultato="RPC_E_INVALID_EXTENSION"; else if (i_error==0x80010113L) risultato="RPC_E_INVALID_IPID"; else if (i_error==0x80010114L) risultato="RPC_E_INVALID_OBJECT"; else if (i_error==0x80010115L) risultato="RPC_S_CALLPENDING"; else if (i_error==0x80010116L) risultato="RPC_S_WAITONTIMER"; else if (i_error==0x80010117L) risultato="RPC_E_CALL_COMPLETE"; else if (i_error==0x80010118L) risultato="RPC_E_UNSECURE_CALL"; else if (i_error==0x80010119L) risultato="RPC_E_TOO_LATE"; else if (i_error==0x8001011AL) risultato="RPC_E_NO_GOOD_SECURITY_PACKAGES"; else if (i_error==0x8001011BL) risultato="RPC_E_ACCESS_DENIED"; else if (i_error==0x8001011CL) risultato="RPC_E_REMOTE_DISABLED"; else if (i_error==0x8001011DL) risultato="RPC_E_INVALID_OBJREF"; else if (i_error==0x8001011EL) risultato="RPC_E_NO_CONTEXT"; else if (i_error==0x8001011FL) risultato="RPC_E_TIMEOUT"; else if (i_error==0x80010120L) risultato="RPC_E_NO_SYNC"; else if (i_error==0x80010121L) risultato="RPC_E_FULLSIC_REQUIRED"; else if (i_error==0x80010122L) risultato="RPC_E_INVALID_STD_NAME"; else if (i_error==0x80010123L) risultato="CO_E_FAILEDTOIMPERSONATE"; else if (i_error==0x80010124L) risultato="CO_E_FAILEDTOGETSECCTX"; else if (i_error==0x80010125L) risultato="CO_E_FAILEDTOOPENTHREADTOKEN"; else if (i_error==0x80010126L) risultato="CO_E_FAILEDTOGETTOKENINFO"; else if (i_error==0x80010127L) risultato="CO_E_TRUSTEEDOESNTMATCHCLIENT"; else if (i_error==0x80010128L) risultato="CO_E_FAILEDTOQUERYCLIENTBLANKET"; else if (i_error==0x80010129L) risultato="CO_E_FAILEDTOSETDACL"; else if (i_error==0x8001012AL) risultato="CO_E_ACCESSCHECKFAILED"; else if (i_error==0x8001012BL) risultato="CO_E_NETACCESSAPIFAILED"; else if (i_error==0x8001012CL) risultato="CO_E_WRONGTRUSTEENAMESYNTAX"; else if (i_error==0x8001012DL) risultato="CO_E_INVALIDSID"; else if (i_error==0x8001012EL) risultato="CO_E_CONVERSIONFAILED"; else if (i_error==0x8001012FL) risultato="CO_E_NOMATCHINGSIDFOUND"; else if (i_error==0x80010130L) risultato="CO_E_LOOKUPACCSIDFAILED"; else if (i_error==0x80010131L) risultato="CO_E_NOMATCHINGNAMEFOUND"; else if (i_error==0x80010132L) risultato="CO_E_LOOKUPACCNAMEFAILED"; else if (i_error==0x80010133L) risultato="CO_E_SETSERLHNDLFAILED"; else if (i_error==0x80010134L) risultato="CO_E_FAILEDTOGETWINDIR"; else if (i_error==0x80010135L) risultato="CO_E_PATHTOOLONG"; else if (i_error==0x80010136L) risultato="CO_E_FAILEDTOGENUUID"; else if (i_error==0x80010137L) risultato="CO_E_FAILEDTOCREATEFILE"; else if (i_error==0x80010138L) risultato="CO_E_FAILEDTOCLOSEHANDLE"; else if (i_error==0x80010139L) risultato="CO_E_EXCEEDSYSACLLIMIT"; else if (i_error==0x8001013AL) risultato="CO_E_ACESINWRONGORDER"; else if (i_error==0x8001013BL) risultato="CO_E_INCOMPATIBLESTREAMVERSION"; else if (i_error==0x8001013CL) risultato="CO_E_FAILEDTOOPENPROCESSTOKEN"; else if (i_error==0x8001013DL) risultato="CO_E_DECODEFAILED"; else if (i_error==0x8001013FL) risultato="CO_E_ACNOTINITIALIZED"; else if (i_error==0x80010140L) risultato="CO_E_CANCEL_DISABLED"; else if (i_error==0x8001FFFFL) risultato="RPC_E_UNEXPECTED"; else if (i_error==0xC0090001L) risultato="ERROR_AUDITING_DISABLED"; else if (i_error==0xC0090002L) risultato="ERROR_ALL_SIDS_FILTERED"; else if (i_error==0xC0090003L) risultato="ERROR_BIZRULES_NOT_ENABLED"; else if (i_error==0x80090001L) risultato="NTE_BAD_UID"; else if (i_error==0x80090002L) risultato="NTE_BAD_HASH"; else if (i_error==0x80090003L) risultato="NTE_BAD_KEY"; else if (i_error==0x80090004L) risultato="NTE_BAD_LEN"; else if (i_error==0x80090005L) risultato="NTE_BAD_DATA"; else if (i_error==0x80090006L) risultato="NTE_BAD_SIGNATURE"; else if (i_error==0x80090007L) risultato="NTE_BAD_VER"; else if (i_error==0x80090008L) risultato="NTE_BAD_ALGID"; else if (i_error==0x80090009L) risultato="NTE_BAD_FLAGS"; else if (i_error==0x8009000AL) risultato="NTE_BAD_TYPE"; else if (i_error==0x8009000BL) risultato="NTE_BAD_KEY_STATE"; else if (i_error==0x8009000CL) risultato="NTE_BAD_HASH_STATE"; else if (i_error==0x8009000DL) risultato="NTE_NO_KEY"; else if (i_error==0x8009000EL) risultato="NTE_NO_MEMORY"; else if (i_error==0x8009000FL) risultato="NTE_EXISTS"; else if (i_error==0x80090010L) risultato="NTE_PERM"; else if (i_error==0x80090011L) risultato="NTE_NOT_FOUND"; else if (i_error==0x80090012L) risultato="NTE_DOUBLE_ENCRYPT"; else if (i_error==0x80090013L) risultato="NTE_BAD_PROVIDER"; else if (i_error==0x80090014L) risultato="NTE_BAD_PROV_TYPE"; else if (i_error==0x80090015L) risultato="NTE_BAD_PUBLIC_KEY"; else if (i_error==0x80090016L) risultato="NTE_BAD_KEYSET"; else if (i_error==0x80090017L) risultato="NTE_PROV_TYPE_NOT_DEF"; else if (i_error==0x80090018L) risultato="NTE_PROV_TYPE_ENTRY_BAD"; else if (i_error==0x80090019L) risultato="NTE_KEYSET_NOT_DEF"; else if (i_error==0x8009001AL) risultato="NTE_KEYSET_ENTRY_BAD"; else if (i_error==0x8009001BL) risultato="NTE_PROV_TYPE_NO_MATCH"; else if (i_error==0x8009001CL) risultato="NTE_SIGNATURE_FILE_BAD"; else if (i_error==0x8009001DL) risultato="NTE_PROVIDER_DLL_FAIL"; else if (i_error==0x8009001EL) risultato="NTE_PROV_DLL_NOT_FOUND"; else if (i_error==0x8009001FL) risultato="NTE_BAD_KEYSET_PARAM"; else if (i_error==0x80090020L) risultato="NTE_FAIL"; else if (i_error==0x80090021L) risultato="NTE_SYS_ERR"; else if (i_error==0x80090022L) risultato="NTE_SILENT_CONTEXT"; else if (i_error==0x80090023L) risultato="NTE_TOKEN_KEYSET_STORAGE_FULL"; else if (i_error==0x80090024L) risultato="NTE_TEMPORARY_PROFILE"; else if (i_error==0x80090025L) risultato="NTE_FIXEDPARAMETER"; else if (i_error==0x80090026L) risultato="NTE_INVALID_HANDLE"; else if (i_error==0x80090027L) risultato="NTE_INVALID_PARAMETER"; else if (i_error==0x80090028L) risultato="NTE_BUFFER_TOO_SMALL"; else if (i_error==0x80090029L) risultato="NTE_NOT_SUPPORTED"; else if (i_error==0x8009002AL) risultato="NTE_NO_MORE_ITEMS"; else if (i_error==0x8009002BL) risultato="NTE_BUFFERS_OVERLAP"; else if (i_error==0x8009002CL) risultato="NTE_DECRYPTION_FAILURE"; else if (i_error==0x8009002DL) risultato="NTE_INTERNAL_ERROR"; else if (i_error==0x8009002EL) risultato="NTE_UI_REQUIRED"; else if (i_error==0x8009002FL) risultato="NTE_HMAC_NOT_SUPPORTED"; else if (i_error==0x80090030L) risultato="NTE_DEVICE_NOT_READY"; else if (i_error==0x80090031L) risultato="NTE_AUTHENTICATION_IGNORED"; else if (i_error==0x80090032L) risultato="NTE_VALIDATION_FAILED"; else if (i_error==0x80090033L) risultato="NTE_INCORRECT_PASSWORD"; else if (i_error==0x80090034L) risultato="NTE_ENCRYPTION_FAILURE"; else if (i_error==0x80090035L) risultato="NTE_DEVICE_NOT_FOUND"; else if (i_error==0x80090036L) risultato="NTE_USER_CANCELLED"; else if (i_error==0x80090037L) risultato="NTE_PASSWORD_CHANGE_REQUIRED"; else if (i_error==0x80090038L) risultato="NTE_NOT_ACTIVE_CONSOLE"; else if (i_error==0x80090300L) risultato="SEC_E_INSUFFICIENT_MEMORY"; else if (i_error==0x80090301L) risultato="SEC_E_INVALID_HANDLE"; else if (i_error==0x80090302L) risultato="SEC_E_UNSUPPORTED_FUNCTION"; else if (i_error==0x80090303L) risultato="SEC_E_TARGET_UNKNOWN"; else if (i_error==0x80090304L) risultato="SEC_E_INTERNAL_ERROR"; else if (i_error==0x80090305L) risultato="SEC_E_SECPKG_NOT_FOUND"; else if (i_error==0x80090306L) risultato="SEC_E_NOT_OWNER"; else if (i_error==0x80090307L) risultato="SEC_E_CANNOT_INSTALL"; else if (i_error==0x80090308L) risultato="SEC_E_INVALID_TOKEN"; else if (i_error==0x80090309L) risultato="SEC_E_CANNOT_PACK"; else if (i_error==0x8009030AL) risultato="SEC_E_QOP_NOT_SUPPORTED"; else if (i_error==0x8009030BL) risultato="SEC_E_NO_IMPERSONATION"; else if (i_error==0x8009030CL) risultato="SEC_E_LOGON_DENIED"; else if (i_error==0x8009030DL) risultato="SEC_E_UNKNOWN_CREDENTIALS"; else if (i_error==0x8009030EL) risultato="SEC_E_NO_CREDENTIALS"; else if (i_error==0x8009030FL) risultato="SEC_E_MESSAGE_ALTERED"; else if (i_error==0x80090310L) risultato="SEC_E_OUT_OF_SEQUENCE"; else if (i_error==0x80090311L) risultato="SEC_E_NO_AUTHENTICATING_AUTHORITY"; else if (i_error==0x00090312L) risultato="SEC_I_CONTINUE_NEEDED"; else if (i_error==0x00090313L) risultato="SEC_I_COMPLETE_NEEDED"; else if (i_error==0x00090314L) risultato="SEC_I_COMPLETE_AND_CONTINUE"; else if (i_error==0x00090315L) risultato="SEC_I_LOCAL_LOGON"; else if (i_error==0x80090316L) risultato="SEC_E_BAD_PKGID"; else if (i_error==0x80090317L) risultato="SEC_E_CONTEXT_EXPIRED"; else if (i_error==0x00090317L) risultato="SEC_I_CONTEXT_EXPIRED"; else if (i_error==0x80090318L) risultato="SEC_E_INCOMPLETE_MESSAGE"; else if (i_error==0x80090320L) risultato="SEC_E_INCOMPLETE_CREDENTIALS"; else if (i_error==0x80090321L) risultato="SEC_E_BUFFER_TOO_SMALL"; else if (i_error==0x00090320L) risultato="SEC_I_INCOMPLETE_CREDENTIALS"; else if (i_error==0x00090321L) risultato="SEC_I_RENEGOTIATE"; else if (i_error==0x80090322L) risultato="SEC_E_WRONG_PRINCIPAL"; else if (i_error==0x00090323L) risultato="SEC_I_NO_LSA_CONTEXT"; else if (i_error==0x80090324L) risultato="SEC_E_TIME_SKEW"; else if (i_error==0x80090325L) risultato="SEC_E_UNTRUSTED_ROOT"; else if (i_error==0x80090326L) risultato="SEC_E_ILLEGAL_MESSAGE"; else if (i_error==0x80090327L) risultato="SEC_E_CERT_UNKNOWN"; else if (i_error==0x80090328L) risultato="SEC_E_CERT_EXPIRED"; else if (i_error==0x80090329L) risultato="SEC_E_ENCRYPT_FAILURE"; else if (i_error==0x80090330L) risultato="SEC_E_DECRYPT_FAILURE"; else if (i_error==0x80090331L) risultato="SEC_E_ALGORITHM_MISMATCH"; else if (i_error==0x80090332L) risultato="SEC_E_SECURITY_QOS_FAILED"; else if (i_error==0x80090333L) risultato="SEC_E_UNFINISHED_CONTEXT_DELETED"; else if (i_error==0x80090334L) risultato="SEC_E_NO_TGT_REPLY"; else if (i_error==0x80090335L) risultato="SEC_E_NO_IP_ADDRESSES"; else if (i_error==0x80090336L) risultato="SEC_E_WRONG_CREDENTIAL_HANDLE"; else if (i_error==0x80090337L) risultato="SEC_E_CRYPTO_SYSTEM_INVALID"; else if (i_error==0x80090338L) risultato="SEC_E_MAX_REFERRALS_EXCEEDED"; else if (i_error==0x80090339L) risultato="SEC_E_MUST_BE_KDC"; else if (i_error==0x8009033AL) risultato="SEC_E_STRONG_CRYPTO_NOT_SUPPORTED"; else if (i_error==0x8009033BL) risultato="SEC_E_TOO_MANY_PRINCIPALS"; else if (i_error==0x8009033CL) risultato="SEC_E_NO_PA_DATA"; else if (i_error==0x8009033DL) risultato="SEC_E_PKINIT_NAME_MISMATCH"; else if (i_error==0x8009033EL) risultato="SEC_E_SMARTCARD_LOGON_REQUIRED"; else if (i_error==0x8009033FL) risultato="SEC_E_SHUTDOWN_IN_PROGRESS"; else if (i_error==0x80090340L) risultato="SEC_E_KDC_INVALID_REQUEST"; else if (i_error==0x80090341L) risultato="SEC_E_KDC_UNABLE_TO_REFER"; else if (i_error==0x80090342L) risultato="SEC_E_KDC_UNKNOWN_ETYPE"; else if (i_error==0x80090343L) risultato="SEC_E_UNSUPPORTED_PREAUTH"; else if (i_error==0x80090345L) risultato="SEC_E_DELEGATION_REQUIRED"; else if (i_error==0x80090346L) risultato="SEC_E_BAD_BINDINGS"; else if (i_error==0x80090347L) risultato="SEC_E_MULTIPLE_ACCOUNTS"; else if (i_error==0x80090348L) risultato="SEC_E_NO_KERB_KEY"; else if (i_error==0x80090349L) risultato="SEC_E_CERT_WRONG_USAGE"; else if (i_error==0x80090350L) risultato="SEC_E_DOWNGRADE_DETECTED"; else if (i_error==0x80090351L) risultato="SEC_E_SMARTCARD_CERT_REVOKED"; else if (i_error==0x80090352L) risultato="SEC_E_ISSUING_CA_UNTRUSTED"; else if (i_error==0x80090353L) risultato="SEC_E_REVOCATION_OFFLINE_C"; else if (i_error==0x80090354L) risultato="SEC_E_PKINIT_CLIENT_FAILURE"; else if (i_error==0x80090355L) risultato="SEC_E_SMARTCARD_CERT_EXPIRED"; else if (i_error==0x80090356L) risultato="SEC_E_NO_S4U_PROT_SUPPORT"; else if (i_error==0x80090357L) risultato="SEC_E_CROSSREALM_DELEGATION_FAILURE"; else if (i_error==0x80090358L) risultato="SEC_E_REVOCATION_OFFLINE_KDC"; else if (i_error==0x80090359L) risultato="SEC_E_ISSUING_CA_UNTRUSTED_KDC"; else if (i_error==0x8009035AL) risultato="SEC_E_KDC_CERT_EXPIRED"; else if (i_error==0x8009035BL) risultato="SEC_E_KDC_CERT_REVOKED"; else if (i_error==0x0009035CL) risultato="SEC_I_SIGNATURE_NEEDED"; else if (i_error==0x8009035DL) risultato="SEC_E_INVALID_PARAMETER"; else if (i_error==0x8009035EL) risultato="SEC_E_DELEGATION_POLICY"; else if (i_error==0x8009035FL) risultato="SEC_E_POLICY_NLTM_ONLY"; else if (i_error==0x00090360L) risultato="SEC_I_NO_RENEGOTIATION"; else if (i_error==0x80090361L) risultato="SEC_E_NO_CONTEXT"; else if (i_error==0x80090362L) risultato="SEC_E_PKU2U_CERT_FAILURE"; else if (i_error==0x80090363L) risultato="SEC_E_MUTUAL_AUTH_FAILED"; else if (i_error==0x00090364L) risultato="SEC_I_MESSAGE_FRAGMENT"; else if (i_error==0x80090365L) risultato="SEC_E_ONLY_HTTPS_ALLOWED"; else if (i_error==0x00090366L) risultato="SEC_I_CONTINUE_NEEDED_MESSAGE_OK"; else if (i_error==0x80090367L) risultato="SEC_E_APPLICATION_PROTOCOL_MISMATCH"; else if (i_error==0x00090368L) risultato="SEC_I_ASYNC_CALL_PENDING"; else if (i_error==0x80090369L) risultato="SEC_E_INVALID_UPN_NAME"; else if (i_error==0x80091001L) risultato="CRYPT_E_MSG_ERROR"; else if (i_error==0x80091002L) risultato="CRYPT_E_UNKNOWN_ALGO"; else if (i_error==0x80091003L) risultato="CRYPT_E_OID_FORMAT"; else if (i_error==0x80091004L) risultato="CRYPT_E_INVALID_MSG_TYPE"; else if (i_error==0x80091005L) risultato="CRYPT_E_UNEXPECTED_ENCODING"; else if (i_error==0x80091006L) risultato="CRYPT_E_AUTH_ATTR_MISSING"; else if (i_error==0x80091007L) risultato="CRYPT_E_HASH_VALUE"; else if (i_error==0x80091008L) risultato="CRYPT_E_INVALID_INDEX"; else if (i_error==0x80091009L) risultato="CRYPT_E_ALREADY_DECRYPTED"; else if (i_error==0x8009100AL) risultato="CRYPT_E_NOT_DECRYPTED"; else if (i_error==0x8009100BL) risultato="CRYPT_E_RECIPIENT_NOT_FOUND"; else if (i_error==0x8009100CL) risultato="CRYPT_E_CONTROL_TYPE"; else if (i_error==0x8009100DL) risultato="CRYPT_E_ISSUER_SERIALNUMBER"; else if (i_error==0x8009100EL) risultato="CRYPT_E_SIGNER_NOT_FOUND"; else if (i_error==0x8009100FL) risultato="CRYPT_E_ATTRIBUTES_MISSING"; else if (i_error==0x80091010L) risultato="CRYPT_E_STREAM_MSG_NOT_READY"; else if (i_error==0x80091011L) risultato="CRYPT_E_STREAM_INSUFFICIENT_DATA"; else if (i_error==0x00091012L) risultato="CRYPT_I_NEW_PROTECTION_REQUIRED"; else if (i_error==0x80092001L) risultato="CRYPT_E_BAD_LEN"; else if (i_error==0x80092002L) risultato="CRYPT_E_BAD_ENCODE"; else if (i_error==0x80092003L) risultato="CRYPT_E_FILE_ERROR"; else if (i_error==0x80092004L) risultato="CRYPT_E_NOT_FOUND"; else if (i_error==0x80092005L) risultato="CRYPT_E_EXISTS"; else if (i_error==0x80092006L) risultato="CRYPT_E_NO_PROVIDER"; else if (i_error==0x80092007L) risultato="CRYPT_E_SELF_SIGNED"; else if (i_error==0x80092008L) risultato="CRYPT_E_DELETED_PREV"; else if (i_error==0x80092009L) risultato="CRYPT_E_NO_MATCH"; else if (i_error==0x8009200AL) risultato="CRYPT_E_UNEXPECTED_MSG_TYPE"; else if (i_error==0x8009200BL) risultato="CRYPT_E_NO_KEY_PROPERTY"; else if (i_error==0x8009200CL) risultato="CRYPT_E_NO_DECRYPT_CERT"; else if (i_error==0x8009200DL) risultato="CRYPT_E_BAD_MSG"; else if (i_error==0x8009200EL) risultato="CRYPT_E_NO_SIGNER"; else if (i_error==0x8009200FL) risultato="CRYPT_E_PENDING_CLOSE"; else if (i_error==0x80092010L) risultato="CRYPT_E_REVOKED"; else if (i_error==0x80092011L) risultato="CRYPT_E_NO_REVOCATION_DLL"; else if (i_error==0x80092012L) risultato="CRYPT_E_NO_REVOCATION_CHECK"; else if (i_error==0x80092013L) risultato="CRYPT_E_REVOCATION_OFFLINE"; else if (i_error==0x80092014L) risultato="CRYPT_E_NOT_IN_REVOCATION_DATABASE"; else if (i_error==0x80092020L) risultato="CRYPT_E_INVALID_NUMERIC_STRING"; else if (i_error==0x80092021L) risultato="CRYPT_E_INVALID_PRINTABLE_STRING"; else if (i_error==0x80092022L) risultato="CRYPT_E_INVALID_IA5_STRING"; else if (i_error==0x80092023L) risultato="CRYPT_E_INVALID_X500_STRING"; else if (i_error==0x80092024L) risultato="CRYPT_E_NOT_CHAR_STRING"; else if (i_error==0x80092025L) risultato="CRYPT_E_FILERESIZED"; else if (i_error==0x80092026L) risultato="CRYPT_E_SECURITY_SETTINGS"; else if (i_error==0x80092027L) risultato="CRYPT_E_NO_VERIFY_USAGE_DLL"; else if (i_error==0x80092028L) risultato="CRYPT_E_NO_VERIFY_USAGE_CHECK"; else if (i_error==0x80092029L) risultato="CRYPT_E_VERIFY_USAGE_OFFLINE"; else if (i_error==0x8009202AL) risultato="CRYPT_E_NOT_IN_CTL"; else if (i_error==0x8009202BL) risultato="CRYPT_E_NO_TRUSTED_SIGNER"; else if (i_error==0x8009202CL) risultato="CRYPT_E_MISSING_PUBKEY_PARA"; else if (i_error==0x8009202DL) risultato="CRYPT_E_OBJECT_LOCATOR_OBJECT_NOT_FOUND"; else if (i_error==0x80093000L) risultato="CRYPT_E_OSS_ERROR"; else if (i_error==0x80093001L) risultato="OSS_MORE_BUF"; else if (i_error==0x80093002L) risultato="OSS_NEGATIVE_UINTEGER"; else if (i_error==0x80093003L) risultato="OSS_PDU_RANGE"; else if (i_error==0x80093004L) risultato="OSS_MORE_INPUT"; else if (i_error==0x80093005L) risultato="OSS_DATA_ERROR"; else if (i_error==0x80093006L) risultato="OSS_BAD_ARG"; else if (i_error==0x80093007L) risultato="OSS_BAD_VERSION"; else if (i_error==0x80093008L) risultato="OSS_OUT_MEMORY"; else if (i_error==0x80093009L) risultato="OSS_PDU_MISMATCH"; else if (i_error==0x8009300AL) risultato="OSS_LIMITED"; else if (i_error==0x8009300BL) risultato="OSS_BAD_PTR"; else if (i_error==0x8009300CL) risultato="OSS_BAD_TIME"; else if (i_error==0x8009300DL) risultato="OSS_INDEFINITE_NOT_SUPPORTED"; else if (i_error==0x8009300EL) risultato="OSS_MEM_ERROR"; else if (i_error==0x8009300FL) risultato="OSS_BAD_TABLE"; else if (i_error==0x80093010L) risultato="OSS_TOO_LONG"; else if (i_error==0x80093011L) risultato="OSS_CONSTRAINT_VIOLATED"; else if (i_error==0x80093012L) risultato="OSS_FATAL_ERROR"; else if (i_error==0x80093013L) risultato="OSS_ACCESS_SERIALIZATION_ERROR"; else if (i_error==0x80093014L) risultato="OSS_NULL_TBL"; else if (i_error==0x80093015L) risultato="OSS_NULL_FCN"; else if (i_error==0x80093016L) risultato="OSS_BAD_ENCRULES"; else if (i_error==0x80093017L) risultato="OSS_UNAVAIL_ENCRULES"; else if (i_error==0x80093018L) risultato="OSS_CANT_OPEN_TRACE_WINDOW"; else if (i_error==0x80093019L) risultato="OSS_UNIMPLEMENTED"; else if (i_error==0x8009301AL) risultato="OSS_OID_DLL_NOT_LINKED"; else if (i_error==0x8009301BL) risultato="OSS_CANT_OPEN_TRACE_FILE"; else if (i_error==0x8009301CL) risultato="OSS_TRACE_FILE_ALREADY_OPEN"; else if (i_error==0x8009301DL) risultato="OSS_TABLE_MISMATCH"; else if (i_error==0x8009301EL) risultato="OSS_TYPE_NOT_SUPPORTED"; else if (i_error==0x8009301FL) risultato="OSS_REAL_DLL_NOT_LINKED"; else if (i_error==0x80093020L) risultato="OSS_REAL_CODE_NOT_LINKED"; else if (i_error==0x80093021L) risultato="OSS_OUT_OF_RANGE"; else if (i_error==0x80093022L) risultato="OSS_COPIER_DLL_NOT_LINKED"; else if (i_error==0x80093023L) risultato="OSS_CONSTRAINT_DLL_NOT_LINKED"; else if (i_error==0x80093024L) risultato="OSS_COMPARATOR_DLL_NOT_LINKED"; else if (i_error==0x80093025L) risultato="OSS_COMPARATOR_CODE_NOT_LINKED"; else if (i_error==0x80093026L) risultato="OSS_MEM_MGR_DLL_NOT_LINKED"; else if (i_error==0x80093027L) risultato="OSS_PDV_DLL_NOT_LINKED"; else if (i_error==0x80093028L) risultato="OSS_PDV_CODE_NOT_LINKED"; else if (i_error==0x80093029L) risultato="OSS_API_DLL_NOT_LINKED"; else if (i_error==0x8009302AL) risultato="OSS_BERDER_DLL_NOT_LINKED"; else if (i_error==0x8009302BL) risultato="OSS_PER_DLL_NOT_LINKED"; else if (i_error==0x8009302CL) risultato="OSS_OPEN_TYPE_ERROR"; else if (i_error==0x8009302DL) risultato="OSS_MUTEX_NOT_CREATED"; else if (i_error==0x8009302EL) risultato="OSS_CANT_CLOSE_TRACE_FILE"; else if (i_error==0x80093100L) risultato="CRYPT_E_ASN1_ERROR"; else if (i_error==0x80093101L) risultato="CRYPT_E_ASN1_INTERNAL"; else if (i_error==0x80093102L) risultato="CRYPT_E_ASN1_EOD"; else if (i_error==0x80093103L) risultato="CRYPT_E_ASN1_CORRUPT"; else if (i_error==0x80093104L) risultato="CRYPT_E_ASN1_LARGE"; else if (i_error==0x80093105L) risultato="CRYPT_E_ASN1_CONSTRAINT"; else if (i_error==0x80093106L) risultato="CRYPT_E_ASN1_MEMORY"; else if (i_error==0x80093107L) risultato="CRYPT_E_ASN1_OVERFLOW"; else if (i_error==0x80093108L) risultato="CRYPT_E_ASN1_BADPDU"; else if (i_error==0x80093109L) risultato="CRYPT_E_ASN1_BADARGS"; else if (i_error==0x8009310AL) risultato="CRYPT_E_ASN1_BADREAL"; else if (i_error==0x8009310BL) risultato="CRYPT_E_ASN1_BADTAG"; else if (i_error==0x8009310CL) risultato="CRYPT_E_ASN1_CHOICE"; else if (i_error==0x8009310DL) risultato="CRYPT_E_ASN1_RULE"; else if (i_error==0x8009310EL) risultato="CRYPT_E_ASN1_UTF8"; else if (i_error==0x80093133L) risultato="CRYPT_E_ASN1_PDU_TYPE"; else if (i_error==0x80093134L) risultato="CRYPT_E_ASN1_NYI"; else if (i_error==0x80093201L) risultato="CRYPT_E_ASN1_EXTENDED"; else if (i_error==0x80093202L) risultato="CRYPT_E_ASN1_NOEOD"; else if (i_error==0x80094001L) risultato="CERTSRV_E_BAD_REQUESTSUBJECT"; else if (i_error==0x80094002L) risultato="CERTSRV_E_NO_REQUEST"; else if (i_error==0x80094003L) risultato="CERTSRV_E_BAD_REQUESTSTATUS"; else if (i_error==0x80094004L) risultato="CERTSRV_E_PROPERTY_EMPTY"; else if (i_error==0x80094005L) risultato="CERTSRV_E_INVALID_CA_CERTIFICATE"; else if (i_error==0x80094006L) risultato="CERTSRV_E_SERVER_SUSPENDED"; else if (i_error==0x80094007L) risultato="CERTSRV_E_ENCODING_LENGTH"; else if (i_error==0x80094008L) risultato="CERTSRV_E_ROLECONFLICT"; else if (i_error==0x80094009L) risultato="CERTSRV_E_RESTRICTEDOFFICER"; else if (i_error==0x8009400AL) risultato="CERTSRV_E_KEY_ARCHIVAL_NOT_CONFIGURED"; else if (i_error==0x8009400BL) risultato="CERTSRV_E_NO_VALID_KRA"; else if (i_error==0x8009400CL) risultato="CERTSRV_E_BAD_REQUEST_KEY_ARCHIVAL"; else if (i_error==0x8009400DL) risultato="CERTSRV_E_NO_CAADMIN_DEFINED"; else if (i_error==0x8009400EL) risultato="CERTSRV_E_BAD_RENEWAL_CERT_ATTRIBUTE"; else if (i_error==0x8009400FL) risultato="CERTSRV_E_NO_DB_SESSIONS"; else if (i_error==0x80094010L) risultato="CERTSRV_E_ALIGNMENT_FAULT"; else if (i_error==0x80094011L) risultato="CERTSRV_E_ENROLL_DENIED"; else if (i_error==0x80094012L) risultato="CERTSRV_E_TEMPLATE_DENIED"; else if (i_error==0x80094013L) risultato="CERTSRV_E_DOWNLEVEL_DC_SSL_OR_UPGRADE"; else if (i_error==0x80094014L) risultato="CERTSRV_E_ADMIN_DENIED_REQUEST"; else if (i_error==0x80094015L) risultato="CERTSRV_E_NO_POLICY_SERVER"; else if (i_error==0x80094016L) risultato="CERTSRV_E_WEAK_SIGNATURE_OR_KEY"; else if (i_error==0x80094017L) risultato="CERTSRV_E_KEY_ATTESTATION_NOT_SUPPORTED"; else if (i_error==0x80094018L) risultato="CERTSRV_E_ENCRYPTION_CERT_REQUIRED"; else if (i_error==0x80094800L) risultato="CERTSRV_E_UNSUPPORTED_CERT_TYPE"; else if (i_error==0x80094801L) risultato="CERTSRV_E_NO_CERT_TYPE"; else if (i_error==0x80094802L) risultato="CERTSRV_E_TEMPLATE_CONFLICT"; else if (i_error==0x80094803L) risultato="CERTSRV_E_SUBJECT_ALT_NAME_REQUIRED"; else if (i_error==0x80094804L) risultato="CERTSRV_E_ARCHIVED_KEY_REQUIRED"; else if (i_error==0x80094805L) risultato="CERTSRV_E_SMIME_REQUIRED"; else if (i_error==0x80094806L) risultato="CERTSRV_E_BAD_RENEWAL_SUBJECT"; else if (i_error==0x80094807L) risultato="CERTSRV_E_BAD_TEMPLATE_VERSION"; else if (i_error==0x80094808L) risultato="CERTSRV_E_TEMPLATE_POLICY_REQUIRED"; else if (i_error==0x80094809L) risultato="CERTSRV_E_SIGNATURE_POLICY_REQUIRED"; else if (i_error==0x8009480AL) risultato="CERTSRV_E_SIGNATURE_COUNT"; else if (i_error==0x8009480BL) risultato="CERTSRV_E_SIGNATURE_REJECTED"; else if (i_error==0x8009480CL) risultato="CERTSRV_E_ISSUANCE_POLICY_REQUIRED"; else if (i_error==0x8009480DL) risultato="CERTSRV_E_SUBJECT_UPN_REQUIRED"; else if (i_error==0x8009480EL) risultato="CERTSRV_E_SUBJECT_DIRECTORY_GUID_REQUIRED"; else if (i_error==0x8009480FL) risultato="CERTSRV_E_SUBJECT_DNS_REQUIRED"; else if (i_error==0x80094810L) risultato="CERTSRV_E_ARCHIVED_KEY_UNEXPECTED"; else if (i_error==0x80094811L) risultato="CERTSRV_E_KEY_LENGTH"; else if (i_error==0x80094812L) risultato="CERTSRV_E_SUBJECT_EMAIL_REQUIRED"; else if (i_error==0x80094813L) risultato="CERTSRV_E_UNKNOWN_CERT_TYPE"; else if (i_error==0x80094814L) risultato="CERTSRV_E_CERT_TYPE_OVERLAP"; else if (i_error==0x80094815L) risultato="CERTSRV_E_TOO_MANY_SIGNATURES"; else if (i_error==0x80094816L) risultato="CERTSRV_E_RENEWAL_BAD_PUBLIC_KEY"; else if (i_error==0x80094817L) risultato="CERTSRV_E_INVALID_EK"; else if (i_error==0x80094818L) risultato="CERTSRV_E_INVALID_IDBINDING"; else if (i_error==0x80094819L) risultato="CERTSRV_E_INVALID_ATTESTATION"; else if (i_error==0x8009481AL) risultato="CERTSRV_E_KEY_ATTESTATION"; else if (i_error==0x8009481BL) risultato="CERTSRV_E_CORRUPT_KEY_ATTESTATION"; else if (i_error==0x8009481CL) risultato="CERTSRV_E_EXPIRED_CHALLENGE"; else if (i_error==0x8009481DL) risultato="CERTSRV_E_INVALID_RESPONSE"; else if (i_error==0x8009481EL) risultato="CERTSRV_E_INVALID_REQUESTID"; else if (i_error==0x80095000L) risultato="XENROLL_E_KEY_NOT_EXPORTABLE"; else if (i_error==0x80095001L) risultato="XENROLL_E_CANNOT_ADD_ROOT_CERT"; else if (i_error==0x80095002L) risultato="XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND"; else if (i_error==0x80095003L) risultato="XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH"; else if (i_error==0x80095004L) risultato="XENROLL_E_RESPONSE_KA_HASH_MISMATCH"; else if (i_error==0x80095005L) risultato="XENROLL_E_KEYSPEC_SMIME_MISMATCH"; else if (i_error==0x80096001L) risultato="TRUST_E_SYSTEM_ERROR"; else if (i_error==0x80096002L) risultato="TRUST_E_NO_SIGNER_CERT"; else if (i_error==0x80096003L) risultato="TRUST_E_COUNTER_SIGNER"; else if (i_error==0x80096004L) risultato="TRUST_E_CERT_SIGNATURE"; else if (i_error==0x80096005L) risultato="TRUST_E_TIME_STAMP"; else if (i_error==0x80096010L) risultato="TRUST_E_BAD_DIGEST"; else if (i_error==0x80096011L) risultato="TRUST_E_MALFORMED_SIGNATURE"; else if (i_error==0x80096019L) risultato="TRUST_E_BASIC_CONSTRAINTS"; else if (i_error==0x8009601EL) risultato="TRUST_E_FINANCIAL_CRITERIA"; else if (i_error==0x80097001L) risultato="MSSIPOTF_E_OUTOFMEMRANGE"; else if (i_error==0x80097002L) risultato="MSSIPOTF_E_CANTGETOBJECT"; else if (i_error==0x80097003L) risultato="MSSIPOTF_E_NOHEADTABLE"; else if (i_error==0x80097004L) risultato="MSSIPOTF_E_BAD_MAGICNUMBER"; else if (i_error==0x80097005L) risultato="MSSIPOTF_E_BAD_OFFSET_TABLE"; else if (i_error==0x80097006L) risultato="MSSIPOTF_E_TABLE_TAGORDER"; else if (i_error==0x80097007L) risultato="MSSIPOTF_E_TABLE_LONGWORD"; else if (i_error==0x80097008L) risultato="MSSIPOTF_E_BAD_FIRST_TABLE_PLACEMENT"; else if (i_error==0x80097009L) risultato="MSSIPOTF_E_TABLES_OVERLAP"; else if (i_error==0x8009700AL) risultato="MSSIPOTF_E_TABLE_PADBYTES"; else if (i_error==0x8009700BL) risultato="MSSIPOTF_E_FILETOOSMALL"; else if (i_error==0x8009700CL) risultato="MSSIPOTF_E_TABLE_CHECKSUM"; else if (i_error==0x8009700DL) risultato="MSSIPOTF_E_FILE_CHECKSUM"; else if (i_error==0x80097010L) risultato="MSSIPOTF_E_FAILED_POLICY"; else if (i_error==0x80097011L) risultato="MSSIPOTF_E_FAILED_HINTS_CHECK"; else if (i_error==0x80097012L) risultato="MSSIPOTF_E_NOT_OPENTYPE"; else if (i_error==0x80097013L) risultato="MSSIPOTF_E_FILE"; else if (i_error==0x80097014L) risultato="MSSIPOTF_E_CRYPT"; else if (i_error==0x80097015L) risultato="MSSIPOTF_E_BADVERSION"; else if (i_error==0x80097016L) risultato="MSSIPOTF_E_DSIG_STRUCTURE"; else if (i_error==0x80097017L) risultato="MSSIPOTF_E_PCONST_CHECK"; else if (i_error==0x80097018L) risultato="MSSIPOTF_E_STRUCTURE"; else if (i_error==0x80097019L) risultato="ERROR_CRED_REQUIRES_CONFIRMATION"; else if (i_error==0) risultato="NTE_OP_OK"; else if (i_error==0x800B0001L) risultato="TRUST_E_PROVIDER_UNKNOWN"; else if (i_error==0x800B0002L) risultato="TRUST_E_ACTION_UNKNOWN"; else if (i_error==0x800B0003L) risultato="TRUST_E_SUBJECT_FORM_UNKNOWN"; else if (i_error==0x800B0004L) risultato="TRUST_E_SUBJECT_NOT_TRUSTED"; else if (i_error==0x800B0005L) risultato="DIGSIG_E_ENCODE"; else if (i_error==0x800B0006L) risultato="DIGSIG_E_DECODE"; else if (i_error==0x800B0007L) risultato="DIGSIG_E_EXTENSIBILITY"; else if (i_error==0x800B0008L) risultato="DIGSIG_E_CRYPTO"; else if (i_error==0x800B0009L) risultato="PERSIST_E_SIZEDEFINITE"; else if (i_error==0x800B000AL) risultato="PERSIST_E_SIZEINDEFINITE"; else if (i_error==0x800B000BL) risultato="PERSIST_E_NOTSELFSIZING"; else if (i_error==0x800B0100L) risultato="TRUST_E_NOSIGNATURE"; else if (i_error==0x800B0101L) risultato="CERT_E_EXPIRED"; else if (i_error==0x800B0102L) risultato="CERT_E_VALIDITYPERIODNESTING"; else if (i_error==0x800B0103L) risultato="CERT_E_ROLE"; else if (i_error==0x800B0104L) risultato="CERT_E_PATHLENCONST"; else if (i_error==0x800B0105L) risultato="CERT_E_CRITICAL"; else if (i_error==0x800B0106L) risultato="CERT_E_PURPOSE"; else if (i_error==0x800B0107L) risultato="CERT_E_ISSUERCHAINING"; else if (i_error==0x800B0108L) risultato="CERT_E_MALFORMED"; else if (i_error==0x800B0109L) risultato="CERT_E_UNTRUSTEDROOT"; else if (i_error==0x800B010AL) risultato="CERT_E_CHAINING"; else if (i_error==0x800B010BL) risultato="TRUST_E_FAIL"; else if (i_error==0x800B010CL) risultato="CERT_E_REVOKED"; else if (i_error==0x800B010DL) risultato="CERT_E_UNTRUSTEDTESTROOT"; else if (i_error==0x800B010EL) risultato="CERT_E_REVOCATION_FAILURE"; else if (i_error==0x800B010FL) risultato="CERT_E_CN_NO_MATCH"; else if (i_error==0x800B0110L) risultato="CERT_E_WRONG_USAGE"; else if (i_error==0x800B0111L) risultato="TRUST_E_EXPLICIT_DISTRUST"; else if (i_error==0x800B0112L) risultato="CERT_E_UNTRUSTEDCA"; else if (i_error==0x800B0113L) risultato="CERT_E_INVALID_POLICY"; else if (i_error==0x800B0114L) risultato="CERT_E_INVALID_NAME"; else if (i_error==0x800F0000L) risultato="SPAPI_E_EXPECTED_SECTION_NAME"; else if (i_error==0x800F0001L) risultato="SPAPI_E_BAD_SECTION_NAME_LINE"; else if (i_error==0x800F0002L) risultato="SPAPI_E_SECTION_NAME_TOO_LONG"; else if (i_error==0x800F0003L) risultato="SPAPI_E_GENERAL_SYNTAX"; else if (i_error==0x800F0100L) risultato="SPAPI_E_WRONG_INF_STYLE"; else if (i_error==0x800F0101L) risultato="SPAPI_E_SECTION_NOT_FOUND"; else if (i_error==0x800F0102L) risultato="SPAPI_E_LINE_NOT_FOUND"; else if (i_error==0x800F0103L) risultato="SPAPI_E_NO_BACKUP"; else if (i_error==0x800F0200L) risultato="SPAPI_E_NO_ASSOCIATED_CLASS"; else if (i_error==0x800F0201L) risultato="SPAPI_E_CLASS_MISMATCH"; else if (i_error==0x800F0202L) risultato="SPAPI_E_DUPLICATE_FOUND"; else if (i_error==0x800F0203L) risultato="SPAPI_E_NO_DRIVER_SELECTED"; else if (i_error==0x800F0204L) risultato="SPAPI_E_KEY_DOES_NOT_EXIST"; else if (i_error==0x800F0205L) risultato="SPAPI_E_INVALID_DEVINST_NAME"; else if (i_error==0x800F0206L) risultato="SPAPI_E_INVALID_CLASS"; else if (i_error==0x800F0207L) risultato="SPAPI_E_DEVINST_ALREADY_EXISTS"; else if (i_error==0x800F0208L) risultato="SPAPI_E_DEVINFO_NOT_REGISTERED"; else if (i_error==0x800F0209L) risultato="SPAPI_E_INVALID_REG_PROPERTY"; else if (i_error==0x800F020AL) risultato="SPAPI_E_NO_INF"; else if (i_error==0x800F020BL) risultato="SPAPI_E_NO_SUCH_DEVINST"; else if (i_error==0x800F020CL) risultato="SPAPI_E_CANT_LOAD_CLASS_ICON"; else if (i_error==0x800F020DL) risultato="SPAPI_E_INVALID_CLASS_INSTALLER"; else if (i_error==0x800F020EL) risultato="SPAPI_E_DI_DO_DEFAULT"; else if (i_error==0x800F020FL) risultato="SPAPI_E_DI_NOFILECOPY"; else if (i_error==0x800F0210L) risultato="SPAPI_E_INVALID_HWPROFILE"; else if (i_error==0x800F0211L) risultato="SPAPI_E_NO_DEVICE_SELECTED"; else if (i_error==0x800F0212L) risultato="SPAPI_E_DEVINFO_LISTLOCKED"; else if (i_error==0x800F0213L) risultato="SPAPI_E_DEVINFO_DATA_LOCKED"; else if (i_error==0x800F0214L) risultato="SPAPI_E_DI_BAD_PATH"; else if (i_error==0x800F0215L) risultato="SPAPI_E_NO_CLASSINSTALL_PARAMS"; else if (i_error==0x800F0216L) risultato="SPAPI_E_FILEQUEUE_LOCKED"; else if (i_error==0x800F0217L) risultato="SPAPI_E_BAD_SERVICE_INSTALLSECT"; else if (i_error==0x800F0218L) risultato="SPAPI_E_NO_CLASS_DRIVER_LIST"; else if (i_error==0x800F0219L) risultato="SPAPI_E_NO_ASSOCIATED_SERVICE"; else if (i_error==0x800F021AL) risultato="SPAPI_E_NO_DEFAULT_DEVICE_INTERFACE"; else if (i_error==0x800F021BL) risultato="SPAPI_E_DEVICE_INTERFACE_ACTIVE"; else if (i_error==0x800F021CL) risultato="SPAPI_E_DEVICE_INTERFACE_REMOVED"; else if (i_error==0x800F021DL) risultato="SPAPI_E_BAD_INTERFACE_INSTALLSECT"; else if (i_error==0x800F021EL) risultato="SPAPI_E_NO_SUCH_INTERFACE_CLASS"; else if (i_error==0x800F021FL) risultato="SPAPI_E_INVALID_REFERENCE_STRING"; else if (i_error==0x800F0220L) risultato="SPAPI_E_INVALID_MACHINENAME"; else if (i_error==0x800F0221L) risultato="SPAPI_E_REMOTE_COMM_FAILURE"; else if (i_error==0x800F0222L) risultato="SPAPI_E_MACHINE_UNAVAILABLE"; else if (i_error==0x800F0223L) risultato="SPAPI_E_NO_CONFIGMGR_SERVICES"; else if (i_error==0x800F0224L) risultato="SPAPI_E_INVALID_PROPPAGE_PROVIDER"; else if (i_error==0x800F0225L) risultato="SPAPI_E_NO_SUCH_DEVICE_INTERFACE"; else if (i_error==0x800F0226L) risultato="SPAPI_E_DI_POSTPROCESSING_REQUIRED"; else if (i_error==0x800F0227L) risultato="SPAPI_E_INVALID_COINSTALLER"; else if (i_error==0x800F0228L) risultato="SPAPI_E_NO_COMPAT_DRIVERS"; else if (i_error==0x800F0229L) risultato="SPAPI_E_NO_DEVICE_ICON"; else if (i_error==0x800F022AL) risultato="SPAPI_E_INVALID_INF_LOGCONFIG"; else if (i_error==0x800F022BL) risultato="SPAPI_E_DI_DONT_INSTALL"; else if (i_error==0x800F022CL) risultato="SPAPI_E_INVALID_FILTER_DRIVER"; else if (i_error==0x800F022DL) risultato="SPAPI_E_NON_WINDOWS_NT_DRIVER"; else if (i_error==0x800F022EL) risultato="SPAPI_E_NON_WINDOWS_DRIVER"; else if (i_error==0x800F022FL) risultato="SPAPI_E_NO_CATALOG_FOR_OEM_INF"; else if (i_error==0x800F0230L) risultato="SPAPI_E_DEVINSTALL_QUEUE_NONNATIVE"; else if (i_error==0x800F0231L) risultato="SPAPI_E_NOT_DISABLEABLE"; else if (i_error==0x800F0232L) risultato="SPAPI_E_CANT_REMOVE_DEVINST"; else if (i_error==0x800F0233L) risultato="SPAPI_E_INVALID_TARGET"; else if (i_error==0x800F0234L) risultato="SPAPI_E_DRIVER_NONNATIVE"; else if (i_error==0x800F0235L) risultato="SPAPI_E_IN_WOW64"; else if (i_error==0x800F0236L) risultato="SPAPI_E_SET_SYSTEM_RESTORE_POINT"; else if (i_error==0x800F0237L) risultato="SPAPI_E_INCORRECTLY_COPIED_INF"; else if (i_error==0x800F0238L) risultato="SPAPI_E_SCE_DISABLED"; else if (i_error==0x800F0239L) risultato="SPAPI_E_UNKNOWN_EXCEPTION"; else if (i_error==0x800F023AL) risultato="SPAPI_E_PNP_REGISTRY_ERROR"; else if (i_error==0x800F023BL) risultato="SPAPI_E_REMOTE_REQUEST_UNSUPPORTED"; else if (i_error==0x800F023CL) risultato="SPAPI_E_NOT_AN_INSTALLED_OEM_INF"; else if (i_error==0x800F023DL) risultato="SPAPI_E_INF_IN_USE_BY_DEVICES"; else if (i_error==0x800F023EL) risultato="SPAPI_E_DI_FUNCTION_OBSOLETE"; else if (i_error==0x800F023FL) risultato="SPAPI_E_NO_AUTHENTICODE_CATALOG"; else if (i_error==0x800F0240L) risultato="SPAPI_E_AUTHENTICODE_DISALLOWED"; else if (i_error==0x800F0241L) risultato="SPAPI_E_AUTHENTICODE_TRUSTED_PUBLISHER"; else if (i_error==0x800F0242L) risultato="SPAPI_E_AUTHENTICODE_TRUST_NOT_ESTABLISHED"; else if (i_error==0x800F0243L) risultato="SPAPI_E_AUTHENTICODE_PUBLISHER_NOT_TRUSTED"; else if (i_error==0x800F0244L) risultato="SPAPI_E_SIGNATURE_OSATTRIBUTE_MISMATCH"; else if (i_error==0x800F0245L) risultato="SPAPI_E_ONLY_VALIDATE_VIA_AUTHENTICODE"; else if (i_error==0x800F0246L) risultato="SPAPI_E_DEVICE_INSTALLER_NOT_READY"; else if (i_error==0x800F0247L) risultato="SPAPI_E_DRIVER_STORE_ADD_FAILED"; else if (i_error==0x800F0248L) risultato="SPAPI_E_DEVICE_INSTALL_BLOCKED"; else if (i_error==0x800F0249L) risultato="SPAPI_E_DRIVER_INSTALL_BLOCKED"; else if (i_error==0x800F024AL) risultato="SPAPI_E_WRONG_INF_TYPE"; else if (i_error==0x800F024BL) risultato="SPAPI_E_FILE_HASH_NOT_IN_CATALOG"; else if (i_error==0x800F024CL) risultato="SPAPI_E_DRIVER_STORE_DELETE_FAILED"; else if (i_error==0x800F0300L) risultato="SPAPI_E_UNRECOVERABLE_STACK_OVERFLOW"; else if (i_error==0x800F1000L) risultato="SPAPI_E_ERROR_NOT_INSTALLED"; else if (i_error==NO_ERROR) risultato="SCARD_S_SUCCESS"; else if (i_error==0x80100001L) risultato="SCARD_F_INTERNAL_ERROR"; else if (i_error==0x80100002L) risultato="SCARD_E_CANCELLED"; else if (i_error==0x80100003L) risultato="SCARD_E_INVALID_HANDLE"; else if (i_error==0x80100004L) risultato="SCARD_E_INVALID_PARAMETER"; else if (i_error==0x80100005L) risultato="SCARD_E_INVALID_TARGET"; else if (i_error==0x80100006L) risultato="SCARD_E_NO_MEMORY"; else if (i_error==0x80100007L) risultato="SCARD_F_WAITED_TOO_LONG"; else if (i_error==0x80100008L) risultato="SCARD_E_INSUFFICIENT_BUFFER"; else if (i_error==0x80100009L) risultato="SCARD_E_UNKNOWN_READER"; else if (i_error==0x8010000AL) risultato="SCARD_E_TIMEOUT"; else if (i_error==0x8010000BL) risultato="SCARD_E_SHARING_VIOLATION"; else if (i_error==0x8010000CL) risultato="SCARD_E_NO_SMARTCARD"; else if (i_error==0x8010000DL) risultato="SCARD_E_UNKNOWN_CARD"; else if (i_error==0x8010000EL) risultato="SCARD_E_CANT_DISPOSE"; else if (i_error==0x8010000FL) risultato="SCARD_E_PROTO_MISMATCH"; else if (i_error==0x80100010L) risultato="SCARD_E_NOT_READY"; else if (i_error==0x80100011L) risultato="SCARD_E_INVALID_VALUE"; else if (i_error==0x80100012L) risultato="SCARD_E_SYSTEM_CANCELLED"; else if (i_error==0x80100013L) risultato="SCARD_F_COMM_ERROR"; else if (i_error==0x80100014L) risultato="SCARD_F_UNKNOWN_ERROR"; else if (i_error==0x80100015L) risultato="SCARD_E_INVALID_ATR"; else if (i_error==0x80100016L) risultato="SCARD_E_NOT_TRANSACTED"; else if (i_error==0x80100017L) risultato="SCARD_E_READER_UNAVAILABLE"; else if (i_error==0x80100018L) risultato="SCARD_P_SHUTDOWN"; else if (i_error==0x80100019L) risultato="SCARD_E_PCI_TOO_SMALL"; else if (i_error==0x8010001AL) risultato="SCARD_E_READER_UNSUPPORTED"; else if (i_error==0x8010001BL) risultato="SCARD_E_DUPLICATE_READER"; else if (i_error==0x8010001CL) risultato="SCARD_E_CARD_UNSUPPORTED"; else if (i_error==0x8010001DL) risultato="SCARD_E_NO_SERVICE"; else if (i_error==0x8010001EL) risultato="SCARD_E_SERVICE_STOPPED"; else if (i_error==0x8010001FL) risultato="SCARD_E_UNEXPECTED"; else if (i_error==0x80100020L) risultato="SCARD_E_ICC_INSTALLATION"; else if (i_error==0x80100021L) risultato="SCARD_E_ICC_CREATEORDER"; else if (i_error==0x80100022L) risultato="SCARD_E_UNSUPPORTED_FEATURE"; else if (i_error==0x80100023L) risultato="SCARD_E_DIR_NOT_FOUND"; else if (i_error==0x80100024L) risultato="SCARD_E_FILE_NOT_FOUND"; else if (i_error==0x80100025L) risultato="SCARD_E_NO_DIR"; else if (i_error==0x80100026L) risultato="SCARD_E_NO_FILE"; else if (i_error==0x80100027L) risultato="SCARD_E_NO_ACCESS"; else if (i_error==0x80100028L) risultato="SCARD_E_WRITE_TOO_MANY"; else if (i_error==0x80100029L) risultato="SCARD_E_BAD_SEEK"; else if (i_error==0x8010002AL) risultato="SCARD_E_INVALID_CHV"; else if (i_error==0x8010002BL) risultato="SCARD_E_UNKNOWN_RES_MNG"; else if (i_error==0x8010002CL) risultato="SCARD_E_NO_SUCH_CERTIFICATE"; else if (i_error==0x8010002DL) risultato="SCARD_E_CERTIFICATE_UNAVAILABLE"; else if (i_error==0x8010002EL) risultato="SCARD_E_NO_READERS_AVAILABLE"; else if (i_error==0x8010002FL) risultato="SCARD_E_COMM_DATA_LOST"; else if (i_error==0x80100030L) risultato="SCARD_E_NO_KEY_CONTAINER"; else if (i_error==0x80100031L) risultato="SCARD_E_SERVER_TOO_BUSY"; else if (i_error==0x80100032L) risultato="SCARD_E_PIN_CACHE_EXPIRED"; else if (i_error==0x80100033L) risultato="SCARD_E_NO_PIN_CACHE"; else if (i_error==0x80100034L) risultato="SCARD_E_READ_ONLY_CARD"; else if (i_error==0x80100065L) risultato="SCARD_W_UNSUPPORTED_CARD"; else if (i_error==0x80100066L) risultato="SCARD_W_UNRESPONSIVE_CARD"; else if (i_error==0x80100067L) risultato="SCARD_W_UNPOWERED_CARD"; else if (i_error==0x80100068L) risultato="SCARD_W_RESET_CARD"; else if (i_error==0x80100069L) risultato="SCARD_W_REMOVED_CARD"; else if (i_error==0x8010006AL) risultato="SCARD_W_SECURITY_VIOLATION"; else if (i_error==0x8010006BL) risultato="SCARD_W_WRONG_CHV"; else if (i_error==0x8010006CL) risultato="SCARD_W_CHV_BLOCKED"; else if (i_error==0x8010006DL) risultato="SCARD_W_EOF"; else if (i_error==0x8010006EL) risultato="SCARD_W_CANCELLED_BY_USER"; else if (i_error==0x8010006FL) risultato="SCARD_W_CARD_NOT_AUTHENTICATED"; else if (i_error==0x80100070L) risultato="SCARD_W_CACHE_ITEM_NOT_FOUND"; else if (i_error==0x80100071L) risultato="SCARD_W_CACHE_ITEM_STALE"; else if (i_error==0x80100072L) risultato="SCARD_W_CACHE_ITEM_TOO_BIG"; else if (i_error==0x80110401L) risultato="COMADMIN_E_OBJECTERRORS"; else if (i_error==0x80110402L) risultato="COMADMIN_E_OBJECTINVALID"; else if (i_error==0x80110403L) risultato="COMADMIN_E_KEYMISSING"; else if (i_error==0x80110404L) risultato="COMADMIN_E_ALREADYINSTALLED"; else if (i_error==0x80110407L) risultato="COMADMIN_E_APP_FILE_WRITEFAIL"; else if (i_error==0x80110408L) risultato="COMADMIN_E_APP_FILE_READFAIL"; else if (i_error==0x80110409L) risultato="COMADMIN_E_APP_FILE_VERSION"; else if (i_error==0x8011040AL) risultato="COMADMIN_E_BADPATH"; else if (i_error==0x8011040BL) risultato="COMADMIN_E_APPLICATIONEXISTS"; else if (i_error==0x8011040CL) risultato="COMADMIN_E_ROLEEXISTS"; else if (i_error==0x8011040DL) risultato="COMADMIN_E_CANTCOPYFILE"; else if (i_error==0x8011040FL) risultato="COMADMIN_E_NOUSER"; else if (i_error==0x80110410L) risultato="COMADMIN_E_INVALIDUSERIDS"; else if (i_error==0x80110411L) risultato="COMADMIN_E_NOREGISTRYCLSID"; else if (i_error==0x80110412L) risultato="COMADMIN_E_BADREGISTRYPROGID"; else if (i_error==0x80110413L) risultato="COMADMIN_E_AUTHENTICATIONLEVEL"; else if (i_error==0x80110414L) risultato="COMADMIN_E_USERPASSWDNOTVALID"; else if (i_error==0x80110418L) risultato="COMADMIN_E_CLSIDORIIDMISMATCH"; else if (i_error==0x80110419L) risultato="COMADMIN_E_REMOTEINTERFACE"; else if (i_error==0x8011041AL) risultato="COMADMIN_E_DLLREGISTERSERVER"; else if (i_error==0x8011041BL) risultato="COMADMIN_E_NOSERVERSHARE"; else if (i_error==0x8011041DL) risultato="COMADMIN_E_DLLLOADFAILED"; else if (i_error==0x8011041EL) risultato="COMADMIN_E_BADREGISTRYLIBID"; else if (i_error==0x8011041FL) risultato="COMADMIN_E_APPDIRNOTFOUND"; else if (i_error==0x80110423L) risultato="COMADMIN_E_REGISTRARFAILED"; else if (i_error==0x80110424L) risultato="COMADMIN_E_COMPFILE_DOESNOTEXIST"; else if (i_error==0x80110425L) risultato="COMADMIN_E_COMPFILE_LOADDLLFAIL"; else if (i_error==0x80110426L) risultato="COMADMIN_E_COMPFILE_GETCLASSOBJ"; else if (i_error==0x80110427L) risultato="COMADMIN_E_COMPFILE_CLASSNOTAVAIL"; else if (i_error==0x80110428L) risultato="COMADMIN_E_COMPFILE_BADTLB"; else if (i_error==0x80110429L) risultato="COMADMIN_E_COMPFILE_NOTINSTALLABLE"; else if (i_error==0x8011042AL) risultato="COMADMIN_E_NOTCHANGEABLE"; else if (i_error==0x8011042BL) risultato="COMADMIN_E_NOTDELETEABLE"; else if (i_error==0x8011042CL) risultato="COMADMIN_E_SESSION"; else if (i_error==0x8011042DL) risultato="COMADMIN_E_COMP_MOVE_LOCKED"; else if (i_error==0x8011042EL) risultato="COMADMIN_E_COMP_MOVE_BAD_DEST"; else if (i_error==0x80110430L) risultato="COMADMIN_E_REGISTERTLB"; else if (i_error==0x80110433L) risultato="COMADMIN_E_SYSTEMAPP"; else if (i_error==0x80110434L) risultato="COMADMIN_E_COMPFILE_NOREGISTRAR"; else if (i_error==0x80110435L) risultato="COMADMIN_E_COREQCOMPINSTALLED"; else if (i_error==0x80110436L) risultato="COMADMIN_E_SERVICENOTINSTALLED"; else if (i_error==0x80110437L) risultato="COMADMIN_E_PROPERTYSAVEFAILED"; else if (i_error==0x80110438L) risultato="COMADMIN_E_OBJECTEXISTS"; else if (i_error==0x80110439L) risultato="COMADMIN_E_COMPONENTEXISTS"; else if (i_error==0x8011043BL) risultato="COMADMIN_E_REGFILE_CORRUPT"; else if (i_error==0x8011043CL) risultato="COMADMIN_E_PROPERTY_OVERFLOW"; else if (i_error==0x8011043EL) risultato="COMADMIN_E_NOTINREGISTRY"; else if (i_error==0x8011043FL) risultato="COMADMIN_E_OBJECTNOTPOOLABLE"; else if (i_error==0x80110446L) risultato="COMADMIN_E_APPLID_MATCHES_CLSID"; else if (i_error==0x80110447L) risultato="COMADMIN_E_ROLE_DOES_NOT_EXIST"; else if (i_error==0x80110448L) risultato="COMADMIN_E_START_APP_NEEDS_COMPONENTS"; else if (i_error==0x80110449L) risultato="COMADMIN_E_REQUIRES_DIFFERENT_PLATFORM"; else if (i_error==0x8011044AL) risultato="COMADMIN_E_CAN_NOT_EXPORT_APP_PROXY"; else if (i_error==0x8011044BL) risultato="COMADMIN_E_CAN_NOT_START_APP"; else if (i_error==0x8011044CL) risultato="COMADMIN_E_CAN_NOT_EXPORT_SYS_APP"; else if (i_error==0x8011044DL) risultato="COMADMIN_E_CANT_SUBSCRIBE_TO_COMPONENT"; else if (i_error==0x8011044EL) risultato="COMADMIN_E_EVENTCLASS_CANT_BE_SUBSCRIBER"; else if (i_error==0x8011044FL) risultato="COMADMIN_E_LIB_APP_PROXY_INCOMPATIBLE"; else if (i_error==0x80110450L) risultato="COMADMIN_E_BASE_PARTITION_ONLY"; else if (i_error==0x80110451L) risultato="COMADMIN_E_START_APP_DISABLED"; else if (i_error==0x80110457L) risultato="COMADMIN_E_CAT_DUPLICATE_PARTITION_NAME"; else if (i_error==0x80110458L) risultato="COMADMIN_E_CAT_INVALID_PARTITION_NAME"; else if (i_error==0x80110459L) risultato="COMADMIN_E_CAT_PARTITION_IN_USE"; else if (i_error==0x8011045AL) risultato="COMADMIN_E_FILE_PARTITION_DUPLICATE_FILES"; else if (i_error==0x8011045BL) risultato="COMADMIN_E_CAT_IMPORTED_COMPONENTS_NOT_ALLOWED"; else if (i_error==0x8011045CL) risultato="COMADMIN_E_AMBIGUOUS_APPLICATION_NAME"; else if (i_error==0x8011045DL) risultato="COMADMIN_E_AMBIGUOUS_PARTITION_NAME"; else if (i_error==0x80110472L) risultato="COMADMIN_E_REGDB_NOTINITIALIZED"; else if (i_error==0x80110473L) risultato="COMADMIN_E_REGDB_NOTOPEN"; else if (i_error==0x80110474L) risultato="COMADMIN_E_REGDB_SYSTEMERR"; else if (i_error==0x80110475L) risultato="COMADMIN_E_REGDB_ALREADYRUNNING"; else if (i_error==0x80110480L) risultato="COMADMIN_E_MIG_VERSIONNOTSUPPORTED"; else if (i_error==0x80110481L) risultato="COMADMIN_E_MIG_SCHEMANOTFOUND"; else if (i_error==0x80110482L) risultato="COMADMIN_E_CAT_BITNESSMISMATCH"; else if (i_error==0x80110483L) risultato="COMADMIN_E_CAT_UNACCEPTABLEBITNESS"; else if (i_error==0x80110484L) risultato="COMADMIN_E_CAT_WRONGAPPBITNESS"; else if (i_error==0x80110485L) risultato="COMADMIN_E_CAT_PAUSE_RESUME_NOT_SUPPORTED"; else if (i_error==0x80110486L) risultato="COMADMIN_E_CAT_SERVERFAULT"; else if (i_error==0x80110600L) risultato="COMQC_E_APPLICATION_NOT_QUEUED"; else if (i_error==0x80110601L) risultato="COMQC_E_NO_QUEUEABLE_INTERFACES"; else if (i_error==0x80110602L) risultato="COMQC_E_QUEUING_SERVICE_NOT_AVAILABLE"; else if (i_error==0x80110603L) risultato="COMQC_E_NO_IPERSISTSTREAM"; else if (i_error==0x80110604L) risultato="COMQC_E_BAD_MESSAGE"; else if (i_error==0x80110605L) risultato="COMQC_E_UNAUTHENTICATED"; else if (i_error==0x80110606L) risultato="COMQC_E_UNTRUSTED_ENQUEUER"; else if (i_error==0x80110701L) risultato="MSDTC_E_DUPLICATE_RESOURCE"; else if (i_error==0x80110808L) risultato="COMADMIN_E_OBJECT_PARENT_MISSING"; else if (i_error==0x80110809L) risultato="COMADMIN_E_OBJECT_DOES_NOT_EXIST"; else if (i_error==0x8011080AL) risultato="COMADMIN_E_APP_NOT_RUNNING"; else if (i_error==0x8011080BL) risultato="COMADMIN_E_INVALID_PARTITION"; else if (i_error==0x8011080DL) risultato="COMADMIN_E_SVCAPP_NOT_POOLABLE_OR_RECYCLABLE"; else if (i_error==0x8011080EL) risultato="COMADMIN_E_USER_IN_SET"; else if (i_error==0x8011080FL) risultato="COMADMIN_E_CANTRECYCLELIBRARYAPPS"; else if (i_error==0x80110811L) risultato="COMADMIN_E_CANTRECYCLESERVICEAPPS"; else if (i_error==0x80110812L) risultato="COMADMIN_E_PROCESSALREADYRECYCLED"; else if (i_error==0x80110813L) risultato="COMADMIN_E_PAUSEDPROCESSMAYNOTBERECYCLED"; else if (i_error==0x80110814L) risultato="COMADMIN_E_CANTMAKEINPROCSERVICE"; else if (i_error==0x80110815L) risultato="COMADMIN_E_PROGIDINUSEBYCLSID"; else if (i_error==0x80110816L) risultato="COMADMIN_E_DEFAULT_PARTITION_NOT_IN_SET"; else if (i_error==0x80110817L) risultato="COMADMIN_E_RECYCLEDPROCESSMAYNOTBEPAUSED"; else if (i_error==0x80110818L) risultato="COMADMIN_E_PARTITION_ACCESSDENIED"; else if (i_error==0x80110819L) risultato="COMADMIN_E_PARTITION_MSI_ONLY"; else if (i_error==0x8011081AL) risultato="COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_1_0_FORMAT"; else if (i_error==0x8011081BL) risultato="COMADMIN_E_LEGACYCOMPS_NOT_ALLOWED_IN_NONBASE_PARTITIONS"; else if (i_error==0x8011081CL) risultato="COMADMIN_E_COMP_MOVE_SOURCE"; else if (i_error==0x8011081DL) risultato="COMADMIN_E_COMP_MOVE_DEST"; else if (i_error==0x8011081EL) risultato="COMADMIN_E_COMP_MOVE_PRIVATE"; else if (i_error==0x8011081FL) risultato="COMADMIN_E_BASEPARTITION_REQUIRED_IN_SET"; else if (i_error==0x80110820L) risultato="COMADMIN_E_CANNOT_ALIAS_EVENTCLASS"; else if (i_error==0x80110821L) risultato="COMADMIN_E_PRIVATE_ACCESSDENIED"; else if (i_error==0x80110822L) risultato="COMADMIN_E_SAFERINVALID"; else if (i_error==0x80110823L) risultato="COMADMIN_E_REGISTRY_ACCESSDENIED"; else if (i_error==0x80110824L) risultato="COMADMIN_E_PARTITIONS_DISABLED"; else if (i_error==0x001B0000L) risultato="WER_S_REPORT_DEBUG"; else if (i_error==0x001B0001L) risultato="WER_S_REPORT_UPLOADED"; else if (i_error==0x001B0002L) risultato="WER_S_REPORT_QUEUED"; else if (i_error==0x001B0003L) risultato="WER_S_DISABLED"; else if (i_error==0x001B0004L) risultato="WER_S_SUSPENDED_UPLOAD"; else if (i_error==0x001B0005L) risultato="WER_S_DISABLED_QUEUE"; else if (i_error==0x001B0006L) risultato="WER_S_DISABLED_ARCHIVE"; else if (i_error==0x001B0007L) risultato="WER_S_REPORT_ASYNC"; else if (i_error==0x001B0008L) risultato="WER_S_IGNORE_ASSERT_INSTANCE"; else if (i_error==0x001B0009L) risultato="WER_S_IGNORE_ALL_ASSERTS"; else if (i_error==0x001B000AL) risultato="WER_S_ASSERT_CONTINUE"; else if (i_error==0x001B000BL) risultato="WER_S_THROTTLED"; else if (i_error==0x001B000CL) risultato="WER_S_REPORT_UPLOADED_CAB"; else if (i_error==0x801B8000L) risultato="WER_E_CRASH_FAILURE"; else if (i_error==0x801B8001L) risultato="WER_E_CANCELED"; else if (i_error==0x801B8002L) risultato="WER_E_NETWORK_FAILURE"; else if (i_error==0x801B8003L) risultato="WER_E_NOT_INITIALIZED"; else if (i_error==0x801B8004L) risultato="WER_E_ALREADY_REPORTING"; else if (i_error==0x801B8005L) risultato="WER_E_DUMP_THROTTLED"; else if (i_error==0x801B8006L) risultato="WER_E_INSUFFICIENT_CONSENT"; else if (i_error==0x001F0001L) risultato="ERROR_FLT_IO_COMPLETE"; else if (i_error==0x801F0001L) risultato="ERROR_FLT_NO_HANDLER_DEFINED"; else if (i_error==0x801F0002L) risultato="ERROR_FLT_CONTEXT_ALREADY_DEFINED"; else if (i_error==0x801F0003L) risultato="ERROR_FLT_INVALID_ASYNCHRONOUS_REQUEST"; else if (i_error==0x801F0004L) risultato="ERROR_FLT_DISALLOW_FAST_IO"; else if (i_error==0x801F0005L) risultato="ERROR_FLT_INVALID_NAME_REQUEST"; else if (i_error==0x801F0006L) risultato="ERROR_FLT_NOT_SAFE_TO_POST_OPERATION"; else if (i_error==0x801F0007L) risultato="ERROR_FLT_NOT_INITIALIZED"; else if (i_error==0x801F0008L) risultato="ERROR_FLT_FILTER_NOT_READY"; else if (i_error==0x801F0009L) risultato="ERROR_FLT_POST_OPERATION_CLEANUP"; else if (i_error==0x801F000AL) risultato="ERROR_FLT_INTERNAL_ERROR"; else if (i_error==0x801F000BL) risultato="ERROR_FLT_DELETING_OBJECT"; else if (i_error==0x801F000CL) risultato="ERROR_FLT_MUST_BE_NONPAGED_POOL"; else if (i_error==0x801F000DL) risultato="ERROR_FLT_DUPLICATE_ENTRY"; else if (i_error==0x801F000EL) risultato="ERROR_FLT_CBDQ_DISABLED"; else if (i_error==0x801F000FL) risultato="ERROR_FLT_DO_NOT_ATTACH"; else if (i_error==0x801F0010L) risultato="ERROR_FLT_DO_NOT_DETACH"; else if (i_error==0x801F0011L) risultato="ERROR_FLT_INSTANCE_ALTITUDE_COLLISION"; else if (i_error==0x801F0012L) risultato="ERROR_FLT_INSTANCE_NAME_COLLISION"; else if (i_error==0x801F0013L) risultato="ERROR_FLT_FILTER_NOT_FOUND"; else if (i_error==0x801F0014L) risultato="ERROR_FLT_VOLUME_NOT_FOUND"; else if (i_error==0x801F0015L) risultato="ERROR_FLT_INSTANCE_NOT_FOUND"; else if (i_error==0x801F0016L) risultato="ERROR_FLT_CONTEXT_ALLOCATION_NOT_FOUND"; else if (i_error==0x801F0017L) risultato="ERROR_FLT_INVALID_CONTEXT_REGISTRATION"; else if (i_error==0x801F0018L) risultato="ERROR_FLT_NAME_CACHE_MISS"; else if (i_error==0x801F0019L) risultato="ERROR_FLT_NO_DEVICE_OBJECT"; else if (i_error==0x801F001AL) risultato="ERROR_FLT_VOLUME_ALREADY_MOUNTED"; else if (i_error==0x801F001BL) risultato="ERROR_FLT_ALREADY_ENLISTED"; else if (i_error==0x801F001CL) risultato="ERROR_FLT_CONTEXT_ALREADY_LINKED"; else if (i_error==0x801F0020L) risultato="ERROR_FLT_NO_WAITER_FOR_REPLY"; else if (i_error==0x801F0023L) risultato="ERROR_FLT_REGISTRATION_BUSY"; else if (i_error==0x80260001L) risultato="ERROR_HUNG_DISPLAY_DRIVER_THREAD"; else if (i_error==0x80263001L) risultato="DWM_E_COMPOSITIONDISABLED"; else if (i_error==0x80263002L) risultato="DWM_E_REMOTING_NOT_SUPPORTED"; else if (i_error==0x80263003L) risultato="DWM_E_NO_REDIRECTION_SURFACE_AVAILABLE"; else if (i_error==0x80263004L) risultato="DWM_E_NOT_QUEUING_PRESENTS"; else if (i_error==0x80263005L) risultato="DWM_E_ADAPTER_NOT_FOUND"; else if (i_error==0x00263005L) risultato="DWM_S_GDI_REDIRECTION_SURFACE"; else if (i_error==0x80263007L) risultato="DWM_E_TEXTURE_TOO_LARGE"; else if (i_error==0x00263008L) risultato="DWM_S_GDI_REDIRECTION_SURFACE_BLT_VIA_GDI"; else if (i_error==0x00261001L) risultato="ERROR_MONITOR_NO_DESCRIPTOR"; else if (i_error==0x00261002L) risultato="ERROR_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT"; else if (i_error==0xC0261003L) risultato="ERROR_MONITOR_INVALID_DESCRIPTOR_CHECKSUM"; else if (i_error==0xC0261004L) risultato="ERROR_MONITOR_INVALID_STANDARD_TIMING_BLOCK"; else if (i_error==0xC0261005L) risultato="ERROR_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED"; else if (i_error==0xC0261006L) risultato="ERROR_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK"; else if (i_error==0xC0261007L) risultato="ERROR_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK"; else if (i_error==0xC0261008L) risultato="ERROR_MONITOR_NO_MORE_DESCRIPTOR_DATA"; else if (i_error==0xC0261009L) risultato="ERROR_MONITOR_INVALID_DETAILED_TIMING_BLOCK"; else if (i_error==0xC026100AL) risultato="ERROR_MONITOR_INVALID_MANUFACTURE_DATE"; else if (i_error==0xC0262000L) risultato="ERROR_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER"; else if (i_error==0xC0262001L) risultato="ERROR_GRAPHICS_INSUFFICIENT_DMA_BUFFER"; else if (i_error==0xC0262002L) risultato="ERROR_GRAPHICS_INVALID_DISPLAY_ADAPTER"; else if (i_error==0xC0262003L) risultato="ERROR_GRAPHICS_ADAPTER_WAS_RESET"; else if (i_error==0xC0262004L) risultato="ERROR_GRAPHICS_INVALID_DRIVER_MODEL"; else if (i_error==0xC0262005L) risultato="ERROR_GRAPHICS_PRESENT_MODE_CHANGED"; else if (i_error==0xC0262006L) risultato="ERROR_GRAPHICS_PRESENT_OCCLUDED"; else if (i_error==0xC0262007L) risultato="ERROR_GRAPHICS_PRESENT_DENIED"; else if (i_error==0xC0262008L) risultato="ERROR_GRAPHICS_CANNOTCOLORCONVERT"; else if (i_error==0xC0262009L) risultato="ERROR_GRAPHICS_DRIVER_MISMATCH"; else if (i_error==0x4026200AL) risultato="ERROR_GRAPHICS_PARTIAL_DATA_POPULATED"; else if (i_error==0xC026200BL) risultato="ERROR_GRAPHICS_PRESENT_REDIRECTION_DISABLED"; else if (i_error==0xC026200CL) risultato="ERROR_GRAPHICS_PRESENT_UNOCCLUDED"; else if (i_error==0xC026200DL) risultato="ERROR_GRAPHICS_WINDOWDC_NOT_AVAILABLE"; else if (i_error==0xC026200EL) risultato="ERROR_GRAPHICS_WINDOWLESS_PRESENT_DISABLED"; else if (i_error==0xC0262100L) risultato="ERROR_GRAPHICS_NO_VIDEO_MEMORY"; else if (i_error==0xC0262101L) risultato="ERROR_GRAPHICS_CANT_LOCK_MEMORY"; else if (i_error==0xC0262102L) risultato="ERROR_GRAPHICS_ALLOCATION_BUSY"; else if (i_error==0xC0262103L) risultato="ERROR_GRAPHICS_TOO_MANY_REFERENCES"; else if (i_error==0xC0262104L) risultato="ERROR_GRAPHICS_TRY_AGAIN_LATER"; else if (i_error==0xC0262105L) risultato="ERROR_GRAPHICS_TRY_AGAIN_NOW"; else if (i_error==0xC0262106L) risultato="ERROR_GRAPHICS_ALLOCATION_INVALID"; else if (i_error==0xC0262107L) risultato="ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE"; else if (i_error==0xC0262108L) risultato="ERROR_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED"; else if (i_error==0xC0262109L) risultato="ERROR_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION"; else if (i_error==0xC0262110L) risultato="ERROR_GRAPHICS_INVALID_ALLOCATION_USAGE"; else if (i_error==0xC0262111L) risultato="ERROR_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION"; else if (i_error==0xC0262112L) risultato="ERROR_GRAPHICS_ALLOCATION_CLOSED"; else if (i_error==0xC0262113L) risultato="ERROR_GRAPHICS_INVALID_ALLOCATION_INSTANCE"; else if (i_error==0xC0262114L) risultato="ERROR_GRAPHICS_INVALID_ALLOCATION_HANDLE"; else if (i_error==0xC0262115L) risultato="ERROR_GRAPHICS_WRONG_ALLOCATION_DEVICE"; else if (i_error==0xC0262116L) risultato="ERROR_GRAPHICS_ALLOCATION_CONTENT_LOST"; else if (i_error==0xC0262200L) risultato="ERROR_GRAPHICS_GPU_EXCEPTION_ON_DEVICE"; else if (i_error==0x40262201L) risultato="ERROR_GRAPHICS_SKIP_ALLOCATION_PREPARATION"; else if (i_error==0xC0262300L) risultato="ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY"; else if (i_error==0xC0262301L) risultato="ERROR_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED"; else if (i_error==0xC0262302L) risultato="ERROR_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED"; else if (i_error==0xC0262303L) risultato="ERROR_GRAPHICS_INVALID_VIDPN"; else if (i_error==0xC0262304L) risultato="ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE"; else if (i_error==0xC0262305L) risultato="ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET"; else if (i_error==0xC0262306L) risultato="ERROR_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED"; else if (i_error==0x00262307L) risultato="ERROR_GRAPHICS_MODE_NOT_PINNED"; else if (i_error==0xC0262308L) risultato="ERROR_GRAPHICS_INVALID_VIDPN_SOURCEMODESET"; else if (i_error==0xC0262309L) risultato="ERROR_GRAPHICS_INVALID_VIDPN_TARGETMODESET"; else if (i_error==0xC026230AL) risultato="ERROR_GRAPHICS_INVALID_FREQUENCY"; else if (i_error==0xC026230BL) risultato="ERROR_GRAPHICS_INVALID_ACTIVE_REGION"; else if (i_error==0xC026230CL) risultato="ERROR_GRAPHICS_INVALID_TOTAL_REGION"; else if (i_error==0xC0262310L) risultato="ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE"; else if (i_error==0xC0262311L) risultato="ERROR_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE"; else if (i_error==0xC0262312L) risultato="ERROR_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET"; else if (i_error==0xC0262313L) risultato="ERROR_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY"; else if (i_error==0xC0262314L) risultato="ERROR_GRAPHICS_MODE_ALREADY_IN_MODESET"; else if (i_error==0xC0262315L) risultato="ERROR_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET"; else if (i_error==0xC0262316L) risultato="ERROR_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET"; else if (i_error==0xC0262317L) risultato="ERROR_GRAPHICS_SOURCE_ALREADY_IN_SET"; else if (i_error==0xC0262318L) risultato="ERROR_GRAPHICS_TARGET_ALREADY_IN_SET"; else if (i_error==0xC0262319L) risultato="ERROR_GRAPHICS_INVALID_VIDPN_PRESENT_PATH"; else if (i_error==0xC026231AL) risultato="ERROR_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY"; else if (i_error==0xC026231BL) risultato="ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET"; else if (i_error==0xC026231CL) risultato="ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE"; else if (i_error==0xC026231DL) risultato="ERROR_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET"; else if (i_error==0x0026231EL) risultato="ERROR_GRAPHICS_NO_PREFERRED_MODE"; else if (i_error==0xC026231FL) risultato="ERROR_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET"; else if (i_error==0xC0262320L) risultato="ERROR_GRAPHICS_STALE_MODESET"; else if (i_error==0xC0262321L) risultato="ERROR_GRAPHICS_INVALID_MONITOR_SOURCEMODESET"; else if (i_error==0xC0262322L) risultato="ERROR_GRAPHICS_INVALID_MONITOR_SOURCE_MODE"; else if (i_error==0xC0262323L) risultato="ERROR_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN"; else if (i_error==0xC0262324L) risultato="ERROR_GRAPHICS_MODE_ID_MUST_BE_UNIQUE"; else if (i_error==0xC0262325L) risultato="ERROR_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION"; else if (i_error==0xC0262326L) risultato="ERROR_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES"; else if (i_error==0xC0262327L) risultato="ERROR_GRAPHICS_PATH_NOT_IN_TOPOLOGY"; else if (i_error==0xC0262328L) risultato="ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE"; else if (i_error==0xC0262329L) risultato="ERROR_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET"; else if (i_error==0xC026232AL) risultato="ERROR_GRAPHICS_INVALID_MONITORDESCRIPTORSET"; else if (i_error==0xC026232BL) risultato="ERROR_GRAPHICS_INVALID_MONITORDESCRIPTOR"; else if (i_error==0xC026232CL) risultato="ERROR_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET"; else if (i_error==0xC026232DL) risultato="ERROR_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET"; else if (i_error==0xC026232EL) risultato="ERROR_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE"; else if (i_error==0xC026232FL) risultato="ERROR_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE"; else if (i_error==0xC0262330L) risultato="ERROR_GRAPHICS_RESOURCES_NOT_RELATED"; else if (i_error==0xC0262331L) risultato="ERROR_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE"; else if (i_error==0xC0262332L) risultato="ERROR_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE"; else if (i_error==0xC0262333L) risultato="ERROR_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET"; else if (i_error==0xC0262334L) risultato="ERROR_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER"; else if (i_error==0xC0262335L) risultato="ERROR_GRAPHICS_NO_VIDPNMGR"; else if (i_error==0xC0262336L) risultato="ERROR_GRAPHICS_NO_ACTIVE_VIDPN"; else if (i_error==0xC0262337L) risultato="ERROR_GRAPHICS_STALE_VIDPN_TOPOLOGY"; else if (i_error==0xC0262338L) risultato="ERROR_GRAPHICS_MONITOR_NOT_CONNECTED"; else if (i_error==0xC0262339L) risultato="ERROR_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY"; else if (i_error==0xC026233AL) risultato="ERROR_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE"; else if (i_error==0xC026233BL) risultato="ERROR_GRAPHICS_INVALID_VISIBLEREGION_SIZE"; else if (i_error==0xC026233CL) risultato="ERROR_GRAPHICS_INVALID_STRIDE"; else if (i_error==0xC026233DL) risultato="ERROR_GRAPHICS_INVALID_PIXELFORMAT"; else if (i_error==0xC026233EL) risultato="ERROR_GRAPHICS_INVALID_COLORBASIS"; else if (i_error==0xC026233FL) risultato="ERROR_GRAPHICS_INVALID_PIXELVALUEACCESSMODE"; else if (i_error==0xC0262340L) risultato="ERROR_GRAPHICS_TARGET_NOT_IN_TOPOLOGY"; else if (i_error==0xC0262341L) risultato="ERROR_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT"; else if (i_error==0xC0262342L) risultato="ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE"; else if (i_error==0xC0262343L) risultato="ERROR_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN"; else if (i_error==0xC0262344L) risultato="ERROR_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL"; else if (i_error==0xC0262345L) risultato="ERROR_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION"; else if (i_error==0xC0262346L) risultato="ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED"; else if (i_error==0xC0262347L) risultato="ERROR_GRAPHICS_INVALID_GAMMA_RAMP"; else if (i_error==0xC0262348L) risultato="ERROR_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED"; else if (i_error==0xC0262349L) risultato="ERROR_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED"; else if (i_error==0xC026234AL) risultato="ERROR_GRAPHICS_MODE_NOT_IN_MODESET"; else if (i_error==0x0026234BL) risultato="ERROR_GRAPHICS_DATASET_IS_EMPTY"; else if (i_error==0x0026234CL) risultato="ERROR_GRAPHICS_NO_MORE_ELEMENTS_IN_DATASET"; else if (i_error==0xC026234DL) risultato="ERROR_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON"; else if (i_error==0xC026234EL) risultato="ERROR_GRAPHICS_INVALID_PATH_CONTENT_TYPE"; else if (i_error==0xC026234FL) risultato="ERROR_GRAPHICS_INVALID_COPYPROTECTION_TYPE"; else if (i_error==0xC0262350L) risultato="ERROR_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS"; else if (i_error==0x00262351L) risultato="ERROR_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_PINNED"; else if (i_error==0xC0262352L) risultato="ERROR_GRAPHICS_INVALID_SCANLINE_ORDERING"; else if (i_error==0xC0262353L) risultato="ERROR_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED"; else if (i_error==0xC0262354L) risultato="ERROR_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS"; else if (i_error==0xC0262355L) risultato="ERROR_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT"; else if (i_error==0xC0262356L) risultato="ERROR_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM"; else if (i_error==0xC0262357L) risultato="ERROR_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN"; else if (i_error==0xC0262358L) risultato="ERROR_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT"; else if (i_error==0xC0262359L) risultato="ERROR_GRAPHICS_MAX_NUM_PATHS_REACHED"; else if (i_error==0xC026235AL) risultato="ERROR_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION"; else if (i_error==0xC026235BL) risultato="ERROR_GRAPHICS_INVALID_CLIENT_TYPE"; else if (i_error==0xC026235CL) risultato="ERROR_GRAPHICS_CLIENTVIDPN_NOT_SET"; else if (i_error==0xC0262400L) risultato="ERROR_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED"; else if (i_error==0xC0262401L) risultato="ERROR_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED"; else if (i_error==0x4026242FL) risultato="ERROR_GRAPHICS_UNKNOWN_CHILD_STATUS"; else if (i_error==0xC0262430L) risultato="ERROR_GRAPHICS_NOT_A_LINKED_ADAPTER"; else if (i_error==0xC0262431L) risultato="ERROR_GRAPHICS_LEADLINK_NOT_ENUMERATED"; else if (i_error==0xC0262432L) risultato="ERROR_GRAPHICS_CHAINLINKS_NOT_ENUMERATED"; else if (i_error==0xC0262433L) risultato="ERROR_GRAPHICS_ADAPTER_CHAIN_NOT_READY"; else if (i_error==0xC0262434L) risultato="ERROR_GRAPHICS_CHAINLINKS_NOT_STARTED"; else if (i_error==0xC0262435L) risultato="ERROR_GRAPHICS_CHAINLINKS_NOT_POWERED_ON"; else if (i_error==0xC0262436L) risultato="ERROR_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE"; else if (i_error==0x40262437L) risultato="ERROR_GRAPHICS_LEADLINK_START_DEFERRED"; else if (i_error==0xC0262438L) risultato="ERROR_GRAPHICS_NOT_POST_DEVICE_DRIVER"; else if (i_error==0x40262439L) risultato="ERROR_GRAPHICS_POLLING_TOO_FREQUENTLY"; else if (i_error==0x4026243AL) risultato="ERROR_GRAPHICS_START_DEFERRED"; else if (i_error==0xC026243BL) risultato="ERROR_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED"; else if (i_error==0x4026243CL) risultato="ERROR_GRAPHICS_DEPENDABLE_CHILD_STATUS"; else if (i_error==0xC0262500L) risultato="ERROR_GRAPHICS_OPM_NOT_SUPPORTED"; else if (i_error==0xC0262501L) risultato="ERROR_GRAPHICS_COPP_NOT_SUPPORTED"; else if (i_error==0xC0262502L) risultato="ERROR_GRAPHICS_UAB_NOT_SUPPORTED"; else if (i_error==0xC0262503L) risultato="ERROR_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS"; else if (i_error==0xC0262505L) risultato="ERROR_GRAPHICS_OPM_NO_VIDEO_OUTPUTS_EXIST"; else if (i_error==0xC026250BL) risultato="ERROR_GRAPHICS_OPM_INTERNAL_ERROR"; else if (i_error==0xC026250CL) risultato="ERROR_GRAPHICS_OPM_INVALID_HANDLE"; else if (i_error==0xC026250EL) risultato="ERROR_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH"; else if (i_error==0xC026250FL) risultato="ERROR_GRAPHICS_OPM_SPANNING_MODE_ENABLED"; else if (i_error==0xC0262510L) risultato="ERROR_GRAPHICS_OPM_THEATER_MODE_ENABLED"; else if (i_error==0xC0262511L) risultato="ERROR_GRAPHICS_PVP_HFS_FAILED"; else if (i_error==0xC0262512L) risultato="ERROR_GRAPHICS_OPM_INVALID_SRM"; else if (i_error==0xC0262513L) risultato="ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP"; else if (i_error==0xC0262514L) risultato="ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP"; else if (i_error==0xC0262515L) risultato="ERROR_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA"; else if (i_error==0xC0262516L) risultato="ERROR_GRAPHICS_OPM_HDCP_SRM_NEVER_SET"; else if (i_error==0xC0262517L) risultato="ERROR_GRAPHICS_OPM_RESOLUTION_TOO_HIGH"; else if (i_error==0xC0262518L) risultato="ERROR_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE"; else if (i_error==0xC026251AL) risultato="ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_NO_LONGER_EXISTS"; else if (i_error==0xC026251BL) risultato="ERROR_GRAPHICS_OPM_SESSION_TYPE_CHANGE_IN_PROGRESS"; else if (i_error==0xC026251CL) risultato="ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS"; else if (i_error==0xC026251DL) risultato="ERROR_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST"; else if (i_error==0xC026251EL) risultato="ERROR_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR"; else if (i_error==0xC026251FL) risultato="ERROR_GRAPHICS_OPM_VIDEO_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS"; else if (i_error==0xC0262520L) risultato="ERROR_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED"; else if (i_error==0xC0262521L) risultato="ERROR_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST"; else if (i_error==0xC0262580L) risultato="ERROR_GRAPHICS_I2C_NOT_SUPPORTED"; else if (i_error==0xC0262581L) risultato="ERROR_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST"; else if (i_error==0xC0262582L) risultato="ERROR_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA"; else if (i_error==0xC0262583L) risultato="ERROR_GRAPHICS_I2C_ERROR_RECEIVING_DATA"; else if (i_error==0xC0262584L) risultato="ERROR_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED"; else if (i_error==0xC0262585L) risultato="ERROR_GRAPHICS_DDCCI_INVALID_DATA"; else if (i_error==0xC0262586L) risultato="ERROR_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE"; else if (i_error==0xC0262587L) risultato="ERROR_GRAPHICS_MCA_INVALID_CAPABILITIES_STRING"; else if (i_error==0xC0262588L) risultato="ERROR_GRAPHICS_MCA_INTERNAL_ERROR"; else if (i_error==0xC0262589L) risultato="ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND"; else if (i_error==0xC026258AL) risultato="ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH"; else if (i_error==0xC026258BL) risultato="ERROR_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM"; else if (i_error==0xC026258CL) risultato="ERROR_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE"; else if (i_error==0xC026258DL) risultato="ERROR_GRAPHICS_MONITOR_NO_LONGER_EXISTS"; else if (i_error==0xC02625D8L) risultato="ERROR_GRAPHICS_DDCCI_CURRENT_CURRENT_VALUE_GREATER_THAN_MAXIMUM_VALUE"; else if (i_error==0xC02625D9L) risultato="ERROR_GRAPHICS_MCA_INVALID_VCP_VERSION"; else if (i_error==0xC02625DAL) risultato="ERROR_GRAPHICS_MCA_MONITOR_VIOLATES_MCCS_SPECIFICATION"; else if (i_error==0xC02625DBL) risultato="ERROR_GRAPHICS_MCA_MCCS_VERSION_MISMATCH"; else if (i_error==0xC02625DCL) risultato="ERROR_GRAPHICS_MCA_UNSUPPORTED_MCCS_VERSION"; else if (i_error==0xC02625DEL) risultato="ERROR_GRAPHICS_MCA_INVALID_TECHNOLOGY_TYPE_RETURNED"; else if (i_error==0xC02625DFL) risultato="ERROR_GRAPHICS_MCA_UNSUPPORTED_COLOR_TEMPERATURE"; else if (i_error==0xC02625E0L) risultato="ERROR_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED"; else if (i_error==0xC02625E1L) risultato="ERROR_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME"; else if (i_error==0xC02625E2L) risultato="ERROR_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP"; else if (i_error==0xC02625E3L) risultato="ERROR_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED"; else if (i_error==0xC02625E4L) risultato="ERROR_GRAPHICS_INVALID_POINTER"; else if (i_error==0xC02625E5L) risultato="ERROR_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE"; else if (i_error==0xC02625E6L) risultato="ERROR_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL"; else if (i_error==0xC02625E7L) risultato="ERROR_GRAPHICS_INTERNAL_ERROR"; else if (i_error==0xC02605E8L) risultato="ERROR_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS"; else if (i_error==0x80270001L) risultato="NAP_E_INVALID_PACKET"; else if (i_error==0x80270002L) risultato="NAP_E_MISSING_SOH"; else if (i_error==0x80270003L) risultato="NAP_E_CONFLICTING_ID"; else if (i_error==0x80270004L) risultato="NAP_E_NO_CACHED_SOH"; else if (i_error==0x80270005L) risultato="NAP_E_STILL_BOUND"; else if (i_error==0x80270006L) risultato="NAP_E_NOT_REGISTERED"; else if (i_error==0x80270007L) risultato="NAP_E_NOT_INITIALIZED"; else if (i_error==0x80270008L) risultato="NAP_E_MISMATCHED_ID"; else if (i_error==0x80270009L) risultato="NAP_E_NOT_PENDING"; else if (i_error==0x8027000AL) risultato="NAP_E_ID_NOT_FOUND"; else if (i_error==0x8027000BL) risultato="NAP_E_MAXSIZE_TOO_SMALL"; else if (i_error==0x8027000CL) risultato="NAP_E_SERVICE_NOT_RUNNING"; else if (i_error==0x0027000DL) risultato="NAP_S_CERT_ALREADY_PRESENT"; else if (i_error==0x8027000EL) risultato="NAP_E_ENTITY_DISABLED"; else if (i_error==0x8027000FL) risultato="NAP_E_NETSH_GROUPPOLICY_ERROR"; else if (i_error==0x80270010L) risultato="NAP_E_TOO_MANY_CALLS"; else if (i_error==0x80270011L) risultato="NAP_E_SHV_CONFIG_EXISTED"; else if (i_error==0x80270012L) risultato="NAP_E_SHV_CONFIG_NOT_FOUND"; else if (i_error==0x80270013L) risultato="NAP_E_SHV_TIMEOUT"; else if (i_error==0x80280000L) risultato="TPM_E_ERROR_MASK"; else if (i_error==0x80280001L) risultato="TPM_E_AUTHFAIL"; else if (i_error==0x80280002L) risultato="TPM_E_BADINDEX"; else if (i_error==0x80280003L) risultato="TPM_E_BAD_PARAMETER"; else if (i_error==0x80280004L) risultato="TPM_E_AUDITFAILURE"; else if (i_error==0x80280005L) risultato="TPM_E_CLEAR_DISABLED"; else if (i_error==0x80280006L) risultato="TPM_E_DEACTIVATED"; else if (i_error==0x80280007L) risultato="TPM_E_DISABLED"; else if (i_error==0x80280008L) risultato="TPM_E_DISABLED_CMD"; else if (i_error==0x80280009L) risultato="TPM_E_FAIL"; else if (i_error==0x8028000AL) risultato="TPM_E_BAD_ORDINAL"; else if (i_error==0x8028000BL) risultato="TPM_E_INSTALL_DISABLED"; else if (i_error==0x8028000CL) risultato="TPM_E_INVALID_KEYHANDLE"; else if (i_error==0x8028000DL) risultato="TPM_E_KEYNOTFOUND"; else if (i_error==0x8028000EL) risultato="TPM_E_INAPPROPRIATE_ENC"; else if (i_error==0x8028000FL) risultato="TPM_E_MIGRATEFAIL"; else if (i_error==0x80280010L) risultato="TPM_E_INVALID_PCR_INFO"; else if (i_error==0x80280011L) risultato="TPM_E_NOSPACE"; else if (i_error==0x80280012L) risultato="TPM_E_NOSRK"; else if (i_error==0x80280013L) risultato="TPM_E_NOTSEALED_BLOB"; else if (i_error==0x80280014L) risultato="TPM_E_OWNER_SET"; else if (i_error==0x80280015L) risultato="TPM_E_RESOURCES"; else if (i_error==0x80280016L) risultato="TPM_E_SHORTRANDOM"; else if (i_error==0x80280017L) risultato="TPM_E_SIZE"; else if (i_error==0x80280018L) risultato="TPM_E_WRONGPCRVAL"; else if (i_error==0x80280019L) risultato="TPM_E_BAD_PARAM_SIZE"; else if (i_error==0x8028001AL) risultato="TPM_E_SHA_THREAD"; else if (i_error==0x8028001BL) risultato="TPM_E_SHA_ERROR"; else if (i_error==0x8028001CL) risultato="TPM_E_FAILEDSELFTEST"; else if (i_error==0x8028001DL) risultato="TPM_E_AUTH2FAIL"; else if (i_error==0x8028001EL) risultato="TPM_E_BADTAG"; else if (i_error==0x8028001FL) risultato="TPM_E_IOERROR"; else if (i_error==0x80280020L) risultato="TPM_E_ENCRYPT_ERROR"; else if (i_error==0x80280021L) risultato="TPM_E_DECRYPT_ERROR"; else if (i_error==0x80280022L) risultato="TPM_E_INVALID_AUTHHANDLE"; else if (i_error==0x80280023L) risultato="TPM_E_NO_ENDORSEMENT"; else if (i_error==0x80280024L) risultato="TPM_E_INVALID_KEYUSAGE"; else if (i_error==0x80280025L) risultato="TPM_E_WRONG_ENTITYTYPE"; else if (i_error==0x80280026L) risultato="TPM_E_INVALID_POSTINIT"; else if (i_error==0x80280027L) risultato="TPM_E_INAPPROPRIATE_SIG"; else if (i_error==0x80280028L) risultato="TPM_E_BAD_KEY_PROPERTY"; else if (i_error==0x80280029L) risultato="TPM_E_BAD_MIGRATION"; else if (i_error==0x8028002AL) risultato="TPM_E_BAD_SCHEME"; else if (i_error==0x8028002BL) risultato="TPM_E_BAD_DATASIZE"; else if (i_error==0x8028002CL) risultato="TPM_E_BAD_MODE"; else if (i_error==0x8028002DL) risultato="TPM_E_BAD_PRESENCE"; else if (i_error==0x8028002EL) risultato="TPM_E_BAD_VERSION"; else if (i_error==0x8028002FL) risultato="TPM_E_NO_WRAP_TRANSPORT"; else if (i_error==0x80280030L) risultato="TPM_E_AUDITFAIL_UNSUCCESSFUL"; else if (i_error==0x80280031L) risultato="TPM_E_AUDITFAIL_SUCCESSFUL"; else if (i_error==0x80280032L) risultato="TPM_E_NOTRESETABLE"; else if (i_error==0x80280033L) risultato="TPM_E_NOTLOCAL"; else if (i_error==0x80280034L) risultato="TPM_E_BAD_TYPE"; else if (i_error==0x80280035L) risultato="TPM_E_INVALID_RESOURCE"; else if (i_error==0x80280036L) risultato="TPM_E_NOTFIPS"; else if (i_error==0x80280037L) risultato="TPM_E_INVALID_FAMILY"; else if (i_error==0x80280038L) risultato="TPM_E_NO_NV_PERMISSION"; else if (i_error==0x80280039L) risultato="TPM_E_REQUIRES_SIGN"; else if (i_error==0x8028003AL) risultato="TPM_E_KEY_NOTSUPPORTED"; else if (i_error==0x8028003BL) risultato="TPM_E_AUTH_CONFLICT"; else if (i_error==0x8028003CL) risultato="TPM_E_AREA_LOCKED"; else if (i_error==0x8028003DL) risultato="TPM_E_BAD_LOCALITY"; else if (i_error==0x8028003EL) risultato="TPM_E_READ_ONLY"; else if (i_error==0x8028003FL) risultato="TPM_E_PER_NOWRITE"; else if (i_error==0x80280040L) risultato="TPM_E_FAMILYCOUNT"; else if (i_error==0x80280041L) risultato="TPM_E_WRITE_LOCKED"; else if (i_error==0x80280042L) risultato="TPM_E_BAD_ATTRIBUTES"; else if (i_error==0x80280043L) risultato="TPM_E_INVALID_STRUCTURE"; else if (i_error==0x80280044L) risultato="TPM_E_KEY_OWNER_CONTROL"; else if (i_error==0x80280045L) risultato="TPM_E_BAD_COUNTER"; else if (i_error==0x80280046L) risultato="TPM_E_NOT_FULLWRITE"; else if (i_error==0x80280047L) risultato="TPM_E_CONTEXT_GAP"; else if (i_error==0x80280048L) risultato="TPM_E_MAXNVWRITES"; else if (i_error==0x80280049L) risultato="TPM_E_NOOPERATOR"; else if (i_error==0x8028004AL) risultato="TPM_E_RESOURCEMISSING"; else if (i_error==0x8028004BL) risultato="TPM_E_DELEGATE_LOCK"; else if (i_error==0x8028004CL) risultato="TPM_E_DELEGATE_FAMILY"; else if (i_error==0x8028004DL) risultato="TPM_E_DELEGATE_ADMIN"; else if (i_error==0x8028004EL) risultato="TPM_E_TRANSPORT_NOTEXCLUSIVE"; else if (i_error==0x8028004FL) risultato="TPM_E_OWNER_CONTROL"; else if (i_error==0x80280050L) risultato="TPM_E_DAA_RESOURCES"; else if (i_error==0x80280051L) risultato="TPM_E_DAA_INPUT_DATA0"; else if (i_error==0x80280052L) risultato="TPM_E_DAA_INPUT_DATA1"; else if (i_error==0x80280053L) risultato="TPM_E_DAA_ISSUER_SETTINGS"; else if (i_error==0x80280054L) risultato="TPM_E_DAA_TPM_SETTINGS"; else if (i_error==0x80280055L) risultato="TPM_E_DAA_STAGE"; else if (i_error==0x80280056L) risultato="TPM_E_DAA_ISSUER_VALIDITY"; else if (i_error==0x80280057L) risultato="TPM_E_DAA_WRONG_W"; else if (i_error==0x80280058L) risultato="TPM_E_BAD_HANDLE"; else if (i_error==0x80280059L) risultato="TPM_E_BAD_DELEGATE"; else if (i_error==0x8028005AL) risultato="TPM_E_BADCONTEXT"; else if (i_error==0x8028005BL) risultato="TPM_E_TOOMANYCONTEXTS"; else if (i_error==0x8028005CL) risultato="TPM_E_MA_TICKET_SIGNATURE"; else if (i_error==0x8028005DL) risultato="TPM_E_MA_DESTINATION"; else if (i_error==0x8028005EL) risultato="TPM_E_MA_SOURCE"; else if (i_error==0x8028005FL) risultato="TPM_E_MA_AUTHORITY"; else if (i_error==0x80280061L) risultato="TPM_E_PERMANENTEK"; else if (i_error==0x80280062L) risultato="TPM_E_BAD_SIGNATURE"; else if (i_error==0x80280063L) risultato="TPM_E_NOCONTEXTSPACE"; else if (i_error==0x80280400L) risultato="TPM_E_COMMAND_BLOCKED"; else if (i_error==0x80280401L) risultato="TPM_E_INVALID_HANDLE"; else if (i_error==0x80280402L) risultato="TPM_E_DUPLICATE_VHANDLE"; else if (i_error==0x80280403L) risultato="TPM_E_EMBEDDED_COMMAND_BLOCKED"; else if (i_error==0x80280404L) risultato="TPM_E_EMBEDDED_COMMAND_UNSUPPORTED"; else if (i_error==0x80280800L) risultato="TPM_E_RETRY"; else if (i_error==0x80280801L) risultato="TPM_E_NEEDS_SELFTEST"; else if (i_error==0x80280802L) risultato="TPM_E_DOING_SELFTEST"; else if (i_error==0x80280803L) risultato="TPM_E_DEFEND_LOCK_RUNNING"; else if (i_error==0x80284001L) risultato="TBS_E_INTERNAL_ERROR"; else if (i_error==0x80284002L) risultato="TBS_E_BAD_PARAMETER"; else if (i_error==0x80284003L) risultato="TBS_E_INVALID_OUTPUT_POINTER"; else if (i_error==0x80284004L) risultato="TBS_E_INVALID_CONTEXT"; else if (i_error==0x80284005L) risultato="TBS_E_INSUFFICIENT_BUFFER"; else if (i_error==0x80284006L) risultato="TBS_E_IOERROR"; else if (i_error==0x80284007L) risultato="TBS_E_INVALID_CONTEXT_PARAM"; else if (i_error==0x80284008L) risultato="TBS_E_SERVICE_NOT_RUNNING"; else if (i_error==0x80284009L) risultato="TBS_E_TOO_MANY_TBS_CONTEXTS"; else if (i_error==0x8028400AL) risultato="TBS_E_TOO_MANY_RESOURCES"; else if (i_error==0x8028400BL) risultato="TBS_E_SERVICE_START_PENDING"; else if (i_error==0x8028400CL) risultato="TBS_E_PPI_NOT_SUPPORTED"; else if (i_error==0x8028400DL) risultato="TBS_E_COMMAND_CANCELED"; else if (i_error==0x8028400EL) risultato="TBS_E_BUFFER_TOO_LARGE"; else if (i_error==0x8028400FL) risultato="TBS_E_TPM_NOT_FOUND"; else if (i_error==0x80284010L) risultato="TBS_E_SERVICE_DISABLED"; else if (i_error==0x80284011L) risultato="TBS_E_NO_EVENT_LOG"; else if (i_error==0x80284012L) risultato="TBS_E_ACCESS_DENIED"; else if (i_error==0x80284013L) risultato="TBS_E_PROVISIONING_NOT_ALLOWED"; else if (i_error==0x80284014L) risultato="TBS_E_PPI_FUNCTION_UNSUPPORTED"; else if (i_error==0x80284015L) risultato="TBS_E_OWNERAUTH_NOT_FOUND"; else if (i_error==0x80284016L) risultato="TBS_E_PROVISIONING_INCOMPLETE"; else if (i_error==0x80290100L) risultato="TPMAPI_E_INVALID_STATE"; else if (i_error==0x80290101L) risultato="TPMAPI_E_NOT_ENOUGH_DATA"; else if (i_error==0x80290102L) risultato="TPMAPI_E_TOO_MUCH_DATA"; else if (i_error==0x80290103L) risultato="TPMAPI_E_INVALID_OUTPUT_POINTER"; else if (i_error==0x80290104L) risultato="TPMAPI_E_INVALID_PARAMETER"; else if (i_error==0x80290105L) risultato="TPMAPI_E_OUT_OF_MEMORY"; else if (i_error==0x80290106L) risultato="TPMAPI_E_BUFFER_TOO_SMALL"; else if (i_error==0x80290107L) risultato="TPMAPI_E_INTERNAL_ERROR"; else if (i_error==0x80290108L) risultato="TPMAPI_E_ACCESS_DENIED"; else if (i_error==0x80290109L) risultato="TPMAPI_E_AUTHORIZATION_FAILED"; else if (i_error==0x8029010AL) risultato="TPMAPI_E_INVALID_CONTEXT_HANDLE"; else if (i_error==0x8029010BL) risultato="TPMAPI_E_TBS_COMMUNICATION_ERROR"; else if (i_error==0x8029010CL) risultato="TPMAPI_E_TPM_COMMAND_ERROR"; else if (i_error==0x8029010DL) risultato="TPMAPI_E_MESSAGE_TOO_LARGE"; else if (i_error==0x8029010EL) risultato="TPMAPI_E_INVALID_ENCODING"; else if (i_error==0x8029010FL) risultato="TPMAPI_E_INVALID_KEY_SIZE"; else if (i_error==0x80290110L) risultato="TPMAPI_E_ENCRYPTION_FAILED"; else if (i_error==0x80290111L) risultato="TPMAPI_E_INVALID_KEY_PARAMS"; else if (i_error==0x80290112L) risultato="TPMAPI_E_INVALID_MIGRATION_AUTHORIZATION_BLOB"; else if (i_error==0x80290113L) risultato="TPMAPI_E_INVALID_PCR_INDEX"; else if (i_error==0x80290114L) risultato="TPMAPI_E_INVALID_DELEGATE_BLOB"; else if (i_error==0x80290115L) risultato="TPMAPI_E_INVALID_CONTEXT_PARAMS"; else if (i_error==0x80290116L) risultato="TPMAPI_E_INVALID_KEY_BLOB"; else if (i_error==0x80290117L) risultato="TPMAPI_E_INVALID_PCR_DATA"; else if (i_error==0x80290118L) risultato="TPMAPI_E_INVALID_OWNER_AUTH"; else if (i_error==0x80290119L) risultato="TPMAPI_E_FIPS_RNG_CHECK_FAILED"; else if (i_error==0x8029011AL) risultato="TPMAPI_E_EMPTY_TCG_LOG"; else if (i_error==0x8029011BL) risultato="TPMAPI_E_INVALID_TCG_LOG_ENTRY"; else if (i_error==0x8029011CL) risultato="TPMAPI_E_TCG_SEPARATOR_ABSENT"; else if (i_error==0x8029011DL) risultato="TPMAPI_E_TCG_INVALID_DIGEST_ENTRY"; else if (i_error==0x8029011EL) risultato="TPMAPI_E_POLICY_DENIES_OPERATION"; else if (i_error==0x80290200L) risultato="TBSIMP_E_BUFFER_TOO_SMALL"; else if (i_error==0x80290201L) risultato="TBSIMP_E_CLEANUP_FAILED"; else if (i_error==0x80290202L) risultato="TBSIMP_E_INVALID_CONTEXT_HANDLE"; else if (i_error==0x80290203L) risultato="TBSIMP_E_INVALID_CONTEXT_PARAM"; else if (i_error==0x80290204L) risultato="TBSIMP_E_TPM_ERROR"; else if (i_error==0x80290205L) risultato="TBSIMP_E_HASH_BAD_KEY"; else if (i_error==0x80290206L) risultato="TBSIMP_E_DUPLICATE_VHANDLE"; else if (i_error==0x80290207L) risultato="TBSIMP_E_INVALID_OUTPUT_POINTER"; else if (i_error==0x80290208L) risultato="TBSIMP_E_INVALID_PARAMETER"; else if (i_error==0x80290209L) risultato="TBSIMP_E_RPC_INIT_FAILED"; else if (i_error==0x8029020AL) risultato="TBSIMP_E_SCHEDULER_NOT_RUNNING"; else if (i_error==0x8029020BL) risultato="TBSIMP_E_COMMAND_CANCELED"; else if (i_error==0x8029020CL) risultato="TBSIMP_E_OUT_OF_MEMORY"; else if (i_error==0x8029020DL) risultato="TBSIMP_E_LISTNO_MORE_ITEMS"; else if (i_error==0x8029020EL) risultato="TBSIMP_E_LISTNOT_FOUND"; else if (i_error==0x8029020FL) risultato="TBSIMP_E_NOT_ENOUGH_SPACE"; else if (i_error==0x80290210L) risultato="TBSIMP_E_NOT_ENOUGH_TPM_CONTEXTS"; else if (i_error==0x80290211L) risultato="TBSIMP_E_COMMAND_FAILED"; else if (i_error==0x80290212L) risultato="TBSIMP_E_UNKNOWN_ORDINAL"; else if (i_error==0x80290213L) risultato="TBSIMP_E_RESOURCE_EXPIRED"; else if (i_error==0x80290214L) risultato="TBSIMP_E_INVALID_RESOURCE"; else if (i_error==0x80290215L) risultato="TBSIMP_E_NOTHING_TO_UNLOAD"; else if (i_error==0x80290216L) risultato="TBSIMP_E_HASH_TABLE_FULL"; else if (i_error==0x80290217L) risultato="TBSIMP_E_TOO_MANY_TBS_CONTEXTS"; else if (i_error==0x80290218L) risultato="TBSIMP_E_TOO_MANY_RESOURCES"; else if (i_error==0x80290219L) risultato="TBSIMP_E_PPI_NOT_SUPPORTED"; else if (i_error==0x8029021AL) risultato="TBSIMP_E_TPM_INCOMPATIBLE"; else if (i_error==0x8029021BL) risultato="TBSIMP_E_NO_EVENT_LOG"; else if (i_error==0x80290300L) risultato="TPM_E_PPI_ACPI_FAILURE"; else if (i_error==0x80290301L) risultato="TPM_E_PPI_USER_ABORT"; else if (i_error==0x80290302L) risultato="TPM_E_PPI_BIOS_FAILURE"; else if (i_error==0x80290303L) risultato="TPM_E_PPI_NOT_SUPPORTED"; else if (i_error==0x80290304L) risultato="TPM_E_PPI_BLOCKED_IN_BIOS"; else if (i_error==0x80290400L) risultato="TPM_E_PCP_ERROR_MASK"; else if (i_error==0x80290401L) risultato="TPM_E_PCP_DEVICE_NOT_READY"; else if (i_error==0x80290402L) risultato="TPM_E_PCP_INVALID_HANDLE"; else if (i_error==0x80290403L) risultato="TPM_E_PCP_INVALID_PARAMETER"; else if (i_error==0x80290404L) risultato="TPM_E_PCP_FLAG_NOT_SUPPORTED"; else if (i_error==0x80290405L) risultato="TPM_E_PCP_NOT_SUPPORTED"; else if (i_error==0x80290406L) risultato="TPM_E_PCP_BUFFER_TOO_SMALL"; else if (i_error==0x80290407L) risultato="TPM_E_PCP_INTERNAL_ERROR"; else if (i_error==0x80290408L) risultato="TPM_E_PCP_AUTHENTICATION_FAILED"; else if (i_error==0x80290409L) risultato="TPM_E_PCP_AUTHENTICATION_IGNORED"; else if (i_error==0x8029040AL) risultato="TPM_E_PCP_POLICY_NOT_FOUND"; else if (i_error==0x8029040BL) risultato="TPM_E_PCP_PROFILE_NOT_FOUND"; else if (i_error==0x8029040CL) risultato="TPM_E_PCP_VALIDATION_FAILED"; else if (i_error==0x80300002L) risultato="PLA_E_DCS_NOT_FOUND"; else if (i_error==0x803000AAL) risultato="PLA_E_DCS_IN_USE"; else if (i_error==0x80300045L) risultato="PLA_E_TOO_MANY_FOLDERS"; else if (i_error==0x80300070L) risultato="PLA_E_NO_MIN_DISK"; else if (i_error==0x803000B7L) risultato="PLA_E_DCS_ALREADY_EXISTS"; else if (i_error==0x00300100L) risultato="PLA_S_PROPERTY_IGNORED"; else if (i_error==0x80300101L) risultato="PLA_E_PROPERTY_CONFLICT"; else if (i_error==0x80300102L) risultato="PLA_E_DCS_SINGLETON_REQUIRED"; else if (i_error==0x80300103L) risultato="PLA_E_CREDENTIALS_REQUIRED"; else if (i_error==0x80300104L) risultato="PLA_E_DCS_NOT_RUNNING"; else if (i_error==0x80300105L) risultato="PLA_E_CONFLICT_INCL_EXCL_API"; else if (i_error==0x80300106L) risultato="PLA_E_NETWORK_EXE_NOT_VALID"; else if (i_error==0x80300107L) risultato="PLA_E_EXE_ALREADY_CONFIGURED"; else if (i_error==0x80300108L) risultato="PLA_E_EXE_PATH_NOT_VALID"; else if (i_error==0x80300109L) risultato="PLA_E_DC_ALREADY_EXISTS"; else if (i_error==0x8030010AL) risultato="PLA_E_DCS_START_WAIT_TIMEOUT"; else if (i_error==0x8030010BL) risultato="PLA_E_DC_START_WAIT_TIMEOUT"; else if (i_error==0x8030010CL) risultato="PLA_E_REPORT_WAIT_TIMEOUT"; else if (i_error==0x8030010DL) risultato="PLA_E_NO_DUPLICATES"; else if (i_error==0x8030010EL) risultato="PLA_E_EXE_FULL_PATH_REQUIRED"; else if (i_error==0x8030010FL) risultato="PLA_E_INVALID_SESSION_NAME"; else if (i_error==0x80300110L) risultato="PLA_E_PLA_CHANNEL_NOT_ENABLED"; else if (i_error==0x80300111L) risultato="PLA_E_TASKSCHED_CHANNEL_NOT_ENABLED"; else if (i_error==0x80300112L) risultato="PLA_E_RULES_MANAGER_FAILED"; else if (i_error==0x80300113L) risultato="PLA_E_CABAPI_FAILURE"; else if (i_error==0x80310000L) risultato="FVE_E_LOCKED_VOLUME"; else if (i_error==0x80310001L) risultato="FVE_E_NOT_ENCRYPTED"; else if (i_error==0x80310002L) risultato="FVE_E_NO_TPM_BIOS"; else if (i_error==0x80310003L) risultato="FVE_E_NO_MBR_METRIC"; else if (i_error==0x80310004L) risultato="FVE_E_NO_BOOTSECTOR_METRIC"; else if (i_error==0x80310005L) risultato="FVE_E_NO_BOOTMGR_METRIC"; else if (i_error==0x80310006L) risultato="FVE_E_WRONG_BOOTMGR"; else if (i_error==0x80310007L) risultato="FVE_E_SECURE_KEY_REQUIRED"; else if (i_error==0x80310008L) risultato="FVE_E_NOT_ACTIVATED"; else if (i_error==0x80310009L) risultato="FVE_E_ACTION_NOT_ALLOWED"; else if (i_error==0x8031000AL) risultato="FVE_E_AD_SCHEMA_NOT_INSTALLED"; else if (i_error==0x8031000BL) risultato="FVE_E_AD_INVALID_DATATYPE"; else if (i_error==0x8031000CL) risultato="FVE_E_AD_INVALID_DATASIZE"; else if (i_error==0x8031000DL) risultato="FVE_E_AD_NO_VALUES"; else if (i_error==0x8031000EL) risultato="FVE_E_AD_ATTR_NOT_SET"; else if (i_error==0x8031000FL) risultato="FVE_E_AD_GUID_NOT_FOUND"; else if (i_error==0x80310010L) risultato="FVE_E_BAD_INFORMATION"; else if (i_error==0x80310011L) risultato="FVE_E_TOO_SMALL"; else if (i_error==0x80310012L) risultato="FVE_E_SYSTEM_VOLUME"; else if (i_error==0x80310013L) risultato="FVE_E_FAILED_WRONG_FS"; else if (i_error==0x80310014L) risultato="FVE_E_BAD_PARTITION_SIZE"; else if (i_error==0x80310015L) risultato="FVE_E_NOT_SUPPORTED"; else if (i_error==0x80310016L) risultato="FVE_E_BAD_DATA"; else if (i_error==0x80310017L) risultato="FVE_E_VOLUME_NOT_BOUND"; else if (i_error==0x80310018L) risultato="FVE_E_TPM_NOT_OWNED"; else if (i_error==0x80310019L) risultato="FVE_E_NOT_DATA_VOLUME"; else if (i_error==0x8031001AL) risultato="FVE_E_AD_INSUFFICIENT_BUFFER"; else if (i_error==0x8031001BL) risultato="FVE_E_CONV_READ"; else if (i_error==0x8031001CL) risultato="FVE_E_CONV_WRITE"; else if (i_error==0x8031001DL) risultato="FVE_E_KEY_REQUIRED"; else if (i_error==0x8031001EL) risultato="FVE_E_CLUSTERING_NOT_SUPPORTED"; else if (i_error==0x8031001FL) risultato="FVE_E_VOLUME_BOUND_ALREADY"; else if (i_error==0x80310020L) risultato="FVE_E_OS_NOT_PROTECTED"; else if (i_error==0x80310021L) risultato="FVE_E_PROTECTION_DISABLED"; else if (i_error==0x80310022L) risultato="FVE_E_RECOVERY_KEY_REQUIRED"; else if (i_error==0x80310023L) risultato="FVE_E_FOREIGN_VOLUME"; else if (i_error==0x80310024L) risultato="FVE_E_OVERLAPPED_UPDATE"; else if (i_error==0x80310025L) risultato="FVE_E_TPM_SRK_AUTH_NOT_ZERO"; else if (i_error==0x80310026L) risultato="FVE_E_FAILED_SECTOR_SIZE"; else if (i_error==0x80310027L) risultato="FVE_E_FAILED_AUTHENTICATION"; else if (i_error==0x80310028L) risultato="FVE_E_NOT_OS_VOLUME"; else if (i_error==0x80310029L) risultato="FVE_E_AUTOUNLOCK_ENABLED"; else if (i_error==0x8031002AL) risultato="FVE_E_WRONG_BOOTSECTOR"; else if (i_error==0x8031002BL) risultato="FVE_E_WRONG_SYSTEM_FS"; else if (i_error==0x8031002CL) risultato="FVE_E_POLICY_PASSWORD_REQUIRED"; else if (i_error==0x8031002DL) risultato="FVE_E_CANNOT_SET_FVEK_ENCRYPTED"; else if (i_error==0x8031002EL) risultato="FVE_E_CANNOT_ENCRYPT_NO_KEY"; else if (i_error==0x80310030L) risultato="FVE_E_BOOTABLE_CDDVD"; else if (i_error==0x80310031L) risultato="FVE_E_PROTECTOR_EXISTS"; else if (i_error==0x80310032L) risultato="FVE_E_RELATIVE_PATH"; else if (i_error==0x80310033L) risultato="FVE_E_PROTECTOR_NOT_FOUND"; else if (i_error==0x80310034L) risultato="FVE_E_INVALID_KEY_FORMAT"; else if (i_error==0x80310035L) risultato="FVE_E_INVALID_PASSWORD_FORMAT"; else if (i_error==0x80310036L) risultato="FVE_E_FIPS_RNG_CHECK_FAILED"; else if (i_error==0x80310037L) risultato="FVE_E_FIPS_PREVENTS_RECOVERY_PASSWORD"; else if (i_error==0x80310038L) risultato="FVE_E_FIPS_PREVENTS_EXTERNAL_KEY_EXPORT"; else if (i_error==0x80310039L) risultato="FVE_E_NOT_DECRYPTED"; else if (i_error==0x8031003AL) risultato="FVE_E_INVALID_PROTECTOR_TYPE"; else if (i_error==0x8031003BL) risultato="FVE_E_NO_PROTECTORS_TO_TEST"; else if (i_error==0x8031003CL) risultato="FVE_E_KEYFILE_NOT_FOUND"; else if (i_error==0x8031003DL) risultato="FVE_E_KEYFILE_INVALID"; else if (i_error==0x8031003EL) risultato="FVE_E_KEYFILE_NO_VMK"; else if (i_error==0x8031003FL) risultato="FVE_E_TPM_DISABLED"; else if (i_error==0x80310040L) risultato="FVE_E_NOT_ALLOWED_IN_SAFE_MODE"; else if (i_error==0x80310041L) risultato="FVE_E_TPM_INVALID_PCR"; else if (i_error==0x80310042L) risultato="FVE_E_TPM_NO_VMK"; else if (i_error==0x80310043L) risultato="FVE_E_PIN_INVALID"; else if (i_error==0x80310044L) risultato="FVE_E_AUTH_INVALID_APPLICATION"; else if (i_error==0x80310045L) risultato="FVE_E_AUTH_INVALID_CONFIG"; else if (i_error==0x80310046L) risultato="FVE_E_FIPS_DISABLE_PROTECTION_NOT_ALLOWED"; else if (i_error==0x80310047L) risultato="FVE_E_FS_NOT_EXTENDED"; else if (i_error==0x80310048L) risultato="FVE_E_FIRMWARE_TYPE_NOT_SUPPORTED"; else if (i_error==0x80310049L) risultato="FVE_E_NO_LICENSE"; else if (i_error==0x8031004AL) risultato="FVE_E_NOT_ON_STACK"; else if (i_error==0x8031004BL) risultato="FVE_E_FS_MOUNTED"; else if (i_error==0x8031004CL) risultato="FVE_E_TOKEN_NOT_IMPERSONATED"; else if (i_error==0x8031004DL) risultato="FVE_E_DRY_RUN_FAILED"; else if (i_error==0x8031004EL) risultato="FVE_E_REBOOT_REQUIRED"; else if (i_error==0x8031004FL) risultato="FVE_E_DEBUGGER_ENABLED"; else if (i_error==0x80310050L) risultato="FVE_E_RAW_ACCESS"; else if (i_error==0x80310051L) risultato="FVE_E_RAW_BLOCKED"; else if (i_error==0x80310052L) risultato="FVE_E_BCD_APPLICATIONS_PATH_INCORRECT"; else if (i_error==0x80310053L) risultato="FVE_E_NOT_ALLOWED_IN_VERSION"; else if (i_error==0x80310054L) risultato="FVE_E_NO_AUTOUNLOCK_MASTER_KEY"; else if (i_error==0x80310055L) risultato="FVE_E_MOR_FAILED"; else if (i_error==0x80310056L) risultato="FVE_E_HIDDEN_VOLUME"; else if (i_error==0x80310057L) risultato="FVE_E_TRANSIENT_STATE"; else if (i_error==0x80310058L) risultato="FVE_E_PUBKEY_NOT_ALLOWED"; else if (i_error==0x80310059L) risultato="FVE_E_VOLUME_HANDLE_OPEN"; else if (i_error==0x8031005AL) risultato="FVE_E_NO_FEATURE_LICENSE"; else if (i_error==0x8031005BL) risultato="FVE_E_INVALID_STARTUP_OPTIONS"; else if (i_error==0x8031005CL) risultato="FVE_E_POLICY_RECOVERY_PASSWORD_NOT_ALLOWED"; else if (i_error==0x8031005DL) risultato="FVE_E_POLICY_RECOVERY_PASSWORD_REQUIRED"; else if (i_error==0x8031005EL) risultato="FVE_E_POLICY_RECOVERY_KEY_NOT_ALLOWED"; else if (i_error==0x8031005FL) risultato="FVE_E_POLICY_RECOVERY_KEY_REQUIRED"; else if (i_error==0x80310060L) risultato="FVE_E_POLICY_STARTUP_PIN_NOT_ALLOWED"; else if (i_error==0x80310061L) risultato="FVE_E_POLICY_STARTUP_PIN_REQUIRED"; else if (i_error==0x80310062L) risultato="FVE_E_POLICY_STARTUP_KEY_NOT_ALLOWED"; else if (i_error==0x80310063L) risultato="FVE_E_POLICY_STARTUP_KEY_REQUIRED"; else if (i_error==0x80310064L) risultato="FVE_E_POLICY_STARTUP_PIN_KEY_NOT_ALLOWED"; else if (i_error==0x80310065L) risultato="FVE_E_POLICY_STARTUP_PIN_KEY_REQUIRED"; else if (i_error==0x80310066L) risultato="FVE_E_POLICY_STARTUP_TPM_NOT_ALLOWED"; else if (i_error==0x80310067L) risultato="FVE_E_POLICY_STARTUP_TPM_REQUIRED"; else if (i_error==0x80310068L) risultato="FVE_E_POLICY_INVALID_PIN_LENGTH"; else if (i_error==0x80310069L) risultato="FVE_E_KEY_PROTECTOR_NOT_SUPPORTED"; else if (i_error==0x8031006AL) risultato="FVE_E_POLICY_PASSPHRASE_NOT_ALLOWED"; else if (i_error==0x8031006BL) risultato="FVE_E_POLICY_PASSPHRASE_REQUIRED"; else if (i_error==0x8031006CL) risultato="FVE_E_FIPS_PREVENTS_PASSPHRASE"; else if (i_error==0x8031006DL) risultato="FVE_E_OS_VOLUME_PASSPHRASE_NOT_ALLOWED"; else if (i_error==0x8031006EL) risultato="FVE_E_INVALID_BITLOCKER_OID"; else if (i_error==0x8031006FL) risultato="FVE_E_VOLUME_TOO_SMALL"; else if (i_error==0x80310070L) risultato="FVE_E_DV_NOT_SUPPORTED_ON_FS"; else if (i_error==0x80310071L) risultato="FVE_E_DV_NOT_ALLOWED_BY_GP"; else if (i_error==0x80310072L) risultato="FVE_E_POLICY_USER_CERTIFICATE_NOT_ALLOWED"; else if (i_error==0x80310073L) risultato="FVE_E_POLICY_USER_CERTIFICATE_REQUIRED"; else if (i_error==0x80310074L) risultato="FVE_E_POLICY_USER_CERT_MUST_BE_HW"; else if (i_error==0x80310075L) risultato="FVE_E_POLICY_USER_CONFIGURE_FDV_AUTOUNLOCK_NOT_ALLOWED"; else if (i_error==0x80310076L) risultato="FVE_E_POLICY_USER_CONFIGURE_RDV_AUTOUNLOCK_NOT_ALLOWED"; else if (i_error==0x80310077L) risultato="FVE_E_POLICY_USER_CONFIGURE_RDV_NOT_ALLOWED"; else if (i_error==0x80310078L) risultato="FVE_E_POLICY_USER_ENABLE_RDV_NOT_ALLOWED"; else if (i_error==0x80310079L) risultato="FVE_E_POLICY_USER_DISABLE_RDV_NOT_ALLOWED"; else if (i_error==0x80310080L) risultato="FVE_E_POLICY_INVALID_PASSPHRASE_LENGTH"; else if (i_error==0x80310081L) risultato="FVE_E_POLICY_PASSPHRASE_TOO_SIMPLE"; else if (i_error==0x80310082L) risultato="FVE_E_RECOVERY_PARTITION"; else if (i_error==0x80310083L) risultato="FVE_E_POLICY_CONFLICT_FDV_RK_OFF_AUK_ON"; else if (i_error==0x80310084L) risultato="FVE_E_POLICY_CONFLICT_RDV_RK_OFF_AUK_ON"; else if (i_error==0x80310085L) risultato="FVE_E_NON_BITLOCKER_OID"; else if (i_error==0x80310086L) risultato="FVE_E_POLICY_PROHIBITS_SELFSIGNED"; else if (i_error==0x80310087L) risultato="FVE_E_POLICY_CONFLICT_RO_AND_STARTUP_KEY_REQUIRED"; else if (i_error==0x80310088L) risultato="FVE_E_CONV_RECOVERY_FAILED"; else if (i_error==0x80310089L) risultato="FVE_E_VIRTUALIZED_SPACE_TOO_BIG"; else if (i_error==0x80310090L) risultato="FVE_E_POLICY_CONFLICT_OSV_RP_OFF_ADB_ON"; else if (i_error==0x80310091L) risultato="FVE_E_POLICY_CONFLICT_FDV_RP_OFF_ADB_ON"; else if (i_error==0x80310092L) risultato="FVE_E_POLICY_CONFLICT_RDV_RP_OFF_ADB_ON"; else if (i_error==0x80310093L) risultato="FVE_E_NON_BITLOCKER_KU"; else if (i_error==0x80310094L) risultato="FVE_E_PRIVATEKEY_AUTH_FAILED"; else if (i_error==0x80310095L) risultato="FVE_E_REMOVAL_OF_DRA_FAILED"; else if (i_error==0x80310096L) risultato="FVE_E_OPERATION_NOT_SUPPORTED_ON_VISTA_VOLUME"; else if (i_error==0x80310097L) risultato="FVE_E_CANT_LOCK_AUTOUNLOCK_ENABLED_VOLUME"; else if (i_error==0x80310098L) risultato="FVE_E_FIPS_HASH_KDF_NOT_ALLOWED"; else if (i_error==0x80310099L) risultato="FVE_E_ENH_PIN_INVALID"; else if (i_error==0x8031009AL) risultato="FVE_E_INVALID_PIN_CHARS"; else if (i_error==0x8031009BL) risultato="FVE_E_INVALID_DATUM_TYPE"; else if (i_error==0x8031009CL) risultato="FVE_E_EFI_ONLY"; else if (i_error==0x8031009DL) risultato="FVE_E_MULTIPLE_NKP_CERTS"; else if (i_error==0x8031009EL) risultato="FVE_E_REMOVAL_OF_NKP_FAILED"; else if (i_error==0x8031009FL) risultato="FVE_E_INVALID_NKP_CERT"; else if (i_error==0x803100A0L) risultato="FVE_E_NO_EXISTING_PIN"; else if (i_error==0x803100A1L) risultato="FVE_E_PROTECTOR_CHANGE_PIN_MISMATCH"; else if (i_error==0x803100A2L) risultato="FVE_E_PIN_PROTECTOR_CHANGE_BY_STD_USER_DISALLOWED"; else if (i_error==0x803100A3L) risultato="FVE_E_PROTECTOR_CHANGE_MAX_PIN_CHANGE_ATTEMPTS_REACHED"; else if (i_error==0x803100A4L) risultato="FVE_E_POLICY_PASSPHRASE_REQUIRES_ASCII"; else if (i_error==0x803100A5L) risultato="FVE_E_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE"; else if (i_error==0x803100A6L) risultato="FVE_E_WIPE_NOT_ALLOWED_ON_TP_STORAGE"; else if (i_error==0x803100A7L) risultato="FVE_E_KEY_LENGTH_NOT_SUPPORTED_BY_EDRIVE"; else if (i_error==0x803100A8L) risultato="FVE_E_NO_EXISTING_PASSPHRASE"; else if (i_error==0x803100A9L) risultato="FVE_E_PROTECTOR_CHANGE_PASSPHRASE_MISMATCH"; else if (i_error==0x803100AAL) risultato="FVE_E_PASSPHRASE_TOO_LONG"; else if (i_error==0x803100ABL) risultato="FVE_E_NO_PASSPHRASE_WITH_TPM"; else if (i_error==0x803100ACL) risultato="FVE_E_NO_TPM_WITH_PASSPHRASE"; else if (i_error==0x803100ADL) risultato="FVE_E_NOT_ALLOWED_ON_CSV_STACK"; else if (i_error==0x803100AEL) risultato="FVE_E_NOT_ALLOWED_ON_CLUSTER"; else if (i_error==0x803100AFL) risultato="FVE_E_EDRIVE_NO_FAILOVER_TO_SW"; else if (i_error==0x803100B0L) risultato="FVE_E_EDRIVE_BAND_IN_USE"; else if (i_error==0x803100B1L) risultato="FVE_E_EDRIVE_DISALLOWED_BY_GP"; else if (i_error==0x803100B2L) risultato="FVE_E_EDRIVE_INCOMPATIBLE_VOLUME"; else if (i_error==0x803100B3L) risultato="FVE_E_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING"; else if (i_error==0x803100B4L) risultato="FVE_E_EDRIVE_DV_NOT_SUPPORTED"; else if (i_error==0x803100B5L) risultato="FVE_E_NO_PREBOOT_KEYBOARD_DETECTED"; else if (i_error==0x803100B6L) risultato="FVE_E_NO_PREBOOT_KEYBOARD_OR_WINRE_DETECTED"; else if (i_error==0x803100B7L) risultato="FVE_E_POLICY_REQUIRES_STARTUP_PIN_ON_TOUCH_DEVICE"; else if (i_error==0x803100B8L) risultato="FVE_E_POLICY_REQUIRES_RECOVERY_PASSWORD_ON_TOUCH_DEVICE"; else if (i_error==0x803100B9L) risultato="FVE_E_WIPE_CANCEL_NOT_APPLICABLE"; else if (i_error==0x803100BAL) risultato="FVE_E_SECUREBOOT_DISABLED"; else if (i_error==0x803100BBL) risultato="FVE_E_SECUREBOOT_CONFIGURATION_INVALID"; else if (i_error==0x803100BCL) risultato="FVE_E_EDRIVE_DRY_RUN_FAILED"; else if (i_error==0x803100BDL) risultato="FVE_E_SHADOW_COPY_PRESENT"; else if (i_error==0x803100BEL) risultato="FVE_E_POLICY_INVALID_ENHANCED_BCD_SETTINGS"; else if (i_error==0x803100BFL) risultato="FVE_E_EDRIVE_INCOMPATIBLE_FIRMWARE"; else if (i_error==0x803100C0L) risultato="FVE_E_PROTECTOR_CHANGE_MAX_PASSPHRASE_CHANGE_ATTEMPTS_REACHED"; else if (i_error==0x803100C1L) risultato="FVE_E_PASSPHRASE_PROTECTOR_CHANGE_BY_STD_USER_DISALLOWED"; else if (i_error==0x803100C2L) risultato="FVE_E_LIVEID_ACCOUNT_SUSPENDED"; else if (i_error==0x803100C3L) risultato="FVE_E_LIVEID_ACCOUNT_BLOCKED"; else if (i_error==0x803100C4L) risultato="FVE_E_NOT_PROVISIONED_ON_ALL_VOLUMES"; else if (i_error==0x803100C5L) risultato="FVE_E_DE_FIXED_DATA_NOT_SUPPORTED"; else if (i_error==0x803100C6L) risultato="FVE_E_DE_HARDWARE_NOT_COMPLIANT"; else if (i_error==0x803100C7L) risultato="FVE_E_DE_WINRE_NOT_CONFIGURED"; else if (i_error==0x803100C8L) risultato="FVE_E_DE_PROTECTION_SUSPENDED"; else if (i_error==0x803100C9L) risultato="FVE_E_DE_OS_VOLUME_NOT_PROTECTED"; else if (i_error==0x803100CAL) risultato="FVE_E_DE_DEVICE_LOCKEDOUT"; else if (i_error==0x803100CBL) risultato="FVE_E_DE_PROTECTION_NOT_YET_ENABLED"; else if (i_error==0x803100CCL) risultato="FVE_E_INVALID_PIN_CHARS_DETAILED"; else if (i_error==0x803100CDL) risultato="FVE_E_DEVICE_LOCKOUT_COUNTER_UNAVAILABLE"; else if (i_error==0x803100CEL) risultato="FVE_E_DEVICELOCKOUT_COUNTER_MISMATCH"; else if (i_error==0x803100CFL) risultato="FVE_E_BUFFER_TOO_LARGE"; else if (i_error==0x803100D0L) risultato="FVE_E_NO_SUCH_CAPABILITY_ON_TARGET"; else if (i_error==0x803100D1L) risultato="FVE_E_DE_PREVENTED_FOR_OS"; else if (i_error==0x803100D2L) risultato="FVE_E_DE_VOLUME_OPTED_OUT"; else if (i_error==0x803100D3L) risultato="FVE_E_DE_VOLUME_NOT_SUPPORTED"; else if (i_error==0x803100D4L) risultato="FVE_E_EOW_NOT_SUPPORTED_IN_VERSION"; else if (i_error==0x803100D5L) risultato="FVE_E_ADBACKUP_NOT_ENABLED"; else if (i_error==0x803100D6L) risultato="FVE_E_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT"; else if (i_error==0x803100D7L) risultato="FVE_E_NOT_DE_VOLUME"; else if (i_error==0x803100D8L) risultato="FVE_E_PROTECTION_CANNOT_BE_DISABLED"; else if (i_error==0x803100D9L) risultato="FVE_E_OSV_KSR_NOT_ALLOWED"; else if (i_error==0x80320001L) risultato="FWP_E_CALLOUT_NOT_FOUND"; else if (i_error==0x80320002L) risultato="FWP_E_CONDITION_NOT_FOUND"; else if (i_error==0x80320003L) risultato="FWP_E_FILTER_NOT_FOUND"; else if (i_error==0x80320004L) risultato="FWP_E_LAYER_NOT_FOUND"; else if (i_error==0x80320005L) risultato="FWP_E_PROVIDER_NOT_FOUND"; else if (i_error==0x80320006L) risultato="FWP_E_PROVIDER_CONTEXT_NOT_FOUND"; else if (i_error==0x80320007L) risultato="FWP_E_SUBLAYER_NOT_FOUND"; else if (i_error==0x80320008L) risultato="FWP_E_NOT_FOUND"; else if (i_error==0x80320009L) risultato="FWP_E_ALREADY_EXISTS"; else if (i_error==0x8032000AL) risultato="FWP_E_IN_USE"; else if (i_error==0x8032000BL) risultato="FWP_E_DYNAMIC_SESSION_IN_PROGRESS"; else if (i_error==0x8032000CL) risultato="FWP_E_WRONG_SESSION"; else if (i_error==0x8032000DL) risultato="FWP_E_NO_TXN_IN_PROGRESS"; else if (i_error==0x8032000EL) risultato="FWP_E_TXN_IN_PROGRESS"; else if (i_error==0x8032000FL) risultato="FWP_E_TXN_ABORTED"; else if (i_error==0x80320010L) risultato="FWP_E_SESSION_ABORTED"; else if (i_error==0x80320011L) risultato="FWP_E_INCOMPATIBLE_TXN"; else if (i_error==0x80320012L) risultato="FWP_E_TIMEOUT"; else if (i_error==0x80320013L) risultato="FWP_E_NET_EVENTS_DISABLED"; else if (i_error==0x80320014L) risultato="FWP_E_INCOMPATIBLE_LAYER"; else if (i_error==0x80320015L) risultato="FWP_E_KM_CLIENTS_ONLY"; else if (i_error==0x80320016L) risultato="FWP_E_LIFETIME_MISMATCH"; else if (i_error==0x80320017L) risultato="FWP_E_BUILTIN_OBJECT"; else if (i_error==0x80320018L) risultato="FWP_E_TOO_MANY_CALLOUTS"; else if (i_error==0x80320019L) risultato="FWP_E_NOTIFICATION_DROPPED"; else if (i_error==0x8032001AL) risultato="FWP_E_TRAFFIC_MISMATCH"; else if (i_error==0x8032001BL) risultato="FWP_E_INCOMPATIBLE_SA_STATE"; else if (i_error==0x8032001CL) risultato="FWP_E_NULL_POINTER"; else if (i_error==0x8032001DL) risultato="FWP_E_INVALID_ENUMERATOR"; else if (i_error==0x8032001EL) risultato="FWP_E_INVALID_FLAGS"; else if (i_error==0x8032001FL) risultato="FWP_E_INVALID_NET_MASK"; else if (i_error==0x80320020L) risultato="FWP_E_INVALID_RANGE"; else if (i_error==0x80320021L) risultato="FWP_E_INVALID_INTERVAL"; else if (i_error==0x80320022L) risultato="FWP_E_ZERO_LENGTH_ARRAY"; else if (i_error==0x80320023L) risultato="FWP_E_NULL_DISPLAY_NAME"; else if (i_error==0x80320024L) risultato="FWP_E_INVALID_ACTION_TYPE"; else if (i_error==0x80320025L) risultato="FWP_E_INVALID_WEIGHT"; else if (i_error==0x80320026L) risultato="FWP_E_MATCH_TYPE_MISMATCH"; else if (i_error==0x80320027L) risultato="FWP_E_TYPE_MISMATCH"; else if (i_error==0x80320028L) risultato="FWP_E_OUT_OF_BOUNDS"; else if (i_error==0x80320029L) risultato="FWP_E_RESERVED"; else if (i_error==0x8032002AL) risultato="FWP_E_DUPLICATE_CONDITION"; else if (i_error==0x8032002BL) risultato="FWP_E_DUPLICATE_KEYMOD"; else if (i_error==0x8032002CL) risultato="FWP_E_ACTION_INCOMPATIBLE_WITH_LAYER"; else if (i_error==0x8032002DL) risultato="FWP_E_ACTION_INCOMPATIBLE_WITH_SUBLAYER"; else if (i_error==0x8032002EL) risultato="FWP_E_CONTEXT_INCOMPATIBLE_WITH_LAYER"; else if (i_error==0x8032002FL) risultato="FWP_E_CONTEXT_INCOMPATIBLE_WITH_CALLOUT"; else if (i_error==0x80320030L) risultato="FWP_E_INCOMPATIBLE_AUTH_METHOD"; else if (i_error==0x80320031L) risultato="FWP_E_INCOMPATIBLE_DH_GROUP"; else if (i_error==0x80320032L) risultato="FWP_E_EM_NOT_SUPPORTED"; else if (i_error==0x80320033L) risultato="FWP_E_NEVER_MATCH"; else if (i_error==0x80320034L) risultato="FWP_E_PROVIDER_CONTEXT_MISMATCH"; else if (i_error==0x80320035L) risultato="FWP_E_INVALID_PARAMETER"; else if (i_error==0x80320036L) risultato="FWP_E_TOO_MANY_SUBLAYERS"; else if (i_error==0x80320037L) risultato="FWP_E_CALLOUT_NOTIFICATION_FAILED"; else if (i_error==0x80320038L) risultato="FWP_E_INVALID_AUTH_TRANSFORM"; else if (i_error==0x80320039L) risultato="FWP_E_INVALID_CIPHER_TRANSFORM"; else if (i_error==0x8032003AL) risultato="FWP_E_INCOMPATIBLE_CIPHER_TRANSFORM"; else if (i_error==0x8032003BL) risultato="FWP_E_INVALID_TRANSFORM_COMBINATION"; else if (i_error==0x8032003CL) risultato="FWP_E_DUPLICATE_AUTH_METHOD"; else if (i_error==0x8032003DL) risultato="FWP_E_INVALID_TUNNEL_ENDPOINT"; else if (i_error==0x8032003EL) risultato="FWP_E_L2_DRIVER_NOT_READY"; else if (i_error==0x8032003FL) risultato="FWP_E_KEY_DICTATOR_ALREADY_REGISTERED"; else if (i_error==0x80320040L) risultato="FWP_E_KEY_DICTATION_INVALID_KEYING_MATERIAL"; else if (i_error==0x80320041L) risultato="FWP_E_CONNECTIONS_DISABLED"; else if (i_error==0x80320042L) risultato="FWP_E_INVALID_DNS_NAME"; else if (i_error==0x80320043L) risultato="FWP_E_STILL_ON"; else if (i_error==0x80320044L) risultato="FWP_E_IKEEXT_NOT_RUNNING"; else if (i_error==0x80320104L) risultato="FWP_E_DROP_NOICMP"; else if (i_error==0x003D0000L) risultato="WS_S_ASYNC"; else if (i_error==0x003D0001L) risultato="WS_S_END"; else if (i_error==0x803D0000L) risultato="WS_E_INVALID_FORMAT"; else if (i_error==0x803D0001L) risultato="WS_E_OBJECT_FAULTED"; else if (i_error==0x803D0002L) risultato="WS_E_NUMERIC_OVERFLOW"; else if (i_error==0x803D0003L) risultato="WS_E_INVALID_OPERATION"; else if (i_error==0x803D0004L) risultato="WS_E_OPERATION_ABORTED"; else if (i_error==0x803D0005L) risultato="WS_E_ENDPOINT_ACCESS_DENIED"; else if (i_error==0x803D0006L) risultato="WS_E_OPERATION_TIMED_OUT"; else if (i_error==0x803D0007L) risultato="WS_E_OPERATION_ABANDONED"; else if (i_error==0x803D0008L) risultato="WS_E_QUOTA_EXCEEDED"; else if (i_error==0x803D0009L) risultato="WS_E_NO_TRANSLATION_AVAILABLE"; else if (i_error==0x803D000AL) risultato="WS_E_SECURITY_VERIFICATION_FAILURE"; else if (i_error==0x803D000BL) risultato="WS_E_ADDRESS_IN_USE"; else if (i_error==0x803D000CL) risultato="WS_E_ADDRESS_NOT_AVAILABLE"; else if (i_error==0x803D000DL) risultato="WS_E_ENDPOINT_NOT_FOUND"; else if (i_error==0x803D000EL) risultato="WS_E_ENDPOINT_NOT_AVAILABLE"; else if (i_error==0x803D000FL) risultato="WS_E_ENDPOINT_FAILURE"; else if (i_error==0x803D0010L) risultato="WS_E_ENDPOINT_UNREACHABLE"; else if (i_error==0x803D0011L) risultato="WS_E_ENDPOINT_ACTION_NOT_SUPPORTED"; else if (i_error==0x803D0012L) risultato="WS_E_ENDPOINT_TOO_BUSY"; else if (i_error==0x803D0013L) risultato="WS_E_ENDPOINT_FAULT_RECEIVED"; else if (i_error==0x803D0014L) risultato="WS_E_ENDPOINT_DISCONNECTED"; else if (i_error==0x803D0015L) risultato="WS_E_PROXY_FAILURE"; else if (i_error==0x803D0016L) risultato="WS_E_PROXY_ACCESS_DENIED"; else if (i_error==0x803D0017L) risultato="WS_E_NOT_SUPPORTED"; else if (i_error==0x803D0018L) risultato="WS_E_PROXY_REQUIRES_BASIC_AUTH"; else if (i_error==0x803D0019L) risultato="WS_E_PROXY_REQUIRES_DIGEST_AUTH"; else if (i_error==0x803D001AL) risultato="WS_E_PROXY_REQUIRES_NTLM_AUTH"; else if (i_error==0x803D001BL) risultato="WS_E_PROXY_REQUIRES_NEGOTIATE_AUTH"; else if (i_error==0x803D001CL) risultato="WS_E_SERVER_REQUIRES_BASIC_AUTH"; else if (i_error==0x803D001DL) risultato="WS_E_SERVER_REQUIRES_DIGEST_AUTH"; else if (i_error==0x803D001EL) risultato="WS_E_SERVER_REQUIRES_NTLM_AUTH"; else if (i_error==0x803D001FL) risultato="WS_E_SERVER_REQUIRES_NEGOTIATE_AUTH"; else if (i_error==0x803D0020L) risultato="WS_E_INVALID_ENDPOINT_URL"; else if (i_error==0x803D0021L) risultato="WS_E_OTHER"; else if (i_error==0x803D0022L) risultato="WS_E_SECURITY_TOKEN_EXPIRED"; else if (i_error==0x803D0023L) risultato="WS_E_SECURITY_SYSTEM_FAILURE"; else if (i_error==0x80340002L) risultato="ERROR_NDIS_INTERFACE_CLOSING"; else if (i_error==0x80340004L) risultato="ERROR_NDIS_BAD_VERSION"; else if (i_error==0x80340005L) risultato="ERROR_NDIS_BAD_CHARACTERISTICS"; else if (i_error==0x80340006L) risultato="ERROR_NDIS_ADAPTER_NOT_FOUND"; else if (i_error==0x80340007L) risultato="ERROR_NDIS_OPEN_FAILED"; else if (i_error==0x80340008L) risultato="ERROR_NDIS_DEVICE_FAILED"; else if (i_error==0x80340009L) risultato="ERROR_NDIS_MULTICAST_FULL"; else if (i_error==0x8034000AL) risultato="ERROR_NDIS_MULTICAST_EXISTS"; else if (i_error==0x8034000BL) risultato="ERROR_NDIS_MULTICAST_NOT_FOUND"; else if (i_error==0x8034000CL) risultato="ERROR_NDIS_REQUEST_ABORTED"; else if (i_error==0x8034000DL) risultato="ERROR_NDIS_RESET_IN_PROGRESS"; else if (i_error==0x803400BBL) risultato="ERROR_NDIS_NOT_SUPPORTED"; else if (i_error==0x8034000FL) risultato="ERROR_NDIS_INVALID_PACKET"; else if (i_error==0x80340011L) risultato="ERROR_NDIS_ADAPTER_NOT_READY"; else if (i_error==0x80340014L) risultato="ERROR_NDIS_INVALID_LENGTH"; else if (i_error==0x80340015L) risultato="ERROR_NDIS_INVALID_DATA"; else if (i_error==0x80340016L) risultato="ERROR_NDIS_BUFFER_TOO_SHORT"; else if (i_error==0x80340017L) risultato="ERROR_NDIS_INVALID_OID"; else if (i_error==0x80340018L) risultato="ERROR_NDIS_ADAPTER_REMOVED"; else if (i_error==0x80340019L) risultato="ERROR_NDIS_UNSUPPORTED_MEDIA"; else if (i_error==0x8034001AL) risultato="ERROR_NDIS_GROUP_ADDRESS_IN_USE"; else if (i_error==0x8034001BL) risultato="ERROR_NDIS_FILE_NOT_FOUND"; else if (i_error==0x8034001CL) risultato="ERROR_NDIS_ERROR_READING_FILE"; else if (i_error==0x8034001DL) risultato="ERROR_NDIS_ALREADY_MAPPED"; else if (i_error==0x8034001EL) risultato="ERROR_NDIS_RESOURCE_CONFLICT"; else if (i_error==0x8034001FL) risultato="ERROR_NDIS_MEDIA_DISCONNECTED"; else if (i_error==0x80340022L) risultato="ERROR_NDIS_INVALID_ADDRESS"; else if (i_error==0x80340010L) risultato="ERROR_NDIS_INVALID_DEVICE_REQUEST"; else if (i_error==0x8034002AL) risultato="ERROR_NDIS_PAUSED"; else if (i_error==0x8034002BL) risultato="ERROR_NDIS_INTERFACE_NOT_FOUND"; else if (i_error==0x8034002CL) risultato="ERROR_NDIS_UNSUPPORTED_REVISION"; else if (i_error==0x8034002DL) risultato="ERROR_NDIS_INVALID_PORT"; else if (i_error==0x8034002EL) risultato="ERROR_NDIS_INVALID_PORT_STATE"; else if (i_error==0x8034002FL) risultato="ERROR_NDIS_LOW_POWER_STATE"; else if (i_error==0x80340030L) risultato="ERROR_NDIS_REINIT_REQUIRED"; else if (i_error==0x80342000L) risultato="ERROR_NDIS_DOT11_AUTO_CONFIG_ENABLED"; else if (i_error==0x80342001L) risultato="ERROR_NDIS_DOT11_MEDIA_IN_USE"; else if (i_error==0x80342002L) risultato="ERROR_NDIS_DOT11_POWER_STATE_INVALID"; else if (i_error==0x80342003L) risultato="ERROR_NDIS_PM_WOL_PATTERN_LISTFULL"; else if (i_error==0x80342004L) risultato="ERROR_NDIS_PM_PROTOCOL_OFFLOAD_LISTFULL"; else if (i_error==0x80342005L) risultato="ERROR_NDIS_DOT11_AP_CHANNEL_CURRENTLY_NOT_AVAILABLE"; else if (i_error==0x80342006L) risultato="ERROR_NDIS_DOT11_AP_BAND_CURRENTLY_NOT_AVAILABLE"; else if (i_error==0x80342007L) risultato="ERROR_NDIS_DOT11_AP_CHANNEL_NOT_ALLOWED"; else if (i_error==0x80342008L) risultato="ERROR_NDIS_DOT11_AP_BAND_NOT_ALLOWED"; else if (i_error==0x00340001L) risultato="ERROR_NDIS_INDICATION_REQUIRED"; else if (i_error==0xC034100FL) risultato="ERROR_NDIS_OFFLOAD_POLICY"; else if (i_error==0xC0341012L) risultato="ERROR_NDIS_OFFLOAD_CONNECTION_REJECTED"; else if (i_error==0xC0341013L) risultato="ERROR_NDIS_OFFLOAD_PATH_REJECTED"; else if (i_error==0xC0350002L) risultato="ERROR_HV_INVALID_HYPERCALL_CODE"; else if (i_error==0xC0350003L) risultato="ERROR_HV_INVALID_HYPERCALL_INPUT"; else if (i_error==0xC0350004L) risultato="ERROR_HV_INVALID_ALIGNMENT"; else if (i_error==0xC0350005L) risultato="ERROR_HV_INVALID_PARAMETER"; else if (i_error==0xC0350006L) risultato="ERROR_HV_ACCESS_DENIED"; else if (i_error==0xC0350007L) risultato="ERROR_HV_INVALID_PARTITION_STATE"; else if (i_error==0xC0350008L) risultato="ERROR_HV_OPERATION_DENIED"; else if (i_error==0xC0350009L) risultato="ERROR_HV_UNKNOWN_PROPERTY"; else if (i_error==0xC035000AL) risultato="ERROR_HV_PROPERTY_VALUE_OUT_OF_RANGE"; else if (i_error==0xC035000BL) risultato="ERROR_HV_INSUFFICIENT_MEMORY"; else if (i_error==0xC035000CL) risultato="ERROR_HV_PARTITION_TOO_DEEP"; else if (i_error==0xC035000DL) risultato="ERROR_HV_INVALID_PARTITION_ID"; else if (i_error==0xC035000EL) risultato="ERROR_HV_INVALID_VP_INDEX"; else if (i_error==0xC0350011L) risultato="ERROR_HV_INVALID_PORT_ID"; else if (i_error==0xC0350012L) risultato="ERROR_HV_INVALID_CONNECTION_ID"; else if (i_error==0xC0350013L) risultato="ERROR_HV_INSUFFICIENT_BUFFERS"; else if (i_error==0xC0350014L) risultato="ERROR_HV_NOT_ACKNOWLEDGED"; else if (i_error==0xC0350015L) risultato="ERROR_HV_INVALID_VP_STATE"; else if (i_error==0xC0350016L) risultato="ERROR_HV_ACKNOWLEDGED"; else if (i_error==0xC0350017L) risultato="ERROR_HV_INVALID_SAVE_RESTORE_STATE"; else if (i_error==0xC0350018L) risultato="ERROR_HV_INVALID_SYNIC_STATE"; else if (i_error==0xC0350019L) risultato="ERROR_HV_OBJECT_IN_USE"; else if (i_error==0xC035001AL) risultato="ERROR_HV_INVALID_PROXIMITY_DOMAIN_INFO"; else if (i_error==0xC035001BL) risultato="ERROR_HV_NO_DATA"; else if (i_error==0xC035001CL) risultato="ERROR_HV_INACTIVE"; else if (i_error==0xC035001DL) risultato="ERROR_HV_NO_RESOURCES"; else if (i_error==0xC035001EL) risultato="ERROR_HV_FEATURE_UNAVAILABLE"; else if (i_error==0xC0350033L) risultato="ERROR_HV_INSUFFICIENT_BUFFER"; else if (i_error==0xC0350038L) risultato="ERROR_HV_INSUFFICIENT_DEVICE_DOMAINS"; else if (i_error==0xC035003CL) risultato="ERROR_HV_CPUID_FEATURE_VALIDATION"; else if (i_error==0xC035003DL) risultato="ERROR_HV_CPUID_XSAVE_FEATURE_VALIDATION"; else if (i_error==0xC035003EL) risultato="ERROR_HV_PROCESSOR_STARTUP_TIMEOUT"; else if (i_error==0xC035003FL) risultato="ERROR_HV_SMX_ENABLED"; else if (i_error==0xC0350041L) risultato="ERROR_HV_INVALID_LP_INDEX"; else if (i_error==0xC0350050L) risultato="ERROR_HV_INVALID_REGISTER_VALUE"; else if (i_error==0xC0350051L) risultato="ERROR_HV_INVALID_VTL_STATE"; else if (i_error==0xC0350055L) risultato="ERROR_HV_NX_NOT_DETECTED"; else if (i_error==0xC0350057L) risultato="ERROR_HV_INVALID_DEVICE_ID"; else if (i_error==0xC0350058L) risultato="ERROR_HV_INVALID_DEVICE_STATE"; else if (i_error==0x00350059L) risultato="ERROR_HV_PENDING_PAGE_REQUESTS"; else if (i_error==0xC0350060L) risultato="ERROR_HV_PAGE_REQUEST_INVALID"; else if (i_error==0xC035006FL) risultato="ERROR_HV_INVALID_CPU_GROUP_ID"; else if (i_error==0xC0350070L) risultato="ERROR_HV_INVALID_CPU_GROUP_STATE"; else if (i_error==0xC0350071L) risultato="ERROR_HV_NOT_ALLOWED_WITH_NESTED_VIRT_ACTIVE"; else if (i_error==0xC0351000L) risultato="ERROR_HV_NOT_PRESENT"; else if (i_error==0xC0370001L) risultato="ERROR_VID_DUPLICATE_HANDLER"; else if (i_error==0xC0370002L) risultato="ERROR_VID_TOO_MANY_HANDLERS"; else if (i_error==0xC0370003L) risultato="ERROR_VID_QUEUE_FULL"; else if (i_error==0xC0370004L) risultato="ERROR_VID_HANDLER_NOT_PRESENT"; else if (i_error==0xC0370005L) risultato="ERROR_VID_INVALID_OBJECT_NAME"; else if (i_error==0xC0370006L) risultato="ERROR_VID_PARTITION_NAME_TOO_LONG"; else if (i_error==0xC0370007L) risultato="ERROR_VID_MESSAGE_QUEUE_NAME_TOO_LONG"; else if (i_error==0xC0370008L) risultato="ERROR_VID_PARTITION_ALREADY_EXISTS"; else if (i_error==0xC0370009L) risultato="ERROR_VID_PARTITION_DOES_NOT_EXIST"; else if (i_error==0xC037000AL) risultato="ERROR_VID_PARTITION_NAME_NOT_FOUND"; else if (i_error==0xC037000BL) risultato="ERROR_VID_MESSAGE_QUEUE_ALREADY_EXISTS"; else if (i_error==0xC037000CL) risultato="ERROR_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT"; else if (i_error==0xC037000DL) risultato="ERROR_VID_MB_STILL_REFERENCED"; else if (i_error==0xC037000EL) risultato="ERROR_VID_CHILD_GPA_PAGE_SET_CORRUPTED"; else if (i_error==0xC037000FL) risultato="ERROR_VID_INVALID_NUMA_SETTINGS"; else if (i_error==0xC0370010L) risultato="ERROR_VID_INVALID_NUMA_NODE_INDEX"; else if (i_error==0xC0370011L) risultato="ERROR_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED"; else if (i_error==0xC0370012L) risultato="ERROR_VID_INVALID_MEMORY_BLOCK_HANDLE"; else if (i_error==0xC0370013L) risultato="ERROR_VID_PAGE_RANGE_OVERFLOW"; else if (i_error==0xC0370014L) risultato="ERROR_VID_INVALID_MESSAGE_QUEUE_HANDLE"; else if (i_error==0xC0370015L) risultato="ERROR_VID_INVALID_GPA_RANGE_HANDLE"; else if (i_error==0xC0370016L) risultato="ERROR_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE"; else if (i_error==0xC0370017L) risultato="ERROR_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED"; else if (i_error==0xC0370018L) risultato="ERROR_VID_INVALID_PPM_HANDLE"; else if (i_error==0xC0370019L) risultato="ERROR_VID_MBPS_ARE_LOCKED"; else if (i_error==0xC037001AL) risultato="ERROR_VID_MESSAGE_QUEUE_CLOSED"; else if (i_error==0xC037001BL) risultato="ERROR_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED"; else if (i_error==0xC037001CL) risultato="ERROR_VID_STOP_PENDING"; else if (i_error==0xC037001DL) risultato="ERROR_VID_INVALID_PROCESSOR_STATE"; else if (i_error==0xC037001EL) risultato="ERROR_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT"; else if (i_error==0xC037001FL) risultato="ERROR_VID_KM_INTERFACE_ALREADY_INITIALIZED"; else if (i_error==0xC0370020L) risultato="ERROR_VID_MB_PROPERTY_ALREADY_SET_RESET"; else if (i_error==0xC0370021L) risultato="ERROR_VID_MMIO_RANGE_DESTROYED"; else if (i_error==0xC0370022L) risultato="ERROR_VID_INVALID_CHILD_GPA_PAGE_SET"; else if (i_error==0xC0370023L) risultato="ERROR_VID_RESERVE_PAGE_SET_IS_BEING_USED"; else if (i_error==0xC0370024L) risultato="ERROR_VID_RESERVE_PAGE_SET_TOO_SMALL"; else if (i_error==0xC0370025L) risultato="ERROR_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE"; else if (i_error==0xC0370026L) risultato="ERROR_VID_MBP_COUNT_EXCEEDED_LIMIT"; else if (i_error==0xC0370027L) risultato="ERROR_VID_SAVED_STATE_CORRUPT"; else if (i_error==0xC0370028L) risultato="ERROR_VID_SAVED_STATE_UNRECOGNIZED_ITEM"; else if (i_error==0xC0370029L) risultato="ERROR_VID_SAVED_STATE_INCOMPATIBLE"; else if (i_error==0xC037002AL) risultato="ERROR_VID_VTL_ACCESS_DENIED"; else if (i_error==0xC0370100L) risultato="ERROR_VMCOMPUTE_TERMINATED_DURING_START"; else if (i_error==0xC0370101L) risultato="ERROR_VMCOMPUTE_IMAGE_MISMATCH"; else if (i_error==0xC0370102L) risultato="ERROR_VMCOMPUTE_HYPERV_NOT_INSTALLED"; else if (i_error==0xC0370103L) risultato="ERROR_VMCOMPUTE_OPERATION_PENDING"; else if (i_error==0xC0370104L) risultato="ERROR_VMCOMPUTE_TOO_MANY_NOTIFICATIONS"; else if (i_error==0xC0370105L) risultato="ERROR_VMCOMPUTE_INVALID_STATE"; else if (i_error==0xC0370106L) risultato="ERROR_VMCOMPUTE_UNEXPECTED_EXIT"; else if (i_error==0xC0370107L) risultato="ERROR_VMCOMPUTE_TERMINATED"; else if (i_error==0xC0370108L) risultato="ERROR_VMCOMPUTE_CONNECT_FAILED"; else if (i_error==0xC0370109L) risultato="ERROR_VMCOMPUTE_TIMEOUT"; else if (i_error==0xC037010AL) risultato="ERROR_VMCOMPUTE_CONNECTION_CLOSED"; else if (i_error==0xC037010BL) risultato="ERROR_VMCOMPUTE_UNKNOWN_MESSAGE"; else if (i_error==0xC037010CL) risultato="ERROR_VMCOMPUTE_UNSUPPORTED_PROTOCOL_VERSION"; else if (i_error==0xC037010DL) risultato="ERROR_VMCOMPUTE_INVALID_JSON"; else if (i_error==0xC037010EL) risultato="ERROR_VMCOMPUTE_SYSTEM_NOT_FOUND"; else if (i_error==0xC037010FL) risultato="ERROR_VMCOMPUTE_SYSTEM_ALREADY_EXISTS"; else if (i_error==0xC0370110L) risultato="ERROR_VMCOMPUTE_SYSTEM_ALREADY_STOPPED"; else if (i_error==0xC0370200L) risultato="ERROR_VNET_VIRTUAL_SWITCH_NAME_NOT_FOUND"; else if (i_error==0x80370001L) risultato="ERROR_VID_REMOTE_NODE_PARENT_GPA_PAGES_USED"; else if (i_error==0x80380001L) risultato="ERROR_VOLMGR_INCOMPLETE_REGENERATION"; else if (i_error==0x80380002L) risultato="ERROR_VOLMGR_INCOMPLETE_DISK_MIGRATION"; else if (i_error==0xC0380001L) risultato="ERROR_VOLMGR_DATABASE_FULL"; else if (i_error==0xC0380002L) risultato="ERROR_VOLMGR_DISK_CONFIGURATION_CORRUPTED"; else if (i_error==0xC0380003L) risultato="ERROR_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC"; else if (i_error==0xC0380004L) risultato="ERROR_VOLMGR_PACK_CONFIG_UPDATE_FAILED"; else if (i_error==0xC0380005L) risultato="ERROR_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME"; else if (i_error==0xC0380006L) risultato="ERROR_VOLMGR_DISK_DUPLICATE"; else if (i_error==0xC0380007L) risultato="ERROR_VOLMGR_DISK_DYNAMIC"; else if (i_error==0xC0380008L) risultato="ERROR_VOLMGR_DISK_ID_INVALID"; else if (i_error==0xC0380009L) risultato="ERROR_VOLMGR_DISK_INVALID"; else if (i_error==0xC038000AL) risultato="ERROR_VOLMGR_DISK_LAST_VOTER"; else if (i_error==0xC038000BL) risultato="ERROR_VOLMGR_DISK_LAYOUT_INVALID"; else if (i_error==0xC038000CL) risultato="ERROR_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS"; else if (i_error==0xC038000DL) risultato="ERROR_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED"; else if (i_error==0xC038000EL) risultato="ERROR_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL"; else if (i_error==0xC038000FL) risultato="ERROR_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS"; else if (i_error==0xC0380010L) risultato="ERROR_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS"; else if (i_error==0xC0380011L) risultato="ERROR_VOLMGR_DISK_MISSING"; else if (i_error==0xC0380012L) risultato="ERROR_VOLMGR_DISK_NOT_EMPTY"; else if (i_error==0xC0380013L) risultato="ERROR_VOLMGR_DISK_NOT_ENOUGH_SPACE"; else if (i_error==0xC0380014L) risultato="ERROR_VOLMGR_DISK_REVECTORING_FAILED"; else if (i_error==0xC0380015L) risultato="ERROR_VOLMGR_DISK_SECTOR_SIZE_INVALID"; else if (i_error==0xC0380016L) risultato="ERROR_VOLMGR_DISK_SET_NOT_CONTAINED"; else if (i_error==0xC0380017L) risultato="ERROR_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS"; else if (i_error==0xC0380018L) risultato="ERROR_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES"; else if (i_error==0xC0380019L) risultato="ERROR_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED"; else if (i_error==0xC038001AL) risultato="ERROR_VOLMGR_EXTENT_ALREADY_USED"; else if (i_error==0xC038001BL) risultato="ERROR_VOLMGR_EXTENT_NOT_CONTIGUOUS"; else if (i_error==0xC038001CL) risultato="ERROR_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION"; else if (i_error==0xC038001DL) risultato="ERROR_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED"; else if (i_error==0xC038001EL) risultato="ERROR_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION"; else if (i_error==0xC038001FL) risultato="ERROR_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH"; else if (i_error==0xC0380020L) risultato="ERROR_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED"; else if (i_error==0xC0380021L) risultato="ERROR_VOLMGR_INTERLEAVE_LENGTH_INVALID"; else if (i_error==0xC0380022L) risultato="ERROR_VOLMGR_MAXIMUM_REGISTERED_USERS"; else if (i_error==0xC0380023L) risultato="ERROR_VOLMGR_MEMBER_IN_SYNC"; else if (i_error==0xC0380024L) risultato="ERROR_VOLMGR_MEMBER_INDEX_DUPLICATE"; else if (i_error==0xC0380025L) risultato="ERROR_VOLMGR_MEMBER_INDEX_INVALID"; else if (i_error==0xC0380026L) risultato="ERROR_VOLMGR_MEMBER_MISSING"; else if (i_error==0xC0380027L) risultato="ERROR_VOLMGR_MEMBER_NOT_DETACHED"; else if (i_error==0xC0380028L) risultato="ERROR_VOLMGR_MEMBER_REGENERATING"; else if (i_error==0xC0380029L) risultato="ERROR_VOLMGR_ALL_DISKS_FAILED"; else if (i_error==0xC038002AL) risultato="ERROR_VOLMGR_NO_REGISTERED_USERS"; else if (i_error==0xC038002BL) risultato="ERROR_VOLMGR_NO_SUCH_USER"; else if (i_error==0xC038002CL) risultato="ERROR_VOLMGR_NOTIFICATION_RESET"; else if (i_error==0xC038002DL) risultato="ERROR_VOLMGR_NUMBER_OF_MEMBERS_INVALID"; else if (i_error==0xC038002EL) risultato="ERROR_VOLMGR_NUMBER_OF_PLEXES_INVALID"; else if (i_error==0xC038002FL) risultato="ERROR_VOLMGR_PACK_DUPLICATE"; else if (i_error==0xC0380030L) risultato="ERROR_VOLMGR_PACK_ID_INVALID"; else if (i_error==0xC0380031L) risultato="ERROR_VOLMGR_PACK_INVALID"; else if (i_error==0xC0380032L) risultato="ERROR_VOLMGR_PACK_NAME_INVALID"; else if (i_error==0xC0380033L) risultato="ERROR_VOLMGR_PACK_OFFLINE"; else if (i_error==0xC0380034L) risultato="ERROR_VOLMGR_PACK_HAS_QUORUM"; else if (i_error==0xC0380035L) risultato="ERROR_VOLMGR_PACK_WITHOUT_QUORUM"; else if (i_error==0xC0380036L) risultato="ERROR_VOLMGR_PARTITION_STYLE_INVALID"; else if (i_error==0xC0380037L) risultato="ERROR_VOLMGR_PARTITION_UPDATE_FAILED"; else if (i_error==0xC0380038L) risultato="ERROR_VOLMGR_PLEX_IN_SYNC"; else if (i_error==0xC0380039L) risultato="ERROR_VOLMGR_PLEX_INDEX_DUPLICATE"; else if (i_error==0xC038003AL) risultato="ERROR_VOLMGR_PLEX_INDEX_INVALID"; else if (i_error==0xC038003BL) risultato="ERROR_VOLMGR_PLEX_LAST_ACTIVE"; else if (i_error==0xC038003CL) risultato="ERROR_VOLMGR_PLEX_MISSING"; else if (i_error==0xC038003DL) risultato="ERROR_VOLMGR_PLEX_REGENERATING"; else if (i_error==0xC038003EL) risultato="ERROR_VOLMGR_PLEX_TYPE_INVALID"; else if (i_error==0xC038003FL) risultato="ERROR_VOLMGR_PLEX_NOT_RAID5"; else if (i_error==0xC0380040L) risultato="ERROR_VOLMGR_PLEX_NOT_SIMPLE"; else if (i_error==0xC0380041L) risultato="ERROR_VOLMGR_STRUCTURE_SIZE_INVALID"; else if (i_error==0xC0380042L) risultato="ERROR_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS"; else if (i_error==0xC0380043L) risultato="ERROR_VOLMGR_TRANSACTION_IN_PROGRESS"; else if (i_error==0xC0380044L) risultato="ERROR_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE"; else if (i_error==0xC0380045L) risultato="ERROR_VOLMGR_VOLUME_CONTAINS_MISSING_DISK"; else if (i_error==0xC0380046L) risultato="ERROR_VOLMGR_VOLUME_ID_INVALID"; else if (i_error==0xC0380047L) risultato="ERROR_VOLMGR_VOLUME_LENGTH_INVALID"; else if (i_error==0xC0380048L) risultato="ERROR_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE"; else if (i_error==0xC0380049L) risultato="ERROR_VOLMGR_VOLUME_NOT_MIRRORED"; else if (i_error==0xC038004AL) risultato="ERROR_VOLMGR_VOLUME_NOT_RETAINED"; else if (i_error==0xC038004BL) risultato="ERROR_VOLMGR_VOLUME_OFFLINE"; else if (i_error==0xC038004CL) risultato="ERROR_VOLMGR_VOLUME_RETAINED"; else if (i_error==0xC038004DL) risultato="ERROR_VOLMGR_NUMBER_OF_EXTENTS_INVALID"; else if (i_error==0xC038004EL) risultato="ERROR_VOLMGR_DIFFERENT_SECTOR_SIZE"; else if (i_error==0xC038004FL) risultato="ERROR_VOLMGR_BAD_BOOT_DISK"; else if (i_error==0xC0380050L) risultato="ERROR_VOLMGR_PACK_CONFIG_OFFLINE"; else if (i_error==0xC0380051L) risultato="ERROR_VOLMGR_PACK_CONFIG_ONLINE"; else if (i_error==0xC0380052L) risultato="ERROR_VOLMGR_NOT_PRIMARY_PACK"; else if (i_error==0xC0380053L) risultato="ERROR_VOLMGR_PACK_LOG_UPDATE_FAILED"; else if (i_error==0xC0380054L) risultato="ERROR_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID"; else if (i_error==0xC0380055L) risultato="ERROR_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID"; else if (i_error==0xC0380056L) risultato="ERROR_VOLMGR_VOLUME_MIRRORED"; else if (i_error==0xC0380057L) risultato="ERROR_VOLMGR_PLEX_NOT_SIMPLE_SPANNED"; else if (i_error==0xC0380058L) risultato="ERROR_VOLMGR_NO_VALID_LOG_COPIES"; else if (i_error==0xC0380059L) risultato="ERROR_VOLMGR_PRIMARY_PACK_PRESENT"; else if (i_error==0xC038005AL) risultato="ERROR_VOLMGR_NUMBER_OF_DISKS_INVALID"; else if (i_error==0xC038005BL) risultato="ERROR_VOLMGR_MIRROR_NOT_SUPPORTED"; else if (i_error==0xC038005CL) risultato="ERROR_VOLMGR_RAID5_NOT_SUPPORTED"; else if (i_error==0x80390001L) risultato="ERROR_BCD_NOT_ALL_ENTRIES_IMPORTED"; else if (i_error==0xC0390002L) risultato="ERROR_BCD_TOO_MANY_ELEMENTS"; else if (i_error==0x80390003L) risultato="ERROR_BCD_NOT_ALL_ENTRIES_SYNCHRONIZED"; else if (i_error==0xC03A0001L) risultato="ERROR_VHD_DRIVE_FOOTER_MISSING"; else if (i_error==0xC03A0002L) risultato="ERROR_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH"; else if (i_error==0xC03A0003L) risultato="ERROR_VHD_DRIVE_FOOTER_CORRUPT"; else if (i_error==0xC03A0004L) risultato="ERROR_VHD_FORMAT_UNKNOWN"; else if (i_error==0xC03A0005L) risultato="ERROR_VHD_FORMAT_UNSUPPORTED_VERSION"; else if (i_error==0xC03A0006L) risultato="ERROR_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH"; else if (i_error==0xC03A0007L) risultato="ERROR_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION"; else if (i_error==0xC03A0008L) risultato="ERROR_VHD_SPARSE_HEADER_CORRUPT"; else if (i_error==0xC03A0009L) risultato="ERROR_VHD_BLOCK_ALLOCATION_FAILURE"; else if (i_error==0xC03A000AL) risultato="ERROR_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT"; else if (i_error==0xC03A000BL) risultato="ERROR_VHD_INVALID_BLOCK_SIZE"; else if (i_error==0xC03A000CL) risultato="ERROR_VHD_BITMAP_MISMATCH"; else if (i_error==0xC03A000DL) risultato="ERROR_VHD_PARENT_VHD_NOT_FOUND"; else if (i_error==0xC03A000EL) risultato="ERROR_VHD_CHILD_PARENT_ID_MISMATCH"; else if (i_error==0xC03A000FL) risultato="ERROR_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH"; else if (i_error==0xC03A0010L) risultato="ERROR_VHD_METADATA_READ_FAILURE"; else if (i_error==0xC03A0011L) risultato="ERROR_VHD_METADATA_WRITE_FAILURE"; else if (i_error==0xC03A0012L) risultato="ERROR_VHD_INVALID_SIZE"; else if (i_error==0xC03A0013L) risultato="ERROR_VHD_INVALID_FILE_SIZE"; else if (i_error==0xC03A0014L) risultato="ERROR_VIRTDISK_PROVIDER_NOT_FOUND"; else if (i_error==0xC03A0015L) risultato="ERROR_VIRTDISK_NOT_VIRTUAL_DISK"; else if (i_error==0xC03A0016L) risultato="ERROR_VHD_PARENT_VHD_ACCESS_DENIED"; else if (i_error==0xC03A0017L) risultato="ERROR_VHD_CHILD_PARENT_SIZE_MISMATCH"; else if (i_error==0xC03A0018L) risultato="ERROR_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED"; else if (i_error==0xC03A0019L) risultato="ERROR_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT"; else if (i_error==0xC03A001AL) risultato="ERROR_VIRTUAL_DISK_LIMITATION"; else if (i_error==0xC03A001BL) risultato="ERROR_VHD_INVALID_TYPE"; else if (i_error==0xC03A001CL) risultato="ERROR_VHD_INVALID_STATE"; else if (i_error==0xC03A001DL) risultato="ERROR_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE"; else if (i_error==0xC03A001EL) risultato="ERROR_VIRTDISK_DISK_ALREADY_OWNED"; else if (i_error==0xC03A001FL) risultato="ERROR_VIRTDISK_DISK_ONLINE_AND_WRITABLE"; else if (i_error==0xC03A0020L) risultato="ERROR_CTLOG_TRACKING_NOT_INITIALIZED"; else if (i_error==0xC03A0021L) risultato="ERROR_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE"; else if (i_error==0xC03A0022L) risultato="ERROR_CTLOG_VHD_CHANGED_OFFLINE"; else if (i_error==0xC03A0023L) risultato="ERROR_CTLOG_INVALID_TRACKING_STATE"; else if (i_error==0xC03A0024L) risultato="ERROR_CTLOG_INCONSISTENT_TRACKING_FILE"; else if (i_error==0xC03A0025L) risultato="ERROR_VHD_RESIZE_WOULD_TRUNCATE_DATA"; else if (i_error==0xC03A0026L) risultato="ERROR_VHD_COULD_NOT_COMPUTE_MINIMUM_VIRTUAL_SIZE"; else if (i_error==0xC03A0027L) risultato="ERROR_VHD_ALREADY_AT_OR_BELOW_MINIMUM_VIRTUAL_SIZE"; else if (i_error==0xC03A0028L) risultato="ERROR_VHD_METADATA_FULL"; else if (i_error==0xC03A0029L) risultato="ERROR_VHD_INVALID_CHANGE_TRACKING_ID"; else if (i_error==0xC03A002AL) risultato="ERROR_VHD_CHANGE_TRACKING_DISABLED"; else if (i_error==0xC03A0030L) risultato="ERROR_VHD_MISSING_CHANGE_TRACKING_INFORMATION"; else if (i_error==0x803A0001L) risultato="ERROR_QUERY_STORAGE_ERROR"; else if (i_error==0xC03B0001L) risultato="ERROR_HNS_PORT_ALLOCATED"; else if (i_error==0xC03B0002L) risultato="ERROR_HNS_MAPPING_NOT_SUPPORTED"; else if (i_error==0x803C0100L) risultato="SDIAG_E_CANCELLED"; else if (i_error==0x803C0101L) risultato="SDIAG_E_SCRIPT"; else if (i_error==0x803C0102L) risultato="SDIAG_E_POWERSHELL"; else if (i_error==0x803C0103L) risultato="SDIAG_E_MANAGEDHOST"; else if (i_error==0x803C0104L) risultato="SDIAG_E_NOVERIFIER"; else if (i_error==0x003C0105L) risultato="SDIAG_S_CANNOTRUN"; else if (i_error==0x803C0106L) risultato="SDIAG_E_DISABLED"; else if (i_error==0x803C0107L) risultato="SDIAG_E_TRUST"; else if (i_error==0x803C0108L) risultato="SDIAG_E_CANNOTRUN"; else if (i_error==0x803C0109L) risultato="SDIAG_E_VERSION"; else if (i_error==0x803C010AL) risultato="SDIAG_E_RESOURCE"; else if (i_error==0x803C010BL) risultato="SDIAG_E_ROOTCAUSE"; else if (i_error==0x803E0100L) risultato="WPN_E_CHANNEL_CLOSED"; else if (i_error==0x803E0101L) risultato="WPN_E_CHANNEL_REQUEST_NOT_COMPLETE"; else if (i_error==0x803E0102L) risultato="WPN_E_INVALID_APP"; else if (i_error==0x803E0103L) risultato="WPN_E_OUTSTANDING_CHANNEL_REQUEST"; else if (i_error==0x803E0104L) risultato="WPN_E_DUPLICATE_CHANNEL"; else if (i_error==0x803E0105L) risultato="WPN_E_PLATFORM_UNAVAILABLE"; else if (i_error==0x803E0106L) risultato="WPN_E_NOTIFICATION_POSTED"; else if (i_error==0x803E0107L) risultato="WPN_E_NOTIFICATION_HIDDEN"; else if (i_error==0x803E0108L) risultato="WPN_E_NOTIFICATION_NOT_POSTED"; else if (i_error==0x803E0109L) risultato="WPN_E_CLOUD_DISABLED"; else if (i_error==0x803E0110L) risultato="WPN_E_CLOUD_INCAPABLE"; else if (i_error==0x803E011AL) risultato="WPN_E_CLOUD_AUTH_UNAVAILABLE"; else if (i_error==0x803E011BL) risultato="WPN_E_CLOUD_SERVICE_UNAVAILABLE"; else if (i_error==0x803E011CL) risultato="WPN_E_FAILED_LOCK_SCREEN_UPDATE_INTIALIZATION"; else if (i_error==0x803E0111L) risultato="WPN_E_NOTIFICATION_DISABLED"; else if (i_error==0x803E0112L) risultato="WPN_E_NOTIFICATION_INCAPABLE"; else if (i_error==0x803E0113L) risultato="WPN_E_INTERNET_INCAPABLE"; else if (i_error==0x803E0114L) risultato="WPN_E_NOTIFICATION_TYPE_DISABLED"; else if (i_error==0x803E0115L) risultato="WPN_E_NOTIFICATION_SIZE"; else if (i_error==0x803E0116L) risultato="WPN_E_TAG_SIZE"; else if (i_error==0x803E0117L) risultato="WPN_E_ACCESS_DENIED"; else if (i_error==0x803E0118L) risultato="WPN_E_DUPLICATE_REGISTRATION"; else if (i_error==0x803E0119L) risultato="WPN_E_PUSH_NOTIFICATION_INCAPABLE"; else if (i_error==0x803E0120L) risultato="WPN_E_DEV_ID_SIZE"; else if (i_error==0x803E012AL) risultato="WPN_E_TAG_ALPHANUMERIC"; else if (i_error==0x803E012BL) risultato="WPN_E_INVALID_HTTP_STATUS_CODE"; else if (i_error==0x803E0200L) risultato="WPN_E_OUT_OF_SESSION"; else if (i_error==0x803E0201L) risultato="WPN_E_POWER_SAVE"; else if (i_error==0x803E0202L) risultato="WPN_E_IMAGE_NOT_FOUND_IN_CACHE"; else if (i_error==0x803E0203L) risultato="WPN_E_ALL_URL_NOT_COMPLETED"; else if (i_error==0x803E0204L) risultato="WPN_E_INVALID_CLOUD_IMAGE"; else if (i_error==0x803E0205L) risultato="WPN_E_NOTIFICATION_ID_MATCHED"; else if (i_error==0x803E0206L) risultato="WPN_E_CALLBACK_ALREADY_REGISTERED"; else if (i_error==0x803E0207L) risultato="WPN_E_TOAST_NOTIFICATION_DROPPED"; else if (i_error==0x803E0208L) risultato="WPN_E_STORAGE_LOCKED"; else if (i_error==0x803E0209L) risultato="WPN_E_GROUP_SIZE"; else if (i_error==0x803E020AL) risultato="WPN_E_GROUP_ALPHANUMERIC"; else if (i_error==0x803E020BL) risultato="WPN_E_CLOUD_DISABLED_FOR_APP"; else if (i_error==0x80548201L) risultato="E_MBN_CONTEXT_NOT_ACTIVATED"; else if (i_error==0x80548202L) risultato="E_MBN_BAD_SIM"; else if (i_error==0x80548203L) risultato="E_MBN_DATA_CLASS_NOT_AVAILABLE"; else if (i_error==0x80548204L) risultato="E_MBN_INVALID_ACCESS_STRING"; else if (i_error==0x80548205L) risultato="E_MBN_MAX_ACTIVATED_CONTEXTS"; else if (i_error==0x80548206L) risultato="E_MBN_PACKET_SVC_DETACHED"; else if (i_error==0x80548207L) risultato="E_MBN_PROVIDER_NOT_VISIBLE"; else if (i_error==0x80548208L) risultato="E_MBN_RADIO_POWER_OFF"; else if (i_error==0x80548209L) risultato="E_MBN_SERVICE_NOT_ACTIVATED"; else if (i_error==0x8054820AL) risultato="E_MBN_SIM_NOT_INSERTED"; else if (i_error==0x8054820BL) risultato="E_MBN_VOICE_CALL_IN_PROGRESS"; else if (i_error==0x8054820CL) risultato="E_MBN_INVALID_CACHE"; else if (i_error==0x8054820DL) risultato="E_MBN_NOT_REGISTERED"; else if (i_error==0x8054820EL) risultato="E_MBN_PROVIDERS_NOT_FOUND"; else if (i_error==0x8054820FL) risultato="E_MBN_PIN_NOT_SUPPORTED"; else if (i_error==0x80548210L) risultato="E_MBN_PIN_REQUIRED"; else if (i_error==0x80548211L) risultato="E_MBN_PIN_DISABLED"; else if (i_error==0x80548212L) risultato="E_MBN_FAILURE"; else if (i_error==0x80548218L) risultato="E_MBN_INVALID_PROFILE"; else if (i_error==0x80548219L) risultato="E_MBN_DEFAULT_PROFILE_EXIST"; else if (i_error==0x80548220L) risultato="E_MBN_SMS_ENCODING_NOT_SUPPORTED"; else if (i_error==0x80548221L) risultato="E_MBN_SMS_FILTER_NOT_SUPPORTED"; else if (i_error==0x80548222L) risultato="E_MBN_SMS_INVALID_MEMORY_INDEX"; else if (i_error==0x80548223L) risultato="E_MBN_SMS_LANG_NOT_SUPPORTED"; else if (i_error==0x80548224L) risultato="E_MBN_SMS_MEMORY_FAILURE"; else if (i_error==0x80548225L) risultato="E_MBN_SMS_NETWORK_TIMEOUT"; else if (i_error==0x80548226L) risultato="E_MBN_SMS_UNKNOWN_SMSC_ADDRESS"; else if (i_error==0x80548227L) risultato="E_MBN_SMS_FORMAT_NOT_SUPPORTED"; else if (i_error==0x80548228L) risultato="E_MBN_SMS_OPERATION_NOT_ALLOWED"; else if (i_error==0x80548229L) risultato="E_MBN_SMS_MEMORY_FULL"; else if (i_error==0x80630001L) risultato="PEER_E_IPV6_NOT_INSTALLED"; else if (i_error==0x80630002L) risultato="PEER_E_NOT_INITIALIZED"; else if (i_error==0x80630003L) risultato="PEER_E_CANNOT_START_SERVICE"; else if (i_error==0x80630004L) risultato="PEER_E_NOT_LICENSED"; else if (i_error==0x80630010L) risultato="PEER_E_INVALID_GRAPH"; else if (i_error==0x80630011L) risultato="PEER_E_DBNAME_CHANGED"; else if (i_error==0x80630012L) risultato="PEER_E_DUPLICATE_GRAPH"; else if (i_error==0x80630013L) risultato="PEER_E_GRAPH_NOT_READY"; else if (i_error==0x80630014L) risultato="PEER_E_GRAPH_SHUTTING_DOWN"; else if (i_error==0x80630015L) risultato="PEER_E_GRAPH_IN_USE"; else if (i_error==0x80630016L) risultato="PEER_E_INVALID_DATABASE"; else if (i_error==0x80630017L) risultato="PEER_E_TOO_MANY_ATTRIBUTES"; else if (i_error==0x80630103L) risultato="PEER_E_CONNECTION_NOT_FOUND"; else if (i_error==0x80630106L) risultato="PEER_E_CONNECT_SELF"; else if (i_error==0x80630107L) risultato="PEER_E_ALREADY_LISTENING"; else if (i_error==0x80630108L) risultato="PEER_E_NODE_NOT_FOUND"; else if (i_error==0x80630109L) risultato="PEER_E_CONNECTION_FAILED"; else if (i_error==0x8063010AL) risultato="PEER_E_CONNECTION_NOT_AUTHENTICATED"; else if (i_error==0x8063010BL) risultato="PEER_E_CONNECTION_REFUSED"; else if (i_error==0x80630201L) risultato="PEER_E_CLASSIFIER_TOO_LONG"; else if (i_error==0x80630202L) risultato="PEER_E_TOO_MANY_IDENTITIES"; else if (i_error==0x80630203L) risultato="PEER_E_NO_KEY_ACCESS"; else if (i_error==0x80630204L) risultato="PEER_E_GROUPS_EXIST"; else if (i_error==0x80630301L) risultato="PEER_E_RECORD_NOT_FOUND"; else if (i_error==0x80630302L) risultato="PEER_E_DATABASE_ACCESSDENIED"; else if (i_error==0x80630303L) risultato="PEER_E_DBINITIALIZATION_FAILED"; else if (i_error==0x80630304L) risultato="PEER_E_MAX_RECORD_SIZE_EXCEEDED"; else if (i_error==0x80630305L) risultato="PEER_E_DATABASE_ALREADY_PRESENT"; else if (i_error==0x80630306L) risultato="PEER_E_DATABASE_NOT_PRESENT"; else if (i_error==0x80630401L) risultato="PEER_E_IDENTITY_NOT_FOUND"; else if (i_error==0x80630501L) risultato="PEER_E_EVENT_HANDLE_NOT_FOUND"; else if (i_error==0x80630601L) risultato="PEER_E_INVALID_SEARCH"; else if (i_error==0x80630602L) risultato="PEER_E_INVALID_ATTRIBUTES"; else if (i_error==0x80630701L) risultato="PEER_E_INVITATION_NOT_TRUSTED"; else if (i_error==0x80630703L) risultato="PEER_E_CHAIN_TOO_LONG"; else if (i_error==0x80630705L) risultato="PEER_E_INVALID_TIME_PERIOD"; else if (i_error==0x80630706L) risultato="PEER_E_CIRCULAR_CHAIN_DETECTED"; else if (i_error==0x80630801L) risultato="PEER_E_CERT_STORE_CORRUPTED"; else if (i_error==0x80631001L) risultato="PEER_E_NO_CLOUD"; else if (i_error==0x80631005L) risultato="PEER_E_CLOUD_NAME_AMBIGUOUS"; else if (i_error==0x80632010L) risultato="PEER_E_INVALID_RECORD"; else if (i_error==0x80632020L) risultato="PEER_E_NOT_AUTHORIZED"; else if (i_error==0x80632021L) risultato="PEER_E_PASSWORD_DOES_NOT_MEET_POLICY"; else if (i_error==0x80632030L) risultato="PEER_E_DEFERRED_VALIDATION"; else if (i_error==0x80632040L) risultato="PEER_E_INVALID_GROUP_PROPERTIES"; else if (i_error==0x80632050L) risultato="PEER_E_INVALID_PEER_NAME"; else if (i_error==0x80632060L) risultato="PEER_E_INVALID_CLASSIFIER"; else if (i_error==0x80632070L) risultato="PEER_E_INVALID_FRIENDLY_NAME"; else if (i_error==0x80632071L) risultato="PEER_E_INVALID_ROLE_PROPERTY"; else if (i_error==0x80632072L) risultato="PEER_E_INVALID_CLASSIFIER_PROPERTY"; else if (i_error==0x80632080L) risultato="PEER_E_INVALID_RECORD_EXPIRATION"; else if (i_error==0x80632081L) risultato="PEER_E_INVALID_CREDENTIAL_INFO"; else if (i_error==0x80632082L) risultato="PEER_E_INVALID_CREDENTIAL"; else if (i_error==0x80632083L) risultato="PEER_E_INVALID_RECORD_SIZE"; else if (i_error==0x80632090L) risultato="PEER_E_UNSUPPORTED_VERSION"; else if (i_error==0x80632091L) risultato="PEER_E_GROUP_NOT_READY"; else if (i_error==0x80632092L) risultato="PEER_E_GROUP_IN_USE"; else if (i_error==0x80632093L) risultato="PEER_E_INVALID_GROUP"; else if (i_error==0x80632094L) risultato="PEER_E_NO_MEMBERS_FOUND"; else if (i_error==0x80632095L) risultato="PEER_E_NO_MEMBER_CONNECTIONS"; else if (i_error==0x80632096L) risultato="PEER_E_UNABLE_TO_LISTEN"; else if (i_error==0x806320A0L) risultato="PEER_E_IDENTITY_DELETED"; else if (i_error==0x806320A1L) risultato="PEER_E_SERVICE_NOT_AVAILABLE"; else if (i_error==0x80636001L) risultato="PEER_E_CONTACT_NOT_FOUND"; else if (i_error==0x00630001L) risultato="PEER_S_GRAPH_DATA_CREATED"; else if (i_error==0x00630002L) risultato="PEER_S_NO_EVENT_DATA"; else if (i_error==0x00632000L) risultato="PEER_S_ALREADY_CONNECTED"; else if (i_error==0x00636000L) risultato="PEER_S_SUBSCRIPTION_EXISTS"; else if (i_error==0x00630005L) risultato="PEER_S_NO_CONNECTIVITY"; else if (i_error==0x00630006L) risultato="PEER_S_ALREADY_A_MEMBER"; else if (i_error==0x80634001L) risultato="PEER_E_CANNOT_CONVERT_PEER_NAME"; else if (i_error==0x80634002L) risultato="PEER_E_INVALID_PEER_HOST_NAME"; else if (i_error==0x80634003L) risultato="PEER_E_NO_MORE"; else if (i_error==0x80634005L) risultato="PEER_E_PNRP_DUPLICATE_PEER_NAME"; else if (i_error==0x80637000L) risultato="PEER_E_INVITE_CANCELLED"; else if (i_error==0x80637001L) risultato="PEER_E_INVITE_RESPONSE_NOT_AVAILABLE"; else if (i_error==0x80637003L) risultato="PEER_E_NOT_SIGNED_IN"; else if (i_error==0x80637004L) risultato="PEER_E_PRIVACY_DECLINED"; else if (i_error==0x80637005L) risultato="PEER_E_TIMEOUT"; else if (i_error==0x80637007L) risultato="PEER_E_INVALID_ADDRESS"; else if (i_error==0x80637008L) risultato="PEER_E_FW_EXCEPTION_DISABLED"; else if (i_error==0x80637009L) risultato="PEER_E_FW_BLOCKED_BY_POLICY"; else if (i_error==0x8063700AL) risultato="PEER_E_FW_BLOCKED_BY_SHIELDS_UP"; else if (i_error==0x8063700BL) risultato="PEER_E_FW_DECLINED"; else if (i_error==0x802A0001L) risultato="UI_E_CREATE_FAILED"; else if (i_error==0x802A0002L) risultato="UI_E_SHUTDOWN_CALLED"; else if (i_error==0x802A0003L) risultato="UI_E_ILLEGAL_REENTRANCY"; else if (i_error==0x802A0004L) risultato="UI_E_OBJECT_SEALED"; else if (i_error==0x802A0005L) risultato="UI_E_VALUE_NOT_SET"; else if (i_error==0x802A0006L) risultato="UI_E_VALUE_NOT_DETERMINED"; else if (i_error==0x802A0007L) risultato="UI_E_INVALID_OUTPUT"; else if (i_error==0x802A0008L) risultato="UI_E_BOOLEAN_EXPECTED"; else if (i_error==0x802A0009L) risultato="UI_E_DIFFERENT_OWNER"; else if (i_error==0x802A000AL) risultato="UI_E_AMBIGUOUS_MATCH"; else if (i_error==0x802A000BL) risultato="UI_E_FP_OVERFLOW"; else if (i_error==0x802A000CL) risultato="UI_E_WRONG_THREAD"; else if (i_error==0x802A0101L) risultato="UI_E_STORYBOARD_ACTIVE"; else if (i_error==0x802A0102L) risultato="UI_E_STORYBOARD_NOT_PLAYING"; else if (i_error==0x802A0103L) risultato="UI_E_START_KEYFRAME_AFTER_END"; else if (i_error==0x802A0104L) risultato="UI_E_END_KEYFRAME_NOT_DETERMINED"; else if (i_error==0x802A0105L) risultato="UI_E_LOOPS_OVERLAP"; else if (i_error==0x802A0106L) risultato="UI_E_TRANSITION_ALREADY_USED"; else if (i_error==0x802A0107L) risultato="UI_E_TRANSITION_NOT_IN_STORYBOARD"; else if (i_error==0x802A0108L) risultato="UI_E_TRANSITION_ECLIPSED"; else if (i_error==0x802A0109L) risultato="UI_E_TIME_BEFORE_LAST_UPDATE"; else if (i_error==0x802A010AL) risultato="UI_E_TIMER_CLIENT_ALREADY_CONNECTED"; else if (i_error==0x802A010BL) risultato="UI_E_INVALID_DIMENSION"; else if (i_error==0x802A010CL) risultato="UI_E_PRIMITIVE_OUT_OF_BOUNDS"; else if (i_error==0x802A0201L) risultato="UI_E_WINDOW_CLOSED"; else if (i_error==0x80650001L) risultato="E_BLUETOOTH_ATT_INVALID_HANDLE"; else if (i_error==0x80650002L) risultato="E_BLUETOOTH_ATT_READ_NOT_PERMITTED"; else if (i_error==0x80650003L) risultato="E_BLUETOOTH_ATT_WRITE_NOT_PERMITTED"; else if (i_error==0x80650004L) risultato="E_BLUETOOTH_ATT_INVALID_PDU"; else if (i_error==0x80650005L) risultato="E_BLUETOOTH_ATT_INSUFFICIENT_AUTHENTICATION"; else if (i_error==0x80650006L) risultato="E_BLUETOOTH_ATT_REQUEST_NOT_SUPPORTED"; else if (i_error==0x80650007L) risultato="E_BLUETOOTH_ATT_INVALID_OFFSET"; else if (i_error==0x80650008L) risultato="E_BLUETOOTH_ATT_INSUFFICIENT_AUTHORIZATION"; else if (i_error==0x80650009L) risultato="E_BLUETOOTH_ATT_PREPARE_QUEUE_FULL"; else if (i_error==0x8065000AL) risultato="E_BLUETOOTH_ATT_ATTRIBUTE_NOT_FOUND"; else if (i_error==0x8065000BL) risultato="E_BLUETOOTH_ATT_ATTRIBUTE_NOT_LONG"; else if (i_error==0x8065000CL) risultato="E_BLUETOOTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE"; else if (i_error==0x8065000DL) risultato="E_BLUETOOTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH"; else if (i_error==0x8065000EL) risultato="E_BLUETOOTH_ATT_UNLIKELY"; else if (i_error==0x8065000FL) risultato="E_BLUETOOTH_ATT_INSUFFICIENT_ENCRYPTION"; else if (i_error==0x80650010L) risultato="E_BLUETOOTH_ATT_UNSUPPORTED_GROUP_TYPE"; else if (i_error==0x80650011L) risultato="E_BLUETOOTH_ATT_INSUFFICIENT_RESOURCES"; else if (i_error==0x80651000L) risultato="E_BLUETOOTH_ATT_UNKNOWN_ERROR"; else if (i_error==0x80660001L) risultato="E_AUDIO_ENGINE_NODE_NOT_FOUND"; else if (i_error==0x80660002L) risultato="E_HDAUDIO_EMPTY_CONNECTION_LIST"; else if (i_error==0x80660003L) risultato="E_HDAUDIO_CONNECTION_LISTNOT_SUPPORTED"; else if (i_error==0x80660004L) risultato="E_HDAUDIO_NO_LOGICAL_DEVICES_CREATED"; else if (i_error==0x80660005L) risultato="E_HDAUDIO_NULL_LINKED_LISTENTRY"; else if (i_error==0x80670001L) risultato="STATEREPOSITORY_E_CONCURRENCY_LOCKING_FAILURE"; else if (i_error==0x80670002L) risultato="STATEREPOSITORY_E_STATEMENT_INPROGRESS"; else if (i_error==0x80670003L) risultato="STATEREPOSITORY_E_CONFIGURATION_INVALID"; else if (i_error==0x80670004L) risultato="STATEREPOSITORY_E_UNKNOWN_SCHEMA_VERSION"; else if (i_error==0x80670005L) risultato="STATEREPOSITORY_ERROR_DICTIONARY_CORRUPTED"; else if (i_error==0x80670006L) risultato="STATEREPOSITORY_E_BLOCKED"; else if (i_error==0x80670007L) risultato="STATEREPOSITORY_E_BUSY_RETRY"; else if (i_error==0x80670008L) risultato="STATEREPOSITORY_E_BUSY_RECOVERY_RETRY"; else if (i_error==0x80670009L) risultato="STATEREPOSITORY_E_LOCKED_RETRY"; else if (i_error==0x8067000AL) risultato="STATEREPOSITORY_E_LOCKED_SHAREDCACHE_RETRY"; else if (i_error==0x8067000BL) risultato="STATEREPOSITORY_E_TRANSACTION_REQUIRED"; else if (i_error==0x00E70001L) risultato="ERROR_SPACES_POOL_WAS_DELETED"; else if (i_error==0x80E70001L) risultato="ERROR_SPACES_FAULT_DOMAIN_TYPE_INVALID"; else if (i_error==0x80E70002L) risultato="ERROR_SPACES_INTERNAL_ERROR"; else if (i_error==0x80E70003L) risultato="ERROR_SPACES_RESILIENCY_TYPE_INVALID"; else if (i_error==0x80E70004L) risultato="ERROR_SPACES_DRIVE_SECTOR_SIZE_INVALID"; else if (i_error==0x80E70006L) risultato="ERROR_SPACES_DRIVE_REDUNDANCY_INVALID"; else if (i_error==0x80E70007L) risultato="ERROR_SPACES_NUMBER_OF_DATA_COPIES_INVALID"; else if (i_error==0x80E70008L) risultato="ERROR_SPACES_PARITY_LAYOUT_INVALID"; else if (i_error==0x80E70009L) risultato="ERROR_SPACES_INTERLEAVE_LENGTH_INVALID"; else if (i_error==0x80E7000AL) risultato="ERROR_SPACES_NUMBER_OF_COLUMNS_INVALID"; else if (i_error==0x80E7000BL) risultato="ERROR_SPACES_NOT_ENOUGH_DRIVES"; else if (i_error==0x80E7000CL) risultato="ERROR_SPACES_EXTENDED_ERROR"; else if (i_error==0x80E7000DL) risultato="ERROR_SPACES_PROVISIONING_TYPE_INVALID"; else if (i_error==0x80E7000EL) risultato="ERROR_SPACES_ALLOCATION_SIZE_INVALID"; else if (i_error==0x80E7000FL) risultato="ERROR_SPACES_ENCLOSURE_AWARE_INVALID"; else if (i_error==0x80E70010L) risultato="ERROR_SPACES_WRITE_CACHE_SIZE_INVALID"; else if (i_error==0x80E70011L) risultato="ERROR_SPACES_NUMBER_OF_GROUPS_INVALID"; else if (i_error==0x80E70012L) risultato="ERROR_SPACES_DRIVE_OPERATIONAL_STATE_INVALID"; else if (i_error==0x80820001L) risultato="ERROR_VOLSNAP_BOOTFILE_NOT_VALID"; else if (i_error==0x80820002L) risultato="ERROR_VOLSNAP_ACTIVATION_TIMEOUT"; else if (i_error==0x80830001L) risultato="ERROR_TIERING_NOT_SUPPORTED_ON_VOLUME"; else if (i_error==0x80830002L) risultato="ERROR_TIERING_VOLUME_DISMOUNT_IN_PROGRESS"; else if (i_error==0x80830003L) risultato="ERROR_TIERING_STORAGE_TIER_NOT_FOUND"; else if (i_error==0x80830004L) risultato="ERROR_TIERING_INVALID_FILE_ID"; else if (i_error==0x80830005L) risultato="ERROR_TIERING_WRONG_CLUSTER_NODE"; else if (i_error==0x80830006L) risultato="ERROR_TIERING_ALREADY_PROCESSING"; else if (i_error==0x80830007L) risultato="ERROR_TIERING_CANNOT_PIN_OBJECT"; else if (i_error==0xC0E80000L) risultato="ERROR_SECCORE_INVALID_COMMAND"; else if (i_error==0xC0EA0001L) risultato="ERROR_NO_APPLICABLE_APP_LICENSES_FOUND"; else if (i_error==0xC0EA0002L) risultato="ERROR_CLIP_LICENSE_NOT_FOUND"; else if (i_error==0xC0EA0003L) risultato="ERROR_CLIP_DEVICE_LICENSE_MISSING"; else if (i_error==0xC0EA0004L) risultato="ERROR_CLIP_LICENSE_INVALID_SIGNATURE"; else if (i_error==0xC0EA0005L) risultato="ERROR_CLIP_KEYHOLDER_LICENSE_MISSING_OR_INVALID"; else if (i_error==0xC0EA0006L) risultato="ERROR_CLIP_LICENSE_EXPIRED"; else if (i_error==0xC0EA0007L) risultato="ERROR_CLIP_LICENSE_SIGNED_BY_UNKNOWN_SOURCE"; else if (i_error==0xC0EA0008L) risultato="ERROR_CLIP_LICENSE_NOT_SIGNED"; else if (i_error==0xC0EA0009L) risultato="ERROR_CLIP_LICENSE_HARDWARE_ID_OUT_OF_TOLERANCE"; else if (i_error==0xC0EA000AL) risultato="ERROR_CLIP_LICENSE_DEVICE_ID_MISMATCH"; else if (i_error==0x087A0001L) risultato="DXGI_STATUS_OCCLUDED"; else if (i_error==0x087A0002L) risultato="DXGI_STATUS_CLIPPED"; else if (i_error==0x087A0004L) risultato="DXGI_STATUS_NO_REDIRECTION"; else if (i_error==0x087A0005L) risultato="DXGI_STATUS_NO_DESKTOP_ACCESS"; else if (i_error==0x087A0006L) risultato="DXGI_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE"; else if (i_error==0x087A0007L) risultato="DXGI_STATUS_MODE_CHANGED"; else if (i_error==0x087A0008L) risultato="DXGI_STATUS_MODE_CHANGE_IN_PROGRESS"; else if (i_error==0x887A0001L) risultato="DXGI_ERROR_INVALID_CALL"; else if (i_error==0x887A0002L) risultato="DXGI_ERROR_NOT_FOUND"; else if (i_error==0x887A0003L) risultato="DXGI_ERROR_MORE_DATA"; else if (i_error==0x887A0004L) risultato="DXGI_ERROR_UNSUPPORTED"; else if (i_error==0x887A0005L) risultato="DXGI_ERROR_DEVICE_REMOVED"; else if (i_error==0x887A0006L) risultato="DXGI_ERROR_DEVICE_HUNG"; else if (i_error==0x887A0007L) risultato="DXGI_ERROR_DEVICE_RESET"; else if (i_error==0x887A000AL) risultato="DXGI_ERROR_WAS_STILL_DRAWING"; else if (i_error==0x887A000BL) risultato="DXGI_ERROR_FRAME_STATISTICS_DISJOINT"; else if (i_error==0x887A000CL) risultato="DXGI_ERROR_GRAPHICS_VIDPN_SOURCE_IN_USE"; else if (i_error==0x887A0020L) risultato="DXGI_ERROR_DRIVER_INTERNAL_ERROR"; else if (i_error==0x887A0021L) risultato="DXGI_ERROR_NONEXCLUSIVE"; else if (i_error==0x887A0022L) risultato="DXGI_ERROR_NOT_CURRENTLY_AVAILABLE"; else if (i_error==0x887A0023L) risultato="DXGI_ERROR_REMOTE_CLIENT_DISCONNECTED"; else if (i_error==0x887A0024L) risultato="DXGI_ERROR_REMOTE_OUTOFMEMORY"; else if (i_error==0x887A0026L) risultato="DXGI_ERROR_ACCESS_LOST"; else if (i_error==0x887A0027L) risultato="DXGI_ERROR_WAIT_TIMEOUT"; else if (i_error==0x887A0028L) risultato="DXGI_ERROR_SESSION_DISCONNECTED"; else if (i_error==0x887A0029L) risultato="DXGI_ERROR_RESTRICT_TO_OUTPUT_STALE"; else if (i_error==0x887A002AL) risultato="DXGI_ERROR_CANNOT_PROTECT_CONTENT"; else if (i_error==0x887A002BL) risultato="DXGI_ERROR_ACCESS_DENIED"; else if (i_error==0x887A002CL) risultato="DXGI_ERROR_NAME_ALREADY_EXISTS"; else if (i_error==0x887A002DL) risultato="DXGI_ERROR_SDK_COMPONENT_MISSING"; else if (i_error==0x887A002EL) risultato="DXGI_ERROR_NOT_CURRENT"; else if (i_error==0x887A0030L) risultato="DXGI_ERROR_HW_PROTECTION_OUTOFMEMORY"; else if (i_error==0x087A0009L) risultato="DXGI_STATUS_UNOCCLUDED"; else if (i_error==0x087A000AL) risultato="DXGI_STATUS_DDA_WAS_STILL_DRAWING"; else if (i_error==0x887A0025L) risultato="DXGI_ERROR_MODE_CHANGE_IN_PROGRESS"; else if (i_error==0x087A002FL) risultato="DXGI_STATUS_PRESENT_REQUIRED"; else if (i_error==0x887B0001L) risultato="DXGI_DDI_ERR_WASSTILLDRAWING"; else if (i_error==0x887B0002L) risultato="DXGI_DDI_ERR_UNSUPPORTED"; else if (i_error==0x887B0003L) risultato="DXGI_DDI_ERR_NONEXCLUSIVE"; else if (i_error==0x88790001L) risultato="D3D10_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS"; else if (i_error==0x88790002L) risultato="D3D10_ERROR_FILE_NOT_FOUND"; else if (i_error==0x887C0001L) risultato="D3D11_ERROR_TOO_MANY_UNIQUE_STATE_OBJECTS"; else if (i_error==0x887C0002L) risultato="D3D11_ERROR_FILE_NOT_FOUND"; else if (i_error==0x887C0003L) risultato="D3D11_ERROR_TOO_MANY_UNIQUE_VIEW_OBJECTS"; else if (i_error==0x887C0004L) risultato="D3D11_ERROR_DEFERRED_CONTEXT_MAP_WITHOUT_INITIAL_DISCARD"; else if (i_error==0x887E0001L) risultato="D3D12_ERROR_ADAPTER_NOT_FOUND"; else if (i_error==0x887E0002L) risultato="D3D12_ERROR_DRIVER_VERSION_MISMATCH"; else if (i_error==0x88990001L) risultato="D2DERR_WRONG_STATE"; else if (i_error==0x88990002L) risultato="D2DERR_NOT_INITIALIZED"; else if (i_error==0x88990003L) risultato="D2DERR_UNSUPPORTED_OPERATION"; else if (i_error==0x88990004L) risultato="D2DERR_SCANNER_FAILED"; else if (i_error==0x88990005L) risultato="D2DERR_SCREEN_ACCESS_DENIED"; else if (i_error==0x88990006L) risultato="D2DERR_DISPLAY_STATE_INVALID"; else if (i_error==0x88990007L) risultato="D2DERR_ZERO_VECTOR"; else if (i_error==0x88990008L) risultato="D2DERR_INTERNAL_ERROR"; else if (i_error==0x88990009L) risultato="D2DERR_DISPLAY_FORMAT_NOT_SUPPORTED"; else if (i_error==0x8899000AL) risultato="D2DERR_INVALID_CALL"; else if (i_error==0x8899000BL) risultato="D2DERR_NO_HARDWARE_DEVICE"; else if (i_error==0x8899000CL) risultato="D2DERR_RECREATE_TARGET"; else if (i_error==0x8899000DL) risultato="D2DERR_TOO_MANY_SHADER_ELEMENTS"; else if (i_error==0x8899000EL) risultato="D2DERR_SHADER_COMPILE_FAILED"; else if (i_error==0x8899000FL) risultato="D2DERR_MAX_TEXTURE_SIZE_EXCEEDED"; else if (i_error==0x88990010L) risultato="D2DERR_UNSUPPORTED_VERSION"; else if (i_error==0x88990011L) risultato="D2DERR_BAD_NUMBER"; else if (i_error==0x88990012L) risultato="D2DERR_WRONG_FACTORY"; else if (i_error==0x88990013L) risultato="D2DERR_LAYER_ALREADY_IN_USE"; else if (i_error==0x88990014L) risultato="D2DERR_POP_CALL_DID_NOT_MATCH_PUSH"; else if (i_error==0x88990015L) risultato="D2DERR_WRONG_RESOURCE_DOMAIN"; else if (i_error==0x88990016L) risultato="D2DERR_PUSH_POP_UNBALANCED"; else if (i_error==0x88990017L) risultato="D2DERR_RENDER_TARGET_HAS_LAYER_OR_CLIPRECT"; else if (i_error==0x88990018L) risultato="D2DERR_INCOMPATIBLE_BRUSH_TYPES"; else if (i_error==0x88990019L) risultato="D2DERR_WIN32_ERROR"; else if (i_error==0x8899001AL) risultato="D2DERR_TARGET_NOT_GDI_COMPATIBLE"; else if (i_error==0x8899001BL) risultato="D2DERR_TEXT_EFFECT_IS_WRONG_TYPE"; else if (i_error==0x8899001CL) risultato="D2DERR_TEXT_RENDERER_NOT_RELEASED"; else if (i_error==0x8899001DL) risultato="D2DERR_EXCEEDS_MAX_BITMAP_SIZE"; else if (i_error==0x8899001EL) risultato="D2DERR_INVALID_GRAPH_CONFIGURATION"; else if (i_error==0x8899001FL) risultato="D2DERR_INVALID_INTERNAL_GRAPH_CONFIGURATION"; else if (i_error==0x88990020L) risultato="D2DERR_CYCLIC_GRAPH"; else if (i_error==0x88990021L) risultato="D2DERR_BITMAP_CANNOT_DRAW"; else if (i_error==0x88990022L) risultato="D2DERR_OUTSTANDING_BITMAP_REFERENCES"; else if (i_error==0x88990023L) risultato="D2DERR_ORIGINAL_TARGET_NOT_BOUND"; else if (i_error==0x88990024L) risultato="D2DERR_INVALID_TARGET"; else if (i_error==0x88990025L) risultato="D2DERR_BITMAP_BOUND_AS_TARGET"; else if (i_error==0x88990026L) risultato="D2DERR_INSUFFICIENT_DEVICE_CAPABILITIES"; else if (i_error==0x88990027L) risultato="D2DERR_INTERMEDIATE_TOO_LARGE"; else if (i_error==0x88990028L) risultato="D2DERR_EFFECT_IS_NOT_REGISTERED"; else if (i_error==0x88990029L) risultato="D2DERR_INVALID_PROPERTY"; else if (i_error==0x8899002AL) risultato="D2DERR_NO_SUBPROPERTIES"; else if (i_error==0x8899002BL) risultato="D2DERR_PRINT_JOB_CLOSED"; else if (i_error==0x8899002CL) risultato="D2DERR_PRINT_FORMAT_NOT_SUPPORTED"; else if (i_error==0x8899002DL) risultato="D2DERR_TOO_MANY_TRANSFORM_INPUTS"; else if (i_error==0x8899002EL) risultato="D2DERR_INVALID_GLYPH_IMAGE"; else if (i_error==0x88985000L) risultato="DWRITE_E_FILEFORMAT"; else if (i_error==0x88985001L) risultato="DWRITE_E_UNEXPECTED"; else if (i_error==0x88985002L) risultato="DWRITE_E_NOFONT"; else if (i_error==0x88985003L) risultato="DWRITE_E_FILENOTFOUND"; else if (i_error==0x88985004L) risultato="DWRITE_E_FILEACCESS"; else if (i_error==0x88985005L) risultato="DWRITE_E_FONTCOLLECTIONOBSOLETE"; else if (i_error==0x88985006L) risultato="DWRITE_E_ALREADYREGISTERED"; else if (i_error==0x88985007L) risultato="DWRITE_E_CACHEFORMAT"; else if (i_error==0x88985008L) risultato="DWRITE_E_CACHEVERSION"; else if (i_error==0x88985009L) risultato="DWRITE_E_UNSUPPORTEDOPERATION"; else if (i_error==0x8898500AL) risultato="DWRITE_E_TEXTRENDERERINCOMPATIBLE"; else if (i_error==0x8898500BL) risultato="DWRITE_E_FLOWDIRECTIONCONFLICTS"; else if (i_error==0x8898500CL) risultato="DWRITE_E_NOCOLOR"; else if (i_error==0x88982F04L) risultato="WINCODEC_ERR_WRONGSTATE"; else if (i_error==0x88982F05L) risultato="WINCODEC_ERR_VALUEOUTOFRANGE"; else if (i_error==0x88982F07L) risultato="WINCODEC_ERR_UNKNOWNIMAGEFORMAT"; else if (i_error==0x88982F0BL) risultato="WINCODEC_ERR_UNSUPPORTEDVERSION"; else if (i_error==0x88982F0CL) risultato="WINCODEC_ERR_NOTINITIALIZED"; else if (i_error==0x88982F0DL) risultato="WINCODEC_ERR_ALREADYLOCKED"; else if (i_error==0x88982F40L) risultato="WINCODEC_ERR_PROPERTYNOTFOUND"; else if (i_error==0x88982F41L) risultato="WINCODEC_ERR_PROPERTYNOTSUPPORTED"; else if (i_error==0x88982F42L) risultato="WINCODEC_ERR_PROPERTYSIZE"; else if (i_error==0x88982F43L) risultato="WINCODEC_ERR_CODECPRESENT"; else if (i_error==0x88982F44L) risultato="WINCODEC_ERR_CODECNOTHUMBNAIL"; else if (i_error==0x88982F45L) risultato="WINCODEC_ERR_PALETTEUNAVAILABLE"; else if (i_error==0x88982F46L) risultato="WINCODEC_ERR_CODECTOOMANYSCANLINES"; else if (i_error==0x88982F48L) risultato="WINCODEC_ERR_INTERNALERROR"; else if (i_error==0x88982F49L) risultato="WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS"; else if (i_error==0x88982F50L) risultato="WINCODEC_ERR_COMPONENTNOTFOUND"; else if (i_error==0x88982F51L) risultato="WINCODEC_ERR_IMAGESIZEOUTOFRANGE"; else if (i_error==0x88982F52L) risultato="WINCODEC_ERR_TOOMUCHMETADATA"; else if (i_error==0x88982F60L) risultato="WINCODEC_ERR_BADIMAGE"; else if (i_error==0x88982F61L) risultato="WINCODEC_ERR_BADHEADER"; else if (i_error==0x88982F62L) risultato="WINCODEC_ERR_FRAMEMISSING"; else if (i_error==0x88982F63L) risultato="WINCODEC_ERR_BADMETADATAHEADER"; else if (i_error==0x88982F70L) risultato="WINCODEC_ERR_BADSTREAMDATA"; else if (i_error==0x88982F71L) risultato="WINCODEC_ERR_STREAMWRITE"; else if (i_error==0x88982F72L) risultato="WINCODEC_ERR_STREAMREAD"; else if (i_error==0x88982F73L) risultato="WINCODEC_ERR_STREAMNOTAVAILABLE"; else if (i_error==0x88982F80L) risultato="WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT"; else if (i_error==0x88982F81L) risultato="WINCODEC_ERR_UNSUPPORTEDOPERATION"; else if (i_error==0x88982F8AL) risultato="WINCODEC_ERR_INVALIDREGISTRATION"; else if (i_error==0x88982F8BL) risultato="WINCODEC_ERR_COMPONENTINITIALIZEFAILURE"; else if (i_error==0x88982F8CL) risultato="WINCODEC_ERR_INSUFFICIENTBUFFER"; else if (i_error==0x88982F8DL) risultato="WINCODEC_ERR_DUPLICATEMETADATAPRESENT"; else if (i_error==0x88982F8EL) risultato="WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE"; else if (i_error==0x88982F8FL) risultato="WINCODEC_ERR_UNEXPECTEDSIZE"; else if (i_error==0x88982F90L) risultato="WINCODEC_ERR_INVALIDQUERYREQUEST"; else if (i_error==0x88982F91L) risultato="WINCODEC_ERR_UNEXPECTEDMETADATATYPE"; else if (i_error==0x88982F92L) risultato="WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT"; else if (i_error==0x88982F93L) risultato="WINCODEC_ERR_INVALIDQUERYCHARACTER"; else if (i_error==0x88982F94L) risultato="WINCODEC_ERR_WIN32ERROR"; else if (i_error==0x88982F95L) risultato="WINCODEC_ERR_INVALIDPROGRESSIVELEVEL"; else if (i_error==0x88982F96L) risultato="WINCODEC_ERR_INVALIDJPEGSCANINDEX"; else if (i_error==0x88980001L) risultato="MILERR_OBJECTBUSY"; else if (i_error==0x88980002L) risultato="MILERR_INSUFFICIENTBUFFER"; else if (i_error==0x88980003L) risultato="MILERR_WIN32ERROR"; else if (i_error==0x88980004L) risultato="MILERR_SCANNER_FAILED"; else if (i_error==0x88980005L) risultato="MILERR_SCREENACCESSDENIED"; else if (i_error==0x88980006L) risultato="MILERR_DISPLAYSTATEINVALID"; else if (i_error==0x88980007L) risultato="MILERR_NONINVERTIBLEMATRIX"; else if (i_error==0x88980008L) risultato="MILERR_ZEROVECTOR"; else if (i_error==0x88980009L) risultato="MILERR_TERMINATED"; else if (i_error==0x8898000AL) risultato="MILERR_BADNUMBER"; else if (i_error==0x88980080L) risultato="MILERR_INTERNALERROR"; else if (i_error==0x88980084L) risultato="MILERR_DISPLAYFORMATNOTSUPPORTED"; else if (i_error==0x88980085L) risultato="MILERR_INVALIDCALL"; else if (i_error==0x88980086L) risultato="MILERR_ALREADYLOCKED"; else if (i_error==0x88980087L) risultato="MILERR_NOTLOCKED"; else if (i_error==0x88980088L) risultato="MILERR_DEVICECANNOTRENDERTEXT"; else if (i_error==0x88980089L) risultato="MILERR_GLYPHBITMAPMISSED"; else if (i_error==0x8898008AL) risultato="MILERR_MALFORMEDGLYPHCACHE"; else if (i_error==0x8898008BL) risultato="MILERR_GENERIC_IGNORE"; else if (i_error==0x8898008CL) risultato="MILERR_MALFORMED_GUIDELINE_DATA"; else if (i_error==0x8898008DL) risultato="MILERR_NO_HARDWARE_DEVICE"; else if (i_error==0x8898008EL) risultato="MILERR_NEED_RECREATE_AND_PRESENT"; else if (i_error==0x8898008FL) risultato="MILERR_ALREADY_INITIALIZED"; else if (i_error==0x88980090L) risultato="MILERR_MISMATCHED_SIZE"; else if (i_error==0x88980091L) risultato="MILERR_NO_REDIRECTION_SURFACE_AVAILABLE"; else if (i_error==0x88980092L) risultato="MILERR_REMOTING_NOT_SUPPORTED"; else if (i_error==0x88980093L) risultato="MILERR_QUEUED_PRESENT_NOT_SUPPORTED"; else if (i_error==0x88980094L) risultato="MILERR_NOT_QUEUING_PRESENTS"; else if (i_error==0x88980095L) risultato="MILERR_NO_REDIRECTION_SURFACE_RETRY_LATER"; else if (i_error==0x88980096L) risultato="MILERR_TOOMANYSHADERELEMNTS"; else if (i_error==0x88980097L) risultato="MILERR_MROW_READLOCK_FAILED"; else if (i_error==0x88980098L) risultato="MILERR_MROW_UPDATE_FAILED"; else if (i_error==0x88980099L) risultato="MILERR_SHADER_COMPILE_FAILED"; else if (i_error==0x8898009AL) risultato="MILERR_MAX_TEXTURE_SIZE_EXCEEDED"; else if (i_error==0x8898009BL) risultato="MILERR_QPC_TIME_WENT_BACKWARD"; else if (i_error==0x8898009DL) risultato="MILERR_DXGI_ENUMERATION_OUT_OF_SYNC"; else if (i_error==0x8898009EL) risultato="MILERR_ADAPTER_NOT_FOUND"; else if (i_error==0x8898009FL) risultato="MILERR_COLORSPACE_NOT_SUPPORTED"; else if (i_error==0x889800A0L) risultato="MILERR_PREFILTER_NOT_SUPPORTED"; else if (i_error==0x889800A1L) risultato="MILERR_DISPLAYID_ACCESS_DENIED"; else if (i_error==0x88980400L) risultato="UCEERR_INVALIDPACKETHEADER"; else if (i_error==0x88980401L) risultato="UCEERR_UNKNOWNPACKET"; else if (i_error==0x88980402L) risultato="UCEERR_ILLEGALPACKET"; else if (i_error==0x88980403L) risultato="UCEERR_MALFORMEDPACKET"; else if (i_error==0x88980404L) risultato="UCEERR_ILLEGALHANDLE"; else if (i_error==0x88980405L) risultato="UCEERR_HANDLELOOKUPFAILED"; else if (i_error==0x88980406L) risultato="UCEERR_RENDERTHREADFAILURE"; else if (i_error==0x88980407L) risultato="UCEERR_CTXSTACKFRSTTARGETNULL"; else if (i_error==0x88980408L) risultato="UCEERR_CONNECTIONIDLOOKUPFAILED"; else if (i_error==0x88980409L) risultato="UCEERR_BLOCKSFULL"; else if (i_error==0x8898040AL) risultato="UCEERR_MEMORYFAILURE"; else if (i_error==0x8898040BL) risultato="UCEERR_PACKETRECORDOUTOFRANGE"; else if (i_error==0x8898040CL) risultato="UCEERR_ILLEGALRECORDTYPE"; else if (i_error==0x8898040DL) risultato="UCEERR_OUTOFHANDLES"; else if (i_error==0x8898040EL) risultato="UCEERR_UNCHANGABLE_UPDATE_ATTEMPTED"; else if (i_error==0x8898040FL) risultato="UCEERR_NO_MULTIPLE_WORKER_THREADS"; else if (i_error==0x88980410L) risultato="UCEERR_REMOTINGNOTSUPPORTED"; else if (i_error==0x88980411L) risultato="UCEERR_MISSINGENDCOMMAND"; else if (i_error==0x88980412L) risultato="UCEERR_MISSINGBEGINCOMMAND"; else if (i_error==0x88980413L) risultato="UCEERR_CHANNELSYNCTIMEDOUT"; else if (i_error==0x88980414L) risultato="UCEERR_CHANNELSYNCABANDONED"; else if (i_error==0x88980415L) risultato="UCEERR_UNSUPPORTEDTRANSPORTVERSION"; else if (i_error==0x88980416L) risultato="UCEERR_TRANSPORTUNAVAILABLE"; else if (i_error==0x88980417L) risultato="UCEERR_FEEDBACK_UNSUPPORTED"; else if (i_error==0x88980418L) risultato="UCEERR_COMMANDTRANSPORTDENIED"; else if (i_error==0x88980419L) risultato="UCEERR_GRAPHICSSTREAMUNAVAILABLE"; else if (i_error==0x88980420L) risultato="UCEERR_GRAPHICSSTREAMALREADYOPEN"; else if (i_error==0x88980421L) risultato="UCEERR_TRANSPORTDISCONNECTED"; else if (i_error==0x88980422L) risultato="UCEERR_TRANSPORTOVERLOADED"; else if (i_error==0x88980423L) risultato="UCEERR_PARTITION_ZOMBIED"; else if (i_error==0x88980500L) risultato="MILAVERR_NOCLOCK"; else if (i_error==0x88980501L) risultato="MILAVERR_NOMEDIATYPE"; else if (i_error==0x88980502L) risultato="MILAVERR_NOVIDEOMIXER"; else if (i_error==0x88980503L) risultato="MILAVERR_NOVIDEOPRESENTER"; else if (i_error==0x88980504L) risultato="MILAVERR_NOREADYFRAMES"; else if (i_error==0x88980505L) risultato="MILAVERR_MODULENOTLOADED"; else if (i_error==0x88980506L) risultato="MILAVERR_WMPFACTORYNOTREGISTERED"; else if (i_error==0x88980507L) risultato="MILAVERR_INVALIDWMPVERSION"; else if (i_error==0x88980508L) risultato="MILAVERR_INSUFFICIENTVIDEORESOURCES"; else if (i_error==0x88980509L) risultato="MILAVERR_VIDEOACCELERATIONNOTAVAILABLE"; else if (i_error==0x8898050AL) risultato="MILAVERR_REQUESTEDTEXTURETOOBIG"; else if (i_error==0x8898050BL) risultato="MILAVERR_SEEKFAILED"; else if (i_error==0x8898050CL) risultato="MILAVERR_UNEXPECTEDWMPFAILURE"; else if (i_error==0x8898050DL) risultato="MILAVERR_MEDIAPLAYERCLOSED"; else if (i_error==0x8898050EL) risultato="MILAVERR_UNKNOWNHARDWAREERROR"; else if (i_error==0x8898060EL) risultato="MILEFFECTSERR_UNKNOWNPROPERTY"; else if (i_error==0x8898060FL) risultato="MILEFFECTSERR_EFFECTNOTPARTOFGROUP"; else if (i_error==0x88980610L) risultato="MILEFFECTSERR_NOINPUTSOURCEATTACHED"; else if (i_error==0x88980611L) risultato="MILEFFECTSERR_CONNECTORNOTCONNECTED"; else if (i_error==0x88980612L) risultato="MILEFFECTSERR_CONNECTORNOTASSOCIATEDWITHEFFECT"; else if (i_error==0x88980613L) risultato="MILEFFECTSERR_RESERVED"; else if (i_error==0x88980614L) risultato="MILEFFECTSERR_CYCLEDETECTED"; else if (i_error==0x88980615L) risultato="MILEFFECTSERR_EFFECTINMORETHANONEGRAPH"; else if (i_error==0x88980616L) risultato="MILEFFECTSERR_EFFECTALREADYINAGRAPH"; else if (i_error==0x88980617L) risultato="MILEFFECTSERR_EFFECTHASNOCHILDREN"; else if (i_error==0x88980618L) risultato="MILEFFECTSERR_ALREADYATTACHEDTOLISTENER"; else if (i_error==0x88980619L) risultato="MILEFFECTSERR_NOTAFFINETRANSFORM"; else if (i_error==0x8898061AL) risultato="MILEFFECTSERR_EMPTYBOUNDS"; else if (i_error==0x8898061BL) risultato="MILEFFECTSERR_OUTPUTSIZETOOLARGE"; else if (i_error==0x88980700L) risultato="DWMERR_STATE_TRANSITION_FAILED"; else if (i_error==0x88980701L) risultato="DWMERR_THEME_FAILED"; else if (i_error==0x88980702L) risultato="DWMERR_CATASTROPHIC_FAILURE"; else if (i_error==0x88980800L) risultato="DCOMPOSITION_ERROR_WINDOW_ALREADY_COMPOSED"; else if (i_error==0x88980801L) risultato="DCOMPOSITION_ERROR_SURFACE_BEING_RENDERED"; else if (i_error==0x88980802L) risultato="DCOMPOSITION_ERROR_SURFACE_NOT_BEING_RENDERED"; else if (i_error==0x80860001L) risultato="ONL_E_INVALID_AUTHENTICATION_TARGET"; else if (i_error==0x80860002L) risultato="ONL_E_ACCESS_DENIED_BY_TOU"; else if (i_error==0x80860003L) risultato="ONL_E_INVALID_APPLICATION"; else if (i_error==0x80860004L) risultato="ONL_E_PASSWORD_UPDATE_REQUIRED"; else if (i_error==0x80860005L) risultato="ONL_E_ACCOUNT_UPDATE_REQUIRED"; else if (i_error==0x80860006L) risultato="ONL_E_FORCESIGNIN"; else if (i_error==0x80860007L) risultato="ONL_E_ACCOUNT_LOCKED"; else if (i_error==0x80860008L) risultato="ONL_E_PARENTAL_CONSENT_REQUIRED"; else if (i_error==0x80860009L) risultato="ONL_E_EMAIL_VERIFICATION_REQUIRED"; else if (i_error==0x8086000AL) risultato="ONL_E_ACCOUNT_SUSPENDED_COMPROIMISE"; else if (i_error==0x8086000BL) risultato="ONL_E_ACCOUNT_SUSPENDED_ABUSE"; else if (i_error==0x8086000CL) risultato="ONL_E_ACTION_REQUIRED"; else if (i_error==0x8086000DL) risultato="ONL_CONNECTION_COUNT_LIMIT"; else if (i_error==0x8086000EL) risultato="ONL_E_CONNECTED_ACCOUNT_CAN_NOT_SIGNOUT"; else if (i_error==0x8086000FL) risultato="ONL_E_USER_AUTHENTICATION_REQUIRED"; else if (i_error==0x80860010L) risultato="ONL_E_REQUEST_THROTTLED"; else if (i_error==0x80270220L) risultato="FA_E_MAX_PERSISTED_ITEMS_REACHED"; else if (i_error==0x80270222L) risultato="FA_E_HOMEGROUP_NOT_AVAILABLE"; else if (i_error==0x80270250L) risultato="E_MONITOR_RESOLUTION_TOO_LOW"; else if (i_error==0x80270251L) risultato="E_ELEVATED_ACTIVATION_NOT_SUPPORTED"; else if (i_error==0x80270252L) risultato="E_UAC_DISABLED"; else if (i_error==0x80270253L) risultato="E_FULL_ADMIN_NOT_SUPPORTED"; else if (i_error==0x80270254L) risultato="E_APPLICATION_NOT_REGISTERED"; else if (i_error==0x80270255L) risultato="E_MULTIPLE_EXTENSIONS_FOR_APPLICATION"; else if (i_error==0x80270256L) risultato="E_MULTIPLE_PACKAGES_FOR_FAMILY"; else if (i_error==0x80270257L) risultato="E_APPLICATION_MANAGER_NOT_RUNNING"; else if (i_error==0x00270258L) risultato="S_STORE_LAUNCHED_FOR_REMEDIATION"; else if (i_error==0x00270259L) risultato="S_APPLICATION_ACTIVATION_ERROR_HANDLED_BY_DIALOG"; else if (i_error==0x8027025AL) risultato="E_APPLICATION_ACTIVATION_TIMED_OUT"; else if (i_error==0x8027025BL) risultato="E_APPLICATION_ACTIVATION_EXEC_FAILURE"; else if (i_error==0x8027025CL) risultato="E_APPLICATION_TEMPORARY_LICENSE_ERROR"; else if (i_error==0x8027025DL) risultato="E_APPLICATION_TRIAL_LICENSE_EXPIRED"; else if (i_error==0x80270260L) risultato="E_SKYDRIVE_ROOT_TARGET_FILE_SYSTEM_NOT_SUPPORTED"; else if (i_error==0x80270261L) risultato="E_SKYDRIVE_ROOT_TARGET_OVERLAP"; else if (i_error==0x80270262L) risultato="E_SKYDRIVE_ROOT_TARGET_CANNOT_INDEX"; else if (i_error==0x80270263L) risultato="E_SKYDRIVE_FILE_NOT_UPLOADED"; else if (i_error==0x80270264L) risultato="E_SKYDRIVE_UPDATE_AVAILABILITY_FAIL"; else if (i_error==0x80270265L) risultato="E_SKYDRIVE_ROOT_TARGET_VOLUME_ROOT_NOT_SUPPORTED"; else if (i_error==0x8802B001L) risultato="E_SYNCENGINE_FILE_SIZE_OVER_LIMIT"; else if (i_error==0x8802B002L) risultato="E_SYNCENGINE_FILE_SIZE_EXCEEDS_REMAINING_QUOTA"; else if (i_error==0x8802B003L) risultato="E_SYNCENGINE_UNSUPPORTED_FILE_NAME"; else if (i_error==0x8802B004L) risultato="E_SYNCENGINE_FOLDER_ITEM_COUNT_LIMIT_EXCEEDED"; else if (i_error==0x8802B005L) risultato="E_SYNCENGINE_FILE_SYNC_PARTNER_ERROR"; else if (i_error==0x8802B006L) risultato="E_SYNCENGINE_SYNC_PAUSED_BY_SERVICE"; else if (i_error==0x8802C002L) risultato="E_SYNCENGINE_FILE_IDENTIFIER_UNKNOWN"; else if (i_error==0x8802C003L) risultato="E_SYNCENGINE_SERVICE_AUTHENTICATION_FAILED"; else if (i_error==0x8802C004L) risultato="E_SYNCENGINE_UNKNOWN_SERVICE_ERROR"; else if (i_error==0x8802C005L) risultato="E_SYNCENGINE_SERVICE_RETURNED_UNEXPECTED_SIZE"; else if (i_error==0x8802C006L) risultato="E_SYNCENGINE_REQUEST_BLOCKED_BY_SERVICE"; else if (i_error==0x8802C007L) risultato="E_SYNCENGINE_REQUEST_BLOCKED_DUE_TO_CLIENT_ERROR"; else if (i_error==0x8802D001L) risultato="E_SYNCENGINE_FOLDER_INACCESSIBLE"; else if (i_error==0x8802D002L) risultato="E_SYNCENGINE_UNSUPPORTED_FOLDER_NAME"; else if (i_error==0x8802D003L) risultato="E_SYNCENGINE_UNSUPPORTED_MARKET"; else if (i_error==0x8802D004L) risultato="E_SYNCENGINE_PATH_LENGTH_LIMIT_EXCEEDED"; else if (i_error==0x8802D005L) risultato="E_SYNCENGINE_REMOTE_PATH_LENGTH_LIMIT_EXCEEDED"; else if (i_error==0x8802D006L) risultato="E_SYNCENGINE_CLIENT_UPDATE_NEEDED"; else if (i_error==0x8802D007L) risultato="E_SYNCENGINE_PROXY_AUTHENTICATION_REQUIRED"; else if (i_error==0x8802D008L) risultato="E_SYNCENGINE_STORAGE_SERVICE_PROVISIONING_FAILED"; else if (i_error==0x8802D009L) risultato="E_SYNCENGINE_UNSUPPORTED_REPARSE_POINT"; else if (i_error==0x8802D00AL) risultato="E_SYNCENGINE_STORAGE_SERVICE_BLOCKED"; else if (i_error==0x8802D00BL) risultato="E_SYNCENGINE_FOLDER_IN_REDIRECTION"; else if (i_error==0x80550001L) risultato="EAS_E_POLICY_NOT_MANAGED_BY_OS"; else if (i_error==0x80550002L) risultato="EAS_E_POLICY_COMPLIANT_WITH_ACTIONS"; else if (i_error==0x80550003L) risultato="EAS_E_REQUESTED_POLICY_NOT_ENFORCEABLE"; else if (i_error==0x80550004L) risultato="EAS_E_CURRENT_USER_HAS_BLANK_PASSWORD"; else if (i_error==0x80550005L) risultato="EAS_E_REQUESTED_POLICY_PASSWORD_EXPIRATION_INCOMPATIBLE"; else if (i_error==0x80550006L) risultato="EAS_E_USER_CANNOT_CHANGE_PASSWORD"; else if (i_error==0x80550007L) risultato="EAS_E_ADMINS_HAVE_BLANK_PASSWORD"; else if (i_error==0x80550008L) risultato="EAS_E_ADMINS_CANNOT_CHANGE_PASSWORD"; else if (i_error==0x80550009L) risultato="EAS_E_LOCAL_CONTROLLED_USERS_CANNOT_CHANGE_PASSWORD"; else if (i_error==0x8055000AL) risultato="EAS_E_PASSWORD_POLICY_NOT_ENFORCEABLE_FOR_CONNECTED_ADMINS"; else if (i_error==0x8055000BL) risultato="EAS_E_CONNECTED_ADMINS_NEED_TO_CHANGE_PASSWORD"; else if (i_error==0x8055000CL) risultato="EAS_E_PASSWORD_POLICY_NOT_ENFORCEABLE_FOR_CURRENT_CONNECTED_USER"; else if (i_error==0x8055000DL) risultato="EAS_E_CURRENT_CONNECTED_USER_NEED_TO_CHANGE_PASSWORD"; else if (i_error==0x83750001L) risultato="WEB_E_UNSUPPORTED_FORMAT"; else if (i_error==0x83750002L) risultato="WEB_E_INVALID_XML"; else if (i_error==0x83750003L) risultato="WEB_E_MISSING_REQUIRED_ELEMENT"; else if (i_error==0x83750004L) risultato="WEB_E_MISSING_REQUIRED_ATTRIBUTE"; else if (i_error==0x83750005L) risultato="WEB_E_UNEXPECTED_CONTENT"; else if (i_error==0x83750006L) risultato="WEB_E_RESOURCE_TOO_LARGE"; else if (i_error==0x83750007L) risultato="WEB_E_INVALID_JSON_STRING"; else if (i_error==0x83750008L) risultato="WEB_E_INVALID_JSON_NUMBER"; else if (i_error==0x83750009L) risultato="WEB_E_JSON_VALUE_NOT_FOUND"; else if (i_error==0x80190001L) risultato="HTTP_E_STATUS_UNEXPECTED"; else if (i_error==0x80190003L) risultato="HTTP_E_STATUS_UNEXPECTED_REDIRECTION"; else if (i_error==0x80190004L) risultato="HTTP_E_STATUS_UNEXPECTED_CLIENT_ERROR"; else if (i_error==0x80190005L) risultato="HTTP_E_STATUS_UNEXPECTED_SERVER_ERROR"; else if (i_error==0x8019012CL) risultato="HTTP_E_STATUS_AMBIGUOUS"; else if (i_error==0x8019012DL) risultato="HTTP_E_STATUS_MOVED"; else if (i_error==0x8019012EL) risultato="HTTP_E_STATUS_REDIRECT"; else if (i_error==0x8019012FL) risultato="HTTP_E_STATUS_REDIRECT_METHOD"; else if (i_error==0x80190130L) risultato="HTTP_E_STATUS_NOT_MODIFIED"; else if (i_error==0x80190131L) risultato="HTTP_E_STATUS_USE_PROXY"; else if (i_error==0x80190133L) risultato="HTTP_E_STATUS_REDIRECT_KEEP_VERB"; else if (i_error==0x80190190L) risultato="HTTP_E_STATUS_BAD_REQUEST"; else if (i_error==0x80190191L) risultato="HTTP_E_STATUS_DENIED"; else if (i_error==0x80190192L) risultato="HTTP_E_STATUS_PAYMENT_REQ"; else if (i_error==0x80190193L) risultato="HTTP_E_STATUS_FORBIDDEN"; else if (i_error==0x80190194L) risultato="HTTP_E_STATUS_NOT_FOUND"; else if (i_error==0x80190195L) risultato="HTTP_E_STATUS_BAD_METHOD"; else if (i_error==0x80190196L) risultato="HTTP_E_STATUS_NONE_ACCEPTABLE"; else if (i_error==0x80190197L) risultato="HTTP_E_STATUS_PROXY_AUTH_REQ"; else if (i_error==0x80190198L) risultato="HTTP_E_STATUS_REQUEST_TIMEOUT"; else if (i_error==0x80190199L) risultato="HTTP_E_STATUS_CONFLICT"; else if (i_error==0x8019019AL) risultato="HTTP_E_STATUS_GONE"; else if (i_error==0x8019019BL) risultato="HTTP_E_STATUS_LENGTH_REQUIRED"; else if (i_error==0x8019019CL) risultato="HTTP_E_STATUS_PRECOND_FAILED"; else if (i_error==0x8019019DL) risultato="HTTP_E_STATUS_REQUEST_TOO_LARGE"; else if (i_error==0x8019019EL) risultato="HTTP_E_STATUS_URI_TOO_LONG"; else if (i_error==0x8019019FL) risultato="HTTP_E_STATUS_UNSUPPORTED_MEDIA"; else if (i_error==0x801901A0L) risultato="HTTP_E_STATUS_RANGE_NOT_SATISFIABLE"; else if (i_error==0x801901A1L) risultato="HTTP_E_STATUS_EXPECTATION_FAILED"; else if (i_error==0x801901F4L) risultato="HTTP_E_STATUS_SERVER_ERROR"; else if (i_error==0x801901F5L) risultato="HTTP_E_STATUS_NOT_SUPPORTED"; else if (i_error==0x801901F6L) risultato="HTTP_E_STATUS_BAD_GATEWAY"; else if (i_error==0x801901F7L) risultato="HTTP_E_STATUS_SERVICE_UNAVAIL"; else if (i_error==0x801901F8L) risultato="HTTP_E_STATUS_GATEWAY_TIMEOUT"; else if (i_error==0x801901F9L) risultato="HTTP_E_STATUS_VERSION_NOT_SUP"; else if (i_error==0x83760001L) risultato="E_INVALID_PROTOCOL_OPERATION"; else if (i_error==0x83760002L) risultato="E_INVALID_PROTOCOL_FORMAT"; else if (i_error==0x83760003L) risultato="E_PROTOCOL_EXTENSIONS_NOT_SUPPORTED"; else if (i_error==0x83760004L) risultato="E_SUBPROTOCOL_NOT_SUPPORTED"; else if (i_error==0x83760005L) risultato="E_PROTOCOL_VERSION_NOT_SUPPORTED"; else if (i_error==0x80400000L) risultato="INPUT_E_OUT_OF_ORDER"; else if (i_error==0x80400001L) risultato="INPUT_E_REENTRANCY"; else if (i_error==0x80400002L) risultato="INPUT_E_MULTIMODAL"; else if (i_error==0x80400003L) risultato="INPUT_E_PACKET"; else if (i_error==0x80400004L) risultato="INPUT_E_FRAME"; else if (i_error==0x80400005L) risultato="INPUT_E_HISTORY"; else if (i_error==0x80400006L) risultato="INPUT_E_DEVICE_INFO"; else if (i_error==0x80400007L) risultato="INPUT_E_TRANSFORM"; else if (i_error==0x80400008L) risultato="INPUT_E_DEVICE_PROPERTY"; else if (i_error==0x800C0002L) risultato="INET_E_INVALID_URL"; else if (i_error==0x800C0003L) risultato="INET_E_NO_SESSION"; else if (i_error==0x800C0004L) risultato="INET_E_CANNOT_CONNECT"; else if (i_error==0x800C0005L) risultato="INET_E_RESOURCE_NOT_FOUND"; else if (i_error==0x800C0006L) risultato="INET_E_OBJECT_NOT_FOUND"; else if (i_error==0x800C0007L) risultato="INET_E_DATA_NOT_AVAILABLE"; else if (i_error==0x800C0008L) risultato="INET_E_DOWNLOAD_FAILURE"; else if (i_error==0x800C0009L) risultato="INET_E_AUTHENTICATION_REQUIRED"; else if (i_error==0x800C000AL) risultato="INET_E_NO_VALID_MEDIA"; else if (i_error==0x800C000BL) risultato="INET_E_CONNECTION_TIMEOUT"; else if (i_error==0x800C000CL) risultato="INET_E_INVALID_REQUEST"; else if (i_error==0x800C000DL) risultato="INET_E_UNKNOWN_PROTOCOL"; else if (i_error==0x800C000EL) risultato="INET_E_SECURITY_PROBLEM"; else if (i_error==0x800C000FL) risultato="INET_E_CANNOT_LOAD_DATA"; else if (i_error==0x800C0010L) risultato="INET_E_CANNOT_INSTANTIATE_OBJECT"; else if (i_error==0x800C0019L) risultato="INET_E_INVALID_CERTIFICATE"; else if (i_error==0x800C0014L) risultato="INET_E_REDIRECT_FAILED"; else if (i_error==0x800C0015L) risultato="INET_E_REDIRECT_TO_DIR"; else if (i_error==0x80B00001L) risultato="ERROR_DBG_CREATE_PROCESS_FAILURE_LOCKDOWN"; else if (i_error==0x80B00002L) risultato="ERROR_DBG_ATTACH_PROCESS_FAILURE_LOCKDOWN"; else if (i_error==0x80B00003L) risultato="ERROR_DBG_CONNECT_SERVER_FAILURE_LOCKDOWN"; else if (i_error==0x80B00004L) risultato="ERROR_DBG_START_SERVER_FAILURE_LOCKDOWN"; else if (i_error==0x89010001L) risultato="ERROR_IO_PREEMPTED"; else if (i_error==0x89020001L) risultato="JSCRIPT_E_CANTEXECUTE"; else if (i_error==0x88010001L) risultato="WEP_E_NOT_PROVISIONED_ON_ALL_VOLUMES"; else if (i_error==0x88010002L) risultato="WEP_E_FIXED_DATA_NOT_SUPPORTED"; else if (i_error==0x88010003L) risultato="WEP_E_HARDWARE_NOT_COMPLIANT"; else if (i_error==0x88010004L) risultato="WEP_E_LOCK_NOT_CONFIGURED"; else if (i_error==0x88010005L) risultato="WEP_E_PROTECTION_SUSPENDED"; else if (i_error==0x88010006L) risultato="WEP_E_NO_LICENSE"; else if (i_error==0x88010007L) risultato="WEP_E_OS_NOT_PROTECTED"; else if (i_error==0x88010008L) risultato="WEP_E_UNEXPECTED_FAIL"; else if (i_error==0x88010009L) risultato="WEP_E_BUFFER_TOO_LARGE"; else if (i_error==0xC05C0000L) risultato="ERROR_SVHDX_ERROR_STORED"; else if (i_error==0xC05CFF00L) risultato="ERROR_SVHDX_ERROR_NOT_AVAILABLE"; else if (i_error==0xC05CFF01L) risultato="ERROR_SVHDX_UNIT_ATTENTION_AVAILABLE"; else if (i_error==0xC05CFF02L) risultato="ERROR_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED"; else if (i_error==0xC05CFF03L) risultato="ERROR_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED"; else if (i_error==0xC05CFF04L) risultato="ERROR_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED"; else if (i_error==0xC05CFF05L) risultato="ERROR_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED"; else if (i_error==0xC05CFF06L) risultato="ERROR_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED"; else if (i_error==0xC05CFF07L) risultato="ERROR_SVHDX_RESERVATION_CONFLICT"; else if (i_error==0xC05CFF08L) risultato="ERROR_SVHDX_WRONG_FILE_TYPE"; else if (i_error==0xC05CFF09L) risultato="ERROR_SVHDX_VERSION_MISMATCH"; else if (i_error==0xC05CFF0AL) risultato="ERROR_VHD_SHARED"; else if (i_error==0xC05CFF0BL) risultato="ERROR_SVHDX_NO_INITIATOR"; else if (i_error==0xC05CFF0CL) risultato="ERROR_VHDSET_BACKING_STORAGE_NOT_FOUND"; else if (i_error==0xC05D0000L) risultato="ERROR_SMB_NO_PREAUTH_INTEGRITY_HASH_OVERLAP"; else if (i_error==0xC05D0001L) risultato="ERROR_SMB_BAD_CLUSTER_DIALECT"; else if (i_error==0x80072EE1L) risultato="WININET_E_OUT_OF_HANDLES"; else if (i_error==0x80072EE2L) risultato="WININET_E_TIMEOUT"; else if (i_error==0x80072EE3L) risultato="WININET_E_EXTENDED_ERROR"; else if (i_error==0x80072EE4L) risultato="WININET_E_INTERNAL_ERROR"; else if (i_error==0x80072EE5L) risultato="WININET_E_INVALID_URL"; else if (i_error==0x80072EE6L) risultato="WININET_E_UNRECOGNIZED_SCHEME"; else if (i_error==0x80072EE7L) risultato="WININET_E_NAME_NOT_RESOLVED"; else if (i_error==0x80072EE8L) risultato="WININET_E_PROTOCOL_NOT_FOUND"; else if (i_error==0x80072EE9L) risultato="WININET_E_INVALID_OPTION"; else if (i_error==0x80072EEAL) risultato="WININET_E_BAD_OPTION_LENGTH"; else if (i_error==0x80072EEBL) risultato="WININET_E_OPTION_NOT_SETTABLE"; else if (i_error==0x80072EECL) risultato="WININET_E_SHUTDOWN"; else if (i_error==0x80072EEDL) risultato="WININET_E_INCORRECT_USER_NAME"; else if (i_error==0x80072EEEL) risultato="WININET_E_INCORRECT_PASSWORD"; else if (i_error==0x80072EEFL) risultato="WININET_E_LOGIN_FAILURE"; else if (i_error==0x80072EF0L) risultato="WININET_E_INVALID_OPERATION"; else if (i_error==0x80072EF1L) risultato="WININET_E_OPERATION_CANCELLED"; else if (i_error==0x80072EF2L) risultato="WININET_E_INCORRECT_HANDLE_TYPE"; else if (i_error==0x80072EF3L) risultato="WININET_E_INCORRECT_HANDLE_STATE"; else if (i_error==0x80072EF4L) risultato="WININET_E_NOT_PROXY_REQUEST"; else if (i_error==0x80072EF5L) risultato="WININET_E_REGISTRY_VALUE_NOT_FOUND"; else if (i_error==0x80072EF6L) risultato="WININET_E_BAD_REGISTRY_PARAMETER"; else if (i_error==0x80072EF7L) risultato="WININET_E_NO_DIRECT_ACCESS"; else if (i_error==0x80072EF8L) risultato="WININET_E_NO_CONTEXT"; else if (i_error==0x80072EF9L) risultato="WININET_E_NO_CALLBACK"; else if (i_error==0x80072EFAL) risultato="WININET_E_REQUEST_PENDING"; else if (i_error==0x80072EFBL) risultato="WININET_E_INCORRECT_FORMAT"; else if (i_error==0x80072EFCL) risultato="WININET_E_ITEM_NOT_FOUND"; else if (i_error==0x80072EFDL) risultato="WININET_E_CANNOT_CONNECT"; else if (i_error==0x80072EFEL) risultato="WININET_E_CONNECTION_ABORTED"; else if (i_error==0x80072EFFL) risultato="WININET_E_CONNECTION_RESET"; else if (i_error==0x80072F00L) risultato="WININET_E_FORCE_RETRY"; else if (i_error==0x80072F01L) risultato="WININET_E_INVALID_PROXY_REQUEST"; else if (i_error==0x80072F02L) risultato="WININET_E_NEED_UI"; else if (i_error==0x80072F04L) risultato="WININET_E_HANDLE_EXISTS"; else if (i_error==0x80072F05L) risultato="WININET_E_SEC_CERT_DATE_INVALID"; else if (i_error==0x80072F06L) risultato="WININET_E_SEC_CERT_CN_INVALID"; else if (i_error==0x80072F07L) risultato="WININET_E_HTTP_TO_HTTPS_ON_REDIR"; else if (i_error==0x80072F08L) risultato="WININET_E_HTTPS_TO_HTTP_ON_REDIR"; else if (i_error==0x80072F09L) risultato="WININET_E_MIXED_SECURITY"; else if (i_error==0x80072F0AL) risultato="WININET_E_CHG_POST_IS_NON_SECURE"; else if (i_error==0x80072F0BL) risultato="WININET_E_POST_IS_NON_SECURE"; else if (i_error==0x80072F0CL) risultato="WININET_E_CLIENT_AUTH_CERT_NEEDED"; else if (i_error==0x80072F0DL) risultato="WININET_E_INVALID_CA"; else if (i_error==0x80072F0EL) risultato="WININET_E_CLIENT_AUTH_NOT_SETUP"; else if (i_error==0x80072F0FL) risultato="WININET_E_ASYNC_THREAD_FAILED"; else if (i_error==0x80072F10L) risultato="WININET_E_REDIRECT_SCHEME_CHANGE"; else if (i_error==0x80072F11L) risultato="WININET_E_DIALOG_PENDING"; else if (i_error==0x80072F12L) risultato="WININET_E_RETRY_DIALOG"; else if (i_error==0x80072F13L) risultato="WININET_E_NO_NEW_CONTAINERS"; else if (i_error==0x80072F14L) risultato="WININET_E_HTTPS_HTTP_SUBMIT_REDIR"; else if (i_error==0x80072F17L) risultato="WININET_E_SEC_CERT_ERRORS"; else if (i_error==0x80072F19L) risultato="WININET_E_SEC_CERT_REV_FAILED"; else if (i_error==0x80072F76L) risultato="WININET_E_HEADER_NOT_FOUND"; else if (i_error==0x80072F77L) risultato="WININET_E_DOWNLEVEL_SERVER"; else if (i_error==0x80072F78L) risultato="WININET_E_INVALID_SERVER_RESPONSE"; else if (i_error==0x80072F79L) risultato="WININET_E_INVALID_HEADER"; else if (i_error==0x80072F7AL) risultato="WININET_E_INVALID_QUERY_REQUEST"; else if (i_error==0x80072F7BL) risultato="WININET_E_HEADER_ALREADY_EXISTS"; else if (i_error==0x80072F7CL) risultato="WININET_E_REDIRECT_FAILED"; else if (i_error==0x80072F7DL) risultato="WININET_E_SECURITY_CHANNEL_ERROR"; else if (i_error==0x80072F7EL) risultato="WININET_E_UNABLE_TO_CACHE_FILE"; else if (i_error==0x80072F7FL) risultato="WININET_E_TCPIP_NOT_INSTALLED"; else if (i_error==0x80072F83L) risultato="WININET_E_DISCONNECTED"; else if (i_error==0x80072F84L) risultato="WININET_E_SERVER_UNREACHABLE"; else if (i_error==0x80072F85L) risultato="WININET_E_PROXY_SERVER_UNREACHABLE"; else if (i_error==0x80072F86L) risultato="WININET_E_BAD_AUTO_PROXY_SCRIPT"; else if (i_error==0x80072F87L) risultato="WININET_E_UNABLE_TO_DOWNLOAD_SCRIPT"; else if (i_error==0x80072F89L) risultato="WININET_E_SEC_INVALID_CERT"; else if (i_error==0x80072F8AL) risultato="WININET_E_SEC_CERT_REVOKED"; else if (i_error==0x80072F8BL) risultato="WININET_E_FAILED_DUETOSECURITYCHECK"; else if (i_error==0x80072F8CL) risultato="WININET_E_NOT_INITIALIZED"; else if (i_error==0x80072F8EL) risultato="WININET_E_LOGIN_FAILURE_DISPLAY_ENTITY_BODY"; else if (i_error==0x80072F8FL) risultato="WININET_E_DECODING_FAILED"; else if (i_error==0x80072F80L) risultato="WININET_E_NOT_REDIRECTED"; else if (i_error==0x80072F81L) risultato="WININET_E_COOKIE_NEEDS_CONFIRMATION"; else if (i_error==0x80072F82L) risultato="WININET_E_COOKIE_DECLINED"; else if (i_error==0x80072F88L) risultato="WININET_E_REDIRECT_NEEDS_CONFIRMATION"; else if (i_error==0x87AF0001L) risultato="SQLITE_E_ERROR"; else if (i_error==0x87AF0002L) risultato="SQLITE_E_INTERNAL"; else if (i_error==0x87AF0003L) risultato="SQLITE_E_PERM"; else if (i_error==0x87AF0004L) risultato="SQLITE_E_ABORT"; else if (i_error==0x87AF0005L) risultato="SQLITE_E_BUSY"; else if (i_error==0x87AF0006L) risultato="SQLITE_E_LOCKED"; else if (i_error==0x87AF0007L) risultato="SQLITE_E_NOMEM"; else if (i_error==0x87AF0008L) risultato="SQLITE_E_READONLY"; else if (i_error==0x87AF0009L) risultato="SQLITE_E_INTERRUPT"; else if (i_error==0x87AF000AL) risultato="SQLITE_E_IOERR"; else if (i_error==0x87AF000BL) risultato="SQLITE_E_CORRUPT"; else if (i_error==0x87AF000CL) risultato="SQLITE_E_NOTFOUND"; else if (i_error==0x87AF000DL) risultato="SQLITE_E_FULL"; else if (i_error==0x87AF000EL) risultato="SQLITE_E_CANTOPEN"; else if (i_error==0x87AF000FL) risultato="SQLITE_E_PROTOCOL"; else if (i_error==0x87AF0010L) risultato="SQLITE_E_EMPTY"; else if (i_error==0x87AF0011L) risultato="SQLITE_E_SCHEMA"; else if (i_error==0x87AF0012L) risultato="SQLITE_E_TOOBIG"; else if (i_error==0x87AF0013L) risultato="SQLITE_E_CONSTRAINT"; else if (i_error==0x87AF0014L) risultato="SQLITE_E_MISMATCH"; else if (i_error==0x87AF0015L) risultato="SQLITE_E_MISUSE"; else if (i_error==0x87AF0016L) risultato="SQLITE_E_NOLFS"; else if (i_error==0x87AF0017L) risultato="SQLITE_E_AUTH"; else if (i_error==0x87AF0018L) risultato="SQLITE_E_FORMAT"; else if (i_error==0x87AF0019L) risultato="SQLITE_E_RANGE"; else if (i_error==0x87AF001AL) risultato="SQLITE_E_NOTADB"; else if (i_error==0x87AF001BL) risultato="SQLITE_E_NOTICE"; else if (i_error==0x87AF001CL) risultato="SQLITE_E_WARNING"; else if (i_error==0x87AF0064L) risultato="SQLITE_E_ROW"; else if (i_error==0x87AF0065L) risultato="SQLITE_E_DONE"; else if (i_error==0x87AF010AL) risultato="SQLITE_E_IOERR_READ"; else if (i_error==0x87AF020AL) risultato="SQLITE_E_IOERR_SHORT_READ"; else if (i_error==0x87AF030AL) risultato="SQLITE_E_IOERR_WRITE"; else if (i_error==0x87AF040AL) risultato="SQLITE_E_IOERR_FSYNC"; else if (i_error==0x87AF050AL) risultato="SQLITE_E_IOERR_DIR_FSYNC"; else if (i_error==0x87AF060AL) risultato="SQLITE_E_IOERR_TRUNCATE"; else if (i_error==0x87AF070AL) risultato="SQLITE_E_IOERR_FSTAT"; else if (i_error==0x87AF080AL) risultato="SQLITE_E_IOERR_UNLOCK"; else if (i_error==0x87AF090AL) risultato="SQLITE_E_IOERR_RDLOCK"; else if (i_error==0x87AF0A0AL) risultato="SQLITE_E_IOERR_DELETE"; else if (i_error==0x87AF0B0AL) risultato="SQLITE_E_IOERR_BLOCKED"; else if (i_error==0x87AF0C0AL) risultato="SQLITE_E_IOERR_NOMEM"; else if (i_error==0x87AF0D0AL) risultato="SQLITE_E_IOERR_ACCESS"; else if (i_error==0x87AF0E0AL) risultato="SQLITE_E_IOERR_CHECKRESERVEDLOCK"; else if (i_error==0x87AF0F0AL) risultato="SQLITE_E_IOERR_LOCK"; else if (i_error==0x87AF100AL) risultato="SQLITE_E_IOERR_CLOSE"; else if (i_error==0x87AF110AL) risultato="SQLITE_E_IOERR_DIR_CLOSE"; else if (i_error==0x87AF120AL) risultato="SQLITE_E_IOERR_SHMOPEN"; else if (i_error==0x87AF130AL) risultato="SQLITE_E_IOERR_SHMSIZE"; else if (i_error==0x87AF140AL) risultato="SQLITE_E_IOERR_SHMLOCK"; else if (i_error==0x87AF150AL) risultato="SQLITE_E_IOERR_SHMMAP"; else if (i_error==0x87AF160AL) risultato="SQLITE_E_IOERR_SEEK"; else if (i_error==0x87AF170AL) risultato="SQLITE_E_IOERR_DELETE_NOENT"; else if (i_error==0x87AF180AL) risultato="SQLITE_E_IOERR_MMAP"; else if (i_error==0x87AF190AL) risultato="SQLITE_E_IOERR_GETTEMPPATH"; else if (i_error==0x87AF1A0AL) risultato="SQLITE_E_IOERR_CONVPATH"; else if (i_error==0x87AF1A02L) risultato="SQLITE_E_IOERR_VNODE"; else if (i_error==0x87AF1A03L) risultato="SQLITE_E_IOERR_AUTH"; else if (i_error==0x87AF0106L) risultato="SQLITE_E_LOCKED_SHAREDCACHE"; else if (i_error==0x87AF0105L) risultato="SQLITE_E_BUSY_RECOVERY"; else if (i_error==0x87AF0205L) risultato="SQLITE_E_BUSY_SNAPSHOT"; else if (i_error==0x87AF010EL) risultato="SQLITE_E_CANTOPEN_NOTEMPDIR"; else if (i_error==0x87AF020EL) risultato="SQLITE_E_CANTOPEN_ISDIR"; else if (i_error==0x87AF030EL) risultato="SQLITE_E_CANTOPEN_FULLPATH"; else if (i_error==0x87AF040EL) risultato="SQLITE_E_CANTOPEN_CONVPATH"; else if (i_error==0x87AF010BL) risultato="SQLITE_E_CORRUPT_VTAB"; else if (i_error==0x87AF0108L) risultato="SQLITE_E_READONLY_RECOVERY"; else if (i_error==0x87AF0208L) risultato="SQLITE_E_READONLY_CANTLOCK"; else if (i_error==0x87AF0308L) risultato="SQLITE_E_READONLY_ROLLBACK"; else if (i_error==0x87AF0408L) risultato="SQLITE_E_READONLY_DBMOVED"; else if (i_error==0x87AF0204L) risultato="SQLITE_E_ABORT_ROLLBACK"; else if (i_error==0x87AF0113L) risultato="SQLITE_E_CONSTRAINT_CHECK"; else if (i_error==0x87AF0213L) risultato="SQLITE_E_CONSTRAINT_COMMITHOOK"; else if (i_error==0x87AF0313L) risultato="SQLITE_E_CONSTRAINT_FOREIGNKEY"; else if (i_error==0x87AF0413L) risultato="SQLITE_E_CONSTRAINT_FUNCTION"; else if (i_error==0x87AF0513L) risultato="SQLITE_E_CONSTRAINT_NOTNULL"; else if (i_error==0x87AF0613L) risultato="SQLITE_E_CONSTRAINT_PRIMARYKEY"; else if (i_error==0x87AF0713L) risultato="SQLITE_E_CONSTRAINT_TRIGGER"; else if (i_error==0x87AF0813L) risultato="SQLITE_E_CONSTRAINT_UNIQUE"; else if (i_error==0x87AF0913L) risultato="SQLITE_E_CONSTRAINT_VTAB"; else if (i_error==0x87AF0A13L) risultato="SQLITE_E_CONSTRAINT_ROWID"; else if (i_error==0x87AF011BL) risultato="SQLITE_E_NOTICE_RECOVER_WAL"; else if (i_error==0x87AF021BL) risultato="SQLITE_E_NOTICE_RECOVER_ROLLBACK"; else if (i_error==0x87AF011CL) risultato="SQLITE_E_WARNING_AUTOINDEX"; else if (i_error==0x87C51001L) risultato="UTC_E_TOGGLE_TRACE_STARTED"; else if (i_error==0x87C51002L) risultato="UTC_E_ALTERNATIVE_TRACE_CANNOT_PREEMPT"; else if (i_error==0x87C51003L) risultato="UTC_E_AOT_NOT_RUNNING"; else if (i_error==0x87C51004L) risultato="UTC_E_SCRIPT_TYPE_INVALID"; else if (i_error==0x87C51005L) risultato="UTC_E_SCENARIODEF_NOT_FOUND"; else if (i_error==0x87C51006L) risultato="UTC_E_TRACEPROFILE_NOT_FOUND"; else if (i_error==0x87C51007L) risultato="UTC_E_FORWARDER_ALREADY_ENABLED"; else if (i_error==0x87C51008L) risultato="UTC_E_FORWARDER_ALREADY_DISABLED"; else if (i_error==0x87C51009L) risultato="UTC_E_EVENTLOG_ENTRY_MALFORMED"; else if (i_error==0x87C5100AL) risultato="UTC_E_DIAGRULES_SCHEMAVERSION_MISMATCH"; else if (i_error==0x87C5100BL) risultato="UTC_E_SCRIPT_TERMINATED"; else if (i_error==0x87C5100CL) risultato="UTC_E_INVALID_CUSTOM_FILTER"; else if (i_error==0x87C5100DL) risultato="UTC_E_TRACE_NOT_RUNNING"; else if (i_error==0x87C5100EL) risultato="UTC_E_REESCALATED_TOO_QUICKLY"; else if (i_error==0x87C5100FL) risultato="UTC_E_ESCALATION_ALREADY_RUNNING"; else if (i_error==0x87C51010L) risultato="UTC_E_PERFTRACK_ALREADY_TRACING"; else if (i_error==0x87C51011L) risultato="UTC_E_REACHED_MAX_ESCALATIONS"; else if (i_error==0x87C51012L) risultato="UTC_E_FORWARDER_PRODUCER_MISMATCH"; else if (i_error==0x87C51013L) risultato="UTC_E_INTENTIONAL_SCRIPT_FAILURE"; else if (i_error==0x87C51014L) risultato="UTC_E_SQM_INIT_FAILED"; else if (i_error==0x87C51015L) risultato="UTC_E_NO_WER_LOGGER_SUPPORTED"; else if (i_error==0x87C51016L) risultato="UTC_E_TRACERS_DONT_EXIST"; else if (i_error==0x87C51017L) risultato="UTC_E_WINRT_INIT_FAILED"; else if (i_error==0x87C51018L) risultato="UTC_E_SCENARIODEF_SCHEMAVERSION_MISMATCH"; else if (i_error==0x87C51019L) risultato="UTC_E_INVALID_FILTER"; else if (i_error==0x87C5101AL) risultato="UTC_E_EXE_TERMINATED"; else if (i_error==0x87C5101BL) risultato="UTC_E_ESCALATION_NOT_AUTHORIZED"; else if (i_error==0x87C5101CL) risultato="UTC_E_SETUP_NOT_AUTHORIZED"; else if (i_error==0x87C5101DL) risultato="UTC_E_CHILD_PROCESS_FAILED"; else if (i_error==0x87C5101EL) risultato="UTC_E_COMMAND_LINE_NOT_AUTHORIZED"; else if (i_error==0x87C5101FL) risultato="UTC_E_CANNOT_LOAD_SCENARIO_EDITOR_XML"; else if (i_error==0x87C51020L) risultato="UTC_E_ESCALATION_TIMED_OUT"; else if (i_error==0x87C51021L) risultato="UTC_E_SETUP_TIMED_OUT"; else if (i_error==0x87C51022L) risultato="UTC_E_TRIGGER_MISMATCH"; else if (i_error==0x87C51023L) risultato="UTC_E_TRIGGER_NOT_FOUND"; else if (i_error==0x87C51024L) risultato="UTC_E_SIF_NOT_SUPPORTED"; else if (i_error==0x87C51025L) risultato="UTC_E_DELAY_TERMINATED"; else if (i_error==0x87C51026L) risultato="UTC_E_DEVICE_TICKET_ERROR"; else if (i_error==0x87C51027L) risultato="UTC_E_TRACE_BUFFER_LIMIT_EXCEEDED"; else if (i_error==0x87C51028L) risultato="UTC_E_API_RESULT_UNAVAILABLE"; else if (i_error==0x87C51029L) risultato="UTC_E_RPC_TIMEOUT"; else if (i_error==0x87C5102AL) risultato="UTC_E_RPC_WAIT_FAILED"; else if (i_error==0x87C5102BL) risultato="UTC_E_API_BUSY"; else if (i_error==0x87C5102CL) risultato="UTC_E_TRACE_MIN_DURATION_REQUIREMENT_NOT_MET"; else if (i_error==0x87C5102DL) risultato="UTC_E_EXCLUSIVITY_NOT_AVAILABLE"; else if (i_error==0x87C5102EL) risultato="UTC_E_GETFILE_FILE_PATH_NOT_APPROVED"; else if (i_error==0x87C5102FL) risultato="UTC_E_ESCALATION_DIRECTORY_ALREADY_EXISTS"; else { snprintf(buffer,sizeof(buffer),"Windows error # %ld\n",i_error); risultato=buffer; } if (risultato!="") while (risultato.size()<25) risultato+=" "; return risultato; } void enumerateerrors() { if (g_errors.size()==0) { myprintf("00076: no file errors tracked\n"); return; } myprintf("\n"); myprintf("00077: File errors report\n"); for (MAPPAERRORS::iterator p=g_errors.begin(); p!=g_errors.end(); ++p) { myprintf("00078! Error %08d # %8s |%s| \n",p->first,migliaia((int64_t)p->second.counter),decodewinerror(p->first,NULL).c_str()); if (flagdebug2) { for (unsigned int i=0;isecond.filenames.size();i++) { printUTF8(p->second.filenames[i].c_str()); myprintf(">>\n"); myprintf("%08X %s\n",p->second.attrs[i],decodewinattribute(p->second.attrs[i]).c_str()); } printbar('-'); } } } void printerr(const char* i_where,const char* filename,int32_t i_fileattr) { if (flagignore) return; int err=GetLastError(); MAPPAERRORS::iterator a=g_errors.find(err); if (a!=g_errors.end()) { a->second.counter++; if (filename) { a->second.filenames.push_back(filename); a->second.attrs.push_back(i_fileattr); } } else { s_error myblock; myblock.counter=1; if (filename) { myblock.filenames.push_back(filename); myblock.attrs.push_back(i_fileattr); } g_errors.insert(std::pair(err,myblock)); } string swhere=i_where; g_exec_text=swhere+": "+decodewinerror(err,filename); if (!flagquiet) { myprintf("\r"); printbar(' ',false); myprintf("\r"); myprintf("00079! %s %Z\n",g_exec_text.c_str(),filename); } g_exec_text=g_exec_text+" "+filename; if (filename) { uint64_t spazio=getfreespace(filename); if (spazio<16384) { string mypath=filename; if (direxists(mypath)) { myprintf("\n\n"); myprintf("00080! MAYBE OUT OF FREE SPACE? %s\n",i_where); } else { myprintf("\n\n"); myprintf("00081! MAYBE OUT OF FREE SPACE OR INVALID PATH? %s\n",i_where); } } } } #endif // corresponds to #ifdef (#ifdef unix) void ioerr(const char* msg) { printerr("11896",msg,0); throw std::runtime_error(msg); } /* checksum section */ /// LICENSE_START.10 /////////////////// calculate CRC32 // ////////////////////////////////////////////////////////// // Crc32.h // Copyright (c) 2011-2019 Stephan Brumme. All rights reserved. // Slicing-by-16 contributed by Bulat Ziganshin // Tableless bytewise CRC contributed by Hagai Gold // see http://create.stephan-brumme.com/disclaimer.html // #define CRC32_USE_LOOKUP_TABLE_SLICING_BY_16 uint32_t crc32_combine (uint32_t crcA, uint32_t crcB, size_t lengthB); uint32_t crc32_16bytes (const void* data, size_t length, uint32_t previousCrc32 = 0); /// #include #ifdef __GNUC__ #define PREFETCH(location) __builtin_prefetch(location) #else #define PREFETCH(location) ; #endif // corresponds to #ifdef (#ifdef __GNUC__) ///#endif namespace { const uint32_t Polynomial = 0xEDB88320; /// Slicing-By-16 const size_t MaxSlice = 16; } // anonymous namespace extern const uint32_t Crc32Lookup[MaxSlice][256]; // extern is needed to keep compiler happy #define POLYNOMIAL 0xEDB88320 uint32_t crc32_16bytes(const void* data, size_t length, uint32_t previousCrc32) { #ifdef ALIGNMALLOC { const uint8_t* bytes = (const uint8_t*) data; uint32_t crc = ~previousCrc32; while (length--) { crc ^= *bytes++; for (int i = 0; i < 8; i++) if (crc & 1) crc = (crc >> 1) ^ POLYNOMIAL; else crc >>= 1; } return ~crc; } #else uint32_t crc = ~previousCrc32; // same as previousCrc32 ^ 0xFFFFFFFF const uint32_t* current = (const uint32_t*) data; // enabling optimization (at least -O2) automatically unrolls the inner for-loop const size_t Unroll = 4; const size_t BytesAtOnce = 16 * Unroll; while (length >= BytesAtOnce) { for (size_t unrolling = 0; unrolling < Unroll; unrolling++) { #if __BYTE_ORDER == __BIG_ENDIAN uint32_t one = *current++ ^ swap(crc); uint32_t two = *current++; uint32_t three = *current++; uint32_t four = *current++; crc = Crc32Lookup[ 0][ four & 0xFF] ^ Crc32Lookup[ 1][(four >> 8) & 0xFF] ^ Crc32Lookup[ 2][(four >> 16) & 0xFF] ^ Crc32Lookup[ 3][(four >> 24) & 0xFF] ^ Crc32Lookup[ 4][ three & 0xFF] ^ Crc32Lookup[ 5][(three >> 8) & 0xFF] ^ Crc32Lookup[ 6][(three >> 16) & 0xFF] ^ Crc32Lookup[ 7][(three >> 24) & 0xFF] ^ Crc32Lookup[ 8][ two & 0xFF] ^ Crc32Lookup[ 9][(two >> 8) & 0xFF] ^ Crc32Lookup[10][(two >> 16) & 0xFF] ^ Crc32Lookup[11][(two >> 24) & 0xFF] ^ Crc32Lookup[12][ one & 0xFF] ^ Crc32Lookup[13][(one >> 8) & 0xFF] ^ Crc32Lookup[14][(one >> 16) & 0xFF] ^ Crc32Lookup[15][(one >> 24) & 0xFF]; #else uint32_t one = *current++ ^ crc; uint32_t two = *current++; uint32_t three = *current++; uint32_t four = *current++; crc = Crc32Lookup[ 0][(four >> 24) & 0xFF] ^ Crc32Lookup[ 1][(four >> 16) & 0xFF] ^ Crc32Lookup[ 2][(four >> 8) & 0xFF] ^ Crc32Lookup[ 3][ four & 0xFF] ^ Crc32Lookup[ 4][(three >> 24) & 0xFF] ^ Crc32Lookup[ 5][(three >> 16) & 0xFF] ^ Crc32Lookup[ 6][(three >> 8) & 0xFF] ^ Crc32Lookup[ 7][ three & 0xFF] ^ Crc32Lookup[ 8][(two >> 24) & 0xFF] ^ Crc32Lookup[ 9][(two >> 16) & 0xFF] ^ Crc32Lookup[10][(two >> 8) & 0xFF] ^ Crc32Lookup[11][ two & 0xFF] ^ Crc32Lookup[12][(one >> 24) & 0xFF] ^ Crc32Lookup[13][(one >> 16) & 0xFF] ^ Crc32Lookup[14][(one >> 8) & 0xFF] ^ Crc32Lookup[15][ one & 0xFF]; #endif // corresponds to #if (#if __BYTE_ORDER == __BIG_ENDIAN) } length -= BytesAtOnce; } const uint8_t* currentChar = (const uint8_t*) current; // remaining 1 to 63 bytes (standard algorithm) while (length-- != 0) crc = (crc >> 8) ^ Crc32Lookup[0][(crc & 0xFF) ^ *currentChar++]; return ~crc; // same as crc ^ 0xFFFFFFFF #endif // corresponds to #ifdef (#ifdef ALIGNMALLOC) } /// merge two CRC32 such that result = crc32(dataB, lengthB, crc32(dataA, lengthA)) uint32_t crc32_combine(uint32_t crcA, uint32_t crcB, size_t lengthB) { // degenerated case if (lengthB == 0) return crcA; /// CRC32 => 32 bits const uint32_t CrcBits = 32; uint32_t odd [CrcBits]; // odd-power-of-two zeros operator uint32_t even[CrcBits]; // even-power-of-two zeros operator // put operator for one zero bit in odd odd[0] = Polynomial; // CRC-32 polynomial for (unsigned int i = 1; i < CrcBits; i++) odd[i] = 1 << (i - 1); // put operator for two zero bits in even // same as gf2_matrix_square(even, odd); for (unsigned int i = 0; i < CrcBits; i++) { uint32_t vec = odd[i]; even[i] = 0; for (int j = 0; vec != 0; j++, vec >>= 1) if (vec & 1) even[i] ^= odd[j]; } // put operator for four zero bits in odd // same as gf2_matrix_square(odd, even); for (unsigned int i = 0; i < CrcBits; i++) { uint32_t vec = even[i]; odd[i] = 0; for (int j = 0; vec != 0; j++, vec >>= 1) if (vec & 1) odd[i] ^= even[j]; } // the following loop becomes much shorter if I keep swapping even and odd uint32_t* a = even; uint32_t* b = odd; // apply secondLength zeros to firstCrc32 for (; lengthB > 0; lengthB >>= 1) { // same as gf2_matrix_square(a, b); for (unsigned int i = 0; i < CrcBits; i++) { uint32_t vec = b[i]; a[i] = 0; for (int j = 0; vec != 0; j++, vec >>= 1) if (vec & 1) a[i] ^= b[j]; } // apply zeros operator for this bit if (lengthB & 1) { // same as firstCrc32 = gf2_matrix_times(a, firstCrc32); uint32_t sum = 0; for (int i = 0; crcA != 0; i++, crcA >>= 1) if (crcA & 1) sum ^= a[i]; crcA = sum; } // switch even and odd uint32_t* t = a; a = b; b = t; } // return combined crc return crcA ^ crcB; } // ////////////////////////////////////////////////////////// // constants /// look-up table, already declared above const uint32_t Crc32Lookup[MaxSlice][256] = { { // note: the first number of every second row corresponds to the half-byte look-up table ! 0x00000000,0x77073096,0xEE0E612C,0x990951BA,0x076DC419,0x706AF48F,0xE963A535,0x9E6495A3, 0x0EDB8832,0x79DCB8A4,0xE0D5E91E,0x97D2D988,0x09B64C2B,0x7EB17CBD,0xE7B82D07,0x90BF1D91, 0x1DB71064,0x6AB020F2,0xF3B97148,0x84BE41DE,0x1ADAD47D,0x6DDDE4EB,0xF4D4B551,0x83D385C7, 0x136C9856,0x646BA8C0,0xFD62F97A,0x8A65C9EC,0x14015C4F,0x63066CD9,0xFA0F3D63,0x8D080DF5, 0x3B6E20C8,0x4C69105E,0xD56041E4,0xA2677172,0x3C03E4D1,0x4B04D447,0xD20D85FD,0xA50AB56B, 0x35B5A8FA,0x42B2986C,0xDBBBC9D6,0xACBCF940,0x32D86CE3,0x45DF5C75,0xDCD60DCF,0xABD13D59, 0x26D930AC,0x51DE003A,0xC8D75180,0xBFD06116,0x21B4F4B5,0x56B3C423,0xCFBA9599,0xB8BDA50F, 0x2802B89E,0x5F058808,0xC60CD9B2,0xB10BE924,0x2F6F7C87,0x58684C11,0xC1611DAB,0xB6662D3D, 0x76DC4190,0x01DB7106,0x98D220BC,0xEFD5102A,0x71B18589,0x06B6B51F,0x9FBFE4A5,0xE8B8D433, 0x7807C9A2,0x0F00F934,0x9609A88E,0xE10E9818,0x7F6A0DBB,0x086D3D2D,0x91646C97,0xE6635C01, 0x6B6B51F4,0x1C6C6162,0x856530D8,0xF262004E,0x6C0695ED,0x1B01A57B,0x8208F4C1,0xF50FC457, 0x65B0D9C6,0x12B7E950,0x8BBEB8EA,0xFCB9887C,0x62DD1DDF,0x15DA2D49,0x8CD37CF3,0xFBD44C65, 0x4DB26158,0x3AB551CE,0xA3BC0074,0xD4BB30E2,0x4ADFA541,0x3DD895D7,0xA4D1C46D,0xD3D6F4FB, 0x4369E96A,0x346ED9FC,0xAD678846,0xDA60B8D0,0x44042D73,0x33031DE5,0xAA0A4C5F,0xDD0D7CC9, 0x5005713C,0x270241AA,0xBE0B1010,0xC90C2086,0x5768B525,0x206F85B3,0xB966D409,0xCE61E49F, 0x5EDEF90E,0x29D9C998,0xB0D09822,0xC7D7A8B4,0x59B33D17,0x2EB40D81,0xB7BD5C3B,0xC0BA6CAD, 0xEDB88320,0x9ABFB3B6,0x03B6E20C,0x74B1D29A,0xEAD54739,0x9DD277AF,0x04DB2615,0x73DC1683, 0xE3630B12,0x94643B84,0x0D6D6A3E,0x7A6A5AA8,0xE40ECF0B,0x9309FF9D,0x0A00AE27,0x7D079EB1, 0xF00F9344,0x8708A3D2,0x1E01F268,0x6906C2FE,0xF762575D,0x806567CB,0x196C3671,0x6E6B06E7, 0xFED41B76,0x89D32BE0,0x10DA7A5A,0x67DD4ACC,0xF9B9DF6F,0x8EBEEFF9,0x17B7BE43,0x60B08ED5, 0xD6D6A3E8,0xA1D1937E,0x38D8C2C4,0x4FDFF252,0xD1BB67F1,0xA6BC5767,0x3FB506DD,0x48B2364B, 0xD80D2BDA,0xAF0A1B4C,0x36034AF6,0x41047A60,0xDF60EFC3,0xA867DF55,0x316E8EEF,0x4669BE79, 0xCB61B38C,0xBC66831A,0x256FD2A0,0x5268E236,0xCC0C7795,0xBB0B4703,0x220216B9,0x5505262F, 0xC5BA3BBE,0xB2BD0B28,0x2BB45A92,0x5CB36A04,0xC2D7FFA7,0xB5D0CF31,0x2CD99E8B,0x5BDEAE1D, 0x9B64C2B0,0xEC63F226,0x756AA39C,0x026D930A,0x9C0906A9,0xEB0E363F,0x72076785,0x05005713, 0x95BF4A82,0xE2B87A14,0x7BB12BAE,0x0CB61B38,0x92D28E9B,0xE5D5BE0D,0x7CDCEFB7,0x0BDBDF21, 0x86D3D2D4,0xF1D4E242,0x68DDB3F8,0x1FDA836E,0x81BE16CD,0xF6B9265B,0x6FB077E1,0x18B74777, 0x88085AE6,0xFF0F6A70,0x66063BCA,0x11010B5C,0x8F659EFF,0xF862AE69,0x616BFFD3,0x166CCF45, 0xA00AE278,0xD70DD2EE,0x4E048354,0x3903B3C2,0xA7672661,0xD06016F7,0x4969474D,0x3E6E77DB, 0xAED16A4A,0xD9D65ADC,0x40DF0B66,0x37D83BF0,0xA9BCAE53,0xDEBB9EC5,0x47B2CF7F,0x30B5FFE9, 0xBDBDF21C,0xCABAC28A,0x53B39330,0x24B4A3A6,0xBAD03605,0xCDD70693,0x54DE5729,0x23D967BF, 0xB3667A2E,0xC4614AB8,0x5D681B02,0x2A6F2B94,0xB40BBE37,0xC30C8EA1,0x5A05DF1B,0x2D02EF8D, } // beyond this point only relevant for Slicing-by-4, Slicing-by-8 and Slicing-by-16 ,{ 0x00000000,0x191B3141,0x32366282,0x2B2D53C3,0x646CC504,0x7D77F445,0x565AA786,0x4F4196C7, 0xC8D98A08,0xD1C2BB49,0xFAEFE88A,0xE3F4D9CB,0xACB54F0C,0xB5AE7E4D,0x9E832D8E,0x87981CCF, 0x4AC21251,0x53D92310,0x78F470D3,0x61EF4192,0x2EAED755,0x37B5E614,0x1C98B5D7,0x05838496, 0x821B9859,0x9B00A918,0xB02DFADB,0xA936CB9A,0xE6775D5D,0xFF6C6C1C,0xD4413FDF,0xCD5A0E9E, 0x958424A2,0x8C9F15E3,0xA7B24620,0xBEA97761,0xF1E8E1A6,0xE8F3D0E7,0xC3DE8324,0xDAC5B265, 0x5D5DAEAA,0x44469FEB,0x6F6BCC28,0x7670FD69,0x39316BAE,0x202A5AEF,0x0B07092C,0x121C386D, 0xDF4636F3,0xC65D07B2,0xED705471,0xF46B6530,0xBB2AF3F7,0xA231C2B6,0x891C9175,0x9007A034, 0x179FBCFB,0x0E848DBA,0x25A9DE79,0x3CB2EF38,0x73F379FF,0x6AE848BE,0x41C51B7D,0x58DE2A3C, 0xF0794F05,0xE9627E44,0xC24F2D87,0xDB541CC6,0x94158A01,0x8D0EBB40,0xA623E883,0xBF38D9C2, 0x38A0C50D,0x21BBF44C,0x0A96A78F,0x138D96CE,0x5CCC0009,0x45D73148,0x6EFA628B,0x77E153CA, 0xBABB5D54,0xA3A06C15,0x888D3FD6,0x91960E97,0xDED79850,0xC7CCA911,0xECE1FAD2,0xF5FACB93, 0x7262D75C,0x6B79E61D,0x4054B5DE,0x594F849F,0x160E1258,0x0F152319,0x243870DA,0x3D23419B, 0x65FD6BA7,0x7CE65AE6,0x57CB0925,0x4ED03864,0x0191AEA3,0x188A9FE2,0x33A7CC21,0x2ABCFD60, 0xAD24E1AF,0xB43FD0EE,0x9F12832D,0x8609B26C,0xC94824AB,0xD05315EA,0xFB7E4629,0xE2657768, 0x2F3F79F6,0x362448B7,0x1D091B74,0x04122A35,0x4B53BCF2,0x52488DB3,0x7965DE70,0x607EEF31, 0xE7E6F3FE,0xFEFDC2BF,0xD5D0917C,0xCCCBA03D,0x838A36FA,0x9A9107BB,0xB1BC5478,0xA8A76539, 0x3B83984B,0x2298A90A,0x09B5FAC9,0x10AECB88,0x5FEF5D4F,0x46F46C0E,0x6DD93FCD,0x74C20E8C, 0xF35A1243,0xEA412302,0xC16C70C1,0xD8774180,0x9736D747,0x8E2DE606,0xA500B5C5,0xBC1B8484, 0x71418A1A,0x685ABB5B,0x4377E898,0x5A6CD9D9,0x152D4F1E,0x0C367E5F,0x271B2D9C,0x3E001CDD, 0xB9980012,0xA0833153,0x8BAE6290,0x92B553D1,0xDDF4C516,0xC4EFF457,0xEFC2A794,0xF6D996D5, 0xAE07BCE9,0xB71C8DA8,0x9C31DE6B,0x852AEF2A,0xCA6B79ED,0xD37048AC,0xF85D1B6F,0xE1462A2E, 0x66DE36E1,0x7FC507A0,0x54E85463,0x4DF36522,0x02B2F3E5,0x1BA9C2A4,0x30849167,0x299FA026, 0xE4C5AEB8,0xFDDE9FF9,0xD6F3CC3A,0xCFE8FD7B,0x80A96BBC,0x99B25AFD,0xB29F093E,0xAB84387F, 0x2C1C24B0,0x350715F1,0x1E2A4632,0x07317773,0x4870E1B4,0x516BD0F5,0x7A468336,0x635DB277, 0xCBFAD74E,0xD2E1E60F,0xF9CCB5CC,0xE0D7848D,0xAF96124A,0xB68D230B,0x9DA070C8,0x84BB4189, 0x03235D46,0x1A386C07,0x31153FC4,0x280E0E85,0x674F9842,0x7E54A903,0x5579FAC0,0x4C62CB81, 0x8138C51F,0x9823F45E,0xB30EA79D,0xAA1596DC,0xE554001B,0xFC4F315A,0xD7626299,0xCE7953D8, 0x49E14F17,0x50FA7E56,0x7BD72D95,0x62CC1CD4,0x2D8D8A13,0x3496BB52,0x1FBBE891,0x06A0D9D0, 0x5E7EF3EC,0x4765C2AD,0x6C48916E,0x7553A02F,0x3A1236E8,0x230907A9,0x0824546A,0x113F652B, 0x96A779E4,0x8FBC48A5,0xA4911B66,0xBD8A2A27,0xF2CBBCE0,0xEBD08DA1,0xC0FDDE62,0xD9E6EF23, 0x14BCE1BD,0x0DA7D0FC,0x268A833F,0x3F91B27E,0x70D024B9,0x69CB15F8,0x42E6463B,0x5BFD777A, 0xDC656BB5,0xC57E5AF4,0xEE530937,0xF7483876,0xB809AEB1,0xA1129FF0,0x8A3FCC33,0x9324FD72, }, { 0x00000000,0x01C26A37,0x0384D46E,0x0246BE59,0x0709A8DC,0x06CBC2EB,0x048D7CB2,0x054F1685, 0x0E1351B8,0x0FD13B8F,0x0D9785D6,0x0C55EFE1,0x091AF964,0x08D89353,0x0A9E2D0A,0x0B5C473D, 0x1C26A370,0x1DE4C947,0x1FA2771E,0x1E601D29,0x1B2F0BAC,0x1AED619B,0x18ABDFC2,0x1969B5F5, 0x1235F2C8,0x13F798FF,0x11B126A6,0x10734C91,0x153C5A14,0x14FE3023,0x16B88E7A,0x177AE44D, 0x384D46E0,0x398F2CD7,0x3BC9928E,0x3A0BF8B9,0x3F44EE3C,0x3E86840B,0x3CC03A52,0x3D025065, 0x365E1758,0x379C7D6F,0x35DAC336,0x3418A901,0x3157BF84,0x3095D5B3,0x32D36BEA,0x331101DD, 0x246BE590,0x25A98FA7,0x27EF31FE,0x262D5BC9,0x23624D4C,0x22A0277B,0x20E69922,0x2124F315, 0x2A78B428,0x2BBADE1F,0x29FC6046,0x283E0A71,0x2D711CF4,0x2CB376C3,0x2EF5C89A,0x2F37A2AD, 0x709A8DC0,0x7158E7F7,0x731E59AE,0x72DC3399,0x7793251C,0x76514F2B,0x7417F172,0x75D59B45, 0x7E89DC78,0x7F4BB64F,0x7D0D0816,0x7CCF6221,0x798074A4,0x78421E93,0x7A04A0CA,0x7BC6CAFD, 0x6CBC2EB0,0x6D7E4487,0x6F38FADE,0x6EFA90E9,0x6BB5866C,0x6A77EC5B,0x68315202,0x69F33835, 0x62AF7F08,0x636D153F,0x612BAB66,0x60E9C151,0x65A6D7D4,0x6464BDE3,0x662203BA,0x67E0698D, 0x48D7CB20,0x4915A117,0x4B531F4E,0x4A917579,0x4FDE63FC,0x4E1C09CB,0x4C5AB792,0x4D98DDA5, 0x46C49A98,0x4706F0AF,0x45404EF6,0x448224C1,0x41CD3244,0x400F5873,0x4249E62A,0x438B8C1D, 0x54F16850,0x55330267,0x5775BC3E,0x56B7D609,0x53F8C08C,0x523AAABB,0x507C14E2,0x51BE7ED5, 0x5AE239E8,0x5B2053DF,0x5966ED86,0x58A487B1,0x5DEB9134,0x5C29FB03,0x5E6F455A,0x5FAD2F6D, 0xE1351B80,0xE0F771B7,0xE2B1CFEE,0xE373A5D9,0xE63CB35C,0xE7FED96B,0xE5B86732,0xE47A0D05, 0xEF264A38,0xEEE4200F,0xECA29E56,0xED60F461,0xE82FE2E4,0xE9ED88D3,0xEBAB368A,0xEA695CBD, 0xFD13B8F0,0xFCD1D2C7,0xFE976C9E,0xFF5506A9,0xFA1A102C,0xFBD87A1B,0xF99EC442,0xF85CAE75, 0xF300E948,0xF2C2837F,0xF0843D26,0xF1465711,0xF4094194,0xF5CB2BA3,0xF78D95FA,0xF64FFFCD, 0xD9785D60,0xD8BA3757,0xDAFC890E,0xDB3EE339,0xDE71F5BC,0xDFB39F8B,0xDDF521D2,0xDC374BE5, 0xD76B0CD8,0xD6A966EF,0xD4EFD8B6,0xD52DB281,0xD062A404,0xD1A0CE33,0xD3E6706A,0xD2241A5D, 0xC55EFE10,0xC49C9427,0xC6DA2A7E,0xC7184049,0xC25756CC,0xC3953CFB,0xC1D382A2,0xC011E895, 0xCB4DAFA8,0xCA8FC59F,0xC8C97BC6,0xC90B11F1,0xCC440774,0xCD866D43,0xCFC0D31A,0xCE02B92D, 0x91AF9640,0x906DFC77,0x922B422E,0x93E92819,0x96A63E9C,0x976454AB,0x9522EAF2,0x94E080C5, 0x9FBCC7F8,0x9E7EADCF,0x9C381396,0x9DFA79A1,0x98B56F24,0x99770513,0x9B31BB4A,0x9AF3D17D, 0x8D893530,0x8C4B5F07,0x8E0DE15E,0x8FCF8B69,0x8A809DEC,0x8B42F7DB,0x89044982,0x88C623B5, 0x839A6488,0x82580EBF,0x801EB0E6,0x81DCDAD1,0x8493CC54,0x8551A663,0x8717183A,0x86D5720D, 0xA9E2D0A0,0xA820BA97,0xAA6604CE,0xABA46EF9,0xAEEB787C,0xAF29124B,0xAD6FAC12,0xACADC625, 0xA7F18118,0xA633EB2F,0xA4755576,0xA5B73F41,0xA0F829C4,0xA13A43F3,0xA37CFDAA,0xA2BE979D, 0xB5C473D0,0xB40619E7,0xB640A7BE,0xB782CD89,0xB2CDDB0C,0xB30FB13B,0xB1490F62,0xB08B6555, 0xBBD72268,0xBA15485F,0xB853F606,0xB9919C31,0xBCDE8AB4,0xBD1CE083,0xBF5A5EDA,0xBE9834ED, }, { 0x00000000,0xB8BC6765,0xAA09C88B,0x12B5AFEE,0x8F629757,0x37DEF032,0x256B5FDC,0x9DD738B9, 0xC5B428EF,0x7D084F8A,0x6FBDE064,0xD7018701,0x4AD6BFB8,0xF26AD8DD,0xE0DF7733,0x58631056, 0x5019579F,0xE8A530FA,0xFA109F14,0x42ACF871,0xDF7BC0C8,0x67C7A7AD,0x75720843,0xCDCE6F26, 0x95AD7F70,0x2D111815,0x3FA4B7FB,0x8718D09E,0x1ACFE827,0xA2738F42,0xB0C620AC,0x087A47C9, 0xA032AF3E,0x188EC85B,0x0A3B67B5,0xB28700D0,0x2F503869,0x97EC5F0C,0x8559F0E2,0x3DE59787, 0x658687D1,0xDD3AE0B4,0xCF8F4F5A,0x7733283F,0xEAE41086,0x525877E3,0x40EDD80D,0xF851BF68, 0xF02BF8A1,0x48979FC4,0x5A22302A,0xE29E574F,0x7F496FF6,0xC7F50893,0xD540A77D,0x6DFCC018, 0x359FD04E,0x8D23B72B,0x9F9618C5,0x272A7FA0,0xBAFD4719,0x0241207C,0x10F48F92,0xA848E8F7, 0x9B14583D,0x23A83F58,0x311D90B6,0x89A1F7D3,0x1476CF6A,0xACCAA80F,0xBE7F07E1,0x06C36084, 0x5EA070D2,0xE61C17B7,0xF4A9B859,0x4C15DF3C,0xD1C2E785,0x697E80E0,0x7BCB2F0E,0xC377486B, 0xCB0D0FA2,0x73B168C7,0x6104C729,0xD9B8A04C,0x446F98F5,0xFCD3FF90,0xEE66507E,0x56DA371B, 0x0EB9274D,0xB6054028,0xA4B0EFC6,0x1C0C88A3,0x81DBB01A,0x3967D77F,0x2BD27891,0x936E1FF4, 0x3B26F703,0x839A9066,0x912F3F88,0x299358ED,0xB4446054,0x0CF80731,0x1E4DA8DF,0xA6F1CFBA, 0xFE92DFEC,0x462EB889,0x549B1767,0xEC277002,0x71F048BB,0xC94C2FDE,0xDBF98030,0x6345E755, 0x6B3FA09C,0xD383C7F9,0xC1366817,0x798A0F72,0xE45D37CB,0x5CE150AE,0x4E54FF40,0xF6E89825, 0xAE8B8873,0x1637EF16,0x048240F8,0xBC3E279D,0x21E91F24,0x99557841,0x8BE0D7AF,0x335CB0CA, 0xED59B63B,0x55E5D15E,0x47507EB0,0xFFEC19D5,0x623B216C,0xDA874609,0xC832E9E7,0x708E8E82, 0x28ED9ED4,0x9051F9B1,0x82E4565F,0x3A58313A,0xA78F0983,0x1F336EE6,0x0D86C108,0xB53AA66D, 0xBD40E1A4,0x05FC86C1,0x1749292F,0xAFF54E4A,0x322276F3,0x8A9E1196,0x982BBE78,0x2097D91D, 0x78F4C94B,0xC048AE2E,0xD2FD01C0,0x6A4166A5,0xF7965E1C,0x4F2A3979,0x5D9F9697,0xE523F1F2, 0x4D6B1905,0xF5D77E60,0xE762D18E,0x5FDEB6EB,0xC2098E52,0x7AB5E937,0x680046D9,0xD0BC21BC, 0x88DF31EA,0x3063568F,0x22D6F961,0x9A6A9E04,0x07BDA6BD,0xBF01C1D8,0xADB46E36,0x15080953, 0x1D724E9A,0xA5CE29FF,0xB77B8611,0x0FC7E174,0x9210D9CD,0x2AACBEA8,0x38191146,0x80A57623, 0xD8C66675,0x607A0110,0x72CFAEFE,0xCA73C99B,0x57A4F122,0xEF189647,0xFDAD39A9,0x45115ECC, 0x764DEE06,0xCEF18963,0xDC44268D,0x64F841E8,0xF92F7951,0x41931E34,0x5326B1DA,0xEB9AD6BF, 0xB3F9C6E9,0x0B45A18C,0x19F00E62,0xA14C6907,0x3C9B51BE,0x842736DB,0x96929935,0x2E2EFE50, 0x2654B999,0x9EE8DEFC,0x8C5D7112,0x34E11677,0xA9362ECE,0x118A49AB,0x033FE645,0xBB838120, 0xE3E09176,0x5B5CF613,0x49E959FD,0xF1553E98,0x6C820621,0xD43E6144,0xC68BCEAA,0x7E37A9CF, 0xD67F4138,0x6EC3265D,0x7C7689B3,0xC4CAEED6,0x591DD66F,0xE1A1B10A,0xF3141EE4,0x4BA87981, 0x13CB69D7,0xAB770EB2,0xB9C2A15C,0x017EC639,0x9CA9FE80,0x241599E5,0x36A0360B,0x8E1C516E, 0x866616A7,0x3EDA71C2,0x2C6FDE2C,0x94D3B949,0x090481F0,0xB1B8E695,0xA30D497B,0x1BB12E1E, 0x43D23E48,0xFB6E592D,0xE9DBF6C3,0x516791A6,0xCCB0A91F,0x740CCE7A,0x66B96194,0xDE0506F1, } // beyond this point only relevant for Slicing-by-8 and Slicing-by-16 ,{ 0x00000000,0x3D6029B0,0x7AC05360,0x47A07AD0,0xF580A6C0,0xC8E08F70,0x8F40F5A0,0xB220DC10, 0x30704BC1,0x0D106271,0x4AB018A1,0x77D03111,0xC5F0ED01,0xF890C4B1,0xBF30BE61,0x825097D1, 0x60E09782,0x5D80BE32,0x1A20C4E2,0x2740ED52,0x95603142,0xA80018F2,0xEFA06222,0xD2C04B92, 0x5090DC43,0x6DF0F5F3,0x2A508F23,0x1730A693,0xA5107A83,0x98705333,0xDFD029E3,0xE2B00053, 0xC1C12F04,0xFCA106B4,0xBB017C64,0x866155D4,0x344189C4,0x0921A074,0x4E81DAA4,0x73E1F314, 0xF1B164C5,0xCCD14D75,0x8B7137A5,0xB6111E15,0x0431C205,0x3951EBB5,0x7EF19165,0x4391B8D5, 0xA121B886,0x9C419136,0xDBE1EBE6,0xE681C256,0x54A11E46,0x69C137F6,0x2E614D26,0x13016496, 0x9151F347,0xAC31DAF7,0xEB91A027,0xD6F18997,0x64D15587,0x59B17C37,0x1E1106E7,0x23712F57, 0x58F35849,0x659371F9,0x22330B29,0x1F532299,0xAD73FE89,0x9013D739,0xD7B3ADE9,0xEAD38459, 0x68831388,0x55E33A38,0x124340E8,0x2F236958,0x9D03B548,0xA0639CF8,0xE7C3E628,0xDAA3CF98, 0x3813CFCB,0x0573E67B,0x42D39CAB,0x7FB3B51B,0xCD93690B,0xF0F340BB,0xB7533A6B,0x8A3313DB, 0x0863840A,0x3503ADBA,0x72A3D76A,0x4FC3FEDA,0xFDE322CA,0xC0830B7A,0x872371AA,0xBA43581A, 0x9932774D,0xA4525EFD,0xE3F2242D,0xDE920D9D,0x6CB2D18D,0x51D2F83D,0x167282ED,0x2B12AB5D, 0xA9423C8C,0x9422153C,0xD3826FEC,0xEEE2465C,0x5CC29A4C,0x61A2B3FC,0x2602C92C,0x1B62E09C, 0xF9D2E0CF,0xC4B2C97F,0x8312B3AF,0xBE729A1F,0x0C52460F,0x31326FBF,0x7692156F,0x4BF23CDF, 0xC9A2AB0E,0xF4C282BE,0xB362F86E,0x8E02D1DE,0x3C220DCE,0x0142247E,0x46E25EAE,0x7B82771E, 0xB1E6B092,0x8C869922,0xCB26E3F2,0xF646CA42,0x44661652,0x79063FE2,0x3EA64532,0x03C66C82, 0x8196FB53,0xBCF6D2E3,0xFB56A833,0xC6368183,0x74165D93,0x49767423,0x0ED60EF3,0x33B62743, 0xD1062710,0xEC660EA0,0xABC67470,0x96A65DC0,0x248681D0,0x19E6A860,0x5E46D2B0,0x6326FB00, 0xE1766CD1,0xDC164561,0x9BB63FB1,0xA6D61601,0x14F6CA11,0x2996E3A1,0x6E369971,0x5356B0C1, 0x70279F96,0x4D47B626,0x0AE7CCF6,0x3787E546,0x85A73956,0xB8C710E6,0xFF676A36,0xC2074386, 0x4057D457,0x7D37FDE7,0x3A978737,0x07F7AE87,0xB5D77297,0x88B75B27,0xCF1721F7,0xF2770847, 0x10C70814,0x2DA721A4,0x6A075B74,0x576772C4,0xE547AED4,0xD8278764,0x9F87FDB4,0xA2E7D404, 0x20B743D5,0x1DD76A65,0x5A7710B5,0x67173905,0xD537E515,0xE857CCA5,0xAFF7B675,0x92979FC5, 0xE915E8DB,0xD475C16B,0x93D5BBBB,0xAEB5920B,0x1C954E1B,0x21F567AB,0x66551D7B,0x5B3534CB, 0xD965A31A,0xE4058AAA,0xA3A5F07A,0x9EC5D9CA,0x2CE505DA,0x11852C6A,0x562556BA,0x6B457F0A, 0x89F57F59,0xB49556E9,0xF3352C39,0xCE550589,0x7C75D999,0x4115F029,0x06B58AF9,0x3BD5A349, 0xB9853498,0x84E51D28,0xC34567F8,0xFE254E48,0x4C059258,0x7165BBE8,0x36C5C138,0x0BA5E888, 0x28D4C7DF,0x15B4EE6F,0x521494BF,0x6F74BD0F,0xDD54611F,0xE03448AF,0xA794327F,0x9AF41BCF, 0x18A48C1E,0x25C4A5AE,0x6264DF7E,0x5F04F6CE,0xED242ADE,0xD044036E,0x97E479BE,0xAA84500E, 0x4834505D,0x755479ED,0x32F4033D,0x0F942A8D,0xBDB4F69D,0x80D4DF2D,0xC774A5FD,0xFA148C4D, 0x78441B9C,0x4524322C,0x028448FC,0x3FE4614C,0x8DC4BD5C,0xB0A494EC,0xF704EE3C,0xCA64C78C, }, { 0x00000000,0xCB5CD3A5,0x4DC8A10B,0x869472AE,0x9B914216,0x50CD91B3,0xD659E31D,0x1D0530B8, 0xEC53826D,0x270F51C8,0xA19B2366,0x6AC7F0C3,0x77C2C07B,0xBC9E13DE,0x3A0A6170,0xF156B2D5, 0x03D6029B,0xC88AD13E,0x4E1EA390,0x85427035,0x9847408D,0x531B9328,0xD58FE186,0x1ED33223, 0xEF8580F6,0x24D95353,0xA24D21FD,0x6911F258,0x7414C2E0,0xBF481145,0x39DC63EB,0xF280B04E, 0x07AC0536,0xCCF0D693,0x4A64A43D,0x81387798,0x9C3D4720,0x57619485,0xD1F5E62B,0x1AA9358E, 0xEBFF875B,0x20A354FE,0xA6372650,0x6D6BF5F5,0x706EC54D,0xBB3216E8,0x3DA66446,0xF6FAB7E3, 0x047A07AD,0xCF26D408,0x49B2A6A6,0x82EE7503,0x9FEB45BB,0x54B7961E,0xD223E4B0,0x197F3715, 0xE82985C0,0x23755665,0xA5E124CB,0x6EBDF76E,0x73B8C7D6,0xB8E41473,0x3E7066DD,0xF52CB578, 0x0F580A6C,0xC404D9C9,0x4290AB67,0x89CC78C2,0x94C9487A,0x5F959BDF,0xD901E971,0x125D3AD4, 0xE30B8801,0x28575BA4,0xAEC3290A,0x659FFAAF,0x789ACA17,0xB3C619B2,0x35526B1C,0xFE0EB8B9, 0x0C8E08F7,0xC7D2DB52,0x4146A9FC,0x8A1A7A59,0x971F4AE1,0x5C439944,0xDAD7EBEA,0x118B384F, 0xE0DD8A9A,0x2B81593F,0xAD152B91,0x6649F834,0x7B4CC88C,0xB0101B29,0x36846987,0xFDD8BA22, 0x08F40F5A,0xC3A8DCFF,0x453CAE51,0x8E607DF4,0x93654D4C,0x58399EE9,0xDEADEC47,0x15F13FE2, 0xE4A78D37,0x2FFB5E92,0xA96F2C3C,0x6233FF99,0x7F36CF21,0xB46A1C84,0x32FE6E2A,0xF9A2BD8F, 0x0B220DC1,0xC07EDE64,0x46EAACCA,0x8DB67F6F,0x90B34FD7,0x5BEF9C72,0xDD7BEEDC,0x16273D79, 0xE7718FAC,0x2C2D5C09,0xAAB92EA7,0x61E5FD02,0x7CE0CDBA,0xB7BC1E1F,0x31286CB1,0xFA74BF14, 0x1EB014D8,0xD5ECC77D,0x5378B5D3,0x98246676,0x852156CE,0x4E7D856B,0xC8E9F7C5,0x03B52460, 0xF2E396B5,0x39BF4510,0xBF2B37BE,0x7477E41B,0x6972D4A3,0xA22E0706,0x24BA75A8,0xEFE6A60D, 0x1D661643,0xD63AC5E6,0x50AEB748,0x9BF264ED,0x86F75455,0x4DAB87F0,0xCB3FF55E,0x006326FB, 0xF135942E,0x3A69478B,0xBCFD3525,0x77A1E680,0x6AA4D638,0xA1F8059D,0x276C7733,0xEC30A496, 0x191C11EE,0xD240C24B,0x54D4B0E5,0x9F886340,0x828D53F8,0x49D1805D,0xCF45F2F3,0x04192156, 0xF54F9383,0x3E134026,0xB8873288,0x73DBE12D,0x6EDED195,0xA5820230,0x2316709E,0xE84AA33B, 0x1ACA1375,0xD196C0D0,0x5702B27E,0x9C5E61DB,0x815B5163,0x4A0782C6,0xCC93F068,0x07CF23CD, 0xF6999118,0x3DC542BD,0xBB513013,0x700DE3B6,0x6D08D30E,0xA65400AB,0x20C07205,0xEB9CA1A0, 0x11E81EB4,0xDAB4CD11,0x5C20BFBF,0x977C6C1A,0x8A795CA2,0x41258F07,0xC7B1FDA9,0x0CED2E0C, 0xFDBB9CD9,0x36E74F7C,0xB0733DD2,0x7B2FEE77,0x662ADECF,0xAD760D6A,0x2BE27FC4,0xE0BEAC61, 0x123E1C2F,0xD962CF8A,0x5FF6BD24,0x94AA6E81,0x89AF5E39,0x42F38D9C,0xC467FF32,0x0F3B2C97, 0xFE6D9E42,0x35314DE7,0xB3A53F49,0x78F9ECEC,0x65FCDC54,0xAEA00FF1,0x28347D5F,0xE368AEFA, 0x16441B82,0xDD18C827,0x5B8CBA89,0x90D0692C,0x8DD55994,0x46898A31,0xC01DF89F,0x0B412B3A, 0xFA1799EF,0x314B4A4A,0xB7DF38E4,0x7C83EB41,0x6186DBF9,0xAADA085C,0x2C4E7AF2,0xE712A957, 0x15921919,0xDECECABC,0x585AB812,0x93066BB7,0x8E035B0F,0x455F88AA,0xC3CBFA04,0x089729A1, 0xF9C19B74,0x329D48D1,0xB4093A7F,0x7F55E9DA,0x6250D962,0xA90C0AC7,0x2F987869,0xE4C4ABCC, }, { 0x00000000,0xA6770BB4,0x979F1129,0x31E81A9D,0xF44F2413,0x52382FA7,0x63D0353A,0xC5A73E8E, 0x33EF4E67,0x959845D3,0xA4705F4E,0x020754FA,0xC7A06A74,0x61D761C0,0x503F7B5D,0xF64870E9, 0x67DE9CCE,0xC1A9977A,0xF0418DE7,0x56368653,0x9391B8DD,0x35E6B369,0x040EA9F4,0xA279A240, 0x5431D2A9,0xF246D91D,0xC3AEC380,0x65D9C834,0xA07EF6BA,0x0609FD0E,0x37E1E793,0x9196EC27, 0xCFBD399C,0x69CA3228,0x582228B5,0xFE552301,0x3BF21D8F,0x9D85163B,0xAC6D0CA6,0x0A1A0712, 0xFC5277FB,0x5A257C4F,0x6BCD66D2,0xCDBA6D66,0x081D53E8,0xAE6A585C,0x9F8242C1,0x39F54975, 0xA863A552,0x0E14AEE6,0x3FFCB47B,0x998BBFCF,0x5C2C8141,0xFA5B8AF5,0xCBB39068,0x6DC49BDC, 0x9B8CEB35,0x3DFBE081,0x0C13FA1C,0xAA64F1A8,0x6FC3CF26,0xC9B4C492,0xF85CDE0F,0x5E2BD5BB, 0x440B7579,0xE27C7ECD,0xD3946450,0x75E36FE4,0xB044516A,0x16335ADE,0x27DB4043,0x81AC4BF7, 0x77E43B1E,0xD19330AA,0xE07B2A37,0x460C2183,0x83AB1F0D,0x25DC14B9,0x14340E24,0xB2430590, 0x23D5E9B7,0x85A2E203,0xB44AF89E,0x123DF32A,0xD79ACDA4,0x71EDC610,0x4005DC8D,0xE672D739, 0x103AA7D0,0xB64DAC64,0x87A5B6F9,0x21D2BD4D,0xE47583C3,0x42028877,0x73EA92EA,0xD59D995E, 0x8BB64CE5,0x2DC14751,0x1C295DCC,0xBA5E5678,0x7FF968F6,0xD98E6342,0xE86679DF,0x4E11726B, 0xB8590282,0x1E2E0936,0x2FC613AB,0x89B1181F,0x4C162691,0xEA612D25,0xDB8937B8,0x7DFE3C0C, 0xEC68D02B,0x4A1FDB9F,0x7BF7C102,0xDD80CAB6,0x1827F438,0xBE50FF8C,0x8FB8E511,0x29CFEEA5, 0xDF879E4C,0x79F095F8,0x48188F65,0xEE6F84D1,0x2BC8BA5F,0x8DBFB1EB,0xBC57AB76,0x1A20A0C2, 0x8816EAF2,0x2E61E146,0x1F89FBDB,0xB9FEF06F,0x7C59CEE1,0xDA2EC555,0xEBC6DFC8,0x4DB1D47C, 0xBBF9A495,0x1D8EAF21,0x2C66B5BC,0x8A11BE08,0x4FB68086,0xE9C18B32,0xD82991AF,0x7E5E9A1B, 0xEFC8763C,0x49BF7D88,0x78576715,0xDE206CA1,0x1B87522F,0xBDF0599B,0x8C184306,0x2A6F48B2, 0xDC27385B,0x7A5033EF,0x4BB82972,0xEDCF22C6,0x28681C48,0x8E1F17FC,0xBFF70D61,0x198006D5, 0x47ABD36E,0xE1DCD8DA,0xD034C247,0x7643C9F3,0xB3E4F77D,0x1593FCC9,0x247BE654,0x820CEDE0, 0x74449D09,0xD23396BD,0xE3DB8C20,0x45AC8794,0x800BB91A,0x267CB2AE,0x1794A833,0xB1E3A387, 0x20754FA0,0x86024414,0xB7EA5E89,0x119D553D,0xD43A6BB3,0x724D6007,0x43A57A9A,0xE5D2712E, 0x139A01C7,0xB5ED0A73,0x840510EE,0x22721B5A,0xE7D525D4,0x41A22E60,0x704A34FD,0xD63D3F49, 0xCC1D9F8B,0x6A6A943F,0x5B828EA2,0xFDF58516,0x3852BB98,0x9E25B02C,0xAFCDAAB1,0x09BAA105, 0xFFF2D1EC,0x5985DA58,0x686DC0C5,0xCE1ACB71,0x0BBDF5FF,0xADCAFE4B,0x9C22E4D6,0x3A55EF62, 0xABC30345,0x0DB408F1,0x3C5C126C,0x9A2B19D8,0x5F8C2756,0xF9FB2CE2,0xC813367F,0x6E643DCB, 0x982C4D22,0x3E5B4696,0x0FB35C0B,0xA9C457BF,0x6C636931,0xCA146285,0xFBFC7818,0x5D8B73AC, 0x03A0A617,0xA5D7ADA3,0x943FB73E,0x3248BC8A,0xF7EF8204,0x519889B0,0x6070932D,0xC6079899, 0x304FE870,0x9638E3C4,0xA7D0F959,0x01A7F2ED,0xC400CC63,0x6277C7D7,0x539FDD4A,0xF5E8D6FE, 0x647E3AD9,0xC209316D,0xF3E12BF0,0x55962044,0x90311ECA,0x3646157E,0x07AE0FE3,0xA1D90457, 0x579174BE,0xF1E67F0A,0xC00E6597,0x66796E23,0xA3DE50AD,0x05A95B19,0x34414184,0x92364A30, }, { 0x00000000,0xCCAA009E,0x4225077D,0x8E8F07E3,0x844A0EFA,0x48E00E64,0xC66F0987,0x0AC50919, 0xD3E51BB5,0x1F4F1B2B,0x91C01CC8,0x5D6A1C56,0x57AF154F,0x9B0515D1,0x158A1232,0xD92012AC, 0x7CBB312B,0xB01131B5,0x3E9E3656,0xF23436C8,0xF8F13FD1,0x345B3F4F,0xBAD438AC,0x767E3832, 0xAF5E2A9E,0x63F42A00,0xED7B2DE3,0x21D12D7D,0x2B142464,0xE7BE24FA,0x69312319,0xA59B2387, 0xF9766256,0x35DC62C8,0xBB53652B,0x77F965B5,0x7D3C6CAC,0xB1966C32,0x3F196BD1,0xF3B36B4F, 0x2A9379E3,0xE639797D,0x68B67E9E,0xA41C7E00,0xAED97719,0x62737787,0xECFC7064,0x205670FA, 0x85CD537D,0x496753E3,0xC7E85400,0x0B42549E,0x01875D87,0xCD2D5D19,0x43A25AFA,0x8F085A64, 0x562848C8,0x9A824856,0x140D4FB5,0xD8A74F2B,0xD2624632,0x1EC846AC,0x9047414F,0x5CED41D1, 0x299DC2ED,0xE537C273,0x6BB8C590,0xA712C50E,0xADD7CC17,0x617DCC89,0xEFF2CB6A,0x2358CBF4, 0xFA78D958,0x36D2D9C6,0xB85DDE25,0x74F7DEBB,0x7E32D7A2,0xB298D73C,0x3C17D0DF,0xF0BDD041, 0x5526F3C6,0x998CF358,0x1703F4BB,0xDBA9F425,0xD16CFD3C,0x1DC6FDA2,0x9349FA41,0x5FE3FADF, 0x86C3E873,0x4A69E8ED,0xC4E6EF0E,0x084CEF90,0x0289E689,0xCE23E617,0x40ACE1F4,0x8C06E16A, 0xD0EBA0BB,0x1C41A025,0x92CEA7C6,0x5E64A758,0x54A1AE41,0x980BAEDF,0x1684A93C,0xDA2EA9A2, 0x030EBB0E,0xCFA4BB90,0x412BBC73,0x8D81BCED,0x8744B5F4,0x4BEEB56A,0xC561B289,0x09CBB217, 0xAC509190,0x60FA910E,0xEE7596ED,0x22DF9673,0x281A9F6A,0xE4B09FF4,0x6A3F9817,0xA6959889, 0x7FB58A25,0xB31F8ABB,0x3D908D58,0xF13A8DC6,0xFBFF84DF,0x37558441,0xB9DA83A2,0x7570833C, 0x533B85DA,0x9F918544,0x111E82A7,0xDDB48239,0xD7718B20,0x1BDB8BBE,0x95548C5D,0x59FE8CC3, 0x80DE9E6F,0x4C749EF1,0xC2FB9912,0x0E51998C,0x04949095,0xC83E900B,0x46B197E8,0x8A1B9776, 0x2F80B4F1,0xE32AB46F,0x6DA5B38C,0xA10FB312,0xABCABA0B,0x6760BA95,0xE9EFBD76,0x2545BDE8, 0xFC65AF44,0x30CFAFDA,0xBE40A839,0x72EAA8A7,0x782FA1BE,0xB485A120,0x3A0AA6C3,0xF6A0A65D, 0xAA4DE78C,0x66E7E712,0xE868E0F1,0x24C2E06F,0x2E07E976,0xE2ADE9E8,0x6C22EE0B,0xA088EE95, 0x79A8FC39,0xB502FCA7,0x3B8DFB44,0xF727FBDA,0xFDE2F2C3,0x3148F25D,0xBFC7F5BE,0x736DF520, 0xD6F6D6A7,0x1A5CD639,0x94D3D1DA,0x5879D144,0x52BCD85D,0x9E16D8C3,0x1099DF20,0xDC33DFBE, 0x0513CD12,0xC9B9CD8C,0x4736CA6F,0x8B9CCAF1,0x8159C3E8,0x4DF3C376,0xC37CC495,0x0FD6C40B, 0x7AA64737,0xB60C47A9,0x3883404A,0xF42940D4,0xFEEC49CD,0x32464953,0xBCC94EB0,0x70634E2E, 0xA9435C82,0x65E95C1C,0xEB665BFF,0x27CC5B61,0x2D095278,0xE1A352E6,0x6F2C5505,0xA386559B, 0x061D761C,0xCAB77682,0x44387161,0x889271FF,0x825778E6,0x4EFD7878,0xC0727F9B,0x0CD87F05, 0xD5F86DA9,0x19526D37,0x97DD6AD4,0x5B776A4A,0x51B26353,0x9D1863CD,0x1397642E,0xDF3D64B0, 0x83D02561,0x4F7A25FF,0xC1F5221C,0x0D5F2282,0x079A2B9B,0xCB302B05,0x45BF2CE6,0x89152C78, 0x50353ED4,0x9C9F3E4A,0x121039A9,0xDEBA3937,0xD47F302E,0x18D530B0,0x965A3753,0x5AF037CD, 0xFF6B144A,0x33C114D4,0xBD4E1337,0x71E413A9,0x7B211AB0,0xB78B1A2E,0x39041DCD,0xF5AE1D53, 0x2C8E0FFF,0xE0240F61,0x6EAB0882,0xA201081C,0xA8C40105,0x646E019B,0xEAE10678,0x264B06E6, } // beyond this point only relevant for Slicing-by-16 ,{ 0x00000000,0x177B1443,0x2EF62886,0x398D3CC5,0x5DEC510C,0x4A97454F,0x731A798A,0x64616DC9, 0xBBD8A218,0xACA3B65B,0x952E8A9E,0x82559EDD,0xE634F314,0xF14FE757,0xC8C2DB92,0xDFB9CFD1, 0xACC04271,0xBBBB5632,0x82366AF7,0x954D7EB4,0xF12C137D,0xE657073E,0xDFDA3BFB,0xC8A12FB8, 0x1718E069,0x0063F42A,0x39EEC8EF,0x2E95DCAC,0x4AF4B165,0x5D8FA526,0x640299E3,0x73798DA0, 0x82F182A3,0x958A96E0,0xAC07AA25,0xBB7CBE66,0xDF1DD3AF,0xC866C7EC,0xF1EBFB29,0xE690EF6A, 0x392920BB,0x2E5234F8,0x17DF083D,0x00A41C7E,0x64C571B7,0x73BE65F4,0x4A335931,0x5D484D72, 0x2E31C0D2,0x394AD491,0x00C7E854,0x17BCFC17,0x73DD91DE,0x64A6859D,0x5D2BB958,0x4A50AD1B, 0x95E962CA,0x82927689,0xBB1F4A4C,0xAC645E0F,0xC80533C6,0xDF7E2785,0xE6F31B40,0xF1880F03, 0xDE920307,0xC9E91744,0xF0642B81,0xE71F3FC2,0x837E520B,0x94054648,0xAD887A8D,0xBAF36ECE, 0x654AA11F,0x7231B55C,0x4BBC8999,0x5CC79DDA,0x38A6F013,0x2FDDE450,0x1650D895,0x012BCCD6, 0x72524176,0x65295535,0x5CA469F0,0x4BDF7DB3,0x2FBE107A,0x38C50439,0x014838FC,0x16332CBF, 0xC98AE36E,0xDEF1F72D,0xE77CCBE8,0xF007DFAB,0x9466B262,0x831DA621,0xBA909AE4,0xADEB8EA7, 0x5C6381A4,0x4B1895E7,0x7295A922,0x65EEBD61,0x018FD0A8,0x16F4C4EB,0x2F79F82E,0x3802EC6D, 0xE7BB23BC,0xF0C037FF,0xC94D0B3A,0xDE361F79,0xBA5772B0,0xAD2C66F3,0x94A15A36,0x83DA4E75, 0xF0A3C3D5,0xE7D8D796,0xDE55EB53,0xC92EFF10,0xAD4F92D9,0xBA34869A,0x83B9BA5F,0x94C2AE1C, 0x4B7B61CD,0x5C00758E,0x658D494B,0x72F65D08,0x169730C1,0x01EC2482,0x38611847,0x2F1A0C04, 0x6655004F,0x712E140C,0x48A328C9,0x5FD83C8A,0x3BB95143,0x2CC24500,0x154F79C5,0x02346D86, 0xDD8DA257,0xCAF6B614,0xF37B8AD1,0xE4009E92,0x8061F35B,0x971AE718,0xAE97DBDD,0xB9ECCF9E, 0xCA95423E,0xDDEE567D,0xE4636AB8,0xF3187EFB,0x97791332,0x80020771,0xB98F3BB4,0xAEF42FF7, 0x714DE026,0x6636F465,0x5FBBC8A0,0x48C0DCE3,0x2CA1B12A,0x3BDAA569,0x025799AC,0x152C8DEF, 0xE4A482EC,0xF3DF96AF,0xCA52AA6A,0xDD29BE29,0xB948D3E0,0xAE33C7A3,0x97BEFB66,0x80C5EF25, 0x5F7C20F4,0x480734B7,0x718A0872,0x66F11C31,0x029071F8,0x15EB65BB,0x2C66597E,0x3B1D4D3D, 0x4864C09D,0x5F1FD4DE,0x6692E81B,0x71E9FC58,0x15889191,0x02F385D2,0x3B7EB917,0x2C05AD54, 0xF3BC6285,0xE4C776C6,0xDD4A4A03,0xCA315E40,0xAE503389,0xB92B27CA,0x80A61B0F,0x97DD0F4C, 0xB8C70348,0xAFBC170B,0x96312BCE,0x814A3F8D,0xE52B5244,0xF2504607,0xCBDD7AC2,0xDCA66E81, 0x031FA150,0x1464B513,0x2DE989D6,0x3A929D95,0x5EF3F05C,0x4988E41F,0x7005D8DA,0x677ECC99, 0x14074139,0x037C557A,0x3AF169BF,0x2D8A7DFC,0x49EB1035,0x5E900476,0x671D38B3,0x70662CF0, 0xAFDFE321,0xB8A4F762,0x8129CBA7,0x9652DFE4,0xF233B22D,0xE548A66E,0xDCC59AAB,0xCBBE8EE8, 0x3A3681EB,0x2D4D95A8,0x14C0A96D,0x03BBBD2E,0x67DAD0E7,0x70A1C4A4,0x492CF861,0x5E57EC22, 0x81EE23F3,0x969537B0,0xAF180B75,0xB8631F36,0xDC0272FF,0xCB7966BC,0xF2F45A79,0xE58F4E3A, 0x96F6C39A,0x818DD7D9,0xB800EB1C,0xAF7BFF5F,0xCB1A9296,0xDC6186D5,0xE5ECBA10,0xF297AE53, 0x2D2E6182,0x3A5575C1,0x03D84904,0x14A35D47,0x70C2308E,0x67B924CD,0x5E341808,0x494F0C4B, }, { 0x00000000,0xEFC26B3E,0x04F5D03D,0xEB37BB03,0x09EBA07A,0xE629CB44,0x0D1E7047,0xE2DC1B79, 0x13D740F4,0xFC152BCA,0x172290C9,0xF8E0FBF7,0x1A3CE08E,0xF5FE8BB0,0x1EC930B3,0xF10B5B8D, 0x27AE81E8,0xC86CEAD6,0x235B51D5,0xCC993AEB,0x2E452192,0xC1874AAC,0x2AB0F1AF,0xC5729A91, 0x3479C11C,0xDBBBAA22,0x308C1121,0xDF4E7A1F,0x3D926166,0xD2500A58,0x3967B15B,0xD6A5DA65, 0x4F5D03D0,0xA09F68EE,0x4BA8D3ED,0xA46AB8D3,0x46B6A3AA,0xA974C894,0x42437397,0xAD8118A9, 0x5C8A4324,0xB348281A,0x587F9319,0xB7BDF827,0x5561E35E,0xBAA38860,0x51943363,0xBE56585D, 0x68F38238,0x8731E906,0x6C065205,0x83C4393B,0x61182242,0x8EDA497C,0x65EDF27F,0x8A2F9941, 0x7B24C2CC,0x94E6A9F2,0x7FD112F1,0x901379CF,0x72CF62B6,0x9D0D0988,0x763AB28B,0x99F8D9B5, 0x9EBA07A0,0x71786C9E,0x9A4FD79D,0x758DBCA3,0x9751A7DA,0x7893CCE4,0x93A477E7,0x7C661CD9, 0x8D6D4754,0x62AF2C6A,0x89989769,0x665AFC57,0x8486E72E,0x6B448C10,0x80733713,0x6FB15C2D, 0xB9148648,0x56D6ED76,0xBDE15675,0x52233D4B,0xB0FF2632,0x5F3D4D0C,0xB40AF60F,0x5BC89D31, 0xAAC3C6BC,0x4501AD82,0xAE361681,0x41F47DBF,0xA32866C6,0x4CEA0DF8,0xA7DDB6FB,0x481FDDC5, 0xD1E70470,0x3E256F4E,0xD512D44D,0x3AD0BF73,0xD80CA40A,0x37CECF34,0xDCF97437,0x333B1F09, 0xC2304484,0x2DF22FBA,0xC6C594B9,0x2907FF87,0xCBDBE4FE,0x24198FC0,0xCF2E34C3,0x20EC5FFD, 0xF6498598,0x198BEEA6,0xF2BC55A5,0x1D7E3E9B,0xFFA225E2,0x10604EDC,0xFB57F5DF,0x14959EE1, 0xE59EC56C,0x0A5CAE52,0xE16B1551,0x0EA97E6F,0xEC756516,0x03B70E28,0xE880B52B,0x0742DE15, 0xE6050901,0x09C7623F,0xE2F0D93C,0x0D32B202,0xEFEEA97B,0x002CC245,0xEB1B7946,0x04D91278, 0xF5D249F5,0x1A1022CB,0xF12799C8,0x1EE5F2F6,0xFC39E98F,0x13FB82B1,0xF8CC39B2,0x170E528C, 0xC1AB88E9,0x2E69E3D7,0xC55E58D4,0x2A9C33EA,0xC8402893,0x278243AD,0xCCB5F8AE,0x23779390, 0xD27CC81D,0x3DBEA323,0xD6891820,0x394B731E,0xDB976867,0x34550359,0xDF62B85A,0x30A0D364, 0xA9580AD1,0x469A61EF,0xADADDAEC,0x426FB1D2,0xA0B3AAAB,0x4F71C195,0xA4467A96,0x4B8411A8, 0xBA8F4A25,0x554D211B,0xBE7A9A18,0x51B8F126,0xB364EA5F,0x5CA68161,0xB7913A62,0x5853515C, 0x8EF68B39,0x6134E007,0x8A035B04,0x65C1303A,0x871D2B43,0x68DF407D,0x83E8FB7E,0x6C2A9040, 0x9D21CBCD,0x72E3A0F3,0x99D41BF0,0x761670CE,0x94CA6BB7,0x7B080089,0x903FBB8A,0x7FFDD0B4, 0x78BF0EA1,0x977D659F,0x7C4ADE9C,0x9388B5A2,0x7154AEDB,0x9E96C5E5,0x75A17EE6,0x9A6315D8, 0x6B684E55,0x84AA256B,0x6F9D9E68,0x805FF556,0x6283EE2F,0x8D418511,0x66763E12,0x89B4552C, 0x5F118F49,0xB0D3E477,0x5BE45F74,0xB426344A,0x56FA2F33,0xB938440D,0x520FFF0E,0xBDCD9430, 0x4CC6CFBD,0xA304A483,0x48331F80,0xA7F174BE,0x452D6FC7,0xAAEF04F9,0x41D8BFFA,0xAE1AD4C4, 0x37E20D71,0xD820664F,0x3317DD4C,0xDCD5B672,0x3E09AD0B,0xD1CBC635,0x3AFC7D36,0xD53E1608, 0x24354D85,0xCBF726BB,0x20C09DB8,0xCF02F686,0x2DDEEDFF,0xC21C86C1,0x292B3DC2,0xC6E956FC, 0x104C8C99,0xFF8EE7A7,0x14B95CA4,0xFB7B379A,0x19A72CE3,0xF66547DD,0x1D52FCDE,0xF29097E0, 0x039BCC6D,0xEC59A753,0x076E1C50,0xE8AC776E,0x0A706C17,0xE5B20729,0x0E85BC2A,0xE147D714, }, { 0x00000000,0xC18EDFC0,0x586CB9C1,0x99E26601,0xB0D97382,0x7157AC42,0xE8B5CA43,0x293B1583, 0xBAC3E145,0x7B4D3E85,0xE2AF5884,0x23218744,0x0A1A92C7,0xCB944D07,0x52762B06,0x93F8F4C6, 0xAEF6C4CB,0x6F781B0B,0xF69A7D0A,0x3714A2CA,0x1E2FB749,0xDFA16889,0x46430E88,0x87CDD148, 0x1435258E,0xD5BBFA4E,0x4C599C4F,0x8DD7438F,0xA4EC560C,0x656289CC,0xFC80EFCD,0x3D0E300D, 0x869C8FD7,0x47125017,0xDEF03616,0x1F7EE9D6,0x3645FC55,0xF7CB2395,0x6E294594,0xAFA79A54, 0x3C5F6E92,0xFDD1B152,0x6433D753,0xA5BD0893,0x8C861D10,0x4D08C2D0,0xD4EAA4D1,0x15647B11, 0x286A4B1C,0xE9E494DC,0x7006F2DD,0xB1882D1D,0x98B3389E,0x593DE75E,0xC0DF815F,0x01515E9F, 0x92A9AA59,0x53277599,0xCAC51398,0x0B4BCC58,0x2270D9DB,0xE3FE061B,0x7A1C601A,0xBB92BFDA, 0xD64819EF,0x17C6C62F,0x8E24A02E,0x4FAA7FEE,0x66916A6D,0xA71FB5AD,0x3EFDD3AC,0xFF730C6C, 0x6C8BF8AA,0xAD05276A,0x34E7416B,0xF5699EAB,0xDC528B28,0x1DDC54E8,0x843E32E9,0x45B0ED29, 0x78BEDD24,0xB93002E4,0x20D264E5,0xE15CBB25,0xC867AEA6,0x09E97166,0x900B1767,0x5185C8A7, 0xC27D3C61,0x03F3E3A1,0x9A1185A0,0x5B9F5A60,0x72A44FE3,0xB32A9023,0x2AC8F622,0xEB4629E2, 0x50D49638,0x915A49F8,0x08B82FF9,0xC936F039,0xE00DE5BA,0x21833A7A,0xB8615C7B,0x79EF83BB, 0xEA17777D,0x2B99A8BD,0xB27BCEBC,0x73F5117C,0x5ACE04FF,0x9B40DB3F,0x02A2BD3E,0xC32C62FE, 0xFE2252F3,0x3FAC8D33,0xA64EEB32,0x67C034F2,0x4EFB2171,0x8F75FEB1,0x169798B0,0xD7194770, 0x44E1B3B6,0x856F6C76,0x1C8D0A77,0xDD03D5B7,0xF438C034,0x35B61FF4,0xAC5479F5,0x6DDAA635, 0x77E1359F,0xB66FEA5F,0x2F8D8C5E,0xEE03539E,0xC738461D,0x06B699DD,0x9F54FFDC,0x5EDA201C, 0xCD22D4DA,0x0CAC0B1A,0x954E6D1B,0x54C0B2DB,0x7DFBA758,0xBC757898,0x25971E99,0xE419C159, 0xD917F154,0x18992E94,0x817B4895,0x40F59755,0x69CE82D6,0xA8405D16,0x31A23B17,0xF02CE4D7, 0x63D41011,0xA25ACFD1,0x3BB8A9D0,0xFA367610,0xD30D6393,0x1283BC53,0x8B61DA52,0x4AEF0592, 0xF17DBA48,0x30F36588,0xA9110389,0x689FDC49,0x41A4C9CA,0x802A160A,0x19C8700B,0xD846AFCB, 0x4BBE5B0D,0x8A3084CD,0x13D2E2CC,0xD25C3D0C,0xFB67288F,0x3AE9F74F,0xA30B914E,0x62854E8E, 0x5F8B7E83,0x9E05A143,0x07E7C742,0xC6691882,0xEF520D01,0x2EDCD2C1,0xB73EB4C0,0x76B06B00, 0xE5489FC6,0x24C64006,0xBD242607,0x7CAAF9C7,0x5591EC44,0x941F3384,0x0DFD5585,0xCC738A45, 0xA1A92C70,0x6027F3B0,0xF9C595B1,0x384B4A71,0x11705FF2,0xD0FE8032,0x491CE633,0x889239F3, 0x1B6ACD35,0xDAE412F5,0x430674F4,0x8288AB34,0xABB3BEB7,0x6A3D6177,0xF3DF0776,0x3251D8B6, 0x0F5FE8BB,0xCED1377B,0x5733517A,0x96BD8EBA,0xBF869B39,0x7E0844F9,0xE7EA22F8,0x2664FD38, 0xB59C09FE,0x7412D63E,0xEDF0B03F,0x2C7E6FFF,0x05457A7C,0xC4CBA5BC,0x5D29C3BD,0x9CA71C7D, 0x2735A3A7,0xE6BB7C67,0x7F591A66,0xBED7C5A6,0x97ECD025,0x56620FE5,0xCF8069E4,0x0E0EB624, 0x9DF642E2,0x5C789D22,0xC59AFB23,0x041424E3,0x2D2F3160,0xECA1EEA0,0x754388A1,0xB4CD5761, 0x89C3676C,0x484DB8AC,0xD1AFDEAD,0x1021016D,0x391A14EE,0xF894CB2E,0x6176AD2F,0xA0F872EF, 0x33008629,0xF28E59E9,0x6B6C3FE8,0xAAE2E028,0x83D9F5AB,0x42572A6B,0xDBB54C6A,0x1A3B93AA, }, { 0x00000000,0x9BA54C6F,0xEC3B9E9F,0x779ED2F0,0x03063B7F,0x98A37710,0xEF3DA5E0,0x7498E98F, 0x060C76FE,0x9DA93A91,0xEA37E861,0x7192A40E,0x050A4D81,0x9EAF01EE,0xE931D31E,0x72949F71, 0x0C18EDFC,0x97BDA193,0xE0237363,0x7B863F0C,0x0F1ED683,0x94BB9AEC,0xE325481C,0x78800473, 0x0A149B02,0x91B1D76D,0xE62F059D,0x7D8A49F2,0x0912A07D,0x92B7EC12,0xE5293EE2,0x7E8C728D, 0x1831DBF8,0x83949797,0xF40A4567,0x6FAF0908,0x1B37E087,0x8092ACE8,0xF70C7E18,0x6CA93277, 0x1E3DAD06,0x8598E169,0xF2063399,0x69A37FF6,0x1D3B9679,0x869EDA16,0xF10008E6,0x6AA54489, 0x14293604,0x8F8C7A6B,0xF812A89B,0x63B7E4F4,0x172F0D7B,0x8C8A4114,0xFB1493E4,0x60B1DF8B, 0x122540FA,0x89800C95,0xFE1EDE65,0x65BB920A,0x11237B85,0x8A8637EA,0xFD18E51A,0x66BDA975, 0x3063B7F0,0xABC6FB9F,0xDC58296F,0x47FD6500,0x33658C8F,0xA8C0C0E0,0xDF5E1210,0x44FB5E7F, 0x366FC10E,0xADCA8D61,0xDA545F91,0x41F113FE,0x3569FA71,0xAECCB61E,0xD95264EE,0x42F72881, 0x3C7B5A0C,0xA7DE1663,0xD040C493,0x4BE588FC,0x3F7D6173,0xA4D82D1C,0xD346FFEC,0x48E3B383, 0x3A772CF2,0xA1D2609D,0xD64CB26D,0x4DE9FE02,0x3971178D,0xA2D45BE2,0xD54A8912,0x4EEFC57D, 0x28526C08,0xB3F72067,0xC469F297,0x5FCCBEF8,0x2B545777,0xB0F11B18,0xC76FC9E8,0x5CCA8587, 0x2E5E1AF6,0xB5FB5699,0xC2658469,0x59C0C806,0x2D582189,0xB6FD6DE6,0xC163BF16,0x5AC6F379, 0x244A81F4,0xBFEFCD9B,0xC8711F6B,0x53D45304,0x274CBA8B,0xBCE9F6E4,0xCB772414,0x50D2687B, 0x2246F70A,0xB9E3BB65,0xCE7D6995,0x55D825FA,0x2140CC75,0xBAE5801A,0xCD7B52EA,0x56DE1E85, 0x60C76FE0,0xFB62238F,0x8CFCF17F,0x1759BD10,0x63C1549F,0xF86418F0,0x8FFACA00,0x145F866F, 0x66CB191E,0xFD6E5571,0x8AF08781,0x1155CBEE,0x65CD2261,0xFE686E0E,0x89F6BCFE,0x1253F091, 0x6CDF821C,0xF77ACE73,0x80E41C83,0x1B4150EC,0x6FD9B963,0xF47CF50C,0x83E227FC,0x18476B93, 0x6AD3F4E2,0xF176B88D,0x86E86A7D,0x1D4D2612,0x69D5CF9D,0xF27083F2,0x85EE5102,0x1E4B1D6D, 0x78F6B418,0xE353F877,0x94CD2A87,0x0F6866E8,0x7BF08F67,0xE055C308,0x97CB11F8,0x0C6E5D97, 0x7EFAC2E6,0xE55F8E89,0x92C15C79,0x09641016,0x7DFCF999,0xE659B5F6,0x91C76706,0x0A622B69, 0x74EE59E4,0xEF4B158B,0x98D5C77B,0x03708B14,0x77E8629B,0xEC4D2EF4,0x9BD3FC04,0x0076B06B, 0x72E22F1A,0xE9476375,0x9ED9B185,0x057CFDEA,0x71E41465,0xEA41580A,0x9DDF8AFA,0x067AC695, 0x50A4D810,0xCB01947F,0xBC9F468F,0x273A0AE0,0x53A2E36F,0xC807AF00,0xBF997DF0,0x243C319F, 0x56A8AEEE,0xCD0DE281,0xBA933071,0x21367C1E,0x55AE9591,0xCE0BD9FE,0xB9950B0E,0x22304761, 0x5CBC35EC,0xC7197983,0xB087AB73,0x2B22E71C,0x5FBA0E93,0xC41F42FC,0xB381900C,0x2824DC63, 0x5AB04312,0xC1150F7D,0xB68BDD8D,0x2D2E91E2,0x59B6786D,0xC2133402,0xB58DE6F2,0x2E28AA9D, 0x489503E8,0xD3304F87,0xA4AE9D77,0x3F0BD118,0x4B933897,0xD03674F8,0xA7A8A608,0x3C0DEA67, 0x4E997516,0xD53C3979,0xA2A2EB89,0x3907A7E6,0x4D9F4E69,0xD63A0206,0xA1A4D0F6,0x3A019C99, 0x448DEE14,0xDF28A27B,0xA8B6708B,0x33133CE4,0x478BD56B,0xDC2E9904,0xABB04BF4,0x3015079B, 0x428198EA,0xD924D485,0xAEBA0675,0x351F4A1A,0x4187A395,0xDA22EFFA,0xADBC3D0A,0x36197165, }, { 0x00000000,0xDD96D985,0x605CB54B,0xBDCA6CCE,0xC0B96A96,0x1D2FB313,0xA0E5DFDD,0x7D730658, 0x5A03D36D,0x87950AE8,0x3A5F6626,0xE7C9BFA3,0x9ABAB9FB,0x472C607E,0xFAE60CB0,0x2770D535, 0xB407A6DA,0x69917F5F,0xD45B1391,0x09CDCA14,0x74BECC4C,0xA92815C9,0x14E27907,0xC974A082, 0xEE0475B7,0x3392AC32,0x8E58C0FC,0x53CE1979,0x2EBD1F21,0xF32BC6A4,0x4EE1AA6A,0x937773EF, 0xB37E4BF5,0x6EE89270,0xD322FEBE,0x0EB4273B,0x73C72163,0xAE51F8E6,0x139B9428,0xCE0D4DAD, 0xE97D9898,0x34EB411D,0x89212DD3,0x54B7F456,0x29C4F20E,0xF4522B8B,0x49984745,0x940E9EC0, 0x0779ED2F,0xDAEF34AA,0x67255864,0xBAB381E1,0xC7C087B9,0x1A565E3C,0xA79C32F2,0x7A0AEB77, 0x5D7A3E42,0x80ECE7C7,0x3D268B09,0xE0B0528C,0x9DC354D4,0x40558D51,0xFD9FE19F,0x2009381A, 0xBD8D91AB,0x601B482E,0xDDD124E0,0x0047FD65,0x7D34FB3D,0xA0A222B8,0x1D684E76,0xC0FE97F3, 0xE78E42C6,0x3A189B43,0x87D2F78D,0x5A442E08,0x27372850,0xFAA1F1D5,0x476B9D1B,0x9AFD449E, 0x098A3771,0xD41CEEF4,0x69D6823A,0xB4405BBF,0xC9335DE7,0x14A58462,0xA96FE8AC,0x74F93129, 0x5389E41C,0x8E1F3D99,0x33D55157,0xEE4388D2,0x93308E8A,0x4EA6570F,0xF36C3BC1,0x2EFAE244, 0x0EF3DA5E,0xD36503DB,0x6EAF6F15,0xB339B690,0xCE4AB0C8,0x13DC694D,0xAE160583,0x7380DC06, 0x54F00933,0x8966D0B6,0x34ACBC78,0xE93A65FD,0x944963A5,0x49DFBA20,0xF415D6EE,0x29830F6B, 0xBAF47C84,0x6762A501,0xDAA8C9CF,0x073E104A,0x7A4D1612,0xA7DBCF97,0x1A11A359,0xC7877ADC, 0xE0F7AFE9,0x3D61766C,0x80AB1AA2,0x5D3DC327,0x204EC57F,0xFDD81CFA,0x40127034,0x9D84A9B1, 0xA06A2517,0x7DFCFC92,0xC036905C,0x1DA049D9,0x60D34F81,0xBD459604,0x008FFACA,0xDD19234F, 0xFA69F67A,0x27FF2FFF,0x9A354331,0x47A39AB4,0x3AD09CEC,0xE7464569,0x5A8C29A7,0x871AF022, 0x146D83CD,0xC9FB5A48,0x74313686,0xA9A7EF03,0xD4D4E95B,0x094230DE,0xB4885C10,0x691E8595, 0x4E6E50A0,0x93F88925,0x2E32E5EB,0xF3A43C6E,0x8ED73A36,0x5341E3B3,0xEE8B8F7D,0x331D56F8, 0x13146EE2,0xCE82B767,0x7348DBA9,0xAEDE022C,0xD3AD0474,0x0E3BDDF1,0xB3F1B13F,0x6E6768BA, 0x4917BD8F,0x9481640A,0x294B08C4,0xF4DDD141,0x89AED719,0x54380E9C,0xE9F26252,0x3464BBD7, 0xA713C838,0x7A8511BD,0xC74F7D73,0x1AD9A4F6,0x67AAA2AE,0xBA3C7B2B,0x07F617E5,0xDA60CE60, 0xFD101B55,0x2086C2D0,0x9D4CAE1E,0x40DA779B,0x3DA971C3,0xE03FA846,0x5DF5C488,0x80631D0D, 0x1DE7B4BC,0xC0716D39,0x7DBB01F7,0xA02DD872,0xDD5EDE2A,0x00C807AF,0xBD026B61,0x6094B2E4, 0x47E467D1,0x9A72BE54,0x27B8D29A,0xFA2E0B1F,0x875D0D47,0x5ACBD4C2,0xE701B80C,0x3A976189, 0xA9E01266,0x7476CBE3,0xC9BCA72D,0x142A7EA8,0x695978F0,0xB4CFA175,0x0905CDBB,0xD493143E, 0xF3E3C10B,0x2E75188E,0x93BF7440,0x4E29ADC5,0x335AAB9D,0xEECC7218,0x53061ED6,0x8E90C753, 0xAE99FF49,0x730F26CC,0xCEC54A02,0x13539387,0x6E2095DF,0xB3B64C5A,0x0E7C2094,0xD3EAF911, 0xF49A2C24,0x290CF5A1,0x94C6996F,0x495040EA,0x342346B2,0xE9B59F37,0x547FF3F9,0x89E92A7C, 0x1A9E5993,0xC7088016,0x7AC2ECD8,0xA754355D,0xDA273305,0x07B1EA80,0xBA7B864E,0x67ED5FCB, 0x409D8AFE,0x9D0B537B,0x20C13FB5,0xFD57E630,0x8024E068,0x5DB239ED,0xE0785523,0x3DEE8CA6, }, { 0x00000000,0x9D0FE176,0xE16EC4AD,0x7C6125DB,0x19AC8F1B,0x84A36E6D,0xF8C24BB6,0x65CDAAC0, 0x33591E36,0xAE56FF40,0xD237DA9B,0x4F383BED,0x2AF5912D,0xB7FA705B,0xCB9B5580,0x5694B4F6, 0x66B23C6C,0xFBBDDD1A,0x87DCF8C1,0x1AD319B7,0x7F1EB377,0xE2115201,0x9E7077DA,0x037F96AC, 0x55EB225A,0xC8E4C32C,0xB485E6F7,0x298A0781,0x4C47AD41,0xD1484C37,0xAD2969EC,0x3026889A, 0xCD6478D8,0x506B99AE,0x2C0ABC75,0xB1055D03,0xD4C8F7C3,0x49C716B5,0x35A6336E,0xA8A9D218, 0xFE3D66EE,0x63328798,0x1F53A243,0x825C4335,0xE791E9F5,0x7A9E0883,0x06FF2D58,0x9BF0CC2E, 0xABD644B4,0x36D9A5C2,0x4AB88019,0xD7B7616F,0xB27ACBAF,0x2F752AD9,0x53140F02,0xCE1BEE74, 0x988F5A82,0x0580BBF4,0x79E19E2F,0xE4EE7F59,0x8123D599,0x1C2C34EF,0x604D1134,0xFD42F042, 0x41B9F7F1,0xDCB61687,0xA0D7335C,0x3DD8D22A,0x581578EA,0xC51A999C,0xB97BBC47,0x24745D31, 0x72E0E9C7,0xEFEF08B1,0x938E2D6A,0x0E81CC1C,0x6B4C66DC,0xF64387AA,0x8A22A271,0x172D4307, 0x270BCB9D,0xBA042AEB,0xC6650F30,0x5B6AEE46,0x3EA74486,0xA3A8A5F0,0xDFC9802B,0x42C6615D, 0x1452D5AB,0x895D34DD,0xF53C1106,0x6833F070,0x0DFE5AB0,0x90F1BBC6,0xEC909E1D,0x719F7F6B, 0x8CDD8F29,0x11D26E5F,0x6DB34B84,0xF0BCAAF2,0x95710032,0x087EE144,0x741FC49F,0xE91025E9, 0xBF84911F,0x228B7069,0x5EEA55B2,0xC3E5B4C4,0xA6281E04,0x3B27FF72,0x4746DAA9,0xDA493BDF, 0xEA6FB345,0x77605233,0x0B0177E8,0x960E969E,0xF3C33C5E,0x6ECCDD28,0x12ADF8F3,0x8FA21985, 0xD936AD73,0x44394C05,0x385869DE,0xA55788A8,0xC09A2268,0x5D95C31E,0x21F4E6C5,0xBCFB07B3, 0x8373EFE2,0x1E7C0E94,0x621D2B4F,0xFF12CA39,0x9ADF60F9,0x07D0818F,0x7BB1A454,0xE6BE4522, 0xB02AF1D4,0x2D2510A2,0x51443579,0xCC4BD40F,0xA9867ECF,0x34899FB9,0x48E8BA62,0xD5E75B14, 0xE5C1D38E,0x78CE32F8,0x04AF1723,0x99A0F655,0xFC6D5C95,0x6162BDE3,0x1D039838,0x800C794E, 0xD698CDB8,0x4B972CCE,0x37F60915,0xAAF9E863,0xCF3442A3,0x523BA3D5,0x2E5A860E,0xB3556778, 0x4E17973A,0xD318764C,0xAF795397,0x3276B2E1,0x57BB1821,0xCAB4F957,0xB6D5DC8C,0x2BDA3DFA, 0x7D4E890C,0xE041687A,0x9C204DA1,0x012FACD7,0x64E20617,0xF9EDE761,0x858CC2BA,0x188323CC, 0x28A5AB56,0xB5AA4A20,0xC9CB6FFB,0x54C48E8D,0x3109244D,0xAC06C53B,0xD067E0E0,0x4D680196, 0x1BFCB560,0x86F35416,0xFA9271CD,0x679D90BB,0x02503A7B,0x9F5FDB0D,0xE33EFED6,0x7E311FA0, 0xC2CA1813,0x5FC5F965,0x23A4DCBE,0xBEAB3DC8,0xDB669708,0x4669767E,0x3A0853A5,0xA707B2D3, 0xF1930625,0x6C9CE753,0x10FDC288,0x8DF223FE,0xE83F893E,0x75306848,0x09514D93,0x945EACE5, 0xA478247F,0x3977C509,0x4516E0D2,0xD81901A4,0xBDD4AB64,0x20DB4A12,0x5CBA6FC9,0xC1B58EBF, 0x97213A49,0x0A2EDB3F,0x764FFEE4,0xEB401F92,0x8E8DB552,0x13825424,0x6FE371FF,0xF2EC9089, 0x0FAE60CB,0x92A181BD,0xEEC0A466,0x73CF4510,0x1602EFD0,0x8B0D0EA6,0xF76C2B7D,0x6A63CA0B, 0x3CF77EFD,0xA1F89F8B,0xDD99BA50,0x40965B26,0x255BF1E6,0xB8541090,0xC435354B,0x593AD43D, 0x691C5CA7,0xF413BDD1,0x8872980A,0x157D797C,0x70B0D3BC,0xEDBF32CA,0x91DE1711,0x0CD1F667, 0x5A454291,0xC74AA3E7,0xBB2B863C,0x2624674A,0x43E9CD8A,0xDEE62CFC,0xA2870927,0x3F88E851, }, { 0x00000000,0xB9FBDBE8,0xA886B191,0x117D6A79,0x8A7C6563,0x3387BE8B,0x22FAD4F2,0x9B010F1A, 0xCF89CC87,0x7672176F,0x670F7D16,0xDEF4A6FE,0x45F5A9E4,0xFC0E720C,0xED731875,0x5488C39D, 0x44629F4F,0xFD9944A7,0xECE42EDE,0x551FF536,0xCE1EFA2C,0x77E521C4,0x66984BBD,0xDF639055, 0x8BEB53C8,0x32108820,0x236DE259,0x9A9639B1,0x019736AB,0xB86CED43,0xA911873A,0x10EA5CD2, 0x88C53E9E,0x313EE576,0x20438F0F,0x99B854E7,0x02B95BFD,0xBB428015,0xAA3FEA6C,0x13C43184, 0x474CF219,0xFEB729F1,0xEFCA4388,0x56319860,0xCD30977A,0x74CB4C92,0x65B626EB,0xDC4DFD03, 0xCCA7A1D1,0x755C7A39,0x64211040,0xDDDACBA8,0x46DBC4B2,0xFF201F5A,0xEE5D7523,0x57A6AECB, 0x032E6D56,0xBAD5B6BE,0xABA8DCC7,0x1253072F,0x89520835,0x30A9D3DD,0x21D4B9A4,0x982F624C, 0xCAFB7B7D,0x7300A095,0x627DCAEC,0xDB861104,0x40871E1E,0xF97CC5F6,0xE801AF8F,0x51FA7467, 0x0572B7FA,0xBC896C12,0xADF4066B,0x140FDD83,0x8F0ED299,0x36F50971,0x27886308,0x9E73B8E0, 0x8E99E432,0x37623FDA,0x261F55A3,0x9FE48E4B,0x04E58151,0xBD1E5AB9,0xAC6330C0,0x1598EB28, 0x411028B5,0xF8EBF35D,0xE9969924,0x506D42CC,0xCB6C4DD6,0x7297963E,0x63EAFC47,0xDA1127AF, 0x423E45E3,0xFBC59E0B,0xEAB8F472,0x53432F9A,0xC8422080,0x71B9FB68,0x60C49111,0xD93F4AF9, 0x8DB78964,0x344C528C,0x253138F5,0x9CCAE31D,0x07CBEC07,0xBE3037EF,0xAF4D5D96,0x16B6867E, 0x065CDAAC,0xBFA70144,0xAEDA6B3D,0x1721B0D5,0x8C20BFCF,0x35DB6427,0x24A60E5E,0x9D5DD5B6, 0xC9D5162B,0x702ECDC3,0x6153A7BA,0xD8A87C52,0x43A97348,0xFA52A8A0,0xEB2FC2D9,0x52D41931, 0x4E87F0BB,0xF77C2B53,0xE601412A,0x5FFA9AC2,0xC4FB95D8,0x7D004E30,0x6C7D2449,0xD586FFA1, 0x810E3C3C,0x38F5E7D4,0x29888DAD,0x90735645,0x0B72595F,0xB28982B7,0xA3F4E8CE,0x1A0F3326, 0x0AE56FF4,0xB31EB41C,0xA263DE65,0x1B98058D,0x80990A97,0x3962D17F,0x281FBB06,0x91E460EE, 0xC56CA373,0x7C97789B,0x6DEA12E2,0xD411C90A,0x4F10C610,0xF6EB1DF8,0xE7967781,0x5E6DAC69, 0xC642CE25,0x7FB915CD,0x6EC47FB4,0xD73FA45C,0x4C3EAB46,0xF5C570AE,0xE4B81AD7,0x5D43C13F, 0x09CB02A2,0xB030D94A,0xA14DB333,0x18B668DB,0x83B767C1,0x3A4CBC29,0x2B31D650,0x92CA0DB8, 0x8220516A,0x3BDB8A82,0x2AA6E0FB,0x935D3B13,0x085C3409,0xB1A7EFE1,0xA0DA8598,0x19215E70, 0x4DA99DED,0xF4524605,0xE52F2C7C,0x5CD4F794,0xC7D5F88E,0x7E2E2366,0x6F53491F,0xD6A892F7, 0x847C8BC6,0x3D87502E,0x2CFA3A57,0x9501E1BF,0x0E00EEA5,0xB7FB354D,0xA6865F34,0x1F7D84DC, 0x4BF54741,0xF20E9CA9,0xE373F6D0,0x5A882D38,0xC1892222,0x7872F9CA,0x690F93B3,0xD0F4485B, 0xC01E1489,0x79E5CF61,0x6898A518,0xD1637EF0,0x4A6271EA,0xF399AA02,0xE2E4C07B,0x5B1F1B93, 0x0F97D80E,0xB66C03E6,0xA711699F,0x1EEAB277,0x85EBBD6D,0x3C106685,0x2D6D0CFC,0x9496D714, 0x0CB9B558,0xB5426EB0,0xA43F04C9,0x1DC4DF21,0x86C5D03B,0x3F3E0BD3,0x2E4361AA,0x97B8BA42, 0xC33079DF,0x7ACBA237,0x6BB6C84E,0xD24D13A6,0x494C1CBC,0xF0B7C754,0xE1CAAD2D,0x583176C5, 0x48DB2A17,0xF120F1FF,0xE05D9B86,0x59A6406E,0xC2A74F74,0x7B5C949C,0x6A21FEE5,0xD3DA250D, 0x8752E690,0x3EA93D78,0x2FD45701,0x962F8CE9,0x0D2E83F3,0xB4D5581B,0xA5A83262,0x1C53E98A, }, { 0x00000000,0xAE689191,0x87A02563,0x29C8B4F2,0xD4314C87,0x7A59DD16,0x539169E4,0xFDF9F875, 0x73139F4F,0xDD7B0EDE,0xF4B3BA2C,0x5ADB2BBD,0xA722D3C8,0x094A4259,0x2082F6AB,0x8EEA673A, 0xE6273E9E,0x484FAF0F,0x61871BFD,0xCFEF8A6C,0x32167219,0x9C7EE388,0xB5B6577A,0x1BDEC6EB, 0x9534A1D1,0x3B5C3040,0x129484B2,0xBCFC1523,0x4105ED56,0xEF6D7CC7,0xC6A5C835,0x68CD59A4, 0x173F7B7D,0xB957EAEC,0x909F5E1E,0x3EF7CF8F,0xC30E37FA,0x6D66A66B,0x44AE1299,0xEAC68308, 0x642CE432,0xCA4475A3,0xE38CC151,0x4DE450C0,0xB01DA8B5,0x1E753924,0x37BD8DD6,0x99D51C47, 0xF11845E3,0x5F70D472,0x76B86080,0xD8D0F111,0x25290964,0x8B4198F5,0xA2892C07,0x0CE1BD96, 0x820BDAAC,0x2C634B3D,0x05ABFFCF,0xABC36E5E,0x563A962B,0xF85207BA,0xD19AB348,0x7FF222D9, 0x2E7EF6FA,0x8016676B,0xA9DED399,0x07B64208,0xFA4FBA7D,0x54272BEC,0x7DEF9F1E,0xD3870E8F, 0x5D6D69B5,0xF305F824,0xDACD4CD6,0x74A5DD47,0x895C2532,0x2734B4A3,0x0EFC0051,0xA09491C0, 0xC859C864,0x663159F5,0x4FF9ED07,0xE1917C96,0x1C6884E3,0xB2001572,0x9BC8A180,0x35A03011, 0xBB4A572B,0x1522C6BA,0x3CEA7248,0x9282E3D9,0x6F7B1BAC,0xC1138A3D,0xE8DB3ECF,0x46B3AF5E, 0x39418D87,0x97291C16,0xBEE1A8E4,0x10893975,0xED70C100,0x43185091,0x6AD0E463,0xC4B875F2, 0x4A5212C8,0xE43A8359,0xCDF237AB,0x639AA63A,0x9E635E4F,0x300BCFDE,0x19C37B2C,0xB7ABEABD, 0xDF66B319,0x710E2288,0x58C6967A,0xF6AE07EB,0x0B57FF9E,0xA53F6E0F,0x8CF7DAFD,0x229F4B6C, 0xAC752C56,0x021DBDC7,0x2BD50935,0x85BD98A4,0x784460D1,0xD62CF140,0xFFE445B2,0x518CD423, 0x5CFDEDF4,0xF2957C65,0xDB5DC897,0x75355906,0x88CCA173,0x26A430E2,0x0F6C8410,0xA1041581, 0x2FEE72BB,0x8186E32A,0xA84E57D8,0x0626C649,0xFBDF3E3C,0x55B7AFAD,0x7C7F1B5F,0xD2178ACE, 0xBADAD36A,0x14B242FB,0x3D7AF609,0x93126798,0x6EEB9FED,0xC0830E7C,0xE94BBA8E,0x47232B1F, 0xC9C94C25,0x67A1DDB4,0x4E696946,0xE001F8D7,0x1DF800A2,0xB3909133,0x9A5825C1,0x3430B450, 0x4BC29689,0xE5AA0718,0xCC62B3EA,0x620A227B,0x9FF3DA0E,0x319B4B9F,0x1853FF6D,0xB63B6EFC, 0x38D109C6,0x96B99857,0xBF712CA5,0x1119BD34,0xECE04541,0x4288D4D0,0x6B406022,0xC528F1B3, 0xADE5A817,0x038D3986,0x2A458D74,0x842D1CE5,0x79D4E490,0xD7BC7501,0xFE74C1F3,0x501C5062, 0xDEF63758,0x709EA6C9,0x5956123B,0xF73E83AA,0x0AC77BDF,0xA4AFEA4E,0x8D675EBC,0x230FCF2D, 0x72831B0E,0xDCEB8A9F,0xF5233E6D,0x5B4BAFFC,0xA6B25789,0x08DAC618,0x211272EA,0x8F7AE37B, 0x01908441,0xAFF815D0,0x8630A122,0x285830B3,0xD5A1C8C6,0x7BC95957,0x5201EDA5,0xFC697C34, 0x94A42590,0x3ACCB401,0x130400F3,0xBD6C9162,0x40956917,0xEEFDF886,0xC7354C74,0x695DDDE5, 0xE7B7BADF,0x49DF2B4E,0x60179FBC,0xCE7F0E2D,0x3386F658,0x9DEE67C9,0xB426D33B,0x1A4E42AA, 0x65BC6073,0xCBD4F1E2,0xE21C4510,0x4C74D481,0xB18D2CF4,0x1FE5BD65,0x362D0997,0x98459806, 0x16AFFF3C,0xB8C76EAD,0x910FDA5F,0x3F674BCE,0xC29EB3BB,0x6CF6222A,0x453E96D8,0xEB560749, 0x839B5EED,0x2DF3CF7C,0x043B7B8E,0xAA53EA1F,0x57AA126A,0xF9C283FB,0xD00A3709,0x7E62A698, 0xF088C1A2,0x5EE05033,0x7728E4C1,0xD9407550,0x24B98D25,0x8AD11CB4,0xA319A846,0x0D7139D7, } }; /// LICENSE_END.10 /* File-funtions section */ // Windows/Linux compatible file type #ifdef unix typedef FILE* FP; const FP FPNULL=NULL; const char* const RB="rb"; const char* const WB="wb"; const char* const RBPLUS="rb+"; const char* const ABPLUS="ab+"; const char* const AB="ab"; vector g_write_fp; vector g_write_filename; FP myfopen(const char* filename, const char* mode,int64_t i_date=0) { if (g_control_c) { myprintf("\n\nThe house is closed by control-c!\n"); return FPNULL; } FP risultato=fopen(filename,mode); if (risultato!=FPNULL) { #if (!defined(SOLARIS)) if (i_date!=0) if (strcmp(mode, WB) == 0 || strcmp(mode, AB) == 0 || strcmp(mode, ABPLUS) == 0) { struct timeval times[2]; time_t nowz; time(&nowz); const struct tm *local = localtime(&nowz); if (local == NULL) { myprintf("40525! guru on tm\n"); } else { times[0].tv_sec = unix_time(i_date) - local->tm_gmtoff; // atime times[0].tv_usec = 0; times[1].tv_sec = unix_time(i_date) - - local->tm_gmtoff; // mtime times[1].tv_usec = 0; if (futimes(fileno(risultato),times)!=0) myprintf("39787! WARN Linux myfopen futimes error!\n"); else { if (flagverbose) myprintf("39791: Linux setting times OK at %s\n",migliaia(i_date)); } } } #endif // corresponds to #if (#if (!defined(SOLARIS))) if (g_chunk_size>0) if (strcmp(mode,RB)!=0) { g_write_fp.push_back(risultato); g_write_filename.push_back(filename); if (flagdebug3) myprintf("00082: write on (pool %s) |%s| %s\n",migliaia(g_write_fp.size()),migliaia(int64_t(risultato)),filename); } } return risultato; } int myfclose(FP* fp) { if ((*fp)==FPNULL) { if (flagdebug) myprintf("00083: fclose on unix FPNULL ignored\n"); return EOF; } if (g_chunk_size>0) { for (unsigned int i=0;itm_gmtoff; // atime times[0].tv_usec = 0; times[1].tv_sec = unix_time(date) - local->tm_gmtoff; // mtime times[1].tv_usec = 0; if (futimes(fileno(i_fp), times) != 0) myprintf("48744! WARN Linux tocca_now futimes error!\n"); } #endif } #else // Windows typedef HANDLE FP; const FP FPNULL=INVALID_HANDLE_VALUE; vector g_write_fp; vector g_write_filename; void tocca_now(FP i_fp) { if (i_fp==FPNULL) return; if (flagdebug) myprintf("48718: Windows tocca_now %s\n",migliaia(int64_t(i_fp))); SYSTEMTIME st; GetLocalTime(&st); FILETIME ft,ftutc; SystemTimeToFileTime(&st, &ft); LocalFileTimeToFileTime(&ft, &ftutc); if (!SetFileTime(i_fp, NULL, NULL, &ftutc)) myprintf("48725! WARN tocca_now cannot set filetime (error %s) su fp %s\n",migliaia((int64_t)GetLastError()),migliaia2(int64_t(i_fp))); } typedef enum {RB, WB, RBPLUS, WBPLUS} MODE; // fopen modes // Open file. Only modes "rb", "wb", "rb+" and "wb+" are supported on WINDOWS FP myfopen(const char* filename, MODE mode, int64_t i_date=0) { if (g_control_c) { myprintf("\n\nThe house is closed by control-c!\n"); return FPNULL; } if (filename==NULL) { myprintf("39836$ myfopen with NULL filename!\n"); return FPNULL; } DWORD access=0; if (mode!=WB) access=GENERIC_READ; if (mode!=RB) access|=GENERIC_WRITE; DWORD disp=OPEN_ALWAYS; // wb or wb+ if (mode==RB || mode==RBPLUS) disp=OPEN_EXISTING; DWORD share=FILE_SHARE_READ; if (mode==RB) share|=FILE_SHARE_WRITE|FILE_SHARE_DELETE; /// kludge: we are doing a "C:" backup, bypass ACLS if (command=='q') { if (flagdebug3) myprintf("39851: fopen with command 'q' CreateFile\n"); return CreateFile(utow(filename).c_str(), access, share,NULL, disp, FILE_FLAG_BACKUP_SEMANTICS, NULL); } if (flagdebug3) myprintf("00089: CreateFile\n"); FP risultato=CreateFile(utow(filename).c_str(), access, share,NULL, disp, FILE_ATTRIBUTE_NORMAL , NULL); if (flagdebug3) myprintf("00090: Createfile risultato %s\n",migliaia(int64_t(risultato))); if ((mode==WB) || (mode=WBPLUS)) if (i_date!=0) { SYSTEMTIME st; st.wYear =i_date/10000000000LL%10000; st.wMonth =i_date/100000000%100; st.wDayOfWeek =0; // ignored st.wDay =i_date/1000000%100; st.wHour =i_date/10000%100; st.wMinute =i_date/100%100; st.wSecond =i_date%100; st.wMilliseconds =0; FILETIME ft; SystemTimeToFileTime(&st, &ft); if (flagdebug3) myprintf("39874: setting filetime on myfopen at %s\n",migliaia(i_date)); if (!SetFileTime(risultato, NULL, NULL, &ft)) myprintf("39387! failed settime (error %s) on %Z\n",migliaia((int64_t)GetLastError()),filename); } if (g_chunk_size>0) if ((mode==WB) || (mode==WBPLUS)) { g_write_fp.push_back(risultato); g_write_filename.push_back(filename); if (flagdebug3) myprintf("00091: write on (pool %s) |%s| %s\n",migliaia(g_write_fp.size()),migliaia(int64_t(risultato)),filename); } return risultato; } int myfclose(FP* fp) { if ((*fp)==FPNULL) { if (flagdebug) myprintf("00092: win fclose on FPNULL ignored\n"); return EOF; } if (g_chunk_size>0) { for (unsigned int i=0;i1) r/=size; return r; } // Get file position int64_t ftello(FP fp) { if ((int64_t)fp==0) { myprintf("00098! ftello on FP zero\n"); return 0; } LONG h=0; DWORD r=SetFilePointer(fp, 0, &h, FILE_CURRENT); return r+(uint64_t(h)<<32); } // Move file pointer by offset. origin is SEEK_SET (from start), SEEK_CUR, // (from current position), or SEEK_END (from end). int fseeko(FP fp, int64_t offset, int origin) { if (origin==SEEK_SET) origin=FILE_BEGIN; else if (origin==SEEK_CUR) origin=FILE_CURRENT; else if (origin==SEEK_END) origin=FILE_END; LONG h=uint64_t(offset)>>32; SetFilePointer(fp, offset&0xffffffffull, &h, origin); return GetLastError()!=NO_ERROR; } #endif // corresponds to #ifdef (#ifdef unix) FP g_fp_zpaq =0; int g_crc32_sequence_data =0; int g_crc32_sequence_index =0; uint32_t g_crc32_index =0; // Write nobj objects of size size from ptr to fp. Return number written. // "overloaded" from fwrite() for flagfasttxt size_t myfwrite(const void* ptr, size_t size, size_t nobj, FP fp) { if (fp==0) { if (flagdebug3) myprintf("00099! FP NOT POSITIVE\n"); return 0; } if ((nobj*size)==0) return 0; /* char mynomefile[100]; uint32_t crc=crc32_16bytes(ptr,nobj*size); if ((fp==g_fp_zpaq) || (g_fp_zpaq==0)) snprintf(mynomefile,sizeof(mynomefile),"z:\\d_%08d_start_%11s_size_%7s_%08X",g_crc32_sequence_data,migliaia3(ftello(fp)),migliaia2(nobj*size),crc); else snprintf(mynomefile,sizeof(mynomefile),"z:\\i_%08d_start_%11s_size_%7s_%08X",g_crc32_sequence_index,migliaia3(ftello(fp)),migliaia2(nobj*size)); FILE* myfile=fopen(mynomefile, "wb"); if (myfile==NULL) { myprintf("00100: cannot write on %s\n",mynomefile); exit(0); } fwrite(ptr,size*nobj,1,myfile); fclose(myfile); */ #ifdef _WIN32 DWORD r=0; if (flagdebug3) myprintf("00101: WriteFile FP %s size %s nobj %s r= %08d FTELLO %s\n",migliaia(int64_t(fp)),migliaia3(int64_t(size)),migliaia4(int64_t(nobj)),r,migliaia2(ftello(fp))); WriteFile(fp, ptr, size*nobj, &r, NULL); #else size_t r=fwrite(ptr, size, nobj, fp); #endif // corresponds to #ifdef (#ifdef _WIN32) g_fexpected+=(size*nobj); g_fwritten+=r; if (flagfasttxt || flagbackupzeta) { if ((fp==g_fp_zpaq) || (g_fp_zpaq==0)) { if (flagdebug3) { myprintf("00102: fwrite |%08d| pos %9s g_hep %s r=|%d| ",int(g_crc32_sequence_data),migliaia(ftello(fp)),migliaia2(g_header_pos),r); myprintf("00103: g_crc_get_header %d\n",int(g_crc_getheader)); } if (g_crc32_sequence_data==0) // this is the header of an encrypted piece { if (r==32) { g_crc_header=crc32_16bytes(ptr,r); if (flagdebug3) myprintf("00104: HEADER r=%08d %08X\n",r,g_crc_header); g_franzhash_file.add(ptr,r); g_franzhash_file_bytes+=r; if (flagdebug3) myprintf("00106$ FRANZ-HEADER r=%08d %s\n",r,bin2hex_64(g_franzhash_file.hash()).c_str()); } else { uint32_t crc=0; crc=crc32_16bytes((char*)ptr+104,r-104); g_crc_body=crc32_combine(g_crc_body,crc,r-104); if (flagdebug3) myprintf(" SKIPPOZ 104 [1] "); g_veryfirst=false; g_franzhash_file.add((char*)ptr+104,r-104); g_franzhash_file_bytes+=r-104; if (flagdebug3) myprintf("00101$ FRANZ-SKIPPO 104 [1] r=%08d %s\n",r-104,bin2hex_64(g_franzhash_file.hash()).c_str()); } } else { if (r==104) { g_crc_jidac=crc32_16bytes(ptr,r); if (flagdebug3) myprintf("00105: JIDAC r=%08d %08X\n",r,g_crc_jidac); memcpy(g_franzhash_104,ptr,r); } else { uint32_t crc=0; if (g_veryfirst) { if (flagdebug3) myprintf(" SKIPPO 104 [2] "); crc=crc32_16bytes((char*)ptr+104,r-104); g_crc_body=crc32_combine(g_crc_body,crc,r-104); g_veryfirst=false; g_franzhash_file.add((char*)ptr+104,r-104); g_franzhash_file_bytes+=r-104; if (flagdebug3) myprintf("00106$ FRANZ-SKIPPO 104 [2] r=%08d %s\n",r-104,bin2hex_64(g_franzhash_file.hash()).c_str()); } else { crc=crc32_16bytes(ptr,r); g_crc_body=crc32_combine(g_crc_body,crc,r); g_franzhash_file.add(ptr,r); g_franzhash_file_bytes+=r; if (flagdebug3) myprintf("00108$ FRANZ-BODY r=%08d %s\n",r,bin2hex_64(g_franzhash_file.hash()).c_str()); } if (flagdebug3) myprintf("00106: BODY %08X\n",g_crc_body); } } g_crc32_sequence_data++; } else { if (flagdebug2) myprintf("00107: Doing CRC-32 on index for bytes %s\n",migliaia(r)); uint32_t crc =crc32_16bytes(ptr,r); g_crc32_index =crc32_combine(g_crc32_index,crc,r); g_crc32_sequence_index++; } } if (flagdebug) if ((size*nobj)!=r) myprintf("00108! expected bytes != written (media full?) %s vs %s\n",migliaia((int64_t)(size*nobj)),migliaia2((int64_t)r)); if (size>1) r/=size; return r; } // a bit different: check only for "real" files bool realfileexists(const string& i_filename) { #ifdef unix struct stat buffer; if (stat(i_filename.c_str(),&buffer)==0) if (!S_ISDIR(buffer.st_mode)) return true; #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 HANDLE myhandle; WIN32_FIND_DATA findfiledata; std::wstring wpattern=utow(i_filename.c_str()); myhandle=FindFirstFile(wpattern.c_str(),&findfiledata); if (myhandle!=INVALID_HANDLE_VALUE) { FindClose(myhandle); if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) return false; else return true; } #endif // corresponds to #ifdef (#ifdef _WIN32) return false; } /// return size, date and attr bool getfileinfo(string i_filename,int64_t& o_size,int64_t& o_date,int64_t& o_attr) { o_size=0; o_date=0; o_attr=0; #ifdef unix while (i_filename.size()>1 && i_filename[i_filename.size()-1]=='/') i_filename=i_filename.substr(0, i_filename.size()-1); struct stat sb; if (!lstat(i_filename.c_str(), &sb)) { if (S_ISREG(sb.st_mode)) { o_date=decimal_time(sb.st_mtime); o_size=sb.st_size; o_attr='u'+(sb.st_mode<<8); return true; } } #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 WIN32_FIND_DATA ffd; string t=i_filename; if (t.size()>0 && t[t.size()-1]=='/') t+="*"; HANDLE h=FindFirstFile(utow(t.c_str()).c_str(), &ffd); if (h==INVALID_HANDLE_VALUE && GetLastError()!=ERROR_FILE_NOT_FOUND && GetLastError()!=ERROR_PATH_NOT_FOUND) printerr("36230",t.c_str(),0); if (h!=INVALID_HANDLE_VALUE) { SYSTEMTIME st; if (FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) o_date=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; o_size=ffd.nFileSizeLow+(int64_t(ffd.nFileSizeHigh)<<32); o_attr=ffd.dwFileAttributes; FindClose(h); return true; } FindClose(h); #endif // corresponds to #ifdef (#ifdef _WIN32) return false; } bool getdirinfo(string i_folder,int64_t& o_date,int64_t& o_attr) { o_date=0; o_attr=0; if (!isdirectory(i_folder)) { myprintf("00111! This is not a folder <<%Z>>\n",i_folder.c_str()); return false; } #ifdef unix struct stat sb; if (!lstat(i_folder.c_str(), &sb)) if (S_ISDIR(sb.st_mode)) { /* time_t st_atime; // time of last access time_t st_mtime; // time of last modification time_t st_ctime; // time of last status change */ o_date=decimal_time(sb.st_mtime); o_attr='u'+(sb.st_mode<<8); return true; } #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 i_folder+="*.*"; WIN32_FIND_DATA ffd; HANDLE h=FindFirstFile(utow(i_folder.c_str()).c_str(), &ffd); if (h==INVALID_HANDLE_VALUE) { myprintf("00113! INVALID_HANDLE for <<%s>>\n",i_folder.c_str()); return false; } SYSTEMTIME st; if (FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) o_date=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; /* if (FileTimeToSystemTime(&ffd.ftCreationTime, &st)) creationdate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; if (FileTimeToSystemTime(&ffd.ftLastAccessTime, &st)) accessdate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; */ o_attr=ffd.dwFileAttributes; FindClose(h); return true; #endif // corresponds to #ifdef (#ifdef _WIN32) return false; } bool delete_file_no_mercy(const char* filename) { #ifdef unix return remove(filename)==0; #else return DeleteFile(utow(filename).c_str()); #endif // corresponds to #ifdef (#ifdef unix) } bool delete_dir(const char* i_directory) { #ifdef unix return remove(i_directory)==0; #else SetFileAttributesW(utow(i_directory).c_str(),FILE_ATTRIBUTE_NORMAL); return RemoveDirectoryW(utow(i_directory).c_str()); #endif // corresponds to #ifdef (#ifdef unix) } /// risky command to make a rd folder /s (or rm -r) #ifdef unix int erredbarras(const std::string &i_path) { bool risultato=false; DIR *d=opendir(i_path.c_str()); if (d) { const struct dirent *p; risultato=true; while (risultato && (p=readdir(d))) { if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, "..")) continue; bool risultato2=false; struct stat statbuf; std::string temp; if (isdirectory(i_path)) temp=i_path+p->d_name; else temp=i_path+"/"+p->d_name; if (!stat(temp.c_str(), &statbuf)) { if (S_ISDIR(statbuf.st_mode)) risultato2=erredbarras(temp); else { if (flagdebug) myprintf("00114: delete file %s\n",temp.c_str()); risultato2=delete_file(temp.c_str()); } } risultato=risultato2; } closedir(d); } if (risultato) { if (flagdebug) myprintf("00115: delete dir %s\n\n",i_path.c_str()); delete_dir(i_path.c_str()); } return risultato; } #endif // corresponds to #ifdef (#ifdef unix) bool stermina(string i_path,int32_t i_expectedfile=0) { if (i_path=="") return false; if (flagdebug2) myprintf("00116: PRE ------------------ %s ----------\n",i_path.c_str()); #ifdef _WIN32 if (flaglongpath) if (iswindowspath(i_path)) if (!islongpath(i_path)) i_path="//?/"+i_path; #endif // corresponds to #ifdef (#ifdef _WIN32) if (isdirectory(i_path)) i_path=i_path.substr(0, i_path.size()-1); if (flagdebug2) myprintf("00117: POST ------------------ %s ----------\n",i_path.c_str()); g_rd=0; // global file counter for huge dirs on slow media g_rd_expected=i_expectedfile; g_startrd=mtime(); g_rd_ultimotempo=0; #ifdef _WIN32 erredbarras(utow(i_path.c_str())); #else erredbarras(i_path); #endif // corresponds to #ifdef (#ifdef _WIN32) return (!direxists(i_path)); } string nomefileseesistegia(const string i_nomefile) { if (!fileexists(i_nomefile)) return i_nomefile; string percorso=extractfilepath(i_nomefile); string estensione=prendiestensione(i_nomefile); string nomefile=prendinomefileebasta(i_nomefile); char numero[10]; for (int i=1;i<99999;i++) { snprintf(numero,sizeof(numero),"%05d",i); string snumero=numero; string candidato=percorso+nomefile+"_"+snumero+"."+estensione; if (!fileexists(candidato)) return candidato; } return (""); } string forbiddenstring[] = {"CON","PRN","AUX","NUL","COM1","COM2","COM3","COM4","COM5","COM6","COM7","COM8","COM9","LPT1","LPT2","LPT3","LPT4","LPT5","LPT6","LPT7","LPT8","LPT9"}; size_t forbiddenstringsize = sizeof(forbiddenstring)/sizeof(forbiddenstring[0]); char forbiddenchar[] = {'<','>','"','|','?','*'}; size_t forbiddencharsize = sizeof(forbiddenchar)/sizeof(forbiddenchar[0]); bool isreserved(const string& i_filename,string& o_fixed) { o_fixed=i_filename; bool risultato=false; #ifdef _WIN32 bool isfolder=isdirectory(i_filename); vector pezzi; explode(i_filename,'/',pezzi); for (unsigned int i=0;i4096) { myprintf("00142! payload too big (>4KB)\n"); return false; } string thepath=i_filename+":"+i_adsname; HANDLE hFile = CreateFileW((utow(thepath.c_str()).c_str()), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile==INVALID_HANDLE_VALUE) { myprintf("00143! invalid file handle on %Z\n",i_filename.c_str()); return false; } DWORD bw; if (WriteFile(hFile,i_thepayload.c_str(),i_thepayload.size(),&bw,NULL)) { CloseHandle(hFile); return true; } CloseHandle(hFile); return false; } bool win32_readads(string i_filename,string i_adsname,string& o_thepayload) { if (i_filename=="") { myprintf("00145! cannot ADS on ''\n"); return false; } if (i_adsname=="") { myprintf("00146! ADS cannot be empty\n"); return false; } o_thepayload=""; string thepath=i_filename+":"+i_adsname; HANDLE hFile = CreateFileW((utow(thepath.c_str()).c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile==INVALID_HANDLE_VALUE) { myprintf("00147! invalid file handle on %Z\n",i_filename.c_str()); return false; } unsigned char buffer[4096]={0}; DWORD br; if (ReadFile(hFile,buffer,sizeof(buffer),&br,NULL)) { string temp((char*)buffer); o_thepayload=temp; CloseHandle(hFile); return true; } CloseHandle(hFile); return false; } bool win32_readads_sb(string i_filename,string i_adsname,StringBuffer* o_stringbuffer) { if (i_filename=="") { myprintf("00149! cannot ADS on ''\n"); return false; } if (i_adsname=="") { myprintf("00150! ADS cannot be empty\n"); return false; } if (o_stringbuffer==NULL) { myprintf("00151! stringbuffer null\n"); return false; } string thepath=i_filename+":"+i_adsname; HANDLE hFile = CreateFileW((utow(thepath.c_str()).c_str()), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile==INVALID_HANDLE_VALUE) { myprintf("00152! invalid file handle on %Z\n",i_filename.c_str()); return false; } unsigned char buffer[4096]={0}; DWORD br; while (ReadFile(hFile,buffer,sizeof(buffer),&br,NULL)) { ///myprintf("00154: chunkino %s\n",migliaia(br)); if (br==0) break; (*o_stringbuffer).write((const char*)buffer,br); } CloseHandle(hFile); return true; } /// something to get VSS done via batch file void waitexecute(string i_filename,string i_parameters,int i_show) { SHELLEXECUTEINFOA ShExecInfo =SHELLEXECUTEINFOA(); ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFOA); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; ShExecInfo.hwnd = NULL; ShExecInfo.lpVerb = NULL; ShExecInfo.lpFile = i_filename.c_str(); ShExecInfo.lpParameters = i_parameters.c_str(); ShExecInfo.lpDirectory = NULL; ShExecInfo.nShow = i_show; ShExecInfo.hInstApp = NULL; ShellExecuteExA(&ShExecInfo); WaitForSingleObject(ShExecInfo.hProcess, INFINITE); CloseHandle(ShExecInfo.hProcess); } void waitexecutepadre(const std::string& i_filename, const std::string& i_parameters) { SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; // Crea pipe per l'output HANDLE hChildStdoutRd, hChildStdoutWr; if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) return; // Assicura che l'handle di scrittura non sia ereditato SetHandleInformation(hChildStdoutRd, HANDLE_FLAG_INHERIT, 0); STARTUPINFOA si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.hStdError = hChildStdoutWr; si.hStdOutput = hChildStdoutWr; si.dwFlags |= STARTF_USESTDHANDLES; ZeroMemory(&pi, sizeof(pi)); std::string cmdLine = "\"" + i_filename + "\" " + i_parameters; // Crea il processo if (!CreateProcessA( NULL, // No module name (use command line) const_cast(cmdLine.c_str()), // Command line NULL, // Process handle not inheritable NULL, // Thread handle not inheritable TRUE, // Set handle inheritance to TRUE 0, // No creation flags NULL, // Use parent's environment block NULL, // Use parent's starting directory &si, // Pointer to STARTUPINFO structure &pi) // Pointer to PROCESS_INFORMATION structure ) { CloseHandle(hChildStdoutWr); CloseHandle(hChildStdoutRd); return; } CloseHandle(hChildStdoutWr); // Leggi l'output char buffer[4096]; DWORD bytesRead; while (ReadFile(hChildStdoutRd, buffer, sizeof(buffer) - 1, &bytesRead, NULL) && bytesRead != 0) { buffer[bytesRead] = '\0'; // Null-terminate WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), buffer, bytesRead, NULL, NULL); } // Aspetta che il processo termini WaitForSingleObject(pi.hProcess, INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hChildStdoutRd); } bool isadmin() { BOOL fIsElevated = FALSE; HANDLE hToken = NULL; TOKEN_ELEVATION elevation; DWORD dwSize; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) { myprintf("\n"); myprintf("00155! Failed to get Process Token\n"); goto Cleanup; /// yessss!!! the migthy GOTO!!!! } if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) { myprintf("\n"); myprintf("00156! Failed to get Token Information\n"); goto Cleanup; } fIsElevated = elevation.TokenIsElevated; Cleanup: if (hToken) { CloseHandle(hToken); hToken = NULL; } return fIsElevated; } #endif // corresponds to #if (#if defined(_WIN32)) // Return true if a file or directory (UTF-8 without trailing /) exists. bool exists(string filename) { int len=filename.size(); if (len<1) return false; if (filename[len-1]=='/') filename=filename.substr(0, len-1); #ifdef unix struct stat sb; return !lstat(filename.c_str(), &sb); #else return GetFileAttributes(utow(filename.c_str()).c_str()) !=INVALID_FILE_ATTRIBUTES; #endif // corresponds to #ifdef (#ifdef unix) } #ifdef _WIN32 bool wintouch(string i_filename, int64_t i_date, int64_t i_creationdate) { if ((i_creationdate==0) && (i_date==0)) return true; if (i_filename=="") return false; if (strstr(i_filename.c_str(), ":$DATA")!=0) return true; FP fp=CreateFile(utow(i_filename.c_str()).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fp==FPNULL) { myprintf("00157! WARN cannot open %Z\n",i_filename.c_str()); return false; } if (i_date>0) { SYSTEMTIME st; st.wYear =i_date/10000000000LL%10000; st.wMonth =i_date/100000000%100; st.wDayOfWeek =0; // ignored st.wDay =i_date/1000000%100; st.wHour =i_date/10000%100; st.wMinute =i_date/100%100; st.wSecond =i_date%100; st.wMilliseconds =0; FILETIME ft; SystemTimeToFileTime(&st, &ft); if (!SetFileTime(fp, NULL, NULL, &ft)) { myprintf("00159! WARN cannot set filetime (error %s) on %Z\n",migliaia((int64_t)GetLastError()),i_filename.c_str()); CloseHandle(fp); return false; } } if (i_creationdate>0) { SYSTEMTIME creation_st; creation_st.wYear =i_creationdate/10000000000LL%10000; creation_st.wMonth =i_creationdate/100000000%100; creation_st.wDayOfWeek =0; // ignored creation_st.wDay =i_creationdate/1000000%100; creation_st.wHour =i_creationdate/10000%100; creation_st.wMinute =i_creationdate/100%100; creation_st.wSecond =i_creationdate%100; creation_st.wMilliseconds =0; FILETIME creation_ft; SystemTimeToFileTime(&creation_st, &creation_ft); if (!SetFileTime(fp, &creation_ft, NULL, NULL)) { myprintf("00161! WARN cannot set creation/filetime (error %s) on %Z\n",migliaia((int64_t)GetLastError()),i_filename.c_str()); CloseHandle(fp); return false; } } CloseHandle(fp); return true; } #endif // corresponds to #ifdef (#ifdef _WIN32) // Close fp if open. Set date and attributes unless 0 bool close(const char* filename, int64_t date, int64_t attr, FP fp=FPNULL) { assert(filename); if (fp==stdout) return true; #ifdef unix if (fp!=FPNULL) myfclose(&fp); if (date>0) { struct utimbuf ub; ub.actime=time(NULL); ub.modtime=unix_time(date); utime(filename, &ub); } if ((attr&255)=='u') chmod(filename, attr>>8); ///(CWE-362). Use fchmod( ) instead. return true; #else const bool ads=strstr(filename, ":$DATA")!=0; // alternate data stream? bool allok=true; if (date>0 && !ads) { if (fp==FPNULL) // Windows require HANDLE fp=CreateFile(utow(filename).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fp!=FPNULL) { SYSTEMTIME st; st.wYear=date/10000000000LL%10000; st.wMonth=date/100000000%100; st.wDayOfWeek=0; // ignored st.wDay=date/1000000%100; st.wHour=date/10000%100; st.wMinute=date/100%100; st.wSecond=date%100; st.wMilliseconds=0; FILETIME ft; SystemTimeToFileTime(&st, &ft); if (!SetFileTime(fp, NULL, NULL, &ft)) { myprintf("00163! WARN cannot set filetime (error %s) on %Z\n",migliaia((int64_t)GetLastError()),filename); allok=false; } } } if (fp!=FPNULL) CloseHandle(fp); if ((attr&255)=='w' && !ads) if (fileexists(filename)) if (!SetFileAttributes(utow(filename).c_str(), attr>>8)) { #ifdef _WIN32 DWORD err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("00165! WARN kind %s cannot set attributes on %Z\n",migliaia((int64_t)err),filename); allok=false; } return allok; #endif // corresponds to #ifdef (#ifdef unix) } bool filetouchnow(const char* filename) { if (filename==NULL) return true; #ifdef unix /* int64_t date=now(); #if (!defined(SOLARIS)) struct timeval times[2]; time_t nowz; time(&nowz); const struct tm *local = localtime(&nowz); if (local == NULL) { myprintf("47034! guru on tm (3)\n"); } else { times[0].tv_sec = unix_time(date) - local->tm_gmtoff; // atime times[0].tv_usec = 0; times[1].tv_sec = unix_time(date) - local->tm_gmtoff; // mtime times[1].tv_usec = 0; if (futimes(fileno(fp), times) != 0) myprintf("47043! WARN Linux tocca_now futimes error!\n"); } #endif */ return true; #else bool allok=true; if (strstr(filename,":$DATA")==0) { FP fp=CreateFile(utow(filename).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fp!=FPNULL) { SYSTEMTIME st; GetLocalTime(&st); FILETIME ft,ftutc; SystemTimeToFileTime(&st, &ft); LocalFileTimeToFileTime(&ft, &ftutc); if (!SetFileTime(fp, NULL, NULL, &ftutc)) myprintf("48725! WARN WIN filetouchnow set filetime (error %s) su fp %s\n",migliaia((int64_t)GetLastError()),migliaia2(int64_t(fp))); CloseHandle(fp); } } return allok; #endif // corresponds to #ifdef (#ifdef unix) return true; } bool touch(const char* filename, int64_t date, int64_t attr) { if (filename==NULL) return true; #ifdef unix if (date>0) { struct utimbuf ub; ub.actime=time(NULL); ub.modtime=unix_time(date); utime(filename, &ub); } if (attr!=-1) if ((attr&255)=='u') chmod(filename, attr>>8); return true; #else bool allok=true; if (strstr(filename,":$DATA")==0) { FP fp=CreateFile(utow(filename).c_str(), FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); if (fp!=FPNULL) { SYSTEMTIME st; st.wYear =date/10000000000LL%10000; st.wMonth =date/100000000%100; st.wDayOfWeek =0; // ignored st.wDay =date/1000000%100; st.wHour =date/10000%100; st.wMinute =date/100%100; st.wSecond =date%100; st.wMilliseconds =0; FILETIME ft; SystemTimeToFileTime(&st, &ft); if (!SetFileTime(fp, NULL, NULL, &ft)) { myprintf("00167! WARN cannot set filetime (error %s) on %Z\n",migliaia((int64_t)GetLastError()),filename); allok=false; } CloseHandle(fp); if (attr!=-1) if (!SetFileAttributes(utow(filename).c_str(), attr>>8)) { myprintf("00169! WARN kind %s cannot set attributes on %Z\n",migliaia((int64_t)GetLastError()),filename); allok=false; } } } return allok; #endif // corresponds to #ifdef (#ifdef unix) return true; } string excludetrailingbackslash(string i_dir) { if (i_dir=="") return ""; if ((i_dir[i_dir.size()-1]=='\\') || (i_dir[i_dir.size()-1]=='/')) return i_dir.substr(0,i_dir.size()-1); return ""; } string includetrailingbackslash(string i_dir) { /// fix for altered-string (!) string mydir=i_dir; if (mydir.size()==2) if (isalpha(mydir[0])) if (mydir[1]==':') return mydir+"/"; if (!isdirectory(i_dir)) return i_dir+"/"; else return i_dir; } // Create directories as needed. For example if path="/tmp/foo/bar" // then create directories /, /tmp, and /tmp/foo unless they exist. // Set date and attributes if not 0. void makepath(string path, int64_t date=0, int64_t attr=0) { for (unsigned i=0; i>32; if (SetFilePointer(out, length, &hi, FILE_BEGIN) !=INVALID_SET_FILE_POINTER && SetEndOfFile(out) && CloseHandle(out)) return 0; } return -1; } #endif // corresponds to #ifndef (#ifndef unix) bool saggiascrivibilitacartella(string i_cartella) { if (i_cartella=="") { if (flagdebug) myprintf("00171! empty folder to be checked\n"); return false; } if (flagdebug3) myprintf("00172: i_cartella %s\n",i_cartella.c_str()); i_cartella=extractfilepath(i_cartella); if (flagdebug3) myprintf("00173: i_cartella %s\n",i_cartella.c_str()); if (!isdirectory(i_cartella)) i_cartella+="/"; if (flagdebug3) myprintf("00174: Folder %s\n",i_cartella.c_str()); string percorso=extractfilepath(i_cartella); if (flagdebug2) myprintf("00175: Percorso %s\n",percorso.c_str()); if (percorso=="") { if (flagdebug) myprintf("00176: percorso empty\n"); return false; } if (flagdebug3) myprintf("00177: makepath of |%s|\n",percorso.c_str()); makepath(percorso); string testfile; testfile=percorso+"test$$$.txt.me"; if (flagdebug3) myprintf("00178: TEST FILE PRE <<%s>>\n",testfile.c_str()); testfile=nomefileseesistegia(testfile); if (flagdebug2) myprintf("00179: TEST FILE POST <<%s>>\n",testfile.c_str()); FILE* testbyte=fopen(testfile.c_str(), "wb"); if (testbyte!=NULL) { fprintf(testbyte,"this-file-can-be-deleted"); fclose(testbyte); } bool risultato=fileexists(testfile); delete_file(testfile.c_str()); return risultato; } #ifdef _WIN32 string g_realtemp() { string temppath=""; wchar_t charpath[MAX_PATH]; if (GetTempPathW(MAX_PATH, charpath)) { wstring ws(charpath); string str(ws.begin(), ws.end()); return str; } return temppath; } #endif // corresponds to #ifdef (#ifdef _WIN32) string g_gettempdirectory() { #if defined(_WIN32) || defined(_WIN64) string temppath=""; wchar_t charpath[MAX_PATH]; if (GetTempPathW(MAX_PATH, charpath)) { wstring ws(charpath); string str(ws.begin(), ws.end()); string randomfolder=str+"_zpaqfranz\\"+std::to_string(g_start)+'\\'; myreplaceall(randomfolder,"\\","/"); if (flagdebug3) myprintf("00180: ********************** randomfolder [1] |%s|\n",randomfolder.c_str()); /// randomfolder="y:/"; if (!saggiascrivibilitacartella(randomfolder)) { myprintf("00181! Guru, cannot write inside randomfolder %s\n",randomfolder.c_str()); seppuku(); } return randomfolder; } return temppath; #else #if defined(ESX) || defined(ANCIENT) string randomfolder="/tmp/_zpaqfranz/"; #else ///string temporaneo=migliaia(mtime()); /// string randomfolder="/tmp/_zpaqfranz/"+temporaneo+'/'; string randomfolder="/tmp/_zpaqfranz/"+std::to_string(mtime())+'/'; #endif // corresponds to #if (#if defined(ESX) || defined(ANCIENT)) if (flagdebug3) myprintf("00182: LinuX ********************** randomfolder [1] |%s|\n",randomfolder.c_str()); if (!saggiascrivibilitacartella(randomfolder)) { myprintf("00183! Guru, cannot write inside randomfolder %s\n",randomfolder.c_str()); seppuku(); } return randomfolder; #endif // corresponds to #if (#if defined(_WIN32) || defined(_WIN64)) } /* some zpaq functions */ void remove_dir_if_empty(string i_path) { if (i_path=="") return; if (i_path==".") return; if (i_path=="..") return; #ifdef _WIN32 i_path=linuxtowinpath(i_path); RemoveDirectoryW(utow(i_path.c_str()).c_str()); #else rmdir(i_path.c_str()); #endif // corresponds to #ifdef (#ifdef _WIN32) } void remove_temp_file(string i_thefile) { if (i_thefile=="") { if (flagdebug3) myprintf("00184! temp file empty\n"); return; } if (fileexists(i_thefile)==false) { if (flagdebug3) myprintf("00185! remove_temp_file not found %s\n",i_thefile.c_str()); return; } string percorso=extractfilepath(i_thefile); if (flagdebug3) myprintf("00186: percorso %s\n",percorso.c_str()); delete_file(i_thefile.c_str()); remove_dir_if_empty(percorso); } #ifdef _WIN32 //// VSS on Windows by... batchfile //// delete all kind of shadows copies (if any) void vss_deleteshadows(string i_cartella) { if (flagvss) { i_cartella=linuxtowinpath(i_cartella); string filebatch =g_gettempdirectory()+"vsz.bat"; filebatch=nomefileseesistegia(filebatch); print_datetime(); myprintf("00187: VSS: starting release\n"); if (fileexists(filebatch)) if (remove(filebatch.c_str())!=0) { myprintf("00188! Highlander batch %s\n", filebatch.c_str()); return; } FILE* batch=fopen(filebatch.c_str(), "wb"); if (batch==NULL) { myprintf("00189! cannot write on %s\n",filebatch.c_str()); exit(0); } fprintf(batch,"@echo OFF\n"); if (i_cartella!="") fprintf(batch,"rmdir %s\n",i_cartella.c_str()); fprintf(batch,"@wmic shadowcopy delete /nointeractive\n"); fclose(batch); waitexecute(filebatch,"",SW_HIDE); print_datetime(); myprintf("00190: VSS: end releasing\n"); remove_temp_file(filebatch); } } string relativetolongpath(string i_filename) { ///https://googleprojectzero.blogspot.com/2016/02/the-definitive-guide-on-win32-to-nt.html if (i_filename=="") return ""; #ifdef _WIN32 if (uint64_t len=GetFullPathNameW(utow(i_filename.c_str()).c_str(),0,0,0)) { wchar_t* buf= (wchar_t*)franz_malloc((len)*sizeof(WCHAR)); ///g_allocatedram+=(len)*sizeof(WCHAR); if (buf==NULL) { myprintf("00191! guru in malloc\n"); seppuku(); return ""; } uint64_t len2=GetFullPathNameW(utow(i_filename.c_str()).c_str(),len,buf,0); if (len2>0) { string risultato=wtou(buf); if (flagdebug || flagverbose) { myprintf("00192$ WARNING converted RELATIVE to FULL path |%Z| => |%Z|\n",i_filename.c_str(),risultato.c_str()); } franz_free(buf); g_allocatedram-=(len)*sizeof(WCHAR); return risultato; } } #endif // corresponds to #ifdef (#ifdef _WIN32) return i_filename; } #endif // corresponds to #ifdef (#ifdef _WIN32) string getuname() { #ifdef _WIN64 return "WIN64"; #endif // corresponds to #ifdef (#ifdef _WIN64) #ifdef _WIN32 return "WIN32"; #endif // corresponds to #ifdef (#ifdef _WIN32) #ifdef unix struct utsname uts; int err=uname(&uts); if (err!=0) { myprintf("00194! getuname error %d\n", err); return "UNAME-ERROR"; } if (flagdebug2) { myprintf("00195: sysname : %s\n",uts.sysname); myprintf("00196: nodename: %s\n",uts.nodename); myprintf("00197: release : %s\n",uts.release); myprintf("00198: version : %s\n",uts.version); myprintf("00199: machine : %s\n",uts.machine); } return uts.machine; #endif // corresponds to #ifdef (#ifdef unix) return ""; } // Guess number of cores. In 32 bit mode, max is 2. int numberOfProcessors() { #ifdef __HAIKU__ system_info haikuinfo; get_system_info(&haikuinfo); return haikuinfo.cpu_count; #endif // corresponds to #ifdef (#ifdef __HAIKU__) #ifdef ESX return 1; #endif // corresponds to #ifdef (#ifdef ESX) int rc=0; // result #ifdef SOLARIS if (flagdebug3) myprintf("41105: SOLARIS number of processors\n"); if (flaght) { } else { /// decoding non-HT in SOLARIS is hard, sorry... kstat_ctl_t *kc; kstat_t *ksp; kstat_named_t *knp; int logical_cpu_count = 0; kc = kstat_open(); if (kc == NULL) { myprintf("41214! ktstat_open KAPUTT\n"); return 1; } char cpu_info[] = "cpu_info"; for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) if (strcmp(ksp->ks_module, cpu_info) == 0) logical_cpu_count++; kstat_close(kc); rc=logical_cpu_count; } #endif // corresponds to #ifdef (#ifdef SOLARIS) #if (defined(__APPLE__)) size_t len = sizeof(rc); if (sysctlbyname("hw.physicalcpu", &rc, &len, NULL, 0) < 0) { myprintf("41210! hw.physicalcpu KAPUTT\n"); return 1; } #endif // corresponds to #if (#if (defined(__APPLE__))) #ifdef BSD // BSD or Mac OS/X size_t rclen=sizeof(rc); if (flaght) { ///OpenBSD fix #ifdef HW_NCPUONLINE int mib[2]={CTL_HW, HW_NCPUONLINE}; #else int mib[2]={CTL_HW, HW_NCPU}; #endif // corresponds to #ifdef (#ifdef HW_NCPUONLINE) if (sysctl(mib, 2, &rc, &rclen, 0, 0)!=0) perror("sysctl"); } else { #if defined(__FreeBSD__) || defined(__OpenBSD__) #if defined(__FreeBSD__) if (sysctlbyname("hw.ncpu", &rc, &rclen, NULL, 0) < 0) { myprintf("41220! hw.ncpu KAPUTT\n"); return 1; } #endif // corresponds to #if (#if defined(__FreeBSD__)) #if defined(__OpenBSD__) int mib[2]={CTL_HW, HW_NCPUONLINE}; if (sysctl(mib, 2, &rc, &rclen, NULL, 0) < 0) { myprintf("41296! HW_NCPUONLINE (OPENBSD) KAPUTT\n"); return 1; } #endif // corresponds to #if (#if defined(__OpenBSD__)) #endif // corresponds to #if (#if defined(__FreeBSD__) || defined(__OpenBSD__)) } #endif //BSD // corresponds to #ifdef (#ifdef BSD // BSD or Mac OS/X) #if defined(__linux__) if (flaght) { // Count lines of the form "processor\t: %d\n" in /proc/cpuinfo // where %d is 0, 1, 2,..., rc-1 FILE *in=fopen("/proc/cpuinfo", "r"); if (!in) return 1; std::string s; int c; while ((c=getc(in))!=EOF) { if (c>='A' && c<='Z') c+='a'-'A'; // convert to lowercase if (c>' ') s+=c; // remove white space if (c=='\n') { // end of line? if (s.size()>10 && s.substr(0, 10)=="processor:") { c=atoi(s.c_str()+10); if (c==rc) ++rc; } s=""; } } fclose(in); } else { FILE *cpuinfo = fopen("/proc/cpuinfo", "r"); if (cpuinfo == NULL) { myprintf("41229: /proc/cpuinfo KAPUTT\n"); return 1; } char line[1024]; int cpu_cores = 0; int siblings = 0; int logical_cores=0; while (fgets(line, sizeof(line), cpuinfo) != NULL) if (strncmp(line, "processor", 9) == 0) logical_cores++; else if (strncmp(line, "cpu cores", 9) == 0) sscanf(line, "cpu cores : %d", &cpu_cores); else if (strncmp(line, "siblings", 8) == 0) sscanf(line, "siblings : %d", &siblings); fclose(cpuinfo); rc=cpu_cores; } #endif // corresponds to #if (#if defined(__linux__) ) #ifdef _WIN32 // In Windows return %NUMBER_OF_PROCESSORS% if (flaght) { SYSTEM_INFO si= SYSTEM_INFO(); GetSystemInfo(&si); rc=si.dwNumberOfProcessors; } else { int physical_cores = 0; ///int logical_cores = 0; SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); ///logical_cores = sysInfo.dwNumberOfProcessors; DWORD length = 0; GetLogicalProcessorInformation(NULL, &length); if (length == 0) { myprintf("41244! GetLogicalProcessorInformation KAPUTT\n"); return 1; } PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(length); if (buffer == NULL) { myprintf("41251! malloc KAPUTT\n"); return 1; } if (GetLogicalProcessorInformation(buffer, &length) == FALSE) { myprintf("41257: GetLogical (2) kaputt!\n"); free(buffer); return 1; } for (DWORD i = 0; i < length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i++) if (buffer[i].Relationship == RelationProcessorCore) physical_cores++; free(buffer); rc=physical_cores; } #endif // corresponds to #ifdef (#ifdef _WIN32) if (rc<1) rc=1; /// numero massimo core 32bit if (sizeof(char*)==4 && rc>2) rc=2; return rc; } // In Windows convert upper case to lower case. inline int tolowerW(int c) { #ifndef unix if (c>='A' && c<='Z') return c-'A'+'a'; #endif // corresponds to #ifndef (#ifndef unix) return c; } // Return true if strings a == b or a+"/" is a prefix of b // or a ends in "/" and is a prefix of b. // Match ? in a to any char in b. // Match * in a to any string in b. // In Windows, not case sensitive. bool ispath(const char* a, const char* b) { for (; *a; ++a, ++b) { const int ca=tolowerW(*a); const int cb=tolowerW(*b); if (ca=='*') { while (true) { if (ispath(a+1, b)) return true; if (!*b) return false; ++b; } } else if (ca=='?') { if (*b==0) return false; } else if (ca==cb && ca=='/' && a[1]==0) return true; else if (ca!=cb) return false; } return *b==0 || *b=='/'; } // Read 4 byte little-endian int and advance s unsigned btoi(const char* &s) { s+=4; return (s[-4]&255)|((s[-3]&255)<<8)|((s[-2]&255)<<16)|((s[-1]&255)<<24); } // Read 8 byte little-endian int and advance s int64_t btol(const char* &s) { uint64_t r=btoi(s); return r+(uint64_t(btoi(s))<<32); } // return a/b such that there is exactly one "/" in between, and // in Windows, any drive letter in b the : is removed and there // is a "/" after. string append_path(string a, string b) { int na=a.size(); int nb=b.size(); #ifndef unix if (nb>1 && b[1]==':') { // remove : from drive letter if (nb>2 && b[2]!='/') b[1]='/'; else b=b[0]+b.substr(2), --nb; } #endif // corresponds to #ifndef (#ifndef unix) if (nb>0 && b[0]=='/') b=b.substr(1); if (na>0 && a[na-1]=='/') a=a.substr(0, na-1); return a+"/"+b; } bool iswildcards(const string& i_string) { bool stars=strstr(i_string.c_str(), "*")!=0; // for debug reason no "collapse" bool questionmark=strstr(i_string.c_str(), "?")!=0; return stars+questionmark; } bool check_if_password(string i_filename) { if (flagdebug) myprintf("00200: check_if_password of %s\n",i_filename.c_str()); if (iswildcards(i_filename)) { if (flagdebug2) myprintf("00201: wildcard detected, no password check\n"); return false; } if (!fileexists(i_filename)) return false; FILE* inFile = freadopen(i_filename.c_str()); if (inFile==NULL) { #ifdef _WIN32 DWORD err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("00202! ERR <%s> kind %s\n",i_filename.c_str(),migliaia((int64_t)err)); seppuku(); exit(0); } char s[4]={0}; const int nr=fread(s,1,4,inFile); /// for (int i=0;i<4;i++) /// myprintf("%d %c %d\n",(int)i,s[i],s[i]); fclose(inFile); if (nr>0 && memcmp(s, "7kSt", 4) && (memcmp(s, "zPQ", 3) || s[3]<1)) return true; return false; } /* Sort section */ ///// sort by offset, then by filename ///// use sprintf for debug, not very fast. bool comparecrc32block(s_crc32block a, s_crc32block b) { return a.filename+myulltoa(a.crc32start,40)b.hashhex; } bool comparesizehash(s_fileandsize a, s_fileandsize b) { return (a.size < b.size) || ((a.size == b.size) && (a.hashhex > b.hashhex)) || ((a.size == b.size) && (a.hashhex == b.hashhex) && (a.filename &a, const std::pair &b) { return (a.first < b.first); } */ /// possible problems with unsigned to calculate the differences. We do NOT want to link abs() int64_t myabs(int64_t i_first,int64_t i_second) { if (i_first>i_second) return i_first-i_second; else return i_second-i_first; } /* random section */ struct xorshift128plus_key_s { uint64_t part1; uint64_t part2; }; typedef struct xorshift128plus_key_s xorshift128plus_key_t; static inline void xorshift128plus_init(uint64_t key1, uint64_t key2, xorshift128plus_key_t *key) { key->part1 = key1; key->part2 = key2; } uint64_t xorshift128plus(xorshift128plus_key_t * key) { uint64_t s1 = key->part1; const uint64_t s0 = key->part2; key->part1 = s0; s1 ^= s1 << 23; // a key->part2 = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5); // b, c return key->part2 + s0; } void populateRandom_xorshift128plus(uint32_t *answer, uint32_t size,uint64_t i_key1, uint64_t i_key2) { xorshift128plus_key_t mykey; /// nowarning mykey.part1 = i_key1; mykey.part2 = i_key2; xorshift128plus_init(i_key1, i_key2, &mykey); uint32_t i = size; while (i > 2) { *(uint64_t *)(answer + size - i) = xorshift128plus(&mykey); i -= 2; } if (i != 0) answer[size - i] = (uint32_t)xorshift128plus(&mykey); } /// LICENSE_START.12 /* crc32c.c -- compute CRC-32C using the Intel crc32 instruction * Copyright (C) 2013, 2015, 2021 Mark Adler * Version 1.4 31 May 2021 Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Mark Adler madler@alumni.caltech.edu Reworked and fixed by me */ #define POLY 0x82f63b78 #ifdef __WIN64 /* Hardware CRC-32C for Intel and compatible processors. */ static inline uint32_t gf2_matrix_times(uint32_t *mat, uint32_t vec) { uint32_t sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } static inline void gf2_matrix_square(uint32_t *square, uint32_t *mat) { for (unsigned n = 0; n < 32; n++) square[n] = gf2_matrix_times(mat, mat[n]); } static void crc32c_zeros_op(uint32_t *even, size_t len) { uint32_t odd[32]; /* odd-power-of-two zeros operator */ /* put operator for one zero bit in odd */ odd[0] = POLY; /* CRC-32C polynomial */ uint32_t row = 1; for (unsigned n = 1; n < 32; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* first square will put the operator for one zero byte (eight zero bits), in even -- next square puts operator for two zero bytes in odd, and so on, until len has been rotated down to zero */ do { gf2_matrix_square(even, odd); len >>= 1; if (len == 0) return; gf2_matrix_square(odd, even); len >>= 1; } while (len); /* answer ended up in odd -- copy to even */ for (unsigned n = 0; n < 32; n++) even[n] = odd[n]; } /* Take a length and build four lookup tables for applying the zeros operator for that length, byte-by-byte on the operand. */ static void crc32c_zeros(uint32_t zeros[][256], size_t len) { uint32_t op[32]; crc32c_zeros_op(op, len); for (unsigned n = 0; n < 256; n++) { zeros[0][n] = gf2_matrix_times(op, n); zeros[1][n] = gf2_matrix_times(op, n << 8); zeros[2][n] = gf2_matrix_times(op, n << 16); zeros[3][n] = gf2_matrix_times(op, n << 24); } } /* Apply the zeros operator table to crc. */ static inline uint32_t crc32c_shift(uint32_t zeros[][256], uint32_t crc) { return zeros[0][crc & 0xff] ^ zeros[1][(crc >> 8) & 0xff] ^ zeros[2][(crc >> 16) & 0xff] ^ zeros[3][crc >> 24]; } /* Block sizes for three-way parallel crc computation. LONG and MYSHORT must both be powers of two. The associated string constants must be set accordingly, for use in constructing the assembler instructions. */ #define MYLONG 8192 #define LONGx1 "8192" #define LONGx2 "16384" #define MYSHORT 256 #define SHORTx1 "256" #define SHORTx2 "512" /* Tables for hardware crc that shift a crc by LONG and MYSHORT zeros. */ static pthread_once_t crc32c_once_hw = PTHREAD_ONCE_INIT; static uint32_t crc32c_long[4][256]; static uint32_t crc32c_short[4][256]; /* Initialize tables for shifting crcs. */ static void crc32c_init_hw(void) { crc32c_zeros(crc32c_long, MYLONG); crc32c_zeros(crc32c_short, MYSHORT); } /* Compute CRC-32C using the Intel hardware instruction. */ static uint32_t crc32c_hw(uint32_t crc, unsigned char const *buf, size_t len) { /* populate shift tables the first time through */ pthread_once(&crc32c_once_hw, crc32c_init_hw); /* pre-process the crc */ crc = ~crc; uint64_t crc0 = crc; /* 64-bits for crc32q instruction */ /* compute the crc for up to seven leading bytes to bring the data pointer to an eight-byte boundary */ unsigned char const *next = buf; while (len && ((uintptr_t)next & 7) != 0) { __asm__("crc32b\t" "(%1), %0" : "=r"(crc0) : "r"(next), "0"(crc0)); next++; len--; } /* compute the crc on sets of LONG*3 bytes, executing three independent crc instructions, each on LONG bytes -- this is optimized for the Nehalem, Westmere, Sandy Bridge, and Ivy Bridge architectures, which have a throughput of one crc per cycle, but a latency of three cycles */ while (len >= MYLONG*3) { uint64_t crc1 = 0; uint64_t crc2 = 0; unsigned char const * const end = next + MYLONG; do { __asm__("crc32q\t" "(%3), %0\n\t" "crc32q\t" LONGx1 "(%3), %1\n\t" "crc32q\t" LONGx2 "(%3), %2" : "=r"(crc0), "=r"(crc1), "=r"(crc2) : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2)); next += 8; } while (next < end); crc0 = crc32c_shift(crc32c_long, crc0) ^ crc1; crc0 = crc32c_shift(crc32c_long, crc0) ^ crc2; next += MYLONG*2; len -= MYLONG*3; } /* do the same thing, but now on MYSHORT*3 blocks for the remaining data less than a LONG*3 block */ while (len >= MYSHORT*3) { uint64_t crc1 = 0; uint64_t crc2 = 0; unsigned char const * const end = next + MYSHORT; do { __asm__("crc32q\t" "(%3), %0\n\t" "crc32q\t" SHORTx1 "(%3), %1\n\t" "crc32q\t" SHORTx2 "(%3), %2" : "=r"(crc0), "=r"(crc1), "=r"(crc2) : "r"(next), "0"(crc0), "1"(crc1), "2"(crc2)); next += 8; } while (next < end); crc0 = crc32c_shift(crc32c_short, crc0) ^ crc1; crc0 = crc32c_shift(crc32c_short, crc0) ^ crc2; next += MYSHORT*2; len -= MYSHORT*3; } /* compute the crc on the remaining eight-byte units less than a MYSHORT*3 block */ { unsigned char const * const end = next + (len - (len & 7)); while (next < end) { __asm__("crc32q\t" "(%1), %0" : "=r"(crc0) : "r"(next), "0"(crc0)); next += 8; } len &= 7; } /* compute the crc for up to seven trailing bytes */ while (len) { __asm__("crc32b\t" "(%1), %0" : "=r"(crc0) : "r"(next), "0"(crc0)); next++; len--; } /* return a post-processed crc */ return ~crc0; } /* Check for SSE 4.2. SSE 4.2 was first supported in Nehalem processors introduced in November, 2008. This does not check for the existence of the cpuid instruction itself, which was introduced on the 486SL in 1992, so this will fail on earlier x86 processors. cpuid works on all Pentium and later processors. */ #define SSE42(have) \ do { \ uint32_t eax, ecx; \ eax = 1; \ __asm__("cpuid" \ : "=c"(ecx) \ : "a"(eax) \ : "%ebx", "%edx"); \ (have) = (ecx >> 20) & 1; \ } while (0) #endif // corresponds to #ifdef (#ifdef __WIN64) static pthread_once_t crc32c_once_little = PTHREAD_ONCE_INIT; static uint32_t crc32c_table_little[8][256]; static void crc32c_init_sw_little(void) { for (unsigned n = 0; n < 256; n++) { uint32_t crc = n; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc32c_table_little[0][n] = crc; } for (unsigned n = 0; n < 256; n++) { uint32_t crc = crc32c_table_little[0][n]; for (unsigned k = 1; k < 8; k++) { crc = crc32c_table_little[0][crc & 0xff] ^ (crc >> 8); crc32c_table_little[k][n] = crc; } } } uint32_t crc32c_sw_little(uint32_t crc, unsigned char const *buf, size_t len) { unsigned char const *next = buf; pthread_once(&crc32c_once_little, crc32c_init_sw_little); crc = ~crc; while (len && ((uintptr_t)next & 7) != 0) { crc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); len--; } if (len >= 8) { uint64_t crcw = crc; do { crcw ^= *(uint64_t const *)next; crcw = crc32c_table_little[7][crcw & 0xff] ^ crc32c_table_little[6][(crcw >> 8) & 0xff] ^ crc32c_table_little[5][(crcw >> 16) & 0xff] ^ crc32c_table_little[4][(crcw >> 24) & 0xff] ^ crc32c_table_little[3][(crcw >> 32) & 0xff] ^ crc32c_table_little[2][(crcw >> 40) & 0xff] ^ crc32c_table_little[1][(crcw >> 48) & 0xff] ^ crc32c_table_little[0][crcw >> 56]; next += 8; len -= 8; } while (len >= 8); crc = crcw; } while (len) { crc = crc32c_table_little[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); len--; } return ~crc; } #ifdef BIG /* Swap the bytes in a uint64_t. (Only for big-endian.) */ static inline uint64_t swap_crc32c(uint64_t x) { x = ((x << 8) & (uint64_t)0xff00ff00ff00ff00ULL) | ((x >> 8) & (uint64_t)0xff00ff00ff00ffULL); x = ((x << 16) & (uint64_t)0xffff0000ffff0000ULL) | ((x >> 16) & (uint64_t)0xffff0000ffffULL); return (x << 32) | (x >> 32); } static pthread_once_t crc32c_once_big = PTHREAD_ONCE_INIT; static uint32_t crc32c_table_big_byte[256]; static uint64_t crc32c_table_big[8][256]; static void crc32c_init_sw_big(void) { for (unsigned n = 0; n < 256; n++) { uint32_t crc = n; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc = crc & 1 ? (crc >> 1) ^ POLY : crc >> 1; crc32c_table_big_byte[n] = crc; } for (unsigned n = 0; n < 256; n++) { uint32_t crc = crc32c_table_big_byte[n]; crc32c_table_big[0][n] = swap_crc32c(crc); for (unsigned k = 1; k < 8; k++) { crc = crc32c_table_big_byte[crc & 0xff] ^ (crc >> 8); crc32c_table_big[k][n] = swap_crc32c(crc); } } } uint32_t crc32c_sw_big(uint32_t crc, unsigned char const *buf, size_t len) { unsigned char const *next = buf; pthread_once(&crc32c_once_big, crc32c_init_sw_big); crc = ~crc; while (len && ((uintptr_t)next & 7) != 0) { crc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8); len--; } if (len >= 8) { uint64_t crcw = swap_crc32c(crc); do { crcw ^= *(uint64_t const *)next; crcw = crc32c_table_big[0][crcw & 0xff] ^ crc32c_table_big[1][(crcw >> 8) & 0xff] ^ crc32c_table_big[2][(crcw >> 16) & 0xff] ^ crc32c_table_big[3][(crcw >> 24) & 0xff] ^ crc32c_table_big[4][(crcw >> 32) & 0xff] ^ crc32c_table_big[5][(crcw >> 40) & 0xff] ^ crc32c_table_big[6][(crcw >> 48) & 0xff] ^ crc32c_table_big[7][(crcw >> 56)]; next += 8; len -= 8; } while (len >= 8); crc = swap_crc32c(crcw); } while (len) { crc = crc32c_table_big_byte[(crc ^ *next++) & 0xff] ^ (crc >> 8); len--; } return ~crc; } #endif // corresponds to #ifdef (#ifdef BIG) uint32_t crc32c(uint32_t crc, const unsigned char *buf, size_t len) { /// this is faster the checking global variable #if defined(_WIN64) int sse42; SSE42(sse42); return sse42 ? crc32c_hw(crc, buf, len) : crc32c_sw_little(crc, buf, len); #else #ifdef BIG return crc32c_sw_big(crc, buf, len); #else return crc32c_sw_little(crc, buf, len); #endif // corresponds to #ifdef (#ifdef BIG) #endif // corresponds to #if (#if defined(_WIN64)) } /// LICENSE_END.12 #define MAX_PWD_LEN 32000 void disable_terminal_echo() { #ifndef _WIN32 struct termios term; tcgetattr(STDIN_FILENO, &term); term.c_lflag &= ~(ECHO | ICANON); tcsetattr(STDIN_FILENO, TCSANOW, &term); #endif // corresponds to #ifndef (#ifndef _WIN32) } void restore_terminal_echo() { #ifndef _WIN32 struct termios term; tcgetattr(STDIN_FILENO, &term); term.c_lflag |= ECHO | ICANON; tcsetattr(STDIN_FILENO, TCSANOW, &term); #endif // corresponds to #ifndef (#ifndef _WIN32) } int read_char() { #ifdef _WIN32 return _getch(); #else return getchar(); #endif // corresponds to #ifdef (#ifdef _WIN32) } bool iscontrolsomething(int i_char) { return ( #ifdef _WIN32 (i_char==27) || #endif // corresponds to #ifdef (#ifdef _WIN32) ((i_char>=0) && (i_char<=7)) || (i_char==9) || (i_char==11) || (i_char==12) || ((i_char>=14) && (i_char<=26)) || ((i_char>=28) && (i_char<=31)) || (i_char==45) ); } typedef struct { char buffer[MAX_PWD_LEN]; int cursor_pos; int length; } sinputstate; #ifdef _WIN32 void enable_raw_mode() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); SetConsoleMode(hStdin, ENABLE_PROCESSED_INPUT); } void disable_raw_mode() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); SetConsoleMode(hStdin, ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); } int read_key() { int ch=_getch(); if (iscontrolsomething(ch)) ///ESC, control-C { restore_terminal_echo(); myprintf("\n"); myprintf("42262: Win: exiting due to strange key pressed |%d|\n",ch&255); seppuku(); } if ((ch==224) || (ch==0)) { ch=_getch(); switch (ch) { case 75: return 1000; // left case 77: return 1001; // right case 72: return 1002; // up case 80: return 1003; // down case 83: return 1004; // Canc case 82: return 1005; // Ins default: return ch; } } return ch; } #else struct termios orig_termios; void enable_raw_mode() { struct termios raw; tcgetattr(STDIN_FILENO, &orig_termios); raw = orig_termios; raw.c_lflag &= ~(ECHO | ICANON); raw.c_cc[VMIN] = 1; raw.c_cc[VTIME] = 0; tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); } void disable_raw_mode() { tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios); } int read_key() { int ch=getchar(); if (iscontrolsomething(ch)) ///ESC, control-C { restore_terminal_echo(); myprintf("\n"); myprintf("42099: *nix exiting due to strange key pressed |%d|\n",ch&255); seppuku(); } if (ch==27) if (getchar()=='[') switch (getchar()) { case 'D': return 1000; // left case 'C': return 1001; // right case 'A': return 1002; // up case 'B': return 1003; // down case '3': // Canc (longer escape) getchar(); // final ~ return 1004; case '2': // Ins getchar(); // final ~ return 1005; } return ch; } #endif // corresponds to #ifdef (#ifdef _WIN32) // Funzioni generiche di gestione input void insert_char(sinputstate *state, char ch) { if (state->length < MAX_PWD_LEN - 1) { // move to right memmove(state->buffer + state->cursor_pos + 1, state->buffer + state->cursor_pos, state->length - state->cursor_pos); state->buffer[state->cursor_pos] = ch; state->cursor_pos++; state->length++; state->buffer[state->length] = '\0'; } } void delete_char(sinputstate *state) { // backspace if (state->cursor_pos > 0) { // move to left memmove(state->buffer + state->cursor_pos - 1, state->buffer + state->cursor_pos, state->length - state->cursor_pos + 1); // +1 per includere il terminatore state->cursor_pos--; state->length--; } } void delete_char_forward(sinputstate *state) { // Canc if (state->cursor_pos < state->length) { // move to left from current pos memmove(state->buffer + state->cursor_pos, state->buffer + state->cursor_pos + 1, state->length - state->cursor_pos); state->length--; } } void move_cursor(sinputstate *state, int direction) { switch (direction) { case 1000: // left if (state->cursor_pos > 0) state->cursor_pos--; break; case 1001: // right if (state->cursor_pos < state->length) state->cursor_pos++; break; } } void redraw_input(sinputstate *state,string i_testo) { printf("\r"); setupConsole(); printf("\033[K"); // clear up to end restoreConsole(); color_yellow(); myprintf("%s", i_testo.c_str()); color_restore(); // Stampa il contenuto del buffer for (int i = 0; i < state->length; i++) if (flagdebug) printf("%c", state->buffer[i]); else printf("*"); printf("\r"); setupConsole(); for (int unsigned i=0;icursor_pos;i++) printf("\033[C"); // toright restoreConsole(); fflush(stdout); } string internal_password_withcursor(string i_default) { string myresult =""; sinputstate state; memset(&state,0,sizeof(state)); int ch; myprintf("\n"); if (i_default=="") i_default="Enter password :"; redraw_input(&state,i_default); enable_raw_mode(); while (1) { ch = read_key(); if ((ch=='\n') || (ch== '\r')) break; // CR if ((ch==127) || (ch=='\b') || (ch==8)) // Backspace delete_char(&state); else if ((ch==1000)|| (ch== 1001)) // left/right move_cursor(&state, ch); else if (ch==1004) // Canc delete_char_forward(&state); else if (isprint(ch)) // goodchar insert_char(&state, ch); redraw_input(&state,i_default); } disable_raw_mode(); myprintf("\n"); myresult=state.buffer; if (flagdebug) myprintf("42074: Password |%s|\n",myresult.c_str()); return myresult; } string internal_password_nocursor(const string i_default) { string myresult=""; myprintf("\n"); color_yellow(); if (i_default!="") myprintf("42040: %s :",i_default.c_str()); else myprintf("42025: Enter password :"); color_restore(); char password[MAX_PWD_LEN]; memset(password,0,MAX_PWD_LEN); int pos=0; int ch; disable_terminal_echo(); while (1) { ch=read_char(); if ((ch=='\n') || (ch== '\r')) break; // CR /// printf(" |%03d| \n",ch&255); // backspace if ((ch==127) || (ch=='\b') || (ch==8)) { if (pos>0) { pos--; password[pos] = '\0'; printf("\b \b"); // Cancella l'ultimo asterisco fflush(stdout); } } // Caratteri normali else if (iscontrolsomething(ch)) ///ESC, control-C { restore_terminal_echo(); myprintf("\n"); myprintf("02053: Exiting due to strange key pressed |%d|\n",ch&255); seppuku(); } else if (isprint(ch)) if (pos sz; // part sizes int64_t total_sz; int64_t off; // current offset string fn; // filename, possibly multi-part with wildcards public: vector filepartnames; string lastfilename; // Open filename. If password then decrypt input. InputArchive(const char* filename); // Read and return 1 byte or -1 (EOF) int get() { error("get() not implemented"); return -1; } int get_chunknumber() { return sz.size(); } int64_t get_totalsize() { return total_sz; } // Read up to len bytes into obuf at current offset. Return 0..len bytes // actually read. 0 indicates EOF. int read(char* obuf, int len) { int nr=fread(obuf, 1, len, fp); ///printf("n1 %s\n",migliaia(nr)); if (nr==0) { seek(0, SEEK_CUR); nr=fread(obuf, 1, len, fp); } if (nr==0) return 0; if (aes) aes->encrypt(obuf, nr, off); off+=nr; /// myprintf("00204: BLOKKO len %d\n",len); return nr; } // Like fseeko() void seek(int64_t p, int whence); // Like ftello() int64_t tell() { return off; } int64_t totalsize() { int64_t temp=0; for (unsigned i=0; i1); int64_t sum=0; unsigned i; for (i=0;; ++i) { sum+=sz[i]; if (sum>off || i+1>=sz.size()) break; } const string next=subpart(fn, i+1); myfclose(&fp); fp=myfopen(next.c_str(), RB); if (fp==FPNULL) ioerr(next.c_str()); fseeko(fp, off-sum, SEEK_END); } // Open for input. Decrypt with password and using the salt in the // first 32 bytes. If filename has wildcards then assume multi-part // and read their concatenation. InputArchive::InputArchive(const char* filename):fn(filename) { assert(filename); lastfilename=""; off=0; total_sz=0; // Get file sizes const string part0=subpart(filename, 0); for (unsigned i=1; ; ++i) { const string parti=subpart(filename, i); if (i>1 && parti==part0) break; fp=myfopen(parti.c_str(), RB); if (fp==FPNULL) break; filepartnames.push_back(parti); lastfilename=parti; fseeko(fp, 0, SEEK_END); sz.push_back(ftello(fp)); total_sz+=sz.back(); if (fp!=NULL) myfclose(&fp); } // Open first part const string part1=subpart(filename,1); /// bypass the password, use the global one if (g_password==NULL) if (check_if_password(part1)) { myprintf("00205! Archive seems encrypted (or corrupted)"); string spassword=mygetpasswordblind(""); if (spassword!="") { libzpaq::SHA256 sha256; for (unsigned int i=0;i>=8; } return i_size; } int32_t arraytoint32(const char* i_buffer) { if (i_buffer==NULL) { myprintf("00208! i_buffer is NULL\n"); seppuku(); return -1; } int64_t risultato=0; for (int i=3;i>=0;i--) { uint8_t numerino=*(i_buffer+i); risultato=risultato+numerino; if (i>0) risultato<<=8; } return risultato; } int64_t arraytoint64(const char* i_buffer) { if (i_buffer==NULL) { myprintf("00209! i_buffer is NULL\n"); seppuku(); return -1; } int64_t risultato=0; for (int i=7;i>=0;i--) { uint8_t numerino=*(i_buffer+i); /// printf("Letto %d %02X\n",(int)i,numerino); risultato=risultato+numerino; if (i>0) risultato<<=8; } return risultato; } int64_t g_debug_sequence=0; // An Archive is a file supporting encryption class OutputArchive: public ArchiveBase, public libzpaq::Writer { int64_t off; // preceding multi-part bytes unsigned ptr; // write pointer in buf: 0 <= ptr <= BUFSIZE enum {BUFSIZE=1<<16}; char buf[BUFSIZE]; // I/O buffer string thefilename; bool flagindex; FP firstfp; uint64_t chunksize; int64_t writtensofar; unsigned int chunknumber; string firstfilename; int64_t writtenonlastchunk; int64_t previoussize; public: bool firstchunk; vector filepartnames; // Open. If password then encrypt output. OutputArchive(string i_thearchive,const char* filename, const char* password=0, const char* salt_=0, int64_t off_=0); string lastfilename() { return thefilename; } // Write pending output void flush() { if (flagdebug3) myprintf("00210: flush k1\n"); assert(fp!=FPNULL); string nomefile=prendinomefileebasta(thefilename); g_archivefp=fp; if (flagdebug3) myprintf("00211: flush k2\n"); if (ptr==104) if (flagdebug4) myprintf("00212: =============== g_write_on_first %d firstp %s\n",int(g_write_on_first),migliaia(int64_t(firstfp))); if (flagdebug3) myprintf("00213: flush k3\n"); if (g_write_on_first && (ptr==104) && (firstfp!=FPNULL)) { if (flagdebug3) myprintf("00214: ################ fixing on firstfp %s size %d @ %s\n",migliaia3(int64_t(firstfp)),ptr,migliaia(g_write_on_seek)); fseeko(firstfp,g_write_on_seek,SEEK_SET); if (flagdebug3) myprintf("00215: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ write on first, 104 ftello %s off %s encrypt @%s\n",migliaia(ftello(firstfp)),migliaia2(off),migliaia3(ftello(firstfp)+off)); if (flagdebug3) myprintf("00216: HERE WE ARE @ %12s on fp %12s size %s\n",migliaia3(ftello(firstfp)),migliaia(int64_t(firstfp)),migliaia2(ptr)); char debugfilename[100]; FP debugoutf; if (flagdebug4) { snprintf(debugfilename,sizeof(debugfilename),"z:\\fp_%04d,%04d_u_%08d_size_%06d_%s.bin",(int)g_debug_sequence++,(int)int64_t(firstfp),(int)int64_t(ftello(firstfp)),ptr,nomefile.c_str()); debugoutf=myfopen(debugfilename,WB); myfwrite(buf,1,ptr,debugoutf); myfclose(&debugoutf); } if (firstchunk) { if (flagdebug3) myprintf("00217: i am first chunk => off to zero\n"); off=0; } else { if (flagdebug3) myprintf("00218: not first chunk, off to %s\n",migliaia(off)); } int64_t criptoposition=ftello(firstfp)+off; if (flagdebug4) myprintf("00219: write104 at %s (fetello %s + off %s) on file %s should thefilename %s\n",migliaia(ftello(firstfp)+off),migliaia2(ftello(firstfp)),migliaia3(off),debugfilename,thefilename.c_str()); if (aes) { if (flagdebug3) myprintf("00220: aes crypt size %s criptoposition %s\n",migliaia(ptr),migliaia2(criptoposition)); aes->encrypt(buf, ptr,criptoposition); } if (flagdebug4) { snprintf(debugfilename,sizeof(debugfilename),"z:\\enc_%04d,%04d_u_%08d_size_%06d_%s_at_%08d_due.bin",(int)g_debug_sequence++,(int)int64_t(fp),(int)int64_t(ftello(fp)),ptr,nomefile.c_str(),(int)criptoposition); debugoutf=myfopen(debugfilename,WB); myfwrite(buf,1,ptr,debugoutf); myfclose(&debugoutf); } if (flagdebug3) myprintf("00221: realfwrite104 on firstfp %s @ftello %s\n",migliaia(int64_t(firstfp)),migliaia2(int64_t(ftello(firstfp)))); myfwrite(buf, 1, ptr, firstfp); if (flagdebug3) myprintf("00222: closing the firstp %s\n",migliaia(int64_t(firstfp))); tocca_now(firstfp); myfclose(&firstfp); firstfp=FPNULL; fp=FPNULL; ptr=0; return; } if (flagdebug3) myprintf("00223: flush k4\n"); if (flagdebug3) { if ((int64_t)fp!=0) { myprintf("00224: -pre fp %s\n",migliaia((int64_t)fp)); myprintf("00225: write @ %12s on fp %12s (%d) size %s\n",migliaia3(ftello(fp)),migliaia(int64_t(fp)),int64_t(fp),migliaia2(ptr)); myprintf("00226: -post\n"); } } if (flagdebug3) myprintf("00227: flush k4bis\n"); char debugfilename[100]; FP debugoutf; if (flagdebug4) { snprintf(debugfilename,sizeof(debugfilename),"z:\\fp_%04d,%04d_u_%08d_size_%06d_%s.bin",(int)g_debug_sequence++,(int)int64_t(fp),(int)int64_t(ftello(fp)),ptr,nomefile.c_str()); debugoutf=myfopen(debugfilename,WB); myfwrite(buf,1,ptr,debugoutf); myfclose(&debugoutf); } if (flagdebug3) if ((int64_t)fp!=0) myprintf("00228: !!!!!!!!!!!!!!!!!!!!!! unecrypted on [ENCRYPT @ %s] %s\n",migliaia(ftello(fp)+off),debugfilename); if (flagdebug3) myprintf("00229: flush k5\n"); if (ptr==104) if (flagdebug3) if ((int64_t)fp!=0) myprintf("00230:-------------------------------------- regular 104 encrypt @%s\n",migliaia(int64_t(ftello(fp)+off))); if (flagdebug3) myprintf("00231: MMMMMMMMMMMMMMMMMMMMMMMMMMM off %s writtensofar %s onlast %s|\n",migliaia3(off),migliaia(writtensofar),migliaia2(writtenonlastchunk)); if (flagdebug3) myprintf("00232: flush k6\n"); int64_t cryptoffset; if (g_chunk_size>0) { cryptoffset=writtensofar+previoussize; ///va primo run if ((aes) && (previoussize==0)) cryptoffset+=32; ///primo run } else { if ((int64_t)fp!=0) cryptoffset=ftello(fp)+off; else cryptoffset=0; } if (flagdebug3) myprintf("00233: flush k7\n"); if (aes) { if (flagdebug4) if ((int64_t)fp!=0) myprintf("00234: AES seq %08d [size %6s] crypt %10s (ftello %10s + off %10s + written %10s) %s\n", g_debug_sequence, migliaia5(ptr), migliaia(cryptoffset), migliaia2(ftello(fp)), migliaia3(off), migliaia4(writtensofar), nomefile.c_str()); aes->encrypt(buf, ptr, cryptoffset); } if (flagdebug4) { snprintf(debugfilename,sizeof(debugfilename),"z:\\enc_%04d,%04d_u_%08d_size_%06d_%s_at_%08d.bin",(int)g_debug_sequence++,(int)int64_t(fp),(int)int64_t(ftello(fp)),ptr,nomefile.c_str(),(int)cryptoffset); debugoutf=myfopen(debugfilename,WB); myfwrite(buf,1,ptr,debugoutf); myfclose(&debugoutf); } myfwrite(buf, 1, ptr, fp); writtensofar +=ptr; chunksize +=ptr; if (flagdebug3) myprintf("00235: flush k8\n"); if (g_chunk_size>0) if (chunksize>g_chunk_size) { if ((fp!=firstfp) && (fp!=FPNULL)) { if (flagdebug3) { myprintf("\r \r"); myprintf("\r"); myprintf("00236: closing __________________________ %s |%s|\n",migliaia(int64_t(fp)),thefilename.c_str()); } tocca_now(fp); myfclose(&fp); } thefilename=format_filename(++chunknumber); if (flagdebug3) myprintf("00237: the (new) filename %s\n",thefilename.c_str()); fp=myfopen(thefilename.c_str(), WB,DATE_1980); if (!isopen()) ioerr(thefilename.c_str()); if (flagdebug3) myprintf("00238: file open and ready on fp %s!\n",migliaia(int64_t(fp))); chunksize=0; writtenonlastchunk=writtensofar; g_addedchunklist.push_back(thefilename); ///g_addedchunklist_fp.push_back(fp); } ptr=0; } // Position the next read or write offset to p. void seek(int64_t p, int whence) { if (g_fakewrite) /// ransomware { if (whence==SEEK_SET) off=p; else off+=p; // assume at end } if (fp!=FPNULL) { if (flagdebug3) myprintf("00239: calling flush from seek fp %s\n",migliaia(int64_t(fp))); flush(); if (flagdebug3) myprintf("00240: calling fseeko for fp %s to %s\n",migliaia(int64_t(fp)),migliaia2(int64_t(p))); fseeko(fp, p, whence); } else if (whence==SEEK_SET) off=p; else off+=p; // assume at end } // Return current file offset. int64_t tell() const { if (g_fakewrite) /// ransomware return off; if (fp!=FPNULL) return ftello(fp)+ptr; else return off; } int64_t tellwritten() const { if (g_fakewrite) /// ransomware return off; return writtensofar+ptr; } // Write one byte void put(int c) { if (g_fakewrite) /// ransomware { ++off; //we do not flush return; } if (fp==FPNULL) ++off; else { if (ptr>=BUFSIZE) flush(); buf[ptr++]=c; } } // Write buf[0..n-1] void write(const char* ibuf, int len) { if (g_fakewrite) /// ransomware { off+=len; return; } if (fp==FPNULL) off+=len; else while (len-->0) put(*ibuf++); } // Flush output and close void close() { if (fp!=FPNULL) { if (flagdebug3) myprintf("00241: calling flush on fp=%s\n",migliaia(int64_t(fp))); flush(); if (fp!=FPNULL) { tocca_now(fp); if (flagdebug3) myprintf("00242: calling close %s\n",migliaia(int64_t(fp))); myfclose(&fp); } } fp=FPNULL; } string format_filename(unsigned int i_number) { if (g_chunk_size==0) return firstfilename; int64_t maxpart=10; for (unsigned int i=0;i(maxpart-1)) { myprintf("00244! GURU: the number %s cannot be stored in maxpart %s\n",migliaia(i_number),migliaia2(maxpart-1)); myprintf("00245! maybe you need a longer ? pattern <<%s>>\n",firstfilename.c_str()); seppuku(); return ""; } string part0=subpart(firstfilename, 0); if (flagdebug3) myprintf("00246: i_number %d part0 %s firstfilename %s\n",i_number,part0.c_str(),firstfilename.c_str()); if (part0!=firstfilename) { string temp=subpart(firstfilename,i_number); if (flagdebug2) myprintf("00247: created by subpart %s\n",temp.c_str()); filepartnames.push_back(temp); return temp; } return firstfilename; } }; // this is for SMALL list of parameters int listfiles(string i_path,const string& i_extension,bool i_fullname,vector* o_thelist) { if (o_thelist==NULL) { myprintf("00248! GURU o_thelist is null\n"); return 0; } #ifndef unix vector tobesorted; if (flagdebug3) { myprintf("00249: i_path %s\n",i_path.c_str()); myprintf("00250: i_extension %s\n",i_extension.c_str()); } i_path=extractfilepath(i_path); std::wstring wpattern = utow(i_path.c_str())+utow("*.")+utow(i_extension.c_str()); const std::string s_pattern(wpattern.begin(),wpattern.end()); if (flagdebug) myprintf("00251: get handle for w pattern %s\n",wtou(wpattern.c_str()).c_str()); WIN32_FIND_DATAW findfiledata; HANDLE myhandle=FindFirstFileW(wpattern.c_str(),&findfiledata); if (myhandle==INVALID_HANDLE_VALUE) { if (flagdebug) myprintf("00252! Invalid handle %s\n",s_pattern.c_str()); return 0; } do { std::string t=wtou(findfiledata.cFileName); if ((t!=".") && (t!="..")) { std::wstring wfilepath; if (i_fullname) wfilepath=utow(i_path.c_str())/*+L"\\"*/+findfiledata.cFileName; else wfilepath=findfiledata.cFileName; const std::string s_wfilepath(wfilepath.begin(),wfilepath.end()); if (flagdebug) myprintf("00253: Working on %s ",s_wfilepath.c_str()); if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (flagdebug) myprintf(": DO NOTHING\n"); } else { if (flagdebug) myprintf(": OK PUSH BACK\n"); tobesorted.push_back(wtou(wfilepath.c_str())); } } } while(FindNextFile(myhandle,&findfiledata)==TRUE); if (myhandle) FindClose(myhandle); if (flagdebug3) for (unsigned int i=0;i>\n",i_path.c_str()); return 0; } vector tobesorted; while ((ent=readdir(dir))!=NULL) { string thename=ent->d_name; if ((thename!=".") && (thename!="..") && (!isdirectory(thename))) { string fullname; if (i_fullname) fullname=i_path+thename; else fullname=thename; string estensione =prendiestensione(thename); if (flagdebug3) { myprintf("00256: i_path %s\n",i_path.c_str()); myprintf("00257: thename %s\n",thename.c_str()); myprintf("00258: fullname %s\n",fullname.c_str()); myprintf("00259: estensione %s\n",estensione.c_str()); } bool flagaggiungi=true; if (i_extension!="") flagaggiungi=(estensione==i_extension); if (flagaggiungi) { if (flagdebug2) myprintf("00260: ZZZZ %s\n", fullname.c_str()); tobesorted.push_back(fullname); } } } closedir (dir); std::sort(tobesorted.begin(),tobesorted.end()); for (unsigned int i=0;i0) risultato=atoi(numerini.c_str()); if (flagdebug3) myprintf("00262: numerini |%s| int %s\n",numerini.c_str(),migliaia(risultato)); } } else { if (flagdebug) myprintf("00263! -14 is not '_' for |%s|\n",candidato.c_str()); } return risultato; } typedef int (*callback_issomething)(int); string stringtosomething(const string& i_input,callback_issomething i_check) { string onlysomething=""; for (unsigned int i=0;i filenamearray; vector partarray; string lastpart; string nextpart; int howmanychunks; bool ismultipart; bool isgood; int howmanyjolly; int64_t totalchunksize; int nextpart_integer; int64_t maxpart; easymultipart(string i_filename): howmanychunks(0), ismultipart(false), isgood(false), howmanyjolly(0), totalchunksize(0), nextpart_integer(0), maxpart(0) { if (!iszpaq(i_filename)) i_filename+=".zpaq"; #ifdef _WIN32 /// i_filename=stringtolower(i_filename); #endif // corresponds to #ifdef (#ifdef _WIN32) /// we really want a path, even relative thefilename =i_filename; lastpart =""; nextpart =""; if (i_filename=="") { myprintf("00264! multipartfilename is empty\n"); return; } maxpart=10; for (unsigned int i=0;i0; if (howmanyjolly>9) { myprintf("00265! too many jolly '?' (max 9), founded %d in %s\n",howmanyjolly,i_filename.c_str()); seppuku(); return; } if (!ismultipart) return; enumerate(); partarray.clear(); int parts =0; // number of existing parts in multipart string part0=subpart(i_filename,0); string thehole =""; totalchunksize=0; for (int i=1;; ++i) { string partname=subpart(i_filename,i); if (partname==part0) error("84285: too many archive parts"); if (!fileexists(partname)) { thehole=partname; if (flagdebug3) myprintf("00266: filenamearraysize %08d partname %08d does not exists\n",filenamearray.size(),i,partname.c_str()); if (i==1) thehole=""; else if ((filenamearray.size()>0) && (i>0)) { if (flagdebug3) { myprintf("00267: last filenamearraysize %s\n",filenamearray[filenamearray.size()-1].filename.c_str()); myprintf("00268: i-1 %s\n",subpart(i_filename,i-1).c_str()); } if (filenamearray[filenamearray.size()-1].filename==subpart(i_filename,i-1)) thehole=""; } break; } else { s_fileandsize myblock; myblock.filename=partname; int64_t tempsize=prendidimensionefile(partname.c_str()); totalchunksize+=tempsize; myblock.size=tempsize; myblock.attr=0; myblock.date=0; myblock.isdir=isdirectory(partname); myblock.flaghashstored=false; partarray.push_back(myblock); } ++parts; } std::sort(partarray.begin(),partarray.end(),comparefilename); isgood=(thehole==""); //filenamearray.size()==partarray.size(); if (thehole!="") { /// myprintf("00269: PART NUMBER MISMATCH: disk %s vs part %s (HOLE IN %s)\n",migliaia(filenamearray.size()),migliaia2(partarray.size()),thehole.c_str()); myprintf("00270! [2] AT LEAST ONE HOLE DETECTED! <<%Z>>\n",thehole.c_str()); if (filenamearray.size()>partarray.size()) // this should be for (unsigned int i=0;i0) { if (fileexists(subpart(i_filename, parts))) lastpart=subpart(i_filename, parts); nextpart=subpart(i_filename, parts+1); nextpart_integer=parts+1; } else { nextpart=subpart(i_filename, 1); nextpart_integer=1; } } string enumerate() { vector candidate; listfiles(extractfilepath(thefilename),"zpaq",true,&candidate); for (unsigned int i=0;i0) { firstfilename=i_thearchive; easymultipart chunkedoutput(i_thearchive); if (chunkedoutput.filenamearray.size()==0) firstchunk=true; else firstchunk=false; if (flagdebug4) { myprintf("00280: is firstchunk %d\n",(int)firstchunk); myprintf("00281: chunkedoutput count %s total size %21s\n",migliaia(chunkedoutput.filenamearray.size()),migliaia2(chunkedoutput.totalchunksize)); myprintf("00282: last %s next %s\n",chunkedoutput.lastpart.c_str(),chunkedoutput.nextpart.c_str()); } if (chunkedoutput.nextpart_integer>chunkedoutput.maxpart) { myprintf("00283: proposed next_partinteger %s is > maxpart %s\n",migliaia(chunkedoutput.nextpart_integer),migliaia2(chunkedoutput.maxpart)); seppuku(); return; } chunknumber=chunkedoutput.nextpart_integer; thefilename=chunkedoutput.nextpart; if (flagdebug) myprintf("00284: changed thefilename to %s\n",thefilename.c_str()); previoussize=chunkedoutput.totalchunksize; if (flagdebug4) myprintf("00285: previoussize %s\n",migliaia(previoussize)); } // Open existing file char salt[32]={0}; #ifdef BSD if (flagappend) { if (flagdebug2) myprintf("00286: try BSD ABPLUS\n"); fp=myfopen(thefilename.c_str(), ABPLUS); } else fp=myfopen(thefilename.c_str(), RBPLUS); #else fp=myfopen(thefilename.c_str(), RBPLUS); #endif // corresponds to #ifdef (#ifdef BSD) if (flagdebug3) myprintf("00287: ***********************************************************\n"); if (g_chunk_size>0) { ///g_addedchunklist_fp.push_back(fp); g_addedchunklist.push_back(thefilename); } if (isopen()) { if (flagdebug3) { printbar('1'); myprintf("00288: off inside isopen is %s\n",migliaia(off)); } if (off!=0) { if (flagdebug) { myprintf("00289: thefilename is %s %s\n",thefilename.c_str(),migliaia(off)); if (fileexists(thefilename)) myprintf("00290: does exists\n"); else myprintf("00291: does not exists\n"); } error("38583$ file exists and off > 0 (maybe try to add to chunked?)"); } if (password) { if (flagdebug2) myprintf("00292: password, reading salt\n"); if (fread(salt, 1, 32, fp)!=32) error("38679: cannot read salt"); if (salt_ && memcmp(salt, salt_, 32)) error("salt mismatch"); else { if (flagdebug2) myprintf("00293: salt done!\n"); } } seek(0, SEEK_END); } // Create new file else { if (flagdebug3) myprintf("00295: not isopen\n"); #ifdef BSD if (flagappend) { if (flagdebug2) myprintf("00296: try BSD flagappend\n"); fp=myfopen(thefilename.c_str(), AB); } else fp=myfopen(thefilename.c_str(), WB); #else fp=myfopen(thefilename.c_str(), WB,DATE_1980); #endif // corresponds to #ifdef (#ifdef BSD) if (!isopen()) ioerr(thefilename.c_str()); if (g_chunk_size>0) { ///g_addedchunklist_fp.push_back(fp); g_addedchunklist.push_back(thefilename); } if (password) { if (!salt_) { error("38722: salt not specified"); seppuku(); exit(0); } memcpy(salt, salt_, 32); if (off==0 && myfwrite(salt, 1, 32, fp)!=32) ioerr(thefilename.c_str()); if (flagdebug3) myprintf("00297: written SALT (32bytes) on %s\n",thefilename.c_str()); #ifndef _WIN32 fflush(fp); /// unix fix #endif // corresponds to #ifndef (#ifndef _WIN32) } } if (flagdebug) myprintf("00299: opened 1 thefilename %s\n",thefilename.c_str()); firstfp=FPNULL; chunksize=0; if (g_chunk_size>0) { firstfp=fp; g_archivefp_first=firstfp; if (flagdebug3) myprintf("00300: )))))))))))))))))))) Take note: firstfp is %s\n",migliaia(int64_t(firstfp))); } if (thefilename!=g_indexname) { g_fp_zpaq =fp; flagindex=false; if (flagdebug3) myprintf("00301: ;;;;;;;;;;;;;;;;;;;;;;;;;; settato index %s %08d;;;;;;;;;;;;;\n",migliaia(int64_t(g_fp_zpaq)),int64_t(g_fp_zpaq)); } if (flagindex) { if (flagdebug) myprintf("00302: OutputArchive ISINDEX %s %s\n",thefilename.c_str(),migliaia(int64_t(fp))); } else { if (flagdebug) myprintf("00303: OutputArchive ZPAQ %s %s\n",thefilename.c_str(),migliaia(int64_t(fp))); } // Set up encryption if (password) { char key[32]; libzpaq::stretchKey(key, password, salt); aes=new libzpaq::AES_CTR(key, 32, salt); g_allocatedram+=sizeof(libzpaq::AES_CTR); } } ////////////////////////////// misc /////////////////////////////////// //zpaq // For libzpaq output to a string less than 64K chars struct StringWriter: public libzpaq::Writer { string s; void put(int c) { if (s.size()>=65535) error("string too long"); s+=char(c); } }; // enum for version ///static const int64_t HT_BAD= -0x7FFFFFFFFFFFFFFALL; // no such frag static const int64_t DEFAULT_VERSION=99999999999999LL; // unless -until // fragment hash table entry struct HT { uint32_t crc32; // new: take the CRC-32 of the fragment uint32_t crc32size; unsigned char sha1[20]; // fragment hash int usize; // uncompressed size, -1 if unknown, -2 if not init int64_t csize; // if >=0 then block offset else -fragment number double estimatedratio; HT(const char* s=0, int u=-2) { crc32=0; crc32size=0; csize=0; estimatedratio=0; if (s) memcpy(sha1, s, 20); else memset(sha1, 0, 20); usize=u; } }; /// a "fake" class to mimic normal filesystem write, reducing coding complexity class franzfs { private: public: char* data; char space[16]; uint64_t filesize; uint64_t position; void seekstart() { if (!data) { myprintf("00304! Guru data is null in seek start\n"); return; } if (filesize==0) { myprintf("00305! Guru filesize is zero seek start\n"); return; } position=0; } size_t ramread(size_t i_size,char* o_ptr) { if (o_ptr==NULL) return 0; if (i_size==0) return 0; if (!data) { myprintf("00306! Guru data is null\n"); return 0; } if ((position+i_size)>filesize) i_size=filesize-position; memcpy(o_ptr,data+position,i_size); position+=i_size; /// myprintf("00307: letti %21s posizione %21s\n",migliaia(i_size),migliaia2(position)); return i_size; } size_t ramwrite(uint64_t i_offset,const char* i_ptr, size_t i_size) { if (i_offset>filesize) { myprintf("00308: i_offset greater then filesize %s %s\n",migliaia((int64_t)i_offset),migliaia2((int64_t)filesize)); return 0; } if (i_ptr==NULL) return 0; if (i_size==0) return 0; if (!data) { myprintf("00309! Guru data is null\n"); seppuku(); return 0; } position=i_offset; if (position+i_size>filesize) { myprintf("00310! cannot write beyond size %s %s %s\n",migliaia((int64_t)position),migliaia2((int64_t)i_size),migliaia3((int64_t)filesize)); return 0; } memcpy(data+position,i_ptr,i_size); position+=i_size; return i_size; } franzfs(){data=NULL;position=0;} bool init(int64_t i_size) { /// myprintf("00311: init1\n"); data=(char*)franz_malloc(i_size); ///g_allocatedram+=i_size; /// myprintf("00312: init2\n"); if (data==NULL) { myprintf("00313! GURU on malloc\n"); return false; } ///myprintf("00314: init3\n"); memset(data,0,i_size); // required by zpaq extraction method ///myprintf("00315: init4\n"); g_ramdisksize+=i_size; filesize=i_size; if (flagdebug2) myprintf("00316: allocated %21s data %s\n",migliaia(i_size),migliaia2(int64_t(data))); return true; } bool reset() { if (data==NULL) { myprintf("00317! GURU on reset\n"); return false; } if (filesize==0) { myprintf("00318! GURU on filesize\n"); return false; } franz_free(data); g_ramdisksize-=filesize; filesize=0; if (flagdebug2) myprintf("00319: Deallocated %s\n",migliaia((int64_t)filesize)); return true; } }; #define FIX_TOOLONG 1; #define FIX_ADS 2; #define FIX_UTF8 4; #define FIX_RESERVED 8; #define FIX_WINDOWSPATH 16; #define FIX_WINDOWSUNC 32; #define FIX_RELATIVE 64; int64_t g_dt_ram; #define WORK_NONE 0 #define WORK_UPDATED 1 #define WORK_ADDED 2 #define WORK_REMOVED 3 // filename entry struct DT // if you get some warning here, update your compiler! { int64_t date; // if you get some warning here, update your compiler! // decimal YYYYMMDDHHMMSS (UT) or 0 if deleted int64_t size; // size or -1 if unknown int64_t attr; // first 8 attribute bytes int64_t data; // sort key or frags written. -1 = do not write int64_t creationdate; // on windows, linux/freebsd/mac... maybe int64_t accessdate; // on windows vector ptr; // fragment list int written; // 0..ptr.size() = fragments output. -1=ignore bool isordered; // fragments in a single ordered chunk bool isselected; string hexhash; // for new functions, not for add string hashtype; // for paranoid() string hexcrc32; /// guilist string outputname; // written filename int franz_block_size; char *franz_block;//[FRANZOFFSETV3]; uint32_t file_crc32; int64_t hashedsize; int chunk; int64_t expectedsize; int version; bool forceadd; bool is4; uint64_t red_total; int red_count; int red_min; int red_max; int red_avg; uint64_t red_candidate; /// now using pointer to shrink DT from more then 1K to 296 bytes XXH3_state_t *pfile_xxh3; // this is the problem: XXH3's 64-byte align not always work with too old-too new compilers XXHash64 *pfile_xxhash64; libzpaq::SHA256 *pfile_sha256; libzpaq::SHA1 *pfile_sha1; SHA3 *pfile_sha3; MD5 *pfile_md5; blake3_hasher *pfile_blake3; NESSIEstruct *pfile_whirlpool; HighwayHashCat *pfile_highway64; franzfs *pramfile; int64_t kompressedsize; int filework; //0 = nothing; 1=updated; 2=added, 3=removed DT(): date(0), size(0), attr(0), data(0),creationdate(0),accessdate(0),written(-1),isordered(false),isselected(false),/*franz_block_size(FRANZOFFSETV3),*/file_crc32(0),hashedsize(0),chunk(-1),expectedsize(0),version(0),forceadd(false),is4(false),red_total(0),red_count(0),red_min(256),red_max(0),red_avg(0),red_candidate(0),kompressedsize(0),filework(0) { /// let's save a bit of RAM (during compression) franz_block_size=FRANZOFFSETV3; if (command=='a') if (flagfrugal) { franz_block_size=FRANZOFFSETV2; if ((g_franzotype==FRANZO_CRC_32) || (g_franzotype==FRANZO_XXHASH64) || (g_franzotype==FRANZO_XXHASH64B)||(g_franzotype==FRANZO_MD5B)||(g_franzotype==FRANZO_BLAKE3B)|| (g_franzotype==FRANZO_SHA_256B)||(g_franzotype==FRANZO_SHA3B)||(g_franzotype==FRANZO_XXH3B)||(g_franzotype==FRANZO_SHA_1B)) franz_block_size=FRANZOFFSETV1; else if ((g_franzotype==FRANZO_WHIRLPOOL) || (g_franzotype==FRANZO_HIGHWAY64) || (g_franzotype==FRANZO_HIGHWAY128) || (g_franzotype==FRANZO_HIGHWAY256)) franz_block_size=FRANZOFFSETV3; if (flagnochecksum) franz_block_size=0; } /// myprintf("00320: franz_block_size %d franzo_type %d |%c|\n",franz_block_size,g_franzotype,command); franz_block=NULL; if (franz_block_size>0) { franz_block=(char*)franz_malloc(franz_block_size); if (franz_block==NULL) { myprintf("00321! cannot franz_malloc\n"); seppuku(); } memset(franz_block,0,franz_block_size); g_dt_ram+=franz_block_size; g_allocatedram-=franz_block_size; // (updated in franz_malloc) } //g_dt_ram+=franz_block_size+sizeof(DT); hexhash =""; hexcrc32 =""; ///specificmethod ='Z'; hashtype =""; outputname =""; ///listtext =""; ///fragmentlisthash=""; pfile_highway64=NULL; if ((g_franzotype==FRANZO_HIGHWAY64) || (g_franzotype==FRANZO_HIGHWAY128) || (g_franzotype==FRANZO_HIGHWAY256)) { pfile_highway64=new HighwayHashCat; uint64_t key[4] = {1, 2, 3, 4}; HighwayHashCatStart(key,pfile_highway64); g_dt_ram+=sizeof(HighwayHashCat); } pfile_xxhash64=NULL; if ((g_franzotype==FRANZO_XXHASH64) || (g_franzotype==FRANZO_WINHASH64) || (g_franzotype==FRANZO_XXHASH64B)) { pfile_xxhash64=new XXHash64(0); g_dt_ram+=sizeof(XXHash64); } pfile_md5=NULL; if ((g_franzotype==FRANZO_MD5) || (g_franzotype==FRANZO_MD5B)) { pfile_md5=new MD5; g_dt_ram+=sizeof(MD5); } pfile_sha1=NULL; if ((g_franzotype==FRANZO_SHA_1)||(g_franzotype==FRANZO_SHA_1B)) { pfile_sha1=new libzpaq::SHA1; ///You get this warning before C++17 g_dt_ram+=sizeof(libzpaq::SHA1); } pfile_sha256=NULL; if ((g_franzotype==FRANZO_SHA_256)||(g_franzotype==FRANZO_SHA_256B)) { pfile_sha256=new libzpaq::SHA256; ///You get this warning before C++17 g_dt_ram+=sizeof(libzpaq::SHA256); } pfile_sha3=NULL; if ((g_franzotype==FRANZO_SHA3)||(g_franzotype==FRANZO_SHA3B)) { pfile_sha3=new SHA3; g_dt_ram+=sizeof(SHA3); } /// beware of time and space, but now we are sure to maintain 64 byte alignment pfile_whirlpool=NULL; if (g_franzotype==FRANZO_WHIRLPOOL) { pfile_whirlpool=new NESSIEstruct; NESSIEinit(pfile_whirlpool); g_dt_ram+=sizeof(NESSIEstruct); } pfile_xxh3=NULL; if ((g_franzotype==FRANZO_XXH3)||(g_franzotype==FRANZO_XXH3B)) { pfile_xxh3=(XXH3_state_t*)aligned_malloc(64, sizeof(XXH3_state_t)); (void)XXH3_128bits_reset(pfile_xxh3); g_dt_ram+=sizeof(XXH3_state_t); } pfile_blake3=NULL; if ((g_franzotype==FRANZO_BLAKE3)||(g_franzotype==FRANZO_BLAKE3B)) { pfile_blake3=(blake3_hasher*)franz_malloc(sizeof(blake3_hasher)); blake3_hasher_init(pfile_blake3); g_dt_ram+=sizeof(blake3_hasher); } pramfile=NULL; } /* too slow ~DT() { if (pfile_highway64) { delete pfile_highway64; pfile_highway64=NULL; } if (pfile_xxhash64) { delete pfile_xxhash64; pfile_xxhash64=NULL; } if (pfile_md5) { delete pfile_md5; pfile_md5=NULL; } if (pfile_sha1) { delete pfile_sha1; pfile_sha1=NULL; } if (pfile_sha256) { delete pfile_sha256; pfile_sha256=NULL; } if (pfile_sha3) { delete pfile_sha3; pfile_sha3=NULL; } if (pfile_whirlpool) { delete pfile_whirlpool; pfile_whirlpool=NULL; } if (pfile_xxh3) { aligned_free(pfile_xxh3); pfile_xxh3=NULL; } if (pfile_blake3) { franz_free(pfile_blake3); pfile_blake3=NULL; } } */ }; typedef map DTMap; // list of blocks to extract struct Block { int64_t offset; // location in archive int64_t usize; // uncompressed size, -1 if unknown (streaming) int64_t bsize; // compressed size vector files; // list of files pointing here unsigned start; // index in ht of first fragment unsigned size; // number of fragments to decompress unsigned frags; // number of fragments in block unsigned extracted; // number of fragments decompressed OK enum {READY, WORKING, GOOD, BAD} state; Block(unsigned s, int64_t o): offset(o), usize(-1), bsize(0), start(s), size(0), frags(0), extracted(0), state(READY) {} }; // Version info struct VER { int64_t date; // Date of C block, 0 if streaming int64_t lastdate; // Latest date of any block int64_t offset; // start of transaction C block int64_t data_offset; // start of first D block int64_t csize; // size of compressed data, -1 = no index int updates; // file updates int deletes; // file deletions unsigned firstFragment;// first fragment ID int64_t usize; // uncompressed size of files VER() {memset(this, 0, sizeof(*this));} }; // Windows API functions not in Windows XP to be dynamically loaded #ifndef unix typedef HANDLE (WINAPI* FindFirstStreamW_t) (LPCWSTR, STREAM_INFO_LEVELS, LPVOID, DWORD); FindFirstStreamW_t findFirstStreamW=0; typedef BOOL (WINAPI* FindNextStreamW_t)(HANDLE, LPVOID); FindNextStreamW_t findNextStreamW=0; typedef BOOL (WINAPI* GetFinalPathNameByHandleW_t)(HANDLE, LPWSTR,DWORD,DWORD); GetFinalPathNameByHandleW_t getFinalPathNameByHandleW=0; #endif // corresponds to #ifndef (#ifndef unix) typedef map int64tstringmap; typedef map stringstringmap; class CompressJob; typedef void (*callback_function)(char*); // type for conciseness /* Portion to list the contents of zpaq files in the most concise way possible, to reduce the time necessary for subsequent uses (e.g. from GUIs written in other languages), on Windows. Like this https://github.com/fcorbelli/zpaqlist A classic method for an extracting GUI for zpaq is to redirect the output of the command zpaq l (list) to a temporary file, read it, parse and then process, but it takes time. The output of zpaqlist (or zpaqfranz with the brand-new pakka command) is composed by - version # !1266 - version list | 1 2019-05-12 15:42:22 | 2 2019-05-13 09:22:49 | 3 2019-05-14 17:18:06 | 4 2019-05-16 14:17:25 | 5 2019-05-16 15:30:17 | 6 2019-05-16 23:30:17 (...) - total row number (with +) +38915424 - sorted by version and file name (for a time machine-like use) - and, by default, does not duplicate identical file names. - version_number - datetime (or D for deleted) - size (with dots) - filename or ? (if not changed from previous) Example (two record) The file f:/zarc/ihsv/pakka/30_3/zpaqfranz.exe is 3.089.462 bytes long, and was found in the 946 version, @ 02/10/2020 14:25:34 (European-style date format) In the version 959 the file result deleted (not present) -946 02/10/2020 14:25:34 3.089.462 f:/zarc/ihsv/pakka/30_3/zpaqfranz.exe -959 D 0 ? When the size of the output is large (and can even be hundreds of MB) the savings both in writing (on magnetic disks), reading and parsing can be considerable. For small archives (KB) there is obviously no difference compared to zpaq */ int64_t list_global_start=0; // set to mtime() at start of main() #ifdef _WIN32 namespace libzpaq2 { /* This is similar, but NOT equal, to newer libzpaq A bit of Frankenstein, to incorporate older 6.60 inside 7.15-based source */ // Symbolic constants, instruction size, and names typedef enum {LIST_NONE,LIST_CONS,LIST_CM,ILIST_CM,LIST_MATCH,LIST_AVG,LIST_LIST_MIX2, LIST_MIX,LIST_ILIST_SSE,LIST_SSE} list_CompType; ///////////////////////// Predictor ////////////////////////// // Decoder decompresses using an arithmetic code class list_Decoder { public: libzpaq::Reader* in; // destination list_Decoder(libzpaq::ZPAQL& z); int decompress(); // return a byte or EOF int skip(); // skip to the end of the segment, return next byte void init(); // initialize at start of block int stat(int x) {return pr.stat(x);} private: U32 low, high; // range U32 curr; // last 4 bytes of archive libzpaq::Predictor pr; // to get p enum {BUFSIZE=1<<16}; libzpaq::Array buf; // input buffer of size BUFSIZE bytes // of unmodeled data. buf[low..high-1] is input with curr // remaining in sub-block. int decode(int p); // return decoded bit (0..1) with prob. p (0..65535) void loadbuf(); // read unmodeled data into buf to EOS }; //////////////////////// list_Decompresser //////////////////////// // For decompression and listing archive contents class list_Decompresser { public: list_Decompresser(): z(), dec(z), pp(), state(BLOCK), decode_state(FIRSTSEG) {} void setInput(libzpaq::Reader* in) {dec.in=in;} bool findBlock(double* memptr = 0); void hcomp(libzpaq::Writer* out2) {z.write(out2, false);} bool findFilename(libzpaq::Writer* = 0); void readComment(libzpaq::Writer* = 0); void setOutput(libzpaq::Writer* out) {pp.setOutput(out);} void setSHA1(libzpaq::SHA1* sha1ptr) {pp.setSHA1(sha1ptr);} bool decompress(int n = -1); // n bytes, -1=all, return true until done bool pcomp(libzpaq::Writer* out2) {return pp.z.write(out2, true);} void readSegmentEnd(char* sha1string = 0); int stat(int x) {return dec.stat(x);} private: libzpaq::ZPAQL z; list_Decoder dec; libzpaq::PostProcessor pp; enum {BLOCK, FILENAME, COMMENT, DATA, SEGEND} state; // expected next enum {FIRSTSEG, SEG, SKIP} decode_state; // which segment in block? }; /////////////////////// Decoder /////////////////////// list_Decoder::list_Decoder(libzpaq::ZPAQL& z): in(0), low(1), high(0xFFFFFFFF), curr(0), pr(z), buf(BUFSIZE) { } void list_Decoder::init() { pr.init(); if (pr.isModeled()) low=1, high=0xFFFFFFFF, curr=0; else low=high=curr=0; } // Read un-modeled input into buf[low=0..high-1] // with curr remaining in subblock to read. void list_Decoder::loadbuf() { if (curr==0) { for (int i=0; i<4; ++i) { int c=in->get(); if (c<0) libzpaq::error("unexpected end of input"); curr=curr<<8|c; } } U32 n=buf.size(); if (n>curr) n=curr; high=in->read(&buf[0], n); curr-=high; low=0; } // Return next bit of decoded input, which has 16 bit probability p of being 1 int list_Decoder::decode(int p) { if (currhigh) libzpaq::error("archive corrupted"); U32 mid=low+U32(((high-low)*U64(U32(p)))>>16); // split range int y; if (curr<=mid) y=1, high=mid; // pick half else y=0, low=mid+1; while ((high^low)<0x1000000) { // shift out identical leading bytes high=high<<8|255; low=low<<8; low+=(low==0); int c=in->get(); if (c<0) libzpaq::error("unexpected end of file"); curr=curr<<8|c; } return y; } // Decompress 1 byte or -1 at end of input int list_Decoder::decompress() { if (pr.isModeled()) { // n>0 components? if (curr==0) { // segment initialization for (int i=0; i<4; ++i) curr=curr<<8|in->get(); } if (decode(0)) { if (curr!=0) libzpaq::error("decoding end of stream"); return -1; } else { int c=1; while (c<256) { // get 8 bits int p=pr.predict()*2+1; c+=c+decode(p); pr.update(c&1); } return c-256; } } else { if (low==high) loadbuf(); if (low==high) return -1; return buf[low++]&255; } } // Find end of compressed data and return next byte int list_Decoder::skip() { int c=-1; if (pr.isModeled()) { while (curr==0) // at start? curr=in->get(); while (curr && (c=in->get())>=0) // find 4 zeros curr=curr<<8|c; while ((c=in->get())==0) ; // might be more than 4 return c; } else { if (curr==0) // at start? for (int i=0; i<4 && (c=in->get())>=0; ++i) curr=curr<<8|c; while (curr>0) { U32 n=BUFSIZE; if (n>curr) n=curr; U32 n1=in->read(&buf[0], n); curr-=n1; if (n1<1) return -1; if (curr==0) for (int i=0; i<4 && (c=in->get())>=0; ++i) curr=curr<<8|c; } if (c>=0) c=in->get(); return c; } } // Find the start of a block and return true if found. Set memptr // to memory used. bool list_Decompresser::findBlock(double* memptr) { ///printf("08116: findblock\n"); // Find start of block U32 h1=0x3D49B113, h2=0x29EB7F93, h3=0x2614BE13, h4=0x3828EB13; // Rolling hashes initialized to hash of first 13 bytes int c; ///int64_t startct=0; while ((c=dec.in->get())!=-1) { /// printf("08122: getted c %03d startct %08d\n",c,startct++); h1=h1*12+c; h2=h2*20+c; h3=h3*28+c; h4=h4*44+c; if (h1==0xB16B88F1 && h2==0xFF5376F1 && h3==0x72AC5BF1 && h4==0x2F909AF1) break; // hash of 16 byte string } if (c==-1) return false; // Read header if ((c=dec.in->get())!=1 && c!=2) libzpaq::error("unsupported ZPAQ level"); if (dec.in->get()!=1) libzpaq::error("unsupported list_ZPAQL type"); z.read(dec.in); if (c==1 && z.header.isize()>6 && z.header[6]==0) libzpaq::error("ZPAQ level 1 requires at least 1 component"); if (memptr) *memptr=z.memory(); state=FILENAME; decode_state=FIRSTSEG; ///printf("08144: dec %08d\n",dec.in->ftell()); ///printf("08144: dec %08d\n",dec.in->tell()); return true; } // Read the start of a segment (1) or end of block code (255). // If a segment is found, write the filename and return true, else false. bool list_Decompresser::findFilename(libzpaq::Writer* filename) { int c=dec.in->get(); if (c==1) { // segment found while (true) { c=dec.in->get(); if (c==-1) libzpaq::error("unexpected EOF"); if (c==0) { state=COMMENT; return true; } if (filename) filename->put(c); } } else if (c==255) { // end of block found state=BLOCK; return false; } else libzpaq::error("missing segment or end of block"); return false; } // Read the comment from the segment header void list_Decompresser::readComment(libzpaq::Writer* comment) { state=DATA; while (true) { int c=dec.in->get(); if (c==-1) libzpaq::error("unexpected EOF"); if (c==0) break; if (comment) comment->put(c); } if (dec.in->get()!=0) libzpaq::error("missing reserved byte"); } // Decompress n bytes, or all if n < 0. Return false if done bool list_Decompresser::decompress(int n) { // Initialize models to start decompressing block if (decode_state==FIRSTSEG) { dec.init(); pp.init(z.header[4], z.header[5]); decode_state=SEG; } // Decompress and load PCOMP into postprocessor while ((pp.getState()&3)!=1) pp.write(dec.decompress()); // Decompress n bytes, or all if n < 0 while (n) { int c=dec.decompress(); pp.write(c); if (c==-1) { state=SEGEND; return false; } if (n>0) --n; } return true; } // Read end of block. If a SHA1 checksum is present, write 1 and the // 20 byte checksum into sha1string, else write 0 in first byte. // If sha1string is 0 then discard it. void list_Decompresser::readSegmentEnd(char* sha1string) { // Skip remaining data if any and get next byte int c=0; if (state==DATA) { c=dec.skip(); decode_state=SKIP; } else if (state==SEGEND) c=dec.in->get(); state=FILENAME; // Read checksum if (c==254) { if (sha1string) sha1string[0]=0; // no checksum } else if (c==253) { if (sha1string) sha1string[0]=1; for (int i=1; i<=20; ++i) { c=dec.in->get(); if (sha1string) sha1string[i]=c; } } else libzpaq::error("missing end of segment marker"); } } // end namespace libzpaq2 // Global variables int64_t list_g_dimensione=0; FILE* list_outputlog=stdout; FILE* list_con=stdout; // log output, can be stderr static const int64_t LIST_MAX_QUIET=0x7FFFFFFFFFFFFFFFLL; // no output but errors // signed size of a string or vector template int list_size(const T& x) { return x.size(); } // In Windows, convert 16-bit wide string to UTF-8 and \ to / string list_wtou(const wchar_t* s) { string r; if (!s) return r; for (; *s; ++s) { if (*s=='\\') r+='/'; else if (*s<128) r+=*s; else if (*s<2048) r+=192+*s/64, r+=128+*s%64; else r+=224+*s/4096, r+=128+*s/64%64, r+=128+*s%64; } return r; } // In Windows, convert UTF-8 string to wide string ignoring // invalid UTF-8 or >64K. If doslash then convert "/" to "\". std::wstring list_utow(const char* ss, bool doslash=false) { std::wstring r; if (!ss) return r; const unsigned char* s=(const unsigned char*)ss; for (; s && *s; ++s) { if (s[0]=='/' && doslash) r+='\\'; else if (s[0]<128) r+=s[0]; else if (s[0]>=192 && s[0]<224 && s[1]>=128 && s[1]<192) r+=(s[0]-192)*64+s[1]-128, ++s; else if (s[0]>=224 && s[0]<240 && s[1]>=128 && s[1]<192 && s[2]>=128 && s[2]<192) r+=(s[0]-224)*4096+(s[1]-128)*64+s[2]-128, s+=2; } return r; } // Print a UTF-8 string to f (stdout, stderr) so it displays properly void list_printutf8(const char* s, FILE* f) { const HANDLE h=(HANDLE)_get_osfhandle(_fileno(f)); DWORD ft=GetFileType(h); if (ft==FILE_TYPE_CHAR) { fflush(f); std::wstring w=list_utow(s); // Windows console: convert to UTF-16 DWORD n=0; WriteConsole(h, w.c_str(), w.size(), &n, 0); } else // stdout redirected to file fprintf(f, "%s", s); } // Convert 64 bit decimal YYYYMMDDHHMMSS to "YYYY-MM-DD HH:MM:SS" // where -1 = unknown date, 0 = deleted. string list_dateToString(int64_t date) { if (date<=0) return " "; string s="0000-00-00 00:00:00"; static const int t[]={18,17,15,14,12,11,9,8,6,5,3,2,1,0}; for (int i=0; i<14; ++i) s[t[i]]+=int(date%10), date/=10; return s; } string list_mydateToString(int64_t date) { if (date<=0) return " "; /// 0123456789012345678 string s="0000-00-00 00:00:00"; string s2="00/00/0000 00:00:00"; static const int t[]={18,17,15,14,12,11,9,8,6,5,3,2,1,0}; for (int i=0; i<14; ++i) s[t[i]]+=int(date%10), date/=10; /// convert in european date format dd/mm/yyyy hh:mm:ss s2[0]=s[8]; s2[1]=s[9]; s2[3]=s[5]; s2[4]=s[6]; s2[6]=s[0]; s2[7]=s[1]; s2[8]=s[2]; s2[9]=s[3]; s2[11]=s[11]; s2[12]=s[12]; s2[14]=s[14]; s2[15]=s[15]; s2[17]=s[17]; s2[18]=s[18]; return s2; } /////////////////////////////// File ////////////////////////////////// // Convert non-negative decimal number x to string of at least n digits string list_itos(int64_t x, int n=1) { string r; for (; x || n>0; x/=10, --n) r=string(1, '0'+x%10)+r; return r; } // Replace * and ? in fn with part or digits of part string list_subpart(string fn, int part) { for (int j=fn.size()-1; j>=0; --j) { if (fn[j]=='?') fn[j]='0'+part%10, part/=10; else if (fn[j]=='*') fn=fn.substr(0, j)+list_itos(part)+fn.substr(j+1), part=0; } return fn; } // Return true if a file or directory (UTF-8 without trailing /) list_exists. // If part>0 then replace * and ? in filename with part or its digits. bool list_exists(string filename, int part=0) { if (part>0) filename=list_subpart(filename, part); int len=filename.size(); if (len<1) return false; if (filename[len-1]=='/') filename=filename.substr(0, len-1); return GetFileAttributes(list_utow(filename.c_str(), true).c_str()) !=INVALID_FILE_ATTRIBUTES; } // Print error message void list_printerr(const char* filename) { #ifdef _WIN32 int err=GetLastError(); list_printutf8(filename, stderr); if (err==ERROR_FILE_NOT_FOUND) fprintf(stderr, ": file not found\n"); else if (err==ERROR_PATH_NOT_FOUND) fprintf(stderr, ": path not found\n"); else if (err==ERROR_ACCESS_DENIED) fprintf(stderr, ": access denied\n"); else if (err==ERROR_SHARING_VIOLATION) fprintf(stderr, ": sharing violation\n"); else if (err==ERROR_BAD_PATHNAME) fprintf(stderr, ": bad pathname\n"); else if (err==ERROR_INVALID_NAME) fprintf(stderr, ": invalid name\n"); else fprintf(stderr, ": Windows error %d\n", err); #else fprintf(stderr, ": nix error\n"); #endif // corresponds to #ifdef (#ifdef _WIN32) } // Base class of InputFile and list_OutputFile (OS independent) class list_File { protected: enum {BUFSIZE=1<<16}; // buffer size int ptr; // next byte to read or write in buf libzpaq::Array buf; // I/O buffer libzpaq::AES_CTR *aes; // if not NULL then encrypt int64_t eoff; // extra offset for multi-file encryption list_File(): ptr(0), buf(BUFSIZE), aes(0), eoff(0) {} }; // list_File types accepting UTF-8 filenames class list_InputFile: public list_File, public libzpaq::Reader { HANDLE in; // input file handle DWORD n; // buffer size public: list_InputFile(): in(INVALID_HANDLE_VALUE), n(0) {} // Open for reading. Return true if successful. // Encrypt with aes+e if aes. bool open(const char* filename, libzpaq::AES_CTR* a=0, int64_t e=0) { n=ptr=0; std::wstring w=list_utow(filename, true); in=CreateFile(w.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (in==INVALID_HANDLE_VALUE) list_printerr(filename); aes=a; eoff=e; return in!=INVALID_HANDLE_VALUE; } bool isopen() {return in!=INVALID_HANDLE_VALUE;} // Read 1 byte int get() { if (ptr>=int(n)) { ptr=0; ReadFile(in, &buf[0], BUFSIZE, &n, NULL); if (n==0) return EOF; if (aes) { int64_t off=tell()+eoff; if (off<32) libzpaq::error("attempt to read salt"); aes->encrypt(&buf[0], n, off); } } return buf[ptr++]&255; } // set file pointer void seek(int64_t pos, int whence) { if (whence==SEEK_SET) whence=FILE_BEGIN; else if (whence==SEEK_END) whence=FILE_END; else if (whence==SEEK_CUR) { whence=FILE_BEGIN; pos+=tell(); } long offhigh=pos>>32; SetFilePointer(in, pos, &offhigh, whence); n=ptr=0; } // get file pointer int64_t tell() { long offhigh=0; DWORD r=SetFilePointer(in, 0, &offhigh, FILE_CURRENT); return (int64_t(offhigh)<<32)+r+ptr-n; } // Close handle if open void close() { if (in!=INVALID_HANDLE_VALUE) { CloseHandle(in); in=INVALID_HANDLE_VALUE; } } ~list_InputFile() {close();} }; /////////////////////////////// list_Archive /////////////////////////////// // An list_Archive is a multi-part file that supports encrypted input class list_Archive: public libzpaq::Reader, public libzpaq::Writer { libzpaq::AES_CTR* aes; // NULL if not encrypted struct FE { // list_File element for multi-part archives string fn; // file name int64_t end; // size of previous and current files FE(): end(0) {} FE(const string& s, int64_t e): fn(s), end(e) {} }; vector files; // list of parts. only last part is writable. int fi; // current file in files int64_t listoff; // total offset over all files int mode; // 'r' or 'w' for reading or writing or 0 if closed list_InputFile in; // currently open input file /// list_OutputFile out; // currently open output file public: // Constructor list_Archive(): aes(0), fi(0), listoff(0), mode(0) {} // Destructor ~list_Archive() {close();} // Open filename for read and write. If filename contains wildards * or ? // then replace * with part number 1, 2, 3... or ? with single digits // up to the last existing file. Return true if at least one file is found. // If password is not NULL then assume the concatenation of the files // is in encrypted format. mode_ is 'r' for reading or 'w' for writing. // If the filename contains wildcards then output is to the first // non-existing file, else to filename. If newsize>=0 then truncate // the output to newsize bytes. If password and offset>0 then encrypt // output as if previous parts had size offset and salt salt. bool open(bool i_quiet,const char* filename, const char* password=0, int mode_='r', int64_t newsize=-1, int64_t offset=0, const char* salt=0); // True if archive is open bool isopen() const {return files.size()>0;} // Position the next read or write offset to p. void seek(int64_t p, int whence); // Return current file offset. int64_t tell() const {return listoff;} // Read up to n bytes into buf at current offset. Return 0..n bytes // actually read. 0 indicates EOF. int read(char* buf, int n) { if (fi>=list_size(files)) return 0; if (!in.isopen()) return 0; n=in.read(buf, n); seek(n, SEEK_CUR); return n; } // Read and return 1 byte or -1 (EOF) int get() { if (fi>=list_size(files)) return -1; while (listoff==files[fi].end) { in.close(); if (++fi>=list_size(files)) return -1; if (!in.open(files[fi].fn.c_str(), aes, fi>0 ? files[fi-1].end : 0)) libzpaq::error("cannot read next archive part"); } ++listoff; return in.get(); } // Write one byte void put(int c) { c+=3; /// nowarning please ++listoff; } // Write buf[0..n-1] // Close any open part void close() { if (in.isopen()) in.close(); if (aes) { delete aes; aes=0; } files.clear(); fi=0; listoff=0; mode=0; } }; void list_print_datetime(void) { int hours, minutes, seconds, day, month, year; time_t now; time(&now); struct tm *local = localtime(&now); hours = local->tm_hour; // get hours since midnight (0-23) minutes = local->tm_min; // get minutes passed after the hour (0-59) seconds = local->tm_sec; // get seconds passed after the minute (0-59) day = local->tm_mday; // get day of month (1 to 31) month = local->tm_mon + 1; // get month of year (0 to 11) year = local->tm_year + 1900; // get year since 1900 printf("%02d/%02d/%d %02d:%02d:%02d ", day, month, year, hours,minutes,seconds); } bool list_Archive::open(bool i_quiet,const char* filename, const char* password, int mode_, int64_t newsize, int64_t offset, const char* salt) { mode=mode_; list_g_dimensione=0; // Read part files and get sizes. Get salt from the first part. string next; int64_t startscan=mtime(); int i; for (i=1; !offset; ++i) { next=list_subpart(filename, i); if (!list_exists(next)) break; if (files.size()>0 && files[0].fn==next) break; // part overflow // set up key from salt in first file if (!in.open(next.c_str())) libzpaq::error("cannot read archive"); if (i==1 && password && newsize!=0) { char slt[32], key[32]; if (in.read(slt, 32)!=32) libzpaq::error("no salt"); libzpaq::stretchKey(key, password, slt); aes=new libzpaq::AES_CTR(key, 32, slt); g_allocatedram+=sizeof(libzpaq::AES_CTR); } // Get file size in.seek(0, SEEK_END); files.push_back(FE(next, in.tell()+(files.size() ? files[files.size()-1].end : 0))); list_g_dimensione+=in.tell(); in.close(); if (next==filename) break; // no wildcards } if (!i_quiet) { list_print_datetime(); printf("Multipart scan %f s chunks %d\n",(mtime()-startscan)/1000.0,i); } // If offset is not 0 then use it for the part sizes and use // salt as the salt of the first part. if (offset>0) { files.push_back(FE("", offset)); files.push_back(FE(filename, offset)); if (password) { char key[32]={0}; libzpaq::stretchKey(key, password, salt); aes=new libzpaq::AES_CTR(key, 32, salt); g_allocatedram+=sizeof(libzpaq::AES_CTR); } } // Open file for reading fi=files.size(); if (mode=='r') { seek(32*(password!=0), SEEK_SET); // open first input file return files.size()>0; } return false; } void list_Archive::seek(int64_t p, int whence) { if (whence==SEEK_SET) listoff=p; else if (whence==SEEK_CUR) listoff+=p; else if (whence==SEEK_END) listoff=(files.size() ? files.back().end : 0)+p; else exit(0); if (mode=='r') { int oldfi=fi; for (fi=0; fi=files[fi].end; ++fi); if (fi!=oldfi) { in.close(); if (fi0 ? files[fi-1].end : 0)) libzpaq::error("cannot reopen archive after seek"); } if (fi2) rc=2; return rc; } ////////////////////////////// StringBuffer ////////////////////////// // For libzpaq output to a string struct list_StringWriter: public libzpaq::Writer { string s; void put(int c) {s+=char(c);} }; // For (de)compressing to/from a string. Writing appends bytes // which can be later read. class list_StringBuffer: public libzpaq::Reader, public libzpaq::Writer { unsigned char* p; // allocated memory, not NUL terminated, may be NULL size_t al; // number of bytes allocated, 0 iff p is NULL size_t wpos; // index of next byte to write, wpos <= al size_t rpos; // index of next byte to read, rpos < wpos or return EOF. size_t limit; // max size, default = -1 const size_t init; // initial size on first use after reset // Increase capacity to a without changing size void reserve(size_t a) { if (a<=al) return; unsigned char* q=0; g_allocatedram+=a; if (a>0) q=(unsigned char*)(p ? realloc(p, a) : malloc(a)); if (a>0 && !q) { myprintf("50937$ list_StringBuffer realloc %1.0f to %1.0f at %s failed\n",double(al), double(a), migliaia(int64_t(p))); libzpaq::error("Out of memory"); } p=q; al=a; } // Enlarge al to make room to write at least n bytes. void lengthen(unsigned n) { if (wpos+n>limit) libzpaq::error("list_StringBuffer overflow"); if (wpos+n<=al) return; size_t a=al; while (wpos+n>=a) a=a*2+init; reserve(a); } // No assignment or copy void operator=(const list_StringBuffer&); list_StringBuffer(const list_StringBuffer&); public: // Direct access to data unsigned char* data() {return p;} // Allocate no memory initially list_StringBuffer(size_t n=0): p(0), al(0), wpos(0), rpos(0), limit(size_t(-1)), init(n>128?n:128) {} // Set output limit void setLimit(size_t n) {limit=n;} // Free memory ~list_StringBuffer() {if (p) free(p);} // Return number of bytes written. size_t size() const {return wpos;} // Return number of bytes left to read size_t remaining() const {return wpos-rpos;} // Reset size to 0. void reset() { if (p) free(p); p=0; al=rpos=wpos=0; } // Write a single byte. void put(int c) { // write 1 byte lengthen(1); p[wpos++]=c; } // Write buf[0..n-1] void write(const char* buf, int n) { if (n<1) return; lengthen(n); memcpy(p+wpos, buf, n); wpos+=n; } // Read a single byte. Return EOF (-1) and reset at end of string. int get() { return rposwpos) n=wpos-rpos; if (n>0) memcpy(buf, p+rpos, n); rpos+=n; return n; } // Return the entire string as a read-only array. const char* c_str() const {return (const char*)p;} // Truncate the string to size i. void resize(size_t i) {wpos=i;} // Write a string. void operator+=(const string& t) {write(t.data(), t.size());} // Swap efficiently (init is not swapped) void swap(list_StringBuffer& s) { std::swap(p, s.p); std::swap(al, s.al); std::swap(wpos, s.wpos); std::swap(rpos, s.rpos); std::swap(limit, s.limit); } }; ////////////////////////////// misc /////////////////////////////////// // Read 4 byte little-endian int and advance s int list_btoi(const char* &s) { s+=4; return (s[-4]&255)|((s[-3]&255)<<8)|((s[-2]&255)<<16)|((s[-1]&255)<<24); } // Read 8 byte little-endian int and advance s int64_t list_btol(const char* &s) { int64_t r=unsigned(list_btoi(s)); return r+(int64_t(list_btoi(s))<<32); } string generaterandomstring(unsigned int i_length) { if (i_length==0) { myprintf("03168: i_lenght in C5\n"); seppuku(); } static const char characters[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; char* randomstring=(char*)franz_malloc(i_length+1); if (randomstring==NULL) { myprintf("03169: C5 on malloc\n"); seppuku(); } srand((unsigned)time(NULL)); for (unsigned int i=0;i 2.0) { normalized /= 2.0; exponent++; } while (normalized < 1.0) { normalized *= 2.0; exponent--; } // Calcolo logaritmo usando serie di Taylor // ln(x) = 2 * [ (x-1)/(x+1) + (1/3)((x-1)/(x+1))³ + (1/5)((x-1)/(x+1))⁵ + ... ] double y = (normalized - 1.0) / (normalized + 1.0); double y2 = y * y; double result = 0.0; double term = y; for (int n = 1; n <= MAX_ITERATIONS; n += 2) { result += term / n; term *= y2; // Criterio di interruzione if (term < MYEPSILON && term > -MYEPSILON) break; } // Moltiplica per 2 e aggiungi contributo dell'esponente double risultato= 2.0 * result + exponent * 0.69314718056; // 0.69314718056 è ln(2) double check=log(x); myprintf("51122: log delta %f\n",risultato-check); return risultato; #endif } double custom_log2(double x) { #ifndef NOLM return log2(x); #else double risultato=custom_log(x) * 1.4426950408889634; // 1/ln(2) double check=log2(x); myprintf("51123: log2 delta %f\n",risultato-check); #endif } double custom_exp(double x) { #ifndef NOLM return exp(x); #else if (x == 0.0) return 1.0; if (x > 700.0) return __builtin_huge_valf(); // Evita overflow if (x < -700.0) return 0.0; // Evita underflow // Riduce x usando exp(x) = exp(x/2)^2 int power = 0; while (x > 1.0) { x /= 2.0; power++; } while (x < -1.0) { x /= 2.0; power--; } // Serie di Taylor double result = 1.0; double term = 1.0; for (int n = 1; n <= MAX_ITERATIONS; n++) { term *= x / n; result += term; if (term < MYEPSILON) break; } // Ricompone il risultato while (power > 0) { result *= result; power--; } while (power < 0) { result = result * result; power++; } double check=exp(x); myprintf("51124: exp delta %f\n",result-check); return result; #endif } bool myavanzamentoby1sec(int64_t i_lavorati,int64_t i_totali,int64_t i_inizio,bool i_barran=true) { bool hostampato=false; static int ultimotempo=0; int secondi=(mtime()-i_inizio)/1000; int percentuale=int(i_lavorati*100.0/(i_totali+0.5)); if (percentuale>100) percentuale=100; if (secondi!=ultimotempo) { ultimotempo=secondi; double eta=0.001*(mtime()-i_inizio)*(i_totali-i_lavorati)/(i_lavorati+1.0); if (secondi==0) secondi=1; if (eta<356000) { myprintf("%03d%% %02d:%02d:%02d (%10s) of (%10s) %20s/s", percentuale, int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(i_lavorati), tohuman2(i_totali),migliaia3(i_lavorati/secondi)); if (i_barran) myprintf("\n"); else myprintf("\r"); hostampato=true; } fflush(stdout); } return hostampato; } #ifdef _WIN64 class downcallback:public IBindStatusCallback { private: int64_t startdownload; public: downcallback() { startdownload=mtime();} STDMETHOD(OnProgress)(ULONG ulProgress,ULONG ulProgressMax,ULONG ulStatusCode,LPCWSTR wszStatusText) { myavanzamentoby1sec(ulProgress,ulProgressMax,startdownload,false); return S_OK; } STDMETHOD(OnStartBinding)(/* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR *pib) { return E_NOTIMPL; } STDMETHOD(GetPriority)(/* [out] */ LONG __RPC_FAR *pnPriority) { return E_NOTIMPL; } STDMETHOD(OnLowResource)(/* [in] */ DWORD reserved) { return E_NOTIMPL; } STDMETHOD(OnStopBinding)(/* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError) { return E_NOTIMPL; } STDMETHOD(GetBindInfo)(/* [out] */ DWORD __RPC_FAR *grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo) { return E_NOTIMPL; } STDMETHOD(OnDataAvailable)(/* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ STGMEDIUM __RPC_FAR *pstgmed) { return E_NOTIMPL; } STDMETHOD(OnObjectAvailable)(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk) { return E_NOTIMPL; } STDMETHOD_(ULONG,AddRef)() { return 0; } STDMETHOD_(ULONG,Release)() { return 0; } STDMETHOD(QueryInterface)(/* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject) { return E_NOTIMPL; } }; #endif // corresponds to #ifdef (#ifdef _WIN64) bool downloadfile(string i_verurl, string i_verfile, bool i_showupdate) { #if defined(SOLARIS) || defined(__HAIKU__) return false; #else if (i_verurl == "") { myprintf("03170: i_verurl empty\n"); return false; } if (i_verfile == "") { myprintf("03171: i_verfile empty\n"); return false; } if (flagverbose) { myprintf("03172: Download from URL %s\n", i_verurl.c_str()); myprintf("03173: to file %s\n", i_verfile.c_str()); } #ifdef _WIN32 if (flagdebug3) myprintf("03174: WIN32 version of filedownload\n"); #ifdef _WIN64 downcallback thecallback; downcallback* p_thecallback = NULL; if (i_showupdate) p_thecallback = &thecallback; if (S_OK != URLDownloadToFileW(NULL, utow(i_verurl.c_str()).c_str(), utow(i_verfile.c_str()).c_str(), 0, p_thecallback)) #else if (S_OK != URLDownloadToFileW(NULL, utow(i_verurl.c_str()).c_str(), utow(i_verfile.c_str()).c_str(), 0, 0)) #endif { myprintf("03175: Error C5: cannot download file (no internet?)\n"); return false; } #else #define INTERNET_BUFFER_SIZE 1024 if (flagdebug) myprintf("03176: starting *nix download\n"); char buffer[INTERNET_BUFFER_SIZE]; char *hostname, *path; const char *url = i_verurl.c_str(); if (flagdebug3) myprintf("03177: before test1\n"); if (strncmp(url, "http://", 7) == 0) hostname = strdup(url + 7); else { myprintf("03178: Download work only on http\n"); return false; } if (flagdebug3) myprintf("03179: before test2\n"); path = strchr(hostname, '/'); if (path == NULL) { myprintf("03180: cannot strchr / in hostname!\n"); free(hostname); return false; } else { *path = '\0'; path++; } if (flagdebug3) myprintf("03181: path |%s|\n", path); #ifndef IPV6 int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { myprintf("03182: Error C5: socket kaputt\n"); free(hostname); return false; } struct hostent *server = gethostbyname(hostname); if (server == NULL) { myprintf("03183$ cannot resolve %s\n", hostname); free(hostname); return false; } struct sockaddr_in serv_addr; memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(80); if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { myprintf("03184$ C5 on connect\n"); free(hostname); return false; } #else struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = 0; hints.ai_addrlen = 0; hints.ai_addr = NULL; hints.ai_canonname = NULL; hints.ai_next = NULL; struct addrinfo *addresses = NULL; int ret = getaddrinfo(hostname, "80", &hints, &addresses); if (ret) { myprintf("03183$ IPV6 cannot resolve %s: %s\n", hostname, gai_strerror(ret)); free(hostname); // Aggiunto free qui return false; } int sockfd; struct addrinfo *address; for (address = addresses; address; address = address->ai_next) { sockfd = socket(address->ai_family, address->ai_socktype, address->ai_protocol); if (sockfd == -1) continue; if (!connect(sockfd, address->ai_addr, address->ai_addrlen)) break; close(sockfd); } freeaddrinfo(addresses); if (address == NULL) { myprintf("39345$ IPV6 C5 on connect\n"); free(hostname); // Aggiunto free qui return false; } #endif snprintf(buffer, INTERNET_BUFFER_SIZE, "GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n", path, hostname); free(hostname); if (write(sockfd, buffer, strlen(buffer)) < 0) { myprintf("03185: kaputt writing on socket\n"); close(sockfd); // Aggiunto close qui return false; } FILE *file = fopen(i_verfile.c_str(), "wb"); if (file == NULL) { myprintf("03186: cannot open file to write %s\n", i_verfile.c_str()); close(sockfd); // Aggiunto close qui return false; } ssize_t n; while ((n = read(sockfd, buffer, INTERNET_BUFFER_SIZE)) > 0) { if (flagdebug3) myprintf("03187: read %s from socket\n", migliaia(n)); fwrite(buffer, 1, n, file); } if (n < 0) { myprintf("03188: socket negative!\n"); fclose(file); close(sockfd); return false; } fclose(file); close(sockfd); return (prendidimensionefile(i_verfile.c_str()) > 0); #endif #endif return true; } string mm_hash_calc_file(int i_algo,const char * i_filename,bool i_flagcalccrc32,uint32_t& o_crc32,const int64_t i_inizio,const int64_t i_totali,int64_t& io_lavorati,int64_t& o_thefilesize) { o_thefilesize=0; o_crc32=0; char buffer[256]; string risultato ="26304:ERROR"; int64_t lunghezza =prendidimensionefile(i_filename); char* data =NULL; char zero =0; /// my zerobytelong "file" #ifdef unix int myfilehandle=0; // for unix #else HANDLE mapping =0; HANDLE myfile =0; #endif // corresponds to #ifdef (#ifdef unix) if (lunghezza==0) { // 0 length file. Fix to get same results as "normal" hash data=&zero; } else { #ifdef unix myfilehandle=open(i_filename,O_RDONLY); if (myfilehandle<=0) return "26364: ERROR IN OPEN"; data=(char *)mmap(0,lunghezza,PROT_READ,MAP_PRIVATE,myfilehandle,0); if (data==MAP_FAILED) { close(myfilehandle); return "26369: map failed"; } #else wstring wfilename=utow(i_filename); myfile=CreateFile(wfilename.c_str(),GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); if (myfile==INVALID_HANDLE_VALUE) { myprintf("00769: Invalid handle for %s\n",i_filename); return "26311:ERROR"; } mapping=CreateFileMapping(myfile,0,PAGE_READONLY, 0, 0, 0); if (mapping==0) { if (myfile!=0) CloseHandle(myfile); return "26322:ERROR"; } data=(char*)MapViewOfFile(mapping,FILE_MAP_READ,0,0,0); #endif // corresponds to #ifdef (#ifdef unix) } if (data) { if (i_algo==ALGO_NILSIMSA) { nilsimsa_compute(data,lunghezza,buffer); risultato=binarytohex((const unsigned char*)buffer,64); } else if (i_algo==ALGO_WYHASH) { uint64_t _wyp[4]; make_secret(0,_wyp); uint64_t mywyhash=wyhash(data,lunghezza,0,_wyp); risultato=bin2hex_64(mywyhash); } else if ((i_algo==FRANZO_XXHASH64) || (i_algo==FRANZO_WINHASH64) || (i_algo==FRANZO_XXHASH64B)) { uint64_t myseed = 0; XXHash64 myhash(myseed); myhash.add(data,lunghezza); risultato=bin2hex_64(myhash.hash()); } else if ((i_algo==FRANZO_SHA_1)||(i_algo==FRANZO_SHA_1B)) { libzpaq::SHA1 sha1; for (int64_t i=0;i0)) myavanzamentoby1sec(io_lavorati,i_totali,i_inizio,false); } #ifdef unix if (myfilehandle!=0) close(myfilehandle); if (lunghezza>0) { int errore=munmap(data,lunghezza); if (errore!=0) return "26506: unmapping guru"; } #else else { myprintf("00770: data empty\n"); if (mapping!=0) CloseHandle(mapping); if (myfile!=0) CloseHandle(myfile); return "26441: ERROR"; } if (lunghezza>0) UnmapViewOfFile(data); if (mapping!=0) CloseHandle(mapping); if (myfile!=0) CloseHandle(myfile); #endif // corresponds to #ifdef (#ifdef unix) o_thefilesize=lunghezza; return risultato; } class franz_do_hash { /* do you think this is kind of "weird" C/C++/Delphi? Well, we need to compile on gcc 3.4 therefore no C++20, no C++14, no... nothing franz_do_hash hashfrombuffer(par->algo[i]); hashfrombuffer.init(); hashfrombuffer.update(par->data[i],par->filesize[i]); hashstringato=hashfrombuffer.finalize(); franz_do_hash dummy(tmpalgo[i]); string risu=dummy.filehash(work,false,par->inizio,par->dimensione); */ private: bool isinit; bool isfinalized; XXHash64 *p_xxhash64; libzpaq::SHA1 *p_sha1; libzpaq::SHA256 *p_sha256; SHA3 *p_sha3; XXH3_state_t *p_xxh3; MD5 *p_md5; blake3_hasher *p_blake3; NESSIEstruct *p_whihasher; HighwayHashCat *p_highway64state; uint32_t *p_crc32; uint32_t *p_crc32c; finalize_function ffinalize; public: string i_hashtype2; int ihashtype; bool flagcalccrc32; bool i_filehash; // if false, do a RAM hash ///string i_filename; bool i_flagmm; int64_t i_inizio; int64_t i_totali; int i_chunksize; uint32_t* i_buffer8bit; string o_status; string o_hexhash; int64_t o_thefilesize; uint32_t o_crc32; string o_hexcrc32; uint32_t o_crc32c; string o_hexcrc32c; void init(); void update(char *i_buffer,const int i_buflen); string finalize(); franz_do_hash(string i_type): ihashtype(-1), flagcalccrc32(false), i_filehash(true), i_flagmm(false), i_inizio(0), i_totali(0), i_chunksize(0), i_buffer8bit(NULL), o_thefilesize(0), o_crc32(0), o_crc32c(0) { ffinalize =NULL; if (i_type=="") { /// myprintf("00771: i_type empty\n"); /// seppuku(); return; } myreplace(i_type,"WINXXHASH64","XXHASH64"); for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (stringtoupper(i_type)==(p->second.hashname)) { ffinalize=p->second.ffinalize; ihashtype=p->first; ///printf("stopme %d\n",p->first); ///exit(0); } if (ffinalize==NULL) { myprintf("00772! GURU cannot find finalize for %s\n",i_type.c_str()); seppuku(); return; } i_hashtype2 =i_type; o_status =""; o_hexhash =""; o_hexcrc32 =""; o_hexcrc32c =""; isinit =false; isfinalized =false; } franz_do_hash(int i_franzotype): ihashtype(-1), flagcalccrc32(false), i_filehash(true), i_flagmm(false), i_inizio(0), i_totali(0), i_chunksize(0), i_buffer8bit(NULL), o_thefilesize(0), o_crc32(0), o_crc32c(0) { MAPPATIPOHASH::iterator p=g_mappatipohash.find(i_franzotype); if (p==g_mappatipohash.end()) { myprintf("00773! GURU, cannot convert int %d to ASCII!\n",i_franzotype); seppuku(); return; } i_hashtype2 =p->second.hashname; ihashtype =i_franzotype; o_status =""; o_hexhash =""; o_hexcrc32 =""; o_hexcrc32c =""; isinit =false; isfinalized =false; } string filehash(string i_filename,bool i_flagcalccrc32,int64_t i_inizio,int64_t i_totali); }; void franz_do_hash::init() { p_crc32 =NULL; p_crc32c =NULL; p_xxhash64 =NULL; p_sha1 =NULL; p_sha256 =NULL; p_sha3 =NULL; p_xxh3 =NULL; p_md5 =NULL; p_blake3 =NULL; p_whihasher =NULL; p_highway64state=NULL; if (ihashtype==-1) { myprintf("00774: GURU hashtype empty\n"); seppuku(); return; } if (i_hashtype2=="NONE") return; if ((ihashtype==FRANZO_XXHASH64) || (ihashtype==FRANZO_WINHASH64) || (ihashtype==FRANZO_XXHASH64B)) { p_xxhash64=new XXHash64(0); g_allocatedram+=sizeof(XXHash64); } else if ((ihashtype==FRANZO_SHA_1)||(ihashtype==FRANZO_SHA_1B)) { p_sha1=new libzpaq::SHA1; ///You get this warning before C++17 g_allocatedram+=sizeof(libzpaq::SHA1); } else if ((ihashtype==FRANZO_SHA_256)||(ihashtype==FRANZO_SHA_256B)) { p_sha256=new libzpaq::SHA256; ///You get this warning before C++17 g_allocatedram+=sizeof(libzpaq::SHA256); } else if ((ihashtype==FRANZO_XXH3)||(ihashtype==FRANZO_XXH3B)) { p_xxh3=(XXH3_state_t*)aligned_malloc(64, sizeof(XXH3_state_t)); (void)XXH3_128bits_reset(p_xxh3); g_allocatedram+=sizeof(XXH3_state_t); } else if ((ihashtype==FRANZO_MD5) || (ihashtype==FRANZO_MD5B)) { p_md5=new MD5; g_allocatedram+=sizeof(MD5); } else if ((ihashtype==FRANZO_SHA3)||(ihashtype==FRANZO_SHA3B)) { p_sha3=new SHA3; g_allocatedram+=sizeof(SHA3); } else if ((ihashtype==FRANZO_BLAKE3)||(ihashtype==FRANZO_BLAKE3B)) { p_blake3=(blake3_hasher*)franz_malloc(sizeof(blake3_hasher)); blake3_hasher_init(p_blake3); g_allocatedram+=sizeof(blake3_hasher); } else if (ihashtype==FRANZO_WHIRLPOOL) { p_whihasher=new NESSIEstruct; NESSIEinit(p_whihasher); g_allocatedram+=sizeof(NESSIEstruct); } else if ((ihashtype==FRANZO_HIGHWAY64) || (ihashtype==FRANZO_HIGHWAY128) || (ihashtype==FRANZO_HIGHWAY256)) { p_highway64state=new HighwayHashCat; uint64_t key[4] = {1, 2, 3, 4}; HighwayHashCatStart(key,p_highway64state); g_allocatedram+=sizeof(HighwayHashCat); } else if (ihashtype==FRANZO_CRC_32) { } else if (ihashtype==ALGO_CRC32C) { } else { myprintf("00775: GURU hashtype unknown |%s| %d\n",i_hashtype2.c_str(),ihashtype); seppuku(); return; } isinit =true; isfinalized =false; } string franz_do_hash::finalize() { if (ihashtype==-1) { myprintf("00776: GURU hashtype empty\n"); seppuku(); return "47302: GURU hashtype empty"; } if (!isinit) { myprintf("00777: GURU not init!\n"); seppuku(); return "47308: GURU not init!"; } if (isfinalized) { myprintf("00778: already finalized!\n"); seppuku(); return "47314: already finalized!"; } if ((ihashtype==FRANZO_XXHASH64) || (ihashtype==FRANZO_WINHASH64) || (ihashtype==FRANZO_XXHASH64B)) o_hexhash=ffinalize(p_xxhash64); else if ((ihashtype==FRANZO_SHA_1)||(ihashtype==FRANZO_SHA_1B)) o_hexhash=ffinalize(p_sha1); else if ((ihashtype==FRANZO_SHA_256)||(ihashtype==FRANZO_SHA_256B)) o_hexhash=ffinalize(p_sha256); else if ((ihashtype==FRANZO_XXH3)||(ihashtype==FRANZO_XXH3B)) o_hexhash=ffinalize(p_xxh3); else if ((ihashtype==FRANZO_MD5) || (ihashtype==FRANZO_MD5B)) o_hexhash=ffinalize(p_md5); else if ((ihashtype==FRANZO_SHA3)||(ihashtype==FRANZO_SHA3B)) o_hexhash=ffinalize(p_sha3); else if ((ihashtype==FRANZO_BLAKE3)||(ihashtype==FRANZO_BLAKE3B)) o_hexhash=ffinalize(p_blake3); else if (ihashtype==FRANZO_WHIRLPOOL) o_hexhash=ffinalize(p_whihasher); else if (ihashtype==FRANZO_HIGHWAY64) o_hexhash=ffinalize(p_highway64state); else if (ihashtype==FRANZO_HIGHWAY128) o_hexhash=ffinalize(p_highway64state); else if (ihashtype==FRANZO_HIGHWAY256) o_hexhash=ffinalize(p_highway64state); else if (ihashtype==FRANZO_CRC_32) { o_hexhash =ffinalize(p_crc32); o_hexcrc32 =o_hexhash; } else if (ihashtype==ALGO_CRC32C) o_hexhash =ffinalize(p_crc32c); else { myprintf("00779: GURU hashtype unknown |%s|\n",i_hashtype2.c_str()); seppuku(); return "47453: GURU hashtype unknown |%s|"; } isinit =false; isfinalized =true; return o_hexhash; } void franz_do_hash::update(char *i_buffer,const int i_buflen) { // (*p_xxhash64).add(i_buffer,i_buflen); ///return; /* if (!isinit) { myprintf("00780: GURU hash not init\n"); seppuku(); return; } if (isfinalized) { myprintf("00781: GURU hash finalized, cannot update\n"); seppuku(); return; } */ if ((ihashtype==FRANZO_XXHASH64) || (ihashtype==FRANZO_WINHASH64) || (ihashtype==FRANZO_XXHASH64B)) { /* if (p_xxhash64==NULL) { myprintf("00782: guru pointer null %s\n",i_hashtype2.c_str()); seppuku(); return; } */ (*p_xxhash64).add(i_buffer,i_buflen); return; } else if ((ihashtype==FRANZO_SHA_1)||(ihashtype==FRANZO_SHA_1B)) { /* if (p_sha1==NULL) { myprintf("00783: guru pointer null %s\n",i_hashtype2.c_str()); seppuku(); return; } */ (*p_sha1).write(i_buffer,i_buflen); return; } else if ((ihashtype==FRANZO_SHA_256)||(ihashtype==FRANZO_SHA_256B)) { /* if (p_sha256==NULL) { myprintf("00784: guru pointer null %s\n",i_hashtype2.c_str()); seppuku(); return; } */ (*p_sha256).write(i_buffer,i_buflen); /// for (int i=0;i>\n",i_filename.c_str()); o_status="62703: CANNOT HASH A FOLDER"; return ""; } char temp[128]; if (ihashtype==ALGO_NILSIMSA) { o_hexhash=mm_hash_calc_file(ALGO_NILSIMSA,i_filename.c_str(),i_flagcalccrc32,o_crc32,i_inizio,i_totali,g_dimensione,o_thefilesize); return o_hexhash; } if (ihashtype==ALGO_WYHASH) { o_hexhash=mm_hash_calc_file(ALGO_WYHASH,i_filename.c_str(),i_flagcalccrc32,o_crc32,i_inizio,i_totali,g_dimensione,o_thefilesize); return o_hexhash; } FILE* myfilez = freadopen(i_filename.c_str()); if (flagdebug3) myprintf("00797: myfilez FILE* is %s\n",migliaia(int64_t(myfilez))); if (myfilez==NULL) { if (!flagignore) { #ifdef _WIN32 int err=GetLastError(); string codice=decodewinerror(err,NULL); myprintf("00798! error kind %d %s opening <<%Z>>\n",err,codice.c_str(),i_filename.c_str()); #else int err=1; myprintf("00799! error kind %d opening <<%Z>>\n",err,i_filename.c_str()); #endif // corresponds to #ifdef (#ifdef _WIN32) } o_status="62697: ERROR OPENING FILE"; return ""; } int64_t lunghezza =prendidimensionefile(i_filename.c_str());//prendidimensionehandle(myfilez); if (flagdebug3) myprintf("00801: hashing lunghezza [prendidimensionefile] %s\n",migliaia(lunghezza)); int64_t letti =0; #ifdef __HAIKU__ const int BUFSIZE =16384; #else #ifdef ANCIENT const int BUFSIZE =16384; #else const int BUFSIZE =65536*8; #endif // corresponds to #ifdef (#ifdef ANCIENT) #endif // corresponds to #ifdef (#ifdef __HAIKU__) unsigned char unzBuf[BUFSIZE]; int n=BUFSIZE; uint64_t myseed = 0; XXHash64 myhash(myseed); int mytype=ihashtype; if ((ihashtype==ALGO_ZETA) || (ihashtype==ALGO_ZETAENC)) { if (prendidimensionefile(i_filename.c_str())<104+32) return "0000000000000000"; if (ihashtype==ALGO_ZETAENC) { /// myprintf("57714: ALGO ZETAENC ATTIVATA\n"); n=32; int r=fread(unzBuf,1,n,myfilez); if (r!=n) { myprintf("01802: Error reading head of ZETA\n"); fclose(myfilez); o_hexhash =""; o_thefilesize =0; return ""; } myhash.add(unzBuf,r); letti+=r; } /// else ///myprintf("57714: ALGO ZETA\n"); fseeko(myfilez,104,SEEK_CUR); n=BUFSIZE; while (1) { int r=fread(unzBuf, 1, n, myfilez); myhash.add(unzBuf,r); g_dimensione+=r; if (g_dimensione>i_totali) i_totali=g_dimensione; letti+=r; if (r!=n) break; if ((flagnoeta==false) && (i_inizio>0) && (i_totali>0)) myavanzamentoby1sec(g_dimensione,i_totali,i_inizio,false); } fclose(myfilez); if ((flagnoeta==false) && (i_inizio>0) && (i_totali>0)) myavanzamentoby1sec(g_dimensione,i_totali,i_inizio,false); /// myhash.add(g_franzhash_104,104); /// letti+=104; o_hexhash =bin2hex_64(myhash.hash()); o_thefilesize =lunghezza; g_dimensione +=lunghezza; o_thefilesize =letti; return o_hexhash; } /// just an extimate. If <64K get xxhash64 // otherwise get 16K head +16KB mid, +16KB tail =>xxhash64 if (ihashtype==ALGO_QUICK) { if (lunghezza<65536) { mytype=FRANZO_XXHASH64; } else { n=16384; int r=0; r=fread(unzBuf,1,n,myfilez); if (r!=n) { myprintf("00802: Error reading head\n"); fclose(myfilez); o_hexhash =""; o_thefilesize =0; return ""; } myhash.add(unzBuf,r); int64_t off=lunghezza/2; fseeko(myfilez,off,SEEK_SET); r=fread(unzBuf,1,n, myfilez); if (r!=n) { myprintf("00803: Error reading mid\n"); fclose(myfilez); o_hexhash =""; o_thefilesize =0; return ""; } myhash.add(unzBuf,r); fseeko(myfilez,-n,SEEK_END); r=fread(unzBuf,1,n,myfilez); if (r!=n) { myprintf("00804: Error reading tail\n"); fclose(myfilez); o_hexhash =""; o_thefilesize =0; return ""; } myhash.add(unzBuf,r); fclose(myfilez); if ((flagnoeta==false) && (i_inizio>0) && (i_totali>0)) myavanzamentoby1sec(g_dimensione,i_totali,i_inizio,false); o_hexhash =bin2hex_64(myhash.hash()); o_thefilesize =lunghezza; g_dimensione +=lunghezza; return o_hexhash; } } libzpaq::SHA1 sha1; MD5 md5; libzpaq::SHA256 mysha256; XXH3_state_t state128; if ((mytype==FRANZO_XXH3)||(mytype==FRANZO_XXH3B)) (void)XXH3_128bits_reset(&state128); blake3_hasher hasher; if ((mytype==FRANZO_BLAKE3)||(mytype==FRANZO_BLAKE3B)) blake3_hasher_init(&hasher); SHA3 sha3; NESSIEstruct whihasher; if (mytype==FRANZO_WHIRLPOOL) NESSIEinit(&whihasher); size_t f[256] = { 0 }; HighwayHashCat state; uint64_t hash; uint64_t key[4] = {1, 2, 3, 4}; if ((mytype==FRANZO_HIGHWAY64) || (mytype==FRANZO_HIGHWAY128) || (mytype==FRANZO_HIGHWAY256)) HighwayHashCatStart(key, &state); if (mytype==FRANZO_CRC_32) i_flagcalccrc32=true; if (mytype==ALGO_CRC32C) { ssize_t got; size_t off, n; uint32_t crc=0; while ((got = fread(unzBuf,sizeof(char),BUFSIZE,myfilez)) > 0) { off=0; do { n = (size_t)got - off; if (n > (unsigned int)BUFSIZE) n = BUFSIZE; crc=crc32c(crc, (const unsigned char*)unzBuf+off,n); off += n; } while (off < (size_t)got); if (i_flagcalccrc32) o_crc32=crc32_16bytes(unzBuf,got,o_crc32); g_dimensione+=got; letti+=got; if ((flagnoeta==false) && (i_inizio>0) && (i_totali>0)) myavanzamentoby1sec(g_dimensione,i_totali,i_inizio,false); } snprintf(temp,sizeof(temp),"%08X",crc); o_hexhash=temp; } else while (1) { int r=fread(unzBuf, 1, n, myfilez); #ifdef _WIN32 if (flagdebug3) { myprintf("00805: hash fread %08d bytes returned r %08d\n",n,r); if (r==0) { DWORD situation=GetLastError(); string lasterror=decodewinerror(situation,i_filename.c_str()); myprintf("00806: fread returned 0 bytes! situation %08d lasterror %s\n",situation,lasterror.c_str()); } } #endif // corresponds to #ifdef (#ifdef _WIN32) if (mytype==FRANZO_XXHASH64B) myhash.add(unzBuf,r); else if (mytype==FRANZO_XXHASH64) myhash.add(unzBuf,r); else if ((mytype==FRANZO_SHA_1)||(mytype==FRANZO_SHA_1B)) sha1.write((const char*)unzBuf,r); else if ((mytype==FRANZO_SHA_256)||(mytype==FRANZO_SHA_256B)) mysha256.write((const char*)unzBuf,r); else if ((mytype==FRANZO_XXH3)||(mytype==FRANZO_XXH3B)) { ///myprintf("00807: update XXH3!!!\n"); (void)XXH3_128bits_update(&state128,unzBuf,r); ///myprintf("00808: update XXH3 done!!!\n"); } else if ((mytype==FRANZO_BLAKE3)||(mytype==FRANZO_BLAKE3B)) { /// myprintf("00809: update BLAKE3!!!\n"); blake3_hasher_update(&hasher,unzBuf,r); } else if ((mytype==FRANZO_MD5) || (mytype==FRANZO_MD5B)) md5.add(unzBuf,r); else if ((mytype==FRANZO_SHA3)||(mytype==FRANZO_SHA3B)) sha3.add(unzBuf,r); else if (mytype==FRANZO_WHIRLPOOL) NESSIEadd(unzBuf,r*8,&whihasher); else if (mytype==ALGO_ENTROPY) { for(int i=0;ii_totali) i_totali=g_dimensione; letti+=r; if (r!=n) break; //////bool myavanzamentoby1sec(int64_t i_lavorati,int64_t i_totali,int64_t i_inizio,bool i_barran=true) if ((flagnoeta==false) && (i_inizio>0) && (i_totali>0)) myavanzamentoby1sec(g_dimensione,i_totali,i_inizio,false); } if (myfilez!=NULL) fclose(myfilez); if (i_flagcalccrc32) { snprintf(temp,sizeof(temp),"%08X",o_crc32); o_hexcrc32 =temp; } if (mytype==FRANZO_CRC_32) { snprintf(temp,sizeof(temp),"%08X",o_crc32); o_hexhash =temp; } if (mytype==FRANZO_XXHASH64B) o_hexhash=bin2hex_64(myhash.hash()); if (mytype==FRANZO_XXHASH64) o_hexhash=bin2hex_64(myhash.hash()); if ((mytype==FRANZO_SHA_1)||(mytype==FRANZO_SHA_1B)) { char sha1result[20]; memcpy(sha1result, sha1.result(), 20); o_hexhash=binarytohex((const unsigned char*)sha1result,20); } if ((mytype==FRANZO_SHA_256)||(mytype==FRANZO_SHA_256B)) { char sha256result[32]; memcpy(sha256result,mysha256.result(),32); o_hexhash=binarytohex((const unsigned char*)sha256result,32); } if ((mytype==FRANZO_XXH3)||(mytype==FRANZO_XXH3B)) { XXH128_hash_t myhash=XXH3_128bits_digest(&state128); o_hexhash=bin2hex_128(myhash.high64,myhash.low64); } if ((mytype==FRANZO_BLAKE3)||(mytype==FRANZO_BLAKE3B)) { uint8_t output[BLAKE3_OUT_LEN]; blake3_hasher_finalize(&hasher, output, BLAKE3_OUT_LEN); o_hexhash=binarytohex((const unsigned char*)output,BLAKE3_OUT_LEN); ///myprintf("00810: finalizzo BLAKE3!!! %s\n",o_hexhash.c_str()); } if ((mytype==FRANZO_MD5) || (mytype==FRANZO_MD5B)) o_hexhash=md5.getHash(); if ((mytype==FRANZO_SHA3)||(mytype==FRANZO_SHA3B)) o_hexhash=sha3.getHash(); if (mytype==FRANZO_WHIRLPOOL) { unsigned char output[512]={0}; NESSIEfinalize(&whihasher,output); o_hexhash=binarytohex(output,64); } if (mytype==ALGO_ENTROPY) { double entropy=0.0; double byteletti=letti; if (letti>0) for(size_t i=0;i<256; i++) if (f[i]) { double prob=(double)f[i]/byteletti; entropy += prob * custom_log2(prob); } if (entropy) snprintf(temp,sizeof(temp), "%8.4f", (float)-entropy); else snprintf(temp,sizeof(temp), "%8.4f", (float)0); ///quick "fix" for -0.0000 o_hexhash=temp; } if (mytype==FRANZO_HIGHWAY64) { hash=HighwayHashCatFinish64(&state); o_hexhash=bin2hex_64(hash); } if (mytype==FRANZO_HIGHWAY128) { uint64_t hash[2]; HighwayHashCatFinish128(&state,hash); o_hexhash=binarytohex((const unsigned char*)hash,16); } if (mytype==FRANZO_HIGHWAY256) { uint64_t hash[4]; HighwayHashCatFinish256(&state,hash); o_hexhash=binarytohex((const unsigned char*)hash,32); } if (!flagignore) if (lunghezza!=letti) { myprintf("\n"); myprintf("00811: *** CORRUPTED FILE DETECTED! expected %s readed %s bytes *** %Z\n",migliaia(lunghezza),migliaia2(letti),i_filename.c_str()); } o_thefilesize=letti; ///myprintf("00813: ****************************** ritorno lunghezza %s\n",migliaia(lunghezza)); return o_hexhash; } #ifdef SFTP typedef void (*curl_easy_reset_t)(CURL *); typedef CURL * (*curl_easy_init_t) (void); typedef CURLcode (*curl_easy_setopt_t) (CURL *, CURLoption, ...); typedef CURLcode (*curl_easy_perform_t) (CURL *); typedef const char * (*curl_easy_strerror_t) (CURLcode); typedef CURLcode (*curl_easy_getinfo_t) (CURL *, CURLINFO, ...); typedef struct curl_slist * (*curl_slist_append_t) (struct curl_slist *, const char *); typedef void (*curl_slist_free_all_t) (struct curl_slist *); typedef void (*curl_easy_cleanup_t) (CURL *); typedef CURLcode (*curl_global_init_t) (long); typedef void (*curl_global_cleanup_t) (void); struct curldynfunctions { curl_easy_reset_t easy_reset; curl_easy_init_t easy_init; curl_easy_setopt_t easy_setopt; curl_easy_perform_t easy_perform; curl_easy_strerror_t easy_strerror; curl_easy_getinfo_t easy_getinfo; curl_slist_append_t slist_append; curl_slist_free_all_t slist_free_all; curl_easy_cleanup_t easy_cleanup; curl_global_init_t global_init; curl_global_cleanup_t global_cleanup; }; /// dummy progress struct Progress { double lastruntime; }; struct sftpfileinfo { std::string name; std::string fullname; int64_t size; time_t modtime; std::string permissions; std::string owner; std::string group; bool isdirectory; }; class zpaqfranzsftp { private: CURL* curl; int sftpport; std::string host; std::string username; std::string password; std::string sshKeyPath; static int64_t startupload; static int lasteta; static bool dllloaded; static int64_t sessionuploaded; static int64_t uploaded; static int64_t tobeuploaded; static int64_t finalsize; static curldynfunctions curldll; static string findso(const std::string& i_libname) { const std::vector common_paths = { "", "/usr/lib/", "/usr/local/lib/", "/lib/", "/usr/lib64/", "/usr/local/lib64/", "./", "/usr/lib/x86_64-linux-gnu/" }; for (unsigned int i=0;i>\n",full_path.c_str()); if (fileexists(full_path.c_str())) return full_path; } return ""; } static bool loadLibrary() { if (dllloaded) return true; #ifdef _WIN32 #ifdef _WIN64 string dllname="libcurl-x64.dll"; #else string dllname="libcurl.dll"; #endif HMODULE hModule = LoadLibraryA(dllname.c_str()); if (!hModule) { myprintf("45559$ Cannot load %s\n",dllname.c_str()); return false; } // Load all function pointers curldll.easy_reset = (curl_easy_reset_t) GetProcAddress(hModule,"curl_easy_reset"); curldll.easy_init = (curl_easy_init_t) GetProcAddress(hModule,"curl_easy_init"); curldll.easy_setopt = (curl_easy_setopt_t) GetProcAddress(hModule,"curl_easy_setopt"); curldll.easy_perform = (curl_easy_perform_t) GetProcAddress(hModule,"curl_easy_perform"); curldll.easy_strerror = (curl_easy_strerror_t) GetProcAddress(hModule,"curl_easy_strerror"); curldll.easy_getinfo = (curl_easy_getinfo_t) GetProcAddress(hModule,"curl_easy_getinfo"); curldll.slist_append = (curl_slist_append_t) GetProcAddress(hModule,"curl_slist_append"); curldll.slist_free_all = (curl_slist_free_all_t) GetProcAddress(hModule,"curl_slist_free_all"); curldll.easy_cleanup = (curl_easy_cleanup_t) GetProcAddress(hModule,"curl_easy_cleanup"); curldll.global_init = (curl_global_init_t) GetProcAddress(hModule,"curl_global_init"); curldll.global_cleanup = (curl_global_cleanup_t) GetProcAddress(hModule,"curl_global_cleanup"); // Verify all functions were loaded if ( !curldll.easy_reset || !curldll.easy_init || !curldll.easy_setopt || !curldll.easy_perform || !curldll.easy_strerror || !curldll.easy_getinfo || !curldll.slist_append || !curldll.slist_free_all || !curldll.easy_cleanup || !curldll.global_init || !curldll.global_cleanup) { myprintf("46967: Failed to load one or more libcurl functions (older %s?)\n",dllname.c_str()); return false; } dllloaded=true; return true; #else string libcurlposition=findso("libcurl.so"); if (libcurlposition=="") { myprintf("52612$ Cannot find libcurl.so => I will try blindly\n"); libcurlposition="libcurl.so"; } else { if (flagverbose) myprintf("52615: libcurl.so founded in %Z\n",libcurlposition.c_str()); } /// libcurlposition= "/usr/local/lib/libcurl.so"; void *hModule = dlopen(libcurlposition.c_str(), RTLD_LAZY); if (!hModule) { const char* last_error = dlerror(); myprintf("46919$ Cannot load libcurl.so from <<%Z>> lasterror %s\n",libcurlposition.c_str(),last_error); return false; } curldll.easy_reset = (curl_easy_reset_t)dlsym(hModule, "curl_easy_reset"); curldll.easy_init = (curl_easy_init_t)dlsym(hModule, "curl_easy_init"); curldll.easy_setopt = (curl_easy_setopt_t)dlsym(hModule, "curl_easy_setopt"); curldll.easy_perform = (curl_easy_perform_t)dlsym(hModule, "curl_easy_perform"); curldll.easy_strerror = (curl_easy_strerror_t)dlsym(hModule, "curl_easy_strerror"); curldll.easy_getinfo = (curl_easy_getinfo_t)dlsym(hModule, "curl_easy_getinfo"); curldll.slist_append = (curl_slist_append_t)dlsym(hModule, "curl_slist_append"); curldll.slist_free_all = (curl_slist_free_all_t)dlsym(hModule, "curl_slist_free_all"); curldll.easy_cleanup = (curl_easy_cleanup_t)dlsym(hModule, "curl_easy_cleanup"); curldll.global_init = (curl_global_init_t)dlsym(hModule, "curl_global_init"); curldll.global_cleanup = (curl_global_cleanup_t)dlsym(hModule, "curl_global_cleanup"); dllloaded=true; return true; #endif } static size_t listCallback(void *buffer, size_t size, size_t nmemb, void *userp) { std::vector* lines = (std::vector*)userp; std::string line((char*)buffer, size * nmemb); if(line.length() > 0 && line != "\n" && line != "\r\n") lines->push_back(line); return size * nmemb; } static size_t writeCallback(void* ptr, size_t size, size_t nmemb, FILE* stream) { size_t written = fwrite(ptr, size, nmemb, stream); ///printf("DEBUG: Write callback - Requested: %d, Written: %d bytes\n", size * nmemb, written); return written; } static int debugCallback(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) { (void)handle; (void)userp; switch(type) { case CURLINFO_TEXT: /// if (flagdebug3) myprintf("DEBUG: Info: %.*s", (int)size, data); break; case CURLINFO_HEADER_OUT: myprintf("DEBUG: Sent header: %.*s", (int)size, data); break; case CURLINFO_DATA_OUT: ///printf("DEBUG: Sent data: %d bytes\n", size); uploaded+=size; break; case CURLINFO_SSL_DATA_OUT: myprintf("DEBUG: Sent SSL data: %d bytes\n", size); break; case CURLINFO_HEADER_IN: myprintf("DEBUG: Received header: %.*s", (int)size, data); break; case CURLINFO_DATA_IN: myprintf("DEBUG: Received data: %d bytes\n", size); break; case CURLINFO_SSL_DATA_IN: myprintf("DEBUG: Received SSL data: %d bytes\n", size); break; default: break; } return 0; } static int progressCallback(void* clientp, curl_off_t dltotal, curl_off_t dlnow,curl_off_t ultotal, curl_off_t ulnow) { if (ultotal==1) if (clientp) if (flagdebug) myprintf("52953: compiler be quiet\n"); static std::vector speedSamples; double elapsedSecs = mtime()-g_start/1000.0; int tempotrascorso=(mtime()-startupload)/1000; if (tempotrascorso!=lasteta) { lasteta=tempotrascorso; curl_off_t now = (dltotal > 0) ? dlnow : ulnow; double instantSpeed = now / elapsedSecs; speedSamples.push_back(instantSpeed); double avgSpeed = 0; for(double speed : speedSamples) avgSpeed += speed; avgSpeed /= speedSamples.size(); double percentage = uploaded*100.0/tobeuploaded; double eta=0.001*(mtime()-startupload)*(tobeuploaded-uploaded)/(uploaded+1.0); if (eta<356000) myprintf("\r%03d%% %02d:%02d:%02d speed %9s/s avg: %9s/s %s=>%s",(int)percentage,int(eta/3600), int(eta/60)%60, int(eta)%60,tohuman(instantSpeed),tohuman(avgSpeed),migliaia3(tobeuploaded),migliaia4(uploaded)); fflush(stdout); } return 0; } static int progresscallbackupload(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow) { if (dltotal==1) if (ulnow==1) if (ultotal==1) if (dlnow==1) if (ulnow==1) if (clientp) if (flagdebug) myprintf("52984: compiler be quiet\n"); int tempotrascorso = (mtime() - startupload) / 1000; // Tempo trascorso in secondi if (tempotrascorso != lasteta) // Aggiorna solo se c'è un cambiamento nel tempo trascorso { lasteta = tempotrascorso; // Calcolo della percentuale completata double percentage = uploaded * 100.0 / finalsize; // Calcolo della velocità media int avgspeed = sessionuploaded / tempotrascorso; // Calcolo del tempo rimanente (ETA) int64_t current_time = mtime(); int64_t elapsed_time_ms = current_time - startupload; // Tempo trascorso in millisecondi int eta = 0; // Variabile per il tempo stimato di completamento if (sessionuploaded > 0) // Solo se sono stati caricati byte { // Calcolo della velocità di upload double upload_speed = static_cast(sessionuploaded) / elapsed_time_ms; // Calcolo dei byte rimanenti int64_t remaining_bytes = tobeuploaded - sessionuploaded; // Calcolo del tempo rimanente in millisecondi double remaining_time_ms = remaining_bytes / upload_speed; // Conversione in secondi eta = static_cast(remaining_time_ms / 1000); } // Verifica che l'ETA sia valido if (eta < 356000) // Valore massimo ragionevole per l'ETA { myprintf( "\r%03d%% %02d:%02d:%02d %10s/%s [%10s/s]=>remote %9s/%s", (int)percentage, int(eta / 3600), // Ore int(eta / 60) % 60, // Minuti int(eta) % 60, // Secondi tohuman2(sessionuploaded), // Byte caricati in formato leggibile tohuman3(tobeuploaded), // Byte totali da caricare tohuman(avgspeed), // Velocità media in formato leggibile tohuman4(uploaded), // Byte caricati verso la destinazione remota tohuman5(finalsize)); // Byte totali da caricare verso la destinazione remota fflush(stdout); // Assicura che l'output venga mostrato immediatamente } } return 0; // Restituisce 0 per indicare che il caricamento può continuare } static size_t readfunc(char *ptr, size_t size, size_t nmemb, void *stream) { FILE *f = (FILE *)stream; size_t n; if(ferror(f)) return CURL_READFUNC_ABORT; n = fread(ptr, size, nmemb, f) * size; uploaded +=n; sessionuploaded +=n; return n; } string take_permission(string i_line, string* o_permission) { if (o_permission==NULL) { myprintf("47713: GURU o_permission null\n"); seppuku(); } (*o_permission)=""; if (i_line.size()<10) return i_line; const std::string validchars = "drwxt-"; for (int i=0;i<10;i++) if (validchars.find(i_line[i])==std::string::npos) return i_line; (*o_permission)=i_line.substr(0,10); return i_line.substr(10); } string get_number(string i_line,int64_t* o_number) { if (o_number==NULL) { myprintf("47676$ GURU o_number null\n"); seppuku(); } (*o_number)=0; if (i_line=="") return ""; unsigned int i=0; while (i|"; if (strchr(invalid_chars, c)) return false; if (isprint((unsigned char)c)) return true; return false; } string get_filename(string i_line,string* o_string) { if (o_string==NULL) { myprintf("47800$ GURU o_string null\n"); seppuku(); } (*o_string)=""; if (i_line=="") return ""; unsigned int i=0; while (i* o_info) { if (o_info==NULL) { myprintf("47767$ o_info null\n"); seppuku(); } string my_permission; int64_t my_links; string my_user; string my_group; int64_t my_size; string my_month; int64_t my_day; int64_t my_hour; int64_t my_min; string my_name; string elaborata =take_permission (i_line,&my_permission); string elaborata2 =get_number (elaborata,&my_links); string elaborata3 =get_alpha (elaborata2,&my_user); string elaborata4 =get_alpha (elaborata3,&my_group); string elaborata5 =get_number (elaborata4,&my_size); string elaborata6 =get_alpha (elaborata5,&my_month); string elaborata7 =get_number (elaborata6,&my_day); string elaborata8 =get_number (elaborata7,&my_hour); string elaborata9 =get_number (elaborata8,&my_min); string elaborata10 =get_filename (elaborata9,&my_name); if (my_permission!="") if (my_permission[0]!='d') { (*o_info).push_back(sftpfileinfo()); (*o_info).back().name=my_name; (*o_info).back().size=my_size; (*o_info).back().permissions=my_permission; (*o_info).back().owner=my_user; (*o_info).back().group=my_group; (*o_info).back().isdirectory=true; } } public: static int kickstart(string i_fullzpaqexename) { string randnocache="?"+generaterandomstring(10); #ifdef _WIN64 string dllname="libcurl-x64.dll"; string http_dll="http://www.francocorbelli.it/zpaqfranz/win64/"+dllname; #else string dllname="libcurl.dll"; string http_dll="http://www.francocorbelli.it/zpaqfranz/win32/"+dllname; #endif myprintf("07755! Houston, %s not found. Getting from author's website\n",dllname.c_str()); string mypath=extractfilepath(i_fullzpaqexename); if (flagdebug) myprintf("07776: fullzpaqexename %s\n",i_fullzpaqexename.c_str()); string dllfile =mypath+dllname; myprintf("03191: Downloading %s 8.11.1.0 => %Z\n",dllname.c_str(),dllfile.c_str()); myprintf("03192: Taking from %s\n",http_dll.c_str()); string dllurl =http_dll+randnocache; if (!downloadfile(dllurl,dllfile,true)) { myprintf("07767$ Cannot download %s, sorry (no Internet?)\n",dllname.c_str()); return 2; } myprintf("\n"); franz_do_hash dummy("SHA-256"); int64_t starthash=mtime(); int64_t dimensionescaricata=prendidimensionefile(dllfile.c_str()); string hashreloaded=dummy.filehash(dllfile,false,starthash,dimensionescaricata); myprintf("\n"); #ifdef _WIN64 string goodhash="2EA8DBCA33DE476B23497A10ACE1A76C54DDCEF061E866771BF737A376DDC882"; #else string goodhash="620492F47179274AFE840A1AC4EDDFDC5E7F87A014D296FB35CCFDFA2251D46B"; #endif if (hashreloaded!=goodhash) { myprintf("07773$ %s size %s, checking SHA-256\n",dllname.c_str(),migliaia(dimensionescaricata)); myprintf("07771$ SHA-256 expected %s != downloaded %s\n",goodhash.c_str(),hashreloaded.c_str()); return 2; } myprintf("00734$ Please restart zpaqfranz. %s is now OK\n",dllname.c_str()); return 1; } /* static */ string generateurl(string i_remote) { if (i_remote=="") { myprintf("08559$ SFTP i_remote empty\n"); return ""; } if (username=="") { myprintf("08560$ SFTP username empty\n"); return ""; } if (password=="") { myprintf("08561$ SFTP password empty\n"); return ""; } if (host=="") { myprintf("08562$ SFTP host empty\n"); return ""; } if ((sftpport<1) || (sftpport>65535)) { myprintf("08563$ SFTP sftpport must be in 1..65535 instead of %s\n",migliaia(sftpport)); return ""; } if (!i_remote.empty()) if(i_remote[0]!='/') i_remote="/"+i_remote; string risultato="sftp://"+username+":"+password+"@"+host+":"+myto_string(sftpport)+i_remote; if (flagdebug3) myprintf("08593: generaterul |%s|\n",risultato.c_str()); return risultato; } bool carica(const std::string& i_local, const std::string& i_remote, bool i_force) { if (!isloaded()) { myprintf("47276! SFTP functionality (carica) not available\n"); return false; } if (!curl) return false; string url=generateurl(i_remote); if (url=="") { myprintf("45825$ Cannot generate SFTP url\n"); return false; } FILE *f = NULL; CURLcode result = CURLE_GOT_NOTHING; struct Progress progress; curl_off_t remoteFileSizeByte = getremotefilesize(url); if(remoteFileSizeByte==-1) myprintf("45852$ Remote file does not exists %Z\n",i_remote.c_str()); uploaded =remoteFileSizeByte; finalsize =prendidimensionefile(i_local.c_str()); myprintf("45839: Data to be uploaded %21s\n",migliaia(finalsize)); if (uploaded>0) myprintf("45838: Already done %21s (%03d %%)\n",migliaia(uploaded),int(100.0*uploaded/finalsize)); if (uploaded>finalsize) { color_red(); myprintf("47366: The remote file is bigger than the local one: restart from scratch\n"); color_restore(); sftpdeletefile(i_remote); ///reset(); i_force=true; uploaded=0; } tobeuploaded=finalsize-uploaded; myprintf("45839: Bytes to send %21s (%03d %%)\n",migliaia(tobeuploaded),100-int(100.0*uploaded/finalsize)); f = fopen(i_local.c_str(), "rb"); if(!f) { myprintf("45866$ Cannot open local file %Z\n",i_local.c_str()); return false; } startupload =mtime(); if (flagverbose) myprintf("45838: SFTP upload of %21s bytes started\n",migliaia(tobeuploaded)); curldll.easy_setopt(curl, CURLOPT_UPLOAD, 1L); curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_READFUNCTION, readfunc); curldll.easy_setopt(curl, CURLOPT_READDATA, f); // Aggiungi le opzioni per il callback di progresso curldll.easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progresscallbackupload); curldll.easy_setopt(curl, CURLOPT_XFERINFODATA, &progress); curldll.easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); if (!i_force) { #ifdef _WIN32 _fseeki64(f, remoteFileSizeByte, SEEK_SET); #else fseek(f, (long)remoteFileSizeByte, SEEK_SET); #endif // corresponds to #ifdef (#ifdef _WIN32) curldll.easy_setopt(curl, CURLOPT_APPEND, 1L); } result = curldll.easy_perform(curl); fclose(f); if(result != CURLE_OK) { myprintf("45905$ SFTP ERROR %s\n", curldll.easy_strerror(result)); curldll.easy_cleanup(curl); return false; } curldll.easy_cleanup(curl); myprintf("\n"); myprintf("45901: Upload ended in %.3f sec\n",(mtime()-startupload)/1000.0); return true; } zpaqfranzsftp(const std::string& host, const std::string& username, const std::string& password, const int i_port) : sftpport(i_port),host(host),username(username),password(password) { if (flagdebug3) myprintf("47255: Initializing CURL: %p\n", (void*)curl); if (loadLibrary()) { curl = curldll.easy_init(); if (flagdebug3) myprintf("47261: CURL initializated: %p\n", (void*)curl); } else { curl = nullptr; if (flagdebug3) myprintf("47267: WARNING: SFTP functionality disabled - libcurl not available\n"); } } bool isloaded() const { return curl != nullptr && dllloaded; } bool sftpdownloadfile(const std::string& remotePath, const std::string& localPath) { if (!isloaded()) { myprintf("47272! SFTP functionality (download) not available\n"); return false; } if (!curl) return false; FILE* localFile = fopen(localPath.c_str(), "wb"); if (!localFile) { myprintf("ERROR: Cannot create local file: %s\n", localPath.c_str()); return false; } std::string url = "sftp://" + host + "/" + remotePath; if (flagdebug3) myprintf("47295: Downloading from %s\n", url.c_str()); curldll.easy_setopt(curl, CURLOPT_VERBOSE, 1L); curldll.easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debugCallback); curldll.easy_setopt(curl, CURLOPT_UPLOAD, 0L); curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_PORT, sftpport); curldll.easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curldll.easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); curldll.easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); curldll.easy_setopt(curl, CURLOPT_WRITEDATA, localFile); curldll.easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, progressCallback); curldll.easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); if (!sshKeyPath.empty()) curldll.easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, sshKeyPath.c_str()); CURLcode res = curldll.easy_perform(curl); const char* error = curldll.easy_strerror(res); if (flagdebug3) myprintf("47317: Download result: %d (%s)\n", res, error); fclose(localFile); myprintf("\n"); return (res == CURLE_OK); } /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// int64_t getfilesize(const std::string& remotePath) { if (!isloaded()) { myprintf("47338! SFTP functionality (getfilesize) not available\n"); return false; } if (!curl) return -1; std::string url = "sftp://" + host + "/" + remotePath; if (flagdebug3) myprintf("DEBUG: Getting size of %s\n", url.c_str()); reset(); curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_PORT, sftpport); curldll.easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curldll.easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); curldll.easy_setopt(curl, CURLOPT_NOBODY, 1L); curldll.easy_setopt(curl, CURLOPT_FILETIME, 1L); if (!sshKeyPath.empty()) curldll.easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, sshKeyPath.c_str()); CURLcode res = curldll.easy_perform(curl); if (res == CURLE_OK) { double size; curldll.easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &size); curldll.easy_cleanup(curl); return static_cast(size); } return -1; } /* * sftpGetRemoteFileSize returns the remote file size in byte; -1 on error */ static curl_off_t getremotefilesize(const string i_remotefile) { if (i_remotefile=="") { myprintf("45753$ i_remotefile empty\n"); return -1; } CURLcode result = CURLE_GOT_NOTHING; curl_off_t remoteFileSizeByte = -1; CURL *curlHandlePtr = curldll.easy_init(); if (flagverbose) curldll.easy_setopt(curlHandlePtr, CURLOPT_VERBOSE, 1L); curldll.easy_setopt(curlHandlePtr, CURLOPT_URL, i_remotefile.c_str()); curldll.easy_setopt(curlHandlePtr, CURLOPT_NOPROGRESS, 1); curldll.easy_setopt(curlHandlePtr, CURLOPT_NOBODY, 1); curldll.easy_setopt(curlHandlePtr, CURLOPT_HEADER, 1); curldll.easy_setopt(curlHandlePtr, CURLOPT_FILETIME, 1); result = curldll.easy_perform(curlHandlePtr); if(result==CURLE_OK) { result = curldll.easy_getinfo(curlHandlePtr,CURLINFO_CONTENT_LENGTH_DOWNLOAD_T,&remoteFileSizeByte); if (result) { myprintf("45772$ Error in getinfo()\n"); return -1; } } curldll.easy_cleanup(curlHandlePtr); return remoteFileSizeByte; } bool sftpdeletefile(const std::string& i_remotefile) { if (!isloaded()) { myprintf("47141: SFTP functionality (deletefile) not available\n"); return false; } if (!curl) return false; std::string url = "sftp://" + host + "/"; if (flagdebug3) myprintf("47501: sftp delete Connecting to %s to delete %s\n", url.c_str(), i_remotefile.c_str()); curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_PORT, sftpport); curldll.easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curldll.easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); if (flagverbose) curldll.easy_setopt(curl, CURLOPT_VERBOSE, 1L); else // Disabilita output verboso curldll.easy_setopt(curl, CURLOPT_NOBODY, 1L); struct curl_slist *commands = nullptr; std::string rmCommand = "rm " + i_remotefile; commands = curldll.slist_append(commands, rmCommand.c_str()); curldll.easy_setopt(curl, CURLOPT_POSTQUOTE, commands); if (!sshKeyPath.empty()) curldll.easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, sshKeyPath.c_str()); CURLcode res = curldll.easy_perform(curl); const char* error = curldll.easy_strerror(res); if (res!=CURLE_OK) myprintf("47520$ SFTP Delete result: %d (%s)\n", res, error); curldll.slist_free_all(commands); return (res == CURLE_OK); } bool listremotedir(const std::string& i_remote,std::vector* o_filearray) { if (!isloaded()) { myprintf("47508! SFTP functionality (listremotedir) not available\n"); return false; } if (o_filearray==NULL) { myprintf("47507: o_filearray null\n"); seppuku(); } if (!curl) return false; string url=generateurl(i_remote); if (url=="") { myprintf("45513$ Cannot generate SFTP (ls) url\n"); return false; } url=includetrailingbackslash(url); myprintf("47509: Listing remote : %s\n", i_remote.c_str()); std::vector listData; curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_WRITEFUNCTION, listCallback); curldll.easy_setopt(curl, CURLOPT_WRITEDATA, &listData); curldll.easy_setopt(curl, CURLOPT_DIRLISTONLY, 0L); if (!sshKeyPath.empty()) curldll.easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, sshKeyPath.c_str()); CURLcode res = curldll.easy_perform(curl); if (res!=CURLE_OK) { myprintf("47534: List failed: %s\n", curldll.easy_strerror(res)); return false; } for (size_t i=0;i0); } bool readfilerange(const std::string& remotePath, const std::string& localPath, curl_off_t start, curl_off_t end) { if (!isloaded()) { myprintf("47608$ SFTP readfilerange not available\n"); return false; } if (!curl) return false; FILE* localFile = fopen(localPath.c_str(), "wb"); if (!localFile) { myprintf("47616$ Cannot create local file: %s\n", localPath.c_str()); return false; } std::string url = "sftp://" + host + "/" + remotePath; if (flagdebug3) myprintf("DEBUG: Reading range %s-%s from %s\n", migliaia(start), migliaia2(end), url.c_str()); std::string rangeStr = std::to_string(start) + "-" + std::to_string(end); curldll.easy_setopt(curl, CURLOPT_RANGE, rangeStr.c_str()); if (flagdebug3) myprintf("46125: succhiamento *********** |%s|\n",rangeStr.c_str()); curldll.easy_setopt(curl, CURLOPT_URL, url.c_str()); curldll.easy_setopt(curl, CURLOPT_PORT, sftpport); curldll.easy_setopt(curl, CURLOPT_USERNAME, username.c_str()); curldll.easy_setopt(curl, CURLOPT_PASSWORD, password.c_str()); curldll.easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback); curldll.easy_setopt(curl, CURLOPT_WRITEDATA, localFile); curldll.easy_setopt(curl, CURLOPT_NOBODY, 0L); // Add this line in readFileRange //curldll.easy_setopt(curl, CURLOPT_RANGE, range); if (!sshKeyPath.empty()) curldll.easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, sshKeyPath.c_str()); CURLcode res = curldll.easy_perform(curl); fclose(localFile); return (res == CURLE_OK); } bool reset() { if (!isloaded()) return false; // Clean up existing handle if (curl) curldll.easy_cleanup(curl); // Create new handle curl = curldll.easy_init(); if (!curl) return false; // Reset static variables uploaded = 0; tobeuploaded = 0; sessionuploaded = 0; finalsize = 0; startupload = 0; lasteta =0; return true; } void distruggi() { if (curl && dllloaded) { curldll.easy_cleanup(curl); curldll.global_cleanup(); dllloaded=false; } } bool sftpmkdir(const std::string& remotePath) { if (!isloaded()) { myprintf("00813! SFTP functionality (mkdirRecursive) not available\n"); return false; } if (!curl) return false; // Normalizza il path rimuovendo eventuali slash iniziali o finali extra std::string normalizedPath = remotePath; while (!normalizedPath.empty() && normalizedPath[normalizedPath.size()-1] == '/') normalizedPath.erase(normalizedPath.size()-1); while (!normalizedPath.empty() && normalizedPath[0] == '/') normalizedPath.erase(0, 1); // Divide il percorso in componenti std::vector components; std::string current; for (size_t i=0;i>\n", currentPath.c_str()); color_restore(); } } else { if (flagverbose) { color_green(); myprintf("46332: Remote path does esixts (this is good) <<%Z>>\n",currentPath.c_str()); color_restore(); } } } return true; } ~zpaqfranzsftp() { distruggi(); /* if (curl && dllloaded) { curldll.easy_cleanup(curl); curldll.global_cleanup(); } */ } }; curldynfunctions zpaqfranzsftp::curldll = {}; bool zpaqfranzsftp::dllloaded = false; int64_t zpaqfranzsftp::uploaded = 0; int64_t zpaqfranzsftp::tobeuploaded = 0; int64_t zpaqfranzsftp::sessionuploaded = 0; int64_t zpaqfranzsftp::finalsize = 0; int64_t zpaqfranzsftp::startupload = 0; int zpaqfranzsftp::lasteta=0; #endif // corresponds to #ifdef (#ifdef SFTP) /////////////////////////////// Jidac ///////////////////////////////// // A Jidac object represents an archive contents: a list of file // fragments with hash, size, and archive offset, and a list of // files with date, attributes, and list of fragment pointers. // Methods add to, extract from, compare, and list the archive. // enum for list_HT::csize and version #ifdef _WIN32 static const int64_t LIST_DEFAULT_VERSION=99999999999999LL; // unless -until #endif // fragment hash table entry struct list_HT { unsigned char sha1[20]; // fragment hash int usize; // uncompressed size, -1 if unknown int64_t csize; // if >=0 then block offset else -fragment number list_HT(const char* s=0, int u=-1, int64_t c=LIST_HT_BAD) { if (s) memcpy(sha1, s, 20); else memset(sha1, 0, 20); usize=u; csize=c; } }; // filename version entry struct list_DTV { int64_t date; // decimal YYYYMMDDHHMMSS (UT) or 0 if deleted int64_t size; // size or -1 if unknown int64_t attr; // first 8 attribute bytes double csize; // approximate compressed size vector ptr; // list of fragment indexes to list_HT int version; // which transaction was it added? list_DTV(): date(0), size(0), attr(0), csize(0), version(0) {} }; // filename entry struct list_DT { int64_t edate; // date of external file, 0=not found int64_t esize; // size of external file int64_t eattr; // external file attributes ('u' or 'w' in low byte) uint64_t sortkey; // determines sort order for compression vector eptr; // fragment list of external file to add vector dtv; // list of versions int written; // 0..ptr.size() = fragments output. -1=ignore list_DT(): edate(0), esize(0), eattr(0), sortkey(0), written(-1) {} }; typedef map list_DTMap; // Version info struct list_VER { int64_t date; // 0 if not JIDAC int64_t usize; // uncompressed size of files int64_t offset; // start of transaction int64_t csize; // size of compressed data, -1 = no index int updates; // file updates int deletes; // file deletions unsigned firstFragment;// first fragment ID list_VER() {memset(this, 0, sizeof(*this));} }; #ifdef _WIN32 inline void list_progress(int i_list_ver,int i_list_dt,int64_t ts, int64_t td) { static int ultimotempo=0; int secondi=(mtime()-list_global_start)/1000; if (td>ts) td=ts; if (secondi!=ultimotempo) { ultimotempo=secondi; list_print_datetime(); printf("V %06d (%08d) %5.2f%% %s / %s\n",i_list_ver,i_list_dt,td*100.0/(ts+0.5),migliaia(td),migliaia2(ts)); } } #endif // corresponds to #ifdef (#ifdef _WIN32 ) #define LIST_NORMAL 0 #define LIST_ERR 1 #define LIST_RECOVER 2 int64_t count_of_map(DTMap* i_thedt) { if (i_thedt==NULL) return 0; return (*i_thedt).size(); } int64_t ram_of_map(DTMap* i_thedt) { if (i_thedt==NULL) return 0; int64_t totale=0; for (DTMap::iterator p=(*i_thedt).begin(); p!=(*i_thedt).end(); ++p) { totale+=sizeof(DT); totale+=p->second.ptr.size()*sizeof(unsigned); totale+=p->second.hexhash.size()+1; totale+=p->second.hashtype.size()+1; totale+=p->second.hexcrc32.size()+1; totale+=p->second.outputname.size()+1; totale+=p->second.franz_block_size; } return totale; } // Do everything. // Very weird approach, this is about plain-old C, almost zero ++ class Jidac { public: DTMap dt; // set of files in archive vector tofiles; // -to option vector files; // filename args int extract(); // extract, return 1 if error else 0 void jidacreset(); int loadparameters(int argc, const char** argv); int doCommand(); friend ThreadReturn decompressThread(void* arg); friend ThreadReturn decompressthreadramdisk(void* arg); friend struct ExtractJob; void usageall (string i_command); // verbose help string archive; // archive name bool isselected(const char* filename, bool rn,int64_t i_size);// files, -only, -not /// void internal_listpaqlevel(); private: #ifdef _WIN32 vector list_ht; // list of fragments list_DTMap list_dt; // set of files vector list_ver; // version info int64_t pakka_read_archive(const char* arc); // read arc int pakkalist(); #endif // corresponds to #ifdef (#ifdef _WIN32 ) string fullcommandline; vector results; // warning and errors string zpaqfranzexename; string fullzpaqexename; MAPPAHELP help_map; /// maps: string command, helpfunctions(bool,bool) MAPPAHELP switches_map; string fullarchive; vector files_size; // instead of a struct many vectors vector files_count; // why? a bit faster vector files_time; vector files_edt; vector iblock_files; int all; // -all option int fragment; // -fragment option int summary; // do summary if >0, else brief. OLD 7.15 summary option if > 0, detailed if -1 int howmanythreads; // default is number of cores unsigned int menoenne; int64_t date; // now as decimal YYYYMMDDHHMMSS (UT) int64_t version; // version number or 14 digit date string method; // default "1" const char* index; // index option string plainpassword; string plainpassword2; char new_password_string[32]; // -repack hashed password char* new_password; // points to new_password_string or NULL string nottype; // -not =... string sfxnottype; // -not =... vector level0; // list of m0 vector level1; // list of m1 vector level2; // list of m2 vector level3; // list of m3 vector level4; // list of m4 vector level5; // list of m5 vector notfiles; // list of prefixes to exclude vector sfxnotfiles; // list of prefixes to exclude vector onlyfiles; // list of prefixes to include vector chunkfiles; // list of prefixes to include vector sfxonlyfiles; // list of prefixes to include vector alwaysfiles; // list of prefixes to pack ALWAYS string repack; // -repack output file string checktxt; // check txt string backuptxt; string backupindex; string fasttxt; string indexfasttxt; map mappacommenti; string versioncomment; ///bool flagnoattributes; // -noattributes option ///bool flagforce; // -force option ///bool flagcomment; bool flagtest; ///bool flagskipzfs; ///bool flagnoqnap; // exclude @Recently-Snapshot and @Recycle ///bool flagforcewindows; // force alterate data stream $DATA$, system volume information ///bool flagnopath; // do not store path ///bool flagnosort; // do not sort files std::sort(vf.begin(), vf.end(), compareFilename); uint32_t filelength; uint32_t dirlength; string snapmark; string searchfrom; // search something in path string replaceto; // replace (something like awk) string searchhash; // Archive state int64_t dhsize; // total size of D blocks according to H blocks int64_t dcsize; // total size of D blocks according to C blocks vector ht; // list of fragments DTMap edt; // set of external files to add or compare vector block; // list of data blocks to extract vector ver; // version info int64tstringmap sha1collision; // Commands int redu(); // check redundancy int add(); // add, return 1 if error else 0 int addhome(); // add, return 1 if error else 0 int list(); // list (one parameter) / check (more than one) #ifndef ANCIENT int ls(); int tui(); #endif int list715(); int collision(bool i_flagall); // check for SHA-1 collisions int fzf(); int ecommand(); // extract on ./ int append(); // anti-ramsomware (slow) int multisomething(); // extract/test with "*" int setpassword(); // set or change password int extractw(); // chunked-extract, return 1 if error else 0 int info(); // wrap for list int findj(); // find files int zpaqdirsize(); // get size of a folder int testverify(); // check int kill(); // align to archive int utf(); // check-sanitize strange filename int test(); // test, return 1 if error else 0 int verify(bool i_readfile); // verify onfilesystem, return 1 if error else 0 int consolidate(string i_archive); // concat files into one int summa(); // get hash / or sum int hasha(); // get hash / or sum int decimation(); // get only the newest file int deduplicate(); // get hash / or sum int paranoid(); // paranoid test by unz. Really slow & lot of RAM int fillami(); // media check int dir(); // Windows-like dir command int robocopy(); // Like robocopy, but with XLS int mycopy(); // Like copy, but with progress int zero(); // Delete empty directory int trim(); // Trim incomplete transaction int crop(); // Truncate int rd(); // Remove dir (rd /s or rm-f) int purgersync(); // Purge rsync temporary file int sfx(); // Write autoextract module int oneonone(); int fix(string i_thearchive); ///int dd(); int zfsproxbackup(); int zfsproxrestore(); int zfsbackup(); int zfsrestore(); int zfsreceive(); int dircompare(bool i_flagonlysize,bool i_flagrobocopy); int homesize(); int benchmark(); int autotest(); int pause(); int update(); int isopen(); int versum(); int last2(); int last(); int testbackup(); int consolidatebackup(); int comparehex(); int work(); #ifdef SFTP int sftp(); #endif // corresponds to #ifdef (#ifdef SFTP) int count(); int backup(); int zfslist(); int zfspurge(); int zfssize(); int zfsadd(); int zfsenumerate(const string& i_command); int mysql(); #ifdef _WIN32 int download(); int windowsc(); // Backup (kind of) drive C: int adminrun(); // Run windowsc() int read_archive2(int64_t i_starthere,string i_filename); #endif // corresponds to #ifdef (#ifdef _WIN32) void load_help_map (); // not in the constructor! void helphelp (); // help void usage (bool i_flagdie); // help void examples (string i_command); // some examples // Support functions void printsanitizeflags(); string rename(string name); // rename from -to int64_t read_archive(callback_function i_advance,const char* arc, int *errors=0, int i_myappend=0,bool i_quiet=false); // read arc void scandir(bool i_checkifselected,DTMap& i_edt,string filename, bool i_recursive=true); // scan dirs to dt void addfile(bool i_checkifselected,DTMap& i_edt,string filename, int64_t edate, int64_t esize,int64_t eattr,int64_t i_creationdate,int64_t i_accessdate); // add external file to dt int64_t franzparallelscandir(bool i_flaghash,bool i_recursive,bool i_forcedir); int64_t franzparallelhashfiles(string i_hashtype,int64_t i_totalsize,vector i_thefiles,bool i_silent,vector >& o_hashname); bool equal(DTMap::const_iterator p, const char* filename, uint32_t &o_crc32,string i_myhashtype,string i_myhash,string& o_hash);// compare file contents with p void write715attr(libzpaq::StringBuffer& i_sb, uint64_t i_data, unsigned int i_quanti); void writefranzattr(DTMap::iterator i_dtmap,libzpaq::StringBuffer& i_sb, uint64_t i_data, unsigned int i_quanti,string i_filename,uint32_t i_crc32fromfragments,uint32_t i_crc32,string i_thehash,int64_t i_creationdate,int64_t i_accessdate,const struct franz_posix* i_posix,bool i_isadded); int enumeratecomments(); int searchcomments(string i_testo,vector &filelist); string zfs_get_snaplist(string i_header,string i_footer,vector& o_array_primachiocciola,vector& o_array_dopochiocciola,vector& o_array_size); string sanitizzanomefile(string i_filename,int i_filelength,int& io_collisioni,MAPPAFILEHASH& io_mappacollisioni); int writesfxmodule(string i_filename); #ifdef _WIN32 int decompress_sfx_to_file(FILE* i_outfile); int ads(); #endif // corresponds to #ifdef (#ifdef _WIN32) int extractqueue2(int i_chunk,int i_chunksize); int multiverify(vector & i_arrayfilename); bool removetempdirifempty(string i_folder,bool i_deleteifsizezero); void handleflaglongpath(); bool getfoldersize(string i_folder,uint64_t& o_totalsize,uint32_t & o_totalfile,uint32_t& o_totalfolder,uint32_t& o_longfiles); uint64_t hashastringa(const string& i_string); uint32_t casekollision(DTMap& i_dtmap,vector& o_collisions,bool i_fix); void changedtmapkey(string i_oldkey,string i_newkey); int removeemptydirs(string i_folder,bool i_kill); ///int writeresource(string i_filename,bool i_force,const char* i_mime64); #ifdef _WIN32 int decompress_mime64_to_file(FILE* i_outfile,const char* i_mime64); #endif // corresponds to #ifdef (#ifdef _WIN32) int hashselect(); // string prepare_dd(); bool getjollylist(string i_fullarchive,DTMap* o_thedt); bool cli_filesandcommand (const string& i_opt,string i_string,char i_command,int argc,const char** argv, int* i_i); bool cli_onlystring (const string& i_opt,string i_string,string i_alias,string& o_thefile,int argc,const char** argv, int* i_i,bool* i_theflag); bool cli_getdate (string& i_opt,string i_string,int argc,const char** argv, int* i_i,int64_t* o_date); bool cli_getint (const string& i_opt,string i_string,bool i_flagoptional,const string& i_short,int argc,const char** argv, int* i_i,int i_default,int* o_thenumber); bool cli_getuint (const string& i_opt,string i_string,bool i_flagoptional,const string& i_short,int argc,const char** argv, int* i_i,unsigned int i_default,unsigned int* o_thenumber); bool cli_getuint64 (const string& i_opt,string i_string,bool i_flagoptional,const string& i_short,int argc,const char** argv, int* i_i,uint64_t i_default,uint64_t* o_thenumber); bool cli_getstring (const string& i_opt,string i_string,bool i_flagoptional,const string& i_short,int argc,const char** argv, int* i_i,const string& i_default,string* o_thestring); bool cli_getarray (const string& i_opt,string i_string,int argc,const char** argv, int* i_i,vector* o_files,string* o_stringtype); bool cli_getkey (const string& i_opt,string i_string,int argc,const char** argv, int* i_i,string* o_plain,char** o_password,char* o_password_string); int get_filelist(callback_function i_advance,vector* o_filelist,int64_t& o_sizeuncompressed,int64_t& o_sizededuplicated,int64_t& o_sizecompressed,int64_t& o_sizeall,int64_t& o_dhsize,int64_t& o_dcsize); void filter_filelist(vector* i_filelist,vector* o_filtered,string i_filtro,string i_ordine,string i_crc32,string i_hash); #ifdef _WIN32 bool searchunixfile(); bool fill_ads(string i_filename,int64_t i_startiblock); bool work_ads(string i_thefile,string i_adsname,string i_description); bool isonly(string i_filename); bool exists_fasttxt_ads(string i_filename); #endif // corresponds to #ifdef (#ifdef _WIN32) string get_lastfilename(string i_file,int64_t& o_totalfilesize); int64_t getzpaqsum(string i_archive,int64_t& o_usize,int64_t& o_allsize,int64_t& o_dtsize,int64_t& o_compressedsize); bool isbackuprunning(); int fastquicktxt(); int versum_hashdeep (FILE* i_thefile,vector& o_files,vector& o_filealgo,vector& o_filehash,vector& o_filesize,int64_t& o_expected_size,int& o_expected_file); int versum_zpaqfranz(FILE* i_thefile,vector& o_files,vector& o_filealgo,vector& o_filehash,vector& o_filesize,int64_t& o_expected_size,int& o_expected_file); int versum_againstzpaq(vector i_myfiles,vector i_filealgo,vector i_filehash,vector& o_missing,int& o_errori,int64_t& o_total_hashed); int makecrc32txt(string i_filename, string& o_initialquickhash,int64_t& o_initialzpaqsize,string& o_initialzpaqquick, string& o_initialzpaqcrc32,string& o_prezpaqcrc32,int64_t& prezpaqsize,string& o_thecrcfile); int rebuildcrc32(string i_filename,string& o_prezpaqcrc32,int64_t& o_prezpaqsize,string& o_thecrcfile); void decodelastversion(); bool acceptonlynot(string i_filename); int listfolders(string i_path,vector* o_thelist); void franzreplace(string& i_filename); string secure_copy_file( const string& i_filename,const string& i_outfilename,int64_t i_startcopy,int64_t i_totalsize,int64_t i_totalcount,int64_t& o_writtensize,int64_t& o_donesize,int64_t& o_donecount, int64_t i_sorgente_size, int64_t i_sorgente_date, int64_t i_sorgente_attr, int64_t i_destinazione_size, int64_t i_destinazione_date, int64_t i_destinazione_attr, unsigned char* i_buffer, size_t i_buffersize ); int checksha1collision(DTMap& i_dtmap,bool i_decodefranzblock); void updatehash(DTMap::iterator* i_p,char* i_buf,int i_buflen); int64_t get_dt(int *errors, const char* arc); int dump(); /// char getspecificlevel(const string& i_filename); /// void loadpaqlevel(); int loadzfsdiff(string i_filediff,vector& o_added,vector& o_deleted); int listfast(); void blockdecoder(); void htdecoder(); void dtdecoder(); bool noselection(); /// int scan_archive(vector& cblock_position,vector& dblock_position,vector& hblock_position,vector& iblock_position); bool sanitizeline(string i_filename); bool sanitizefile(string i_filename); #ifdef _WIN32 void runhigh(string i_addendum); bool isrealfile(const string& i_filename); #endif // corresponds to #ifdef (#ifdef _WIN32) public: int64_t get_dt_ram() { return ram_of_map(&dt);} int64_t get_edt_ram() { return ram_of_map(&edt);} int64_t get_dt_count() { return count_of_map(&dt); } int64_t get_edt_count() { return count_of_map(&edt); } ///bool ismounted(const string i_path); ///int64_t fragmenttoblockoffset(int i_fragment); void list_datetime (const int64_t i_datetime,const bool i_flagnewversion); void list_filesize (const int64_t i_filesize,int i_thesizesize); void list_compressedfilesize(const int64_t i_compressedfilesize,const int64_t i_filesize,const bool i_flagnewversion,const bool i_isfolder,const bool i_isdeleted); //void list_seconddata (const char i_car); void list_creationdate (int64_t i_mycreationtime); void list_attributes (int64_t i_attributes); int64_t datacreazione(const string i_file); void rename_a_dtmap(DTMap& i_source); bool grep(const string i_filename,const string i_search); int checkautotest(string i_path); bool isjitable(); void tabba(); int external(); string getbackupnameifany(string i_filename); int sumhome(); bool is_incomplete_trans(const char* arc); bool onlynorecursion(string filename); #ifdef _WIN32 bool getmysqlfrominternet(); #endif }; Jidac* pjidac; #ifdef unix std::string exec(const char* cmd) { #ifdef ANCIENT return ""; #else /// "unfolded" for compiler "quiteness" char buffer[128]; std::string result; FILE* pipe = popen(cmd,"r"); if (!pipe) { myprintf("00322! popen kaputt\n"); return ""; } while (fgets(buffer,sizeof(buffer),pipe)!=NULL) result+=buffer; if (pclose(pipe)==-1) { myprintf("00323! pclose failed\n"); return ""; } return result; #endif // corresponds to #ifdef (#ifdef ANCIENT) } #else // a debug function string exec(const char* cmd) { myprintf("00324: Debug function (Windows does not have ZFS!)\n"); if (cmd==NULL) // compiler be quiet return "NULL"; return ""; } #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 string tail(string const& i_source, size_t const i_length) { if (i_length>=i_source.size()) return i_source; return i_source.substr(i_source.size()-i_length); } #endif // corresponds to #ifdef (#ifdef _WIN32) string x_one_vector(string i_command,string i_text,vector& o_line) { o_line.clear(); if (i_command=="") return ""; string risultato=exec(i_command.c_str()); if (i_text!="") if (flagverbose) myprintf("00325: running %s\n",i_text.c_str()); if (risultato=="") { if (flagverbose) myprintf("00326: x_one %s\n",i_command.c_str()); return ""; } if (flagdebug2) myprintf("00327: x_one %s => %s\n",i_command.c_str(),risultato.c_str()); unsigned int i=0; string lineetta=""; while (i %s\n",i_command.c_str(),risultato.c_str()); } return risultato; } int Jidac::zfsreceive() { myprintf("00332: zfsreceive\n",archive.c_str()); if (files.size()!=1) { myprintf("00333: zfsreceive examples (count %d)\n",files.size()); myprintf("00334: [1]: zfsreceive /pippo.zpaq rpool/restored -script thescript.sh\n"); myprintf("00335: [1]: zfsreceive /pippo.zpaq rpool/restored -script thescript.sh -snapshot mymark\n"); return 2; } if (g_script=="") { myprintf("00336! you must specify an -script thescript.sh\n"); return 2; } string myoutput=g_script; string themark ="franco"; if (snapmark!="") themark=snapmark; string estensione=prendiestensione(archive); if (estensione!="zpaq") { myprintf("00337! please use .zpaq extension on archive name <<%Z>>\n",archive.c_str()); return 1; } string thepool =files[0]; /// test pool for / int howmanyslash=0; int howmanyat =0; for (unsigned int i=0;i0) { myprintf("00342! a dataset |%s| cannot have @\n",thepool.c_str()); return 2; } int errors=0; command='l'; g_optional="versum"; //force isselected flagstdout=true; read_archive(NULL,archive.c_str(),&errors,1); /// AND NOW THE MAGIC ONE! vector filename; vector filesize; for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) { string temp=a->first.c_str(); string estensione=prendiestensione(temp); if (estensione=="zfs") { if (a->second.isordered) { filesize.push_back(a->second.size); filename.push_back(a->first.c_str()); } else { myprintf("00343! GURU file is not ordered <<%s>> \n",a->first.c_str()); return 2; } } } char nomeatteso[20]; for (unsigned int i=0;i abort\n",(int)i,snomeatteso.c_str(),filename[i].c_str()); return 2; } } FILE* batch=fopen(myoutput.c_str(), "w"); if (batch==NULL) { myprintf("00345! cannot write on script %s\n",myoutput.c_str()); return 2; } string pv=""; #ifndef _WIN32 if (fileexists("/usr/local/bin/pv")) pv="/usr/local/bin/pv|"; else if (fileexists("/usr/bin/pv")) pv="/usr/bin/pv|"; else if (fileexists("/bin/pv")) pv="/bin/pv|"; #endif // corresponds to #ifndef (#ifndef _WIN32) if (pv!="") myprintf("00346: Activating pv on <<%s>>\n",pv.c_str()); for (unsigned int i=0;i>\n",myoutput.c_str()); return 0; } int Jidac::zfsrestore() { myprintf("00350: zfsrestore\n"); if (files.size()!=2) { myprintf("00351: zfsrestore examples (count %d)\n",files.size()); myprintf("00352: [1]: zfsrestore /restoredzfsfolder rpool/restored -script thescript.sh\n"); myprintf("00353: [2]: zfsrestore /restoredzfsfonder rpool/restored -script thescript.sh -snapshot mymark\n"); return 2; } if (g_script=="") { myprintf("00354! you must specify an -script thescript.sh\n"); return 2; } string myoutput=g_script; string themark ="franco"; if (snapmark!="") themark=snapmark; string thefolder =files[0]; string thepool =files[1]; int howmanyslash=0; int howmanyat =0; for (unsigned int i=0;i0) { myprintf("00359! a pool |%s| cannot have @\n",thepool.c_str()); return 2; } files.resize(1); flagforcezfs=true; DTMap myblock; g_arraybytescanned.push_back(0); g_arrayfilescanned.push_back(0); myprintf("00360: Searching files <<%s>>\n",files[0].c_str()); edt.clear(); scandir(false,edt,files[0].c_str(),false); vector filename; for (DTMap::iterator a=edt.begin(); a!=edt.end(); ++a) { string temp=a->first.c_str(); string estensione=prendiestensione(temp); if (estensione=="zfs") filename.push_back(a->first.c_str()); } if (filename.size()==0) { myprintf("00361! no .zfs files founded in archive\n"); return 2; } char nomeatteso[20]; for (unsigned int i=0;i abort\n",(int)i,snomeatteso.c_str(),filename[i].c_str()); return 2; } } FILE* batch=fopen(myoutput.c_str(), "w"); if (batch==NULL) { myprintf("00363! cannot write on script %s\n",myoutput.c_str()); return 2; } string pv=""; #ifndef _WIN32 if (fileexists("/usr/local/bin/pv")) pv="/usr/local/bin/pv|"; else if (fileexists("/usr/bin/pv")) pv="/usr/bin/pv|"; else if (fileexists("/bin/pv")) pv="/bin/pv|"; #endif // corresponds to #ifndef (#ifndef _WIN32) for (unsigned int i=0;i>\n",myoutput.c_str()); return 0; } int Jidac::zfsbackup() { string estensione=prendiestensione(archive); if (estensione!="zpaq") { myprintf("00367! please use .zpaq extension on archive name <<%Z>>\n",archive.c_str()); return 1; } if (files.size()!=1) { myprintf("00369! please use 1 single pool/dataset\n"); return 1; } string thepool =files[0]; if (isdirectory(thepool)) { myprintf("00370! A pool-dataset |%s| cannot end with a / \n",thepool.c_str()); myprintf("00371: Good examples tank tank/d\n"); return 2; } string themark ="zpaqfranz"; if (snapmark!="") themark=snapmark; int howmanyslash=0; int howmanyat =0; for (unsigned int i=0;i1) { myprintf("00376! A pool-dataset |%s| must have exactly 0 or 1 / instead of %d\n",thepool.c_str(),howmanyslash); return 2; } if (howmanyat>0) { myprintf("00377! A pool-dataset |%s| cannot have @\n",thepool.c_str()); return 2; } if (!fileexists(archive)) { myprintf("00378: The archive does not exist, checking for snapshots\n"); vector array_primachiocciola; vector array_dopochiocciola; vector array_size; (void)zfs_get_snaplist(thepool,themark,array_primachiocciola,array_dopochiocciola,array_size); if (array_primachiocciola.size()!=0) { myprintf("00379! Archive does not exists, but we got %d snapshots => abort\n",array_primachiocciola.size()); return 2; } char buffer[1000]; snprintf(buffer,sizeof(buffer),"%s%08d",themark.c_str(),1); string thesnap=buffer; string fullsnap=thepool+"@"+thesnap; myprintf("00380: The snap |%s|\n",thesnap.c_str()); myprintf("00381: Fullsnap |%s|\n",fullsnap.c_str()); myprintf("00382: Exename |%s|\n",zpaqfranzexename.c_str()); myprintf("00383: Now preparing a brand-new archive and snapshot (starting from 00000001)\n"); string filebatch="/tmp/newbackup_zfs_"+purgedpool+".sh"; filebatch=nomefileseesistegia(filebatch); myprintf("00384: CREATING script %s\n",filebatch.c_str()); FILE* batch=fopen(filebatch.c_str(), "w"); if (batch==NULL) { myprintf("00385! cannot write on script %s\n",filebatch.c_str()); return 2; } fprintf(batch,"zfs snapshot %s\n",fullsnap.c_str()); string hashofile=""; if (flaghashdeep) { string hashdeepposition=""; #ifndef _WIN32 if (fileexists("/usr/local/bin/hashdeep")) hashdeepposition="/usr/local/bin/hashdeep"; else if (fileexists("/usr/bin/pv")) hashdeepposition="/usr/bin/hashdeep"; else if (fileexists("/bin/pv")) hashdeepposition="/bin/hashdeep"; #endif // corresponds to #ifndef (#ifndef _WIN32) myprintf("00386: hashdeep <<%s>>\n",hashdeepposition.c_str()); if (hashdeepposition=="") { myprintf("00387! Cannot locate hashdeep, abort!\n"); fclose(batch); return 2; } string zfsfolder="/"+thepool+"/.zfs/snapshot/"+thesnap+"/"; myprintf("00388: zfsfolder <<%s>>\n",zfsfolder.c_str()); hashofile="/tmp/hasho_"+purgedpool+"_"+thesnap+".txt"; hashofile=nomefileseesistegia(hashofile); myprintf("00389: Hash-o-file <<%s>>\n",hashofile.c_str()); fprintf(batch,"/sbin/zfs set snapdir=hidden %s\n",thepool.c_str()); fprintf(batch,"%s -c md5 -r %s >%s\n", hashdeepposition.c_str(), zfsfolder.c_str(), hashofile.c_str()); } fprintf(batch,"zfs send %s@%s00000001 |%s a %s 00000001.zfs -stdin\n",thepool.c_str(),themark.c_str(),fullzpaqexename.c_str(),archive.c_str()); if (flaghashdeep) fprintf(batch,"%s a %s %s\n",fullzpaqexename.c_str(),archive.c_str(),hashofile.c_str()); fclose(batch); #ifndef _WIN32 if (chmod(filebatch.c_str(),0700)!=0) { myprintf("00390! error on chmod 700 on <<%s>>\n",filebatch.c_str()); return 2; } myprintf("00391: RUNNING script %s\n",filebatch.c_str()); string runresult=exec(filebatch.c_str()); if (mypos("(all OK)",runresult)!=0) { myprintf("00392: The run seems OK, filesize %s\n",migliaia(prendidimensionefile(archive.c_str()))); if (flagkill) { myprintf("00393: Deleting <<%s>>\n",filebatch.c_str()); delete_file(filebatch.c_str()); if (hashofile!="") { myprintf("00394: Deleting hasho <<%s>>\n",hashofile.c_str()); delete_file(hashofile.c_str()); } } return 0; } else { myprintf("00395! GURU, something seems wrong, filesize %s\n",migliaia(prendidimensionefile(archive.c_str()))); return 2; } #endif // corresponds to #ifndef (#ifndef _WIN32) return 0; } // archive does exists myprintf("00396: The archive exist, checking latest snapshot\n"); int errors=0; command='l'; g_optional="versum"; //force isselected #ifndef _WIN32 int64_t oldsize=prendidimensionefile(archive.c_str()); #endif // corresponds to #ifndef (#ifndef _WIN32) read_archive(NULL,archive.c_str(),&errors,1); /// AND NOW THE MAGIC ONE! vector filename; for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) { string temp=a->first.c_str(); string estensione=prendiestensione(temp); if (estensione=="zfs") filename.push_back(a->first.c_str()); } char nomeatteso[40]; for (unsigned int i=0;i abort\n",(int)i,snomeatteso.c_str(),filename[i].c_str()); } string snomeatteso=myulltoa(filename.size(),8); string expectedsnapshot=themark+snomeatteso; string fullexpectedsnapshot=thepool+'@'+themark+snomeatteso; myprintf("00398: Searching for snapshot |%s|\n",fullexpectedsnapshot.c_str()); vector array_primachiocciola; vector array_dopochiocciola; vector array_size; (void)zfs_get_snaplist(thepool,themark,array_primachiocciola,array_dopochiocciola,array_size); if (array_primachiocciola.size()==0) { myprintf("00399! Cannot find the expected snapshot |%s|\n",fullexpectedsnapshot.c_str()); return 2; } int foundindex=-1; for (unsigned int i=0;i %s\n",(int)i,array_dopochiocciola[i].c_str()); if (expectedsnapshot==array_dopochiocciola[i]) { myprintf("00401: The expected snapshot exists (this is good) index %d |%s|\n",(int)i,expectedsnapshot.c_str()); foundindex=i; break; } } if (((foundindex+1)!=(int)array_primachiocciola.size()) || (foundindex==-1)) { myprintf("00402! The founded index %d is < snapshot size %d, cowardly abort (not the LAST snapshot)\n",foundindex,array_primachiocciola.size()); return 2; } string ultimo =array_dopochiocciola[foundindex]; string solocifre =""; for (unsigned int i=0;i>\n",hashdeepposition.c_str()); if (hashdeepposition=="") { myprintf("00409! cannot locate hashdeep, abort!\n"); fclose(batch); return 2; } string thesnap=themark+nuovonome; string zfsfolder="/"+thepool+"/.zfs/snapshot/"+thesnap+"/"; myprintf("00410: Zfsfolder <<%s>>\n",zfsfolder.c_str()); hashofile="/tmp/hasho_"+purgedpool+"_"+thesnap+".txt"; hashofile=nomefileseesistegia(hashofile); myprintf("00411: Hashofile <<%s>>\n",hashofile.c_str()); fprintf(batch,"/sbin/zfs set snapdir=hidden %s\n",thepool.c_str()); fprintf(batch,"%s -c md5 -r %s >%s\n", hashdeepposition.c_str(), zfsfolder.c_str(), hashofile.c_str()); } fprintf(batch,"zfs send -i %s %s |%s a %s %s.zfs -stdin\n",fullexpectedsnapshot.c_str(),nuovonomefull.c_str(),fullzpaqexename.c_str(),archive.c_str(),nuovonome.c_str()); if (flaghashdeep) fprintf(batch,"%s a %s %s\n",fullzpaqexename.c_str(),archive.c_str(),hashofile.c_str()); if (flagkill) fprintf(batch,"zfs destroy %s\n",fullexpectedsnapshot.c_str()); fclose(batch); #ifndef _WIN32 if (chmod(filebatch.c_str(),0700)!=0) { myprintf("00412! Error on chmod 700 on %s\n",filebatch.c_str()); return 2; } myprintf("00413: RUNNING script %s\n",filebatch.c_str()); string runresult=exec(filebatch.c_str()); // dirrrrty if (mypos("(all OK)",runresult)!=0) { int64_t newsize=prendidimensionefile(archive.c_str()); myprintf("00414: Seems OK, filesize %s => %s (%s)\n",migliaia(oldsize),migliaia2(newsize),migliaia3(myabs(newsize,oldsize))); if (flagkill) { myprintf("00415: Deleting <<%s>>\n",filebatch.c_str()); delete_file(filebatch.c_str()); } return 0; } else { myprintf("00416! GURU, something seems wrong, filesize %s\n",migliaia(prendidimensionefile(archive.c_str()))); return 2; } #endif // corresponds to #ifndef (#ifndef _WIN32) return 0; } /// detecting case collision: xxhash64 is more than enough (fast and compact) uint64_t Jidac::hashastringa(const string& i_string) { uint64_t myseed = 0; XXHash64 myhash(myseed); myhash.add(i_string.c_str(),i_string.size()); return myhash.hash(); } /// change the key of a map is not so easy (slow) /// this is something like filesystem behavior: just add and mark as deleted /// note: this is find, not binary search. quite slow, but resilient void Jidac::changedtmapkey(string i_oldkey,string i_newkey) { DTMap::iterator myp=dt.find(i_oldkey); if (myp==dt.end()) return; DT olddt=myp->second; dt[i_newkey]=olddt; myp->second.date=0; ///fake delete } uint32_t Jidac::casekollision(DTMap& i_dtmap,vector& o_collisions,bool i_fix=false) { int64_t startkoll=mtime(); if (flagverbose) myprintf("00417: Case-collision checks on %s files ",migliaia((int64_t)i_dtmap.size())); uint32_t fixed=0; o_collisions.clear(); vector hashedstrings; for (DTMap::iterator p=i_dtmap.begin(); p!=i_dtmap.end(); ++p) if (all || p->second.date) { string fn =rename(p->first); string filename =stringtolower(fn); uint64_t hashato=hashastringa(filename); if (binary_search(hashedstrings.begin(),hashedstrings.end(),hashato)==true) { if (i_fix) { char buf[32]; string percorso =extractfilepath(fn); string nomefile =prendinomefileebasta(fn); string estensione =prendiestensione(fn); int iterazione =1; string rifatto =""; do { snprintf(buf,sizeof(buf),"_%08d",iterazione++); if (percorso!="") rifatto=percorso; string pezzetto=buf; if (nomefile!="") rifatto+=nomefile+buf; if (estensione!="") rifatto+="."+estensione; hashato=hashastringa(rifatto); if (binary_search(hashedstrings.begin(),hashedstrings.end(),hashato)==false) break; } while (iterazione<1000); if (iterazione<1000) { changedtmapkey(p->first,rifatto); fixed++; } else { myprintf("00418! ERROR IMPOSSIBLE TO 'DECASE' %Z\n",filename.c_str()); } } else o_collisions.push_back(fn); } else { #ifndef ANCIENT ///macos std::vector::iterator it; it = std::upper_bound(hashedstrings.begin(),hashedstrings.end(),hashato); hashedstrings.insert(it,hashato); /* auto it = std::upper_bound(hashedstrings.cbegin(),hashedstrings.cend(),hashato); hashedstrings.insert(it,hashato); */ #endif // corresponds to #ifndef (#ifndef ANCIENT) } } int64_t endkoll=mtime(); if (flagverbose) myprintf("00420: done in %.2fs\n",(endkoll-startkoll)*0.001); return (fixed); } void Jidac::jidacreset() { g_freeze=""; files_size.clear(); files_count.clear(); files_time.clear(); files_edt.clear(); ver.clear(); block.clear(); dt.clear(); ht.clear(); edt.clear(); ht.resize(1); // element 0 not used ver.resize(1); // version 0 dhsize=dcsize=0; g_crc32.clear(); /// tofiles.clear(); /// files.clear(); } int Jidac::paranoid() //////////////////////////////////////////////////////////////////////////// ///////// This is a merge of unzpaq206.cpp, patched by me to become unz.cpp ///////// Now support FRANZOFFSET { #ifdef _WIN32 #ifndef _WIN64 myprintf("00423$ WARNING: paranoid test use a lot of RAM, not good for Win32, better Win64\n"); #endif // corresponds to #ifndef (#ifndef _WIN64) #endif // corresponds to #ifdef (#ifdef _WIN32) unz(archive.c_str(), g_password); return 0; } // Callback for user defined ZPAQ error handling. // It will be called on input error with an English language error message. // This function should not return. extern void unzerror(const char* msg); // Virtual base classes for input and output // get() and put() must be overridden to read or write 1 byte. class unzReader { public: virtual int get() = 0; // should return 0..255, or -1 at EOF virtual ~unzReader() {} }; class unzWriter { public: virtual void put(int c) = 0; // should output low 8 bits of c virtual ~unzWriter() {} }; // An Array of T is cleared and aligned on a 64 byte address // with no constructors called. No copy or assignment. // Array a(n, ex=0); - creates n< class Array { T *data; // user location of [0] on a 64 byte boundary size_t n; // user size int offset; // distance back in bytes to start of actual allocation void operator=(const Array&); // no assignment Array(const Array&); // no copy public: Array(size_t sz=0, int ex=0): data(0), n(0), offset(0) { resize(sz, ex);} // [0..sz-1] = 0 void resize(size_t sz, int ex=0); // change size, erase content to zeros ~Array() {resize(0);} // free memory size_t size() const {return n;} // get size int isize() const {return int(n);} // get size as an int T& operator[](size_t i) {assert(n>0 && i0 && (n&(n-1))==0); return data[i&(n-1)];} }; // Change size to sz< void Array::resize(size_t sz, int ex) { assert(size_t(-1)>0); // unsigned type? while (ex>0) { if (sz>sz*2) unzerror("Array too big"); sz*=2, --ex; } if (n>0) { assert(offset>=0 && offset<=64); assert((char*)data-offset); free((char*)data-offset); } n=0; if (sz==0) return; n=sz; const size_t nb=128+n*sizeof(T); // test for overflow if (nb<=128 || (nb-128)/sizeof(T)!=n) unzerror("Array too big"); data=(T*)calloc(nb, 1); g_allocatedram+=nb; if (!data) unzerror("out of memory"); // Align array on a 64 byte address. // This optimization is NOT required by the ZPAQ standard. offset=64-(((char*)data-(char*)0)&63); assert(offset>0 && offset<=64); data=(T*)((char*)data+offset); } //////////////////////////// unzSHA1 //////////////////////////// // For computing SHA-1 checksums class unzSHA1 { public: void put(int c) { // hash 1 byte uint32_t& r=w[len0>>5&15]; r=(r<<8)|(c&255); if (!(len0+=8)) ++len1; if ((len0&511)==0) process(); } double size() const {return len0/8+len1*536870912.0;} // size in bytes const char* result(); unzSHA1() {init();} private: void init(); uint32_t len0, len1; uint32_t h[5]; uint32_t w[80]; char hbuf[20]; void process(); }; // Start a new hash void unzSHA1::init() { len0=len1=0; h[0]=0x67452301; h[1]=0xEFCDAB89; h[2]=0x98BADCFE; h[3]=0x10325476; h[4]=0xC3D2E1F0; } // Return old result and start a new hash const char* unzSHA1::result() { // pad and append length const uint32_t s1=len1, s0=len0; put(0x80); while ((len0&511)!=448) put(0); put(s1>>24); put(s1>>16); put(s1>>8); put(s1); put(s0>>24); put(s0>>16); put(s0>>8); put(s0); // copy h to hbuf for (int i=0; i<5; ++i) { hbuf[4*i]=h[i]>>24; hbuf[4*i+1]=h[i]>>16; hbuf[4*i+2]=h[i]>>8; hbuf[4*i+3]=h[i]; } // return hash prior to clearing state init(); return hbuf; } // Hash 1 block of 64 bytes void unzSHA1::process() { for (int i=16; i<80; ++i) { w[i]=w[i-3]^w[i-8]^w[i-14]^w[i-16]; w[i]=w[i]<<1|w[i]>>31; } uint32_t a=h[0]; uint32_t b=h[1]; uint32_t c=h[2]; uint32_t d=h[3]; uint32_t e=h[4]; const uint32_t k1=0x5A827999, k2=0x6ED9EBA1, k3=0x8F1BBCDC, k4=0xCA62C1D6; #define f1(a,b,c,d,e,i) e+=(a<<5|a>>27)+((b&c)|(~b&d))+k1+w[i]; b=b<<30|b>>2; #define f5(i) f1(a,b,c,d,e,i) f1(e,a,b,c,d,i+1) f1(d,e,a,b,c,i+2) \ f1(c,d,e,a,b,i+3) f1(b,c,d,e,a,i+4) f5(0) f5(5) f5(10) f5(15) #undef f1 #define f1(a,b,c,d,e,i) e+=(a<<5|a>>27)+(b^c^d)+k2+w[i]; b=b<<30|b>>2; f5(20) f5(25) f5(30) f5(35) #undef f1 #define f1(a,b,c,d,e,i) e+=(a<<5|a>>27)+((b&c)|(b&d)|(c&d))+k3+w[i]; \ b=b<<30|b>>2; f5(40) f5(45) f5(50) f5(55) #undef f1 #define f1(a,b,c,d,e,i) e+=(a<<5|a>>27)+(b^c^d)+k4+w[i]; b=b<<30|b>>2; f5(60) f5(65) f5(70) f5(75) #undef f1 #undef f5 h[0]+=a; h[1]+=b; h[2]+=c; h[3]+=d; h[4]+=e; } //////////////////////////// unzSHA256 ////////////////////////// // For computing SHA-256 checksums // http://en.wikipedia.org/wiki/SHA-2 class unzSHA256 { public: void put(int c) { // hash 1 byte unsigned& r=w[len0>>5&15]; r=(r<<8)|(c&255); if (!(len0+=8)) ++len1; if ((len0&511)==0) process(); } double size() const {return len0/8+len1*536870912.0;} // size in bytes uint64_t usize() const {return len0/8+(uint64_t(len1)<<29);} //size in bytes const char* result(); // get hash and reset unzSHA256() {init();} private: void init(); unsigned len0, len1; unsigned s[8]; unsigned w[16]; char hbuf[32]; void process(); }; void unzSHA256::init() { len0=len1=0; s[0]=0x6a09e667; s[1]=0xbb67ae85; s[2]=0x3c6ef372; s[3]=0xa54ff53a; s[4]=0x510e527f; s[5]=0x9b05688c; s[6]=0x1f83d9ab; s[7]=0x5be0cd19; memset(w, 0, sizeof(w)); } void unzSHA256::process() { #define ror(a,b) ((a)>>(b)|(a<<(32-(b)))) #define m(i) \ w[(i)&15]+=w[(i-7)&15] \ +(ror(w[(i-15)&15],7)^ror(w[(i-15)&15],18)^(w[(i-15)&15]>>3)) \ +(ror(w[(i-2)&15],17)^ror(w[(i-2)&15],19)^(w[(i-2)&15]>>10)) #define r(a,b,c,d,e,f,g,h,i) { \ unsigned t1=ror(e,14)^e; \ t1=ror(t1,5)^e; \ h+=ror(t1,6)+((e&f)^(~e&g))+k[i]+w[(i)&15]; } \ d+=h; \ {unsigned t1=ror(a,9)^a; \ t1=ror(t1,11)^a; \ h+=ror(t1,2)+((a&b)^(c&(a^b))); } #define mr(a,b,c,d,e,f,g,h,i) m(i); r(a,b,c,d,e,f,g,h,i); #define r8(i) \ r(a,b,c,d,e,f,g,h,i); \ r(h,a,b,c,d,e,f,g,i+1); \ r(g,h,a,b,c,d,e,f,i+2); \ r(f,g,h,a,b,c,d,e,i+3); \ r(e,f,g,h,a,b,c,d,i+4); \ r(d,e,f,g,h,a,b,c,i+5); \ r(c,d,e,f,g,h,a,b,i+6); \ r(b,c,d,e,f,g,h,a,i+7); #define mr8(i) \ mr(a,b,c,d,e,f,g,h,i); \ mr(h,a,b,c,d,e,f,g,i+1); \ mr(g,h,a,b,c,d,e,f,i+2); \ mr(f,g,h,a,b,c,d,e,i+3); \ mr(e,f,g,h,a,b,c,d,i+4); \ mr(d,e,f,g,h,a,b,c,i+5); \ mr(c,d,e,f,g,h,a,b,i+6); \ mr(b,c,d,e,f,g,h,a,i+7); static const unsigned k[64]={ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2}; unsigned a=s[0]; unsigned b=s[1]; unsigned c=s[2]; unsigned d=s[3]; unsigned e=s[4]; unsigned f=s[5]; unsigned g=s[6]; unsigned h=s[7]; r8(0); r8(8); mr8(16); mr8(24); mr8(32); mr8(40); mr8(48); mr8(56); s[0]+=a; s[1]+=b; s[2]+=c; s[3]+=d; s[4]+=e; s[5]+=f; s[6]+=g; s[7]+=h; #undef mr8 #undef r8 #undef mr #undef r #undef m #undef ror } // Return old result and start a new hash const char* unzSHA256::result() { // pad and append length const unsigned s1=len1, s0=len0; put(0x80); while ((len0&511)!=448) put(0); put(s1>>24); put(s1>>16); put(s1>>8); put(s1); put(s0>>24); put(s0>>16); put(s0>>8); put(s0); // copy s to hbuf for (int i=0; i<8; ++i) { hbuf[4*i]=s[i]>>24; hbuf[4*i+1]=s[i]>>16; hbuf[4*i+2]=s[i]>>8; hbuf[4*i+3]=s[i]; } // return hash prior to clearing state init(); return hbuf; } //////////////////////////// AES ///////////////////////////// // For encrypting with AES in CTR mode. // The i'th 16 byte block is encrypted by XOR with AES(i) // (i is big endian or MSB first, starting with 0). class unzAES_CTR { uint32_t Te0[256], Te1[256], Te2[256], Te3[256], Te4[256]; // encryption tables uint32_t ek[60]; // round key int Nr; // number of rounds (10, 12, 14 for AES 128, 192, 256) uint32_t iv0, iv1; // first 8 bytes in CTR mode public: unzAES_CTR(const char* key, int keylen, const char* iv=0); // Schedule: keylen is 16, 24, or 32, iv is 8 bytes or NULL void encrypt(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, unsigned char* ct); void encrypt(char* unzBuf, int n, uint64_t offset); // encrypt n bytes of unzBuf }; // Some AES code is derived from libtomcrypt 1.17 (public domain). #define Te4_0 0x000000FF & Te4 #define Te4_1 0x0000FF00 & Te4 #define Te4_2 0x00FF0000 & Te4 #define Te4_3 0xFF000000 & Te4 // Extract byte n of x static inline unsigned unzbyte(unsigned x, unsigned n) {return (x>>(8*n))&255;} // x = y[0..3] MSB first static inline void LOAD32H(uint32_t& x, const char* y) { const unsigned char* u=(const unsigned char*)y; x=u[0]<<24|u[1]<<16|u[2]<<8|u[3]; } // y[0..3] = x MSB first static inline void STORE32H(uint32_t& x, unsigned char* y) { y[0]=x>>24; y[1]=x>>16; y[2]=x>>8; y[3]=x; } #define setup_mix(temp) \ ((Te4_3[unzbyte(temp, 2)]) ^ (Te4_2[unzbyte(temp, 1)]) ^ \ (Te4_1[unzbyte(temp, 0)]) ^ (Te4_0[unzbyte(temp, 3)])) // Initialize encryption tables and round key. keylen is 16, 24, or 32. unzAES_CTR::unzAES_CTR(const char* key, int keylen, const char* iv) { assert(key != NULL); assert(keylen==16 || keylen==24 || keylen==32); // Initialize IV (default 0) iv0=iv1=0; if (iv) { LOAD32H(iv0, iv); LOAD32H(iv1, iv+4); } // Initialize encryption tables for (int i=0; i<256; ++i) { unsigned s1= "\x63\x7c\x77\x7b\xf2\x6b\x6f\xc5\x30\x01\x67\x2b\xfe\xd7\xab\x76" "\xca\x82\xc9\x7d\xfa\x59\x47\xf0\xad\xd4\xa2\xaf\x9c\xa4\x72\xc0" "\xb7\xfd\x93\x26\x36\x3f\xf7\xcc\x34\xa5\xe5\xf1\x71\xd8\x31\x15" "\x04\xc7\x23\xc3\x18\x96\x05\x9a\x07\x12\x80\xe2\xeb\x27\xb2\x75" "\x09\x83\x2c\x1a\x1b\x6e\x5a\xa0\x52\x3b\xd6\xb3\x29\xe3\x2f\x84" "\x53\xd1\x00\xed\x20\xfc\xb1\x5b\x6a\xcb\xbe\x39\x4a\x4c\x58\xcf" "\xd0\xef\xaa\xfb\x43\x4d\x33\x85\x45\xf9\x02\x7f\x50\x3c\x9f\xa8" "\x51\xa3\x40\x8f\x92\x9d\x38\xf5\xbc\xb6\xda\x21\x10\xff\xf3\xd2" "\xcd\x0c\x13\xec\x5f\x97\x44\x17\xc4\xa7\x7e\x3d\x64\x5d\x19\x73" "\x60\x81\x4f\xdc\x22\x2a\x90\x88\x46\xee\xb8\x14\xde\x5e\x0b\xdb" "\xe0\x32\x3a\x0a\x49\x06\x24\x5c\xc2\xd3\xac\x62\x91\x95\xe4\x79" "\xe7\xc8\x37\x6d\x8d\xd5\x4e\xa9\x6c\x56\xf4\xea\x65\x7a\xae\x08" "\xba\x78\x25\x2e\x1c\xa6\xb4\xc6\xe8\xdd\x74\x1f\x4b\xbd\x8b\x8a" "\x70\x3e\xb5\x66\x48\x03\xf6\x0e\x61\x35\x57\xb9\x86\xc1\x1d\x9e" "\xe1\xf8\x98\x11\x69\xd9\x8e\x94\x9b\x1e\x87\xe9\xce\x55\x28\xdf" "\x8c\xa1\x89\x0d\xbf\xe6\x42\x68\x41\x99\x2d\x0f\xb0\x54\xbb\x16" [i]&255; unsigned s2=s1<<1; if (s2>=0x100) s2^=0x11b; unsigned s3=s1^s2; Te0[i]=s2<<24|s1<<16|s1<<8|s3; Te1[i]=s3<<24|s2<<16|s1<<8|s1; Te2[i]=s1<<24|s3<<16|s2<<8|s1; Te3[i]=s1<<24|s1<<16|s3<<8|s2; Te4[i]=s1<<24|s1<<16|s1<<8|s1; } // setup the forward key Nr = 10 + ((keylen/8)-2)*2; // 10, 12, or 14 rounds int i = 0; uint32_t* rk = &ek[0]; uint32_t temp; static const uint32_t rcon[10] = { 0x01000000UL, 0x02000000UL, 0x04000000UL, 0x08000000UL, 0x10000000UL, 0x20000000UL, 0x40000000UL, 0x80000000UL, 0x1B000000UL, 0x36000000UL}; // round constants LOAD32H(rk[0], key ); LOAD32H(rk[1], key + 4); LOAD32H(rk[2], key + 8); LOAD32H(rk[3], key + 12); if (keylen == 16) { for (;;) { temp = rk[3]; rk[4] = rk[0] ^ setup_mix(temp) ^ rcon[i]; rk[5] = rk[1] ^ rk[4]; rk[6] = rk[2] ^ rk[5]; rk[7] = rk[3] ^ rk[6]; if (++i == 10) { break; } rk += 4; } } else if (keylen == 24) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); for (;;) { temp = rk[5]; rk[ 6] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 7] = rk[ 1] ^ rk[ 6]; rk[ 8] = rk[ 2] ^ rk[ 7]; rk[ 9] = rk[ 3] ^ rk[ 8]; if (++i == 8) { break; } rk[10] = rk[ 4] ^ rk[ 9]; rk[11] = rk[ 5] ^ rk[10]; rk += 6; } } else if (keylen == 32) { LOAD32H(rk[4], key + 16); LOAD32H(rk[5], key + 20); LOAD32H(rk[6], key + 24); LOAD32H(rk[7], key + 28); for (;;) { temp = rk[7]; rk[ 8] = rk[ 0] ^ setup_mix(temp) ^ rcon[i]; rk[ 9] = rk[ 1] ^ rk[ 8]; rk[10] = rk[ 2] ^ rk[ 9]; rk[11] = rk[ 3] ^ rk[10]; if (++i == 7) { break; } temp = rk[11]; rk[12] = rk[ 4] ^ setup_mix(temp<<24|temp>>8); rk[13] = rk[ 5] ^ rk[12]; rk[14] = rk[ 6] ^ rk[13]; rk[15] = rk[ 7] ^ rk[14]; rk += 8; } } } // Encrypt to ct[16] void unzAES_CTR::encrypt(uint32_t s0, uint32_t s1, uint32_t s2, uint32_t s3, unsigned char* ct) { int r = Nr >> 1; uint32_t *rk = &ek[0]; uint32_t t0=0, t1=0, t2=0, t3=0; s0 ^= rk[0]; s1 ^= rk[1]; s2 ^= rk[2]; s3 ^= rk[3]; for (;;) { t0 = Te0[unzbyte(s0, 3)] ^ Te1[unzbyte(s1, 2)] ^ Te2[unzbyte(s2, 1)] ^ Te3[unzbyte(s3, 0)] ^ rk[4]; t1 = Te0[unzbyte(s1, 3)] ^ Te1[unzbyte(s2, 2)] ^ Te2[unzbyte(s3, 1)] ^ Te3[unzbyte(s0, 0)] ^ rk[5]; t2 = Te0[unzbyte(s2, 3)] ^ Te1[unzbyte(s3, 2)] ^ Te2[unzbyte(s0, 1)] ^ Te3[unzbyte(s1, 0)] ^ rk[6]; t3 = Te0[unzbyte(s3, 3)] ^ Te1[unzbyte(s0, 2)] ^ Te2[unzbyte(s1, 1)] ^ Te3[unzbyte(s2, 0)] ^ rk[7]; rk += 8; if (--r == 0) { break; } s0 = Te0[unzbyte(t0, 3)] ^ Te1[unzbyte(t1, 2)] ^ Te2[unzbyte(t2, 1)] ^ Te3[unzbyte(t3, 0)] ^ rk[0]; s1 = Te0[unzbyte(t1, 3)] ^ Te1[unzbyte(t2, 2)] ^ Te2[unzbyte(t3, 1)] ^ Te3[unzbyte(t0, 0)] ^ rk[1]; s2 = Te0[unzbyte(t2, 3)] ^ Te1[unzbyte(t3, 2)] ^ Te2[unzbyte(t0, 1)] ^ Te3[unzbyte(t1, 0)] ^ rk[2]; s3 = Te0[unzbyte(t3, 3)] ^ Te1[unzbyte(t0, 2)] ^ Te2[unzbyte(t1, 1)] ^ Te3[unzbyte(t2, 0)] ^ rk[3]; } // apply last round and map cipher state to byte array block: s0 = (Te4_3[unzbyte(t0, 3)]) ^ (Te4_2[unzbyte(t1, 2)]) ^ (Te4_1[unzbyte(t2, 1)]) ^ (Te4_0[unzbyte(t3, 0)]) ^ rk[0]; STORE32H(s0, ct); s1 = (Te4_3[unzbyte(t1, 3)]) ^ (Te4_2[unzbyte(t2, 2)]) ^ (Te4_1[unzbyte(t3, 1)]) ^ (Te4_0[unzbyte(t0, 0)]) ^ rk[1]; STORE32H(s1, ct+4); s2 = (Te4_3[unzbyte(t2, 3)]) ^ (Te4_2[unzbyte(t3, 2)]) ^ (Te4_1[unzbyte(t0, 1)]) ^ (Te4_0[unzbyte(t1, 0)]) ^ rk[2]; STORE32H(s2, ct+8); s3 = (Te4_3[unzbyte(t3, 3)]) ^ (Te4_2[unzbyte(t0, 2)]) ^ (Te4_1[unzbyte(t1, 1)]) ^ (Te4_0[unzbyte(t2, 0)]) ^ rk[3]; STORE32H(s3, ct+12); } // Encrypt or decrypt slice unzBuf[0..n-1] at offset by XOR with AES(i) where // i is the 128 bit big-endian distance from the start in 16 byte blocks. void unzAES_CTR::encrypt(char* unzBuf, int n, uint64_t offset) { for (uint64_t i=offset/16; i<=(offset+n)/16; ++i) { unsigned char ct[16]; encrypt(iv0, iv1, i>>32, i, ct); for (int j=0; j<16; ++j) { const int k=i*16-offset+j; if (k>=0 && k=0; j-=8) sha256.put(i>>j); memcpy(b, sha256.result(), 32); for (int j=0; j>(32-b))) x[ 4] ^= R(x[ 0]+x[12], 7); x[ 8] ^= R(x[ 4]+x[ 0], 9); x[12] ^= R(x[ 8]+x[ 4],13); x[ 0] ^= R(x[12]+x[ 8],18); x[ 9] ^= R(x[ 5]+x[ 1], 7); x[13] ^= R(x[ 9]+x[ 5], 9); x[ 1] ^= R(x[13]+x[ 9],13); x[ 5] ^= R(x[ 1]+x[13],18); x[14] ^= R(x[10]+x[ 6], 7); x[ 2] ^= R(x[14]+x[10], 9); x[ 6] ^= R(x[ 2]+x[14],13); x[10] ^= R(x[ 6]+x[ 2],18); x[ 3] ^= R(x[15]+x[11], 7); x[ 7] ^= R(x[ 3]+x[15], 9); x[11] ^= R(x[ 7]+x[ 3],13); x[15] ^= R(x[11]+x[ 7],18); x[ 1] ^= R(x[ 0]+x[ 3], 7); x[ 2] ^= R(x[ 1]+x[ 0], 9); x[ 3] ^= R(x[ 2]+x[ 1],13); x[ 0] ^= R(x[ 3]+x[ 2],18); x[ 6] ^= R(x[ 5]+x[ 4], 7); x[ 7] ^= R(x[ 6]+x[ 5], 9); x[ 4] ^= R(x[ 7]+x[ 6],13); x[ 5] ^= R(x[ 4]+x[ 7],18); x[11] ^= R(x[10]+x[ 9], 7); x[ 8] ^= R(x[11]+x[10], 9); x[ 9] ^= R(x[ 8]+x[11],13); x[10] ^= R(x[ 9]+x[ 8],18); x[12] ^= R(x[15]+x[14], 7); x[13] ^= R(x[12]+x[15], 9); x[14] ^= R(x[13]+x[12],13); x[15] ^= R(x[14]+x[13],18); #undef R } for (int i=0; i<16; ++i) b[i]+=x[i]; } // BlockMix_{Salsa20/8, r} on b[0..128*r-1] static void blockmix(uint32_t* b, int r) { assert(r<=8); uint32_t x[16]; uint32_t y[256]; memcpy(x, b+32*r-16, 64); for (int i=0; i<2*r; ++i) { for (int j=0; j<16; ++j) x[j]^=b[i*16+j]; salsa8(x); memcpy(&y[i*16], x, 64); } for (int i=0; i x(32*r), v(32*r*n); for (int i=0; i>(i%4*8); } // Strengthen password pw[0..pwlen-1] and salt[0..saltlen-1] // to produce key unzBuf[0..buflen-1]. Uses O(n*r*p) time and 128*r*n bytes // of memory. n must be a power of 2 and r <= 8. void unzscrypt(const char* pw, int pwlen, const char* salt, int saltlen, int n, int r, int p, char* unzBuf, int buflen) { assert(r<=8); assert(n>0 && (n&(n-1))==0); // power of 2? Array b(p*r*128); unzpbkdf2(pw, pwlen, salt, saltlen, &b[0], p*r*128); for (int i=0; i header; // hsize[2] hh hm ph pm n COMP (guard) HCOMP (guard) int cend; // COMP in header[7...cend-1] int hbegin, hend; // HCOMP/PCOMP in header[hbegin...hend-1] private: // Machine state for executing HCOMP Array m; // memory array M for HCOMP Array h; // hash array H for HCOMP Array r; // 256 element register array uint32_t a, b, c, d; // machine registers int f; // condition flag int pc; // program counter // Support code void init(int hbits, int mbits); // initialize H and M sizes int execute(); // execute 1 instruction, return 0 after HALT, else 1 void unzdiv(uint32_t x) {if (x) a/=x; else a=0;} void mod(uint32_t x) {if (x) a%=x; else a=0;} void swap(uint32_t& x) {a^=x; x^=a; a^=x;} void swap(uint8_t& x) {a^=x; x^=a; a^=x;} void err(); // exit with run time error }; // Read header from in2 int unzZPAQL::read(unzReader* in2) { // Get header size and allocate int hsize=in2->get(); if (hsize<0) unzerror("end of header"); hsize+=in2->get()*256; if (hsize<0) unzerror("end of header"); header.resize(hsize+300); cend=hbegin=hend=0; header[cend++]=hsize&255; header[cend++]=hsize>>8; while (cend<7) header[cend++]=in2->get(); // hh hm ph pm n // Read COMP int n=header[cend-1]; for (int i=0; iget(); // component type if (type==-1) unzerror("unexpected end of file"); header[cend++]=type; // component type int size=compsize[type]; if (size<1) unzerror("Invalid component type"); if (cend+size>hsize) unzerror("COMP overflows header"); for (int j=1; jget(); } if ((header[cend++]=in2->get())!=0) unzerror("missing COMP END"); // Insert a guard gap and read HCOMP hbegin=hend=cend+128; if (hend>hsize+129) unzerror("missing HCOMP"); while (hendget(); if (op<0) unzerror("unexpected end of file"); header[hend++]=op; } if ((header[hend++]=in2->get())!=0) unzerror("missing HCOMP END"); assert(cend>=7 && cendhbegin && hend6); assert(output==0); assert(sha1==0); init(header[2], header[3]); // hh, hm } // Initialize machine state as PCOMP void unzZPAQL::initp() { assert(header.isize()>6); init(header[4], header[5]); // ph, pm } // Initialize machine state to run a program. void unzZPAQL::init(int hbits, int mbits) { assert(header.isize()>0); assert(cend>=7); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend6); assert(hbegin>=cend+128); assert(hend>=hbegin); assert(hend0); assert(h.size()>0); assert(header[0]+256*header[1]==cend+hend-hbegin-2); pc=hbegin; a=input; while (execute()) ; } void unzZPAQL::outc(int c) { if (output) output->put(c); if (sha1) sha1->put(c); } // Execute one instruction, return 0 after HALT else 1 int unzZPAQL::execute() { switch(header[pc++]) { case 0: err(); break; // ERROR case 1: ++a; break; // A++ case 2: --a; break; // A-- case 3: a = ~a; break; // A! case 4: a = 0; break; // A=0 case 7: a = r[header[pc++]]; break; // A=R N case 8: swap(b); break; // B<>A case 9: ++b; break; // B++ case 10: --b; break; // B-- case 11: b = ~b; break; // B! case 12: b = 0; break; // B=0 case 15: b = r[header[pc++]]; break; // B=R N case 16: swap(c); break; // C<>A case 17: ++c; break; // C++ case 18: --c; break; // C-- case 19: c = ~c; break; // C! case 20: c = 0; break; // C=0 case 23: c = r[header[pc++]]; break; // C=R N case 24: swap(d); break; // D<>A case 25: ++d; break; // D++ case 26: --d; break; // D-- case 27: d = ~d; break; // D! case 28: d = 0; break; // D=0 case 31: d = r[header[pc++]]; break; // D=R N case 32: swap(m(b)); break; // *B<>A case 33: ++m(b); break; // *B++ case 34: --m(b); break; // *B-- case 35: m(b) = ~m(b); break; // *B! case 36: m(b) = 0; break; // *B=0 case 39: if (f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JT N case 40: swap(m(c)); break; // *C<>A case 41: ++m(c); break; // *C++ case 42: --m(c); break; // *C-- case 43: m(c) = ~m(c); break; // *C! case 44: m(c) = 0; break; // *C=0 case 47: if (!f) pc+=((header[pc]+128)&255)-127; else ++pc; break; // JF N case 48: swap(h(d)); break; // *D<>A case 49: ++h(d); break; // *D++ case 50: --h(d); break; // *D-- case 51: h(d) = ~h(d); break; // *D! case 52: h(d) = 0; break; // *D=0 case 55: r[header[pc++]] = a; break; // R=A N case 56: return 0 ; // HALT case 57: outc(a&255); break; // OUT case 59: a = (a+m(b)+512)*773; break; // HASH case 60: h(d) = (h(d)+a+512)*773; break; // HASHD case 63: pc+=((header[pc]+128)&255)-127; break; // JMP N case 64: break; // A=A case 65: a = b; break; // A=B case 66: a = c; break; // A=C case 67: a = d; break; // A=D case 68: a = m(b); break; // A=*B case 69: a = m(c); break; // A=*C case 70: a = h(d); break; // A=*D case 71: a = header[pc++]; break; // A= N case 72: b = a; break; // B=A case 73: break; // B=B case 74: b = c; break; // B=C case 75: b = d; break; // B=D case 76: b = m(b); break; // B=*B case 77: b = m(c); break; // B=*C case 78: b = h(d); break; // B=*D case 79: b = header[pc++]; break; // B= N case 80: c = a; break; // C=A case 81: c = b; break; // C=B case 82: break; // C=C case 83: c = d; break; // C=D case 84: c = m(b); break; // C=*B case 85: c = m(c); break; // C=*C case 86: c = h(d); break; // C=*D case 87: c = header[pc++]; break; // C= N case 88: d = a; break; // D=A case 89: d = b; break; // D=B case 90: d = c; break; // D=C case 91: break; // D=D case 92: d = m(b); break; // D=*B case 93: d = m(c); break; // D=*C case 94: d = h(d); break; // D=*D case 95: d = header[pc++]; break; // D= N case 96: m(b) = a; break; // *B=A case 97: m(b) = b; break; // *B=B case 98: m(b) = c; break; // *B=C case 99: m(b) = d; break; // *B=D case 100: break; // *B=*B case 101: m(b) = m(c); break; // *B=*C case 102: m(b) = h(d); break; // *B=*D case 103: m(b) = header[pc++]; break; // *B= N case 104: m(c) = a; break; // *C=A case 105: m(c) = b; break; // *C=B case 106: m(c) = c; break; // *C=C case 107: m(c) = d; break; // *C=D case 108: m(c) = m(b); break; // *C=*B case 109: break; // *C=*C case 110: m(c) = h(d); break; // *C=*D case 111: m(c) = header[pc++]; break; // *C= N case 112: h(d) = a; break; // *D=A case 113: h(d) = b; break; // *D=B case 114: h(d) = c; break; // *D=C case 115: h(d) = d; break; // *D=D case 116: h(d) = m(b); break; // *D=*B case 117: h(d) = m(c); break; // *D=*C case 118: break; // *D=*D case 119: h(d) = header[pc++]; break; // *D= N case 128: a += a; break; // A+=A case 129: a += b; break; // A+=B case 130: a += c; break; // A+=C case 131: a += d; break; // A+=D case 132: a += m(b); break; // A+=*B case 133: a += m(c); break; // A+=*C case 134: a += h(d); break; // A+=*D case 135: a += header[pc++]; break; // A+= N case 136: a -= a; break; // A-=A case 137: a -= b; break; // A-=B case 138: a -= c; break; // A-=C case 139: a -= d; break; // A-=D case 140: a -= m(b); break; // A-=*B case 141: a -= m(c); break; // A-=*C case 142: a -= h(d); break; // A-=*D case 143: a -= header[pc++]; break; // A-= N case 144: a *= a; break; // A*=A case 145: a *= b; break; // A*=B case 146: a *= c; break; // A*=C case 147: a *= d; break; // A*=D case 148: a *= m(b); break; // A*=*B case 149: a *= m(c); break; // A*=*C case 150: a *= h(d); break; // A*=*D case 151: a *= header[pc++]; break; // A*= N case 152: unzdiv(a); break; // A/=A case 153: unzdiv(b); break; // A/=B case 154: unzdiv(c); break; // A/=C case 155: unzdiv(d); break; // A/=D case 156: unzdiv(m(b)); break; // A/=*B case 157: unzdiv(m(c)); break; // A/=*C case 158: unzdiv(h(d)); break; // A/=*D case 159: unzdiv(header[pc++]); break; // A/= N case 160: mod(a); break; // A%=A case 161: mod(b); break; // A%=B case 162: mod(c); break; // A%=C case 163: mod(d); break; // A%=D case 164: mod(m(b)); break; // A%=*B case 165: mod(m(c)); break; // A%=*C case 166: mod(h(d)); break; // A%=*D case 167: mod(header[pc++]); break; // A%= N case 168: a &= a; break; // A&=A case 169: a &= b; break; // A&=B case 170: a &= c; break; // A&=C case 171: a &= d; break; // A&=D case 172: a &= m(b); break; // A&=*B case 173: a &= m(c); break; // A&=*C case 174: a &= h(d); break; // A&=*D case 175: a &= header[pc++]; break; // A&= N case 176: a &= ~ a; break; // A&~A case 177: a &= ~ b; break; // A&~B case 178: a &= ~ c; break; // A&~C case 179: a &= ~ d; break; // A&~D case 180: a &= ~ m(b); break; // A&~*B case 181: a &= ~ m(c); break; // A&~*C case 182: a &= ~ h(d); break; // A&~*D case 183: a &= ~ header[pc++]; break; // A&~ N case 184: a |= a; break; // A|=A case 185: a |= b; break; // A|=B case 186: a |= c; break; // A|=C case 187: a |= d; break; // A|=D case 188: a |= m(b); break; // A|=*B case 189: a |= m(c); break; // A|=*C case 190: a |= h(d); break; // A|=*D case 191: a |= header[pc++]; break; // A|= N case 192: a ^= a; break; // A^=A case 193: a ^= b; break; // A^=B case 194: a ^= c; break; // A^=C case 195: a ^= d; break; // A^=D case 196: a ^= m(b); break; // A^=*B case 197: a ^= m(c); break; // A^=*C case 198: a ^= h(d); break; // A^=*D case 199: a ^= header[pc++]; break; // A^= N case 200: a <<= (a&31); break; // A<<=A case 201: a <<= (b&31); break; // A<<=B case 202: a <<= (c&31); break; // A<<=C case 203: a <<= (d&31); break; // A<<=D case 204: a <<= (m(b)&31); break; // A<<=*B case 205: a <<= (m(c)&31); break; // A<<=*C case 206: a <<= (h(d)&31); break; // A<<=*D case 207: a <<= (header[pc++]&31); break; // A<<= N case 208: a >>= (a&31); break; // A>>=A case 209: a >>= (b&31); break; // A>>=B case 210: a >>= (c&31); break; // A>>=C case 211: a >>= (d&31); break; // A>>=D case 212: a >>= (m(b)&31); break; // A>>=*B case 213: a >>= (m(c)&31); break; // A>>=*C case 214: a >>= (h(d)&31); break; // A>>=*D case 215: a >>= (header[pc++]&31); break; // A>>= N case 216: f = (true); break; // A==A f = (a == a) case 217: f = (a == b); break; // A==B case 218: f = (a == c); break; // A==C case 219: f = (a == d); break; // A==D case 220: f = (a == uint32_t(m(b))); break; // A==*B case 221: f = (a == uint32_t(m(c))); break; // A==*C case 222: f = (a == h(d)); break; // A==*D case 223: f = (a == uint32_t(header[pc++])); break; // A== N case 224: f = (false); break; // AA f= (a > a) case 233: f = (a > b); break; // A>B case 234: f = (a > c); break; // A>C case 235: f = (a > d); break; // A>D case 236: f = (a > uint32_t(m(b))); break; // A>*B case 237: f = (a > uint32_t(m(c))); break; // A>*C case 238: f = (a > h(d)); break; // A>*D case 239: f = (a > uint32_t(header[pc++])); break; // A> N case 255: if((pc=hbegin+header[pc]+256*header[pc+1])>=hend)err();break;//LJ default: err(); } return 1; } // Print illegal instruction error message and exit void unzZPAQL::err() { unzerror("unzZPAQL execution error"); } ///////////////////////// Component ////////////////////////// // A Component is a context model, indirect context model, match model, // fixed weight mixer, adaptive 2 input mixer without or with current // partial byte as context, adaptive m input mixer (without or with), // or SSE (without or with). struct unzComponent { uint32_t limit; // max count for cm uint32_t cxt; // saved context uint32_t a, b, c; // multi-purpose variables Array cm; // cm[cxt] -> p in bits 31..10, n in 9..0; MATCH index Array ht; // ICM/ISSE hash table[0..size1][0..15] and MATCH unzBuf Array a16; // MIX weights void init(); // initialize to all 0 unzComponent() {init();} }; void unzComponent::init() { limit=cxt=a=b=c=0; cm.resize(0); ht.resize(0); a16.resize(0); } ////////////////////////// StateTable //////////////////////// // Next state table generator class StateTable { enum {N=64}; // sizes of b, t int num_states(int n0, int n1); // compute t[n0][n1][1] void discount(int& n0); // set new value of n0 after 1 or n1 after 0 void next_state(int& n0, int& n1, int y); // new (n0,n1) after bit y public: uint8_t ns[1024]; // state*4 -> next state if 0, if 1, n0, n1 int next(int state, int y) { // next state for bit y assert(state>=0 && state<256); assert(y>=0 && y<4); return ns[state*4+y]; } int cminit(int state) { // initial probability of 1 * 2^23 assert(state>=0 && state<256); return ((ns[state*4+3]*2+1)<<22)/(ns[state*4+2]+ns[state*4+3]+1); } StateTable(); }; // How many states with count of n0 zeros, n1 ones (0...2) int StateTable::num_states(int n0, int n1) { const int B=6; const int bound[B]={20,48,15,8,6,5}; // n0 -> max n1, n1 -> max n0 if (n0=B || n0>bound[n1]) return 0; return 1+(n1>0 && n0+n1<=17); } // New value of count n0 if 1 is observed (and vice versa) void StateTable::discount(int& n0) { n0=(n0>=1)+(n0>=2)+(n0>=3)+(n0>=4)+(n0>=5)+(n0>=7)+(n0>=8); } // compute next n0,n1 (0 to N) given input y (0 or 1) void StateTable::next_state(int& n0, int& n1, int y) { if (n0 20,0 // 48,1,0 -> 48,1 // 15,2,0 -> 8,1 // 8,3,0 -> 6,2 // 8,3,1 -> 5,3 // 6,4,0 -> 5,3 // 5,5,0 -> 5,4 // 5,5,1 -> 4,5 while (!num_states(n0, n1)) { if (n1<2) --n0; else { n0=(n0*(n1-1)+(n1/2))/n1; --n1; } } } } // Initialize next state table ns[state*4] -> next if 0, next if 1, n0, n1 StateTable::StateTable() { // Assign states by increasing priority const int N=50; uint8_t t[N][N][2]={{{0}}}; // (n0,n1,y) -> state number int state=0; for (int i=0; i=0 && n<=2); if (n) { t[n0][n1][0]=state; t[n0][n1][1]=state+n-1; state+=n; } } } // Generate next state table memset(ns, 0, sizeof(ns)); for (int n0=0; n0=0 && s<256); int s0=n0, s1=n1; next_state(s0, s1, 0); assert(s0>=0 && s0=0 && s1=0 && s0=0 && s10 components? assert(z.header.isize()>6); return z.header[6]!=0; } private: // unzPredictor state int c8; // last 0...7 bits. int hmap4; // c8 split into nibbles int p[256]; // predictions uint32_t h[256]; // unrolled copy of z.h unzZPAQL& z; // VM to compute context hashes, includes H, n unzComponent comp[256]; // the model, includes P // Modeling support functions int dt2k[256]; // division table for match: dt2k[i] = 2^12/i int dt[1024]; // division table for cm: dt[i] = 2^16/(i+1.5) uint16_t squasht[4096]; // squash() lookup table short stretcht[32768];// stretch() lookup table StateTable st; // next, cminit functions // reduce prediction error in cr.cm void train(unzComponent& cr, int y) { assert(y==0 || y==1); uint32_t& pn=cr.cm(cr.cxt); uint32_t count=pn&0x3ff; int error=y*32767-(cr.cm(cr.cxt)>>17); pn+=(error*dt[count]&-1024)+(count floor(32768/(1+exp(-x/64))) int squash(int x) { assert(x>=-2048 && x<=2047); return squasht[x+2048]; } // x -> round(64*log((x+0.5)/(32767.5-x))), approx inverse of squash int stretch(int x) { assert(x>=0 && x<=32767); return stretcht[x]; } // bound x to a 12 bit signed int int clamp2k(int x) { if (x<-2048) return -2048; else if (x>2047) return 2047; else return x; } // bound x to a 20 bit signed int int clamp512k(int x) { if (x<-(1<<19)) return -(1<<19); else if (x>=(1<<19)) return (1<<19)-1; else return x; } // Get cxt in ht, creating a new row if needed size_t find(Array& ht, int sizebits, uint32_t cxt); }; // Initailize model-independent tables unzPredictor::unzPredictor(unzZPAQL& zr): c8(1), hmap4(1), z(zr) { assert(sizeof(uint8_t)==1); assert(sizeof(uint16_t)==2); assert(sizeof(uint32_t)==4); assert(sizeof(uint64_t)==8); assert(sizeof(short)==2); assert(sizeof(int)==4); // Initialize tables dt2k[0]=0; for (int i=1; i<256; ++i) dt2k[i]=2048/i; for (int i=0; i<1024; ++i) dt[i]=(1<<17)/(i*2+3)*2; for (int i=0; i<32768; ++i) stretcht[i]=int(custom_log((i+0.5)/(32767.5-i))*64+0.5+100000)-100000; for (int i=0; i<4096; ++i) squasht[i]=int(32768.0/(1+custom_exp((i-2048)*(-1.0/64)))); // Verify floating point math for squash() and stretch() uint32_t sqsum=0, stsum=0; for (int i=32767; i>=0; --i) stsum=stsum*3+stretch(i); for (int i=4095; i>=0; --i) sqsum=sqsum*3+squash(i-2048); assert(stsum==3887533746u); assert(sqsum==2278286169u); } // Initialize the predictor with a new model in z void unzPredictor::init() { // Initialize context hash function z.inith(); // Initialize predictions for (int i=0; i<256; ++i) h[i]=p[i]=0; // Initialize components for (int i=0; i<256; ++i) // clear old model comp[i].init(); int n=z.header[6]; // hsize[0..1] hh hm ph pm n (comp)[n] 0 0[128] (hcomp) 0 const uint8_t* cp=&z.header[7]; // start of component list for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); unzComponent& cr=comp[i]; switch(cp[0]) { case CONS: // c p[i]=(cp[1]-128)*4; break; case CM: // sizebits limit if (cp[1]>32) unzerror("max size for CM is 32"); cr.cm.resize(1, cp[1]); // packed CM (22 bits) + CMCOUNT (10 bits) cr.limit=cp[2]*4; for (size_t j=0; j26) unzerror("max size for ICM is 26"); cr.limit=1023; cr.cm.resize(256); cr.ht.resize(64, cp[1]); for (size_t j=0; j32 || cp[2]>32) unzerror("max size for MATCH is 32 32"); cr.cm.resize(1, cp[1]); // index cr.ht.resize(1, cp[2]); // unzBuf cr.ht(0)=1; break; case AVG: // j k wt if (cp[1]>=i) unzerror("AVG j >= i"); if (cp[2]>=i) unzerror("AVG k >= i"); break; case MIX2: // sizebits j k rate mask if (cp[1]>32) unzerror("max size for MIX2 is 32"); if (cp[3]>=i) unzerror("MIX2 k >= i"); if (cp[2]>=i) unzerror("MIX2 j >= i"); cr.c=(size_t(1)<32) unzerror("max size for MIX is 32"); if (cp[2]>=i) unzerror("MIX j >= i"); if (cp[3]<1 || cp[3]>i-cp[2]) unzerror("MIX m not in 1..i-j"); int m=cp[3]; // number of inputs assert(m>=1); cr.c=(size_t(1)<32) unzerror("max size for ISSE is 32"); if (cp[2]>=i) unzerror("ISSE j >= i"); cr.ht.resize(64, cp[1]); cr.cm.resize(512); for (int j=0; j<256; ++j) { cr.cm[j*2]=1<<15; cr.cm[j*2+1]=clamp512k(stretch(st.cminit(j)>>8)*1024); } break; case SSE: // sizebits j start limit if (cp[1]>32) unzerror("max size for SSE is 32"); if (cp[2]>=i) unzerror("SSE j >= i"); if (cp[3]>cp[4]*4) unzerror("SSE start > limit*4"); cr.cm.resize(32, cp[1]); cr.limit=cp[4]*4; for (size_t j=0; j0); cp+=compsize[*cp]; assert(cp>=&z.header[7] && cp<&z.header[z.cend]); } } // Return next bit prediction using interpreted COMP code int unzPredictor::predict() { assert(c8>=1 && c8<=255); // Predict next bit int n=z.header[6]; assert(n>0 && n<=255); const uint8_t* cp=&z.header[7]; ///assert(cp[-1]==n); for (int i=0; i&z.header[0] && cp<&z.header[z.header.isize()-8]); unzComponent& cr=comp[i]; switch(cp[0]) { case CONS: // c break; case CM: // sizebits limit cr.cxt=h[i]^hmap4; p[i]=stretch(cr.cm(cr.cxt)>>17); break; case ICM: // sizebits assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; p[i]=stretch(cr.cm(cr.cxt)>>8); break; case MATCH: // sizebits bufbits: a=len, b=offset, c=bit, cxt=bitpos, // ht=unzBuf, limit=pos assert(cr.cm.size()==(size_t(1)<>(7-cr.cxt))&1; // predicted bit p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767); } break; case AVG: // j k wt p[i]=(p[cp[1]]*cp[3]+p[cp[2]]*(256-cp[3]))>>8; break; case MIX2: { // sizebits j k rate mask // c=size cm=wt[size] cxt=input cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1)); assert(cr.cxt=0 && w<65536); p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16; assert(p[i]>=-2048 && p[i]<2048); } break; case MIX: { // sizebits j m rate mask // c=size cm=wt[size][m] cxt=index of wt in cm int m=cp[3]; assert(m>=1 && m<=i); cr.cxt=h[i]+(c8&cp[5]); cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights assert(cr.cxt<=cr.cm.size()-m); const int* wt=(int*)&cr.cm[cr.cxt]; p[i]=0; for (int j=0; j>8)*p[cp[2]+j]; p[i]=clamp2k(p[i]>>8); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert((hmap4&15)>0); if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8); cr.cxt=cr.ht[cr.c+(hmap4&15)]; // bit history const int *wt=(int*)&cr.cm[cr.cxt*2]; p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16); } break; case SSE: { // sizebits j start limit cr.cxt=(h[i]+c8)*32; int pq=p[cp[2]]+992; if (pq<0) pq=0; if (pq>1983) pq=1983; int wt=pq&63; pq>>=6; assert(pq>=0 && pq<=30); cr.cxt+=pq; p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt)+(cr.cm(cr.cxt+1)>>10)*wt) >>13); cr.cxt+=wt>>5; } break; default: unzerror("component predict not implemented"); } cp+=compsize[cp[0]]; assert(cp<&z.header[z.cend]); assert(p[i]>=-2048 && p[i]<2048); } assert(cp[0]==NONE); return squash(p[n-1]); } // Update model with decoded bit y (0...1) void unzPredictor::update(int y) { assert(y==0 || y==1); assert(c8>=1 && c8<=255); assert(hmap4>=1 && hmap4<=511); // Update components const uint8_t* cp=&z.header[7]; int n=z.header[6]; assert(n>=1 && n<=255); ///assert(cp[-1]==n); for (int i=0; i>8))>>2; } break; case MATCH: // sizebits bufbits: // a=len, b=offset, c=bit, cm=index, cxt=bitpos // ht=unzBuf, limit=pos { assert(cr.a<=255); assert(cr.c==0 || cr.c==1); assert(cr.cxt<8); assert(cr.cm.size()==(size_t(1)<>5; int w=cr.a16[cr.cxt]; w+=(err*(p[cp[2]]-p[cp[3]])+(1<<12))>>13; if (w<0) w=0; if (w>65535) w=65535; cr.a16[cr.cxt]=w; } break; case MIX: { // sizebits j m rate mask // cm=wt[size][m], cxt=input int m=cp[3]; assert(m>0 && m<=i); assert(cr.cm.size()==m*cr.c); assert(cr.cxt+m<=cr.cm.size()); int err=(y*32767-squash(p[i]))*cp[4]>>4; int* wt=(int*)&cr.cm[cr.cxt]; for (int j=0; j>13)); } break; case ISSE: { // sizebits j -- c=hi, cxt=bh assert(cr.cxt==uint32_t(cr.ht[cr.c+(hmap4&15)])); int err=y*32767-squash(p[i]); int *wt=(int*)&cr.cm[cr.cxt*2]; wt[0]=clamp512k(wt[0]+((err*p[cp[2]]+(1<<12))>>13)); wt[1]=clamp512k(wt[1]+((err+16)>>5)); cr.ht[cr.c+(hmap4&15)]=st.next(cr.cxt, y); } break; case SSE: // sizebits j start limit train(cr, y); break; default: assert(0); } cp+=compsize[cp[0]]; assert(cp>=&z.header[7] && cp<&z.header[z.cend] && cp<&z.header[z.header.isize()-8]); } assert(cp[0]==NONE); // Save bit y in c8, hmap4 c8+=c8+y; if (c8>=256) { z.run(c8-256); hmap4=1; c8=1; for (int i=0; i=16 && c8<32) hmap4=(hmap4&0xf)<<5|y<<4|1; else hmap4=(hmap4&0x1f0)|(((hmap4&0xf)*2+y)&0xf); } // Find cxt row in hash table ht. ht has rows of 16 indexed by the // low sizebits of cxt with element 0 having the next higher 8 bits for // collision detection. If not found after 3 adjacent tries, replace the // row with lowest element 1 as priority. Return index of row. size_t unzPredictor::find(Array& ht, int sizebits, uint32_t cxt) { assert(ht.size()==size_t(16)<>sizebits&255; size_t h0=(cxt*16)&(ht.size()-16); if (ht[h0]==chk) return h0; size_t h1=h0^16; if (ht[h1]==chk) return h1; size_t h2=h0^32; if (ht[h2]==chk) return h2; if (ht[h0+1]<=ht[h1+1] && ht[h0+1]<=ht[h2+1]) return memset(&ht[h0], 0, 16), ht[h0]=chk, h0; else if (ht[h1+1]=0 && p<65536); assert(high>low && low>0); if (currhigh) unzerror("archive corrupted"); assert(curr>=low && curr<=high); uint32_t mid=low+uint32_t(((high-low)*uint64_t(uint32_t(p)))>>16); // split range assert(high>mid && mid>=low); int y=curr<=mid; if (y) high=mid; else low=mid+1; // pick half while ((high^low)<0x1000000) { // shift out identical leading bytes high=high<<8|255; low=low<<8; low+=(low==0); int c=in->get(); if (c<0) unzerror("unexpected end of file"); curr=curr<<8|c; } return y; } // Decompress 1 byte or -1 at end of input int unzDecoder::decompress() { if (pr.isModeled()) { // n>0 components? if (curr==0) { // segment initialization for (int i=0; i<4; ++i) curr=curr<<8|in->get(); } if (decode(0)) { if (curr!=0) unzerror("decoding end of input"); return -1; } else { int c=1; while (c<256) { // get 8 bits int p=pr.predict()*2+1; c+=c+decode(p); pr.update(c&1); } return c-256; } } else { if (curr==0) { // segment initialization for (int i=0; i<4; ++i) curr=curr<<8|in->get(); if (curr==0) return -1; } assert(curr>0); --curr; return in->get(); } } /////////////////////////// unzPostProcessor //////////////////// class unzPostProcessor { int state; // input parse state: 0=INIT, 1=PASS, 2..4=loading, 5=POST int hsize; // header size int ph, pm; // sizes of H and M in z public: unzZPAQL z; // holds PCOMP unzPostProcessor(): state(0), hsize(0), ph(0), pm(0) {} void init(int h, int m); // ph, pm sizes of H and M int write(int c); // Input a byte, return state void setOutput(unzWriter* out) {z.output=out;} void setSHA1(unzSHA1* sha1ptr) {z.sha1=sha1ptr;} int getState() const {return state;} }; // Copy ph, pm from block header void unzPostProcessor::init(int h, int m) { state=hsize=0; ph=h; pm=m; z.clear(); } // (PASS=0 | PROG=1 psize[0..1] pcomp[0..psize-1]) data... EOB=-1 // Return state: 1=PASS, 2..4=loading PROG, 5=PROG loaded int unzPostProcessor::write(int c) { assert(c>=-1 && c<=255); switch (state) { case 0: // initial state if (c<0) unzerror("Unexpected EOS"); state=c+1; // 1=PASS, 2=PROG if (state>2) unzerror("unknown post processing type"); if (state==1) z.clear(); break; case 1: // PASS if (c>=0) z.outc(c); break; case 2: // PROG if (c<0) unzerror("Unexpected EOS"); hsize=c; // low byte of size state=3; break; case 3: // PROG psize[0] if (c<0) unzerror("Unexpected EOS"); hsize+=c*256; // high byte of psize if (hsize<1) unzerror("Empty PCOMP"); z.header.resize(hsize+300); z.cend=8; z.hbegin=z.hend=z.cend+128; z.header[4]=ph; z.header[5]=pm; state=4; break; case 4: // PROG psize[0..1] pcomp[0...] if (c<0) unzerror("Unexpected EOS"); assert(z.hend>8; z.initp(); state=5; } break; case 5: // PROG ... data z.run(c); break; } return state; } //////////////////////// unzDecompresser //////////////////////// // For decompression and listing archive contents class unzDecompresser { public: unzDecompresser(): z(), dec(z), pp(), state(BLOCK), decode_state(FIRSTSEG) {} void setInput(unzReader* in) {dec.in=in;} bool findBlock(); bool findFilename(unzWriter* = 0); void readComment(unzWriter* = 0); void setOutput(unzWriter* out) {pp.setOutput(out);} void setSHA1(unzSHA1* sha1ptr) {pp.setSHA1(sha1ptr);} void decompress(); // decompress segment void readSegmentEnd(char* sha1string = 0); private: unzZPAQL z; unzDecoder dec; unzPostProcessor pp; enum {BLOCK, FILENAME, COMMENT, DATA, SEGEND} state; // expected next enum {FIRSTSEG, SEG} decode_state; // which segment in block? }; // Find the start of a block and return true if found. Set memptr // to memory used. bool unzDecompresser::findBlock() { assert(state==BLOCK); // Find start of block uint32_t h1=0x3D49B113, h2=0x29EB7F93, h3=0x2614BE13, h4=0x3828EB13; // Rolling hashes initialized to hash of first 13 bytes int c; while ((c=dec.in->get())!=-1) { h1=h1*12+c; h2=h2*20+c; h3=h3*28+c; h4=h4*44+c; if (h1==0xB16B88F1 && h2==0xFF5376F1 && h3==0x72AC5BF1 && h4==0x2F909AF1) break; // hash of 16 byte string } if (c==-1) return false; // Read header if ((c=dec.in->get())!=1 && c!=2) unzerror("unsupported ZPAQ level"); if (dec.in->get()!=1) unzerror("unsupported unzZPAQL type"); z.read(dec.in); if (c==1 && z.header.isize()>6 && z.header[6]==0) unzerror("ZPAQ level 1 requires at least 1 component"); state=FILENAME; decode_state=FIRSTSEG; return true; } // Read the start of a segment (1) or end of block code (255). // If a segment is found, write the filename and return true, else false. bool unzDecompresser::findFilename(unzWriter* filename) { assert(state==FILENAME); int c=dec.in->get(); if (c==1) { // segment found while (true) { c=dec.in->get(); if (c==-1) unzerror("unexpected EOF"); if (c==0) { state=COMMENT; return true; } if (filename) filename->put(c); } } else if (c==255) { // end of block found state=BLOCK; return false; } else unzerror("missing segment or end of block"); return false; } // Read the comment from the segment header void unzDecompresser::readComment(unzWriter* comment) { assert(state==COMMENT); state=DATA; while (true) { int c=dec.in->get(); if (c==-1) unzerror("unexpected EOF"); if (c==0) break; if (comment) comment->put(c); } if (dec.in->get()!=0) unzerror("missing reserved byte"); } // Decompress n bytes, or all if n < 0. Return false if done void unzDecompresser::decompress() { assert(state==DATA); // Initialize models to start decompressing block if (decode_state==FIRSTSEG) { dec.init(); assert(z.header.size()>5); pp.init(z.header[4], z.header[5]); decode_state=SEG; } // Decompress and load PCOMP into postprocessor while ((pp.getState()&3)!=1) pp.write(dec.decompress()); // Decompress n bytes, or all if n < 0 while (true) { int c=dec.decompress(); pp.write(c); if (c==-1) { state=SEGEND; return; } } } // Read end of block. If a unzSHA1 checksum is present, write 1 and the // 20 byte checksum into sha1string, else write 0 in first byte. // If sha1string is 0 then discard it. void unzDecompresser::readSegmentEnd(char* sha1string) { assert(state==SEGEND); // Read checksum int c=dec.in->get(); if (c==254) { if (sha1string) sha1string[0]=0; // no checksum } else if (c==253) { if (sha1string) sha1string[0]=1; for (int i=1; i<=20; ++i) { c=dec.in->get(); if (sha1string) sha1string[i]=c; } } else unzerror("missing end of segment marker"); state=FILENAME; } ///////////////////////// Driver program //////////////////// uint64_t unzoffset=0; // number of bytes input prior to current block // Handle errors void unzerror(const char* msg) { myprintf("\n"); myprintf("00424: Error at offset %1.0f: %s\n", double(unzoffset), msg); exit(1); } // Input archive class unzInputFile: public unzReader { FILE* f; // input file enum {BUFSIZE=4096}; uint64_t offset; // number of bytes read unsigned p, end; // start and end of unread bytes in unzBuf unzAES_CTR* aes; // to decrypt char unzBuf[BUFSIZE]; // input buffer int64_t filesize; public: unzInputFile(): f(0), offset(0), p(0), end(0), aes(0),filesize(-1) {} void open(const char* filename, const char* key); // Return one input byte or -1 for EOF int get() { if (f && p>=end) { p=0; end=fread(unzBuf, 1, BUFSIZE, f); if (aes) aes->encrypt(unzBuf, end, offset); } if (p>=end) return -1; ++offset; return unzBuf[p++]&255; } // Return number of bytes read uint64_t tell() {return offset;} int64_t getfilesize() {return filesize;} }; // Open input. Decrypt with key. void unzInputFile::open(const char* filename, const char* key) { f=fopen(filename, "rb"); if (!f) { perror(filename); return ; } fseeko(f, 0, SEEK_END); filesize=ftello(f); fseeko(f, 0, SEEK_SET); if (key) { char salt[32], stretched_key[32]; unzSHA256 sha256; for (int i=0; i<32; ++i) salt[i]=get(); if (offset!=32) unzerror("no salt"); while (*key) sha256.put(*key++); stretchKey(stretched_key, sha256.result(), salt); aes=new unzAES_CTR(stretched_key, 32, salt); g_allocatedram+=sizeof(unzAES_CTR); if (!aes) unzerror("out of memory"); aes->encrypt(unzBuf, end, 0); } } // File to extract class unzOutputFile: public unzWriter { FILE* f; // output file or NULL unsigned p; // number of pending bytes to write enum {BUFSIZE=4096}; char unzBuf[BUFSIZE]; // output buffer public: unzOutputFile(): f(0), p(0) {} void open(const char* filename); void close(); // write 1 byte void put(int c) { if (f) { unzBuf[p++]=c; if (p==BUFSIZE) fwrite(unzBuf, 1, p, f), p=0; } } virtual ~unzOutputFile() {close();} }; // Open file unless it exists. Print error message if unsuccessful. void unzOutputFile::open(const char* filename) { close(); f=fopen(filename, "rb"); if (f) { fclose(f); f=0; myprintf("00425: file exists: %s\n", filename); } f=fopen(filename, "wb"); if (!f) perror(filename); } // Flush output and close file void unzOutputFile::close() { if (f && p>0) fwrite(unzBuf, 1, p, f); if (f) fclose(f), f=0; p=0; } // Write to string struct unzBuf: public unzWriter { size_t limit; // maximum size std::string s; // saved output unzBuf(size_t l): limit(l) {} // Save c in s void put(int c) { if (s.size()>=limit) unzerror("output overflow"); s+=char(c); } }; // Test if 14 digit date is valid YYYYMMDDHHMMSS format void verify_date(uint64_t date) { int year=date/1000000/10000; int month=date/100000000%100; int day=date/1000000%100; int hour=date/10000%100; int min=date/100%100; int sec=date%100; if (year<1900 || year>2999 || month<1 || month>12 || day<1 || day>31 || hour<0 || hour>59 || min<0 || min>59 || sec<0 || sec>59) { myprintf("\n\n"); myprintf("00426: date %s\n",migliaia(date)); myprintf("00427: year %d\n",year); myprintf("00428: month %d\n",month); myprintf("00429: day %d\n",day); myprintf("00430: hour %d\n",hour); myprintf("00431: min %d\n",min); myprintf("00432: sec %d\n",day); /// unzerror("invalid date"); } } // Test if string is valid UTF8 void unzverify_utf8(const char* s) { while (true) { int c=uint8_t(*s); if (c==0) return; if ((c>=128 && c<194) || c>=245) unzerror("invalid UTF-8 first byte"); int len=1+(c>=192)+(c>=224)+(c>=240); for (int i=1; i ptr; // fragment IDs char sha1hex[FRANZOFFSETV3+1]; // 1+32+32 (unzSHA256)+ zero char sha1decompressedhex[FRANZOFFSETV3+1]; // 1+32+32 (unzSHA256)+ zero std::string sha1fromfile; // 1+32+32 (unzSHA256)+ zero unzDT(): date(0), attr(0),sha1fromfile("") {sha1hex[0]=0x0;sha1decompressedhex[0]=0x0;} }; typedef std::map unzDTMap; bool unzcomparesha1hex(unzDTMap::iterator i_primo, unzDTMap::iterator i_secondo) { return (strcmp(i_primo->second.sha1hex,i_secondo->second.sha1hex)<0); } bool unzcompareprimo(unzDTMap::iterator i_primo, unzDTMap::iterator i_secondo) { return (i_primo->firstfirst); } ///////// end of patched unzpaq206.cpp /* franzo section */ void hex2binary(const std::string& i_hexstr, char* i_bytearray,const unsigned int i_arraysize) { if (i_bytearray==NULL) { myprintf("00433: GURU: i_bytearray null\n"); seppuku(); } if (i_arraysize==0) { myprintf("00434: GURU: i_arraysize zero\n"); seppuku(); } size_t length = i_hexstr.length(); if (length==0) { myprintf("00435: GURU: i_hexstr empty!\n"); seppuku(); } if (length%2!=0) { myprintf("00436: GURU: i_hexstr length not even!\n"); seppuku(); } if ((length/2)!=i_arraysize) { myprintf("00437: GURU: length/2 %s must be i_arraysize %s!\n",migliaia(length/2),migliaia2(i_arraysize)); seppuku(); } for (size_t i=0;isecond.hashname; int hashlen =p->second.hashlen; if (flagdebug2) myprintf("00445: expectedfranzotype %d => |%-15s| len %03d\n",expectedfranzotype,hashname.c_str(),hashlen); risultato =expectedfranzotype; o_hashtype =hashname; o_hashvalue =i_franz_block+2; int offsetcrc= 2+hashlen+2; if (i_isdirectory) o_crc32value=" "; else o_crc32value=i_franz_block+offsetcrc; o_isordered=arraytoint32(i_franz_block+offsetcrc+8+2); if (flagdebug2) myprintf("00446: Ordered stream %08d\n",o_isordered); o_version=arraytoint32(i_franz_block+offsetcrc+8+2+4); if (flagdebug2) myprintf("00447: Version number %08d\n",o_version); o_creationtime =arraytoint64(i_franz_block+offsetcrc+8+2+4+4); o_accesstime =arraytoint64(i_franz_block+offsetcrc+8+2+4+4+8); if (flagdebug2) { myprintf("00448: cdate %s\n",migliaia(o_creationtime)); myprintf("00449: adate %s\n",migliaia(o_accesstime)); } if (!onlyheader) { int64_t offsetposix=offsetcrc+8+2+4+4+8+(8*4); // 8*4= future expansion if (flagdebug2) myprintf("00450: Taking posix too @ offset position %08d\n",offsetposix); ///o_posix=(franz_posix*) (i_franz_block+offsetposix); } } ///myprintf("00451: Risultato %s\n",o_crc32value.c_str()); return risultato; } ///https://gist.github.com/0x3f00/90edbec0c04616d0b8c21586762bf1ac static std::string base64encode(const std::string& data) { static char sEncodingTable[] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; size_t in_len = data.size(); if (in_len == 0) return ""; size_t out_len = 4 * ((in_len + 2) / 3); std::string ret(out_len, '\0'); size_t i; char *p = const_cast(ret.c_str()); if (in_len == 1) { ret[0] = sEncodingTable[(data[0] >> 2) & 0x3F]; ret[1] = sEncodingTable[((data[0] & 0x3) << 4)]; ret[2] = '='; ret[3] = '='; return ret; } if (in_len == 2) { ret[0] = sEncodingTable[(data[0] >> 2) & 0x3F]; ret[1] = sEncodingTable[((data[0] & 0x3) << 4) | ((int)(data[1] & 0xF0) >> 4)]; ret[2] = sEncodingTable[((data[1] & 0xF) << 2)]; ret[3] = '='; return ret; } for (i = 0; i < in_len - 2; i += 3) { *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)]; *p++ = sEncodingTable[data[i + 2] & 0x3F]; } if (i < in_len) { *p++ = sEncodingTable[(data[i] >> 2) & 0x3F]; if (i == (in_len - 1)) { *p++ = sEncodingTable[((data[i] & 0x3) << 4)]; *p++ = '='; } else { *p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)]; *p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)]; } *p++ = '='; } return ret; } string Jidac::sanitizzanomefile(string i_filename,int i_filelength,int& io_collisioni,MAPPAFILEHASH& io_mappacollisioni) { if (i_filename=="") return(""); #ifdef _WIN32 if (flagfixreserved) { const std::string caratteriNonValidi = "\\:*?\"<>|"; for (char& c:i_filename) if (caratteriNonValidi.find(c)!=std::string::npos) c = '_'; } #endif // corresponds to #ifdef (#ifdef _WIN32) string percorso =extractfilepath(i_filename); string nome =prendinomefileebasta(i_filename); string estensione =prendiestensione(i_filename); string senzaestensione =percorso+nome; string newname; int lunghezza=FRANZMAXPATH; if (i_filelength>0) if (i_filelengthsecond.franz_block, myhashtype, myhash, mycrc32, mycreationtime, myaccesstime, myisordered, myversion, myposix, myisadded); if (myhashtype!="") if (myhash!="") { p->second.hexhash=myhash; myhash=myhash.substr(0, 10); newname+="$"+myhashtype+"!"+myhash+"%"; p->second.hashtype=myhashtype; } } else myprintf("00452: not found %s\n",i_filename.c_str()); if (flagdebug3) myprintf("00453: paranoid filename <<%s>>\n",newname.c_str()); return newname; } if (flagflat) /// desperate extract without path and filenames { /// Stay safe string temp=purgeansi(nome.substr(0, 20)); temp=base64encode(temp); snprintf(numero,sizeof(numero),"%08d_%05d_",++io_collisioni,(int)i_filename.length()); newname=numero; newname.append(temp.c_str()); /// retain extension, BUT purge Windows reserved words estensione=purgeansi(estensione); for (unsigned int j=0;j3) estensione=myleft(estensione,3); if (estensione!="") newname+="."+estensione; if (flagdebug3) myprintf("00454: flatted filename <<%s>>\n",newname.c_str()); return newname; } if (flagutf) { string prenome=nome; // this is name, throw everything (FALSE) nome=purgeansi(forcelatinansi(utf8toansi(nome)),false); if (flagdebug3) if (nome!=prenome) { printbar('-'); myprintf("00455: flagutf pre %s\n",prenome.c_str()); myprintf("00456: utf8toansi %s\n",utf8toansi(nome).c_str()); myprintf("00457: force2ansi %s\n",forcelatinansi(utf8toansi(nome)).c_str()); myprintf("00458: purgeansi %s\n",nome.c_str()); } if (flagfixeml) { if (estensione=="eml") { prenome=compressemlfilename(nome); if (nome!=prenome) { if (flagdebug3) { myprintf("00459: eml pre %s\n",nome.c_str()); myprintf("00460: eml post %s\n",prenome.c_str()); } nome=prenome; } } else { for (int i=0;i<10;i++) myreplaceall(newname," "," "); } } /// this is a path, so keep \ and / (TRUE) string prepercorso=percorso; percorso=purgeansi(forcelatinansi(utf8toansi(percorso)),true); if (flagdebug3) if (percorso!=prepercorso) { myprintf("00461: flagutf pre perc %s\n",prepercorso.c_str()); myprintf("00462: flagutf post perc %s\n",percorso.c_str()); } } if (flagdebug3) { myprintf("00463: First %03d %s\n",(int)i_filename.length(),i_filename.c_str()); myprintf("00464: Percorso %03d %s\n",(int)percorso.length(),percorso.c_str()); myprintf("00465: nome %03d %s\n",(int)nome.length(),nome.c_str()); myprintf("00466: ext %03d %s\n",(int)estensione.length(),estensione.c_str()); myprintf("00467: Senza ex %03d %s\n",(int)senzaestensione.length(),senzaestensione.c_str()); } if (flagfix255) { int lunghezzalibera=lunghezza-percorso.length();//%08d_ if (lunghezzalibera<10) { if (flagdebug3) { myprintf("\n\n\n"); myprintf("00468: Path too long: need shrink %08d %s\n",(int)percorso.length(),percorso.c_str()); myprintf("00469: lunghezzalibera %d\n",lunghezzalibera); } vector esploso; string temppercorso=percorso; size_t barra; while (1) { if (flagdebug3) myprintf("00470: temppercorso %s\n",temppercorso.c_str()); barra=temppercorso.find('/'); if (flagdebug3) myprintf("00471: Barra %ld\n",(long int)barra); if (barra==string::npos) break; if (flagdebug3) myprintf("00472: Eureka!!\n"); esploso.push_back(temppercorso.substr(0, barra)); temppercorso=temppercorso.substr(barra+1,temppercorso.length()); } int lunghezzamassima=0; int indicelunghezzamassima=-1; for (unsigned int i=0;ilunghezzamassima) { indicelunghezzamassima=i; lunghezzamassima=esploso[i].length(); } if (flagdebug3) myprintf("00473: Esploso %d %03d %s\n",(int)i,(int)esploso[i].length(),esploso[i].c_str()); } int lunghezzacheserve=lunghezza-10-(percorso.length()-lunghezzamassima); if (lunghezzacheserve(unsigned int)lunghezzalibera) { newname=newname.substr(0,lunghezzalibera-9); if (flagdebug3) myprintf("00477: Trimmone newname %d %s\n",(int)newname.length(),newname.c_str()); } newname=percorso+newname; if (flagdebug2) myprintf("00478: %d: newname %s\n",__LINE__,newname.c_str()); std::map::iterator collisione; string candidato=newname; if (estensione!="") candidato=candidato+'.'+estensione; // to be reworked by much faster sorted array if (flagfix255) /// we are on windows, take care of case { candidato=stringtolower(candidato); } if (flagdebug2) myprintf("00479: candidato %s\n",candidato.c_str()); collisione=io_mappacollisioni.find(candidato); if (collisione!=io_mappacollisioni.end()) { if (flagdebug2) myprintf("00480: found 1 %s\n",candidato.c_str()); if (collisione->second!=candidato) { if (flagdebug3) { myprintf("00481: Collisione %s\n",collisione->second.c_str()); myprintf("00482: newname %s\n",collisione->second.c_str()); } snprintf(numero,sizeof(numero),"_%d",io_collisioni++); newname+=numero; if (flagdebug2) myprintf("00483: postname %s\n\n\n\n\n",newname.c_str()); } } io_mappacollisioni.insert(std::pair(candidato,i_filename)); if (estensione!="") newname+="."+estensione; if (flagdebug3) myprintf("00484: Finalized %d %s\n",(int)newname.length(),newname.c_str()); if (flagdebug3) if (newname.length()>255) { myprintf("00485: WARN pre %08d %s\n",(int)i_filename.length(),i_filename.c_str()); myprintf("00486: WARN post %08d %s\n",(int)newname.length(),newname.c_str()); myprintf("\n"); } return newname; } /* section: progress */ // beware STATIC not good for M/T void print_progress(int64_t ts, int64_t td,int64_t i_scritti,int i_percentuale) { static int ultimapercentuale=0; static int ultimaeta=0; if (flagnoeta==true) return; if (td>ts) td=ts; if (td<1000000) return; double eta=0.001*(mtime()-g_start)*(ts-td)/(td+1.0); int secondi=(mtime()-g_start)/1000; if (secondi==0) secondi=1; int percentuale=int(td*100.0/(ts+0.5)); if (flagpakka) { if (eta<350000) if (((percentuale%10)==0) ||(percentuale==1)) if ((percentuale!=ultimapercentuale) || (percentuale==1)) { ultimapercentuale=percentuale; myprintf("%03d%% %02d:%02d:%02d %20s of %20s %s/s\r", percentuale, int(eta/3600), int(eta/60)%60, int(eta)%60, migliaia(td), migliaia2(ts),migliaia3(td/secondi)); } } else { if (int(eta)!=ultimaeta) if (eta<350000) { ultimaeta=int(eta); int64_t projection=ts; if ((command=='a') || (command=='Z')) if (ts>0) projection=(int64_t)(i_scritti/(1.0*td/ts)); if (i_percentuale>0) myprintf("(%03d%%) %6.2f%% %02d:%02d:%02d (%10s)->(%10s)=>(%10s) %10s/s\r", i_percentuale,td*100.0/(ts+0.5),int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(td),tohuman2(i_scritti),tohuman3(projection),tohuman4(td/secondi)); else { if (i_scritti>0) myprintf(" %6.2f%% %02d:%02d:%02d (%10s)->(%10s)=>(%10s) %10s/s\r", td*100.0/(ts+0.5), int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(td),tohuman2(i_scritti),tohuman3(projection),tohuman4(td/secondi)); else myprintf(" %6.2f%% %02d:%02d:%02d (%10s)=>(%10s) %10s/s\r", td*100.0/(ts+0.5), int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(td),tohuman2(projection),tohuman3(td/secondi)); } } } } /// work with a batch job void avanzamento(int64_t i_lavorati,int64_t i_totali,int64_t i_inizio) { static int ultimapercentuale=0; if (flagnoeta==true) return; int percentuale=int(i_lavorati*100.0/(i_totali+0.5)); if (percentuale>0) if (((percentuale%10)==0) || (percentuale==1)) //if ((((percentuale%10)==0) && (percentuale>0)) || (percentuale==1)) if (percentuale!=ultimapercentuale) { ultimapercentuale=percentuale; double eta=0.001*(mtime()-i_inizio)*(i_totali-i_lavorati)/(i_lavorati+1.0); int secondi=(mtime()-i_inizio)/1000; if (secondi==0) secondi=1; if (eta<356000) myprintf("%03d%% %02d:%02d:%02d (%10s) of (%10s) %20s /s\n", percentuale, int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(i_lavorati), tohuman2(i_totali),migliaia3(i_lavorati/secondi)); fflush(stdout); } } bool myavanzamento(int64_t i_lavorati,int64_t i_totali,int64_t i_inizio,bool i_barran=true) { bool hostampato=false; static int ultimapercentuale=0; int percentuale=int(i_lavorati*100.0/(i_totali+0.5)); if (percentuale>100) percentuale=100; if (((percentuale%5)==0) && (percentuale>0)) if (percentuale!=ultimapercentuale) { ultimapercentuale=percentuale; double eta=0.001*(mtime()-i_inizio)*(i_totali-i_lavorati)/(i_lavorati+1.0); int secondi=(mtime()-i_inizio)/1000; if (secondi==0) secondi=1; if (eta<356000) { myprintf("%03d%% %02d:%02d:%02d (%10s) of (%10s) %20s/s", percentuale, int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman(i_lavorati), tohuman2(i_totali),migliaia3(i_lavorati/secondi)); if (i_barran) myprintf("\n"); else myprintf("\r"); hostampato=true; } fflush(stdout); } return hostampato; } /// sorting functions // Return psecond.size!=q->second.size) return p->second.size>q->second.size; if (p->second.ptrsecond.ptr) return true; if (q->second.ptrsecond.ptr) return false; if (p->second.data!=q->second.data) return p->second.datasecond.data; return p->firstfirst; } // Sort by sortkey, then by full path bool compareFilename(DTMap::iterator ap, DTMap::iterator bp) { if (ap->second.data!=bp->second.data) return ap->second.datasecond.data; return ap->firstfirst; } bool comparedatethenfilename(DTMap::iterator ap, DTMap::iterator bp) { if (ap->second.date!=bp->second.date) return ap->second.datesecond.date; return ap->firstfirst; } /* bool comparesizethenfilename(DTMap::iterator ap, DTMap::iterator bp) { if (ap->second.size!=bp->second.size) return ap->second.sizesecond.size; return ap->firstfirst; } bool compareredavgthenfilename(DTMap::iterator ap, DTMap::iterator bp) { if (ap->second.is4 && bp->second.is4) { int avgap=0; if (ap->second.red_count>0) avgap=ap->second.red_total/ap->second.red_count; int avgbp=0; if (bp->second.red_count>0) avgbp=bp->second.red_total/bp->second.red_count; if (avgap!=avgbp) return avgapfirstfirst; } */ bool compareredallavgthenfilename(DTMap::iterator ap, DTMap::iterator bp) { if (ap->second.red_avg!=bp->second.red_avg) return ap->second.red_avgsecond.red_avg; return ap->firstfirst; } bool compareorderby(DTMap::iterator a, DTMap::iterator b) { // Se orderby è vuoto, non ordina if (orderby.empty()) return false; // Popola g_theorderby una sola volta se necessario if (g_theorderby.empty()) { g_theorderby.clear(); std::string temp_orderby = orderby; if (!temp_orderby.empty() && temp_orderby[temp_orderby.length() - 1] != ';') temp_orderby += ';'; explode(temp_orderby, ';', g_theorderby); } // Confronta i campi in base ai criteri in g_theorderby con ciclo esplicito for (size_t i = 0; i < g_theorderby.size(); ++i) { const std::string& criterio = g_theorderby[i]; if (criterio.empty()) continue; // Confronto per ogni criterio if (criterio == "ext") { std::string a_ext = prendiestensione(a->first); std::string b_ext = prendiestensione(b->first); if (a_ext != b_ext) return flagdesc ? (a_ext > b_ext) : (a_ext < b_ext); } else if (criterio == "name") { std::string a_name = prendinomefileebasta(a->first); std::string b_name = prendinomefileebasta(b->first); if (a_name != b_name) return flagdesc ? (a_name > b_name) : (a_name < b_name); } else if ((criterio == "full") || (criterio == "fullname")) { if (a->first != b->first) return flagdesc ? (a->first > b->first) : (a->first < b->first); } else if (criterio == "hash") ///nonva { if (a->second.hexhash != b->second.hexhash) return flagdesc ? (a->second.hexhash > b->second.hexhash) : (a->second.hexhash < b->second.hexhash); } else if (criterio == "size") { if (a->second.size != b->second.size) return flagdesc ? (a->second.size > b->second.size) : (a->second.size < b->second.size); } else if (criterio == "attr") { if (a->second.attr != b->second.attr) return flagdesc ? (a->second.attr > b->second.attr) : (a->second.attr < b->second.attr); } else if (criterio == "date") { if (a->second.date != b->second.date) return flagdesc ? (a->second.date > b->second.date) : (a->second.date < b->second.date); } else if (criterio == "creation") { if (a->second.creationdate != b->second.creationdate) return flagdesc ? (a->second.creationdate > b->second.creationdate) : (a->second.creationdate < b->second.creationdate); } else if (criterio == "access") { if (a->second.accessdate != b->second.accessdate) return flagdesc ? (a->second.accessdate > b->second.accessdate) : (a->second.accessdate < b->second.accessdate); } else if (criterio == "data") { if (a->second.data != b->second.data) return flagdesc ? (a->second.data > b->second.data) : (a->second.data < b->second.data); } } // Criterio di spareggio: nome completo del file return flagdesc ? (a->first > b->first) : (a->first < b->first); } /* Section: help */ void help_range() { moreprint("+ : -range X:Y Range versions [X-Y]"); moreprint("+ : -range X: Range versions [X-THE LAST]"); moreprint("+ : -range :X Range versions [1-X]"); moreprint("+ : -range X Range is single version X"); moreprint("+ : -range ::X Last X versions"); } void help_date() { moreprint("+ : -datefrom X datetime<=X The length must be even, beware of leading zeros"); moreprint("+ : -dateto Y datetime>=Y OK 2022, 202210, 2022-12-25, 2002-12-25_03:04:05, 20121225030405"); } void help_size() { moreprint("+ : -maxsize X Filter on filesize. Use K, M, G, T and KB,MB,GB,TB"); moreprint("+ : -minsize Y ex. 3000000, 3.000.000, 3000K, 3.2KB, 3M, 3MB, 2G, 3GB, 2TB, 3T"); } void help_orderby() { moreprint("+ : -orderby x Sort files by (one or more of) ext;name;full;fullname;hash;size;\n"); moreprint("+ : attr;date;creation;access;\n"); moreprint("+ : -desc Descending sort (if -orderby)"); } void help_printhash(bool i_flagadd) { char linea[200]; for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (p->second.flagiszpaq) { snprintf(linea,sizeof(linea),"+ : %-13s %s",p->second.switchname.c_str(),p->second.hashdescription.c_str()); moreprint(linea); } if (!i_flagadd) { for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (!p->second.flagiszpaq) { snprintf(linea,sizeof(linea),"+ : %-13s %s",p->second.switchname.c_str(),p->second.hashdescription.c_str()); moreprint(linea); } } } void help_printhashline(bool i_flagadd) { string risultato="+ : "; for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (p->second.flagiszpaq) risultato+=p->second.switchname+" "; moreprint(risultato.c_str()); if (!i_flagadd) { risultato="+ : "; for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (!p->second.flagiszpaq) risultato+=p->second.switchname+" "; moreprint(risultato.c_str()); } } string help_b(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD b (benchmark and CPU stresser)"); moreprint("<>: Rough benchmarking of hash-checksum"); moreprint("<>: franzomips (fake index) showed if no switch selected"); moreprint("<>: By default test ALL for 5 seconds with 400.000 bytes"); moreprint("<>: NOTE: THIS IS THE MAXIMUM PERFORMANCES, not the real one!"); moreprint("<>: -debug Do internal check (for non-Intel CPU)"); moreprint("<>: -verbose Verbose output"); moreprint("<>: -n X Set time limit to X s (<1000)"); moreprint("<>: -minsize Y Run on chunks of Y bytes (<2000000000)"); help_printhash(false); moreprint("+ : -all Multithread run (CPU cooker)"); moreprint("+ : -tX With -all limit to X threads"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Benchmark all: b"); moreprint("Benchmark all on 1.86GB: b -minsize 2000000000"); moreprint("Benchmark all on 1MB: b -minsize 1048576"); moreprint("Benchmark SHA256 and BLAKE3: b -sha256 -blake 3 -minsize 1048576"); moreprint("Benchmark for 10 second each: b -n 10 -sha256 -blake3 -minsize 1048576"); moreprint("CPU heater (cook the CPU) b -all -n 10000"); moreprint("Cook the CPU (all cores): b -all -n 20 -blake3"); moreprint("Cook the CPU (8 cores): b -all -t8 -n 20 -blake3"); } return "CPU benchmark, speed index in (yes!) franzomips"; } string help_autotest(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD autotest (autotest)"); moreprint("<>: Operational self-test on this system"); moreprint("<>: -all Heavy test (all hashes)"); moreprint("<>: -n X On heavy test (-all) use X size (min: 200.000,default 1.000.000)"); moreprint("<>: -n X On light test (not -all) use X ASCII chars"); moreprint("<>: -verbose Verbose output"); moreprint("<>: -to d0 Create (into folder d0) a dotest.sh/bat script)"); moreprint("<>: -checktxt X Test outYY.txt files inside X folder"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Hashing internal test 'ABCD' autotest"); moreprint("Hashing internal test 'ABCDEFGHIJ' autotest -n 10"); moreprint("Hashing internal test autotest -all"); #if defined(HWSHA1) || defined(HWSHA2) moreprint("Hashing internal test autotest -hw"); #endif // corresponds to #if (#if defined(HWSHA1) || defined(HWSHA2)) moreprint("Prepare a z:\\pippo\\dotest.bat autotest -all -verbose -to z:\\pippo"); moreprint("Check output results autotest -checktxt z:\\ugo"); } return "Check for hidden errors after compiling from source"; } string help_isopen(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD isopen()"); moreprint("<>: Check if a file is open (and execute some kind of script)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Check some thunderbird running isopen c:\\pippo\\INBOX -exec_ok killthunderbird.bat"); } return("Check if a file is open (by other software)"); } string help_versum(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD versum (hashdeep-like double check)"); moreprint("+ : Double-check for 'remote' restore (ex. Unix => Win)"); moreprint("+ : Heterogeneous restore can be tricky"); moreprint("+ : -ssd Multithread (for SSDs, do NOT use on spinning drives)"); moreprint("+ : -find Change the source (original) to the destination (extracted)"); moreprint("+ : -replace folder (if different)"); moreprint("+ : -to file.zpaq Test against hashes stored in .zpaq (MUST match algo type!)"); moreprint("+ : aka: do NOT compare sha3 hashes with xxhash64 or something !="); moreprint("+ : -hashdeep Use hashdeep format for the input file (DEFAULT: zpaqfranz)"); moreprint("+ : -checktxt Test against .md5 / _md5.txt file (w/wildcards)"); moreprint("+ : -fasttxt Test against _crc32.txt file (w/wildcards)"); moreprint("+ : -fasttxt -quick Test QUICK against _crc32.txt file (w/wildcards)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Educational purpose zfs-based backup of tank/d with various test on Win (-ssd for multithread)"); ///moreprint("Destroy the snapshot fc (if any) zfs destroy tank/d@fc"); moreprint("Take the snapshot fc of tank/d zfs snapshot tank/d@fc"); moreprint("Get the hash list with xxhash64 sum /tank/d/.zfs/snapshot/fc -forcezfs -ssd -xxhash -noeta -silent -out /tmp/hash_xx64.txt"); moreprint("Create hashdeep.txt w/md5 hashdeep -c md5 -r /tank/d/.zfs/snapshot/fc >/tmp/hashdeep.txt"); moreprint("Make the backup (fixing path w/-to) a /tmp/thebak.zpaq /tank/d/.zfs/snapshot/fc /tmp/hash_xx64.txt /tmp/hashdeep.txt -to /tank/d"); moreprint("Destroy the snapshot zfs destroy tank/d@fc"); moreprint("!- Transfer somehow thebak.zpaq to Win (usually with rsync)"); moreprint("!- Full-scale test (aka:using filesystem), with extraction-restore"); moreprint("Extract in z:\\uno (-longpath) x thebak.zpaq -to z:\\uno -longpath"); moreprint("Verify files by hash list versum z:\\uno\\_tmp\\hash_xx64.txt -ssd -find /tank/d/.zfs/snapshot/fc -replace z:\\uno\\_tank\\d"); moreprint("Paranoid double-check with hashdeep versum z:\\uno\\_tmp\\hashdeep.txt -hashdeep -ssd -find /tank/d/.zfs/snapshot/fc -replace z:\\uno\\_tank\\d"); moreprint("!- Small-scale test, without reading from filesystem"); moreprint("Compare the md5 with the .zpaq versum \"*.zpaq\" -checktxt"); moreprint("Compare the crc32 with the .zpaq versum \"*.zpaq\" -fasttxt"); moreprint("Compare the quick with the .zpaq versum \"*.zpaq\" -fasttxt -quick"); moreprint("Automagically compare .zpaq versum \"*.zpaq\""); } return("Hashdeep-like double check of hashes"); } ///zpaqfranz backup z:\prova_????.zpaq c:\zpaqfranz string help_backup(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD backup Multipart-managed backup: keeps part size/hash/quickhash"); moreprint(" Hardening backups in 'pieces' (ex. rsync, robocopy etc)"); moreprint(" Use command testbackup to check missing or invalid 'pieces'"); moreprint("+ : -backupxxh3 Store XXH3 instead of default MD5"); moreprint("+ : -backupzeta Store ZETA instead of default MD5 [UNENCRYPTED]"); moreprint("+ : -index X Store index (and .pid) files in X folder (for WORM drive)"); moreprint("+ : -tmp .tmp instead of .zpaq for running multipart"); moreprint("+ : -notrim DISABLE autotrim (if possible) of incomplete transaction"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Use the same parameters as add backup z:\\prova.zpaq *.txt -key pippo"); moreprint("Store XXH3 (instead of MD5) backup z:\\prova.zpaq *.txt -backupxxh3"); moreprint("Write index in c:\\temp backup z:\\prova.zpaq c:\\nz -index c:\\temp"); moreprint("Store ZETA (instead of MD5) backup z:\\prova.zpaq *.txt -backupzeta"); moreprint("Rename to .zpaq after completing backup z:\\prova.zpaq *.txt -tmp"); } return("Backup with hardened multipart"); } string help_testbackup(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD testbackup Check multipart-managed backup"); moreprint("+ : -to something Path to .zpaq chunks (if different)"); moreprint("+ : -verify Read from filesystem and recompute hashes"); moreprint("+ : -ssd Multithread (for SSDs, do NOT use on spinning drives)"); moreprint("+ : -paranoid Compare index vs chunks (require password if encrypted)"); moreprint("+ : -verbose Show more things"); moreprint("+ : -find Change something in filenames"); moreprint("+ : -replace for 'dirty' tricks"); moreprint("+ : -checktxt f1 Load md5sum-like textfile to compare against index"); help_range(); moreprint("+ : -index X Get index (and .pid) files in X folder (for WORM drive)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Quick check local backup testbackup foo.zpaq"); moreprint("Multipart in different path testbackup foo.zpaq -to \\\\franzk\\z\\ -ssd"); moreprint("Different path, MD5 full test testbackup foo.zpaq -to \\\\franzk\\z\\ -verify"); moreprint("With multithread (on solid drives) testbackup foo.zpaq -to \\\\franzk\\z\\ -verify -ssd"); moreprint("Check from chunk 10 until last testbackup foo.zpaq -range 10: -verify"); moreprint("Test index with password (if any) testbackup foo.zpaq -paranoid -key pippo"); moreprint("Compare md5 hashes testbackup foo.zpaq -checktxt z:\\md5.txt"); moreprint("Test with index in c:\\temp testbackup z:\\prova.zpaq -index c:\\temp -paranoid"); } return("Multipart hardening"); } string help_work(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD work Multiple commands (verb-noun)"); moreprint("noun big Output a big ASCII string"); moreprint("noun pad Left pad a number"); moreprint("noun filepathnotrailing Get path without \\"); moreprint("noun date Write date/datetime"); moreprint("noun printbar Write out a row of chars"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Write something big work big \"count the ok\" "); moreprint("Write something big work big \"COUNT THE OK\" "); moreprint("Write something big work big forza inter"); moreprint("Pad number 123 to 00000123 work pad 123"); moreprint("Pad number 123 to 0123 work pad 123 -n 4"); moreprint("Extract path work filepathnotrailing z:\\doc\\2\\3.eml"); moreprint("Write datetime work date -terse"); moreprint("Write year_month_day work date \"%year_%month_%day\" -terse"); moreprint("Write ----- work printbar -terse"); moreprint("Write !!!!! work printbar \"!\" -terse"); } return("Multiple commands"); } #ifdef SFTP string help_sftp(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD sftp Multiple commands (verb-noun) for SFTP servers"); moreprint("noun upload Upload a single file to SFTP"); moreprint("noun verify Quick compare local to remote file"); moreprint("noun quick Get the QUICK hash of a remote file"); moreprint("noun ls List remote folder"); moreprint("noun delete Delete remote file"); moreprint("noun size Get size of remote file"); // moreprint("+ : -index X Get index (and .pid) files in X folder (for WORM drive)"); moreprint("+ : -host A IPV4 hostname (ex. pippo.ciao.com)"); moreprint("+ : -user B SFTP username (ex. thesftpuser)"); moreprint("+ : -password C SFTP password (ex. thehardpwd)"); moreprint("+ : -port D SFTP port (ex. 22)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Upload a file sftp upload j:\\1.zpaq /tmp/bak -host 1.2.3.4 -user k1 -password pippo -port 23"); moreprint("Verify a file sftp verify j:\\1.zpaq /tmp/bak/1.zpaq -host 1.2.3.4 -user k1 -password pippo -port 23"); moreprint("Get remote hash sftp quick /tmp/bak/1.zpaq -host 1.2.3.4 -user k1 -password pippo -port 23"); moreprint("ls sftp ls /tmp -host 1.2.3.4 -user k1 -password pippo -port 23"); moreprint("Delete a file sftp delete /tmp/bak/1.zpaq -host 1.2.3.4 -user k1 -password pippo -port 23"); moreprint("Get size sftp size /tmp/bak/1.zpaq -host 1.2.3.4 -user k1 -password pippo -port 23"); } return("SFTP interface"); } #endif // corresponds to #ifdef (#ifdef SFTP) string help_comparehex(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD comparehex Compare HEX substs from two files"); moreprint("+ : First file Name of first text file"); moreprint("+ : Second file Name of second text file"); moreprint("+ : Haystack The string to be searched"); moreprint("+ : Expected len Size of the hash"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Quick check local backup comparehex z:\\1.txt z:\\2.txt \"GLOBAL SHA256:\" 64"); } return("Compare hex substrings from two files"); } string help_count(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD count Count strings inside files (just like grep)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("I expect 3 all OK in logfiles count z:\\*.txt 3 \"all OK\""); moreprint("I expect 10 BIG OK in logfiles count z:\\*.txt 10"); } return("Count substrings in files"); } string help_consolidatebackup(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD consolidate Merge multipart-managed backup in one"); moreprint(" or convert a standard .zpaq to backup"); moreprint("+ : -to something New backup file"); moreprint("+ : -destination X Copy-rename to X"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Convert archive to backup consolidate z:\\foo.zpaq -to k:\\newbackup -key pippo"); moreprint("Rename a backup consolidate z:\\oldname -destination z:\\newname"); moreprint("Copy-Rename a backup consolidate z:\\oldname -destination j:\\output\\newname"); } return("Consolidate multipart backup"); } string help_last2(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD last2 Compare last 2 rows of a textfile, hash filename"); moreprint(" Usually n-1 row the remote md5sum, last the local"); moreprint(" zpaqfranz a z:\\1.zpaq *.bat -checktxt -noeta >z:\\l.txt"); moreprint(" (some kind of rsync-rclone to remote)"); moreprint(" (some kind of md5sum from remote) >z:\\r.txt"); moreprint(" grep \"final MD5:\" z:\\l.txt >>z:\r.txt"); moreprint(" zpaqfranz last2 z:\\r.txt -big"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Compare md5 hashes last2 c:\\stor\\confronto.txt -big"); } return("Compare last2 rows"); } string help_last(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD last Get last of multipart filename, usually for"); moreprint(" scripting. Backups use 8 (eight) ? in filename"); moreprint(" "); moreprint("Windows' example (script use %%, direct only %)"); moreprint(" "); moreprint("FOR /f %%G in ('zpaqfranz last K:\\parte_???????? -pakka -noeta') DO "); moreprint("ssh -i thekey user@theserver.com md5sum '/home/franco/%%G' >remote.txt"); moreprint(" "); moreprint("FOR /f %%G in ('zpaqfranz last K:\\parte_???????? -pakka -noeta') DO "); moreprint("zpaqfranz sum k:/%%G -md5 -pakka -noeta -stdout >>remote.txt"); moreprint(" "); moreprint("zpaqfranz last2 remote.txt -big"); moreprint(" "); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Get the last partname last z:\\prova_????????"); } return("Get the last multipart filename"); } string help_pause(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD pause ()"); moreprint("<>: Get a key from stdin (like pause on DOS)"); moreprint("<>: -n X Wait X seconds, then proceed"); moreprint("<>: -pakka Write less"); moreprint("<>: -silent Write way less"); moreprint("<>: -find x Way for key x"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Wait for any key pause"); moreprint("Wait for key z pause -find z"); moreprint("Wait for 5 seconds (or key) pause -n 5"); moreprint("Wait 5 seconds (or key) small output pause -n 5 -pakka"); moreprint("Wait 5 seconds (or key) NO output pause -n 5 -pakka -silent"); moreprint("Wait 5 seconds (or key) NO output pause -n 5 -pakka -silent"); } return("Halt script execution until timeout expires or keypress"); } string help_setpassword(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD password Change/remove password of single archive (no multipart)"); moreprint("<>: By default DRY RUN (only test)"); moreprint("<>: -force Overwrite output if exists"); moreprint("<>: -space Do not check for free space"); moreprint("<>: -key2 X Use X as new password"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Change pass from X to Y: password z:\\x.zpaq z:\\y.zpaq -key X -key2 Y"); moreprint("Add password X to NON encrypted: password z:\\nocrypt.zpaq z:\\yescrypt.zpaq -key2 X"); moreprint("Remove password X from encrypted: password z:\\crypt.zpaq z:\\nocrypt.zpaq -key X"); } return ("Change/remove password of single archive (no multipart)"); } string help_trim(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD trim Trim incomplete .zpaq file"); moreprint("<>: By default DRY RUN (only test)"); moreprint("<>: -kill Do a 'wet' (effective) in-place run"); moreprint("<>: -to tiny.zpaq Trim on tiny.zpaq"); moreprint("<>: -verify Check the copy before trim"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Trim file (dry run): trim z:\\1.zpaq"); moreprint("Trim file IN PLACE (wet run): trim z:\\1.zpaq -kill"); moreprint("Trim file on other (safer): trim z:\\1.zpaq -to d:\\small.zpaq"); moreprint("Trim file w/verify: trim z:\\1.zpaq -to d:\\small.zpaq -verify"); moreprint("Trim a multipart NON encrypted: trim z:\\uno_???? -kill"); } return("Trim .zpaq archive from the incomplete transaction"); } string help_crop(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD crop Discard latest version(s)"); moreprint("<>: Delete queued versions from the archive"); moreprint(" up to the specified position or -until"); moreprint(" By default DRY RUN (only test)"); moreprint("<>: -kill Do a 'wet' (effective) run"); moreprint("<>: -to tiny.zpaq Reduce to tiny.zpaq (safer)"); moreprint("<>: -until X Discard every versions >X"); moreprint("+ : -maxsize X Manually cut at X (RISKY)"); moreprint("+ : -force Crop in-place (no backup: VERY RISKY!)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Reduce file (dry run, just infos): crop z:\\1.zpaq"); moreprint("Reduce up to version 100: crop z:\\1.zpaq -to d:\\2.zpaq -until 100 -kill"); moreprint("Reduce to first 100.000: crop z:\\1.zpaq -to d:\\2.zpaq -maxsize 100k -kill"); moreprint("Crop in place (NO BACKUP! RISKY!): crop z:\\1.zpaq -until 2 -kill -force"); } return("Reduce .zpaq archive cropping (trimming) versions"); } void print_sub() { moreprint(" Substitute %hour %min %sec %weekday %year %month %day"); moreprint(" %week %date %time %datetime %timestamp (or $hour...)"); } void print_doublequote() { color_yellow(); moreprint("************ REMEMBER TO USE DOUBLE QUOTES! ************"); moreprint("*** -not *.cpp is bad, -not \"*.cpp\" is good ***"); moreprint("*** test_???.zpaq is bad, \"test_???.zpaq\" is good ***"); color_restore(); } string help_a(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD a (add) / append (ransomware)"); moreprint("<>: zpaqfranz store CRC-32/XXH of each file, detecting SHA-1 collisions,"); moreprint(" while zpaq cannot by design. Can be disabled by -crc32 or -715,"); moreprint(" on modern CPU slow down ~10%."); print_sub(); moreprint("<>: By default do NOT store ADSs on Windows (essentially useless)."); moreprint("<>: By default every .XLS file is forcibily added (old Excel change metafiles)."); moreprint("+ : -verbose Verbose output"); moreprint("+ : -n X Show X files to be added, before and after sort"); moreprint("+ : -debug Show a LOT of infos"); moreprint("+ : -summary Be brief"); moreprint("+ : -noeta Do not show ETA (redirect output to log file)"); moreprint("+ : -pakka New-style output (by chunks)"); moreprint("<>: -forcewindows Store ADS stuff (default: NO)"); moreprint("<>: -xls Do NOT force adding of XLS/PPT (default: NO)"); moreprint("<>: -forcezfs Do NOT ignore .zfs (default: YES)"); moreprint("<>: -715 Runs just about like 7.15"); moreprint("+ : -debug -zero Add files but zero-filled (debugging)"); moreprint("+ : -debug -zero -kill Add 0-byte long file (debugging)"); moreprint("+ : -nochecksum Disable zpaqfranz additional checks (faster, less sure)"); moreprint("+ : -nodedup Turn off deduplicator"); moreprint("+ : -store Store mode: no deduplication, no compression"); moreprint("+ : -touch Force 'touch' on date (converting 7.15 to zpaqfranz)"); moreprint("+ : -norecursion Do not recurse into folders (default: YES)"); #ifdef _WIN32 moreprint("+ : -findzpaq On Windows search the .zpaq in every drive letter (USB device)"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("+ : -append Append-only (antiransomware)"); help_printhash(true); moreprint("+ : -test Do a post-add test (doveryay, no proveryay)."); moreprint("+ : -verify Verify hashes against filesystem"); moreprint("+ : -verify -ssd Verify hashes against filesystem MULTITHREAD (do NOT use on spinning drives)"); moreprint("+ : -paranoid Test for file with same size and timestamp, but !=hash (-ssd multithread)"); moreprint("+ : -vss Volume Shadow Copies (Win with admin rights) to backup files from %users%."); moreprint("+ : -timestamp X Setting version datetime @X, ex 2021-12-30_01:03:04 to freeze zfs snapshots"); moreprint(" Must be monotonic. increasing (v[i+1].date>v[i]+date)"); help_date(); moreprint("+ : -comment foo Add a version with ASCII text 'foo'"); moreprint("+ : -filelist Add the list of file to be added in a VFILE"); moreprint("+ : -copy z:\\two Make a 2nd copy of the written data into another folder"); moreprint("+ : -exec_ok p.sh After successful run launch p.sh with archive name as parameter"); moreprint("+ : -freeze kajo If current archive size > maxsize, move to kajo folder"); moreprint("+ : -stdin Input data from stdin (pipe)"); moreprint("+ : -stdout Force a NOT DEDUPLICATED file ready to stdout (pipe OUT)"); moreprint("+ : -checktxt kaj Write out MD5 on kaj. For rsync/rclone sync"); moreprint("+ : -checktxt Write out MD5 on archivename.txt"); moreprint("+ : -buffer X Use a input buffer of X bytes (default: 4KB)"); moreprint("+ : -hashdeep Add the hashdeep MD5 VFILE (-ssd for multithread)"); moreprint("+ : -fasttxt Write out CRC32 on archivename_crc32.txt"); moreprint("+ : -fasttxt -verify Post-check of crc32.txt"); moreprint("+ : -home Create one archive for folder (-not -only)"); moreprint("+ : -collision Double check for SHA-1 collisions"); moreprint("+ : -chunk X Split in chunk of size X"); ///moreprint("+ : -red4 Level [0..255] of redundancy to enable method 4"); ///moreprint("+ : -level0 foo0 Apply method 0 to foo0"); ///moreprint("+ : -level1 foo1 Apply method 1 to foo1"); ///moreprint("+ : -level2 foo2 Apply method 2 to foo2"); ///moreprint("+ : -level3 foo3 Apply method 3 to foo3"); ///moreprint("+ : -level4 foo4 Apply method 4 to foo4"); ///moreprint("+ : -level5 foo5 Apply method 5 to foo5"); #ifdef unix moreprint("+ : -dataset x Add changes on zfs dataset x"); #endif // corresponds to #ifdef (#ifdef unix) help_orderby(); #if defined(_WIN32) moreprint("+ : -sfx autoz Make SFX autoz.exe (on Win)"); moreprint("+ : -sfxto foldr Set -to into the SFX module"); moreprint("+ : -sfxforce Set -force into the SFX module"); moreprint("+ : -sfxnot Like -not for SFX"); moreprint("+ : -sfxonly Like -only for SFX"); moreprint("+ : -sfxuntil Like -until for SFX"); moreprint("+ : -longpath Adding on Windows filenames longer than 255"); moreprint("+ : -windate Store file creation date"); moreprint("+ : -open Early fail if archive is already open"); /// moreprint("+ : -dd Imaging a drive by dd (-minsize bs -maxsize count) - ADMIN"); moreprint("+ : -image Imaging a drive - ADMIN rights required"); moreprint("+ : -ads Store filelist in NTFS' ADS (Alternate Data Stream)"); #endif // corresponds to #if (#if defined(_WIN32)) moreprint("+ : -fast Store filelist inside the archive (EXPERIMENTAL)"); moreprint("+ : -ignore Do not show file access error"); moreprint("+ : -pause Wait for key press after run"); moreprint("+ : -ifexist X Abort if X folder does not exist"); #if defined(_WIN32) moreprint("+ : -thunderbird Take appdata local\\roaming thunderbird"); #endif // corresponds to #if (#if defined(_WIN32)) moreprint("+ : -date Store creation date (slower)"); moreprint("+ : -frugal Use less RAM, but CANNOT WORK with mixed hashes"); moreprint("+ : -stat Show external files added/updated"); moreprint("+ : -external X Run X before add (replace %files or $files)"); moreprint("+ : -touch X Change every filedate to be stored to X"); moreprint("+ : -input X Load the X file as files to be added"); moreprint("+ : -destination X Load the X file as -to"); moreprint("+ : -errorlog X Write the errors on the X file"); moreprint("+ : -ht Enable HyperThread (if any)"); moreprint("+ : -notrim DISABLE autotrim of incomplete transaction (not with -chunk)"); #ifdef _WIN32 moreprint("+ : -noonedrive Do NOT add onedrive placeholders"); #endif } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Add two folders to archive: a z:\\1.zpaq c:\\data\\* d:\\pippo\\*"); moreprint("Add folder, storing full hash SHA3: a z:\\2.zpaq c:\\nz\\ -sha3"); moreprint("Add folder, then verification: a z:\\3.zpaq c:\\nz\\ -test"); moreprint("Add two files: a z:\\4.zpaq.zpaq c:\\vecchio.sql r:\\1.txt"); moreprint("Add as zpaq 7.15 (no checksum): a z:\\5.zpaq c:\\audio -715"); moreprint("Add and mark version: a z:\\6.zpaq c:\\data\\* -comment first_copy"); #if defined(_WIN32) || defined(_WIN64) moreprint("Add by a VSS (Windows admin): a z:\\7.zpaq c:\\users\\utente\\* -vss"); #endif // corresponds to #if (#if defined(_WIN32) || defined(_WIN64)) moreprint("Add folder with timestamping (zfs): a z:\\8.zpaq c:\\data\\* -timestamp 2021-12-30_01:03:04"); moreprint("Create multipart archive: a \"z:\\9_????.zpaq\" c:\\data\\"); moreprint("Create indexed multipart archive: a \"z:\\a_???.zpaq\" c:\\data\\ -index z:\\a_000.zpaq"); moreprint("Add folder, with encryption: a z:\\b.zpaq c:\\nz\\ -key mygoodpassword"); moreprint("Add folder, maximum compress: a z:\\c.zpaq c:\\nz\\ -m5"); moreprint("Store the filelist VFILE: a z:\\d.zpaq c:\\nz\\ -filelist"); moreprint("Add WITHOUT CRC-32/hash (like 715): a z:\\e.zpaq c:\\nz\\ -nochecksum"); moreprint("Add 2nd copy to USB drive (U): a \"z:\\f_???.zpaq\" c:\\nz\\ -copy u:\\usb"); moreprint("Launch pippo.bat after OK: a \"z:\\g_???.zpaq\" c:\\nz\\ -exec_ok u:\\pippo.bat"); moreprint("Archive file if bigger of 10GB: a z:\\h.zpaq c:\\nz\\ -freeze y:\\archived -maxsize 10000000000"); #if defined(_WIN32) moreprint("Make z:\\2.exe from z:\\1.zpaq: a z:\\1.zpaq *.cpp -sfx z:\\2.exe"); moreprint("2.exe extract/overwrite into z:\\kom: a z:\\1.zpaq *.cpp -sfx z:\\2.exe -sfxto z:\\kom -sfxforce"); #endif // corresponds to #if (#if defined(_WIN32)) moreprint("Prepare a debug archive...for me a z:\\1.zpaq c:\\nz\\ -debug -zero"); moreprint("In-place 7.15 to zpaqfranz 1/2 a z:\\1.zpaq c:\\nz\\ -touch"); moreprint("In-place 7.15 to zpaqfranz 2/2 a z:\\1.zpaq c:\\nz\\"); moreprint("Hard-check of files a z:\\1.zpaq c:\\nz\\ -paranoid"); moreprint("Hard-check of files multithread a z:\\1.zpaq c:\\nz\\ -paranoid -ssd"); moreprint("Archive, without recursion a z:\\1.zpaq f:\\zarc\\*.* -norecursion"); moreprint("Archive mysqldump a z:\\1.zpaq mydump.sql -stdin"); moreprint("MD5 quick check a z:\\knb.zpaq c:\\nz\\ -checktxt z:\\pippo.txt"); moreprint("Write MD5 on z:\\knb.txt a z:\\knb.zpaq c:\\nz\\ -checktxt"); moreprint("Write CRC32 on z:\\1_crc32.txt a z:\\1.zpaq c:\\nz\\ -fasttxt"); #ifdef _WIN32 moreprint("Find file /prova/ci.zpaq on drives a z:\\prova\\ci.zpaq c:\\nz\\* -findzpaq"); moreprint("Abort if file already open a z:\\2.zpaq c:\\nz\\* -open"); /// moreprint("Raw imaging drive C with DD a z:\\2.zpaq c: -dd"); moreprint("Raw imaging drive E with built in a z:\\2.zpaq e: -image"); moreprint("Imaging C with pwd and big buffer a z:\\2.zpaq c: -image -buffer 1MB -key pippo"); moreprint("Create VFILE-l-hashdeep.txt w/md5 a z:\\2.zpaq *.txt *.cpp -hashdeep -ssd"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("Multiple z:\\utenti_something.zpaq a z:\\utenti.zpaq c:\\users -home"); moreprint("All users, but not franco a /temp/test1 /home -home -not franco"); moreprint("Only SARA and NERI folders a /temp/test2 /home -home -only \"*SARA\" -only \"*NERI\""); moreprint("Sort (orderby) before add a z:\\test.txt c:\\dropbox -orderby ext;name"); moreprint("Sorting files from largest a z:\\test.txt c:\\dropbox -orderby size -desc"); moreprint("Manage SHA-1 collisions a z:\\1.zpaq messageA messageB -collision"); ///moreprint("Activate method 4 on compressible a z:\\1.zpaq c:\\testfolder -red4 100"); ///moreprint("Activate method 4 on more files a z:\\1.zpaq c:\\testfolder -red4 50"); ///moreprint("Mix methods a z:\\1.zpaq c:\\fold -leve1 *.avi -level1 *.7z -level4 *.txt"); #ifdef unix moreprint("Update from tank/d dataset a /tmp/test.zpaq * -dataset \"tank/d\""); #endif // corresponds to #ifdef (#ifdef unix) #ifdef _WIN32 moreprint("Store filelist on NTFS a z:\\1.zpaq *.cpp -ads"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("Split in 1GB chunks a z:\\1.zpaq c:\\pippo -chunk 1GB"); moreprint("Store (EXPERIMENTAL) filelist a z:\\1.zpaq c:\\pippo -fast"); moreprint("Do not mess output with errors a z:\\1.zpaq c:\\users -ignore"); moreprint("Wait for a key strike a z:\\1.zpaq c:\\users -pause"); moreprint("Abort if /monta...rar does not exist a /1.zpaq /thefolder -ifexist /monta/nas1_nfs3/rar"); #ifdef _WIN32 moreprint("Take Thunderbird email of utente a z:\\1.zpaq c:\\users\\utente -thunderbird"); moreprint("Close and take Thunderbird email a z:\\1.zpaq c:\\users\\utente -thunderbird -kill"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("Store creation date (slower) a z:\\1.zpaq c:\\users\\utente -date"); moreprint("Use less RAM: DO NOT MIX HASHES! a z:\\1.zpaq c:\\nz -frugal"); moreprint("Store external VFILE-l-external.txt a z:\\2.zpaq c:\\nz -external \"c:\\nz\\hashdeep64 -r -c sha1 %files\""); moreprint("Alter the filedate (piped) type 1.txt|zpaqfranz a z:\\2.zpaq 1.sql -stdin -touch 2024_02_03"); moreprint("Load files from text file a z:\\1.zpaq -input z:\\thelist.txt"); moreprint("Write errors a z:\\1.zpaq c:\\windows\\system32 -errorlog z:\\errors.txt -silent"); moreprint("Load files/to from text files a z:\\1.zpaq -input z:\\input.txt -destination z:\\destination.txt"); #ifdef _WIN32 moreprint("Do NOT add onedrive placeholder a z:\\1.zpaq c:\\users\\utente\\onedrive -onedrive"); #endif } return("Add or append files to archive"); } string help_update(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD update (refresh zpaqfranz from Internet)"); moreprint("+ : Check/download from http://www.francocorbelli.it/zpaqfranz"); #ifdef _WIN64 moreprint("+ : or from two user-entered URLs"); moreprint("+ : -force Wet-run (do the update, default dry-run)"); moreprint("+ : -force -kill Replace current zpaqfranz from Internet"); #endif // corresponds to #ifdef (#ifdef _WIN64) } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Check for updates update"); #ifdef _WIN64 moreprint("Check for updates upgrade"); moreprint("Update (if any) update -force"); moreprint("Get always from Internet update -force -kill"); moreprint("Use specific URLs update https://www.pippo.com/ugo.sha256 http://www.pluto.com/zpaqnew.exe"); #endif // corresponds to #ifdef (#ifdef _WIN64) } #ifdef _WIN32 return ("Update zpaqfranz from Internet"); #else return ("Check for updated zpaqfranz from Internet"); #endif // corresponds to #ifdef (#ifdef _WIN32) } #ifdef _WIN64 string help_download(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD download (get file from Internet)"); moreprint("+ : -force Overwrite output file"); moreprint("+ : -space Do not check the output path"); moreprint("+ : -checktxt z Test hash in z file (len 32=MD5, 40=SHA-1, 64=SHA-256)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Download in ugo.txt download https://www.1.it/2.cpp ./2.cpp"); moreprint("Download+check SHA256 download http://www.1.it/3.cpp z:\\3.cpp -checktxt http://www.1.it/3.sha256"); moreprint("Download+check MD5 download http://www.1.it/4.cpp z:\\4.cpp -checktxt http://www.1.it/4.md5"); } return ("Download file from Internet"); } #endif // corresponds to #ifdef (#ifdef _WIN64) #ifdef _WIN32 string help_rd(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD rd (remove directory on Windows)"); moreprint("+ : Delete hard-to-remove dir (like rd /s or rm -r)"); moreprint("+ : -kill Wet run (default: DRY run)\n"); moreprint("+ : -force Remove folder if not-zero files present\n"); moreprint("+ : -space Do not check if writeable (ex. 0 bytes free)\n"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) moreprint("Remove folder z:\\kajo: rd z:\\kajo -force -kill -space"); return ("Remove hard-to-delete Windows' folder (ex. path too lengthy)"); } string help_pakka(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD pakka (create zpaqlist-compatible output)"); moreprint("+ : Delete hard-to-remove dir (like rd /s or rm -r)"); moreprint("+ : -all All version(s)"); moreprint("+ : -distinct Do not deduplicate output"); moreprint("+ : -until X Choose version X"); moreprint("+ : -out thefile Write output on thefile"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("List to file pakka h:\\zarc\\1.zpaq -out z:\\default.txt"); moreprint("Disable de-duplicator pakka h:\\zarc\\1.zpaq -all -distinct -out z:\\default.txt"); moreprint("Get version 10 pakka h:\\zarc\\1.zpaq -until 10 -out z:\\10.txt"); } return ("Auxiliary output for third-party extractor software"); } #endif // corresponds to #ifdef (#ifdef _WIN32) string help_fzf(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD fzf List archive content 'plain-and-dirty'"); moreprint("+ : -all Show all version\n"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("List filenames fzf z:\\kajo.zpaq"); moreprint("List filenames/pipe in fzf fzf z:\\kajo.zpaq|fzf"); } return ("List archive filenames 'plain-and-dirty'"); } string help_collision(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD collision Inspect for SHA-1 collisions\n"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Inspect file collision z:\\kajo.zpaq"); } return ("Inspect archive for SHA-1 collisions"); } string help_dump(bool i_usage,bool i_example) { if (i_usage) { moreprint("dump technical infos (not for huge archives!)\n"); moreprint("BTW will show archive compatibility level"); moreprint(" 60+ = zpaqfranz from v60 and more ~jul 2024"); moreprint(" <60 = zpaqfranz up to v59.x"); moreprint(" 715 = standard zpaq 7.15 (or zpaqfranz -715)"); moreprint("+ : -summary Brief"); moreprint("+ : -verbose Show useful infos"); moreprint("+ : -all A bit deeper"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Default infos dump z:\\kajo.zpaq"); moreprint("More dump z:\\kajo.zpaq -verbose"); moreprint("Brief dump z:\\kajo.zpaq -summary"); moreprint("A lot of things dump z:\\kajo.zpaq -all"); } return ("Technical info (not for huge archives!)"); } string help_redu(bool i_usage,bool i_example) { if (i_usage) { moreprint("redu technical (quick) exam of files\n"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Default infos redu z:\\*.exe"); } return ("Inspect archive for SHA-1 collisions"); } string help_w(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD w (Chunked-extraction)"); moreprint("+ : Extract/test in chunks, on disk or 'ramdisk' (RAM)"); moreprint("+ : The output -to folder MUST BE EMPTY"); moreprint("+ : -maxsize X Maxsize of the chunk @ X bytes"); moreprint("+ : -ramdisk Use 'RAMDISK'"); moreprint("+ : -frugal Use less possible RAM (default: get 75% of free RAM)'"); moreprint("+ : -ssd Multithread writing from ramdisk"); moreprint("+ : -test Do not write on media"); moreprint("+ : -verbose Show useful infos"); moreprint("+ : -checksum Do CRC-32 / hashes test"); moreprint("+ : -verify Do a 'check-against-filesystem'"); moreprint("+ : -paranoid Extract to filesystem, then delete if OK (need -verify)"); #ifdef _WIN32 moreprint("+ : -longpath Extracting on Windows filenames longer than 255"); #endif // corresponds to #ifdef (#ifdef _WIN32) } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Extract to a spinning drive: w z:\\1.zpaq -to p:\\muz7\\ -ramdisk -longpath"); moreprint("Paranoid check into folder muz7: w z:\\1.zpaq -to z:\\muz7\\ -paranoid -verify -verbose -frugal -longpath"); moreprint("Paranoid max chunksize 1000000000: w z:\\1.zpaq -to z:\\muz7\\ -paranoid -verify -maxsize 1000000000"); moreprint("Test in RAM (no disk write,M/T) w z:\\1.zpaq -ramdisk -test -checksum -ssd -frugal"); moreprint("Top test (W/disk write on SSD z:\\) w z:\\1.zpaq -to z:\\kajo -ramdisk -paranoid -verify -checksum -longpath -ssd"); } return ("Very big files chunked extraction/test"); } string help_x(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD x (extract)"); moreprint("+ : During extraction,if CRC-32s are present, the codes are checked."); moreprint("+ : Extract multiple files with '*'"); moreprint("+ : -all All versions"); moreprint("+ : -all -comment Restore all versions with DATETIME and comment (if any)"); moreprint("+ : -checksum force a full hash-code verify (if added with -checksum)"); moreprint("+ : -zero extract to dummy, 0-length files. Do an empty-full restore."); moreprint("+ : -zero -debug extract full-sized files, 0 filled (Dry restore)"); moreprint("+ : -zero -debug -kill Only extract filenames (0 bytes long)"); moreprint("+ : -utf change everything non latin to latin (Linux/*Nix => NTFS compatibility)"); moreprint("+ : -fix255 shrink max file name, avoid different case collision (Linux => NTFS)"); moreprint(" (pippo.txt and PIPPO.txt are be silently overwritten by 7.15)."); moreprint("+ : -fixeml compress .eml filenames."); #ifdef _WIN32 moreprint("+ : -longpath Extracting on Windows filenames longer than 255"); moreprint("+ : -fixreserved fix reserved filenames on Windows (ex. LPT1)."); moreprint("+ : -windate Restore (if any) file's creation date"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("+ : -flat emergency restore of everything into a single folder (Linux => NTFS)"); moreprint("+ : -filelist show (if any) a stored filelist"); moreprint("+ : -force Force overwrite AND extracting of corrupted files (if any)"); moreprint("+ : -space Do not check free space before extract"); moreprint("+ : -find/replace Replace part of text"); moreprint("+ : -replace X Juxtapose X to stored path"); moreprint("+ : -image Change the progress to handle huge files (-minsize X default 20MB)"); moreprint("+ : -stdout Output (if possible) a single file on stdout"); moreprint("+ : -external Show (if any) a stored external file"); moreprint("+ : -ramdisk Extract to RAM, then write (if possible)"); help_range(); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Single file to file extraction x 1.zpaq \"/k/foo/b.md\" -to \"/tmp/restored/b.md\""); moreprint("Single file to folder tree x 1.zpaq -only \"*whatever\" -to /tmp/foldertree"); moreprint("Everything into folder muz7: x z:\\1.zpaq -to z:\\muz7\\"); moreprint("0-bytes files (check restoration): x z:\\1.zpaq -to z:\\muz7\\ -kill"); moreprint("Extract into single directory: x z:\\1.zpaq -to z:\\muz7\\ -flat"); moreprint("Extract without utf,<255,.eml: x z:\\1.zpaq -to z:\\muz7\\ -utf -fix255 -fixeml"); moreprint("Extract forcing overwrite: x z:\\1.zpaq -to z:\\muz7\\ -force"); moreprint("Extract version K: x z:\\1.zpaq -to z:\\muz7\\ -until K"); moreprint("Extract last versions of multipart: x \"z:\\a_???\" -to z:\\ugo"); moreprint("Extract into muz7 every versions: x z:\\1.zpaq -to z:\\muz7\\ -all"); moreprint("Show the filelist (if any): x z:\\1.zpaq -filelist"); moreprint("Show the filelist (if any) of v3: x z:\\1.zpaq -filelist -until 3"); moreprint("Extract all *.xls into new archive: x z:\\1.zpaq *.xls -repack onlyxls.zpaq"); moreprint("Extract from a VSS (Windows): x z:\\1.zpaq \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy1\\path -to d:\\output"); moreprint("Replace path in extract x 1.zpaq -find /tank/ -replace z:\\uno\\"); moreprint("Change path in extract, longpath x 1.zpaq -replace z:\\uno\\ -longpath"); moreprint("Create files' tree x 1.zpaq -to z:\\testdir\\ -debug -kill -zero -longpath"); moreprint("Range-extract version x copia.zpaq -only *comp.pas -to z:\\allcomp -all -range 100:1000"); moreprint("Restore datetime and comments x copia.zpaq -to z:\\prova\\ -all -comment"); moreprint("Restore huge image w/smart progress x copia.zpaq -to z:\\prova\\ -image"); moreprint("Single file to stdout x copia.zpaq 00000015.zfs >z:\\15.zfs"); moreprint("Extract multiple zpaqs x \"vu*.zpaq\" -to z:\\pippo\\"); moreprint("Show external VFILE x z:\\1.zpaq -external -silent"); moreprint("Spinning drive with lot of RAM x z:\11.zpaq -to z:\\ugo -ramdisk"); } return("Extract the file(s)"); } string help_l(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD l (list)"); moreprint("+ : If source folders are specified, do a compare of the archive's content."); moreprint(" A 'verify' more than a 'list', much faster than the standard,"); moreprint(" as it performs a block calc codes of source files, but not of"); moreprint(" the archived ones; also checks the CRC-32, to intercept any SHA1 collisions."); moreprint(" Use the exact same parameters of add(), just use l instead of a."); moreprint("+ : -force Shows all files (even marked as corrupted)"); moreprint("+ : -checksum Shows CRC-32/hash, if any"); moreprint("+ : -summary Compact file list"); moreprint("+ : -comment foo Works on version foo, if possible"); moreprint("+ : -comment Enumerate version-comment"); moreprint("+ : -find pippo Just like |grep -i pippo"); moreprint("+ : -replace foo Replace -find with -replace in the output"); moreprint("+ : -to knb Do the standard rename()"); moreprint("+ : -utc Do not convert to localtime (show UTC)"); moreprint("+ : -stdout If -verbose show if files' fragments are ordered"); #ifdef _WIN32 moreprint("+ : -windate Show (if any) file's creation date"); moreprint("+ : -ads Skip NTFS filelist (if any)"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("+ : -fast Try to extract the filelist (if present)"); moreprint("+ : -date Show creation date (if any)"); moreprint("+ : -attr Show the attr"); moreprint("+ : -terse Make a 'script-aware' output"); moreprint("+ : -nodel Do not show deleted files (with -all)"); moreprint("+ : -csv \"some\" Enable -csv delimiter (\\t for TAB)"); moreprint("+ : -csvhf \"!\" CSV line header/footer (\\t for TAB)"); help_date(); help_size(); help_orderby(); help_range(); moreprint("+ : -715 Binary-compatible zpaq 7.15 output"); moreprint("+ : -norecursion Do not recurse with -only (see example below)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Last version: l z:\\1.zpaq"); moreprint("Last version w/checksums: l z:\\1.zpaq -checksum"); moreprint("Compact output: l z:\\1.zpaq -checksum -summary"); moreprint("Compact output renamed: l z:\\1.zpaq -checksum -summary -to z:\\knb"); moreprint("All (every) version: l z:\\1.zpaq -all"); moreprint("Version comments (if any): l z:\\1.zpaq -comment"); moreprint("V.comments verbose (if any): l z:\\1.zpaq -comment -all"); moreprint("Only stored 'zpaq.cpp': l z:\\1.zpaq -find zpaq.cpp -pakka"); moreprint("Find-and-replace (like awk or sed) l r:\\1.zpaq -find c:/biz/ -replace z:\\mydir\\"); moreprint("List the 10 greatest file l z:\\1.zpaq -all -orderby size -desc -n 10"); moreprint("List files >1G l z:\\1.zpaq -minsize 1g"); moreprint("List files >100M of 2017 l z:\\1.zpaq -minsize 100m -datefrom 2017 -dateto 2017"); moreprint("List ORDERED files (-stdout) l z:\\1.zpaq -stdout"); moreprint("Compare to files on disk l z:\\1.zpaq \"//192.168.1.100/scanner/\" -ssd"); moreprint("Find the versions of a file l z:\\1.zpaq -only \"*/the/file.doc\" -all"); moreprint("Force recomputing list l z:\\1.zpaq -ads"); moreprint("Try to get the fast filelist l z:\\1.zpaq -fast"); moreprint("Files added in versions 2 and 3 l z:\\1.zpaq -range 2:3"); moreprint("Files added in last version l z:\\1.zpaq -range ::1"); moreprint("Show creation date (if any) l z:\\1.zpaq -date"); moreprint("Fixed sized/no header and footer l z:\\1.zpaq -terse"); moreprint("Where are the restorable versions? l z:\\1.zpaq -find \"$$$$\" -all -nodel"); moreprint("TAB-delimited CSV output l z:\\1.zpaq -terse -csv \"\\t\""); moreprint("Enclose fields between double quote l z:\\1.zpaq -terse -csv \"\\\",\\\"\" -csvhf \"\\\"\""); moreprint("Output just like zpaq 7.15 l z:\\1.zpaq -715"); moreprint("Show a folder WITHOUT subfolders l z:\\1.zpaq -only c:/dropbox/snapshot -norecursion"); moreprint("Show a folder WITH subfolders l z:\\1.zpaq -only c:/dropbox/snapshot"); } return("List file(s)"); } string help_i(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD i (info)"); moreprint("+ : Directly shows the versions into the archive, with size and comments"); moreprint("+ : -comment Shows comments (if any)"); moreprint("+ : -stat Count 'weird' files and show uncompressed size (slow)"); help_range(); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Show versions info (command i): i z:\\1.zpaq"); moreprint("Count 'not good filenames': i z:\\1.zpaq -stat"); moreprint("Shows version comment: i z:\\1.zpaq -comment"); moreprint("Show version 153: i z:\\1.zpaq -range 153"); moreprint("Show last 5 versions: i z:\\1.zpaq -range ::5"); } return("File (archive) information"); } #ifndef ANCIENT string help_ls(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD ls Navigate inside .zpaq like a 'filesystem'"); color_yellow(); moreprint("CMD EXPERIMENTAL"); color_restore(); moreprint("CMD Enter help or ? to commands list"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Enter inside archive ls z:\\1.zpaq"); } return ("Navigate inside .zpaq"); } string help_tui(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD tui Start text-based TUI"); moreprint("CMD Please strike ? key to get all commands"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Launch the TUI tui z:\\okane.zpaq"); } return("Text-based UI (listing-extraction)"); } #endif #ifdef _WIN32 string help_q(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD q Windows archiving of C: (*** admin rights mandatory ***)"); moreprint("+ : Take as much C: as possible (no Windows and swapfile)"); moreprint("+ : This is NOT a full backup (aka: bare-metal restorable)"); moreprint("+ : -forcewindows INCLUDE Windows folder"); moreprint("+ : -frugal Exclude Windows, %programfiles% and %temp%"); moreprint("+ : -all Get everything (except swapfile)"); moreprint("+ : -to c:\\piz Use c:\\piz for snap (default c:\\franzsnap)"); moreprint("+ : It is possible to use %pcname as placeholder"); moreprint("+ : Just about all switches of add() (-key -m -only ...)"); moreprint("+ : except files selection (always C:/*)"); moreprint("+ : **** The folder franzsnap MUST NOT EXIST and be on C:"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("NOT C:\\WINDOWS, NOT RECYCLE BIN q z:\\1.zpaq"); moreprint("Everything q z:\\1.zpaq -all"); moreprint("Everything NOT C:\\DROPBOX q z:\\1.zpaq -all -not c:/franzsnap/dropbox"); moreprint("NOT C:\\WINDOWS, NOT %programs% q z:\\1.zpaq -frugal"); moreprint("Only C/C++ files and header q z:\\1.zpaq -only *.c* -only *.h*"); moreprint("For multi-PC 'backup' on one zpaq q z:\\1.zpaq -frugal -to c:\\snap_%pcname -verbose"); } return("Windows archive of C: with VSS"); } string help_ads(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD ads Manipulate NTFS Alternate Data Stream"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Show ADS ads z:\\1.zpaq"); moreprint("Remove ADS (all of them) ads z:\\*.zpaq -kill"); moreprint("Remove ADS (only one) ads z:\\*.zpaq -only fasttxt -kill"); moreprint("Rebuild ADS filelist ads z:\\1.zpaq -force"); } return("ADS Alternate Data Stream manipulator"); } string help_g(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD g Run a q command (Windows archiving of C:)"); moreprint("+ : If the user is in the administrator group, BUT"); moreprint("+ : the current shell does not have admin rights, this will work"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("NOT C:\\WINDOWS, NOT RECYCLE BIN g z:\\1.zpaq"); moreprint("... same as command q, but with g"); } return("Windows C: archiver from a shell without admin rights"); } #endif // corresponds to #ifdef (#ifdef _WIN32) string help_find(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD find files"); moreprint("+ : Search file(s) with wildcards. DO NOT FORGET DOUBLE QUOTES ON *NIX!"); moreprint("+ : -verbose Show date/size (default:NO)"); help_date(); help_size(); help_orderby(); moreprint("+ : -find Like grep -i"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("'Double filter' find c:\\dropbox *.txt -minsize 1000000 -find franco"); moreprint("Search in multiple folders find c:\\uno z:\\kb -only *franco*"); moreprint("Search file ending with 01.cpp find c:\\zpaqfranz *01.cpp"); moreprint("Search all .cpp find c:\\zpaqfranz *.cpp -verbose"); moreprint("Search *francia* BEWARE DOUBLE QUOTE! find /root \"*francia*\""); moreprint("Search filtered on date find c:\\zpaqfranz *.cpp -datefrom 20220920 -dateto 2022-10-01"); moreprint("Search every file of 2017 find . -datefrom 2017 -dateto 2017"); moreprint("Search every EXE file of 2017 find . *.exe -datefrom 2017 -dateto 2017"); moreprint("10 biggest cpp find . *.cpp -orderby size -desc -limit 10 -verbose"); } return("Search file(s) with the wildcards"); } string help_e(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD e Extract on current folder"); moreprint("+ : Shortcut for extracting on Windows with longpath"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Extract everything 'here' e z:\\1.zpaq -longpath"); } return("Extract the file(s) in the current folder"); } string help_dirsize(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD dirsize Show cumulative folder(s) size"); moreprint(" Case INsensitive ENDING with parameters (unless -force)"); moreprint(" i.e. marcus == /1/marcus, /tank/d/documenti/MARCUS"); moreprint("+ : -force Exact match; /tank/marcus != /tank/MARCUS"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Search with 2 parameters : dirsize z:\\1.zpaq marcus vanessa"); moreprint("Getting size (insensitive) : dirsize z:\\1.zpaq /tank/d/documenti/marcus -force"); } return("Show cumulative folder(s) size"); } #ifdef _WIN32 string help_sfx(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD sfx (sfx module, with encryption support)"); moreprint("+ : (no switch): Write SFX along the .zpaq"); moreprint(" (w/switch) : Convert .zpaq (max 2GB) to Windows .EXE"); moreprint("+ : -to X Extract the .zpaq from a .exe into X"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Create z:\\1.exe : sfx z:\\1.zpaq"); moreprint("Convert 1.zpaq to 2.exe : sfx z:\\1.zpaq -sfx z:\\2.exe"); moreprint("Extract sfx module : sfx z:\\64bit.exe"); moreprint("Extract the zpaq (if any) : sfx z:\\1.exe -to z:\\1.zpaq -space -force"); } return("Create SFX module (with encryption support)"); } #endif // corresponds to #ifdef (#ifdef _WIN32) string help_rsync(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD rsync Delete dangling temporary rsync file"); moreprint("+ : -kill Wet run (default: dry run)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Purge temporary (dry run): rsync \\\\nas\\thebackup"); moreprint("Purge temporary (WET run): rsync \\\\nas\\thebackup -kill"); } return("Delete rsync's dangling temporary files"); } string help_t(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD t (test)"); moreprint("+ : NO PATH: check all blocks, and CRC-32s of the files"); moreprint(" corresponds to what would be generated by extracting"); moreprint(" WITH PATH: compares files/folders in the path(s) with the"); moreprint(" archive's content"); moreprint("+ : -checksum Enable hash checksums"); moreprint("+ : -verify Do a filesystem post-check: STORED CRC==DECOMPRESSED==FROM FILE."); moreprint("+ : -verify -ssd Multithread verify (do NOT use on spinning drives)"); moreprint("+ : -find pippo For path-rework of verify"); moreprint("+ : -replace plu For path-rework of verify (find and replace)"); moreprint("+ : -paranoid Extract all into -to something, check every file with stored hash"); moreprint("+ : delete every equal files"); moreprint("+ : -collision Test collisions"); moreprint("+ : -quick Do not check hash, only size/date"); moreprint("+ : -crc32 Run a triple CRC-32 check (!) against the filesystem"); moreprint("+ : Use -find/replace to fix path (if needed); -ssd for M/T"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Last version: t z:\\1.zpaq"); moreprint("All versions: t z:\\1.zpaq -all"); moreprint("Last+Against filesystem, 4 threads: t z:\\1.zpaq -verify -ssd -t4"); moreprint("Real paranoid: extract all t z:\\1.zpaq -to z:\\knb -paranoid"); moreprint("Multiple paranoid check (Win): t *.zpaq -to z:\\temp\\ -paranoid -longpath -big"); moreprint("Multiple test (*NIX): t \"/copie/*.zpaq\" "); moreprint("Compare with string manipulation: t z:\\2 c:\\nz -find k:\\nz -replace c:\\nz -verify"); moreprint("All version SHA-1 collisions: t z:\\1.zpaq -collision -all"); moreprint("Triple check CRC-32: t z:\\1.zpaq -crc32"); moreprint("3 check w/path manipulation: t z:\\1.zpaq -crc32 -find \"x:/memme/\" -replace \"c:/nz/\""); moreprint("BEWARE: path(s) changes the logic!"); moreprint("Fast-SHA1 (nz the source dir): t z:\\1.zpaq c:\\nz"); moreprint("SHA1 + hash: t z:\\1.zpaq c:\\nz -verify"); moreprint("Quick-and-dirty size/date t z:\\1.zpaq c:\\nz c:\\kz -quick"); } return("Test archive integrity/compare with filesystem"); } string help_v(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD v (verify)"); moreprint("+ : Verify all files (by hashes) against filesystem"); moreprint("+ : -ssd Multithread (for SSD/NVMe). Do NOT use on spinning drives"); moreprint("+ : -tX Limit -ssd to X threads"); moreprint("+ : -until Y Check the version Y"); moreprint("+ : -find pippo For path-rework of verify"); moreprint("+ : -replace plu For path-rework of verify (find and replace)"); moreprint("+ : -verbose Show distinct errors"); moreprint("+ : -debug Show a lot of info"); moreprint("+ : -output x.txt Put errors in x.txt (alias -out)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Last version: v z:\\1.zpaq"); moreprint("Show errors line by line: v z:\\1.zpaq -verbose"); moreprint("2n version: v z:\\1.zpaq -until 2"); moreprint("Remake path: v z:\\1.zpaq -find c:\\dropbox -replace z:\\knb"); moreprint("1st version, multithread: v z:\\1.zpaq -until 1 -ssd"); } return ("Verify an archive (against filesystem)"); } string help_p(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD p (paranoid test)"); moreprint("+ : Test the archive (** NOT multipart **) in a very paranoid fashion."); moreprint(" ZPAQ reference decompressor is used to extract blocks in RAM."); moreprint(" Runs on unzpaq206.cpp source instead of 7.15 extract: double check"); moreprint(" to avoid the risk of 'silent' bugs. The RAM needed can"); moreprint(" quickly become unmanageable (warn: be very careful with 32bit versions)."); moreprint("+ : -noeta Brief"); moreprint("+ : -verbose Shows positive checks"); moreprint("+ : -verify Next level (mine) of paranoia: check hashes against the filesystem."); moreprint(" Essentially equivalent to extracting in a temporary folder and check"); moreprint(" against initial folders. For very paranoid people, or debug reason."); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Paranoid, use a lot of RAM: p z:\\1.zpaq"); moreprint("Very paranoid, use a lot of RAM: p z:\\1.zpaq -verify"); } return("Paranoid test (slow, a lot of RAM needed)"); } string help_c(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD c (compare dirs)"); moreprint("+ : Compare a 'master' directory (d0) against N 'slaves' (d1, d2... dN)."); moreprint(" The slaves are made by zpaq restores, or rsync, robocopy, zfs replica."); moreprint(" It is not easy to check on different filesystems (ex. NAS-Linux, NTFS)"); moreprint(" By default check file name and file size (excluding .zfs), not the content."); moreprint("+ : -ssd Concurrent threads will be created, each scan a slave dir (-t K to limit)."); moreprint(" NOT good for single spinning drives, good for multiple slaves on different media."); help_printhash(false); help_size(); moreprint("+ : -715 Work as 7.15 (with .zfs and ADS)"); moreprint("+ : -forcezfs Include .zfs"); moreprint("+ : -checksum Run hash compare"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Compare master d0 against d1,d2,d3: c c:\\d0 k:\\d1 j:\\d2 p:\\d3"); moreprint("Multithread compare: c c:\\d0 k:\\d1 j:\\d2 p:\\d3 -ssd"); moreprint("Hashed compare d0 against d1,d2,d3: c c:\\d0 k:\\d1 j:\\d2 p:\\d3 -checksum -xxh3"); } return("Compare one master dir against one or more slaves dir(s)"); } string help_s(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD s (size)"); moreprint("+ : Cumulative size of N directory, and free space (estimate for *Nix)."); moreprint(" Everything containing .zfs and :$DATA (Windows's ADS) ignored by default"); moreprint(" Very quick-and-dirty check of rsynced folders against the master"); moreprint("+ : -ssd for multithreaded executions (warning for single spinning drive)"); moreprint("+ : -minsize X Show a warning if free space < X"); moreprint("+ : -715 Work as 7.15 (with .zfs and ADS)"); moreprint("+ : -forcezfs Include .zfs"); moreprint("+ : -home Show 1-level cumulative size"); moreprint("+ : -ignore Do not show file errors (ex. ERROR_ACCESS_DENIED)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Dir cumulative size (no .zfs/NTFS): s r:\\vbox s:\\uno"); moreprint("Multithreaded size: s r:\\vbox s:\\uno -ssd"); moreprint("(Kind of) size of c:\\users s c:\\users -home -ssd -ignore"); } return("Get dir(s) size, return free disk space"); } string help_oneonone(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD 1on1 Julius Erving and Larry Bird Go One on One"); moreprint("+ : Deduplicate a folder against another one"); moreprint("+ : -deleteinto X Delete files in X (if any)"); moreprint("+ : -checksum Only rely on checksums (NOT filenames)"); ///moreprint("+ : -zero Deduplicate 0-length files too"); moreprint("+ : -ssd Multithreaded executions (warning for single spinning drive)"); moreprint("+ : -forcezfs Do not exclude zfs files (default: IGNORE)"); moreprint("+ : -kill Wet run (default: DRY RUN)"); help_printhash(false); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Dry run, =hash,=filename,multithread 1on1 c:\\dropbox -deleteinto z:\\pippero2 -ssd"); moreprint("Real run, 0-files too 1on1 c:\\dropbox -deleteinto z:\\pippero2 -zero -kill"); moreprint("Real run, with XXH3, with * 1on1 c:\\dropbox -deleteinto z:\\pippero2 -xxh3 -kill -forcezfs"); } return("Delete folder2's files with same name/hash of folder1"); } string help_r(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD r ('robocopy')"); moreprint("+ : Mirror a master folder, just like robocopy /mir or rsync -a --delete"); moreprint(" to one or more slave (destination) folders"); print_sub(); moreprint(" ENFORCING XLS, ignore .zfs and ADS by default"); moreprint("+ : -kill wet run (default: dry-run"); moreprint("+ : -space do not exit if not enough space reported"); moreprint("+ : -ssd run one thread for folder"); moreprint("+ : -verify after copy quick check if OK (only filename and size)"); moreprint("+ : -checksum heavy (hash) test of equality. Suggest: -xxh3 fast and reliable."); help_size(); moreprint("+ : -xls Do not enforce backup of XLS/PPT"); moreprint("+ : -715 Work as 7.15 (with .zfs and ADS)"); moreprint("+ : -forcezfs Include .zfs"); moreprint("+ : -append Only append data (*risky, use with zpaq archives)"); moreprint("+ : -zero Fill all output file with zeros (for debug)"); moreprint("+ : -verbose Show internal timings"); moreprint("+ : -buffer X Use a input buffer of X bytes (default: 1MB)"); moreprint("+ : -pakka Check-before-touch (faster for big tree over LAN)"); #ifdef _WIN32 moreprint("+ : -big Special Windows function for big files over LAN"); #endif // corresponds to #ifdef (#ifdef _WIN32) } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Robocopy d0 in d1,d2 (dry run): r c:\\d0 k:\\d1 j:\\d2 p:\\d3"); moreprint("Robocopy d0 in d1,d2 (WET run): r c:\\d0 k:\\d1 j:\\d2 p:\\d3 -kill"); moreprint("Robocopy with verify (WET run): r c:\\d0 k:\\d1 j:\\d2 p:\\d3 -kill -verify"); moreprint("Robocopy with hash verify (WET run): r c:\\d0 k:\\d1 j:\\d2 p:\\d3 -kill -verify -checksum -xxh3"); moreprint("Robocopy d0 in d1, forced (WET run): r c:\\d0 k:\\d1 j:\\d2 -kill -space"); moreprint("Robocopy append mode (WET run): r c:\\d0 z:\\backup_%day -append -kill"); moreprint("Robocopy d0 in d1,w/infos (WET run): r c:\\d0 k:\\d1 -kill -verbose"); moreprint("Robocopy d0=>d1 over LAN (WET run): r c:\\d0 \\\\nas\\d1 -kill -verbose -pakka"); #ifdef _WIN32 moreprint("Huge file to NAS (Windows)(WET run): r c:\\d0 \\\\nas\\share\\d1 -kill -big"); #endif // corresponds to #ifdef (#ifdef _WIN32) moreprint("Robocopy only huge files (WET run): r c:\\d0 z:\\dest -kill -minsize 10GB"); moreprint("Robocopy only E01 files (WET run): r c:\\d0 z:\\dest -kill -only *.e01"); } return("Robocopy one master to multiple slave folders"); } string help_cp(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD cp ('friendly copy') "); moreprint("+ : Copy files (with wildcards) into -to folder"); moreprint("+ : with 1 sec progression feedback. Huge file, tiny bandwidth"); moreprint(" and unreliable media (-verify)"); moreprint("+ : By default overwrite, use -paranoid to create unique name"); moreprint("+ : -verify Do an heavy (XXH3) check of copied data"); moreprint("+ : -paranoid Rename output file to do not overwrite"); moreprint("+ : -append Only append data (*risky, use with zpaq archives)"); moreprint("+ : -force Do no check if destination is writeable"); moreprint("+ : -space Do no check if enough destination free space"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Copy k:\\*.mp4 d:\\a.txt in z:\\pluto cp k:\\*.mp4 d:\\a.txt -to z:\\pluto"); moreprint("Copy with verify cp k:\\*.mp4 -to z:\\pluto -verify"); moreprint("Copy WITHOUT overwrite cp k:\\*.mp4 -to z:\\pluto -paranoid"); moreprint("Resumable copy (append only) cp k:\\*.zpaq -to z:\\pluto -append"); } return("Friendly file copy with ETA (resumable)"); } string help_zfs(bool i_usage,bool i_example) { if (i_usage) { moreprint("On UNIX you get some zfs-specific commands\n"); moreprint("--- Enumerate / delete snapshots / sizeof"); moreprint("zfslist"); moreprint("zfspurge"); moreprint("zfssize"); moreprint("--- Freezing snapshot inside archive"); moreprint("zfsadd"); moreprint("--- Make / restore zfs backups inside zpaq"); moreprint("zfsbackup"); moreprint("zfsreceive"); moreprint("zfsrestore"); moreprint("--- Make / restore zfs backups of proxmox VM"); moreprint("zfsproxbackup"); moreprint("zfsproxrestore"); } if (i_example) { moreprint("Ask extensive help, example zpaqfranz h zfsadd zpaqfranz h zfslist"); } return "Bunch of zfs-specific commands"; } string help_zfsadd(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsadd Freeze a selection of snapshots into an archive"); moreprint(" Optional subfolder as 3rd parameter"); moreprint("+ : -script pi.sh Write a script-ready on pi.sh (alias -out)"); moreprint("+ : -force Do the freezing (wet run)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint(""); moreprint("**** LUKE... REMEMBER... !USE THE DOUBLEQUOTES! ..."); moreprint(""); moreprint(" BEWARE of single - \"-pippo\" DOES NOT WORK!"); moreprint(""); moreprint("zfsadd /tmp/kong.zpaq \"tank/d@2021\" \"--60d\""); moreprint("zfsadd /tmp/kong.zpaq \"tank/d@2021\" \"--60d\" \"scanner\""); moreprint("zfsadd /tmp/kong.zpaq \"tank/d@2021\" \"--60d\" \"scanner\" -force"); moreprint("zfsadd /tmp/kong.zpaq \"tank/d@2021\" \"--60d\" \"scanner\" -script ./dothejob.sh"); } return("Freeze zfs' snapshots inside the archive"); } string help_zfspurge(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfspurge Destroy selected zfs snapshot (works like zfslist)"); moreprint("+ : -script pi.sh Write a script-ready on pi.sh (alias -out)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint(""); moreprint("**** LUKE... REMEMBER... !USE THE DOUBLEQUOTES! ..."); moreprint(""); moreprint(" BEWARE of single - \"-pippo\" DOES NOT WORK!"); moreprint(""); moreprint("zfspurge \"tank/d@2021\" \"--60d\""); moreprint("zfspurge \"*\" \"*\""); moreprint("zfspurge \"tank\" \"--7d\""); moreprint("zfspurge \"tank\" \"--7d\" -script mygoodscript.sh"); } return("Purge snapshots with wildcards"); } string help_zfslist(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfslist Show (/filtering) existing zfs snapshot"); moreprint("+ : -script pi.sh Write a script-ready on pi.sh (alias -out)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { if ((g_optional=="zfslist") || (g_optional=="")) { moreprint(""); moreprint("**** LUKE... REMEMBER... !USE THE DOUBLEQUOTES! ..."); moreprint(""); moreprint(" BEWARE of single - \"-pippo\" DOES NOT WORK!"); moreprint(""); moreprint("zfslist \"tank/d@\""); moreprint("zfslist \"*\""); moreprint("zfslist \"*\" \"syncoid\""); moreprint("zfslist \"*\" \"10d\" -script pippo.sh"); } } return("List zfs' snapshots with wildcard"); } string help_zfssize(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfssize Show (/filtering) the SIZE of existing zfs snapshot"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { if ((g_optional=="zfssize") || (g_optional=="")) { moreprint(""); moreprint("**** LUKE... REMEMBER... !USE THE DOUBLEQUOTES! ..."); moreprint(""); moreprint(" BEWARE of single - \"-pippo\" DOES NOT WORK!"); moreprint(""); moreprint("zfssize \"tank/d@\""); moreprint("zfssize \"*\""); moreprint("zfssize \"*\" \"syncoid\""); moreprint("zfssize \"*\" \"10d\" -script pippo.sh"); } } return("List zfs' SIZE of snapshots with wildcard"); } string help_zfsproxbackup(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsproxbackup"); moreprint(" Archiving proxmox backups (from zfs local storage)"); moreprint(" Getting VM disks from /var/lib/vz"); moreprint("+ : -force Destroy temporary snapshot (before backup)"); moreprint("+ : -kill Remove snapshot (after backup)"); moreprint("+ : -all Get all VM"); moreprint("+ : -not Do not backup (exclude)"); moreprint("+ : -snapshot kj Make 'snapname' to kj (default: francoproxmox)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Backup/encrypt w/key 'pippo' VM 200 zfsproxbackup /bak/200.zpaq 200 -force -kill -key pippo"); moreprint("Backup 2 VMs: 200 and 300 zfsproxbackup /bak/200_300.zpaq 200 300"); moreprint("Backup ALL VMs zfsproxbackup /bak/all.zpaq -all -force -kill"); moreprint("Backup all EXCEPT 200 and 300 zfsproxbackup /bak/part.zpaq -all -not 200 -not 300 -force -kill"); } return("Backup of proxmox on zfs"); } string help_zfsproxrestore(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsproxrestore"); moreprint(" Restore proxmox backups (on local storage)"); moreprint(" into /var/lib/vz and /etc/pve/qemu-server"); moreprint(" Without files selection restore everything"); moreprint(" Files can be a sequence of WMIDs (ex. 200 300)"); moreprint("+ : -kill Remove snapshot (after backup)"); moreprint("+ : -not Do not restore (exclude)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Restore all VMs zfsproxrestore /backup/allvm.zpaq"); moreprint("Restore 2 VMs: 200 and 300 zfsproxrestore /backup/allvm.zpaq 200 300"); moreprint("Restore VM 200, release snapshot zfsproxrestore /backup/allvm.zpaq 200 -kill"); moreprint("Restore all VMs, except 200 zfsproxrestore /backup/allvm.zpaq -not 200 -kill"); } return("Restore of proxmox on zfs"); } string help_zfsbackup(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsbackup Backup w/incremental zfs snapshots for long-term storage"); moreprint("+ : Usually root privileges required"); moreprint("+ : -snapshot kj Make 'snapname' to kj (default: zpaqfranco)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Update tank/d backup,retain snapshot zfsbackup /tmp/incr.zpaq tank/d"); moreprint("Update tank backup,delete snapshot zfsbackup /tmp/incr.zpaq tank -kill"); moreprint("Update tank/d backup,w/hashdeep zfsbackup /tmp/incr.zpaq tank/d"); moreprint("Choose snapmark to 'mycopy' zfsbackup /tmp/incr.zpaq tank/d -snapshot mycopy"); } return("Backup of zfs' streams"); } string help_zfsrestore(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsrestore Prepare a script for restoring from EXTRACTED .zfs backup files"); moreprint("+ : -snapshot kj Make 'snapname' to kj (default: franco)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Restore *.zfs into /rez to rpool/rk zfsrestore /rez rpool/rk -script myscript.sh"); moreprint("Restore *.zfs into /rez to rpool/rk zfsrestore /rez rpool/rk -script myscript.sh -snapshot ugo"); } return("Restore from extracted .zfs stream"); } string help_zfsreceive(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD zfsreceive Prepare a script for restoring from zpaq archive"); moreprint("+ : -snapshot kj Make 'snapname' to kj (default: franco)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Rebuild rpool/restored from archive zfsreceive /tmp/ordinato.zpaq rpool/restored -script myscript.sh"); } return("Restore (with zfs) from zpaq archive"); } string help_z(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD z (delete empty directories, zero length)"); moreprint("+ : Remove empty directories in d0...dK folders. Conservative (ex hidden Thumbs.db)"); moreprint("+ : -kill Do a wet run (default dry run)"); moreprint("+ : -verbose Show infos"); #ifdef _WIN32 moreprint("+ : -longpath Extracting on Windows filenames longer than 255"); #endif // corresponds to #ifdef (#ifdef _WIN32) } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Delete empty dirs in d0,d1(dry run): z c:\\d0 k:\\d1"); moreprint("Delete empty dirs in d0,d1(WET run): z c:\\d0 k:\\d1 -kill -longpath"); } return("Remove empty directories"); } string help_m(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD m (merge, consolidate)"); moreprint("+ : Merge a split (multipart) archive into a single one,"); moreprint(" just like a concatenated cat or copy /b"); moreprint("+ : -force Overwrite existing output"); moreprint("+ : -space Ignore lack of free space"); moreprint("+ : -verify Double-check (XXH3 hash test)"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Merge (consolidate) multipart: m \"p:\\test\\prova_???\" z:\\cons.zpaq -verify"); } return("Merge (consolidate) multipart archive into one"); } string help_d(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD d (deduplicate)"); moreprint("+ : Deduplicate a single folder WITHOUT ASKING ANYTHING!"); moreprint("+ : Please note: a FOLDER==ending with /"); moreprint("+ : -ssd Multithread run"); moreprint("+ : -force Wet run (default: dry-run)"); moreprint("+ : -verbose Show duplicated files"); moreprint("+ : -(somehash) Use (somehash), one of the available next two lines, for detection"); help_printhashline(false); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Deduplicate d0 (dry run, w/xxh3) : d c:\\d0\\"); moreprint("Deduplicate d0 (dry run,xxh3,M/T): d c:\\d0\\ -ssd"); moreprint("Deduplicate d0 WITHOUT MERCY (wet): d c:\\d0\\ -kill"); moreprint("Dedup WITHOUT MERCY (wet run,sha256):d c:\\d0\\ -force -sha256"); } return("Deduplicate files inside a single folder WITHOUT MERCY"); } string help_mysqldump(bool i_usage,bool i_example) { if (i_usage) { if (i_usage) { moreprint("CMD mysqldump Dump all MySQL/MariaDB databases into a ZPAQ archive"); moreprint(" Requires 'mysql' (or 'mariadb') and 'mysqldump' (or 'mariadb-dump')"); #ifdef _WIN32 moreprint(" On Windows, append '.exe' to executable names [of course]"); #endif moreprint(" Use one of these methods to locate executables:"); moreprint(" - Specify path with -bin something"); moreprint(" - Let the program search automatically (default)"); #ifdef _WIN32 moreprint(" - Use -space to download from the Internet (Windows only)"); #endif moreprint(""); moreprint("+ : -bin path Path where mysql/mariadb(.exe) and mysqldump/mariadb-dump(.exe) are located"); #ifdef _WIN32 moreprint("+ : -space Download mysql.exe and mysqldump.exe from the Internet"); #endif moreprint("+ : -u user MySQL/MariaDB username"); moreprint("+ : -p password MySQL/MariaDB password (use quotes if it contains spaces)"); moreprint("+ : -h host MySQL/MariaDB host (e.g., localhost or IP address)"); moreprint("+ : -P port MySQL/MariaDB port (default: 3306)"); moreprint("+ : -key pwd Password for encrypting the ZPAQ archive"); moreprint("+ : -mX ZPAQ compression method (X = 0-5, none to highest)"); moreprint("+ : -verbose Be... verbose"); moreprint("+ : -only pattern Select only databases containing the specified text or matching pattern"); moreprint(" -only 2015 matches any DB containing '2015' (e.g., db2015, test2015prod)"); moreprint("+ : -not pattern Exclude databases containing the specified text or matching pattern"); moreprint(" -not temp matches any DB containing 'temp' (e.g., temporary, temp_db)"); moreprint(" *** Note: System databases (information_schema, performance_schema,"); moreprint(" sys) are automatically excluded"); } } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Dump all databases (Windows): mysqldump z:\\1.zpaq -u root -p pluto -h 127.0.0.1 -P 3306 -key pippo -m2"); moreprint("Get tools from Internet (Windows): mysqldump z:\\1.zpaq -u root -p pluto -space"); moreprint("Auto-search on Linux: mysqldump /tmp/test.zpaq -u root -p pluto"); moreprint("Specify path on Linux: mysqldump /tmp/test.zpaq -u root -p pluto -bin \"/bin\""); moreprint("Include databases with '2015': mysqldump test.zpaq -u root -p pluto -only 2015"); moreprint("Exclude databases with 'geo': mysqldump test.zpaq -u root -p pluto -not geo"); moreprint("Multiple conditions: mysqldump test.zpaq -u root -p pluto -only prod -not backup"); } return("Dump all mysql databases inside a .zpaq"); } string help_utf(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD utf (deal with strange filenames)"); moreprint("+ : Check (or sanitize) paths with non-latin chars"); moreprint(" Can become a real problem extracting on different filesystems (ex. *nix => NTFS)"); moreprint("+ : -kill Wet run (default dry run)"); moreprint("+ : -verbose Show what is running"); moreprint("+ : -fix255 Show files too long"); /* moreprint("+ : -utf Sanitize filenames (strip non-latin)"); moreprint("+ : -fix255 Sanitize file length and filecase collisions pippo.txt PIPPO.txt)"); moreprint("+ : -fixeml Sanitize .eml filenames (Fwd Fwd Fwd => Fwd)"); moreprint("+ : -dirlength X Set the 'fix' limit"); moreprint("+ : -filelength Y Set the 'fix' limit"); */ } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Check UTF-filenames (dry run): utf z:\\knb"); moreprint("Sanitize UTF-filenames (wet run): utf z:\\knb -kill"); /* moreprint("Check >255 and case collisions: utf z:\\knb -fix255"); moreprint("Fix .eml filenames (dry run): utf z:\\knb -fixeml"); */ } return("Convert filenames to Latin, fix too long filenames etc."); } string help_f(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD f (fill, or wipe)"); moreprint("+ : Fill (wipe) 99% of free disk space in 500MB chunks"); moreprint(" Check if disk-controller-system-RAM-cache-cables are working fine"); moreprint("+ : -verbose Show write speed (useful to check speed consistency)"); moreprint("+ : -force Do NOT delete (after run) the temporary filename. By default free"); moreprint("+ : -zero Zero-fill instead of random. Use to prepare a thin VMDK shrink"); moreprint("+ : -verify For -zero: do a verify."); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Fill (wipe) almost all free space: f z:\\"); moreprint("Fill (wipe) keep temp files: f z:\\ -force -verbose"); moreprint("Zero free space (VM shrink): f z:\\ -zero"); moreprint("Zero free space (WITH verify): f z:\\ -zero -verify"); } return("Free disk space fills (=reliability test) or wipe (privacy)"); } string help_summa(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD sum"); moreprint("CMD sha1 (retained for historical reasons, 7.15 always uses SHA-1 only)"); moreprint("+ : Calculate hash/cksum of files/dirs, dupes and cumulative GLOBAL SHA256"); moreprint(" (If two directories have the same GLOBAL SHA256 they are ==)"); moreprint(" With no switches, by default, use SHA-1 (reliable, but not very fast)"); help_printhash(false); moreprint("+ : -ssd make N thread (do not use with spinning HDDs, but SSDs and NVMes)"); moreprint("+ : -mm use memory mapped file instead of 'regular' fread"); moreprint("+ : -kill show the files to be deleted to manually deduplicate"); moreprint("+ : -home get a 1-level checksum, for comparing hierarchically user-organized folders."); moreprint("+ : -summary show only GLOBAL (fast manual compare of directories)"); moreprint("+ : -rename rename all files with the hash"); moreprint("+ : -forcezfs force .zfs path (DEFAULT: skip)"); moreprint("+ : -kill -force runs a deduplication without ask anything!"); help_size(); moreprint("+ : -715 Work as 7.15 (with .zfs and ADS)"); moreprint("+ : -checktxt kaj Check MD5 against kaj file. For rsync/rclone sync"); moreprint("+ : -hashdeep Make (into mandatory -out) hashdeep-compatible output"); moreprint("+ : -zeta Make the ZETA hash"); moreprint("+ : -zetaenc Make the ZETA-encrypted hash"); help_orderby(); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("SHA1 of all files (and duplicated): sum z:\\knb"); moreprint("SHA1 multithread, only summary: sum z:\\knb -ssd -summary"); moreprint("XXH3 multithread: sum z:\\knb -ssd -xxh3"); moreprint("CRC-32c HW accelerated: sum z:\\knb -crc32c -pakka -noeta"); moreprint("Hashes to be compared (dir1): sum c:\\nz -pakka -noeta -nosort -crc32c -find c:\\nz -replace bakdir >1.txt"); moreprint("Hashes to be compared (dir2): sum z:\\knb -pakka -noeta -nosort -crc32c -find z:\\knb -replace bakdir >2.txt"); moreprint("Duplicated files with sha256: sum z:\\knb -kill -sha256"); moreprint("Duplicated files minsize 1000000: sum z:\\knb -kill -ssd -minsize 1000000"); moreprint("MAGIC cumulative hashes of 1-level: sum p:\\staff -xxh3 -home -ssd"); moreprint("BLAKE3 multithread from memory map: sum z:\\knb -ssd -blake3 -mm"); moreprint("MD5 quick check sum z:\\knb.zpaq -checktxt z:\\pippo.txt"); moreprint("hashdeep-compatible (multithread) sum *.jpg *.cpp -hashdeep -ssd -out z:\\thehash.txt"); moreprint("like md5sum sum *.txt -md5 -pakka -noeta -stdout -nosort"); moreprint("Order the output sum z:\\ -xxh3 -orderby size -desc -only *.cpp"); moreprint("ZETA multithread: sum z:\\knb -ssd -zeta"); } return("Calc hash/checksums, find duplicated files"); } string help_hasha(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD hash Calculate hash of files/dirs"); moreprint(" With no switches, by default, use SHA-1 (reliable, but not very fast)"); help_printhash(false); moreprint("+ : -ssd make N thread (do not use with spinning HDDs, but SSDs and NVMes)"); moreprint("+ : -mm use memory mapped file instead of 'regular' fread"); moreprint("+ : -forcezfs force .zfs path (DEFAULT: skip)"); help_size(); moreprint("+ : -715 Work as 7.15 (with .zfs and ADS)"); moreprint("+ : -verbose Show more infos"); moreprint("+ : -stdout Do not mess the output"); moreprint("+ : -pakka Do not mess the output"); moreprint("+ : -noeta Do not show ETA"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("SHA1 of all files: hash z:\\knb"); moreprint("SHA1 of all files, multithread: hash z:\\knb -ssd"); moreprint("XXH3 multithreaded: hash z:\\knb -ssd -xxh3"); moreprint("SHA256 to file: hash z:\\knb -ssd -sha256 -stdout -out 1.txt"); } return("Calc hash"); } string help_dir(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD dir (yes, dir as in Windows, even better)."); moreprint("+ : I really hate ls: does not show the cumulative filesize (!)"); moreprint(" 'Mini clone' of Windows's dir command, with the main switches"); moreprint("+ : /s Recursive (note: Win-switch must be BEFORE 'normal' switch"); moreprint("+ : /os Order by size"); moreprint("+ : /a Show all (hidden)"); moreprint("+ : -checksum Show hashes for every file"); moreprint("+ : -(somehash) Use (somehash) to find duplicate/show checksums"); help_printhashline(false); moreprint("+ : -n X like |tail -X"); help_size(); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint("Windows-dir command clone: dir /root/script /od"); moreprint("Show the 10 largest .mp4 file in c:\\:dir c:\\ /s /os -n 10 -find .mp4"); moreprint("Find .mp4 duplicate in C:\\: dir c:\\ /s -crc32 -find .mp4"); moreprint("How big is c:\\z,with subdirs?: dir c:\\z /s -n 1"); moreprint("100 biggest dup. files in c:\\z?: dir c:\\z /s -crc32 -n 100"); moreprint("Show -md5 checksum, recurse by size: dir z:\\cb /s /os -checksum -md5"); moreprint("Find duplicate, recurse by size: dir z:\\cb /s /os -xxh3"); moreprint("Like dir: dir z:\\cb\\*.avi"); moreprint("Better than dir: dir c:\\*.cpp /s /os -n 100"); moreprint("Get last 5 backup files: dir c:\\backup\\*.zpaq /on -n 5 -terse"); } return("A better dir (yes, Windows' dir)"); } string help_k(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD k (kill, risky!)"); moreprint("+ : Kill (delete) all files and directories that aren't in an archive"); moreprint(" removing excess files"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint(" RISKY COMMAND: DO NOT USE IF YOU DO NOT UNDERSTAND!"); moreprint("Create an archive a z:\\1.zpaq c:\\z"); moreprint("Extract into z:\\knb x z:\\1.zpaq c:\\z -to z:\\knb"); moreprint("... something happens (change) in"); moreprint("z:\\knb and we want to turn back"); moreprint("WITHOUT delete everything and "); moreprint("extract again (maybe it's huge): k z:\\1.zpaq c:\\z -to z:\\knb"); } return("Kill (delete) everything not in the archive (RISKY!)"); } string help_n(bool i_usage,bool i_example) { if (i_usage) { moreprint("CMD n (decimatioN)"); moreprint("+ : Keep -n X files in a folder (NO recursive scan), delete all the others"); moreprint(" At least one * must be used to filter."); moreprint(" with -exec execute external command"); moreprint("+ : -kill Do a wet run (default dry run)"); moreprint("+ : -exec p.bat Instead of delete launch p.bat with parameter"); moreprint("+ : /od Order by date (default)"); moreprint("+ : /on Order by name"); moreprint("+ : -verbose Show infos"); moreprint("+ : -force Continue even if >50 files founded"); } if (i_usage && i_example) moreprint(" Examples:"); if (i_example) { moreprint(" RISKY COMMAND: DO NOT USE IF YOU DO NOT UNDERSTAND!"); moreprint("Keep 10 newest files in z:\\1\\ n z:\\1\\*.txt -n 10 -kill"); moreprint("Keep 20 ordered by name n z:\\1\\dumpy_*.sql -n 20 -kill -force /on"); moreprint("Keep 30 txt ordered by name n z:\\1\\*.txt -n 20 -kill -force /on"); moreprint("Check the last file with ugo.bat n z:\\1\\*.txt -kill -exec ugo.bat"); } return("Decimate (keeping the newer X) older files"); } string help_mainswitches(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) { moreprint(" -all [N]: All versions (default 4 digits)"); moreprint(" -key X: Archive password X"); moreprint(" -mN -method N:0=no compression, 1..5=faster..better "); moreprint(" -force: Always overwrite"); moreprint(" -test: Verify (extract/add)"); moreprint(" -kill: Allow destructive operations ('wet runs')"); moreprint(" -to out...: Prefix files to out"); moreprint(" -until N: Roll back to N'th version"); #ifdef HWSHA1 moreprint(" -hw: Hardware-accelerated SHA1 code (not in all CPUs)"); #endif // corresponds to #ifdef (#ifdef HWSHA1) #ifdef HWSHA2 /// moreprint(" -hw: Hardware-accelerated SHA1/2 code (not in all CPUs)"); #endif // corresponds to #ifdef (#ifdef HWSHA2) } return("Most used switches"); } string help_switches(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) { char buffer[200]; time_t nowz=time(NULL); tm* t=gmtime(&nowz); int64_t date=(t->tm_year+1900)*10000000000LL+(t->tm_mon+1)*100000000LL +t->tm_mday*1000000+t->tm_hour*10000+t->tm_min*100+t->tm_sec; snprintf(buffer,sizeof(buffer)," -until %s Set date, roll back (UT, default time: 235959)",dateToString(flagutc,date).c_str()); moreprint(buffer); moreprint(" -not files... Exclude. * and ? match any string or char"); moreprint(" =[+-#^?] List: exclude by comparison result"); moreprint(" -only files... Include only matches (default: *) example *pippo*.mp4"); moreprint(" -always files Always (force) adding some file"); moreprint(" -noattributes Ignore/don't save file attributes or permissions"); moreprint(" -index F Extract: create index F for archive"); moreprint(" Add: create suffix for archive indexed by F, update F"); moreprint(" -sN -summary N If >0 show only summary (sha1())"); } return("Usual switches"); } string help_commonswitches(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) g_programflags.tutti(); return("(Almost) all common switches"); } string help_franzswitches(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) { moreprint("+ : f-big ASCII art on final result"); moreprint("+ : -utc Do not convert to localtime (use UTC, like 715)"); moreprint("+ : -715 Works just about like v7.15"); moreprint("+ : -checksum Store SHA1+CRC32 for every file"); moreprint("+ : -verify Force re-read of file during t (test command) or c"); moreprint("+ : -noeta Do not show ETA"); moreprint("+ : -pakka Output for PAKKA (briefly)"); moreprint("+ : -verbose Show more"); moreprint("+ : -silent Be mute (!)"); moreprint("+ : -summary Concise output"); moreprint("+ : -zfs Skip paths including .zfs"); moreprint("+ : -forcezfs Force paths including .zfs"); moreprint("+ : -noqnap Skip path including @Recently-Snapshot and @Recycle"); moreprint("+ : -nomac Skip ._something and .DS_Store and Thumbs.db"); moreprint("+ : -nosynology Skip #snapshot, #recycle etc"); moreprint("+ : -forcewindows Take $DATA$ and System Volume Information"); moreprint("+ : -xls Do NOT always force XLS/PPT"); moreprint("+ : -nopath Do not store path"); moreprint("+ : -nosort Do not sort file when adding or listing"); moreprint("+ : -find X Search for X in full filename (ex. list)"); moreprint("+ : -replace Y Replace X with Y in full filename (ex. list)"); moreprint("+ : -n X Only print last X lines in dir (like tail)/first X (list)"); moreprint("+ : -limit X (like -n)"); help_size(); moreprint("+ : -filelength X Utf command: find file with length>X, extract maxfilelen"); moreprint("+ : -dirlength X Utf command: find dirs with length>X, extract maxdirlen"); moreprint("+ : -comment foo Add/find ASCII comment string to versions"); #if defined(_WIN32) moreprint("+ : -vss Do a VSS for drive C: (Windows with administrative rights)"); moreprint("+ : -open Check if .zpaq is already open => abort if yes"); #endif // corresponds to #if (#if defined(_WIN32)) help_printhash(false); moreprint("+ : -exec_ok f.sh After OK launch f.sh"); moreprint("+ : -exec_error z After NOT OK launch z"); moreprint("+ : -exec_warn cz At Warn launch cz"); moreprint("+ : -exec pip.bat Launch pip.bat %1 with command n"); moreprint("+ : -output s.txt Output on s.txt too (alias: -out)"); moreprint("+ : -kill Show 'script-ready' log of dup files"); moreprint("+ : -kill In extraction write 0-bytes file instead of data"); moreprint("+ : -utf Remove non-utf8 chars"); moreprint("+ : -utf8 Like -utf"); moreprint("+ : -fix255 Shrink total file length and case collisions (NTFS)"); moreprint("+ : -fixeml Heuristically compress .eml filenames (Fwd Fwd Fwd =>Fwd)"); moreprint("+ : -flat Everything in single path (emergency extract of strange files)"); moreprint("+ : -debug Show lot of infos (superverbose)"); moreprint("+ : -timestamp X Set version datetime@X 14 digit (2021-12-30_01:03:04)"); // force the timestamp help_date(); moreprint("+ : -filelist Store the add() list in VFILE-l-filelist.txt"); moreprint("+ : -nodedup Disabling deduplication"); help_orderby(); moreprint("+ : -store Store mode: turn off deduplication and compression"); moreprint("+ : -norecursion Do not recurse into folders (default: YES)"); moreprint("+ : -nocolor disable colors"); #ifdef _WIN32 moreprint("+ : -longpath add/extract on Windows filenames longer than 255"); moreprint("+ : -noconsole disable console manipulation (older Windows)"); moreprint("+ support env variable NO_CONSOLE (no-color.org)"); #endif // corresponds to #ifdef (#ifdef _WIN32) } return("Advanced switches"); } /* void print_a_level(vector* i_level) { if (i_level==NULL) return; string temp; temp=""; for (unsigned int i=0;i<(*i_level).size();i++) { string dummy=(*i_level)[i]; myreplaceall(dummy,"*.",""); temp +=dummy; if (i!=(*i_level).size()-1) temp+=","; if (temp.size()>=60) { myreplaceall(temp,"*.",""); moreprint(temp.c_str()); temp=""; } } if (temp!="") moreprint(temp.c_str()); } void Jidac::internal_listpaqlevel() { loadpaqlevel(); if (level0.size()>0) { moreprint("+ : -level0 Do not compress (store)"); print_a_level(&level0); } if (level1.size()>0) { moreprint("+ : -level1 Compress fast (default) 128MB/thread"); print_a_level(&level1); } if (level2.size()>0) { moreprint("+ : -level2 Compress a bit more 450MB/thread"); print_a_level(&level2); } if (level3.size()>0) { moreprint("+ : -level3 Compress more 450MB/thread"); print_a_level(&level3); } if (level4.size()>0) { moreprint("+ : -level4 Compress a lot 550MB/thread"); print_a_level(&level4); } if (level5.size()>0) { moreprint("+ : -level5 Placebo level 850MB/thread"); print_a_level(&level5); } } string help_paq(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) { if (pjidac!=NULL) (*pjidac).internal_listpaqlevel(); } return("Shows -paq autolevels"); } */ string help_voodooswitches(bool i_usage,bool i_example) { if ((i_usage) || (i_example)) { moreprint(" -repack F [X] Extract to new archive F with key X (default: none)"); moreprint(" -tN -threads N Use N threads (default: 0 = all cores)"); moreprint(" -fragment N Use 2^N KiB average fragment size (default: 6)"); moreprint(" -mNB -method NB Use 2^B MiB blocks (0..11, default: 04, 14, 26..56)"); moreprint(" -method {xs}B[,N2]...[{ciawmst}[N1[,N2]...]]... Advanced:"); moreprint(" x=journaling (default). s=streaming (no dedupe)"); moreprint(" N2: 0=no pre/post. 1,2=packed,byte LZ77. 3=BWT. 4..7=0..3 with E8E9"); moreprint(" N3=LZ77 min match. N4=longer match to try first (0=none). 2^N5=search"); moreprint(" depth. 2^N6=hash table size (N6=B+21: suffix array). N7=lookahead"); moreprint(" Context modeling defaults shown below:"); moreprint(" c0,0,0: context model. N1: 0=ICM, 1..256=CM max count. 1000..1256 halves"); moreprint(" memory. N2: 1..255=offset mod N2, 1000..1255=offset from N2-1000 byte"); moreprint(" N3...: order 0... context masks (0..255). 256..511=mask+byte LZ77"); moreprint(" parse state, >1000: gap of N3-1000 zeros"); moreprint(" i: ISSE chain. N1=context order. N2...=order increment"); moreprint(" a24,0,0: MATCH: N1=hash multiplier. N2=halve buffer. N3=halve hash tab"); moreprint(" w1,65,26,223,20,0: Order 0..N1-1 word ISSE chain. A word is bytes"); moreprint(" N2..N2+N3-1 ANDed with N4, hash mulitpiler N5, memory halved by N6"); moreprint(" m8,24: MIX all previous models, N1 context bits, learning rate N2"); moreprint(" s8,32,255: SSE last model. N1 context bits, count range N2..N3"); moreprint(" t8,24: MIX2 last 2 models, N1 context bits, learning rate N2"); } return("Nerd's switches"); } void Jidac::load_help_map() { /// a map is not so good, but we want to keep the executable small /// NOT in the constructor help_map.insert(std::pair("a",help_a)); help_map.insert(std::pair("b",help_b)); help_map.insert(std::pair("c",help_c)); help_map.insert(std::pair("d",help_d)); help_map.insert(std::pair("e",help_e)); help_map.insert(std::pair("f",help_f)); help_map.insert(std::pair("i",help_i)); help_map.insert(std::pair("k",help_k)); help_map.insert(std::pair("l",help_l)); help_map.insert(std::pair("m",help_m)); help_map.insert(std::pair("n",help_n)); help_map.insert(std::pair("p",help_p)); help_map.insert(std::pair("r",help_r)); help_map.insert(std::pair("1on1",help_oneonone)); help_map.insert(std::pair("s",help_s)); help_map.insert(std::pair("t",help_t)); help_map.insert(std::pair("v",help_v)); help_map.insert(std::pair("w",help_w)); help_map.insert(std::pair("x",help_x)); help_map.insert(std::pair("z",help_z)); help_map.insert(std::pair("find", help_find)); help_map.insert(std::pair("trim", help_trim)); help_map.insert(std::pair("crop", help_crop)); help_map.insert(std::pair("password", help_setpassword)); help_map.insert(std::pair("dirsize", help_dirsize)); help_map.insert(std::pair("cp", help_cp)); help_map.insert(std::pair("dir", help_dir)); help_map.insert(std::pair("sum", help_summa)); help_map.insert(std::pair("hash", help_hasha)); help_map.insert(std::pair("utf", help_utf)); help_map.insert(std::pair("rsync", help_rsync)); help_map.insert(std::pair("pause", help_pause)); help_map.insert(std::pair("isopen", help_isopen)); help_map.insert(std::pair("autotest", help_autotest)); help_map.insert(std::pair("versum", help_versum)); help_map.insert(std::pair("testbackup", help_testbackup)); help_map.insert(std::pair("count", help_count)); help_map.insert(std::pair("comparehex", help_comparehex)); help_map.insert(std::pair("work", help_work)); help_map.insert(std::pair("consolidate", help_consolidatebackup)); help_map.insert(std::pair("backup", help_backup)); help_map.insert(std::pair("last2", help_last2)); help_map.insert(std::pair("last", help_last)); help_map.insert(std::pair("fzf", help_fzf)); help_map.insert(std::pair("collision", help_collision)); help_map.insert(std::pair("dump", help_dump)); help_map.insert(std::pair("redu", help_redu)); help_map.insert(std::pair("mysqldump", help_mysqldump)); #ifndef ANCIENT help_map.insert(std::pair("ls", help_ls)); help_map.insert(std::pair("tui", help_tui)); #endif #ifdef SFTP help_map.insert(std::pair("sftp", help_sftp)); #endif // corresponds to #ifdef (#ifdef SFTP) #if defined(_WIN32) help_map.insert(std::pair("pakka", help_pakka)); help_map.insert(std::pair("ads",help_ads)); help_map.insert(std::pair("g",help_g)); help_map.insert(std::pair("q",help_q)); help_map.insert(std::pair("sfx", help_sfx)); help_map.insert(std::pair("rd", help_rd)); #endif // corresponds to #if (#if defined(_WIN32)) help_map.insert(std::pair("update", help_update)); help_map.insert(std::pair("upgrade", help_update)); #ifdef _WIN64 help_map.insert(std::pair("download", help_download)); #endif // corresponds to #ifdef (#ifdef _WIN64) #if defined(unix) help_map.insert(std::pair("zfs", help_zfs)); help_map.insert(std::pair("zfsproxbackup", help_zfsproxbackup)); help_map.insert(std::pair("zfsproxrestore", help_zfsproxrestore)); help_map.insert(std::pair("zfsbackup", help_zfsbackup)); help_map.insert(std::pair("zfsrestore", help_zfsrestore)); help_map.insert(std::pair("zfsreceive", help_zfsreceive)); help_map.insert(std::pair("zfsadd", help_zfsadd)); help_map.insert(std::pair("zfslist", help_zfslist)); help_map.insert(std::pair("zfspurge", help_zfspurge)); help_map.insert(std::pair("zfssize", help_zfssize)); #endif // corresponds to #if (#if defined(unix)) switches_map.insert(std::pair("main", help_mainswitches)); switches_map.insert(std::pair("normal", help_switches)); switches_map.insert(std::pair("franz", help_franzswitches)); switches_map.insert(std::pair("common", help_commonswitches)); ///switches_map.insert(std::pair("paq", help_paq)); switches_map.insert(std::pair("voodoo", help_voodooswitches)); } void Jidac::usage(bool i_flagdie=true) { moreprint("Usage: zpaqfranz command archive.zpaq files|directories -switches"); moreprint(" double quote for multipart archive name => \"test_???.zpaq\""); #if defined(unix) moreprint("UNIX zfs commands available (zpaqfranz h zfs for details)"); #endif // corresponds to #if (#if defined(unix)) moreprint(" "); moreprint(" a: Append files | x: Extract | t: Test"); moreprint(" l: List | v: Verify on FS | i: Info"); moreprint(" w: Chunked extract | p: Paranoid verify | sum: File hashing"); #if defined(_WIN32) moreprint("sfx: Create Win SFX | g: Win C: image | tui: Text-GUIl"); #endif // corresponds to #if (#if defined(_WIN32)) moreprint(" "); moreprint(" -to out...: Prefix files to out -until N: Rollback to ver.N"); moreprint(" -all [N]: All versions N digit -key X: Archive password"); moreprint(" -test: Run additional tests -force: Always overwrite"); moreprint(" -mN: 0..5= faster..better -kill: Destructive ON"); #ifdef HWSHA1 moreprint(" -hw: hardware-accelerated SHA1 code (not in all CPUs)"); #endif // corresponds to #ifdef (#ifdef HWSHA1) moreprint(" "); #ifdef HWSHA2 if (ihavehw()) { color_yellow(); moreprint("More help: zpaqfranz h Extended help: zpaqfranz h h ",true); color_green(); moreprint("HW SHA1/2 ON"); } else { color_yellow(); moreprint(" More help: zpaqfranz h Extended help: zpaqfranz h h"); } #else color_yellow(); moreprint(" More help: zpaqfranz h Extended help: zpaqfranz h h"); #endif // corresponds to #ifdef (#ifdef HWSHA2) color_restore(); color_red(); #if defined(_WIN32) moreprint("Get newer Win version (Internet) : zpaqfranz update -force"); #else moreprint("Look for newer version (Internet): zpaqfranz update"); #endif // corresponds to #if (#if defined(_WIN32)) color_restore(); if (i_flagdie) seppuku(); } void Jidac::helphelp() { if (!flagnoconsole) { setupConsole(); printf("\033[2J"); //cls erase the first line printf("\033[%d;0H",(int)1); restoreConsole(); } load_help_map(); color_green(); moreprint(" FFFF"); moreprint(" ZZZZZZ PPPPP. AAAAA. QQQQQQ FFFFF RRRRR AAAAA. NNNNNN. ZZZZZZ"); moreprint(" ZZZZ PPP PPP AAA QQQ QQQ FFF RRRR AAA NNN NNN ZZZZ"); moreprint(" ZZZZ PPP PPP .AAAAAAA QQQ QQQ FFF RRR .AAAAAAA NNN NNN ZZZZ"); moreprint(" ZZZZ PPP PPPP AAA AAA QQQQ QQQ FFF RRR AAA AAA NNN NNN ZZZZ"); moreprint("ZZZZZZZ PPPPP. AAAAAA QQQQQ FFF RRR AAAAAA NNN NNN ZZZZZZZ"); moreprint(" PPP QQQ"); color_red(); moreprint("(C) 2021-2025 by Franco Corbelli: provided as-is,no warranty whatsoever"); color_yellow(); moreprint(" WWW: https://sourceforge.net/projects/zpaqfranz"); color_restore(); moreprint(" Swiss army knife for backup and disaster recovery"); moreprint(" Like 7z or RAR on steroids,with deduplicated \"snapshots\" (versions)"); moreprint(" Conceptually similar to Mac time machine, but much more efficiently"); moreprint(" Keeps backup always-to-always,no need to prune (bye bye Ransomware)"); moreprint(" Easily handles millions of files and TBs of data, non-latin support"); moreprint(" Multithreaded HW accelerations, full encryption, multipart archives"); moreprint(" Minimal data transfer => low bandwidth Virtual Machine Cloud backup"); moreprint(" Data integrity check CRC32+XXHASH|SHA-1|SHA-2|SHA-3|MD5|XXH3|BLAKE3"); #ifdef unix moreprint(" Specific zfs handling functions,full multiplatform interoperability"); #endif // corresponds to #ifdef (#ifdef unix) moreprint(" Windows, FreeBSD, OpenBSD, Linux, MacOS, Solaris, OmniOS and others"); color_red(); moreprint(" Extended help: zpaqfranz h h ALL IN: zpaqfranz h full"); color_restore(); } //// print a lot more void Jidac::usageall(string i_command) { load_help_map(); if (i_command=="") { moreprint("Get help for one command with zpaqfranz h something"); moreprint(" zpaqfranz h all -nomore => everything, ready to be pipep"); moreprint(" zpaqfranz h a => ask help and examples for command 'a'"); moreprint(" zpaqfranz -he a => ask examples for command 'a'"); moreprint(" "); for (MAPPAHELP::iterator p=help_map.begin(); p!=help_map.end(); ++p) { char linea[200]; string temp=(*p->second)(false,false); snprintf(linea,sizeof(linea),"%-15s",p->first.c_str()); color_green(); moreprint(linea,true); color_restore(); snprintf(linea,sizeof(linea),"%s",temp.c_str()); moreprint(linea); } for (MAPPAHELP::iterator p=switches_map.begin(); p!=switches_map.end(); ++p) { char linea[200]; string temp=(*p->second)(false,false); snprintf(linea,sizeof(linea),"%-15s",p->first.c_str()); color_green(); moreprint(linea,true); color_restore(); snprintf(linea,sizeof(linea),"%s",temp.c_str()); moreprint(linea); } seppuku(); return; } MAPPAHELP::iterator a=help_map.find(i_command); if (a==help_map.end()) { // maybe we want a switch ? if (i_command!="") { MAPPAHELP::iterator b=switches_map.find(i_command); if (b!=switches_map.end()) { (*b->second)(true,true); seppuku(); } } // if not found => show everything usage(false); // do not seppuku! moreprint("Usage full:"); for (MAPPAHELP::iterator p=help_map.begin(); p!=help_map.end(); ++p) { (*p->second)(true,true); morebar('-'); } morebar('-'); moreprint("Extended switches:"); help_switches(true,true); morebar('-'); moreprint("zpaqfranz switches:"); help_franzswitches(true,true); morebar('-'); moreprint("Voodoo switches"); help_voodooswitches(true,true); } else { // please note: first parameter help, second example (*a->second)(true,true); morebar('-'); } print_doublequote(); seppuku(); } void Jidac::examples(string i_command) { load_help_map(); // not in the constructor! // if not found => show everything MAPPAHELP::iterator a=help_map.find(i_command); if (a==help_map.end()) { for (MAPPAHELP::iterator p=help_map.begin(); p!=help_map.end(); ++p) { (*p->second)(false,true); morebar('-'); } } else { // please note: first parameter help, second example (*a->second)(false,true); morebar('-'); } } void open_output(string i_filename) { if (i_filename!="") if (g_output_handle==0) { g_output=i_filename; g_output_handle=fopen(i_filename.c_str(),"wb"); if (g_output_handle==NULL) printf("28342: ERROR OPENING LOG FILE %s\n",i_filename.c_str()); } } // Rename name using tofiles[] string Jidac::rename(string name) { franzreplace(name); /* kludge extracting \\franzk\z\NS\something -to z:\pippo with longpath converted to z:\pippo\__franzk_z (...) ./somewhere => _/somewhere etc */ #ifdef _WIN32 if (flaglongpath) if ((command=='x') || (command=='w')) if (tofiles.size()==1) { /* if (flagdebug3) { myprintf("00487: longname |"); printUTF8(name.c_str()); myprintf("| => fixed to |"); } */ if (name.size()>2) // fix for *nix relative paths if (name[0]=='.') if (name[1]=='/') name[0]='_'; myreplaceall(name,"/./","/_/"); myreplaceall(name,"/../","/__/"); if (iswindowsunc(name)) { replace(name,"//","__"); replace(name,"/","_"); } if (name.size()>2) if (isalpha(name[0])) if (name[1]==':') if (name[2]=='/') name[1]='_'; string finale=includetrailingbackslash(tofiles[0])+name; if (flagdebug3) { myprintf("00488: longname |%Z| => fixed to |%Z|\n",name.c_str(),finale.c_str()); } return finale; } #endif // corresponds to #ifdef (#ifdef _WIN32) if (flagnopath) { string myname=name; for (unsigned i=0; i> file <<%s>> to <<%s>>\n",files[i].c_str(),name.c_str(),myname.c_str()); } return myname; } if (files.size()==0 && tofiles.size()>0) // append prefix tofiles[0] { name=append_path(tofiles[0], name); } else { // replace prefix files[i] with tofiles[i] const int n=name.size(); for (unsigned i=0; i Extract all versions from 2 to 4 -range 2: -> Extract all versions from 2 to -range :3 -> Extract all versions from 1 to 3 (equal to: 1:3) -range 2 -range ::3 -> Extract the last 3 */ ///myprintf("00496: entering decode\n"); g_rangefrom =0; g_rangeto =0; g_rangelast =0; if (i_range=="") return; string primaparte =""; string secondaparte =""; unsigned int i=0; // pre-check for ::3 if (i_range.size()>=3) { if (!isdigit(i_range[i])) if (!isdigit(i_range[i+1])) { string resto=myright(i_range,i_range.size()-2); string temp=""; for (unsigned int j=0;j0) { g_rangelast=lastver; return; } } } i=0; while (i FROM (%d)\n",g_rangeto,g_rangefrom); g_rangefrom =0; g_rangeto =0; seppuku(); } if (flagdebug) { printbar('-'); myprintf("00507: final Rangefrom %d\n",g_rangefrom); myprintf("00508: final Rangeto %d\n",g_rangeto); } if (g_rangefrom==0) { myprintf("00509: cannot decode range |%s| you should use something like 2:4 or 2: or :3\n",i_range.c_str()); seppuku(); } if (!do_not_print_headers()) { myprintf("00510: franz:%-21s %21s\n","rangefrom (version)",migliaia(g_rangefrom)); myprintf("00511: franz:%-21s %21s\n","rangeto (version)",migliaia(g_rangeto)); } } /* On FreeBSD (and zfs) home is very often a symlink, but the readlink() sometimes report relative links (/home => usr/home) */ #ifdef unix string my_realpath(std::string const& i_path) { #ifdef ANCIENT char buf[16384]; #else char buf[33000]; //No MAXPATHLEN on Solaris #endif // corresponds to #ifdef (#ifdef ANCIENT) if (i_path.size()>sizeof(buf)) { error("33975: realpath"); } char *res=realpath(i_path.c_str(),buf); if (res) { return buf; } else { if (flagdebug) myprintf("00512: error on realpath of %s\n",i_path.c_str()); return i_path; } } #endif // corresponds to #ifdef (#ifdef unix) ///#include for _NSGetExecutablePath #ifdef __APPLE__ #include #endif // corresponds to #ifdef (#ifdef __APPLE__) string finalizza_none(void* p_hash) { if (p_hash==NULL) return ""; return ""; } string finalizza_sha3(void* p_hash) { if (p_hash==NULL) return ""; SHA3* casted=(SHA3*)p_hash; return (*casted).getHash(); } string finalizza_xxhash64(void* p_hash) { if (p_hash==NULL) return ""; XXHash64* casted=(XXHash64*)p_hash; return bin2hex_64((*casted).hash()); // return binarytohex((const unsigned char*)(*casted).hash(),8); } string finalizza_sha1(void* p_hash) { if (p_hash==NULL) return ""; libzpaq::SHA1* casted=(libzpaq::SHA1*)p_hash; char sha1result[20]; memcpy(sha1result, (*casted).result(), 20); return binarytohex((const unsigned char*)sha1result,20); } string finalizza_sha256(void* p_hash) { if (p_hash==NULL) return ""; libzpaq::SHA256* casted=(libzpaq::SHA256*)p_hash; char sha256result[32]; memcpy(sha256result, (*casted).result(), 32); return binarytohex((const unsigned char*)sha256result,32); } string finalizza_xxh3(void* p_hash) { if (p_hash==NULL) return ""; XXH3_state_t* casted=(XXH3_state_t*)p_hash; XXH128_hash_t myhash=XXH3_128bits_digest(casted); return bin2hex_128(myhash.high64,myhash.low64); } string finalizza_md5(void* p_hash) { if (p_hash==NULL) return ""; MD5* casted=(MD5*)p_hash; return (*casted).getHash(); } string finalizza_blake3(void* p_hash) { if (p_hash==NULL) return ""; blake3_hasher * casted=(blake3_hasher *)p_hash; uint8_t output[BLAKE3_OUT_LEN]; blake3_hasher_finalize(casted,output,BLAKE3_OUT_LEN); return binarytohex((const unsigned char*)output,BLAKE3_OUT_LEN); } string finalizza_whirlpool(void* p_hash) { if (p_hash==NULL) return ""; NESSIEstruct * casted=(NESSIEstruct *)p_hash; unsigned char output[512]={0}; NESSIEfinalize(casted,output); return binarytohex(output,64); } string finalizza_highway64(void* p_hash) { if (p_hash==NULL) return ""; HighwayHashCat * casted=(HighwayHashCat *)p_hash; uint64_t hash=HighwayHashCatFinish64(casted); return bin2hex_64(hash); } string finalizza_highway128(void* p_hash) { if (p_hash==NULL) return ""; HighwayHashCat * casted=(HighwayHashCat *)p_hash; uint64_t hash[2]; HighwayHashCatFinish128(casted,hash); return binarytohex((const unsigned char*)&hash,16); } string finalizza_highway256(void* p_hash) { if (p_hash==NULL) return ""; HighwayHashCat * casted=(HighwayHashCat *)p_hash; uint64_t hash[4]; HighwayHashCatFinish256(casted,hash); return binarytohex((const unsigned char*)&hash,32); } string finalizza_crc32(void* p_hash) { if (p_hash==NULL) return ""; const uint32_t* casted=(uint32_t*)p_hash; char temp[10]; snprintf(temp,sizeof(temp),"%08X",(*casted)); return temp; } string finalizza_crc32c(void* p_hash) { if (p_hash==NULL) return ""; const uint32_t* casted=(uint32_t*)p_hash; char temp[10]; snprintf(temp,sizeof(temp),"%08X",(*casted)); return temp; } string finalizza_wyhash(void* p_hash) { if (p_hash==NULL) return ""; return ""; } string finalizza_nilsimsa(void* p_hash) { if (p_hash==NULL) return ""; return ""; } string finalizza_entropy(void* p_hash) { if (p_hash==NULL) return ""; return ""; } /// this must compile on 20-years-old C++ bool Jidac::cli_filesandcommand(const string& i_opt,string i_string,char i_command,int argc,const char** argv, int* i_i) { if ((argv==NULL) || (i_i==NULL)) { myprintf("00513: GURU null data\n"); seppuku(); return false; } if (i_opt==i_string) { command=i_command; while (++(*i_i)* o_files,string* o_stringtype) { if ((argv==NULL) || (i_i==NULL) || (o_files==NULL)) { myprintf("00521: GURU null data\n"); seppuku(); return false; } if (i_opt==i_string) { while (++(*i_i)<(argc) && (argv[(*i_i)][0]!='-')) { if (o_stringtype!=NULL) { if (argv[(*i_i)][0]=='=') (*o_stringtype)=argv[(*i_i)]; else (*o_files).push_back(argv[(*i_i)]); } else (*o_files).push_back(argv[(*i_i)]); } --(*i_i); if (!do_not_print_headers()) if ((*o_files).size()>0) { for (unsigned int i=0;i<(*o_files).size();i++) myprintf("00522: franz:%-21s %21s\n",i_string.c_str(),(*o_files)[i].c_str()); printbar('-'); } return true; } return false; } bool Jidac::cli_getint(const string& i_opt,string i_string,bool i_flagoptional,const string& i_short,int argc,const char** argv, int* i_i,int i_default,int* o_thenumber) { if ((argv==NULL) || (i_i==NULL) || (o_thenumber==NULL)) { myprintf("00523: GURU null data\n"); seppuku(); return false; } if (i_opt==i_string) { (*o_thenumber)=i_default; if (i_flagoptional) { if ( ((*i_i)=1) { string mytimestamp=argv[(*i_i)+1]; (*i_i)++; ///format_datetime int64_t newdate=encodestringdate(mytimestamp,true); if (newdate!=-1) { (*o_date)=newdate; if (!do_not_print_headers()) { if (flagdebug3) myprintf("00531: franz:%s change from %s => %s\n",i_string.c_str(),dateToString(flagutc,*o_date).c_str(),dateToString(flagutc,newdate).c_str()); myprintf("00532: franz:%-21s <<%s>>\n",i_string.c_str(),dateToString(true,newdate).c_str()); } i_opt="skipme"; } } return false; } bool Jidac::cli_onlystring(const string& i_opt,string i_string,string i_alias,string& o_thefile,int argc,const char** argv, int* i_i,bool* i_theflag) { if ((argv==NULL) || (i_i==NULL)) { myprintf("00533: GURU null data\n"); seppuku(); return false; } if (i_alias=="") i_alias="@N3b12vc$fjvn4ba"; if ((i_opt==i_string) || (i_opt==i_alias)) { if (o_thefile=="") { if (++(*i_i)>\n",i_string.c_str(),o_thefile.c_str()); } if (i_theflag!=NULL) (*i_theflag)=true; } else (*i_i)--; } return true; } return false; } bool readfiletoarray(string i_filename,vector& o_lines) { o_lines.clear(); if (!fileexists(i_filename)) { myprintf("00535! cannot find %Z\n",i_filename.c_str()); return false; } FILE* myfile = freadopen(i_filename.c_str()); if (myfile==NULL) { myprintf("00537: cannot open file %Z\n",i_filename.c_str()); return false; } #ifdef ANCIENT char line[16384]; #else char line[65536]; #endif // corresponds to #ifdef (#ifdef ANCIENT) string linea; while (fgets(line, sizeof(line), myfile)) { linea=line; if (flagdebug3) myprintf("00539: line %s\n",linea.c_str()); myreplaceall(linea,std::string(1,10),""); myreplaceall(linea,std::string(1,13),""); o_lines.push_back(linea); } fclose(myfile); return true; } bool isbigendian(void) { union { uint32_t i; char c[4]; } bint = {0x01020304}; return bint.c[0] == 1; } void replacetabs(std::string &str) { std::string::size_type pos = 0; while ((pos=str.find("\\t", pos))!=std::string::npos) str.replace(pos++,2,"\t"); } int Jidac::loadparameters(int argc, const char** argv) { ///printf("*********************** CARICO *******************\n"); bool flagdummy=false; g_programflags.add(&flag715, "-715", "Runs just about like zpaq 7.15", "a;"); g_programflags.add(&flagappend, "-append", "Append-only (antiransomware, slow)", "a;"); g_programflags.add(&flagbackupxxh3, "-backupxxh3", "Use XXH3 in backup instead of MD5", ""); g_programflags.add(&flagbackupzeta, "-backupzeta", "Use ZETA in backup instead of MD5", ""); g_programflags.add(&flagbig, "-big", "Write the result of the processing in large text", "all;"); g_programflags.add(&flagchecksum, "-checksum", "Do checksums", ""); g_programflags.add(&flagchecktxt, "-checktxt", "Create Checktxt.txt", ""); #ifdef _WIN32 g_programflags.add(&flagsfx, "-sfx", "Enable SFX module", ""); #endif // corresponds to #ifdef (#ifdef _WIN32) g_programflags.add(&flagfasttxt, "-fasttxt", "Create test .txt with CRC-32 and QUICK", ""); g_programflags.add(&flagcomment, "-comment", "Comment version", ""); g_programflags.add(&flagdebug, "-debug", "Show debug line number", ""); g_programflags.add(&flagdebug2, "-debug2", "Show debug infos", ""); g_programflags.add(&flagdebug3, "-debug3", "Show A LOT of debug", ""); g_programflags.add(&flagdebug4, "-debug4", "Write debug data on z:\\", ""); g_programflags.add(&flagdebug5, "-debug5", "Show RAM usage", ""); g_programflags.add(&flagdesc, "-desc", "Orderby desc", ""); g_programflags.add(&flagnosymlink, "-symlink", "Ignore Windows REPARSE_POINT (Symlink)", ""); g_programflags.add(&flagdonotforcexls, "-xls", "Do NOT force adding of XLS/PPT (default: NO)", "a;"); g_programflags.add(&flagdummy, "-debug -zero -kill", "Add 0-byte long file (debugging)", ""); g_programflags.add(&flagdummy, "-debug -zero", "Add files but zero-filled (debugging)", ""); g_programflags.add(&flagfilelist, "-filelist", "Create a filelist .txt", ""); #ifdef _WIN32 g_programflags.add(&flagads, "-ads", "Store filelists on NTFS", ""); #endif // corresponds to #ifdef (#ifdef _WIN32) g_programflags.add(&flagfast, "-fast", "Store filelists inside", ""); g_programflags.add(&flagfix255, "-fix255", "Fix 255", ""); g_programflags.add(&flagfixeml, "-fixeml", "Fix eml filenames", ""); g_programflags.add(&flagflat, "-flat", "Flat filenames", ""); g_programflags.add(&flagforce, "-force", "Force (usually overwrite)", ""); g_programflags.add(&flagforcewindows, "-forcewindows", "Store ADS stuff (default: NO)", "a;"); g_programflags.add(&flagforcezfs, "-forcezfs", "Enforce using .zfs", ""); g_programflags.add(&flagfrugal, "-frugal", "Frugal backup", ""); g_programflags.add(&flaghashdeep, "-hashdeep", "Hashdeep", ""); g_programflags.add(&flagignore, "-ignore", "Ignore (do not show) file errors", "a;"); g_programflags.add(&flagnotrim, "-notrim", "Disable autotrim of incomplete transactions", ""); g_programflags.add(&flagonedrive, "-onedrive", "Do NOT get onedrive placeholders", ""); g_programflags.add(&flaghome, "-home", "Divide into multiple files, one for each folder.", "a;"); g_programflags.add(&flagkill, "-kill", "It usually means 'do something dangerous.'", ""); g_programflags.add(&flaght, "-ht", "Enable Hyperthread (if any)", ""); g_programflags.add(&flagnocaptcha, "-nocaptcha", "Skip chaptcha", ""); g_programflags.add(&flagmm, "-mm", "Memory mapped file", ""); g_programflags.add(&flagnoattributes, "-noattributes", "Do not store file attribute", ""); g_programflags.add(&flagattr, "-attr", "Show attribute (listing)", ""); g_programflags.add(&flagthunderbird, "-thunderbird", "Thunderbird's e-mail", ""); g_programflags.add(&flagnodedup, "-nodedup", "Turn off deduplicator", ""); g_programflags.add(&flagnoeta, "-noeta", "Do not show ETA", ""); g_programflags.add(&flagnopath, "-nopath", "Do not store path", ""); g_programflags.add(&flagnoqnap, "-noqnap", "Exclude QNAP snap & trash", "a;"); g_programflags.add(&flagnomac, "-nomac", "Exclude Mac hidden files", "a;"); g_programflags.add(&flagnosynology, "-nosynology", "Exclude Synology system files", "a;"); g_programflags.add(&flagnorecursion, "-norecursion", "Do not recurse into folders (default: YES)", ""); g_programflags.add(&flagnosort, "-nosort", "Do not sort file", ""); g_programflags.add(&flagpakka, "-pakka", "New output style", ""); g_programflags.add(&flagdistinct, "-distinct", "PAKKA zpaqlist", ""); g_programflags.add(&flagparanoid, "-paranoid", "Paranoid 'something'", ""); ///g_programflags.add(&flagpaq, "-paq", "Enable paq-levels", ""); g_programflags.add(&flagcollision, "-collision", "Collision check", ""); g_programflags.add(&flagramdisk, "-ramdisk", "Ramdisk (really: heap)", ""); g_programflags.add(&flagrename, "-rename", "Rename", ""); g_programflags.add(&flagsilent, "-silent", "Silent (no) output", ""); g_programflags.add(&flagnoconsole, "-noconsole", "Do not manipulate console", "",flagnoconsole); g_programflags.add(&flagskipzfs, "-zfs", "Do NOT ignore .zfs (default: YES)", ""); //flagskipzfs g_programflags.add(&flagspace, "-space", "Do not check space/writeability", ""); g_programflags.add(&flagssd, "-ssd", "Reads the files with multithreading from the solid-state drive", ""); g_programflags.add(&flagnomore, "-nomore", "Disable internal 'more' (ex |less)", ""); g_programflags.add(&flagnopid, "-nopid", "Do not use pids in backup", ""); g_programflags.add(&flagsalt, "-salt", "Fix encryption salt to 0", ""); g_programflags.add(&flaghdd, "-hdd", "HDD (use if possible RAM before drive)", ""); g_programflags.add(&flagstat, "-stat", "Shows statistics", ""); g_programflags.add(&flagstdin, "-stdin", "Reads the data to be compressed from stdin", ""); g_programflags.add(&flagterse, "-terse", "Create output without header and footer", ""); g_programflags.add(&flagnodel, "-nodel", "Do not show deleted files (in listing)", ""); g_programflags.add(&flagstdout, "-stdout", "File suitable for extraction via piping to stdout (reduces efficiency).", ""); g_programflags.add(&flagstore, "-store", "Store mode: no deduplication, no compression", ""); g_programflags.add(&flagtar, "-tar", "TAR mode (store posix)", ""); g_programflags.add(&flagtmp, "-tmp", "Use .tmp instead of .zpaq during backup", ""); g_programflags.add(&flagtest, "-test", "Only do test", ""); g_programflags.add(&flagtouch, "-touch", "Force 'touch' on date (7.15 to zpaqfranz)", ""); g_programflags.add(&flagutc, "-utc", "Use UTC time", ""); g_programflags.add(&flagdate, "-date", "Show/save creation date (if possible)", ""); g_programflags.add(&flagutf, "-utf", "UTF-8", ""); g_programflags.add(&flagverbose, "-verbose", "Verbose output", ""); g_programflags.add(&flagverify, "-verify", "Verify (read from filesystem)", ""); g_programflags.add(&flagvss, "-vss", "Enable Volume Shadow Copies", "a;"); g_programflags.add(&flagzero, "-zero", "Zeroing something", ""); g_programflags.add(&flagpause, "-pause", "Pause after run (for runhigh)", ""); g_programflags.add(&flagquiet, "-quiet", "Do not show filesystem errors", ""); g_programflags.add(&g_sfxflagforce, "-sfxforce", "Sfx force", ""); g_programflags.add(&g_sfxflagall, "-sfxall", "Sfx all", ""); g_programflags.add(&flagbarraod, "/od", "Order by date", "dir;"); g_programflags.add(&flagbarraon, "/on", "Order by name", "dir;"); g_programflags.add(&flagbarraos, "/os", "Order by size", "dir;"); g_programflags.add(&flagnocolor, "-nocolor", "Monochrome output", "",flagnocolor); g_programflags.add(&flagnodelete, "-nodelete", "Do not logical delete files", ""); #ifdef _WIN32 /// g_programflags.add(&flagdd, "-dd", "dd", ""); g_programflags.add(&flagfindzpaq, "-findzpaq", "Search .zpaq in every drive letter (USB device)", ""); g_programflags.add(&flagfixcase, "-fixcase", "Fix CAse", ""); g_programflags.add(&flagfixreserved, "-fixreserved", "fixreserved", ""); g_programflags.add(&flagimage, "-image", "Drive image", ""); g_programflags.add(&flaglongpath, "-longpath", "Longpath", ""); g_programflags.add(&flagopen, "-open", "Abort if archive seems already opened", ""); #endif // corresponds to #ifdef (#ifdef _WIN32) g_programflags.add(&flaghw, "-hw", "Use HW SHA1", "a;x;"); g_programflags.add(&flagnojit, "-nojit", "Do not use JIT", ""); for (int i=0; i(FRANZO_NONE , tipohash("NONE", 0,"Disable checksums", true ,"-nochecksum", &flagnochecksum, &finalizza_none, ""))); g_mappatipohash.insert(std::pair(FRANZO_CRC_32 , tipohash("CRC-32", 8,"Old but ubiquitous, superfast, not very strong", true ,"-crc32", &flagcrc32, &finalizza_crc32, TOSTRING(FRANZO_CRC_32)))); g_mappatipohash.insert(std::pair(FRANZO_XXHASH64 , tipohash("XXHASH64", 16,"Very fast, low CPU usage, zpaqfranz's default", true ,"-xxhash", &flagxxhash64, &finalizza_xxhash64, TOSTRING(FRANZO_XXHASH64)))); g_mappatipohash.insert(std::pair(FRANZO_XXHASH64B , tipohash("XXHASH64B", 16,"Very fast, low CPU usage, zpaqfranz's 60+ default", true ,"-xxhashb", &flagxxhash64b, &finalizza_xxhash64, TOSTRING(FRANZO_XXHASH64B)))); g_mappatipohash.insert(std::pair(FRANZO_SHA_1 , tipohash("SHA-1", 40,"Fair speed, very reliable, some collisions known", true ,"-sha1", &flagsha1, &finalizza_sha1, TOSTRING(FRANZO_SHA_1)))); g_mappatipohash.insert(std::pair(FRANZO_SHA_1B , tipohash("SHA-1B", 40,"Fair speed, very reliable, some collisions known", true ,"-sha1b", &flagsha1b, &finalizza_sha1, TOSTRING(FRANZO_SHA_1B)))); g_mappatipohash.insert(std::pair(FRANZO_SHA_256 , tipohash("SHA-256", 64,"CPU intensive, one of the most reliable. Legal proof in EU", true ,"-sha256", &flagsha256, &finalizza_sha256, TOSTRING(FRANZO_SHA_256)))); g_mappatipohash.insert(std::pair(FRANZO_SHA_256B , tipohash("SHA-256B", 64,"CPU intensive, one of the most reliable. Legal proof in EU", true ,"-sha256b", &flagsha256b, &finalizza_sha256, TOSTRING(FRANZO_SHA_256B)))); g_mappatipohash.insert(std::pair(FRANZO_XXH3 , tipohash("XXH3", 32,"Very fast and strong, zpaqfranz default for file comparing", true ,"-xxh3", &flagxxh3, &finalizza_xxh3, TOSTRING(FRANZO_SHA3)))); g_mappatipohash.insert(std::pair(FRANZO_XXH3B , tipohash("XXH3B", 32,"Very fast and strong, zpaqfranz default for file comparing", true ,"-xxh3b", &flagxxh3b, &finalizza_xxh3, TOSTRING(FRANZO_XXH3B)))); g_mappatipohash.insert(std::pair(FRANZO_MD5 , tipohash("MD5", 32,"Common, fast, hashdeep compatible. Not cryptographic good", true ,"-md5", &flagmd5, &finalizza_md5, TOSTRING(FRANZO_MD5)))); g_mappatipohash.insert(std::pair(FRANZO_MD5B , tipohash("MD5B", 32,"Common, fast, hashdeep compatible. Not cryptographic good", true ,"-md5b", &flagmd5b, &finalizza_md5, TOSTRING(FRANZO_MD5B)))); g_mappatipohash.insert(std::pair(FRANZO_BLAKE3 , tipohash("BLAKE3", 64,"Fast, CPU intensive (on Win64 HW acceleration), reliable", true ,"-blake3", &flagblake3, &finalizza_blake3, TOSTRING(FRANZO_BLAKE3)))); g_mappatipohash.insert(std::pair(FRANZO_BLAKE3B , tipohash("BLAKE3B", 64,"Fast, CPU intensive (on Win64 HW acceleration), reliable", true ,"-blake3b", &flagblake3b, &finalizza_blake3, TOSTRING(FRANZO_BLAKE3B)))); g_mappatipohash.insert(std::pair(FRANZO_SHA3 , tipohash("SHA-3", 64,"Latest NIST standard, very strong", true ,"-sha3", &flagsha3, &finalizza_sha3, TOSTRING(FRANZO_SHA3)))); g_mappatipohash.insert(std::pair(FRANZO_SHA3B , tipohash("SHA-3B", 64,"Latest NIST standard, very strong", true ,"-sha3b", &flagsha3b, &finalizza_sha3, TOSTRING(FRANZO_SHA3B)))); g_mappatipohash.insert(std::pair(FRANZO_WHIRLPOOL , tipohash("WHIRLPOOL", 128,"Slow but very reliable", true ,"-whirlpool", &flagwhirlpool, &finalizza_whirlpool, TOSTRING(FRANZO_WHIRLPOOL)))); g_mappatipohash.insert(std::pair(FRANZO_HIGHWAY64 , tipohash("HIGHWAY64", 16,"Experimental Google's HighwayHash, straight C, 64 bit", true ,"-highway64", &flaghighway64, &finalizza_highway64, TOSTRING(FRANZO_HIGHWAY64)))); g_mappatipohash.insert(std::pair(FRANZO_HIGHWAY128, tipohash("HIGHWAY128", 32,"Experimental Google's HighwayHash, straight C, 128 bit", true ,"-highway128", &flaghighway128, &finalizza_highway128, TOSTRING(FRANZO_HIGHWAY128)))); g_mappatipohash.insert(std::pair(FRANZO_HIGHWAY256, tipohash("HIGHWAY256", 64,"Experimental Google's HighwayHash, straight C, 256 bit", true ,"-highway256", &flaghighway256, &finalizza_highway256, TOSTRING(FRANZO_HIGHWAY256)))); g_mappatipohash.insert(std::pair(ALGO_CRC32C , tipohash("CRC-32C", 8,"'Castagnoli' variation of CRC-32, HW accelerated", false ,"-crc32c", &flagcrc32c, &finalizza_crc32c, TOSTRING(ALGO_CRC32C)))); g_mappatipohash.insert(std::pair(ALGO_WYHASH , tipohash("WYHASH", 16,"Maybe the fastest, limited 'strength'", false ,"-wyhash", &flagwyhash, &finalizza_wyhash, TOSTRING(ALGO_WYHASH)))); g_mappatipohash.insert(std::pair(ALGO_NILSIMSA , tipohash("NILSIMSA", 128,"Look for similarities, not differences", false ,"-nilsimsa", &flagnilsimsa, &finalizza_nilsimsa, TOSTRING(ALGO_NILSIMSA)))); g_mappatipohash.insert(std::pair(ALGO_ENTROPY , tipohash("ENTROPY", 6,"Quick-and-dirty entropy estimator", false ,"-entropy", &flagentropy, &finalizza_entropy, TOSTRING(ALGO_ENTROPY)))); g_mappatipohash.insert(std::pair(ALGO_QUICK , tipohash("QUICK", 16,"Quick partial hasher", false ,"-quick", &flagquick, &finalizza_xxhash64, TOSTRING(ALGO_QUICK)))); g_mappatipohash.insert(std::pair(ALGO_ZETA , tipohash("ZETA", 16,"Zpaq partial hasher", false ,"-zeta", &flagzeta, &finalizza_xxhash64, TOSTRING(ALGO_ZETA)))); g_mappatipohash.insert(std::pair(ALGO_ZETAENC , tipohash("ZETAENC", 16,"Zpaq partial hasher (encrypted)", false ,"-zetaenc", &flagzetaenc, &finalizza_xxhash64, TOSTRING(ALGO_ZETAENC)))); #ifdef _WIN32 g_mappatipohash.insert(std::pair(FRANZO_WINHASH64,tipohash("WINHASH64", 16,"Same as xxhash64 (with Windows' dates)", true ,"-windate", &flagwindate, &finalizza_xxhash64, TOSTRING(FRANZO_WINHASH64)))); #endif // corresponds to #ifdef (#ifdef _WIN32) // Initialize options to default values // Why some variables out of Jidac? Because of pthread: does not like very much C++ objects // quick and dirty. g_ioBUFSIZE =1048576; //not more just like zpaq g_thechosenhash =FRANZO_SHA_1; //FRANZO_SHA_1; g_thechosenhash_str ="SHA-1"; fullcommandline =""; plainpassword =""; g_mysql_host ="127.0.0.1"; g_mysql_port =3306; g_mysql_password =""; g_mysql_user ="root"; #ifdef SFTP g_sftp_host =""; g_sftp_port =22; g_sftp_password =""; g_sftp_user =""; #endif // corresponds to #ifdef (#ifdef SFTP) g_franzsnap ="c:/franzsnap"; g_vss_shadow =""; g_replaceme =""; g_franzotype =FRANZO_XXHASH64B; //by default take CRC-32 AND XXHASH64 g_franzotypelen =16; g_255 =0; // errors on longer than 255 chars g_deleteinto =""; g_sfx =""; g_sfxto =""; g_sfxnot =""; g_sfxonly =""; g_sfxuntil =""; g_freeze =""; g_archive =""; g_indexname =""; g_csvstring =""; g_csvhf =""; g_bin =""; g_pidname =""; g_backupposition =""; g_output_handle =NULL; g_error_handle =NULL; g_archivefp =FPNULL; g_output =""; g_error =""; g_exec_error =""; g_exec_warn =""; g_exec_ok =""; g_exec =""; g_exec_text =""; g_copy =""; g_until =""; #ifdef unix g_tempsnapshot =""; g_basesnapshot =""; g_dataset =""; #endif // corresponds to #ifdef (#ifdef unix) command =0; fragment =6; minsize =0; maxsize =0; dirlength =0; filelength =0; all =0; g_password =0; index =0; method =""; repack =""; checktxt =""; fasttxt =""; indexfasttxt =""; backuptxt =""; backupindex =""; new_password =0; summary =-1; menoenne =0; versioncomment =""; searchfrom =""; snapmark =""; orderby =""; replaceto =""; searchhash =""; zpaqfranzexename =""; fullzpaqexename =""; howmanythreads =0; version =DEFAULT_VERSION; date =0; g_flagmultipart =false; g_flagcreating =false; g_testifselected =false; bool flagforzarobocopy=false; if (argc>1) for (int i=1; i0) { zpaqfranzexename=argv[0]; #ifdef _WIN32 if (!isextension(zpaqfranzexename.c_str(), ".exe")) zpaqfranzexename+=".exe"; #endif // corresponds to #ifdef (#ifdef _WIN32) } const char *no_color=getenv("NO_COLOR"); if ((no_color!=NULL) && (no_color[0]!='\0')) flagnocolor=true; #ifdef _WIN32 color_save(); wchar_t myexepath[_MAX_PATH]; GetModuleFileName(NULL,myexepath,_MAX_PATH); fullzpaqexename=wtou(myexepath); #endif // corresponds to #ifdef (#ifdef _WIN32) #ifdef unix fullzpaqexename=my_realpath(zpaqfranzexename); #ifdef BSD // BSD #ifndef __OpenBSD__ // OpenBSD is not FreeBSD #ifndef __APPLE__ // Mac is different (of course) if (flagdebug) myprintf("00540: Pretend to be FreeBSD\n"); int mib[4]; mib[0]=CTL_KERN; mib[1]=KERN_PROC; mib[2]=KERN_PROC_PATHNAME; mib[3]=-1; char buf[1024]; size_t cb=sizeof(buf); sysctl(mib,4,buf,&cb,NULL,0); fullzpaqexename=my_realpath(buf); #endif // corresponds to #ifndef (#ifndef __APPLE__ // Mac is different (of course)) #endif // corresponds to #ifndef (#ifndef __OpenBSD__ // OpenBSD is not FreeBSD) #endif // corresponds to #ifdef (#ifdef BSD // BSD) #ifdef __linux__ if (flagdebug) myprintf("00541: Pretend to be Linux\n"); const size_t bufSize = PATH_MAX + 1; char buf[bufSize]={0}; const char *linkName = "/proc/self/exe"; if (readlink(linkName, buf, bufSize - 1)>0) fullzpaqexename=buf; ///else ///myprintf("00542: something wrong!"); #endif // corresponds to #ifdef (#ifdef __linux__) #ifdef SOLARIS if (flagdebug) myprintf("00543: Pretend to be Solaris\n"); fullzpaqexename=getexecname(); #endif // corresponds to #ifdef (#ifdef SOLARIS) #ifdef __APPLE__ // Mac is different (of course) if (flagdebug) myprintf("00544: Pretend to be Mac\n"); char buf[1024]; uint32_t size = sizeof(buf); if (_NSGetExecutablePath(buf, &size) == 0) fullzpaqexename=buf; #endif // corresponds to #ifdef (#ifdef __APPLE__ // Mac is different (of course)) /// If I pretend to be... dir... work like dir! string myexename=extractfilename(zpaqfranzexename); if (myexename=="dir") { files.clear(); int i=0; while (++i=2) // early disable output { if (stringcomparei(argv[1],"last")) flagpakka=true; if (stringcomparei(argv[1],"fzf")) { flagpakka=true; flagstdout=false; flagnoeta=true; } } if (flagdebug) myprintf("52860: k0 flagnojit %d\n",int(flagnojit)); #if defined(__amd64__) || defined(__i386__) if (flagdebug) myprintf("52820: This seems amd64/i386, turning OFF flagnojit\n"); flagnojit=false; #ifdef unix if (flagdebug) myprintf("52588: UNIX: checking OS support for JIT\n"); void* p=(void*)mmap(0,8192, PROT_READ|PROT_WRITE|PROT_EXEC,MAP_PRIVATE|MAP_ANON, -1, 0); if (p==MAP_FAILED) { if (flagverbose) myprintf("52594$ OS unsupported, turning ON flagnojit\n"); flagnojit=true; } else { if (flagdebug) myprintf("52850: mmap OK, releasing\n"); munmap(p,8192); } #endif // corresponds to #ifdef (#ifdef unix) #else if (flagdebug) myprintf("52824: CPU not amd64/i386, turning ON flagnojit\n"); flagnojit=true; #endif // corresponds to #if (#if defined(__amd64__) || defined(__i386__)) if (flagdebug) myprintf("52861: k1 flagnojit %d\n",int(flagnojit)); #if defined(NOJIT) || defined(BIG) // those are really "strange" if (flagdebug) myprintf("52847: -DNOJIT or -DBIG => turning on flagnojit\n"); flagnojit=true; #endif // corresponds to #if (#if defined(NOJIT) || defined(BIG) // those are really "strange") if (flagdebug) myprintf("52862: k2 flagnojit %d\n",int(flagnojit)); string textnojit="-JIT,"; if (flagnojit) textnojit="-NOJIT,"; #ifdef ESX textnojit="-ESX,"; #endif // corresponds to #ifdef (#ifdef ESX) #ifdef NAS textnojit="-NAS,"; #endif // corresponds to #ifdef (#ifdef NAS) if (flag715) myprintf("52511: zpaq v7.15 journaling archiver, compiled Aug 17 2016\n"); else { if ((!flagpakka) && (!flagstdout) && (!flagterse)) { char buffer[300]; if (iswindowsxp()) textnojit+="-WinXP"; #ifdef SFTP textnojit+="SFTP"; #endif // corresponds to #ifdef (#ifdef SFTP) snprintf(buffer,sizeof(buffer),"zpaqfranz v" ZPAQ_VERSION "%s" TEXT_BIG TEXT_ALIGN TEXT_HWPRE TEXT_HWBLAKE3 TEXT_HWSHA1 TEXT_HWSHA2 TEXT_IPV ZSFX_VERSION ZPAQ_DATE,textnojit.c_str()); color_green(); moreprint(buffer); color_restore(); } } if (flagdebug) myprintf("00547: FULL exename <<%s>>\n",fullzpaqexename.c_str()); for (int i=1;i0) { BOOL success=SetProcessWorkingSetSize(hProcess,largePageMinimum,largePageMinimum); if (success) myprintf("52927: Large page OK %s\n",migliaia(largePageMinimum)); else myprintf("52929! Large page KAPUTT %s\n",migliaia(largePageMinimum)); } else myprintf("52930$ Large page support not available on this system\n"); } #endif // corresponds to #ifdef (#ifdef _WIN64) /// check some magic to show help in heuristic way /// I know, it's bad, but help is always needed! if (argc==1) // zero parameters { usage(); seppuku(); } if (argc==2) // only ONE { const string parametro=argv[1]; if ((stringcomparei(parametro,"help")) || (stringcomparei(parametro,"-h")) || (stringcomparei(parametro,"h")) || (stringcomparei(parametro,"?")) || (stringcomparei(parametro,"-?")) || (stringcomparei(parametro,"/?")) || (stringcomparei(parametro,"--help")) || (stringcomparei(parametro,"-help"))) { helphelp(); seppuku(); } if ((stringcomparei(parametro,"-he")) || (stringcomparei(parametro,"-helpe")) || (stringcomparei(parametro,"-example")) || (stringcomparei(parametro,"-examples"))) { examples(""); seppuku(); } } if ((argc==3)||(argc==4)) // only TWO (-examples sha1) { const string parametro =argv[1]; const string comando =argv[2]; if ((stringcomparei(parametro,"help")) || (stringcomparei(parametro,"-h")) || (stringcomparei(parametro,"h")) || (stringcomparei(parametro,"?")) || (stringcomparei(parametro,"/?")) || (stringcomparei(parametro,"-?")) || (stringcomparei(parametro,"--help")) || (stringcomparei(parametro,"-help"))) { if (comando=="h") /// zpaqfranz h h usageall(""); else { ///myprintf("$$$$$$$$$$$$$ comando %s\n",comando.c_str()); usageall(comando); } seppuku(); } if ((stringcomparei(parametro,"-he")) || (stringcomparei(parametro,"-helpe")) || (stringcomparei(parametro,"-example")) || (stringcomparei(parametro,"-examples"))) { examples(comando); seppuku(); } } // Init archive state ht.resize(1); // element 0 not used ver.resize(1); // version 0 dhsize=dcsize=0; // Get date time_t nowz=time(NULL); const tm* t=gmtime(&nowz); date=(t->tm_year+1900)*10000000000LL+(t->tm_mon+1)*100000000LL +t->tm_mday*1000000+t->tm_hour*10000+t->tm_min*100+t->tm_sec; g_optional=""; /// a bit of refactoring. getting, early, the hasher static const string dummyhash="-dummyhash"; int howmanyhasher=0; for (int i=1; isecond.switchname)) if ((p->second.switchflag)!=NULL) { *(p->second.switchflag)=true; argv[i]=dummyhash.c_str(); howmanyhasher++; g_thechosenhash=p->first; g_thechosenhash_str=p->second.hashname; } if (howmanyhasher>1) { myprintf("\n"); myprintf("00548: ABORT: you cannot choose more than ONE hasher, but you picked %d\n",howmanyhasher); for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (p->second.switchname!="") myprintf("%s ",p->second.switchname.c_str()); myprintf("\n"); seppuku(); return 0; } if (flagdebug) myprintf("00549: The chosen algo %d %s\n",g_thechosenhash,g_thechosenhash_str.c_str()); #ifdef HWSHA2 if (ihavehw()) { if (flagverbose) myprintf("00550: DETECTED SHA1/2 HW INSTRUCTIONS\n"); flaghw=true; } #endif // corresponds to #ifdef (#ifdef HWSHA2) // Get optional options. the hasher turned to -dummyhash string myrange=""; for (int i=1; iopt %s\n",opt.c_str()); if (opt=="-dummyhash") { /// taken by hash selection } else if ((opt=="benchmark") || (opt=="b")) command='b'; else if ((opt=="autotest")) command='8'; else if ((opt=="pause")) command='0'; else if (cli_filesandcommand(opt,"d", 'd',argc,argv,&i)); else if (cli_filesandcommand(opt,"dir", '2',argc,argv,&i)); else if (cli_filesandcommand(opt,"find", 'j',argc,argv,&i)); else if (cli_filesandcommand(opt,"isopen", '!',argc,argv,&i)); else if (cli_filesandcommand(opt,"password", '6',argc,argv,&i)); else if (cli_filesandcommand(opt,"rsync", '3',argc,argv,&i)); else if (cli_filesandcommand(opt,"1on1", ')',argc,argv,&i)); else if (cli_filesandcommand(opt,"sum", '1',argc,argv,&i)); else if (cli_filesandcommand(opt,"hash", '9',argc,argv,&i)); else if (cli_filesandcommand(opt,"trim", '4',argc,argv,&i)); else if (cli_filesandcommand(opt,"versum", '|',argc,argv,&i)); else if (cli_filesandcommand(opt,"last2", '^',argc,argv,&i)); else if (cli_filesandcommand(opt,"testbackup", '_',argc,argv,&i)); else if (cli_filesandcommand(opt,"comparehex", '?',argc,argv,&i)); else if (cli_filesandcommand(opt,"work", ']',argc,argv,&i)); #ifdef SFTP else if (cli_filesandcommand(opt,"sftp", '@',argc,argv,&i)); #endif // corresponds to #ifdef (#ifdef SFTP) else if (cli_filesandcommand(opt,"big", '/',argc,argv,&i)); else if (cli_filesandcommand(opt,"count", '[',argc,argv,&i)); else if (cli_filesandcommand(opt,"consolidate", 'Y',argc,argv,&i)); else if (cli_filesandcommand(opt,"zfsrestore", '%',argc,argv,&i)); else if (cli_filesandcommand(opt,"zfslist", 'B',argc,argv,&i)); else if (cli_filesandcommand(opt,"zfspurge", 'C',argc,argv,&i)); else if (cli_filesandcommand(opt,"zfssize", 'H',argc,argv,&i)); #if defined(_WIN32) else if (cli_filesandcommand(opt,"rd", '7',argc,argv,&i)); #endif // corresponds to #if (#if defined(_WIN32)) else if (( opt=="pakka" || opt=="add" || opt=="backup" || opt=="append" || opt=="extract" || opt=="last" || opt=="list" || opt=="mysqldump" || #ifndef ANCIENT opt=="ls" || opt=="tui" || #endif opt=="dump" || opt=="collision" || opt=="fzf" || opt=="k" || opt=="a" || opt=="e" || opt=="x" || opt=="p" || opt=="t" || opt=="test" || opt=="l" || opt=="v" || opt=="w" || opt=="i" || opt=="q" || opt=="g" || opt=="sfx" || opt=="crop" || opt=="m" || opt=="dirsize" || opt=="zfsadd" || opt=="zfsreceive" || opt=="zfsproxbackup" || opt=="zfsproxrestore" || opt=="zfsbackup") && i automagically added\n",candidate.c_str()); } } } } else if ( (opt=="n") || (opt=="f") || (opt=="c") || (opt=="s") || (opt=="utf") || (opt=="r") || (opt=="robocopy") || (opt=="cp") || #ifdef _WIN32 (opt=="ads") || #endif // corresponds to #ifdef (#ifdef _WIN32) #ifdef _WIN64 (opt=="download") || #endif // corresponds to #ifdef (#ifdef _WIN64) (opt=="update") || (opt=="upgrade") || (opt=="redu") || opt=="z") { command=opt[0]; if (opt=="cp") command='o'; if ((opt=="upgrade") || (opt=="update")) command='U'; #ifdef _WIN64 if (opt=="download") command='W'; #endif // corresponds to #ifdef (#ifdef _WIN64) if (opt=="redu") command='R'; #ifdef _WIN32 if (opt=="ads") command='S'; if (opt=="update") command='U'; #endif // corresponds to #ifdef (#ifdef _WIN32) if (flagforzarobocopy) { ///myprintf("00556: i=%d argc %d\n",(int)i,argc); if (i==1) i--; } while (++i>\n","-to",mytemp.c_str()); } if (tofiles.size()==0) tofiles.push_back(""); --i; } else if (opt=="-until" && i+1-1) usage(); ++i; } else { // positive version or date while (++i=19000000LL && version<=29991231LL) version=version*100+23; if (version>=1900000000LL && version<=2999123123LL) version=version*100+59; if (version>=190000000000LL && version<=299912312359LL) version=version*100+59; if (version>9999999) { if (version<19000101000000LL || version>29991231235959LL) { fflush(stdout); myprintf("00561: Version date %1.0f must be 19000101000000 to 29991231235959\n",double(version)); g_exec_text="Version date must be 19000101000000 to 29991231235959"; exit(1); } date=version; } } else if (opt=="skipme") { } else { if (!g_programflags.exists(argv[i])) myprintf("00562! Unknown option ignored: %s\n", argv[i]); } } /* Check from "weird" parameters */ if (flagnosynology) { myprintf("00563: Filling -not for -nosynology\n"); notfiles.push_back("*/@recycle/*"); notfiles.push_back("*/#recycle/*"); notfiles.push_back("*/#snapshot/*"); notfiles.push_back("*/@ActiveBackup/*"); notfiles.push_back("*/@sharebin/*"); notfiles.push_back("*/@appconf/*"); notfiles.push_back("*/@appdata/*"); notfiles.push_back("*/@apphome/*"); notfiles.push_back("*/@appshare/*"); notfiles.push_back("*/@apptemp/*"); notfiles.push_back("*/@clamav/*"); notfiles.push_back("*/@database/*"); notfiles.push_back("*/@docker/*"); notfiles.push_back("*/@eaDir/*"); notfiles.push_back("*/@maillog/*"); notfiles.push_back("*/@MailScanner/*"); notfiles.push_back("*/@postfix/*"); notfiles.push_back("*/@S2S/*"); notfiles.push_back("*/@sharesnap/*"); notfiles.push_back("*/@synoconfd/*"); notfiles.push_back("*/@SynologyDrive/*"); notfiles.push_back("*/@SynoFinder-etc-volume/*"); notfiles.push_back("*/@SynoFinder-log/*"); notfiles.push_back("*/@tmp/*"); notfiles.push_back("*/@USBCopy/*"); notfiles.push_back("*/@userpreference/*"); } if (g_rangefrom>0) { if (g_until!="") { myprintf("00564! -until incompatible with -range\n"); return 2; } all=8; } myreplaceall(g_csvstring,"/","\\"); replacetabs(g_csvstring); myreplaceall(g_csvhf,"/","\\"); replacetabs(g_csvhf); #ifdef _WIN32 if (flagvss) { if (!isadmin()) { myprintf("\n"); myprintf("00565: Admin rights required for VSS => runhigh()\n"); runhigh(" -pause"); return 2; } } if (flagimage && flagstdin) { myprintf("00566! -image incompatible with -stdin\n"); return 2; } /* if (flagimage && flagdd) { myprintf("00567: -image incompatible with -dd\n"); return 2; } if (flagstdin && flagdd) { myprintf("00568: -stdin incompatible with -dd\n"); return 2; } */ if (flagimage) if (!isadmin()) { myprintf("\n"); myprintf("00569! Impossible to image: admin rights required\n"); return 2; } #endif // corresponds to #ifdef (#ifdef _WIN32) /* fix some defaults */ if (snapmark!="") { string newmark =""; string temp =snapmark; for (unsigned int i=0;i30) newmark.erase(30,std::string::npos); if (newmark!="") { if (newmark!=snapmark) myprintf("00570: franz:zfs snapshot mark to |%s|\n",newmark.c_str()); snapmark=newmark; } } if (g_output!="") open_output(g_output); if (g_error!="") if (fileexists(g_error)) { if (flagverbose) printf("02743: DELETING ERROR FILE %s\n",g_error.c_str()); delete_file(g_error.c_str()); } if (flagforcezfs) flagskipzfs=false; // win over skip #ifdef HWSHA1 if (flaghw) Sha1Prepare(true); else Sha1Prepare(false); #endif // corresponds to #ifdef (#ifdef HWSHA1) // write franzs' parameters (if not very briefly) if ((!flagpakka) && (!flagstdout) && (!flagterse)) { string franzparameters=""; for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if ((p->second.switchflag)!=NULL) if (*(p->second.switchflag)) franzparameters+=p->second.switchname+" "; string attivati=g_programflags.compact(); franzparameters+=attivati; if (franzparameters!="") if (!do_not_print_headers()) myprintf("00571: franz:%s\n",franzparameters.c_str()); } if (howmanythreads<1) howmanythreads=numberOfProcessors(); // Test date if (nowz==-1 || date<19000000000000LL || date>30000000000000LL) error("date is incorrect, use -until YYYY-MM-DD HH:MM:SS to set"); // Adjust negative version if (version<0) { Jidac jidac(*this); jidac.version=DEFAULT_VERSION; jidac.read_archive(NULL,archive.c_str()); version+=jidac.ver.size()-1; myprintf("00575: Version %1.0f\n", version+.0); } /* Substitute %day into archive and files and comments */ archive=format_datetime(archive); for (unsigned int i=0;i long |%s|\n",onlyfiles[i].c_str()); } for (unsigned int i=0;i long |%s|\n",notfiles[i].c_str()); } if (flagdebug3) printbar('$'); } #endif // corresponds to #ifdef (#ifdef _WIN32) return 0; } // Return 1 if error else 0. int Jidac::doCommand() { if (g_chunk_size>0) { if (command!='a') { myprintf("00582! -chunk works only with a command\n"); return 2; } if (!iswildcards(archive)) { myprintf("00583! the archive must be multipart (with some ?) for -chunk\n"); return 2; } if (g_indexname!="") { myprintf("00584! -chunk incompatible with -index\n"); return 2; } } // Execute command if (flaginput) { if (fileexists(g_input)) { vector inputfiles; readfiletoarray(g_input,inputfiles); if (!do_not_print_headers()) myprintf("00585: Inputfiles count %s\n",migliaia(inputfiles.size())); if (inputfiles.size()>0) for (unsigned int i=0;i destinationfiles; readfiletoarray(g_destination,destinationfiles); if (!do_not_print_headers()) myprintf("00323: Destination count %s\n",migliaia(destinationfiles.size())); if (destinationfiles.size()>0) for (unsigned int i=0;i0) // enforce: we do not want to change anything when adding { if (flagstore) { flagnodedup=true; method='0'; } g_fakewrite =false; flagfixeml =false; flagfix255 =false; flagutf =false; #ifdef _WIN32 flagfixcase =false; flagfixreserved =false; #endif // corresponds to #ifdef (#ifdef _WIN32) flagflat =false; g_franzotype=FRANZO_XXHASH64B; // by default 2 (CRC32+XXHASH64) g_franzotypelen=16; for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) { /// myprintf("00588: iterator %d\n",p->first); if (p->second.switchflag!=NULL) if (*(p->second.switchflag)) if (p->second.flagiszpaq) { g_franzotype=p->first; g_franzotypelen=p->second.hashlen; break; } } if (flag715 || flagnochecksum) g_franzotype=FRANZO_NONE; if (flagappend) return append(); if (flaghome) return addhome(); else return add(); } else if (command=='+') return crop(); else if (command=='!') return isopen(); else if (command=='|') return versum(); else if (command=='^') return last2(); else if (command=='_') return testbackup(); else if (command=='?') return comparehex(); else if (command=='[') return count(); else if (command==']') return work(); #ifdef SFTP else if (command=='@') return sftp(); #endif // corresponds to #ifdef (#ifdef SFTP) else if (command=='$') return zfsbackup(); else if (command=='=') return zfsproxbackup(); else if (command=='(') return zfsproxrestore(); else if (command=='%') return zfsrestore(); else if (command==';') return zfsreceive(); else if (command==')') return oneonone(); else if (command=='0') return pause(); else if (command=='1') return summa(); else if (command=='2') return dir(); else if (command=='3') return purgersync(); else if (command=='4') return trim(); else if (command=='5') return zpaqdirsize(); else if (command=='6') return setpassword(); else if (command=='7') return rd(); else if (command=='8') return autotest(); else if (command=='9') return hasha(); else if (command=='A') return zfsadd(); else if (command=='B') return zfslist(); else if (command=='C') return zfspurge(); else if (command=='D') return dump(); else if (command=='F') return fzf(); ///G else if (command=='H') return zfssize(); ///I J else if (command=='K') return collision(true); else if (command=='L') return last(); else if (command=='R') return redu(); #ifdef _WIN32 else if (command=='.') return pakkalist(); else if (command=='S') return ads(); #endif // corresponds to #ifdef (#ifdef _WIN32) else if (command=='U') return update(); #ifdef _WIN64 else if (command=='W') return download(); #endif // corresponds to #ifdef (#ifdef _WIN64) else if (command=='Y') return consolidatebackup(); else if (command=='Z') return backup(); else if (command=='b') return benchmark(); else if (command=='c') return dircompare(false,false); else if (command=='d') return deduplicate(); else if (command=='e') return ecommand(); else if (command=='f') return fillami(); #ifdef _WIN32 else if (command=='g') return adminrun(); #endif // corresponds to #ifdef (#ifdef _WIN32) else if (command=='i') return info(); else if (command=='j') return findj(); else if (command=='k') return kill(); else if (command=='l') return list(); else if (command=='m') return consolidate(archive); else if (command=='n') return decimation(); else if (command=='o') return mycopy(); else if (command=='p') return paranoid(); #ifdef _WIN32 else if (command=='q') return windowsc(); #endif // corresponds to #ifdef (#ifdef _WIN32) else if (command=='r') return robocopy(); else if (command=='s') return dircompare(true,false); else if (command=='t') return multisomething(); else if (command=='u') return utf(); else if (command=='v') return verify(true); else if (command=='w') return extractw(); else if (command=='x') return multisomething(); else if (command=='y') return sfx(); else if (command=='z') return zero(); #ifndef ANCIENT else if (command==':') return ls(); else if (command=='T') return tui(); #endif else if (command=='M') return mysql(); else usage(); return 0; } bool Jidac::getfoldersize(string i_folder,uint64_t& o_totalsize,uint32_t & o_totalfile,uint32_t& o_totaldir,uint32_t& o_longfiles) { o_totalsize =0; o_totalfile =0; o_totaldir =0; o_longfiles =0; if (i_folder=="") return false; /// we need to cut last / for Windows longpath if (isdirectory(i_folder)) i_folder=i_folder.substr(0,i_folder.size()-1); DTMap mydestinationdir; if (flagdebug) { myprintf("00589: Scanning dir <<%Z>>\n",i_folder.c_str()); } scandir(true,mydestinationdir,i_folder); printbar(' ',false); myprintf("\r"); for (DTMap::iterator p=mydestinationdir.begin(); p!=mydestinationdir.end(); ++p) { string fn=p->first; if (fn.size()>255) o_longfiles++; if (!isdirectory(p->first)) { o_totalsize+=p->second.size; o_totalfile++; } else o_totaldir++; } if (flagdebug) myprintf("00591: files %s dirs %s size %s long %s\n",migliaia((int64_t)o_totalfile),migliaia2((int64_t)o_totaldir),migliaia3((int64_t)o_totalsize),migliaia4((int64_t)o_longfiles)); if (o_totalfile || o_totaldir || o_totalsize) return true; return false; } int Jidac::rd() { myprintf("00592: Remove Directory "); if (files.size()==0) { myprintf("00593! rd exactly at least one folder\n"); return 2; } // cut the last / because we want longfile support on Windows for (unsigned int i=0;i3) /// ../pippo if (i_filename[0]=='.') if (i_filename[1]=='.') if (i_filename[2]=='/') { (*o_relativepath)++; risultato&=FIX_RELATIVE; } } return risultato; } bool isfileopen(const string& i_filename) { #ifdef _WIN32 if (i_filename=="") return false; if (!fileexists(i_filename)) return false; HANDLE h=CreateFileW(utow(i_filename.c_str()).c_str(), GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL); if ((h!=NULL) && (h!=INVALID_HANDLE_VALUE)) { CloseHandle(h); return false; } return true; #else return false; #endif // corresponds to #ifdef (#ifdef _WIN32) } int compressfraglist(const vector& ptr, bool i_flagprint) { int howmanyhypens =0; bool hyphen =false; for (unsigned int i=0; i2) if ((solonome[0]=='.') && (solonome[1]=='_')) { if (flagverbose) myprintf("00610: Skip Mac ._something %s\n",i_stringa.c_str()); return true; } return false; } // Funzione per verificare se filename soddisfa le condizioni richieste bool Jidac::onlynorecursion(string filename) { if (flagdebug5) myprintf("Vado di checkfilename %s su %s\n",filename.c_str(),onlyfiles[0].c_str()); for (unsigned int i=0;i percorso.size()) { if (flagdebug5) myprintf("Entro2 %s\n",ilfile.substr(0,percorso.size()).c_str()); if (ilfile.substr(0,percorso.size()) == percorso) { string remaining = ilfile.substr(percorso.size()); if (flagdebug5) myprintf("Entro3 remaining %s\n",remaining.c_str()); if (std::count(remaining.begin(),remaining.end(),'/')==1) return true; } } } else { string percorsofile=includetrailingbackslash(extractfilepath(ilfile)); if (percorsofile==percorso) { if (flagdebug5) myprintf("OK: un file %s con percorsofile %s == percorso %s\n",ilfile.c_str(),percorsofile.c_str(),percorso.c_str()); return true; } } } return false; } // Test whether filename and attributes are selected by files, -only, and -not // If rn then test renamed filename. // if i_size >0 check file size too (minsize,maxsize) bool Jidac::isselected(const char* filename, bool rn,int64_t i_size) { if (g_optional=="versum") return true; //dirsize, take ALL the stuff, for pos() filtering if (g_optional=="dirsize") return true; //dirsize, take ALL the stuff, for pos() filtering if (g_optional=="zfsadd") return true; // skip all this stuff, take everything bool matched=true; #ifdef _WIN32 if (flagonedrive) if (!isrealfile(filename)) { if (flagverbose) myprintf("57254$ Skip placeholder <<%Z>>\n",filename); return false; } #endif if (!flagforcezfs) if (flagskipzfs) //this is an "automagically" exclude for zfs' snapshots if (iszfs(filename)) { if (flagverbose) myprintf("00611: Verbose: Skip .zfs %s\n",filename); return false; } if (flagnomac) if (ismac(filename)) return false; /* if (flagnosynology) if (issynology(filename)) return false; */ if (flagnoqnap) //this is an "automagically" exclude for qnap's snapshots if ( (strstr(filename, "@Recently-Snapshot")) || (strstr(filename, "@Recycle")) || (strstr(filename, "/.streams/")) ) { if (flagverbose) myprintf("00612: Verbose: Skip qnap %s\n",filename); return false; } if (!flagforcewindows) //this "automagically" exclude anything with System Volume Information { if (strstr(filename, "System Volume Information")) { if (flagverbose) myprintf("00613: Verbose: Skip System Volume Information %s\n",filename); return false; } if (strstr(filename, "$RECYCLE.BIN")) { if (flagverbose) myprintf("00614: Verbose: Skip trash %s\n",filename); return false; } } /// search for fake file (ASCII versions) if (isads(filename)) { if (mypos("VCOMMENT ",filename)>-1) return true; if (mypos("VFILE-",filename)>-1) return true; if (mypos("MFILE-",filename)>-1) return true; } if (!flagforcewindows) if (isads(filename)) return false; if (i_size>0) { if (maxsize) if (maxsize<(uint64_t)i_size) { if (flagdebug) myprintf("00615: (-maxsize) too big %19s %s\n",migliaia(i_size),filename); return false; } if (minsize) if (minsize>(uint64_t)i_size) { if (flagdebug) myprintf("00616: (-minsize) too small %19s %s\n",migliaia(i_size),filename); return false; } } if (files.size()>0) { matched=false; for (unsigned i=0; i0) { matched=false; if (flagnorecursion) { matched=onlynorecursion(filename); } else { for (unsigned i=0; i %s\n",filename.c_str()); return; } if (flagnomac) if (ismac(filename)) return; /* if (flagnosynology) if (issynology(filename)) return false; */ if (flagnoqnap) { if (filename.find("@Recently-Snapshot")!=std::string::npos) { if (flagverbose) myprintf("00626: Verbose: Skip qnap snapshot ----> %s\n",filename.c_str()); return; } if (filename.find("@Recycle")!=std::string::npos) { if (flagverbose) myprintf("00627: Verbose: Skip qnap recycle ----> %s\n",filename.c_str()); return; } } #ifdef unix // Add regular files and directories while (filename.size()>1 && filename[filename.size()-1]=='/') filename=filename.substr(0, filename.size()-1); // remove trailing / struct stat sb; if (!lstat(filename.c_str(), &sb)) { int64_t creationdate=0; if (S_ISREG(sb.st_mode)) { if (flagdate) { creationdate=datacreazione(filename); if (flagdebug3) myprintf("00628: Birth date %s of %s\n",dateToString(flagutc,creationdate).c_str(),filename.c_str()); } addfile(i_checkifselected,i_edt,filename, decimal_time(sb.st_mtime), sb.st_size,'u'+(sb.st_mode<<8),creationdate,0); } // Traverse directory if (S_ISDIR(sb.st_mode)) { addfile(i_checkifselected,i_edt,filename=="/" ? "/" : filename+"/", decimal_time(sb.st_mtime),0, 'u'+(int64_t(sb.st_mode)<<8),creationdate,0); DIR* dirp=opendir(filename.c_str()); if (dirp) { for (dirent* dp=readdir(dirp); dp; dp=readdir(dirp)) { if (strcmp(".", dp->d_name) && strcmp("..", dp->d_name)) { string s=filename; if (s!="/") s+="/"; s+=dp->d_name; if (i_recursive) scandir(i_checkifselected,i_edt,s); else { if (!lstat(s.c_str(), &sb)) { int64_t creationdate=0; if (S_ISREG(sb.st_mode)) { if (flagdate) { creationdate=datacreazione(s); if (flagdebug3) myprintf("00629: Birth date %s of %s\n",dateToString(flagutc,creationdate).c_str(),s.c_str()); } addfile(i_checkifselected,i_edt,s, decimal_time(sb.st_mtime), sb.st_size,'u'+(sb.st_mode<<8),creationdate,0); } if (S_ISDIR(sb.st_mode)) addfile(i_checkifselected,i_edt,s=="/" ? "/" :s+"/", decimal_time(sb.st_mtime),0, 'u'+(int64_t(sb.st_mode)<<8),creationdate,0); } } } } closedir(dirp); } else { perror(filename.c_str()); } } } else { if (!flagstdin) perror(filename.c_str()); } #else // Windows: expand wildcards in filename // Expand wildcards WIN32_FIND_DATA ffd; string t=filename; if (t.size()>0 && t[t.size()-1]=='/') t+="*"; HANDLE h=FindFirstFile(utow(t.c_str()).c_str(), &ffd); if (!flagverbose) if (h==INVALID_HANDLE_VALUE) if (GetLastError()==5) //ERROR_ACCESS_DENIED if (mypos("/System Volume Information/",t)>=0) { FindClose(h); return; } if (h==INVALID_HANDLE_VALUE && GetLastError()!=ERROR_FILE_NOT_FOUND && GetLastError()!=ERROR_PATH_NOT_FOUND) printerr("15367",t.c_str(),0); while (h!=INVALID_HANDLE_VALUE) { // For each file, get name, date, size, attributes SYSTEMTIME st; /* [out, optional] LPFILETIME lpCreationTime, [out, optional] LPFILETIME lpLastAccessTime, [out, optional] LPFILETIME lpLastWriteTime */ int64_t edate=0; if (FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) edate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; int64_t creationdate=0; if (FileTimeToSystemTime(&ffd.ftCreationTime, &st)) creationdate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; int64_t accessdate=0; /* if (FileTimeToSystemTime(&ffd.ftLastAccessTime, &st)) accessdate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; */ int64_t esize=ffd.nFileSizeLow+(int64_t(ffd.nFileSizeHigh)<<32); const int64_t eattr='w'+(int64_t(ffd.dwFileAttributes)<<8); // Ignore links, the names "." and ".." or any unselected file t=wtou(ffd.cFileName); /// Ok this is rather weird, but is Microsoft afterall /// a SYMLINK in a VSS can become rather tricky /// this should (?) get the "real" name of a SYMLINK /// Microsoft documentations sucks big time ///string solonome=extractfilename(t); if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { string miofilename=path(filename)+t; string nuovonome=my_realpath(miofilename); if (nuovonome!="") { int64_t newsize=dim(nuovonome); esize=newsize; } string percorso=""; size_t destra= nuovonome.rfind(t); if (destra!=std::string::npos) percorso=myleft(nuovonome,destra)+"*"; if (percorso!="") filename=percorso; } if (flagdebug3) // sometimes Windows get very strange attributes { string myfn=path(filename)+t; myprintf("00630: FATTR %08X RES0 %08X %Z\n",(unsigned int)ffd.dwFileAttributes,(unsigned int)ffd.dwReserved0,myfn.c_str()); string temp=decodewinattribute(ffd.dwFileAttributes); myprintf("00631: %s\n",temp.c_str()); } if (t=="." || t=="..") edate=0; // don't add, of course /* OK, now test Windows crazy fake files */ if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (ffd.dwReserved0==IO_REPARSE_TAG_SYMLINK)) { int64_t newsize=dim(filename); if (flagdebug) myprintf("00632: maybe Windows-symlinked file, fake size %s real size %s %s\n",migliaia(esize),migliaia(newsize),filename.c_str()); esize=newsize; } if (ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { /* REPARSE_POINTS are a nightmare For now: just skip char buffer[100000]; int bufsize=100000; size_t byteletti; DWORD tag; string tipo; string thefile=path(filename)+t; if (flagverbose) myprintf("00633: try to get reparse point %s\n",thefile.c_str()); if (getreparsepointW(false,thefile,buffer,bufsize,byteletti,tag,tipo)) { if (flagverbose) { myprintf("00634: Reparse <<%s>>\n",thefile.c_str()); myprintf("00635: TAG %08X LEN %11s |%s|\n",tag,migliaia(byteletti),tipo.c_str()); } } else { if (flagverbose) myprintf("00636: fallito getreparsepointW %s\n",thefile.c_str()); } */ } if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))) { /// Houston, we have a strange deduplicated .vhdx file? /// add as by default if (flagdebug) myprintf("00637: Something strange (VHDX? SYMLINK?) FILE_ATTRIBUTE_REPARSE_POINT not DIR %s\n",t.c_str()); if (flagnosymlink) { edate=0; if (flagverbose) myprintf("00638: Skipped due to -symlink REPARSE_POINT && !DIRECTORY\n"); } } else { /// A junction? if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { ///https://bvckup2.com/support/forum/topic/981 ///https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/c8e77b37-3909-4fe6-a4ea-2b9d423b1ee4 if ( (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_1) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_2) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_3) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_4) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_5) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_6) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_7) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_8) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_9) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_A) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_B) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_C) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_D) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_E) || (ffd.dwReserved0==MYIO_REPARSE_TAG_CLOUD_F) ) { if (flagdebug) myprintf("00639: this seems a ONEDRIVE-something, try to keep\n"); } else { if (flagdebug) { string myfn=path(filename)+t; myprintf("00640: discard REPARSE POINT & DIRECTORY <<%Z>>\n",myfn.c_str()); } edate=0; // don't add } } } string fn=path(filename)+t; // Save directory names with a trailing / and scan their contents // Otherwise, save plain files if (edate) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fn+="/"; addfile(i_checkifselected,i_edt,fn, edate, esize, eattr,creationdate,accessdate); if (i_recursive) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { fn+="*"; scandir(i_checkifselected,i_edt,fn); } // enumerate alternate streams (Win2003/Vista or later) else if (findFirstStreamW && findNextStreamW) { if (flagforcewindows) { WIN32_FIND_STREAM_DATA fsd; HANDLE ah=findFirstStreamW(utow(fn.c_str()).c_str(), FindStreamInfoStandard, &fsd, 0); while (ah!=INVALID_HANDLE_VALUE && findNextStreamW(ah, &fsd)) addfile(i_checkifselected,i_edt,fn+wtou(fsd.cStreamName), edate, fsd.StreamSize.QuadPart, eattr,creationdate,accessdate); if (ah!=INVALID_HANDLE_VALUE) FindClose(ah); } } } } if (!FindNextFile(h, &ffd)) { if (GetLastError()!=ERROR_NO_MORE_FILES) printerr("15417",(fn+fn).c_str(),ffd.dwFileAttributes); break; } } FindClose(h); #endif // corresponds to #ifdef (#ifdef unix) } // Add external file and its date, size, and attributes to dt void Jidac::addfile(bool i_checkifselected,DTMap& i_edt,string filename, int64_t edate, int64_t esize, int64_t eattr, int64_t i_creationdate,int64_t i_accessdate) { static int milione=0; if (i_checkifselected) if (!isselected(filename.c_str(), false,esize)) return; // OK, let's handle longpath on VSS by a kludge // cook some spaghetti code! if (command=='q') if (filename.size()>250) myreplace(filename,g_franzsnap,g_vss_shadow); if (command!='j') { if (g_datefrom>0) if (edate<=g_datefrom) return; if (g_dateto>0) if (edate>=g_dateto) return; } DT& d=i_edt[filename]; if (g_touch!=0) d.date=g_touch; else d.date=edate; d.creationdate=i_creationdate; d.accessdate=i_accessdate; d.size=esize; d.attr=flagnoattributes?0:eattr; d.data=0; g_bytescanned+=esize; g_filescanned++; static int ultimotempo =-1; double scantime =(mtime()-g_start+1); int iscantime =(int64_t)(scantime/1000); if (flagdebug5) { milione++; if (milione % 1000000 == 0) { int64_t dt_ram =get_dt_ram(); int64_t edt_ram =get_edt_ram(); int64_t extsize =(dt_ram+edt_ram+g_dt_ram)/100*165; myprintf("00642: Scanned %10s %02d:%02d:%02d %10s file/s (%21s) RAM~ %10s\n", migliaia((int64_t)i_edt.size()), int(iscantime/3600), int(iscantime/60)%60, int(iscantime)%60, migliaia3((int)(i_edt.size()/(scantime/1000.0))),migliaia2(g_bytescanned),tohuman(extsize)); fflush(stdout); /// getcaptcha("ok","Fill (wipe) free space"); return; } } if (flagnoeta==false) if (iscantime!=ultimotempo) { ultimotempo=iscantime; myprintf("00643: Scanned %10s %02d:%02d:%02d %10s file/s (%21s)\r", migliaia((int64_t)i_edt.size()), int(iscantime/3600), int(iscantime/60)%60, int(iscantime)%60, migliaia3((int)(i_edt.size()/(scantime/1000.0))),migliaia2(g_bytescanned)); fflush(stdout); } } //////////////////////////////// add ////////////////////////////////// // Append n bytes of x to sb in LSB order inline void puti(libzpaq::StringBuffer& sb, uint64_t x, int n) { for (; n>0; --n) sb.put(x&255), x>>=8; } // A CompressJob is a queue of blocks to compress and write to the archive. // Each block cycles through states EMPTY, FILLING, FULL, COMPRESSING, // COMPRESSED, WRITING. The main thread waits for EMPTY buffers and // fills them. A set of compressThreads waits for FULL threads and compresses // them. A writeThread waits for COMPRESSED buffers at the front // of the queue and writes and removes them. // Buffer queue element struct CJ { enum {EMPTY, FULL, COMPRESSING, COMPRESSED, WRITING} state; StringBuffer in; // uncompressed input StringBuffer out; // compressed output string filename; // to write in filename field string comment; // if "" use default string method; // compression level or "" to mark end of data Semaphore full; // 1 if in is FULL of data ready to compress Semaphore compressed; // 1 if out contains COMPRESSED data CJ(): state(EMPTY) {} }; // Instructions to a compression job class CompressJob { public: Mutex mutex; // protects state changes OutputArchive* out; // archive, public for ESXi support private: int job; // number of jobs CJ* q; // buffer queue unsigned qsize; // number of elements in q int front; // next to remove from queue Semaphore empty; // number of empty buffers ready to fill Semaphore compressors; // number of compressors available to run public: friend ThreadReturn compressThread(void* arg); friend ThreadReturn writeThread(void* arg); CompressJob(int threads, int buffers, OutputArchive * f): out(f),job(0), q(0), qsize(buffers), front(0) { if (buffers<=0) { myprintf("54912! Invalid buffers! %s\n",migliaia(buffers)); throw std::invalid_argument("54913: Invalid buffer size"); } q=new CJ[buffers]; g_allocatedram+=sizeof(CJ)*buffers; if (!q) throw std::bad_alloc(); init_mutex(mutex); empty.init(buffers); compressors.init(threads); for (int i=0; i=0; --i) { q[i].compressed.destroy(); q[i].full.destroy(); } compressors.destroy(); empty.destroy(); destroy_mutex(mutex); delete[] q; } void appendz(StringBuffer& s, const char* filename, const string& method, const char* comment=0); vector csize; // compressed block sizes }; // Write s at the back of the queue. Signal end of input with method="" void CompressJob::appendz(StringBuffer& s, const char* fn, const string& method, const char* comment) { for (unsigned k=(method=="")?qsize:1; k>0; --k) { empty.wait(); lock(mutex); unsigned i, j; for (i=0; i=0 && jobNumber> %08X size %ld\n",myblock.filename.c_str(),myblock.crc32,myblock.crc32size); cj.state=CJ::COMPRESSED; cj.compressed.signal(); job.compressors.signal(); release(job.mutex); } } catch (std::exception& e) { lock(job.mutex); fflush(stdout); myprintf("00647: job %d: %s\n", jobNumber+1, e.what()); g_exec_text="job error"; release(job.mutex); exit(1); } return 0; } // Write compressed data to the archive in the background ThreadReturn writeThread(void* arg) { CompressJob& job=*(CompressJob*)arg; try { // work until done while (true) { // wait for something to write CJ& cj=job.q[job.front]; // no other threads move front cj.compressed.wait(); // Quit if end of input lock(job.mutex); if (cj.method=="") { release(job.mutex); return 0; } // Write to archive assert(cj.state==CJ::COMPRESSED); cj.state=CJ::WRITING; job.csize.push_back(cj.out.size()); if (job.out && cj.out.size()>0) { release(job.mutex); assert(cj.out.c_str()); const char* p=cj.out.c_str(); int64_t n=cj.out.size(); g_scritti+=n; // very rude if (flagfast) if (cj.filename==g_thememfileblock) { if (g_thememfilestart==0) g_thememfilestart=job.out->tell(); if (flagdebug3) myprintf("00648: $$$$$$$$$$$$$$$$$$$$$ %s %s len=%s\n",migliaia(g_thememfilestart),cj.filename.c_str(),migliaia2(g_thememfilelength)); } const int64_t N=1<<30; while (n>N) { job.out->write(p, N); p+=N; n-=N; } job.out->write(p, n); lock(job.mutex); } cj.out.resize(0); cj.state=CJ::EMPTY; job.front=(job.front+1)%job.qsize; job.empty.signal(); release(job.mutex); } } catch (std::exception& e) { fflush(stdout); ///this is a very dirty trick to do NOT check for control-C inside the thread if (!g_control_c) { myprintf("00649: zpaqfranz exiting from writeThread: %s\n", e.what()); g_exec_text="exiting from writethread"; exit(1); } else { myprintf("\n*** WRITE THREAD GET A CONTROL-C !!!! ***\n"); } } return 0; } // Write a ZPAQ compressed JIDAC block header. Output size should not // depend on input data. void writeJidacHeader(libzpaq::Writer *out, int64_t date, int64_t cdata, unsigned htsize) { if (!out) return; if (flagdebug3) myprintf("00650: start writejidacheader date %s cdata %s htsize %s\n",migliaia(date),migliaia2(cdata),migliaia3(htsize)); /* if (g_fp_zpaq!=FPNULL) myprintf("00653: g_fp_zpaq %s\n",migliaia(ftello(g_fp_zpaq))); */ assert(date>=19000000000000LL && date<30000000000000LL); /* cdata=2; htsize=3; */ StringBuffer is; puti(is, cdata, 8); libzpaq::compressBlock(&is, out, "0", ("jDC"+itos(date, 14)+"c"+itos(htsize, 10)).c_str(), "jDC\x01"); if (flagdebug3) myprintf("00651: ended writejidacheader\n"); } // Maps sha1 -> fragment ID in ht with known size class HTIndex { vector& htr; // reference to ht libzpaq::Array t; // sha1 prefix -> index into ht unsigned htsize; // number of IDs in t // Compuate a hash index for sha1[20] unsigned hash(const char* sha1) { return (*(const unsigned*)sha1)&(t.size()-1); } public: // r = ht, sz = estimated number of fragments needed HTIndex(vector& r, size_t sz): htr(r), t(0), htsize(1) { int b; for (b=1; sz*3>>b; ++b) ; t.resize(1, b-1); update(); } // Find sha1 in ht. Return its index or 0 if not found. unsigned find(const char* sha1) { unsigned h=hash(sha1); for (unsigned i=0; i=t.size()/4*3) { t.resize(t.size(), 1); htsize=1; } if (htr[htsize].usize>=0 && memcmp(htr[htsize].sha1, zero, 20)!=0) { unsigned h=hash((const char*)htr[htsize].sha1); for (unsigned i=0; iput(c); if (b) b->put(c); } void write(const char* buf, int n) { if (a) a->write(buf, n); if (b) b->write(buf, n); } WriterPair(): a(0), b(0) {} }; void Jidac::write715attr(libzpaq::StringBuffer& i_sb, uint64_t i_data, unsigned int i_quanti) { /// assert(i_sb); assert(i_quanti<=8); puti(i_sb, i_quanti, 4); puti(i_sb, i_data, i_quanti); } /* Values used in typeflag field. */ #define REGTYPE '0' /* regular file */ #define AREGTYPE '\0' /* regular file */ #define LNKTYPE '1' /* link */ #define SYMTYPE '2' /* reserved */ #define CHRTYPE '3' /* character special */ #define BLKTYPE '4' /* block special */ #define DIRTYPE '5' /* directory */ #define FIFOTYPE '6' /* FIFO special */ #define CONTTYPE '7' /* reserved */ /// atime, ctime, flagisstdout, int version struct franz_posix { /// char mode [8]; char typeflag [8]; ///Type of file (first byte), flaglink (second) char uid [8]; ///Owner user ID char gid [8]; ///Owner group ID char uname [32]; char gname [32]; char devmajor [8]; char devminor [8]; char linkname [256]; }; /* void dump_franzattr(string i_thehash,int32_t i_writtencrc,char* i_buffer,int i_franzsize,int64_t i_creationdate,bool i_isadded) { myprintf("00652: g_franzotype |%s|\n",migliaia(g_franzotype)); myprintf("00653: franzsize |%s|\n",migliaia(i_franzsize)); myprintf("00654: hash |%s|\n",i_thehash.c_str()); myprintf("00655: crc32 |%08X|\n",i_writtencrc); myprintf("00656: creationdate |%s|\n",bin2hex_64(i_creationdate).c_str()); myprintf("00657: isadded |%d|\n",(int)i_isadded); for (int i=0;i0); // I do not like empty() assert(i_quanti<8); //just to be sure at least 1 zero pad, so < and not <= assert(i_filename!=""); uint32_t writtencrc; if (flagverify) writtencrc=i_crc32fromfragments; else writtencrc=i_crc32; i_dtmap->second.hexcrc32=bin2hex_32(writtencrc); if (g_franzotype==FRANZO_NONE) /*|| (i_thehash=="")*/ // 7.15 { if (flagdebug3) myprintf("00658: old-style attr with hash |%s|\n",i_thehash.c_str()); write715attr(i_sb,i_data,i_quanti); return; } if (flagverify || flagcollision) if (i_crc32!=i_crc32fromfragments) { myprintf("\n"); myprintf("00659: GURU-C: on file %s\n",i_filename.c_str()); myprintf("00660: GURU: CRC-32 from fragments %08X\n",i_crc32fromfragments); myprintf("00661: GURU: CRC-32 from file %08X\n",i_crc32); // if (!flagdebug) /// error("Guru-C checking crc32"); } if (g_franzotype==FRANZO_CRC_32) /// store only CRC-32 { char mybuffer[FRANZOFFSETV1]={0}; snprintf(mybuffer+41,sizeof(mybuffer)-41,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV1, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV1); if (flagdebug3) myprintf("00662: Mode1: CRC32 by frag <<%s>> %s\n",mybuffer+41,i_filename.c_str()); } else if ((g_franzotype==FRANZO_XXHASH64B) || (g_franzotype==FRANZO_MD5B) ||(g_franzotype==FRANZO_BLAKE3B)||(g_franzotype==FRANZO_SHA_256B) ||(g_franzotype==FRANZO_SHA3B)||(g_franzotype==FRANZO_XXH3B)||(g_franzotype==FRANZO_SHA_1B)) { char mybuffer[FRANZOFFSETV1]={0}; int primobyte =g_franzotype/10+'0'; int secondobyte =g_franzotype%10+'0'; ///myprintf("00663: primo %d secondo %d\n",primobyte,secondobyte); mybuffer[0]=primobyte; mybuffer[1]=secondobyte; /* if (primobyte==mybuffer[0]) myprintf("00664: uguale\n"); else myprintf("00665: diverso\n"); seppuku(); */ mybuffer[49]=1; // backward compatibility, not zero //myprintf("$$$$$$$$$$$$$$ |%s| g_franzotypelen %d\n",i_thehash.c_str(),g_franzotypelen); hex2binary(i_thehash, mybuffer+2,g_franzotypelen/2); inttoarray(writtencrc, mybuffer+34,4); inttoarray(i_creationdate, mybuffer+38,8); mybuffer[47]=i_isadded; puti(i_sb, 8+FRANZOFFSETV1, 4); puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV1); /// please note the dirty trick: start by +10 /// dump_franzattr(i_thehash,writtencrc,mybuffer,FRANZOFFSETV1,i_creationdate,i_isadded); /* g_franzotype |14| franzsize |50| hash |40F9EBAF86404803| crc32 |B95E043D| creationdate |00001268A346224A| isadded |1| offset 000 valore 049 31 car 1 * offset 001 valore 052 34 car 4 * offset 002 valore 003 03 offset 003 valore 072 48 car H offset 004 valore 064 40 car @ offset 005 valore 134 86 offset 006 valore 175 AF offset 007 valore 235 EB offset 008 valore 249 F9 offset 009 valore 064 40 car @ offset 010 valore 000 00 offset 011 valore 000 00 offset 012 valore 000 00 offset 013 valore 000 00 offset 014 valore 000 00 offset 015 valore 000 00 offset 016 valore 000 00 offset 017 valore 000 00 offset 018 valore 000 00 offset 019 valore 000 00 offset 020 valore 000 00 offset 021 valore 000 00 offset 022 valore 000 00 offset 023 valore 000 00 offset 024 valore 000 00 offset 025 valore 000 00 offset 026 valore 000 00 offset 027 valore 000 00 offset 028 valore 000 00 offset 029 valore 000 00 offset 030 valore 000 00 offset 031 valore 000 00 offset 032 valore 000 00 offset 033 valore 000 00 offset 034 valore 061 3D car = offset 035 valore 004 04 offset 036 valore 094 5E car ^ offset 037 valore 185 B9 offset 038 valore 074 4A car J offset 039 valore 034 22 car " offset 040 valore 070 46 car F offset 041 valore 163 A3 offset 042 valore 104 68 car h offset 043 valore 018 12 offset 044 valore 000 00 offset 045 valore 000 00 offset 046 valore 000 00 isordered offset 047 valore 001 01 isadded offset 048 valore 000 00 offset 049 valore 001 01 * */ if (flagdebug3) myprintf("00666: Mode14: BINARY: <<%s>> CRC32 <<%08X>> %s\n",i_thehash.c_str(),writtencrc,i_filename.c_str()); } else if (g_franzotype==FRANZO_XXHASH64) { assert(i_thehash.length()==32); char mybuffer[FRANZOFFSETV1]={0}; snprintf(mybuffer+8,sizeof(mybuffer)-8, "%s",i_thehash.c_str()); snprintf(mybuffer+41,sizeof(mybuffer)-41,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV1, 4); puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV1); /// please note the dirty trick: start by +10 if (flagdebug3) myprintf("00667: Mode2: XXHASH64: <<%s>> CRC32 <<%s>> %s\n",mybuffer+8,mybuffer+41,i_filename.c_str()); } else if (g_franzotype==FRANZO_SHA_1) //3= 51 (SHA1-0-CRC32) { char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "08"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 if (flagdebug3) myprintf("00668: Model8: SHA1 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if (g_franzotype==FRANZO_SHA_256) ///4= 52 (01-SHA256-0-CRC32) { assert(i_thehash.length()==64); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "04"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); /// please note the dirty trick: start by +8 if (flagdebug3) myprintf("00669: Mode4: SHA256 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if (g_franzotype==FRANZO_SHA3) ///2= 52 (01-SHA3-0-CRC32) { assert(i_thehash.length()==64); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "02"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 if (flagdebug3) myprintf("00670: Mode7: SHA3 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if (g_franzotype==FRANZO_MD5) ///1= 52 (01-MD5-0-CRC32) { assert(i_thehash.length()==32); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "01"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 if (flagdebug3) myprintf("00671: Mode8: MD5 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if ((g_franzotype==FRANZO_WHIRLPOOL) || (g_franzotype==FRANZO_HIGHWAY64) || (g_franzotype==FRANZO_HIGHWAY128) || (g_franzotype==FRANZO_HIGHWAY256)) ///1= 52 (01-MD5-0-CRC32) { /// [0][1] + 0 2bytes long FRANZO_CODE /// + 2 128 bytes hash /// +2+128+1 8 bytes CRC32 /// 8 bytes creationdate (binary) /// 8 bytes accessdate (binary) char mybuffer[FRANZOFFSETV3]={0}; if (flagdebug3) { myprintf("\n"); myprintf("00672: thehash %s\n",i_thehash.c_str()); myprintf("00673: writtencrc %08X\n",writtencrc); } string mycode; if (flagtar) mycode=std::string()+"4"+char(g_franzotype+'A'); else mycode=std::string()+"3"+char(g_franzotype+'A'); if (flagdebug3) myprintf("00674: MYCODE |%s|\n",mycode.c_str()); if (mycode.size()!=2) { myprintf("00675: GURU mycode must be 2 chars!\n"); seppuku(); return; } int offsetcrc =0; int offset =0; snprintf(mybuffer+offset,sizeof(mybuffer)-offset,"%s",mycode.c_str()); //two bytes offset+=mycode.size(); if (flagdebug3) myprintf("00676: Offset1 (after mycode) %3d\n",offset); snprintf(mybuffer+offset,sizeof(mybuffer)-offset,"%s",i_thehash.c_str()); offset+=i_thehash.size()+2; if (flagdebug3) myprintf("00677: Offset2 (after hash) %3d\n",offset); offsetcrc=offset; snprintf(mybuffer+offset,sizeof(mybuffer)-offset,"%08X",writtencrc); offset+=8+2; if (flagdebug3) myprintf("00678: Offset3 (after CRC) %3d\n",offset); uint32_t orderedstream=0; if (flagstdin) orderedstream=1; offset+=inttoarray(orderedstream ,mybuffer+offset,4); if (flagdebug3) myprintf("00679: Offset4 (after ordered)%3d\n",offset); // catch "holes" into multipart uint32_t versionnumber=1440408; offset+=inttoarray(versionnumber ,mybuffer+offset,4); if (flagdebug3) myprintf("00680: Offset5 (after version)%3d\n",offset); ///i_creationdate=987654321L; ///i_accessdate=554433229944L; offset+=inttoarray(i_creationdate ,mybuffer+offset,8); if (flagdebug3) myprintf("00681: Offset6 (after cdate) %3d\n",offset); offset+=inttoarray(i_accessdate ,mybuffer+offset,8); if (flagdebug3) myprintf("00682: Offset6 (after adate) %3d\n",offset); uint64_t azero=0; for (int i=0;i<3;i++) offset+=inttoarray(azero ,mybuffer+offset,8); if (flagdebug3) myprintf("00683: Offset7 (after spare) %3d\n",offset); int dascrivere=offset; if (flagtar) if (i_posix!=NULL) { if (flagdebug) myprintf("00684: flagtar and posix not null, use all FRANZOFFSETV3\n"); dascrivere=FRANZOFFSETV3; } if (flagdebug3) myprintf("00685: To write %08d header %08d + sizeof %08d\n",dascrivere,offset,sizeof(franz_posix)); if (dascrivere>FRANZOFFSETV3) { myprintf("00686: GURU dascrivere %08d > FRANZOFFSETV3 %08d\n",dascrivere,FRANZOFFSETV3); seppuku(); return; } puti(i_sb, 8+dascrivere, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,dascrivere); ///please note the dirty trick: start by +8 if (flagdebug3) myprintf("00687: Mode |%s| %s <<%s>> CRC32 <<%s>> %s\n",mycode.c_str(),decodefranzoffset(g_franzotype).c_str(),mybuffer+2,mybuffer+offsetcrc,i_filename.c_str()); } else if (g_franzotype==FRANZO_WINHASH64) ///10= 52 (10-XXHASH64-0-CRC32-0-creationwrite) { /// lpCreationTime, lpLastAccessTime, /// 2 byte 10 /// bit /// 0-1 10 type /// 2-66 /// 66-67 0x0 /// 68-72 CRC32 ASCII /// 73 0x ///printf("FRANZO WINNNNNNNNNN ENCODE\n"); /* i_creationdate=0xAABBCCDDEECF; i_accessdate=0xBBCCDDEEAB; */ assert(i_thehash.length()==32); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "10"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); inttoarray(i_creationdate ,mybuffer+2+31+1,8); inttoarray(i_accessdate ,mybuffer+2+31+1+8,8); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 if (flagdebug3) myprintf("00688: Mode10: WINHASH64 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if (g_franzotype==FRANZO_BLAKE3) ///3= 52 (01-BLAKE3-0-CRC32) { assert(i_thehash.length()==64); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "03"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 if (flagdebug) myprintf("00689: Mode6: BLAKE3 <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else if (g_franzotype==FRANZO_XXH3) ///5= 52 (00XXH3-0-CRC32) { assert(i_thehash.length()==32); char mybuffer[FRANZOFFSETV2]={0}; snprintf(mybuffer,sizeof(mybuffer), "09"); //<<< look at this snprintf(mybuffer+2,sizeof(mybuffer)-2, "%s",i_thehash.c_str()); snprintf(mybuffer+2+64+1,sizeof(mybuffer)-2-64-1,"%08X",writtencrc); puti(i_sb, 8+FRANZOFFSETV2, 4); // 8+FRANZOFFSETV1 block puti(i_sb, i_data, i_quanti); puti(i_sb, 0, (8 - i_quanti)); // pad with zeros (for 7.15 little bug) i_sb.write(mybuffer,FRANZOFFSETV2); ///please note the dirty trick: start by +8 /// please note the dirty trick: start by +8 if (flagdebug) myprintf("00690: Mode5: XXH3: <<%s>> CRC32 <<%s>> %s\n",mybuffer+2,mybuffer+67,i_filename.c_str()); } else perror("22144: unknown franzotype"); } // An extract job is a set of blocks with at least one file pointing to them. // Blocks are extracted in separate threads, set READY -> WORKING. // A block is extracted to memory up to the last fragment that has a file // pointing to it. Then the checksums are verified. Then for each file // pointing to the block, each of the fragments that it points to within // the block are written in order. struct ExtractJob { // list of jobs int chunk; Mutex mutex; // protects state Mutex write_mutex; // protects writing to disk int job; // number of jobs started Jidac& jd; // what to extract FP outf; // currently open output file DTMap::iterator lastdt; // currently open output file name double maxMemory; // largest memory used by any block (test mode) int64_t total_size; // bytes to extract int64_t total_done; // bytes extracted so far ExtractJob(Jidac& j): chunk(0),job(0), jd(j), outf(FPNULL), lastdt(j.dt.end()), maxMemory(0), total_size(0), total_done(0) { init_mutex(mutex); init_mutex(write_mutex); } ~ExtractJob() { destroy_mutex(mutex); destroy_mutex(write_mutex); } }; // Decompress blocks in a job until none are READY ThreadReturn decompressThread(void* arg) { ExtractJob& job=*(ExtractJob*)arg; int jobNumber=0; char byte0={0}; // Get job number lock(job.mutex); jobNumber=++job.job; release(job.mutex); ///myprintf("00691: K1 %s\n",job.jd.archive.c_str()); // Open archive for reading InputArchive in(job.jd.archive.c_str()/*,job.jd.g_password*/); if (!in.isopen()) return 0; StringBuffer out; // Look for next READY job. int next=0; // current job while (true) { lock(job.mutex); for (unsigned i=0; i<=job.jd.block.size(); ++i) { unsigned k=i+next; if (k>=job.jd.block.size()) k-=job.jd.block.size(); if (i==job.jd.block.size()) { // no more jobs? release(job.mutex); return 0; } Block& b=job.jd.block[k]; if (b.state==Block::READY && b.size>0 && b.usize>=0) { b.state=Block::WORKING; release(job.mutex); next=k; break; } } Block& b=job.jd.block[next]; // Get uncompressed size of block unsigned output_size=0; // minimum size to decompress assert(b.start>0); for (unsigned j=0; j=0); output_size+=job.jd.ht[b.start+j].usize; } // Decompress double mem=0; // how much memory used to decompress try { assert(b.start>0); assert(b.start0); assert(b.start+b.size<=job.jd.ht.size()); ///myprintf("00692: Andiamo su offset %lld %lld\n",b.offset,output_size); in.seek(b.offset, SEEK_SET); libzpaq::Decompresser d; d.setInput(&in); out.resize(0); assert(b.usize>=0); assert(b.usize<=0xffffffffu); out.setLimit(b.usize); d.setOutput(&out); if (!d.findBlock(&mem)) error("archive block not found"); if (mem>job.maxMemory) job.maxMemory=mem; while (d.findFilename()) { d.readComment(); while (out.size()=output_size) break; d.readSegmentEnd(); } if (out.size()0 && j=0); assert(job.jd.ht[j].usize<=0x7fffffff); if (q+job.jd.ht[j].usize>out.size()) error("Incomplete decompression"); char sha1result[20]; sha1.write(out.c_str()+q, job.jd.ht[j].usize); memcpy(sha1result, sha1.result(), 20); q+=job.jd.ht[j].usize; if (memcmp(sha1result, job.jd.ht[j].sha1, 20)) { lock(job.mutex); fflush(stdout); myprintf("00694: Job %d: fragment %u size %d checksum failed\n", jobNumber, j, job.jd.ht[j].usize); g_exec_text="fragment checksum failed"; release(job.mutex); error("bad checksum"); } ++b.extracted; } } // If out of memory, let another thread try catch (std::bad_alloc& e) { lock(job.mutex); fflush(stdout); myprintf("00695: Job %d killed: %s\n", jobNumber, e.what()); g_exec_text="Job killed"; b.state=Block::READY; b.extracted=0; out.resize(0); release(job.mutex); return 0; } // Other errors: assume bad input catch (std::exception& e) { lock(job.mutex); fflush(stdout); myprintf("00696: Job %d: skipping [%u..%u] at %1.0f: %s\n", jobNumber, b.start+b.extracted, b.start+b.size-1, b.offset+0.0, e.what()); release(job.mutex); continue; } // Write the files in dt that point to this block lock(job.write_mutex); for (unsigned ip=0; ipsecond.date==0 || p->second.data<0 || p->second.data>=int64_t(p->second.ptr.size())) continue; // don't write // Look for pointers to this block const vector& ptr=p->second.ptr; int64_t offset=0; // write offset for (unsigned j=0; j=b.start+b.extracted) { offset+=job.jd.ht[ptr[j]].usize; continue; } // Close last opened file if different if (p!=job.lastdt) { if (job.outf!=FPNULL) { assert(job.lastdt!=job.jd.dt.end()); assert(job.lastdt->second.date); assert(job.lastdt->second.data second.ptr.size())); myfclose(&job.outf); } job.lastdt=job.jd.dt.end(); } string filename; // Open file for output if (job.lastdt==job.jd.dt.end()) { filename=job.jd.rename(p->first); /* if (!flagstdout) if (flagramdisk) if (!isdirectory(filename)) if (p->second.pramfile==NULL) { p->second.pramfile=new franzfs; (*p->second.pramfile).init(p->second.size); g_allocatedram+=sizeof(franzfs); } */ assert(job.outf==FPNULL); if ((p->second.data==0) && (!flagstdout)) { if (!job.jd.flagtest) { if (flagdebug2) { myprintf("00697: MAKEPATH: %Z\n",filename.c_str()); } makepath(filename); } #ifdef _WIN32 if (!flagimage) #endif // corresponds to #ifdef (#ifdef _WIN32) { lock(job.mutex); print_progress(job.total_size, job.total_done,-1,-1); release(job.mutex); } if (!job.jd.flagtest) { /// sometimes (in Windows) the path is not made (ex. path too long) /// let's try to make (is just a fix). Please note utw #ifdef _WIN32 string percorso=extractfilepath(filename); if (percorso!="") { if (!flaglongpath) myreplaceall(percorso,"/","\\"); if (!direxists(percorso)) { if (flagdebug) myprintf("00699: ERROR DIRNOTEX %s\n",percorso.c_str()); string temppercorso=percorso; size_t barra; string percorsino; while (1) { barra=temppercorso.find('\\'); if (barra==string::npos) break; percorsino+=temppercorso.substr(0, barra)+'\\'; if (direxists(percorsino)) { if (flagdebug2) myprintf("00700: Small path exists %s\n",percorsino.c_str()); } else { string dafare=percorsino; ///dafare.pop_back(); if (flagdebug2) { myprintf("\n\n"); myprintf("00701: Make path of %03d\n---\n%s\n---\n",(int)dafare.length(),dafare.c_str()); } bool creazione=CreateDirectory(utow(dafare.c_str()).c_str(), 0); if (!flaglongpath) if (!creazione) printerr("17519",dafare.c_str(),0); } temppercorso=temppercorso.substr(barra+1,temppercorso.length()); } } if (!flaglongpath) if (!direxists(percorso)) myprintf("00702: percorso does not exists <<%s>>\n",percorso.c_str()); } #endif // corresponds to #ifdef (#ifdef _WIN32) /// filename=nomefileseesistegia(filename); ///printf("K1 +++\n"); if (flagstdout) job.outf=stdout; else job.outf=myfopen(filename.c_str(), WB); ///printf("K2 ---\n"); if (job.outf==FPNULL) { lock(job.mutex); printerr("17451",filename.c_str(),0); release(job.mutex); } if (g_chunk_size>0) { ///g_addedchunklist_fp.push_back(job.outf); g_addedchunklist.push_back(filename); } #ifndef unix else if ((p->second.attr&0x200ff)==0x20000+'w') { // sparse? DWORD br=0; ///printf("K3 +++\n"); if (!DeviceIoControl(job.outf, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &br, NULL)) // set sparse attribute printerr("17459",filename.c_str(),0); ///printf("K4 +++\n"); } #endif // corresponds to #ifndef (#ifndef unix) } } else if (!job.jd.flagtest) { if (flagstdout) job.outf=stdout; else job.outf=myfopen(filename.c_str(), RBPLUS); // update existing file } if (!job.jd.flagtest && job.outf==FPNULL) break; // skip errors if (g_chunk_size>0) { ///g_addedchunklist_fp.push_back(job.outf); g_addedchunklist.push_back(filename); } job.lastdt=p; assert(job.jd.flagtest || job.outf!=FPNULL); } assert(job.lastdt==p); // Find block offset of fragment uint64_t q=0; // fragment offset from start of block for (unsigned k=b.start; k0); assert(k=0); q+=job.jd.ht[k].usize; } assert(q+job.jd.ht[ptr[j]].usize<=out.size()); // Combine consecutive fragments into a single write assert(offset>=0); ++p->second.data; uint64_t usize=job.jd.ht[ptr[j]].usize; assert(usize<=0x7fffffff); assert(b.start+b.size<=job.jd.ht.size()); while (j+1=0 && usize+job.jd.ht[ptr[j+1]].usize<=0x7fffffff) { ++p->second.data; assert(p->second.data<=int64_t(ptr.size())); assert(job.jd.ht[ptr[j+1]].usize>=0); usize+=job.jd.ht[ptr[++j]].usize; } assert(usize<=0x7fffffff); assert(q+usize<=out.size()); // Write the merged fragment unless they are all zeros and it // does not include the last fragment. uint64_t nz=q; // first nonzero byte in fragments to be written while (nzfirst.c_str(),"Globals.pas")) //if (stristr(job.lastdt->first.c_str(),"globals.pas")) { /// let's calc the CRC32 of the block, and store (keyed by filename) /// in comments debug code if (offset>g_scritti) g_scritti=offset; uint32_t crc; crc=crc32_16bytes(out.c_str()+q, usize); s_crc32block myblock; myblock.crc32=crc; myblock.crc32start=offset; myblock.crc32size=usize; myblock.filename=job.lastdt->first; g_crc32.push_back(myblock); } /* if (job.jd.flagtest && (nzsecond.pramfile!=NULL) (*p->second.pramfile).ramwrite(offset,(char*)out.c_str()+q,usize); */ if (!job.jd.flagtest && (nzfirst.c_str()); if (flagramdisk) { /// do a "ramdisk" write } else { // write on realfilesystem if (job.outf!=NULL) { /// print_progress cannot handle huge file (ex. vmdks) due to seek-and-write on /// filesystems without "smartness" /// example: seek @ 300GB and write 1KB /// FS must write 300GB of zeros, then 1KB /// with a slow spinning drive this can seems a "freeze" /// =>when extracting this kind of file use -image and even -minsize something /// if something is 1 all writes (and seeks) will be showed #ifdef _WIN32 if (!flagnoeta) if (flagimage) { int64_t zerofill=0; if (offset>g_maxposition) { zerofill=offset-g_maxposition; g_maxposition=offset; } uint64_t showsize=20000000; if (minsize>0) showsize=minsize; if ((zerofill+usize)>showsize) { double eta=0.001*(mtime()-g_start)*(job.total_size-job.total_done)/(job.total_done+1.0); if (job.total_done==0) eta=0; int secondi=(mtime()-g_start)/1000; if (secondi==0) secondi=1; printf("W %10s+%10s=%10s | done %10s of %10s %6.2f%% %02d:%02d:%02d %s/s\r",tohuman(usize),tohuman2(zerofill),tohuman3(usize+zerofill),tohuman4(job.total_done),tohuman5(job.total_size), job.total_done*100.0/(job.total_size+0.5), int(eta/3600), int(eta/60)%60, int(eta)%60, tohuman3(job.total_done/secondi) ); } } #endif // corresponds to #ifdef (#ifdef _WIN32) if (!flagstdout) { if (flagdebug3) myprintf("00704: KA +++ seek offset %21s write %12s\n",migliaia(offset),migliaia2(offset)); fseeko(job.outf, offset, SEEK_SET); myfwrite(out.c_str()+q, 1, usize, job.outf); } else fwrite(out.c_str()+q, 1, usize, stdout); } } } } offset+=usize; lock(job.mutex); job.total_done+=usize; release(job.mutex); ///myprintf("00705: Scrittoni %f\n",(double)job.total_done); // Close file. If this is the last fragment then set date and attr. // Do not set read-only attribute in Windows yet. if (p->second.data==int64_t(ptr.size())) { assert(p->second.date); assert(job.lastdt!=job.jd.dt.end()); assert(job.jd.flagtest || job.outf!=FPNULL); if (!job.jd.flagtest) { assert(job.outf!=FPNULL); string fn=job.jd.rename(p->first); int64_t attr=p->second.attr; int64_t date=p->second.date; if ((p->second.attr&0x1ff)=='w'+256) attr=0; // read-only? if (p->second.data!=int64_t(p->second.ptr.size())) date=attr=0; // not last frag close(fn.c_str(), date, attr, job.outf); job.outf=FPNULL; } job.lastdt=job.jd.dt.end(); } } // end for j } // end for ip // Last file release(job.write_mutex); } // end while true // Last block return 0; } ThreadReturn decompressthreadramdisk(void* arg) { ExtractJob& job=*(ExtractJob*)arg; int jobNumber=0; // Get job number lock(job.mutex); jobNumber=++job.job; release(job.mutex); InputArchive in(job.jd.archive.c_str()/*,job.jd.g_password*/); if (!in.isopen()) return 0; StringBuffer out; // Look for next READY job. int next=0; // current job while (true) { lock(job.mutex); for (unsigned i=0; i<=job.jd.block.size(); ++i) { unsigned k=i+next; if (k>=job.jd.block.size()) k-=job.jd.block.size(); if (i==job.jd.block.size()) { // no more jobs? release(job.mutex); return 0; } Block& b=job.jd.block[k]; if (b.state==Block::READY && b.size>0 && b.usize>=0) { b.state=Block::WORKING; release(job.mutex); next=k; break; } } Block& b=job.jd.block[next]; // Get uncompressed size of block unsigned output_size=0; // minimum size to decompress assert(b.start>0); for (unsigned j=0; j=0); output_size+=job.jd.ht[b.start+j].usize; } // Decompress double mem=0; // how much memory used to decompress try { assert(b.start>0); assert(b.start0); assert(b.start+b.size<=job.jd.ht.size()); in.seek(b.offset, SEEK_SET); libzpaq::Decompresser d; d.setInput(&in); out.resize(0); assert(b.usize>=0); assert(b.usize<=0xffffffffu); out.setLimit(b.usize); d.setOutput(&out); if (!d.findBlock(&mem)) error("31284 archive block not found"); if (mem>job.maxMemory) job.maxMemory=mem; while (d.findFilename()) { d.readComment(); while (out.size()=output_size) break; d.readSegmentEnd(); } if (out.size()0 && j=0); assert(job.jd.ht[j].usize<=0x7fffffff); if (q+job.jd.ht[j].usize>out.size()) error("31318 Incomplete decompression"); if (flagchecksum) { char sha1result[20]; sha1.write(out.c_str()+q, job.jd.ht[j].usize); memcpy(sha1result, sha1.result(), 20); q+=job.jd.ht[j].usize; if (memcmp(sha1result, job.jd.ht[j].sha1, 20)) { lock(job.mutex); fflush(stdout); myprintf("00707: Job %d: fragment %u size %d checksum failed\n",jobNumber, j, job.jd.ht[j].usize); g_exec_text="31327: fragment checksum failed"; release(job.mutex); error("31330 bad checksum"); } } else q+=job.jd.ht[j].usize; ++b.extracted; } } // If out of memory, let another thread try catch (std::bad_alloc& e) { lock(job.mutex); fflush(stdout); myprintf("00708: Job %d killed: %s\n", jobNumber, e.what()); g_exec_text="31341 Job killed"; b.state=Block::READY; b.extracted=0; out.resize(0); release(job.mutex); return 0; } // Other errors: assume bad input catch (std::exception& e) { lock(job.mutex); fflush(stdout); myprintf("00709: Job %d: skipping [%u..%u] at %1.0f: %s\n",jobNumber, b.start+b.extracted, b.start+b.size-1,b.offset+0.0, e.what()); release(job.mutex); continue; } // Write the files in dt that point to this block lock(job.write_mutex); for (unsigned ip=0; ipsecond.date==0 || p->second.data<0 || p->second.data>=int64_t(p->second.ptr.size())) continue; // don't write // Look for pointers to this block const vector& ptr=p->second.ptr; int64_t offset=0; // write offset for (unsigned j=0; j=b.start+b.extracted) { offset+=job.jd.ht[ptr[j]].usize; continue; } // Close last opened file if different if (p!=job.lastdt) job.lastdt=job.jd.dt.end(); if (job.lastdt==job.jd.dt.end()) { if (!isdirectory(job.jd.rename(p->first))) if (p->second.pramfile==NULL) { p->second.pramfile=new franzfs; (*p->second.pramfile).init(p->second.size); g_allocatedram+=sizeof(franzfs); } if (p->second.pramfile==NULL) error("31399 cannot init ramdisk"); if (p->second.data==0) { #ifdef _WIN32 if (!flagimage) #endif // corresponds to #ifdef (#ifdef _WIN32) { lock(job.mutex); print_progress(job.total_size, job.total_done,-1,-1); release(job.mutex); } } job.lastdt=p; } assert(job.lastdt==p); // Find block offset of fragment uint64_t q=0; // fragment offset from start of block for (unsigned k=b.start; k0); assert(k=0); q+=job.jd.ht[k].usize; } assert(q+job.jd.ht[ptr[j]].usize<=out.size()); // Combine consecutive fragments into a single write assert(offset>=0); ++p->second.data; uint64_t usize=job.jd.ht[ptr[j]].usize; assert(usize<=0x7fffffff); assert(b.start+b.size<=job.jd.ht.size()); while (j+1=0 && usize+job.jd.ht[ptr[j+1]].usize<=0x7fffffff) { ++p->second.data; assert(p->second.data<=int64_t(ptr.size())); assert(job.jd.ht[ptr[j+1]].usize>=0); usize+=job.jd.ht[ptr[++j]].usize; } assert(usize<=0x7fffffff); assert(q+usize<=out.size()); // Write the merged fragment unless they are all zeros and it // does not include the last fragment. uint64_t nz=q; // first nonzero byte in fragments to be written while (nzg_scritti) g_scritti=offset; if (!(flagzero && flagdebug)) //-zero -debug =>write an all zeroed-file if (p->second.pramfile!=NULL) (*p->second.pramfile).ramwrite(offset,(char*)out.c_str()+q,usize); } offset+=usize; lock(job.mutex); job.total_done+=usize; release(job.mutex); if (p->second.data==int64_t(ptr.size())) { assert(job.lastdt!=job.jd.dt.end()); job.lastdt=job.jd.dt.end(); } } // end for j } // end for ip // Last file release(job.write_mutex); } // end while true // Last block return 0; } // Streaming output destination struct OutputFile: public libzpaq::Writer { FP f; void put(int c) { char ch=c; if (f!=FPNULL) myfwrite(&ch, 1, 1, f); } void write(const char* buf, int n) {if (f!=FPNULL) myfwrite(buf, 1, n, f);} OutputFile(FP out=FPNULL): f(out) {} }; int64_t copywitheta(int64_t i_tobecopied,libzpaq::Reader& in, libzpaq::Writer& out, uint64_t n=~0ull) { const unsigned BUFSIZE=4096; int64_t result=0; char buf[BUFSIZE]; int64_t inizio=mtime(); while (n>0) { int nc=n>BUFSIZE ? BUFSIZE : n; int nr=in.read(buf, nc); if (nr<1) break; out.write(buf, nr); result+=nr; avanzamento(result,i_tobecopied,inizio); n-=nr; } return result; } // Copy at most n bytes from in to out (default all). Return how many copied. int64_t copy(libzpaq::Reader& in, libzpaq::Writer& out, uint64_t n=~0ull) { const unsigned BUFSIZE=4096; int64_t result=0; char buf[BUFSIZE]; while (n>0) { int nc=n>BUFSIZE ? BUFSIZE : n; int nr=in.read(buf, nc); if (nr<1) break; out.write(buf, nr); result+=nr; n-=nr; } return result; } uint32_t crchex2int(const char *hex) { assert(hex); uint32_t val = 0; for (int i=0;i<8;i++) { uint8_t byte = *hex++; if (byte >= '0' && byte <= '9') byte = byte - '0'; else if (byte >= 'a' && byte <='f') byte = byte - 'a' + 10; else if (byte >= 'A' && byte <='F') byte = byte - 'A' + 10; val = (val << 4) | (byte & 0xF); } return val; } void Jidac::printsanitizeflags() { if (flagflat || flagutf || flagfix255 || flagfixeml) { myprintf("\n"); myprintf("00710: ******\n"); if (flagflat) myprintf("00711$ ****** WARNING: all files FLATted, without non-latin chars, max %d length\n",(int)FRANZMAXPATH); else { if (flagutf) myprintf("00712: ****** -utf No Non-latin chars\n"); if (flagfix255) myprintf("00713: ****** -fix255 Shrink filenames to %d, case insensitive\n",(int)FRANZMAXPATH); if (flagfixeml) myprintf("00714: ****** -fixeml Heuristic compress .eml filenames (Fwd Fwd Fwd=>Fwd etc)\n"); #ifdef _WIN32 if (flagfixreserved) myprintf("00715: ****** -fixreserved (fix LPT1, : etc)\n"); if (flagfixcase) myprintf("00716: ****** -fixcase (fix pippo.txt and PIPPO.txt)\n"); #endif // corresponds to #ifdef (#ifdef _WIN32) } myprintf("00717: ******\n\n"); } } int Jidac::info() { versioncomment=""; all=8; archive=getbackupnameifany(archive); return enumeratecomments(); } int Jidac::zpaqdirsize() { if (archive=="") { myprintf("00718! empty archive name\n"); return 2; } if (files.size()==0) { myprintf("00719! at least one folder needed\n"); return 2; } int errors=0; read_archive(NULL,archive.c_str(),&errors,0,true); /// note: kudged isselected if (flagdebug3) { myprintf("\n\n"); myprintf("00720: dtsize %s\n\n",migliaia((int64_t)dt.size())); } /// just a bit... overkill DTMap* dp[2]={&dt, &edt}; for (int i=0; i<2; ++i) for (DTMap::iterator p=dp[i]->begin(); p!=dp[i]->end(); ++p) { int len=p->first.size(); if (len>0 && p->first[len]!='/') for (int j=0; jfirst[j]=='/') { DTMap::iterator q=dp[i]->find(p->first.substr(0, j+1)); if (q!=dp[i]->end()) q->second.size+=p->second.size; } } } /* a "complex" thing... just to sort the output (!) */ vector filelist; myprintf("\n\n"); if (flagforce) { myprintf("00721: case sensitive == search, because of -force switch\n"); for (unsigned int i=0;ifirst)) { int posizione=myposi(files[i],a->first); if (posizione>-1) if ((unsigned int)posizione==(unsigned int)(a->first.size()-files[i].size())) filelist.push_back(a); } if (flagdebug) if (filelist.size()==oldsize) myprintf("00724$ WARNING cannot find folder in the zpaq <<%s>>\n",files[i].c_str()); } } sort(filelist.begin(), filelist.end(), compareFragmentList); myprintf("\n\n"); for (unsigned fi=0;fi>\n",migliaia(p->second.size),dateToString(flagutc,p->second.date).c_str(),p->first.c_str()); } if (flagforce) // .find() search { if (filelist.size()==files.size()) return 0; else { myprintf("00725: folder searched %s != founded %s\n",migliaia((int64_t)files.size()),migliaia2((int64_t)filelist.size())); return 1; } } return 0; } void Jidac::decodelastversion() { if (g_rangelast>0) { myprintf("00726: You ask the last %08d versions (...wait...)\n",g_rangelast); int errors=0; if (archive!="") read_archive(NULL,archive.c_str(),&errors,1,true); /// AND NOW THE MAGIC ONE! int lastver=ver.size()-1; myprintf("00727: Last version present %08d\n",lastver); if (g_rangelast>lastver) { myprintf("00728: Quit because weird vers selection\n"); seppuku(); } jidacreset(); g_rangefrom =lastver-g_rangelast+1; g_rangeto =lastver; myprintf("00729: From version %08d to %08d\n",g_rangefrom,g_rangeto); } } bool ismemfile(const string& i_filename) { if (mypos("MFILE-",i_filename)>-1) return true; return false; } bool iszpaqfranzvirtualfile(const string& i_filename) { if (mypos("VCOMMENT ",i_filename)>-1) return true; if (mypos("VFILE-",i_filename)>-1) return true; if (mypos("MFILE-",i_filename)>-1) return true; return false; } bool unziszpaqfranzvirtualfile(const string& i_filename) { if (mypos("VCOMMENT ",i_filename)>-1) return true; if (mypos("VFILE-",i_filename)>-1) return true; return false; } #ifdef _WIN32 class franz_ads { private: string filename; string adsname; HANDLE hFile; int64_t written; public: int64_t size() { return written; } bool isopen() { return hFile!=0; } void close() { if (isopen()) { CloseHandle(hFile); hFile=0; } } DWORD write(char* i_buffer,int i_len) { if (flagdebug3) myprintf("00730: entering write\n"); if (!isopen()) return -1; if (flagdebug3) myprintf("00731: before write\n"); DWORD bw; if (WriteFile(hFile,i_buffer,i_len,&bw,NULL)) { if (flagdebug3) myprintf("00732: done write\n"); written+=bw; return bw; } return -1; } DWORD write_uint16(uint16_t i) { if (!isopen()) return -1; DWORD bw; if (WriteFile(hFile,&i,sizeof(i),&bw,NULL)) { written+=sizeof(i); return bw; } return -1; } franz_ads(string i_filename,string i_adsname,char i_mode): filename(""), adsname(""), hFile(0), written(0) { if ((i_mode!='r') && (i_mode!='w')) { myprintf("00733: ADS mode can be only r or w %c\n",i_mode); return; } if (i_filename=="") { myprintf("00734: ADS i_filename empty\n"); return; } if (i_adsname=="") { myprintf("00735: ADS i_adsname empty\n"); return; } if (!fileexists(i_filename)) { myprintf("00736: ADS filename does not exits %Z\n",i_filename.c_str()); return; } for (unsigned int i=0;i= ringBufferBytes - messageMaxBytes) decOffset = 0; } if (flagverbose) { int64_t tempo=mtime()-startdecompress; myprintf("\n"); myprintf("00744: ADS: Time %s (print %s) (wrk %s) # %s / %s bytes\n",migliaia(tempo),migliaia2(printtime),migliaia3(tempo-printtime),migliaia4(lines),migliaia5(bytesdecompressed)); myprintf("00745: Use the l (list) command with -ads to force a full rebuild of the list\n"); } free(decBuf); free(cmpBuf); LZ4_freeStreamDecode(lz4StreamDecode); } bool win32_print_ads(string i_filename,string i_adsname,int i_maxmessagelen) { string thepath=i_filename+":"+i_adsname; FILE* theads = freadopen(thepath.c_str()); if (theads==NULL) { if (flagdebug) { myprintf("00746! cannot open %Z\n",thepath.c_str()); } return false; } decompress_print(theads,i_maxmessagelen); fclose(theads); return true; } #endif // corresponds to #ifdef (#ifdef _WIN32) bool ischecksum() { for (MAPPATIPOHASH::iterator p=g_mappatipohash.begin(); p!=g_mappatipohash.end(); ++p) if (p->second.switchflag!=NULL) if (p->second.switchflag!= (&flagnochecksum)) if (*(p->second.switchflag)) return true; return false; } bool Jidac::noselection() { return ( (g_until=="") && (g_rangefrom==0) && (g_rangeto==0) && (g_rangelast==0) && (minsize==0) && (maxsize==0) && (g_datefrom==0) && (g_dateto==0) && (!flagchecksum) && (orderby=="") && (!flagdesc) && (replaceto=="") && (searchfrom=="") ); } // List contents int Jidac::list() { if (flag715) { summary=0; return list715(); } if (archive=="") { myprintf("00748! archive is empty\n"); return 2; } archive=getbackupnameifany(archive); if (flagfast) { if (noselection()) return listfast(); else myprintf("00749: cannot do -fast because some selection in output\n"); } #ifdef _WIN32 if ((g_password==NULL) && (noselection())) if (!flagads) { InputArchive in(archive.c_str()); if (in.lastfilename!="") if (win32_print_ads(in.lastfilename,"zpaqlist",16384)) return 0; } #endif // corresponds to #ifdef (#ifdef _WIN32) if (flagterse) flagattr=true; int64_t csize=0; if (flagcomment) { if (versioncomment=="") return enumeratecomments(); enumeratecomments(); vector myfilelist; int versione=searchcomments(versioncomment,myfilelist); if (versione==0) { myprintf("00750: cannot find version comment <<%s>>\n",versioncomment.c_str()); return 1; } if (versione==-1) { myprintf("00751: multiple match for version comment <<%s>>\n",versioncomment.c_str()); return 1; } version=versione; flagcomment=false; myprintf("00752: Found version -until %d scanning again...\n",versione); jidacreset(); } decodelastversion(); if (g_rangefrom>0) // a version-range selection, stick with 8 hardcoded digit all=8; if (files.size()>=1) return testverify(); int errors=0; bool flagshow; if (flagterse) csize=read_archive(NULL,archive.c_str(),&errors,1,true); /// AND NOW THE MAGIC ONE! else { csize=read_archive(NULL,archive.c_str(),&errors,1); myprintf("\n"); } g_bytescanned =0; g_filescanned =0; g_worked =0; vector filelist; for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) if (a->second.data!='-' && (all || a->second.date)) { a->second.data='-'; filelist.push_back(a); } if (orderby!="") { myprintf("00753: Sorting output (orderby |%s|) ",orderby.c_str()); if (flagdesc) myprintf(" descending "); sort(filelist.begin(), filelist.end(), compareorderby); } if (menoenne) myprintf(" limit to first %d ",menoenne); if (!flagterse) myprintf("\n"); int64_t usize=0; map mappacommenti; for (unsigned i=0;ifirst)) { string fakefile=p->first; myreplace(fakefile,":$DATA",""); size_t found = fakefile.find("VCOMMENT "); if (found != string::npos) { string numeroversione=fakefile.substr(found+9,8); int numver=mystoi(numeroversione); string commento=fakefile.substr(found+9+8+1,65000); mappacommenti.insert(std::pair(numver, commento)); } } } flagchecksum=ischecksum() || flagchecksum; int thesizesize=19; if (!flagattr) { int64_t largest=0; for (unsigned int i=0;ifirst; if (isdirectory(myfilename)) { unsigned v; int64_t sizetoprint=filelist[i]->second.size; myfilename=myright(myfilename,myfilename.size()-all-3); if ((int)myfilename.length()==(all+1)) { bool alldigit=true; for (unsigned int jj=0;jj0 && filelist[i]->first.size()==all+1u && (v=atoi(filelist[i]->first.c_str()))>0 && vlargest) largest=sizetoprint; } } } } else { if (filelist[i]->second.size>largest) largest=filelist[i]->second.size; } } string temp=migliaia(largest); thesizesize=temp.size()+1; if (thesizesize<4) thesizesize=4; string sizeheader(thesizesize,'-'); if (flagdebug2) { myprintf("00754: largest %s thesize %d\n",temp.c_str(),thesizesize); myprintf("00755: |%s|\n",temp.c_str()); myprintf("00756: |%s|\n",sizeheader.c_str()); ///return 0; } char lineatemp[200]; if (all) { string verheader(all,'-'); if (flagdate) { snprintf(lineatemp,sizeof(lineatemp)," Date Time Creation %*s Ratio %*s Name/Info",thesizesize,"Size",all,"Ver"); myprintf("00757: %s\n",lineatemp); myprintf("00758: ---------- -------- -------------------- %s ----- %s ----------\n",sizeheader.c_str(),verheader.c_str()); } else { snprintf(lineatemp,sizeof(lineatemp)," Date Time %*s Ratio %*s Name/Info",thesizesize,"Size",all,"Ver"); myprintf("00759: %s\n",lineatemp); myprintf("00760: ---------- -------- %s ----- %s ----------\n",sizeheader.c_str(),verheader.c_str()); } } else { if (flagdate) { snprintf(lineatemp,sizeof(lineatemp)," Date Time Creation %*s Ratio Name",thesizesize,"Size"); myprintf("00761: %s\n",lineatemp); myprintf("00762: ---------- -------- -------------------- %s ----- -----\n",sizeheader.c_str()); } else { snprintf(lineatemp,sizeof(lineatemp)," Date Time %*s Ratio Name",thesizesize,"Size"); myprintf("00763: %s\n",lineatemp); myprintf("00764: ---------- -------- %s ----- -----\n",sizeheader.c_str()); } } } unsigned fi; for (fi=0;fi=menoenne) break; DTMap::iterator p=filelist[fi]; flagshow=true; /* if (isads(p->first)) { if (strstr(p->first.c_str(),"VCOMMENT ")) flagshow=false; } */ if ((!flag715) && (!flagforcewindows) && (!all)) flagshow=!iszpaqfranzvirtualfile(p->first); /// a little of change if -search is used if (searchfrom!="") flagshow=stristr(p->first.c_str(),searchfrom.c_str()); /// redundant, but not a really big deal if (flagchecksum) if (isdirectory(p->first)) flagshow=false; if ((minsize>0) || (maxsize>0)) if (isdirectory(p->first)) flagshow=false; if (maxsize>0) if (maxsize<(uint64_t)p->second.size) flagshow=false; if (minsize>0) if (minsize>(uint64_t)p->second.size) flagshow=false; if (g_datefrom>0) if ((p->second.date)<=g_datefrom) flagshow=false; if (g_dateto>0) if ((p->second.date)>=g_dateto) flagshow=false; if (g_rangefrom>0) if (p->first.size()>8) //hardcoded 8 { string inizio=myleft(p->first,8); int iversion=atoll(inizio.c_str()); flagshow=((iversion>=g_rangefrom) && (iversion<=g_rangeto)); } if (p->second.date==0) if (flagnodel) flagshow=false; if (flagshow) if (!strchr(nottype.c_str(), p->second.data)) { if (p->first!="" && (!isdirectory(p->first))) usize+=p->second.size; string myfilename =p->first; string myhashtype =""; string myhash =""; string mycrc32 =""; int64_t mycreationtime =0; int64_t myaccesstime =0; bool myisordered=false; int myversion=0; franz_posix* myposix=NULL; bool myisadded=false; int franzotypedetected= decode_franz_block(isdirectory(myfilename),p->second.franz_block, myhashtype, myhash, mycrc32, mycreationtime, myaccesstime, myisordered, myversion, myposix,myisadded); if (flagdebug3) myprintf("00765: franzotype %d myhashtype %s myhash %s mycrc32 %s myisadded %d\n",franzotypedetected,myhashtype.c_str(),myhash.c_str(),mycrc32.c_str(),(int)myisadded); bool flaghoadded=(myhashtype=="XXHASH64B") ||(myhashtype=="MD5B") || (myhashtype=="BLAKE3B")||(myhashtype=="SHA-256B")||(myhashtype=="SHA-3B")||(myhashtype=="XXH3B")||(myhashtype=="SHA1-B"); if (!flagchecksum) { franzotypedetected =0; myhashtype =""; myhash =""; mycrc32 =""; } if (franzotypedetected>1) { if ((myhashtype!="") && (myhash!="")) myhash=myhashtype+": "+myhash+" "; if (mycrc32!="") mycrc32="CRC32: "+mycrc32+" "; } else { if ((myhashtype=="") && (myhash=="") && (mycrc32!="")) mycrc32="CRC32: "+mycrc32+" "; } if (summary<=0) { unsigned v; string theversionnumber =""; bool flagnewversion =false; bool isfolder =isdirectory(myfilename); int64_t sizetoprint =p->second.size; int64_t compressedtoprint =p->second.kompressedsize; if (all) { theversionnumber=myfilename.substr(0,all); if (!isfolder) myfilename=myfilename.substr(all+3,myfilename.size()-all-3); else myfilename=myright(myfilename,myfilename.size()-all-3); if ((int)myfilename.length()==(all+1)) if (myfilename[myfilename.length()-1]=='/') { bool alldigit=true; for (unsigned int i=0;i0 && p->first.size()==all+1u && (v=atoi(p->first.c_str()))>0 && v0) myfilename=rename(myfilename); } /// if (flagattr) /// list_seconddata(p->second.data); // if ( !(flagterse && flagnewversion) ) { if (g_csvhf!="") myprintf(g_csvhf.c_str()); list_datetime(p->second.date,flagnewversion); tabba(); if (flagdate) { list_creationdate(mycreationtime); tabba(); } if (flagattr || flagterse) { list_attributes(p->second.attr); tabba(); } list_filesize(sizetoprint,thesizesize); tabba(); list_compressedfilesize(compressedtoprint,sizetoprint,flagnewversion,isfolder,p->second.date==0); tabba(); if (theversionnumber!="") { if (g_csvstring=="") myprintf("%s|",theversionnumber.c_str()); else myprintf("%s",theversionnumber.c_str()); if (g_csvstring!="") tabba(); } if ((myhash!="") || (mycrc32!="")) { color_yellow(); if (myhash!="") { myprintf("%s ",myhash.c_str()); tabba(); } if (mycrc32!="") { myprintf("%s ",mycrc32.c_str()); tabba(); } color_restore(); } //if (flagattr||flagterse) ////myfilename=" "+myfilename; /// search and replace, if requested ///franzreplace(myfilename); if (flagstdout) if (p->second.isordered) myfilename="[STDOUT] "+myfilename; string simbolino="+"; if (p->second.date==0) simbolino="-"; else { if (flaghoadded) if (!myisadded) simbolino="#"; } if (all>0 && p->first.size()==all+1u && (v=atoi(p->first.c_str()))>0 && v0 && p->first.size()==all+1u && (v=atoi(p->first.c_str()))>0 && v::iterator commento=mappacommenti.find(v); color_blackongreen(); myprintf("Files: changed/added %s removed %s", migliaia(ver[v].updates),migliaia2(ver[v].deletes)); if(commento!= mappacommenti.end()) myprintf(" <<%s>>",commento->second.c_str()); color_restore(); } if (g_csvhf!="") myprintf(g_csvhf.c_str()); myprintf("\n"); } } } } // end for i = each file version if (flagterse) return 0; int64_t allsize=0; for (DTMap::const_iterator p=dt.begin(); p!=dt.end(); ++p) if (p->second.date) for (unsigned j=0; jsecond.ptr.size(); ++j) { unsigned k=p->second.ptr[j]; if (k>0 && k=0) allsize+=ht[k].usize; } int64_t sizecompressed=(csize+dhsize-dcsize); myprintf("\n"); myprintf("00766: %21s (%s) of %s (%s) in %s files shown\n",migliaia(usize),tohuman(usize),migliaia2(allsize),tohuman2(allsize),migliaia3(fi)); myprintf("00767: %21s compressed ",migliaia(sizecompressed)); if (allsize>0) { double ratio=(double)sizecompressed/(double)allsize; myprintf(" Ratio %.3f <<%Z>>\n",ratio,archive.c_str()); } else myprintf("\n"); if (dhsize!=dcsize) // index? myprintf("00768: Note: %s of %s compressed bytes are in archive\n", migliaia((int64_t)(dcsize+0.0)), migliaia2((int64_t)(dhsize+0.0))); if (flagcollision) checksha1collision(dt,true); return 0; } /////////////////////////////// extract /////////////////////////////// // Return true if the internal file p // and external file contents are equal or neither exists. // If filename is 0 then return true if it is possible to compare. // In the meantime calc the crc32 of the entire file bool Jidac::equal(DTMap::const_iterator p, const char* filename,uint32_t &o_crc32,string i_myhashtype,const string i_myhash,string& o_hash) { if (flagdebug3) { myprintf("\n\n"); myprintf("00814: equal p first %s\n",p->first.c_str()); myprintf("00815: equal filename %s\n",filename); } o_crc32=0; o_hash=""; if (i_myhash=="FAKE") o_hash="FAKE"; // test if all fragment sizes and hashes exist if (filename==0) { static const char zero[20]={0}; for (unsigned i=0; isecond.ptr.size(); ++i) { unsigned j=p->second.ptr[i]; if (j<1 || j>=ht.size() || ht[j].usize<0 || !memcmp(ht[j].sha1, zero, 20)) return false; } return true; } // internal or neither file exists if (p->second.date==0) { bool risultato=!exists(filename); if (flagdebug3) myprintf("00816: second date zero, risultato %d\n",(int)risultato); return risultato; } // directories always match if (p->first!="" && isdirectory(p->first)) { bool risultato=exists(filename); if (flagdebug3) myprintf("00817: p->first isdirectory, check exists %d\n",(int)risultato); return risultato; } // compare sizes FP in=myfopen(filename, RB); if ((in==NULL) || (in==FPNULL)) { if (flagdebug3) myprintf("00818: failed fopen %s\n",filename); return false; } fseeko(in, 0, SEEK_END); if (ftello(in)!=p->second.size) { if (flagdebug3) myprintf("00819: ftello(in) %s <> p second size %s\n",migliaia(ftello(in)),migliaia2(p->second.size)); ///return oldfclose(in), false; myfclose(&in); return false; } if (flagquick) { myfclose(&in); if (flagdebug3) myprintf("00820: flagquick, return true\n"); return true; } // compare hashes chunk by chunk. fseeko(in, 0, SEEK_SET); libzpaq::SHA1 sha1; const int BUFSIZE=4096; char buf[BUFSIZE]; bool flagshow=false; if (!flagnoeta) if (flagverbose || (p->second.size>100000000)) //only 100MB+ files flagshow=true; if (flagshow) myprintf("\n"); int64_t done =0; int ultimapercentuale =-1; if (flagdebug3) myprintf("00821: franz_do_hash\n"); if (i_myhashtype=="") // a seppuku if myhashtype is "" i_myhashtype="NONE"; franz_do_hash hashfrombuffer(i_myhashtype); hashfrombuffer.init(); int64_t timestart=mtime(); for (unsigned i=0; isecond.ptr.size(); ++i) { unsigned f=p->second.ptr[i]; if (f<1 || f>=ht.size() || ht[f].usize<0) { myfclose(&in); return false; } double percentuale; if (flagshow) { percentuale=100.0*((double)i/(double)p->second.ptr.size()); int proper=(int)percentuale; if (percentuale>0) if (proper!=ultimapercentuale) { if (proper==99) proper=100; double tempo=(mtime()-timestart+1)/1000.0; int myspeed=(int)(done/tempo); if (flagchecksum || flagverify ||flagparanoid) myprintf("00822: SHA1 %03d%% %10s/%10s @ %10s/s + %s\r",proper,tohuman(done),tohuman3(p->second.size),tohuman2(myspeed),i_myhashtype.c_str()); else myprintf("00823: SHA1 %03d%% %10s/%10s @ %10s/s\r",proper,tohuman(done),tohuman3(p->second.size),tohuman2(myspeed)); ultimapercentuale=(int)percentuale; } } for (int j=0; jBUFSIZE) n=BUFSIZE; int r=fread(buf, 1, n, in); o_crc32=crc32_16bytes(buf,r,o_crc32); done+=r; g_worked+=r; if (flagchecksum || flagparanoid || flagverify) hashfrombuffer.update(buf,r); if (r!=n) { myfclose(&in); return false; } sha1.write(buf, n); j+=n; } if (memcmp(sha1.result(), ht[f].sha1, 20)!=0) { myfclose(&in); return false; } } if (fread(buf, 1, BUFSIZE, in)!=0) { myfclose(&in); return false; } myfclose(&in); if (flagchecksum || flagverify ||flagparanoid) { o_hash=hashfrombuffer.finalize(); if (flagdebug3) myprintf("00824: o_hash in equal %s\n",o_hash.c_str()); } return true; } bool ishex(const char i_char) { return (((i_char>=48) && (i_char<=57)) || ((i_char>=65) && (i_char<=70)) || ((i_char>=97) && (i_char<=102))); } #ifdef _WIN32 bool isletterpath(const string& i_filename) { if (i_filename.size()<3) return false; if (isalpha(i_filename[0])) if (i_filename[1]==':') if ((i_filename[2]=='/') || (i_filename[2]=='\\')) return true; return false; } #endif // corresponds to #ifdef (#ifdef _WIN32) int Jidac::setpassword() { if (files.size()!=2) { myprintf("00825! setpassword require exactly two file-parameters: source and destination\n"); return 2; } archive=files[0]; if (!iszpaq(archive)) archive+=".zpaq"; repack=files[1]; if (!iszpaq(repack)) repack+=".zpaq"; string part0=subpart(archive,0); if (part0!=archive) { myprintf("00826! so sorry, this seems a multipart archive, abort\n"); return 2; } if (!flagspace) if (!saggiascrivibilitacartella(repack)) { myprintf("00827! Cannot write on output %s\n",repack.c_str()); myprintf("00828! Aborting. Use -space to bypass and enforcing.\n"); return 2; } myprintf("\n\n"); myprintf("00829: Opening the source archive\n"); if (g_password!=NULL) { myprintf("00830: please take note: if the source password is incorrect\n"); myprintf("00831: the output file will be silently corrupted\n"); myprintf("\n\n"); } if (new_password==NULL) { myprintf("00832: New password (-key2) empty, enter . for NO password\n"); string spassword=mygetpasswordblind(""); if (spassword==".") myprintf("00833: password in output removed\n"); else { if (spassword!="") { libzpaq::SHA256 sha256; for (unsigned int i=0;i>\n", migliaia(in.tell()),archive.c_str()); myprintf("00842: Destination %19s <<%Z>>\n", migliaia(out.tell()),repack.c_str()); out.close(); myprintf("\n"); myprintf("00845: Now quick check of the output file\n"); g_password=new_password; read_archive(NULL,repack.c_str()); /// AND NOW THE MAGIC ONE! return 0; } // Extract files from archive. If force is true then overwrite // existing files and set the dates and attributes of exising directories. // Otherwise create only new files and directories. Return 1 if error else 0. struct tparametriramtodisk { ///vector o_hashcalculated; vector filenameondisk; vector filedate; vector fileattr; vector algo; vector filehash; vector filesize; vector data; vector filecrc; vector filefix; int tnumber; uint64_t timestart; bool flagtest; uint64_t o_timeend; int64_t o_hashedsize; int64_t o_crcsize; int64_t o_writtenbythread; int64_t o_timecrc; int64_t o_timehash; int64_t o_timefilesystem; int64_t o_timewrite; uint32_t o_writeerror; uint32_t o_fileok; uint32_t o_fileerror; uint32_t o_filesnotchecked; uint32_t o_filewithoutcrc; uint32_t o_filecrc; uint32_t o_filecrcok; uint32_t o_filecrcerror; tparametriramtodisk(): tnumber(0),timestart(0),flagtest(false), o_timeend(0), o_hashedsize(0), o_crcsize(0), o_writtenbythread(0), o_timecrc(0), o_timehash(0), o_timefilesystem(0), o_timewrite(0), o_writeerror(0), o_fileok(0), o_fileerror(0), o_filesnotchecked(0), o_filewithoutcrc(0), o_filecrc(0), o_filecrcok(0), o_filecrcerror(0) {} }; void * scriviramtodisk(void *t) { assert(t); tparametriramtodisk* par= ((struct tparametriramtodisk*)(t)); char buffer[100]; string hashstringato; string crc32fromram; par->o_crcsize =0; par->o_hashedsize =0; par->o_writtenbythread =0; par->o_timecrc =0; par->o_timehash =0; par->o_timefilesystem =0; par->o_timewrite =0; par->o_writeerror =0; par->o_fileok =0; par->o_fileerror =0; par->o_filesnotchecked =0; par->o_filewithoutcrc =0; par->o_filecrc =0; par->o_filecrcok =0; par->o_filecrcerror =0; for (unsigned int i=0;ifilenameondisk.size();i++) { if (flagchecksum) if (!isdirectory(par->filenameondisk[i])) if (par->data[i]!=NULL) { if (par->filecrc[i]!="") { int64_t startcrc=mtime(); par->o_filecrc++; uint32_t crc=0; crc=crc32_16bytes (par->data[i],par->filesize[i],crc); snprintf(buffer,sizeof(buffer),"%08X",crc); crc32fromram=buffer; if (crc32fromram==par->filecrc[i]) par->o_filecrcok++; else { if (par->filecrc[i]!="00000000") { if (flagverbose) myprintf("00846: ERROR CRC stored %s from ram|%s|\n",par->filecrc[i].c_str(),crc32fromram.c_str()); par->o_filecrcerror++; } } par->o_crcsize+=par->filesize[i]; par->o_timecrc+=(mtime()-startcrc); } else par->o_filewithoutcrc++; int64_t starthash=mtime(); if (par->algo[i]=="") par->o_filesnotchecked++; else { if (flagdebug3) myprintf("00847: franz_do_hash\n"); franz_do_hash hashfrombuffer(par->algo[i]); hashfrombuffer.init(); hashfrombuffer.update(par->data[i],par->filesize[i]); hashstringato=hashfrombuffer.finalize(); par->o_hashedsize+=par->filesize[i]; } if (flagdebug) myprintf("00848: INFO hash stored %s %s from ram|%s| %s\n",par->algo[i].c_str(),par->filecrc[i].c_str(),hashstringato.c_str(),par->filenameondisk[i].c_str()); ///if (par->filehash[i]!="!ERROR!") if (par->filehash[i]!=hashstringato) { par->o_fileerror++; if (flagverbose) myprintf("00849: ERROR hash stored |%s| |%s| from ram|%s| %s\n",par->algo[i].c_str(),par->filehash[i].c_str(),hashstringato.c_str(),par->filenameondisk[i].c_str()); } else { if (hashstringato!="") par->o_fileok++; } int64_t temp=(mtime()-starthash);///*0.001; par->o_timehash+=temp; } if (!par->flagtest) { int64_t startfilesystem=mtime(); ///myprintf("00850: makepath %s\n",par->filenameondisk[i]); makepath(par->filenameondisk[i], par->filedate[i],par->fileattr[i]); FP myfile=myfopen(par->filenameondisk[i].c_str(), WB); if (myfile==FPNULL) { myprintf("\n"); myprintf("00851! Hard guru during fopen (no free RAM?)!\n"); seppuku(); } par->o_timefilesystem+=(mtime()-startfilesystem); int64_t startwrite=mtime(); /// splitting for 32-bit version. I know, it is weird, but necessary int64_t scritti=0; int64_t n=1000000000; int64_t w=0; while (1) { int64_t dascrivere=par->filesize[i]-scritti; if (dascrivere>n) dascrivere=n; w=myfwrite(par->data[i]+scritti,1,dascrivere,myfile); scritti+=w; if (w!=n) break; } ///size_t scritti=fwrite(par->data[i],1,par->filesize[i],myfile); par->o_writtenbythread+=scritti; myfclose(&myfile); close(par->filenameondisk[i].c_str(),par->filedate[i],par->fileattr[i]); par->o_timewrite+=(mtime()-startwrite); if (scritti!=par->filesize[i]) { if (flagverbose) { myprintf("00852: written != expected %21s %21s on %Z\n",migliaia(scritti),migliaia2(par->filesize[i]),par->filenameondisk[i].c_str()); } par->o_writeerror++; } } myavanzamentoby1sec(g_fwritten,g_ramdisksize,par->timestart,false); } par->o_timeend=mtime(); pthread_exit(NULL); return 0; } int Jidac::ecommand() { myprintf("00854: Extracting on current directory\n"); tofiles.clear(); string relative="./"; #ifdef _WIN32 if (flaglongpath) { relative=relativetolongpath(relative); myprintf("=> Windows longpath => %Z\n",relative.c_str()); } #endif // corresponds to #ifdef (#ifdef _WIN32) tofiles.push_back(relative); return extract(); } int myrename(string sfrom,string sto) { #ifdef _WIN32 if (flaglongpath) { sfrom =makelongpath(sfrom); sto =makelongpath(sto); } std::wstring wfrom =utow(sfrom.c_str()); std::wstring wto =utow(sto.c_str()); if (!MoveFileW(wfrom.c_str(),wto.c_str())) { myprintf("00855! ERROR WIN renaming\n"); myprintf("00856! from <<%Z>>\n",sfrom.c_str()); myprintf("00857! to <<%Z>>\n",sto.c_str()); decodewinerror(GetLastError(),"dummy"); for (unsigned int j=0;j>\n",sfrom.c_str()); myprintf("00865: to <<%s>>\n",sto.c_str()); if (flagverbose) for (unsigned int j=0;jsecond.attr&255)=='u') // unix attributes { risultato=true; break; } return risultato; } #endif // corresponds to #ifdef (#ifdef _WIN32) /////////////////////////////// list ////////////////////////////////// /// quanti==1 => version (>0) /// quanti==0 => 0 /// else => -1 multiple match int Jidac::searchcomments(string i_testo,vector &filelist) { unsigned int quanti=0; int versione=-1; filelist.clear(); for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) { a->second.data='-'; filelist.push_back(a); } ///VCOMMENT 00000002 seconda_versione:$DATA for (unsigned i=0;ifirst)) { string fakefile=p->first; myreplace(fakefile,":$DATA",""); size_t found = fakefile.find("VCOMMENT "); if (found != string::npos) { string numeroversione=fakefile.substr(found+9,8); int numver=mystoi(numeroversione); string commento=fakefile.substr(found+9+8+1,65000); if (i_testo.length()>0) if (!stringcomparei(commento,i_testo)) continue; mappacommenti.insert(std::pair(numver, commento)); versione=numver; quanti++; } } } if (quanti==1) return versione; else if (quanti==0) return 0; else return -1; } int Jidac::enumeratecomments() { // Read archive into dt, which may be "" for empty. int64_t csize=0; int errors=0; if (archive!="") csize=read_archive(NULL,archive.c_str(),&errors,1); /// AND NOW THE MAGIC ONE! if (command!='i') { myprintf("\n"); myprintf("00995: Version(s) enumerator\n"); } vector filelist; searchcomments(versioncomment,filelist); if (command!='i') for (MAPPACOMMENTI::const_iterator p=mappacommenti.begin(); p!=mappacommenti.end(); ++p) myprintf("%08d <<%s>>\n",p->first,p->second.c_str()); for (DTMap::iterator p=edt.begin(); p!=edt.end(); ++p) { DTMap::iterator a=dt.find(rename(p->first)); if ((a!=dt.end()) && (a->second.date)) { a->second.data='-'; filelist.push_back(a); } p->second.data='+'; filelist.push_back(p); } for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) if (a->second.data!='-' && (a->second.date)) { a->second.data='-'; filelist.push_back(a); } /* if (flagstat) { bool iserr=false; int updates=0, deletes=0, undated=0; int64_t earliest=0, latest=0; int errors=0; for (unsigned i=1; i=0) ++blocks, blockSize=0; if (ht[i].usize<0) ++unknown; else { usize+=ht[i].usize; if (ht[i].usize>largestFragment) largestFragment=ht[i].usize; blockSize+=ht[i].usize; if (blockSize>largestBlock) largestBlock=blockSize; } if (ht[i].csize>csize || ht[i].csize<-int(i)) ++errors; unsigned j; for (j=0; j<20; ++j) if (ht[i].sha1[j]) break; nohash+=j==20; } } myprintf("00996: Known uncompressed %20s (%s)\n", migliaia(usize),tohuman(usize)); ///myprintf("00997: Versions %s\n",migliaia(ver.size()-1)); ///myprintf("00998: +/# %12s -%12s\n",migliaia(updates),migliaia2(deletes)); myprintf("00999: First version %s last %s\n",dateToString(flagutc,earliest).c_str(),dateToString(flagutc,latest).c_str()); myprintf("01000: Undated version %s Out of sequence %s",migliaia(undated),migliaia2(errors)); if ((undated+errors)==0) myprintf(": this is GOOD\n"); else myprintf(": something WRONG\n"); myprintf("01001: Blocks %s blocks fragments %s highest frag %s\n", migliaia(blocks),migliaia2(used),migliaia3(ht.size()-1)); if (used>0) myprintf("01002: Average fragment size %1.3f\n", double(usize)/used); myprintf("01003: Largest fragment size %20s\n",migliaia(largestFragment)); myprintf("01004: Largest uncompressed block size %20s\n",migliaia(largestBlock)); myprintf("01005: Fragments of unknown size %s without hashes %s missing %s",migliaia(unknown),migliaia2(nohash),migliaia3(errors)); if ((unknown+nohash+errors)==0) myprintf(": this is GOOD\n"); else myprintf(": something WRONG\n"); } */ if (all) { if (g_rangelast>0) { int lastver=ver.size()-1; g_rangefrom =lastver-g_rangelast+1; g_rangeto =lastver; } if (flagstat) { myprintf("01006: ----------------------------------------------------------------------------------------------\n"); myprintf("01007: < Ver > < date > < time > < added > < uncompressed > < compressed >\n"); myprintf("01008: ----------------------------------------------------------------------------------------------\n"); } else { myprintf("01009: --------------------------------------------------------------------------\n"); myprintf("01010: < Ver > < date > < time > < added > < bytes added >\n"); myprintf("01011: --------------------------------------------------------------------------\n"); } vector linetobeprinted; for (unsigned fi=0;fifirst.size()==all+1u && (v=atoi(p->first.c_str()))>0 && v0) if (!(((int)v>=(int)g_rangefrom) && ((int)v<=(int)g_rangeto))) show=false; if (show) linetobeprinted.push_back(fi); } } unsigned int from =0; if (menoenne) if (menoenne=linetobeprinted[from]) { DTMap::iterator p=filelist[fi]; unsigned v=atoi(p->first.c_str()); lastdate=dateToString(flagutc,p->second.date); myprintf("01012: V%08u %s ",v,lastdate.c_str()); if (flagstat) { myprintf(" +%08d -%08d %20s [%20s]", ver[v].updates, ver[v].deletes, migliaia2(ver[v].usize),migliaia((int64_t)((v+1 %20s", ver[v].updates, ver[v].deletes, migliaia((int64_t)((v+1::iterator commento; commento=mappacommenti.find(v); if(commento!= mappacommenti.end()) myprintf(" <<%s>>", commento->second.c_str()); myprintf("\n"); } } if (flagstat) { myprintf("59648: ----------------------------------------------------------------------------------------------\n"); myprintf("59649: %20s %20s\n",migliaia(totaluncompressed),migliaia2(totalcompressed)); } else { myprintf("59644: --------------------------------------------------------------------------\n"); myprintf("59643: %20s\n",migliaia(totalcompressed)); } if (flagbig) if (lastdate!="") { myprintf("\n"); string primi10=lastdate.substr(0,10); myreplaceall(primi10,"-"," "); ascii::Ascii font=ascii::Ascii(); font.print(primi10); } } return 0; } int Jidac::kill() { myprintf("01013: KILL of:"); if (files.size()==0) return -1; if (archive=="") return -1; read_archive(NULL,archive.c_str()); // Read external files into edt ///uint64_t howmanyfiles=0; g_bytescanned=0; g_filescanned=0; g_worked=0; files_count.clear(); edt.clear(); string cartellaoutput=tofiles[0]; scandir(false,edt,cartellaoutput); if (edt.size()) myprintf("01014: Total files found: %s\n", migliaia(edt.size())); else { myprintf("01015: Found nothing in filesystem\n"); return 1; } myprintf("\n"); vector inzpaqrinominato; vector tobekilled; vector dirtobekilled; for (DTMap::iterator a=dt.begin(); a!=dt.end(); ++a) { string dentrofile=a->first; myreplace(dentrofile,files[0],tofiles[0]); if (a->second.date==0) { if (flagverbose) myprintf("01016: DELETED "); } else inzpaqrinominato.push_back(dentrofile); if (flagverbose) myprintf("01017: Into zpaq %s > renamed %s\n",a->first.c_str(),dentrofile.c_str()); } std::sort(inzpaqrinominato.begin(), inzpaqrinominato.end()); uint64_t sizetobekilled=0; for (DTMap::iterator a=edt.begin(); a!=edt.end(); ++a) if (binary_search(inzpaqrinominato.begin(),inzpaqrinominato.end(),a->first)==false) { if (isdirectory(a->first)) dirtobekilled.push_back(a->first); else { tobekilled.push_back(a->first); sizetobekilled+=a->second.size; } } for (unsigned int i=0;i killed %s\n",migliaia(dirtobekilled.size()),migliaia2(killeddir)); myprintf("01030: File to be removed %s -> killed %s\n",migliaia(tobekilled.size()),migliaia2(killed)); if ((killeddir+killed)!=(dirtobekilled.size()+tobekilled.size())) { myprintf("01031: FAILED !! some highlander !!\n"); return 1; } return 0; } /* section: multithread */ struct tparametrihash { vector o_hashcalculated; vector o_sizegetted; vector originalfilenames; vector filestobehashed; vector originalindex; vector filehash; vector algo; uint64_t timestart; uint64_t timeend; int64_t inizio; int64_t dimensione; int tnumber; }; void * scansionahash(void *t) { assert(t); tparametrihash* par= ((struct tparametrihash*)(t)); vector& tmpfilestobehashed = par->filestobehashed; vector& tmpalgo = par->algo; if (tmpfilestobehashed.size()!=tmpalgo.size()) { myprintf("01032: FILETOBEHASHED != ALGO\n"); seppuku(); } vector& tmphashcalculated = par->o_hashcalculated; vector& tmpsizegetted = par->o_sizegetted; g_dimensione=0; for (unsigned int i=0;iinizio,par->dimensione); if (!flaghashdeep) if (flagnosort) { pthread_mutex_lock(&g_mylock); int printlen=0; if (flagpakka) { myprintf("01034: %s ",stringtolower(risu).c_str()); printlen=risu.size()+2; } else { myprintf("01035: |%s: %s [%19s] |",tmpalgo[i].c_str(),risu.c_str(),migliaia(dummy.o_thefilesize)); printlen=tmpalgo[i].size()+risu.size()+19+8; } printUTF8(work.c_str()); printlen+=work.size(); if (printlen<68) { string temp; while (printlen++<68) temp+=" "; myprintf("%s",temp.c_str()); } myprintf("\n"); pthread_mutex_unlock(&g_mylock); } ///myprintf("01036: risultato %s\n",risu.c_str()); ///,g_dimensione,thefilesize); tmphashcalculated.push_back(risu); tmpsizegetted.push_back(dummy.o_thefilesize); /// tmphashcalculated.push_back(hash_calc_file(string2algo(tmpalgo[i]),tmpfilestobehashed[i].c_str(),false,dummycrc,par->inizio,par->dimensione,g_dimensione)); } pthread_exit(NULL); return 0; } int Jidac::deduplicate() { myprintf("01037: *** DIRECTLY DELETE DUPLICATED FILES ***\n"); if (files.size()==0) { myprintf("01038: Sorry, works only on exactly 1 dir\n"); return 1; } if (files.size()>1) { myprintf("01039: Sorry, works only on exactly 1 dir\n"); return 1; } if (!isdirectory(files[0])) { myprintf("01040: Sorry, you must enter a directory\n"); return 1; } if (flagverbose) summary=-1; else summary=1; flagchecksum=false; flagverify=true; if (!ischecksum()) flagxxh3=true; flagkill=true; if (!flagforce) myprintf("01041: -force not present: dry run\n"); return summa(); } struct tparametribenchmark { int chunksize; // no big data :-) uint32_t* buffer32bit; int timelimit; string runningalgo; int tnumber; string risultato; double speed; tparametribenchmark(): chunksize(0),buffer32bit(0),timelimit(0),runningalgo(""),tnumber(0),risultato(""),speed(0) {} }; string do_benchmark(int i_tnumber,int i_timelimit,string i_runningalgo,int i_chunksize,uint32_t* buffer32bit,double& o_speed) { int64_t starttutto =mtime(); int64_t lavorati =0; uint64_t totalhashtime =0; int ultimotrascorso =0; int buffersize=i_chunksize*4-7; MD5 md5; libzpaq::SHA1 sha1; XXH3_state_t state128; /// franzSHA256 mysha256; libzpaq::SHA256 sha256; uint64_t _wyp[4]; make_secret(0,_wyp); SHA3 sha3; NESSIEstruct whasher; NESSIEinit(&whasher); blake3_hasher hasher; blake3_hasher_init(&hasher); uint32_t crc = 0; uint32_t crcc = 0; uint64_t myseed = 0; XXHash64 myhash(myseed); HighwayHashCat state; uint64_t key[4] = {1, 2, 3, 4}; HighwayHashCatStart(key, &state); int i=0; while (1) { int64_t startrandom=mtime(); populateRandom_xorshift128plus(buffer32bit, i_chunksize,324+i,4444+i); int64_t randtime=mtime()-startrandom; if ((i_runningalgo=="XXH3")||(i_runningalgo=="XXH3B")) { (void)XXH3_128bits_reset(&state128); (void)XXH3_128bits_update(&state128, buffer32bit, buffersize); } else if (i_runningalgo=="SHA-1") sha1.write((const char*)buffer32bit,buffersize); else if (i_runningalgo=="SHA-1B") sha1.write((const char*)buffer32bit,buffersize); else if (i_runningalgo=="SHA-256") sha256.write((const char*)buffer32bit,buffersize); else if (i_runningalgo=="SHA-256B") sha256.write((const char*)buffer32bit,buffersize); else if (i_runningalgo=="WYHASH") wyhash((const char*)buffer32bit,buffersize,0,_wyp); else if (i_runningalgo=="MD5") md5.add((const char*)buffer32bit,buffersize); else if (i_runningalgo=="MD5B") md5.add((const char*)buffer32bit,buffersize); else if (i_runningalgo=="SHA-3") sha3.add((const char*)buffer32bit,buffersize); else if (i_runningalgo=="SHA-3B") sha3.add((const char*)buffer32bit,buffersize); else if (i_runningalgo=="WHIRLPOOL") NESSIEadd((const unsigned char*)buffer32bit,buffersize*8,&whasher); else if (i_runningalgo=="BLAKE3") blake3_hasher_update(&hasher, (const char*)buffer32bit,buffersize); else if (i_runningalgo=="BLAKE3B") blake3_hasher_update(&hasher, (const char*)buffer32bit,buffersize); else if (i_runningalgo=="CRC-32") crc=crc32_16bytes ((const char*)buffer32bit,buffersize, crc); else if (i_runningalgo=="CRC-32C") crcc = crc32c(crcc, (const unsigned char*)buffer32bit,buffersize); else if (i_runningalgo=="XXHASH64") myhash.add((const unsigned char*)buffer32bit,buffersize); else if ((i_runningalgo=="HIGHWAY64") || (i_runningalgo=="HIGHWAY128") || (i_runningalgo=="HIGHWAY256")) HighwayHashCatAppend((const uint8_t*)buffer32bit,buffersize,&state); /* else { myprintf("01042: GURU unknown algo %s\n",i_runningalgo.c_str()); seppuku(); return 0; } */ totalhashtime=mtime()-starttutto-randtime; if (totalhashtime==0) totalhashtime=1; lavorati+= (i_chunksize*4); double hashingtime=totalhashtime/1000.0; o_speed=lavorati/hashingtime; int trascorso=(int)((mtime()-starttutto+1)/1000.0); if (trascorso!=ultimotrascorso) { if (i_tnumber<0) /// not a pthread { myprintf("%03d s %12s: speed (%11s/s) ",trascorso,i_runningalgo.c_str(), tohuman3((int64_t)o_speed)); if (flagverbose) myprintf("\n"); else myprintf("\r"); } else { pthread_mutex_lock(&g_mylock); if ((!flagsilent) && (!flagnoconsole)) { setupConsole(); printf("\033[%d;0H",(int)i_tnumber+1); restoreConsole(); } myprintf("01043: Thread %02d %03d s %12s: speed (%11s/s)",i_tnumber,trascorso,i_runningalgo.c_str(),tohuman3((int64_t)o_speed)); pthread_mutex_unlock(&g_mylock); } ultimotrascorso=trascorso; } if ((int)((mtime()-starttutto)/1000)>=i_timelimit) break; i++; } double hashingtime=totalhashtime/1000.0; o_speed=lavorati/hashingtime; lavorati+=mtime()-starttutto; int trascorso=(int)((mtime()-starttutto+1)/1000.0); myprintf("%08d s %12s: speed (%11s/s) ",trascorso,i_runningalgo.c_str(),tohuman3((int64_t)o_speed)); myprintf("\n"); char buf[100]; snprintf(buf,sizeof(buf),"%12s: %11s/s (done %11s)",i_runningalgo.c_str(),tohuman((int64_t)o_speed),tohuman2(lavorati)); string risultato=buf; return risultato; } void * benchmark_thread(void *t) { assert(t); tparametribenchmark* par= ((struct tparametribenchmark*)(t)); par->risultato=do_benchmark(par->tnumber,par->timelimit,par->runningalgo,par->chunksize,par->buffer32bit,par->speed); pthread_exit(NULL); return 0; } struct s_benchmark { string algoritmo; double speed; string risultati; }; bool compare_s_benchmark(const s_benchmark &a, const s_benchmark &b) { return a.speed < b.speed; } string filecopy(bool i_singlefile,bool i_append,const string& i_infile,const string& i_outfile,bool i_verify,bool i_donotcheckspace,bool i_overwrite,uint64_t i_maxoutputsize) { if ((i_infile)=="") return ""; if ((i_outfile)=="") return ""; if (i_append==true) { if (i_infile=="QUIT-COMP_$WARN_ING") return ""; } string percorso=i_outfile; if (i_singlefile) percorso=extractfilepath(i_outfile); if (!isdirectory(percorso)) percorso+="/"; if (!direxists(percorso)) makepath(percorso); int64_t larghezzain =prendidimensionefile(i_infile.c_str()); if (i_maxoutputsize>0) larghezzain=i_maxoutputsize; string solofile=extractfilename(i_infile); string filedefinitivo=percorso+solofile; if (i_singlefile) filedefinitivo=i_outfile; if (!i_overwrite) { if (flagdebug3) myprintf("01044: Pre not overwrite %s\n",filedefinitivo.c_str()); filedefinitivo=nomefileseesistegia(filedefinitivo); if (flagdebug3) myprintf("01045: Post not overwrite %s\n",filedefinitivo.c_str()); } if (flagdebug2) myprintf("01046: ready to make a copy in %s\n",filedefinitivo.c_str()); int64_t dimensioneoutput =0; int64_t bytestoappend =0; if (i_append) { dimensioneoutput =prendidimensionefile(filedefinitivo.c_str()); bytestoappend =larghezzain-dimensioneoutput; if (bytestoappend>0) { if (dimensioneoutput>0) myprintf("01047: Ready to append %s bytes to %s => %s\n",migliaia(bytestoappend),migliaia2(dimensioneoutput),migliaia3(larghezzain)); } else if (bytestoappend<0) { myprintf("01048: Destination file larger than source (-append), deleting ...\n"); if (!delete_file(filedefinitivo.c_str())) { myprintf("01049! We get an highlander %Z\n",filedefinitivo.c_str()); return ""; } bytestoappend =larghezzain; i_append =false; } else if (bytestoappend==0) { if (flagdebug2) myprintf("01051: Source and destination filesize ==, exit\n"); return filedefinitivo; } //// 100.000 => 80.000 ///dimensionedacopiare 100.000 } else bytestoappend=larghezzain; if (!i_donotcheckspace) { int64_t spaziolibero =getfreespace(percorso); if (spaziolibero>\n",migliaia(bytestoappend),migliaia2(spaziolibero),percorso.c_str()); return ""; } } FILE* outFile=NULL; #ifdef _WIN32 wstring widename=utow(filedefinitivo.c_str()); if (i_append) outFile=_wfopen(widename.c_str(), L"ab" ); else outFile=_wfopen(widename.c_str(), L"wb" ); #else if (i_append) outFile=fopen(filedefinitivo.c_str(), "ab"); else outFile=fopen(filedefinitivo.c_str(), "wb"); #endif // corresponds to #ifdef (#ifdef _WIN32) if (outFile==NULL) { myprintf("01053: CANNOT OPEN outfile %s\n",filedefinitivo.c_str()); return ""; } int64_t donesize=0; XXH3_state_t state128; (void)XXH3_128bits_reset(&state128); FILE* inFile = freadopen(i_infile.c_str()); if (inFile==NULL) { #ifdef _WIN32 int err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("01054: ERR <%s> kind %d\n",i_infile.c_str(),err); fclose(outFile); return ""; } if (i_append) { if (flagdebug2) myprintf("01055: Seeking input to %s because of -append\n",migliaia(dimensioneoutput)); if (fseeko(inFile,dimensioneoutput, SEEK_SET)!=0) { #ifdef _WIN32 int err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("01056: seek ERR <%s> kind %d\n",i_infile.c_str(),err); fclose(outFile); fclose(inFile); return ""; } } size_t readSize; int64_t startcopy=mtime(); bool hostampato=false; /* if (g_ioBUFSIZE==4096) g_ioBUFSIZE=1048576; */ unsigned char *buffer=(unsigned char*)franz_malloc(g_ioBUFSIZE); ///g_allocatedram+=g_ioBUFSIZE; if (buffer==NULL) { myprintf("01057: GURU allocating io buf of size %s\n",g_ioBUFSIZE); seppuku(); fclose(outFile); fclose(inFile); return ""; } if (flagdebug3) myprintf("01058: Buffer size %s\n",migliaia(g_ioBUFSIZE)); while ((readSize = fread(buffer, 1, g_ioBUFSIZE, inFile)) > 0) { if (i_maxoutputsize>0) if (uint64_t(donesize+readSize)>i_maxoutputsize) { int64_t bytestowrite=i_maxoutputsize-donesize; int64_t written=fwrite(buffer,1,bytestowrite,outFile); donesize+=written; break; } int64_t written=fwrite(buffer,1,readSize,outFile); donesize+=written; if (!i_append) if (i_verify) (void)XXH3_128bits_update(&state128, buffer, readSize); if (!flagnoeta) hostampato |= myavanzamentoby1sec(donesize,bytestoappend,startcopy,false); } if (hostampato) { printbar(' '); myprintf("\r"); } if (flagdebug2) { myprintf("01059: Done\n"); myprintf("01060: Written %20s\n",migliaia(donesize)); myprintf("01061: Expected %20s\n\n",migliaia(bytestoappend)); } if (donesize!=bytestoappend) { myprintf("01062: GURU bytes written does not match expected\n"); return ""; } fclose(outFile); if (buffer!=NULL) { franz_free(buffer); buffer=0; } dimensioneoutput =prendidimensionefile(filedefinitivo.c_str()); if (larghezzain!=dimensioneoutput) { myprintf("01063: GURU input size %s != output size %s\n",migliaia(larghezzain),migliaia2(dimensioneoutput)); return ""; } if (i_verify) { if (!flagnoeta) { ///printbar('='); myprintf("01064: XXH3 verify of %Z\n",filedefinitivo.c_str()); } if (i_append) { if (flagdebug2) myprintf("01066: Full re-read, because of -append\n"); fseeko(inFile,0,SEEK_SET); donesize=0; bytestoappend=prendidimensionehandle(inFile); startcopy=mtime(); while ((readSize = fread(buffer, 1, g_ioBUFSIZE, inFile)) > 0) { donesize+=readSize; (void)XXH3_128bits_update(&state128, buffer, readSize); if (!flagnoeta) myavanzamentoby1sec(donesize,bytestoappend,startcopy,false); } } XXH128_hash_t myhash=XXH3_128bits_digest(&state128); char risultato[33]; snprintf(risultato,sizeof(risultato),"%s",bin2hex_128(myhash.high64,myhash.low64).c_str()); int64_t startverify=mtime(); g_dimensione=0; if (flagdebug3) myprintf("01067: franz_do_hash\n"); franz_do_hash dummy("XXH3"); if (flagdebug3) myprintf("01068: filehash on %s\n",filedefinitivo.c_str()); string hashreloaded=dummy.filehash(filedefinitivo,false,startverify,larghezzain); if (flagverbose || flagdebug) { myprintf("01069: Expected XXH3 hash of the output file %s\n",risultato); myprintf("01070: Calculated XXH3 hash of the output file %s\n",hashreloaded.c_str()); } if (hashreloaded!=risultato) { myprintf("01071: GURU hash of output file does not match!\n"); fclose(inFile); return ""; } } fclose(inFile); return filedefinitivo; } bool isjolly(const string& i_filename) { return strrchr(i_filename.c_str(),'?'); } int Jidac::trim() { if (g_password) { myprintf("60290! Cannot trim with encryption, sorry\n"); return 2; } if (files.size()!=1) { myprintf("01072! TRIM works with ONLY one single .zpaq file (no multipart)\n"); return 2; } if (isjolly(files[0])) { if (flagdebug) myprintf("59604: Jolly founded => multipart trim\n"); return fix(files[0]); } if (tofiles.size()>1) { myprintf("01073! TROM -to with only ONE output, please\n"); return 2; } archive=files[0]; // append ".zpaq" to archive if no extension if (!iszpaq(archive)) archive+=".zpaq"; myprintf("01074: TRIMMING on %s\n",archive.c_str()); int64_t archivesize=prendidimensionefile(archive.c_str()); // Read archive or index into ht, dt, ver. int errors=0; string arcname=archive; // input archive name if (index) arcname=index; int64_t header_pos=0; if (exists(subpart(arcname, 1))) header_pos=read_archive(NULL,arcname.c_str(), &errors); // Set arcname, offset, header_pos, and salt to open out archive arcname=archive; // output file name int64_t offset=0; // total size of existing parts char salt[32]={0}; // encryption salt if (g_password) libzpaq::random(salt, 32); // Remote archive if (index) error("33709: cannot trim with an index"); string part0=subpart(archive, 0); if (part0!=archive) { // multi-part? myprintf("01075! so sorry, this seems a multipart archive, abort\n"); return 2; } // Get salt from first part if it exists if (g_password) { FP fp=myfopen(subpart(archive, 1).c_str(), RB); if (fp==FPNULL) { if (header_pos>32) error("archive first part not found"); header_pos=32; } else { if (fp!=NULL) { if (fread(salt, 1, 32, fp)!=32) error("cannot read salt"); myfclose(&fp); } } } if (!exists(arcname)) { myprintf("01076! archive does not seems to exists %Z\n",arcname.c_str()); ///fclose(fp); return 2; } if (header_pos+offset>archivesize) { myprintf("01078! invalid offset %s vs filesize %s\n",migliaia(header_pos+offset),migliaia2(archivesize)); ///fclose(fp); return 2; } if (header_pos+offset==archivesize) { myprintf("01079: TRIM seems not necessary on size %s\n",migliaia(header_pos+offset)); ///fclose(fp); return 1; } if (tofiles.size()==1) { string trimmeddestination=tofiles[0]; if (isdirectory(trimmeddestination)) { myprintf("01080! error -to is a folder, must be a file\n"); return 2; } if (!iszpaq(trimmeddestination)) trimmeddestination+=".zpaq"; if (!flagforce) if (!saggiascrivibilitacartella(trimmeddestination)) { myprintf("01081! sorry -to folder seems not writeable. Use -force to bypass\n"); return 2; } int64_t spaziolibero=0; spaziolibero=getfreespace(trimmeddestination); if (spazioliberofirst; myreplaceall(filename,"\\","/"); string percorso=extractfilepath(filename); filename=extractfilename(filename); int lunghezza=filename.length(); if (lunghezza>10) { if (filename[0]=='.') if (filename[lunghezza-7]=='.') { string estensionefinale=myright(filename,6); bool spazzatura=true; for (unsigned int i=0;i0) && (estensione.length()<=4)) { string filetobepurged=percorso+filename; #if defined (_WIN32) myprintf("del "); #else myprintf("rm "); #endif // corresponds to #if (#if defined (_WIN32)) myprintf("\""); printUTF8(filetobepurged.c_str()); myprintf("\""); myprintf("\n"); tobeerased++; if (flagkill) { myprintf("01096: Deleting...\n"); if (delete_file(filetobepurged.c_str())) erased++; } } } } } } if (flagkill) { myprintf("01097: Erased %08d / %08d\n",erased,tobeerased); if (tobeerased==erased) return 0; else return 1; } if (tobeerased>0) return 0; else return 2; } bool isfilesequal(string i_source,string i_destination,bool i_flagfast=false) { if (i_source=="") return false; if (i_destination=="") return false; if ((isdirectory(i_source)) && (isdirectory(i_destination))) return true; if (!(( (!isdirectory(i_source)) && (!isdirectory(i_destination)) ))) return false; if (!fileexists(i_source)) return false; if (!fileexists(i_destination)) return false; FILE* source_file = freadopen(i_source.c_str()); if (source_file==NULL) { #ifdef _WIN32 int err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("01098: ERR <%s> kind %d\n",i_source.c_str(),err); return false; } fseeko(source_file, 0, SEEK_END); int64_t sorgente_dimensione=ftello(source_file); fseeko(source_file, 0, SEEK_SET); FILE* destination_file = freadopen(i_destination.c_str()); if (destination_file==NULL) { #ifdef _WIN32 int err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("01099: ERR <%s> kind %d\n",i_destination.c_str(),err); fclose(source_file); return false; } fseeko(destination_file, 0, SEEK_END); int64_t destinazione_dimensione=ftello(destination_file); fseeko(destination_file, 0, SEEK_SET); if (i_flagfast) { if (sorgente_dimensione 0) { readdestination=fread(bufferdestination, 1, blockSize, destination_file); if (readsource!=readdestination) { ///myprintf("01108: read source != read dest %s %s\n",migliaia(readsource),migliaia2(readdestination)); fclose(source_file); fclose(destination_file); return false; } if (memcmp(buffersource, bufferdestination, readsource)) { /// myprintf("01109: failed mem compare\n"); fclose(source_file); fclose(destination_file); return false; } /// confrontatitotale+=readsource; } } fclose(source_file); fclose(destination_file); if (flagdebug) if (i_flagfast) myprintf("01110: fast files ==\n"); return true; } int Jidac::mycopy() { myprintf("01111: Your friendly neighborhood cp/copy "); if (flagverify) myprintf(" without a trusting attitude (-verify) "); if (flagparanoid) myprintf(" no overwrite (-paranoid) "); myprintf("\n"); if (files.size()==0) { myprintf("01112! No source files\n"); return 2; } if (tofiles.size()!=1) { myprintf("01113! exactly one -to required\n"); return 2; } string todirectory=tofiles[0]; if (!isdirectory(todirectory)) todirectory+='/'; if (!flagforce) if (!saggiascrivibilitacartella(todirectory)) { myprintf("01114! sorry -to directory seems not writeable. Use -force to bypass\n"); return 2; } vector sourcelist; vector sourcesize; int64_t totalsourcesize=0; for (unsigned int i=0;ifirst)) { sourcelist.push_back(p->first); sourcesize.push_back(p->second.size); totalsourcesize+=p->second.size; } } } if (sourcelist.size()==0) { myprintf("01115! cannot build source file list\n"); return 2; } int64_t spaziolibero=0; spaziolibero=getfreespace(todirectory); if (spaziolibero #include int64_t internal_getramdisksize() { if (flagdebug2) myprintf("01127: Hello Solaris\n"); long freemem; static kstat_t *ks = NULL; kvm_t *kd; static kstat_ctl_t *kc = NULL; kstat_named_t *kn; /* total comes from sysconf */ ///*freemem = sysconf(_SC_PHYS_PAGES); if ((kc=kstat_open()) == NULL) error("36416: unable to open kstat"); // Solaris compilers does not like some "direct assign", firing warnings // So this seems ugly, but for a reason char p_unix [100]; char p_system_pages [100]; char p_freemem [100]; snprintf(p_unix,sizeof(p_unix),"unix"); snprintf(p_system_pages,sizeof(p_system_pages),"system_pages"); snprintf(p_freemem,sizeof(p_freemem),"freemem"); ks = kstat_lookup(kc, p_unix, 0, p_system_pages); if (ks==NULL) error("36340: ks is null, quit"); if (kstat_read(kc,ks,0)!=-1) { kn=(kstat_named_t*)kstat_data_lookup(ks, p_freemem); if (kn!=NULL) freemem=(long)(kn->value.ui32); else error("36440: guru on kstat lookup"); } else error("36443: guru on kstat_read"); // yes, skip overflow on "strange" compilators. Slow, but who cares? int pagesize = getpagesize(); int64_t big_pagesize = pagesize; int64_t big_freemem = freemem; int64_t big_ram =big_freemem*big_pagesize; return big_ram; } #endif // corresponds to #ifdef (#ifdef SOLARIS) #ifdef __OpenBSD__ // OpenBSD is not == FreeBSD. int64_t internal_getramdisksize() { if (flagdebug2) myprintf("01128: Hello OpenBSD\n"); static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP}; struct uvmexp uvmexp; size_t size; size = sizeof(uvmexp); if (sysctl(uvmexp_mib, 2, &uvmexp, &size, NULL, 0) == -1) error("36445 sysctl failed"); int pagesize = getpagesize(); // yes, skip overflow on "strange" compilators. Slow, but who cares? int64_t big_pagesize =pagesize; int64_t big_free =uvmexp.free; int64_t big_ram =big_pagesize*big_free; return big_ram; } #endif // corresponds to #ifdef (#ifdef __OpenBSD__ // OpenBSD is not == FreeBSD.) #ifdef __APPLE__ // Mac OS/X #include int64_t internal_getramdisksize() { if (flagdebug2) myprintf("01129: Hello Mac\n"); kern_return_t status; unsigned int count = HOST_VM_INFO_COUNT; static vm_statistics_data_t vm_stats; status = host_statistics(mach_host_self(), HOST_VM_INFO,(host_info_t)&vm_stats, &count); if(status!=KERN_SUCCESS) error("36487: vm_statistics() failed"); int pagesize = getpagesize(); int64_t big_pagesize =pagesize; int64_t big_free =vm_stats.free_count; int64_t big_ram =big_pagesize*big_free; return big_ram; } #endif // corresponds to #ifdef (#ifdef __APPLE__ // Mac OS/X) #ifdef BSD // FreeBSD #ifndef __OpenBSD__ // OpenBSD does not have sysctlbyname (yet) #ifndef __APPLE__ // Mac is different (of course) int64_t internal_getramdisksize() { if (flagdebug2) myprintf("01130: Hello FreeBSD\n"); int pagesize =0; int inactive =0; int free =0; size_t size = sizeof free; sysctlbyname("vm.stats.vm.v_free_count", &free, &size, NULL, 0); sysctlbyname("vm.stats.vm.v_inactive_count", &inactive, &size, NULL, 0); size = sizeof pagesize; sysctlbyname("vm.stats.vm.v_page_size", &pagesize, &size, NULL, 0); return (free+inactive)*pagesize;/// / 1024 ; } #endif // corresponds to #ifndef (#ifndef __APPLE__ // Mac is different (of course)) #endif // corresponds to #ifndef (#ifndef __OpenBSD__ // OpenBSD does not have sysctlbyname (yet)) #endif // corresponds to #ifdef (#ifdef BSD // FreeBSD) /// play old "file-like", should work in just about all flavours of Linux #ifdef __linux__ int64_t internal_getramdisksize() { if (flagdebug2) myprintf("01131: Hello Linux\n"); FILE *meminfo = fopen("/proc/meminfo", "r"); if(meminfo == NULL) { myprintf("01132: error, cannot open /proc/meminfo, maybe I am NOT running on Linux?\n"); return 0; } char line[256]; while(fgets(line, sizeof(line), meminfo)) { int ram; string linea=line; if (mypos("MemAvailable:",linea)!=-1) { if (flagdebug3) myprintf("01133: MemAvailable: |%s|\n",linea.c_str()); string onlynumber=""; for (unsigned int i=0;i> 1) & 033333333333)-((u >> 2) & 011111111111); return ((uCount + (uCount >> 3)) & 030707070707) % 63; } int bittino(int i) { i=~i; return contabit((i&(-i))-1); } */ /* AUTOTEST file https://github.com/fcorbelli/zpaqfranz/tree/main/AUTOTEST This is a Windows binary test file */ /// splitted for old C++ compilers. ///DEBIANSTART char extract_test1[]={"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"}; char extract_test2[]={"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"}; char extract_test3[]={"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"}; char extract_test4[]={"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"}; ///DEBIANEND ///char extract_test1[]={"DEBIAN"};char extract_test2[]={""};char extract_test3[]={""};char extract_test4[]={""}; int Jidac::pause() { int thekey=0; if (searchfrom!="") { if (flagdebug) myprintf("01137: searchfrom is <<%s>>\n",searchfrom.c_str()); if (searchfrom.size()==1) { thekey=searchfrom[0]; if (flagdebug) myprintf("01138: thekey is %d %c\n",thekey,thekey); } else { if (flagdebug) myprintf("01139: -find not 1 char long, ignoring!\n"); } } if (menoenne>0) { unsigned int secondi=1; while ((secondi<=menoenne) && (!iskeypressed(thekey))) { myprintf("01140: Wait %03d seconds (or press any key)\r",(menoenne-secondi)+1); fflush(stdout); sleep(1); secondi++; } myprintf("\n"); fflush(stdout); } else { myprintf("\n\n"); if (thekey!=0) myprintf("01141: **** Hit the key %c to continue (beware of case) ****\n",thekey); else myprintf("01142: **** Hit a key to continue ****\n"); while ((!iskeypressed(thekey))) sleep(1); /// mygetch(false); } return 0; } bool debugwritebuffertofile(string i_filename,const void* i_buffer,size_t i_size) { if (i_buffer==NULL) { myprintf("01143: i_buffer null\n"); seppuku(); return false; } if (i_size==0) { myprintf("01144: i_size 0\n"); seppuku(); return false; } if (i_filename.size()<1) { myprintf("01145: i_filenamesize <1\n"); seppuku(); return false; } FILE* myfile=fopen(i_filename.c_str(),"wb"); if (myfile==NULL) { myprintf("01146: cannot write on %s\n",i_filename.c_str()); seppuku(); return false; } fwrite(i_buffer,i_size,1,myfile); fclose(myfile); return true; } int Jidac::autotest() { myprintf("01147: Self-test for correct internal functioning\n"); // for non-Intel CPU if (flagchecktxt) if (checktxt!="") return checkautotest(checktxt); int chunksize=1000000; if (all) if (menoenne>=200000) chunksize=menoenne; uint8_t *buffer8bit=(uint8_t*)franz_malloc(chunksize*sizeof(uint8_t)); ///g_allocatedram+=chunksize*sizeof(uint8_t); if (buffer8bit==0) { myprintf("01148! GURU cannot alloc the buffer8bit\n"); return 2; } if (flagdebug) myprintf("01149: buffer8bit %s\n",migliaia(int64_t(buffer8bit))); // why this strange thing? Because we want to debug on BIG ENDIAN, of course uint32_t *buffer32bit = (uint32_t*)franz_malloc(chunksize*sizeof(uint32_t)); ///g_allocatedram+=chunksize*sizeof(uint32_t); if (buffer32bit==0) { franz_free(buffer8bit); myprintf("01150! GURU cannot alloc the buffer32bit\n"); return 2; } if (flagdebug) myprintf("01151: buffer32bit %s\n",migliaia(int64_t(buffer32bit))); int64_t startcalc=mtime(); MAPPAAUTOCHECK myautocheck_map; hash_autocheck myblock; myblock.ok="93EA42CC35E379AD67927C4F3B7AB78EA038A7FD67D7B245975752FDF319B0A8C40E4F4AD30D9069CBB96777AE2CA6ED23A5FEB1DCF30487401317887E97584A"; myautocheck_map.insert(std::pair("WHIRLPOOL",myblock)); myblock.ok="B99C2AD7BDE24144"; myautocheck_map.insert(std::pair("HIGHWAY64",myblock)); myblock.ok="794503BA1B12CF8848907AAF0F62A8C5"; myautocheck_map.insert(std::pair("HIGHWAY128",myblock)); myblock.ok="6F9B44DF54E86972F2873FEFEBB06BD7E29CF9C7DB71096FF0270D72726088EF"; myautocheck_map.insert(std::pair("HIGHWAY256",myblock)); myblock.ok="5AF0D4BB454A7D349CE97EFAFFD93CAC3B200DF166BEB9BFE2EC1838F35396AD"; myautocheck_map.insert(std::pair("BLAKE3",myblock)); myblock.ok="0D26839A"; myautocheck_map.insert(std::pair("CRC-32",myblock)); myblock.ok="50CB8A6F"; myautocheck_map.insert(std::pair("CRC-32C",myblock)); myblock.ok="A245C815AD0C65DBBC48094B281B245A"; myautocheck_map.insert(std::pair("MD5",myblock)); myblock.ok="F1D057704157A6A69F4A6AF06321FF8EA57BC719D070B5E28A92E362D03F66AD"; myautocheck_map.insert(std::pair("SHA-256-PUT",myblock)); myblock.ok="F1D057704157A6A69F4A6AF06321FF8EA57BC719D070B5E28A92E362D03F66AD"; myautocheck_map.insert(std::pair("SHA-256-WRITE",myblock)); myblock.ok="A6F8AEA5086E5EEC6585ECCCE91901C7B810BD9A1EDD06CA0EE7DBF23AD773DE"; myautocheck_map.insert(std::pair("SHA-3",myblock)); myblock.ok="CEFB9B8DD36BFE7EE6CB3B1E5E5CA8D259A53FFF"; myautocheck_map.insert(std::pair("SHA1-PUT",myblock)); myblock.ok="CEFB9B8DD36BFE7EE6CB3B1E5E5CA8D259A53FFF"; myautocheck_map.insert(std::pair("SHA1-WRITE",myblock)); myblock.ok="93EA42CC35E379AD67927C4F3B7AB78EA038A7FD67D7B245975752FDF319B0A8C40E4F4AD30D9069CBB96777AE2CA6ED23A5FEB1DCF30487401317887E97584A"; myautocheck_map.insert(std::pair("WHIRLPOOL",myblock)); myblock.ok="25F384F0514225C3878240045180B970"; myautocheck_map.insert(std::pair("XXH3",myblock)); myblock.ok="996D383079195E18"; myautocheck_map.insert(std::pair("XXHASH64",myblock)); myblock.ok="996D383079195E18"; myautocheck_map.insert(std::pair("XXHASH64Y",myblock)); ///myblock.ok="EMPTY"; ///myautocheck_map.insert(std::pair("WHYHASH",myblock)); if (flagdebug3) myprintf("01152: end of insert\n"); XXH3_state_t state128; XXH3_128bits_reset(&state128); libzpaq::SHA1 sha1; libzpaq::SHA1 sha1put; libzpaq::SHA256 sha256put; libzpaq::SHA256 sha256write2; MD5 md5; SHA3 sha3; NESSIEstruct hasher; NESSIEinit(&hasher); blake3_hasher hasherblake3; blake3_hasher_init(&hasherblake3); uint32_t crc =0; uint32_t crcc =0; uint64_t myseed =0; XXHash64 myhash(myseed); XXH64_hash_t seme=0; XXH64_state_t* state = XXH64_createState(); assert(state != NULL && "Out of memory!"); XXH64_reset(state,seme); HighwayHashCat highway64state; uint64_t key[4] = {1, 2, 3, 4}; HighwayHashCatStart(key,&highway64state); char buffer[256]; int64_t total_hashed=0; string outfolder=""; string outfile; char mynomefile[260]; unsigned int chunk=0; string extract1=""; if (flagdebug3) myprintf("01153: end of init\n"); if (tofiles.size()==1) { outfolder=includetrailingbackslash(tofiles[0]); #ifdef unix if (outfolder[0]!='/') { myprintf("01154! on non-Win full path required: -to /tmp/testfolder is OK -to ./testdir NOT GOOD\n"); return 2; } #endif // corresponds to #ifdef (#ifdef unix) if (flagdebug2) myprintf("01155: outfolder <<%s>>\n",outfolder.c_str()); if (mypos(" ",outfolder)>=0) { franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01156! -to folder cannot contain spaces\n"); return 2; } if (!saggiascrivibilitacartella(outfolder)) { franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01157! cannot write test data into -to\n"); return 2; } else { if (flagdebug3) myprintf("01158: saggiascrivibilitacartella OK |%s|\n",outfolder.c_str()); } uint64_t tofoldersize =0; uint32_t tofoldernumber =0; uint32_t tofolderfolder =0; uint32_t tofolderlongfiles =0; if (getfoldersize(outfolder,tofoldersize,tofoldernumber,tofolderfolder,tofolderlongfiles)) { if (flagdebug3) myprintf("01159: getfoldersize OK, tofoldersize %s\n",migliaia(tofoldersize)); if (tofoldersize>0) { myprintf("01160! WARNING the folder <<%Z>>\n",outfolder.c_str()); franz_free(buffer8bit); franz_free(buffer32bit); return 1; } } else { if (flagdebug) myprintf("01162: getfoldersize failed!\n"); } int64_t spazio=getfreespace(outfolder); if ((spazio/1000000000)<18) if (!flagspace) { myprintf("01163! You need at least 18GB free on %s (founded %s). Use -space to bypass\n",outfolder.c_str(),tohuman(spazio)); return 2; } ///warning: string literal of length 198756 exceeds maximum length 65536 that C++ compilers are required to suppor extract1=extract_test1; if (extract1=="DEBIAN") { myprintf("\n\n"); myprintf("01164: *** This seems Debian: sorry, cannot make FULL autotest on this platform\n"); myprintf("01165: *** You need to download the full source code from github and manually\n"); myprintf("01166: *** compile\n\n"); } else { string extract2=extract_test2; string extract3=extract_test3; string extract4=extract_test4; const string extract_test=extract1+extract2+extract3+extract4; if (flagdebug3) myprintf("01167: extract_test size %s\n",migliaia(extract_test.size())); size_t the_file_len=mimesize(extract_test.c_str()); if (flagdebug3) myprintf("01168: the_file_len %s\n",migliaia(the_file_len)); char* the_file; the_file=(char*)franz_malloc(the_file_len); ///g_allocatedram+=the_file_len; if (the_file==NULL) { franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01169! error in malloc\n"); return 2; } if (flagdebug3) myprintf("01170: the_file alloc OK %s\n",migliaia(int64_t(the_file))); if (!mime2binary(extract_test.c_str(),(unsigned char *)the_file,the_file_len)) { franz_free(the_file); franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01171! mime decoder kaputt!\n"); return 2; } else { if (flagdebug3) myprintf("01172: mime decoder OK on extract_test %s\n",extract_test.c_str()); } outfile=outfolder+"sha256.zpaq"; myprintf("01173: Creating autotest folder in <<%Z>>\n",outfolder.c_str()); #ifdef _WIN32 std::wstring widename=utow(outfile.c_str()); FILE* outFile=_wfopen(widename.c_str(), L"wb"); if (flagdebug3) myprintf("01175: creato widename\n"); #else FILE* outFile=fopen(outfile.c_str(),"wb"); if (flagdebug3) myprintf("01176: fopen non wide\n"); #endif // corresponds to #ifdef (#ifdef _WIN32) if (outFile==NULL) { franz_free(the_file); franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01177! CANNOT OPEN outfile %s\n",outfile.c_str()); return 2; } if (flagdebug3) { myprintf("01178: outFile handle %s\n",migliaia(int64_t(outFile))); myprintf("01179: sto per fare fwrite\n"); myprintf("01180: the_file %s\n",migliaia(int64_t(the_file))); myprintf("01181: the_file_len %s\n",migliaia(int64_t(the_file_len))); myprintf("01182: outFile handle %s\n",migliaia(int64_t(outFile))); } unsigned int scritti=fwrite(the_file,1,the_file_len,outFile); if (flagdebug3) myprintf("01183: scritti %s\n",migliaia(scritti)); fclose(outFile); if (flagdebug2) myprintf("01184: dopo fclose\n"); if (scritti!=the_file_len) { franz_free(the_file); franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01185! error extracting file .zpaq written %s expected %s => %s\n",migliaia(scritti),migliaia2(the_file_len),outfile.c_str()); return 2; } if (flagdebug2) myprintf("01186: dimensione outfile %s\n",migliaia(prendidimensionefile(outfile.c_str()))); } } if (all) { for (int i=0;i<10;i++) { myprintf("01187: Iteration %d/9 chunksize %12s \n",(int)i,migliaia(chunksize)); populateRandom_xorshift128plus(buffer32bit, chunksize,324+i,4444+i); if (flagverbose) { myprintf("01188: King0 %08X\n",(uint32_t)buffer32bit[0]); myprintf("01189: King1 %08X\n",(uint32_t)buffer32bit[1]); myprintf("01190: King2 %08X\n",(uint32_t)buffer32bit[2]); myprintf("01191: King3 %08X\n",(uint32_t)buffer32bit[3]); myprintf("01192: King4 %08X\n",(uint32_t)buffer32bit[4]); myprintf("01193: King5 %08X\n",(uint32_t)buffer32bit[5]); myprintf("01194: King6 %08X\n",(uint32_t)buffer32bit[6]); myprintf("01195: King7 %08X\n",(uint32_t)buffer32bit[7]); } // yes we want to check BIG/LITTLE ENDIAN too #ifdef BIG /// explicit swap (debug) with TWO variables, slow but who cares? int j=0; while (j(unsigned int)chunksize) { franz_free(buffer8bit); franz_free(buffer32bit); myprintf("01208! -n too big, max %s\n",migliaia(sizeof(chunksize))); return 2; } flagverbose=true; chunksize=5; if (menoenne>0) chunksize=menoenne; myprintf("01209: Quick check chunksize %d: ",chunksize); for (int j=0;jsecond.calculated=bin2hex_64(hash_64); a=myautocheck_map.find("HIGHWAY128"); if (a==myautocheck_map.end()) error("guru 52286 HIGHWAY128"); uint64_t hash_128[2]; HighwayHashCatFinish128(&highway64state,hash_128); a->second.calculated=binarytohex((const unsigned char*)hash_128,16); a=myautocheck_map.find("HIGHWAY256"); if (a==myautocheck_map.end()) error("guru 52286 HIGHWAY256"); uint64_t hash_256[4]; HighwayHashCatFinish256(&highway64state,hash_256); a->second.calculated=binarytohex((const unsigned char*)hash_256,32); a=myautocheck_map.find("SHA-3"); if (a==myautocheck_map.end()) error("guru 32469 SHA-3"); a->second.calculated=sha3.getHash(); a=myautocheck_map.find("MD5"); if (a==myautocheck_map.end()) error("guru 32476 MD5"); a->second.calculated=md5.getHash(); NESSIEfinalize(&hasher,(unsigned char*)buffer); a=myautocheck_map.find("WHIRLPOOL"); if (a==myautocheck_map.end()) error("guru 32484 WHIRLPOOL"); a->second.calculated=binarytohex((const unsigned char*)buffer,64); XXH128_hash_t myhashres=XXH3_128bits_digest(&state128); a=myautocheck_map.find("XXH3"); if (a==myautocheck_map.end()) error("guru 32494 XXH3"); a->second.calculated=bin2hex_128(myhashres.high64,myhashres.low64); uint8_t output[BLAKE3_OUT_LEN]; blake3_hasher_finalize(&hasherblake3,output,BLAKE3_OUT_LEN); a=myautocheck_map.find("BLAKE3"); if (a==myautocheck_map.end()) error("guru 32494 BLAKE3"); a->second.calculated=binarytohex((const unsigned char*)output,BLAKE3_OUT_LEN); memcpy(buffer,sha256put.result(), 32); a=myautocheck_map.find("SHA-256-PUT"); if (a==myautocheck_map.end()) error("guru 54599 SHA-256-PUT"); a->second.calculated=binarytohex((const unsigned char*)buffer,32); memcpy(buffer,sha256write2.result(), 32); a=myautocheck_map.find("SHA-256-WRITE"); if (a==myautocheck_map.end()) error("guru 54390 SHA-256-WRITE"); a->second.calculated=binarytohex((const unsigned char*)buffer,32); a=myautocheck_map.find("XXHASH64"); if (a==myautocheck_map.end()) error("guru 32494 XXHASH64"); a->second.calculated=bin2hex_64(myhash.hash()); memcpy(buffer,sha1.result(),20); a=myautocheck_map.find("SHA1-WRITE"); if (a==myautocheck_map.end()) error("guru 32494 SHA1-WRITE"); a->second.calculated=binarytohex((const unsigned char*)buffer,20); memcpy(buffer,sha1put.result(),20); a=myautocheck_map.find("SHA1-PUT"); if (a==myautocheck_map.end()) error("guru 32494 SHA1-PUT"); a->second.calculated=binarytohex((const unsigned char*)buffer,20); snprintf(buffer,sizeof(buffer),"%08X",crc); a=myautocheck_map.find("CRC-32"); if (a==myautocheck_map.end()) error("guru 32494 CRC-32"); a->second.calculated=buffer; snprintf(buffer,sizeof(buffer),"%08X",crcc); a=myautocheck_map.find("CRC-32C"); if (a==myautocheck_map.end()) error("guru 32494 CRC-32C"); a->second.calculated=buffer; XXH64_hash_t yann=XXH64_digest(state); a=myautocheck_map.find("XXHASH64Y"); if (a==myautocheck_map.end()) error("guru 32495 XXHASH64Y"); a->second.calculated=bin2hex_64(yann); if (flagdebug3) myprintf("01211: end myautocheck\n"); int64_t endtime=mtime(); if (isbigendian()) myprintf("01212: This seems a BIG ENDIAN CPU (aka:'strange')\n"); else myprintf("01213: This seems a LITTLE ENDIAN CPU (aka:'normal')\n"); if (flagverbose) { printbar('-'); for (MAPPAAUTOCHECK::iterator p=myautocheck_map.begin(); p!=myautocheck_map.end(); ++p) myprintf("01214: CALC %15s: %s\n",p->first.c_str(),p->second.calculated.c_str()); printbar('-'); } bool allok=true; if (all) { for (MAPPAAUTOCHECK::iterator p=myautocheck_map.begin(); p!=myautocheck_map.end(); ++p) if (p->second.ok==p->second.calculated) myprintf("%15s : OK\n",p->first.c_str()); else { myprintf("%15s : ERROR OK %s CALCULATED %s\n",p->first.c_str(),p->second.ok.c_str(),p->second.calculated.c_str()); allok=false; } } myprintf("01215: Time %.2f seconds for bytes %s\n",(endtime-startcalc)*0.001,migliaia(total_hashed)); if (outfolder!="") { chunksize=1000000; for (unsigned int j=1;j<=15;j++) { snprintf(mynomefile,sizeof(mynomefile),"%sbigone%02d.big",outfolder.c_str(),j); FILE* myfile=fopen(mynomefile, "wb"); if (myfile==NULL) { myprintf("01216: cannot write on %s\n",mynomefile); seppuku(); } myprintf("01217: Big file %s ",mynomefile); for (unsigned int i=0;i<100;i++) { if (j==15) memset(buffer32bit,0,chunksize); else if (j%3==0) memset(buffer32bit,j,chunksize); else populateRandom_xorshift128plus(buffer32bit,chunksize,j+777+i,j+192+i); fwrite(buffer32bit,4,chunksize,myfile); if (i>0) if (i%10==0) myprintf("%02d ",i); } myprintf("\n"); fclose(myfile); } #ifdef _WIN32 string linuxpath =outfolder; outfolder =linuxtowinpath(outfolder); string filebatch =outfolder+"dotest.bat"; char barra='\\'; string acapo="\r\n"; #else string filebatch =outfolder+"dotest.sh"; string linuxpath =outfolder; char barra='/'; string acapo="\n"; #endif // corresponds to #ifdef (#ifdef _WIN32) filebatch=nomefileseesistegia(filebatch); if (fileexists(filebatch)) if (remove(filebatch.c_str())!=0) { myprintf("01218: Highlander batch %s\n", filebatch.c_str()); franz_free(buffer8bit); franz_free(buffer32bit); return 1; } if (flagdebug3) myprintf("01219: filebatch %s\n",filebatch.c_str()); string filezpaq=outfolder+"testme.zpaq"; #ifdef _WIN32 wchar_t myexepath[_MAX_PATH]; GetModuleFileName(NULL,myexepath,_MAX_PATH); string myzpaqexe=wtou(myexepath); myzpaqexe=linuxtowinpath(myzpaqexe); #else if (extract1=="DEBIAN") { myprintf("01220: Sorry, no full test on Debian allowed. Download and compile source from github\n"); seppuku(); } string myzpaqexe=my_realpath(zpaqfranzexename); #endif // corresponds to #ifdef (#ifdef _WIN32) if (flagdebug2) myprintf("01221: myzpaqexe %s\n",myzpaqexe.c_str()); FILE* batch=fopen(filebatch.c_str(), "wb"); if (batch==NULL) { myprintf("01222: cannot write on %s\n",filebatch.c_str()); seppuku(); } if (flagdebug2) myprintf("01223: batch FILE* %s\n",migliaia(int64_t(batch))); #ifdef _WIN32 fprintf(batch,"@echo OFF\r\n"); #endif // corresponds to #ifdef (#ifdef _WIN32) fprintf(batch,"\"%s\" x \"%ssha256.zpaq\" -space -to \"%ste\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%ste\" -sha256 -rename -force -out \"%sout01.txt\"%s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s00\" -xxhash -comment \"xxhash\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s01\" -xxh3 -comment \"xxh3\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s02\" -sha1 -comment \"sha1\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s03\" -sha256 -comment \"sha256\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s04\" -sha3 -comment \"sha3\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s05\" -blake3 -comment \"blake3\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s06\" -md5 -comment \"md5\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s07\" -whirlpool -comment \"whirlpool\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s08\" -highway64 -comment \"high64\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%s\" \"%s09\" -highway128 -comment \"high128\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" x \"%s\" \"%s00%c0770%c00771.dat\" -space -to \"%sverifica\" %s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),barra,barra,outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%sverifica\" -sha256 -out \"%sout02.txt\"%s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" t \"%s\" -until 10 -verify -out \"%sout03.txt\"%s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" v \"%s\" -all -out \"%sout04.txt\"%s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" w \"%s\" -all -test -checksum -verbose -out \"%sout05.txt\"%s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" p \"%s\" -verify -out \"%sout06.txt\"%s",myzpaqexe.c_str(),filezpaq.c_str(),outfolder.c_str(),acapo.c_str()); string temp2=excludetrailingbackslash(outfolder); fprintf(batch,"\"%s\" x \"%s\" -to \"%sfranco\" -space -find \"%s\" -replace \"\" %s",myzpaqexe.c_str(),filezpaq.c_str(),linuxpath.c_str(),temp2.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%sfranco/01\" \"%sfranco/02\" \"%sfranco/03\" \"%sfranco/04\" \"%sfranco/05\" \"%sfranco/06\" \"%sfranco/07\" \"%sfranco/08\" \"%sfranco/09\" -xxh3 -summary -out \"%sout07.txt\"%s",myzpaqexe.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), linuxpath.c_str(), outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s00\" -key pippo -md5b -chunk 200k -to \"./locale/00\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s01\" -key pippo -xxhashb -chunk 200k -to \"./locale/01\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s02\" -key pippo -blake3 -chunk 200k -to \"./locale/02\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s03\" -key pippo -xxh3b -chunk 200k -to \"./locale/03\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s04\" -key pippo -xxhashb -chunk 500k -to \"./locale/04\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s05\" -key pippo -sha3b -chunk 200k -to \"./locale/05\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s06\" -key pippo -whirlpool -chunk 200k -to \"./locale/06\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s07\" -key pippo -sha256b -chunk 200k -to \"./locale/07\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s08\" -key pippo -xxhashb -chunk 50k -to \"./locale/08\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%schunk_????.zpaq\" \"%s09\" -key pippo -sha256 -chunk 50k -to \"./locale/09\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" x \"%schunk_????.zpaq\" -space -key pippo %s", myzpaqexe.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%slocale\" -summary -out \"%sout08.txt\"%s", myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" t \"%schunk_????.zpaq\" -key pippo -paranoid -to \"%skane\" -space -out \"%sout09.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"echo errore >>\"%slocale%c04%c2229%c10000.dat\"%s",outfolder.c_str(),barra,barra,barra,acapo.c_str()); fprintf(batch,"\"%s\" v \"%schunk_????.zpaq\" -key pippo -verbose -out \"%sout10.txt\"%s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" c \"%slocale\" \"%sfranco\" -xxh3 -checksum -out \"%sout11.txt\"%s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/0*\" -xxhashb -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/1*\" -md5b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/2*\" -xxh3b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/3*\" -sha256b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/4*\" -sha3b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/5*\" -blake3b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/6*\" -sha1b -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/7*\" -whirlpool -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/8*\" -highway64 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/9*\" -highway128 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/A*\" -xxhash -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/B*\" -md5 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/C*\" -xxh3 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/D*\" -sha256 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/E*\" -sha3 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" backup \"%smultipart.zpaq\" \"%ste\" -only \"*te/F*\" -blake3 -key pippo %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" testbackup \"%smultipart.zpaq\" -paranoid -verify -key pippo -out \"%sout12.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" x \"%smultipart_????????\" -key pippo -until 17 -space -to \"%sex_multipart\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" t \"%smultipart_????????\" -key pippo -until 17 -verify -to \"%sex_multipart\" -out \"%sout13.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" t \"%smultipart_????????\" \"%ste\" -key pippo -checksum -out \"%sout14.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s00\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s01\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s02\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s03\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%ssha256.zpaq\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s04\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s05\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s06\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s07\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s09\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" a \"%sbinary.zpaq\" \"%s09\" -xxhashb -frugal %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" x \"%sbinary.zpaq\" -only \"*sha256.zpaq\" -space -find \"sha256.zpaq\" -replace \"restored.zpaq\" %s",myzpaqexe.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%srestored.zpaq\" \"%ssha256.zpaq\" -stdout -pakka -noeta -out \"%sout15.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" p \"%sbinary.zpaq\" -verify -out \"%sout16.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" r \"%s04\" \"%slocale%c04\" -kill -out \"%sout17.txt\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),barra,outfolder.c_str(),acapo.c_str()); string onlylist="-only \"*05000.dat\" -only \"*06000.dat\" -only \"*15000.dat\" -only \"*00777.dat\" -only \"*00778.dat\" -only \"*02332.dat\" -only \"*04663.dat\" -only \"*07771.dat\" -only \"*11656.dat\" -only \"*16318.dat\" -only \"*21757.dat\" -only \"*34996.dat\""; fprintf(batch,"\"%s\" x \"%sbinary.zpaq\" -all %s -space -to \"%sex_binary\" %s", myzpaqexe.c_str(),outfolder.c_str(),onlylist.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%sex_binary\" -summary -blake3 -out \"%sout18.txt\" %s", myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%slocale\" %s -summary -blake3 -out \"%sout19.txt\" %s", myzpaqexe.c_str(),outfolder.c_str(),onlylist.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%s00\" \"%s01\" \"%s02\" \"%s03\" \"%s04\" \"%s05\" \"%s06\" \"%s07\" \"%s08\" \"%s09\" %s -summary -blake3 -out \"%sout20.txt\" %s", myzpaqexe.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), outfolder.c_str(), onlylist.c_str(), outfolder.c_str(),acapo.c_str()); for (unsigned j=1;j<=15;j++) fprintf(batch,"\"%s\" a \"%sthebigone.zpaq\" \"%sbigone%02d.big\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),j,acapo.c_str()); fprintf(batch,"\"%s\" x \"%sthebigone.zpaq\" -space -to \"%sex_bigone\" %s",myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); fprintf(batch,"\"%s\" sum \"%sex_bigone\" -summary -sha3 -out \"%sout21.txt\" %s", myzpaqexe.c_str(),outfolder.c_str(),outfolder.c_str(),acapo.c_str()); string temp=excludetrailingbackslash(outfolder); fprintf(batch,"\"%s\" autotest -checktxt \"%s\" %s",myzpaqexe.c_str(),temp.c_str(),acapo.c_str()); if (flagdebug3) myprintf("01224: before fclose\n"); fclose(batch); if (flagdebug3) myprintf("01225: after fclose\n"); // ok we want the +x #ifdef unix chmod(filebatch.c_str(),0700); if (flagdebug3) myprintf("01226: after chmod\n"); #endif // corresponds to #ifdef (#ifdef unix) myprintf("\n\n"); myprintf("01227: The test batchfile is: %s\n",filebatch.c_str()); } if (flagdebug3) myprintf("01228: franz_free buffer8bit %s\n",migliaia(int64_t(buffer8bit))); franz_free(buffer8bit); if (flagdebug3) myprintf("01229: franz_free buffer32bit %s\n",migliaia(int64_t(buffer32bit))); franz_free(buffer32bit); if (flagdebug2) myprintf("01230: allok %d\n",int(allok)); if (allok) return 0; else return 2; return 0; // compiler be quiet } int Jidac::findj() { if (files.size()==0) { myprintf("01231: no files selected to find\n"); return 1; } if (files.size()==2) { myprintf("01232: magically search %s\n",files[1].c_str()); onlyfiles.push_back(files[1]); files.pop_back(); } if (files[0]==".") files[0]+='/'; int64_t startscan=mtime(); for (unsigned int i=0;i filelist; for (DTMap::iterator p=edt.begin(); p!=edt.end(); ++p) { bool flagshow=true; if (searchfrom!="") if (stristr(p->first.c_str(),searchfrom.c_str())==0) flagshow=false; if (g_datefrom>0) if ((p->second.date)<=g_datefrom) flagshow=false; if (g_dateto>0) if ((p->second.date)>=g_dateto) flagshow=false; if (maxsize>0) if (maxsize<(uint64_t)p->second.size) flagshow=false; if (minsize>0) if (minsize>(uint64_t)p->second.size) flagshow=false; if (flagshow) { filelist.push_back(p); howmany++; totalsize+=p->second.size; } } ///////// ext;size;name;hash;date;data if (orderby=="") { if ((g_datefrom>0) || (g_dateto>0)) orderby+="date;"; if ((maxsize>0) || (minsize>0)) orderby+="size;"; } if (orderby!="") { myprintf("01234: orderby |%s|\n",orderby.c_str()); sort(filelist.begin(), filelist.end(), compareorderby); } for (unsigned int i=0;i sort by size and stop at 10 if (i>=menoenne) break; if (flagverbose) myprintf("%s %19s ",dateToString(flagutc,filelist[i]->second.date).c_str(),migliaia((int64_t)filelist[i]->second.size)); printUTF8(filelist[i]->first.c_str()); myprintf("\n"); } if (howmany) { printbar('='); myprintf("01235: Files %s for %s bytes (%s)\n",migliaia((int64_t)howmany),migliaia((int64_t)totalsize),tohuman((int64_t)totalsize)); } return 0; } ///zpaqfranz isopen "C:\Users\utente\AppData\Roaming\Thunderbird\Profiles\to6z2c6f.default\ImapMail\imap.googlemail.com\INBOX" int Jidac::isopen() { if (files.size()!=1) { myprintf("01236! for isopen() exactly 1 file needed\n"); return 2; } if (!fileexists(files[0])) { myprintf("01237! file does not exists %Z\n",files[0].c_str()); return 1; } if (isfileopen(files[0])) { myprintf("01239: file seems open %Z\n",files[0].c_str()); return 1; } myprintf("01241: file is NOT open %Z\n",files[0].c_str()); return 0; } /* Section: main */ /* #define MAX_FILE_PATH 1024 void close_open_files() { #ifdef __linux__ if (flagverbose) myprintf("01243: Seems Linux, scanning proc\n"); char path[MAX_FILE_PATH]; DIR *dir; struct dirent *ent; char fd_path[MAX_FILE_PATH]; int fd; pid_t pid=getpid(); snprintf(path, sizeof(path), "/proc/%d/fd", pid); if (flagverbose) myprintf("01244: mypid is %d path is |%s|\n",pid, path); if ((dir=opendir(path))!=NULL) { while ((ent=readdir(dir))!=NULL) { if (flagverbose) myprintf("01245: File to be closed (. and .. skipped) %s\n",ent->d_name); if ((strcmp(ent->d_name, ".")==0) || (strcmp(ent->d_name, "..")==0)) continue; snprintf(fd_path,sizeof(fd_path),"/proc/%d/fd/%s",pid,ent->d_name); fd=atoi(ent->d_name); if (flagverbose) myprintf("01246: fd %d fd_path %s\n",fd,fd_path); if (fd>2) { if (flagverbose) myprintf("01247: Closing fd (>2) %d\n", fd); close(fd); } } closedir(dir); } else { myprintf("01248: (strange Linux?) cannot open /proc/[pid]/fd %s\n",path); } return; #endif // corresponds to #ifdef (#ifdef __linux__) if (flagverbose) myprintf("01249: close_open_files() on non-Linux: do nothing\n"); } */ /// control-c handler void my_handler(int s) { g_control_c=true; // block open new files for write color_restore(); fflush(stdout); myprintf("\n\n"); myprintf("01250: CONTROL-C detected, try some housekeeping...\n"); #ifdef unix printf("\x1B[?25h"); // Mostra il cursore fflush(stdout); if (g_dataset!="") { string destroy_diff2 =x_one("zfs destroy " +g_tempsnapshot,"59870: Destroy diff snapshot (if any)"); string destroy_base =x_one("zfs destroy " +g_basesnapshot,"59870: Destroy base snapshot (if any)"); if (flagdebug) { myprintf("01251: %s\n",destroy_diff2.c_str()); myprintf("01252: %s\n",destroy_base.c_str()); } string take_base =x_one("zfs snapshot " +g_basesnapshot,"Taking base snapshot"); if (flagdebug) myprintf("01253: %s\n",take_base.c_str()); } // control-C in blind password struct termios tty; tcgetattr(STDIN_FILENO, &tty); tty.c_lflag |= ECHO; tcsetattr(STDIN_FILENO, TCSANOW, &tty); #endif // corresponds to #ifdef (#ifdef unix) if (g_chunk_size>0) { printbar('-'); myprintf("01254: OK we get a chunk size limit of %s on %s files\n",migliaia(g_chunk_size),migliaia2(g_addedchunklist.size())); myprintf("01255: g_archivefp_first handle %21s\n",migliaia(int64_t(g_archivefp_first))); myprintf("01256: g_archivefp handle %21s\n",migliaia(int64_t(g_archivefp))); if (g_write_fp.size()==2) if (g_write_fp[0]==g_archivefp_first) if (g_write_fp[1]==g_archivefp) myprintf("01257: archivefp/first match (this is good)\n"); myprintf("01258: write pool before emergency close (should be 2 max 3)\n"); vector fp_da_chiudere; for (unsigned int i=0;i0) { myprintf("01260: Closing %08d handles\n",fp_da_chiudere.size()); for (unsigned int i=0;i0) { unsigned int deleted =0; unsigned int expected =0; myprintf("01268: Fixed-size chunk: (try) deleting all of them (should be %s)\n",migliaia(g_addedchunklist.size()-1)); for (unsigned int i=0;i>\n",i,g_addedchunklist[i].c_str()); } } else { if (flagdebug3) myprintf("01272: file not found to be killed %s\n",g_addedchunklist[i].c_str()); } } if (expected==deleted) color_green(); else color_red(); myprintf("01273: Expected file %s deleted %s\n",migliaia(expected),migliaia2(deleted)); color_restore(); } else { if ((g_archivefp!=FPNULL) && (g_archivefp!=NULL)) { myprintf("01274: Closing file handle %s\n",migliaia(int64_t(g_archivefp))); myfclose(&g_archivefp); myprintf("01275: myfclose done on archivefp now %s\n",migliaia(int64_t(g_archivefp))); } if ((g_archivefp_first!=FPNULL) && (g_archivefp_first!=NULL)) { myprintf("01276: Closing file handle first %s\n",migliaia(int64_t(g_archivefp_first))); myfclose(&g_archivefp_first); myprintf("01277: myfclose done on archivefp_first now %s\n",migliaia(int64_t(g_archivefp_first))); } if (flagalwayscheck) if (fileexists(g_archive)) if (prendidimensionefile(g_archive.c_str())>=0) { if (delete_file(g_archive.c_str())) myprintf("01278: Erased chunk <<%Z>>\n",g_archive.c_str()); else myprintf("01279! *CANNOT DELETE* <<%Z>>\n",g_archive.c_str()); } // we must trim the index too! if (!g_flagcreating) { int64_t newdim=prendidimensionefile(g_archive.c_str()); if (newdim>g_starting_zpaqsize) { myprintf("01282: should roll back %s from %s to %s\n",g_archive.c_str(),migliaia(newdim), migliaia2(g_starting_zpaqsize)); /// if (truncate(g_archive.c_str(), g_starting_zpaqsize)) /// printerr("61920",g_archive.c_str(),0); if (g_starting_zpaqdate>0) { if (flagdebug3) myprintf("01283: should touching back to %s\n",dateToString(false,g_starting_zpaqdate).c_str()); ///if (!touch(g_archive.c_str(),g_starting_zpaqdate,g_starting_zpaqattr)) ///myprintf("01284: WARNING trouble in touching\n"); } } } } if (!flagnopid) if (g_pidname!="") { if (g_pid_handle!=0) { myprintf("01285: Closing pid handle\n"); fclose(g_pid_handle); } if (delete_file(g_pidname.c_str())) myprintf("01286: Erased pid <<%Z>>\n",g_pidname.c_str()); else myprintf("01287! *FAILED* delete of <<%Z>>\n",g_pidname.c_str()); } // 2==control-C (maybe) if (s==2) { #ifdef _WIN32 if (command=='q') { myprintf("01290: *** VSS RUNNING, DETACHING\n"); vss_deleteshadows(linuxtowinpath(g_franzsnap)); } #endif // corresponds to #ifdef (#ifdef _WIN32) if ((!flagsilent) && (!flagnoconsole)) { setupConsole(); printf("\033[?25h"); fflush(stdout); restoreConsole(); } } color_restore(); #ifndef _WIN32 fflush(stdout); #endif // corresponds to #ifndef (#ifndef _WIN32) myprintf("\nGoodbye after %1.3f seconds (%s)\n",(mtime()-g_start)/1000.0,timetohuman((uint32_t)((mtime()-g_start)/1000.0)).c_str()); exit(1); } // Convert argv to UTF-8 and replace \ with / #ifdef unix int main(int argc, const char** argv) { #else #ifdef _MSC_VER int wmain(int argc, LPWSTR* argw) { #else int main() { int argc=0; LPWSTR* argw=CommandLineToArgvW(GetCommandLine(), &argc); #endif // corresponds to #ifdef (#ifdef _MSC_VER) #ifdef _WIN32 /* Getting "real" Windows versions is a... real nightmare Nothing is easy, in Windows https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/ntexapi_x/kuser_shared_data/index.htm The dirtiest trick: getting from KUSER_SHARED_DATA founded @ 0x7ffe0000 (!) */ BYTE* kusershareddata=(BYTE*)0x7FFE0000; if ((*(ULONG*)(kusershareddata+0x26c))>=10) { if (flagdebug) myprintf("01291: ************ Windows 10 or later => keeping flagnoconsole |%d|\n",int(flagnoconsole)); } else { if (flagdebug) myprintf("01292: ************ Previous of Windows 10 => enforcing flagnoconsole=true\n"); flagnoconsole=true; } #endif // corresponds to #ifdef (#ifdef _WIN32) /// This is Windows: take care of parameters vector args(argc); libzpaq::Array argp(argc); for (int i=0; i= 6) && (vi.dwMinorVersion >= 1); #endif // corresponds to #ifdef (#ifdef _WIN32) // infact unused, too slow g_sse42=false; #if defined(_WIN64) int sse42; SSE42(sse42); if (sse42) g_sse42=true; #endif // corresponds to #if (#if defined(_WIN64)) Jidac jidac; pjidac=&jidac; int risultatoparametri=jidac.loadparameters(argc,argv); if (risultatoparametri>0) return risultatoparametri; int errorcode=0; try { errorcode=jidac.doCommand(); } catch (std::exception& e) { fflush(stdout); myprintf("01294: zpaqfranz error: %s\n", e.what()); errorcode=2; } fflush(stdout); if (g_fwritten!=g_fexpected) { myprintf("\n"); printbar('*'); myprintf("01295: Something STRANGE happened. Archive seems corrupt. Media full?\n"); myprintf("01296: WRITTEN BYTES %19s\n",migliaia(g_fwritten)); myprintf("01297: EXPECTED %19s\n",migliaia(g_fexpected)); printbar('*'); errorcode=2; } if (flagdebug) { int64_t dt_ram =jidac.get_dt_ram(); int64_t edt_ram =jidac.get_edt_ram(); /// myprintf("01298: RAM information: sizeof(DT) %s g_dt_ram %s\n",migliaia(sizeof(DT)),migliaia2(g_dt_ram)); myprintf("01299: internal count %12s ~%18s\n",migliaia(jidac.get_dt_count()), migliaia2(dt_ram)); myprintf("01300: external count %12s ~%18s\n",migliaia(jidac.get_edt_count()),migliaia2(jidac.get_edt_ram())); myprintf("01301: RAM for files' data (approx) ~%18s\n",migliaia(dt_ram+edt_ram)); } if (flagpause) { int thekey=0; myprintf("\n57597: Press any key to continue\n"); while ((!iskeypressed(thekey))) sleep(1); myprintf("\n"); fflush(stdout); } /// exit(0); if ((!flaghashdeep) && (!flagstdout) && (command!='L') && (command!='F') && (command!='.') && (!flagterse)) /// we need to make output compatible with hashdeep? { if (g_allocatedram<0) g_allocatedram=0; if (g_arrayram<0) g_arrayram=0; if ( !((command=='l') && (flag715)) ) { ///myprintf("62944: RAM: heap %s +array %s +files %s = %s\n",tohuman(g_allocatedram),tohuman2(g_arrayram),tohuman3(g_dt_ram),tohuman4(g_allocatedram+g_dt_ram+g_arrayram)); ///myprintf("01302: %1.3f seconds (%s) ", (mtime()-g_start)/1000.0,timetohuman((uint32_t)((mtime()-g_start)/1000.0)).c_str()); if (!flagnotrim) if (g_incomplete_version>0) { color_red(); ascii::Ascii font=ascii::Ascii(); font.print("incomplete"); myprintf("62378: Detected a 'gap' in the archive due to incomplete transaction(s) %s\n",migliaia(g_incomplete_version)); myprintf("62379: This means that the archive is corrupted (killed process? out of space?)\n"); myprintf("62380: Suggestion: use the trim command ASAP to remove the incomplete part,\n"); myprintf("62381: preventing the issue from spreading\n"); color_restore(); } string mem_heap=tohuman(g_allocatedram); myreplaceall(mem_heap," ",""); myreplaceall(mem_heap,"0.00B","0"); myreplaceall(mem_heap,".00B",""); string mem_array=tohuman(g_arrayram); myreplaceall(mem_array," ",""); myreplaceall(mem_array,"0.00B","0"); myreplaceall(mem_array,".00B",""); string mem_dt=tohuman(g_dt_ram); myreplaceall(mem_dt," ",""); myreplaceall(mem_dt,"0.00B","0"); myreplaceall(mem_dt,".00B",""); string mem_all=tohuman(g_allocatedram+g_dt_ram+g_arrayram); myreplaceall(mem_all," ",""); myreplaceall(mem_all,"0.00B","0"); myreplaceall(mem_all,".00B",""); if (flagverbose) myprintf("01302: %1.3fs (%s,heap %s|array %s|dt %s=>%s) ", (mtime()-g_start)/1000.0,timetohuman((uint32_t)((mtime()-g_start)/1000.0)).c_str(),mem_heap.c_str(),mem_array.c_str(),mem_dt.c_str(),mem_all.c_str()); else myprintf("01302: %1.3fs (%s,%s) ", (mtime()-g_start)/1000.0, timetohuman((uint32_t)((mtime()-g_start)/1000.0)).c_str(), mem_all.c_str()); if (command=='q') myprintf(" on VSS operation\n"); else { if (!flagnotrim) if (g_incomplete_version>0) { color_red(); myprintf(" *INCOMPLETE TRANS* "); color_restore(); errorcode=2; } if (errorcode==0) { color_green(); myprintf("(all OK)\n"); if (flagbig) bigok(); color_restore(); } else if (errorcode==1) { color_red(); myprintf("(with warnings)\n"); if (flagbig) bigwarning(); color_restore(); } else { color_red(); myprintf("(with errors)\n"); if (flagbig) bigerror(); color_restore(); } } } if (g_255) { myprintf("\n"); myprintf("01303: Seems %08d errors by path/filename too long (>255)\n", g_255); } if (errorcode>=2) { if (flagdebug2) myprintf("01304: call xcommand on errorcode>=2 %s\n",migliaia(errorcode)); xcommand(g_exec_error,g_exec_text); } else if (errorcode==1) { if (flagdebug2) myprintf("01305: call xcommand on errorcode==1\n"); xcommand(g_exec_warn,g_exec_text); } else { if (flagdebug2) myprintf("01306: call xcommand with a different errorcode (not 1, not 2) %d\n",errorcode); /// when adding multipart archive, and no errors, take the last filename if (g_archive!="") { g_exec_text=g_archive; if (flagdebug2) myprintf("01307: g_archive not null, setting g_exec_text to %s\n",g_exec_text.c_str()); } if (g_exec_ok!="") xcommand(g_exec_ok,g_exec_text); } } else { if (flagbig) { if (errorcode==0) { color_green(); bigok(); } else if (errorcode==1) { color_red(); bigwarning(); } else { color_red(); bigerror(); } color_restore(); } } if (g_output_handle!=0) fclose(g_output_handle); if (g_error_handle!=0) fclose(g_error_handle); #ifdef _WIN32 if (!flagnoconsole) { //// set back the console SetConsoleCP (g_ConsoleCP); SetConsoleOutputCP (g_ConsoleOutputCP); ///myprintf("01308: ConsoleCP %d ConsoleOutputCP %d\n",g_ConsoleCP,g_ConsoleOutputCP); } #endif // corresponds to #ifdef (#ifdef _WIN32) color_restore(); return errorcode; } /// 55.10, reworked. Not 255-shrink, no dirnameifalreadyexists int Jidac::utf() { if (files.size()!=1) { myprintf("01309! you can fix exactly ONE folder at time\n"); return 2; } if (!flagkill) myprintf("01310: Fix UTF-8 dry run (because no -kill)\n\n"); g_bytescanned=0; g_filescanned=0; g_worked=0; edt.clear(); for (unsigned i=0; i mydirs; unsigned int howmanyfiles=0; unsigned int longfiles=0; unsigned int longdirs=0; for (DTMap::iterator p=edt.begin(); p!=edt.end(); ++p) if (isdirectory(p->first)) { if (p->first.size()>250) { longdirs++; if (flagfix255) { myprintf("01311: TOO LONG %08d %Z\n",p->first.size(),p->first.c_str()); } } string thedir=p->first; string ansidir=purgeansi(forcelatinansi(utf8toansi(thedir)),true); //it is a path if (ansidir!=thedir) { if (flagverbose) { myprintf("01313: Dir candidate %Z\n",thedir.c_str()); } myreplace(thedir,includetrailingbackslash(files[0]),""); mydirs.push_back(thedir); } } else { if (p->first.size()>250) { longfiles++; if (flagfix255) { myprintf("01315: TOO LONG %08d %Z\n",p->first.size(),p->first.c_str()); } } string thefile=extractfilename(p->first); string ansifile=purgeansi(forcelatinansi(utf8toansi(thefile)),true); //it is a path if (thefile!=ansifile) { howmanyfiles++; } } myprintf("01317: UTF-8 dirs: %12s\n",migliaia(mydirs.size())); myprintf("01318: UTF-8 files: %12s\n",migliaia(howmanyfiles)); if (longdirs) myprintf("01319: LONG dirs: %12s\n",migliaia(longdirs)); if (longfiles) myprintf("01320: LONG files: %12s\n",migliaia(longfiles)); #if defined(_WIN32) if (!flaglongpath) if ((longdirs+longfiles)>0) { myprintf("\n"); myprintf("01321$ *** WINDOWS WARNING *** found long path. Suggestion: use -longpath switch\n"); } #endif // corresponds to #if (#if defined(_WIN32)) int errori=0; if (flagkill) { if (mydirs.size()>0) { myprintf("01322: First stage - try to fix (%s) folder names\n",migliaia(mydirs.size())); unsigned int renameddir=0; unsigned int i=0; while (i No son: ERROR renaming %Z => %Z\n",from.c_str(),sto.c_str()); printUTF8(from.c_str()); myprintf(" => %s\n",sto.c_str()); } errori++; } else { if (flagverbose) { myprintf("===========> No son: successfully renamed %Z => %Z\n",from.c_str(),sto.c_str()); } renameddir++; } } else { string from=includetrailingbackslash(files[0])+thedir; string nuovopadre=purgeansi(forcelatinansi(utf8toansi(thedir)),true); string sto=includetrailingbackslash(files[0])+nuovopadre; //it is a path if (myrename(from,sto)!=0) { if (flagverbose) { myprintf("===========> GURU renaming "); printUTF8(from.c_str()); myprintf(" => %s\n",sto.c_str()); } errori++; } else { if (flagverbose) { myprintf("===========> Successfully renamed father "); printUTF8(from.c_str()); myprintf(" => %s\n",sto.c_str()); myprintf("01327: Fixing the sons\n"); } renameddir++; unsigned int j=i+1; while (mypos(thedir,mydirs[j])==0) { myreplace(mydirs[j],includetrailingbackslash(thedir),includetrailingbackslash(nuovopadre)); j++; if (j==mydirs.size()) break; } j=i+1; while (mypos(nuovopadre,mydirs[j])==0) { if (flagverbose) { myprintf("01328: New son: %Z\n",mydirs[j].c_str()); } j++; if (j==mydirs.size()) break; } } } if (flagverbose) myprintf("\n\n\n"); i++; if (i>=mydirs.size()) break; } myprintf("01329: End of first stage, errors %s renamed %s\n",migliaia(errori),migliaia2(renameddir)); if ((errori>0) && (!flagforce)) { myprintf("01330! errors found and not -force: quit\n"); return 2; } if (howmanyfiles==0) { myprintf("01331: No files to be renamed, quit\n"); return 0; } myprintf("01332: Stage 2: rescan filesystem\n"); g_bytescanned =0; g_filescanned =0; g_worked =0; edt.clear(); for (unsigned ii=0; iifirst)) { string thefile=extractfilename(p->first); string ansifile=purgeansi(forcelatinansi(utf8toansi(thefile)),true); //it is a path if (thefile!=ansifile) { string from =includetrailingbackslash(extractfilepath(p->first))+thefile; string sto =includetrailingbackslash(extractfilepath(p->first))+ansifile; if (myrename(from,sto)!=0) { myprintf("===========> KAPUTT RENAMING file %Z => %s\n",from.c_str(),sto.c_str()); errori++; } else { if (flagverbose) { myprintf("===========> GOOD: successfully renamed %Z => %s\n",from.c_str(),sto.c_str()); } filerenamed++; } } } if (filerenamed==howmanyfiles) myprintf("01334: File renamed == howmanyfiles == %s : this is GOOD\n",migliaia(filerenamed)); else { myprintf("01335: ERROR: file renamed %s != howmanyfiles %s : this is BAD\n",migliaia(filerenamed),migliaia2(howmanyfiles)); errori++; } } } return errori; } /// LICENSE_START.3 /// a patched... main()! int unz(const char * archive,const char * key) { if (!archive) return 0; uint64_t until=0; bool index=false; myprintf("01336: PARANOID TEST: working on %s\n",archive); // Journaling archive state std::map bsize; // frag ID -> d block compressed size std::map unzdt; // filename -> date, attr, frags std::vector frag; // ID -> hash[20] size[4] data std::string last_filename; // streaming destination unsigned int zpaqvirtualfile=0; uint64_t ramsize=0; uint64_t csize=0; // expected offset of next non d block bool streaming=false, journaling=false; // archive type int64_t inizio=mtime(); uint64_t lavorati=0; // Decompress blocks unzInputFile in; // Archive in.open(archive, key); int64_t total_size=in.getfilesize(); unzDecompresser d; d.setInput(&in); ////unzOutputFile out; // streaming output bool done=false; // stop reading? bool firstSegment=true; while (!done && d.findBlock()) { unzBuf filename(65535); while (!done && d.findFilename(&filename)) { unzBuf comment(65535); d.readComment(&comment); unzverify_utf8(filename.s.c_str()); // Test for journaling or streaming block. They cannot be mixed. uint64_t jsize=0; // journaling block size in comment if (comment.s.size()>=4 && comment.s.substr(comment.s.size()-4)=="jDC\x01") { // read jsize = uncompressed size from comment as a decimal string unsigned i; for (i=0; i>32) unzerror("size in comment > 4294967295"); } if (i<1) unzerror("missing size in comment"); if (streaming) unzerror("journaling block after streaming block"); journaling=true; } else { if (journaling) unzerror("streaming block after journaling block"); if (index) unzerror("streaming block in index"); streaming=true; ///d.setOutput(&out); ///d.setOutput(); } /* if (streaming) myprintf("01337: Streaming\n"); if (journaling) myprintf("01338: journaling\n"); */ // Test journaling filename. The format must be // jDC[YYYYMMDDHHMMSS][t][NNNNNNNNNN] // where YYYYMMDDHHMMSS is the date, t is the type {c,d,h,i}, and // NNNNNNNNNN is the 10 digit first fragment ID for types c,d,h. // They must be in ascending lexicographical order. uint64_t date=0, id=0; // date and frag ID from filename char type=0; // c,d,h,i if (journaling) // di solito { if (filename.s.size()!=28) unzerror("filename size not 28"); if (filename.s.substr(0, 3)!="jDC") unzerror("filename not jDC"); type=filename.s[17]; if (!strchr("cdhi", type)) unzerror("type not c,d,h,i"); if (filename.s<=last_filename) unzerror("filenames out of order"); last_filename=filename.s; // Read date for (int i=3; i<17; ++i) { if (!isdigit(filename.s[i])) unzerror("non-digit in date"); date=date*10+filename.s[i]-'0'; } verify_date(date); // Read frag ID for (int i=18; i<28; ++i) { if (!isdigit(filename.s[i])) unzerror("non-digit in fragment ID"); id=id*10+filename.s[i]-'0'; } if (id<1 || id>4294967295llu) unzerror("fragment ID out of range"); } // Select streaming output file if (streaming && (firstSegment || filename.s!="")) { ///std::string fn=filename.s; /// out.open(fn.c_str()); } firstSegment=false; // Decompress fflush(stdout); unzBuf seg(jsize); if (journaling) d.setOutput(&seg); unzSHA1 sha1; d.setSHA1(&sha1); d.decompress(); if (journaling && seg.s.size()!=jsize) unzerror("incomplete output"); // Verify checksum char checksum[21]; d.readSegmentEnd(checksum); // if (!noeta) /// myprintf(""); if (checksum[0]==1) { if (memcmp(checksum+1, sha1.result(), 20)) unzerror("unzSHA1 mismatch"); // else myprintf("01339: OK"); } else if (checksum[0]==0) myprintf("01340: not checked"); else unzerror("invalid checksum type"); filename.s=""; // check csize at first non-d block if (csize && strchr("chi", type)) { if (csize!=unzoffset) { myprintf("01341: Z2: csize=%1.0f, offset=%1.0f\n",double(csize), double(unzoffset)); unzerror("csize does not point here"); } csize=0; } ///myprintf("=======================================\n"); // Get csize from c block const size_t len=seg.s.size(); if (type=='c') { if (len<8) unzerror("c block too small"); csize=unzget8(seg.s.data()); lavorati+=csize; if (flagnoeta==false) { print_datetime(); myprintf("%20s (%20s)\n", migliaia(lavorati),migliaia(csize)); } // test for end of archive marker if (csize>>63) { myprintf("01342: Incomplete transaction at end of archive (OK)\n"); done=true; } else if (index && csize!=0) unzerror("nonzero csize in index"); // test for rollback if (until && date>until) { myprintf("01343: Rollback: %1.0f is after %1.0f\n",double(date), double(until)); done=true; } // Set csize to expected offset of first non d block // assuming 1 more byte for unread end of block marker. csize+=in.tell()+1; } // Test and save d block if (type=='d') { if (index) unzerror("d block in index"); bsize[id]=in.tell()+1-unzoffset; // compressed size /// myprintf(" %u -> %1.0f ", bsize[id], double(seg.s.size())); // Test frag size list at end. The format is f[id..id+n-1] fid n // where fid may be id or 0. sizes must sum to the rest of block. if (len<8) unzerror("d block too small"); const char* end=seg.s.data()+len; // end of block uint32_t fid=unzget4(end-8); // 0 or ID const uint32_t n=unzget4(end-4); // number of frags if (fid==0) fid=id; ///if (!noeta) ///myprintf("."); ///myprintf("[%u..%u) ", fid, fid+n); if (fid!=id) unzerror("missing ID"); if (n>(len-8)/4) unzerror("frag list too big"); uint64_t sum=0; // computed sum of frag sizes for (unsigned j=0; j=frag.size() || frag[id+i].size()<24) unzerror("no matching d block"); else if (frag[id+i].substr(0, 24)!=std::string(p, p+24)) unzerror("frag size or hash mismatch"); /// sum+=unzget4(p+20); p+=24; } ///myprintf("-> %u OK\n", sum); } // Test i blocks and save files to extract. Format is: // date filename 0 na attr[0..na) ni ptr[0..ni) (to update) // 0 filename (to delete) // Date is 64 bits in YYYYMMDDHHMMSS format. if (type=='i') { const char* p=seg.s.data(); const char* end=p+seg.s.size(); while (p=0 && *p<32) myprintf("^%c", *p+64); /// else putchar(*p); fn+=*p++; } if (p==end) unzerror("missing NUL in filename"); ++p; if (fn.size()>65535) unzerror("filename size > 65535"); unzverify_utf8(fn.c_str()); bool isvirtual=unziszpaqfranzvirtualfile(fn); if (isvirtual) zpaqvirtualfile++; // read attr if ((f.date>0) && (!isvirtual)) { if (end-p<4) unzerror("missing attr size"); uint32_t na=unzget4(p); p+=4; if (na>65535) unzerror("attr size > 65535"); ///myprintf("2 NA VALE %d\n",na); if (na>FRANZOFFSETV1) // houston we have a FRANZBLOCK? { assert((na-8)=frag.size()) unzerror("frag ID out of range"); if (frag[a]=="") unzerror("missing frag data"); } } } /// UBUNTU if (!isvirtual) unzdt[fn]=f; /// unzdt.insert(std::pair(fn,f)); } } ///myprintf("\r"); ///print_datetime(); myprintf("01344: Remaining %3s %% frags %12s (RAM used ~ %15s)\r",migliaia2(100-(unzoffset*100/(total_size+1))),migliaia(frag.size()),migliaia2(ramsize)); } // end while findFilename unzoffset=in.tell(); } // end while findBlock myprintf("\n"); myprintf("01345: %s bytes of %s tested\n", migliaia(in.tell()), archive); printbar('-'); myprintf("01346: Second stage: rebuilding hashes\n"); std::vector mappadt; std::vector vf; std::map::iterator p; int64_t hashed=0; int64_t iniziocalcolo=mtime(); int unknownfranzo=0; for (p=unzdt.begin(); p!=unzdt.end(); ++p) mappadt.push_back(p); std::sort(mappadt.begin(), mappadt.end(),unzcompareprimo); for (unsigned int i=0; isecond; if (f.date) { uint64_t size=0; for (uint32_t k=0; i0 && f.ptr[k]=24) size+=unzget4(frag[f.ptr[k]].data()+20); if (!index) { std::string fn=p->first; if ((!isads(fn)) && (!iszfs(fn)) && (!isdirectory(fn))) { int64_t startrecalc=mtime(); string hashstoredinzpaq=""; string myhashtype=""; string mycrc32=""; int64_t mycreationtime=0; int64_t myaccesstime=0; bool myisordered=false; int myversion=0; franz_posix* myposix=NULL; bool myisadded=false; int unzfranzotype=decode_franz_block(isdirectory(p->first),p->second.sha1hex, myhashtype, hashstoredinzpaq, mycrc32, mycreationtime, myaccesstime, myisordered, myversion, myposix,myisadded); if ((unzfranzotype==FRANZO_XXHASH64) ||(unzfranzotype==FRANZO_WINHASH64)||(unzfranzotype==FRANZO_XXHASH64B)) { uint64_t myseed = 0; XXHash64 myhash(myseed); for (uint32_t k=0; ksecond.sha1decompressedhex,FRANZOFFSETV3,"%s",bin2hex_64(myhash.hash()).c_str()); } else if ((unzfranzotype==FRANZO_SHA_1)||(unzfranzotype==FRANZO_SHA_1B)) { unzSHA1 mysha1; for (uint32_t k=0; ksecond.sha1decompressedhex+j*2,FRANZOFFSETV3-j*2,"%02X", (unsigned char)sha1result[j]); p->second.sha1decompressedhex[40]=0x0; } else if ((unzfranzotype==FRANZO_SHA_256)||(unzfranzotype==FRANZO_SHA_256B)) { unzSHA256 mysha256; for (uint32_t k=0; ksecond.sha1decompressedhex+j*2,FRANZOFFSETV3-j*2,"%02X", (unsigned char)sha256result[j]); p->second.sha1decompressedhex[64]=0x0; } else if ((unzfranzotype==FRANZO_BLAKE3)||(unzfranzotype==FRANZO_BLAKE3B)) { blake3_hasher hasher; blake3_hasher_init(&hasher); for (uint32_t k=0; ksecond.sha1decompressedhex+j*2,FRANZOFFSETV3-j*2,"%02X", (unsigned char)output[j]); p->second.sha1decompressedhex[64]=0x0; } else if ((unzfranzotype==FRANZO_SHA3)||(unzfranzotype==FRANZO_SHA3B)) { SHA3 hasher; for (uint32_t k=0; ksecond.sha1decompressedhex,FRANZOFFSETV3,"%s",hasher.getHash().c_str()); p->second.sha1decompressedhex[64]=0x0; } else if ((unzfranzotype==FRANZO_MD5) || (unzfranzotype==FRANZO_MD5B)) { MD5 hasher; for (uint32_t k=0; ksecond.sha1decompressedhex,0,64); snprintf(p->second.sha1decompressedhex,FRANZOFFSETV3,"%s",hasher.getHash().c_str()); } else if ((unzfranzotype==FRANZO_XXH3)||(unzfranzotype==FRANZO_XXH3B)) { XXH3_state_t state128; (void)XXH3_128bits_reset(&state128); for (uint32_t k=0; ksecond.sha1decompressedhex,FRANZOFFSETV3,"%s",bin2hex_128(myhash.high64,myhash.low64).c_str()); } else if (unzfranzotype==FRANZO_WHIRLPOOL) { NESSIEstruct hasher; NESSIEinit(&hasher); for (uint32_t i=0; isecond.sha1decompressedhex,sizeof(p->second.sha1decompressedhex),"%s",nessie.c_str()); } else if ((unzfranzotype==FRANZO_HIGHWAY64) || (unzfranzotype==FRANZO_HIGHWAY128) || (unzfranzotype==FRANZO_HIGHWAY256)) { HighwayHashCat highway64state; uint64_t key[4] = {1, 2, 3, 4}; HighwayHashCatStart(key,&highway64state); for (uint32_t i=0; isecond.sha1decompressedhex,sizeof(p->second.sha1decompressedhex),"%s",bin2hex_64(hash).c_str()); } if (unzfranzotype==FRANZO_HIGHWAY128) { uint64_t hash[2]; HighwayHashCatFinish128(&highway64state,hash); string temp=binarytohex((const unsigned char*)hash,16); snprintf(p->second.sha1decompressedhex,sizeof(p->second.sha1decompressedhex),"%s",temp.c_str()); } if (unzfranzotype==FRANZO_HIGHWAY256) { uint64_t hash[4]; HighwayHashCatFinish256(&highway64state,hash); string temp=binarytohex((const unsigned char*)hash,32); snprintf(p->second.sha1decompressedhex,sizeof(p->second.sha1decompressedhex),"%s",temp.c_str()); } } else { myprintf("\n"); myprintf("01347: WARN UNKNOWN UNZFRANZOTYPE %d (maybe newer zpaqfranz archive?)\n",unzfranzotype); unknownfranzo++; } vf.push_back(p); if (flagverbose) myprintf("01348: File <<%-20s>> %08u of %08lld (%20s) %1.3f %s\n",myhashtype.c_str(),i+1,(int64_t)mappadt.size(),migliaia(size),(mtime()-startrecalc)/1000.0,fn.c_str()); } } } } if (unknownfranzo>0) { myprintf("\n"); myprintf("01349$ *** WARNING UNKNOWN FRANZOTYPE %s. Maybe the archive is done with a newer zpaqfranz version?\n",migliaia(unknownfranzo)); } std::sort(vf.begin(), vf.end(), unzcomparesha1hex); int64_t finecalcolo=mtime(); myprintf("01350: Calc time (hash rebuild from fragments) %f hashed bytes %s\n",(finecalcolo-iniziocalcolo)*0.001,migliaia(hashed)); printbar('-'); myprintf("01351: Third stage"); if (flagverify || flagparanoid) myprintf(": with check against filesystem"); myprintf("\n"); ////////////////////////////// /////// now some tests /////// if possible check SHA1 into the ZPAQ with SHA1 extracted with SHA1 of the current file unsigned int status_e=0; unsigned int status_nohash=0; unsigned int status_filenotfound=0; unsigned int status_1=0; unsigned int status_2=0; ///int64_t rihashati=0; g_dimensione=0; std::string hashfromfile; int64_t starthash=mtime(); for (unsigned i=0; ifirst; if (finalfile!="VFILE-l-filelist.txt") { string hashstoredinzpaq =""; string myhashtype =""; string mycrc32 =""; int64_t mycreationtime=0; int64_t myaccesstime=0; bool myisordered=false; int myversion=0; franz_posix* myposix=NULL; bool myisadded=false; int myfranzo=decode_franz_block(isdirectory(p->first),p->second.sha1hex, myhashtype, hashstoredinzpaq, mycrc32,mycreationtime,myaccesstime,myisordered,myversion,myposix,myisadded); if (myfranzo==-1) error("33351: archive use an unknown hasher (maybe a more advanced zpaqfraz)!"); string unzfranzostring=""; if (flagverify || flagparanoid) { MAPPATIPOHASH::iterator a=g_mappatipohash.end(); for (MAPPATIPOHASH::iterator pp=g_mappatipohash.begin(); pp!=g_mappatipohash.end(); ++pp) if (myhashtype==pp->second.hashname) { /// myprintf("01352: Faccio test 1 %s\n",pp->second.hashname.c_str()); a=pp; break; } if (a!=g_mappatipohash.end()) { unzfranzostring=a->second.hashname; myreplace(unzfranzostring,"+CRC-32",""); if (!fileexists(p->first)) { if (flagdebug2) myprintf("01353: FILE NOT FOUND on %s: FILE %s\n",myhashtype.c_str(),p->first.c_str()); status_filenotfound++; } else { if (flagdebug3) myprintf("01354: franz_do_hash\n"); franz_do_hash dummy(a->first); if (flagdebug3) myprintf("01355: filehash on %s\n",p->first.c_str()); hashfromfile=dummy.filehash( p->first.c_str(),true,starthash,hashed); } } else { myprintf("01356: Cannot find hasher %s\n",myhashtype.c_str()); } } std::string hashdecompresso=p->second.sha1decompressedhex; if (flagverify || flagparanoid) if (hashfromfile=="") status_nohash++; bool localok=true; if (!hashstoredinzpaq.empty()) { if (hashstoredinzpaq==hashdecompresso) status_1++; else localok=false; } if (!hashfromfile.empty()) { if (hashfromfile==hashdecompresso) status_2++; else localok=false; } if ((!localok) || (flagverbose)) if (unzfranzostring!="") { myprintf("01357: %14s: %s\n",myhashtype.c_str(),p->first.c_str()); myprintf("01358: DECOMPRESSED : %s\n",hashdecompresso.c_str()); if (!hashstoredinzpaq.empty()) myprintf("01359: STORED IN ZPAQ: %s\n",hashstoredinzpaq.c_str()); if (!hashfromfile.empty()) myprintf("01360: FROM FILE : %s\n",hashfromfile.c_str()); myprintf("\n"); if (!localok) status_e++; } } } int64_t fine=mtime(); unsigned int total_files=vf.size(); myprintf("\n"); myprintf("01361: SUMMARY : %12.2f (total time)\n",(fine-inizio)/1000.0); if (zpaqvirtualfile) myprintf("01362: Virtual : %12s (skipped, does not exists in 7.15)\n",migliaia(zpaqvirtualfile)); myprintf("01363: Total : %12s\n",migliaia(total_files)); if (status_e>0) myprintf("01364! ERRORS : %12s (ERROR: something WRONG)\n",migliaia(status_e)); if (status_nohash>0) myprintf("01365$ WARNING : %12s (UNKNOWN:cannot verify nohash)\n",migliaia(status_nohash)); if (status_filenotfound>0) myprintf("01366$ WARNING : %12s (UNKNOWN:file not found)\n",migliaia(status_filenotfound)); if (status_1>0) myprintf("01367: GOOD : %12s of %12s (stored=decompressed)\n",migliaia(status_1),migliaia2(total_files)); if (status_2>0) myprintf("01368: SURE : %12s of %12s (stored=decompressed=file on disk)\n",migliaia(status_2),migliaia(total_files)); if (status_e==0) { if (status_nohash+status_filenotfound) myprintf("01369: Unknown (cannot verify)\n"); else { if (flagverify || flagparanoid) myprintf("01370: All OK (paranoid test with check against filesystem)\n"); else myprintf("01371: All OK (paranoid test)\n"); } } else { myprintf("01372! WITH ERRORS\n"); return 2; } return 0; } /// LICENSE_END.3 /// /* ZPAQ does not store blocks of zeros at all. This means that they are not, materially, in the file, and therefore cannot be used to calculate the CRC-32. This is a function capable of doing it, even for large sizes (hundreds of gigabytes or more in the case of thick virtual machine disks), up to ~9.000TB The function I wrote split a number into its powers of 2, takes the CRC-32 code from a precomputed table, and finally combines them. It's not the most efficient method (some 10-20 iterations are typically needed), but it's still decent */ const uint32_t zero_block_crc32[54] = { 0xD202EF8D,0x41D912FF,0x2144DF1C,0x6522DF69,0xECBB4B55,0x190A55AD,0x758D6336,0xC2A8FA9D, 0x0D968558,0xB2AA7578,0xEFB5AF2E,0xF1E8BA9E,0xC71C0011,0xD8F49994,0xAB54D286,0x011FFCA6, 0xD7978EEB,0x7EE8CDCD,0xE20EEA22,0x75660AAC,0xA738EA1C,0x8D89877E,0x1147406A,0x1AD2BC45, 0xA47CA14A,0x59450445,0xB2EB30ED,0x80654151,0x2A0E7DBB,0x6DB88320,0x5B64C2B0,0x4DBDF21C, 0xD202EF8D,0x41D912FF,0x2144DF1C,0x6522DF69,0xECBB4B55,0x190A55AD,0x758D6336,0xC2A8FA9D, 0x0D968558,0xB2AA7578,0xEFB5AF2E,0xF1E8BA9E,0xC71C0011,0xD8F49994,0xAB54D286,0x011FFCA6, 0xD7978EEB,0x7EE8CDCD,0xE20EEA22,0x75660AAC,0xA738EA1C,0x8D89877E }; uint32_t crc32ofzeroblock(uint64_t i_size) { /// assert(i_size<9.007.199.254.740.992); //8D89877E 2^53 9.007.199.254.740.992 if (i_size==0) return 0; uint32_t mycrc=0; unsigned int i=0; while (i_size > 0) { if ((i_size%2)==1) mycrc=crc32_combine(mycrc,zero_block_crc32[i],1< chunk_name; vector chunk_size; const string part0=subpart(i_archive, 0); for (unsigned i=1; ;i++) { const string parti=subpart(i_archive, i); if (i>1 && parti==part0) break; if (!fileexists(parti)) break; int64_t dimensione=prendidimensionefile(parti.c_str()); if (dimensione<0) break; chunk_size.push_back(dimensione); chunk_name.push_back(parti); } if (chunk_name.size()==0) { myprintf("01374! Something strange: cannot find archive chunks\n"); return 2; } int64_t total_size=0; for (int unsigned i=0;i>\n",(int)i,migliaia(chunk_size[i]),chunk_name[i].c_str()); total_size+=chunk_size[i]; } printbar('-'); myprintf("01376: Total %s %20s (%s)\n",migliaia2(chunk_name.size()),migliaia(total_size),tohuman(total_size)); if (files.size()!=1) { myprintf("01377: WARN exactly one file as output for merge needed\n"); return 1; } string outfile=files[0]; if (fileexists(outfile)) if (!flagforce) { myprintf("01378: outfile exists, and no -force. Quit %s\n",outfile.c_str()); return 1; } int64_t spazio=getfreespace(outfile); myprintf("01379: Outfile <<%s>>\n",outfile.c_str()); myprintf("01380: Free space %20s\n",migliaia(spazio)); myprintf("01381: Needed %20s\n",migliaia(total_size)); if (spazio kind %d\n",sorgente_nome.c_str(),err); return 2; } size_t readSize; int64_t chunk_readed=0; int64_t chunk_written=0; while ((readSize = fread(buffer, 1, blockSize, inFile)) > 0) { int64_t written=fwrite(buffer,1,readSize,outFile); chunk_written+=written; chunk_readed+=readSize; donesize+=written; if (flagverify) (void)XXH3_128bits_update(&state128, buffer, readSize); avanzamento(donesize,total_size,startcopy); } fclose(inFile); if (flagverbose) myprintf("01386: Chunk %08d R %20s W %20s E %20s\n",(int)i,migliaia(chunk_readed),migliaia2(chunk_written),migliaia3(chunk_size[i])); if ((chunk_readed!=chunk_written) || (chunk_readed!=chunk_size[i])) { myprintf("01387: GURU on chunk %d Read, Write, Expec not equal!\n",i); return 1; } } fclose(outFile); myprintf("01388: Done\n"); myprintf("01389: Written %20s\n",migliaia(donesize)); myprintf("01390: Expected %20s\n\n",migliaia(total_size)); if (donesize!=total_size) { myprintf("01391: GURU bytes written does not match expected\n"); return 1; } if (flagverify) { myprintf("01392: -flagverify: double check...\n"); XXH128_hash_t myhash=XXH3_128bits_digest(&state128); char risultato[33]; snprintf(risultato,sizeof(risultato),"%s",bin2hex_128(myhash.high64,myhash.low64).c_str()); int64_t startverify=mtime(); g_dimensione=0; if (flagdebug3) myprintf("01393: franz_do_hash\n"); franz_do_hash dummy("XXH3"); if (flagdebug3) myprintf("01394: filehash on %s\n",outfile.c_str()); string hashreloaded=dummy.filehash(outfile,false,startverify,total_size); ///string hashreloaded=xxhash_calc_file(outfile.c_str(),false,dummycrc32,startverify,total_size,io_lavorati,thefilesize); myprintf("01395: Expected XXH3 hash of the output file %s\n",risultato); myprintf("01396: Calculated XXH3 hash of the output file %s\n",hashreloaded.c_str()); if (hashreloaded!=risultato) { myprintf("01397: GURU hash of output file does not match!\n"); return 1; } } return 0; } int Jidac::test() { archive=getbackupnameifany(archive); if ((files.size()>0)) { if (flagquick) myprintf("01398: -quick and dirty (only date/size) test\n"); else { if (flagchecksum || flagverify || flagparanoid) myprintf("01399: SHA-1-chunked verify+HASH checksum\n"); else myprintf("01400: SHA-1-chunked verify\n"); } return testverify(); } if (flagparanoid) { if (tofiles.size()!=1) { myprintf("01401! -paranoid needs a -to\n"); return 2; } uint64_t tofoldersize=0; uint32_t tofoldernumber=0; uint32_t tofolderfolder=0; uint32_t tofolderlongfiles=0; if (getfoldersize(tofiles[0],tofoldersize,tofoldernumber,tofolderfolder,tofolderlongfiles)) if (tofoldersize>0) { myprintf("01402$ WARNING the folder <<%Z>> contain %s bytes\n\n\n\n", tofiles[0].c_str(),migliaia(tofoldersize)); if (!getcaptcha("withoutmercy","Extract-check-delete without confirmation")) return 1; } return extract(); } int64_t starttest=mtime(); flagtest=true; summary=1; int read_errors=0; const int64_t sz=read_archive(NULL,archive.c_str(),&read_errors); if (read_errors>0) myprintf("65757! cannot read_archive (%s) THIS IS VERY BAD!!!\n",migliaia(read_errors)); if (sz<1) error("archive not found"); for (unsigned i=0; i=ht.size()) error("block start too high"); if (i>0 && block[i].start0 && block[i].start==block[i-1].start) error("empty block"); if (i>0 && block[i].offset0 && block[i-1].offset+block[i-1].bsize>block[i].offset) error("overlapping blocks"); } ///myprintf("01403: franz: fine test blocchi\n"); // Label files to extract with data=0. ExtractJob job(*this); int total_files=0; for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) { p->second.data=-1; // skip if (p->second.date && p->first!="") { const string fn=rename(p->first); /// myprintf("--------------------> %s\n",fn.c_str()); const bool isdir=p->first[p->first.size()-1]=='/'; if (isdir) // update directories later p->second.data=0; else if (block.size()>0) { // files to decompress p->second.data=0; unsigned lo=0, hi=block.size()-1; // block indexes for binary search for (unsigned i=0; p->second.data>=0 && isecond.ptr.size(); ++i) { unsigned j=p->second.ptr[i]; // fragment index ///myprintf("01404: Fragment index %lld\n",j); if (j==0 || j>=ht.size() || ht[j].usize<-1) { fflush(stdout); printUTF8(p->first.c_str()); myprintf(": 3 bad frag IDs, skipping...\n"); p->second.data=-1; // skip continue; } assert(j>0 && j=block.size() || j=block[lo+1].start)) { lo=0; // find block with fragment j by binary search hi=block.size()-1; while (lolo); assert(mid<=hi); if (j=0 && lo=block[lo].start); assert(lo+1==block.size() || jfirst.c_str()); } } ++total_files; job.total_size+=p->second.size; } } // end if selected } // end for /// dimtotalefile=job.total_size; myprintf("01405: To be checked %s in %s files (%d threads)\n",migliaia(job.total_size), migliaia2(total_files), howmanythreads); vector tid(howmanythreads); if (howmanythreads==1) { if (flagverbose) myprintf("01406: monothread decompress (test)\n"); decompressThread(&job); } else { for (unsigned i=0; ifirst); if (p->second.data>=0 && p->second.date && fn!="" && fn[fn.size()-1]!='/') { ++extracted; if (p->second.ptr.size()!=unsigned(p->second.data)) { fflush(stdout); if (++errors==1) myprintf( "\n57113: Failed (extracted/total fragments, file):\n"); myprintf("01407! UJO %u/%u %Z\n", int(p->second.data), int(p->second.ptr.size()),fn.c_str()); } } } if (errors>0) { fflush(stdout); myprintf( "\nChecked %u of %u files OK (%u errors)" " using %1.3f MB x %d threads\n", extracted-errors, extracted, errors, job.maxMemory/1000000, int(tid.size())); } else myprintf("01408: 7.15 stage time %10.2f no error detected (RAM ~%s), try CRC-32 (if any)\n", (mtime()-starttest)/1000.0,tohuman((int64_t)(tid.size()*job.maxMemory))); //// OK now check against CRC32 and the entire World (if any) int64_t startverify=mtime(); sort(g_crc32.begin(),g_crc32.end(),comparecrc32block); unsigned int status_e =0; //all kinds of error unsigned int status_e_hash =0; //errors on hashes by file unsigned int status_e_crc =0; //errors on crcs by file unsigned int status_e_blocks =0; //errors on crcs by blocks unsigned int status_0 =0; unsigned int status_1 =0; uint32_t checkedfiles =0; uint32_t uncheckedfiles =0; unsigned int parti =1; int64_t lavorati =0; uint64_t dalavorare =0; uint32_t currentcrc32 =0; uint32_t crc32stored; uint32_t triple_ok =0; uint32_t triple_error =0; /// uint32_t missing_files =0; /// uint32_t different_size =0; vector filestobecrced; for (unsigned int i=0;isecond.franz_block, myhashtype, myhash, mycrc32,mycreationtime,myaccesstime,myisordered,myversion,myposix,myisadded); crc32stored=crchex2int(mycrc32.c_str()); } if (flagdebug3) { myprintf("01411: MYhashtype %s\n",myhashtype.c_str()); myprintf("01412: Myhash %s\n",myhash.c_str()); myprintf("01413: Mycrc32 %s\n",mycrc32.c_str()); myprintf("\n"); } /// Houston, we have something that start with a sequence of zeros, let's compute the missing CRC if (it.crc32start>0) { uint64_t holesize=it.crc32start; uint32_t zerocrc =crc32zeros(holesize); currentcrc32 =crc32_combine(currentcrc32, zerocrc,holesize); lavorati +=holesize; zeroedblocks +=holesize; howmanyzero++; } currentcrc32=crc32_combine(currentcrc32, it.crc32,it.crc32size); lavorati+=it.crc32size; if ((i+1)second.size) { ///different_size++; triple_error++; if (flagverbose) { myprintf("01416: ERROR: expected %s <> %s <<%Z>>\n", migliaia(p->second.size),migliaia2(prendidimensionefile(filedefinitivo.c_str())),filedefinitivo.c_str()); } } else { filestobecrced.push_back(filedefinitivo); p->second.file_crc32=currentcrc32; } } else { triple_error++; if (flagverbose) { myprintf("01417: ERROR: cannot find <<%Z>>\n",filedefinitivo.c_str()); /// missing_files++; } } /* else { franz_do_hash dummyquick2("CRC-32"); if (flagdebug3) myprintf("01418: filehash CRC-32 on %s\n",filedefinitivo.c_str()); g_dimensione=0; string crcfromfilesystem=dummyquick2.filehash(filedefinitivo,false,startverify,prendidimensionefile(filedefinitivo.c_str())); if (crcfromfilesystem!="") { uint32_t fromfilesystem=crchex2int(crcfromfilesystem.c_str()); if (flagdebug3) myprintf("01419: stored %08X decompressed %08X from filesystem %08X\n",crc32stored,currentcrc32,fromfilesystem); if (fromfilesystem==currentcrc32) { if (flagdebug3) myprintf("01420: Triple == %08X for %s\n",fromfilesystem,filedefinitivo.c_str()); triple_ok++; } else { myprintf("01421: CRC-32 stored %08X decomp %08X file %08X <<",crc32stored,currentcrc32,fromfilesystem); printUTF8(filedefinitivo.c_str()); myprintf(">>\n"); triple_error++; } } } */ } else status_1++; } else { if (crc32stored!=0) { myprintf("01422: ERROR: STORED CRC-32 %08X != DECOMPRESSED %08X (ck %08d) %s\n",crc32stored,currentcrc32,parti,filedefinitivo.c_str()); status_e_blocks++; } } } else { // we have and old style ZPAQ without CRC32 uncheckedfiles++; ///myprintf("01423: CRC32: %08X %08X (parti %08d) %s\n",currentcrc32,chekkone,parti,filedefinitivo.c_str()); } parti=1; currentcrc32=0; i++; } myprintf("\n"); myprintf("01424: CRC-32 time %14.2fs\n",(mtime()-startverify)/1000.0); myprintf("01425: Blocks %19s (%12s)\n",migliaia(dalavorare),migliaia2(g_crc32.size())); myprintf("01426: Zeros %19s (%12s) %f s\n",migliaia(zeroedblocks),migliaia2(howmanyzero),(g_zerotime/1000.0)); myprintf("01427: Total %19s speed %s/s (%s/s)\n",migliaia(dalavorare+zeroedblocks),migliaia2((int64_t)((dalavorare+zeroedblocks)/((mtime()-startverify+1)/1000.0))),tohuman((int64_t)((dalavorare+zeroedblocks)/((mtime()-startverify+1)/1000.0)))); if (checkedfiles>0) myprintf("01428: Checked : %08d of %08d (zpaqfranz)\n",checkedfiles,total_files); if (uncheckedfiles>0) { myprintf("01429: UNcheck : %08d of %08d (zpaq 7.15?)\n",uncheckedfiles,total_files); status_0=uncheckedfiles; } if (status_e_hash) myprintf("01430: ERRORS HASH : %08d (ERROR verifyng hash from disk)\n",status_e_hash); if (status_e_crc) myprintf("01431: ERRORS CRC FI : %08d (ERROR verifyng CRC-32 from disk)\n",status_e_crc); if (status_e_blocks) myprintf("01432: ERRORS : %08d (ERROR in CRC-32, SHA-1 collisions?)\n",status_e_blocks); if (flagcrc32) { myprintf("01433: Triple checking CRC-32 on %s files (%s)\n",migliaia(filestobecrced.size()),tohuman(dalavorare+zeroedblocks)); vector > crc32_pair; int64_t starttriple=mtime(); franzparallelhashfiles("CRC-32",dalavorare+zeroedblocks,filestobecrced,false,crc32_pair); printbar(' '); myprintf("01434: Time doing CRC-32 %14.2fs\n",(mtime()-starttriple)/1000.0); /// for (int i=0;ifirst.c_str()); ///seppuku(); } else { uint32_t crc32fromfilesystem =crchex2int(crc32_pair[i].first.c_str()); if (p->second.file_crc32==crc32fromfilesystem) { triple_ok++; if (flagdebug3) myprintf("01438: OK SOURCE %08d %s %s\n",(int)i,crc32_pair[i].first.c_str(),crc32_pair[i].second.c_str()); } else { triple_error++; if (flagverbose) { myprintf("01439: KAPUTT CRC-32 expected %08X founded %08X %s\n", p->second.file_crc32, crc32fromfilesystem, crc32_pair[i].second.c_str()); } } } } color_green(); myprintf("01440: Triple OK : %08d (CRC-32 stored, decompressed and filesystem)\n",triple_ok); if (triple_error) color_red(); myprintf("01441: Triple ERRORS : %08d (-crc32 failed against filesystem)\n",triple_error); color_restore(); } status_e = status_e_hash+status_e_crc+status_e_blocks+triple_error; if (status_e) printbar('-'); if (status_0) myprintf("01442$ WARNING : %08d (Cannot say anything)\n",status_0); if (status_1) myprintf("01443: GOOD : %08d of %08d (stored=decompressed)\n",status_1,total_files); if (status_e==0) { if (status_0) myprintf("01444: VERDICT : UNKNOWN (Cannot say anything)\n"); else myprintf("01445: VERDICT : OK (CRC-32 stored vs decompressed)\n"); } else { myprintf("01446: WITH ERRORS\n"); errors=2; } if (flagverify) { printbar('+'); myprintf("01447: Re-testing (hashing) from filesystem (-verify) if possible\n"); errors+=verify(false); } if (flagcollision) collision(true); /* if ((searchfrom!="") || (replaceto!="")) { myprintf("600300: due to -search/replace fixing the filenames\n"); rename_a_dtmap(dt); } uint64_t howmanyfiles =0; g_bytescanned =0; g_filescanned =0; g_worked =0; files_count.clear(); edt.clear(); for (unsigned i=0;i>\n",migliaia((int64_t)files_count[i]),files[i].c_str()); printbar('-'); myprintf("01450: Total files found: %s\n", migliaia((int64_t)edt.size())); myprintf("\n"); if (flagdebug3) { for (DTMap::iterator p=edt.begin(); p!=edt.end(); ++p) myprintf("01451: EDT %s\n",p->first.c_str()); printbar('-'); for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) myprintf("01452: DT %s\n",p->first.c_str()); } vector filelist; DTMap filelist_externalnotinzpaq; DTMap filelist_inzpaqnotinexternal; DTMap filelist_both; myprintf("01453: Comparing External to ZPAQ\n"); for (DTMap::iterator p=edt.begin(); p!=edt.end(); ++p) { DTMap::iterator a=dt.find(rename(p->first)); if (a==dt.end()) filelist_externalnotinzpaq[p->first]=p->second; else filelist_both[p->first]=p->second; } myprintf("01454: Comparing ZPAQ to External\n"); for (DTMap::iterator p=dt.begin(); p!=dt.end(); ++p) { string filename=rename(p->first); ///myprintf("01455: cerco (da dt) %s\n",filename.c_str()); DTMap::iterator a=edt.find(filename); if (a==edt.end()) { /// myprintf("01456: UNO in dt not in edt %s\n",p->first.c_str()); filelist_inzpaqnotinexternal[p->first]=p->second; } else { /// myprintf("01457: DUE in edt AND in dt %s\n",p->first.c_str()); filelist_both[p->first]=p->second; } } myprintf("01458: External not in ZPAQ %s\n",migliaia(filelist_externalnotinzpaq.size())); myprintf("01459: Internal not on filesystem %s\n",migliaia(filelist_inzpaqnotinexternal.size())); myprintf("01460: Files both %s\n",migliaia(filelist_both.size())); vector filestobecrced; int64_t tobetested=0; int missingcrc=0; int ok_directory =0; int kaputt_directory=0; int different_size =0; for (DTMap::iterator p=filelist_both.begin(); p!=filelist_both.end(); ++p) { string filename=rename(p->first); p->second.hexcrc32 =""; p->second.file_crc32 =0; p->second.expectedsize =-1; // flag not checked if (isdirectory(p->first)) { bool risultato=exists(filename); myprintf("01461: p->first isdirectory, check exists %d\n",(int)risultato); if (risultato) { ok_directory++; p->second.expectedsize =1; // flag checked } else { kaputt_directory++; p->second.expectedsize =0; // flag checked } } else { string myhashtype =""; string myhash =""; string mycrc32 =""; int64_t mycreationtime =0; int64_t myaccesstime =0; bool myisordered =false; int myversion =0; franz_posix* myposix =NULL; bool myisadded =false; string hashfromfile=""; decode_franz_block(false,p->second.franz_block, myhashtype, myhash, mycrc32, mycreationtime, myaccesstime, myisordered, myversion, myposix,myisadded); tobetested+=p->second.size; p->second.outputname=filename; if (mycrc32!="") { p->second.file_crc32 =crchex2int(mycrc32.c_str()); p->second.hexcrc32 =mycrc32; if (prendidimensionefile(filename.c_str())!=p->second.size) { p->second.expectedsize =0; // flag checked myprintf("01462: prendidimensionefile %s <> p second size %s\n",migliaia(prendidimensionefile(filename.c_str())),migliaia2(p->second.size)); different_size++; } else filestobecrced.push_back(filename); } } } myprintf("01463: First pass, done\n"); myprintf("01464: different_size %08d\n",different_size); myprintf("01465: CRC to be done %08d\n",filestobecrced.size()); vector > crc32_pair; franzparallelhashfiles("CRC-32",tobetested,filestobecrced,crc32_pair); ///if (flagdebug3) { for (unsigned int i=0;isecond.hexcrc32==crc32_pair[i].first) { p->second.expectedsize =1; // flag checked //myprintf("01467: OK SOURCE %08d %s %s\n",(int)i,crc32_pair[i].first.c_str(),crc32_pair[i].second.c_str()); } else { p->second.expectedsize =0; // flag checked myprintf("01468: KAPUTT SOURCE %08d CRC-32 expected %s founded %s %s\n",(int)i,crc32_pair[i].first.c_str(),p->second.hexcrc32.c_str(),crc32_pair[i].second.c_str()); } } } } */ if (read_errors) return 2; return (errors+status_e)>0; } /* We need something out of an object (Jidac), addfile() and scandir(), because pthread does not like very much objects. Yes, quick and dirty */ void myaddfile(uint32_t i_tnumber,DTMap& i_edt,string i_filename, int64_t i_date,int64_t i_size, bool i_flagcalchash) { if (g_testifselected) if (pjidac!=NULL) if (!(*pjidac).isselected(i_filename.c_str(), false,i_size)) { if (flagdebug3) myprintf("01469: discarded %s\n",i_filename.c_str()); return; } ///Raze to the ground ads and zfs as soon as possible if (!flag715) if (isads(i_filename)) return; if (!flagforcezfs) if (iszfs(i_filename)) return; if (minsize>0) if ((uint64_t)i_size0) if ((uint64_t)i_size>maxsize) { if (flagdebug) myprintf("01471: (-maxsize) too large %19s %s\n",migliaia(i_size),i_filename.c_str()); return; } DT& d=i_edt[i_filename]; d.date=i_date; d.size=i_size; d.attr=0; d.data=0; d.hexhash=""; /// this seems weird, and it is. but mutex slow downs about 10x. So use -noeta to be sure no races if (i_flagcalchash) if (!isdirectory(i_filename)) { int64_t starthash=mtime(); g_dimensione=0; franz_do_hash dummy(g_thechosenhash); if (flagdebug3) myprintf("01472: filehash on %s\n",i_filename.c_str()); d.hexhash=dummy.filehash(i_filename,false,0,prendidimensionefile(i_filename.c_str())); /// d.hexhash=hash_calc_file(flag2algo(),i_filename.c_str(),false,dummycrc,mtime(),prendidimensionefile(i_filename.c_str()),dummy,thefilesize); if (flagverbose) { myprintf("%s: |%s| [%d] %6.3f %Z\n",g_thechosenhash_str.c_str(),d.hexhash.c_str(),i_tnumber,(mtime()-starthash)/1000.0,i_filename.c_str()); } } /// thread safe, but... who cares? if (g_arraybytescanned.size()==0) { myprintf("01473: GURU g_arraybytescanned not pushed?\n"); seppuku(); return; } pthread_mutex_lock(&g_mylock); g_arraybytescanned[i_tnumber]+=i_size; g_arrayfilescanned[i_tnumber]++; if (!flagnoeta) { if (i_flagcalchash) { if (!(g_arrayfilescanned[i_tnumber] % 100)) { for (unsigned int i=0; i %s\n",filename.c_str()); return; } if (!flagforcezfs) if (iszfs(filename)) { if (flagverbose) myprintf("01476: Skip .zfs ----> %s\n",filename.c_str()); return; } #ifdef unix // Add regular files and directories while (filename.size()>1 && filename[filename.size()-1]=='/') filename=filename.substr(0, filename.size()-1); // remove trailing / struct stat sb; if (!lstat(filename.c_str(), &sb)) { if (S_ISREG(sb.st_mode)) myaddfile(i_tnumber,i_edt,filename, decimal_time(sb.st_mtime), sb.st_size,i_flagcalchash); // Traverse directory if (S_ISDIR(sb.st_mode)) { myaddfile(i_tnumber,i_edt,filename=="/" ? "/" : filename+"/", decimal_time(sb.st_mtime),0, i_flagcalchash); DIR* dirp=opendir(filename.c_str()); if (dirp) { for (dirent* dp=readdir(dirp); dp; dp=readdir(dirp)) { if (strcmp(".", dp->d_name) && strcmp("..", dp->d_name)) { string s=filename; if (s!="/") s+="/"; s+=dp->d_name; if (i_recursive) myscandir(i_tnumber,i_edt,s,true,i_flagcalchash); else { if (!lstat(s.c_str(), &sb)) { if (S_ISREG(sb.st_mode)) myaddfile(i_tnumber,i_edt,s, decimal_time(sb.st_mtime), sb.st_size,i_flagcalchash); if (S_ISDIR(sb.st_mode)) myaddfile(i_tnumber,i_edt,s=="/" ? "/" :s+"/", decimal_time(sb.st_mtime),0, i_flagcalchash); } } } } closedir(dirp); } else { if (!flagignore) perror(filename.c_str()); } } } else perror(filename.c_str()); #else // Windows: expand wildcards in filename // Expand wildcards WIN32_FIND_DATA ffd; string t=filename; /// myprintf("01477: %s\n",t.c_str()); if (t.size()>0 && t[t.size()-1]=='/') t+="*"; ///myprintf("01478: %s\n",t.c_str()); HANDLE h=FindFirstFile(utow(t.c_str()).c_str(), &ffd); if (h==INVALID_HANDLE_VALUE && GetLastError()!=ERROR_FILE_NOT_FOUND && GetLastError()!=ERROR_PATH_NOT_FOUND) if (!flagignore) printerr("59345",t.c_str(),0); /// myprintf("01479: 22: %s\n",t.c_str()); while (h!=INVALID_HANDLE_VALUE) { // For each file, get name, date, size, attributes SYSTEMTIME st; int64_t edate=0; if (FileTimeToSystemTime(&ffd.ftLastWriteTime, &st)) edate=st.wYear*10000000000LL+st.wMonth*100000000LL+st.wDay*1000000 +st.wHour*10000+st.wMinute*100+st.wSecond; const int64_t esize=ffd.nFileSizeLow+(int64_t(ffd.nFileSizeHigh)<<32); // Ignore links, the names "." and ".." or any unselected file t=wtou(ffd.cFileName); if (flagdebug3) // sometimes Windows get very strange attributes { myprintf("01480: %08X MY new t2 %s\n",(unsigned int)ffd.dwFileAttributes,t.c_str()); string temp=decodewinattribute(ffd.dwFileAttributes); myprintf("01481: %s\n",temp.c_str()); myprintf("\n"); } if (t=="." || t=="..") edate=0; // don't add, of course if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))) { /// Houston, we have a strange deduplicated .vhdx file? /// add as by default if (flagverbose) myprintf("01482: Verbose: found something strange2 (VHDX?) %s\n",t.c_str()); } else { /// A junction? if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) edate=0; // don't add } string fn=path(filename)+t; // Save directory names with a trailing / and scan their contents // Otherwise, save plain files if (edate) { if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) fn+="/"; myaddfile(i_tnumber,i_edt,fn, edate, esize, i_flagcalchash); if (i_recursive) if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { fn+="*"; myscandir(i_tnumber,i_edt,fn,true,i_flagcalchash); } } if (!FindNextFile(h, &ffd)) { if (GetLastError()!=ERROR_NO_MORE_FILES) printerr("29656",fn.c_str(),ffd.dwFileAttributes); break; } } FindClose(h); #endif // corresponds to #ifdef (#ifdef unix) } bool isbackuppart(string i_partname,string i_mask) { #ifdef _WIN32 i_partname =stringtolower(i_partname); i_mask =stringtolower(i_mask); #endif // corresponds to #ifdef (#ifdef _WIN32) if (flagdebug2) myprintf("01483: i_partname |%s| i_mask |%s|\n",i_partname.c_str(),i_mask.c_str()); if (isdirectory(i_partname)) { if (flagdebug) myprintf("01484: i_partname is a folder |%s|\n",i_partname.c_str()); return false; } if (i_partname=="") { if (flagdebug) myprintf("01485: partname empty\n"); return false; } if (!iszpaq(i_partname)) { if (flagdebug) myprintf("01486: partname not a .zpaq |%s|\n",i_partname.c_str()); return false; } if (i_mask=="") { if (flagdebug) { myprintf("01487: i_mask empty\n"); ///string onlyname=extractfilename(i_partname); if (i_partname.size()>14) i_mask=i_partname.substr(0,i_partname.size()-14); myprintf("01488: new i_mask =>|%s|\n",i_mask.c_str()); } } string candidato=extractfilename(i_partname); if (candidato.size()<14) { if (flagdebug) myprintf("01489: partname too short of |%s|\n",i_partname.c_str()); return false; } myreplace(i_mask,"????????.zpaq",""); string onlyname=prendinomefileebasta(i_mask); if (onlyname.size()==0) { if (flagdebug) myprintf("01490: onlyfilename empty of mask |%s|\n",i_mask.c_str()); return false; } if (mypos(onlyname,candidato)!=0) { if (flagdebug) myprintf("01491: cannot match |%s| in |%s|\n",onlyname.c_str(),candidato.c_str()); return false; } if (candidato[candidato.size()-14]!='_') { if (flagdebug) myprintf("01492: char -14 not _ in |%s|\n",candidato.c_str()); return false; } int thepart=getpartnumber(i_partname); if (thepart<0) { if (flagdebug) myprintf("01493: thepart <0 for %s\n",i_partname.c_str()); return false; } return true; } bool compare_second(const std::pair& a,const std::pair& b) { return (a.second filenamearray; vector partarray; string lastpart; string nextpart; int howmanychunks; bool ismultipart; bool isgood; int howmanyjolly; int64_t filenamearray_size; multipart(string i_filename): howmanychunks(0), ismultipart(false), isgood(false), howmanyjolly(0), filenamearray_size(0) { if (!iszpaq(i_filename)) i_filename+=".zpaq"; #ifdef _WIN32 i_filename=stringtolower(i_filename); #endif // corresponds to #ifdef (#ifdef _WIN32) /// we really want a path, even relative thefilename =i_filename; lastpart =""; nextpart =""; if (i_filename=="") { myprintf("01494: multipartfilename is empty\n"); return; } for (unsigned int i=0;i0; if (!ismultipart) return; enumerate(); partarray.clear(); int parts =0; // number of existing parts in multipart string part0=subpart(i_filename,0); if (flagdebug3) myprintf("01495: part0 %s i_filename %s\n",part0.c_str(),i_filename.c_str()); string thehole =""; for (int i=1;; ++i) { string partname=subpart(i_filename,i); if (flagdebug2) myprintf("01496: partname on %08d %s\n",i,partname.c_str()); if (partname==part0) error("84285: too many archive parts"); if (!fileexists(partname)) { thehole=partname; if (flagdebug3) myprintf("01497: filenamearraysize %08d partname %08d does not exists\n",filenamearray.size(),i,partname.c_str()); if (i==1) thehole=""; else if ((filenamearray.size()>0) && (i>0)) { if (flagdebug3) { myprintf("01498: last filenamearraysize %s\n",filenamearray[filenamearray.size()-1].filename.c_str()); myprintf("01499: i-1 %s\n",subpart(i_filename,i-1).c_str()); } if (filenamearray[filenamearray.size()-1].filename==subpart(i_filename,i-1)) thehole=""; } break; } else { s_fileandsize myblock; myblock.filename=partname; myblock.size=prendidimensionefile(partname.c_str()); myblock.attr=0; myblock.date=0; myblock.isdir=isdirectory(partname); myblock.flaghashstored=false; partarray.push_back(myblock); if (flagdebug2) myprintf("01500: pushing on partarray the partname %s\n",partname.c_str()); } ++parts; } std::sort(partarray.begin(),partarray.end(),comparefilename); isgood=(thehole=="");// filenamearray.size()==partarray.size(); if (thehole!="") { /// myprintf("01501: PART NUMBER MISMATCH: disk %s vs part %s (HOLE IN %s)\n",migliaia(filenamearray.size()),migliaia2(partarray.size()),thehole.c_str()); myprintf("01502: [1] AT LEAST ONE HOLE DETECTED! <<%Z>>\n",thehole.c_str()); if (filenamearray.size()>partarray.size()) // this should be for (unsigned int i=0;i0) { if (fileexists(subpart(i_filename, parts))) lastpart=subpart(i_filename, parts); nextpart=subpart(i_filename, parts+1); } else nextpart=subpart(i_filename, 1); } string enumerate() { /// UNIX get strange behaviour with folders and jolly /// this "thing" is weird, but works on Win and *nix DTMap thedt; flagforcezfs=true; g_arraybytescanned.clear(); g_arrayfilescanned.clear(); g_arraybytescanned.push_back(0); g_arrayfilescanned.push_back(0); string onlypath=extractfilepath(thefilename); string onlyname=extractfilename(thefilename); myreplace(onlyname,"????????.zpaq",""); myreplace(onlyname,".zpaq",""); if (flagdebug3) { myprintf("01504: scan by %s\n",onlypath.c_str()); myprintf("01505: filename %s\n",thefilename.c_str()); myprintf("01506: onlyname %s\n",onlyname.c_str()); } string temppath=onlypath; if (mypos("/",temppath)==-1) temppath="./"+temppath; myscandir(0,thedt,temppath,false,false); printbar(' ',false); myprintf("\r"); if (flagdebug) myprintf("01507: scanned %s\n",migliaia(thedt.size())); if (thedt.size()==0) return ""; filenamearray.clear(); for (DTMap::iterator p=thedt.begin(); p!=thedt.end(); ++p) { s_fileandsize myblock; string currentfilename=p->first; #ifdef _WIN32 currentfilename=stringtolower(currentfilename); #endif // corresponds to #ifdef (#ifdef _WIN32) if (isbackuppart(currentfilename,onlyname)) { int thepartnumber=getpartnumber(currentfilename); if (thepartnumber>0) { myblock.filename =currentfilename; myblock.size =p->second.size; myblock.attr =p->second.attr; myblock.date =p->second.date; myblock.isdir =false; myblock.flaghashstored =false; filenamearray.push_back(myblock); /// myprintf("01508: %s %s\n",estensione.c_str(),p->first.c_str()); } } else { if (flagdebug3) myprintf("01509: Not backup part %s\n",currentfilename.c_str()); } } std::sort(filenamearray.begin(),filenamearray.end(),comparefilename); if (flagdebug2) myprintf("01510: filenamearray size post %s\n",migliaia(filenamearray.size())); if (filenamearray.size()==0) return ""; else { if (flagdebug3) for (int unsigned i=0;i0) for (unsigned i=0; i0) { matched=false; for (unsigned i=0;i* o_thelist) { if (o_thelist==NULL) { myprintf("01516: GURU o_thelist is null\n"); return 0; } if (!isdirectory(i_path)) i_path+="/"; vector tobesorted; #ifndef unix if (flagdebug2) myprintf("01517: i_path %s\n",i_path.c_str()); i_path=extractfilepath(i_path); std::wstring wpattern = utow(i_path.c_str())+utow("*.*"); const std::string s_pattern(wpattern.begin(),wpattern.end()); if (flagdebug3) myprintf("01518: get handle for w pattern %s\n",wtou(wpattern.c_str()).c_str()); WIN32_FIND_DATAW findfiledata; HANDLE myhandle=FindFirstFileW(wpattern.c_str(),&findfiledata); if (myhandle==INVALID_HANDLE_VALUE) { if (flagdebug) myprintf("01519: Invalid handle %s\n",s_pattern.c_str()); return 0; } do { std::string t=wtou(findfiledata.cFileName); if ((t!=".") && (t!="..")) { std::wstring wfilepath; ///wfilepath=utow(i_path.c_str())/*+L"\\"*/+findfiledata.cFileName; wfilepath=findfiledata.cFileName; const std::string s_wfilepath(wfilepath.begin(),wfilepath.end()); if (flagdebug3) myprintf("01520: Working on %s ",s_wfilepath.c_str()); if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (flagdebug3) myprintf(": OK PUSH BACK FOLDER\n"); string readytopush=wtou(wfilepath.c_str()); if (acceptonlynot(t)) tobesorted.push_back(readytopush); } } } while(FindNextFile(myhandle,&findfiledata)==TRUE); if (myhandle) FindClose(myhandle); #else DIR *dir; const struct dirent *ent; if ((dir=opendir(i_path.c_str()))==NULL) { myprintf("01521: cannot scan in <<%s>>\n",i_path.c_str()); return 0; } while ((ent=readdir(dir))!=NULL) { string thename=ent->d_name; string fullname=i_path+thename; if (flagdebug3) myprintf("01522: working on thename %s fullname %s\n",thename.c_str(),fullname.c_str()); if ((thename!=".") && (thename!="..") && (thename!=".zfs")) { if (acceptonlynot(thename)) { if (direxists(fullname)) { tobesorted.push_back(thename); if (flagdebug3) myprintf("01523: no direxists fullname %s\n",fullname.c_str()); } else { if (flagdebug3) myprintf("01524: no direxists fullname %s\n",fullname.c_str()); } } } } closedir (dir); #endif // corresponds to #ifndef (#ifndef unix) if (flagdebug) for (unsigned int i=0;i> for extension <<%s>>\n",fullarchive.c_str(),estensione.c_str()); g_bytescanned =0; g_filescanned =0; g_worked =0; flagskipzfs =true; // strip down zfs DTMap thedt; #ifdef unix if (flagdebug) myprintf("01528: running on NIX\n"); vector candidate; listfiles(extractfilepath(fullarchive),estensione,true,&candidate); if (flagdebug3) myprintf("01529: candidate %s with pattern %s\n",migliaia(candidate.size()),fullarchive.c_str()); for (unsigned int i=0;i>\n",filename.c_str()); } DT& d=thedt[filename]; d.date =0; d.creationdate =0; d.accessdate =0; d.size =0; d.attr =0; d.data =0; } else { if (flagdebug3) myprintf("01532: DISCARDED %s in %s\n",fullarchive.c_str(),filename.c_str()); } } #else scandir(false,thedt,fullarchive,false); printbar(' ',false); myprintf("\r"); #endif // corresponds to #ifdef (#ifdef unix) if (thedt.size()==0) { myprintf("01533: no archive founded => quit\n"); return 1; } myprintf("01534: Founded %s archive(s), working\n",migliaia(thedt.size())); int risultato=0; int therun=0; for (DTMap::iterator p=thedt.begin(); p!=thedt.end(); ++p) { therun++; jidacreset(); archive=p->first; int riscomando=0; if (command=='x') riscomando=extract(); else if (command=='t') riscomando=test(); string stato=""; if (riscomando==0) stato="OK"; else if (riscomando==1) stato="WARNING"; else stato="ERROR"; printbar('-'); myprintf("\r"); myprintf("01535: Status %08d/%08d: %d %s on <<%Z>>\n",therun,thedt.size(),riscomando,stato.c_str(),archive.c_str()); if (flagbig) { if (riscomando==0) bigok(); else if (riscomando==1) bigwarning(); else bigerror(); } printbar('-'); risultato+=riscomando; } return risultato; } /// parameters to run scan threads struct tparametri { bool recursive; string directorytobescanned; DTMap theDT; bool flagcalchash; uint64_t timestart; uint64_t timeend; int tnumber; }; /// run a myscandir() instead of Jidac::scandir() (too hard to use a member) void * scansiona(void *t) { assert(t); tparametri* par= ((struct tparametri*)(t)); DTMap& tempDTMap = par->theDT; myscandir(par->tnumber,tempDTMap,par->directorytobescanned,par->recursive,par->flagcalchash); par->timeend=mtime(); pthread_exit(NULL); return 0; } #ifdef _WIN32 typedef DWORD (*callback_avanzamento)( LARGE_INTEGER, // file size LARGE_INTEGER, // bytes transferred LARGE_INTEGER, // bytes in stream LARGE_INTEGER, // bytes transferred for stream DWORD, // current stream DWORD, // callback reason HANDLE, // handle to source file HANDLE, // handle to destination file LPVOID // from CopyFileEx ); // type for conciseness DWORD win_avanzamento( LARGE_INTEGER TotalFileSize, // file size LARGE_INTEGER TotalBytesTransferred, // bytes transferred LARGE_INTEGER StreamSize, // bytes in stream LARGE_INTEGER StreamBytesTransferred, // bytes transferred for stream DWORD dwStreamNumber, // current stream DWORD dwCallbackReason, // callback reason HANDLE hSourceFile, // handle to source file HANDLE hDestinationFile, // handle to destination file LPVOID lpData // from CopyFileEx ) { static int lastpercentuale=0; if (int64_t(dwStreamNumber)+int64_t(dwCallbackReason)+int64_t(hSourceFile)+int64_t(hDestinationFile)+int64_t(lpData)==12445) if (StreamSize.HighPart==TotalBytesTransferred.HighPart) if (StreamBytesTransferred.HighPart==StreamSize.HighPart) lastpercentuale++; // compiler be quiet! int64_t numeratore =(TotalBytesTransferred .HighPart*2147483648+TotalBytesTransferred.LowPart)*100 ; int64_t denominatore=(TotalFileSize .HighPart*2147483648+TotalFileSize.LowPart)+1; if (denominatore>LARGEFILE) { int percentuale=numeratore/denominatore; if (percentuale==1) myprintf("\r%s",tohuman(denominatore)); else percentuale/=5; if (percentuale!=lastpercentuale) { myprintf("."); lastpercentuale=percentuale; } } return PROGRESS_CONTINUE; } bool windows_copy(string i_src_filename,string i_dest_filename,callback_avanzamento callback_fn) { wstring in_widename=utow(i_src_filename.c_str()); wstring out_widename=utow(i_dest_filename.c_str()); LPPROGRESS_ROUTINE prog_fn = (LPPROGRESS_ROUTINE) callback_fn; if (callback_fn) return (CopyFileEx (in_widename.c_str(),out_widename.c_str(),prog_fn,NULL,0,0)!=0); else return (CopyFile (in_widename.c_str(),out_widename.c_str(),TRUE)!=0); } #endif // corresponds to #ifdef (#ifdef _WIN32) /// make a "robocopy" from source to destination file. /// if "someone" call with valid parameters do NOT do a getfileinfo (slow) string Jidac::secure_copy_file( const string& i_filename,const string& i_outfilename,int64_t i_startcopy,int64_t i_totalsize,int64_t i_totalcount,int64_t& o_writtensize,int64_t& o_donesize,int64_t& o_donecount, int64_t i_sorgente_size, int64_t i_sorgente_date, int64_t i_sorgente_attr, int64_t i_destinazione_size, int64_t i_destinazione_date, int64_t i_destinazione_attr, unsigned char* i_buffer, size_t i_buffersize ) { if (i_buffer==NULL) { myprintf("01536: GURU buffer null\n"); seppuku(); return ""; } if (i_buffersize==0) { myprintf("01537: buffer size 0\n"); seppuku(); return ""; } static int ultimapercentuale=0; if (flagdebug3) { myprintf("\n"); myprintf("01538: From: %s\n",i_filename.c_str()); myprintf("01539: To: %s\n",i_outfilename.c_str()); } if (i_filename=="") return "30833:SOURCE-EMPTY"; if (i_outfilename=="") return "30836:DEST-EMPTY"; int64_t s1=mtime(); if (isdirectory(i_filename)) { makepath(i_outfilename); return "OK"; } g_robocopy_makepath+=mtime()-s1; int64_t sorgente_dimensione =0; int64_t sorgente_data =0; int64_t sorgente_attr =0; int64_t destinazione_dimensione =0; int64_t destinazione_data =0; int64_t destinazione_attr =0; bool sorgente_esiste =false; bool destinazione_esiste =false; /* hopefully the source is ALWAYS existing! int64_t start_sorgente_esiste=mtime(); sorgente_esiste =getfileinfo(i_filename,sorgente_dimensione,sorgente_data,sorgente_attr); g_robocopy_check_sorgente+=mtime()-start_sorgente_esiste; */ sorgente_esiste =true; // trust in caller sorgente_dimensione =i_sorgente_size; sorgente_data =i_sorgente_date; sorgente_attr =i_sorgente_attr; if (i_destinazione_size>=0) { /// someone call us with valid size=> take the parameters destinazione_esiste =true; destinazione_dimensione =i_destinazione_size; destinazione_data =i_destinazione_date; destinazione_attr =i_destinazione_attr; } else { /// houston, we have to make ourself int64_t start_destinazione_esiste=mtime(); destinazione_esiste =getfileinfo(i_outfilename,destinazione_dimensione,destinazione_data,destinazione_attr); g_robocopy_check_destinazione+=mtime()-start_destinazione_esiste; } if (flagdebug3) { myprintf("01540: Sorgente esiste %d\n",(int)sorgente_esiste); myprintf("01541: Sorgente size %s\n",migliaia(sorgente_dimensione)); myprintf("01542: Sorgente data %s\n",migliaia(sorgente_data)); myprintf("01543: Destinazione esiste %d\n",(int)destinazione_esiste); myprintf("01544: Destinazione size %s\n",migliaia(destinazione_dimensione)); myprintf("01545: Destinazione data %s\n",migliaia(destinazione_data)); myprintf("\n"); } if (!flagdonotforcexls) if (isxls(i_filename)) { /// Old Office (2000) can change xls (and ppt) metadata without "touching" /// Therefore size-and-date algo does not work, to detect change, making hash check fail /// (zpaq, rsync, robocopy for example) /// The changes are in the beginning of the file, so a 64K block comparison is normally /// faster than the full hash computation (for different files). /// Obviously for the very same files it is almost identical if (flagdebug2) myprintf("01546: enforcing xls/ppt test %s\n",i_filename.c_str()); int64_t s2=mtime(); destinazione_esiste=isfilesequal(i_filename,i_outfilename,flagzero); g_robocopy_isequal+=mtime()-s2; if (destinazione_esiste) { if (flagdebug2) myprintf("01547: Equal XLS: skip %s\n",i_outfilename.c_str()); int64_t s3=mtime(); close(i_outfilename.c_str(),sorgente_data,sorgente_attr); g_robocopy_close+=mtime()-s3; return "="; } else { if (flagdebug2) myprintf("01548: Different XLSs!\n"); } } if (destinazione_esiste) { if (flagdebug3) myprintf("01549: Esiste1\n"); if (sorgente_esiste) { if (flagdebug3) { myprintf("01550: Esiste2\n"); } if (destinazione_dimensione==sorgente_dimensione) { if (flagdebug3) myprintf("01551: Stessa dimensione\n"); if (flagdebug3) { myprintf("01552: PPP %s\n",migliaia(myabs(destinazione_data,sorgente_data))); } /// this 2 is really important: it is the modulo-differences /// 1 or even 0 is not good for NTFS or Windows if (myabs(destinazione_data,sorgente_data)<=2) { if (flagdebug3) myprintf("01553: Stessa data\n"); if (flagkill) if (sorgente_attr!=destinazione_attr) { int64_t s3=mtime(); close(i_outfilename.c_str(),sorgente_data,sorgente_attr); g_robocopy_close2+=mtime()-s3; } o_writtensize +=sorgente_dimensione; o_donesize +=sorgente_dimensione; o_donecount++; if (!flagnoeta) { int percentuale=100*o_donecount/(i_totalcount+1); if (percentuale%10==0) if (percentuale!=ultimapercentuale) { ultimapercentuale=percentuale; int percentualebyte=100*o_donesize/(i_totalsize+1); double tempotrascorso=((mtime()-i_startcopy)/1000.0); double tempototale=(100.0/percentuale)*tempotrascorso; double tempoleft=tempototale-tempotrascorso; myprintf("[%02d %%] %10s / %s (%11s / %s [%02d %%]) ETA %02d:%02d:%02d\n",percentuale,migliaia(o_donecount),migliaia2(i_totalcount),tohuman(o_donesize),tohuman2(i_totalsize), percentualebyte,int(tempoleft/3600), int(tempoleft/60)%60, int(tempoleft)%60); } } return "="; } } } if (flagkill) if ((!flagappend) && (!iszpaq(i_outfilename))) { int64_t s4=mtime(); delete_file(i_outfilename.c_str()); g_robocopy_delete+=mtime()-s4; if (flagdebug3) myprintf("01554: Cancellato %s\n",i_outfilename.c_str()); } } if (!flagkill) return "OK"; #ifdef _WIN32 if (flagbig) { bool copyresult=false; int64_t sw1=mtime(); if (flagnoeta) copyresult=windows_copy(i_filename,i_outfilename,NULL); else copyresult=windows_copy(i_filename,i_outfilename,win_avanzamento); g_robocopy_fread+=mtime()-sw1; if (!flagnoeta) if (sorgente_dimensione>LARGEFILE) myprintf("\r \r"); if (copyresult) { int64_t sw2=mtime(); close(i_outfilename.c_str(),sorgente_data,sorgente_attr); g_robocopy_touch+=mtime()-sw2; o_donecount++; o_writtensize+=sorgente_dimensione; o_donesize+=sorgente_dimensione; if (!flagnoeta) myavanzamento(o_donesize,i_totalsize,i_startcopy); return "OK"; } else return "ERROR"; } #endif // corresponds to #ifdef (#ifdef _WIN32) int64_t s5=mtime(); FILE* inFile = freadopen(i_filename.c_str()); g_robocopy_readopen+=mtime()-s5; if (inFile==NULL) { #ifdef _WIN32 int err=GetLastError(); #else int err=1; #endif // corresponds to #ifdef (#ifdef _WIN32) myprintf("\n"); myprintf("01555: ERR <%s> kind %d\n",i_filename.c_str(),err); return "KAPUTT"; } if (flagappend) { if (destinazione_dimensione>=sorgente_dimensione) flagappend=false; // full overwrite if (!iszpaq(i_filename)) { if (flagdebug) myprintf("01556: not a ZPAQ / not flagappend!\n"); flagappend=false; } else { if (flagdebug) myprintf("01557: we have a ZPAQ and a --append!\n"); } } /// to fix excluded myaddfiles() int64_t s6=mtime(); /// makepath(i_outfilename); string percorso=extractfilepath(i_outfilename); if (!direxists(percorso)) makepath(i_outfilename); g_robocopy_makepath2+=mtime()-s6; int64_t s7=mtime(); FILE* outFile=NULL; if (flagdebug) { if (fileexists(i_outfilename)) myprintf("01558: ESISTE file %s\n",i_outfilename.c_str()); else myprintf("01559: NON ESISTE APPEND %s\n",i_outfilename.c_str()); } if (flagappend) if (!isfilesequal(i_filename,i_outfilename,true)) { if (flagdebug) myprintf("01560: fast check failed, turn back to full copy %s %s\n",i_filename.c_str(),i_outfilename.c_str()); flagappend=false; } #ifdef _WIN32 wstring widename=utow(i_outfilename.c_str()); if (flagappend) { if (flagdebug) { myprintf("\n"); myprintf("01561: Apro con APPEND \n"); } outFile=_wfopen(widename.c_str(), L"ab" ); } else { if (flagdebug) { myprintf("\n"); myprintf("01562: Apro con WRITE \n"); } outFile=_wfopen(widename.c_str(), L"wb" ); } #else if (flagappend) outFile=fopen(i_outfilename.c_str(), "ab"); else outFile=fopen(i_outfilename.c_str(), "wb"); #endif // corresponds to #ifdef (#ifdef _WIN32) if (outFile==NULL) return "30847:CANNOT OPEN outfile "+i_outfilename; g_robocopy_openoutfile+=mtime()-s7; size_t readSize; int larghezzaconsole=terminalwidth(); if (larghezzaconsole>=50) larghezzaconsole=50; else larghezzaconsole=0; if (flagnoeta) larghezzaconsole=0; int64_t scrittitotali=0; int64_t dascrivere=sorgente_dimensione; int lastbarra=0; if ((sorgente_dimensione>LARGEFILE) && (larghezzaconsole>0)) myprintf("%s",tohuman(sorgente_dimensione)); if (flagappend) { if (destinazione_dimensione 0) { if (flagzero) memset(i_buffer,0,i_buffersize); int64_t s11=mtime(); int scritti=fwrite(i_buffer,1,readSize,outFile); g_robocopy_fwrite+=mtime()-s11; ///myprintf("01568: Scritti %19s\n",migliaia(scritti)); scrittitotali +=scritti; o_donesize +=scritti; o_writtensize +=scritti; if (!flagnoeta) { if ((sorgente_dimensione>LARGEFILE) && (larghezzaconsole>0)) { int barra=larghezzaconsole*scrittitotali/(sorgente_dimensione+1); if (barra>lastbarra) { myprintf("."); lastbarra=barra; } } else myavanzamento(o_donesize,i_totalsize,i_startcopy); } } if (flagappend) if (flagdebug) { myprintf("\n"); myprintf("01569: Scrittitotali %s\n",migliaia(scrittitotali)); } if (!flagnoeta) { if ((sorgente_dimensione>LARGEFILE) && (larghezzaconsole>0)) myprintf("\r \r"); myavanzamento(o_donesize,i_totalsize,i_startcopy); } g_robocopy_fread+=mtime()-s8; int64_t s9=mtime(); fclose(inFile); fclose(outFile); g_robocopy_fclose+=mtime()-s9; /// note: this is a "touch" for the attr int64_t s10=mtime(); close(i_outfilename.c_str(),sorgente_data,sorgente_attr); ///touch(i_outfilename.c_str(),sorgente_data,sorgente_attr); g_robocopy_touch+=mtime()-s10; o_donecount++; if (scrittitotali!=dascrivere) { myprintf("\n"); myprintf("01570: HOUSTON something seems wrong: expected %s, done %s\n",migliaia(dascrivere),migliaia2(scrittitotali)); myprintf("01571: Corrupted source files? Lost connection? Cannot access? Media full?\n"); return "35109: COPY CORRUPTED"; } return "OK"; } int pos(const std::string &i_stringa,const std::string& i_cerca) { return (i_stringa.find(i_cerca)); } string Jidac::zfs_get_snaplist(string i_header,const string i_footer,vector& o_array_primachiocciola,vector& o_array_dopochiocciola,vector& o_array_size) { /* #ifdef _WIN32 o_array_primachiocciola.clear(); o_array_dopochiocciola.clear(); o_array_primachiocciola.push_back("zroot/tmp"); o_array_dopochiocciola.push_back("zpaqfranz00000002"); o_array_primachiocciola.push_back("zroot/tmp"); o_array_dopochiocciola.push_back("zpaqfranz00000003"); o_array_primachiocciola.push_back("zroot/tmp"); o_array_dopochiocciola.push_back("zpaqfranz00000004"); return "ciao"; #endif // corresponds to #ifdef (#ifdef _WIN32) */ string filebatch="/tmp/exec_zfs.sh"; filebatch=nomefileseesistegia(filebatch); if (flagdebug) myprintf("01572: script EXECUTING %s\n",filebatch.c_str()); FILE* batch=fopen(filebatch.c_str(), "wb"); if (batch==NULL) { myprintf("01573: cannot write on filebatch %s\n",filebatch.c_str()); exit(0); } fprintf(batch,"zfs list -t snapshot\n"); fclose(batch); if (chmod(filebatch.c_str(),0700)!=0) return "30515: error on chmod"; string snapshotlist=exec(filebatch.c_str()); if (snapshotlist=="") return "30490: snapshot list empty"; string temp; int posizioneused =-1; unsigned int i =0; while (i=0) { temp=temp.substr(0,posizioneused); int posizionechiocciola=pos(temp,"@"); if (posizionechiocciola>0) { string primachiocciola=temp.substr(0,posizionechiocciola); string nomesnap=temp.substr(posizionechiocciola+1,temp.length()); string trimmato=""; for (unsigned int j=0;j=0)) { nomesnap=mytrim2(nomesnap); o_array_dopochiocciola.push_back(nomesnap); primachiocciola=mytrim2(primachiocciola); o_array_primachiocciola.push_back(primachiocciola); o_array_size.push_back(usedsize); } } } } temp=""; } i++; } delete_file(filebatch.c_str()); return snapshotlist; } int Jidac::zfsenumerate(const string& i_command) { string header =files[0];//"tank/d@2021"; string footer =""; ///string exepath =zpaqfranzexename; if (files.size()>1) footer=files[1]; if (header=="*") header=""; if (footer=="*") footer=""; vector array_primachiocciola; vector array_dopochiocciola; vector array_size; string risul=zfs_get_snaplist(header,footer,array_primachiocciola,array_dopochiocciola,array_size); if (flagdebug3) myprintf("01574: %s\n",risul.c_str()); vector thefile; // this is a double check that the rebuilded snapshot name does really exists in the // original file. Split one lines at time explode(risul,'\n',thefile); if (flagdebug3) for (unsigned int i=0;i>\n",myoutput.c_str()); scripthandle=fopen(myoutput.c_str(),"wb"); if (scripthandle==NULL) { myprintf("01578! ERROR OPENING SCRIPT FILE %s\n",myoutput.c_str()); return 2; } } vector snapshot_folder; vector snapshot_date; vector snapshot_to; for (unsigned int i=0;i=0) { flagtrovato=true; break; } if (flagtrovato) { string theoutput=i_command+tutto; if (command=='H') ///zfssize myprintf("%10s - %s\n",array_size[i].c_str(),theoutput.c_str()); else myprintf("%s\n",theoutput.c_str()); if (scripthandle!=0) fprintf(scripthandle,"%s\n",theoutput.c_str()); } else { myprintf("01579! guru evaluating <<%s>>\n",doublecheck.c_str()); return 2; } } if (scripthandle!=0) { fclose(scripthandle); #ifdef unix // ok we want the +x chmod(myoutput.c_str(),0700); #endif // corresponds to #ifdef (#ifdef unix) } return 0; } int Jidac::zfssize() { if ((files.size()!=1) && (files.size()!=2)) { myprintf("01580: zfssize needs 1 or 2 parameter(s)\n\n"); myprintf("01581: *** DO NOT FORGET THE DOUBLEQUOTE ***\n\n"); help_zfssize(true,true); return 1; } return zfsenumerate(""); } int Jidac::zfspurge() { if ((files.size()!=1) && (files.size()!=2)) { myprintf("01582: zfspurge needs 1 or 2 parameter(s)\n\n"); myprintf("01583: *** DO NOT FORGET THE DOUBLEQUOTE ***\n\n"); help_zfspurge(true,true); return 1; } return zfsenumerate("zfs destroy "); } int Jidac::zfslist() { if ((files.size()!=1) && (files.size()!=2)) { myprintf("01584: zfslist needs 1 or 2 parameter(s)\n\n"); myprintf("01585: *** DO NOT FORGET THE DOUBLEQUOTE ***\n\n"); help_zfslist(true,true); return 1; } return zfsenumerate(""); } int64_t getdatefromsnapshot(string i_snaptoget) { if (i_snaptoget=="") return -1; string getcreationdate ="zfs get -p creation "+i_snaptoget; string creationresult =x_one(getcreationdate,"Getting creation "+i_snaptoget+" ..."); if (creationresult=="") { myprintf("01586: Guru, cannot open snapshot %s\n",i_snaptoget.c_str()); seppuku(); return 2; } int poscreation=pos(creationresult," creation "); if (poscreation<=0) { myprintf("01587! Guru, poscreation strange %d\n",poscreation); seppuku(); return 2; } unsigned int i=poscreation+11; // strlen(" creation ") string dategetted=""; while (i1) footer=files[1]; if (header=="*") header=""; if (footer=="*") footer=""; vector array_primachiocciola; vector array_dopochiocciola; vector array_size; string risul=zfs_get_snaplist(header,footer,array_primachiocciola,array_dopochiocciola,array_size); if (flagdebug3) myprintf("01592: %s\n",risul.c_str()); vector thefile; explode(risul,'\n',thefile); if (array_primachiocciola.size()==0) { myprintf("01593: nothing to do. Do you use the doublequote?\n"); return 1; } FILE* scripthandle=0; string myoutput=g_script; if (myoutput!="") { myprintf("01594: Writing on script <<%s>>\n",myoutput.c_str()); scripthandle=fopen(myoutput.c_str(),"wb"); if (scripthandle==NULL) { myprintf("01595! ERROR OPENING SCRIPT FILE %s\n",myoutput.c_str()); return 2; } } if (flagdebug3) for (unsigned int i=0;i snapshot_folder; vector snapshot_date; vector snapshot_to; for (unsigned int i=0;i=0) { flagtrovato=true; break; } if (flagtrovato) { if (prima_chiocciola[0]!='/') prima_chiocciola="/"+prima_chiocciola; string percorso =prima_chiocciola+"/.zfs/snapshot/"+dopo_chiocciola+"/"; string timestamp =dopo_chiocciola; myreplace(timestamp,footer,""); int64_t testdate=-1; //=encodestringdate(timestamp,true); if (testdate==-1) { /// myprintf("01607: timestamp is strange %s\n",timestamp.c_str()); testdate=getdatefromsnapshot(tutto); if (testdate!=-1) if (flagverbose) myprintf("01608: Snapshot creation date %s\n",dateToString(false,testdate).c_str()); } if (testdate==-1) { myprintf("01609! testdate == -1 ! \n"); return 2; } else { timestamp=dateToString(false,testdate); myreplaceall(timestamp," ","_"); snapshot_date .push_back(testdate); snapshot_folder .push_back(percorso+onlysubdir); snapshot_to .push_back(prima_chiocciola+"/"+onlysubdir); } tutto=exepath+" a "+zpaqfile+" "+percorso+onlysubdir+" -to "+prima_chiocciola+"/"+onlysubdir+" -timestamp "+timestamp; if (scripthandle!=0) fprintf(scripthandle,"%s\n",tutto.c_str()); } else { myprintf("01610! guru evaluating <<%s>>\n",doublecheck.c_str()); return 2; } } if (scripthandle!=0) { fclose(scripthandle); #ifdef unix // ok we want the +x chmod(myoutput.c_str(),0700); #endif // corresponds to #ifdef (#ifdef unix) } if (flagforce) /// -force, to be checked if (snapshot_date.size()>0) { bool allok=true; for (unsigned int i=0;i