//
// arcHelp.cpp: low-level archiving functions.
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
//
//




#ifdef NEED_PCH
   #include "pch.h"
#else
   #include "stdafx.h"
#endif // !NEED_PCH

#define IS_ARCHELP_CPP
#define IS_ARCHELP_CPP


#include "arcHelp.h"
#include "globs.h"
// #include "ghost.h"
#include <sys/stat.h>

#ifndef _WIN32
#include <string.h>
#define _stat64 stat64
#endif





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// class KeyValData:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////




// qxKeyValData()

KeyValData::KeyValData() {
} // KeyValData::KeyValData() 



// qxKeyValData()

KeyValData::KeyValData(const KeyValData &rs)
   : m_uchSing(rs.m_uchSing)
   , m_intSing(rs.m_intSing)
   , m_sllSing(rs.m_sllSing)
   , m_doubSing(rs.m_doubSing)
   , m_starSing(rs.m_starSing)
   , m_kvdSing(rs.m_kvdSing)
   , m_uchArry(rs.m_uchArry)
   , m_schArry(rs.m_schArry)
   , m_intArry(rs.m_intArry)
   , m_sllArry(rs.m_sllArry)
   , m_ullArry(rs.m_ullArry)
   , m_doubArry(rs.m_doubArry)
{
} // KeyValData::KeyValData(const KeyValData &rs)



// qxKeyValData()

KeyValData::KeyValData(const std::vector<unsigned char> &vcValData) {
   const unsigned char *pcStart  = (const unsigned char *)(&vcValData[0]);
   const unsigned char *pcTooFar = pcStart  +  vcValData.size();
   const unsigned char *pcWalk   = pcStart;
   this->fleshMe(pcWalk, pcTooFar, false);  // don't append.
} // KeyValData::KeyValData() 






// qxKeyValData()

KeyValData::KeyValData(const unsigned char *pcStart, int nChar) {
   const unsigned char *pcTooFar = pcStart  +  nChar;
   const unsigned char *pcWalk   = pcStart;
   this->fleshMe(pcWalk, pcTooFar, false);  // don't append.
} // KeyValData::KeyValData() 






// qx~KeyValData()

KeyValData::~KeyValData() {
   clearMe();  // not really necessary, but clean.
} // KeyValData::~KeyValData() 





// qxKeyValData::operator=()
// qxoperator=()

const KeyValData &KeyValData::operator=(const KeyValData &rs) {
   if(this != &rs) {
      m_uchSing   = rs.m_uchSing;
      m_intSing   = rs.m_intSing;
      m_sllSing   = rs.m_sllSing;
      m_doubSing  = rs.m_doubSing;
      m_starSing  = rs.m_starSing;
      m_kvdSing   = rs.m_kvdSing;
      m_uchArry   = rs.m_uchArry;
      m_schArry   = rs.m_schArry;
      m_intArry   = rs.m_intArry;
      m_sllArry   = rs.m_sllArry;
      m_ullArry   = rs.m_ullArry;
      m_doubArry  = rs.m_doubArry;
   } // if(this != &rs)

   return *this;
} // const KeyValData &KeyValData::operator=(const KeyValData &rs) 




// qxKeyValData::operator==()
// qxoperator==()

bool KeyValData::operator==(const KeyValData &rs) const {
   if(this != &rs) {
      if(m_uchSing  != rs.m_uchSing)  return false;
      if(m_intSing  != rs.m_intSing)  return false;
      if(m_sllSing  != rs.m_sllSing)  return false;
      if(m_doubSing != rs.m_doubSing) return false;
      if(m_starSing != rs.m_starSing) return false;
      if(m_kvdSing  != rs.m_kvdSing)  return false;
      if(m_uchArry  != rs.m_uchArry)  return false;
      if(m_schArry  != rs.m_schArry)  return false;
      if(m_intArry  != rs.m_intArry)  return false;
      if(m_sllArry  != rs.m_sllArry)  return false;
      if(m_ullArry  != rs.m_ullArry)  return false;
      if(m_doubArry != rs.m_doubArry) return false;
   } // if(this != &rs)

   return true;
} // bool KeyValData::operator==(const KeyValData &rs) const





// qxclearMe()

int KeyValData::clearMe() {
   m_uchSing.clear();
   m_intSing.clear();
   m_sllSing.clear();
   m_doubSing.clear();
   m_starSing.clear();
   m_kvdSing.clear();

   m_schArry.clear();
   m_uchArry.clear();
   m_intArry.clear();
   m_ullArry.clear();
   m_sllArry.clear();
   m_doubArry.clear();

   return 0;
} // int KeyValData::clearMe()




// qxbIsPrintableChar()

inline bool bIsPrintableChar(unsigned char c) {
   if((c & 0x80) != 0)
      return false;          // high bit set

   if((c & 0x60) == 0)
      return false;          // control char, 0x00 thru 0x1F

   if(c == 0x7F)
      return false;          // del - not printable.

   return true;
} // inline bool bIsPrintableChar(unsigned char c)




//
//
// Input:
//    params
//    bAppend (default false)
//    bNoPtrFollow (default false)
//
//
//
// qxfleshMe()

int KeyValData::fleshMe(const std::vector<unsigned char> &params, bool bAppend, bool bNoPtrFollow) {
   const unsigned char *pcStart  = (const unsigned char *)(&params[0]);
   const unsigned char *pcTooFar = pcStart  +  params.size();
   const unsigned char *pcWalk   = pcStart;

   int ii = this->fleshMe(pcWalk, pcTooFar, bAppend, bNoPtrFollow);

   return ii;
} // int KeyValData::fleshMe()...




//
// Input:
//    pcWalk
//    pcTooFar
//    bAppend (default false)
//    bNoPtrFollow (default false)
//
//
//
// 12-25-16 (jdl): bNoPtrFollow (default false).
//
// qxfleshMe()

int KeyValData::fleshMe(const unsigned char *&pcWalk, const unsigned char *pcTooFar, bool bAppend, bool bNoPtrFollow) {
   int iRet = 0;

   if(!bAppend)
      clearMe();

   int ii;
   unsigned int iuKeywordLength, iuArrayLength;


   while(1) {
      std::string ssKeyword;
      char c;

      if((ii = unArcVarUin(pcWalk, pcTooFar, iuKeywordLength)) != 0)
         return NADA;

      if(iuKeywordLength == 0)
         break;       // zero-length next keyword signals end of data stream

      for(unsigned int i=0; i<iuKeywordLength; i++) {
         if((ii = unArcChar(pcWalk, pcTooFar, c)) != 0)
            return NADA;

         // keywords should use only 0x20 through 0x7E:
         if(!bIsPrintableChar(c))
            return NADA;

         ssKeyword += c;
      } // for(unsigned int i=0; i<iuKeywordLength; i++)

      unsigned char ucDataType;

      if((ii = unArcUchar(pcWalk, pcTooFar, ucDataType)) != 0)
         return NADA;

      switch(ucDataType) {
         case cucUnsignedChar:
            {
            unsigned char uc;
            if((ii = unArcUchar(pcWalk, pcTooFar, uc)) != 0)
               return NADA;

            m_uchSing[ssKeyword].push_back(uc);
            }
            break;
         case cucSignedInt4:
            {
            int i;
            if((ii = unArcInt(pcWalk, pcTooFar, i)) != 0)
               return NADA;

            m_intSing[ssKeyword].push_back(i);
            }
            break;
         case cucSignedLL8:
            {
            signed long long sll;
            if((ii = unArcLlong(pcWalk, pcTooFar, sll)) != 0)
               return NADA;

            m_sllSing[ssKeyword].push_back(sll);
            }
            break;
         case cucDouble:
            {
            double d;
            if((ii = unArcDoub(pcWalk, pcTooFar, d)) != 0)
               return NADA;

            m_doubSing[ssKeyword].push_back(d);
            }
            break;
         case cucVoidStar:
            void *pv;
            if((ii = unArcPtr(pcWalk, pcTooFar, pv)) != 0)
               return NADA;

            if(ssKeyword == BS_ARC_KEYWORD) {
               if(bNoPtrFollow) {
                  // new 12-25-16: assume pointer is invalid.
                  qprintf(fp_dbg, "Not following invalid BS_ARC_KEYWORD pointer.\n");
               } else {
                  // new 08-27-16: immediately interpret this data as a separate BS stream:
                  const std::vector<unsigned char> *pVc = (const std::vector<unsigned char> *)pv;
                  ii = this->fleshMe(*pVc, true, bNoPtrFollow);   // true: append: don't clear.
                  if(ii < 0)
                     return NADA;
               } // !if(bNoPtrFollow)
            } else {
               // always, before 08-27-16, and still the usual: push it into our data for later processing.
               m_starSing[ssKeyword].push_back(pv);
            } // !if(ssKeyword == BS_ARC_KEYWORD)

            break;
         case cucKeyValData:
            {
               // we've called this a "cuc" but it's more like a "car" in that we've stored the length.
               // char sc;
               std::vector<signed char> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               // for efficiency, work directly with the guy:
               unsigned int iSz = (unsigned int)m_kvdSing[ssKeyword].size();    // instantiates at 0 size if necessary.
               m_kvdSing[ssKeyword].resize(iSz+1);
               KeyValData &kvd = m_kvdSing[ssKeyword][iSz];

               const unsigned char *pcTF2 = pcWalk + iuArrayLength;
               if(pcTF2 > pcTooFar)
                  return NADAfunc("arcHelp.cpp, line 337");

               ii = kvd.fleshMe(pcWalk, pcTF2, false, bNoPtrFollow);
               if(ii != 0)
                  return NADAfunc("arcHelp.cpp, line 341");

            }
            break;
         case carSignedChar:
            {
               // signed char sc;  // unArcChar() doesn't like it.
               char sc;
               std::vector<signed char> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcChar(pcWalk, pcTooFar, sc)) != 0)
                     return NADA;

                  vcTmp.push_back(sc);
               } // for(int j=0; j<iuArrayLength; j++) 

               m_schArry[ssKeyword].push_back(vcTmp);

            }
            break;
         case carUnsignedChar:
            {
               unsigned char uc;
               std::vector<unsigned char> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcUchar(pcWalk, pcTooFar, uc)) != 0)
                     return NADA;

                  vcTmp.push_back(uc);
               } // for(int j=0; j<iuArrayLength; j++) 


// two

               if(ssKeyword == BS_ARC_KEYWORD) {
                  // new 11-14-15: immediately interpret this data as a separate BS stream:
                  ii = this->fleshMe(vcTmp, true, bNoPtrFollow);   // true: append: don't clear.
                  if(ii < 0)
                     return NADA;
               } else {
                  // always, before 11-14-15, and still the usual: push it into our data for later processing.
                  m_uchArry[ssKeyword].push_back(vcTmp);
               } // !if(ssKeyword == BS_ARC_KEYWORD)
            }
            break;
         case carSignedInt4:
            {
               int i;
               std::vector<int> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcInt(pcWalk, pcTooFar, i)) != 0)
                     return NADA;

                  vcTmp.push_back(i);
               } // for(int j=0; j<iuArrayLength; j++) 

               m_intArry[ssKeyword].push_back(vcTmp);
            }
            break;
         case carSignedLL8:
            {
               signed long long sll;
               std::vector<signed long long> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcLlong(pcWalk, pcTooFar, sll)) != 0)
                     return NADA;

                  vcTmp.push_back(sll);
               } // for(int j=0; j<iuArrayLength; j++) 

               m_sllArry[ssKeyword].push_back(vcTmp);
            }
            break;
         case carUnsignedLL8:
            {
               unsigned long long ull;
               std::vector<unsigned long long> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcUllong(pcWalk, pcTooFar, ull)) != 0)
                     return NADA;

                  vcTmp.push_back(ull);
               } // for(int j=0; j<iuArrayLength; j++) 

               m_ullArry[ssKeyword].push_back(vcTmp);
            }
            break;
         case carDouble:
            {
               double d;
               std::vector<double> vcTmp;
               if((ii = unArcVarUin(pcWalk, pcTooFar, iuArrayLength)) != 0)
                  return NADA;

               for(int j=0; j<(int)iuArrayLength; j++) {
                  if((ii = unArcDoub(pcWalk, pcTooFar, d)) != 0)
                     return NADA;

                  vcTmp.push_back(d);
               } // for(int j=0; j<iuArrayLength; j++) 

               m_doubArry[ssKeyword].push_back(vcTmp);
            }
            break;
         default:
            iRet = NADA;
            break;
      } // switch(ucType)

      if(iRet < 0)
         break;
   } // while(1)

   return iRet;
} // int KeyValData::fleshMe()





//
//
//
// 10-22-22 (jdl): don't print out anything with zero entries.
//
// qxdumpKvd()

