
// Steg2.cpp : Defines the class behaviors for the application.
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//

#include "pch.h"
#include "framework.h"
#include "Steg2.h"
#include "Steg2Dlg.h"
#include "globs.h"
#include "bufin.h"
#include <direct.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// int mainWork(int argc, const char **argv);      // didn't want a special .h file just for this.



// from https://stackoverflow.com/questions/5094502/how-do-i-write-to-stdout-from-an-mfc-program:

void EnablePrintfAtMFC() {
   if (AttachConsole(ATTACH_PARENT_PROCESS)) {
      FILE* pCout;
      freopen_s(&pCout, "CONOUT$", "w", stdout);
      // std::cout.clear();
      // std::wcout.clear();
   }
}


#include "stufpic.h"   // qxtemp?  For scatterWalk()


// qxscatterWalk()

int scatterWalk() {
   static bool bInit = false;
   static int lmask[9], lmrev[9];

   if(!bInit) {
      for(int i=0; i<=8; i++) {
         lmask[i] = 0xFFFFFFFF << i;
         lmrev[i] = ~lmask[i];
      } // for(i=0; i<=8; i++)

      bInit = true;
   } // if(!bInit)

   jgrLil  jgGuy;
   jgGuy.setSize(1, 1);
   // jgGuy.writeBmp("tiny.bmp");

   int nNumer = 1;
   int nDenom = 1;
   int maxBits= 0;

   bitsLib abl(nNumer, nDenom, maxBits);

   // double bitsCanTakeScattered(jgrLil &jgGuy, int nNumer, int nDenom, int maxBits, double *pBitsPerIval, double *pErrsPerIval, bitsLib *pBitsLib)
   bitsCanTakeScattered(jgGuy, nNumer, nDenom, maxBits, NULL, NULL, &abl);

   for(int iSgn=-1; iSgn<2; iSgn+=2) {
      qprintf(fp_dbg, "\nThis is scatterWalk() with iSgn %d.\n", iSgn);
      int iVal = ((iSgn < 0) ? (253) : (2));

      while(1) {                                            // until we can't push iVal any more.
         // look for the best possible offset:
         int iVmax(iVal), iVmin(iVal);

         for(int iOff=0; iOff<256; iOff++) {
            bitsPair bp = abl.vcVcLib[iVal][iOff];
            int      nb = bp.nBits + (bp.highRemain > 0);   // assume hurdle zero.

            if(nb == 0)
               continue;

            int  iNuMin = ((iVal + iOff) & lmask[nb]) - iOff;
            int  iNuMax = iNuMin + lmrev[nb];               // lmrev: 0, 1, 3, 7, 15, ...

            iVmax       = MAX(iVmax, iNuMax);
            iVmin       = MIN(iVmin, iNuMin);

         } // for(int iOff=0; iOff<256; iOff++)

         int    ivNu = ((iSgn < 0) ? (iVmin) : (iVmax));

         if(ivNu == iVal) {
            qprintf(fp_dbg, "Done with iSgn %d, iVal %d.\n\n", iSgn, iVal);
            break;
         } // if(ivNu == iVal)

         qprintf(fp_dbg, "%d -> %d.\n", iVal, ivNu);

         iVal = ivNu;
      } // while(1)                                         // until we can't push iVal any more.
   } // for(int iSgn=-1; iSgn<2; iSgn+=2)

   return 0;  // qxtemp
} // int scatterWalk()




// CSteg2App

BEGIN_MESSAGE_MAP(CSteg2App, CWinApp)
   ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CSteg2App construction

CSteg2App::CSteg2App()
{
   // support Restart Manager
   m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

   // TODO: add construction code here,
   // Place all significant initialization in InitInstance
}


// The one and only CSteg2App object

CSteg2App theApp;


// CSteg2App initialization

