From 8b7b3d2a4e1b670fe00bb8aa1393cbf6134c300e Mon Sep 17 00:00:00 2001
From: Stanislav Bas <stanislav.m.bas@gmail.com>
Date: Thu, 16 Jul 2015 19:52:31 +0300
Subject: [PATCH] Refine DELE handling in ESM records. Add position-independent
 DELE search

(cherry picked from commit ad353e6dd0b41e388e2ec3fbcc4bf15d1ef71e57)
---
 components/esm/cellref.cpp     | 126 +++++++++++++---------
 components/esm/esmreader.cpp   |   5 +
 components/esm/esmreader.hpp   |   3 +
 components/esm/loadacti.cpp    |  23 ++--
 components/esm/loadalch.cpp    |  28 +++--
 components/esm/loadappa.cpp    |  27 +++--
 components/esm/loadarmo.cpp    |  26 +++--
 components/esm/loadbody.cpp    |  24 +++--
 components/esm/loadbook.cpp    |  25 +++--
 components/esm/loadbsgn.cpp    |  20 +++-
 components/esm/loadclas.cpp    |  25 +++--
 components/esm/loadclot.cpp    |  26 +++--
 components/esm/loadcont.cpp    |  32 ++++--
 components/esm/loadcrea.cpp    |  33 ++++--
 components/esm/loaddial.cpp    |  46 +++++---
 components/esm/loaddoor.cpp    |  23 ++--
 components/esm/loadench.cpp    |  25 +++--
 components/esm/loadfact.cpp    |  28 +++--
 components/esm/loadglob.cpp    |  31 +++---
 components/esm/loadinfo.cpp    | 189 +++++++++++++--------------------
 components/esm/loadinfo.hpp    |   3 +-
 components/esm/loadingr.cpp    |  24 +++--
 components/esm/loadlevlist.cpp |  87 +++++++++------
 components/esm/loadligh.cpp    |  25 +++--
 components/esm/loadlock.cpp    |  26 +++--
 components/esm/loadltex.cpp    |  43 ++++++--
 components/esm/loadmisc.cpp    |  27 +++--
 components/esm/loadnpc.cpp     |  34 +++---
 components/esm/loadprob.cpp    |  27 +++--
 components/esm/loadregn.cpp    | 105 +++++++++++-------
 components/esm/loadrepa.cpp    |  27 +++--
 components/esm/loadscpt.cpp    |  29 +++--
 components/esm/loadsndg.cpp    |  38 ++++---
 components/esm/loadsoun.cpp    |  27 +++--
 components/esm/loadspel.cpp    |  30 ++++--
 components/esm/loadstat.cpp    |  39 +++++--
 components/esm/loadweap.cpp    |  24 +++--
 37 files changed, 861 insertions(+), 519 deletions(-)

diff --git a/components/esm/cellref.cpp b/components/esm/cellref.cpp
index 713ae2f0b0..c4fc93ff54 100644
--- a/components/esm/cellref.cpp
+++ b/components/esm/cellref.cpp
@@ -2,7 +2,6 @@
 
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
-#include "util.hpp"
 
 ESM::CellRef::CellRef()
     : mScale(1.0f),
@@ -37,7 +36,6 @@ void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
 
 void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
 {
-    mIsDeleted = false;
     loadId(esm, wideRefNum);
     loadData(esm);
 }
@@ -54,62 +52,90 @@ void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum)
     mRefNum.load (esm, wideRefNum);
 
     mRefID = esm.getHNString ("NAME");
