#ifndef UNLZW_H
#define UNLZW_H

#include <stdio.h>

class Pipe {
  struct chunk {
    chunk* next;
  };
public:
  Pipe();
  ~Pipe();
  virtual void write(const void*,size_t);
  void put(char c) { if(wsize==0) enlarge(); *wp++=c; --wsize; }
  virtual int read(void*,size_t);
  int get() { return rsize==0 && !next_chunk()?EOF:(--rsize,*rp++); }
  int lookc() { return rsize==0 && !next_chunk()?EOF:*rp; }
  void reset();
  virtual size_t size() const;
private:
  Pipe(const Pipe&);
  Pipe& operator = (const Pipe&);
  void enlarge();
  bool next_chunk();
  chunk* chunks;
  chunk* wchunk;
  unsigned char* wp;
  int wsize;
  unsigned char* rp;
  int rsize;
};

#ifndef IMPL
#ifdef POWERUP

extern "C" {
    extern const char *(*do_unlzw)(Pipe* in, Pipe* out, const char *cmd);
}

inline const char *unlzw(Pipe& in, Pipe& out, const char *cmd) {
    return do_unlzw(&in, &out, cmd);
}

#else

extern void *unlzwBase;

#define do_unlzw(in, out, cmd) \
({                                                              \
   Pipe* _v1 = (in);                                            \
   Pipe* _v2 = (out);                                           \
   const char* _v3 = (cmd);                                     \
   {                                                            \
      register void *const _bn __asm("a6") = unlzwBase;         \
      register const char *_re __asm("d0");                     \
      register Pipe* _n1 __asm("a0") = _v1;                     \
      register Pipe* _n2 __asm("a1") = _v2;                     \
      register const char* _n3 __asm("a2") = _v3;               \
      __asm volatile ("jsr a6@(-30:W)"                          \
      : "=r" (_re)                                              \
      : "r"(_bn), "r"(_n1), "r"(_n2), "r"(_n3)                  \
      : "d0", "d1", "a0", "a1", "fp0", "fp1", "cc", "memory");  \
      _re;                                                      \
   }                                                            \
})

inline const char *unlzw(Pipe& in, Pipe& out, const char *cmd) {
    if(unlzwBase)
	return do_unlzw(&in, &out, cmd);
    else
	return "No LZW decompression module.";
}


#endif
#endif

#endif

