Fix splitting of cells (noticed by Hartmut).
[reactos.git] / reactos / boot / freeldr / freeldr / reactos / binhive.c
index 60f7329..b062b96 100644 (file)
  */
 
 #include <freeldr.h>
-#include <rtl.h>
-#include <mm.h>
-#include <debug.h>
-
-#include "registry.h"
 
+#define NDEBUG
+#include <debug.h>
 
 #define  REG_HIVE_ID                   0x66676572 /* "regf" */
 #define  REG_BIN_ID                    0x6e696268 /* "hbin" */
 
 
 /* BLOCK_OFFSET = offset in file after header block */
-typedef U32 BLOCK_OFFSET, *PBLOCK_OFFSET;
+typedef ULONG BLOCK_OFFSET, *PBLOCK_OFFSET;
 
 /* header for registry hive file : */
 typedef struct _HIVE_HEADER
 {
   /* Hive identifier "regf" (0x66676572) */
-  U32  BlockId;
+  ULONG  BlockId;
 
   /* Update counter */
-  U32  UpdateCounter1;
+  ULONG  UpdateCounter1;
 
   /* Update counter */
-  U32  UpdateCounter2;
+  ULONG  UpdateCounter2;
 
   /* When this hive file was last modified */
-  U64  DateModified;   /* FILETIME */
+  ULONGLONG  DateModified;
 
-  /* Registry format version ? (1?) */
-  U32  Unused3;
+  /* Registry format major version (1) */
+  ULONG  MajorVersion;
 
-  /* Registry format version ? (3?) */
-  U32  Unused4;
+  /* Registry format minor version (3)
+     Version 3 added fast indexes, version 5 has large value optimizations */
+  ULONG  MinorVersion;
 
-  /* Registry format version ? (0?) */
-  U32  Unused5;
+  /* Registry file type (0 - Primary, 1 - Log) */
+  ULONG  Type;
 
-  /* Registry format version ? (1?) */
-  U32  Unused6;
+  /* Registry format (1 is the only defined value so far) */
+  ULONG  Format;
 
   /* Offset into file from the byte after the end of the base block.
      If the hive is volatile, this is the actual pointer to the KEY_CELL */
   BLOCK_OFFSET  RootKeyOffset;
 
   /* Size of each hive block ? */
-  U32  BlockSize;
+  ULONG  BlockSize;
 
   /* (1?) */
-  U32  Unused7;
+  ULONG  Unused7;
 
   /* Name of hive file */
-  WCHAR  FileName[64];
+  WCHAR  FileName[48];
 
-  /* ? */
-  U32  Unused8[83];
+  ULONG  Reserved[99];
 
   /* Checksum of first 0x200 bytes */
-  U32  Checksum;
+  ULONG  Checksum;
 } __attribute__((packed)) HIVE_HEADER, *PHIVE_HEADER;
 
 
 typedef struct _BIN_HEADER
 {
   /* Bin identifier "hbin" (0x6E696268) */
-  U32  HeaderId;
+  ULONG  HeaderId;
 
-  /* Bin offset */
+  /* Block offset of this bin */
   BLOCK_OFFSET  BinOffset;
 
   /* Size in bytes, multiple of the block size (4KB) */
-  U32  BinSize;
+  ULONG  BinSize;
 
-  /* ? */
-  U32  Unused1;
+  ULONG  Reserved[2];
 
   /* When this bin was last modified */
-  U64  DateModified;           /* FILETIME */
+  ULONGLONG  DateModified;
 
-  /* ? */
-  U32  Unused2;
+  /* ? (In-memory only) */
+  ULONG  MemAlloc;
 } __attribute__((packed)) HBIN, *PHBIN;
 
 
 typedef struct _CELL_HEADER
 {
   /* <0 if used, >0 if free */
-  S32  CellSize;
+  LONG  CellSize;
 } __attribute__((packed)) CELL_HEADER, *PCELL_HEADER;
 
 
 typedef struct _KEY_CELL
 {
   /* Size of this cell */
-  S32  CellSize;
+  LONG  CellSize;
 
   /* Key cell identifier "kn" (0x6b6e) */
-  U16  Id;
+  USHORT  Id;
 
-  /* ? */
-  U16  Type;
+  /* Flags */
+  USHORT  Flags;
 
   /* Time of last flush */
-  U64  LastWriteTime;          /* FILETIME */
+  ULONGLONG  LastWriteTime;            /* FILETIME */
 
   /* ? */
-  U32  UnUsed1;
+  ULONG  UnUsed1;
 
   /* Block offset of parent key cell */
   BLOCK_OFFSET  ParentKeyOffset;
 
   /* Count of sub keys for the key in this key cell */
-  U32  NumberOfSubKeys;
+  ULONG  NumberOfSubKeys;
 
   /* ? */
-  U32  UnUsed2;
+  ULONG  UnUsed2;
 
   /* Block offset of has table for FIXME: subkeys/values? */
   BLOCK_OFFSET  HashTableOffset;
 
   /* ? */
-  U32  UnUsed3;
+  ULONG  UnUsed3;
 
   /* Count of values contained in this key cell */
-  U32  NumberOfValues;
+  ULONG  NumberOfValues;
 
   /* Block offset of VALUE_LIST_CELL */
   BLOCK_OFFSET  ValueListOffset;
@@ -169,23 +165,23 @@ typedef struct _KEY_CELL
   BLOCK_OFFSET  ClassNameOffset;
 
   /* ? */
-  U32  Unused4[5];
+  ULONG  Unused4[5];
 
   /* Size in bytes of key name */
-  U16 NameSize;
+  USHORT NameSize;
 
   /* Size of class name in bytes */
-  U16 ClassSize;
+  USHORT ClassSize;
 
   /* Name of key (not zero terminated) */
-  U8  Name[0];
+  CHAR  Name[0];
 } __attribute__((packed)) KEY_CELL, *PKEY_CELL;
 
 
 /* KEY_CELL.Type constants */
 #define  REG_LINK_KEY_CELL_TYPE        0x10
