Skip to content

Infrastructure

Here we will review initial infrastructure to create handlers for sz and sze sample archives. If you need additional info see 7z-assembly.h

1. Define archive handlers

C++
struct ArchiveHandler {
  const wchar_t* name;
  GUID guid;
  const wchar_t* extension;
  const wchar_t* add_extension;
  UInt32 flags;
  char signature[2];
  bool enable_update;
  void* (*in_factory)();
};

const ArchiveHandler handlers[] = {
    {L"SZ",
     SzHandlerGuid,
     L"sz",
     L"",
     NArcInfoFlags::kByExtOnlyOpen,
     {0x53, 0x5A},
     false,
     []() -> void* {
       return new archive::SzInArchive();
     }},
    {L"SZE",
     SzeHandlerGuid,
     L"sze",
     L"",
     NArcInfoFlags::kByExtOnlyOpen,
     {0x53, 0x45},
     true,
     []() -> void* {
       return new archive::SzeInArchive();
     }},
};
struct ArchiveHandler {
  const wchar_t* name;
  GUID guid;
  const wchar_t* extension;
  const wchar_t* add_extension;
  UInt32 flags;
  char signature[2];
  bool enable_update;
  void* (*in_factory)();
};

const ArchiveHandler handlers[] = {
    {L"SZ",
     SzHandlerGuid,
     L"sz",
     L"",
     NArcInfoFlags::kByExtOnlyOpen,
     {0x53, 0x5A},
     false,
     []() -> void* {
       return new archive::SzInArchive();
     }},
    {L"SZE",
     SzeHandlerGuid,
     L"sze",
     L"",
     NArcInfoFlags::kByExtOnlyOpen,
     {0x53, 0x45},
     true,
     []() -> void* {
       return new archive::SzeInArchive();
     }},
};

Later on we define SZ and SZE handlers with corresponding GUIDs, extensions, etc.

INFO

It worth to mention that NArcInfoFlags::kByExtOnlyOpen to avoid cases when 7zip will recognize archive inside of the archive because of weak signatures.

2. Create Object

CreateObject method is used to create Archive Handlers:

C++
STDAPI_LIB CreateObject(const GUID* clsid, const GUID* iid, void** outObject) {
  for (int i = 0; i < std::size(handlers) && *outObject == nullptr; i++) {
    if (handlers[i].guid == *clsid && *iid == IID_IInArchive) {
      *outObject = handlers[i].in_factory();
    }
  }

  static_cast<IUnknown*>(*outObject)->AddRef();
  return S_OK;
}
STDAPI_LIB CreateObject(const GUID* clsid, const GUID* iid, void** outObject) {
  for (int i = 0; i < std::size(handlers) && *outObject == nullptr; i++) {
    if (handlers[i].guid == *clsid && *iid == IID_IInArchive) {
      *outObject = handlers[i].in_factory();
    }
  }

  static_cast<IUnknown*>(*outObject)->AddRef();
  return S_OK;
}

3. GetHandlerProperty2

Simply query for the properties. All of the handlers are defined in handlers array.

C++
STDAPI_LIB GetHandlerProperty2(UInt32 formatIndex, PROPID propID,
                               PROPVARIANT* value) {
  switch (propID) {
    case NArchive::NHandlerPropID::kName:
      return utils::SetVariant(handlers[formatIndex].name, value);
    case NArchive::NHandlerPropID::kClassID:
      return utils::SetPropGUID(handlers[formatIndex].guid, value);
    case NArchive::NHandlerPropID::kExtension:
      return utils::SetVariant(handlers[formatIndex].extension, value);
    case NArchive::NHandlerPropID::kAddExtension:
      return utils::SetVariant(handlers[formatIndex].add_extension, value);
    case NArchive::NHandlerPropID::kFlags:
      return utils::SetVariant(handlers[formatIndex].flags, value);
    case NArchive::NHandlerPropID::kUpdate:
      return utils::SetVariant(handlers[formatIndex].enable_update, value);
    case NArchive::NHandlerPropID::kTimeFlags:
      return S_OK;
    case NArchive::NHandlerPropID::kSignature:
      return utils::SetVariant(handlers[formatIndex].signature, 2, value);
    case NArchive::NHandlerPropID::kMultiSignature:
      return S_OK;
    case NArchive::NHandlerPropID::kSignatureOffset:
      return utils::SetVariant(0u, value);
    default:
      return E_FAIL;
  }
}
STDAPI_LIB GetHandlerProperty2(UInt32 formatIndex, PROPID propID,
                               PROPVARIANT* value) {
  switch (propID) {
    case NArchive::NHandlerPropID::kName:
      return utils::SetVariant(handlers[formatIndex].name, value);
    case NArchive::NHandlerPropID::kClassID:
      return utils::SetPropGUID(handlers[formatIndex].guid, value);
    case NArchive::NHandlerPropID::kExtension:
      return utils::SetVariant(handlers[formatIndex].extension, value);
    case NArchive::NHandlerPropID::kAddExtension:
      return utils::SetVariant(handlers[formatIndex].add_extension, value);
    case NArchive::NHandlerPropID::kFlags:
      return utils::SetVariant(handlers[formatIndex].flags, value);
    case NArchive::NHandlerPropID::kUpdate:
      return utils::SetVariant(handlers[formatIndex].enable_update, value);
    case NArchive::NHandlerPropID::kTimeFlags:
      return S_OK;
    case NArchive::NHandlerPropID::kSignature:
      return utils::SetVariant(handlers[formatIndex].signature, 2, value);
    case NArchive::NHandlerPropID::kMultiSignature:
      return S_OK;
    case NArchive::NHandlerPropID::kSignatureOffset:
      return utils::SetVariant(0u, value);
    default:
      return E_FAIL;
  }
}

4. GetHandlerProperty and GetNumberOfFormats

We have 2 formats: sz and sze. And redirecting calls from GetHandlerProperty to GetHandlerProperty2

C++
STDAPI_LIB GetHandlerProperty(PROPID propID, PROPVARIANT* value) {
  return GetHandlerProperty2(0, propID, value);
}

STDAPI_LIB GetNumberOfFormats(UINT32* numFormats) {
  *numFormats = static_cast<UInt32>(std::size(handlers));
  return S_OK;
}
STDAPI_LIB GetHandlerProperty(PROPID propID, PROPVARIANT* value) {
  return GetHandlerProperty2(0, propID, value);
}

STDAPI_LIB GetNumberOfFormats(UINT32* numFormats) {
  *numFormats = static_cast<UInt32>(std::size(handlers));
  return S_OK;
}

All set. Now we can start implementation of the SZ and SZE handlers.