+    mIsDeleted = false;
 }
 
 void ESM::CellRef::loadData(ESMReader &esm)
 {
-    // Again, UNAM sometimes appears after NAME and sometimes later.
-    // Or perhaps this UNAM means something different?
-    mReferenceBlocked = -1;
-    esm.getHNOT (mReferenceBlocked, "UNAM");
-
-    mScale = 1.0;
-    esm.getHNOT (mScale, "XSCL");
-
-    mOwner = esm.getHNOString ("ANAM");
-    mGlobalVariable = esm.getHNOString ("BNAM");
-    mSoul = esm.getHNOString ("XSOL");
-
-    mFaction = esm.getHNOString ("CNAM");
+    mScale = 1.0f;
     mFactionRank = -2;
-    esm.getHNOT (mFactionRank, "INDX");
-
-    mGoldValue = 1;
     mChargeInt = -1;
     mEnchantmentCharge = -1;
+    mGoldValue = 1;
+    mLockLevel = 0;
+    mReferenceBlocked = -1;
+    mTeleport = false;
+    mIsDeleted = false;
 
-    esm.getHNOT (mEnchantmentCharge, "XCHG");
-
-    esm.getHNOT (mChargeInt, "INTV");
-
-    esm.getHNOT (mGoldValue, "NAM9");
-
-    // Present for doors that teleport you to another cell.
-    if (esm.isNextSub ("DODT"))
+    bool isLoaded = false;
+    while (!isLoaded && esm.hasMoreSubs())
     {
-        mTeleport = true;
-        esm.getHT (mDoorDest);
-        mDestCell = esm.getHNOString ("DNAM");
+        esm.getSubName();
+        uint32_t name = esm.retSubName().val;
+        switch (name)
+        {
+            case ESM::FourCC<'U','N','A','M'>::value:
+                esm.getHT(mReferenceBlocked);
+                break;
+            case ESM::FourCC<'X','S','C','L'>::value:
+                esm.getHT(mScale);
+                break;
+            case ESM::FourCC<'A','N','A','M'>::value:
+                mOwner = esm.getHString();
+                break;
+            case ESM::FourCC<'B','N','A','M'>::value:
+                mGlobalVariable = esm.getHString();
+                break;
+            case ESM::FourCC<'X','S','O','L'>::value:
+                mSoul = esm.getHString();
+                break;
+            case ESM::FourCC<'C','N','A','M'>::value:
+                mFaction = esm.getHString();
+                break;
+            case ESM::FourCC<'I','N','D','X'>::value:
+                esm.getHT(mFactionRank);
+                break;
+            case ESM::FourCC<'X','C','H','G'>::value:
+                esm.getHT(mEnchantmentCharge);
+                break;
+            case ESM::FourCC<'I','N','T','V'>::value:
+                esm.getHT(mChargeInt);
+                break;
+            case ESM::FourCC<'N','A','M','9'>::value:
+                esm.getHT(mGoldValue);
+                break;
+            case ESM::FourCC<'D','O','D','T'>::value:
+                esm.getHT(mDoorDest);
+                mTeleport = true;
+                break;
+            case ESM::FourCC<'D','N','A','M'>::value:
+                mDestCell = esm.getHString();
+                break;
+            case ESM::FourCC<'F','L','T','V'>::value:
+                esm.getHT(mLockLevel);
+                break;
+            case ESM::FourCC<'K','N','A','M'>::value:
+                mKey = esm.getHString();
+                break;
+            case ESM::FourCC<'T','N','A','M'>::value:
+                mTrap = esm.getHString();
+                break;
+            case ESM::FourCC<'D','A','T','A'>::value:
+                esm.getHT(mPos, 24);
+                break;
+            case ESM::FourCC<'N','A','M','0'>::value:
+                esm.skipHSub();
+                break;
+            case ESM::FourCC<'D','E','L','E'>::value:
+                esm.skipHSub();
+                mIsDeleted = true;
+                break;
+            default:
+                esm.cacheSubName();
+                isLoaded = true;
+                break;
+        }
     }
-    else
-        mTeleport = false;
-
-    mLockLevel = 0; //Set to 0 to indicate no lock
-    esm.getHNOT (mLockLevel, "FLTV");
-
-    mKey = esm.getHNOString ("KNAM");
-    mTrap = esm.getHNOString ("TNAM");
-
-    esm.getHNOT (mReferenceBlocked, "UNAM");
-    if (esm.isNextSub("FLTV")) // no longer used
-        esm.skipHSub();
-
-    esm.getHNOT(mPos, "DATA", 24);
-
-    if (esm.isNextSub("NAM0"))
-        esm.skipHSub();
-
-    mIsDeleted = readDeleSubRecord (esm);
 }
 
 void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const
@@ -148,7 +174,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
     }
 
     if (!inInventory && mLockLevel != 0) {
-            esm.writeHNT("FLTV", mLockLevel);
+        esm.writeHNT("FLTV", mLockLevel);
     }
 
     if (!inInventory)
@@ -165,7 +191,7 @@ void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) cons
 
     if (mIsDeleted)
     {
-        writeDeleSubRecord(esm);
+        esm.writeHNCString("DELE", "");
     }
 }
 
diff --git a/components/esm/esmreader.cpp b/components/esm/esmreader.cpp
index 77ac0ae32c..97fd8d986c 100644
--- a/components/esm/esmreader.cpp
+++ b/components/esm/esmreader.cpp
@@ -185,6 +185,11 @@ bool ESMReader::peekNextSub(const char *name)
     return mCtx.subName == name;
 }
 
+void ESMReader::cacheSubName()
+{
+    mCtx.subCached = true;
+}
+
 // Read subrecord name. This gets called a LOT, so I've optimized it
 // slightly.
 void ESMReader::getSubName()
diff --git a/components/esm/esmreader.hpp b/components/esm/esmreader.hpp
index 4e92b7e5f3..66ef981306 100644
--- a/components/esm/esmreader.hpp
+++ b/components/esm/esmreader.hpp
@@ -187,6 +187,9 @@ public:
 
   bool peekNextSub(const char* name);
 
+  // Store the current subrecord name for the next call of getSubName()
+  void cacheSubName();
+
   // Read subrecord name. This gets called a LOT, so I've optimized it
   // slightly.
   void getSubName();
diff --git a/components/esm/loadacti.cpp b/components/esm/loadacti.cpp
index 14a3abe54a..c32cea1a6b 100644
--- a/components/esm/loadacti.cpp
+++ b/components/esm/loadacti.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,18 +14,23 @@ namespace ESM
 
     void Activator::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -38,15 +42,20 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
     void Activator::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadalch.cpp b/components/esm/loadalch.cpp
index 5faeb99e16..c1213583dd 100644
--- a/components/esm/loadalch.cpp
+++ b/components/esm/loadalch.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -16,13 +15,9 @@ namespace ESM
     void Potion::load(ESMReader &esm)
     {
         mEffects.mList.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -30,6 +25,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -51,17 +54,22 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
-            esm.fail("Missing ALDT");
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
+            esm.fail("Missing ALDT subrecord");
     }
     void Potion::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadappa.cpp b/components/esm/loadappa.cpp
index ea375aa7f6..edf1f473b8 100644
--- a/components/esm/loadappa.cpp
+++ b/components/esm/loadappa.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Apparatus::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -46,18 +50,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
-            esm.fail("Missing AADT");
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
+            esm.fail("Missing AADT subrecord");
     }
 
     void Apparatus::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadarmo.cpp b/components/esm/loadarmo.cpp
index d23a71cac9..d5b9fdd446 100644
--- a/components/esm/loadarmo.cpp
+++ b/components/esm/loadarmo.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -46,13 +45,9 @@ namespace ESM
     void Armor::load(ESMReader &esm)
     {
         mParts.mParts.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -60,6 +55,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -84,18 +87,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing CTDT subrecord");
     }
 
     void Armor::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadbody.cpp b/components/esm/loadbody.cpp