-#define  REG_KEY_CELL_TYPE             0x20
-#define  REG_ROOT_KEY_CELL_TYPE        0x2c
+#define  REG_KEY_NAME_PACKED           0x20
+#define  REG_ROOT_KEY_CELL_TYPE        0x0c
 
 
 // hash record :
@@ -193,37 +189,37 @@ typedef struct _KEY_CELL
 typedef struct _HASH_RECORD
 {
   BLOCK_OFFSET  KeyOffset;
-  U32  HashValue;
+  ULONG  HashValue;
 } __attribute__((packed)) HASH_RECORD, *PHASH_RECORD;
 
 
 typedef struct _HASH_TABLE_CELL
 {
-  S32  CellSize;
-  U16  Id;
-  U16  HashTableSize;
+  LONG  CellSize;
+  USHORT  Id;
+  USHORT  HashTableSize;
   HASH_RECORD  Table[0];
 } __attribute__((packed)) HASH_TABLE_CELL, *PHASH_TABLE_CELL;
 
 
 typedef struct _VALUE_LIST_CELL
 {
-  S32  CellSize;
+  LONG  CellSize;
   BLOCK_OFFSET  ValueOffset[0];
 } __attribute__((packed)) VALUE_LIST_CELL, *PVALUE_LIST_CELL;
 
 
 typedef struct _VALUE_CELL
 {
-  S32  CellSize;
-  U16  Id;     // "kv"
-  U16  NameSize;       // length of Name
-  U32  DataSize;       // length of datas in the cell pointed by DataOffset
+  LONG  CellSize;
+  USHORT  Id;  // "kv"
+  USHORT  NameSize;    // length of Name
+  ULONG  DataSize;     // length of datas in the cell pointed by DataOffset
   BLOCK_OFFSET  DataOffset;// datas are here if high bit of DataSize is set
-  U32  DataType;
-  U16  Flags;
-  U16 Unused1;
-  UCHAR  Name[0]; /* warning : not zero terminated */
+  ULONG  DataType;
+  USHORT  Flags;
+  USHORT Unused1;
+  CHAR  Name[0]; /* warning : not zero terminated */
 } __attribute__((packed)) VALUE_CELL, *PVALUE_CELL;
 
 /* VALUE_CELL.Flags constants */
@@ -236,26 +232,26 @@ typedef struct _VALUE_CELL
 
 typedef struct _DATA_CELL
 {
-  S32  CellSize;
-  UCHAR  Data[0];
+  LONG  CellSize;
+  CHAR  Data[0];
 } __attribute__((packed)) DATA_CELL, *PDATA_CELL;
 
 
 typedef struct _REGISTRY_HIVE
 {
-  U32  FileSize;
+  ULONG  FileSize;
   PHIVE_HEADER  HiveHeader;
-  U32  BlockListSize;
+  ULONG  BlockListSize;
   PHBIN  *BlockList;
-  U32  FreeListSize;
-  U32  FreeListMax;
+  ULONG  FreeListSize;
+  ULONG  FreeListMax;
   PCELL_HEADER *FreeList;
   BLOCK_OFFSET *FreeListOffset;
 } REGISTRY_HIVE, *PREGISTRY_HIVE;
 
 
 static PVOID MbBase = NULL;
-static U32 MbSize = 0;
+static ULONG MbSize = 0;
 
 /* FUNCTIONS ****************************************************************/
 
@@ -268,13 +264,13 @@ InitMbMemory (PVOID ChunkBase)
 
 
 static PVOID
-AllocateMbMemory (U32 MemSize)
+AllocateMbMemory (ULONG MemSize)
 {
   PVOID CurBase;
 
   CurBase = MbBase;
 
-  MbBase = (PVOID)((U32)MbBase + MemSize);
+  MbBase = (PVOID)((ULONG)MbBase + MemSize);
   MbSize += MemSize;
 
   return CurBase;
@@ -286,7 +282,7 @@ FreeMbMemory (VOID)
   MbSize = 0;
 }
 
-static U32
+static ULONG
 GetMbAllocatedSize (VOID)
 {
   return MbSize;
@@ -301,15 +297,14 @@ CmiCreateDefaultHiveHeader (PHIVE_HEADER Header)
   Header->BlockId = REG_HIVE_ID;
   Header->UpdateCounter1 = 0;
   Header->UpdateCounter2 = 0;
-  Header->DateModified = 0ULL;
-  Header->Unused3 = 1;
-  Header->Unused4 = 3;
-  Header->Unused5 = 0;
-  Header->Unused6 = 1;
+  Header->DateModified = 0;
+  Header->MajorVersion = 1;
+  Header->MinorVersion = 3;
+  Header->Type = 0;
+  Header->Format = 1;
   Header->Unused7 = 1;
   Header->RootKeyOffset = -1;
   Header->BlockSize = REG_BLOCK_SIZE;
-  Header->Unused6 = 1;
   Header->Checksum = 0;
 }
 
@@ -326,22 +321,34 @@ CmiCreateDefaultBinCell (PHBIN BinCell)
 
 
 static VOID
-CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell, PCHAR KeyName)
+CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell, PCWSTR KeyName)
 {
-  PCHAR BaseKeyName;
-  U32 NameSize;
-  U32 CellSize;
+  PWCHAR BaseKeyName;
+  ULONG NameSize;
+  ULONG CellSize;
+  ULONG i;
+  BOOL Packable = TRUE;
 
   assert (RootKeyCell);
 
-  BaseKeyName = strrchr(KeyName, '\\') + 1;
-  NameSize = strlen(BaseKeyName);
-  CellSize = ROUND_UP(sizeof(KEY_CELL) + NameSize - 1, 16);
+  BaseKeyName = wcsrchr(KeyName, L'\\') + 1;
+  NameSize = wcslen(BaseKeyName);
+  for (i = 0; i < NameSize; i++)
+    {
+      if (KeyName[i] & 0xFF00)
+        {
+          Packable = FALSE;
+          NameSize *= sizeof(WCHAR);
+          break;
+        }
+    }
+
+  CellSize = ROUND_UP(sizeof(KEY_CELL) + NameSize, 16);
 
   memset (RootKeyCell, 0, CellSize);
   RootKeyCell->CellSize = -CellSize;
   RootKeyCell->Id = REG_KEY_CELL_ID;
-  RootKeyCell->Type = REG_ROOT_KEY_CELL_TYPE;
+  RootKeyCell->Flags = REG_ROOT_KEY_CELL_TYPE;
   RootKeyCell->LastWriteTime = 0ULL;
   RootKeyCell->ParentKeyOffset = 0;
   RootKeyCell->NumberOfSubKeys = 0;
@@ -352,12 +359,23 @@ CmiCreateDefaultRootKeyCell (PKEY_CELL RootKeyCell, PCHAR KeyName)
   RootKeyCell->ClassNameOffset = -1;
   RootKeyCell->NameSize = NameSize;
   RootKeyCell->ClassSize = 0;
-  memcpy (RootKeyCell->Name, BaseKeyName, NameSize);
+  if (Packable)
+    {
+      for(i = 0; i < NameSize; i++)
+        {
+          ((PCHAR)RootKeyCell->Name)[i] = BaseKeyName[i];
+        }
+      RootKeyCell->Flags |= REG_KEY_NAME_PACKED;
+    }
+  else
+    {
+      memcpy (RootKeyCell->Name, BaseKeyName, NameSize);
+    }
 }
 
 
 static PREGISTRY_HIVE
