/*
    Xunzip for Linux, handles gzip and zip files via zlib.
    Copyright (C) 1998 Tero Koskinen

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
*/
// zipHeader.h

#include <fstream.h>

#ifdef USE_GTK
#include <gtk/gtk.h>
#else
#include <qapp.h>
#include <qlistbox.h>
#include <ktablistbox.h>
#endif

#include <zlib.h>
#include "config.h"
#include "utils.h"

#ifndef TK_ZIP_HEADER
#define TK_ZIP_HEADER

class BasicHeader
{
public:
  BasicHeader();
  BasicHeader(const BasicHeader & op);
  ~BasicHeader();

  BasicHeader & operator=(const BasicHeader & op);
  
  void read(ifstream & fin);
  int find(ifstream & fin);

  unsigned int getVersion(void) const { return myVersion; }
  unsigned int getPFlag(void) const { return myFlag; }
  unsigned int getMethod(void) const { return myMethod; }
  unsigned int getLastModTime(void) const { return myLastModTime; }
  unsigned int getLastModDate(void) const { return myLastModDate; }
  unsigned long getCrc32(void) const { return myCrc32; }
  unsigned long getCSize(void) const { return myCSize; }
  unsigned long getUnCSize(void) const { return myUnCSize; }
  unsigned int getFilenameLength(void) const { return myFilenameLength; }
  unsigned int getExtraFieldLength(void) const { return myExtraFieldLength; }
  char *getFilename(void) const { return myFilename; }
  unsigned long getPlace(void) const { return myPlace; }
private:
  unsigned int myVersion;
  unsigned int myFlag;
  unsigned int myMethod;
  unsigned int myLastModTime;
  unsigned int myLastModDate;
  unsigned long myCrc32;
  unsigned long myCSize;
  unsigned long myUnCSize;
  unsigned int myFilenameLength;
  unsigned int myExtraFieldLength;
  char *myFilename;
  unsigned long myPlace; // paikka mista header on alkanut
};

class CentralDirRecord
{
public:
  CentralDirRecord();
  CentralDirRecord(const CentralDirRecord & op);  
  ~CentralDirRecord();
  
  CentralDirRecord & operator=(const CentralDirRecord & op);
  
  void read(ifstream & fin);
  int find(ifstream & fin);

  unsigned int getVersionMadeBy(void) const { return myVerMadeBy; }
  unsigned int getVersion(void) const { return myVersion; }
  unsigned int getPFlag(void) const { return myFlag; }
  unsigned int getMethod(void) const { return myMethod; }
  unsigned int getLastModTime(void) const { return myLastModTime; }
  unsigned int getLastModDate(void) const { return myLastModDate; }
  unsigned long getCrc32(void) const { return myCrc32; }
  unsigned long getCSize(void) const { return myCSize; }
  unsigned long getUnCSize(void) const { return myUnCSize; }
  unsigned int getFilenameLength(void) const { return myFilenameLength; }
  unsigned int getExtraFieldLength(void) const { return myExtraFieldLength; }
  unsigned int getCommentLength(void) const { return myCommentLength; }
  unsigned int getDiskNumber(void) const { return myDiskNumber; }
  unsigned int getInternalAttr(void) const { return myInternalAttr; }
  unsigned long getExternalAttr(void) const { return myExternalAttr; }
  unsigned long getRelOffsetLHeader(void) const { return myRelOffset; }
  
  char *getFilename(void) const { return myFilename; }
  char *getComment(void) const { return myComment; }
  unsigned long getPlace(void) const { return myPlace; }
private:
  unsigned int myVerMadeBy;
  unsigned int myVersion;
  unsigned int myFlag;
  unsigned int myMethod;
  unsigned int myLastModTime;
  unsigned int myLastModDate;
  unsigned long myCrc32;
  unsigned long myCSize;
  unsigned long myUnCSize;
  unsigned int myFilenameLength;
  unsigned int myExtraFieldLength;
  unsigned int myCommentLength;
  unsigned int myDiskNumber;
  unsigned int myInternalAttr;
  unsigned long myExternalAttr;
  unsigned long myRelOffset;
  char *myFilename;
  char *myComment;
  unsigned long myPlace; // mista cdr alkaa
};
// ----- linked lists -----------
class BasicNode {
public:
  BasicNode():next(0) { }
  ~BasicNode() { next=0; }

  BasicNode *getNext(void) { return next; }
  void setNext(BasicNode *p) { if (next) next->setNext(p); else next=p; }
  BasicHeader h;
private:
  BasicNode *next;
};

class BasicHeaderList {
public:
  BasicHeaderList():root(0),nodes(0) { }
  ~BasicHeaderList() { if (root) deleteAll(); }

  int add(BasicHeader & bh);
  void deleteAll(void);
  unsigned int getNodes(void) { return nodes; }
  BasicNode *getNode(int index);
private:
  BasicNode *root;
  unsigned int nodes;
};

class CDRNode {
public:
  CDRNode():next(0) { }
  ~CDRNode() { next=0; }

  CDRNode *getNext(void) { return next; }
  void setNext(CDRNode *p) { if (next) next->setNext(p); else next=p; }
  CentralDirRecord h;
private:
  CDRNode *next;
};

class CentralDirRecordList {
public:
  CentralDirRecordList():root(0),nodes(0) { }
  ~CentralDirRecordList() { if (root) deleteAll(); }

  int add(CentralDirRecord & cdr);
  void deleteAll(void);
  unsigned int getNodes(void) { return nodes; }
  CDRNode *getNode(int index);
  CDRNode *getNodeByName(const char *name);
private:
  CDRNode *root;
  unsigned int nodes;
};

class ZipHeader
{
public:
  ZipHeader() { }
  ~ZipHeader() { }
 
  int find(ifstream & fin); // 0 ei loytynyt, 1=local(basic) header,2=cdr,3=end of cd
};

class ZipPacket
{
public:
  ZipPacket();
  ~ZipPacket();
#ifdef USE_GTK  
  int open(char *file,GtkWidget *lista); // 0=OK,-1=NOT ok!
  int close(GtkWidget *lista);
#else
  int open(const char *file,KTabListBox *lista);
  int close(KTabListBox *lista);
#endif
  int isOpen(void) { return opened; }
  int unZip(const char *path,int sfile=-1); // return 0=OK,-1=NOT ok!
#ifdef USE_GTK
  int testcrc(GtkWidget *lista);
#else
  int testcrc(QListBox *lista);
#endif
  unsigned long getCSize(const char *name);
  unsigned long getUnCSize(const char *name);
  CDRNode* getNode(int index) { return cdList.getNode(index); }
  int getType(void) { return fileType; }
private:
  BasicHeaderList bhList;
  CentralDirRecordList cdList;
  ZipHeader zh;
  ifstream fin;
  int opened;
  int files;
  char tiedosto[FNAME_MAX];
  
  int inflatePacked(unsigned char *compr,
    unsigned long comprLen,ofstream & fout);
  int testInflated(unsigned char *compr,unsigned long comprLen,unsigned long orig_crc);
  int gunzipFile(char *unComprFilename);
  int fileType; // 1 = zipfile, 2= gzip file
};


#endif // TK_ZIP_HEADER
