1
0
mirror of https://github.com/deadw00d/AROS.git synced 2025-12-06 21:40:57 +00:00
Files
AROS-v0/workbench/libs/iffparse/pushchunk.c
Matthias Rustler 6b5a534ce3 workbench: detabbed
2021-05-02 13:55:14 +02:00

239 lines
6.9 KiB
C

/*
Copyright (C) 1995-2016, The AROS Development Team. All rights reserved.
*/
#include "iffparse_intern.h"
/*****************************************************************************
NAME */
#include <proto/iffparse.h>
AROS_LH4(LONG, PushChunk,
/* SYNOPSIS */
AROS_LHA(struct IFFHandle *, iff, A0),
AROS_LHA(LONG , type, D0),
AROS_LHA(LONG , id, D1),
AROS_LHA(LONG , size, D2),
/* LOCATION */
struct Library *, IFFParseBase, 14, IFFParse)
/* FUNCTION
Pushes a new context node onto the context stack. Usually used in write mode.
In write mode the contextnode will be pushed with the given parameters.
In Read mode the type, id and size will be read from the installed stream.
Note that IFFSIZE_UNKNOW can be given for size in write mode. In that case,
the size of will not be known until you do a PopChunk(). PopChunk()
will then seek back in the stream and write the correct size.
INPUTS
iff - pointer to IFFHandle struct.
type - chunk type specifier.
id - chunk identifier.
size - size of the new chunk. May be IFFSIZE_UNKNOWN.
RESULT
error - 0 if successful, IFFERR_#? otherwise.
NOTES
EXAMPLE
BUGS
SEE ALSO
PopChunk()
INTERNALS
We do different things for Read and Write streams (obviosly enough ;->)
Write: Write the supplied id, size and evt type into the stream.
Read: Get a chunk from disk
For Write mode there are som problems with unknown chunk size and
non-random-seekable streams:
4. situations:
SIZE KNOWN && RSEEK - Just write the whole header.
SIZE KNOWN && !RSEEK - Write whole header. No RSEEK does not matter, since
we don't have to seek back to write size in PopChunk
SIZE UNKNOWN && RSEEK - Write whole header. Write size too, just to seek pass it,
even if the size value might be meaningless. We will
seek back and insert the correct size later.
SIZE UNKNOWN && !RSEEK - Here is where the trouble starts. We can not seek back
and insert the correct size later, which means that we MUST
buffer the contents of the chunk, and don't write ANYTHING to
the stream until we know its size.
We preserve the old StreamHandler, and inserts a new one
that buffers all writes into memory.
*****************************************************************************/
{
AROS_LIBFUNC_INIT
LONG err;
LONG byteswritten;
LONG scan = 0;
DEBUG_PUSHCHUNK(dprintf("PushChunk: iff 0x%lx type 0x%08lx (%c%c%c%c) id 0x%08lx (%c%c%c%c) size %d\n",
iff, type, dmkid(type), id, dmkid(id), size));
if (iff->iff_Flags & IFFF_WRITE)
{
struct ContextNode *pcn;
if((pcn = (struct ContextNode *)CurrentChunk(iff)) == NULL)
{
if(iff->iff_Flags & IFFF_NEWFILE)
{
iff->iff_Flags &= ~IFFF_NEWFILE;
}
else
{
return(IFFERR_EOF);
}
}
/* do some syntax checks (cyfm: added 2003/03/01 to "fix"/handle some broken apps) */
if(!GoodID(id))
{
DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid id -> IFFERR_SYNTAX\n"
));
return(IFFERR_SYNTAX);
}
else if(pcn == NULL)
{
/* check if first chunk is either FORM, LIST or CAT */
if( id != ID_FORM && id != ID_LIST && id != ID_CAT)
{
DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid first chunk (neither FORM, nor LIST, nor CAT -> IFFERR_NOTIFF\n"
));
return(IFFERR_NOTIFF);
}
}
else if(id == ID_PROP)
{
/* make sure PROP containing context is a LIST */
if(pcn->cn_ID != ID_LIST)
{
DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid ID in PROP context -> IFFERR_SYNTAX\n"
));
return(IFFERR_SYNTAX);
}
}
else if(id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
{
/* check for valid subtype if we found a generic id */
if(!GoodType(type))
{
DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid type for generic id -> IFFERR_NOTIFF\n"
));
return(IFFERR_NOTIFF);
}
}
else
{
/* if we found a non generic id, make sure the containing context is at
least PROP or FORM */
if((pcn->cn_ID != ID_FORM) && (pcn->cn_ID != ID_PROP))
{
DEBUG_PUSHCHUNK(dprintf("PushChunk: containing context id 0x%08lx (%c%c%c%c) for generic id is neither PROP nor FORM -> IFFERR_SYNTAX\n"
,pcn->cn_ID,dmkid(pcn->cn_ID)));
return(IFFERR_SYNTAX);
}
}
/* we passed the syntax test ! */
/* Do we have a problem - situation ? */
if ( (size == IFFSIZE_UNKNOWN)
&& (!(iff->iff_Flags & IFFF_RSEEK))
)
{
/* Initialize the buffering streamhandler */
err = InitBufferedStream(iff, IPB(IFFParseBase));
if (err) return (err);
}
byteswritten = WriteStreamLong
(
iff,
&id,
IPB(IFFParseBase)
);
/* IFFFERR_ .. ? */
if (byteswritten < 0) return (byteswritten);
/* The chunk size will be written during PopChunk too, but we write
here to seek past it */
byteswritten = WriteStreamLong
(
iff,
&size,
IPB(IFFParseBase)
);
/* IFFERR_... ? */
if (byteswritten < 0) return (byteswritten);
/* If a composite type, then write whole type */
if
( id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
{
byteswritten = WriteStreamLong
(
iff,
&type,
IPB(IFFParseBase)
);
if (byteswritten < 0) return (byteswritten);
scan = sizeof(ULONG);
} /* End of composite */
err = PushContextNode
(
iff,
type,
id,
size,
scan,
IPB(IFFParseBase)
);
}
else /* Read or write mode */
{
/* Read mode. Read the chunk header from stream and put a new contextnode into the stack */
err = GetChunkHeader(iff, IPB(IFFParseBase));
} /* End of Write or Read */
return (err);
AROS_LIBFUNC_EXIT
} /* PushChunk */