int KeyValData::dumpKvd(FILE *fp_out) const {
   if(fp_out == NULL)
      return NADA;

   if(m_uchSing.size() > 0) {
      fprintf(fp_out, "   Unsigned Char scalar (%d entries).\n", (int)m_uchSing.size());
      std::map<std::string, std::vector<unsigned char>>::const_iterator itucs;
      for(itucs=m_uchSing.begin(); itucs!=m_uchSing.end(); itucs++) {
         const std::string &ssKey = itucs->first;
         const std::vector<unsigned char> &vUc = itucs->second;
         for(int j=0; j<vUc.size(); j++) {
            unsigned char ucVal      = vUc[j];
            fprintf(fp_out, "      %-20s %10d.\n", ssKey.c_str(), ucVal);
         } // for(int j=0; j<vUc.size(); j++)
      } // for(itucs=m_uchSing.begin(); itucs!=m_uchSing.end(); itucs++)
   } // if(m_uchSing.size() > 0)


   if(m_intSing.size() > 0) {
      fprintf(fp_out, "   Signed Int scalar (%d entries).\n", (int)m_intSing.size());
      std::map<std::string, std::vector<int>>::const_iterator itis;
      for(itis=m_intSing.begin(); itis!=m_intSing.end(); itis++) {
         const std::string &ssKey = itis->first;
         const std::vector<int> &vInt = itis->second;
         for(int j=0; j<vInt.size(); j++) {
            int iVal                 = vInt[j];
            fprintf(fp_out, "      %-20s %10d.\n", ssKey.c_str(), iVal);
         } // for(int j=0; j<vInt.size(); j++)
      } // for(itis=m_intSing.begin(); itis!=m_intSing.end(); itis++)
   } // if(m_intSing.size() > 0)


   if(m_sllSing.size() > 0) {
      fprintf(fp_out, "   Signed Long Long scalar (%d entries).\n", (int)m_sllSing.size());
      std::map<std::string, std::vector<signed long long>>::const_iterator itlls;
      for(itlls=m_sllSing.begin(); itlls!=m_sllSing.end(); itlls++) {
         const std::string &ssKey = itlls->first;
         const std::vector<signed long long> &vInt = itlls->second;
         for(int j=0; j<vInt.size(); j++) {
            signed long long sllVal   = vInt[j];
            fprintf(fp_out, "      %-20s %20lld.\n", ssKey.c_str(), sllVal);
         } // for(int j=0; j<vInt.size(); j++)
      } // for(itlls=m_sllSing.begin(); itlls!=m_sllSing.end(); itlls++)
   } // if(m_sllSing.size() > 0)


   if(m_doubSing.size() > 0) {
      fprintf(fp_out, "   Double scalar (%d entries).\n", (int)m_doubSing.size());
      std::map<std::string, std::vector<double>>::const_iterator itds;
      for(itds=m_doubSing.begin(); itds!=m_doubSing.end(); itds++) {
         const std::string         &ssKey = itds->first;
         const std::vector<double> &vDoub = itds->second;
         for(int j=0; j<vDoub.size(); j++) {
            double dVal = vDoub[j];
            fprintf(fp_out, "      %-20s %30.15f\n", ssKey.c_str(), dVal);
         } // for(int j=0; j<vDoub.size(); j++)
      } // for(itds=m_doubSing.begin(); itds!=m_doubSing.end(); itds++)
   } // if(m_doubSing.size() > 0)


   if(m_starSing.size() > 0) {
      fprintf(fp_out, "   Pointer scalar (%d entries).\n", (int)m_starSing.size());
      std::map<std::string, std::vector<void *>>::const_iterator itps;
      for(itps=m_starSing.begin(); itps!=m_starSing.end(); itps++) {
         const std::string         &ssKey = itps->first;
         const std::vector<void *> &vStar = itps->second;
         for(int j=0; j<vStar.size(); j++) {
            void *pVal = vStar[j];
            fprintf(fp_out, "      %-20s %p\n", ssKey.c_str(), pVal);
         } // for(int j=0; j<vStar.size(); j++)
      } // for(itps=m_starSing.begin(); itps!=m_starSing.end(); itps++)
   } // if(m_starSing.size() > 0)


   if(m_kvdSing.size() > 0) {
      fprintf(fp_out, "   Nested KeyValData (%d entries).\n", (int)m_kvdSing.size());
      std::map<std::string, std::vector<KeyValData>>::const_iterator itkvd;
      for(itkvd=m_kvdSing.begin(); itkvd!=m_kvdSing.end(); itkvd++) {
         const std::string &ssKey = itkvd->first;
         const std::vector<KeyValData> &vKvd = itkvd->second;
         for(int j=0; j<vKvd.size(); j++) {
            const KeyValData &kvd    = vKvd[j];
            fprintf(fp_out, "      %-20s begin nested dump %d.\n", ssKey.c_str(), j);
            int ii = kvd.dumpKvd(fp_out);
            if(ii != 0)
               return NADAfunc("arcHelp.cpp, line 552");
            fprintf(fp_out, "      %-20s end   nested dump %d.\n", ssKey.c_str(), j);
         } // for(int j=0; j<vKvd.size(); j++)
      } // for(itkvd=m_kvdSing.begin(); itkvd!=m_kvdSing.end(); itkvd++)
   } // if(m_kvdSing.size() > 0)



   if(m_schArry.size() > 0) {
      fprintf(fp_out, "   Signed Char array (%d entries).\n", (int)m_schArry.size());
      std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator itsca;
      for(itsca=m_schArry.begin(); itsca!=m_schArry.end(); itsca++) {
         const std::string &ssKey = itsca->first;
         const std::vector<std::vector<signed char>> &vcSS = itsca->second;
         for(int j=0; j<vcSS.size(); j++) {
            const std::vector<signed char> &vcS = vcSS[j];
            int iSz                     = (int)vcS.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            std::string ssPrintable;
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               signed char scVal = vcS[k];
               if((scVal >= 32) && (scVal < 127))
                  ssPrintable += scVal;
               fprintf(fp_out, "         %10d.\n", scVal);
            } // for(signed int k=0; k<iSz; k++)

            if(ssPrintable.size() == iSz)
               fprintf(fp_out, "         In other words: |%s|\n", ssPrintable.c_str());

         } // for(int j=0; j<vcII.size(); j++)
      } // for(itsca=m_schArry.begin(); itsca!=m_schArry.end(); itsca++)
   } // if(m_schArry.size() > 0)


   if(m_uchArry.size() > 0) {
      fprintf(fp_out, "   Unsigned Char array (%d entries).\n", (int)m_uchArry.size());
      std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator ituca;
      for(ituca=m_uchArry.begin(); ituca!=m_uchArry.end(); ituca++) {
         const std::string &ssKey = ituca->first;
         const std::vector<std::vector<unsigned char>> &vcUU = ituca->second;
         for(int j=0; j<vcUU.size(); j++) {
            const std::vector<unsigned char> &vcU = vcUU[j];
            int iSz                     = (int)vcU.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            std::string ssPrintable;
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               unsigned char ucVal = vcU[k];
               if((ucVal >= 32) && (ucVal < 127))
                  ssPrintable += ucVal;
               fprintf(fp_out, "         %10d.\n", ucVal);
            } // for(unsigned int k=0; k<iSz; k++)

            if(ssPrintable.size() == iSz)
               fprintf(fp_out, "         In other words: |%s|\n", ssPrintable.c_str());

         } // for(int j=0; j<vcII.size(); j++)
      } // for(ituca=m_uchArry.begin(); ituca!=m_uchArry.end(); ituca++)
   } // if(m_uchArry.size() > 0)


   if(m_intArry.size() > 0) {
      fprintf(fp_out, "   Signed Int array (%d entries).\n", (int)m_intArry.size());
      std::map<std::string, std::vector<std::vector<int>>>::const_iterator itia;
      for(itia=m_intArry.begin(); itia!=m_intArry.end(); itia++) {
         const std::string &ssKey = itia->first;
         const std::vector<std::vector<int>> &vcII = itia->second;
         for(int j=0; j<vcII.size(); j++) {
            const std::vector<int> &vcI = vcII[j];
            int iSz                     = (int)vcI.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               int iVal = vcI[k];
               fprintf(fp_out, "         %10d.\n", iVal);
            } // for(unsigned int k=0; k<iSz; k++)
         } // for(int j=0; j<vcII.size(); j++)
      } // for(itia=m_intArry.begin(); itia!=m_intArry.end(); itia++)
   } // if(m_intArry.size() > 0)


   if(m_sllArry.size() > 0) {
      fprintf(fp_out, "   Signed Long Long array (%d entries).\n", (int)m_sllArry.size());
      std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator itslla;
      for(itslla=m_sllArry.begin(); itslla!=m_sllArry.end(); itslla++) {
         const std::string &ssKey = itslla->first;
         const std::vector<std::vector<signed long long>> &vcLL = itslla->second;
         for(int j=0; j<vcLL.size(); j++) {
            const std::vector<signed long long> &vcS = vcLL[j];
            int iSz                     = (int)vcS.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               signed long long sllVal = vcS[k];
               fprintf(fp_out, "         %10lld.\n", sllVal);
            } // for(unsigned int k=0; k<iSz; k++)
         } // for(int j=0; j<vcLL.size(); j++)
      } // for(itslla=m_sllArry.begin(); itslla!=m_sllArry.end(); itslla++)
   } // if(m_sllArry.size() > 0)


   if(m_ullArry.size() > 0) {
      fprintf(fp_out, "   Unsigned Long Long array (%d entries).\n", (int)m_ullArry.size());
      std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator itulla;
      for(itulla=m_ullArry.begin(); itulla!=m_ullArry.end(); itulla++) {
         const std::string &ssKey = itulla->first;
         const std::vector<std::vector<unsigned long long>> &vcULL = itulla->second;
         for(int j=0; j<vcULL.size(); j++) {
            const std::vector<unsigned long long> &vcU = vcULL[j];
            int iSz                     = (int)vcU.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               unsigned long long ullVal = vcU[k];
               fprintf(fp_out, "         %10llu.\n", ullVal);
            } // for(unsigned int k=0; k<iSz; k++)
         } // for(int j=0; j<vcULL.size(); j++)
      } // for(itulla=m_ullArry.begin(); itulla!=m_ullArry.end(); itulla++)
   } // if(m_ullArry.size() > 0)


   if(m_doubArry.size() > 0) {
      fprintf(fp_out, "   Double array (%d entries).\n", (int)m_doubArry.size());
      std::map<std::string, std::vector<std::vector<double>>>::const_iterator itda;
      for(itda=m_doubArry.begin(); itda!=m_doubArry.end(); itda++) {
         const std::string &ssKey = itda->first;
         const std::vector<std::vector<double>> &vcDD = itda->second;
         for(int j=0; j<vcDD.size(); j++) {
            const std::vector<double> &vcD = vcDD[j];
            // const std::vector<double> &vcD = itda->second;
            int iSz                     = (int)vcD.size();
            fprintf(fp_out, "      %-20s %10d array values:\n", ssKey.c_str(), iSz);
            for(unsigned int k=0; k<(unsigned int)iSz; k++) {
               double dVal = vcD[k];
               fprintf(fp_out, "         %30.15f\n", dVal);
            } // for(unsigned int k=0; k<iSz; k++)
         } // for(int j=0; j<vcDD.size(); j++)
      } // for(itda=m_doubArry.begin(); itda!=m_doubArry.end(); itda++)
   } // if(m_doubArry.size() > 0)

   return 0;
} // int KeyValData::dumpKvd(FILE *fp_out) const




//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetUchKeys()

