Some fixes by MorphOS coders.
[tangerine.git] / workbench / libs / iffparse / pushchunk.c
blobe1aa555180173de58cbfb7911693d62fed470c33
1 /*
2 Copyright © 1995-2004, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include "iffparse_intern.h"
8 /*****************************************************************************
10 NAME */
11 #include <proto/iffparse.h>
13 AROS_LH4(LONG, PushChunk,
15 /* SYNOPSIS */
16 AROS_LHA(struct IFFHandle *, iff, A0),
17 AROS_LHA(LONG , type, D0),
18 AROS_LHA(LONG , id, D1),
19 AROS_LHA(LONG , size, D2),
21 /* LOCATION */
22 struct Library *, IFFParseBase, 14, IFFParse)
24 /* FUNCTION
25 Pushes a new context node onto the context stack. Usually used in write mode.
26 In write mode the contextnode will be pushed with the given parameters.
27 In Read mode the type, id and size will be read from the installed stream.
28 Note that IFFSIZE_UNKNOW can be given for size in write mode. In that case,
29 the size of will not be known until you do a PopChunk(). PopChunk()
30 will then seek back in the stream and write the correct size.
33 INPUTS
34 iff - pointer to IFFHandle struct.
35 type - chunk type specifier.
36 id - chunk identifier.
37 size - size of the new chunk. May be IFFSIZE_UNKNOWN.
39 RESULT
40 error - 0 if successfull, IFFERR_#? otherwize.
42 NOTES
44 EXAMPLE
46 BUGS
48 SEE ALSO
49 PopChunk()
51 INTERNALS
52 We do different things for Read and Write streams (obviosly enough ;->)
54 Write: Write the supplied id, size and evt type into the stream.
56 Read: Get a chunk from disk
59 For Write mode there are som problems with unknown chunk size and
60 non-random-seekable streams:
61 4. situations:
63 SIZE KNOWN && RSEEK - Just write the whole header.
64 SIZE KNOWN && !RSEEK - Write whole header. No RSEEK does not matter, since
65 we don't have to seek back to write size in PopChunk
67 SIZE UNKNOWN && RSEEK - Write whole header. Write size too, just to seek pass it,
68 even if the size value might be meaningless. We will
69 seek back and insert the correct size later.
71 SIZE UNKNOWN && !RSEEK - Here is where the trouble starts. We can not seek back
72 and insert the correct size later, which means that we MUST
73 buffer the contents of the chunk, and don't write ANYTHING to
74 the stream until we know its size.
76 We preserve the old StreamHandler, and inserts a new one
77 that buffers all writes into memory.
79 *****************************************************************************/
81 AROS_LIBFUNC_INIT
82 AROS_LIBBASE_EXT_DECL(struct Library *,IFFParseBase)
84 LONG err;
86 LONG byteswritten;
88 LONG scan = 0;
90 DEBUG_PUSHCHUNK(dprintf("PushChunk: iff 0x%lx type 0x%08lx (%c%c%c%c) id 0x%08lx (%c%c%c%c) size %d\n",
91 iff, type, dmkid(type), id, dmkid(id), size));
93 if (iff->iff_Flags & IFFF_WRITE)
95 struct ContextNode *pcn;
96 LONG ptype=0;
97 BOOL newfile=FALSE;
99 if((pcn = (struct ContextNode *)CurrentChunk(iff)) != NULL)
101 ptype = pcn->cn_Type;
103 else
105 if(iff->iff_Flags & IFFF_NEWFILE)
107 newfile = TRUE;
108 iff->iff_Flags &= ~IFFF_NEWFILE;
110 else
112 return(IFFERR_EOF);
116 /* do some syntax checks (cyfm: added 2003/03/01 to "fix"/handle some broken apps) */
118 if(!GoodID(id))
120 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid id -> IFFERR_SYNTAX\n"
123 return(IFFERR_SYNTAX);
126 else if(newfile == TRUE)
128 /* check if first chunk is either FORM, LIST or CAT */
130 if( id != ID_FORM && id != ID_LIST && id != ID_CAT)
132 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid first chunk (neither FORM, nor LIST, nor CAT -> IFFERR_NOTIFF\n"
135 return(IFFERR_NOTIFF);
138 else if(id == ID_PROP)
140 /* make sure PROP containing context is a LIST */
142 if(pcn->cn_ID != ID_LIST)
144 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid ID in PROP context -> IFFERR_SYNTAX\n"
147 return(IFFERR_SYNTAX);
150 else if(id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
152 /* check for valid subtype if we found a generic id */
154 if(!GoodType(type))
156 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid type for generic id -> IFFERR_NOTIFF\n"
159 return(IFFERR_NOTIFF);
162 else
164 /* if we found a non generic id, make sure the containing context is at
165 least PROP or FORM */
167 if((pcn->cn_ID != ID_FORM) && (pcn->cn_ID != ID_PROP))
169 DEBUG_PUSHCHUNK(dprintf("PushChunk: containing context id 0x%08lx (%c%c%c%c) for generic id is neither PROP nor FORM -> IFFERR_SYNTAX\n"
170 ,pcn->cn_ID,dmkid(pcn->cn_ID)));
172 return(IFFERR_SYNTAX);
176 /* we passed the syntax test ! */
178 /* Do we have a problem - situation ? */
179 if ( (size == IFFSIZE_UNKNOWN)
180 && (!(iff->iff_Flags & IFFF_RSEEK))
184 /* Initialize the buffering streamhandler */
185 err = InitBufferedStream(iff, IPB(IFFParseBase));
186 if (err) return (err);
189 byteswritten = WriteStreamLong
191 iff,
192 &id,
193 IPB(IFFParseBase)
196 /* IFFFERR_ .. ? */
197 if (byteswritten < 0) return (byteswritten);
199 /* The chunk size will be written during PopChunk too, but we write
200 here to seek past it */
202 byteswritten = WriteStreamLong
204 iff,
205 &size,
206 IPB(IFFParseBase)
208 /* IFFERR_... ? */
209 if (byteswritten < 0) return (byteswritten);
211 /* If a composite type, then write whole type */
213 ( id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
215 byteswritten = WriteStreamLong
217 iff,
218 &type,
219 IPB(IFFParseBase)
222 if (byteswritten < 0) return (byteswritten);
224 scan = sizeof(ULONG);
226 } /* End of composite */
228 err = PushContextNode
230 iff,
231 type,
233 size,
234 scan,
235 IPB(IFFParseBase)
238 else /* Read or write mode */
240 /* Read mode. Read the chunk header from stream and put a new contextnode into the stack */
241 err = GetChunkHeader(iff, IPB(IFFParseBase));
242 } /* End of Write or Read */
244 return (err);
246 AROS_LIBFUNC_EXIT
247 } /* PushChunk */