index e0ebfd5390..e2c6ad7b2e 100644
--- a/components/esm/loadbody.cpp
+++ b/components/esm/loadbody.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void BodyPart::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -40,19 +44,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
 
-        if (!hasData)
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing BYDT subrecord");
     }
 
     void BodyPart::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadbook.cpp b/components/esm/loadbook.cpp
index 2824b62000..2d0d3ce755 100644
--- a/components/esm/loadbook.cpp
+++ b/components/esm/loadbook.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Book::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -52,17 +56,22 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing BKDT subrecord");
     }
     void Book::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadbsgn.cpp b/components/esm/loadbsgn.cpp
index 8cdeed3f6e..9f5cd72705 100644
--- a/components/esm/loadbsgn.cpp
+++ b/components/esm/loadbsgn.cpp
@@ -16,16 +16,23 @@ namespace ESM
     void BirthSign::load(ESMReader &esm)
     {
         mPowers.mList.clear();
+        mIsDeleted = false;
 
-        mIsDeleted = readDeleSubRecord(esm);
-        mId = esm.getHNString("NAME");
-
+        bool hasName = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'F','N','A','M'>::value:
                     mName = esm.getHString();
                     break;
@@ -40,16 +47,21 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
 
     void BirthSign::save(ESMWriter &esm) const
     {
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
         }
+
         esm.writeHNCString("NAME", mId);
         esm.writeHNOCString("FNAM", mName);
         esm.writeHNOCString("TNAM", mTexture);
diff --git a/components/esm/loadclas.cpp b/components/esm/loadclas.cpp
index 1384a6280d..b58c35d90a 100644
--- a/components/esm/loadclas.cpp
+++ b/components/esm/loadclas.cpp
@@ -5,7 +5,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -45,12 +44,9 @@ namespace ESM
 
     void Class::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -58,6 +54,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'F','N','A','M'>::value:
                     mName = esm.getHString();
                     break;
@@ -72,17 +76,22 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing CLDT subrecord");
     }
     void Class::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadclot.cpp b/components/esm/loadclot.cpp
index 88f2e57154..18f7cd44fb 100644
--- a/components/esm/loadclot.cpp
+++ b/components/esm/loadclot.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -16,13 +15,9 @@ namespace ESM
     void Clothing::load(ESMReader &esm)
     {
         mParts.mParts.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -30,6 +25,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -54,18 +57,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing CTDT subrecord");
     }
 
     void Clothing::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadcont.cpp b/components/esm/loadcont.cpp
index 3d3d7fced8..fadfe5f0fe 100644
--- a/components/esm/loadcont.cpp
+++ b/components/esm/loadcont.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -26,19 +25,17 @@ namespace ESM
     unsigned int Container::sRecordId = REC_CONT;
 
     Container::Container()
-        : mIsDeleted(false)
+        : mWeight(0),
+          mFlags(0x8),
+          mIsDeleted(false)
     {}
 
     void Container::load(ESMReader &esm)
     {
         mInventory.mList.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasWeight = false;
         bool hasFlags = false;
         while (esm.hasMoreSubs())
@@ -47,6 +44,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -73,20 +78,25 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasWeight)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasWeight && !mIsDeleted)
             esm.fail("Missing CNDT subrecord");
-        if (!hasFlags)
+        if (!hasFlags && !mIsDeleted)
             esm.fail("Missing FLAG subrecord");
     }
 
     void Container::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadcrea.cpp b/components/esm/loadcrea.cpp
index 1aead6c04e..b58e662394 100644
--- a/components/esm/loadcrea.cpp
+++ b/components/esm/loadcrea.cpp
@@ -3,14 +3,15 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM {
 
     unsigned int Creature::sRecordId = REC_CREA;
 
     Creature::Creature()
-        : mIsDeleted(false)
+        : mFlags(0),
+          mScale(0.0f),
+          mIsDeleted(false)
     {}
 
     void Creature::load(ESMReader &esm)
@@ -22,14 +23,11 @@ namespace ESM {
         mSpells.mList.clear();
         mTransport.mList.clear();
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
         mScale = 1.f;
         mHasAI = false;
+        mIsDeleted = false;
+
+        bool hasName = false;
         bool hasNpdt = false;
         bool hasFlags = false;
         while (esm.hasMoreSubs())
@@ -38,6 +36,14 @@ namespace ESM {
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -85,20 +91,25 @@ namespace ESM {
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasNpdt)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasNpdt && !mIsDeleted)
             esm.fail("Missing NPDT subrecord");
-        if (!hasFlags)
+        if (!hasFlags && !mIsDeleted)
             esm.fail("Missing FLAG subrecord");
     }
 
     void Creature::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loaddial.cpp b/components/esm/loaddial.cpp
index fcdb57c8db..c517dc7222 100644
--- a/components/esm/loaddial.cpp
+++ b/components/esm/loaddial.cpp
@@ -7,7 +7,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -31,20 +30,36 @@ namespace ESM
 
     void Dialogue::loadData(ESMReader &esm)
     {
-        esm.getSubNameIs("DATA");
-        esm.getSubHeader();
-        int si = esm.getSubSize();
-        if (si == 1)
-            esm.getT(mType);
-        else if (si == 4) // The dialogue is deleted
+        while (esm.hasMoreSubs())
         {
-            int32_t empty;
-            esm.getT(empty); // Skip an empty DATA
-            mIsDeleted = readDeleSubRecord(esm);
-            mType = Unknown;
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'D','A','T','A'>::value:
+                {
+                    esm.getSubHeader();
+                    int size = esm.getSubSize();
+                    if (size == 1)
+                    {
+                        esm.getT(mType);
+                    }
+                    else
+                    {
+                        esm.skip(size);
+                    }
+                    break;
+                }
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mType = Unknown;
+                    mIsDeleted = true;
+                    break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
+            }
         }
-        else
-            esm.fail("Unknown sub record size");
     }
 
     void Dialogue::save(ESMWriter &esm) const
