2 Copyright © 1995-2016, The AROS Development Team. All rights reserved.
7 #include <aros/debug.h>
8 #include "iffparse_intern.h"
10 #define SWAP_SCANEXIT 1
12 /*****************************************************************************
15 #include <proto/iffparse.h>
17 AROS_LH2(LONG
, ParseIFF
,
20 AROS_LHA(struct IFFHandle
*, iff
, A0
),
21 AROS_LHA(LONG
, mode
, D0
),
24 struct Library
*, IFFParseBase
, 7, IFFParse
)
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
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.
50 iff - pointer to IFFHandle struct.
51 mode - IFFPARSE_SCAN, IFFPARSE_STEP or IFFPARSE_RAWSTEP.
54 0 if successful or IFFERR_#?
64 PushChunk(), PopChunk(), EntryHandler(), ExitHandler(), PropChunk[s](),
65 CollectionChunk[s](), StopChunk[s](), StopOnExit()
70 *****************************************************************************/
73 struct ContextNode
*cn
;
77 LONG toseek
; /* To hold number of bytes left to seek in a chunk */
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
99 D(bug("ParseIFF: warning, IFFF_WRITE iffhandle parsed\n"));
101 D(bug("ParseIFF: syntax error (write)\n"));
102 ReturnInt ("ParseIFF",LONG
,IFFERR_SYNTAX
);
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
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
));
131 if (err
== IFF_RETURN2CLIENT
)
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
));
153 /* Determine if top chunk is composite or atomic */
156 if ( GetIntCN(cn
)->cn_Composite
)
157 GetIntIH(iff
)->iff_CurrentState
= IFFSTATE_COMPOSITE
;
159 GetIntIH(iff
)->iff_CurrentState
= IFFSTATE_ATOMIC
;
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
));
175 if (err
== IFF_RETURN2CLIENT
)
182 case IFFSTATE_SCANEXIT
:
184 /* We have done the needed entry stuff inside the ATOMIC chunk scan towards
187 GetIntIH(iff
)->iff_CurrentState
= IFFSTATE_EXIT
;
190 if (mode
== IFFPARSE_SCAN
)
195 toseek
= cn
->cn_Size
- cn
->cn_Scan
;
197 /* If cn_Size is not wordaligned we must seek one more byte */
203 err
= SeekStream(iff
, toseek
, IPB(IFFParseBase
));
210 cn
->cn_Scan
+= toseek
;
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
));
226 if (err
== IFF_RETURN2CLIENT
)
235 case IFFSTATE_POPCHUNK
:
236 /* Before we pop the top node, get its size */
245 if (!(GetIntCN(cn
)->cn_Composite
) && (toseek
= size
- cn
->cn_Scan
))
247 err
= SeekStream(iff
, toseek
, IPB(IFFParseBase
));
259 /* Add size of chunk header */
260 if ( GetIntCN(cn
)->cn_Composite
)
265 /* Pop the top node */
266 PopContextNode(iff
, IPB(IFFParseBase
));
268 /* The underlying node must get updated its scancount */
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.
287 if (cn
->cn_Scan
< cn
->cn_Size
)
288 GetIntIH(iff
)->iff_CurrentState
= IFFSTATE_PUSHCHUNK
;
293 if (!iff
->iff_Depth
)
300 GetIntIH(iff
)->iff_CurrentState
= IFFSTATE_EXIT
;
306 } /* End of switch */
311 D(bug("ParseIFF: return %ld\n", err
));
313 ReturnInt ("ParseIFF",LONG
,err
);