1 // MubHandler.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/CpuArch.h"
6 
7 #include "../../Common/ComTry.h"
8 #include "../../Common/IntToString.h"
9 #include "../../Common/MyString.h"
10 
11 #include "../../Windows/PropVariant.h"
12 
13 #include "../Common/RegisterArc.h"
14 #include "../Common/StreamUtils.h"
15 
16 #include "HandlerCont.h"
17 
Get32(const Byte * p,bool be)18 static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
19 
20 using namespace NWindows;
21 using namespace NCOM;
22 
23 namespace NArchive {
24 namespace NMub {
25 
26 #define MACH_CPU_ARCH_ABI64 (1 << 24)
27 #define MACH_CPU_TYPE_386    7
28 #define MACH_CPU_TYPE_ARM   12
29 #define MACH_CPU_TYPE_SPARC 14
30 #define MACH_CPU_TYPE_PPC   18
31 
32 #define MACH_CPU_TYPE_PPC64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_PPC)
33 #define MACH_CPU_TYPE_AMD64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_386)
34 #define MACH_CPU_TYPE_ARM64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_ARM)
35 
36 #define MACH_CPU_SUBTYPE_LIB64 ((UInt32)1 << 31)
37 
38 #define MACH_CPU_SUBTYPE_I386_ALL 3
39 
40 struct CItem
41 {
42   UInt32 Type;
43   UInt32 SubType;
44   UInt32 Offset;
45   UInt32 Size;
46   // UInt32 Align;
47 };
48 
49 static const UInt32 kNumFilesMax = 10;
50 
51 class CHandler: public CHandlerCont
52 {
53   // UInt64 _startPos;
54   UInt64 _phySize;
55   UInt32 _numItems;
56   bool _bigEndian;
57   CItem _items[kNumFilesMax];
58 
59   HRESULT Open2(IInStream *stream);
60 
GetItem_ExtractInfo(UInt32 index,UInt64 & pos,UInt64 & size) const61   virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const
62   {
63     const CItem &item = _items[index];
64     pos = item.Offset;
65     size = item.Size;
66     return NExtract::NOperationResult::kOK;
67   }
68 
69 public:
70   INTERFACE_IInArchive_Cont(;)
71 };
72 
73 static const Byte kArcProps[] =
74 {
75   kpidBigEndian
76 };
77 
78 static const Byte kProps[] =
79 {
80   kpidSize
81 };
82 
83 IMP_IInArchive_Props
84 IMP_IInArchive_ArcProps
85 
GetArchiveProperty(PROPID propID,PROPVARIANT * value)86 STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
87 {
88   PropVariant_Clear(value);
89   switch (propID)
90   {
91     case kpidBigEndian: PropVarEm_Set_Bool(value, _bigEndian); break;
92     case kpidPhySize: PropVarEm_Set_UInt64(value, _phySize); break;
93   }
94   return S_OK;
95 }
96 
GetProperty(UInt32 index,PROPID propID,PROPVARIANT * value)97 STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
98 {
99   PropVariant_Clear(value);
100   const CItem &item = _items[index];
101   switch (propID)
102   {
103     case kpidExtension:
104     {
105       char temp[32];
106       const char *ext = 0;
107       switch (item.Type)
108       {
109         case MACH_CPU_TYPE_386:   ext = "x86";   break;
110         case MACH_CPU_TYPE_ARM:   ext = "arm";   break;
111         case MACH_CPU_TYPE_SPARC: ext = "sparc"; break;
112         case MACH_CPU_TYPE_PPC:   ext = "ppc";   break;
113         case MACH_CPU_TYPE_AMD64: ext = "x64";   break;
114         case MACH_CPU_TYPE_ARM64: ext = "arm64"; break;
115         case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break;
116         default:
117           temp[0] = 'c';
118           temp[1] = 'p';
119           temp[2] = 'u';
120           ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3);
121           if (item.Type & MACH_CPU_ARCH_ABI64)
122             MyStringCopy(temp + MyStringLen(temp), "_64");
123           break;
124       }
125       if (ext)
126         strcpy(temp, ext);
127       if (item.SubType != 0)
128       if ((item.Type != MACH_CPU_TYPE_386 &&
129            item.Type != MACH_CPU_TYPE_AMD64)
130            || (item.SubType & ~(UInt32)MACH_CPU_SUBTYPE_LIB64) != MACH_CPU_SUBTYPE_I386_ALL
131          )
132       {
133         unsigned pos = MyStringLen(temp);
134         temp[pos++] = '-';
135         ConvertUInt32ToString(item.SubType, temp + pos);
136       }
137       return PropVarEm_Set_Str(value, temp);
138     }
139     case kpidSize:
140     case kpidPackSize:
141       PropVarEm_Set_UInt64(value, item.Size);
142       break;
143   }
144   return S_OK;
145 }
146 
Open2(IInStream * stream)147 HRESULT CHandler::Open2(IInStream *stream)
148 {
149   // RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_startPos));
150 
151   const UInt32 kHeaderSize = 8;
152   const UInt32 kRecordSize = 5 * 4;
153   const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
154   Byte buf[kBufSize];
155   size_t processed = kBufSize;
156   RINOK(ReadStream(stream, buf, &processed));
157   if (processed < kHeaderSize)
158     return S_FALSE;
159 
160   bool be;
161   switch (GetBe32(buf))
162   {
163     case 0xCAFEBABE: be = true; break;
164     case 0xB9FAF10E: be = false; break;
165     default: return S_FALSE;
166   }
167   _bigEndian = be;
168   UInt32 num = Get32(buf + 4, be);
169   if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
170     return S_FALSE;
171   if (num == 0)
172     return S_FALSE;
173   UInt64 endPosMax = kHeaderSize;
174 
175   for (UInt32 i = 0; i < num; i++)
176   {
177     const Byte *p = buf + kHeaderSize + i * kRecordSize;
178     CItem &sb = _items[i];
179     sb.Type = Get32(p, be);
180     sb.SubType = Get32(p + 4, be);
181     sb.Offset = Get32(p + 8, be);
182     sb.Size = Get32(p + 12, be);
183     UInt32 align = Get32(p + 16, be);
184     if (align > 31)
185       return S_FALSE;
186     if (sb.Offset < kHeaderSize + num * kRecordSize)
187       return S_FALSE;
188     if ((sb.Type & ~MACH_CPU_ARCH_ABI64) >= 0x100 ||
189         (sb.SubType & ~MACH_CPU_SUBTYPE_LIB64) >= 0x100)
190       return S_FALSE;
191 
192     UInt64 endPos = (UInt64)sb.Offset + sb.Size;
193     if (endPosMax < endPos)
194       endPosMax = endPos;
195   }
196   _numItems = num;
197   _phySize = endPosMax;
198   return S_OK;
199 }
200 
Open(IInStream * inStream,const UInt64 *,IArchiveOpenCallback *)201 STDMETHODIMP CHandler::Open(IInStream *inStream,
202     const UInt64 * /* maxCheckStartPosition */,
203     IArchiveOpenCallback * /* openArchiveCallback */)
204 {
205   COM_TRY_BEGIN
206   Close();
207   try
208   {
209     if (Open2(inStream) != S_OK)
210       return S_FALSE;
211     _stream = inStream;
212   }
213   catch(...) { return S_FALSE; }
214   return S_OK;
215   COM_TRY_END
216 }
217 
Close()218 STDMETHODIMP CHandler::Close()
219 {
220   _stream.Release();
221   _numItems = 0;
222   _phySize = 0;
223   return S_OK;
224 }
225 
GetNumberOfItems(UInt32 * numItems)226 STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
227 {
228   *numItems = _numItems;
229   return S_OK;
230 }
231 
232 namespace NBe {
233 
234 static const Byte k_Signature[] = {
235     7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0,
236     4, 0xB9, 0xFA, 0xF1, 0x0E };
237 
238 REGISTER_ARC_I(
239   "Mub", "mub", 0, 0xE2,
240   k_Signature,
241   0,
242   NArcInfoFlags::kMultiSignature,
243   NULL)
244 
245 }
246 
247 }}
248