Re: [AD] implementing seek |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
- To: "Coordination of admins/developers of the game programming library Allegro" <alleg-developers@xxxxxxxxxx>
- Subject: Re: [AD] implementing seek
- From: Matthew Leverton <meffer@xxxxxxxxxx>
- Date: Wed, 7 Apr 2010 19:02:56 -0500
On Wed, Apr 7, 2010 at 5:31 PM, Peter Wang <novalazy@xxxxxxxxxx> wrote:
> I suppose there are three choices:
>
> 1. leave the position whereever it ends up
> 2. return to the start of the slice
> 3. skip past the slice
>
> Only (3) can be implemented when the stream is not backwards-seekable,
> and it seems to me like the most useful behaviour anyway.
>
I agree.
Attached is a simple implementation of it as a user program for
demonstration purposes.
Should a splice be able to work concurrently with a random-access
parent? Or can two splices be open at the same time? In order to do
so, it would have to implicitly seek before and after every
read/write.
An aside: Can you query a file interface to determine what it
supports? (Random access, write past end of file, etc)
My proposal is that some form of this is added to the core I/O
routines (not an addon). And subsequently, anybody who wants to treat
a sub part of a file as a single entity to a loader / saver function
must explicitly set up a splice.
~
The output of example loading a text file with the letters a-z:
First character in real file: a
splice is opened with length 3
Read 3 characters, but tried 10000: bcd
EOF? yes
EOF after fseek(0)? no
Next character: b
splice is closed
Next character in real file is: e
Splicing length 10
Splicing the splice with length 2
Read 2 characters, but tried 10000: fg
Inner splice is closed
Next character in first splice is: h
Outer splice is closed
Next character in real file is: p
--
Matthew Leverton
#include <stdio.h>
#include <allegro5/allegro.h>
typedef struct ALLEGRO_FILE_SPLICE ALLEGRO_FILE_SPLICE;
struct ALLEGRO_FILE_SPLICE {
ALLEGRO_FILE file; /* must be first */
ALLEGRO_FILE *parent;
bool eof;
int64_t origin, size, pos;
};
static void splice_fclose(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
al_fseek(s->parent, s->origin + s->size, ALLEGRO_SEEK_SET);
free(fp);
}
static size_t splice_fread(ALLEGRO_FILE *fp, void *ptr, size_t size)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)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 splice_fwrite(ALLEGRO_FILE *fp, const void *ptr, size_t size)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
size_t n = 0;
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 splice_fflush(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
return al_fflush(s->parent);
}
static int64_t splice_ftell(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
return s->pos;
}
static bool splice_fseek(ALLEGRO_FILE *fp, int64_t offset,
int whence)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)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;
}
if (ppos < s->origin || ppos > s->origin + s->size) {
return false;
}
if (!al_fseek(s->parent, ppos, ALLEGRO_SEEK_SET)) {
return false;
}
s->pos = ppos - s->origin;
s->eof = (s->pos >= s->size);
return true;
}
static bool splice_feof(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
return s->eof;
}
static bool splice_ferror(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
return al_ferror(s->parent);
}
static int splice_fungetc(ALLEGRO_FILE *fp, int c)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
/* TODO ? */
return c;
}
static off_t splice_fsize(ALLEGRO_FILE *fp)
{
ALLEGRO_FILE_SPLICE *s = (ALLEGRO_FILE_SPLICE *)fp;
return s->size;
}
static struct ALLEGRO_FILE_INTERFACE splice_vtable = {
NULL, /* open */
splice_fclose,
splice_fread,
splice_fwrite,
splice_fflush,
splice_ftell,
splice_fseek,
splice_feof,
splice_ferror,
splice_fungetc,
splice_fsize
};
ALLEGRO_FILE *al_fopen_splice(ALLEGRO_FILE *fh, size_t size)
{
ALLEGRO_FILE_SPLICE *s = malloc(sizeof(ALLEGRO_FILE_SPLICE));
memset(s, 0, sizeof(*s));
s->file.vtable = &splice_vtable;
s->parent = fh;
s->pos = 0;
s->origin = al_ftell(fh);
s->size = size;
return (ALLEGRO_FILE *)s;
}
int main()
{
ALLEGRO_FILE *f1, *f2, *f3;
char buffer[100];
size_t n;
al_init();
f1 = al_fopen("foo.txt", "rb"); // abcdefghijklmnopqrstuvwxyz
printf("First character in real file: %c\n", al_fgetc(f1));
printf("splice is opened with length 3\n");
f2 = al_fopen_splice(f1, 3);
n = al_fread(f2, buffer, 10000);
buffer[n] = 0;
printf("Read %d characters, but tried 10000: %s\n", n, buffer);
printf("EOF? %s\n", al_feof(f2) ? "yes" : "no");
al_fseek(f2, 0, SEEK_SET);
printf("EOF after fseek(0)? %s\n", al_feof(f2) ? "yes" : "no");
printf("Next character: %c\n", al_fgetc(f1));
al_fclose(f2);
printf("splice is closed\n");
printf("Next character in real file is: %c\n", al_fgetc(f1));
f2 = al_fopen_splice(f1, 10);
f3 = al_fopen_splice(f2, 2);
printf("Splicing length 10\n");
printf("Splicing the splice with length 2\n");
n = al_fread(f3, buffer, 10000);
buffer[n] = 0;
printf("Read %d characters, but tried 10000: %s\n", n, buffer);
al_fclose(f3);
printf("Inner splice is closed\n");
printf("Next character in first splice is: %c\n", al_fgetc(f1));
al_fclose(f2);
printf("Outer splice is closed\n");
printf("Next character in real file is: %c\n", al_fgetc(f1));
al_fclose(f1);
return 0;
}