1 // ApmHandler.cpp 2 3 #include "StdAfx.h" 4 5 #include "../../../C/CpuArch.h" 6 7 #include "../../Common/ComTry.h" 8 9 #include "../../Windows/PropVariant.h" 10 #include "../../Windows/PropVariantUtils.h" 11 12 #include "../Common/RegisterArc.h" 13 #include "../Common/StreamUtils.h" 14 15 #include "HandlerCont.h" 16 17 // #define Get16(p) GetBe16(p) 18 #define Get32(p) GetBe32(p) 19 20 using namespace NWindows; 21 22 namespace NArchive { 23 24 namespace NDmg { 25 const char *Find_Apple_FS_Ext(const AString &name); 26 bool Is_Apple_FS_Or_Unknown(const AString &name); 27 } 28 29 namespace NApm { 30 31 static const Byte kSig0 = 'E'; 32 static const Byte kSig1 = 'R'; 33 34 static const CUInt32PCharPair k_Flags[] = 35 { 36 { 0, "VALID" }, 37 { 1, "ALLOCATED" }, 38 { 2, "IN_USE" }, 39 { 3, "BOOTABLE" }, 40 { 4, "READABLE" }, 41 { 5, "WRITABLE" }, 42 { 6, "OS_PIC_CODE" }, 43 // { 7, "OS_SPECIFIC_2" }, // "Unused" 44 // { 8, "ChainCompatible" }, // "OS_SPECIFIC_1" 45 // { 9, "RealDeviceDriver" }, 46 // { 10, "CanChainToNext" }, 47 { 30, "MOUNTED_AT_STARTUP" }, 48 { 31, "STARTUP" } 49 }; 50 51 #define DPME_FLAGS_VALID (1u << 0) 52 #define DPME_FLAGS_ALLOCATED (1u << 1) 53 54 static const unsigned k_Str_Size = 32; 55 56 struct CItem 57 { 58 UInt32 StartBlock; 59 UInt32 NumBlocks; 60 UInt32 Flags; // pmPartStatus 61 char Name[k_Str_Size]; 62 char Type[k_Str_Size]; 63 /* 64 UInt32 DataStartBlock; 65 UInt32 NumDataBlocks; 66 UInt32 BootStartBlock; 67 UInt32 BootSize; 68 UInt32 BootAddr; 69 UInt32 BootEntry; 70 UInt32 BootChecksum; 71 char Processor[16]; 72 */ 73 Is_Valid_and_AllocatedNArchive::NApm::CItem74 bool Is_Valid_and_Allocated() const 75 { return (Flags & (DPME_FLAGS_VALID | DPME_FLAGS_ALLOCATED)) != 0; } 76 ParseNArchive::NApm::CItem77 bool Parse(const Byte *p, UInt32 &numBlocksInMap) 78 { 79 numBlocksInMap = Get32(p + 4); 80 StartBlock = Get32(p + 8); 81 NumBlocks = Get32(p + 0xc); 82 Flags = Get32(p + 0x58); 83 memcpy(Name, p + 0x10, k_Str_Size); 84 memcpy(Type, p + 0x30, k_Str_Size); 85 if (GetUi32(p) != 0x4d50) // "PM" 86 return false; 87 /* 88 DataStartBlock = Get32(p + 0x50); 89 NumDataBlocks = Get32(p + 0x54); 90 BootStartBlock = Get32(p + 0x5c); 91 BootSize = Get32(p + 0x60); 92 BootAddr = Get32(p + 0x64); 93 if (Get32(p + 0x68) != 0) 94 return false; 95 BootEntry = Get32(p + 0x6c); 96 if (Get32(p + 0x70) != 0) 97 return false; 98 BootChecksum = Get32(p + 0x74); 99 memcpy(Processor, p + 0x78, 16); 100 */ 101 return true; 102 } 103 }; 104 105 106 Z7_class_CHandler_final: public CHandlerCont 107 { 108 Z7_IFACE_COM7_IMP(IInArchive_Cont) 109 110 CRecordVector<CItem> _items; 111 unsigned _blockSizeLog; 112 UInt32 _numBlocks; 113 UInt64 _phySize; 114 bool _isArc; 115 116 UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; } 117 118 virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override 119 { 120 const CItem &item = _items[index]; 121 pos = BlocksToBytes(item.StartBlock); 122 size = BlocksToBytes(item.NumBlocks); 123 return NExtract::NOperationResult::kOK; 124 } 125 }; 126 127 static const UInt32 kSectorSize = 512; 128 129 // we support only 4 cluster sizes: 512, 1024, 2048, 4096 */ 130 131 API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size) 132 { 133 if (size < kSectorSize) 134 return k_IsArc_Res_NEED_MORE; 135 if (GetUi64(p + 8) != 0) 136 return k_IsArc_Res_NO; 137 UInt32 v = GetUi32(p); // we read as little-endian 138 v ^= (kSig0 | (unsigned)kSig1 << 8); 139 if ((v & ~((UInt32)0xf << 17))) 140 return k_IsArc_Res_NO; 141 if ((0x116u >> (v >> 17)) & 1) 142 return k_IsArc_Res_YES; 143 return k_IsArc_Res_NO; 144 } 145 } 146 147 Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */)) 148 { 149 COM_TRY_BEGIN 150 Close(); 151 152 Byte buf[kSectorSize]; 153 unsigned numSectors_in_Cluster; 154 { 155 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 156 if (GetUi64(buf + 8) != 0) 157 return S_FALSE; 158 UInt32 v = GetUi32(buf); // we read as little-endian 159 v ^= (kSig0 | (unsigned)kSig1 << 8); 160 if ((v & ~((UInt32)0xf << 17))) 161 return S_FALSE; 162 v >>= 16; 163 if (v == 0) 164 return S_FALSE; 165 if (v & (v - 1)) 166 return S_FALSE; 167 const unsigned a = (0x30210u >> v) & 3; 168 // a = 0; // for debug 169 numSectors_in_Cluster = 1u << a; 170 _blockSizeLog = 9 + a; 171 } 172 173 UInt32 numBlocks = Get32(buf + 4); 174 _numBlocks = numBlocks; 175 176 { 177 for (unsigned k = numSectors_in_Cluster; --k != 0;) 178 { 179 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 180 } 181 } 182 183 UInt32 numBlocksInMap = 0; 184 185 for (unsigned i = 0;;) 186 { 187 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 188 189 CItem item; 190 191 UInt32 numBlocksInMap2 = 0; 192 if (!item.Parse(buf, numBlocksInMap2)) 193 return S_FALSE; 194 if (i == 0) 195 { 196 numBlocksInMap = numBlocksInMap2; 197 if (numBlocksInMap > (1 << 8) || numBlocksInMap == 0) 198 return S_FALSE; 199 } 200 else if (numBlocksInMap2 != numBlocksInMap) 201 return S_FALSE; 202 203 const UInt32 finish = item.StartBlock + item.NumBlocks; 204 if (finish < item.StartBlock) 205 return S_FALSE; 206 if (numBlocks < finish) 207 numBlocks = finish; 208 209 _items.Add(item); 210 for (unsigned k = numSectors_in_Cluster; --k != 0;) 211 { 212 RINOK(ReadStream_FALSE(stream, buf, kSectorSize)) 213 } 214 if (++i == numBlocksInMap) 215 break; 216 } 217 218 _phySize = BlocksToBytes(numBlocks); 219 _isArc = true; 220 _stream = stream; 221 222 return S_OK; 223 COM_TRY_END 224 } 225 226 227 Z7_COM7F_IMF(CHandler::Close()) 228 { 229 _isArc = false; 230 _phySize = 0; 231 _items.Clear(); 232 _stream.Release(); 233 return S_OK; 234 } 235 236 237 static const Byte kProps[] = 238 { 239 kpidPath, 240 kpidSize, 241 kpidOffset, 242 kpidCharacts 243 }; 244 245 static const Byte kArcProps[] = 246 { 247 kpidClusterSize, 248 kpidNumBlocks 249 }; 250 251 IMP_IInArchive_Props 252 IMP_IInArchive_ArcProps 253 254 static AString GetString(const char *s) 255 { 256 AString res; 257 res.SetFrom_CalcLen(s, k_Str_Size); 258 return res; 259 } 260 261 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)) 262 { 263 COM_TRY_BEGIN 264 NCOM::CPropVariant prop; 265 switch (propID) 266 { 267 case kpidMainSubfile: 268 { 269 int mainIndex = -1; 270 FOR_VECTOR (i, _items) 271 { 272 const CItem &item = _items[i]; 273 if (!item.Is_Valid_and_Allocated()) 274 continue; 275 AString s (GetString(item.Type)); 276 if (NDmg::Is_Apple_FS_Or_Unknown(s)) 277 { 278 if (mainIndex != -1) 279 { 280 mainIndex = -1; 281 break; 282 } 283 mainIndex = (int)i; 284 } 285 } 286 if (mainIndex != -1) 287 prop = (UInt32)(Int32)mainIndex; 288 break; 289 } 290 case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break; 291 case kpidPhySize: prop = _phySize; break; 292 case kpidNumBlocks: prop = _numBlocks; break; 293 294 case kpidErrorFlags: 295 { 296 UInt32 v = 0; 297 if (!_isArc) v |= kpv_ErrorFlags_IsNotArc; 298 prop = v; 299 break; 300 } 301 } 302 prop.Detach(value); 303 return S_OK; 304 COM_TRY_END 305 } 306 307 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems)) 308 { 309 *numItems = _items.Size(); 310 return S_OK; 311 } 312 313 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) 314 { 315 COM_TRY_BEGIN 316 NCOM::CPropVariant prop; 317 const CItem &item = _items[index]; 318 switch (propID) 319 { 320 case kpidPath: 321 { 322 AString s (GetString(item.Name)); 323 if (s.IsEmpty()) 324 s.Add_UInt32(index); 325 AString type (GetString(item.Type)); 326 { 327 const char *ext = NDmg::Find_Apple_FS_Ext(type); 328 if (ext) 329 type = ext; 330 } 331 if (!type.IsEmpty()) 332 { 333 s.Add_Dot(); 334 s += type; 335 } 336 prop = s; 337 break; 338 } 339 case kpidSize: 340 case kpidPackSize: 341 prop = BlocksToBytes(item.NumBlocks); 342 break; 343 case kpidOffset: prop = BlocksToBytes(item.StartBlock); break; 344 case kpidCharacts: FLAGS_TO_PROP(k_Flags, item.Flags, prop); break; 345 } 346 prop.Detach(value); 347 return S_OK; 348 COM_TRY_END 349 } 350 351 static const Byte k_Signature[] = { kSig0, kSig1 }; 352 353 REGISTER_ARC_I( 354 "APM", "apm", NULL, 0xD4, 355 k_Signature, 356 0, 357 0, 358 IsArc_Apm) 359 360 }} 361