// -*- C++ -*-
// --------------------------------------------------------------------
// PDF file parser
// --------------------------------------------------------------------
/*

    This file is part of the extensible drawing editor Ipe.
    Copyright (C) 1993-2004  Otfried Cheong

    Ipe 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.

    As a special exception, you have permission to link Ipe with the
    CGAL library and distribute executables, as long as you follow the
    requirements of the Gnu General Public License in regard to all of
    the software in the executable aside from CGAL.

    Ipe 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 Ipe; if not, you can find it at
    "http://www.gnu.org/copyleft/gpl.html", or write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#ifndef IPEPDFPARSER_H
#define IPEPDFPARSER_H

#include "ipebase.h"

// --------------------------------------------------------------------

class IpePdfNull;
class IpePdfBool;
class IpePdfNumber;
class IpePdfString;
class IpePdfName;
class IpePdfRef;
class IpePdfArray;
class IpePdfDict;

class IpePdfFile;

class IPE_EXPORT IpePdfObj {
public:
  virtual ~IpePdfObj() = 0;
  virtual const IpePdfNull *Null() const;
  virtual const IpePdfBool *Bool() const;
  virtual const IpePdfNumber *Number() const;
  virtual const IpePdfString *String() const;
  virtual const IpePdfName *Name() const;
  virtual const IpePdfRef *Ref() const;
  virtual const IpePdfArray *Array() const;
  virtual const IpePdfDict *Dict() const;
  virtual void Write(IpeStream &stream) const = 0;
  IpeString Repr() const;
};

class IPE_EXPORT IpePdfNull : public IpePdfObj {
public:
  explicit IpePdfNull() { /* nothing */ }
  virtual const IpePdfNull *Null() const;
  virtual void Write(IpeStream &stream) const;
};

class IPE_EXPORT IpePdfBool : public IpePdfObj {
public:
  explicit IpePdfBool(bool val) : iValue(val) { /* nothing */ }
  virtual const IpePdfBool *Bool() const;
  virtual void Write(IpeStream &stream) const;
  inline bool Value() const { return iValue; }
private:
  bool iValue;
};

class IPE_EXPORT IpePdfNumber : public IpePdfObj {
public:
  explicit IpePdfNumber(double val) : iValue(val) { /* nothing */ }
  virtual const IpePdfNumber *Number() const;
  virtual void Write(IpeStream &stream) const;
  inline double Value() const { return iValue; }
private:
  double iValue;
};

class IPE_EXPORT IpePdfString : public IpePdfObj {
public:
  explicit IpePdfString(const IpeString &val) : iValue(val) { /* nothing */ }
  virtual const IpePdfString *String() const;
  virtual void Write(IpeStream &stream) const;
  inline IpeString Value() const { return iValue; }
private:
  IpeString iValue;
};

class IPE_EXPORT IpePdfName : public IpePdfObj {
public:
  explicit IpePdfName(const IpeString &val) : iValue(val) { /* nothing */ }
  virtual const IpePdfName *Name() const;
  virtual void Write(IpeStream &stream) const;
  inline IpeString Value() const { return iValue; }
private:
  IpeString iValue;
};

class IPE_EXPORT IpePdfRef : public IpePdfObj {
public:
  explicit IpePdfRef(int val) : iValue(val) { /* nothing */ }
  virtual const IpePdfRef *Ref() const;
  virtual void Write(IpeStream &stream) const;
  inline int Value() const { return iValue; }
private:
  int iValue;
};

class IPE_EXPORT IpePdfArray : public IpePdfObj {
public:
  explicit IpePdfArray() { /* nothing */ }
  ~IpePdfArray();
  virtual const IpePdfArray *Array() const;
  virtual void Write(IpeStream &stream) const;
  void Append(const IpePdfObj *);
  inline int Count() const { return iObjects.size(); }
  const IpePdfObj *Obj(int index, const IpePdfFile *file) const;
private:
  std::vector<const IpePdfObj *> iObjects;
};

class IPE_EXPORT IpePdfDict : public IpePdfObj {
public:
  explicit IpePdfDict() { /* nothing */ }
  ~IpePdfDict();
  virtual const IpePdfDict *Dict() const;
  virtual void Write(IpeStream &stream) const;
  void SetStream(const IpeBuffer &stream);
  void Add(IpeString key, const IpePdfObj *obj);
  const IpePdfObj *Get(IpeString key, const IpePdfFile *file) const;
  inline int Count() const { return iItems.size(); }
  inline IpeString Key(int index) const { return iItems[index].iKey; }
  inline IpeBuffer Stream() const { return iStream; }
  bool Deflated() const;
  // IpeBuffer Inflate() const;
private:
  struct Item {
    IpeString iKey;
    const IpePdfObj *iVal;
  };
  std::vector<Item> iItems;
  IpeBuffer iStream;
};

// --------------------------------------------------------------------

//! A PDF lexical token.
struct IpePdfToken {
  //! The various types of tokens.
  enum TToken { EErr, EOp, EName, ENumber, EString, ETrue, EFalse, ENull,
		EArrayBg, EArrayEnd, EDictBg, EDictEnd };
  //! The type of this token.
  TToken iType;
  //! The string representing this token.
  IpeString iString;
};

class IPE_EXPORT IpePdfParser {
public:
  IpePdfParser(IpeDataSource &source);

  inline void GetChar() { iCh = iSource.GetChar(); ++iPos; }
  inline bool Eos() const { return (iCh == EOF); }
  inline IpePdfToken Token() const { return iTok; }

  void GetToken();
  IpePdfObj *GetObject();
  IpePdfObj *GetObjectDef();
  IpePdfDict *GetTrailer();
  void SkipXRef();

 private:
  void SkipWhiteSpace();
  IpePdfArray *MakeArray();
  IpePdfDict *MakeDict();

private:
  IpeDataSource &iSource;
  int iPos;
  int iCh;
  IpePdfToken iTok;
};

class IPE_EXPORT IpePdfFile {
public:
  IpePdfFile();
  ~IpePdfFile();
  bool Parse(IpeDataSource &source);
  const IpePdfObj *Object(int num) const;
  const IpePdfDict *Catalog() const;
  const IpePdfDict *Page() const;
private:
  std::map<int, const IpePdfObj *> iObjects;
  const IpePdfDict *iTrailer;
};

// --------------------------------------------------------------------
#endif