@@ -52,8 +67,7 @@ namespace ESM
         esm.writeHNCString("NAME", mId);
         if (mIsDeleted)
         {
-            esm.writeHNT("DATA", static_cast<int32_t>(0));
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
         }
         else
         {
@@ -138,7 +152,7 @@ namespace ESM
     {
         for (InfoContainer::iterator it = mInfo.begin(); it != mInfo.end(); )
         {
-            if (it->mIsDeleted || it->mQuestStatus == DialInfo::QS_Deleted)
+            if (it->mIsDeleted)
                 it = mInfo.erase(it);
             else
                 ++it;
diff --git a/components/esm/loaddoor.cpp b/components/esm/loaddoor.cpp
index 87382fa7b1..4f58a42611 100644
--- a/components/esm/loaddoor.cpp
+++ b/components/esm/loaddoor.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,18 +14,23 @@ namespace ESM
 
     void Door::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -44,16 +48,21 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
 
     void Door::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadench.cpp b/components/esm/loadench.cpp
index 1518e0385a..0e480c379d 100644
--- a/components/esm/loadench.cpp
+++ b/components/esm/loadench.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -16,13 +15,9 @@ namespace ESM
     void Enchantment::load(ESMReader &esm)
     {
         mEffects.mList.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -30,6 +25,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'E','N','D','T'>::value:
                     esm.getHT(mData, 16);
                     hasData = true;
@@ -42,16 +45,20 @@ namespace ESM
                     break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing ENDT subrecord");
     }
 
     void Enchantment::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadfact.cpp b/components/esm/loadfact.cpp
index 53f3aa5a6c..8538b0b95d 100644
--- a/components/esm/loadfact.cpp
+++ b/components/esm/loadfact.cpp
@@ -5,7 +5,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -33,17 +32,13 @@ namespace ESM
 
     void Faction::load(ESMReader &esm)
     {
+        mIsDeleted = false;
         mReactions.clear();
         for (int i=0;i<10;++i)
             mRanks[i].clear();
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
-        int rankCounter=0;
+        int rankCounter = 0;
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -51,6 +46,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'F','N','A','M'>::value:
                     mName = esm.getHString();
                     break;
@@ -75,18 +78,23 @@ namespace ESM
                 }
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing FADT subrecord");
     }
 
     void Faction::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadglob.cpp b/components/esm/loadglob.cpp
index 392df02b54..5f96aff1f3 100644
--- a/components/esm/loadglob.cpp
+++ b/components/esm/loadglob.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,30 +14,38 @@ namespace ESM
 
     void Global::load (ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
+        mId = esm.getHNString ("NAME");
 
-        mValue.read (esm, ESM::Variant::Format_Global);
+        if (esm.isNextSub ("DELE"))
+        {
+            esm.skipHSub();
+            mIsDeleted = true;
+        }
+        else
+        {
+            mValue.read (esm, ESM::Variant::Format_Global);
+        }
     }
 
     void Global::save (ESMWriter &esm) const
     {
-        esm.writeHNCString("NAME", mId);
+        esm.writeHNCString ("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
-            return;
+            esm.writeHNCString ("DELE", "");
+        }
+        else
+        {
+            mValue.write (esm, ESM::Variant::Format_Global);
         }
-
-        mValue.write (esm, ESM::Variant::Format_Global);
     }
 
     void Global::blank()
     {
         mValue.setType (ESM::VT_None);
+        mIsDeleted = false;
     }
 
     bool operator== (const Global& left, const Global& right)
diff --git a/components/esm/loadinfo.cpp b/components/esm/loadinfo.cpp
index 8f5f0f28b0..89fd4e0cd6 100644
--- a/components/esm/loadinfo.cpp
+++ b/components/esm/loadinfo.cpp
@@ -3,14 +3,15 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
     unsigned int DialInfo::sRecordId = REC_INFO;
 
     DialInfo::DialInfo()
-        : mIsDeleted(false)
+        : mFactionLess(false),
+          mQuestStatus(QS_None),
+          mIsDeleted(false)
     {}
 
     void DialInfo::load(ESMReader &esm)
@@ -29,6 +30,7 @@ namespace ESM
     {
         mQuestStatus = QS_None;
         mFactionLess = false;
+        mIsDeleted = false;
 
         mPrev = esm.getHNString("PNAM");
         mNext = esm.getHNString("NNAM");
@@ -36,118 +38,77 @@ namespace ESM
         // Since there's no way to mark selects as "deleted", we have to clear the SelectStructs from all previous loadings
         mSelects.clear();
 
-        // If the info is deleted, NAME and DELE sub-records are followed after NNAM
-        if (esm.isNextSub("NAME"))
+        while (esm.hasMoreSubs())
         {
-            mResponse = esm.getHString();
-            mIsDeleted = readDeleSubRecord(esm);
-            return;
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
+                case ESM::FourCC<'D','A','T','A'>::value:
+                    esm.getHT(mData, 12);
+                    break;
+                case ESM::FourCC<'O','N','A','M'>::value:
+                    mActor = esm.getHString();
+                    break;
+                case ESM::FourCC<'R','N','A','M'>::value:
+                    mRace = esm.getHString();
+                    break;
+                case ESM::FourCC<'C','N','A','M'>::value:
+                    mClass = esm.getHString();
+                    break;
+                case ESM::FourCC<'F','N','A','M'>::value:
+                {
+                    mFaction = esm.getHString();
+                    if (mFaction == "FFFF")
+                    {
+                        mFactionLess = true;
+                    }
+                    break;
+                }
+                case ESM::FourCC<'A','N','A','M'>::value:
+                    mCell = esm.getHString();
+                    break;
+                case ESM::FourCC<'D','N','A','M'>::value:
+                    mPcFaction = esm.getHString();
+                    break;
+                case ESM::FourCC<'S','N','A','M'>::value:
+                    mSound = esm.getHString();
+                    break;
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mResponse = esm.getHString();
+                    break;
+                case ESM::FourCC<'S','C','V','R'>::value:
+                {
+                    SelectStruct ss;
+                    ss.mSelectRule = esm.getHString();
+                    ss.mValue.read(esm, Variant::Format_Info);
+                    mSelects.push_back(ss);
+                    break;
+                }
+                case ESM::FourCC<'B','N','A','M'>::value:
+                    mResultScript = esm.getHString();
+                    break;
+                case ESM::FourCC<'Q','S','T','N'>::value:
+                    mQuestStatus = QS_Name;
+                    esm.skipRecord();
+                    break;
+                case ESM::FourCC<'Q','S','T','F'>::value:
+                    mQuestStatus = QS_Finished;
+                    esm.skipRecord();
+                    break;
+                case ESM::FourCC<'Q','S','T','R'>::value:
+                    mQuestStatus = QS_Restart;
+                    esm.skipRecord();
+                    break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
+            }
         }
-
-        esm.getSubNameIs("DATA");
-        esm.getHT(mData, 12);
-
-        if (!esm.hasMoreSubs())
-            return;
-
-        // What follows is somewhat spaghetti-ish, but it's worth if for
-        // an extra speedup. INFO is by far the most common record type.
-
-        // subName is a reference to the original, so it changes whenever
-        // a new sub name is read. esm.isEmptyOrGetName() will get the
-        // next name for us, or return true if there are no more records.
-        esm.getSubName();
-        const NAME &subName = esm.retSubName();
-
-        if (subName.val == REC_ONAM)
-        {
-            mActor = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_RNAM)
-        {
-            mRace = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_CNAM)
-        {
-            mClass = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-
-        if (subName.val == REC_FNAM)
-        {
-            mFaction = esm.getHString();
-            if (mFaction == "FFFF")
-                mFactionLess = true;
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_ANAM)
-        {
-            mCell = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_DNAM)
-        {
-            mPcFaction = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_SNAM)
-        {
-            mSound = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-        if (subName.val == REC_NAME)
-        {
-            mResponse = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-
-        while (subName.val == REC_SCVR)
-        {
-            SelectStruct ss;
-
-            ss.mSelectRule = esm.getHString();
-
-            ss.mValue.read (esm, Variant::Format_Info);
-
-            mSelects.push_back(ss);
-
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-
-        if (subName.val == REC_BNAM)
-        {
-            mResultScript = esm.getHString();
-            if (esm.isEmptyOrGetName())
-                return;
-        }
-
-        if (subName.val == REC_QSTN)
-            mQuestStatus = QS_Name;
-        else if (subName.val == REC_QSTF)
-            mQuestStatus = QS_Finished;
-        else if (subName.val == REC_QSTR)
-            mQuestStatus = QS_Restart;
-        else if (subName.val == REC_DELE)
-            mQuestStatus = QS_Deleted;
-        else
-            esm.fail(
-                    "Don't know what to do with " + subName.toString()
-                            + " in INFO " + mId);
-
-        if (mQuestStatus != QS_None)
-            // Skip rest of record
-            esm.skipRecord();
     }
 
     void DialInfo::save(ESMWriter &esm) const
@@ -158,8 +119,7 @@ namespace ESM
 
         if (mIsDeleted)
         {
-            esm.writeHNCString("NAME", mResponse);
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
@@ -186,7 +146,6 @@ namespace ESM
         case QS_Name: esm.writeHNT("QSTN",'\1'); break;
         case QS_Finished: esm.writeHNT("QSTF", '\1'); break;
         case QS_Restart: esm.writeHNT("QSTR", '\1'); break;
-        case QS_Deleted: esm.writeHNT("DELE", '\1'); break;
         default: break;
         }
     }
diff --git a/components/esm/loadinfo.hpp b/components/esm/loadinfo.hpp
index c243cd50e0..65363d1be8 100644
--- a/components/esm/loadinfo.hpp
+++ b/components/esm/loadinfo.hpp
@@ -59,8 +59,7 @@ struct DialInfo
         QS_None = 0,
         QS_Name = 1,
         QS_Finished = 2,
-        QS_Restart = 3,
-        QS_Deleted
+        QS_Restart = 3
     };
 
     // Rules for when to include this item in the final list of options
diff --git a/components/esm/loadingr.cpp b/components/esm/loadingr.cpp
index a7018b36db..51a1f48059 100644
--- a/components/esm/loadingr.cpp
+++ b/components/esm/loadingr.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Ingredient::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -46,10 +50,13 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
 
-        if (!hasData)
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing IRDT subrecord");
 
         // horrible hack to fix broken data in records
@@ -79,9 +86,10 @@ namespace ESM
     void Ingredient::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadlevlist.cpp b/components/esm/loadlevlist.cpp
index 1e07086bcd..9c34ef6578 100644
--- a/components/esm/loadlevlist.cpp
+++ b/components/esm/loadlevlist.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -13,49 +12,67 @@ namespace ESM
 
     void LevelledListBase::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
+        mIsDeleted = false;
+
+        bool hasName = false;
+        while (esm.hasMoreSubs())
         {
-            return;
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
+                case ESM::FourCC<'D','A','T','A'>::value:
+                    esm.getHT(mFlags);
+                    break;
+                case ESM::FourCC<'N','N','A','M'>::value:
+                    esm.getHT(mChanceNone);
+                    break;
+                case ESM::FourCC<'I','N','D','X'>::value:
+                {
+                    int length = 0;
+                    esm.getHT(length);
+                    mList.resize(length);
+
+                    // If this levelled list was already loaded by a previous content file,
+                    // we overwrite the list. Merging lists should probably be left to external tools,
+                    // with the limited amount of information there is in the records, all merging methods
+                    // will be flawed in some way. For a proper fix the ESM format would have to be changed
+                    // to actually track list changes instead of including the whole list for every file
+                    // that does something with that list.
+                    for (size_t i = 0; i < mList.size(); i++)
+                    {
+                        LevelItem &li = mList[i];
+                        li.mId = esm.getHNString(mRecName);
+                        esm.getHNT(li.mLevel, "INTV");
+                    }
+                    break;
+                }
+                default:
+                    mList.clear();
+                    esm.skipRecord();
+                    break;
+            }
         }
 
-        esm.getHNT(mFlags, "DATA");
-        esm.getHNT(mChanceNone, "NNAM");
-
-        if (esm.isNextSub("INDX"))
-        {
-            int len;
-            esm.getHT(len);
-            mList.resize(len);
-        }
-        else
-        {
-            // Original engine ignores rest of the record, even if there are items following
-            mList.clear();
-            esm.skipRecord();
-            return;
-        }
-
-        // If this levelled list was already loaded by a previous content file,
-        // we overwrite the list. Merging lists should probably be left to external tools,
-        // with the limited amount of information there is in the records, all merging methods
-        // will be flawed in some way. For a proper fix the ESM format would have to be changed
-        // to actually track list changes instead of including the whole list for every file
-        // that does something with that list.
-
-        for (size_t i = 0; i < mList.size(); i++)
-        {
-            LevelItem &li = mList[i];
-            li.mId = esm.getHNString(mRecName);
-            esm.getHNT(li.mLevel, "INTV");
-        }
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
+
     void LevelledListBase::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadligh.cpp b/components/esm/loadligh.cpp
index a153d500a0..441e96d0ac 100644
--- a/components/esm/loadligh.cpp
+++ b/components/esm/loadligh.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Light::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -49,17 +53,22 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing LHDT subrecord");
     }
     void Light::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadlock.cpp b/components/esm/loadlock.cpp
index 3b169af33e..5ee041daba 100644
--- a/components/esm/loadlock.cpp
+++ b/components/esm/loadlock.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,19 +14,23 @@ namespace ESM
 
     void Lockpick::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
-        bool hasData = true;
+        bool hasName = false;
+        bool hasData = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -46,18 +49,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing LKDT subrecord");
     }
 
     void Lockpick::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadltex.cpp b/components/esm/loadltex.cpp
