added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / libs / iffparse / pushchunk.c
blobf0abdae48ec130857fa9d2b15fbdac58f72b7552
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;
95 LONG ptype=0;
96 BOOL newfile=FALSE;
98 if((pcn = (struct ContextNode *)CurrentChunk(iff)) != NULL)
100 ptype = pcn->cn_Type;
102 else
104 if(iff->iff_Flags & IFFF_NEWFILE)
106 newfile = TRUE;
107 iff->iff_Flags &= ~IFFF_NEWFILE;
109 else
111 return(IFFERR_EOF);
115 /* do some syntax checks (cyfm: added 2003/03/01 to "fix"/handle some broken apps) */
117 if(!GoodID(id))
119 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid id -> IFFERR_SYNTAX\n"
122 return(IFFERR_SYNTAX);
125 else if(newfile == TRUE)
127 /* check if first chunk is either FORM, LIST or CAT */
129 if( id != ID_FORM && id != ID_LIST && id != ID_CAT)
131 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid first chunk (neither FORM, nor LIST, nor CAT -> IFFERR_NOTIFF\n"
134 return(IFFERR_NOTIFF);
137 else if(id == ID_PROP)
139 /* make sure PROP containing context is a LIST */
141 if(pcn->cn_ID != ID_LIST)
143 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid ID in PROP context -> IFFERR_SYNTAX\n"
146 return(IFFERR_SYNTAX);
149 else if(id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
151 /* check for valid subtype if we found a generic id */
153 if(!GoodType(type))
155 DEBUG_PUSHCHUNK(dprintf("PushChunk: invalid type for generic id -> IFFERR_NOTIFF\n"
158 return(IFFERR_NOTIFF);
161 else
163 /* if we found a non generic id, make sure the containing context is at
164 least PROP or FORM */
166 if((pcn->cn_ID != ID_FORM) && (pcn->cn_ID != ID_PROP))
168 DEBUG_PUSHCHUNK(dprintf("PushChunk: containing context id 0x%08lx (%c%c%c%c) for generic id is neither PROP nor FORM -> IFFERR_SYNTAX\n"
169 ,pcn->cn_ID,dmkid(pcn->cn_ID)));
171 return(IFFERR_SYNTAX);
175 /* we passed the syntax test ! */
177 /* Do we have a problem - situation ? */
178 if ( (size == IFFSIZE_UNKNOWN)
179 && (!(iff->iff_Flags & IFFF_RSEEK))
183 /* Initialize the buffering streamhandler */
184 err = InitBufferedStream(iff, IPB(IFFParseBase));
185 if (err) return (err);
188 byteswritten = WriteStreamLong
190 iff,
191 &id,
192 IPB(IFFParseBase)
195 /* IFFFERR_ .. ? */
196 if (byteswritten < 0) return (byteswritten);
198 /* The chunk size will be written during PopChunk too, but we write
199 here to seek past it */
201 byteswritten = WriteStreamLong
203 iff,
204 &size,
205 IPB(IFFParseBase)
207 /* IFFERR_... ? */
208 if (byteswritten < 0) return (byteswritten);
210 /* If a composite type, then write whole type */
212 ( id == ID_FORM || id == ID_LIST || id == ID_CAT || id == ID_PROP )
214 byteswritten = WriteStreamLong
216 iff,
217 &type,
218 IPB(IFFParseBase)
221 if (byteswritten < 0) return (byteswritten);
223 scan = sizeof(ULONG);
225 } /* End of composite */
227 err = PushContextNode
229 iff,
230 type,
232 size,
233 scan,
234 IPB(IFFParseBase)
237 else /* Read or write mode */
239 /* Read mode. Read the chunk header from stream and put a new contextnode into the stack */
240 err = GetChunkHeader(iff, IPB(IFFParseBase));
241 } /* End of Write or Read */
243 return (err);
245 AROS_LIBFUNC_EXIT
246 } /* PushChunk */