//<copyright>
//
// Copyright (c) 1996
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
//
//</copyright>

//<file>
//
// Name:    $RCSfile: codec.h,v $
//
// Purpose: Interface for class CoDec.
//
// Created: 9 Aug 96 Thomas Starlinger
//
// $Id: codec.h,v 1.1 1997/02/05 11:00:02 bmarsch Exp $
//
// Description: 
//   
//</file>
//
// $Log: codec.h,v $
// Revision 1.1  1997/02/05 11:00:02  bmarsch
// Initial revision
//

#ifndef hg_path_codec_h
#define hg_path_codec_h

class ProgressBase;
#include <iostream.h>
#include "str.h"

//<class> 
//  
// Name:    CoDec.
// 
// Purpose: Code/Decode memory in different coding systems (uucode, base64, ...).
// 
// Public Interface:
//
//  - 	CoDec(int m=UUENCODE, ProgressBase* p=nil, float i=0.0);
//  - 	CoDec(char *t, long l=-1, int m=UUENCODE, ProgressBase* p=nil, float i=0.0); 
//      Constructors for the coder class. Class uses a progress indicator if specified.
//
//  - 	~CoDec();
//      Deletes character arrays if allocated by CoDec.
//
//  - 	setBuffer(char* t, long l=-1);
//      Set buffer text by gaining the character pointer (The user MUST not delete the
//      appropriate array until coder work is done).
//
//  - 	setMethod(int m=UUENCODE);
//      Set en/decoding methode.
//
//  - 	getText(int m=-1);
//      Get en/decoded text according to methode m.
//
//  - 	operator >>:
//  - 	operator <<:
//      Stream IO for class CoDec.
//      e.g.: 
//        CoDec test;
//
//        while (cin.good()) {
//          cin >> test;
//          cout << test;
//        }
//      NOTE: For a fully functional stop button, in this example, you have to ask for
//            stop run in the loop yourself.
//
// Private Interface:
//
//  - 	void codeBuffer();
//      En/Decode buffer according to demanded method.
//
// ---- En/Decoding according to unix-to-unix encoding format.
//  - 	uu_encode();
//  - 	uu_decode();
//      Step through memory and call coder functions:
//
//  - 	uu_encode_(...);
//      Coding takes place by depicting the input as bit stream and generating one
//      octet (byte) from 6 bit of the input stream. Add 20hex to get a "printable"
//      character.
//
//  - 	uu_decode_(...);
//      Should be simple to figure out what little sweety is doing ....
//
// ---- En/Decoding according to base64 (documented in RFC1521, ch. 5.2) encoding format.
//  - 	b64_encode();
//  - 	b64_decode();
//      Step through memory and call coder functions:
//
//  - 	b64_encode_(...);
//      Coding sheme is the same as uucode but the gained 6bit numbers are applied to
//      an encoding table as indices (B64_EncodingTable in .C file) -> coded characters.
//
//  - 	b64_decode_(...);
//      Reverse encoding by going the other way round (uses an inverse list for the coding
//      table).
//
//  - 	checkB64(char c);
//      Check if the character is "base64".
//
// ---- En/Decoding according to quoted-printable (documented in RFC1521, ch. 5.1)
//      encoding format.
//  - 	qp_encode();
//  - 	qp_decode();
//      Step through memory and call coder functions:
//
//  - 	qp_encode_(...);
//      Encode according to quoted-printable rules (-> see RFC1521, ch. 5.1).
//
//  - 	qp_decode_(...);
//      Back to the roots ...
//
//  - 	charQPText(int c);
//      Check character c for QP compliance (ASCII 33-60,62-126 incl.)
//   
//  - 	resizeBuffer(char *t, long s, long e);
//      Change size of character array (allocate new memory area -> copy -> delete old).
//
//</class> 

class CoDec {
public:
  enum CoDec_Const {
    ENCODE,
      UUENCODE,
      B64ENCODE,
      QPENCODE,
    DECODE,
      UUDECODE,
      B64DECODE,
      QPDECODE,
    CODEC_CONST_COUNT,
    MAX_BUFFER=0x10000
  };

  CoDec(int m = UUENCODE, ProgressBase* p = nil, float i = 0.0);
  CoDec(const char* t, long l = -1, int m = UUENCODE, ProgressBase* p = nil, float i = 0.0); 
  ~CoDec();

  // Data insert.
  void setBuffer(const char* t, long l = -1);
  void setMethod(int m = UUENCODE) { encoding_method_ = m; }

  // Data callbacks.
  char* getText(int m = -1);

  // <<, >> operators for streams.
  friend istream& operator >> (istream&, CoDec&);
  friend ostream& operator << (ostream&, const CoDec&);

  // Table of encoding names.
  static char* EncodingType[CoDec::CODEC_CONST_COUNT];
  
private:
  // Select the proper coding method.
  void codeBuffer();

  // The coding functions.
  // En/Decoding in uuen/decode format.
  int uu_encode();
  int uu_decode();
  int uu_encode_(const unsigned char* in, unsigned char* outbuf);
  int uu_decode_(const unsigned char* in, unsigned char* outbuf);

  // En/Decoding the base64 format.
  int b64_encode();
  int b64_decode();
  int b64_encode_(const unsigned char* in, unsigned char* outbuf);
  int b64_decode_(const unsigned char* in, unsigned char* outbuf);
  int checkB64(char c);

  // Generate quoted-printable format.
  int qp_encode();
  int qp_decode();
  int qp_encode_(const unsigned char* c, unsigned char*& ptr);
  int qp_decode_(unsigned char*& c, unsigned char*& ptr);
  int charQPText(int c);


  // Create new and larger (or smaller) chunk of mem.
  long resizeBuffer(char* t, long s, long e);

  // Clear and/or delete "home" allocated buffers.
  void clearBuffers(void) {}

  // Two representations for the object.
  // (Recomended only for small objects).
  unsigned char* clear_;
  unsigned char* code_;
  // Actually used space.
  long clear_len_;
  long code_len_;
  // Allocated space (less then zero means space was allocated by user).
  long clear_alloc_;
  long code_alloc_;

  // Two streams.
  // (Recomended for big objects --> >>500kBytes).
  char buffer_[MAX_BUFFER];
  long buffer_len_;
  istream* strIn_;
  ostream* strOut_;

  // Method to use.
  int encoding_method_;

  // Already encoded ?
  int is_encoded_;

  // Show progress.
  ProgressBase* progress_;
  float prg_start_;
  float prg_inc_;

  // Padding character (to fill up non tripple end sequences)
  static const char B64_PaddingChar;
  // base64 encoding table.
  static const char* B64_EncodingTable;
  // base64 decoding table (built by constructor only once => static).
  static char B64_DecodingTable[128];

  // Number of steps the progress indicator should take.
  static const int PRGIND_STEP;
};

// Check if the character is within the valid text chars for quoted printable.
inline int CoDec::charQPText(int c) {
  return ((c>=33 && c<=60) || 
	  (c>=62 && c<=126) || c=='\n');
}

// "Streamy" friends of mine ;->.
istream& operator >> (istream&, CoDec&);
ostream& operator << (ostream&, const CoDec&);

#endif /* hg_path_codec_h */