index 13315e6848..7c14536edf 100644
--- a/components/esm/loadltex.cpp
+++ b/components/esm/loadltex.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,17 +14,49 @@ namespace ESM
 
     void LandTexture::load(ESMReader &esm)
     {
-        mIsDeleted = readDeleSubRecord(esm);
-        mId = esm.getHNString("NAME");
-        esm.getHNT(mIndex, "INTV");
-        mTexture = esm.getHNString("DATA");
+        mIsDeleted = false;
+
+        bool hasName = false;
+        bool hasIndex = false;
+        while (esm.hasMoreSubs())
+        {
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = false;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
+                case ESM::FourCC<'I','N','T','V'>::value:
+                    esm.getHT(mIndex);
+                    hasIndex = true;
+                    break;
+                case ESM::FourCC<'D','A','T','A'>::value:
+                    mTexture = esm.getHString();
+                    break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
+            }
+        }
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasIndex)
+            esm.fail("Missing INTV subrecord");
     }
     void LandTexture::save(ESMWriter &esm) const
     {
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
         }
+
         esm.writeHNCString("NAME", mId);
         esm.writeHNT("INTV", mIndex);
         esm.writeHNCString("DATA", mTexture);
diff --git a/components/esm/loadmisc.cpp b/components/esm/loadmisc.cpp
index 08cbcf7414..de9ccdd6aa 100644
--- a/components/esm/loadmisc.cpp
+++ b/components/esm/loadmisc.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Miscellaneous::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -44,18 +48,25 @@ namespace ESM
                 case ESM::FourCC<'I','T','E','X'>::value:
                     mIcon = esm.getHString();
                     break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing MCDT subrecord");
     }
 
     void Miscellaneous::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadnpc.cpp b/components/esm/loadnpc.cpp