int KeyValData::getUchKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<unsigned char>>::const_iterator it;
   for(it=m_uchSing.begin(); it!=m_uchSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_uchSing.begin(); it!=m_uchSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getUchKeys(std::vector<std::string> &vcSsKeysOut) const




//
//
//
//
//
//
// qxnUchSing()
//

int KeyValData::nUchSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<unsigned char>>::const_iterator it = m_uchSing.find(pcKey);
   if(it == m_uchSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nUchSing(const char *pcKey)...




//
// we need a vector out in case keyword was repeated.
//
//
//
//
// qxgetUchSing()
//

int KeyValData::getUchSing(const char *pcKey, std::vector<unsigned char> &vUchsOut) const {
   vUchsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<unsigned char>>::const_iterator it = m_uchSing.find(pcKey);
   if(it != m_uchSing.end())
      vUchsOut = it->second;

   return (int)vUchsOut.size();
} // int KeyValData::getUchSing(const char *pcKey, std::vector<void *> &vUchsOut)





//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetUchSing()
//

const std::vector<unsigned char> &KeyValData::getUchSing(const char *pcKey) const {
   static std::vector<unsigned char> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<unsigned char>>::const_iterator it = m_uchSing.find(pcKey);
   if(it == m_uchSing.end())
      return vcEmpty;

   return it->second;
}




//
//
//
//
//
// qxgetLastUchSing()

unsigned char KeyValData::getLastUchSing(const char *pcKey, unsigned char ucDefault) const {
   unsigned char ucRet = ucDefault;

   std::vector<unsigned char> vUc;
   int ii = this->getUchSing(pcKey, vUc);
   if(ii > 0)
      ucRet = vUc[ii-1];

   return ucRet;
} // void *KeyValData::getLastUchSing(const char *pcKey, unsigned char ucDefault)



//
//
//
//
//
// qxgetIthUchSing()

unsigned char KeyValData::getIthUchSing(int ith, const char *pcKey, unsigned char ucDefault) const {
   if(pcKey == NULL)
      return (unsigned char)NADAfunc("arcHelp.cpp, line 816");

   unsigned char ucRet = ucDefault;

   if(ith < 0)
      return ucDefault;

   std::vector<unsigned char> vUc;
   int ii = this->getUchSing(pcKey, vUc);
   if(ii > ith)
      ucRet = vUc[ith];

   return ucRet;
} // void *KeyValData::getIthUchSing(const char *pcKey, unsigned char ucDefault)



//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastUchSing()
//

int KeyValData::setLastUchSing(const char *pcKey, unsigned char ucNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 843");

   int nEntries = this->nUchSing(pcKey);
   if(nEntries == 0) {
      this->addUchSing(pcKey, ucNew);
   } else {
      m_uchSing[pcKey][nEntries-1] = ucNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastUchSing(const char *pcKey, unsigned char ucNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthUchSing()
//

int KeyValData::setIthUchSing(int ith, const char *pcKey, unsigned char ucNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 869");

   int nEntries = this->nUchSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 873");

   std::vector<unsigned char> &vcThis = m_uchSing[pcKey];
   vcThis[ith] = ucNew;

   return 0;
} // int KeyValData::setIthUchSing(int ith, const char *pcKey, unsigned char ucNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddUchSing()
//

int KeyValData::addUchSing(const char *pcKey, unsigned char ucNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 894");

   m_uchSing[pcKey].push_back(ucNew);

   return 0;
} // int KeyValData::addUchSing(const char *pcKey, unsigned char ucNew)





//
// clears entry
//
//
//
// qxclrUchSing()
//

int KeyValData::clrUchSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 915");

   m_uchSing.erase(pcKey);

   return 0;
} // int KeyValData::clrUchSing(const char *pcKey)





//
// clears entry, then adds ucNew back
//
//
//
// qxreplaceUchSing()
//

int KeyValData::replaceUchSing(const char *pcKey, unsigned char ucNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 936");

   clrUchSing(pcKey);
   addUchSing(pcKey, ucNew);

   return 0;
} // int KeyValData::replaceUchSing(const char *pcKey, unsigned char ucNew)





//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetIntKeys()

int KeyValData::getIntKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<int>>::const_iterator it;
   for(it=m_intSing.begin(); it!=m_intSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_intSing.begin(); it!=m_intSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getIntKeys(std::vector<std::string> &vcSsKeysOut) const





//
//
//
//
//
//
// qxnIntSing()
//

int KeyValData::nIntSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<int>>::const_iterator it = m_intSing.find(pcKey);
   if(it == m_intSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nIntSing(const char *pcKey)...



//
// we need a vector out in case keyword was repeated.
//
//
//
//
// qxgetIntSing()
//

int KeyValData::getIntSing(const char *pcKey, std::vector<int> &vIntsOut) const {
   vIntsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<int>>::const_iterator it = m_intSing.find(pcKey);
   if(it != m_intSing.end())
      vIntsOut = it->second;

   return (int)vIntsOut.size();
} // int KeyValData::getIntSing(const char *pcKey, std::vector<void *> &vIntsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetIntSing()
//

const std::vector<int> &KeyValData::getIntSing(const char *pcKey) const {
   static std::vector<int> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<int>>::const_iterator it = m_intSing.find(pcKey);
   if(it == m_intSing.end())
      return vcEmpty;

   return it->second;
}




//
//
//
//
//
// qxgetLastIntSing()

int KeyValData::getLastIntSing(const char *pcKey, int iDefault) const {
   int iRet = iDefault;    // in case we don't find this keyword.

   std::vector<int> vI;
   int ii = this->getIntSing(pcKey, vI);
   if(ii > 0)
      iRet = vI[ii-1];

   return iRet;
} // void *KeyValData::getLastIntSing(const char *pcKey, int iDefault)




//
//
//
//
//
// qxgetIthIntSing()

int KeyValData::getIthIntSing(int ith, const char *pcKey, int iDefault) const {
   int iRet = iDefault;

   if(ith < 0)
      return iDefault;

   std::vector<int> vI;
   int ii = this->getIntSing(pcKey, vI);
   if(ii > ith)
      iRet = vI[ith];

   return iRet;
} // int KeyValData::getIthIntSing(const char *pcKey, unsigned char ucDefault)




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastIntSing()
//

int KeyValData::setLastIntSing(const char *pcKey, int iNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1108");

   int nEntries = this->nIntSing(pcKey);
   if(nEntries == 0) {
      this->addIntSing(pcKey, iNew);
   } else {
      m_intSing[pcKey][nEntries-1] = iNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastIntSing(const char *pcKey, int iNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthIntSing()
//

int KeyValData::setIthIntSing(int ith, const char *pcKey, int iNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1134");

   int nEntries = this->nIntSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 1138");

   std::vector<int> &vcThis = m_intSing[pcKey];
   vcThis[ith] = iNew;

   return 0;
} // int KeyValData::setIthIntSing(int ith, const char *pcKey, int iNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddIntSing()
//

int KeyValData::addIntSing(const char *pcKey, int iNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1159");

   m_intSing[pcKey].push_back(iNew);

   return 0;
} // int KeyValData::addIntSing(const char *pcKey, int iNew)





//
// clears entry
//
//
//
// qxclrIntSing()
//

int KeyValData::clrIntSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1180");

   m_intSing.erase(pcKey);

   return 0;
} // int KeyValData::clrIntSing(const char *pcKey)





//
// clears entry, then adds iNew back
//
//
//
// qxreplaceIntSing()
//

int KeyValData::replaceIntSing(const char *pcKey, int iNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1201");

   clrIntSing(pcKey);
   addIntSing(pcKey, iNew);

   return 0;
} // int KeyValData::replaceIntSing(const char *pcKey, int iNew)




//////





//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetSllKeys()

int KeyValData::getSllKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<signed long long>>::const_iterator it;
   for(it=m_sllSing.begin(); it!=m_sllSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_sllSing.begin(); it!=m_sllSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getSllKeys(std::vector<std::string> &vcSsKeysOut) const





//
//
//
//
//
//
// qxnSllSing()
//

int KeyValData::nSllSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<signed long long>>::const_iterator it = m_sllSing.find(pcKey);
   if(it == m_sllSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nSllSing(const char *pcKey)...



//
// we need a vector out in case keyword was repeated.
//
//
//
//
// qxgetSllSing()
//

int KeyValData::getSllSing(const char *pcKey, std::vector<signed long long> &vSllsOut) const {
   vSllsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<signed long long>>::const_iterator it = m_sllSing.find(pcKey);
   if(it != m_sllSing.end())
      vSllsOut = it->second;

   return (int)vSllsOut.size();
} // int KeyValData::getSllSing(const char *pcKey, std::vector<void *> &vSllsOut)





//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetSllSing()
//

const std::vector<signed long long> &KeyValData::getSllSing(const char *pcKey) const {
   static std::vector<signed long long> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<signed long long>>::const_iterator it = m_sllSing.find(pcKey);
   if(it == m_sllSing.end())
      return vcEmpty;

   return it->second;
}




//
//
//
//
//
// qxgetLastSllSing()

signed long long KeyValData::getLastSllSing(const char *pcKey, signed long long iDefault) const {
   signed long long iRet = iDefault;    // in case we don't find this keyword.

   std::vector<signed long long> vI;
   int ii = this->getSllSing(pcKey, vI);
   if(ii > 0)
      iRet = vI[ii-1];

   return iRet;
} // void *KeyValData::getLastSllSing(const char *pcKey, signed long long iDefault)




//
//
//
//
//
// qxgetIthSllSing()

signed long long KeyValData::getIthSllSing(int ith, const char *pcKey, signed long long iDefault) const {
   signed long long iRet = iDefault;

   if(ith < 0)
      return iDefault;

   std::vector<signed long long> vI;
   int ii = this->getSllSing(pcKey, vI);
   if(ii > ith)
      iRet = vI[ith];

   return iRet;
} // signed long long KeyValData::getIthSllSing(const char *pcKey, unsigned char ucDefault)





//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastSllSing()
//

int KeyValData::setLastSllSing(const char *pcKey, signed long long sllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1375");

   int nEntries = this->nSllSing(pcKey);
   if(nEntries == 0) {
      this->addSllSing(pcKey, sllNew);
   } else {
      m_sllSing[pcKey][nEntries-1] = sllNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastSllSing(const char *pcKey, signed long long sllNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthSllSing()
//

int KeyValData::setIthSllSing(int ith, const char *pcKey, signed long long sllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1401");

   int nEntries = this->nSllSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 1405");

   std::vector<signed long long> &vcThis = m_sllSing[pcKey];
   vcThis[ith] = sllNew;

   return 0;
} // int KeyValData::setIthSllSing(int ith, const char *pcKey, signed long long sllNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddSllSing()
//

int KeyValData::addSllSing(const char *pcKey, signed long long sllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1426");

   m_sllSing[pcKey].push_back(sllNew);

   return 0;
} // int KeyValData::addSllSing(const char *pcKey, signed long long sllNew)





//
// clears entry
//
//
//
// qxclrSllSing()
//

int KeyValData::clrSllSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1447");

   m_sllSing.erase(pcKey);

   return 0;
} // int KeyValData::clrSllSing(const char *pcKey)





//
// clears entry, then adds sllNew back
//
//
//
// qxreplaceSllSing()
//

int KeyValData::replaceSllSing(const char *pcKey, signed long long sllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1468");

   clrSllSing(pcKey);
   addSllSing(pcKey, sllNew);

   return 0;
} // int KeyValData::replaceSllSing(const char *pcKey, signed long long sllNew)





//////





//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetDoubKeys()

int KeyValData::getDoubKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<double>>::const_iterator it;
   for(it=m_doubSing.begin(); it!=m_doubSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_doubSing.begin(); it!=m_doubSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getDoubKeys(std::vector<std::string> &vcSsKeysOut) const





//
//
//
//
//
//
// qxnDoubSing()
//

int KeyValData::nDoubSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<double>>::const_iterator it = m_doubSing.find(pcKey);
   if(it == m_doubSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nDoubSing(const char *pcKey)...




//
// we need a vector out in case keyword was repeated.
//
//
//
//
// qxgetDoubSing()
//

int KeyValData::getDoubSing(const char *pcKey, std::vector<double> &vDoubsOut) const {
   vDoubsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<double>>::const_iterator it = m_doubSing.find(pcKey);
   if(it != m_doubSing.end())
      vDoubsOut = it->second;


   return (int)vDoubsOut.size();
} // double KeyValData::getDoubSing(const char *pcKey, std::vector<void *> &vDoubsOut)





//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetDoubSing()
//

const std::vector<double> &KeyValData::getDoubSing(const char *pcKey) const {
   static std::vector<double> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<double>>::const_iterator it = m_doubSing.find(pcKey);
   if(it == m_doubSing.end())
      return vcEmpty;

   return it->second;
}





//
//
//
//
//
// qxgetLastDoubSing()

double KeyValData::getLastDoubSing(const char *pcKey, double dDefault) const {
   double dRet = dDefault;    // in case we don't find this keyword.

   std::vector<double> vD;
   int ii = this->getDoubSing(pcKey, vD);
   if(ii > 0)
      dRet = vD[ii-1];

   return dRet;
} // void *KeyValData::getLastDoubSing(const char *pcKey, double dDefault)



//
//
//
//
//
// qxgetIthDoubSing()

double KeyValData::getIthDoubSing(int ith, const char *pcKey, double dDefault) const {
   double dRet = dDefault;

   if(ith < 0)
      return dDefault;

   std::vector<double> vD;
   int ii = this->getDoubSing(pcKey, vD);
   if(ii > ith)
      dRet = vD[ith];

   return dRet;
} // double KeyValData::getIthDoubSing(const char *pcKey, double dDefault)




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastDoubSing()
//

int KeyValData::setLastDoubSing(const char *pcKey, double dNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1644");

   int nEntries = this->nDoubSing(pcKey);
   if(nEntries == 0) {
      this->addDoubSing(pcKey, dNew);
   } else {
      m_doubSing[pcKey][nEntries-1] = dNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastDoubSing(const char *pcKey, double dNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthDoubSing()
//

int KeyValData::setIthDoubSing(int ith, const char *pcKey, double dNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1670");

   int nEntries = this->nDoubSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 1674");

   std::vector<double> &vcThis = m_doubSing[pcKey];
   vcThis[ith] = dNew;

   return 0;
} // int KeyValData::setIthDoubSing(int ith, const char *pcKey, double dNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddDoubSing()
//

int KeyValData::addDoubSing(const char *pcKey, double dNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1695");

   m_doubSing[pcKey].push_back(dNew);

   return 0;
} // int KeyValData::addDoubSing(const char *pcKey, double dNew)





//
// clears entry
//
//
//
// qxclrDoubSing()
//

int KeyValData::clrDoubSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1716");

   m_doubSing.erase(pcKey);

   return 0;
} // int KeyValData::clrDoubSing(const char *pcKey)





//
// clears entry, then adds dNew back
//
//
//
// qxreplaceDoubSing()
//

int KeyValData::replaceDoubSing(const char *pcKey, double dNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1737");

   clrDoubSing(pcKey);
   addDoubSing(pcKey, dNew);

   return 0;
} // int KeyValData::replaceDoubSing(const char *pcKey, double dNew)





//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetPtrKeys()

int KeyValData::getPtrKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<void *>>::const_iterator it;
   for(it=m_starSing.begin(); it!=m_starSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_starSing.begin(); it!=m_starSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getPtrKeys(std::vector<std::string> &vcSsKeysOut) const






//
//
//
//
//
//
// qxnPtrSing()
//

int KeyValData::nPtrSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<void *>>::const_iterator it = m_starSing.find(pcKey);
   if(it == m_starSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nPtrSing(const char *pcKey)...



//
// we need a vector out in case keyword was repeated.
//
//
//
//
// qxgetPtrSing()
//

int KeyValData::getPtrSing(const char *pcKey, std::vector<void *> &vPtrsOut) const {
   vPtrsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<void *>>::const_iterator it = m_starSing.find(pcKey);
   if(it != m_starSing.end()) {
      vPtrsOut = it->second;
   } else if(jdebug & 0x0001) {
      // fprintf(stdout, "getPtrSing() unable to find key \"%s\".\n", pcKey);
      qprintf(fp_dbg, "getPtrSing() unable to find key \"%s\".\n", pcKey);
   }


   return (int)vPtrsOut.size();
} // int KeyValData::getPtrSing(const char *pcKey, std::vector<void *> &vPtrsOut)






//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetPtrSing()
//

const std::vector<void *> &KeyValData::getPtrSing(const char *pcKey) const {
   const static std::vector<void *> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<void *>>::const_iterator it = m_starSing.find(pcKey);
   if(it == m_starSing.end())
      return vcEmpty;

   return it->second;
}



//
//
//
//
//
// qxgetLastPtrSing()

void *KeyValData::getLastPtrSing(const char *pcKey, void *pvDefault) const {
   void *pRet=pvDefault;    // in case we don't find this keyword.

   std::vector<void *> vPv;
   int ii = this->getPtrSing(pcKey, vPv);
   if(ii > 0)
      pRet = vPv[ii-1];

   return pRet;
} // void *KeyValData::getLastPtrSing(const char *pcKey, void *pvDefault)




//
//
//
//
//
// qxgetIthPtrSing()

void *KeyValData::getIthPtrSing(int ith, const char *pcKey, void *pvDefault) const {
   void *pRet = pvDefault;

   if(ith < 0)
      return pvDefault;

   std::vector<void *> vPv;
   int ii = this->getPtrSing(pcKey, vPv);
   if(ii > ith)
      pRet = vPv[ith];

   return pRet;
} // void *KeyValData::getIthPtrSing(const char *pcKey, unsigned char ucDefault)





//
// tries to find the passed pointer.
//
// return value: NADA if not found; else index of first entry of this value.
//
//
//
//
// qxwhichIthPtrSing()
//

int KeyValData::whichIthPtrSing(const char *pcKey, void *pvFind) const {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1984");


   int nEntries = this->nPtrSing(pcKey);
   if(nEntries <= 0)
      return NADA;

   for(int i=0; i<nEntries; i++) {
      void *pV = this->getIthPtrSing(i, pcKey);
      if(pV == pvFind)
         return i;
   } // for(int i=0; i<nEntries; i++)

   // failed to find:
   return NADA;
} // int KeyValData::whichIthPtrSing()





//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastPtrSing()
//

int KeyValData::setLastPtrSing(const char *pcKey, void * pvNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1912");

   int nEntries = this->nPtrSing(pcKey);
   if(nEntries == 0) {
      this->addPtrSing(pcKey, pvNew);
   } else {
      m_starSing[pcKey][nEntries-1] = pvNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastPtrSing(const char *pcKey, void * pvNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthPtrSing()
//

int KeyValData::setIthPtrSing(int ith, const char *pcKey, void * pvNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1938");

   int nEntries = this->nPtrSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 1942");

   std::vector<void *> &vcThis = m_starSing[pcKey];
   vcThis[ith] = pvNew;

   return 0;
} // int KeyValData::setIthPtrSing(int ith, const char *pcKey, void * pvNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddPtrSing()
//

int KeyValData::addPtrSing(const char *pcKey, void * pvNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1963");

   m_starSing[pcKey].push_back(pvNew);

   return 0;
} // int KeyValData::addPtrSing(const char *pcKey, void * pvNew)





//
// clears entry
//
//
//
// qxclrPtrSing()
//

int KeyValData::clrPtrSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1984");

   m_starSing.erase(pcKey);

   return 0;
} // int KeyValData::clrPtrSing(const char *pcKey)





//
// deletes one entry.
//
//
//
// qxdelIthPtrSing()
//

int KeyValData::delIthPtrSing(const char *pcKey, int ith) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1984");


   int nEntries = this->nPtrSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 1942");

   std::vector<void *> &vcThis = m_starSing[pcKey];

   for(int i=ith; i<(nEntries-1); i++)
      vcThis[i] = vcThis[i+1];

   vcThis.resize(nEntries-1);

   // qxl: clear (remove from map) if empty?

   return 0;
} // int KeyValData::delIthPtrSing()





//
// deletes zero or more entries.  Caller is probably hoping for 1.
//
// return value: number of entries deleted.
//
//
//
//
// qxdelValPtrSing()
//

int KeyValData::delValPtrSing(const char *pcKey, void *pvDelMe) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 1984");


   int nEntries = this->nPtrSing(pcKey);
   if(nEntries <= 0)
      return NADAfunc("arcHelp.cpp, line 1942");

   int nDeld = 0;
   std::vector<void *> &vcThis = m_starSing[pcKey];

   int iLeading=0, iLagging=0;

   for( ; iLeading<nEntries; iLeading++) {
      void *pvTest = vcThis[iLeading];
      if(pvTest == pvDelMe) {
         // kill this: don't advance iLagging.
         nDeld++;
      } else {
         // not what we're after; keep this:
         vcThis[iLagging++] = pvTest;
      } // !if(pvTest == pvDelMe)
   } // for( ; iLeading<nEntries; iLeading++)

   JASSERT((iLagging + nDeld) == nEntries);  // or == iLeading.

   if(nDeld > 0)
      vcThis.resize(iLagging);

   // qxl: clear (remove from map) if empty?

   return nDeld;
} // int KeyValData::delValPtrSing()





//
// clears entry, then adds pvNew back
//
//
//
// qxreplacePtrSing()
//

int KeyValData::replacePtrSing(const char *pcKey, void * pvNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2005");

   clrPtrSing(pcKey);
   addPtrSing(pcKey, pvNew);

   return 0;
} // int KeyValData::replacePtrSing(const char *pcKey, void * pvNew)







//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetKvdKeys()

int KeyValData::getKvdKeys(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<KeyValData>>::const_iterator it;
   for(it=m_kvdSing.begin(); it!=m_kvdSing.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_kvdSing.begin(); it!=m_kvdSing.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getKvdKeys(std::vector<std::string> &vcSsKeysOut) const






//
//
//
//
//
//
// qxnKvdSing()
//

int KeyValData::nKvdSing(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<KeyValData>>::const_iterator it = m_kvdSing.find(pcKey);
   if(it == m_kvdSing.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nKvdSing(const char *pcKey)...



//
// we need a vector out in case keyword was repeated.
//
// NOTE: this copies (potentially) a huge amount of data; try to avoid use!  Instead, use 
//    getLastKvdSing()
//    getIthKvdSing()
//
// both of which come in const and non-const versions, and return references to internal data, not copies of it.
//
//
// qxgetKvdSing()
//

int KeyValData::getKvdSing(const char *pcKey, std::vector<KeyValData> &vKvdsOut) const {
   vKvdsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<KeyValData>>::const_iterator it = m_kvdSing.find(pcKey);
   if(it != m_kvdSing.end())
      vKvdsOut = it->second;

   return (int)vKvdsOut.size();
} // int KeyValData::getKvdSing(const char *pcKey, std::vector<void *> &vIntsOut)





//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetKvdSing()
//

const std::vector<KeyValData> &KeyValData::getKvdSing(const char *pcKey) const {
   static std::vector<KeyValData> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<KeyValData>>::const_iterator it = m_kvdSing.find(pcKey);
   if(it == m_kvdSing.end())
      return vcEmpty;

   return it->second;
}




//
// See .h file for non-const version...
//
//
//
// qxgetLastKvdSing()

const KeyValData &KeyValData::getLastKvdSing(const char *pcKey, const KeyValData &kvdDefault) const {

   int nEntries = this->nKvdSing(pcKey);
   if(nEntries < 1)
      return kvdDefault;

   return this->getIthKvdSing(nEntries-1, pcKey, kvdDefault);

} // void *KeyValData::getLastKvdSing(const char *pcKey, int iDefault)




//
// See .h file for non-const version...
//
//
//
//
// qxgetIthKvdSing()

const KeyValData &KeyValData::getIthKvdSing(int ith, const char *pcKey, const KeyValData &kvdDefault) const {
   const KeyValData *pRet = &kvdDefault;

   int nEntries = this->nKvdSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return *pRet;


   std::map<std::string, std::vector<KeyValData>>::const_iterator it = m_kvdSing.find(pcKey);
   if(it != m_kvdSing.end()) {
      const std::vector<KeyValData> &vcThis = it->second;
      pRet = &vcThis[ith];
   } // if(it != m_kvdSing.end())


   return *pRet;
} // int KeyValData::getIthKvdSing(const char *pcKey, unsigned char ucDefault)




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastKvdSing()
//

int KeyValData::setLastKvdSing(const char *pcKey, const KeyValData &kvdNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2189");

   int nEntries = this->nKvdSing(pcKey);
   if(nEntries == 0) {
      this->addKvdSing(pcKey, kvdNew);
   } else {
      m_kvdSing[pcKey][nEntries-1] = kvdNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastKvdSing(const char *pcKey, const KeyValData &kvdNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthKvdSing()
//

int KeyValData::setIthKvdSing(int ith, const char *pcKey, const KeyValData &kvdNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2215");

   int nEntries = this->nKvdSing(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 2219");

   std::vector<KeyValData> &vcThis = m_kvdSing[pcKey];
   vcThis[ith] = kvdNew;

   return 0;
} // int KeyValData::setIthKvdSing(int ith, const char *pcKey, const KeyValData &kvdNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddKvdSing()
//

int KeyValData::addKvdSing(const char *pcKey, const KeyValData &kvdNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2240");

   m_kvdSing[pcKey].push_back(kvdNew);

   return 0;
} // int KeyValData::addKvdSing(const char *pcKey, const KeyValData &kvdNew)





//
// clears entry
//
//
//
// qxclrKvdSing()
//

int KeyValData::clrKvdSing(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2261");

   m_kvdSing.erase(pcKey);

   return 0;
} // int KeyValData::clrKvdSing(const char *pcKey)





//
// clears entry, then adds kvdNew back
//
//
//
// qxreplaceKvdSing()
//

int KeyValData::replaceKvdSing(const char *pcKey, const KeyValData &kvdNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2282");

   int nNow = this->nKvdSing(pcKey);
   if(nNow <= 0) {
      addKvdSing(pcKey, kvdNew);
   } else {
      std::vector<KeyValData> &vcKey = m_kvdSing[pcKey];
      vcKey[0] = kvdNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceKvdSing(const char *pcKey, const KeyValData &kvdNew)




//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetSchKeya()

int KeyValData::getSchKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it;
   for(it=m_schArry.begin(); it!=m_schArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_schArry.begin(); it!=m_schArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getSchKeya(std::vector<std::string> &vcSsKeysOut) const





//
//
//
//
//
//
// qxnSchArry()
//

int KeyValData::nSchArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it = m_schArry.find(pcKey);
   if(it == m_schArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nSchArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetSchArry()
//

int KeyValData::getSchArry(const char *pcKey, std::vector<std::vector<signed char>> &vvSchsOut) const {
   vvSchsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it = m_schArry.find(pcKey);
   if(it != m_schArry.end())
      vvSchsOut = it->second;

   return (int)vvSchsOut.size();
} // int getSchArry(const char *pcKey, std::vector<std::vector<signed char>> &vvSchsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetSchArry()
//

const std::vector<std::vector<signed char>> &KeyValData::getSchArry(const char *pcKey) const {
   static std::vector<std::vector<signed char>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it = m_schArry.find(pcKey);
   if(it == m_schArry.end())
      return vcEmpty;

   return it->second;
}






//
// gets a vector of std::string instead of a vector of signed char vectors.
//
//
//
//
//
//
// qxgetSchArr2()

int KeyValData::getSchArr2(const char *pcKey, std::vector<std::string> &vssOut) const {
   vssOut.clear();

   std::vector<std::vector<signed char>> vvSchsTmp;
   int ii = this->getSchArry(pcKey, vvSchsTmp);
   if(ii < 0)
      return ii;

   for(unsigned int i=0; i<vvSchsTmp.size(); i++) {
      const std::vector<signed char> &vsc = vvSchsTmp[i];
      std::string ssOne = vschToSs(vsc);
      vssOut.push_back(ssOne);
   } // for(unsigned int i=0; i<vvSchsTmp.size(); i++)

   return (int)vssOut.size();
} // int KeyValData::getSchArr2(const char *pcKey, std::vector<std::string> &ssOut)






//
//
//
//
//
// qxgetLastSchArry()
//

const std::vector<signed char> &KeyValData::getLastSchArry(const char *pcKey, const std::vector<signed char> &vSchDefault) const {

   if(pcKey == NULL)
      return vSchDefault;

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it = m_schArry.find(pcKey);
   if(it == m_schArry.end())
      return vSchDefault;

   const std::vector<std::vector<signed char>> &vvTmp = it->second;
   unsigned int ii = (unsigned int)vvTmp.size();
   if(ii == 0)
      return vSchDefault;

   const std::vector<signed char> &vRet = vvTmp[ii-1];

   return vRet;
} // const std::vector<signed char> &KeyValData::getLastSchArry()







//
//
//
//
//
// qxgetIthSchArry()
//

const std::vector<signed char> &KeyValData::getIthSchArry(int ith, const char *pcKey, const std::vector<signed char> &vSchDefault) const {

   if(pcKey == NULL)
      return vSchDefault;

   std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it = m_schArry.find(pcKey);
   if(it == m_schArry.end())
      return vSchDefault;

   const std::vector<std::vector<signed char>> &vvTmp = it->second;
   unsigned int ii = (unsigned int)vvTmp.size();
   if((ith < 0) || (ith >= (int)ii))
      return vSchDefault;

   const std::vector<signed char> &vRet = vvTmp[ith];

   return vRet;
} // const std::vector<signed char> &KeyValData::getIthSchArry()





//
// gets the last entry as a std::string rather than a vector of signed char.
//
//
//
//
// qxgetLastSchArr2()

std::string KeyValData::getLastSchArr2(const char *pcKey, const std::string &ssDefault) const {
   std::vector<signed char> vscDefault;
   for(unsigned i=0; i<ssDefault.size(); i++) vscDefault.push_back(ssDefault[i]);

   const std::vector<signed char> &vscTmp = this->getLastSchArry(pcKey, vscDefault);
   std::string ssRet = vschToSs(vscTmp);

   return ssRet;
} // std::string KeyValData::getLastSchArr2(const char *pcKey, const std::string &ssDefault)





//
// gets the ith entry as a std::string rather than a vector of signed char.
//
//
//
//
// qxgetIthSchArr2()

std::string KeyValData::getIthSchArr2(int ith, const char *pcKey, const std::string &ssDefault) const {
   std::vector<signed char> vscDefault;
   for(unsigned i=0; i<ssDefault.size(); i++) vscDefault.push_back(ssDefault[i]);

   const std::vector<signed char> &vscTmp = this->getIthSchArry(ith, pcKey, vscDefault);
   std::string ssRet = vschToSs(vscTmp);

   return ssRet;
} // std::string KeyValData::getIthSchArr2()...





//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastSchArry()
//

int KeyValData::setLastSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2563");

   int nEntries = this->nSchArry(pcKey);
   if(nEntries == 0) {
      this->addSchArry(pcKey, vvSchNew);
   } else {
      m_schArry[pcKey][nEntries-1] = vvSchNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthSchArry()
//

int KeyValData::setIthSchArry(int ith, const char *pcKey, const std::vector<signed char> &vvSchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2589");

   int nEntries = this->nSchArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 2593");

   std::vector<std::vector<signed char>> &vcThis = m_schArry[pcKey];
   vcThis[ith] = vvSchNew;

   return 0;
} // int KeyValData::setIthSchArry(int ith, const char *pcKey, const std::vector<signed char> &vvSchNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddSchArry()
//

int KeyValData::addSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2614");

   m_schArry[pcKey].push_back(vvSchNew);

   return 0;
} // int KeyValData::addSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew)




//
// new 02-28-23
//
//
//
//
// qxaddSchArAr()
//

int KeyValData::addSchArAr(const char *pcKey, const std::vector<std::string> &vcSs) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2615");

   for(int i=0; i<(int)vcSs.size(); i++) {
      const std::string &ssLine = vcSs[i];
      std::vector<signed char> vcSc;
      for(int j=0; j<(int)ssLine.size(); j++)
         vcSc.push_back((signed char)ssLine[j]);

      m_schArry[pcKey].push_back(vcSc);
   } // for(int i=0; i<(int)vcSs.size(); i++)


   return 0;
} // int KeyValData::addSchArAr(const char *pcKey, const std::vector<std::string> &vcSs)





//
// clears entry
//
//
//
// qxclrSchArry()
//

int KeyValData::clrSchArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2635");

   m_schArry.erase(pcKey);

   return 0;
} // int KeyValData::clrSchArry(const char *pcKey)





//
// clears entry, then adds vvSchNew back
//
//
//
// qxreplaceSchArry()
//

int KeyValData::replaceSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2656");

   int nNow = this->nSchArry(pcKey);
   if(nNow <= 0) {
      addSchArry(pcKey, vvSchNew);
   } else {
      std::vector<std::vector<signed char>> &vcKey = m_schArry[pcKey];
      vcKey[0] = vvSchNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceSchArry(const char *pcKey, const std::vector<signed char> &vvSchNew)




//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetUchKeya()

int KeyValData::getUchKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it;
   for(it=m_uchArry.begin(); it!=m_uchArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_uchArry.begin(); it!=m_uchArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getUchKeya(std::vector<std::string> &vcSsKeysOut) const






//
//
//
//
//
//
// qxnUchArry()
//

int KeyValData::nUchArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it = m_uchArry.find(pcKey);
   if(it == m_uchArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nUchArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetUchArry()
//

int KeyValData::getUchArry(const char *pcKey, std::vector<std::vector<unsigned char>> &vvUchsOut) const {
   vvUchsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it = m_uchArry.find(pcKey);
   if(it != m_uchArry.end())
      vvUchsOut = it->second;

   return (int)vvUchsOut.size();
} // int getUchArry(const char *pcKey, std::vector<std::vector<unsigned char>> &vvUchsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetUchArry()
//

const std::vector<std::vector<unsigned char>> &KeyValData::getUchArry(const char *pcKey) const {
   static std::vector<std::vector<unsigned char>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it = m_uchArry.find(pcKey);
   if(it == m_uchArry.end())
      return vcEmpty;

   return it->second;
}





//
//
//
//
//
// qxgetLastUchArry()
//

const std::vector<unsigned char> &KeyValData::getLastUchArry(const char *pcKey, const std::vector<unsigned char> &vUchDefault) const {

   if(pcKey == NULL)
      return vUchDefault;

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it = m_uchArry.find(pcKey);
   if(it == m_uchArry.end())
      return vUchDefault;

   const std::vector<std::vector<unsigned char>> &vvTmp = it->second;
   unsigned int ii = (int)vvTmp.size();
   if(ii == 0)
      return vUchDefault;

   const std::vector<unsigned char> &vRet = vvTmp[ii-1];

   return vRet;
} // void *KeyValData::getLastUchArry(const char *pcKey, const std::vector<unsigned char> &vUchDefault)





//
//
//
//
//
// qxgetIthUchArry()
//

const std::vector<unsigned char> &KeyValData::getIthUchArry(int ith, const char *pcKey, const std::vector<unsigned char> &vUchDefault) const {

   if(pcKey == NULL)
      return vUchDefault;

   std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it = m_uchArry.find(pcKey);
   if(it == m_uchArry.end())
      return vUchDefault;

   const std::vector<std::vector<unsigned char>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if((ith < 0) || (ith >= ii))
      return vUchDefault;

   const std::vector<unsigned char> &vRet = vvTmp[ith];

   return vRet;
} // void *KeyValData::getIthUchArry()...




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastUchArry()
//

int KeyValData::setLastUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2858");

   int nEntries = this->nUchArry(pcKey);
   if(nEntries == 0) {
      this->addUchArry(pcKey, vvUchNew);
   } else {
      m_uchArry[pcKey][nEntries-1] = vvUchNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthUchArry()
//

int KeyValData::setIthUchArry(int ith, const char *pcKey, const std::vector<unsigned char> &vvUchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2884");

   int nEntries = this->nUchArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 2888");

   std::vector<std::vector<unsigned char>> &vcThis = m_uchArry[pcKey];
   vcThis[ith] = vvUchNew;

   return 0;
} // int KeyValData::setIthUchArry(int ith, const char *pcKey, const std::vector<unsigned char> &vvUchNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddUchArry()
//

int KeyValData::addUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2909");

   m_uchArry[pcKey].push_back(vvUchNew);

   return 0;
} // int KeyValData::addUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew)





//
// clears entry
//
//
//
// qxclrUchArry()
//

int KeyValData::clrUchArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2930");

   m_uchArry.erase(pcKey);

   return 0;
} // int KeyValData::clrUchArry(const char *pcKey)





//
// clears entry, then adds vvUchNew back
//
//
//
// qxreplaceUchArry()
//

int KeyValData::replaceUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 2951");

   int nNow = this->nUchArry(pcKey);
   if(nNow <= 0) {
      addUchArry(pcKey, vvUchNew);
   } else {
      std::vector<std::vector<unsigned char>> &vcKey = m_uchArry[pcKey];
      vcKey[0] = vvUchNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceUchArry(const char *pcKey, const std::vector<unsigned char> &vvUchNew)





//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetIntKeya()

int KeyValData::getIntKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it;
   for(it=m_intArry.begin(); it!=m_intArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_intArry.begin(); it!=m_intArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getIntKeya(std::vector<std::string> &vcSsKeysOut) const






//
//
//
//
//
//
// qxnIntArry()
//

int KeyValData::nIntArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it = m_intArry.find(pcKey);
   if(it == m_intArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nIntArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetIntArry()
//

int KeyValData::getIntArry(const char *pcKey, std::vector<std::vector<int>> &vvIntsOut) const {
   vvIntsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it = m_intArry.find(pcKey);
   if(it != m_intArry.end())
      vvIntsOut = it->second;

   return (int)vvIntsOut.size();
} // int getIntArry(const char *pcKey, std::vector<std::vector<int>> &vvIntsOut)





//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetIntArry()
//

const std::vector<std::vector<int>> &KeyValData::getIntArry(const char *pcKey) const {
   static std::vector<std::vector<int>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it = m_intArry.find(pcKey);
   if(it == m_intArry.end())
      return vcEmpty;

   return it->second;
}




//
//
//
//
//
// qxgetLastIntArry()
//

const std::vector<int> &KeyValData::getLastIntArry(const char *pcKey, const std::vector<int> &vIntDefault) const {

   if(pcKey == NULL)
      return vIntDefault;

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it = m_intArry.find(pcKey);
   if(it == m_intArry.end())
      return vIntDefault;

   const std::vector<std::vector<int>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if(ii == 0)
      return vIntDefault;

   const std::vector<int> &vRet = vvTmp[ii-1];

   return vRet;
} // void *KeyValData::getLastIntArry(const char *pcKey, const std::vector<int> &vIntDefault)





//
//
//
//
//
// qxgetIthIntArry()
//

const std::vector<int> &KeyValData::getIthIntArry(int ith, const char *pcKey, const std::vector<int> &vIntDefault) const {

   if(pcKey == NULL)
      return vIntDefault;

   std::map<std::string, std::vector<std::vector<int>>>::const_iterator it = m_intArry.find(pcKey);
   if(it == m_intArry.end())
      return vIntDefault;

   const std::vector<std::vector<int>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if((ith < 0) || (ith >= ii))
      return vIntDefault;

   const std::vector<int> &vRet = vvTmp[ith];

   return vRet;
} // void *KeyValData::getIthIntArry()...






//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastIntArry()
//

int KeyValData::setLastIntArry(const char *pcKey, const std::vector<int> &vvINew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3156");

   int nEntries = this->nIntArry(pcKey);
   if(nEntries == 0) {
      this->addIntArry(pcKey, vvINew);
   } else {
      m_intArry[pcKey][nEntries-1] = vvINew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastIntArry(const char *pcKey, const std::vector<int> &vvINew)





//
// replaces the ith entry
// 
//
//
// qxsetIthIntArry()
//

int KeyValData::setIthIntArry(int ith, const char *pcKey, const std::vector<int> &vvINew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3182");

   int nEntries = this->nIntArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 3186");

   std::vector<std::vector<int>> &vcThis = m_intArry[pcKey];
   vcThis[ith] = vvINew;

   return 0;
} // int KeyValData::setIthIntArry(int ith, const char *pcKey, const std::vector<int> &vvINew)




//
// appends new one to whoever's there.
//
//
//
// qxaddIntArry()
//

int KeyValData::addIntArry(const char *pcKey, const std::vector<int> &vvINew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3207");

   m_intArry[pcKey].push_back(vvINew);

   return 0;
} // int KeyValData::addIntArry(const char *pcKey, const std::vector<int> &vvINew)





//
// clears entry
//
//
//
// qxclrIntArry()
//

int KeyValData::clrIntArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3228");

   m_intArry.erase(pcKey);

   return 0;
} // int KeyValData::clrIntArry(const char *pcKey)





//
// clears entry, then adds vvINew back
//
//
//
// qxreplaceIntArry()
//

int KeyValData::replaceIntArry(const char *pcKey, const std::vector<int> &vvINew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3249");

   int nNow = this->nIntArry(pcKey);
   if(nNow <= 0) {
      addIntArry(pcKey, vvINew);
   } else {
      std::vector<std::vector<int>> &vcKey = m_intArry[pcKey];
      vcKey[0] = vvINew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceIntArry(const char *pcKey, const std::vector<int> &vvINew)





//////





//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetSllKeya()

int KeyValData::getSllKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it;
   for(it=m_sllArry.begin(); it!=m_sllArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_sllArry.begin(); it!=m_sllArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getSllKeya(std::vector<std::string> &vcSsKeysOut) const





//////




//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetUllKeya()

int KeyValData::getUllKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it;
   for(it=m_ullArry.begin(); it!=m_ullArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_ullArry.begin(); it!=m_ullArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getUllKeya(std::vector<std::string> &vcSsKeysOut) const







//
//
//
//
//
//
// qxnSllArry()
//

int KeyValData::nSllArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it = m_sllArry.find(pcKey);
   if(it == m_sllArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nSllArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetSllArry()
//

int KeyValData::getSllArry(const char *pcKey, std::vector<std::vector<signed long long>> &vvSllsOut) const {
   vvSllsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it = m_sllArry.find(pcKey);
   if(it != m_sllArry.end())
      vvSllsOut = it->second;

   return (int)vvSllsOut.size();
} // int getSllArry(const char *pcKey, std::vector<std::vector<signed long long>> &vvSllsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetSllArry()
//

const std::vector<std::vector<signed long long>> &KeyValData::getSllArry(const char *pcKey) const {
   static std::vector<std::vector<signed long long>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it = m_sllArry.find(pcKey);
   if(it == m_sllArry.end())
      return vcEmpty;

   return it->second;
}





//
//
//
//
//
// qxgetLastSllArry()
//

const std::vector<signed long long> &KeyValData::getLastSllArry(const char *pcKey, const std::vector<signed long long> &vSllDefault) const {

   if(pcKey == NULL)
      return vSllDefault;

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it = m_sllArry.find(pcKey);
   if(it == m_sllArry.end())
      return vSllDefault;

   const std::vector<std::vector<signed long long>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if(ii == 0)
      return vSllDefault;

   const std::vector<signed long long> &vRet = vvTmp[ii-1];

   return vRet;
} // void *KeyValData::getLastSllArry()




//
//
//
//
//
// qxgetIthSllArry()
//

const std::vector<signed long long> &KeyValData::getIthSllArry(int ith, const char *pcKey, const std::vector<signed long long> &vSllDefault) const {

   if(pcKey == NULL)
      return vSllDefault;

   std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it = m_sllArry.find(pcKey);
   if(it == m_sllArry.end())
      return vSllDefault;

   const std::vector<std::vector<signed long long>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if((ith < 0) || (ith >= ii))
      return vSllDefault;

   const std::vector<signed long long> &vRet = vvTmp[ith];

   return vRet;
} // void *KeyValData::getIthSllArry()...




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastSllArry()
//

int KeyValData::setLastSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3485");

   int nEntries = this->nSllArry(pcKey);
   if(nEntries == 0) {
      this->addSllArry(pcKey, vvSllNew);
   } else {
      m_sllArry[pcKey][nEntries-1] = vvSllNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthSllArry()
//

int KeyValData::setIthSllArry(int ith, const char *pcKey, const std::vector<signed long long> &vvSllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3511");

   int nEntries = this->nSllArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 3515");

   std::vector<std::vector<signed long long>> &vcThis = m_sllArry[pcKey];
   vcThis[ith] = vvSllNew;

   return 0;
} // int KeyValData::setIthSllArry(int ith, const char *pcKey, const std::vector<signed long long> &vvSllNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddSllArry()
//

int KeyValData::addSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3536");

   m_sllArry[pcKey].push_back(vvSllNew);

   return 0;
} // int KeyValData::addSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew)





//
// clears entry
//
//
//
// qxclrSllArry()
//

int KeyValData::clrSllArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3557");

   m_sllArry.erase(pcKey);

   return 0;
} // int KeyValData::clrSllArry(const char *pcKey)





//
// clears entry, then adds vvSllNew back
//
//
//
// qxreplaceSllArry()
//

int KeyValData::replaceSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3578");

   int nNow = this->nSllArry(pcKey);
   if(nNow <= 0) {
      addSllArry(pcKey, vvSllNew);
   } else {
      std::vector<std::vector<signed long long>> &vcKey = m_sllArry[pcKey];
      vcKey[0] = vvSllNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)


   return 0;
} // int KeyValData::replaceSllArry(const char *pcKey, const std::vector<signed long long> &vvSllNew)









//
//
//
//
//
//
// qxnUllArry()
//

int KeyValData::nUllArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it = m_ullArry.find(pcKey);
   if(it == m_ullArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nUllArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetUllArry()
//

int KeyValData::getUllArry(const char *pcKey, std::vector<std::vector<unsigned long long>> &vvUllsOut) const {
   vvUllsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it = m_ullArry.find(pcKey);
   if(it != m_ullArry.end())
      vvUllsOut = it->second;

   return (int)vvUllsOut.size();
} // int getUllArry(const char *pcKey, std::vector<std::vector<unsigned long long>> &vvUllsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetUllArry()
//

const std::vector<std::vector<unsigned long long>> &KeyValData::getUllArry(const char *pcKey) const {
   static std::vector<std::vector<unsigned long long>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it = m_ullArry.find(pcKey);
   if(it == m_ullArry.end())
      return vcEmpty;

   return it->second;
}





//
//
//
//
//
// qxgetLastUllArry()
//

const std::vector<unsigned long long> &KeyValData::getLastUllArry(const char *pcKey, const std::vector<unsigned long long> &vUllDefault) const {

   if(pcKey == NULL)
      return vUllDefault;

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it = m_ullArry.find(pcKey);
   if(it == m_ullArry.end())
      return vUllDefault;

   const std::vector<std::vector<unsigned long long>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if(ii == 0)
      return vUllDefault;

   const std::vector<unsigned long long> &vRet = vvTmp[ii-1];

   return vRet;
} // void *KeyValData::getLastUllArry(const char *pcKey, const std::vector<unsigned long long> &vUllDefault)




//
//
//
//
//
// qxgetIthUllArry()
//

const std::vector<unsigned long long> &KeyValData::getIthUllArry(int ith, const char *pcKey, const std::vector<unsigned long long> &vUllDefault) const {

   if(pcKey == NULL)
      return vUllDefault;

   std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it = m_ullArry.find(pcKey);
   if(it == m_ullArry.end())
      return vUllDefault;

   const std::vector<std::vector<unsigned long long>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if((ith < 0) || (ith >= ii))
      return vUllDefault;

   const std::vector<unsigned long long> &vRet = vvTmp[ith];

   return vRet;
} // void *KeyValData::getIthUllArry()...




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastUllArry()
//

int KeyValData::setLastUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3752");

   int nEntries = this->nUllArry(pcKey);
   if(nEntries == 0) {
      this->addUllArry(pcKey, vvUllNew);
   } else {
      m_ullArry[pcKey][nEntries-1] = vvUllNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthUllArry()
//

int KeyValData::setIthUllArry(int ith, const char *pcKey, const std::vector<unsigned long long> &vvUllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3778");

   int nEntries = this->nUllArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 3782");

   std::vector<std::vector<unsigned long long>> &vcThis = m_ullArry[pcKey];
   vcThis[ith] = vvUllNew;

   return 0;
} // int KeyValData::setIthUllArry(int ith, const char *pcKey, const std::vector<unsigned long long> &vvUllNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddUllArry()
//

int KeyValData::addUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3803");

   m_ullArry[pcKey].push_back(vvUllNew);

   return 0;
} // int KeyValData::addUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew)





//
// clears entry
//
//
//
// qxclrUllArry()
//

int KeyValData::clrUllArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3824");

   m_ullArry.erase(pcKey);

   return 0;
} // int KeyValData::clrUllArry(const char *pcKey)





//
// clears entry, then adds vvUllNew back
//
//
//
// qxreplaceUllArry()
//

int KeyValData::replaceUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 3845");

   int nNow = this->nUllArry(pcKey);
   if(nNow <= 0) {
      addUllArry(pcKey, vvUllNew);
   } else {
      std::vector<std::vector<unsigned long long>> &vcKey = m_ullArry[pcKey];
      vcKey[0] = vvUllNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceUllArry(const char *pcKey, const std::vector<unsigned long long> &vvUllNew)





//////





//
//
// Output:
//    vcSsKeysOut: filled with zero or more names of keys.
//    return value: size of vcSsKeysOut.
//
//
//
//
// qxgetDoubKeya()

int KeyValData::getDoubKeya(std::vector<std::string> &vcSsKeysOut) const {
   vcSsKeysOut.clear();

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it;
   for(it=m_doubArry.begin(); it!=m_doubArry.end(); it++) {
      const std::string &ssKey = it->first;
      vcSsKeysOut.push_back(ssKey);
   } // for(it=m_doubArry.begin(); it!=m_doubArry.end(); it++) {

   return (int)vcSsKeysOut.size();
} // int KeyValData::getDoubKeya(std::vector<std::string> &vcSsKeysOut) const








//
//
//
//
//
//
// qxnDoubArry()
//

int KeyValData::nDoubArry(const char *pcKey) const {

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it = m_doubArry.find(pcKey);
   if(it == m_doubArry.end())
      return NADA;

   return (int)it->second.size();
} // int KeyValData::nDoubArry(const char *pcKey)...





//
// we need a vector of vectors out in case keyword was repeated.
//
//
//
//
// qxgetDoubArry()
//

int KeyValData::getDoubArry(const char *pcKey, std::vector<std::vector<double>> &vvDoubsOut) const {
   vvDoubsOut.clear();

   if(pcKey == NULL)
      return NADA;

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it = m_doubArry.find(pcKey);
   if(it != m_doubArry.end())
      vvDoubsOut = it->second;

   return (int)vvDoubsOut.size();
} // int getDoubArry(const char *pcKey, std::vector<std::vector<double>> &vvDoubsOut)




//
// new version 11-09-18, saves overhead of copying a vector.
//
//
//
//
// qxgetDoubArry()
//

const std::vector<std::vector<double>> &KeyValData::getDoubArry(const char *pcKey) const {
   static std::vector<std::vector<double>> vcEmpty;

   if(pcKey == NULL)
      return vcEmpty;

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it = m_doubArry.find(pcKey);
   if(it == m_doubArry.end())
      return vcEmpty;

   return it->second;
}





//
//
//
//
//
// qxgetLastDoubArry()
//

const std::vector<double> &KeyValData::getLastDoubArry(const char *pcKey, const std::vector<double> &vDoubDefault) const {

   if(pcKey == NULL)
      return vDoubDefault;

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it = m_doubArry.find(pcKey);
   if(it == m_doubArry.end())
      return vDoubDefault;

   const std::vector<std::vector<double>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if(ii == 0)
      return vDoubDefault;

   const std::vector<double> &vRet = vvTmp[ii-1];

   return vRet;
} // void *KeyValData::getLastDoubArry(const char *pcKey, const std::vector<double> &vDoubDefault)





//
//
//
//
//
// qxgetIthDoubArry()
//

const std::vector<double> &KeyValData::getIthDoubArry(int ith, const char *pcKey, const std::vector<double> &vDoubDefault) const {

   if(pcKey == NULL)
      return vDoubDefault;

   std::map<std::string, std::vector<std::vector<double>>>::const_iterator it = m_doubArry.find(pcKey);
   if(it == m_doubArry.end())
      return vDoubDefault;

   const std::vector<std::vector<double>> &vvTmp = it->second;
   int ii = (int)vvTmp.size();
   if((ith < 0) || (ith >= ii))
      return vDoubDefault;

   const std::vector<double> &vRet = vvTmp[ith];

   return vRet;
} // void *KeyValData::getLastIthArry()...




//
// replaces the last entry.  adds if none.
//
//
//
// qxsetLastDoubArry()
//

int KeyValData::setLastDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 4051");

   int nEntries = this->nDoubArry(pcKey);
   if(nEntries == 0) {
      this->addDoubArry(pcKey, vvDoubNew);
   } else {
      m_doubArry[pcKey][nEntries-1] = vvDoubNew;
   } // !if(nEntries == 0)

   return 0;
} // int KeyValData::setLastDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew)





//
// replaces the ith entry
// 
//
//
// qxsetIthDoubArry()
//

int KeyValData::setIthDoubArry(int ith, const char *pcKey, const std::vector<double> &vvDoubNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 4077");

   int nEntries = this->nDoubArry(pcKey);
   if((ith >= nEntries) || (ith < 0))
      return NADAfunc("arcHelp.cpp, line 4081");

   std::vector<std::vector<double>> &vcThis = m_doubArry[pcKey];
   vcThis[ith] = vvDoubNew;

   return 0;
} // int KeyValData::setIthDoubArry(int ith, const char *pcKey, const std::vector<double> &vvDoubNew)




//
// appends new one to whoever's there.
//
//
//
// qxaddDoubArry()
//

int KeyValData::addDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 4102");

   m_doubArry[pcKey].push_back(vvDoubNew);

   return 0;
} // int KeyValData::addDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew)





//
// clears entry
//
//
//
// qxclrDoubArry()
//

int KeyValData::clrDoubArry(const char *pcKey) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 4123");

   m_doubArry.erase(pcKey);

   return 0;
} // int KeyValData::clrDoubArry(const char *pcKey)





//
// clears entry, then adds vvDoubNew back
//
//
//
// qxreplaceDoubArry()
//

int KeyValData::replaceDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew) {
   if(pcKey == NULL)
      return NADAfunc("arcHelp.cpp, line 4144");

   int nNow = this->nDoubArry(pcKey);
   if(nNow <= 0) {
      addDoubArry(pcKey, vvDoubNew);
   } else {
      std::vector<std::vector<double>> &vcKey = m_doubArry[pcKey];
      vcKey[0] = vvDoubNew;     // should handle gracefully if they are already at the same address.
      vcKey.resize(1);
   } // !if(nNow <= 0)

   return 0;
} // int KeyValData::replaceDoubArry(const char *pcKey, const std::vector<double> &vvDoubNew)






//
// new 11-15-16.  makes a vector which would create another instance of us, populated the same as us.
//
// Note: the vector we create is almost certainly not ordered the same as the vector that created us,
// BUT another instance of us populated by the vector we create would look just like us.
//
// Input:
//    this
//
// Output:
//    vcBSout: filled with our data.
//
//
//
//
// qxmakeBS()
//

int KeyValData::makeBS(std::vector<unsigned char> &vcBSout) const {
   // int ii;

   vcBSout.clear();    // start at a fresh place.

   // single elements:
   for(std::map<std::string, std::vector<unsigned char>>::const_iterator it=m_uchSing.begin(); it!=m_uchSing.end(); it++) {
      const std::string                &ssKeyword = it->first;
      const std::vector<unsigned char> &vcUch     = it->second;
      for(int i=0; i<vcUch.size(); i++)
         BSarcUcharSing(vcBSout, ssKeyword.c_str(), vcUch[i]);
   }

   for(std::map<std::string, std::vector<int>>::const_iterator it=m_intSing.begin(); it!=m_intSing.end(); it++) {
      const std::string                &ssKeyword = it->first;
      const std::vector<int>           &vcInt     = it->second;
      for(int i=0; i<vcInt.size(); i++)
         BSarcIntSing(vcBSout, ssKeyword.c_str(), vcInt[i]);
   }

   for(std::map<std::string, std::vector<signed long long>>::const_iterator it=m_sllSing.begin(); it!=m_sllSing.end(); it++) {
      const std::string                   &ssKeyword = it->first;
      const std::vector<signed long long> &vcSll     = it->second;
      for(int i=0; i<vcSll.size(); i++)
         BSarcSllSing(vcBSout, ssKeyword.c_str(), vcSll[i]);
   }

   for(std::map<std::string, std::vector<double>>::const_iterator it=m_doubSing.begin(); it!=m_doubSing.end(); it++) {
      const std::string         &ssKeyword = it->first;
      const std::vector<double> &vcDoub    = it->second;
      for(int i=0; i<vcDoub.size(); i++)
         BSarcDoubSing(vcBSout, ssKeyword.c_str(), vcDoub[i]);
   }

   for(std::map<std::string, std::vector<void *>>::const_iterator it=m_starSing.begin(); it!=m_starSing.end(); it++) {
      const std::string         &ssKeyword = it->first;
      const std::vector<void *> &vcStar    = it->second;
      for(int i=0; i<vcStar.size(); i++)
         BSarcStarSing(vcBSout, ssKeyword.c_str(), vcStar[i]);
   }

   for(std::map<std::string, std::vector<KeyValData>>::const_iterator it=m_kvdSing.begin(); it!=m_kvdSing.end(); it++) {
      const std::string                &ssKeyword = it->first;
      const std::vector<KeyValData>    &vcKvd     = it->second;
      for(int i=0; i<vcKvd.size(); i++)
         BSarcKvdSing(vcBSout, ssKeyword.c_str(), vcKvd[i]);
   }



   // arrayed elements:
   for(std::map<std::string, std::vector<std::vector<signed char>>>::const_iterator it=m_schArry.begin(); it!=m_schArry.end(); it++) {
      const std::string                             &ssKeyword = it->first;
      const std::vector<std::vector<signed char>>   &vcScha    = it->second;
      for(int i=0; i<vcScha.size(); i++)
//       BSarcScharArry(vcBSout, ssKeyword.c_str(), &vcScha[i][0], vcScha[i].size());
         BSarcScharArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcScha[i]), (int)vcScha[i].size());
   }

   for(std::map<std::string, std::vector<std::vector<unsigned char>>>::const_iterator it=m_uchArry.begin(); it!=m_uchArry.end(); it++) {
      const std::string                             &ssKeyword = it->first;
      const std::vector<std::vector<unsigned char>> &vcUcha    = it->second;
      for(int i=0; i<vcUcha.size(); i++)
//       BSarcUcharArry(vcBSout, ssKeyword.c_str(), &vcUcha[i][0], vcUcha[i].size());
         BSarcUcharArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcUcha[i]), (int)vcUcha[i].size());
   }

   for(std::map<std::string, std::vector<std::vector<int>>>::const_iterator it=m_intArry.begin(); it!=m_intArry.end(); it++) {
      const std::string                   &ssKeyword = it->first;
      const std::vector<std::vector<int>> &vcInt     = it->second;
      for(int i=0; i<vcInt.size(); i++)
//       BSarcIntArry(vcBSout, ssKeyword.c_str(), &vcInt[i][0], vcInt[i].size());
         BSarcIntArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcInt[i]), (int)vcInt[i].size());
   }

   for(std::map<std::string, std::vector<std::vector<signed long long>>>::const_iterator it=m_sllArry.begin(); it!=m_sllArry.end(); it++) {
      const std::string                                &ssKeyword = it->first;
      const std::vector<std::vector<signed long long>> &vcSll     = it->second;
      for(int i=0; i<vcSll.size(); i++)
//       BSarcSllArry(vcBSout, ssKeyword.c_str(), &vcSll[i][0], vcSll[i].size());
         BSarcSllArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcSll[i]), (int)vcSll[i].size());
   }

   for(std::map<std::string, std::vector<std::vector<unsigned long long>>>::const_iterator it=m_ullArry.begin(); it!=m_ullArry.end(); it++) {
      const std::string                                  &ssKeyword = it->first;
      const std::vector<std::vector<unsigned long long>> &vcUll     = it->second;
      for(int i=0; i<vcUll.size(); i++)
//       BSarcUllArry(vcBSout, ssKeyword.c_str(), &vcUll[i][0], vcUll[i].size());
         BSarcUllArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcUll[i]), (int)vcUll[i].size());
   }

   for(std::map<std::string, std::vector<std::vector<double>>>::const_iterator it=m_doubArry.begin(); it!=m_doubArry.end(); it++) {
      const std::string                      &ssKeyword = it->first;
      const std::vector<std::vector<double>> &vcDoub    = it->second;
      for(int i=0; i<vcDoub.size(); i++)
//       BSarcDoubArry(vcBSout, ssKeyword.c_str(), &vcDoub[i][0], vcDoub[i].size());
         BSarcDoubArry(vcBSout, ssKeyword.c_str(), ADDR_ZEROTH(vcDoub[i]), (int)vcDoub[i].size());
   }


   BSarcTerminate(vcBSout);

   return 0;
} // int KeyValData::makeBS(std::vector<unsigned char> &vcBSout) const






//
// new 11-25-16.  Removes all but the last entry when there are duplicates with the same keyword.
//
//
// Input:
//    this
//
// Output:
//    this, possibly condensed.
//    return: number of entries (single and/or array) condensed.
//
//
//
//
// qxcondenseEveryone()
//

int KeyValData::condenseEveryone() {
   int nCondensed = 0;


   // single elements:
   for(std::map<std::string, std::vector<unsigned char>>::iterator it=m_uchSing.begin(); it!=m_uchSing.end(); it++) {
//    const std::string          &ssKeyword = it->first;
      std::vector<unsigned char> &vcUch     = it->second;
      int nTimes = (int)vcUch.size();
      if(nTimes > 1) {
         vcUch[0] = vcUch[nTimes-1];
         vcUch.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<int>>::iterator it=m_intSing.begin(); it!=m_intSing.end(); it++) {
//    const std::string          &ssKeyword = it->first;
      std::vector<int>           &vcInt     = it->second;
      int nTimes = (int)vcInt.size();
      if(nTimes > 1) {
         vcInt[0] = vcInt[nTimes-1];
         vcInt.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<signed long long>>::iterator it=m_sllSing.begin(); it!=m_sllSing.end(); it++) {
//    const std::string             &ssKeyword = it->first;
      std::vector<signed long long> &vcSll     = it->second;
      int nTimes = (int)vcSll.size();
      if(nTimes > 1) {
         vcSll[0] = vcSll[nTimes-1];
         vcSll.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<double>>::iterator it=m_doubSing.begin(); it!=m_doubSing.end(); it++) {
//    const std::string   &ssKeyword = it->first;
      std::vector<double> &vcDoub    = it->second;
      int nTimes = (int)vcDoub.size();
      if(nTimes > 1) {
         vcDoub[0] = vcDoub[nTimes-1];
         vcDoub.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<void *>>::iterator it=m_starSing.begin(); it!=m_starSing.end(); it++) {
//    const std::string   &ssKeyword = it->first;
      std::vector<void *> &vcStar    = it->second;
      int nTimes = (int)vcStar.size();
      if(nTimes > 1) {
         vcStar[0] = vcStar[nTimes-1];
         vcStar.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<KeyValData>>::iterator it=m_kvdSing.begin(); it!=m_kvdSing.end(); it++) {
//    const std::string          &ssKeyword = it->first;
      std::vector<KeyValData>    &vcKvd     = it->second;
      int nTimes = (int)vcKvd.size();
      if(nTimes > 1) {
         vcKvd[0] = vcKvd[nTimes-1];
         vcKvd.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }



   // arrayed elements:
   for(std::map<std::string, std::vector<std::vector<signed char>>>::iterator it=m_schArry.begin(); it!=m_schArry.end(); it++) {
//    const std::string                       &ssKeyword = it->first;
      std::vector<std::vector<signed char>>   &vcScha    = it->second;
      int nTimes = (int)vcScha.size();
      if(nTimes > 1) {
         vcScha[0] = vcScha[nTimes-1];
         vcScha.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<std::vector<unsigned char>>>::iterator it=m_uchArry.begin(); it!=m_uchArry.end(); it++) {
//    const std::string                       &ssKeyword = it->first;
      std::vector<std::vector<unsigned char>> &vcUcha    = it->second;
      int nTimes = (int)vcUcha.size();
      if(nTimes > 1) {
         vcUcha[0] = vcUcha[nTimes-1];
         vcUcha.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<std::vector<int>>>::iterator it=m_intArry.begin(); it!=m_intArry.end(); it++) {
//    const std::string             &ssKeyword = it->first;
      std::vector<std::vector<int>> &vcInta    = it->second;
      int nTimes = (int)vcInta.size();
      if(nTimes > 1) {
         vcInta[0] = vcInta[nTimes-1];
         vcInta.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<std::vector<signed long long>>>::iterator it=m_sllArry.begin(); it!=m_sllArry.end(); it++) {
//    const std::string                          &ssKeyword = it->first;
      std::vector<std::vector<signed long long>> &vcSlla    = it->second;
      int nTimes = (int)vcSlla.size();
      if(nTimes > 1) {
         vcSlla[0] = vcSlla[nTimes-1];
         vcSlla.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<std::vector<unsigned long long>>>::iterator it=m_ullArry.begin(); it!=m_ullArry.end(); it++) {
//    const std::string                            &ssKeyword = it->first;
      std::vector<std::vector<unsigned long long>> &vcUlla    = it->second;
      int nTimes = (int)vcUlla.size();
      if(nTimes > 1) {
         vcUlla[0] = vcUlla[nTimes-1];
         vcUlla.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }

   for(std::map<std::string, std::vector<std::vector<double>>>::iterator it=m_doubArry.begin(); it!=m_doubArry.end(); it++) {
//    const std::string                &ssKeyword = it->first;
      std::vector<std::vector<double>> &vcDouba   = it->second;
      int nTimes = (int)vcDouba.size();
      if(nTimes > 1) {
         vcDouba[0] = vcDouba[nTimes-1];
         vcDouba.resize(1);
         nCondensed++;
      } // if(nTimes > 1) 
   }


   return nCondensed;
} // int KeyValData::condenseEveryone()





//
// Like the free function replaceBSpointers() (for a BS (Binary Stream)).
//
// Input:
//    mpOldNew:    first choice for pointer replacement.
//    mpKeyToAddr: if not in mpOldNew, try pulling an address from here.  Used for MT64 pointer.
//    bStaleOk (default false): if true, don't void out stale pointers (ones not found in map(s)).
//    pStLeaveAlone (default NULL): if non-null, keywords to ignore (ex: "pHbrSource").
//
// Output:
//    this: possibly modified.
//    return value: number of addresses modified, or -1 if a problem.
//    nNulledOut: number of pointers previously non-NULL that we changed to NULL.
//
//
//
//
// 12-16-19 (jdl): nNulledOut
// 12-20-19 (jdl): bStaleOk (default false)
// 12-22-19 (jdl): pStLeaveAlone (default NULL)
//
// qxreplacePointers()
//

int KeyValData::replacePointers(const std::map<const void *, void *> &mpOldNew, const std::map<std::string, void *> &mpKeyToAddr, int &nNulledOut, bool bStaleOk, const std::set<std::string> *pStLeaveAlone) {
   // int i;
   char cloc[128];
   int nChanged = 0;
   nNulledOut   = 0;


   for(std::map<std::string, std::vector<void *>>::iterator it=m_starSing.begin(); it!=m_starSing.end(); it++) {
      const std::string   &ssKeyword = it->first;
      std::vector<void *> &vcStar    = it->second;

      if(pStLeaveAlone != NULL) {
         if(bIsInSet(*pStLeaveAlone, ssKeyword))
            continue;
      } // if(pStLeaveAlone != NULL)


      bool bInKeyMap = bIsInMap(mpKeyToAddr, ssKeyword);       // for use when all else fails.
      void *pKeyWord = mapValu2(mpKeyToAddr, ssKeyword, (void *)NULL);
      for(int i=0; i<vcStar.size(); i++) {
         void *vpOld = vcStar[i];
         if(vpOld == NULL)
            continue;                                       // 12-16-19: don't count NULL against us.

         bool bInBigMap = bIsInMap(mpOldNew, (const void *)vpOld);
         void *vpNew = mapValuu(mpOldNew, vpOld, vpOld);    // key AND default value.  we'll NULL if not in either map.

         if(!bInBigMap) {
            vpNew = pKeyWord;
            if(!bInKeyMap) {
               if(bStaleOk) {
                  // for applications such as copySubTree: we assume it points to some valid place outside subTree.
                  vpNew = vpOld;
               } else {
                  // "usual": void out entry.
                  vpNew = NULL;                                // NULL is better than a stale pointer.
                  nNulledOut++;
#ifdef _WIN32                  
                  sprintf_s(cloc, 128, "Keyword \"%s\", %d of %d: NULL'd.\n", ssKeyword.c_str(), (i+1), (int)vcStar.size());
#else                  
                  sprintf(cloc, "Keyword \"%s\", %d of %d: NULL'd.\n", ssKeyword.c_str(), (i+1), (int)vcStar.size());
#endif                                    
                  bool bShow = !!(jdebug & 0x0004);
                  if(bShow) {
                     qprintf(fp_dbg, "%s\n", cloc);
                     // fprintf(stdout, "%s\n", cloc);
                  } // if(bShow)

               } // !if(bStaleOk)

            } // if(!bInKeyMap)
         } // if(!bInBigMap)
         if(vpNew != vpOld) {
            vcStar[i] = vpNew;
            nChanged++;
         } // if(vpNew != vpOld)

      } // for(int i=0; i<vcStar.size(); i++)
   } // for(std::map<std::string, std::vector<void *>>::iterator it=m_starSing.begin(); it!=m_starSing.end(); it++)


   // recursively replace pointers in any subservient KeyValData entries:
   for(std::map<std::string, std::vector<KeyValData>>::iterator it=m_kvdSing.begin(); it!=m_kvdSing.end(); it++) {
//    const std::string          &ssKeyword = it->first;
      std::vector<KeyValData>    &vcKvd     = it->second;
      for(int i=0; i<vcKvd.size(); i++) {
         KeyValData &kvd = vcKvd[i];
         int nno;
         int ii = kvd.replacePointers(mpOldNew, mpKeyToAddr, nno, bStaleOk, pStLeaveAlone);
         if(ii < 0)
            return NADAfunc("arcHelp.cpp, line 4512");

         nChanged   += ii;
         nNulledOut += nno;
      } // for(int i=0; i<vcKvd.size(); i++)
   }

   return nChanged;
} // int KeyValData::replacePointers()...








///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// end of class KeyValData
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////





///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Basic free functions for archiving:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////





// qxarchiveBytes()

int archiveBytes(std::vector<unsigned char> &vecGrowing, const unsigned char *pBytes, long long nBytes) {

   if(nBytes < 0)
      return NADAfnc2("archiveBytes(): asked us to write negative (%lld) bytes.", nBytes);

   if(nBytes == 0)
      return 0;            // nothing to do, but not an error.

   // if we get here, we need non-NULL pBytes.
   if(pBytes == NULL)
      return NADAfnc2("archiveBytes(): asked us to write %lld bytes from NULL address.", nBytes);

   for(long long i=0; i<nBytes; i++) {
      unsigned char uc = *(pBytes+i);
      vecGrowing.push_back(uc);
   } // for(int i=0; i<nBytes; i++)

   return 0;
} // int archiveBytes(std::vector<unsigned char> &vecGrowing, const unsigned char *pBytes, int nBytes)




//
//
// Input:
//    mySpit: a spitObj with 0, 1, or 2 outputs set to be used.
//    pBytes: pointer to bytes to be output.
//    nBytes: number of bytes to output.
//
// Output:
//    return value: 0 if all went well; NADA otherwise.
//    bytes output to 0, 1, or 2 places.
//    mySpit.nBytesOut updated.
//
//
//
//
//
//
// qxarchiveBytes()

int archiveBytes(spitObj &mySpit, const unsigned char *pBytes, long long nBytes) {
   int iRet = 0;

   if(nBytes < 0)
      return NADAfnc2("archiveBytes(): asked us to write negative (%lld) bytes.", nBytes);

   if(nBytes == 0)
      return 0;            // nothing to do, but not an error.

   // if we get here, we need non-NULL pBytes.
   if(pBytes == NULL)
      return NADAfnc2("archiveBytes(): asked us to write %lld bytes from NULL address.", nBytes);

   if(mySpit.pvcOut != NULL) {
      long long lenNow = mySpit.pvcOut->size();
      long long lenNuu = lenNow + nBytes;
      mySpit.pvcOut->resize(lenNuu);
      memcpy(&((*mySpit.pvcOut)[lenNow]), pBytes, nBytes);
#ifdef OLD_CODE
      for(long long i=0; i<nBytes; i++) {
         unsigned char uc = pBytes[i];
         mySpit.pvcOut->push_back(uc);
      } // for(int i=0; i<nBytes; i++)
#endif // OLD_CODE
   } // if(mySpit.pvcOut != NULL)

   if(mySpit.fp_out != NULL) {
      long long i2;
      if((i2 = fwrite(pBytes, sizeof(unsigned char), nBytes, mySpit.fp_out)) != nBytes)
         iRet = NADA;
   } // if(mySpit.fp_out != NULL)

   mySpit.nBytesOut += nBytes;

   return iRet;
} // int archiveBytes(spitObj &mySpit, const unsigned char *pBytes, int nBytes)





//
// We flesh this out to 64 bits for archive consistency between 32- and 64-bit executables.
//
//
//
//
// qxarchivePtr()
//

int archivePtr(std::vector<unsigned char> &vecGrowing, const void *p) {
   unsigned long long ull = (unsigned long long)p;
   int iRet = archiveUllong(vecGrowing, ull);

   return iRet;
} // int archivePtr(std::vector<unsigned char> &vecGrowing, const void *p)




//
// We flesh this out to 64 bits for archive consistency between 32- and 64-bit executables.
//
//
//
//
// qxarchivePtr()
//

int archivePtr(spitObj &mySpit, const void *p) {
   unsigned long long ull = (unsigned long long)p;
   int iRet = archiveUllong(mySpit, ull);

   return iRet;
} // int archivePtr(spitObj &mySpit, const void *p)




//
//
// Based on MIDI file convention.  high-order bytes first; 7 bits data, 1 bit continue flag.
//
// Note that we DO NOT handle negative numbers!  Only 0 and positive integers.
//
// We expect our use to be less than 2^32, so we could have used an unsigned int.
// The cost of promoting to ull seems fairly low, however.
//
//
//
// qxarchiveVarQty()

int archiveVarQty(std::vector<unsigned char> &vecGrowing, unsigned long long ull) {
   int iRet = 0;

   unsigned long long iStill = ull;
   unsigned long long iThis;
   unsigned char ubuf[32];
   unsigned char *ucp = ubuf;


   // zero in gives one byte...
   do {
      iThis  = iStill % 128;
      iStill = iStill / 128;
      if(ucp != ubuf) iThis += 0x80;  // carry bit...
      *(ucp++) = (unsigned char)iThis;
   } while(iStill > 0);

   int n = (int)(ucp - ubuf);  // number of valid bytes...

   // walk back down; stuff into data stream:
   ucp = ubuf + n;
   while(ucp > ubuf) {
      ucp--;
      int ii = archiveBytes(vecGrowing, ucp, 1);
      if(ii != 0)
         iRet = ii;
   } // while(ucp > ubuf)

   return iRet;
} // int archiveVarQty(std::vector<unsigned char> &vecGrowing, unsigned long long ull)





//
//
// Based on MIDI file convention.  high-order bytes first; 7 bits data, 1 bit continue flag.
//
// Note that we DO NOT handle negative numbers!  Only 0 and positive integers.
//
// We expect our use to be less than 2^32, so we could have used an unsigned int.
// The cost of promoting to ull seems fairly low, however.
//
//
//
// qxarchiveVarQty()

int archiveVarQty(spitObj &mySpit, unsigned long long ull) {
   int iRet = 0;

   unsigned long long iStill = ull;
   unsigned long long iThis;
   unsigned char ubuf[32];
   unsigned char *ucp = ubuf;


   // zero in gives one byte...
   do {
      iThis  = iStill % 128;
      iStill = iStill / 128;
      if(ucp != ubuf) iThis += 0x80;  // carry bit...
      *(ucp++) = (unsigned char)iThis;
   } while(iStill > 0);

   int n = (int)(ucp - ubuf);  // number of valid bytes...

   // walk back down; stuff into data stream:
   ucp = ubuf + n;
   while(ucp > ubuf) {
      ucp--;
      int ii = archiveBytes(mySpit, ucp, 1);
      if(ii != 0)
         iRet = ii;
   } // while(ucp > ubuf)

   return iRet;
} // int archiveVarQty(spitObj &mySpit, unsigned long long ull)




//
// Binary Stream archive, unsigned char.
//
//
// qxBSarcUcharSing()

int BSarcUcharSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, unsigned char uc) {
   if(pcKey == NULL)
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucUnsignedChar)) != 0)                        return NADA;
   if((ii = archiveUchar(vecGrowing, uc)) != 0)                                     return NADA;

   return 0;
} // int BSarcUcharSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, unsigned char uc)






//
// Binary Stream archive, int.
//
//
// qxBSarcIntSing()

int BSarcIntSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, int i) {
   if(pcKey == NULL)
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucSignedInt4)) != 0)                          return NADA;
   if((ii = archiveInt(vecGrowing, i)) != 0)                                        return NADA;

   return 0;
} // int BSarcIntSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, int i)




//
// Binary Stream archive, signed long long
//
//
// qxBSarcSllSing()

int BSarcSllSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, signed long long sll) {
   if(pcKey == NULL)
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucSignedLL8)) != 0)                           return NADA;
   if((ii = archiveLlong(vecGrowing, sll)) != 0)                                    return NADA;

   return 0;
} // int BSarcSllSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, int i)




//
// Binary Stream archive, double.
//
//
// qxBSarcDoubSing()

int BSarcDoubSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, double d) {
   if(pcKey == NULL)
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucDouble)) != 0)                              return NADA;
   if((ii = archiveDoub(vecGrowing, d)) != 0)                                       return NADA;

   return 0;
} // int BSarcDoubSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, doub i)






//
// Binary Stream archive, void *.
//
//
// qxBSarcStarSing()

int BSarcStarSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, void *pv) {
   if(pcKey == NULL)
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucVoidStar)) != 0)                            return NADA;
   if((ii = archivePtr(vecGrowing, pv)) != 0)                                       return NADA;

   return 0;
} // int BSarcStarSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, void *pv)







//
// Exotic: embedds a sub-kvd in a stream.
//
//
//
//
//
// qxBSarcKvdSing()

int BSarcKvdSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, const KeyValData &kvd) {
   if(pcKey == NULL)
      return NADA;

   if(&kvd == NULL)
      return NADA;

   std::vector<unsigned char> vecKvd;
   int ii = kvd.makeBS(vecKvd);
   if(ii != 0)
      return NADAfunc("arcHelp.cpp, line 4888");

   int nElem = (int)vecKvd.size();

   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, cucKeyValData)) != 0)                          return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)(&vecKvd[0]), nElem)) != 0) return NADA;

   return 0;
} // int BSarcKvdSing(std::vector<unsigned char> &vecGrowing, const char *pcKey, const KeyValData &kvd)






// qxBSarcScharArry()

int BSarcScharArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const signed char *pSch, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pSch == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carSignedChar)) != 0)                          return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;
// if((ii = archiveBytes(vecGrowing, (const unsigned char *)(&pSch[0]), nElem)) != 0) return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pSch, nElem)) != 0)     return NADA;

   return 0;
} // int BSarcScharArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const signed char *pSch, int nElem)






// qxBSarcUcharArry()

int BSarcUcharArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const unsigned char *pUch, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pUch == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carUnsignedChar)) != 0)                        return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pUch, nElem)) != 0) return NADA;

   return 0;
} // int BSarcUcharArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const unsigned char *pUch, int nElem)






