Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / iffparse / parseiff.c
blob34b9c45df13de92d9973b86f2e64bb5c116c7d41
1 /*
2 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
8 #include "iffparse_intern.h"
10 #define SWAP_SCANEXIT 1
12 /*****************************************************************************
14 NAME */
15 #include <proto/iffparse.h>
17 AROS_LH2(LONG, ParseIFF,
19 /* SYNOPSIS */
20 AROS_LHA(struct IFFHandle *, iff, A0),
21 AROS_LHA(LONG , mode, D0),
23 /* LOCATION */
24 struct Library *, IFFParseBase, 7, IFFParse)
26 /* FUNCTION
27 This function is the parser itself. It has three control modes.
28 IFFPARSE_SCAN - the parser will go through the file invoking
29 entry and exit handlers on its way.
30 When it returns it might be for 3 different reasons:
32 - It invoked a Stop entry/exit handler ( Installed by StopChunk[s] or
33 StopOnExit )
35 - An error occured.
36 (return value will be negative.)
38 - The parser reached EOF and returns IFFERR_EOF.
40 IFFPARSE_STEP - The parser steps through the file, returning to the
41 user each time it enters (returns NULL) and each time it exits
42 (return (IFFERR_EOC) a chunk.
43 It will also invoke entry/exit - handlers.
45 IFFPARSE_RAWSTEP - same as IFFPARSE_STEP except that in this mode
46 the parse won't invoke any handlers.
49 INPUTS
50 iff - pointer to IFFHandle struct.
51 mode - IFFPARSE_SCAN, IFFPARSE_STEP or IFFPARSE_RAWSTEP.
53 RESULT
54 0 if successfull or IFFERR_#?
56 NOTES
59 EXAMPLE
61 BUGS
63 SEE ALSO
64 PushChunk(), PopChunk(), EntryHandler(), ExitHandler(), PropChunk[s](),
65 CollectionChunk[s](), StopChunk[s](), StopOnExit()
68 INTERNALS
70 *****************************************************************************/
72 AROS_LIBFUNC_INIT
73 struct ContextNode *cn;
75 LONG size;
76 LONG err = 0;
77 LONG toseek; /* To hold number of bytes left to seek in a chunk */
78 BOOL done = FALSE;
80 D(bug("ParseIFF (iff=%p, mode=%d)\n", iff, mode));
82 /* Cannot parse iff when it is not opened yet */
83 if (!(iff->iff_Flags & IFFF_OPEN))
85 D(bug("ParseIFF: syntax error (open)\n"));
86 ReturnInt ("ParseIFF",LONG,IFFERR_NOTIFF);
89 /* Cannot parse iff file, when it is opened in write-mode */
90 if (iff->iff_Flags & IFFF_WRITE)
92 /* Some applications accidently pass IFFF_WRITE to OpenIFF()
93 * when IFFF_READ should be used. While this is certainly
94 * wrong, these apps still work with 68k iffparse.library.
96 * So just warn, don't fail. - Piru
98 #if 1
99 D(bug("ParseIFF: warning, IFFF_WRITE iffhandle parsed\n"));
100 #else
101 D(bug("ParseIFF: syntax error (write)\n"));
102 ReturnInt ("ParseIFF",LONG,IFFERR_SYNTAX);
103 #endif
106 /* Main loop for reading the iff file
108 This works as a Finite State Automaton where we between the states might return to the
109 user, and get called by the user again. InternalIFFHandle->CurrentState holds
110 the current state */
112 while (!done)
114 D(bug("ParseIFF: state %d\n", GetIntIH(iff)->iff_CurrentState));
115 switch ( GetIntIH(iff)->iff_CurrentState )
117 case IFFSTATE_COMPOSITE:
119 /* We are inside a FORM, LIST, CAT or PROP
120 and expect a new chunk header to be found,
121 but first we must invoke the handlers on the current one */
123 /* Where to go next */
124 GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
126 /* Invoke the handlers */
127 err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
129 if (err)
131 if (err == IFF_RETURN2CLIENT)
132 err = 0;
133 done = TRUE;
138 break;
140 case IFFSTATE_PUSHCHUNK:
142 /* What we want to do now is to get the next chunk, make a context-node of it,
143 and put it in top of the stack */
145 err = GetChunkHeader(iff, IPB(IFFParseBase));
146 if (err)
148 done = TRUE;
149 break;
153 /* Determine if top chunk is composite or atomic */
154 cn = TopChunk(iff);
156 if ( GetIntCN(cn)->cn_Composite)
157 GetIntIH(iff)->iff_CurrentState = IFFSTATE_COMPOSITE;
158 else
159 GetIntIH(iff)->iff_CurrentState = IFFSTATE_ATOMIC;
162 break;
165 case IFFSTATE_ATOMIC:
167 /* We have entried an atomic chunk. Its contextnode has
168 allready been laid onto the stack */
170 GetIntIH(iff)->iff_CurrentState = IFFSTATE_SCANEXIT;
172 err = InvokeHandlers(iff, mode, IFFLCI_ENTRYHANDLER, IPB(IFFParseBase));
173 if (err)
175 if (err == IFF_RETURN2CLIENT)
176 err = 0L;
178 done = TRUE;
180 break;
182 case IFFSTATE_SCANEXIT:
184 /* We have done the needed entry stuff inside the ATOMIC chunk scan towards
185 the end of it */
187 GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
189 #if SWAP_SCANEXIT
190 if (mode == IFFPARSE_SCAN)
192 #endif
193 cn = TopChunk(iff);
195 toseek = cn->cn_Size - cn->cn_Scan;
197 /* If cn_Size is not wordaligned we must seek one more byte */
198 if (cn->cn_Size & 1)
199 toseek ++;
201 if (toseek)
203 err = SeekStream(iff, toseek, IPB(IFFParseBase));
204 if (err)
206 done = TRUE;
208 else
210 cn->cn_Scan += toseek;
213 #if SWAP_SCANEXIT
215 #endif
216 break;
218 case IFFSTATE_EXIT:
220 /* We are at the end of the chunk, should scan for exithandlers */
221 GetIntIH(iff)->iff_CurrentState = IFFSTATE_POPCHUNK;
223 err = InvokeHandlers(iff, mode, IFFLCI_EXITHANDLER, IPB(IFFParseBase));
224 if (err)
226 if (err == IFF_RETURN2CLIENT)
227 err = 0;
230 done = TRUE;
233 break;
235 case IFFSTATE_POPCHUNK:
236 /* Before we pop the top node, get its size */
237 cn = TopChunk(iff);
238 size = cn->cn_Size;
240 /* Align the size */
241 if (size % 2)
242 size +=1;
244 #if SWAP_SCANEXIT
245 if (!(GetIntCN(cn)->cn_Composite) && (toseek = size - cn->cn_Scan))
247 err = SeekStream(iff, toseek, IPB(IFFParseBase));
248 if (err)
250 done = TRUE;
251 break;
252 } else {
253 cn->cn_Scan = size;
256 #endif
259 /* Add size of chunk header */
260 if ( GetIntCN(cn)->cn_Composite )
261 size += 12;
262 else
263 size += 8;
265 /* Pop the top node */
266 PopContextNode(iff, IPB(IFFParseBase));
268 /* The underlying node must get updated its scancount */
269 cn = TopChunk(iff);
270 cn->cn_Scan += size;
272 /* The outer node is ALWAYS a composite one
273 Now we might have 3 different situations :
275 1. There are more chunks inside this composite chunk, and we should
276 enter the PUSHCHUNK state to get them.
278 2. There are no more chunks in this composite, but we are not in the outer-most
279 composite, so we just want to enter the EXIT state.
281 3. We are at the end of and about to leave the outermost composite chunk,
282 and should therefore return IFFERR_EOF.
286 /* Nr. 1 */
287 if (cn->cn_Scan < cn->cn_Size)
288 GetIntIH(iff)->iff_CurrentState = IFFSTATE_PUSHCHUNK;
290 else
292 /* Nr. 3 */
293 if (!iff->iff_Depth )
295 err = IFFERR_EOF;
296 done = TRUE;
298 else
299 /* Nr. 2 */
300 GetIntIH(iff)->iff_CurrentState = IFFSTATE_EXIT;
303 break;
306 } /* End of switch */
309 } /* End of while */
311 D(bug("ParseIFF: return %ld\n", err));
313 ReturnInt ("ParseIFF",LONG,err);
314 AROS_LIBFUNC_EXIT
315 } /* ParseIFF */