
//
// jarq.h: new 07-19-23.  Non-compressed archiving of multiple files.
//
// Written by John A deLaubenfels, https://www.adaptune.com/steg.htm .
// Permission granted to use freely in any non-fraudulent way.
//
//
//
//
//
//


#ifndef JARQ_H
#define JARQ_H



#ifdef _WIN32
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <utime.h>

int utime(const char *filename, const struct utimbuf *times);

#include <sys/time.h>

#endif // !_WIN32

#include <list>
#include "globs.h"
#include "zlib.h"
#include "arcHelp.h"

#define OLD_JARQ (0x4A617271)   // "Jarq" backward.
#define ARC_JARQ (0x7172614A)   // "Jarq".

#ifndef BYTE
#define BYTE unsigned char
#endif


class JarqOne;
class JarqAnch;



// qxJarqOne

class JarqOne {
friend JarqAnch;
private:
   int                    m_iFormat;
   long long              m_lenFile;      // uncompressed length.
   long long              m_ctime;
   long long              m_mtime;
   long long              m_atime;
   int                    m_mode;
   unsigned int           m_hash;         // 4 bytes of hash for the file's contents.
   std::string            m_ssFileName;
   std::vector<unsigned char> m_vcFileData;
public:
   JarqOne();
   JarqOne(const JarqOne &rs);
   ~JarqOne() {clear();}

   const JarqOne &operator=(const JarqOne &rs);

   void clear(); //  {m_lenFile=m_ctime=m_mtime=m_atime=m_mode=m_iFormat=0; m_ssFileName.clear(); zeroMe(m_vcFileData), m_vcFileData.clear();}

   size_t size() const {return m_vcFileData.size();}

   const char        *getFileName() const {return m_ssFileName.c_str();}
   const std::string &getFileNams() const {return m_ssFileName;}
   void               setFileName(const char *pNuu) {m_ssFileName = ((pNuu == NULL) ? ("") : (pNuu));}

   long long          getLen()      const {return m_lenFile;}

   int                getMode()     const {return m_mode;}
   void               setMode(int llNu) {m_mode = llNu;}

   long long          getCtime()    const {return m_ctime;}
   void               setCtime(long long llNu) {m_ctime = llNu;}

   long long          getMtime()    const {return m_mtime;}
   void               setMtime(long long llNu) {m_mtime = llNu;}

   long long          getAtime()    const {return m_atime;}
   void               setAtime(long long llNu) {m_atime = llNu;}

   int fillOne(const std::vector<unsigned char> &vcData, int iFormat);
   int fillOne(const std::string &ssData, int iFormat);
   int getData(std::vector<unsigned char> &vcData, std::vector<std::string> *pvcErrsOut=NULL) const;

   int readOne(const char *pcFileName, int iFormat, bool bNoSavePath=false);
   int writeOne(std::vector<unsigned char> *pvcContentsOut=NULL, std::vector<std::string> *pvcErrsOut=NULL) const;

   int archiveMe(int irev, spitObj &mySpit) const;
   int unArcMe(int irev, sucqObj &suq);
}; // JarqOne






// qxJarqAnch

class JarqAnch {
private:
   std::string            m_ssArcFileName;
   std::vector<JarqOne>   m_vcOnes;
public:
   JarqAnch() {}
   JarqAnch(const JarqAnch &rs);
   ~JarqAnch() {clear();}

   const JarqAnch &operator=(const JarqAnch &rs);
   const JarqAnch &operator+=(const JarqAnch &rs);

   void clear() {zeroMe(m_ssArcFileName); m_ssArcFileName.clear(); m_vcOnes.clear();}

   size_t size() const {return m_vcOnes.size();}
   void   setSize(int nNew) {m_vcOnes.resize(nNew);}

   int    nSubstantial() const;    // size() less any with blank file name.

   const JarqOne *getIthOne(int ith) const;
   JarqOne *getIthOne(int ith) {return (JarqOne *)(((const JarqAnch *)this)->getIthOne(ith));}

   int addOne(JarqOne &addMe) {this->m_vcOnes.push_back(addMe); return 0;}

   int addOne(const char *pcFileName, int iFormat, bool bNoSavePath=false);
   int addFiles(const std::vector<std::string> &vcFileList, int iFormat, bool bNoSavePath=false);
   int spitFiles(std::vector<std::vector<unsigned char>> *pvcVcContentsOut=NULL, std::vector<FILE *> *pvcFileWrites=NULL, std::vector<std::string> *pvcErrsOut=NULL) const;  // dumps out all files in the archive.

   int readJarq(const char *pcFileName);
   int writeJarq(const char *pcFileName=NULL) const;

   int archiveJarq(int irev, spitObj &mySpit, int nEmpty=0, int nSkip=0) const;
   int unArcJarq(int &irevSaved, sucqObj &suq);
   int arcAppend(const char *pcExisting);

   // 12-12-24: memory-saving versions:
   static int creApp(const std::string &ssArcFile, const std::vector<std::string> &vecSrcFiles, int iFormat, bool bAppend);
   static int extLst(const std::string &ssArcFile, const std::vector<std::string> &vcFiles, const std::vector<std::string> &vcExclude, bool bList, bool bVerbose, bool bRaw);

}; // JarqAnch




// Begin code from
// https://www.experts-exchange.com/articles/3189/In-Memory-Compression-and-Decompression-Using-ZLIB.html

int GetMaxCompressedLen(int nLenSrc);
int CompressData(const BYTE* abSrc, int nLenSrc, BYTE* abDst, int nLenDst);
int UncompressData(const BYTE* abSrc, int nLenSrc, BYTE* abDst, int nLenDst);

// End code from
// https://www.experts-exchange.com/articles/3189/In-Memory-Compression-and-Decompression-Using-ZLIB.html

// my wrappers:
int CompressData(const std::vector<unsigned char> &vcFatIn, std::vector<unsigned char> &vcThinOut);
int UncompressData(const std::vector<unsigned char> &vcThinIn, std::vector<unsigned char> &vcFatOut);


#endif // !JARQ_H