// qxBSarcIntArry()

int BSarcIntArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const int *pInt, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pInt == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carSignedInt4)) != 0)                          return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;

   for(int i=0; i<nElem; i++) {
      if((ii = archiveInt(vecGrowing, pInt[i])) != 0)                               return NADA;
   } // for(int i=0; i<nElem; i++)

   return 0;
} // int BSarcIntArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const int *pInt, int nElem)







// qxBSarcSllArry()

int BSarcSllArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const signed long long *pSll, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pSll == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carSignedLL8)) != 0)                           return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;

   for(int i=0; i<nElem; i++) {
      if((ii = archiveLlong(vecGrowing, pSll[i])) != 0)                             return NADA;
   } // for(int i=0; i<nElem; i++)

   return 0;
} // int BSarcSllArry(std::vector<signed char> &vecGrowing, const char *pcKey, const signed long long *pSll, int nElem)






// qxBSarcUllArry()

int BSarcUllArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const unsigned long long *pUll, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pUll == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carUnsignedLL8)) != 0)                         return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;

   for(int i=0; i<nElem; i++) {
      if((ii = archiveUllong(vecGrowing, pUll[i])) != 0)                            return NADA;
   } // for(int i=0; i<nElem; i++)

   return 0;
} // int BSarcUllArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const unsigned long long *pUll, int nElem)





