Re: [AD] implementing seek

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


On Wed, Apr 7, 2010 at 11:43 PM, Matthew Leverton <meffer@xxxxxxxxxx> wrote:
> fp = al_fopen_slice(fp, 0); // unbounded, parent size is not considered
> fp = al_fopen_slice(fp, 1 .. UINT_MAX - 1); // bounded
> fp = al_fopen_slice(fp, UINT_MAX); // unbounded, parent size is taken
> into consideration
>
Attached is an updated version that is implemented as above.

However, I dislike magic numbers, so maybe it's just better like:

al_fopen_slice(fp, length, bounded);

Examples:
* al_fopen_slice(fp, 0, true);
All reads and writes would fail. The slice is empty and cannot be
written past the end bounds.

* al_fopen_slice(fp, 0, false);
Can write as far as you want. SEEK_END will initially be 0.

* al_fopen_slice(fp, al_fsize(fp), true);
Can read and write up to the end of the original file.

* al_fopen_slice(fp, al_fsize(fp), false);
Can write as far as you want. SEEK_END will initially be the end of
the parent file.

When closing, the parent stream would be positioned to the end of the
slice, which would be the LARGER value of the second parameter or
wherever the slice last wrote.

UINT_MAX would have no special meaning, and in fact, would create a
huge file if used.

--
Matthew Leverton
#include <stdio.h>
#include <allegro5/allegro.h>

typedef struct ALLEGRO_FILE_SLICE ALLEGRO_FILE_SLICE;
struct ALLEGRO_FILE_SLICE {
   ALLEGRO_FILE file;   /* must be first */
   
   ALLEGRO_FILE *parent;

   bool eof, boundless;
   int64_t origin, size, pos;
   
};

static void slice_fclose(ALLEGRO_FILE *fp)
{
   ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
	 al_fseek(s->parent, s->origin + s->size, ALLEGRO_SEEK_SET);
   free(fp);
}

static size_t slice_fread(ALLEGRO_FILE *fp, void *ptr, size_t size)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
	 size_t n  = 0;
	 
	 if (!s->eof) { 
	 	  if (size + s->pos > s->size) {
	 	     size = s->size - s->pos;
	 	  }
	 
	 	  n = al_fread(s->parent, ptr, size);
	 	  s->pos += n;
	 	  if (s->pos >= s->size) {
	 	     s->eof = true;
	 	  }
   }
	 
   return n;
}

static size_t slice_fwrite(ALLEGRO_FILE *fp, const void *ptr, size_t size)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
	 size_t n = 0;
	 
	 if (s->boundless) {
      n = al_fwrite(s->parent, ptr, size);
      s->pos += n;
      if (s->pos > s->size) {
         s->size = s->pos;
         s->eof = true;
      }
   }
	 else if (!s->eof) { 
	 	  if (size + s->pos > s->size) {
	 	     size = s->size - s->pos;
	 	  }
	 
	 	  n = al_fwrite(s->parent, ptr, size);
	 	  s->pos += n;
	 	  if (s->pos >= s->size) {
	 	     s->eof = true;
	 	  }
   }
   
   return n;
}

static bool slice_fflush(ALLEGRO_FILE *fp)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;

   return al_fflush(s->parent);
}

static int64_t slice_ftell(ALLEGRO_FILE *fp)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
   return s->pos;
}

static bool slice_fseek(ALLEGRO_FILE *fp, int64_t offset,
   int whence)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
	 int64_t ppos = -1;
	 
	 if (whence == ALLEGRO_SEEK_SET) {
      ppos = s->origin + offset;
	 }
	 else if (whence == ALLEGRO_SEEK_CUR) {
      ppos = s->origin + s->pos + offset;
	 }
	 else if (whence == ALLEGRO_SEEK_END) {
	    ppos = s->origin + s->size + offset;
	 }
	 
	 /* never allowed to seek before the beginning of the slice */
	 if (ppos < s->origin) {
      return false;
   }
   
   /* not allowed to seek past the end of a bounded slice */
   if (!s->boundless && ppos > s->origin + s->size) {
      return false;
   }
	 	
   /* try to seek via the parent */
	 if (!al_fseek(s->parent, ppos, ALLEGRO_SEEK_SET)) {
      return false;
   }
      
   /* update our relative position */
   s->pos = ppos - s->origin;
	 s->eof = (s->pos >= s->size);
	 
	 /* update the size if moved past it (unbounded slices) */
	 if (s->pos > s->size) {
      ALLEGRO_ASSERT(s->boundless);
      s->size = s->pos;
   }   
	 
   return true;
}

static bool slice_feof(ALLEGRO_FILE *fp)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
   return s->eof;
}

static bool slice_ferror(ALLEGRO_FILE *fp)
{
   ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
   return al_ferror(s->parent);
}

static int slice_fungetc(ALLEGRO_FILE *fp, int c)
{
	 ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
	 /* TODO ? */
   return c;
}

static off_t slice_fsize(ALLEGRO_FILE *fp)
{
   ALLEGRO_FILE_SLICE *s = (ALLEGRO_FILE_SLICE *)fp;
   return s->size;
}

static struct ALLEGRO_FILE_INTERFACE slice_vtable = {
   NULL,    /* open */
   slice_fclose,
   slice_fread,
   slice_fwrite,
   slice_fflush,
   slice_ftell,
   slice_fseek,
   slice_feof,
   slice_ferror,
   slice_fungetc,
   slice_fsize
};

ALLEGRO_FILE *al_fopen_slice(ALLEGRO_FILE *fh, size_t size)
{
   ALLEGRO_FILE_SLICE *s = malloc(sizeof(ALLEGRO_FILE_SLICE));
	
   memset(s, 0, sizeof(*s));	
	
   s->file.vtable = &slice_vtable;
   s->parent = fh;   
   
   s->pos = 0;
   s->origin = al_ftell(fh); 			
   
   if (size == 0) {
      s->size = 0;
      s->boundless = true;
   }
   else if (size == UINT_MAX) {
      s->size = al_fsize(fh) - s->origin;
      s->boundless = true;
   }
   else {
      s->size = size;
      s->boundless = false;
   }
   	
	 return (ALLEGRO_FILE *)s;
}

int main()
{
	ALLEGRO_FILE *f1, *f2, *f3;

	size_t n;
	al_init();
		
	f1 = al_fopen("tmp1.txt", "wb");	
	al_fputs(f1, "0123456789_");
	al_fseek(f1, 0, ALLEGRO_SEEK_SET);	
	f2 = al_fopen_slice(f1, UINT_MAX);
	al_fseek(f2, 0, ALLEGRO_SEEK_END);	
	al_fputc(f2, 'X');
	al_fclose(f2);	
	al_fputc(f1, '*');	
	al_fclose(f1);
	// 0123456789_X*
	
	f1 = al_fopen("tmp2.txt", "wb");	
	al_fputs(f1, "0123456789_");
	al_fseek(f1, 0, ALLEGRO_SEEK_SET);	
	f2 = al_fopen_slice(f1, 0);
	al_fseek(f2, 0, ALLEGRO_SEEK_END);	
	al_fputc(f2, 'X');
	al_fclose(f2);
	al_fputc(f1, '*');
	al_fclose(f1);
	// X*23456789_
	
	
	return 0;
}


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/