//=-- FSGZipped.cpp - GZ Zipped compressed File Streams ----------------------=
//
// This class allows MagicStats to read from GZipped compressed files.  Please
// note that seeking in these files is an extremely expensive operation.
//
//=---------------------------------------------------------------------------=
//  This file is copyright (c) 1997-2000 Chris Lattner
//=---------------------------------------------------------------------------=

#include "FSGZipped.h"

#include <fcntl.h>
#include <stdio.h>

INIT_PLUGIN(FSGZipped)

// FSGZipped - Implemented in terms of ZLib calls 
FSGZipped::FSGZipped(const char *Filename, int OpenCode, 
                     int &ErrorOccurred) {
  unsigned char Header[3];

  ErrorOccurred = 1; F = 0;
  if (OpenCode != FileStreamPlugin::OPEN_READ) return;

  FILE *FD = fopen(Filename, "r");
  if (FD == 0) return;

  fread(Header, 1, 3, FD);
  fclose(FD);

  // Header[] = 0x1F, 0x8B, 0x08...
  if (Header[0] != 0x1F || Header[1] != 0x8B || Header[2] != 0x08)
    return;

  F = gzopen(Filename, "rb");
  if (F == 0) return;

  ErrorOccurred = 0;  // If we made it this far, no error occurred.
  EOFFound = 0;
  NumBuffered = 0;
  BufPtr = 0;
}

FSGZipped::~FSGZipped() {
  if (F != 0)       // F == 0 if constructor failed to open file...
    gzclose(F);
}

// seek - Seek the file to the specified position, return 0 if successful,
// true if seek failed.
//
int FSGZipped::seek(long Position, int From) {
  long FilePos = gzseek(F, Position, From);
  NumBuffered = 0;
  if (From == SeekSet && Position != FilePos)
    return 1;     // Couldn't seek to the specified location...
  else
    return 0;
}

long FSGZipped::tell() {
  return gztell(F) - NumBuffered;
}

int FSGZipped::eof() {
  return EOFFound;
}

int FSGZipped::GetC(char &c) {
  if (EOFFound) return 1;     // Already at EOF.

  if (NumBuffered == 0) {
    NumBuffered = gzread(F, Buffer, 256);
    BufPtr = Buffer;
    if (NumBuffered <= 0) {    // EOF occured
      EOFFound = 1;
      return 1;
    }
    if (NumBuffered < 0) return -1; // Error occurred
  }

  c = *BufPtr++;
  NumBuffered--;
  return 0;
}

FileStreamPlugin *FSGZipped::getline(char *buffer, int BufferLength, 
                                     char Delimiter) {
  char c = Delimiter;
  int BytesWritten = 0;

  if (BufferLength == 0) return this;
  if (BufferLength == 1) {
    buffer[0] = 0;
    return this;
  }

  if (GetC(c)) {
    *buffer = 0;
    return 0;       // Real EOF.
  }

  while (c != Delimiter) {
    *buffer++ = c;
    BytesWritten++;
    if (BytesWritten == BufferLength-1) {
      *buffer = 0;
      return this;
    }

    if (GetC(c)) 
      break;
  }

  *buffer = 0;
  return this;
}