index 1bdd5d4831..ffbbb59a08 100644
--- a/components/esm/loadnpc.cpp
+++ b/components/esm/loadnpc.cpp
@@ -3,40 +3,45 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
     unsigned int NPC::sRecordId = REC_NPC_;
 
     NPC::NPC()
-        : mIsDeleted(false)
+        : mFlags(0),
+          mHasAI(false),
+          mIsDeleted(false)
     {}
 
     void NPC::load(ESMReader &esm)
     {
+        mIsDeleted = false;
         mPersistent = (esm.getRecordFlags() & 0x0400) != 0;
 
         mSpells.mList.clear();
         mInventory.mList.clear();
         mTransport.mList.clear();
         mAiPackage.mList.clear();
+        mHasAI = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasNpdt = false;
         bool hasFlags = false;
-        mHasAI = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -105,19 +110,24 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasNpdt)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasNpdt && !mIsDeleted)
             esm.fail("Missing NPDT subrecord");
-        if (!hasFlags)
+        if (!hasFlags && !mIsDeleted)
             esm.fail("Missing FLAG subrecord");
     }
     void NPC::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadprob.cpp b/components/esm/loadprob.cpp
index f5287f9869..4ce9b9d9c7 100644
--- a/components/esm/loadprob.cpp
+++ b/components/esm/loadprob.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,19 +14,24 @@ namespace ESM
 
     void Probe::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