// qxBSarcDoubArry()

int BSarcDoubArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const double *pDoub, int nElem) {
   if(pcKey == NULL)
      return NADA;

   if((pDoub == NULL) && (nElem > 0))
      return NADA;

   if(nElem < 0)           // we allow zero.
      return NADA;

   int ii;
   unsigned long long iLen = strlen(pcKey);
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;
   if((ii = archiveBytes(vecGrowing, (const unsigned char *)pcKey, iLen)) != 0)     return NADA;

   if((ii = archiveUchar(vecGrowing, carDouble)) != 0)                              return NADA;
   if((ii = archiveVarQty(vecGrowing, nElem)) != 0)                                 return NADA;

   for(int i=0; i<nElem; i++) {
      if((ii = archiveDoub(vecGrowing, pDoub[i])) != 0)                             return NADA;
   } // for(int i=0; i<nElem; i++)

   return 0;
} // int BSarcDoubArry(std::vector<unsigned char> &vecGrowing, const char *pcKey, const double *pDoub, int nElem)






//
// Append a dummy keyword with length 0 to terminate a Binary Stream.
//
//
//
//
// qxBSarcTerminate()

int BSarcTerminate(std::vector<unsigned char> &vecGrowing) {
   int ii;
   unsigned int iLen = 0;
   if((ii = archiveVarQty(vecGrowing, iLen)) != 0)                                  return NADA;

   return 0;
} // int BSarcTerminate(std::vector<unsigned char> &vecGrowing)