BOOL CSteg2App::InitInstance()
{
   // InitCommonControlsEx() is required on Windows XP if an application
   // manifest specifies use of ComCtl32.dll version 6 or later to enable
   // visual styles.  Otherwise, any window creation will fail.
   INITCOMMONCONTROLSEX InitCtrls;
   InitCtrls.dwSize = sizeof(InitCtrls);
   // Set this to include all the common control classes you want to use
   // in your application.
   InitCtrls.dwICC = ICC_WIN95_CLASSES;
   InitCommonControlsEx(&InitCtrls);

   CWinApp::InitInstance();


   AfxEnableControlContainer();

   // Create the shell manager, in case the dialog contains
   // any shell tree view or shell list view controls.
   CShellManager *pShellManager = new CShellManager;

   // Activate "Windows Native" visual manager for enabling themes in MFC controls
   CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));

   // Standard initialization
   // If you are not using these features and wish to reduce the size
   // of your final executable, you should remove from the following
   // the specific initialization routines you do not need
   // Change the registry key under which our settings are stored
   // TODO: You should modify this string to be something appropriate
   // such as the name of your company or organization
   SetRegistryKey(_T("Local AppWizard-Generated Applications"));

#ifdef PROBLEMS
   if(strlen(this->m_lpCmdLine) > 0) {
      EnablePrintfAtMFC();
      fprintf(stdout, "Here we go.\n");  // qxtemp

      std::vector<std::string> vcTokensOut;
      cutLineIntoTokens(this->m_lpCmdLine, vcTokensOut);
      std::vector<const char *> vcArgv;
      vcArgv.push_back("whatever");       // usually the name of the executable; not used here.
      for(int i=0; i<(int)vcTokensOut.size(); i++)
         vcArgv.push_back(vcTokensOut[i].c_str());

      int argc = (int)vcArgv.size();

      int ii = mainWork(argc, &vcArgv[0]);

      return FALSE;  // outta here!
   } // if(strlen(this->m_lpCmdLine) > 0)
#endif // PROBLEMS

   this->readPresets("someName.txt");

   bool bDbg(false);

   if(m_commonInfo.doDbg == 0) {
      bDbg = ((file_t("dbg.txt") > 0) || (file_t("C:\\temp\\dbg.txt") > 0));
   } else {
      bDbg = (m_commonInfo.doDbg > 0);
   } // !if(m_commonInfo.doDbg == 0)

   // possibly open debug file:
   if(bDbg) {
      arcMeDotty("blah.dbg");
      int iio = fopen_s(&fp_dbg, "blah.dbg", "w");
   } // if(bDbg)

   fileCloser afc(&fp_dbg, 1, "blah.dbg");

   // standard backward stuffing ratios:
   m_commonInfo.vcBackRatOld.push_back(onePair(1,   16));

   m_commonInfo.vcBackRatExt.push_back(onePair(1,   16));
   m_commonInfo.vcBackRatExt.push_back(onePair(1,   45));
   m_commonInfo.vcBackRatExt.push_back(onePair(1,  128));
   m_commonInfo.vcBackRatExt.push_back(onePair(1,  362));
   m_commonInfo.vcBackRatExt.push_back(onePair(1, 1024));

   // user-specified backward stuffing ratios:
   Bufin aBuf("backs.txt");
   if(!aBuf.is_active()) {
      // file not found; embed with standard ratios:
      m_commonInfo.vcBackRatEmb = m_commonInfo.vcBackRatExt;
   } else {
      // we'll embed only using user-selected ratios; we'll extract using those and the standard ones.
      std::vector<std::string> vcTokens;
      std::set<onePair> stPairz;
      for(int i=0; i<aBuf.nlines(); i++) {
         const char *cpc = aBuf[i];
         int nTok = cutLineIntoTokens(cpc, vcTokens);
         if(nTok >= 2) {
            onePair apair(atoi(vcTokens[0].c_str()), atoi(vcTokens[1].c_str()));
            if((apair.numer > 0) && (apair.numer < 65536) && (apair.denom > 0) && (apair.denom < 65536) && (apair.numer <= apair.denom)) {
               // m_commonInfo.vcBackRatEmb.push_back(apair);
               stPairz.insert(apair);                 // sort first; vector later.
               // m_commonInfo.vcBackRatExt.push_back(apair);       // order not important.
            } // if((apair.numer > 0) && (apair.numer < 65536) && (apair.denom > 0) && (apair.denom < 65536) && (apair.numer <= apair.denom))
         } // if(nTok >= 2)
      } // for(int i=0; i<aBuf.nlines(); i++)

      // get sorted guys into the embed vector, large to small (small denominator to large denominator):
      std::set<onePair>::const_reverse_iterator itc;
      for(itc=stPairz.rbegin(); itc!=stPairz.rend(); itc++) {
         m_commonInfo.vcBackRatEmb.push_back(*itc);
         m_commonInfo.vcBackRatExt.push_back(*itc);

         qprintf(fp_dbg, "We just pushed back %d/%d.\n", (*itc).numer, (*itc).denom);
      } // for(itc=stPairz.begin(); itc!=stPairz.end(); itc++)

      // sanity check:
      if(m_commonInfo.vcBackRatEmb.size() == 0)
         m_commonInfo.vcBackRatEmb = m_commonInfo.vcBackRatExt;
   } // !if(!aBuf.is_active())