-        bool hasData = true;
+        bool hasName = false;
+        bool hasData = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -46,18 +50,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing PBDT subrecord");
     }
 
     void Probe::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadregn.cpp b/components/esm/loadregn.cpp
index 2d99947b0c..b48ffa4b7b 100644
--- a/components/esm/loadregn.cpp
+++ b/components/esm/loadregn.cpp
@@ -3,64 +3,95 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
     unsigned int Region::sRecordId = REC_REGN;
 
     Region::Region()
-        : mIsDeleted(false)
+        : mMapColor(0),
+          mIsDeleted(false)
     {}
 
     void Region::load(ESMReader &esm)
     {
-        mIsDeleted = readDeleSubRecord(esm);
-        mId = esm.getHNString("NAME");
-        mName = esm.getHNOString("FNAM");
+        mIsDeleted = false;
 
-        esm.getSubNameIs("WEAT");
-        esm.getSubHeader();
-        if (esm.getVer() == VER_12)
-        {
-            mData.mA = 0;
-            mData.mB = 0;
-            esm.getExact(&mData, sizeof(mData) - 2);
-        }
-        else if (esm.getVer() == VER_13)
-        {
-            // May include the additional two bytes (but not necessarily)
-            if (esm.getSubSize() == sizeof(mData))
-                esm.getExact(&mData, sizeof(mData));
-            else
-            {
-                mData.mA = 0;
-                mData.mB = 0;
-                esm.getExact(&mData, sizeof(mData)-2);
-            }
-        }
-        else
-            esm.fail("Don't know what to do in this version");
-
-        mSleepList = esm.getHNOString("BNAM");
-
-        esm.getHNT(mMapColor, "CNAM");
-
-        mSoundList.clear();
+        bool hasName = false;
         while (esm.hasMoreSubs())
         {
-            SoundRef sr;
-            esm.getHNT(sr, "SNAM", 33);
-            mSoundList.push_back(sr);
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
+                case ESM::FourCC<'F','N','A','M'>::value:
+                    mName = esm.getHString();
+                    break;
+                case ESM::FourCC<'W','E','A','T'>::value:
+                {
+                    esm.getSubHeader();
+                    if (esm.getVer() == VER_12)
+                    {
+                        mData.mA = 0;
+                        mData.mB = 0;
+                        esm.getExact(&mData, sizeof(mData) - 2);
+                    }
+                    else if (esm.getVer() == VER_13)
+                    {
+                        // May include the additional two bytes (but not necessarily)
+                        if (esm.getSubSize() == sizeof(mData))
+                        {
+                            esm.getExact(&mData, sizeof(mData));
+                        }
+                        else
+                        {
+                            mData.mA = 0;
+                            mData.mB = 0;
+                            esm.getExact(&mData, sizeof(mData)-2);
+                        }
+                    }
+                    else
+                    {
+                        esm.fail("Don't know what to do in this version");
+                    }
+                    break;
+                }
+                case ESM::FourCC<'B','N','A','M'>::value:
+                    mSleepList = esm.getHString();
+                    break;
+                case ESM::FourCC<'C','N','A','M'>::value:
+                    esm.getHT(mMapColor);
+                    break;
+                case ESM::FourCC<'S','N','A','M'>::value:
+                    SoundRef sr;
+                    esm.getHT(sr, 33);
+                    mSoundList.push_back(sr);
+                    break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
+            }
         }
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
 
     void Region::save(ESMWriter &esm) const
     {
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
         }
+
         esm.writeHNString("NAME", mId);
         esm.writeHNOCString("FNAM", mName);
 
diff --git a/components/esm/loadrepa.cpp b/components/esm/loadrepa.cpp
index fb213efd83..74e682d63e 100644
--- a/components/esm/loadrepa.cpp
+++ b/components/esm/loadrepa.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,19 +14,24 @@ namespace ESM
 
     void Repair::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
-        bool hasData = true;
+        bool hasName = false;
+        bool hasData = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -46,18 +50,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing RIDT subrecord");
     }
 
     void Repair::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp
index e6c5166952..66d9d0057f 100644
--- a/components/esm/loadscpt.cpp
+++ b/components/esm/loadscpt.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -62,23 +61,27 @@ namespace ESM
 
     void Script::load(ESMReader &esm)
     {
-        SCHD data;
-        esm.getHNT(data, "SCHD", 52);
-        mData = data.mData;
-        mId = data.mName.toString();
-
-        // In scripts DELE sub-record appears after a header.
-        // The script data is following after DELE in this case.
-        mIsDeleted = readDeleSubRecord(esm);
-
         mVarNames.clear();
+        mIsDeleted = false;
 
+        bool hasHeader = false;
         while (esm.hasMoreSubs())
         {
             esm.getSubName();
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'S','C','H','D'>::value:
+                    SCHD data;
+                    esm.getHT(data, 52);
+                    mData = data.mData;
+                    mId = data.mName.toString();
+                    hasHeader = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'S','C','V','R'>::value:
                     // list of local variables
                     loadSCVR(esm);
@@ -98,8 +101,12 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
+
+        if (!hasHeader)
+            esm.fail("Missing SCHD subrecord");
     }
 
     void Script::save(ESMWriter &esm) const
@@ -119,7 +126,7 @@ namespace ESM
 
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
         }
 
         if (!mVarNames.empty())