////////////////////////////////////////////////////////////////////////////////////////////////
// End of archiving functions; beginning of unarchive functions
////////////////////////////////////////////////////////////////////////////////////////////////



//
//
//
//
//
// 06-01-17: if we can't hold'm all, copy as many as possible and be sure to advance pcWalk to pcTooFar.
//
// qxunArcBytes()

int unArcBytes(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned char *pBytes, long long nBytes) {

   if(nBytes < 0)
      return NADAfnc2("unArcBytes(): asked us to read negative (%lld) bytes.", nBytes);

   if(nBytes == 0)
      return 0;            // nothing to do, but not an error.

   // if we get here, we need non-NULL pBytes.
   if(pBytes == NULL)
      return NADAfnc2("unArcBytes(): asked us to read %lld bytes into NULL address.", nBytes);

   for(long long i=0; i<nBytes; i++) {
      if(pcWalk >= pcTooFar)
         return NADA;

      *(pBytes++) = *(pcWalk++);
   } // for(int i=0; i<nBytes; i++)

   return 0;
} // int unArcBytes(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned char *pBytes, int nBytes)




//
// Call this when you really need bytes copied.
//
//
//
//
//
// qxunArcBytes()

int unArcBytes(sucqObj &suq, unsigned char *pBytes, long long nBytes) {
   int iRet = 0;

   if(nBytes < 0)
      return NADAfnc2("unArcBytes(): asked us to read negative (%lld) bytes.", nBytes);

   if(nBytes == 0)
      return 0;            // nothing to do, but not an error.

   // if we get here, we need non-NULL pBytes.
   if(pBytes == NULL)
      return NADAfnc2("unArcBytes(): asked us to read %lld bytes into NULL address.", nBytes);


   if((suq.pcWalk != NULL) && (suq.pcTooFar != NULL)) {
      iRet =  unArcBytes(suq.pcWalk, suq.pcTooFar, pBytes, nBytes);
   } else if(suq.fp_in != NULL) {
      // read the file bytes:
      long long i1;
      if((i1 = fread((void *)pBytes, sizeof(unsigned char), nBytes, suq.fp_in)) != nBytes) {
         iRet = NADA;
      } // if((i = fread((void *)(&char1), sizeof(char), totLen, m_fp)) != totLen)
   } else {
      iRet = NADA;
   }

   return iRet;
} // int unArcBytes(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned char *pBytes, int nBytes)