// this->readPresets("someName.txt");   // moved up.

#ifdef TESTT_UE
   // qxtemp: walking experiment:
   scatterWalk();
#endif // TESTT_UE

   // this thread isn't really necessary, but kind of fun:
   _beginthread(CSteg2App::doBackgroundTasks, 0, (void *)(&m_commonInfo));


   CSteg2Dlg dlg;

   dlg.m_pCommonInfo = &m_commonInfo;
   // dlg.m_vcBackRatEmb = m_commonInfo.vcBackRatEmb;
   // dlg.m_vcBackRatExt = m_commonInfo.vcBackRatExt;


   m_pMainWnd = &dlg;
   INT_PTR nResponse = dlg.DoModal();
   if (nResponse == IDOK)
   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with OK
   }
   else if (nResponse == IDCANCEL)
   {
      // TODO: Place code here to handle when the dialog is
      //  dismissed with Cancel
   }
   else if (nResponse == -1)
   {
      TRACE(traceAppMsg, 0, "Warning: dialog creation failed, so application is terminating unexpectedly.\n");
      TRACE(traceAppMsg, 0, "Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\n");
   }

   // Delete the shell manager created above.
   if (pShellManager != nullptr)
   {
      delete pShellManager;
   }

#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)
   ControlBarCleanUp();
#endif

   m_commonInfo.bDoStop = true;
   while(!m_commonInfo.bDidStop)
      Sleep(32);

   this->writePresets("someName.txt");

   const int iM = 64;
   char cbum[iM];

   qprintf(fp_dbg, "Total calls to MT64: %s.\n", comma_me(MT64::nAllCalls(), cbum, iM));

   if (fp_dbg != NULL) {
      for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++) {
         const std::string &ssI = m_commonInfo.vcSsBlahNames[i];
         qprintf(fp_dbg, "blah.dbg destination hoped for: %s.\n", ssI.c_str());
      } // for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++)

      {fclose(fp_dbg); fp_dbg = NULL;}

      for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++) {
         const std::string &ssI = m_commonInfo.vcSsBlahNames[i];
         arcMeDotty(ssI.c_str());
         jcpp("blah.dbg", ssI.c_str());
      } // for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++)
   } // if (fp_dbg != NULL)

   // Since the dialog has been closed, return FALSE so that we exit the
   //  application, rather than start the application's message pump.
   return FALSE;
}



int CSteg2App::ExitInstance()
{
   if (fp_dbg != NULL) {
      for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++) {
         const std::string &ssI = m_commonInfo.vcSsBlahNames[i];
         qprintf(fp_dbg, "blah.dbg destination hoped for: %s.\n", ssI.c_str());
      } // for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++)

      {fclose(fp_dbg); fp_dbg = NULL;}

      for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++) {
         const std::string &ssI = m_commonInfo.vcSsBlahNames[i];
         arcMeDotty(ssI.c_str());
         jcpp("blah.dbg", ssI.c_str());
      } // for(int i=0; i<(int)m_commonInfo.vcSsBlahNames.size(); i++)
   } // if (fp_dbg != NULL)

   return CWinApp::ExitInstance();
}


