6 #include "7zProperties.h"
8 #include "../../../Common/IntToString.h"
9 #include "../../../Common/ComTry.h"
10 #include "../../../Windows/Defs.h"
12 #include "../Common/ItemNameUtils.h"
14 #include "../Common/MultiStream.h"
17 #ifdef __7Z_SET_PROPERTIES
19 #include "../Common/ParseProperties.h"
23 using namespace NWindows
;
31 _numThreads
= NWindows::NSystem::GetNumberOfProcessors();
41 STDMETHODIMP
CHandler::GetNumberOfItems(UInt32
*numItems
)
48 *numItems
= _database
.Files
.Size();
54 STDMETHODIMP
CHandler::GetArchiveProperty(PROPID propID
, PROPVARIANT
*value
)
62 STDMETHODIMP
CHandler::GetNumberOfProperties(UInt32
*numProperties
)
67 STDMETHODIMP
CHandler::GetPropertyInfo(UInt32 index
,
68 BSTR
*name
, PROPID
*propID
, VARTYPE
*varType
)
76 STDMETHODIMP
CHandler::GetNumberOfArchiveProperties(UInt32
*numProperties
)
82 STDMETHODIMP
CHandler::GetArchivePropertyInfo(UInt32 index
,
83 BSTR
*name
, PROPID
*propID
, VARTYPE
*varType
)
89 static void MySetFileTime(bool timeDefined
, FILETIME unixTime
,
90 NWindows::NCOM::CPropVariant
&propVariant
)
93 propVariant
= unixTime
;
97 inline static wchar_t GetHex(Byte value)
99 return (value < 10) ? ('0' + value) : ('A' + (value - 10));
102 static UString ConvertBytesToHexString(const Byte *data, UInt32 size)
105 for (UInt32 i = 0; i < size; i++)
108 result += GetHex(b >> 4);
109 result += GetHex(b & 0xF);
118 static UString
ConvertUInt32ToString(UInt32 value
)
121 ConvertUInt64ToString(value
, buffer
);
125 static UString
GetStringForSizeValue(UInt32 value
)
127 for (int i
= 31; i
>= 0; i
--)
128 if ((UInt32(1) << i
) == value
)
129 return ConvertUInt32ToString(i
);
131 if (value
% (1 << 20) == 0)
133 result
+= ConvertUInt32ToString(value
>> 20);
136 else if (value
% (1 << 10) == 0)
138 result
+= ConvertUInt32ToString(value
>> 10);
143 result
+= ConvertUInt32ToString(value
);
149 static CMethodID k_Copy
= { { 0x0 }, 1 };
150 static CMethodID k_LZMA
= { { 0x3, 0x1, 0x1 }, 3 };
151 static CMethodID k_BCJ
= { { 0x3, 0x3, 0x1, 0x3 }, 4 };
152 static CMethodID k_BCJ2
= { { 0x3, 0x3, 0x1, 0x1B }, 4 };
153 static CMethodID k_PPMD
= { { 0x3, 0x4, 0x1 }, 3 };
154 static CMethodID k_Deflate
= { { 0x4, 0x1, 0x8 }, 3 };
155 static CMethodID k_BZip2
= { { 0x4, 0x2, 0x2 }, 3 };
157 static inline char GetHex(Byte value
)
159 return (value
< 10) ? ('0' + value
) : ('A' + (value
- 10));
161 static inline UString
GetHex2(Byte value
)
164 result
+= GetHex(value
>> 4);
165 result
+= GetHex(value
& 0xF);
171 static inline UInt32
GetUInt32FromMemLE(const Byte
*p
)
173 return p
[0] | (((UInt32
)p
[1]) << 8) | (((UInt32
)p
[2]) << 16) | (((UInt32
)p
[3]) << 24);
176 STDMETHODIMP
CHandler::GetProperty(UInt32 index
, PROPID propID
, PROPVARIANT
*value
)
179 NWindows::NCOM::CPropVariant propVariant
;
182 const CRef2 &ref2 = _refs[index];
183 if (ref2.Refs.IsEmpty())
185 const CRef &ref = ref2.Refs.Front();
189 const CRef
&ref
= _refs
[index
];
190 const CVolume
&volume
= _volumes
[ref
.VolumeIndex
];
191 const CArchiveDatabaseEx
&_database
= volume
.Database
;
192 UInt32 index2
= ref
.ItemIndex
;
193 const CFileItem
&item
= _database
.Files
[index2
];
195 const CFileItem
&item
= _database
.Files
[index
];
196 UInt32 index2
= index
;
203 if (!item
.Name
.IsEmpty())
204 propVariant
= NItemName::GetOSName(item
.Name
);
208 propVariant
= item
.IsDirectory
;
212 propVariant
= item
.UnPackSize
;
213 // propVariant = ref2.UnPackSize;
219 if (ref2.Refs.Size() > 1)
220 propVariant = ref2.StartPos;
223 if (item
.IsStartPosDefined
)
224 propVariant
= item
.StartPos
;
229 // propVariant = ref2.PackSize;
231 CNum folderIndex
= _database
.FileIndexToFolderIndexMap
[index2
];
232 if (folderIndex
!= kNumNoIndex
)
234 if (_database
.FolderStartFileIndex
[folderIndex
] == (CNum
)index2
)
235 propVariant
= _database
.GetFolderFullPackSize(folderIndex
);
238 propVariant = UInt64(0);
242 propVariant
= UInt64(0);
246 case kpidLastAccessTime
:
247 MySetFileTime(item
.IsLastAccessTimeDefined
, item
.LastAccessTime
, propVariant
);
249 case kpidCreationTime
:
250 MySetFileTime(item
.IsCreationTimeDefined
, item
.CreationTime
, propVariant
);
252 case kpidLastWriteTime
:
253 MySetFileTime(item
.IsLastWriteTimeDefined
, item
.LastWriteTime
, propVariant
);
256 if (item
.AreAttributesDefined
)
257 propVariant
= item
.Attributes
;
260 if (item
.IsFileCRCDefined
)
261 propVariant
= item
.FileCRC
;
266 CNum folderIndex
= _database
.FileIndexToFolderIndexMap
[index2
];
267 if (folderIndex
!= kNumNoIndex
)
269 const CFolder
&folderInfo
= _database
.Folders
[folderIndex
];
270 UString methodsString
;
271 for (int i
= folderInfo
.Coders
.Size() - 1; i
>= 0; i
--)
273 const CCoderInfo
&coderInfo
= folderInfo
.Coders
[i
];
274 if (!methodsString
.IsEmpty())
275 methodsString
+= L
' ';
276 CMethodInfo methodInfo
;
280 for (int j
= 0; j
< coderInfo
.AltCoders
.Size(); j
++)
283 methodsString
+= L
"|";
284 const CAltCoderInfo
&altCoderInfo
= coderInfo
.AltCoders
[j
];
289 methodIsKnown
= true;
290 if (altCoderInfo
.MethodID
== k_Copy
)
291 methodName
= L
"Copy";
292 else if (altCoderInfo
.MethodID
== k_LZMA
)
293 methodName
= L
"LZMA";
294 else if (altCoderInfo
.MethodID
== k_BCJ
)
296 else if (altCoderInfo
.MethodID
== k_BCJ2
)
297 methodName
= L
"BCJ2";
298 else if (altCoderInfo
.MethodID
== k_PPMD
)
299 methodName
= L
"PPMD";
300 else if (altCoderInfo
.MethodID
== k_Deflate
)
301 methodName
= L
"Deflate";
302 else if (altCoderInfo
.MethodID
== k_BZip2
)
303 methodName
= L
"BZip2";
305 methodIsKnown
= false;
309 methodIsKnown
= GetMethodInfo(
310 altCoderInfo
.MethodID
, methodInfo
);
311 methodName
= methodInfo
.Name
;
317 methodsString
+= methodName
;
318 if (altCoderInfo
.MethodID
== k_LZMA
)
320 if (altCoderInfo
.Properties
.GetCapacity() >= 5)
322 methodsString
+= L
":";
323 UInt32 dicSize
= GetUInt32FromMemLE(
324 ((const Byte
*)altCoderInfo
.Properties
+ 1));
325 methodsString
+= GetStringForSizeValue(dicSize
);
328 else if (altCoderInfo
.MethodID
== k_PPMD
)
330 if (altCoderInfo
.Properties
.GetCapacity() >= 5)
332 Byte order
= *(const Byte
*)altCoderInfo
.Properties
;
333 methodsString
+= L
":o";
334 methodsString
+= ConvertUInt32ToString(order
);
335 methodsString
+= L
":mem";
336 UInt32 dicSize
= GetUInt32FromMemLE(
337 ((const Byte
*)altCoderInfo
.Properties
+ 1));
338 methodsString
+= GetStringForSizeValue(dicSize
);
343 if (altCoderInfo
.Properties
.GetCapacity() > 0)
345 methodsString
+= L
":[";
346 for (size_t bi
= 0; bi
< altCoderInfo
.Properties
.GetCapacity(); bi
++)
348 if (bi
> 2 && bi
+ 1 < altCoderInfo
.Properties
.GetCapacity())
350 methodsString
+= L
"..";
354 methodsString
+= GetHex2(altCoderInfo
.Properties
[bi
]);
356 methodsString
+= L
"]";
362 methodsString
+= altCoderInfo
.MethodID
.ConvertToString();
366 propVariant
= methodsString
;
372 CNum folderIndex
= _database
.FileIndexToFolderIndexMap
[index2
];
373 if (folderIndex
!= kNumNoIndex
)
374 propVariant
= (UInt32
)folderIndex
;
377 case kpidPackedSize0
:
378 case kpidPackedSize1
:
379 case kpidPackedSize2
:
380 case kpidPackedSize3
:
381 case kpidPackedSize4
:
383 CNum folderIndex
= _database
.FileIndexToFolderIndexMap
[index2
];
384 if (folderIndex
!= kNumNoIndex
)
386 const CFolder
&folderInfo
= _database
.Folders
[folderIndex
];
387 if (_database
.FolderStartFileIndex
[folderIndex
] == (CNum
)index2
&&
388 folderInfo
.PackStreams
.Size() > (int)(propID
- kpidPackedSize0
))
390 propVariant
= _database
.GetFolderPackStreamSize(folderIndex
, propID
- kpidPackedSize0
);
393 propVariant
= UInt64(0);
396 propVariant
= UInt64(0);
401 propVariant
= item
.IsAnti
;
404 propVariant
.Detach(value
);
409 static const wchar_t *kExt
= L
"7z";
410 static const wchar_t *kAfterPart
= L
".7z";
417 UString _unchangedPart
;
418 UString _changedPart
;
421 bool InitName(const UString
&name
)
424 int dotPos
= name
.ReverseFind('.');
425 UString basePart
= name
;
428 UString ext
= name
.Mid(dotPos
+ 1);
429 if (ext
.CompareNoCase(kExt
)==0 ||
430 ext
.CompareNoCase(L
"EXE") == 0)
432 _afterPart
= kAfterPart
;
433 basePart
= name
.Left(dotPos
);
438 bool splitStyle
= false;
439 if (basePart
.Right(numLetters
) == L
"1")
441 while (numLetters
< basePart
.Length())
443 if (basePart
[basePart
.Length() - numLetters
- 1] != '0')
450 _unchangedPart
= basePart
.Left(basePart
.Length() - numLetters
);
451 _changedPart
= basePart
.Right(numLetters
);
455 UString
GetNextName()
458 // if (_newStyle || !_first)
461 int numLetters
= _changedPart
.Length();
462 for (i
= numLetters
- 1; i
>= 0; i
--)
464 wchar_t c
= _changedPart
[i
];
468 newName
= c
+ newName
;
470 newName
= UString(L
'1') + newName
;
474 newName
= UString(c
) + newName
;
477 newName
= _changedPart
[i
] + newName
;
480 _changedPart
= newName
;
483 return _unchangedPart
+ _changedPart
+ _afterPart
;
489 STDMETHODIMP
CHandler::Open(IInStream
*stream
,
490 const UInt64
*maxCheckStartPosition
,
491 IArchiveOpenCallback
*openArchiveCallback
)
496 _fileInfoPopIDs
.Clear();
500 CMyComPtr
<IArchiveOpenCallback
> openArchiveCallbackTemp
= openArchiveCallback
;
504 CMyComPtr
<IArchiveOpenVolumeCallback
> openVolumeCallback
;
508 CMyComPtr
<ICryptoGetTextPassword
> getTextPassword
;
509 if (openArchiveCallback
)
511 openArchiveCallbackTemp
.QueryInterface(
512 IID_ICryptoGetTextPassword
, &getTextPassword
);
516 if (openArchiveCallback
)
518 openArchiveCallbackTemp
.QueryInterface(IID_IArchiveOpenVolumeCallback
, &openVolumeCallback
);
522 CMyComPtr
<IInStream
> inStream
;
523 if (!_volumes
.IsEmpty())
525 if (!openVolumeCallback
)
527 if(_volumes
.Size() == 1)
531 NCOM::CPropVariant propVariant
;
532 RINOK(openVolumeCallback
->GetProperty(kpidName
, &propVariant
));
533 if (propVariant
.vt
!= VT_BSTR
)
535 baseName
= propVariant
.bstrVal
;
537 seqName
.InitName(baseName
);
540 UString fullName
= seqName
.GetNextName();
541 HRESULT result
= openVolumeCallback
->GetStream(fullName
, &inStream
);
542 if (result
== S_FALSE
)
553 RINOK(archive
.Open(inStream
, maxCheckStartPosition
));
555 _volumes
.Add(CVolume());
556 CVolume
&volume
= _volumes
.Back();
557 CArchiveDatabaseEx
&database
= volume
.Database
;
558 volume
.Stream
= inStream
;
559 volume
.StartRef2Index
= _refs
.Size();
561 HRESULT result
= archive
.ReadDatabase(database
572 for(int i
= 0; i
< database
.Files
.Size(); i
++)
575 refNew
.VolumeIndex
= _volumes
.Size() - 1;
576 refNew
.ItemIndex
= i
;
579 const CFileItem &file = database.Files[i];
583 for (j = _refs.Size() - 1; j >= 0; j--)
585 CRef2 &ref2 = _refs[j];
586 const CRef &ref = ref2.Refs.Back();
587 const CVolume &volume2 = _volumes[ref.VolumeIndex];
588 const CArchiveDatabaseEx &database2 = volume2.Database;
589 const CFileItem &file2 = database2.Files[ref.ItemIndex];
590 if (file2.Name.CompareNoCase(file.Name) == 0)
592 if (!file.IsStartPosDefined)
594 if (file.StartPos != ref2.StartPos + ref2.UnPackSize)
596 ref2.Refs.Add(refNew);
606 ref2New.Refs.Add(refNew);
607 j = _refs.Add(ref2New);
609 CRef2 &ref2 = _refs[j];
610 ref2.UnPackSize += file.UnPackSize;
611 ref2.PackSize += database.GetFilePackSize(i);
612 if (ref2.Refs.Size() == 1 && file.IsStartPosDefined)
613 ref2.StartPos = file.StartPos;
616 if (database
.Files
.Size() != 1)
618 const CFileItem
&file
= database
.Files
.Front();
619 if (!file
.IsStartPosDefined
)
624 RINOK(archive
.Open(stream
, maxCheckStartPosition
));
625 HRESULT result
= archive
.ReadDatabase(_database
640 // _inStream = stream;
648 STDMETHODIMP
CHandler::Close()
663 STDMETHODIMP
CHandler::GetStream(UInt32 index
, ISequentialInStream
**stream
)
668 CMultiStream
*streamSpec
= new CMultiStream
;
669 CMyComPtr
<ISequentialInStream
> streamTemp
= streamSpec
;
672 const UString
*fileName
;
673 for (int i
= 0; i
< _refs
.Size(); i
++)
675 const CRef
&ref
= _refs
[i
];
676 const CVolume
&volume
= _volumes
[ref
.VolumeIndex
];
677 const CArchiveDatabaseEx
&database
= volume
.Database
;
678 const CFileItem
&file
= database
.Files
[ref
.ItemIndex
];
680 fileName
= &file
.Name
;
682 if (fileName
->Compare(file
.Name
) != 0)
684 if (!file
.IsStartPosDefined
)
686 if (file
.StartPos
!= pos
)
688 CNum folderIndex
= database
.FileIndexToFolderIndexMap
[ref
.ItemIndex
];
689 if (folderIndex
== kNumNoIndex
)
691 if (file
.UnPackSize
!= 0)
695 if (database
.NumUnPackStreamsVector
[folderIndex
] != 1)
697 const CFolder
&folder
= database
.Folders
[folderIndex
];
698 if (folder
.Coders
.Size() != 1)
700 const CCoderInfo
&coder
= folder
.Coders
.Front();
701 if (coder
.NumInStreams
!= 1 || coder
.NumOutStreams
!= 1)
703 const CAltCoderInfo
&altCoder
= coder
.AltCoders
.Front();
704 if (altCoder
.MethodID
.IDSize
!= 1 || altCoder
.MethodID
.ID
[0] != 0)
707 pos
+= file
.UnPackSize
;
708 CMultiStream::CSubStreamInfo subStreamInfo
;
709 subStreamInfo
.Stream
= volume
.Stream
;
710 subStreamInfo
.Pos
= database
.GetFolderStreamPos(folderIndex
, 0);
711 subStreamInfo
.Size
= file
.UnPackSize
;
712 streamSpec
->Streams
.Add(subStreamInfo
);
715 *stream
= streamTemp
.Detach();
721 #ifdef __7Z_SET_PROPERTIES
724 STDMETHODIMP
CHandler::SetProperties(const wchar_t **names
, const PROPVARIANT
*values
, Int32 numProperties
)
727 const UInt32 numProcessors
= NSystem::GetNumberOfProcessors();
728 _numThreads
= numProcessors
;
730 for (int i
= 0; i
< numProperties
; i
++)
732 UString name
= names
[i
];
736 const PROPVARIANT
&value
= values
[i
];
738 int index
= ParseStringToUInt32(name
, number
);
741 if(name
.Left(2).CompareNoCase(L
"MT") == 0)
743 RINOK(ParseMtProp(name
.Mid(2), value
, numProcessors
, _numThreads
));