diff --git a/components/esm/loadsndg.cpp b/components/esm/loadsndg.cpp
index 261087be05..a20e6ee519 100644
--- a/components/esm/loadsndg.cpp
+++ b/components/esm/loadsndg.cpp
@@ -3,24 +3,21 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
     unsigned int SoundGenerator::sRecordId = REC_SNDG;
 
     SoundGenerator::SoundGenerator()
-        : mIsDeleted(false)
+        : mType(LeftFoot),
+          mIsDeleted(false)
     {}
 
     void SoundGenerator::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +25,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'D','A','T','A'>::value:
                     esm.getHT(mType, 4);
                     hasData = true;
@@ -40,23 +45,26 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
-            esm.fail("Missing DATA");
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
+            esm.fail("Missing DATA subrecord");
     }
     void SoundGenerator::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
-        if (mIsDeleted)
-        {
-            writeDeleSubRecord(esm);
-            return;
-        }
-
         esm.writeHNT("DATA", mType, 4);
         esm.writeHNOCString("CNAM", mCreature);
         esm.writeHNOCString("SNAM", mSound);
+        
+        if (mIsDeleted)
+        {
+            esm.writeHNCString("DELE", "");
+        }
     }
 
     void SoundGenerator::blank()
diff --git a/components/esm/loadsoun.cpp b/components/esm/loadsoun.cpp
index 9a1a52b1e5..55fe692929 100644
--- a/components/esm/loadsoun.cpp
+++ b/components/esm/loadsoun.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Sound::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'F','N','A','M'>::value:
                     mSound = esm.getHString();
                     break;
@@ -37,18 +41,23 @@ namespace ESM
                     break;
                 default:
                     esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
-            esm.fail("Missing DATA");
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
+            esm.fail("Missing DATA subrecord");
     }
 
     void Sound::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
diff --git a/components/esm/loadspel.cpp b/components/esm/loadspel.cpp
index d2d8c7d6df..28feffd209 100644
--- a/components/esm/loadspel.cpp
+++ b/components/esm/loadspel.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -16,13 +15,9 @@ namespace ESM
     void Spell::load(ESMReader &esm)
     {
         mEffects.mList.clear();
+        mIsDeleted = false;
 
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
-
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -31,6 +26,14 @@ namespace ESM
 
             switch (val)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'F','N','A','M'>::value:
                     mName = esm.getHString();
                     break;
@@ -43,18 +46,25 @@ namespace ESM
                     esm.getHT(s, 24);
                     mEffects.mList.push_back(s);
                     break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing SPDT subrecord");
     }
 
     void Spell::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }
 
@@ -70,9 +80,7 @@ namespace ESM
         mData.mFlags = 0;
 
         mName.clear();
-
         mEffects.mList.clear();
-
         mIsDeleted = false;
     }
 }
diff --git a/components/esm/loadstat.cpp b/components/esm/loadstat.cpp
index 2fde46bd2b..9a146a3705 100644
--- a/components/esm/loadstat.cpp
+++ b/components/esm/loadstat.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,24 +14,46 @@ namespace ESM
 
     void Static::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
+        mIsDeleted = false;
+
+        bool hasName = false;
+        while (esm.hasMoreSubs())
         {
-            return;
+            esm.getSubName();
+            uint32_t name = esm.retSubName().val;
+            switch (name)
+            {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
+                case ESM::FourCC<'M','O','D','L'>::value:
+                    mModel = esm.getHString();
+                    break;
+                default:
+                    esm.fail("Unknown subrecord");
+                    break;
+            }
         }
 
-        mModel = esm.getHNString("MODL");
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
     }
     void Static::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
-            return;
+            esm.writeHNCString("DELE", "");
+        }
+        else
+        {
+            esm.writeHNCString("MODL", mModel);
         }
-
-        esm.writeHNCString("MODL", mModel);
     }
 
     void Static::blank()
diff --git a/components/esm/loadweap.cpp b/components/esm/loadweap.cpp
index 38fb94adbf..98302c13d5 100644
--- a/components/esm/loadweap.cpp
+++ b/components/esm/loadweap.cpp
@@ -3,7 +3,6 @@
 #include "esmreader.hpp"
 #include "esmwriter.hpp"
 #include "defs.hpp"
-#include "util.hpp"
 
 namespace ESM
 {
@@ -15,12 +14,9 @@ namespace ESM
 
     void Weapon::load(ESMReader &esm)
     {
-        mId = esm.getHNString("NAME");
-        if (mIsDeleted = readDeleSubRecord(esm))
-        {
-            return;
-        }
+        mIsDeleted = false;
 
+        bool hasName = false;
         bool hasData = false;
         while (esm.hasMoreSubs())
         {
@@ -28,6 +24,14 @@ namespace ESM
             uint32_t name = esm.retSubName().val;
             switch (name)
             {
+                case ESM::FourCC<'N','A','M','E'>::value:
+                    mId = esm.getHString();
+                    hasName = true;
+                    break;
+                case ESM::FourCC<'D','E','L','E'>::value:
+                    esm.skipHSub();
+                    mIsDeleted = true;
+                    break;
                 case ESM::FourCC<'M','O','D','L'>::value:
                     mModel = esm.getHString();
                     break;
@@ -51,15 +55,19 @@ namespace ESM
                     esm.fail("Unknown subrecord");
             }
         }
-        if (!hasData)
+
+        if (!hasName)
+            esm.fail("Missing NAME subrecord");
+        if (!hasData && !mIsDeleted)
             esm.fail("Missing WPDT subrecord");
     }
     void Weapon::save(ESMWriter &esm) const
     {
         esm.writeHNCString("NAME", mId);
+
         if (mIsDeleted)
         {
-            writeDeleSubRecord(esm);
+            esm.writeHNCString("DELE", "");
             return;
         }