void CSteg2App::doBackgroundTasks(void *pParams) {
   stegInfo *pOne = (stegInfo *)pParams;
   pOne->bDidStop = false;

   while(!pOne->bDoStop) {
      if(pOne->ssName.size() > 0) {
         Sleep(32);                             // paranoia about partially-finished operation.

         std::string ssTmp = pOne->ssName;
         pOne->ssName = "";

// #ifdef STILL_FUKT   // but .bat file thing below is no better.
         _spawnlp(_P_NOWAIT, "explorer", "explorer", ssTmp.c_str(), NULL);
// #endif // STILL_FUKT

#ifdef NO_BETTER
         FILE *fp_tmp;
         const char *pcSillyBat = "kjfjenhhyu34.bat";
         int iio = fopen_s(&fp_tmp, pcSillyBat, "w");
         fprintf(fp_tmp, "%%systemRoot%%\\Explorer.exe /e,%s", ssTmp.c_str());
         fclose(fp_tmp); fp_tmp=NULL;

         _spawnlp(_P_NOWAIT, pcSillyBat, pcSillyBat, NULL);
#endif // NO_BETTER
      } // if(pOne->ssName.size() > 0)

      Sleep(32);
   } // while(!pOne->bDoStop)

   pOne->bDidStop = true;

   return;
} // void CSteg2App::doBackgroundTasks(void *pParams)





//
//
//
//
// 04-01-25: new params for desires.
//
// qxreadPresets()

int CSteg2App::readPresets(const char *pcFileName) {

   Bufin abuf(pcFileName);
   if(!abuf.is_active()) {
      qprintf(fp_dbg, "Unable to open preset file \"%s\".\n", pcFileName);

      // default all the folders to here:
      const int iLen(4096);
      char cbuf[iLen];
      _getcwd(cbuf, iLen);

      m_commonInfo.ssExtractCold = cbuf;
      m_commonInfo.ssWrapperLoc  = cbuf;
      m_commonInfo.ssEmbedLoc    = cbuf;
      m_commonInfo.ssEmbedFoldr  = cbuf;
      m_commonInfo.ssMessageLoc  = cbuf;

//    m_commonInfo.noWrite       = 1;              // file would never get written for new user.

      return NADAfunc("Preset file not found.");
   } // if(!abuf.is_active())


   std::map<std::string, int>         mpKeyToInt;
   std::map<std::string, double>      mpKeyToDoub;
   std::map<std::string, std::string> mpKeyToStrng;

   for(int i=0; i<abuf.nlines(); i++) {
      std::string ssLin = abuf[i];
      int ieq = (int)ssLin.find("=");
      if(ieq == std::string::npos)
         continue;

      std::string ssKeRaw = ssLin.substr(0, ieq);   // won't include '='

      std::string ssKey;

      trim_sp(ssKeRaw, ssKey);

      if(ssKey.size() == 0)
         continue;

      // key must have no embedded space(s):
      if(strchr(ssKey.c_str(), ' ') != NULL)
         continue;

      std::string ssValRaw = ssLin.substr(ieq+1, std::string::npos);
      std::string ssValue;
      trim_sp(ssValRaw, ssValue);

      if(ssValue.size() == 0)
         continue;

      // fprintf(stdout, "Key %-20s, value %s\n", ssKey.c_str(), ssValue.c_str());  // qxtemp!

      if(ssValue.c_str()[0] == '"') {
         // string value; we assume closing quote; chop both off:
         int iLenChop = (int)ssValue.size() - 2;
         if(iLenChop < 0)
            continue;

         mpKeyToStrng[ssKey] = ssValue.substr(1, iLenChop);
      } else if(strchr(ssValue.c_str(), '.') != NULL) {
         // double:
         mpKeyToDoub[ssKey] = atof(ssValue.c_str());
      } else {
         // int:
         mpKeyToInt[ssKey] = atoi(ssValue.c_str());
      }
   } // for(int i=0; i<abuf.nlines(); i++)

   bool bShow = false;
   if(bShow) {
      // qxtemp: show the map contents:
      for(std::map<std::string, int>::const_iterator itc=mpKeyToInt.begin(); itc!=mpKeyToInt.end(); itc++) {
         const std::string &ssKey = itc->first;
         int                iVal  = itc->second;
         qprintf(fp_dbg, "%-12s = %d\n", ssKey.c_str(), iVal);
      } // for(std::map<std::string, int>::const_iterator itc=mpKeyToInt.begin(); itc!=mpKeyToInt.end(); itc++)

      for(std::map<std::string, double>::const_iterator itc=mpKeyToDoub.begin(); itc!=mpKeyToDoub.end(); itc++) {
         const std::string &ssKey = itc->first;
         double             dVal  = itc->second;
         qprintf(fp_dbg, "%-12s = %.6f\n", ssKey.c_str(), dVal);
      } // for(std::map<std::string, double>::const_iterator itc=mpKeyToDoub.begin(); itc!=mpKeyToDoub.end(); itc++)

      for(std::map<std::string, std::string>::const_iterator itc=mpKeyToStrng.begin(); itc!=mpKeyToStrng.end(); itc++) {
         const std::string &ssKey = itc->first;
         const std::string &ssVal = itc->second;
         qprintf(fp_dbg, "%-12s = \"%s\"\n", ssKey.c_str(), ssVal.c_str());
      } // for(std::map<std::string, std::string>::const_iterator itc=mpKeyToStrng.begin(); itc!=mpKeyToStrng.end(); itc++)
   } // if(bShow)


   // look for known input of interest; ignore anything else in the maps.
   std::string ssKeyTest;


   // where extractions happen without embed first:
   ssKeyTest = "ExtractCold";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssExtractCold = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))