//
// Call this when you just need bytes exposed for interpretation.
//
// Input:
//    suq: sucqObj.  Should have exactly one input non-NULL.
//    vcBuffer: something that can be used as a buffer.
//
// Output:
//    return value: pointer to requested number of bytes, or NULL if something went wrong.
//    vcBuffer: will have contents ONLY if coming via file.  Caller should NOT use its contents.
//
//
//
//
//
// qxunArcBytes()

const unsigned char *unArcBytes(sucqObj &suq, std::vector<unsigned char> &vcBuffer, long long nBytes) {
   const unsigned char * pRet = NULL;
   vcBuffer.clear();     // ? waste of time?

   if((suq.pcWalk != NULL) && (suq.pcTooFar != NULL)) {
      if((suq.pcWalk + nBytes) > suq.pcTooFar) {
         pRet = NULL;
      } else {
         pRet        = suq.pcWalk;
         suq.pcWalk += nBytes;
      } // !if((suq.pcWalk + nBytes) > suq.pcTooFar)
   } else if(suq.fp_in != NULL) {
      // read the file bytes:
      long long i1;
      vcBuffer.resize(nBytes);
      pRet = &(vcBuffer[0]);
      if((i1 = fread((void *)pRet, sizeof(unsigned char), nBytes, suq.fp_in)) != nBytes)
         pRet = NULL;
   } else {
      pRet = NULL;
   }

   if(pRet != NULL)
      suq.nBytesIn += nBytes;

   return pRet;
} // 






// qxunArcChar()

int unArcChar(const unsigned char *&pcWalk, const unsigned char *pcTooFar, char &cOut) {
   if((pcWalk + sizeof(char)) > pcTooFar)
      return NADA;

   cOut = *((const char *)pcWalk);
   pcWalk += sizeof(char);

   return 0;
} // int unArcChar(const unsigned char *&pcWalk, const unsigned char *pcTooFar, char &cOut)





// qxunArcChar()

int unArcChar(sucqObj &suq, char &cOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(char));
   if(puc == NULL)
      return NADA;

   cOut = *((const char *)puc);

   return 0;
} // int unArcChar()





// qxunArcUchar()

int unArcUchar(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned char &ucOut) {
   if((pcWalk + sizeof(unsigned char)) > pcTooFar)
      return NADA;

   ucOut = *((const unsigned char *)pcWalk);
   pcWalk += sizeof(unsigned char);

   return 0;
} // int unArcUchar(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned char &ucOut)





// qxunArcUchar()

int unArcUchar(sucqObj &suq, unsigned char &ucOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned char));
   if(puc == NULL)
      return NADA;

   ucOut = *puc;

   return 0;
} // int unArcUchar()





// qxunArcShort()

int unArcShort(const unsigned char *&pcWalk, const unsigned char *pcTooFar, short &iOut) {
   if((pcWalk + sizeof(short)) > pcTooFar)
      return NADA;

   iOut = *((const short *)pcWalk);
   pcWalk += sizeof(short);

   return 0;
} // int unArcShort(const unsigned char *&pcWalk, const unsigned char *pcTooFar, short &iOut)




