Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / iffparse / pushchunk.c
blob466d20d8fd23e4e3e0680bf80ffb4e48bbbf0cf1
1 /*
2 Copyright © 1995-2007, 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
83 LONG err;
85 LONG byteswritten;
87 LONG scan = 0;
89 DEBUG_PUSHCHUNK(dprintf("PushChunk: iff 0x%lx type 0x%08lx (%c%c%c%c) id 0x%08lx (%c%c%c%c) size %d\n",
90 iff, type, dmkid(type), id, dmkid(id), size));
92 if (iff->iff_Flags & IFFF_WRITE)
94 struct ContextNode *pcn;
96 if((pcn = (struct ContextNode *)CurrentChunk(iff)) == NULL)
98 if(iff->iff_Flags & IFFF_NEWFILE)
100 iff->iff_Flags &= ~IFFF_NEWFILE;
102 else
104 return(IFFERR_EOF);
108 /* do some syntax checks (cyfm: added 2003/03/01 to "fix"/handle some broken apps) */
110 if(!GoodID(id))
112 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid id -> IFFERR_SYNTAX\n"
115 return(IFFERR_SYNTAX);
118 else if(pcn == NULL)
120 /* check if first chunk is either FORM, LIST or CAT */
122 if( id != ID_FORM && id != ID_LIST && id != ID_CAT)
124 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid first chunk (neither FORM, nor LIST, nor CAT -> IFFERR_NOTIFF\n"
127 return(IFFERR_NOTIFF);
130 else if(id == ID_PROP)
132 /* make sure PROP containing context is a LIST */
134 if(pcn->cn_ID != ID_LIST)
136 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid ID in PROP context -> IFFERR_SYNTAX\n"
139 return(IFFERR_SYNTAX);
142 else if(id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
144 /* check for valid subtype if we found a generic id */
146 if(!GoodType(type))
148 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid type for generic id -> IFFERR_NOTIFF\n"
151 return(IFFERR_NOTIFF);
154 else
156 /* if we found a non generic id, make sure the containing context is at
157 least PROP or FORM */
159 if((pcn->cn_ID != ID_FORM) && (pcn->cn_ID != ID_PROP))
161 DEBUG_PUSHCHUNK(dprintf("PushChunk: containing context id 0x%08lx (%c%c%c%c) for generic id is neither PROP nor FORM -> IFFERR_SYNTAX\n"
162 ,pcn->cn_ID,dmkid(pcn->cn_ID)));
164 return(IFFERR_SYNTAX);
168 /* we passed the syntax test ! */
170 /* Do we have a problem - situation ? */
171 if ( (size == IFFSIZE_UNKNOWN)
172 && (!(iff->iff_Flags & IFFF_RSEEK))
176 /* Initialize the buffering streamhandler */
177 err = InitBufferedStream(iff, IPB(IFFParseBase));
178 if (err) return (err);
181 byteswritten = WriteStreamLong
183 iff,
184 &id,
185 IPB(IFFParseBase)
188 /* IFFFERR_ .. ? */
189 if (byteswritten < 0) return (byteswritten);
191 /* The chunk size will be written during PopChunk too, but we write
192 here to seek past it */
194 byteswritten = WriteStreamLong
196 iff,
197 &size,
198 IPB(IFFParseBase)
200 /* IFFERR_... ? */
201 if (byteswritten < 0) return (byteswritten);
203 /* If a composite type, then write whole type */
205 ( id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
207 byteswritten = WriteStreamLong
209 iff,
210 &type,
211 IPB(IFFParseBase)
214 if (byteswritten < 0) return (byteswritten);
216 scan = sizeof(ULONG);
218 } /* End of composite */
220 err = PushContextNode
222 iff,
223 type,
225 size,
226 scan,
227 IPB(IFFParseBase)
230 else /* Read or write mode */
232 /* Read mode. Read the chunk header from stream and put a new contextnode into the stack */
233 err = GetChunkHeader(iff, IPB(IFFParseBase));
234 } /* End of Write or Read */
236 return (err);
238 AROS_LIBFUNC_EXIT
239 } /* PushChunk */