#ifdef NOT_SAVED
   // where extractions happen after embed first:
   ssKeyTest = "ExtractWarm";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssExtractWarm = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))
#endif // NOT_SAVED


   // where we loaded the last wrapper file:
   ssKeyTest = "WrapperLoc";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssWrapperLoc = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))


   // where we opened the last files to be embedded:
   ssKeyTest = "EmbedLoc";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssEmbedLoc = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))


   // where we opened the last folder to be embedded:
   ssKeyTest = "EmbedFoldr";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssEmbedFoldr = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))


   // where we last saved a message:
   ssKeyTest = "MessageLoc";
   if(bIsInMap(mpKeyToStrng, ssKeyTest)) {
      const std::string &ssValue = mpKeyToStrng[ssKeyTest];
      m_commonInfo.ssMessageLoc = ssValue;
   } // if(bIsInMap(mpKeyToStrng, ssKeyTest))


   ssKeyTest = "maxBits";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int maxBits =  mpKeyToInt[ssKeyTest];
      m_commonInfo.maxBits = maxBits;
   }


   ssKeyTest = "widDesired";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int widDesired =  mpKeyToInt[ssKeyTest];
      m_commonInfo.widDesired = widDesired;
   }


   ssKeyTest = "hgtDesired";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int hgtDesired =  mpKeyToInt[ssKeyTest];
      m_commonInfo.hgtDesired = hgtDesired;
   }


   ssKeyTest = "fszDesired";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int fszDesired =  mpKeyToInt[ssKeyTest];
      m_commonInfo.fszDesired = fszDesired;
   }


   ssKeyTest = "noWrite";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int noWrite =  mpKeyToInt[ssKeyTest];
      m_commonInfo.noWrite = noWrite;
   }


   ssKeyTest = "useScatter";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int iScatter =  mpKeyToInt[ssKeyTest];
      m_commonInfo.useScatter = iScatter;
   }



   ssKeyTest = "lastScatter";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int jScatter =  mpKeyToInt[ssKeyTest];
      m_commonInfo.lastScatter = jScatter;
   }


   ssKeyTest = "nDigitsSafe";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int nSafe =  mpKeyToInt[ssKeyTest];
      m_commonInfo.nDigitsSafe = nSafe;
   }


   ssKeyTest = "bShuffle";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int iShuffle =  mpKeyToInt[ssKeyTest];
      m_commonInfo.bShuffle = !!iShuffle;
   }


   ssKeyTest = "bConserv";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int iConserv =  mpKeyToInt[ssKeyTest];
      m_commonInfo.bConserv = !!iConserv;
   }


   ssKeyTest = "bTrim";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int iTrim =  mpKeyToInt[ssKeyTest];
      m_commonInfo.bTrim = !!iTrim;
   }


   ssKeyTest = "bPassHint";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int iPassHint =  mpKeyToInt[ssKeyTest];
      m_commonInfo.bPassHint = !!iPassHint;
   }


   ssKeyTest = "nNumer";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int nNumer =  mpKeyToInt[ssKeyTest];
      m_commonInfo.nNumer = nNumer;
   }


   ssKeyTest = "nDenom";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int nDenom =  mpKeyToInt[ssKeyTest];
      m_commonInfo.nDenom = nDenom;
   }


   ssKeyTest = "doDbg";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int doDbg =  mpKeyToInt[ssKeyTest];
      m_commonInfo.doDbg = doDbg;
   }


   ssKeyTest = "doBmp";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int doBmp =  mpKeyToInt[ssKeyTest];
      m_commonInfo.doBmp = doBmp;
   }


   ssKeyTest = "doPng";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int doPng =  mpKeyToInt[ssKeyTest];
      m_commonInfo.doPng = doPng;
   }


   ssKeyTest = "embFolder";
   if(bIsInMap(mpKeyToInt, ssKeyTest)) {
      int embFolder =  mpKeyToInt[ssKeyTest];
      m_commonInfo.embFolder = embFolder;
   }


   ssKeyTest = "difDesired";
   if(bIsInMap(mpKeyToDoub, ssKeyTest)) {
      double difDesired =  mpKeyToDoub[ssKeyTest];
      m_commonInfo.difDesired = difDesired;
   }


   ssKeyTest = "factRed";
   if(bIsInMap(mpKeyToDoub, ssKeyTest)) {
      double factRed =  RANGE(mpKeyToDoub[ssKeyTest], 0.0, 1.0);
      m_commonInfo.factRed = factRed;
   }


   ssKeyTest = "factGrn";
   if(bIsInMap(mpKeyToDoub, ssKeyTest)) {
      double factGrn =  RANGE(mpKeyToDoub[ssKeyTest], 0.0, 1.0);
      m_commonInfo.factGrn = factGrn;
   }


   ssKeyTest = "factBlu";
   if(bIsInMap(mpKeyToDoub, ssKeyTest)) {
      double factBlu =  RANGE(mpKeyToDoub[ssKeyTest], 0.0, 1.0);
      m_commonInfo.factBlu = factBlu;
   }

   return 0;
} // int CSteg2App::readPresets(const char *pcFileName)





