//***************************************************************************
//
// this file is (c) '94-'96 Niklas Beisert
//
// this file is part of the cubic player development kit.
// you may only use/modify/spread this file under the terms stated
// in the cubic player development kit accompanying documentation.
//
//***************************************************************************

//cp.ini:
//[defaultconfig]
//  link=arcrar
//[fileselector]
//  arcs=_adbRARReg


// rar archive reader
// example for archive readers

#include <io.h>
#include <stdlib.h>
#include <string.h>
#include "binfile.h"
#include "pfilesel.h"
#include "psetting.h"

static int adbRARScan(const char *path)
{
  char ext[_MAX_EXT];
  char name[_MAX_FNAME];
  char arcname[12];

  _splitpath(path, 0, 0, name, ext);
  fsConvFileName12(arcname, name, ext);

  sbinfile file;
  if (!file.open(path, sbinfile::openro))
    return 1;
  arcentry a;
  memcpy(a.name, arcname, 12);
  a.size=file.length();
  a.flags=ADB_ARC;
  if (!adbAdd(a))
    return 0;
  unsigned short arcref=adbFind(arcname);

  unsigned char markerblock[7];
  if (!file.eread(markerblock, 7))
    return 0;
  if (memcmp(markerblock, "\x52\x61\x72\x21\x1a\x07\x00", 7))
    return 0;

  file.gets();
  if (file.getc()!=0x73)
    return 0;
  unsigned short hdflags=file.getus();
  if (hdflags&0x8000)
    return 0;
  file.seekcur(file.getus()-7);

  while (1)
  {
    struct
    {
      unsigned short crc;
      unsigned char type;
      unsigned short flags;
      unsigned short blklen;
    } rarhead;

    unsigned long nextpos=file.tell();
    if (!file.eread(&rarhead, 7))
      return 1;
    nextpos+=rarhead.blklen;
    unsigned long extra=0;
    if (rarhead.flags&0x8000)
      extra=file.getul();
    nextpos+=extra;
    if ((rarhead.type!=0x74)||(rarhead.flags&5))
    {
      file.seek(nextpos);
      continue;
    }
    unsigned long uncompsize=file.getul();
/*
    file.getc(); // os
    file.getl(); // crc
    file.getl(); // time
    file.getc(); // ver
    file.getc(); // meth
*/
    file.seekcur(11);
    unsigned short namelen=file.getus();
    unsigned long attr=file.getul();
    char filename[256];
    if (namelen>255)
    {
      file.seek(nextpos);
      continue;
    }
    file.read(filename, namelen);
    filename[namelen]=0;
    strupr(filename);
    _splitpath(filename, 0, 0, name, ext);
    if (fsIsModule(ext))
    {
      a.size=uncompsize;
      a.parent=arcref;
      a.flags=0;
      fsConvFileName12(a.name, name, ext);
      if (!adbAdd(a))
        return 0;
    }
    file.seek(nextpos);
  }
  file.close();
  return 1;
}

static int adbRARCall(int act, const char *apath, const char *file, const char *dpath)
{
  switch (act)
  {
  case adbCallGet:
    return !adbCallArc(cfGetProfileString("arcRAR", "get", "rar e -std %a %d %n"), apath, file, dpath);
    break;
  case adbCallPut:
    return !adbCallArc(cfGetProfileString("arcRAR", "put", "rar a -std -ep %a %n"), apath, file, dpath);
    break;
  case adbCallDelete:
    return !adbCallArc(cfGetProfileString("arcRAR", "delete", "rar d -std %a %n"), apath, file, dpath);
    break;
  case adbCallMoveTo:
    if (cfGetProfileString("arcRAR", "moveto", 0))
      return !adbCallArc(cfGetProfileString("arcRAR", "moveto", "rar m -std -ep %a %n"), apath, file, dpath);
    if (!adbRARCall(adbCallPut, apath, file, dpath))
      return 0;
    unlink(file);
    return 1;
  case adbCallMoveFrom:
    if (cfGetProfileString("arcRAR", "movefrom", 0))
      return !adbCallArc(cfGetProfileString("arcRAR", "movefrom", ""), apath, file, dpath);
    if (!adbRARCall(adbCallGet, apath, file, dpath))
      return 0;
    return adbRARCall(adbCallDelete, apath, file, dpath);
  }
  return 0;
}

extern "C"
{
  adbregstruct adbRARReg = {".RAR", adbRARScan, adbRARCall};
};
