File unar-1.10.1-self-extracting_rar.patch of Package unar.10380

Index: unar-1.10.1/XADMaster/XADRAR5Parser.h
===================================================================
--- unar-1.10.1.orig/XADMaster/XADRAR5Parser.h
+++ unar-1.10.1/XADMaster/XADRAR5Parser.h
@@ -9,6 +9,29 @@ typedef struct RAR5Block
 	CSHandle *fh;
 } RAR5Block;
 
+typedef enum {
+    RAR5ArchiveFlagsNone                   = 0,
+    RAR5ArchiveFlagsVolume                 = 0x0001, // Volume. Archive is a part of multivolume set.
+    RAR5ArchiveFlagsVolumeNumberPresent    = 0x0002, // Volume number field is present.
+                                                     // This flag is present in all volumes except first.
+    RAR5ArchiveFlagsSolid                  = 0x0004, // Solid archive.
+    RAR5ArchiveFlagsRecoveryRecordPresent  = 0x0008, // Recovery record is present.
+    RAR5ArchiveFlagsLocked                 = 0x0010, // Locked archive.
+} RAR5ArchiveFlags;
+ typedef enum {
+   RAR5HeaderTypeUnknown    =  0,
+   RAR5HeaderTypeMain       =  1, //   Main archive header.
+   RAR5HeaderTypeFile       =  2, //   File header.
+   RAR5HeaderTypeService    =  3, //   Service header.
+   RAR5HeaderTypeEncryption =  4, //   Archive encryption header.
+   RAR5HeaderTypeEnd        =  5, //   End of archive header.
+} RAR5HeaderType;
+ typedef struct RAR5HeaderBlock
+{
+    RAR5Block block;
+    RAR5ArchiveFlags archiveFlags;
+} RAR5HeaderBlock;
+
 @interface XADRAR5Parser:XADArchiveParser
 {
 	NSData *headerkey;
Index: unar-1.10.1/XADMaster/XADRAR5Parser.m
===================================================================
--- unar-1.10.1.orig/XADMaster/XADRAR5Parser.m
+++ unar-1.10.1/XADMaster/XADRAR5Parser.m
@@ -4,10 +4,16 @@
 #import "XADRARAESHandle.h"
 #import "XADCRCHandle.h"
 #import "NSDateXAD.h"
+#import "CSFileHandle.h"
 #import "Crypto/hmac_sha256.h"
 #import "Crypto/pbkdf2_hmac_sha256.h"
 
 #define ZeroBlock ((RAR5Block){0})
+#define ZeroHeaderBlock ((RAR5HeaderBlock){0})
+
+NSString *RAR5SignatureCannotBeFound=@"RAR5SignatureCannotBeFound";
+const off_t RAR5MaximumSFXHeader  = 1 << 20; // 1 MB
+const off_t RAR5SignatureNotFound = -1;
 
 static uint32_t EncryptRAR5CRC32(uint32_t crc,id context);
 
@@ -34,9 +40,11 @@ static uint64_t ReadRAR5VInt(CSHandle *h
 }
 
 static inline BOOL IsZeroBlock(RAR5Block block) { return block.start==0; }
+static inline BOOL IsZeroHeaderBlock(RAR5HeaderBlock block) { return IsZeroBlock(block.block); }
 
-
-
+ @interface XADRAR5Parser (Multipart)
+ +(BOOL)isPartOfMultiVolume:(CSHandle *)handle;
+@end
 
 @implementation XADRAR5Parser
 
@@ -47,24 +55,43 @@ static inline BOOL IsZeroBlock(RAR5Block
 
 +(BOOL)recognizeFileWithHandle:(CSHandle *)handle firstBytes:(NSData *)data name:(NSString *)name
 {
-	const uint8_t *bytes=[data bytes];
-	int length=[data length];
-
-	if(length<8) return NO; // TODO: fix to use correct min size
-
-	if(IsRAR5Signature(bytes)) return YES;
+    off_t signatureLocation = [self signatureLocationInData:data];
+    return signatureLocation != RAR5SignatureNotFound;
+}
 
-	return NO;
++ (off_t)signatureLocationInData:(NSData *)data {
+    const uint8_t *bytes=[data bytes];
+    int length=[data length];
+
+    if(length<8) return RAR5SignatureNotFound; // TODO: fix to use correct min size
+
+    // for SFXX, RAR Signature can be found not at start, but anywhere in the data
+    int maxxSearch = MIN(length, RAR5MaximumSFXHeader) - 8;
+
+    const uint8_t *sign = bytes;
+    for (int i =0 ; i < maxxSearch; i++, sign++) {
+        if(IsRAR5Signature(sign)) {
+            return i;
+        }
+    }
+    return RAR5SignatureNotFound;
 }
 
 +(NSArray *)volumesForHandle:(CSHandle *)handle firstBytes:(NSData *)data name:(NSString *)name
 {
+    // Check if multipart
+    CSFileHandle *filehandle=[CSFileHandle fileHandleForReadingAtPath:name];
+    if (![self isPartOfMultiVolume:filehandle]) {
+        return nil;
+    }
+
+
 	// New naming scheme. Find the last number in the name, and look for other files
 	// with the same number of digits in the same location.
 	NSArray *matches;
-	if((matches=[name substringsCapturedByPattern:@"^(.*[^0-9])([0-9]+)(.*)\\.rar$" options:REG_ICASE]))
+	if((matches=[name substringsCapturedByPattern:@"^(.*[^0-9])([0-9]+)(.*)\\.(rar|sfx|exe)$" options:REG_ICASE]))
 	return [self scanForVolumesWithFilename:name
-	regex:[XADRegex regexWithPattern:[NSString stringWithFormat:@"^%@[0-9]{%ld}%@.rar$",
+	regex:[XADRegex regexWithPattern:[NSString stringWithFormat:@"^%@[0-9]{%ld}%@.(rar|sfx|exe)$",
 		[[matches objectAtIndex:1] escapedPattern],
 		(long)[(NSString *)[matches objectAtIndex:2] length],
 		[[matches objectAtIndex:3] escapedPattern]] options:REG_ICASE]
@@ -93,6 +120,18 @@ static inline BOOL IsZeroBlock(RAR5Block
 	[super dealloc];
 }
 
+- (void)readUntilSignature {
+    CSHandle * signatureSearchingHandle = [[self handle] subHandleToEndOfFileFrom:0];
+    NSData * data = [signatureSearchingHandle readDataOfLengthAtMost:RAR5MaximumSFXHeader];
+    off_t signatureLocation = [XADRAR5Parser signatureLocationInData:data];
+    if (signatureLocation == RAR5SignatureNotFound) {
+        [NSException raise:RAR5SignatureCannotBeFound format:@"Signature cannot be found %@",[self class]];
+    }
+
+    [self.handle skipBytes:signatureLocation];
+}
+
+
 -(void)parse
 {
 	currsolidstream=nil;
@@ -101,12 +140,13 @@ static inline BOOL IsZeroBlock(RAR5Block
 	NSMutableDictionary *currdict=nil;
 	NSMutableArray *currparts=[NSMutableArray array];
 
-	[[self handle] skipBytes:8];
-
 	// TODO: Catch exceptions and emit partial files?
 
 	@try
 	{
+        [self readUntilSignature];
+        [self.handle skipBytes:8];
+
 		for(;;)
 		{
 			RAR5Block block=[self readBlockHeader];
@@ -117,11 +157,13 @@ static inline BOOL IsZeroBlock(RAR5Block
 
 			switch(block.type)
 			{
-				case 1: // Main archive header.
+				case RAR5HeaderTypeMain: // Main archive header.
+
 					[self skipBlock:block];
 				break;
 
-				case 2: // File header.
+				case RAR5HeaderTypeFile: // File header.
+
 				{
 					NSMutableDictionary *dict=[self readFileBlockHeader:block];
 
@@ -176,10 +218,12 @@ static inline BOOL IsZeroBlock(RAR5Block
 				}
 				break;
 
-				//case 3: // Service header.
+				//case RAR5HeaderTypeService: // Service header.
+
 				//break;
 
-				case 4: // Archive encryption header.
+				case RAR5HeaderTypeEncryption: // Archive encryption header.
+
 				{
 					uint64_t version=ReadRAR5VInt(handle);
 					if(version!=0) [XADException raiseNotSupportedException];
@@ -202,7 +246,8 @@ static inline BOOL IsZeroBlock(RAR5Block
 				}
 				break;
 
-				case 5: // End of archive header.
+				case RAR5HeaderTypeEnd: // End of archive header.
+
 				{
 					uint64_t flags=ReadRAR5VInt(handle);
 					if(flags&0x0001)
@@ -550,6 +595,52 @@ inputParts:(NSArray *)parts isCorrupted:
 	return dict;
 }
 
++(RAR5HeaderBlock)readMasterHeaderFromHandle:(CSHandle *)handle
+{
+
+    RAR5HeaderBlock header;
+     RAR5Block block;
+    block.outerstart=0;
+
+    @try
+    {
+        CSHandle * signatureSearchingHandle = [handle subHandleToEndOfFileFrom:0];
+        NSData * data = [signatureSearchingHandle readDataOfLengthAtMost:RAR5MaximumSFXHeader];
+        off_t signatureLocation = [XADRAR5Parser signatureLocationInData:data];
+        if (signatureLocation == RAR5SignatureNotFound) {
+            [NSException raise:RAR5SignatureCannotBeFound format:@"Signature cannot be found %@",[self class]];
+        }
+
+        [handle skipBytes:signatureLocation];
+        [handle skipBytes:8];
+        if([handle atEndOfFile]) return ZeroHeaderBlock;
+         block.crc=[handle readUInt32LE];
+        block.headersize=ReadRAR5VInt(handle);
+        block.start=[handle offsetInFile];
+        block.type=ReadRAR5VInt(handle);
+        block.flags=ReadRAR5VInt(handle);
+
+        if(block.flags&0x0001) block.extrasize=ReadRAR5VInt(handle);
+        else block.extrasize=0;
+
+        header.archiveFlags=ReadRAR5VInt(handle);
+
+        if(block.flags&0x0002) block.datasize=ReadRAR5VInt(handle);
+        else block.datasize=0;
+    }
+    @catch(id e) { return ZeroHeaderBlock; }
+
+    // If first block wasn't main
+    if (block.type != RAR5HeaderTypeMain) {
+        return ZeroHeaderBlock;
+    }
+
+    block.fh=handle;
+
+    header.block = block;
+    return header;
+}
+
 -(RAR5Block)readBlockHeader
 {
 	CSHandle *fh=[self handle];
@@ -788,3 +879,15 @@ static uint32_t EncryptRAR5CRC32(uint32_
 
 	return newcrc^0xffffffff;
 }
+
+@implementation XADRAR5Parser (Multipart)
+ +(BOOL)isPartOfMultiVolume:(CSHandle *)handle
+{
+    RAR5HeaderBlock header = [self readMasterHeaderFromHandle:handle];
+    if (IsZeroHeaderBlock(header)) {
+        return NO;
+    }
+    return (header.archiveFlags & RAR5ArchiveFlagsVolume);
+}
+@end
+
Index: unar-1.10.1/XADMaster/XADArchiveParser.m
===================================================================
--- unar-1.10.1.orig/XADMaster/XADArchiveParser.m
+++ unar-1.10.1/XADMaster/XADArchiveParser.m
@@ -183,9 +183,9 @@ static int maxheader=0;
 		// Detectors that require lots of work
 		[XADWinZipSFXParser class],
 		[XADZipItSEAParser class],
-		[XADZipSFXParser class],
 		[XADEmbeddedRARParser class],
 		[XADEmbeddedRAR5Parser class],
+		[XADZipSFXParser class],
 		[XAD7ZipSFXParser class],
 		[XADNSISParser class],
 		[XADGzipSFXParser class],
openSUSE Build Service is sponsored by