// Begin ---------------------------------------------------------------

using System;
using System.Runtime.InteropServices;

public class Unrar {

  // Constants
  public const int ERAR_SUCCESS          =  0;
  public const int ERAR_END_ARCHIVE      = 10;
  public const int ERAR_NO_MEMORY        = 11;
  public const int ERAR_BAD_DATA         = 12;
  public const int ERAR_BAD_ARCHIVE      = 13;
  public const int ERAR_UNKNOWN_FORMAT   = 14;
  public const int ERAR_EOPEN            = 15;
  public const int ERAR_ECREATE          = 16;
  public const int ERAR_ECLOSE           = 17;
  public const int ERAR_EREAD            = 18;
  public const int ERAR_EWRITE           = 19;
  public const int ERAR_SMALL_BUF        = 20;
  public const int ERAR_UNKNOWN          = 21;
  public const int ERAR_MISSING_PASSWORD = 22;
  public const int ERAR_EREFERENCE       = 23;
  public const int ERAR_BAD_PASSWORD     = 24;

  public const int RAR_OM_LIST           =  0;
  public const int RAR_OM_EXTRACT        =  1;
  public const int RAR_OM_LIST_INCSPLIT  =  2;

  public const int RAR_SKIP              =  0;
  public const int RAR_TEST              =  1;
  public const int RAR_EXTRACT           =  2;

  public const int RAR_VOL_ASK           =  0;
  public const int RAR_VOL_NOTIFY        =  1;

  public const int RAR_DLL_VERSION       =  8;

  public const int RAR_HASH_NONE         =  0;
  public const int RAR_HASH_CRC32        =  1;
  public const int RAR_HASH_BLAKE2       =  2;

  public const int RHDF_SPLITBEFORE      = 0x01;
  public const int RHDF_SPLITAFTER       = 0x02;
  public const int RHDF_ENCRYPTED        = 0x04;
  public const int RHDF_SOLID            = 0x10;
  public const int RHDF_DIRECTORY        = 0x20;

  public const int UCM_CHANGEVOLUME      =  0;
  public const int UCM_PROCESSDATA       =  1;
  public const int UCM_NEEDPASSWORD      =  2;
  public const int UCM_CHANGEVOLUMEW     =  3;
  public const int UCM_NEEDPASSWORDW     =  4;

  public const int ROADF_VOLUME          = 0x0001;
  public const int ROADF_COMMENT         = 0x0002;
  public const int ROADF_LOCK            = 0x0004;
  public const int ROADF_SOLID           = 0x0008;
  public const int ROADF_NEWNUMBERING    = 0x0010;
  public const int ROADF_SIGNED          = 0x0020;
  public const int ROADF_RECOVERY        = 0x0040;
  public const int ROADF_ENCHEADERS      = 0x0080;
  public const int ROADF_FIRSTVOLUME     = 0x0100;

  public const int ROADOF_KEEPBROKEN     = 0x0001;

  // Structures
  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct RARHeaderData {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string ArcName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string FileName;
    public uint Flags;
    public uint PackSize;
    public uint UnpSize;
    public uint HostOS;
    public uint FileCRC;
    public uint FileTime;
    public uint UnpVer;
    public uint Method;
    public uint FileAttr;
    [MarshalAs(UnmanagedType.LPStr)]
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  public struct RARHeaderDataEx {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
    public string ArcName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string ArcNameW;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)]
    public string FileName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
    public string FileNameW;
    public uint Flags;
    public uint PackSize;
    public uint PackSizeHigh;
    public uint UnpSize;
    public uint UnpSizeHigh;
    public uint HostOS;
    public uint FileCRC;
    public uint FileTime;
    public uint UnpVer;
    public uint Method;
    public uint FileAttr;
    [MarshalAs(UnmanagedType.LPStr)]
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
    public uint DictSize;
    public uint HashType;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string Hash;
    public uint RedirType;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string RedirName;
    public uint RedirNameSize;
    public uint DirTarget;
    public uint MtimeLow;
    public uint MtimeHigh;
    public uint CtimeLow;
    public uint CtimeHigh;
    public uint AtimeLow;
    public uint AtimeHigh;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 988)]
    public uint[] Reserved;
  }

  [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
  public struct RAROpenArchiveData {
    [MarshalAs(UnmanagedType.LPStr)]
    public string ArcName;
    public uint OpenMode;
    public uint OpenResult;
    [MarshalAs(UnmanagedType.LPStr)]
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
  }

  [StructLayout(LayoutKind.Sequential)]
  public struct RAROpenArchiveDataEx {
    [MarshalAs(UnmanagedType.LPStr)]
    public string ArcName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string ArcNameW;
    public uint OpenMode;
    public uint OpenResult;
    [MarshalAs(UnmanagedType.LPStr)]
    public string CmtBuf;
    public uint CmtBufSize;
    public uint CmtSize;
    public uint CmtState;
    public uint Flags;
    public UNRARCALLBACK Callback;
    public IntPtr UserData;
    public uint OpFlags;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string CmtBufW;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 25)]
    public uint[] Reserved;
  }

  // Delegates
  public delegate int UNRARCALLBACK(
    uint msg,
    IntPtr UserData,
    IntPtr P1,
    IntPtr P2
  );

  // External Functions
  #if x64
    private const string UnRARLib = "unrar64.dll";
  #else
    private const string UnRARLib = "unrar.dll";
  #endif

  [DllImport(UnRARLib)]
  public static extern IntPtr RAROpenArchive(
    ref RAROpenArchiveData archiveData
  );

  [DllImport(UnRARLib)]
  public static extern IntPtr RAROpenArchiveEx(
    ref RAROpenArchiveDataEx archiveData
  );

  [DllImport(UnRARLib)]
  public static extern int RARCloseArchive(
    IntPtr hArcData
  );

  [DllImport(UnRARLib)]
  public static extern int RARReadHeader(
    IntPtr hArcData,
    ref RARHeaderData headerData
  );

  [DllImport(UnRARLib)]
  public static extern int RARReadHeaderEx(
    IntPtr hArcData,
    ref RARHeaderDataEx headerData
  );

  [DllImport(UnRARLib)]
  public static extern int RARProcessFile(
    IntPtr hArcData,
    int operation,
    [MarshalAs(UnmanagedType.LPStr)] string destPath,
    [MarshalAs(UnmanagedType.LPStr)] string destName
  );

  [DllImport(UnRARLib)]
  public static extern int RARProcessFileW(
    IntPtr hArcData,
    int operation,
    [MarshalAs(UnmanagedType.LPWStr)] string destPath,
    [MarshalAs(UnmanagedType.LPWStr)] string destName
  );

  [DllImport(UnRARLib)]
  public static extern void RARSetCallback(
    IntPtr hArcData,
    UNRARCALLBACK callback,
    int userData
  );

  [DllImport(UnRARLib)]
  public static extern void RARSetPassword(
    IntPtr hArcData,
    [MarshalAs(UnmanagedType.LPStr)] string password
  );

  [DllImport(UnRARLib)]
  public static extern int RARGetDllVersion();

}

// End -----------------------------------------------------------------