-CmiCreateHive (PCHAR KeyName)
+CmiCreateHive (PCWSTR KeyName)
 {
   PREGISTRY_HIVE Hive;
   PCELL_HEADER FreeCell;
@@ -428,12 +446,12 @@ CmiCreateHive (PCHAR KeyName)
   BinCell->BinOffset = 0;
 
   /* Init root key cell */
-  RootKeyCell = (PKEY_CELL)((U32)BinCell + REG_HBIN_DATA_OFFSET);
+  RootKeyCell = (PKEY_CELL)((ULONG)BinCell + REG_HBIN_DATA_OFFSET);
   CmiCreateDefaultRootKeyCell(RootKeyCell, KeyName);
   Hive->HiveHeader->RootKeyOffset = REG_HBIN_DATA_OFFSET;
 
   /* Init free cell */
-  FreeCell = (PCELL_HEADER)((U32)RootKeyCell - RootKeyCell->CellSize);
+  FreeCell = (PCELL_HEADER)((ULONG)RootKeyCell - RootKeyCell->CellSize);
   FreeCell->CellSize = REG_BLOCK_SIZE - (REG_HBIN_DATA_OFFSET - RootKeyCell->CellSize);
 
   Hive->FreeList[0] = FreeCell;
@@ -463,9 +481,9 @@ static PHBIN
 CmiGetBin (PREGISTRY_HIVE Hive,
           BLOCK_OFFSET BlockOffset)
 {
-  U32 BlockIndex;
+  ULONG BlockIndex;
 
-  if (BlockOffset == (U32) -1)
+  if (BlockOffset == (ULONG) -1)
     return NULL;
 
   BlockIndex = BlockOffset / REG_BLOCK_SIZE;
@@ -483,10 +501,10 @@ CmiMergeFree(PREGISTRY_HIVE RegistryHive,
 {
   BLOCK_OFFSET BlockOffset;
   BLOCK_OFFSET BinOffset;
-  U32 BlockSize;
-  U32 BinSize;
+  ULONG BlockSize;
+  ULONG BinSize;
   PHBIN Bin;
-  U32 i;
+  ULONG i;
 
   DbgPrint((DPRINT_REGISTRY, "CmiMergeFree(Block %lx  Offset %lx  Size %lx) called\n",
           FreeBlock, FreeOffset, FreeBlock->CellSize));
@@ -574,9 +592,9 @@ CmiAddFree(PREGISTRY_HIVE RegistryHive,
 {
   PCELL_HEADER *tmpList;
   BLOCK_OFFSET *tmpListOffset;
-  S32 minInd;
-  S32 maxInd;
-  S32 medInd;
+  LONG minInd;
+  LONG maxInd;
+  LONG medInd;
 
   assert(RegistryHive);
   assert(FreeBlock);
@@ -675,15 +693,15 @@ CmiAddFree(PREGISTRY_HIVE RegistryHive,
 
 static BOOL
 CmiAddBin(PREGISTRY_HIVE RegistryHive,
-         U32 BlockCount,
+         ULONG BlockCount,
          PVOID *NewBlock,
          PBLOCK_OFFSET NewBlockOffset)
 {
   PCELL_HEADER tmpBlock;
   PHBIN *BlockList;
   PHBIN tmpBin;
-  U32 BinSize;
-  U32 i;
+  ULONG BinSize;
+  ULONG i;
 
   BinSize = BlockCount * REG_BLOCK_SIZE;
   tmpBin = AllocateMbMemory (BinSize);
@@ -697,9 +715,8 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
   tmpBin->BinOffset = RegistryHive->FileSize - REG_BLOCK_SIZE;
   RegistryHive->FileSize += BinSize;
   tmpBin->BinSize = BinSize;
-  tmpBin->Unused1 = 0;
   tmpBin->DateModified = 0ULL;
-  tmpBin->Unused2 = 0;
+  tmpBin->MemAlloc = 0;
 
   /* Increase size of list of blocks */
   BlockList = MmAllocateMemory (sizeof(PHBIN) * (RegistryHive->BlockListSize + BlockCount));
@@ -722,7 +739,7 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
   RegistryHive->BlockListSize += BlockCount;
 
   /* Initialize a free block in this heap : */
-  tmpBlock = (PCELL_HEADER)((U32) tmpBin + REG_HBIN_DATA_OFFSET);
+  tmpBlock = (PCELL_HEADER)((ULONG) tmpBin + REG_HBIN_DATA_OFFSET);
   tmpBlock->CellSize = (REG_BLOCK_SIZE - REG_HBIN_DATA_OFFSET);
 
   *NewBlock = (PVOID) tmpBlock;
@@ -736,12 +753,12 @@ CmiAddBin(PREGISTRY_HIVE RegistryHive,
 
 static BOOL
 CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
-                S32 CellSize,
+                LONG CellSize,
                 PVOID *Block,
                 PBLOCK_OFFSET pBlockOffset)
 {
   PCELL_HEADER NewBlock;
-  U32 i;
+  ULONG i;
 
   *Block = NULL;
 
@@ -790,8 +807,9 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
   /* Split the block in two parts */
   if (NewBlock->CellSize > CellSize)
     {
-      NewBlock = (PCELL_HEADER) ((U32)NewBlock + CellSize);
+      NewBlock = (PCELL_HEADER) ((ULONG)NewBlock + CellSize);
       NewBlock->CellSize = ((PCELL_HEADER) (*Block))->CellSize - CellSize;
+      ((PCELL_HEADER) (*Block))->CellSize = CellSize;
       CmiAddFree (RegistryHive,
                  NewBlock,
                  *pBlockOffset + CellSize,
@@ -803,7 +821,7 @@ CmiAllocateCell (PREGISTRY_HIVE RegistryHive,
     }
 
   memset(*Block, 0, CellSize);
-  ((PCELL_HEADER)(*Block))->CellSize = -CellSize;
+  ((PCELL_HEADER)(*Block))->CellSize *= -1;
 
   return TRUE;
 }
@@ -814,9 +832,9 @@ CmiGetCell (PREGISTRY_HIVE Hive,
            BLOCK_OFFSET BlockOffset)
 {
   PHBIN Bin;
-  U32 BlockIndex;
+  ULONG BlockIndex;
 
-  if (BlockOffset == (U32) -1)
+  if (BlockOffset == (ULONG) -1)
     return NULL;
 
   BlockIndex = BlockOffset / REG_BLOCK_SIZE;
@@ -827,20 +845,20 @@ CmiGetCell (PREGISTRY_HIVE Hive,
   if (Bin == NULL)
     return NULL;
 
-  return (PVOID)((U32)Bin + (BlockOffset - Bin->BinOffset));
+  return (PVOID)((ULONG)Bin + (BlockOffset - Bin->BinOffset));
 }
 
 
 static BOOL
 CmiAllocateHashTableCell (PREGISTRY_HIVE Hive,
                          PBLOCK_OFFSET HBOffset,
-                         U32 SubKeyCount)
+                         ULONG SubKeyCount)
 {
   PHASH_TABLE_CELL HashCell;
-  U32 NewHashSize;
+  ULONG NewHashSize;
   BOOL Status;
 
-  NewHashSize = sizeof(HASH_TABLE_CELL) + 
+  NewHashSize = sizeof(HASH_TABLE_CELL) +
                (SubKeyCount * sizeof(HASH_RECORD));
   Status = CmiAllocateCell (Hive,
                            NewHashSize,
@@ -866,7 +884,7 @@ CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive,
 {
   PHASH_TABLE_CELL HashBlock;
   PKEY_CELL ParentKeyCell;
-  U32 i;
+  ULONG i;
 
   ParentKeyCell = CmiGetCell (Hive, ParentKeyOffset);
   if (ParentKeyCell == NULL)
@@ -889,7 +907,7 @@ CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive,
          HashBlock->Table[i].KeyOffset = NKBOffset;
          memcpy (&HashBlock->Table[i].HashValue,
                  NewKeyCell->Name,
-                 4);
+                 min(NewKeyCell->NameSize, sizeof(ULONG)));
          ParentKeyCell->NumberOfSubKeys++;
          return TRUE;
        }
@@ -902,10 +920,10 @@ CmiAddKeyToParentHashTable (PREGISTRY_HIVE Hive,
 static BOOL
 CmiAllocateValueListCell (PREGISTRY_HIVE Hive,
                          PBLOCK_OFFSET ValueListOffset,
-                         U32 ValueCount)
+                         ULONG ValueCount)
 {
   PVALUE_LIST_CELL ValueListCell;
-  U32 ValueListSize;
+  ULONG ValueListSize;
   BOOL Status;
 
   ValueListSize = sizeof(VALUE_LIST_CELL) +
@@ -928,13 +946,24 @@ static BOOL
 CmiAllocateValueCell(PREGISTRY_HIVE Hive,
                     PVALUE_CELL *ValueCell,
                     BLOCK_OFFSET *ValueCellOffset,
-                    PCHAR ValueName)
+                    PWCHAR ValueName)
 {
   PVALUE_CELL NewValueCell;
-  U32 NameSize;
+  ULONG NameSize;
   BOOL Status;
+  BOOLEAN Packable = TRUE;
+  ULONG i;
 
-  NameSize = (ValueName == NULL) ? 0 : strlen (ValueName);
+  NameSize = (ValueName == NULL) ? 0 : wcslen (ValueName);
+  for (i = 0; i < NameSize; i++)
+    {
+      if (ValueName[i] & 0xFF00)
+        {
+          NameSize *= sizeof(WCHAR);
+          Packable = FALSE;
+          break;
+        }
+    }
   Status = CmiAllocateCell (Hive,
                            sizeof(VALUE_CELL) + NameSize,
                            (PVOID*)(PVOID)&NewValueCell,
@@ -947,12 +976,23 @@ CmiAllocateValueCell(PREGISTRY_HIVE Hive,
 
   NewValueCell->Id = REG_VALUE_CELL_ID;
   NewValueCell->NameSize = NameSize;
+  NewValueCell->Flags = 0;
   if (NameSize > 0)
     {
-      memcpy (NewValueCell->Name,
-             ValueName,
-             NameSize);
-      NewValueCell->Flags = REG_VALUE_NAME_PACKED;
+      if (Packable)
+        {
+          for (i = 0; i < NameSize; i++)
+            {
+              ((PCHAR)NewValueCell->Name)[i] = (CHAR)ValueName[i];
+            }
+          NewValueCell->Flags |= REG_VALUE_NAME_PACKED;
+        }
+      else
+        {
+          memcpy (NewValueCell->Name,
+                 ValueName,
+                 NameSize);
+        }
     }
   NewValueCell->DataType = 0;
   NewValueCell->DataSize = 0;
@@ -992,36 +1032,21 @@ CmiAddValueToKeyValueList(PREGISTRY_HIVE Hive,
   return TRUE;
 }
 
-
-static VOID
-memexpand (PWCHAR Dst,
-          PCHAR Src,
-          U32 Length)
-{
-  U32 i;
-
-  for (i = 0; i < Length; i++)
-    Dst[i] = (WCHAR)Src[i];
-}
-
-
 static BOOL
 CmiExportValue (PREGISTRY_HIVE Hive,
                BLOCK_OFFSET KeyCellOffset,
-               HKEY Key,
+               FRLDRHKEY Key,
                PVALUE Value)
 {
   BLOCK_OFFSET ValueCellOffset;
   BLOCK_OFFSET DataCellOffset;
   PVALUE_CELL ValueCell;
   PDATA_CELL DataCell;
-  U32 SrcDataSize;
-  U32 DstDataSize;
-  U32 DataType;
-  PUCHAR Data;
-  BOOL Expand = FALSE;
+  ULONG DataSize;
+  ULONG DataType;
+  PCHAR Data;
 
-  DbgPrint((DPRINT_REGISTRY, "CmiExportValue('%s') called\n",
+  DbgPrint((DPRINT_REGISTRY, "CmiExportValue('%S') called\n",
           (Value == NULL) ? "<default>" : (PCHAR)Value->Name));
   DbgPrint((DPRINT_REGISTRY, "DataSize %lu\n",
           (Value == NULL) ? Key->DataSize : Value->DataSize));
@@ -1040,47 +1065,29 @@ CmiExportValue (PREGISTRY_HIVE Hive,
   if (Value == NULL)
     {
       DataType = Key->DataType;
-      SrcDataSize = Key->DataSize;
+      DataSize = Key->DataSize;
       Data = Key->Data;
     }
   else
     {
       DataType = Value->DataType;
-      SrcDataSize = Value->DataSize;
+      DataSize = Value->DataSize;
       Data = Value->Data;
     }
 
-  DstDataSize = SrcDataSize;
-  if (DataType == REG_SZ ||
-      DataType == REG_EXPAND_SZ ||
-      DataType == REG_MULTI_SZ)
+  if (DataSize <= sizeof(BLOCK_OFFSET))
     {
-      DstDataSize *= sizeof(WCHAR);
-      Expand = TRUE;
-    }
-
-  if (DstDataSize <= sizeof(BLOCK_OFFSET))
-    {
-      ValueCell->DataSize = DstDataSize | REG_DATA_IN_OFFSET;
+      ValueCell->DataSize = DataSize | REG_DATA_IN_OFFSET;
       ValueCell->DataType = DataType;
-      if (Expand)
-       {
-         memexpand ((PWCHAR)&ValueCell->DataOffset,
-                    (PCHAR)&Data,
-                    SrcDataSize);
-       }
-      else
-       {
-         memcpy (&ValueCell->DataOffset,
-                 &Data,
-                 SrcDataSize);
-       }
+      memcpy (&ValueCell->DataOffset,
+             Data,
+             DataSize);
     }
   else
     {
       /* Allocate data cell */
       if (!CmiAllocateCell (Hive,
-                           sizeof(CELL_HEADER) + DstDataSize,
+                           sizeof(CELL_HEADER) + DataSize,
                            (PVOID *)(PVOID)&DataCell,
                            &DataCellOffset))
        {
@@ -1088,30 +1095,12 @@ CmiExportValue (PREGISTRY_HIVE Hive,
        }
 
       ValueCell->DataOffset = DataCellOffset;
-      ValueCell->DataSize = DstDataSize;
+      ValueCell->DataSize = DataSize;
       ValueCell->DataType = DataType;
 
-      if (Expand)
-       {
-         if (SrcDataSize <= sizeof(BLOCK_OFFSET))
-           {
-             memexpand ((PWCHAR)DataCell->Data,
-                        (PCHAR)&Data,
-                        SrcDataSize);
-           }
-         else
-           {
-             memexpand ((PWCHAR)DataCell->Data,
-                        Data,
-                        SrcDataSize);
-           }
-       }
-      else
-       {
-         memcpy (DataCell->Data,
-                 Data,
-                 SrcDataSize);
-       }
+      memcpy (DataCell->Data,
+             Data,
+             DataSize);
     }
 
   return TRUE;
@@ -1121,26 +1110,40 @@ CmiExportValue (PREGISTRY_HIVE Hive,
 static BOOL
 CmiExportSubKey (PREGISTRY_HIVE Hive,
                 BLOCK_OFFSET ParentKeyOffset,
-                HKEY ParentKey,
-                HKEY Key)
+                FRLDRHKEY ParentKey,
+                FRLDRHKEY Key)
 {
   BLOCK_OFFSET NKBOffset;
   PKEY_CELL NewKeyCell;
-  U32 KeyCellSize;
-  U32 SubKeyCount;
-  U32 ValueCount;
+  ULONG KeyCellSize;
+  ULONG SubKeyCount;
+  ULONG ValueCount;
   PLIST_ENTRY Entry;
-  HKEY SubKey;
+  FRLDRHKEY SubKey;
   PVALUE Value;
+  BOOLEAN Packable = TRUE;
+  ULONG i;
+  ULONG NameSize;
 
-  DbgPrint((DPRINT_REGISTRY, "CmiExportSubKey('%s') called\n", Key->Name));
+  DbgPrint((DPRINT_REGISTRY, "CmiExportSubKey('%S') called\n", Key->Name));
 
   /* Don't export links */
   if (Key->DataType == REG_LINK)
     return TRUE;
 
+  NameSize = (Key->NameSize - sizeof(WCHAR)) / sizeof(WCHAR);
+  for (i = 0; i < NameSize; i++)
+    {
+      if (Key->Name[i] & 0xFF00)
+        {
+          Packable = FALSE;
+          NameSize *= sizeof(WCHAR);
+          break;
+        }
+    }
+          
   /* Allocate key cell */
-  KeyCellSize = sizeof(KEY_CELL) + Key->NameSize - 1;
+  KeyCellSize = sizeof(KEY_CELL) + NameSize;
   if (!CmiAllocateCell (Hive, KeyCellSize, (PVOID)&NewKeyCell, &NKBOffset))
     {
       DbgPrint((DPRINT_REGISTRY, "CmiAllocateCell() failed\n"));
@@ -1149,7 +1152,7 @@ CmiExportSubKey (PREGISTRY_HIVE Hive,
 
   /* Initialize key cell */
   NewKeyCell->Id = REG_KEY_CELL_ID;
-  NewKeyCell->Type = REG_KEY_CELL_TYPE;
+  NewKeyCell->Flags = 0;
   NewKeyCell->LastWriteTime = 0ULL;
   NewKeyCell->ParentKeyOffset = ParentKeyOffset;
   NewKeyCell->NumberOfSubKeys = 0;
@@ -1158,11 +1161,23 @@ CmiExportSubKey (PREGISTRY_HIVE Hive,
   NewKeyCell->ValueListOffset = -1;
   NewKeyCell->SecurityKeyOffset = -1;
   NewKeyCell->ClassNameOffset = -1;
-  NewKeyCell->NameSize = Key->NameSize - 1;
+  NewKeyCell->NameSize = NameSize;
   NewKeyCell->ClassSize = 0;
-  memcpy (NewKeyCell->Name,
-         Key->Name,
-         Key->NameSize - 1);
+  if (Packable)
+    {
+      for (i = 0; i < NameSize; i++)
+        {
+          ((PCHAR)NewKeyCell->Name)[i] = (CHAR)Key->Name[i];
+        }
+      NewKeyCell->Flags |= REG_KEY_NAME_PACKED;
+
+    }
+  else
+    {
+      memcpy (NewKeyCell->Name,
+             Key->Name,
+             NameSize);
+    }
 
   /* Add key cell to the parent key's hash table */
   if (!CmiAddKeyToParentHashTable (Hive,
@@ -1243,11 +1258,11 @@ CmiExportSubKey (PREGISTRY_HIVE Hive,
 static VOID
 CmiCalcHiveChecksum (PREGISTRY_HIVE Hive)
 {
-  U32 *Buffer;
-  U32 Sum;
-  U32 i;
+  ULONG *Buffer;
+  ULONG Sum;
+  ULONG i;
 
-  Buffer = (U32*)Hive->HiveHeader;
+  Buffer = (ULONG*)Hive->HiveHeader;
   Sum = 0;
   for (i = 0; i < 127; i++)
     Sum += Buffer[i];
@@ -1256,19 +1271,19 @@ CmiCalcHiveChecksum (PREGISTRY_HIVE Hive)
 }
 
 
-BOOL
+static BOOL
 CmiExportHive (PREGISTRY_HIVE Hive,
-              PCHAR KeyName)
+              PCWSTR KeyName)
 {
   PKEY_CELL KeyCell;
-  HKEY Key;
-  U32 SubKeyCount;
-  U32 ValueCount;
+  FRLDRHKEY Key;
+  ULONG SubKeyCount;
+  ULONG ValueCount;
   PLIST_ENTRY Entry;
-  HKEY SubKey;
+  FRLDRHKEY SubKey;
   PVALUE Value;
 
-  DbgPrint((DPRINT_REGISTRY, "CmiExportHive(%x, '%s') called\n", Hive, KeyName));
+  DbgPrint((DPRINT_REGISTRY, "CmiExportHive(%x, '%S') called\n", Hive, KeyName));
 
   if (RegOpenKey (NULL, KeyName, &Key) != ERROR_SUCCESS)
     {
@@ -1354,16 +1369,13 @@ CmiExportHive (PREGISTRY_HIVE Hive,
 static BOOL
 RegImportValue (PHBIN RootBin,
                PVALUE_CELL ValueCell,
-               HKEY Key)
+               FRLDRHKEY Key)
 {
   PDATA_CELL DataCell;
   PWCHAR wName;
-  PCHAR cName;
-  S32 Error;
-  S32 DataSize;
-  PCHAR cBuffer;
-  PWCHAR wBuffer;
-  S32 i;
+  LONG Error;
+  ULONG DataSize;
+  ULONG i;
 
   if (ValueCell->CellSize >= 0 || ValueCell->Id != REG_VALUE_CELL_ID)
     {
@@ -1373,37 +1385,38 @@ RegImportValue (PHBIN RootBin,
 
   if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
     {
-      cName = MmAllocateMemory (ValueCell->NameSize + 1);
-      memcpy (cName,
-             ValueCell->Name,
-             ValueCell->NameSize);
-      cName[ValueCell->NameSize] = 0;
+      wName = MmAllocateMemory ((ValueCell->NameSize + 1)*sizeof(WCHAR));
+      for (i = 0; i < ValueCell->NameSize; i++)
+        {
+          wName[i] = ((PCHAR)ValueCell->Name)[i];
+        }
+      wName[ValueCell->NameSize] = 0;
     }
   else
     {
-      wName = (PWCHAR)ValueCell->Name;
-      cName = MmAllocateMemory (ValueCell->NameSize / 2 + 1);
-      for (i = 0; i < ValueCell->NameSize / 2; i++)
-       cName[i] = (CHAR)wName[i];
-      cName[ValueCell->NameSize / 2] = 0;
+      wName = MmAllocateMemory (ValueCell->NameSize + sizeof(WCHAR));
+      memcpy (wName,
+             ValueCell->Name,
+             ValueCell->NameSize);
+      wName[ValueCell->NameSize / sizeof(WCHAR)] = 0;
     }
 
   DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
 
-  DbgPrint((DPRINT_REGISTRY, "ValueName: '%s'\n", cName));
+  DbgPrint((DPRINT_REGISTRY, "ValueName: '%S'\n", wName));
   DbgPrint((DPRINT_REGISTRY, "DataSize: %u\n", DataSize));
 
   if (DataSize <= sizeof(BLOCK_OFFSET) && (ValueCell->DataSize & REG_DATA_IN_OFFSET))
     {
       Error = RegSetValue(Key,
-                         cName,
+                         wName,
                          ValueCell->DataType,
-                         (PUCHAR)&ValueCell->DataOffset,
+                         (PCHAR)&ValueCell->DataOffset,
                          DataSize);
       if (Error != ERROR_SUCCESS)
        {
          DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
-         MmFreeMemory (cName);
+         MmFreeMemory (wName);
          return FALSE;
        }
     }
@@ -1415,44 +1428,25 @@ RegImportValue (PHBIN RootBin,
       if (DataCell->CellSize >= 0)
        {
          DbgPrint((DPRINT_REGISTRY, "Invalid data cell size!\n"));
-         MmFreeMemory (cName);
+         MmFreeMemory (wName);
          return FALSE;
        }
 
-      if (ValueCell->DataType == REG_SZ ||
-         ValueCell->DataType == REG_EXPAND_SZ ||
-         ValueCell->DataType == REG_MULTI_SZ)
-       {
-         wBuffer = (PWCHAR)DataCell->Data;
-         cBuffer = MmAllocateMemory(DataSize/2);
-         for (i = 0; i < DataSize / 2; i++)
-           cBuffer[i] = (CHAR)wBuffer[i];
-
-         Error = RegSetValue (Key,
-                              cName,
-                              ValueCell->DataType,
-                              cBuffer,
-                              DataSize/2);
-
-         MmFreeMemory(cBuffer);
-       }
-      else
-       {
-         Error = RegSetValue (Key,
-                              cName,
-                              ValueCell->DataType,
-                              (PUCHAR)DataCell->Data,
-                              DataSize);
-       }
+      Error = RegSetValue (Key,
+                          wName,
+                          ValueCell->DataType,
+                          DataCell->Data,
+                          DataSize);
+       
       if (Error != ERROR_SUCCESS)
        {
          DbgPrint((DPRINT_REGISTRY, "RegSetValue() failed!\n"));
-         MmFreeMemory (cName);
+         MmFreeMemory (wName);
          return FALSE;
        }
     }
 
-  MmFreeMemory (cName);
+  MmFreeMemory (wName);
 
   return TRUE;
 }
@@ -1461,16 +1455,16 @@ RegImportValue (PHBIN RootBin,
 static BOOL
 RegImportSubKey(PHBIN RootBin,
                PKEY_CELL KeyCell,
-               HKEY ParentKey)
+               FRLDRHKEY ParentKey)
 {
   PHASH_TABLE_CELL HashCell;
   PKEY_CELL SubKeyCell;
   PVALUE_LIST_CELL ValueListCell;
   PVALUE_CELL ValueCell = NULL;
-  PCHAR cName;
-  HKEY SubKey;
-  S32 Error;
-  U32 i;
+  PWCHAR wName;
+  FRLDRHKEY SubKey;
+  LONG Error;
+  ULONG i;
 
 
   DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
@@ -1482,20 +1476,31 @@ RegImportSubKey(PHBIN RootBin,
       return FALSE;
     }
 
-  /* FIXME: implement packed key names */
-  cName = MmAllocateMemory (KeyCell->NameSize + 1);
-  memcpy (cName,
-         KeyCell->Name,
-         KeyCell->NameSize);
-  cName[KeyCell->NameSize] = 0;
+  if (KeyCell->Flags & REG_KEY_NAME_PACKED)
+    {
+      wName = MmAllocateMemory ((KeyCell->NameSize + 1) * sizeof(WCHAR));
+      for (i = 0; i < KeyCell->NameSize; i++)
+        {
+          wName[i] = ((PCHAR)KeyCell->Name)[i];
+        }
+      wName[KeyCell->NameSize] = 0;
+    }
+  else
+    {
+      wName = MmAllocateMemory (KeyCell->NameSize + sizeof(WCHAR));
+      memcpy (wName,
+             KeyCell->Name,
+             KeyCell->NameSize);
+      wName[KeyCell->NameSize/sizeof(WCHAR)] = 0;
+    }
 
-  DbgPrint((DPRINT_REGISTRY, "KeyName: '%s'\n", cName));
+  DbgPrint((DPRINT_REGISTRY, "KeyName: '%S'\n", wName));
 
   /* Create new sub key */
   Error = RegCreateKey (ParentKey,
-                       cName,
+                       wName,
                        &SubKey);
-  MmFreeMemory (cName);
+  MmFreeMemory (wName);
   if (Error != ERROR_SUCCESS)
     {
       DbgPrint((DPRINT_REGISTRY, "RegCreateKey() failed!\n"));
@@ -1548,16 +1553,16 @@ RegImportSubKey(PHBIN RootBin,
 
 BOOL
 RegImportBinaryHive(PCHAR ChunkBase,
-                   U32 ChunkSize)
+                   ULONG ChunkSize)
 {
   PHIVE_HEADER HiveHeader;
   PHBIN RootBin;
   PKEY_CELL KeyCell;
   PHASH_TABLE_CELL HashCell;
   PKEY_CELL SubKeyCell;
-  HKEY SystemKey;
-  U32 i;
-  S32 Error;
+  FRLDRHKEY SystemKey;
+  ULONG i;
+  LONG Error;
 
   DbgPrint((DPRINT_REGISTRY, "RegImportBinaryHive(%x, %u) called\n",ChunkBase,ChunkSize));
 
@@ -1569,7 +1574,7 @@ RegImportBinaryHive(PCHAR ChunkBase,
       return FALSE;
     }
 
-  RootBin = (PHBIN)((U32)HiveHeader + REG_BLOCK_SIZE);
+  RootBin = (PHBIN)((ULONG)HiveHeader + REG_BLOCK_SIZE);
   DbgPrint((DPRINT_REGISTRY, "RootBin: %x\n", RootBin));
   if (RootBin->HeaderId != REG_BIN_ID || RootBin->BinSize == 0)
     {
@@ -1577,7 +1582,7 @@ RegImportBinaryHive(PCHAR ChunkBase,
       return FALSE;
     }
 
-  KeyCell = (PKEY_CELL)((U32)RootBin + REG_HBIN_DATA_OFFSET);
+  KeyCell = (PKEY_CELL)((ULONG)RootBin + REG_HBIN_DATA_OFFSET);
   DbgPrint((DPRINT_REGISTRY, "KeyCell: %x\n", KeyCell));
   DbgPrint((DPRINT_REGISTRY, "KeyCell->CellSize: %x\n", KeyCell->CellSize));
   DbgPrint((DPRINT_REGISTRY, "KeyCell->Id: %x\n", KeyCell->Id));
@@ -1592,7 +1597,7 @@ RegImportBinaryHive(PCHAR ChunkBase,
 
   /* Open 'System' key */
   Error = RegOpenKey(NULL,
-                    "\\Registry\\Machine\\SYSTEM",
+                    L"\\Registry\\Machine\\SYSTEM",
                     &SystemKey);
   if (Error != ERROR_SUCCESS)
     {
@@ -1603,14 +1608,14 @@ RegImportBinaryHive(PCHAR ChunkBase,
   /* Enumerate and add subkeys */
   if (KeyCell->NumberOfSubKeys > 0)
     {
-      HashCell = (PHASH_TABLE_CELL)((U32)RootBin + KeyCell->HashTableOffset);
+      HashCell = (PHASH_TABLE_CELL)((ULONG)RootBin + KeyCell->HashTableOffset);
       DbgPrint((DPRINT_REGISTRY, "HashCell: %x\n", HashCell));
 
       for (i = 0; i < KeyCell->NumberOfSubKeys; i++)
        {
          DbgPrint((DPRINT_REGISTRY, "KeyOffset[%d]: %x\n", i, HashCell->Table[i].KeyOffset));
 
-         SubKeyCell = (PKEY_CELL)((U32)RootBin + HashCell->Table[i].KeyOffset);
+         SubKeyCell = (PKEY_CELL)((ULONG)RootBin + HashCell->Table[i].KeyOffset);
 
          DbgPrint((DPRINT_REGISTRY, "SubKeyCell[%d]: %x\n", i, SubKeyCell));
 
@@ -1624,9 +1629,9 @@ RegImportBinaryHive(PCHAR ChunkBase,
 
 
 BOOL
-RegExportBinaryHive(PCHAR KeyName,
+RegExportBinaryHive(PCWSTR KeyName,
                    PCHAR ChunkBase,
-                   U32* ChunkSize)
+                   ULONG* ChunkSize)
 {
   PREGISTRY_HIVE Hive;