//
//
//
//
// 04-01-25: new params for desires.
//
// qxwritePresets()

int CSteg2App::writePresets(const char *pcFileName) {
   int i;

   if(m_commonInfo.noWrite != 0)
      return NADA;

   FILE *fp_out(NULL);

   i = fopen_s(&fp_out, pcFileName, "w");
   if((i != 0) || (fp_out == NULL))
      return NADA;

   fprintf(fp_out, "%-20s = \"%s\"\n", "ExtractCold", m_commonInfo.ssExtractCold.c_str());
// fprintf(fp_out, "%-20s = \"%s\"\n", "ExtractWarm", m_commonInfo.ssExtractWarm.c_str());   // no, fresh with each run.
   fprintf(fp_out, "%-20s = \"%s\"\n", "WrapperLoc",  m_commonInfo.ssWrapperLoc.c_str());
   fprintf(fp_out, "%-20s = \"%s\"\n", "EmbedLoc",    m_commonInfo.ssEmbedLoc.c_str());
   fprintf(fp_out, "%-20s = \"%s\"\n", "EmbedFoldr",  m_commonInfo.ssEmbedFoldr.c_str());
   fprintf(fp_out, "%-20s = \"%s\"\n", "MessageLoc",  m_commonInfo.ssMessageLoc.c_str());

   // write these out only if something non-default was specified on read; otherwise leave out.
   if(m_commonInfo.maxBits > 0)
      fprintf(fp_out, "%-20s = %d\n",  "maxBits",     m_commonInfo.maxBits);
   if(m_commonInfo.widDesired > 0)
      fprintf(fp_out, "%-20s = %d\n",  "widDesired",  m_commonInfo.widDesired);
   if(m_commonInfo.hgtDesired > 0)
      fprintf(fp_out, "%-20s = %d\n",  "hgtDesired",  m_commonInfo.hgtDesired);
   if(m_commonInfo.fszDesired > 0)
      fprintf(fp_out, "%-20s = %d\n",  "fszDesired",  m_commonInfo.fszDesired);
   if(m_commonInfo.useScatter <= 0)
      fprintf(fp_out, "%-20s = %d\n",  "useScatter",  m_commonInfo.useScatter);
   if(m_commonInfo.lastScatter <= 0)
      fprintf(fp_out, "%-20s = %d\n",  "lastScatter", m_commonInfo.lastScatter);
   if(m_commonInfo.nDigitsSafe != 2)
      fprintf(fp_out, "%-20s = %d\n",  "nDigitsSafe", m_commonInfo.nDigitsSafe);
   if(m_commonInfo.bShuffle == false)
      fprintf(fp_out, "%-20s = %d\n",  "bShuffle",    m_commonInfo.bShuffle);
   if(m_commonInfo.bConserv == false)
      fprintf(fp_out, "%-20s = %d\n",  "bConserv",    m_commonInfo.bConserv);
   if(m_commonInfo.bTrim == false)
      fprintf(fp_out, "%-20s = %d\n",  "bTrim",       m_commonInfo.bTrim);
   if(m_commonInfo.bPassHint == false)
      fprintf(fp_out, "%-20s = %d\n",  "bPassHint",   m_commonInfo.bPassHint);
   if(m_commonInfo.nNumer > 0)
      fprintf(fp_out, "%-20s = %d\n",  "nNumer",      m_commonInfo.nNumer);
   if(m_commonInfo.nDenom > 0)
      fprintf(fp_out, "%-20s = %d\n",  "nDenom",      m_commonInfo.nDenom);
   if(m_commonInfo.doDbg != 0)
      fprintf(fp_out, "%-20s = %d\n",  "doDbg",       m_commonInfo.doDbg);
   if(m_commonInfo.doBmp != 0)
      fprintf(fp_out, "%-20s = %d\n",  "doBmp",       m_commonInfo.doBmp);
   if(m_commonInfo.doPng != 1)
      fprintf(fp_out, "%-20s = %d\n",  "doPng",       m_commonInfo.doPng);
   if(m_commonInfo.embFolder != 0)
      fprintf(fp_out, "%-20s = %d\n",  "embFolder",   m_commonInfo.embFolder);
   if(m_commonInfo.difDesired >= 0.0)
      fprintf(fp_out, "%-20s = %.4f\n","difDesired",  m_commonInfo.difDesired);
   if(m_commonInfo.factRed != 1.0)
      fprintf(fp_out, "%-20s = %.4f\n","factRed",     m_commonInfo.factRed);
   if(m_commonInfo.factGrn != 1.0)
      fprintf(fp_out, "%-20s = %.4f\n","factGrn",     m_commonInfo.factGrn);
   if(m_commonInfo.factBlu != 1.0)
      fprintf(fp_out, "%-20s = %.4f\n","factBlu",     m_commonInfo.factBlu);

   fclose(fp_out); fp_out=NULL;

   return 0;
} // int CSteg2App::writePresets(const char *pcFileName)




