text: /*  _______         ____    __         ___    ___
   * \    _  \       \    /  \  /       \   \  /   /       '   '  '
   *  |  | \  \       |  |    ||         |   \/   |         .      .
   *  |  |  |  |      |  |    ||         ||\  /|  |
   *  |  |  |  |      |  |    ||         || \/ |  |         '  '  '
   *  |  |  |  |      |  |    ||         ||    |  |         .      .
   *  |  |_/  /        \  \__//          ||    |  |
   * /_______/ynamic    \____/niversal  /__\  /____\usic   /|  .  . ibliotheque
   *                                                      /  \
   *                                                     / .  \
   * dumbfile.c - Hookable, strictly sequential         / / \  \
   *              file input functions.                | <  /   \_
   *                                                   |  \/ /\   /
   * By entheh.                                         \_  /  > /
   *                                                      | \ / /
   *                                                      |  ' /
   *                                                       \__/
   */
  
  #include <stdlib.h>
  
  #include "dumb.h"
  
  
  
  static const DUMBFILE_SYSTEM *the_dfs = NULL;
  
  
  
  void DUMBEXPORT register_dumbfile_system(const DUMBFILE_SYSTEM *dfs)
  {
  	ASSERT(dfs);
  	ASSERT(dfs->open);
  	ASSERT(dfs->getc);
  	ASSERT(dfs->close);
  	the_dfs = dfs;
  }
  
  
  
  struct DUMBFILE
  {
  	const DUMBFILE_SYSTEM *dfs;
  	void *file;
  	int32 pos;
  };
  
  
  
  DUMBFILE *DUMBEXPORT dumbfile_open(const char *filename)
  {
  	DUMBFILE *f;
  
  	ASSERT(the_dfs);
  
  	f = malloc(sizeof(*f));
  
  	if (!f)
  		return NULL;
  
  	f->dfs = the_dfs;
  
  	f->file = (*the_dfs->open)(filename);
  
  	if (!f->file) {
  		free(f);
  		return NULL;
  	}
  
  	f->pos = 0;
  
  	return f;
  }
  
  
  
  DUMBFILE *DUMBEXPORT dumbfile_open_ex(void *file, const DUMBFILE_SYSTEM *dfs)
  {
  	DUMBFILE *f;
  
  	ASSERT(dfs);
  	ASSERT(dfs->getc);
  	ASSERT(file);
  
  	f = malloc(sizeof(*f));
  
  	if (!f) {
  		if (dfs->close)
  			(*dfs->close)(file);
  		return NULL;
  	}
  
  	f->dfs = dfs;
  	f->file = file;
  
  	f->pos = 0;
  
  	return f;
  }
  
  
  
  int32 DUMBEXPORT dumbfile_pos(DUMBFILE *f)
  {
  	ASSERT(f);
  
  	return f->pos;
  }
  
  
  
  int DUMBEXPORT dumbfile_skip(DUMBFILE *f, int32 n)
  {
  	int rv;
  
  	ASSERT(f);
  	ASSERT(n >= 0);
  
  	if (f->pos < 0)
  		return -1;
  
  	f->pos += n;
  
  	if (f->dfs->skip) {
  		rv = (*f->dfs->skip)(f->file, n);
  		if (rv) {
  			f->pos = -1;
  			return rv;
  		}
  	} else {
  		while (n) {
  			rv = (*f->dfs->getc)(f->file);
  			if (rv < 0) {
  				f->pos = -1;
  				return rv;
  			}
  			n--;
  		}
  	}
  
  	return 0;
  }
  
  
  
  int DUMBEXPORT dumbfile_getc(DUMBFILE *f)
  {
  	int rv;
  
  	ASSERT(f);
  
  	if (f->pos < 0)
  		return -1;
  
  	rv = (*f->dfs->getc)(f->file);
  
  	if (rv < 0) {
  		f->pos = -1;
  		return rv;
  	}
  
  	f->pos++;
  
  	return rv;
  }
  
  
  
  int DUMBEXPORT dumbfile_igetw(DUMBFILE *f)
  {
  	int l, h;
  
  	ASSERT(f);
  
  	if (f->pos < 0)
  		return -1;
  
  	l = (*f->dfs->getc)(f->file);
  	if (l < 0) {
  		f->pos = -1;
  		return l;
  	}
  
  	h = (*f->dfs->getc)(f->file);
  	if (h < 0) {
  		f->pos = -1;
  		return h;
  	}
  
  	f->pos += 2;
  
  	return l | (h << 8);
  }
  
  
  
  int DUMBEXPORT dumbfile_mgetw(DUMBFILE *f)
  {
  	int l, h;
  
  	ASSERT(f);
  
  	if (f->pos < 0)
  		return -1;
  
  	h = (*f->dfs->getc)(f->file);
  	if (h < 0) {
  		f->pos = -1;
  		return h;
  	}
  
  	l = (*f->dfs->getc)(f->file);
  	if (l < 0) {
  		f->pos = -1;
  		return l;
  	}
  
  	f->pos += 2;
  
  	return l | (h << 8);
  }
  
  
  
  int32 DUMBEXPORT dumbfile_igetl(DUMBFILE *f)
  {
  	uint32 rv, b;
  
  	ASSERT(f);
  
  	if (f->pos < 0)
  		return -1;
  
  	rv = (*f->dfs->getc)(f->file);
  	if ((sint32)rv < 0) {
  		f->pos = -1;
  		return rv;
  	}
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b << 8;
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b << 16;
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b << 24;
  
  	f->pos += 4;
  
  	return rv;
  }
  
  
  
  int32 DUMBEXPORT dumbfile_mgetl(DUMBFILE *f)
  {
  	uint32 rv, b;
  
  	ASSERT(f);
  
  	if (f->pos < 0)
  		return -1;
  
  	rv = (*f->dfs->getc)(f->file);
  	if ((sint32)rv < 0) {
  		f->pos = -1;
  		return rv;
  	}
  	rv <<= 24;
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b << 16;
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b << 8;
  
  	b = (*f->dfs->getc)(f->file);
  	if ((sint32)b < 0) {
  		f->pos = -1;
  		return b;
  	}
  	rv |= b;
  
  	f->pos += 4;
  
  	return rv;
  }
  
  
  
  uint32 DUMBEXPORT dumbfile_cgetul(DUMBFILE *f)
  {
  	uint32 rv = 0;
  	int v;
  
  	do {
  		v = dumbfile_getc(f);
  
  		if (v < 0)
  			return v;
  
  		rv <<= 7;
  		rv |= v & 0x7F;
  	} while (v & 0x80);
  
  	return rv;
  }
  
  
  
  sint32 DUMBEXPORT dumbfile_cgetsl(DUMBFILE *f)
  {
  	uint32 rv = dumbfile_cgetul(f);
  
  	if (f->pos < 0)
  		return rv;
  
  	return (rv >> 1) | (rv << 31);
  }
  
  
  
  int32 DUMBEXPORT dumbfile_getnc(char *ptr, int32 n, DUMBFILE *f)
  {
  	int32 rv;
  
  	ASSERT(f);
  	ASSERT(n >= 0);
  
  	if (f->pos < 0)
  		return -1;
  
  	if (f->dfs->getnc) {
  		rv = (*f->dfs->getnc)(ptr, n, f->file);
  		if (rv < n) {
  			f->pos = -1;
  			return MAX(rv, 0);
  		}
  	} else {
  		for (rv = 0; rv < n; rv++) {
  			int c = (*f->dfs->getc)(f->file);
  			if (c < 0) {
  				f->pos = -1;
  				return rv;
  			}
  			*ptr++ = c;
  		}
  	}
  
  	f->pos += rv;
  
  	return rv;
  }
  
  
  
  int DUMBEXPORT dumbfile_error(DUMBFILE *f)
  {
  	ASSERT(f);
  
  	return f->pos < 0;
  }
  
  
  
  int DUMBEXPORT dumbfile_close(DUMBFILE *f)
  {
  	int rv;
  
  	ASSERT(f);
  
  	rv = f->pos < 0;
  
  	if (f->dfs->close)
  		(*f->dfs->close)(f->file);
  
  	free(f);
  
  	return rv;
  }
  