// qxunArcShort()

int unArcShort(sucqObj &suq, short &iOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(short));
   if(puc == NULL)
      return NADA;

   iOut = *((const short *)puc);

   return 0;
} // int unArcShort()





// qxunArcUshort()

int unArcUshort(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned short &uiOut) {
   if((pcWalk + sizeof(unsigned short)) > pcTooFar)
      return NADA;

   uiOut = *((const unsigned short *)pcWalk);
   pcWalk += sizeof(unsigned short);

   return 0;
} // int unArcUshort(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned short &uiOut)




// qxunArcUshort()

int unArcUshort(sucqObj &suq, unsigned short &uiOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned short));
   if(puc == NULL)
      return NADA;

   uiOut = *((const unsigned short *)puc);

   return 0;
} // int unArcUshort()





// qxunArcInt()

int unArcInt(const unsigned char *&pcWalk, const unsigned char *pcTooFar, int &iOut) {
   if((pcWalk + sizeof(int)) > pcTooFar)
      return NADA;

   iOut = *((const int *)pcWalk);
   pcWalk += sizeof(int);

   return 0;
} // int unArcInt(const unsigned char *&pcWalk, const unsigned char *pcTooFar, int &iOut)




// qxunArcInt()

int unArcInt(sucqObj &suq, int &iOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(int));
   if(puc == NULL)
      return NADA;

   iOut = *((const int *)puc);

   return 0;
} // int unArcInt()




//
// looks at what the next int will be but does not advance pcWalk.
//
//
//
//
//
// qxpeekInt()

int peekInt(const unsigned char *&pcWalk, const unsigned char *pcTooFar, int &iOut) {
   const unsigned char *pcHold = pcWalk;
   int iRet = unArcInt(pcWalk, pcTooFar, iOut);
   pcWalk = pcHold;

   return iRet;
} // int peekInt()...





// qxunArcUint()

int unArcUint(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned int &uiOut) {
   if((pcWalk + sizeof(unsigned int)) > pcTooFar)
      return NADA;

   uiOut = *((const unsigned int *)pcWalk);
   pcWalk += sizeof(unsigned int);

   return 0;
} // int unArcUint(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned int &uiOut)




// qxunArcUint()

int unArcUint(sucqObj &suq, unsigned int &uiOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned int));
   if(puc == NULL)
      return NADA;

   uiOut = *((const unsigned int *)puc);

   return 0;
} // int unArcUint()





// qxunArcLong()

int unArcLong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, long &lOut) {
   if((pcWalk + sizeof(long)) > pcTooFar)
      return NADA;

   lOut = *((const long *)pcWalk);
   pcWalk += sizeof(long);

   return 0;
} // int unArcLong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, long &lOut)




// qxunArcLong()

int unArcLong(sucqObj &suq, long &lOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(long));
   if(puc == NULL)
      return NADA;

   lOut = *((const long *)puc);

   return 0;
} // int unArcLong()






// qxunArcUlong()

int unArcUlong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long &ulOut) {
   if((pcWalk + sizeof(unsigned long)) > pcTooFar)
      return NADA;

   ulOut = *((const unsigned long *)pcWalk);
   pcWalk += sizeof(unsigned long);

   return 0;
} // int unArcUlong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long &ulOut)




// qxunArcUlong()

int unArcUlong(sucqObj &suq, unsigned long &ulOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned long));
   if(puc == NULL)
      return NADA;

   ulOut = *((const unsigned long *)puc);

   return 0;
} // int unArcUlong()





// qxunArcLlong()

int unArcLlong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, long long &llOut) {
   if((pcWalk + sizeof(long long)) > pcTooFar)
      return NADA;

   llOut = *((const long *)pcWalk);
   pcWalk += sizeof(long long);

   return 0;
} // int unArcLlong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, long long &llOut)



// qxunArcLlong()

int unArcLlong(sucqObj &suq, long long &llOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(long long));
   if(puc == NULL)
      return NADA;

   llOut = *((const long long *)puc);

   return 0;
} // int unArcLlong()






// qxunArcUllong()

int unArcUllong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long long &ullOut) {
   if((pcWalk + sizeof(unsigned long long)) > pcTooFar)
      return NADA;

   ullOut = *((const unsigned long long *)pcWalk);
   pcWalk += sizeof(unsigned long long);

   return 0;
} // int unArcUllong(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long long &ullOut)




// qxunArcUllong()

int unArcUllong(sucqObj &suq, unsigned long long &ullOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned long long));
   if(puc == NULL)
      return NADA;

   ullOut = *((const unsigned long long *)puc);

   return 0;
} // int unArcUllong()





// qxunArcDoub()

int unArcDoub(const unsigned char *&pcWalk, const unsigned char *pcTooFar, double &dOut) {
   if((pcWalk + sizeof(double)) > pcTooFar)
      return NADA;

   dOut = *((const double *)pcWalk);
   pcWalk += sizeof(double);

   return 0;
} // int unArcDoub(const unsigned char *&pcWalk, const unsigned char *pcTooFar, double &dOut)




// qxunArcDoub()

int unArcDoub(sucqObj &suq, double &dOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(double));
   if(puc == NULL)
      return NADA;

   dOut = *((const double *)puc);

   return 0;
} // int unArcDoub()





//
// We always read 64 bits, and if necessary shoehorn it into a 32-bit address.
//
//
//
//
//
//
// qxunArcPtr()
//

int unArcPtr(const unsigned char *&pcWalk, const unsigned char *pcTooFar, void *&pOut) {
   unsigned long long ull;

   if(unArcUllong(pcWalk, pcTooFar, ull) < 0)
      return NADA;

   if(sizeof(void *) == 4) {
      // 32-bit executable; must shoe-horn:
      pOut = (void *)(ull & 0x00000000FFFFFFFFULL);
   } else {
      // 64-bit executable; no squeezing needed.
      pOut = (void *)ull;
   } // !if(sizeof(void *) == 4)

   return 0;
} // int unArcPtr(const unsigned char *&pcWalk, const unsigned char *pcTooFar, void *&pOut)



// qxunArcPtr()

int unArcPtr(sucqObj &suq, void *&pOut) {
   std::vector<unsigned char> vcBuffer;

   const unsigned char *puc = unArcBytes(suq, vcBuffer, sizeof(unsigned long long));
   if(puc == NULL)
      return NADA;

   unsigned long long ull = *((const unsigned long long *)puc);

   if(sizeof(void *) == 4) {
      // 32-bit executable; must shoe-horn:
      pOut = (void *)(ull & 0x00000000FFFFFFFFULL);
   } else {
      // 64-bit executable; no squeezing needed.
      pOut = (void *)ull;
   } // !if(sizeof(void *) == 4)

   return 0;
} // int unArcPtr()





// qxunArcVarUll()

int unArcVarUll(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long long &ullOut) {
   ullOut = 0xFFFFFFFFFFFFFFFFULL;   // in case we fail
   unsigned long long ullBuild = 0;
   unsigned char uc;

   while(1) {
      int ii = unArcUchar(pcWalk, pcTooFar, uc);
      if(ii != 0)
         return NADA;

      unsigned char ucData  = uc & 0x7F;
      unsigned char ucCarry = uc & 0x80;

      ullBuild += ucData;

      if(ucCarry == 0)
         break;

      // another data byte (or more) remaining.
      //
      // overflow test: make sure highest 7 bits are 0:
      unsigned long long ullTest = ullBuild & 0xFE00000000000000ULL;
      if(ullTest != 0)
         return NADA;

      ullBuild <<= 7;
   } // while(1) 

   ullOut = ullBuild;
   return 0;
} // int unArcVarUll(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned long long &ullOut)





// qxunArcVarUll()

int unArcVarUll(sucqObj &suq, unsigned long long &ullOut) {
   ullOut = 0xFFFFFFFFFFFFFFFFULL;   // in case we fail
   unsigned long long ullBuild = 0;
   unsigned char uc;

   while(1) {
      int ii = unArcUchar(suq, uc);
      if(ii != 0)
         return NADA;

      unsigned char ucData  = uc & 0x7F;
      unsigned char ucCarry = uc & 0x80;

      ullBuild += ucData;

      if(ucCarry == 0)
         break;

      // another data byte (or more) remaining.
      //
      // overflow test: make sure highest 7 bits are 0:
      unsigned long long ullTest = ullBuild & 0xFE00000000000000ULL;
      if(ullTest != 0)
         return NADA;

      ullBuild <<= 7;
   } // while(1) 

   ullOut = ullBuild;
   return 0;
} // int unArcVarUll(sucqObj &suq, unsigned long long &ullOut)





//
// Calling this rather than the Ull version doesn't affect how many bytes are extracted from the data
// stream.  It's just for convenience, to get the output in an unsigned int rather than unsigned long long.
//
//
//
// qxunArcVarUin()
//

int unArcVarUin(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned int &uiOut) {
   uiOut = 0xFFFFFFFFU;

   unsigned long long ullGuy;
   int ii = unArcVarUll(pcWalk, pcTooFar, ullGuy);
   if(ii != 0)
      return NADA;

   // overflow test:
   unsigned long ullTest = ullGuy & 0x00000000FFFFFFFFULL;
   if(ullTest != ullGuy)
      return NADA;

   uiOut = (unsigned int)ullGuy;

   return 0;
} // int unArcVarUin(const unsigned char *&pcWalk, const unsigned char *pcTooFar, unsigned int &uiOut)






//
// Calling this rather than the Ull version doesn't affect how many bytes are extracted from the data
// stream.  It's just for convenience, to get the output in an unsigned int rather than unsigned long long.
//
//
//
// qxunArcVarUin()
//

int unArcVarUin(sucqObj &suq, unsigned int &uiOut) {
   uiOut = 0xFFFFFFFFU;

   unsigned long long ullGuy;
   int ii = unArcVarUll(suq, ullGuy);
   if(ii != 0)
      return NADA;

   // overflow test:
   unsigned long ullTest = ullGuy & 0x00000000FFFFFFFFULL;
   if(ullTest != ullGuy)
      return NADA;

   uiOut = (unsigned int)ullGuy;

   return 0;
} // int unArcVarUin(sucqObj &suq, unsigned int &uiOut)





//
//
// Input:
//    vcBSData
//    mpOldNew
//    mpKeyToAddr: if all else fails, try pulling an address from here.
//
// Output:
//    vcBSData: possibly modified.
//    return value: number of addresses modified, or -1 if a problem.
//
//
//
//
// 11-24-16: this function is BROKEN; qxfix!  If there are subservient kvd's with pointer(s).
// 11-25-16: do it a different way, to support nesting.  NOTE: order of entries in vcBSData will change!
//
// qxreplaceBSpointers()
//

int replaceBSpointers(std::vector<unsigned char> &vcBSData, const std::map<const void *, void *> &mpOldNew, const std::map<std::string, void *> &mpKeyToAddr) {

   // is it empty?
   if(vcBSData.size() == 0)
      return 0;

   int nNulledOut = 0;

   // 11-25-16: call the other other function:
   KeyValData kvd;
   int ii = kvd.fleshMe(vcBSData, false, true);    // false: no append; true: noPtrFollow
   if(ii < 0)
      return NADAfunc("arcHelp.cpp, line 5840");

   int nChanged = kvd.replacePointers(mpOldNew, mpKeyToAddr, nNulledOut);
   if(nChanged < 0)
      return NADAfunc("arcHelp.cpp, line 5844");

   if(nChanged > 0) {
      vcBSData.clear();
      ii = kvd.makeBS(vcBSData);    // NOTE: order of entries in vcBSData will change!  But it will map to the same kvd.
      if(ii < 0)
         return NADAfunc("arcHelp.cpp, line 5850");
   } // if(nChanged > 0)

   return nChanged;
} // int replaceBSpointers(std::vector<unsigned char> &vcBSData, const std::map<const void *, void *> &mpOldNew)






// qxelementSize()

int elementSize(const unsigned char ucDataType) {
   int iSiz = NADA;

   switch(ucDataType) {
      case cucNuttin:
         iSiz = 0;
         break;
      case cucSignedChar:
      case cucUnsignedChar:
      case carSignedChar:
      case carUnsignedChar:
         iSiz = 1;
         break;
      case cucSignedShort:
      case cucUnsignedShort:
      case carSignedShort:
      case carUnsignedShort:
         iSiz = 2;
         break;
      case cucSignedInt4:
      case cucUnsignedInt4:
      case cucFloat:
      case carSignedInt4:
      case carUnsignedInt4:
      case carFloat:
         iSiz = 4;
         break;
      case cucSignedLL8:
      case cucUnsignedLL8:
      case cucDouble:
      case cucVoidStar:              // we flesh out 4-byte pointers.
      case carSignedLL8:
      case carUnsignedLL8:
      case carDouble:
      case carVoidStar:              // we flesh out 4-byte pointers.
         iSiz = 8;
         break;
      default:
         iSiz = NADA;
         break;
   } // switch(ucDataType)

   return iSiz;
} // int elementSize(const unsigned char ucDataType)




//
//
//
// Input:
//    pFileName:
//    vcFillMe
//
// Output:
//    vcFillMe: filled, if return value is 0.
//    return value: -1 if error, else number of bytes read into vcFillMe.
//
//
//
//
//
// qxsuckUchFile()

int suckUchFile(const char *pFileName, std::vector<unsigned char> &vcFillMe) {
   vcFillMe.clear();

   if(pFileName == NULL)
      return NADA;

   struct _stat64  stbu64;    // for big file sizes (>2^31).

   if(_stat64(pFileName, &stbu64) == -1)
      return NADA;

   if((stbu64.st_mode & S_IFMT) == S_IFDIR) 
      return NADA;

   long long totLen = (long long)stbu64.st_size;

   FILE *fpIn;
#ifdef _WIN32   
   if(fopen_s(&fpIn, pFileName, "rb") != 0) {
#else   
   if((fpIn = fopen(pFileName, "rb")) == NULL) {   
#endif   
      qprintf(fp_dbg, "Unable to open file %s.\n", pFileName);
      // fprintf(stdout, "Unable to open file %s.\n", pFileName);
      return NADA;
   }



   vcFillMe.resize(totLen);

   // read the file bytes:
   long long i1;
   if((i1 = fread((void *)(&(vcFillMe[0])), sizeof(unsigned char), totLen, fpIn)) != totLen) {
      fclose(fpIn);    fpIn = NULL;
      vcFillMe.clear();
      return NADA;
   } // if((i = fread((void *)(&char1), sizeof(char), totLen, m_fp)) != totLen)

   fclose(fpIn);    fpIn = NULL;

   return (int)vcFillMe.size();
} // int suckUchFile(const char *pFileName, std::vector<unsigned char> &vcFillMe)




//
//
// Input:
//    pFileName:
//    vcSpitMe:
//    bArchiveExisting (default true): if true, archive any existing file with the specified name.  False: overwrite.
//
// Output:
//    return value: 0 if all went well; -1 otherwise.
//
//
//
// 10-10-16 (jdl): OOPS!  bArchiveExisting wasn't doing anything; fix that.
//
// qxspitUchFile()
//

int spitUchFile(const char *pFileName, const std::vector<unsigned char> &vcSpitMe, bool bArchiveExisting) {
   if(pFileName == NULL)
      return NADA;

   if(bArchiveExisting)
      arcMeSimple(pFileName);

   FILE *fpOut;
#ifdef _WIN32   
   if (fopen_s(&fpOut, pFileName, "wb") != 0) {
#else   
   if ((fpOut = fopen(pFileName, "wb")) == NULL) {   
#endif   
      fprintf(stderr, "Unable to open output file %s.\n", pFileName);
      return NADA;
   }

   long long ivLen = vcSpitMe.size();
   if(ivLen > 0) {
      long long i2;
      if((i2 = fwrite(&vcSpitMe[0], sizeof(unsigned char), ivLen, fpOut)) != ivLen) {
         fprintf(stderr, "Unable to write uch file %s ...\n", pFileName);
         fclose(fpOut); fpOut = NULL;
         return NADA;
      }
   } // if(ivLen > 0)

   // success:
   fclose(fpOut); fpOut=NULL;

   return 0;
} // int spitUchFile()...








