Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / Archive / Tar / TarHandlerOut.cpp
1 // TarHandlerOut.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "Common/ComTry.h"\r
6 #include "Common/StringConvert.h"\r
7 \r
8 #include "Windows/PropVariant.h"\r
9 #include "Windows/Time.h"\r
10 \r
11 #include "TarHandler.h"\r
12 #include "TarUpdate.h"\r
13 \r
14 using namespace NWindows;\r
15 \r
16 namespace NArchive {\r
17 namespace NTar {\r
18 \r
19 STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)\r
20 {\r
21   *type = NFileTimeType::kUnix;\r
22   return S_OK;\r
23 }\r
24 \r
25 static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res)\r
26 {\r
27   NCOM::CPropVariant prop;\r
28   RINOK(callback->GetProperty(index, propId, &prop));\r
29   if (prop.vt == VT_BSTR)\r
30     res = UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP);\r
31   else if (prop.vt != VT_EMPTY)\r
32     return E_INVALIDARG;\r
33   return S_OK;\r
34 }\r
35 \r
36 STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,\r
37     IArchiveUpdateCallback *callback)\r
38 {\r
39   COM_TRY_BEGIN\r
40   if ((_stream && !_errorMessage.IsEmpty()) || _seqStream)\r
41     return E_NOTIMPL;\r
42   CObjectVector<CUpdateItem> updateItems;\r
43   for (UInt32 i = 0; i < numItems; i++)\r
44   {\r
45     CUpdateItem ui;\r
46     Int32 newData;\r
47     Int32 newProps;\r
48     UInt32 indexInArchive;\r
49     if (!callback)\r
50       return E_FAIL;\r
51     RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive));\r
52     ui.NewProps = IntToBool(newProps);\r
53     ui.NewData = IntToBool(newData);\r
54     ui.IndexInArchive = indexInArchive;\r
55     ui.IndexInClient = i;\r
56 \r
57     if (IntToBool(newProps))\r
58     {\r
59       {\r
60         NCOM::CPropVariant prop;\r
61         RINOK(callback->GetProperty(i, kpidIsDir, &prop));\r
62         if (prop.vt == VT_EMPTY)\r
63           ui.IsDir = false;\r
64         else if (prop.vt != VT_BOOL)\r
65           return E_INVALIDARG;\r
66         else\r
67           ui.IsDir = (prop.boolVal != VARIANT_FALSE);\r
68       }\r
69 \r
70       {\r
71         NCOM::CPropVariant prop;\r
72         RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop));\r
73         if (prop.vt == VT_EMPTY)\r
74           ui.Mode = 0777 | (ui.IsDir ? 0040000 : 0100000);\r
75         else if (prop.vt != VT_UI4)\r
76           return E_INVALIDARG;\r
77         else\r
78           ui.Mode = prop.ulVal;\r
79       }\r
80       {\r
81         NCOM::CPropVariant prop;\r
82         RINOK(callback->GetProperty(i, kpidMTime, &prop));\r
83         if (prop.vt == VT_EMPTY)\r
84           ui.Time = 0;\r
85         else if (prop.vt != VT_FILETIME)\r
86           return E_INVALIDARG;\r
87         else if (!NTime::FileTimeToUnixTime(prop.filetime, ui.Time))\r
88           ui.Time = 0;\r
89       }\r
90       {\r
91         NCOM::CPropVariant prop;\r
92         RINOK(callback->GetProperty(i, kpidPath, &prop));\r
93         if (prop.vt == VT_BSTR)\r
94           ui.Name = UnicodeStringToMultiByte(NItemName::MakeLegalName(prop.bstrVal), CP_OEMCP);\r
95         else if (prop.vt != VT_EMPTY)\r
96           return E_INVALIDARG;\r
97         if (ui.IsDir)\r
98           ui.Name += '/';\r
99       }\r
100       RINOK(GetPropString(callback, i, kpidUser, ui.User));\r
101       RINOK(GetPropString(callback, i, kpidGroup, ui.Group));\r
102     }\r
103     if (IntToBool(newData))\r
104     {\r
105       NCOM::CPropVariant prop;\r
106       RINOK(callback->GetProperty(i, kpidSize, &prop));\r
107       if (prop.vt != VT_UI8)\r
108         return E_INVALIDARG;\r
109       ui.Size = prop.uhVal.QuadPart;\r
110       /*\r
111       // now we support GNU extension for big files\r
112       if (ui.Size >= ((UInt64)1 << 33))\r
113         return E_INVALIDARG;\r
114       */\r
115     }\r
116     updateItems.Add(ui);\r
117   }\r
118   return UpdateArchive(_stream, outStream, _items, updateItems, callback);\r
119   COM_TRY_END\r
120 }\r
121 \r
122 }}\r